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