]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/acquire.c
29Jul05
[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 #ifdef xxx_needed
200             /* If we have a dvd that requires mount, 
201              * we need to try to open the label, so the info can be reported
202              * if a wrong volume has been mounted.   
203              */
204             if (dev->is_dvd() && (dcr->VolCatInfo.VolCatParts > 0)) {
205                break;
206             }  
207 #endif
208             
209             Jmsg3(jcr, M_FATAL, 0, _("Open device %s Volume \"%s\" failed: ERR=%s\n"),
210                 dev->print_name(), dcr->VolumeName, strerror_dev(dev));
211             goto get_out;
212          }
213          Dmsg1(100, "opened dev %s OK\n", dev->print_name());
214       }
215       
216       /* Read Volume Label */
217       
218       Dmsg0(200, "calling read-vol-label\n");
219       vol_label_status = read_dev_volume_label(dcr);
220       switch (vol_label_status) {
221       case VOL_OK:
222          vol_ok = true;
223          memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
224          break;                    /* got it */
225       case VOL_IO_ERROR:
226          /*
227           * Send error message generated by read_dev_volume_label()
228           *  only we really had a tape mounted. This supresses superfluous
229           *  error messages when nothing is mounted.
230           */
231          if (tape_previously_mounted) {
232             Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
233          }
234          goto default_path;
235       case VOL_NAME_ERROR:
236          if (tape_initially_mounted) {
237             tape_initially_mounted = false;
238             goto default_path;
239          }
240          /* Fall through */
241       default:
242          Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg);
243 default_path:
244          tape_previously_mounted = true;
245          
246          /* If the device requires mount, close it, so the device can be ejected.
247           * FIXME: This should perhaps be done for all devices. */
248          if (dev->requires_mount()) {
249             force_close_device(dev);
250          }
251          
252          /* Call autochanger only once unless ask_sysop called */
253          if (try_autochanger) {
254             int stat;
255             Dmsg2(200, "calling autoload Vol=%s Slot=%d\n",
256                dcr->VolumeName, dcr->VolCatInfo.Slot);
257             stat = autoload_device(dcr, 0, NULL);
258             if (stat > 0) {
259                try_autochanger = false;
260                continue;              /* try reading volume mounted */
261             }
262          }
263          
264          /* Mount a specific volume and no other */
265          Dmsg0(200, "calling dir_ask_sysop\n");
266          if (!dir_ask_sysop_to_mount_volume(dcr)) {
267             goto get_out;             /* error return */
268          }
269          try_autochanger = true;      /* permit using autochanger again */
270          continue;                    /* try reading again */
271       } /* end switch */
272       break;
273    } /* end for loop */
274    if (!vol_ok) {
275       Jmsg1(jcr, M_FATAL, 0, _("Too many errors trying to mount device %s.\n"),
276             dev->print_name());
277       goto get_out;
278    }
279
280    dev->clear_append();
281    dev->set_read();
282    set_jcr_job_status(jcr, JS_Running);
283    dir_send_job_status(jcr);
284    Jmsg(jcr, M_INFO, 0, _("Ready to read from volume \"%s\" on device %s.\n"),
285       dcr->VolumeName, dev->print_name());
286
287 get_out:
288    dev->unblock();
289    if (!vol_ok) {
290       free_dcr(dcr);
291       dcr = NULL;
292    }
293    return dcr;
294 }
295
296
297 /*
298  * Acquire device for writing. We permit multiple writers.
299  *  If this is the first one, we read the label.
300  *
301  *  Returns: NULL if failed for any reason
302  *           dcr if successful.
303  *   Note, normally reserve_device_for_append() is called
304  *   before this routine.
305  */
306 DCR *acquire_device_for_append(DCR *dcr)
307 {
308    bool release = false;
309    bool recycle = false;
310    bool do_mount = false;
311    DEVICE *dev = dcr->dev;
312    JCR *jcr = dcr->jcr;
313
314    init_device_wait_timers(dcr);
315
316    dev->block(BST_DOING_ACQUIRE);
317    Dmsg1(190, "acquire_append device is %s\n", dev->is_tape()?"tape":
318         (dev->is_dvd()?"DVD":"disk"));
319
320    if (dcr->reserved_device) {
321       dev->reserved_device--;
322       Dmsg1(200, "Dec reserve=%d\n", dev->reserved_device);
323       dcr->reserved_device = false;
324    }
325
326    /*
327     * With the reservation system, this should not happen
328     */
329    if (dev->can_read()) {
330       Jmsg1(jcr, M_FATAL, 0, _("Device %s is busy reading.\n"), dev->print_name());
331       goto get_out;
332    }
333
334    if (dev->can_append()) {
335       Dmsg0(190, "device already in append.\n");
336       /*
337        * Device already in append mode
338        *
339        * Check if we have the right Volume mounted
340        *   OK if current volume info OK
341        *   OK if next volume matches current volume
342        *   otherwise mount desired volume obtained from
343        *    dir_find_next_appendable_volume
344        *  dev->VolHdr.VolumeName is what is in the drive
345        *  dcr->VolumeName is what we pass into the routines, or
346        *    get back from the subroutines.
347        */
348       bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName));
349       if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_WRITE) &&
350           !(dir_find_next_appendable_volume(dcr) &&
351             strcmp(dev->VolHdr.VolumeName, dcr->VolumeName) == 0)) { /* wrong tape mounted */
352          Dmsg2(190, "Wrong tape mounted: %s. wants:%s\n", dev->VolHdr.VolumeName,
353             dcr->VolumeName);
354          /* Release volume reserved by dir_find_next_appendable_volume() */
355          if (dcr->VolumeName[0]) {
356             free_unused_volume(dcr);
357          }
358          if (dev->num_writers != 0 || dev->reserved_device) {
359             Jmsg(jcr, M_FATAL, 0, _("Device %s is busy writing on another Volume.\n"), dev->print_name());
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    } else {
385       /* Not already in append mode, so mount the device */
386       Dmsg0(190, "Not in append mode, try mount.\n");
387       ASSERT(dev->num_writers == 0);
388       do_mount = true;
389    }
390
391    if (do_mount || recycle) {
392       Dmsg0(190, "Do mount_next_write_vol\n");
393       bool mounted = mount_next_write_volume(dcr, release);
394       if (!mounted) {
395          if (!job_canceled(jcr)) {
396             /* Reduce "noise" -- don't print if job canceled */
397             Jmsg(jcr, M_FATAL, 0, _("Could not ready device %s for append.\n"),
398                dev->print_name());
399          }
400          goto get_out;
401       }
402    }
403
404    dev->num_writers++;                /* we are now a writer */
405    if (jcr->NumVolumes == 0) {
406       jcr->NumVolumes = 1;
407    }
408    goto ok_out;
409
410 /*
411  * If we jump here, it is an error return because
412  *  rtn_dev will still be NULL
413  */
414 get_out:
415    free_dcr(dcr);
416    dcr = NULL;
417 ok_out:
418    dev->unblock();
419    return dcr;
420 }
421
422 /*
423  * This job is done, so release the device. From a Unix standpoint,
424  *  the device remains open.
425  *
426  */
427 bool release_device(DCR *dcr)
428 {
429    JCR *jcr = dcr->jcr;
430    DEVICE *dev = dcr->dev;
431    bool ok = true;
432
433    lock_device(dev);
434    Dmsg1(100, "release_device device is %s\n", dev->is_tape()?"tape":"disk");
435
436    /* if device is reserved, job never started, so release the reserve here */
437    if (dcr->reserved_device) {
438       dev->reserved_device--;
439       Dmsg1(200, "Dec reserve=%d\n", dev->reserved_device);
440       dcr->reserved_device = false;
441    }
442
443    if (dev->can_read()) {
444       dev->clear_read();              /* clear read bit */
445
446       /******FIXME**** send read volume usage statistics to director */
447
448    } else if (dev->num_writers > 0) {
449       /* 
450        * Note if WEOT is set, we are at the end of the tape
451        *   and may not be positioned correctly, so the
452        *   job_media_record and update_vol_info have already been
453        *   done, which means we skip them here.
454        */
455       dev->num_writers--;
456       Dmsg1(100, "There are %d writers in release_device\n", dev->num_writers);
457       if (dev->is_labeled()) {
458          Dmsg0(100, "dir_create_jobmedia_record. Release\n");
459          if (!dev->at_weot() && !dir_create_jobmedia_record(dcr)) {
460             Jmsg(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
461                dcr->VolCatInfo.VolCatName, jcr->Job);
462          }
463          /* If no more writers, write an EOF */
464          if (!dev->num_writers && dev->can_write()) {
465             weof_dev(dev, 1);
466             write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
467          }
468          if (!dev->at_weot()) {
469             dev->VolCatInfo.VolCatFiles = dev->file;   /* set number of files */
470             dev->VolCatInfo.VolCatJobs++;              /* increment number of jobs */
471             /* Note! do volume update before close, which zaps VolCatInfo */
472             Dmsg0(100, "dir_update_vol_info. Release0\n");
473             dir_update_volume_info(dcr, false); /* send Volume info to Director */
474          }
475       }
476
477    } else {
478       /*                
479        * If we reach here, it is most likely because the job
480        *   has failed, since the device is not in read mode and
481        *   there are no writers. It was probably reserved.
482        */
483    }
484
485    /* If no writers, close if file or !CAP_ALWAYS_OPEN */
486    if (dev->num_writers == 0 && (!dev->is_tape() || !dev_cap(dev, CAP_ALWAYSOPEN))) {
487       offline_or_rewind_dev(dev);
488       close_device(dev);
489    }
490
491    /* Fire off Alert command and include any output */
492    if (!job_canceled(jcr) && dcr->device->alert_command) {
493       POOLMEM *alert;
494       int status = 1;
495       BPIPE *bpipe;
496       char line[MAXSTRING];
497       alert = get_pool_memory(PM_FNAME);
498       alert = edit_device_codes(dcr, alert, dcr->device->alert_command, "");
499       bpipe = open_bpipe(alert, 0, "r");
500       if (bpipe) {
501          while (fgets(line, sizeof(line), bpipe->rfd)) {
502             Jmsg(jcr, M_ALERT, 0, _("Alert: %s"), line);
503          }
504          status = close_bpipe(bpipe);
505       } else {
506          status = errno;
507       }
508       if (status != 0) {
509          berrno be;
510          Jmsg(jcr, M_ALERT, 0, _("3997 Bad alert command: %s: ERR=%s.\n"),
511               alert, be.strerror(status));
512       }
513
514       Dmsg1(400, "alert status=%d\n", status);
515       free_pool_memory(alert);
516    }
517    unlock_device(dev);
518    free_dcr(dcr);
519    jcr->dcr = NULL;
520    pthread_cond_broadcast(&wait_device_release);
521    return ok;
522 }