]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/acquire.c
Minor modifications outside DVD functions.
[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-2005 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 /*
27  * Create a new Device Control Record and attach
28  *   it to the device (if this is a real job).
29  */
30 DCR *new_dcr(JCR *jcr, DEVICE *dev)
31 {
32    if (jcr && jcr->dcr) {
33       return jcr->dcr;
34    }
35    DCR *dcr = (DCR *)malloc(sizeof(DCR));
36    memset(dcr, 0, sizeof(DCR));
37    if (jcr) {
38       jcr->dcr = dcr;
39    }
40    dcr->jcr = jcr;
41    dcr->dev = dev;
42    if (dev) {
43       dcr->device = dev->device;
44    }
45    dcr->block = new_block(dev);
46    dcr->rec = new_record();
47    dcr->spool_fd = -1;
48    dcr->max_job_spool_size = dev->device->max_job_spool_size;
49    /* Attach this dcr only if dev is initialized */
50    if (dev->fd != 0 && jcr && jcr->JobType != JT_SYSTEM) {
51       dev->attached_dcrs->append(dcr);  /* attach dcr to device */
52 //    jcr->dcrs->append(dcr);         /* put dcr in list for Job */
53    }
54    return dcr;
55 }
56
57 /*
58  * Search the dcrs list for the given dcr. If it is found,
59  *  as it should be, then remove it. Also zap the jcr pointer
60  *  to the dcr if it is the same one.
61  */
62 #ifdef needed
63 static void remove_dcr_from_dcrs(DCR *dcr)
64 {
65    JCR *jcr = dcr->jcr;
66    if (jcr->dcrs) {
67       int i = 0;
68       DCR *ldcr;
69       int num = jcr->dcrs->size();
70       for (i=0; i < num; i++) {
71          ldcr = (DCR *)jcr->dcrs->get(i);
72          if (ldcr == dcr) {
73             jcr->dcrs->remove(i);
74             if (jcr->dcr == dcr) {
75                jcr->dcr = NULL;
76             }
77          }
78       }
79    }
80 }
81 #endif
82
83 /*
84  * Free up all aspects of the given dcr -- i.e. dechain it,
85  *  release allocated memory, zap pointers, ...
86  */
87 void free_dcr(DCR *dcr)
88 {
89    JCR *jcr = dcr->jcr;
90    DEVICE *dev = dcr->dev;
91
92    if (dcr->reserved_device) {
93       lock_device(dev);
94       dev->reserved_device--;
95       Dmsg1(200, "Dec reserve=%d\n", dev->reserved_device);
96       dcr->reserved_device = false;
97       if (dev->num_writers < 0) {
98          Jmsg1(dcr->jcr, M_ERROR, 0, _("Hey! num_writers=%d!!!!\n"), dev->num_writers);
99          dev->num_writers = 0;
100       }
101       unlock_device(dev);
102    }
103
104    /* Detach this dcr only if the dev is initialized */
105    if (dev->fd != 0 && jcr && jcr->JobType != JT_SYSTEM) {
106       dev->attached_dcrs->remove(dcr);  /* detach dcr from device */
107 //    remove_dcr_from_dcrs(dcr);      /* remove dcr from jcr list */
108    }
109    if (dcr->block) {
110       free_block(dcr->block);
111    }
112    if (dcr->rec) {
113       free_record(dcr->rec);
114    }
115    if (dcr->jcr) {
116       dcr->jcr->dcr = NULL;
117    }
118    free_unused_volume(dcr);           /* free unused vols attached to this dcr */
119    free(dcr);
120 }
121
122 /*********************************************************************
123  * Acquire device for reading. 
124  *  The drive should have previously been reserved by calling 
125  *  reserve_device_for_read(). We read the Volume label from the block and
126  *  leave the block pointers just after the label.
127  *
128  *  Returns: NULL if failed for any reason
129  *           dcr  if successful
130  */
131 DCR *acquire_device_for_read(DCR *dcr)
132 {
133    DEVICE *dev = dcr->dev;
134    JCR *jcr = dcr->jcr;
135    bool vol_ok = false;
136    bool tape_previously_mounted;
137    bool tape_initially_mounted;
138    VOL_LIST *vol;
139    bool try_autochanger = true;
140    int i;
141    int vol_label_status;
142    
143    dev->block(BST_DOING_ACQUIRE);
144
145    if (dev->num_writers > 0) {
146       Jmsg2(jcr, M_FATAL, 0, _("Num_writers=%d not zero. Job %d canceled.\n"), 
147          dev->num_writers, jcr->JobId);
148       goto get_out;
149    }
150
151    /* Find next Volume, if any */
152    vol = jcr->VolList;
153    if (!vol) {
154       Jmsg(jcr, M_FATAL, 0, _("No volumes specified. Job %d canceled.\n"), jcr->JobId);
155       goto get_out;
156    }
157    jcr->CurVolume++;
158    for (i=1; i<jcr->CurVolume; i++) {
159       vol = vol->next;
160    }
161    if (!vol) {
162       goto get_out;                   /* should not happen */   
163    }
164    bstrncpy(dcr->VolumeName, vol->VolumeName, sizeof(dcr->VolumeName));
165
166    init_device_wait_timers(dcr);
167
168    tape_previously_mounted = dev->can_read() || dev->can_append() ||
169                              dev->is_labeled();
170    tape_initially_mounted = tape_previously_mounted;
171
172
173    /* Volume info is always needed because of VolParts */
174    Dmsg0(200, "dir_get_volume_info\n");
175    if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_READ)) {
176       Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg);
177    }
178    
179    for (i=0; i<5; i++) {
180       dev->clear_labeled();              /* force reread of label */
181       if (job_canceled(jcr)) {
182          Mmsg1(dev->errmsg, _("Job %d canceled.\n"), jcr->JobId);
183          goto get_out;                /* error return */
184       }
185       /*
186        * This code ensures that the device is ready for
187        * reading. If it is a file, it opens it.
188        * If it is a tape, it checks the volume name
189        */
190       for ( ; !dev->is_open(); ) {
191          Dmsg1(100, "bstored: open vol=%s\n", dcr->VolumeName);
192          if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
193             if (dev->dev_errno == EIO) {   /* no tape loaded */
194               Jmsg3(jcr, M_WARNING, 0, _("Open device %s Volume \"%s\" failed (EIO): ERR=%s\n"),
195                     dev->print_name(), dcr->VolumeName, strerror_dev(dev));
196                goto default_path;
197             }
198             
199             /* If we have a dvd that requires mount, 
200              * we need to try to open the label, so the info can be reported
201              * if a wrong volume has been mounted. */
202 /*            if (dev->is_dvd() && (dcr->VolCatInfo.VolCatParts > 0)) {
203                break;
204             }*/
205             
206             Jmsg3(jcr, M_FATAL, 0, _("Open device %s Volume \"%s\" failed: ERR=%s\n"),
207                 dev->print_name(), dcr->VolumeName, strerror_dev(dev));
208             goto get_out;
209          }
210          Dmsg1(100, "opened dev %s OK\n", dev->print_name());
211       }
212       
213       vol_label_status = read_dev_volume_label(dcr);
214       
215       Dmsg0(200, "calling read-vol-label\n");
216       switch (vol_label_status) {
217       case VOL_OK:
218          vol_ok = true;
219          memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
220          break;                    /* got it */
221       case VOL_IO_ERROR:
222          /*
223           * Send error message generated by read_dev_volume_label()
224           *  only we really had a tape mounted. This supresses superfluous
225           *  error messages when nothing is mounted.
226           */
227          if (tape_previously_mounted) {
228             Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
229          }
230          goto default_path;
231       case VOL_NAME_ERROR:
232          if (tape_initially_mounted) {
233             tape_initially_mounted = false;
234             goto default_path;
235          }
236          /* Fall through */
237       default:
238          Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg);
239 default_path:
240          tape_previously_mounted = true;
241          
242          /* If the device requires mount, close it, so the device can be ejected.
243           * FIXME: This should perhaps be done for all devices. */
244          if (dev->requires_mount()) {
245             force_close_device(dev);
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 (!vol_ok) {
271       Jmsg1(jcr, M_FATAL, 0, _("Too many errors trying to mount device %s.\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->unblock();
285    if (!vol_ok) {
286       free_dcr(dcr);
287       dcr = NULL;
288    }
289    return dcr;
290 }
291
292
293 /*
294  * Acquire device for writing. We permit multiple writers.
295  *  If this is the first one, we read the label.
296  *
297  *  Returns: NULL if failed for any reason
298  *           dcr if successful.
299  *   Note, normally reserve_device_for_append() is called
300  *   before this routine.
301  */
302 DCR *acquire_device_for_append(DCR *dcr)
303 {
304    bool release = false;
305    bool recycle = false;
306    bool do_mount = false;
307    DEVICE *dev = dcr->dev;
308    JCR *jcr = dcr->jcr;
309
310    init_device_wait_timers(dcr);
311
312    dev->block(BST_DOING_ACQUIRE);
313    Dmsg1(190, "acquire_append device is %s\n", dev->is_tape()?"tape":
314         (dev->is_dvd()?"DVD":"disk"));
315
316    if (dcr->reserved_device) {
317       dev->reserved_device--;
318       Dmsg1(200, "Dec reserve=%d\n", dev->reserved_device);
319       dcr->reserved_device = false;
320    }
321
322    /*
323     * With the reservation system, this should not happen
324     */
325    if (dev->can_read()) {
326       Jmsg1(jcr, M_FATAL, 0, _("Device %s is busy reading.\n"), dev->print_name());
327       goto get_out;
328    }
329
330    if (dev->can_append()) {
331       Dmsg0(190, "device already in append.\n");
332       /*
333        * Device already in append mode
334        *
335        * Check if we have the right Volume mounted
336        *   OK if current volume info OK
337        *   OK if next volume matches current volume
338        *   otherwise mount desired volume obtained from
339        *    dir_find_next_appendable_volume
340        *  dev->VolHdr.VolumeName is what is in the drive
341        *  dcr->VolumeName is what we pass into the routines, or
342        *    get back from the subroutines.
343        */
344       bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName));
345       if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_WRITE) &&
346           !(dir_find_next_appendable_volume(dcr) &&
347             strcmp(dev->VolHdr.VolumeName, dcr->VolumeName) == 0)) { /* wrong tape mounted */
348          Dmsg2(190, "Wrong tape mounted: %s. wants:%s\n", dev->VolHdr.VolumeName,
349             dcr->VolumeName);
350          /* Release volume reserved by dir_find_next_appendable_volume() */
351          if (dcr->VolumeName[0]) {
352             free_unused_volume(dcr);
353          }
354          if (dev->num_writers != 0 || dev->reserved_device) {
355             Jmsg(jcr, M_FATAL, 0, _("Device %s is busy writing on another Volume.\n"), dev->print_name());
356             goto get_out;
357          }
358          /* Wrong tape mounted, release it, then fall through to get correct one */
359          Dmsg0(190, "Wrong tape mounted, release and try mount.\n");
360          release = true;
361          do_mount = true;
362       } else {
363          /*
364           * At this point, the correct tape is already mounted, so
365           *   we do not need to do mount_next_write_volume(), unless
366           *   we need to recycle the tape.
367           */
368           recycle = strcmp(dcr->VolCatInfo.VolCatStatus, "Recycle") == 0;
369           Dmsg1(190, "Correct tape mounted. recycle=%d\n", recycle);
370           if (recycle && dev->num_writers != 0) {
371              Jmsg(jcr, M_FATAL, 0, _("Cannot recycle volume \"%s\""
372                   " on device %s because it is in use by another job.\n"),
373                   dev->VolHdr.VolumeName, dev->print_name());
374              goto get_out;
375           }
376           if (dev->num_writers == 0) {
377              memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
378           }
379       }
380    } else {
381       /* Not already in append mode, so mount the device */
382       Dmsg0(190, "Not in append mode, try mount.\n");
383       ASSERT(dev->num_writers == 0);
384       do_mount = true;
385    }
386
387    if (do_mount || recycle) {
388       Dmsg0(190, "Do mount_next_write_vol\n");
389       bool mounted = mount_next_write_volume(dcr, release);
390       if (!mounted) {
391          if (!job_canceled(jcr)) {
392             /* Reduce "noise" -- don't print if job canceled */
393             Jmsg(jcr, M_FATAL, 0, _("Could not ready device %s for append.\n"),
394                dev->print_name());
395          }
396          goto get_out;
397       }
398    }
399
400    dev->num_writers++;                /* we are now a writer */
401    if (jcr->NumVolumes == 0) {
402       jcr->NumVolumes = 1;
403    }
404    goto ok_out;
405
406 /*
407  * If we jump here, it is an error return because
408  *  rtn_dev will still be NULL
409  */
410 get_out:
411    free_dcr(dcr);
412    dcr = NULL;
413 ok_out:
414    dev->unblock();
415    return dcr;
416 }
417
418 /*
419  * This job is done, so release the device. From a Unix standpoint,
420  *  the device remains open.
421  *
422  */
423 bool release_device(DCR *dcr)
424 {
425    JCR *jcr = dcr->jcr;
426    DEVICE *dev = dcr->dev;
427    bool ok = true;
428
429    lock_device(dev);
430    Dmsg1(100, "release_device device is %s\n", dev->is_tape()?"tape":"disk");
431
432    /* if device is reserved, job never started, so release the reserve here */
433    if (dcr->reserved_device) {
434       dev->reserved_device--;
435       Dmsg1(200, "Dec reserve=%d\n", dev->reserved_device);
436       dcr->reserved_device = false;
437    }
438
439    if (dev->can_read()) {
440       dev->clear_read();              /* clear read bit */
441
442       /******FIXME**** send read volume usage statistics to director */
443
444    } else if (dev->num_writers > 0) {
445       /* 
446        * Note if WEOT is set, we are at the end of the tape
447        *   and may not be positioned correctly, so the
448        *   job_media_record and update_vol_info have already been
449        *   done, which means we skip them here.
450        */
451       dev->num_writers--;
452       Dmsg1(100, "There are %d writers in release_device\n", dev->num_writers);
453       if (dev->is_labeled()) {
454          Dmsg0(100, "dir_create_jobmedia_record. Release\n");
455          if (!dev->at_weot() && !dir_create_jobmedia_record(dcr)) {
456             Jmsg(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
457                dcr->VolCatInfo.VolCatName, jcr->Job);
458          }
459          /* If no more writers, write an EOF */
460          if (!dev->num_writers && dev->can_write()) {
461             weof_dev(dev, 1);
462             write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
463          }
464          if (!dev->at_weot()) {
465             dev->VolCatInfo.VolCatFiles = dev->file;   /* set number of files */
466             dev->VolCatInfo.VolCatJobs++;              /* increment number of jobs */
467             /* Note! do volume update before close, which zaps VolCatInfo */
468             Dmsg0(100, "dir_update_vol_info. Release0\n");
469             dir_update_volume_info(dcr, false); /* send Volume info to Director */
470          }
471       }
472
473    } else {
474       /*                
475        * If we reach here, it is most likely because the job
476        *   has failed, since the device is not in read mode and
477        *   there are no writers. It was probably reserved.
478        */
479    }
480
481    /* If no writers, close if file or !CAP_ALWAYS_OPEN */
482    if (dev->num_writers == 0 && (!dev->is_tape() || !dev_cap(dev, CAP_ALWAYSOPEN))) {
483       offline_or_rewind_dev(dev);
484       close_device(dev);
485    }
486
487    /* Fire off Alert command and include any output */
488    if (!job_canceled(jcr) && dcr->device->alert_command) {
489       POOLMEM *alert;
490       int status = 1;
491       BPIPE *bpipe;
492       char line[MAXSTRING];
493       alert = get_pool_memory(PM_FNAME);
494       alert = edit_device_codes(dcr, alert, dcr->device->alert_command, "");
495       bpipe = open_bpipe(alert, 0, "r");
496       if (bpipe) {
497          while (fgets(line, sizeof(line), bpipe->rfd)) {
498             Jmsg(jcr, M_ALERT, 0, _("Alert: %s"), line);
499          }
500          status = close_bpipe(bpipe);
501       } else {
502          status = errno;
503       }
504       if (status != 0) {
505          berrno be;
506          Jmsg(jcr, M_ALERT, 0, _("3997 Bad alert command: %s: ERR=%s.\n"),
507               alert, be.strerror(status));
508       }
509
510       Dmsg1(400, "alert status=%d\n", status);
511       free_pool_memory(alert);
512    }
513    unlock_device(dev);
514    free_dcr(dcr);
515    jcr->dcr = NULL;
516    pthread_cond_broadcast(&wait_device_release);
517    return ok;
518 }