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