]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/mount.c
Correct restore across volumes + document
[bacula/bacula] / bacula / src / stored / mount.c
1 /*
2  *
3  *  Routines for handling mounting tapes for reading and for
4  *    writing.
5  *
6  *   Kern Sibbald, August MMII
7  *                            
8  *   Version $Id$
9  */
10 /*
11    Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
12
13    This program is free software; you can redistribute it and/or
14    modify it under the terms of the GNU General Public License as
15    published by the Free Software Foundation; either version 2 of
16    the License, or (at your option) any later version.
17
18    This program is distributed in the hope that it will be useful,
19    but WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21    General Public License for more details.
22
23    You should have received a copy of the GNU General Public
24    License along with this program; if not, write to the Free
25    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
26    MA 02111-1307, USA.
27
28  */
29
30 #include "bacula.h"                   /* pull in global headers */
31 #include "stored.h"                   /* pull in Storage Deamon headers */
32
33 /* Forward referenced functions */
34 static char *edit_device_codes(JCR *jcr, char *omsg, char *imsg, char *cmd);
35
36
37 /*
38  * If release is set, we rewind the current volume, 
39  * which we no longer want, and ask the user (console) 
40  * to mount the next volume.
41  *
42  *  Continue trying until we get it, and then ensure
43  *  that we can write on it.
44  *
45  * This routine returns a 0 only if it is REALLY
46  *  impossible to get the requested Volume.
47  */
48 int mount_next_write_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, int release)
49 {
50    int recycle, ask, retry = 0, autochanger;
51
52    Dmsg0(190, "Enter mount_next_volume()\n");
53
54 mount_next_vol:
55    if (retry++ > 5) {
56       Jmsg(jcr, M_FATAL, 0, _("Too many errors on device %s.\n"), dev_name(dev));
57       return 0;
58    }
59    if (job_cancelled(jcr)) {
60       Jmsg(jcr, M_FATAL, 0, _("Job cancelled.\n"));
61       return 0;
62    }
63    recycle = ask = autochanger = 0;
64    if (release) {
65       Dmsg0(500, "mount_next_volume release=1\n");
66       /* 
67        * First erase all memory of the current volume   
68        */
69       dev->block_num = 0;
70       dev->file = 0;
71       dev->LastBlockNumWritten = 0;
72       memset(&dev->VolCatInfo, 0, sizeof(dev->VolCatInfo));
73       memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
74       dev->state &= ~ST_LABEL;        /* label not yet read */
75
76       if (!dev_is_tape(dev) || !(dev->capabilities & CAP_ALWAYSOPEN)) {
77          if (dev->capabilities & CAP_OFFLINEUNMOUNT) {
78             offline_dev(dev);
79          }
80          close_dev(dev);
81       }
82
83       /* If we have not closed the device, then at least rewind the tape */
84       if (dev->state & ST_OPENED) {
85          if (dev->capabilities & CAP_OFFLINEUNMOUNT) {
86             offline_dev(dev);
87          }
88          if (!rewind_dev(dev)) {
89             Jmsg2(jcr, M_WARNING, 0, _("Rewind error on device %s. ERR=%s\n"), 
90                   dev_name(dev), strerror_dev(dev));
91          }
92       }
93       ask = 1;                        /* ask operator to mount tape */
94    } else {
95       /* 
96        * Get Director's idea of what tape we should have mounted. 
97        */
98       if (!dir_find_next_appendable_volume(jcr)) {
99          ask = 1;                     /* we must ask */
100       }
101    }
102    release = 1;                       /* release if we "recurse" */
103
104    /* 
105     * Get next volume and ready it for append
106     * This code ensures that the device is ready for
107     * writing. We start from the assumption that there
108     * may not be a tape mounted. 
109     *
110     * If the device is a file, we create the output
111     * file. If it is a tape, we check the volume name
112     * and move the tape to the end of data.
113     *
114     * It assumes that the device is not already in use!
115     *
116     */
117
118    Dmsg0(100, "Enter ready_dev_for_append\n");
119
120    dev->state &= ~(ST_APPEND|ST_READ|ST_EOT|ST_WEOT|ST_EOF);
121
122    jcr->VolFirstFile = jcr->JobFiles; /* first update of Vol FileIndex */
123    for ( ;; ) {
124       int slot = jcr->VolCatInfo.Slot;
125         
126       /*
127        * Handle autoloaders here.  If we cannot autoload it, we
128        *  will fall through to ask the sysop.
129        */
130       if (dev->capabilities && CAP_AUTOCHANGER && slot <= 0) {
131          if (dir_find_next_appendable_volume(jcr)) {
132             slot = jcr->VolCatInfo.Slot; 
133          }
134       }
135       Dmsg1(100, "Want changer slot=%d\n", slot);
136
137       if (slot > 0 && jcr->device->changer_name && jcr->device->changer_command) {
138          uint32_t timeout = jcr->device->max_changer_wait;
139          POOLMEM *changer, *results;
140          int status, loaded;
141
142          results = get_pool_memory(PM_MESSAGE);
143          changer = get_pool_memory(PM_FNAME);
144          /* Find out what is loaded */
145          changer = edit_device_codes(jcr, changer, jcr->device->changer_command, 
146                       "loaded");
147          status = run_program(changer, timeout, results);
148          if (status == 0) {
149             loaded = atoi(results);
150          } else {
151             loaded = -1;              /* force unload */
152          }
153          Dmsg1(100, "loaded=%s\n", results);
154
155          /* If bad status or tape we want is not loaded, load it. */
156          if (status != 0 || loaded != slot) { 
157             if (dev->capabilities & CAP_OFFLINEUNMOUNT) {
158                offline_dev(dev);
159             }
160             /* We are going to load a new tape, so close the device */
161             force_close_dev(dev);
162             if (loaded != 0) {        /* must unload drive */
163                Dmsg0(100, "Doing changer unload.\n");
164                changer = edit_device_codes(jcr, changer, 
165                            jcr->device->changer_command, "unload");
166                status = run_program(changer, timeout, NULL);
167                Dmsg1(100, "unload status=%d\n", status);
168             }
169             /*
170              * Load the desired cassette    
171              */
172             Dmsg1(100, "Doing changer load slot %d\n", slot);
173             changer = edit_device_codes(jcr, changer, 
174                          jcr->device->changer_command, "load");
175             status = run_program(changer, timeout, NULL);
176             Dmsg2(100, "load slot %d status=%d\n", slot, status);
177          }
178          free_pool_memory(changer);
179          free_pool_memory(results);
180          Dmsg1(100, "After changer, status=%d\n", status);
181          if (status == 0) {           /* did we succeed? */
182             ask = 0;                  /* yes, got vol, no need to ask sysop */
183             autochanger = 1;          /* tape loaded by changer */
184          }
185       }
186
187
188       if (ask && !dir_ask_sysop_to_mount_next_volume(jcr, dev)) {
189          return 0;              /* error return */
190       }
191       Dmsg1(200, "want vol=%s\n", jcr->VolumeName);
192
193       /* Open device */
194       for ( ; !(dev->state & ST_OPENED); ) {
195           if (open_dev(dev, jcr->VolCatInfo.VolCatName, READ_WRITE) < 0) {
196              if (dev->dev_errno == EAGAIN || dev->dev_errno == EBUSY) {
197                 sleep(30);
198              }
199              Jmsg2(jcr, M_FATAL, 0, _("Unable to open device %s. ERR=%s\n"), 
200                 dev_name(dev), strerror_dev(dev));
201              return 0;
202           }
203       }
204
205       /*
206        * Now make sure we have the right tape mounted
207        */
208 read_volume:
209       switch (read_dev_volume_label(jcr, dev, block)) {
210          case VOL_OK:
211             Dmsg1(500, "Vol OK name=%s\n", jcr->VolumeName);
212             memcpy(&dev->VolCatInfo, &jcr->VolCatInfo, sizeof(jcr->VolCatInfo));
213             if (strcmp(dev->VolCatInfo.VolCatStatus, "Recycle") == 0) {
214                recycle = 1;
215             }
216             break;                    /* got it */
217          case VOL_NAME_ERROR:
218             Dmsg1(500, "Vol NAME Error Name=%s\n", jcr->VolumeName);
219             /* Check if we can accept this as an anonymous volume */
220             strcpy(jcr->VolumeName, dev->VolHdr.VolName);
221             if (!dev->capabilities & CAP_ANONVOLS || !dir_get_volume_info(jcr)) {
222                goto mount_next_vol;
223             }
224             Dmsg1(200, "want new name=%s\n", jcr->VolumeName);
225             memcpy(&dev->VolCatInfo, &jcr->VolCatInfo, sizeof(jcr->VolCatInfo));
226             break;
227
228          case VOL_NO_LABEL:
229          case VOL_IO_ERROR:
230             Dmsg1(500, "Vol NO_LABEL or IO_ERROR name=%s\n", jcr->VolumeName);
231             /* If permitted, create a label */
232             if (dev->capabilities & CAP_LABEL) {
233                Dmsg0(190, "Create volume label\n");
234                if (!write_volume_label_to_dev(jcr, (DEVRES *)dev->device, jcr->VolumeName,
235                       jcr->pool_name)) {
236                   goto mount_next_vol;
237                }
238                Jmsg(jcr, M_INFO, 0, _("Created Volume label %s on device %s.\n"),
239                   jcr->VolumeName, dev_name(dev));
240                goto read_volume;      /* read label we just wrote */
241             } 
242             /* NOTE! Fall-through wanted. */
243          default:
244             /* Send error message */
245             Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);                         
246             if (autochanger) {
247                Jmsg(jcr, M_ERROR, 0, _("Autochanger Volume %s not found in slot %d.\n\
248     Setting slot to zero in catalog.\n"),
249                   jcr->VolumeName, jcr->VolCatInfo.Slot);
250                jcr->VolCatInfo.Slot = 0; /* invalidate slot */
251                dir_update_volume_info(jcr, &jcr->VolCatInfo, 1);  /* set slot */
252             }
253             goto mount_next_vol;
254       }
255       break;
256    }
257
258    /* 
259     * See if we have a fresh tape or tape with data.
260     *
261     * Note, if the LabelType is PRE_LABEL, it was labeled
262     *  but never written. If so, rewrite the label but set as
263     *  VOL_LABEL.  We rewind and return the label (reconstructed)
264     *  in the block so that in the case of a new tape, data can
265     *  be appended just after the block label.  If we are writing
266     *  an second volume, the calling routine will write the label
267     *  before writing the overflow block.
268     *
269     *  If the tape is marked as Recycle, we rewrite the label.
270     */
271    if (dev->VolHdr.LabelType == PRE_LABEL || recycle) {
272       Dmsg1(190, "ready_for_append found freshly labeled volume. dev=%x\n", dev);
273       dev->VolHdr.LabelType = VOL_LABEL; /* set Volume label */
274       write_volume_label_to_block(jcr, dev, block);
275       /*
276        * Write the block now to ensure we have write permission.
277        *  It is better to find out now rather than later.
278        */
279       dev->VolCatInfo.VolCatBytes = 0;
280       if (!rewind_dev(dev)) {
281          Jmsg2(jcr, M_WARNING, 0, _("Rewind error on device %s. ERR=%s\n"), 
282                dev_name(dev), strerror_dev(dev));
283       }
284       if (recycle) {
285          if (!truncate_dev(dev)) {
286             Jmsg2(jcr, M_WARNING, 0, _("Truncate error on device %s. ERR=%s\n"), 
287                   dev_name(dev), strerror_dev(dev));
288          }
289       }
290       if (!write_block_to_dev(dev, block)) {
291          Jmsg2(jcr, M_ERROR, 0, _("Unable to write device %s. ERR=%s\n"),
292             dev_name(dev), strerror_dev(dev));
293          goto mount_next_vol;
294       }
295       if (!rewind_dev(dev)) {
296          Jmsg2(jcr, M_ERROR, 0, _("Unable to rewind device %s. ERR=%s\n"),
297             dev_name(dev), strerror_dev(dev));
298          goto mount_next_vol;
299       }
300       /* Recreate a correct volume label and return it in the block */
301       write_volume_label_to_block(jcr, dev, block);
302       dev->VolCatInfo.VolCatJobs = 1;
303       dev->VolCatInfo.VolCatFiles = 1;
304       dev->VolCatInfo.VolCatErrors = 0;
305       dev->VolCatInfo.VolCatBlocks = 1;
306       if (recycle) {
307          dev->VolCatInfo.VolCatMounts++;  
308          dev->VolCatInfo.VolCatRecycles++;
309       } else {
310          dev->VolCatInfo.VolCatMounts = 1;
311          dev->VolCatInfo.VolCatRecycles = 0;
312          dev->VolCatInfo.VolCatWrites = 1;
313          dev->VolCatInfo.VolCatReads = 1;
314       }
315       strcpy(dev->VolCatInfo.VolCatStatus, "Append");
316       Dmsg0(100, "dir_update_vol_info. Set Append\n");
317       dir_update_volume_info(jcr, &dev->VolCatInfo, 1);  /* indicate doing relabel */
318       if (recycle) {
319          Jmsg(jcr, M_INFO, 0, _("Recycled volume %s on device %s, all previous data lost.\n"),
320             jcr->VolumeName, dev_name(dev));
321       } else {
322          Jmsg(jcr, M_INFO, 0, _("Wrote label to prelabeled Volume %s on device %s\n"),
323             jcr->VolumeName, dev_name(dev));
324       }
325
326    } else {
327       /*
328        * OK, at this point, we have a valid Bacula label, but
329        * we need to position to the end of the volume, since we are
330        * just now putting it into append mode.
331        */
332       Dmsg0(200, "Device previously written, moving to end of data\n");
333       Jmsg(jcr, M_INFO, 0, _("Volume %s previously written, moving to end of data.\n"),
334          jcr->VolumeName);
335       if (!eod_dev(dev)) {
336          Jmsg(jcr, M_ERROR, 0, _("Unable to position to end of data %s. ERR=%s\n"),
337             dev_name(dev), strerror_dev(dev));
338          Jmsg(jcr, M_INFO, 0, _("Marking Volume %s in Error in Catalog.\n"),
339             jcr->VolumeName);
340          strcpy(dev->VolCatInfo.VolCatStatus, "Error");
341          Dmsg0(100, "dir_update_vol_info. Set Error.\n");
342          dir_update_volume_info(jcr, &dev->VolCatInfo, 0);
343          goto mount_next_vol;
344       }
345       /* *****FIXME**** we should do some checking for files too */
346       if (dev_is_tape(dev)) {
347          Jmsg(jcr, M_INFO, 0, _("Ready to append to end of Volume at file=%d.\n"), dev_file(dev));
348          /*
349           * Check if we are positioned on the tape at the same place
350           * that the database says we should be.
351           */
352          if (dev->VolCatInfo.VolCatFiles != dev_file(dev) + 1) {
353             /* ****FIXME**** this should refuse to write on tape */
354             Jmsg(jcr, M_ERROR, 0, _("Hey! Num files mismatch! Volume=%d Catalog=%d\n"), 
355                dev_file(dev)+1, dev->VolCatInfo.VolCatFiles);
356          }
357       }
358       /* Update Volume Info -- will be written at end of Job */
359       dev->VolCatInfo.VolCatMounts++;      /* Update mounts */
360       dev->VolCatInfo.VolCatJobs++;
361       /* Return an empty block */
362       empty_block(block);             /* we used it for reading so set for write */
363    }
364    dev->state |= ST_APPEND;
365    Dmsg0(100, "Normal return from read_dev_for_append\n");
366    return 1; 
367 }
368
369 int mount_next_read_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
370 {
371    Dmsg2(90, "NumVolumes=%d CurVolume=%d\n", jcr->NumVolumes, jcr->CurVolume);
372    /*
373     * End Of Tape -- mount next Volume (if another specified)
374     */
375    if (jcr->NumVolumes > 1 && jcr->CurVolume < jcr->NumVolumes) {
376       VOL_LIST *vol = jcr->VolList;
377       /* Find next Volume */
378       jcr->CurVolume++;
379       for (int i=1; i<jcr->CurVolume; i++) {
380          vol = vol->next;
381       }
382       pm_strcpy(&jcr->VolumeName, vol->VolumeName);
383       Dmsg1(400, "There is another volume %s.\n", jcr->VolumeName);
384
385       close_dev(dev);
386       dev->state &= ~ST_READ; 
387       if (!acquire_device_for_read(jcr, dev, block)) {
388          Emsg2(M_FATAL, 0, "Cannot open Dev=%s, Vol=%s\n", dev_name(dev),
389                jcr->VolumeName);
390          return 0;
391       }
392       return 1;                       /* next volume mounted */
393    }
394    Dmsg0(90, "End of Device reached.\n");
395    return 0;
396 }
397
398
399 /*
400  * Edit codes into ChangerCommand
401  *  %% = %
402  *  %a = archive device name
403  *  %c = changer device name
404  *  %f = Client's name
405  *  %j = Job name
406  *  %o = command
407  *  %s = Slot base 0
408  *  %S = Slot base 1
409  *  %v = Volume name
410  *
411  *
412  *  omsg = edited output message
413  *  imsg = input string containing edit codes (%x)
414  *  cmd = command string (load, unload, ...) 
415  *
416  */
417 static char *edit_device_codes(JCR *jcr, char *omsg, char *imsg, char *cmd) 
418 {
419    char *p;
420    const char *str;
421    char add[20];
422
423    *omsg = 0;
424    Dmsg1(200, "edit_device_codes: %s\n", imsg);
425    for (p=imsg; *p; p++) {
426       if (*p == '%') {
427          switch (*++p) {
428          case '%':
429             str = "%";
430             break;
431          case 'a':
432             str = jcr->device->dev->dev_name;
433             break;
434          case 'c':
435             str = NPRT(jcr->device->changer_name);
436             break;
437          case 'o':
438             str = NPRT(cmd);
439             break;
440          case 's':
441             sprintf(add, "%d", jcr->VolCatInfo.Slot - 1);
442             str = add;
443             break;
444          case 'S':
445             sprintf(add, "%d", jcr->VolCatInfo.Slot);
446             str = add;
447             break;
448          case 'j':                    /* Job name */
449             str = jcr->Job;
450             break;
451          case 'v':
452             str = NPRT(jcr->VolumeName);
453             break;
454          case 'f':
455             str = NPRT(jcr->client_name);
456             break;
457
458          default:
459             add[0] = '%';
460             add[1] = *p;
461             add[2] = 0;
462             str = add;
463             break;
464          }
465       } else {
466          add[0] = *p;
467          add[1] = 0;
468          str = add;
469       }
470       Dmsg1(200, "add_str %s\n", str);
471       pm_strcat(&omsg, (char *)str);
472       Dmsg1(200, "omsg=%s\n", omsg);
473    }
474    return omsg;
475 }