]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/acquire.c
57b30160fbd6384ff0bc524060782939488a4546
[bacula/bacula] / bacula / src / stored / acquire.c
1 /*
2  *  Routines to acquire and release a device for read/write
3  *
4  *   Kern Sibbald, August MMII
5  *
6  *   Version $Id$
7  */
8 /*
9    Copyright (C) 2002-2006 Kern Sibbald
10
11    This program is free software; you can redistribute it and/or
12    modify it under the terms of the GNU General Public License
13    version 2 as amended with additional clauses defined in the
14    file LICENSE in the main source directory.
15
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
19    the file LICENSE for additional details.
20
21  */
22
23 #include "bacula.h"                   /* pull in global headers */
24 #include "stored.h"                   /* pull in Storage Deamon headers */
25
26 /* Forward referenced functions */
27 static void attach_dcr_to_dev(DCR *dcr);
28
29
30 /*********************************************************************
31  * Acquire device for reading. 
32  *  The drive should have previously been reserved by calling 
33  *  reserve_device_for_read(). We read the Volume label from the block and
34  *  leave the block pointers just after the label.
35  *
36  *  Returns: NULL if failed for any reason
37  *           dcr  if successful
38  */
39 bool acquire_device_for_read(DCR *dcr)
40 {
41    DEVICE *dev = dcr->dev;
42    JCR *jcr = dcr->jcr;
43    bool ok = false;
44    bool tape_previously_mounted;
45    bool tape_initially_mounted;
46    VOL_LIST *vol;
47    bool try_autochanger = true;
48    int i;
49    int vol_label_status;
50    int retry = 0;
51    
52    Dmsg1(50, "jcr->dcr=%p\n", jcr->dcr);
53    dev->block(BST_DOING_ACQUIRE);
54
55    if (dev->num_writers > 0) {
56       Jmsg2(jcr, M_FATAL, 0, _("Num_writers=%d not zero. Job %d canceled.\n"), 
57          dev->num_writers, jcr->JobId);
58       goto get_out;
59    }
60
61    /* Find next Volume, if any */
62    vol = jcr->VolList;
63    if (!vol) {
64       Jmsg(jcr, M_FATAL, 0, _("No volumes specified. Job %d canceled.\n"), jcr->JobId);
65       goto get_out;
66    }
67    jcr->CurVolume++;
68    for (i=1; i<jcr->CurVolume; i++) {
69       vol = vol->next;
70    }
71    if (!vol) {
72       goto get_out;                   /* should not happen */   
73    }
74    bstrncpy(dcr->VolumeName, vol->VolumeName, sizeof(dcr->VolumeName));
75    bstrncpy(dcr->media_type, vol->MediaType, sizeof(dcr->media_type));
76    dcr->VolCatInfo.Slot = vol->Slot;
77     
78    /*
79     * If the MediaType requested for this volume is not the
80     *  same as the current drive, we attempt to find the same
81     *  device that was used to write the orginal volume.  If
82     *  found, we switch to using that device.
83     */
84    Dmsg2(100, "MediaType dcr=%s dev=%s\n", dcr->media_type, dev->device->media_type);
85    if (dcr->media_type[0] && strcmp(dcr->media_type, dev->device->media_type) != 0) {
86       RCTX rctx;
87       DIRSTORE *store;
88       int stat;
89       DCR *dcr_save = jcr->dcr;
90
91       lock_reservations();
92       jcr->dcr = NULL;
93       memset(&rctx, 0, sizeof(RCTX));
94       rctx.jcr = jcr;
95       jcr->reserve_msgs = New(alist(10, not_owned_by_alist));
96       rctx.any_drive = true;
97       rctx.device_name = vol->device;
98       store = new DIRSTORE;
99       memset(store, 0, sizeof(DIRSTORE));
100       store->name[0] = 0; /* No dir name */
101       bstrncpy(store->media_type, vol->MediaType, sizeof(store->media_type));
102       bstrncpy(store->pool_name, dcr->pool_name, sizeof(store->pool_name));
103       bstrncpy(store->pool_type, dcr->pool_type, sizeof(store->pool_type));
104       store->append = false;
105       rctx.store = store;
106       
107       /*
108        * Note, if search_for_device() succeeds, we get a new_dcr,
109        *  which we do not use except for the dev info.
110        */
111       stat = search_res_for_device(rctx);
112       release_msgs(jcr);              /* release queued messages */
113       unlock_reservations();
114       if (stat == 1) {
115          DCR *new_dcr = jcr->read_dcr;
116          dev->unblock();
117          detach_dcr_from_dev(dcr);    /* release old device */
118          /* Copy important info from the new dcr */
119          dev = dcr->dev = new_dcr->dev; 
120          jcr->read_dcr = dcr; 
121          dcr->device = new_dcr->device;
122          dcr->max_job_spool_size = dcr->device->max_job_spool_size;
123          attach_dcr_to_dev(dcr);
124          new_dcr->VolumeName[0] = 0;
125          free_dcr(new_dcr);
126          dev->block(BST_DOING_ACQUIRE); 
127          Jmsg(jcr, M_INFO, 0, _("Media Type change.  New device %s chosen.\n"),
128             dev->print_name());
129          bstrncpy(dcr->VolumeName, vol->VolumeName, sizeof(dcr->VolumeName));
130          bstrncpy(dcr->media_type, vol->MediaType, sizeof(dcr->media_type));
131          dcr->VolCatInfo.Slot = vol->Slot;
132          bstrncpy(dcr->pool_name, store->pool_name, sizeof(dcr->pool_name));
133          bstrncpy(dcr->pool_type, store->pool_type, sizeof(dcr->pool_type));
134       } else if (stat == 0) {   /* device busy */
135          Dmsg1(000, "Device %s is busy.\n", vol->device);
136       } else {
137          /* error */
138          Jmsg1(jcr, M_FATAL, 0, _("No suitable device found to read Volume \"%s\"\n"),
139             vol->VolumeName);
140          jcr->dcr = dcr_save;
141          goto get_out;
142       }
143       jcr->dcr = dcr_save;
144    }
145
146
147    init_device_wait_timers(dcr);
148
149    tape_previously_mounted = dev->can_read() || dev->can_append() ||
150                              dev->is_labeled();
151    tape_initially_mounted = tape_previously_mounted;
152
153
154    /* Volume info is always needed because of VolParts */
155    Dmsg0(200, "dir_get_volume_info\n");
156    if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_READ)) {
157       Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg);
158    }
159    
160    for ( ;; ) {
161       /* If not polling limit retries */
162       if (!dev->poll && retry++ > 10) {
163          break;
164       }
165       dev->clear_labeled();              /* force reread of label */
166       if (job_canceled(jcr)) {
167          Mmsg1(dev->errmsg, _("Job %d canceled.\n"), jcr->JobId);
168          goto get_out;                /* error return */
169       }
170       /*
171        * This code ensures that the device is ready for
172        * reading. If it is a file, it opens it.
173        * If it is a tape, it checks the volume name
174        */
175       Dmsg1(100, "bstored: open vol=%s\n", dcr->VolumeName);
176       if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
177          if (dev->dev_errno == EIO) {   /* no tape loaded */
178            Jmsg3(jcr, M_WARNING, 0, _("Read open device %s Volume \"%s\" failed (EIO): ERR=%s\n"),
179                  dev->print_name(), dcr->VolumeName, dev->bstrerror());
180             goto default_path;
181          }
182          
183          Jmsg3(jcr, M_FATAL, 0, _("Read open device %s Volume \"%s\" failed: ERR=%s\n"),
184              dev->print_name(), dcr->VolumeName, dev->bstrerror());
185          goto get_out;
186       }
187       Dmsg1(100, "opened dev %s OK\n", dev->print_name());
188       
189       /* Read Volume Label */
190       
191       Dmsg0(200, "calling read-vol-label\n");
192       vol_label_status = read_dev_volume_label(dcr);
193       switch (vol_label_status) {
194       case VOL_OK:
195          ok = true;
196          memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
197          break;                    /* got it */
198       case VOL_IO_ERROR:
199          /*
200           * Send error message generated by read_dev_volume_label()
201           *  only we really had a tape mounted. This supresses superfluous
202           *  error messages when nothing is mounted.
203           */
204          if (tape_previously_mounted) {
205             Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
206          }
207          goto default_path;
208       case VOL_NAME_ERROR:
209          if (tape_initially_mounted) {
210             tape_initially_mounted = false;
211             goto default_path;
212          }
213          /* If polling and got a previous bad name, ignore it */
214          if (dev->poll && strcmp(dev->BadVolName, dev->VolHdr.VolumeName) == 0) {
215             goto default_path;
216          } else {
217              bstrncpy(dev->BadVolName, dev->VolHdr.VolumeName, sizeof(dev->BadVolName));
218          }
219          /* Fall through */
220       default:
221          Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg);
222 default_path:
223          tape_previously_mounted = true;
224          
225          /*
226           * If the device requires mount, close it, so the device can be ejected.
227           */
228          if (dev->requires_mount()) {
229             dev->close();
230          }
231          
232          /* Call autochanger only once unless ask_sysop called */
233          if (try_autochanger) {
234             int stat;
235             Dmsg2(200, "calling autoload Vol=%s Slot=%d\n",
236                dcr->VolumeName, dcr->VolCatInfo.Slot);
237             stat = autoload_device(dcr, 0, NULL);
238             if (stat > 0) {
239                try_autochanger = false;
240                continue;              /* try reading volume mounted */
241             }
242          }
243          
244          /* Mount a specific volume and no other */
245          Dmsg0(200, "calling dir_ask_sysop\n");
246          if (!dir_ask_sysop_to_mount_volume(dcr)) {
247             goto get_out;             /* error return */
248          }
249          try_autochanger = true;      /* permit using autochanger again */
250          continue;                    /* try reading again */
251       } /* end switch */
252       break;
253    } /* end for loop */
254    if (!ok) {
255       Jmsg1(jcr, M_FATAL, 0, _("Too many errors trying to mount device %s.\n"),
256             dev->print_name());
257       goto get_out;
258    }
259
260    dev->clear_append();
261    dev->set_read();
262    set_jcr_job_status(jcr, JS_Running);
263    dir_send_job_status(jcr);
264    Jmsg(jcr, M_INFO, 0, _("Ready to read from volume \"%s\" on device %s.\n"),
265       dcr->VolumeName, dev->print_name());
266
267 get_out:
268    P(dev->mutex);
269    if (dcr->reserved_device) {
270       dev->reserved_device--;
271       Dmsg2(100, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name());
272       dcr->reserved_device = false;
273    }
274    V(dev->mutex);
275    dev->unblock();
276    Dmsg1(50, "jcr->dcr=%p\n", jcr->dcr);
277    return ok;
278 }
279
280
281 /*
282  * Acquire device for writing. We permit multiple writers.
283  *  If this is the first one, we read the label.
284  *
285  *  Returns: NULL if failed for any reason
286  *           dcr if successful.
287  *   Note, normally reserve_device_for_append() is called
288  *   before this routine.
289  */
290 DCR *acquire_device_for_append(DCR *dcr)
291 {
292    bool release = false;
293    bool recycle = false;
294    bool do_mount = false;
295    DEVICE *dev = dcr->dev;
296    JCR *jcr = dcr->jcr;
297
298    init_device_wait_timers(dcr);
299
300    dev->block(BST_DOING_ACQUIRE);
301    Dmsg1(190, "acquire_append device is %s\n", dev->is_tape()?"tape":
302         (dev->is_dvd()?"DVD":"disk"));
303
304    /*
305     * With the reservation system, this should not happen
306     */
307    if (dev->can_read()) {
308       Jmsg1(jcr, M_FATAL, 0, _("Device %s is busy reading.\n"), dev->print_name());
309       Dmsg1(200, "Device %s is busy reading.\n", dev->print_name());
310       goto get_out;
311    }
312
313    if (dev->can_append()) {
314       Dmsg0(190, "device already in append.\n");
315       /*
316        * Device already in append mode
317        *
318        * Check if we have the right Volume mounted
319        *   OK if current volume info OK
320        *   OK if next volume matches current volume
321        *   otherwise mount desired volume obtained from
322        *    dir_find_next_appendable_volume
323        *  dev->VolHdr.VolumeName is what is in the drive
324        *  dcr->VolumeName is what we pass into the routines, or
325        *    get back from the subroutines.
326        */
327       bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName));
328       if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_WRITE) &&
329           !(dir_find_next_appendable_volume(dcr) &&
330             strcmp(dev->VolHdr.VolumeName, dcr->VolumeName) == 0)) { /* wrong tape mounted */
331          Dmsg2(190, "Wrong tape mounted: %s. wants:%s\n", dev->VolHdr.VolumeName,
332             dcr->VolumeName);
333          /* Release volume reserved by dir_find_next_appendable_volume() */
334          if (dcr->VolumeName[0]) {
335             free_unused_volume(dcr);
336          }
337          if (dev->num_writers != 0) {
338             Jmsg3(jcr, M_FATAL, 0, _("Wanted Volume \"%s\", but device %s is busy writing on \"%s\" .\n"), 
339                  dcr->VolumeName, dev->print_name(), dev->VolHdr.VolumeName);
340             Dmsg3(200, "Wanted Volume \"%s\", but device %s is busy writing on \"%s\" .\n",  
341                  dcr->VolumeName, dev->print_name(), dev->VolHdr.VolumeName);
342             goto get_out;
343          }
344          /* Wrong tape mounted, release it, then fall through to get correct one */
345          Dmsg0(190, "Wrong tape mounted, release and try mount.\n");
346          release = true;
347          do_mount = true;
348       } else {
349          /*
350           * At this point, the correct tape is already mounted, so
351           *   we do not need to do mount_next_write_volume(), unless
352           *   we need to recycle the tape.
353           */
354           recycle = strcmp(dcr->VolCatInfo.VolCatStatus, "Recycle") == 0;
355           Dmsg1(190, "Correct tape mounted. recycle=%d\n", recycle);
356           if (recycle && dev->num_writers != 0) {
357              Jmsg(jcr, M_FATAL, 0, _("Cannot recycle volume \"%s\""
358                   " on device %s because it is in use by another job.\n"),
359                   dev->VolHdr.VolumeName, dev->print_name());
360              goto get_out;
361           }
362           if (dev->num_writers == 0) {
363              memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
364           }
365       }
366    } else {
367       /* Not already in append mode, so mount the device */
368       Dmsg0(190, "Not in append mode, try mount.\n");
369       ASSERT(dev->num_writers == 0);
370       do_mount = true;
371    }
372
373    if (do_mount || recycle) {
374       Dmsg0(190, "Do mount_next_write_vol\n");
375       bool mounted = mount_next_write_volume(dcr, release);
376       if (!mounted) {
377          if (!job_canceled(jcr)) {
378             /* Reduce "noise" -- don't print if job canceled */
379             Jmsg(jcr, M_FATAL, 0, _("Could not ready device %s for append.\n"),
380                dev->print_name());
381             Dmsg1(200, "Could not ready device %s for append.\n", 
382                dev->print_name());
383          }
384          goto get_out;
385       }
386       Dmsg2(190, "Output pos=%u:%u\n", dcr->dev->file, dcr->dev->block_num);
387    }
388
389    dev->num_writers++;                /* we are now a writer */
390    if (jcr->NumVolumes == 0) {
391       jcr->NumVolumes = 1;
392    }
393    P(dev->mutex);
394    if (dcr->reserved_device) {
395       dev->reserved_device--;
396       Dmsg2(100, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name());
397       dcr->reserved_device = false;
398    }
399    V(dev->mutex);
400    dev->unblock();
401    return dcr;
402
403 /*
404  * Error return
405  */
406 get_out:
407    P(dev->mutex);
408    if (dcr->reserved_device) {
409       dev->reserved_device--;
410       Dmsg2(100, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name());
411       dcr->reserved_device = false;
412    }
413    V(dev->mutex);
414    dev->unblock();
415    return NULL;
416 }
417
418
419 /*
420  * This job is done, so release the device. From a Unix standpoint,
421  *  the device remains open.
422  *
423  */
424 bool release_device(DCR *dcr)
425 {
426    JCR *jcr = dcr->jcr;
427    DEVICE *dev = dcr->dev;
428    bool ok = true;
429
430    lock_device(dev);
431    Dmsg2(100, "release_device device %s is %s\n", dev->print_name(), dev->is_tape()?"tape":"disk");
432
433    /* if device is reserved, job never started, so release the reserve here */
434    if (dcr->reserved_device) {
435       dev->reserved_device--;
436       Dmsg2(100, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name());
437       dcr->reserved_device = false;
438    }
439
440    if (dev->can_read()) {
441       dev->clear_read();              /* clear read bit */
442
443       /******FIXME**** send read volume usage statistics to director */
444
445    } else if (dev->num_writers > 0) {
446       /* 
447        * Note if WEOT is set, we are at the end of the tape
448        *   and may not be positioned correctly, so the
449        *   job_media_record and update_vol_info have already been
450        *   done, which means we skip them here.
451        */
452       dev->num_writers--;
453       Dmsg1(100, "There are %d writers in release_device\n", dev->num_writers);
454       if (dev->is_labeled()) {
455          Dmsg0(100, "dir_create_jobmedia_record. Release\n");
456          if (!dev->at_weot() && !dir_create_jobmedia_record(dcr)) {
457             Jmsg(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
458                dcr->VolCatInfo.VolCatName, jcr->Job);
459          }
460          /* If no more writers, write an EOF */
461          if (!dev->num_writers && dev->can_write()) {
462             dev->weof(1);
463             write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
464          }
465          if (!dev->at_weot()) {
466             dev->VolCatInfo.VolCatFiles = dev->file;   /* set number of files */
467             dev->VolCatInfo.VolCatJobs++;              /* increment number of jobs */
468             /* Note! do volume update before close, which zaps VolCatInfo */
469             Dmsg0(100, "dir_update_vol_info. Release0\n");
470             dir_update_volume_info(dcr, false); /* send Volume info to Director */
471          }
472       }
473
474    } else {
475       /*                
476        * If we reach here, it is most likely because the job
477        *   has failed, since the device is not in read mode and
478        *   there are no writers. It was probably reserved.
479        */
480    }
481
482    /* If no writers, close if file or !CAP_ALWAYS_OPEN */
483    if (dev->num_writers == 0 && (!dev->is_tape() || !dev_cap(dev, CAP_ALWAYSOPEN))) {
484       dvd_remove_empty_part(dcr);        /* get rid of any empty spool part */
485       dev->close();
486    }
487
488    /* Fire off Alert command and include any output */
489    if (!job_canceled(jcr) && dcr->device->alert_command) {
490       POOLMEM *alert;
491       int status = 1;
492       BPIPE *bpipe;
493       char line[MAXSTRING];
494       alert = get_pool_memory(PM_FNAME);
495       alert = edit_device_codes(dcr, alert, dcr->device->alert_command, "");
496       bpipe = open_bpipe(alert, 0, "r");
497       if (bpipe) {
498          while (fgets(line, sizeof(line), bpipe->rfd)) {
499             Jmsg(jcr, M_ALERT, 0, _("Alert: %s"), line);
500          }
501          status = close_bpipe(bpipe);
502       } else {
503          status = errno;
504       }
505       if (status != 0) {
506          berrno be;
507          Jmsg(jcr, M_ALERT, 0, _("3997 Bad alert command: %s: ERR=%s.\n"),
508               alert, be.strerror(status));
509       }
510
511       Dmsg1(400, "alert status=%d\n", status);
512       free_pool_memory(alert);
513    }
514    unlock_device(dev);
515    if (jcr->read_dcr == dcr) {
516       jcr->read_dcr = NULL;
517    }
518    if (jcr->dcr == dcr) {
519       jcr->dcr = NULL;
520    }
521    free_dcr(dcr);
522    return ok;
523 }
524
525 /*
526  * Create a new Device Control Record and attach
527  *   it to the device (if this is a real job).
528  */
529 DCR *new_dcr(JCR *jcr, DEVICE *dev)
530 {
531    DCR *dcr = (DCR *)malloc(sizeof(DCR));
532    memset(dcr, 0, sizeof(DCR));
533    dcr->jcr = jcr;
534    if (dev) {
535       dcr->dev = dev;
536       dcr->device = dev->device;
537       dcr->block = new_block(dev);
538       dcr->rec = new_record();
539       dcr->max_job_spool_size = dev->device->max_job_spool_size;
540       attach_dcr_to_dev(dcr);
541    }
542    dcr->spool_fd = -1;
543    return dcr;
544 }
545
546 /*
547  * Search the dcrs list for the given dcr. If it is found,
548  *  as it should be, then remove it. Also zap the jcr pointer
549  *  to the dcr if it is the same one.
550  */
551 #ifdef needed
552 static void remove_dcr_from_dcrs(DCR *dcr)
553 {
554    JCR *jcr = dcr->jcr;
555    if (jcr->dcrs) {
556       int i = 0;
557       DCR *ldcr;
558       int num = jcr->dcrs->size();
559       for (i=0; i < num; i++) {
560          ldcr = (DCR *)jcr->dcrs->get(i);
561          if (ldcr == dcr) {
562             jcr->dcrs->remove(i);
563             if (jcr->dcr == dcr) {
564                jcr->dcr = NULL;
565             }
566          }
567       }
568    }
569 }
570 #endif
571
572 static void attach_dcr_to_dev(DCR *dcr)
573 {
574    DEVICE *dev = dcr->dev;
575    JCR *jcr = dcr->jcr;
576
577    if (!dcr->attached_to_dev && dev->is_open() && jcr && jcr->JobType != JT_SYSTEM) {
578       dev->attached_dcrs->append(dcr);  /* attach dcr to device */
579       dcr->attached_to_dev = true;
580    }
581 }
582
583 void detach_dcr_from_dev(DCR *dcr)
584 {
585    DEVICE *dev = dcr->dev;
586
587    if (dcr->reserved_device) {
588       dcr->reserved_device = false;
589       lock_device(dev);
590       dev->reserved_device--;
591       Dmsg2(100, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name());
592       dcr->reserved_device = false;
593       /* If we set read mode in reserving, remove it */
594       if (dev->can_read()) {
595          dev->clear_read();
596       }
597       if (dev->num_writers < 0) {
598          Jmsg1(dcr->jcr, M_ERROR, 0, _("Hey! num_writers=%d!!!!\n"), dev->num_writers);
599          dev->num_writers = 0;
600       }
601       unlock_device(dev);
602    }
603
604    /* Detach this dcr only if attached */
605    if (dcr->attached_to_dev) {
606       dcr->dev->attached_dcrs->remove(dcr);  /* detach dcr from device */
607       dcr->attached_to_dev = false;
608 //    remove_dcr_from_dcrs(dcr);      /* remove dcr from jcr list */
609    }
610    free_unused_volume(dcr);           /* free unused vols attached to this dcr */
611    pthread_cond_broadcast(&dcr->dev->wait_next_vol);
612    pthread_cond_broadcast(&wait_device_release);
613 }
614
615 /*
616  * Free up all aspects of the given dcr -- i.e. dechain it,
617  *  release allocated memory, zap pointers, ...
618  */
619 void free_dcr(DCR *dcr)
620 {
621
622    detach_dcr_from_dev(dcr);
623
624    if (dcr->block) {
625       free_block(dcr->block);
626    }
627    if (dcr->rec) {
628       free_record(dcr->rec);
629    }
630    if (dcr->jcr) {
631       dcr->jcr->dcr = NULL;
632    }
633    free(dcr);
634 }