]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/acquire.c
- Detect device mounted for DVD and suppress be sure to
[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 ammended 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(dcr);
119 }
120
121 /*********************************************************************
122  * Acquire device for reading. 
123  *  The drive should have previously been reserved by calling 
124  *  reserve_device_for_read(). We read the Volume label from the block and
125  *  leave the block pointers just after the label.
126  *
127  *  Returns: NULL if failed for any reason
128  *           dcr  if successful
129  */
130 DCR *acquire_device_for_read(DCR *dcr)
131 {
132    DEVICE *dev = dcr->dev;
133    JCR *jcr = dcr->jcr;
134    bool vol_ok = false;
135    bool tape_previously_mounted;
136    bool tape_initially_mounted;
137    VOL_LIST *vol;
138    bool try_autochanger = true;
139    int i;
140    int vol_label_status;
141    
142    dev->block(BST_DOING_ACQUIRE);
143
144    if (dev->num_writers > 0) {
145       Jmsg2(jcr, M_FATAL, 0, _("Num_writers=%d not zero. Job %d canceled.\n"), 
146          dev->num_writers, jcr->JobId);
147       goto get_out;
148    }
149
150    /* Find next Volume, if any */
151    vol = jcr->VolList;
152    if (!vol) {
153       Jmsg(jcr, M_FATAL, 0, _("No volumes specified. Job %d canceled.\n"), jcr->JobId);
154       goto get_out;
155    }
156    jcr->CurVolume++;
157    for (i=1; i<jcr->CurVolume; i++) {
158       vol = vol->next;
159    }
160    if (!vol) {
161       goto get_out;                   /* should not happen */   
162    }
163    bstrncpy(dcr->VolumeName, vol->VolumeName, sizeof(dcr->VolumeName));
164
165    init_device_wait_timers(dcr);
166
167    tape_previously_mounted = dev->can_read() || dev->can_append() ||
168                              dev->is_labeled();
169    tape_initially_mounted = tape_previously_mounted;
170
171
172    /* Volume info is always needed because of VolParts */
173    Dmsg0(200, "dir_get_volume_info\n");
174    if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_READ)) {
175       Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg);
176    }
177    
178    for (i=0; i<5; i++) {
179       dev->clear_labeled();              /* force reread of label */
180       if (job_canceled(jcr)) {
181          Mmsg1(dev->errmsg, _("Job %d canceled.\n"), jcr->JobId);
182          goto get_out;                /* error return */
183       }
184       /*
185        * This code ensures that the device is ready for
186        * reading. If it is a file, it opens it.
187        * If it is a tape, it checks the volume name
188        */
189       for ( ; !dev->is_open(); ) {
190          Dmsg1(120, "bstored: open vol=%s\n", dcr->VolumeName);
191          if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
192             if (dev->dev_errno == EIO) {   /* no tape loaded */
193               Jmsg3(jcr, M_WARNING, 0, _("Open device %s Volume \"%s\" failed: ERR=%s\n"),
194                     dev->print_name(), dcr->VolumeName, strerror_dev(dev));
195                goto default_path;
196             }
197             
198             /* If we have a dvd that requires mount, 
199              * we need to try to open the label, so the info can be reported
200              * if a wrong volume has been mounted. */
201             if (dev->is_dvd() && (dcr->VolCatInfo.VolCatParts > 0)) {
202                break;
203             }
204             
205             Jmsg3(jcr, M_FATAL, 0, _("Open device %s Volume \"%s\" failed: ERR=%s\n"),
206                 dev->print_name(), dcr->VolumeName, strerror_dev(dev));
207             goto get_out;
208          }
209          Dmsg1(129, "opened dev %s OK\n", dev->print_name());
210       }
211       
212       vol_label_status = read_dev_volume_label(dcr);
213       
214       Dmsg0(200, "calling read-vol-label\n");
215       switch (vol_label_status) {
216       case VOL_OK:
217          vol_ok = true;
218          memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
219          break;                    /* got it */
220       case VOL_IO_ERROR:
221          /*
222           * Send error message generated by read_dev_volume_label()
223           *  only we really had a tape mounted. This supresses superfluous
224           *  error messages when nothing is mounted.
225           */
226          if (tape_previously_mounted) {
227             Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
228          }
229          goto default_path;
230       case VOL_NAME_ERROR:
231          if (tape_initially_mounted) {
232             tape_initially_mounted = false;
233             goto default_path;
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          /* If the device requires mount, close it, so the device can be ejected.
242           * FIXME: This should perhaps be done for all devices. */
243          if (dev->requires_mount()) {
244             force_close_device(dev);
245          }
246          
247          /* Call autochanger only once unless ask_sysop called */
248          if (try_autochanger) {
249             int stat;
250             Dmsg2(200, "calling autoload Vol=%s Slot=%d\n",
251                dcr->VolumeName, dcr->VolCatInfo.Slot);
252             stat = autoload_device(dcr, 0, NULL);
253             if (stat > 0) {
254                try_autochanger = false;
255                continue;              /* try reading volume mounted */
256             }
257          }
258          
259          /* Mount a specific volume and no other */
260          Dmsg0(200, "calling dir_ask_sysop\n");
261          if (!dir_ask_sysop_to_mount_volume(dcr)) {
262             goto get_out;             /* error return */
263          }
264          try_autochanger = true;      /* permit using autochanger again */
265          continue;                    /* try reading again */
266       } /* end switch */
267       break;
268    } /* end for loop */
269    if (!vol_ok) {
270       Jmsg1(jcr, M_FATAL, 0, _("Too many errors trying to mount device %s.\n"),
271             dev->print_name());
272       goto get_out;
273    }
274
275    dev->clear_append();
276    dev->set_read();
277    set_jcr_job_status(jcr, JS_Running);
278    dir_send_job_status(jcr);
279    Jmsg(jcr, M_INFO, 0, _("Ready to read from volume \"%s\" on device %s.\n"),
280       dcr->VolumeName, dev->print_name());
281
282 get_out:
283    dev->unblock();
284    if (!vol_ok) {
285       free_dcr(dcr);
286       dcr = NULL;
287    }
288    return dcr;
289 }
290
291
292 /*
293  * Acquire device for writing. We permit multiple writers.
294  *  If this is the first one, we read the label.
295  *
296  *  Returns: NULL if failed for any reason
297  *           dcr if successful.
298  *   Note, normally reserve_device_for_append() is called
299  *   before this routine.
300  */
301 DCR *acquire_device_for_append(DCR *dcr)
302 {
303    bool release = false;
304    bool recycle = false;
305    bool do_mount = false;
306    DEVICE *dev = dcr->dev;
307    JCR *jcr = dcr->jcr;
308
309    init_device_wait_timers(dcr);
310
311    dev->block(BST_DOING_ACQUIRE);
312    Dmsg1(190, "acquire_append device is %s\n", dev->is_tape()?"tape":
313         (dev->is_dvd()?"DVD":"disk"));
314
315    if (dcr->reserved_device) {
316       dev->reserved_device--;
317       Dmsg1(200, "Dec reserve=%d\n", dev->reserved_device);
318       dcr->reserved_device = false;
319    }
320
321    /*
322     * With the reservation system, this should not happen
323     */
324    if (dev->can_read()) {
325       Jmsg1(jcr, M_FATAL, 0, _("Device %s is busy reading.\n"), dev->print_name());
326       goto get_out;
327    }
328
329    if (dev->can_append()) {
330       Dmsg0(190, "device already in append.\n");
331       /*
332        * Device already in append mode
333        *
334        * Check if we have the right Volume mounted
335        *   OK if current volume info OK
336        *   OK if next volume matches current volume
337        *   otherwise mount desired volume obtained from
338        *    dir_find_next_appendable_volume
339        */
340       bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName));
341       if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_WRITE) &&
342           !(dir_find_next_appendable_volume(dcr) &&
343             strcmp(dev->VolHdr.VolumeName, dcr->VolumeName) == 0)) { /* wrong tape mounted */
344          Dmsg0(190, "Wrong tape mounted.\n");
345          if (dev->num_writers != 0 || dev->reserved_device) {
346             Jmsg(jcr, M_FATAL, 0, _("Device %s is busy writing on another Volume.\n"), dev->print_name());
347             goto get_out;
348          }
349          /* Wrong tape mounted, release it, then fall through to get correct one */
350          Dmsg0(190, "Wrong tape mounted, release and try mount.\n");
351          release = true;
352          do_mount = true;
353       } else {
354          /*
355           * At this point, the correct tape is already mounted, so
356           *   we do not need to do mount_next_write_volume(), unless
357           *   we need to recycle the tape.
358           */
359           recycle = strcmp(dcr->VolCatInfo.VolCatStatus, "Recycle") == 0;
360           Dmsg1(190, "Correct tape mounted. recycle=%d\n", recycle);
361           if (recycle && dev->num_writers != 0) {
362              Jmsg(jcr, M_FATAL, 0, _("Cannot recycle volume \"%s\""
363                   " on device %s because it is in use by another job.\n"),
364                   dev->VolHdr.VolumeName, dev->print_name());
365              goto get_out;
366           }
367           if (dev->num_writers == 0) {
368              memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
369           }
370        }
371    } else {
372       /* Not already in append mode, so mount the device */
373       Dmsg0(190, "Not in append mode, try mount.\n");
374       ASSERT(dev->num_writers == 0);
375       do_mount = true;
376    }
377
378    if (do_mount || recycle) {
379       Dmsg0(190, "Do mount_next_write_vol\n");
380       bool mounted = mount_next_write_volume(dcr, release);
381       if (!mounted) {
382          if (!job_canceled(jcr)) {
383             /* Reduce "noise" -- don't print if job canceled */
384             Jmsg(jcr, M_FATAL, 0, _("Could not ready device %s for append.\n"),
385                dev->print_name());
386          }
387          goto get_out;
388       }
389    }
390
391    dev->num_writers++;                /* we are now a writer */
392    if (jcr->NumVolumes == 0) {
393       jcr->NumVolumes = 1;
394    }
395    goto ok_out;
396
397 /*
398  * If we jump here, it is an error return because
399  *  rtn_dev will still be NULL
400  */
401 get_out:
402    free_dcr(dcr);
403    dcr = NULL;
404 ok_out:
405    dev->unblock();
406    return dcr;
407 }
408
409 /*
410  * This job is done, so release the device. From a Unix standpoint,
411  *  the device remains open.
412  *
413  */
414 bool release_device(DCR *dcr)
415 {
416    JCR *jcr = dcr->jcr;
417    DEVICE *dev = dcr->dev;
418    bool ok = true;
419
420    lock_device(dev);
421    Dmsg1(100, "release_device device is %s\n", dev->is_tape()?"tape":"disk");
422
423    /* if device is reserved, job never started, so release the reserve here */
424    if (dcr->reserved_device) {
425       dev->reserved_device--;
426       Dmsg1(200, "Dec reserve=%d\n", dev->reserved_device);
427       dcr->reserved_device = false;
428    }
429
430    if (dev->can_read()) {
431       dev->clear_read();              /* clear read bit */
432
433       /******FIXME**** send read volume usage statistics to director */
434
435    } else if (dev->num_writers > 0) {
436       /* 
437        * Note if WEOT is set, we are at the end of the tape
438        *   and may not be positioned correctly, so the
439        *   job_media_record and update_vol_info have already been
440        *   done, which means we skip them here.
441        */
442       dev->num_writers--;
443       Dmsg1(100, "There are %d writers in release_device\n", dev->num_writers);
444       if (dev->is_labeled()) {
445          Dmsg0(100, "dir_create_jobmedia_record. Release\n");
446          if (!dev->at_weot() && !dir_create_jobmedia_record(dcr)) {
447             Jmsg(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
448                dcr->VolCatInfo.VolCatName, jcr->Job);
449          }
450          /* If no more writers, write an EOF */
451          if (!dev->num_writers && dev->can_write()) {
452             weof_dev(dev, 1);
453             write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
454          }
455          if (!dev->at_weot()) {
456             dev->VolCatInfo.VolCatFiles = dev->file;   /* set number of files */
457             dev->VolCatInfo.VolCatJobs++;              /* increment number of jobs */
458             /* Note! do volume update before close, which zaps VolCatInfo */
459             Dmsg0(100, "dir_update_vol_info. Release0\n");
460             dir_update_volume_info(dcr, false); /* send Volume info to Director */
461          }
462       }
463
464    } else {
465       /*                
466        * If we reach here, it is most likely because the job
467        *   has failed, since the device is not in read mode and
468        *   there are no writers. It was probably reserved.
469        */
470    }
471
472    /* If no writers, close if file or !CAP_ALWAYS_OPEN */
473    if (dev->num_writers == 0 && (!dev->is_tape() || !dev_cap(dev, CAP_ALWAYSOPEN))) {
474       offline_or_rewind_dev(dev);
475       close_device(dev);
476    }
477
478    /* Fire off Alert command and include any output */
479    if (!job_canceled(jcr) && dcr->device->alert_command) {
480       POOLMEM *alert;
481       int status = 1;
482       BPIPE *bpipe;
483       char line[MAXSTRING];
484       alert = get_pool_memory(PM_FNAME);
485       alert = edit_device_codes(dcr, alert, dcr->device->alert_command, "");
486       bpipe = open_bpipe(alert, 0, "r");
487       if (bpipe) {
488          while (fgets(line, sizeof(line), bpipe->rfd)) {
489             Jmsg(jcr, M_ALERT, 0, _("Alert: %s"), line);
490          }
491          status = close_bpipe(bpipe);
492       } else {
493          status = errno;
494       }
495       if (status != 0) {
496          berrno be;
497          Jmsg(jcr, M_ALERT, 0, _("3997 Bad alert command: %s: ERR=%s.\n"),
498               alert, be.strerror(status));
499       }
500
501       Dmsg1(400, "alert status=%d\n", status);
502       free_pool_memory(alert);
503    }
504    unlock_device(dev);
505    free_dcr(dcr);
506    jcr->dcr = NULL;
507    pthread_cond_broadcast(&wait_device_release);
508    return ok;
509 }