]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/dvd.c
- Make all files in working directory have .xxx at end.
[bacula/bacula] / bacula / src / stored / dvd.c
1 /*
2  *
3  *   dvd.c  -- Routines specific to DVD devices (and
4  *             possibly other removable hard media). 
5  *
6  *    Nicolas Boichat, MMV
7  *
8  *   Version $Id$
9  */
10 /*
11    Copyright (C) 2005 Kern Sibbald
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
15    version 2 as amended with additional clauses defined in the
16    file LICENSE in the main source directory.
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 
21    the file LICENSE for additional details.
22
23  */
24
25 #include "bacula.h"
26 #include "stored.h"
27
28 /* Forward referenced functions */
29 static char *edit_device_codes_dev(DEVICE *dev, char *omsg, const char *imsg);
30 static bool do_mount_dev(DEVICE* dev, int mount, int dotimeout);
31 static void add_file_and_part_name(DEVICE *dev, POOL_MEM &archive_name);
32
33 /* 
34  * Write the current volume/part filename to archive_name.
35  */
36 void make_mounted_dvd_filename(DEVICE *dev, POOL_MEM &archive_name) 
37 {
38    pm_strcpy(archive_name, dev->device->mount_point);
39    add_file_and_part_name(dev, archive_name);
40    dev->set_part_spooled(false);
41 }
42
43 void make_spooled_dvd_filename(DEVICE *dev, POOL_MEM &archive_name)
44 {
45    /* Use the working directory if spool directory is not defined */
46    if (dev->device->spool_directory) {
47       pm_strcpy(archive_name, dev->device->spool_directory);
48    } else {
49       pm_strcpy(archive_name, working_directory);
50    }
51    add_file_and_part_name(dev, archive_name);
52    dev->set_part_spooled(true);
53 }      
54
55 static void add_file_and_part_name(DEVICE *dev, POOL_MEM &archive_name)
56 {
57    char partnumber[20];
58    if (archive_name.c_str()[strlen(archive_name.c_str())-1] != '/') {
59       pm_strcat(archive_name, "/");
60    }
61
62    pm_strcat(archive_name, dev->VolCatInfo.VolCatName);
63    /* if part > 1, append .# to the filename (where # is the part number) */
64    if (dev->part > 1) {
65       pm_strcat(archive_name, ".");
66       bsnprintf(partnumber, sizeof(partnumber), "%d", dev->part);
67       pm_strcat(archive_name, partnumber);
68    }
69    Dmsg1(100, "Exit make_dvd_filename: arch=%s\n", archive_name.c_str());
70 }  
71
72 /* Mount the device.
73  * If timeout, wait until the mount command returns 0.
74  * If !timeout, try to mount the device only once.
75  */
76 bool mount_dev(DEVICE* dev, int timeout) 
77 {
78    Dmsg0(900, "Enter mount_dev\n");
79    if (dev->is_mounted()) {
80       return true;
81    } else if (dev->requires_mount()) {
82       return do_mount_dev(dev, 1, timeout);
83    }       
84    return true;
85 }
86
87 /* Unmount the device
88  * If timeout, wait until the unmount command returns 0.
89  * If !timeout, try to unmount the device only once.
90  */
91 bool unmount_dev(DEVICE *dev, int timeout) 
92 {
93    Dmsg0(900, "Enter unmount_dev\n");
94    if (dev->is_mounted()) {
95       return do_mount_dev(dev, 0, timeout);
96    }
97    return true;
98 }
99
100 /* (Un)mount the device */
101 static bool do_mount_dev(DEVICE* dev, int mount, int dotimeout) 
102 {
103    POOL_MEM ocmd(PM_FNAME);
104    POOLMEM *results;
105    char *icmd;
106    int status, timeout;
107    
108    if (mount) {
109       if (dev->is_mounted()) {
110          return true;
111       }
112       icmd = dev->device->mount_command;
113    } else {
114       if (!dev->is_mounted()) {
115          return true;
116       }
117       icmd = dev->device->unmount_command;
118    }
119    
120    edit_device_codes_dev(dev, ocmd.c_str(), icmd);
121    
122    Dmsg2(200, "do_mount_dev: cmd=%s mounted=%d\n", ocmd.c_str(), !!dev->is_mounted());
123
124    if (dotimeout) {
125       /* Try at most 1 time to (un)mount the device. This should perhaps be configurable. */
126       timeout = 1;
127    } else {
128       timeout = 0;
129    }
130    results = get_memory(2000);
131    results[0] = 0;
132    /* If busy retry each second */
133    while ((status = run_program_full_output(ocmd.c_str(), 
134                        dev->max_open_wait/2, results)) != 0) {
135       if (fnmatch("*is already mounted on", results, 0) == 0) {
136          break;
137       }
138       if (timeout-- > 0) {
139          /* Sometimes the device cannot be mounted because it is already mounted.
140           * Try to unmount it, then remount it */
141          if (mount) {
142             Dmsg1(400, "Trying to unmount the device %s...\n", dev->print_name());
143             do_mount_dev(dev, 0, 0);
144          }
145          bmicrosleep(1, 0);
146          continue;
147       }
148       Dmsg2(40, "Device %s cannot be mounted. ERR=%s\n", dev->print_name(), results);
149       Mmsg(dev->errmsg, "Device %s cannot be mounted. ERR=%s\n", 
150            dev->print_name(), results);
151       /*
152        * Now, just to be sure it is not mounted, try to read the
153        *  filesystem.
154        */
155       DIR* dp;
156       struct dirent *entry, *result;
157       int name_max;
158       int count = 0;
159       
160       name_max = pathconf(".", _PC_NAME_MAX);
161       if (name_max < 1024) {
162          name_max = 1024;
163       }
164          
165       if (!(dp = opendir(dev->device->mount_point))) {
166          berrno be;
167          dev->dev_errno = errno;
168          Dmsg3(29, "open_mounted_dev: failed to open dir %s (dev=%s), ERR=%s\n", dev->device->mount_point, dev->dev_name, be.strerror());
169          goto get_out;
170       }
171       
172       entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
173       while (1) {
174          if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
175             dev->dev_errno = ENOENT;
176             Dmsg2(29, "open_mounted_dev: failed to find suitable file in dir %s (dev=%s)\n", dev->device->mount_point, dev->dev_name);
177             break;
178          }
179          count++;
180       }
181       free(entry);
182       closedir(dp);
183       if (count > 2) {
184          mount = 1;                      /* If we got more than . and .. */
185          break;                          /*   there must be something mounted */
186       }
187 get_out:
188       free_pool_memory(results);
189       return false;
190    }
191    
192    dev->set_mounted(mount);              /* set/clear mounted flag */
193    free_pool_memory(results);
194    return true;
195 }
196
197 /* Update the free space on the device */
198 void update_free_space_dev(DEVICE* dev) 
199 {
200    POOL_MEM ocmd(PM_FNAME);
201    POOLMEM* results;
202    char* icmd;
203    int timeout;
204    long long int free;
205    char ed1[50];
206    
207    icmd = dev->device->free_space_command;
208    
209    if (!icmd) {
210       dev->free_space = 0;
211       dev->free_space_errno = 0;
212       dev->clear_media();
213       Dmsg2(29, "update_free_space_dev: free_space=%d, free_space_errno=%d (!icmd)\n", dev->free_space, dev->free_space_errno);
214       return;
215    }
216    
217    edit_device_codes_dev(dev, ocmd.c_str(), icmd);
218    
219    Dmsg1(29, "update_free_space_dev: cmd=%s\n", ocmd.c_str());
220
221    results = get_pool_memory(PM_MESSAGE);
222    results[0] = 0;
223    
224    /* Try at most 3 times to get the free space on the device. This should perhaps be configurable. */
225    timeout = 3;
226    
227    while (1) {
228       if (run_program_full_output(ocmd.c_str(), dev->max_open_wait/2, results) == 0) {
229          Dmsg1(100, "Free space program run : %s\n", results);
230          free = str_to_int64(results);
231          if (free >= 0) {
232             dev->free_space = free;
233             dev->free_space_errno = 1;
234             dev->set_media();
235             Mmsg0(dev->errmsg, "");
236             break;
237          }
238       }
239       dev->free_space = 0;
240       dev->free_space_errno = -EPIPE;
241       Mmsg1(dev->errmsg, "Cannot run free space command (%s)\n", results);
242       
243       if (--timeout > 0) {
244          Dmsg4(40, "Cannot get free space on device %s. free_space=%s, "
245             "free_space_errno=%d ERR=%s\n", dev->dev_name, 
246                edit_uint64(dev->free_space, ed1), dev->free_space_errno, 
247                dev->errmsg);
248          bmicrosleep(1, 0);
249          continue;
250       }
251
252       dev->dev_errno = -dev->free_space_errno;
253       Dmsg4(40, "Cannot get free space on device %s. free_space=%s, "
254          "free_space_errno=%d ERR=%s\n",
255             dev->dev_name, edit_uint64(dev->free_space, ed1),
256             dev->free_space_errno, dev->errmsg);
257       break;
258    }
259    
260    free_pool_memory(results);
261    Dmsg3(29, "update_free_space_dev: free_space=%s, free_space_errno=%d have_media=%d\n", 
262       edit_uint64(dev->free_space, ed1), dev->free_space_errno, dev->have_media());
263    return;
264 }
265
266 /*
267  * Write a part (Vol, Vol.1, ...) from the spool to the DVD   
268  */
269 static bool dvd_write_part(DCR *dcr) 
270 {
271    DEVICE *dev = dcr->dev;
272    Dmsg1(29, "dvd_write_part: device is %s\n", dev->print_name());
273    
274    if (!unmount_dev(dev, 1)) {
275       Dmsg0(29, "dvd_write_part: unable to unmount the device\n");
276    }
277    
278    POOL_MEM ocmd(PM_FNAME);
279    POOL_MEM results(PM_MESSAGE);
280    char* icmd;
281    int status;
282    int timeout;
283    int part;
284    char ed1[50];
285    
286    results.c_str()[0] = 0;
287    icmd = dev->device->write_part_command;
288    
289    /* 
290     * Note! part is used to control whether or not we create a
291     *   new filesystem. If the device could be mounted, it is because
292     *   it already has a filesystem, so we artificially set part=1
293     *   to avoid zapping an existing filesystem.
294     */
295    part = dev->part;
296    if (dev->is_mounted() && dev->part < 2) {
297       dev->part = 2;      /* do not wipe out existing filesystem */
298    }
299    edit_device_codes_dev(dev, ocmd.c_str(), icmd);
300    dev->part = part;
301       
302    /*
303     * Wait at most the time a maximum size part is written in DVD 0.5x speed
304     * FIXME: Minimum speed should be in device configuration 
305     */
306    timeout = dev->max_open_wait + (dev->max_part_size/(1350*1024/2));
307    
308    Dmsg2(29, "dvd_write_part: cmd=%s timeout=%d\n", ocmd.c_str(), timeout);
309       
310    status = run_program_full_output(ocmd.c_str(), timeout, results.c_str());
311    if (status != 0) {
312       Mmsg1(dev->errmsg, "Error while writing current part to the DVD: %s", 
313             results.c_str());
314       Dmsg1(000, "%s", dev->errmsg);
315       dev->dev_errno = EIO;
316       return false;
317    }
318
319    POOL_MEM archive_name(PM_FNAME);
320    /* Delete spool file */
321    make_spooled_dvd_filename(dev, archive_name);
322    unlink(archive_name.c_str());
323    Dmsg1(29, "unlink(%s)\n", archive_name.c_str());
324    update_free_space_dev(dev);
325    Jmsg(dcr->jcr, M_INFO, 0, _("Remaining free space %s on %s\n"), 
326       edit_uint64_with_commas(dev->free_space, ed1), dev->print_name());
327    return true;
328 }
329
330 /* Open the next part file.
331  *  - Close the fd
332  *  - Increment part number 
333  *  - Reopen the device
334  */
335 int open_next_part(DCR *dcr)
336 {
337    DEVICE *dev = dcr->dev;
338
339    Dmsg5(29, "Enter: ==== open_next_part part=%d npart=%d dev=%s vol=%s mode=%d\n", 
340       dev->part, dev->num_parts, dev->print_name(),
341          dev->VolCatInfo.VolCatName, dev->openmode);
342    if (!dev->is_dvd()) {
343       Dmsg1(000, "Device %s is not dvd!!!!\n", dev->print_name()); 
344       return -1;
345    }
346       
347    /* When appending, do not open a new part if the current is empty */
348    if (dev->can_append() && (dev->part >= dev->num_parts) && 
349        (dev->part_size == 0)) {
350       Dmsg0(29, "open_next_part exited immediately (dev->part_size == 0).\n");
351       return dev->fd;
352    }
353    
354    if (dev->fd >= 0) {
355       close(dev->fd);
356    }
357    
358    dev->fd = -1;
359    dev->clear_opened();
360    
361    /*
362     * If we have a part open for write, then write it to
363     *  DVD before opening the next part.
364     */
365    if (dev->is_dvd() && (dev->part >= dev->num_parts) && dev->can_append()) {
366       if (!dvd_write_part(dcr)) {
367          return -1;
368       }
369    }
370      
371    if (dev->part > dev->num_parts) {
372       Dmsg2(000, "In open_next_part: part=%d nump=%d\n", dev->part, dev->num_parts);
373       ASSERT(dev->part <= dev->num_parts);
374    }
375    dev->part_start += dev->part_size;
376    dev->part++;
377    
378    Dmsg2(29, "part=%d num_parts=%d\n", dev->part, dev->num_parts);
379    /* I think this dev->can_append() should not be there */
380    if ((dev->num_parts < dev->part) && dev->can_append()) {
381       POOL_MEM archive_name(PM_FNAME);
382       struct stat buf;
383       /* 
384        * First check what is on DVD.  If out part is there, we
385        *   are in trouble, so bail out.
386        */
387       make_mounted_dvd_filename(dev, archive_name);   /* makes dvd name */
388       if (stat(archive_name.c_str(), &buf) == 0) {
389          /* bad news bail out */
390          Mmsg1(&dev->errmsg, _("Next Volume part already exists on DVD. Cannot continue: %s\n"),
391             archive_name.c_str());
392          return -1;
393       }
394
395       dev->num_parts = dev->part;
396       dev->VolCatInfo.VolCatParts = dev->part;
397       make_spooled_dvd_filename(dev, archive_name);   /* makes spool name */
398       
399       /* Check if the next part exists in spool directory . */
400       if ((stat(archive_name.c_str(), &buf) == 0) || (errno != ENOENT)) {
401          Dmsg1(29, "open_next_part %s is in the way, moving it away...\n", archive_name.c_str());
402          /* Then try to unlink it */
403          if (unlink(archive_name.c_str()) < 0) {
404             berrno be;
405             dev->dev_errno = errno;
406             Mmsg2(dev->errmsg, _("open_next_part can't unlink existing part %s, ERR=%s\n"), 
407                    archive_name.c_str(), be.strerror());
408             return -1;
409          }
410       }
411    }
412    if (dev->num_parts < dev->part) {
413       dev->num_parts = dev->part;
414       dev->VolCatInfo.VolCatParts = dev->part;
415    }
416    Dmsg2(50, "Call dev->open(vol=%s, mode=%d\n", dev->VolCatInfo.VolCatName, 
417          dev->openmode);
418    /* Open next part */
419    if (dev->open(dcr, dev->openmode) < 0) {
420       return -1;
421    } 
422    dev->set_labeled();          /* all next parts are "labeled" */
423    return dev->fd;
424 }
425
426 /* Open the first part file.
427  *  - Close the fd
428  *  - Reopen the device
429  *
430  *   I don't see why this is necessary unless the current
431  *   part is not zero.
432  */
433 int open_first_part(DCR *dcr, int mode)
434 {
435    DEVICE *dev = dcr->dev;
436
437    Dmsg3(29, "Enter: ==== open_first_part dev=%s Vol=%s mode=%d\n", dev->dev_name, 
438          dev->VolCatInfo.VolCatName, dev->openmode);
439
440    if (dev->fd >= 0) {
441       close(dev->fd);
442    }
443    dev->fd = -1;
444    dev->clear_opened();
445    
446    dev->part_start = 0;
447    dev->part = 1;
448    
449    Dmsg2(50, "Call dev->open(vol=%s, mode=%d)\n", dcr->VolCatInfo.VolCatName, 
450          mode);
451    if (dev->open(dcr, mode) < 0) {
452       Dmsg0(50, "open dev() failed\n");
453       return -1;
454    }
455    Dmsg1(50, "Leave open_first_part state=%s\n", dev->is_open()?"open":"not open");
456    return dev->fd;
457 }
458
459
460 /* Protected version of lseek, which opens the right part if necessary */
461 off_t lseek_dev(DEVICE *dev, off_t offset, int whence)
462 {
463    DCR *dcr;
464    off_t pos;
465    
466    Dmsg3(100, "Enter lseek_dev fd=%d part=%d nparts=%d\n", dev->fd,
467       dev->part, dev->num_parts);
468    if (!dev->is_dvd()) { 
469       Dmsg0(100, "Using sys lseek\n");
470       return lseek(dev->fd, offset, whence);
471    }
472       
473    dcr = (DCR *)dev->attached_dcrs->first();  /* any dcr will do */
474    switch(whence) {
475    case SEEK_SET:
476       Dmsg1(100, "lseek_dev SEEK_SET to %d\n", (int)offset);
477       if ((uint64_t)offset >= dev->part_start) {
478          offset -= dev->part_start; /* adjust for start of this part */
479          if (offset == 0 || (uint64_t)offset < dev->part_size) {
480             /* We are staying in the current part, just seek */
481             if ((pos = lseek(dev->fd, offset, SEEK_SET)) < 0) {
482                return pos;   
483             } else {
484                return pos + dev->part_start;
485             }
486          } else {
487             /* Load next part, and start again */
488             if (open_next_part(dcr) < 0) {
489                Dmsg0(100, "lseek_dev failed while trying to open the next part\n");
490                return -1;
491             }
492             return lseek_dev(dev, offset, SEEK_SET);
493          }
494       } else {
495          /*
496           * pos < dev->part_start :
497           * We need to access a previous part, 
498           * so just load the first one, and seek again
499           * until the right one is loaded
500           */
501          if (open_first_part(dcr, dev->openmode) < 0) {
502             Dmsg0(100, "lseek_dev failed while trying to open the first part\n");
503             return -1;
504          }
505          return lseek_dev(dev, offset, SEEK_SET);
506       }
507       break;
508    case SEEK_CUR:
509       Dmsg1(100, "lseek_dev SEEK_CUR to %d\n", (int)offset);
510       if ((pos = lseek(dev->fd, (off_t)0, SEEK_CUR)) < 0) {
511          return pos;   
512       }
513       pos += dev->part_start;
514       if (offset == 0) {
515          return pos;
516       } else { /* Not used in Bacula, but should work */
517          return lseek_dev(dev, pos, SEEK_SET);
518       }
519       break;
520    case SEEK_END:
521       Dmsg1(100, "lseek_dev SEEK_END to %d\n", (int)offset);
522       /*
523        * Bacula does not use offsets for SEEK_END
524        *  Also, Bacula uses seek_end only when it wants to
525        *  append to the volume, so for a dvd that means
526        *  that the volume must be spooled since the DVD
527        *  itself is read-only (as currently implemented).
528        */
529       if (offset > 0) { /* Not used by bacula */
530          Dmsg1(100, "lseek_dev SEEK_END called with an invalid offset %d\n", (int)offset);
531          errno = EINVAL;
532          return -1;
533       }
534       /* If we are already on a spooled part and have the
535        *  right part number, simply seek
536        */
537       if (dev->is_part_spooled() && dev->part == dev->num_parts) {
538          if ((pos = lseek(dev->fd, (off_t)0, SEEK_END)) < 0) {
539             return pos;   
540          } else {
541             return pos + dev->part_start;
542          }
543       } else {
544          /*
545           * Load the first part, then load the next until we reach the last one.
546           * This is the only way to be sure we compute the right file address.
547           *
548           * Save previous openmode, and open all but last part read-only 
549           * (useful for DVDs) 
550           */
551          int modesave = dev->openmode;
552          /* Works because num_parts > 0. */
553          if (open_first_part(dcr, OPEN_READ_ONLY) < 0) {
554             Dmsg0(100, "lseek_dev failed while trying to open the first part\n");
555             return -1;
556          }
557          while (dev->part < (dev->num_parts-1)) {
558             if (open_next_part(dcr) < 0) {
559                Dmsg0(100, "lseek_dev failed while trying to open the next part\n");
560                return -1;
561             }
562          }
563          dev->openmode = modesave;
564          if (open_next_part(dcr) < 0) {
565             Dmsg0(100, "lseek_dev failed while trying to open the next part\n");
566             return -1;
567          }
568          return lseek_dev(dev, 0, SEEK_END);
569       }
570       break;
571    default:
572       errno = EINVAL;
573       return -1;
574    }
575 }
576
577 bool dvd_close_job(DCR *dcr)
578 {
579    DEVICE *dev = dcr->dev;
580    JCR *jcr = dcr->jcr;
581    bool ok = true;
582
583    /* If the device is a dvd and WritePartAfterJob
584     * is set to yes, open the next part, so, in case of a device
585     * that requires mount, it will be written to the device.
586     */
587    if (dev->is_dvd() && jcr->write_part_after_job && (dev->part_size > 0)) {
588       Dmsg1(100, "Writing last part=%d write_partafter_job is set.\n",
589          dev->part);
590       if (dev->part < dev->num_parts) {
591          Jmsg3(jcr, M_FATAL, 0, _("Error while writing, current part number is less than the total number of parts (%d/%d, device=%s)\n"),
592                dev->part, dev->num_parts, dev->print_name());
593          dev->dev_errno = EIO;
594          ok = false;
595       }
596       
597       /* This should be !dvd_write_part(dcr) */
598 //    if (ok && open_next_part(dcr) < 0) {
599       if (ok && !dvd_write_part(dcr)) {
600          Jmsg2(jcr, M_FATAL, 0, _("Unable to write part %s: ERR=%s\n"),
601                dev->print_name(), strerror_dev(dev));
602          dev->dev_errno = EIO;
603          ok = false;
604       }
605    }
606    Dmsg1(200, "Set VolCatParts=%d\n", dev->num_parts);
607    dev->VolCatInfo.VolCatParts = dev->num_parts;
608    return ok;
609 }
610
611
612 /*
613  * Edit codes into (Un)MountCommand, Write(First)PartCommand
614  *  %% = %
615  *  %a = archive device name
616  *  %m = mount point
617  *  %v = last part name
618  *
619  *  omsg = edited output message
620  *  imsg = input string containing edit codes (%x)
621  *
622  */
623 static char *edit_device_codes_dev(DEVICE* dev, char *omsg, const char *imsg)
624 {
625    const char *p;
626    const char *str;
627    char add[20];
628    
629    POOL_MEM archive_name(PM_FNAME);
630
631    *omsg = 0;
632    Dmsg1(800, "edit_device_codes: %s\n", imsg);
633    for (p=imsg; *p; p++) {
634       if (*p == '%') {
635          switch (*++p) {
636          case '%':
637             str = "%";
638             break;
639          case 'n':
640             bsnprintf(add, sizeof(add), "%d", dev->part);
641             str = add;
642             break;
643          case 'a':
644             str = dev->dev_name;
645             break;
646          case 'm':
647             str = dev->device->mount_point;
648             break;
649          case 'v':
650             make_spooled_dvd_filename(dev, archive_name);
651             str = archive_name.c_str();
652             break;
653          default:
654             add[0] = '%';
655             add[1] = *p;
656             add[2] = 0;
657             str = add;
658             break;
659          }
660       } else {
661          add[0] = *p;
662          add[1] = 0;
663          str = add;
664       }
665       Dmsg1(1900, "add_str %s\n", str);
666       pm_strcat(&omsg, (char *)str);
667       Dmsg1(1800, "omsg=%s\n", omsg);
668    }
669    return omsg;
670 }