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