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