]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/acquire.c
Add 5 minute timout to alert directive -- fixes bug #1536
[bacula/bacula] / bacula / src / stored / acquire.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2002-2010 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 and included
11    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 Kern Sibbald.
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  */
34
35 #include "bacula.h"                   /* pull in global headers */
36 #include "stored.h"                   /* pull in Storage Deamon headers */
37
38 /* Forward referenced functions */
39 static void attach_dcr_to_dev(DCR *dcr);
40 static void detach_dcr_from_dev(DCR *dcr);
41 static void set_dcr_from_vol(DCR *dcr, VOL_LIST *vol);
42
43
44 /*********************************************************************
45  * Acquire device for reading. 
46  *  The drive should have previously been reserved by calling 
47  *  reserve_device_for_read(). We read the Volume label from the block and
48  *  leave the block pointers just after the label.
49  *
50  *  Returns: NULL if failed for any reason
51  *           dcr  if successful
52  */
53 bool acquire_device_for_read(DCR *dcr)
54 {
55    DEVICE *dev = dcr->dev;
56    JCR *jcr = dcr->jcr;
57    bool ok = false;
58    bool tape_previously_mounted;
59    bool tape_initially_mounted;
60    VOL_LIST *vol;
61    bool try_autochanger = true;
62    int i;
63    int vol_label_status;
64    int retry = 0;
65    
66    Dmsg2(950, "dcr=%p dev=%p\n", dcr, dcr->dev);
67    Dmsg2(950, "MediaType dcr=%s dev=%s\n", dcr->media_type, dev->device->media_type);
68    dev->dblock(BST_DOING_ACQUIRE);
69
70    if (dev->num_writers > 0) {
71       Jmsg2(jcr, M_FATAL, 0, _("Acquire read: num_writers=%d not zero. Job %d canceled.\n"), 
72          dev->num_writers, jcr->JobId);
73       goto get_out;
74    }
75
76    /* Find next Volume, if any */
77    vol = jcr->VolList;
78    if (!vol) {
79       char ed1[50];
80       Jmsg(jcr, M_FATAL, 0, _("No volumes specified for reading. Job %s canceled.\n"), 
81          edit_int64(jcr->JobId, ed1));
82       goto get_out;
83    }
84    jcr->CurReadVolume++;
85    for (i=1; i<jcr->CurReadVolume; i++) {
86       vol = vol->next;
87    }
88    if (!vol) {
89       Jmsg(jcr, M_FATAL, 0, _("Logic error: no next volume to read. Numvol=%d Curvol=%d\n"),
90          jcr->NumReadVolumes, jcr->CurReadVolume);
91       goto get_out;                   /* should not happen */   
92    }
93    set_dcr_from_vol(dcr, vol);
94
95    Dmsg2(100, "Want Vol=%s Slot=%d\n", vol->VolumeName, vol->Slot);
96     
97    /*
98     * If the MediaType requested for this volume is not the
99     *  same as the current drive, we attempt to find the same
100     *  device that was used to write the orginal volume.  If
101     *  found, we switch to using that device.
102     *
103     *  N.B. A lot of routines rely on the dcr pointer not changing
104     *    read_records.c even has multiple dcrs cached, so we take care
105     *    here to release all important parts of the dcr and re-acquire
106     *    them such as the block pointer (size may change), but we do
107     *    not release the dcr.
108     */
109    Dmsg2(50, "MediaType dcr=%s dev=%s\n", dcr->media_type, dev->device->media_type);
110    if (dcr->media_type[0] && strcmp(dcr->media_type, dev->device->media_type) != 0) {
111       RCTX rctx;
112       DIRSTORE *store;
113       int stat;
114
115       Jmsg3(jcr, M_INFO, 0, _("Changing read device. Want Media Type=\"%s\" have=\"%s\"\n"
116                               "  device=%s\n"), 
117             dcr->media_type, dev->device->media_type, dev->print_name());
118       Dmsg3(50, "Changing read device. Want Media Type=\"%s\" have=\"%s\"\n"
119                               "  device=%s\n", 
120             dcr->media_type, dev->device->media_type, dev->print_name());
121
122       dev->dunblock(DEV_UNLOCKED);
123
124       lock_reservations();
125       memset(&rctx, 0, sizeof(RCTX));
126       rctx.jcr = jcr;
127       jcr->read_dcr = dcr;
128       jcr->reserve_msgs = New(alist(10, not_owned_by_alist));
129       rctx.any_drive = true;
130       rctx.device_name = vol->device;
131       store = new DIRSTORE;
132       memset(store, 0, sizeof(DIRSTORE));
133       store->name[0] = 0; /* No dir name */
134       bstrncpy(store->media_type, vol->MediaType, sizeof(store->media_type));
135       bstrncpy(store->pool_name, dcr->pool_name, sizeof(store->pool_name));
136       bstrncpy(store->pool_type, dcr->pool_type, sizeof(store->pool_type));
137       store->append = false;
138       rctx.store = store;
139       clean_device(dcr);                     /* clean up the dcr */
140       
141       /*
142        * Search for a new device
143        */
144       stat = search_res_for_device(rctx);
145       release_reserve_messages(jcr);         /* release queued messages */
146       unlock_reservations();
147
148       if (stat == 1) {
149          dev = dcr->dev;                     /* get new device pointer */
150          dev->dblock(BST_DOING_ACQUIRE); 
151          dcr->VolumeName[0] = 0;
152          Jmsg(jcr, M_INFO, 0, _("Media Type change.  New read device %s chosen.\n"),
153             dev->print_name());
154          Dmsg1(50, "Media Type change.  New read device %s chosen.\n", dev->print_name());
155
156          bstrncpy(dcr->VolumeName, vol->VolumeName, sizeof(dcr->VolumeName));
157          dcr->setVolCatName(vol->VolumeName);
158          bstrncpy(dcr->media_type, vol->MediaType, sizeof(dcr->media_type));
159          dcr->VolCatInfo.Slot = vol->Slot;
160          dcr->VolCatInfo.InChanger = vol->Slot > 0; 
161          bstrncpy(dcr->pool_name, store->pool_name, sizeof(dcr->pool_name));
162          bstrncpy(dcr->pool_type, store->pool_type, sizeof(dcr->pool_type));
163       } else {
164          /* error */
165          Jmsg1(jcr, M_FATAL, 0, _("No suitable device found to read Volume \"%s\"\n"),
166             vol->VolumeName);
167          Dmsg1(50, "No suitable device found to read Volume \"%s\"\n", vol->VolumeName);
168          goto get_out;
169       }
170    }
171    Dmsg2(400, "MediaType dcr=%s dev=%s\n", dcr->media_type, dev->device->media_type);
172
173    dev->clear_unload();
174
175    if (dev->vol && dev->vol->is_swapping()) {
176       dev->vol->set_slot(vol->Slot);
177       Dmsg3(100, "swapping: slot=%d Vol=%s dev=%s\n", dev->vol->get_slot(),
178          dev->vol->vol_name, dev->print_name());
179    }
180
181    init_device_wait_timers(dcr);
182
183    tape_previously_mounted = dev->can_read() || dev->can_append() ||
184                              dev->is_labeled();
185    tape_initially_mounted = tape_previously_mounted;
186
187
188    /* Volume info is always needed because of VolParts */
189    Dmsg1(150, "dir_get_volume_info vol=%s\n", dcr->VolumeName);
190    if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_READ)) {
191       Dmsg2(150, "dir_get_vol_info failed for vol=%s: %s\n", 
192          dcr->VolumeName, jcr->errmsg);
193       Jmsg1(jcr, M_WARNING, 0, "Read acquire: %s", jcr->errmsg);
194    }
195    dev->set_load();                /* set to load volume */
196    
197    for ( ;; ) {
198       /* If not polling limit retries */
199       if (!dev->poll && retry++ > 10) {
200          break;
201       }
202       dev->clear_labeled();              /* force reread of label */
203       if (job_canceled(jcr)) {
204          char ed1[50];
205          Mmsg1(dev->errmsg, _("Job %s canceled.\n"), edit_int64(jcr->JobId, ed1));
206          Jmsg(jcr, M_INFO, 0, dev->errmsg);
207          goto get_out;                /* error return */
208       }
209
210       dcr->do_unload();
211       dcr->do_swapping(false/*!is_writing*/);
212       dcr->do_load(false /*!is_writing*/);
213       set_dcr_from_vol(dcr, vol);          /* refresh dcr with desired volume info */
214
215       /*
216        * This code ensures that the device is ready for
217        * reading. If it is a file, it opens it.
218        * If it is a tape, it checks the volume name
219        */
220       Dmsg1(100, "bstored: open vol=%s\n", dcr->VolumeName);
221       if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
222          if (!dev->poll) {
223             Jmsg3(jcr, M_WARNING, 0, _("Read open device %s Volume \"%s\" failed: ERR=%s\n"),
224                   dev->print_name(), dcr->VolumeName, dev->bstrerror());
225          }
226          goto default_path;
227       }
228       Dmsg1(50, "opened dev %s OK\n", dev->print_name());
229       
230       /* Read Volume Label */
231       Dmsg0(50, "calling read-vol-label\n");
232       vol_label_status = read_dev_volume_label(dcr);
233       switch (vol_label_status) {
234       case VOL_OK:
235          Dmsg0(50, "Got correct volume.\n");
236          ok = true;
237          dev->VolCatInfo = dcr->VolCatInfo;     /* structure assignment */
238          break;                    /* got it */
239       case VOL_IO_ERROR:
240          Dmsg0(50, "IO Error\n");
241          /*
242           * Send error message generated by read_dev_volume_label()
243           *  only we really had a tape mounted. This supresses superfluous
244           *  error messages when nothing is mounted.
245           */
246          if (tape_previously_mounted) {
247             Jmsg(jcr, M_WARNING, 0, "Read acquire: %s", jcr->errmsg);
248          }
249          goto default_path;
250       case VOL_NAME_ERROR:
251          Dmsg3(50, "Vol name=%s want=%s drv=%s.\n", dev->VolHdr.VolumeName, 
252                dcr->VolumeName, dev->print_name());
253          if (dev->is_volume_to_unload()) {
254             goto default_path;
255          }
256          dev->set_unload();              /* force unload of unwanted tape */
257          if (!unload_autochanger(dcr, -1)) {
258             /* at least free the device so we can re-open with correct volume */
259             dev->close();                                                          
260             free_volume(dev);
261          }
262          dev->set_load();
263          /* Fall through */
264       default:
265          Jmsg1(jcr, M_WARNING, 0, "Read acquire: %s", jcr->errmsg);
266 default_path:
267          Dmsg0(50, "default path\n");
268          tape_previously_mounted = true;
269          
270          /*
271           * If the device requires mount, close it, so the device can be ejected.
272           */
273          if (dev->requires_mount()) {
274             dev->close();
275             free_volume(dev);
276          }
277          
278          /* Call autochanger only once unless ask_sysop called */
279          if (try_autochanger) {
280             int stat;
281             Dmsg2(200, "calling autoload Vol=%s Slot=%d\n",
282                dcr->VolumeName, dcr->VolCatInfo.Slot);
283             stat = autoload_device(dcr, 0, NULL);
284             if (stat > 0) {
285                try_autochanger = false;
286                continue;              /* try reading volume mounted */
287             }
288          }
289          
290          /* Mount a specific volume and no other */
291          Dmsg0(200, "calling dir_ask_sysop\n");
292          if (!dir_ask_sysop_to_mount_volume(dcr, ST_READ)) {
293             goto get_out;             /* error return */
294          }
295
296          /* Volume info is always needed because of VolParts */
297          Dmsg1(150, "dir_get_volume_info vol=%s\n", dcr->VolumeName);
298          if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_READ)) {
299             Dmsg2(150, "dir_get_vol_info failed for vol=%s: %s\n", 
300                   dcr->VolumeName, jcr->errmsg);
301             Jmsg1(jcr, M_WARNING, 0, "Read acquire: %s", jcr->errmsg);
302          }
303          dev->set_load();                /* set to load volume */
304
305          try_autochanger = true;      /* permit trying the autochanger again */
306
307          continue;                    /* try reading again */
308       } /* end switch */
309       break;
310    } /* end for loop */
311
312    if (!ok) {
313       Jmsg1(jcr, M_FATAL, 0, _("Too many errors trying to mount device %s for reading.\n"),
314             dev->print_name());
315       goto get_out;
316    }
317
318    dev->clear_append();
319    dev->set_read();
320    set_jcr_job_status(jcr, JS_Running);
321    dir_send_job_status(jcr);
322    Jmsg(jcr, M_INFO, 0, _("Ready to read from volume \"%s\" on device %s.\n"),
323       dcr->VolumeName, dev->print_name());
324
325 get_out:
326    dev->dlock();
327    dcr->clear_reserved();
328    /* 
329     * Normally we are blocked, but in at least one error case above 
330     *   we are not blocked because we unsuccessfully tried changing
331     *   devices.  
332     */
333    if (dev->is_blocked()) {
334       dev->dunblock(DEV_LOCKED);
335    } else {
336       dev->dunlock();               /* dunblock() unlock the device too */
337    }
338    Dmsg2(950, "dcr=%p dev=%p\n", dcr, dcr->dev);
339    Dmsg2(950, "MediaType dcr=%s dev=%s\n", dcr->media_type, dev->device->media_type);
340    return ok;
341 }
342
343 /*
344  * Acquire device for writing. We permit multiple writers.
345  *  If this is the first one, we read the label.
346  *
347  *  Returns: NULL if failed for any reason
348  *           dcr if successful.
349  *   Note, normally reserve_device_for_append() is called
350  *   before this routine.
351  */
352 DCR *acquire_device_for_append(DCR *dcr)
353 {
354    DEVICE *dev = dcr->dev;
355    JCR *jcr = dcr->jcr;
356    bool ok = false;
357    bool have_vol = false;
358
359    init_device_wait_timers(dcr);
360
361    P(dev->acquire_mutex);           /* only one job at a time */
362    dev->dlock();
363    Dmsg1(100, "acquire_append device is %s\n", dev->is_tape()?"tape":
364         (dev->is_dvd()?"DVD":"disk"));
365
366    /*
367     * With the reservation system, this should not happen
368     */
369    if (dev->can_read()) {
370       Jmsg1(jcr, M_FATAL, 0, _("Want to append, but device %s is busy reading.\n"), dev->print_name());
371       Dmsg1(200, "Want to append but device %s is busy reading.\n", dev->print_name());
372       goto get_out;
373    }
374
375    dev->clear_unload();
376
377    /*
378     * have_vol defines whether or not mount_next_write_volume should
379     *   ask the Director again about what Volume to use.
380     */
381    if (dev->can_append() && dcr->is_suitable_volume_mounted() &&
382        strcmp(dcr->VolCatInfo.VolCatStatus, "Recycle") != 0) {
383       Dmsg0(190, "device already in append.\n");
384       /*
385        * At this point, the correct tape is already mounted, so
386        *   we do not need to do mount_next_write_volume(), unless
387        *   we need to recycle the tape.
388        */
389        if (dev->num_writers == 0) {
390           dev->VolCatInfo = dcr->VolCatInfo;   /* structure assignment */
391        }
392        have_vol = dcr->is_tape_position_ok();
393    }
394
395    if (!have_vol) {
396       dev->r_dlock(true);
397       block_device(dev, BST_DOING_ACQUIRE);
398       dev->dunlock();
399       Dmsg1(190, "jid=%u Do mount_next_write_vol\n", (uint32_t)jcr->JobId);
400       if (!dcr->mount_next_write_volume()) {
401          if (!job_canceled(jcr)) {
402             /* Reduce "noise" -- don't print if job canceled */
403             Jmsg(jcr, M_FATAL, 0, _("Could not ready device %s for append.\n"),
404                dev->print_name());
405             Dmsg1(200, "Could not ready device %s for append.\n", 
406                dev->print_name());
407          }
408          dev->dlock();
409          unblock_device(dev);
410          goto get_out;
411       }
412       Dmsg2(190, "Output pos=%u:%u\n", dcr->dev->file, dcr->dev->block_num);
413       dev->dlock();
414       unblock_device(dev);
415    }
416
417    dev->num_writers++;                /* we are now a writer */
418    if (jcr->NumWriteVolumes == 0) {
419       jcr->NumWriteVolumes = 1;
420    }
421    dev->VolCatInfo.VolCatJobs++;              /* increment number of jobs on vol */
422    Dmsg4(100, "=== nwriters=%d nres=%d vcatjob=%d dev=%s\n", 
423       dev->num_writers, dev->num_reserved(), dev->VolCatInfo.VolCatJobs, 
424       dev->print_name());
425    dir_update_volume_info(dcr, false, false); /* send Volume info to Director */
426    ok = true;
427
428 get_out:
429    dcr->clear_reserved();
430    dev->dunlock();
431    V(dev->acquire_mutex);
432    return ok ? dcr : NULL;
433 }
434
435 /*
436  * This job is done, so release the device. From a Unix standpoint,
437  *  the device remains open.
438  *
439  * Note, if we are spooling, we may enter with the device blocked.
440  * However, in all cases, unblock the device when leaving.
441  *
442  */
443 bool release_device(DCR *dcr)
444 {
445    JCR *jcr = dcr->jcr;
446    DEVICE *dev = dcr->dev;
447    bool ok = true;
448    char tbuf[100];
449
450    dev->dlock();
451    if (!dev->is_blocked()) {
452       block_device(dev, BST_RELEASING);
453    } else if (dev->blocked() == BST_DESPOOLING) {
454       dev->set_blocked(BST_RELEASING);
455    }
456    lock_volumes();
457    Dmsg2(100, "release_device device %s is %s\n", dev->print_name(), dev->is_tape()?"tape":"disk");
458
459    /* if device is reserved, job never started, so release the reserve here */
460    dcr->clear_reserved();
461
462    if (dev->can_read()) {
463       VOLUME_CAT_INFO *vol = &dev->VolCatInfo;
464       dev->clear_read();              /* clear read bit */
465       Dmsg2(150, "dir_update_vol_info. label=%d Vol=%s\n",
466          dev->is_labeled(), vol->VolCatName);
467       if (dev->is_labeled() && vol->VolCatName[0] != 0) {
468          dir_update_volume_info(dcr, false, false); /* send Volume info to Director */
469          remove_read_volume(jcr, dcr->VolumeName);
470          volume_unused(dcr);
471       }
472    } else if (dev->num_writers > 0) {
473       /* 
474        * Note if WEOT is set, we are at the end of the tape
475        *   and may not be positioned correctly, so the
476        *   job_media_record and update_vol_info have already been
477        *   done, which means we skip them here.
478        */
479       dev->num_writers--;
480       Dmsg1(100, "There are %d writers in release_device\n", dev->num_writers);
481       if (dev->is_labeled()) {
482          Dmsg2(200, "dir_create_jobmedia. Release vol=%s dev=%s\n", 
483                dev->getVolCatName(), dev->print_name());
484          if (!dev->at_weot() && !dir_create_jobmedia_record(dcr)) {
485             Jmsg2(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
486                dcr->getVolCatName(), jcr->Job);
487          }
488          /* If no more writers, and no errors, and wrote something, write an EOF */
489          if (!dev->num_writers && dev->can_write() && dev->block_num > 0) {
490             dev->weof(1);
491             write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
492          }
493          if (!dev->at_weot()) {
494             dev->VolCatInfo.VolCatFiles = dev->file;   /* set number of files */
495             /* Note! do volume update before close, which zaps VolCatInfo */
496             dir_update_volume_info(dcr, false, false); /* send Volume info to Director */
497             Dmsg2(200, "dir_update_vol_info. Release vol=%s dev=%s\n", 
498                   dev->getVolCatName(), dev->print_name());
499          }
500          if (dev->num_writers == 0) {         /* if not being used */
501             volume_unused(dcr);               /*  we obviously are not using the volume */
502          }
503       }
504
505    } else {
506       /*                
507        * If we reach here, it is most likely because the job
508        *   has failed, since the device is not in read mode and
509        *   there are no writers. It was probably reserved.
510        */
511       volume_unused(dcr);
512    }
513    Dmsg3(100, "%d writers, %d reserve, dev=%s\n", dev->num_writers, dev->num_reserved(),
514          dev->print_name());
515
516    /* If no writers, close if file or !CAP_ALWAYS_OPEN */
517    if (dev->num_writers == 0 && (!dev->is_tape() || !dev->has_cap(CAP_ALWAYSOPEN))) {
518       dvd_remove_empty_part(dcr);        /* get rid of any empty spool part */
519       dev->close();
520       free_volume(dev);
521    }
522
523    /* Fire off Alert command and include any output */
524    if (!job_canceled(jcr) && dcr->device->alert_command) {
525       POOLMEM *alert;
526       int status = 1;
527       BPIPE *bpipe;
528       char line[MAXSTRING];
529       alert = get_pool_memory(PM_FNAME);
530       alert = edit_device_codes(dcr, alert, dcr->device->alert_command, "");
531       /* Wait maximum 5 minutes */
532       bpipe = open_bpipe(alert, 60 * 5, "r");
533       if (bpipe) {
534          while (fgets(line, sizeof(line), bpipe->rfd)) {
535             Jmsg(jcr, M_ALERT, 0, _("Alert: %s"), line);
536          }
537          status = close_bpipe(bpipe);
538       } else {
539          status = errno;
540       }
541       if (status != 0) {
542          berrno be;
543          Jmsg(jcr, M_ALERT, 0, _("3997 Bad alert command: %s: ERR=%s.\n"),
544               alert, be.bstrerror(status));
545       }
546
547       Dmsg1(400, "alert status=%d\n", status);
548       free_pool_memory(alert);
549    }
550    pthread_cond_broadcast(&dev->wait_next_vol);
551    Dmsg2(100, "JobId=%u broadcast wait_device_release at %s\n", 
552          (uint32_t)jcr->JobId, bstrftimes(tbuf, sizeof(tbuf), (utime_t)time(NULL)));
553    pthread_cond_broadcast(&wait_device_release);
554    unlock_volumes();
555    dev->dunblock(true);
556    if (dcr->keep_dcr) {
557       detach_dcr_from_dev(dcr);
558    } else {
559       free_dcr(dcr);
560    }
561    Dmsg2(100, "===== Device %s released by JobId=%u\n", dev->print_name(),
562          (uint32_t)jcr->JobId);
563    return ok;
564 }
565
566 /*
567  * Clean up the device for reuse without freeing the memory
568  */
569 bool clean_device(DCR *dcr)
570 {
571    bool ok;
572    dcr->keep_dcr = true;                  /* do not free the dcr */
573    ok = release_device(dcr);
574    dcr->keep_dcr = false;
575    return ok;
576 }
577
578 /*
579  * Create a new Device Control Record and attach
580  *   it to the device (if this is a real job).
581  * Note, this has been updated so that it can be called first 
582  *   without a DEVICE, then a second or third time with a DEVICE,
583  *   and each time, it should cleanup and point to the new device.
584  *   This should facilitate switching devices.
585  * Note, each dcr must point to the controlling job (jcr).  However,
586  *   a job can have multiple dcrs, so we must not store in the jcr's
587  *   structure as previously. The higher level routine must store
588  *   this dcr in the right place
589  *
590  */
591 DCR *new_dcr(JCR *jcr, DCR *dcr, DEVICE *dev)
592 {
593    if (!dcr) {
594       int errstat;
595       dcr = (DCR *)malloc(sizeof(DCR));
596       memset(dcr, 0, sizeof(DCR));
597       dcr->tid = pthread_self();
598       dcr->spool_fd = -1;
599       if ((errstat = pthread_mutex_init(&dcr->m_mutex, NULL)) != 0) {
600          berrno be;
601          dev->dev_errno = errstat;
602          Mmsg1(dev->errmsg, _("Unable to init mutex: ERR=%s\n"), be.bstrerror(errstat));
603          Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg);
604       }
605    }
606    dcr->jcr = jcr;                 /* point back to jcr */
607    /* Set device information, possibly change device */
608    if (dev) {
609       if (dcr->block) {
610          free_block(dcr->block);
611       }
612       dcr->block = new_block(dev);
613       if (dcr->rec) {
614          free_record(dcr->rec);
615       }
616       dcr->rec = new_record();
617       if (dcr->attached_to_dev) {
618          detach_dcr_from_dev(dcr);
619       }
620       /* Use job spoolsize prior to device spoolsize */
621       if (jcr->spool_size) {
622          dcr->max_job_spool_size = jcr->spool_size;
623       } else {
624          dcr->max_job_spool_size = dev->device->max_job_spool_size;
625       }
626       dcr->device = dev->device;
627       dcr->dev = dev;
628       attach_dcr_to_dev(dcr);
629    }
630    return dcr;
631 }
632
633 /*
634  * Search the dcrs list for the given dcr. If it is found,
635  *  as it should be, then remove it. Also zap the jcr pointer
636  *  to the dcr if it is the same one.
637  *
638  * Note, this code will be turned on when we can write to multiple
639  *  dcrs at the same time.
640  */
641 #ifdef needed
642 static void remove_dcr_from_dcrs(DCR *dcr)
643 {
644    JCR *jcr = dcr->jcr;
645    if (jcr->dcrs) {
646       int i = 0;
647       DCR *ldcr;
648       int num = jcr->dcrs->size();
649       for (i=0; i < num; i++) {
650          ldcr = (DCR *)jcr->dcrs->get(i);
651          if (ldcr == dcr) {
652             jcr->dcrs->remove(i);
653             if (jcr->dcr == dcr) {
654                jcr->dcr = NULL;
655             }
656          }
657       }
658    }
659 }
660 #endif
661
662 static void attach_dcr_to_dev(DCR *dcr)
663 {
664    DEVICE *dev;
665    JCR *jcr;
666
667    P(dcr->m_mutex);
668    dev = dcr->dev;
669    jcr = dcr->jcr;
670    if (jcr) Dmsg1(500, "JobId=%u enter attach_dcr_to_dev\n", (uint32_t)jcr->JobId);
671    if (!dcr->attached_to_dev && dev->initiated && jcr && jcr->getJobType() != JT_SYSTEM) {
672       dev->attached_dcrs->append(dcr);  /* attach dcr to device */
673       dcr->attached_to_dev = true;
674       Dmsg1(500, "JobId=%u attach_dcr_to_dev\n", (uint32_t)jcr->JobId);
675    }
676    V(dcr->m_mutex);
677 }
678
679 /* 
680  * DCR is locked before calling this routine
681  */
682 static void locked_detach_dcr_from_dev(DCR *dcr)
683 {
684    DEVICE *dev = dcr->dev;
685    Dmsg0(500, "Enter detach_dcr_from_dev\n"); /* jcr is NULL in some cases */
686
687    /* Detach this dcr only if attached */
688    if (dcr->attached_to_dev && dev) {
689       dcr->unreserve_device();
690       dev->dlock();
691       dcr->dev->attached_dcrs->remove(dcr);  /* detach dcr from device */
692 //    remove_dcr_from_dcrs(dcr);      /* remove dcr from jcr list */
693       dev->dunlock();
694    }
695    dcr->attached_to_dev = false;
696 }
697
698
699 static void detach_dcr_from_dev(DCR *dcr)
700 {
701    P(dcr->m_mutex);
702    locked_detach_dcr_from_dev(dcr);
703    V(dcr->m_mutex);
704 }
705
706 /*
707  * Free up all aspects of the given dcr -- i.e. dechain it,
708  *  release allocated memory, zap pointers, ...
709  */
710 void free_dcr(DCR *dcr)
711 {
712    JCR *jcr;
713
714    P(dcr->m_mutex);
715    jcr = dcr->jcr;
716    locked_detach_dcr_from_dev(dcr);
717
718    if (dcr->block) {
719       free_block(dcr->block);
720    }
721    if (dcr->rec) {
722       free_record(dcr->rec);
723    }
724    if (jcr && jcr->dcr == dcr) {
725       jcr->dcr = NULL;
726    }
727    if (jcr && jcr->read_dcr == dcr) {
728       jcr->read_dcr = NULL;
729    }
730    V(dcr->m_mutex);
731    pthread_mutex_destroy(&dcr->m_mutex);
732    free(dcr);
733 }
734
735 static void set_dcr_from_vol(DCR *dcr, VOL_LIST *vol)
736 {
737    /*    
738     * Note, if we want to be able to work from a .bsr file only          
739     *  for disaster recovery, we must "simulate" reading the catalog
740     */
741    bstrncpy(dcr->VolumeName, vol->VolumeName, sizeof(dcr->VolumeName));
742    dcr->setVolCatName(vol->VolumeName);
743    bstrncpy(dcr->media_type, vol->MediaType, sizeof(dcr->media_type));
744    dcr->VolCatInfo.Slot = vol->Slot;
745    dcr->VolCatInfo.InChanger = vol->Slot > 0; 
746 }