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