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