]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/dvd.c
- Fix name space pollution by OpenSSL 0.9.8 reported by
[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 > 1, append .# to the filename (where # is the part number) */
62    if (dev->part > 1) {
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)) {
277       Dmsg0(29, "dvd_write_part: unable to unmount the device\n");
278    }
279    
280    POOL_MEM ocmd(PM_FNAME);
281    POOL_MEM results(PM_MESSAGE);
282    char* icmd;
283    int status;
284    int timeout;
285    int part;
286    char ed1[50];
287    
288    results.c_str()[0] = 0;
289    icmd = dev->device->write_part_command;
290    
291    /* 
292     * Note! part is used to control whether or not we create a
293     *   new filesystem. If the device could be mounted, it is because
294     *   it already has a filesystem, so we artificially set part=1
295     *   to avoid zapping an existing filesystem.
296     */
297    part = dev->part;
298    if (dev->is_mounted() && dev->part < 2) {
299       dev->part = 2;      /* do not wipe out existing filesystem */
300    }
301    edit_device_codes_dev(dev, ocmd.c_str(), icmd);
302    dev->part = part;
303       
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.c_str());
313    Dmsg1(100, "results len=%d\n", strlen(results.c_str()));
314    if (status != 0) {
315       Mmsg1(dev->errmsg, "Error while writing current part to the DVD: %s", 
316             results.c_str());
317       Dmsg1(000, "%s", dev->errmsg);
318       dev->dev_errno = EIO;
319       return false;
320    }
321
322    POOL_MEM archive_name(PM_FNAME);
323    /* Delete spool file */
324    make_spooled_dvd_filename(dev, archive_name);
325    unlink(archive_name.c_str());
326    Dmsg1(29, "unlink(%s)\n", archive_name.c_str());
327    update_free_space_dev(dev);
328    Jmsg(dcr->jcr, M_INFO, 0, _("Remaining free space %s on %s\n"), 
329       edit_uint64_with_commas(dev->free_space, ed1), dev->print_name());
330    Dmsg1(100, "results=%s\n", results.c_str());
331    return true;
332 }
333
334 /* Open the next part file.
335  *  - Close the fd
336  *  - Increment part number 
337  *  - Reopen the device
338  */
339 int open_next_part(DCR *dcr)
340 {
341    DEVICE *dev = dcr->dev;
342
343    Dmsg5(29, "Enter: ==== open_next_part part=%d npart=%d dev=%s vol=%s mode=%d\n", 
344       dev->part, dev->num_parts, dev->print_name(),
345          dev->VolCatInfo.VolCatName, dev->openmode);
346    if (!dev->is_dvd()) {
347       Dmsg1(000, "Device %s is not dvd!!!!\n", dev->print_name()); 
348       return -1;
349    }
350       
351    /* When appending, do not open a new part if the current is empty */
352    if (dev->can_append() && (dev->part >= dev->num_parts) && 
353        (dev->part_size == 0)) {
354       Dmsg0(29, "open_next_part exited immediately (dev->part_size == 0).\n");
355       return dev->fd;
356    }
357    
358    if (dev->fd >= 0) {
359       close(dev->fd);
360    }
361    
362    dev->fd = -1;
363    dev->clear_opened();
364    
365    /*
366     * If we have a part open for write, then write it to
367     *  DVD before opening the next part.
368     */
369    if (dev->is_dvd() && (dev->part >= dev->num_parts) && dev->can_append()) {
370       if (!dvd_write_part(dcr)) {
371          return -1;
372       }
373    }
374      
375    if (dev->part > dev->num_parts) {
376       Dmsg2(000, "In open_next_part: part=%d nump=%d\n", dev->part, dev->num_parts);
377       ASSERT(dev->part <= dev->num_parts);
378    }
379    dev->part_start += dev->part_size;
380    dev->part++;
381    
382    Dmsg2(29, "part=%d num_parts=%d\n", dev->part, dev->num_parts);
383    /* I think this dev->can_append() should not be there */
384    if ((dev->num_parts < dev->part) && dev->can_append()) {
385       POOL_MEM archive_name(PM_FNAME);
386       struct stat buf;
387       /* 
388        * First check what is on DVD.  If out part is there, we
389        *   are in trouble, so bail out.
390        */
391       make_mounted_dvd_filename(dev, archive_name);   /* makes dvd name */
392       if (stat(archive_name.c_str(), &buf) == 0) {
393          /* bad news bail out */
394          Mmsg1(&dev->errmsg, _("Next Volume part already exists on DVD. Cannot continue: %s\n"),
395             archive_name.c_str());
396          return -1;
397       }
398
399       dev->num_parts = dev->part;
400       dev->VolCatInfo.VolCatParts = dev->part;
401       make_spooled_dvd_filename(dev, archive_name);   /* makes spool name */
402       
403       /* Check if the next part exists in spool directory . */
404       if ((stat(archive_name.c_str(), &buf) == 0) || (errno != ENOENT)) {
405          Dmsg1(29, "open_next_part %s is in the way, moving it away...\n", archive_name.c_str());
406          /* Then try to unlink it */
407          if (unlink(archive_name.c_str()) < 0) {
408             berrno be;
409             dev->dev_errno = errno;
410             Mmsg2(dev->errmsg, _("open_next_part can't unlink existing part %s, ERR=%s\n"), 
411                    archive_name.c_str(), be.strerror());
412             return -1;
413          }
414       }
415    }
416    if (dev->num_parts < dev->part) {
417       dev->num_parts = dev->part;
418       dev->VolCatInfo.VolCatParts = dev->part;
419    }
420    Dmsg2(50, "Call dev->open(vol=%s, mode=%d", dev->VolCatInfo.VolCatName, 
421          dev->openmode);
422    /* Open next part */
423    if (dev->open(dcr, dev->openmode) < 0) {
424       return -1;
425    } 
426    dev->set_labeled();          /* all next parts are "labeled" */
427    return dev->fd;
428 }
429
430 /* Open the first part file.
431  *  - Close the fd
432  *  - Reopen the device
433  *
434  *   I don't see why this is necessary unless the current
435  *   part is not zero.
436  */
437 int open_first_part(DCR *dcr, int mode)
438 {
439    DEVICE *dev = dcr->dev;
440
441    Dmsg3(29, "Enter: ==== open_first_part dev=%s Vol=%s mode=%d\n", dev->dev_name, 
442          dev->VolCatInfo.VolCatName, dev->openmode);
443
444    if (dev->fd >= 0) {
445       close(dev->fd);
446    }
447    dev->fd = -1;
448    dev->clear_opened();
449    
450    dev->part_start = 0;
451    dev->part = 1;
452    
453    Dmsg2(50, "Call dev->open(vol=%s, mode=%d)\n", dcr->VolCatInfo.VolCatName, 
454          mode);
455    if (dev->open(dcr, mode) < 0) {
456       Dmsg0(50, "open dev() failed\n");
457       return -1;
458    }
459    Dmsg1(50, "Leave open_first_part state=%s\n", dev->is_open()?"open":"not open");
460    return dev->fd;
461 }
462
463
464 /* Protected version of lseek, which opens the right part if necessary */
465 off_t lseek_dev(DEVICE *dev, off_t offset, int whence)
466 {
467    int openmode;
468    DCR *dcr;
469    off_t pos;
470    
471    Dmsg0(100, "Enter lseek_dev\n");
472    if (!dev->is_dvd() || dev->num_parts <= 1) { /* If there is only one part, simply call lseek. */
473       return lseek(dev->fd, offset, whence);
474    }
475       
476    dcr = (DCR *)dev->attached_dcrs->first();  /* any dcr will do */
477    switch(whence) {
478    case SEEK_SET:
479       Dmsg1(100, "lseek_dev SEEK_SET to %d\n", (int)offset);
480       if ((uint64_t)offset >= dev->part_start) {
481          if ((uint64_t)(offset - dev->part_start) < dev->part_size) {
482             /* We are staying in the current part, just seek */
483             offset -= dev->part_start; /* adjust for start of this part */
484             if ((pos = lseek(dev->fd, offset, SEEK_SET)) < 0) {
485                return pos;   
486             } else {
487                return pos + dev->part_start;
488             }
489          } else {
490             /* Load next part, and start again */
491             if (open_next_part(dcr) < 0) {
492                Dmsg0(100, "lseek_dev failed while trying to open the next part\n");
493                return -1;
494             }
495             return lseek_dev(dev, offset, SEEK_SET);
496          }
497       } else {
498          /*
499           * pos < dev->part_start :
500           * We need to access a previous part, 
501           * so just load the first one, and seek again
502           * until the right one is loaded
503           */
504          if (open_first_part(dcr, dev->openmode) < 0) {
505             Dmsg0(100, "lseek_dev failed while trying to open the first part\n");
506             return -1;
507          }
508          return lseek_dev(dev, offset, SEEK_SET);
509       }
510       break;
511    case SEEK_CUR:
512       Dmsg1(100, "lseek_dev SEEK_CUR to %d\n", (int)offset);
513       if ((pos = lseek(dev->fd, (off_t)0, SEEK_CUR)) < 0) {
514          return pos;   
515       }
516       pos += dev->part_start;
517       if (offset == 0) {
518          return pos;
519       } else { /* Not used in Bacula, but should work */
520          return lseek_dev(dev, pos, SEEK_SET);
521       }
522       break;
523    case SEEK_END:
524       Dmsg1(100, "lseek_dev SEEK_END to %d\n", (int)offset);
525       if (offset > 0) { /* Not used by bacula */
526          Dmsg1(100, "lseek_dev SEEK_END called with an invalid offset %d\n", (int)offset);
527          errno = EINVAL;
528          return -1;
529       }
530       
531       if (dev->part == dev->num_parts) { /* The right part is already loaded */
532          if ((pos = lseek(dev->fd, (off_t)0, SEEK_END)) < 0) {
533             return pos;   
534          } else {
535             return pos + dev->part_start;
536          }
537       } else {
538          /* Load the first part, then load the next until we reach the last one.
539           * This is the only way to be sure we compute the right file address. */
540          /* Save previous openmode, and open all but last part read-only (useful for DVDs) */
541          openmode = dev->openmode;
542          
543          /* Works because num_parts > 0. */
544          if (open_first_part(dcr, OPEN_READ_ONLY) < 0) {
545             Dmsg0(100, "lseek_dev failed while trying to open the first part\n");
546             return -1;
547          }
548          while (dev->part < (dev->num_parts-1)) {
549             if (open_next_part(dcr) < 0) {
550                Dmsg0(100, "lseek_dev failed while trying to open the next part\n");
551                return -1;
552             }
553          }
554          dev->openmode = openmode;
555          if (open_next_part(dcr) < 0) {
556             Dmsg0(100, "lseek_dev failed while trying to open the next part\n");
557             return -1;
558          }
559          return lseek_dev(dev, 0, SEEK_END);
560       }
561       break;
562    default:
563       errno = EINVAL;
564       return -1;
565    }
566 }
567
568 bool dvd_close_job(DCR *dcr)
569 {
570    DEVICE *dev = dcr->dev;
571    JCR *jcr = dcr->jcr;
572    bool ok = true;
573
574    /* If the device is a dvd and WritePartAfterJob
575     * is set to yes, open the next part, so, in case of a device
576     * that requires mount, it will be written to the device.
577     */
578    if (dev->is_dvd() && jcr->write_part_after_job && (dev->part_size > 0)) {
579       Dmsg1(100, "Writing last part=%d write_partafter_job is set.\n",
580          dev->part);
581       if (dev->part < dev->num_parts) {
582          Jmsg3(jcr, M_FATAL, 0, _("Error while writing, current part number is less than the total number of parts (%d/%d, device=%s)\n"),
583                dev->part, dev->num_parts, dev->print_name());
584          dev->dev_errno = EIO;
585          ok = false;
586       }
587       
588       /* This should be !dvd_write_part(dcr) */
589 //    if (ok && open_next_part(dcr) < 0) {
590       if (ok && !dvd_write_part(dcr)) {
591          Jmsg2(jcr, M_FATAL, 0, _("Unable to write part %s: ERR=%s\n"),
592                dev->print_name(), strerror_dev(dev));
593          dev->dev_errno = EIO;
594          ok = false;
595       }
596    }
597    Dmsg1(200, "Set VolCatParts=%d\n", dev->num_parts);
598    dev->VolCatInfo.VolCatParts = dev->num_parts;
599    return ok;
600 }
601
602
603 /*
604  * Edit codes into (Un)MountCommand, Write(First)PartCommand
605  *  %% = %
606  *  %a = archive device name
607  *  %m = mount point
608  *  %v = last part name
609  *
610  *  omsg = edited output message
611  *  imsg = input string containing edit codes (%x)
612  *
613  */
614 static char *edit_device_codes_dev(DEVICE* dev, char *omsg, const char *imsg)
615 {
616    const char *p;
617    const char *str;
618    char add[20];
619    
620    POOL_MEM archive_name(PM_FNAME);
621
622    *omsg = 0;
623    Dmsg1(800, "edit_device_codes: %s\n", imsg);
624    for (p=imsg; *p; p++) {
625       if (*p == '%') {
626          switch (*++p) {
627          case '%':
628             str = "%";
629             break;
630          case 'n':
631             bsnprintf(add, sizeof(add), "%d", dev->part);
632             str = add;
633             break;
634          case 'a':
635             str = dev->dev_name;
636             break;
637          case 'm':
638             str = dev->device->mount_point;
639             break;
640          case 'v':
641             make_spooled_dvd_filename(dev, archive_name);
642             str = archive_name.c_str();
643             break;
644          default:
645             add[0] = '%';
646             add[1] = *p;
647             add[2] = 0;
648             str = add;
649             break;
650          }
651       } else {
652          add[0] = *p;
653          add[1] = 0;
654          str = add;
655       }
656       Dmsg1(1900, "add_str %s\n", str);
657       pm_strcat(&omsg, (char *)str);
658       Dmsg1(1800, "omsg=%s\n", omsg);
659    }
660    return omsg;
661 }