]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/dvd.c
54ee86634727a9011a7f6e358222928a417373ca
[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 void edit_device_codes_dev(DEVICE *dev, POOL_MEM &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 > 0) {
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(90, "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(90, "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    sm_check(__FILE__, __LINE__, false);
109    if (mount) {
110       if (dev->is_mounted()) {
111          Dmsg0(200, "======= DVD mount=1\n");
112          return true;
113       }
114       icmd = dev->device->mount_command;
115    } else {
116       if (!dev->is_mounted()) {
117          Dmsg0(200, "======= DVD mount=0\n");
118          return true;
119       }
120       icmd = dev->device->unmount_command;
121    }
122    
123    edit_device_codes_dev(dev, ocmd, icmd);
124    
125    Dmsg2(200, "do_mount_dev: cmd=%s mounted=%d\n", ocmd.c_str(), !!dev->is_mounted());
126
127    if (dotimeout) {
128       /* Try at most 1 time to (un)mount the device. This should perhaps be configurable. */
129       timeout = 1;
130    } else {
131       timeout = 0;
132    }
133    results = get_memory(2000);
134    results[0] = 0;
135    /* If busy retry each second */
136    while ((status = run_program_full_output(ocmd.c_str(), 
137                        dev->max_open_wait/2, results)) != 0) {
138       /* Doesn't work with internationalisation (This is not a problem) */
139       if (fnmatch("*is already mounted on", results, 0) == 0) {
140          break;
141       }
142       if (timeout-- > 0) {
143          /* Sometimes the device cannot be mounted because it is already mounted.
144           * Try to unmount it, then remount it */
145          if (mount) {
146             Dmsg1(400, "Trying to unmount the device %s...\n", dev->print_name());
147             do_mount_dev(dev, 0, 0);
148          }
149          bmicrosleep(1, 0);
150          continue;
151       }
152       Dmsg2(40, "Device %s cannot be mounted. ERR=%s\n", dev->print_name(), results);
153       Mmsg(dev->errmsg, _("Device %s cannot be mounted. ERR=%s\n"), 
154            dev->print_name(), results);
155       /*
156        * Now, just to be sure it is not mounted, try to read the
157        *  filesystem.
158        */
159       DIR* dp;
160       struct dirent *entry, *result;
161       int name_max;
162       int count = 0;
163       
164       name_max = pathconf(".", _PC_NAME_MAX);
165       if (name_max < 1024) {
166          name_max = 1024;
167       }
168          
169       if (!(dp = opendir(dev->device->mount_point))) {
170          berrno be;
171          dev->dev_errno = errno;
172          Dmsg3(29, "open_mounted_dev: failed to open dir %s (dev=%s), ERR=%s\n", 
173                dev->device->mount_point, dev->print_name(), be.strerror());
174          goto get_out;
175       }
176       
177       entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
178       while (1) {
179          if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
180             dev->dev_errno = EIO;
181             Dmsg2(129, "open_mounted_dev: failed to find suitable file in dir %s (dev=%s)\n", 
182                   dev->device->mount_point, dev->print_name());
183             break;
184          }
185          if ((strcmp(result->d_name, ".")) && (strcmp(result->d_name, "..")) && (strcmp(result->d_name, ".keep"))) {
186             count++; /* result->d_name != ., .. or .keep (Gentoo-specific) */
187          }
188          else {
189             Dmsg2(129, "open_mounted_dev: ignoring %s in %s\n", 
190                   result->d_name, dev->device->mount_point);
191          }
192       }
193       free(entry);
194       closedir(dp);
195       
196       Dmsg1(29, "open_mounted_dev: got %d files in the mount point (not counting ., .. and .keep)\n", count);
197       
198       if (count > 0) {
199          mount = 1;                      /* If we got more than ., .. and .keep */
200          break;                          /*   there must be something mounted */
201       }
202 get_out:
203       dev->set_mounted(false);
204       sm_check(__FILE__, __LINE__, false);
205       free_pool_memory(results);
206       Dmsg0(200, "============ DVD mount=0\n");
207       return false;
208    }
209    
210    dev->set_mounted(mount);              /* set/clear mounted flag */
211    free_pool_memory(results);
212    /* Do not check free space when unmounting */
213    if (mount) {
214       update_free_space_dev(dev);
215    }
216    Dmsg1(200, "============ DVD mount=%d\n", mount);
217    return true;
218 }
219
220 /* Update the free space on the device */
221 void update_free_space_dev(DEVICE* dev) 
222 {
223    POOL_MEM ocmd(PM_FNAME);
224    POOLMEM* results;
225    char* icmd;
226    int timeout;
227    long long int free;
228    char ed1[50];
229    
230    /* The device must be mounted in order to dvd-freespace to work */
231    mount_dev(dev, 1);
232    
233    sm_check(__FILE__, __LINE__, false);
234    icmd = dev->device->free_space_command;
235    
236    if (!icmd) {
237       dev->free_space = 0;
238       dev->free_space_errno = 0;
239       dev->clear_freespace_ok();   /* No valid freespace */
240       dev->clear_media();
241       Dmsg2(29, "update_free_space_dev: free_space=%s, free_space_errno=%d (!icmd)\n", 
242             edit_uint64(dev->free_space, ed1), dev->free_space_errno);
243       return;
244    }
245    
246    edit_device_codes_dev(dev, ocmd, icmd);
247    
248    Dmsg1(29, "update_free_space_dev: cmd=%s\n", ocmd.c_str());
249
250    results = get_pool_memory(PM_MESSAGE);
251    
252    /* Try at most 3 times to get the free space on the device. This should perhaps be configurable. */
253    timeout = 3;
254    
255    while (1) {
256       if (run_program_full_output(ocmd.c_str(), dev->max_open_wait/2, results) == 0) {
257          Dmsg1(100, "Free space program run : %s\n", results);
258          free = str_to_int64(results);
259          if (free >= 0) {
260             dev->free_space = free;
261             dev->free_space_errno = 0;
262             dev->set_freespace_ok();     /* have valid freespace */
263             dev->set_media();
264             Mmsg0(dev->errmsg, "");
265             break;
266          }
267       }
268       dev->free_space = 0;
269       dev->free_space_errno = EPIPE;
270       dev->clear_freespace_ok();         /* no valid freespace */
271       Mmsg1(dev->errmsg, _("Cannot run free space command (%s)\n"), results);
272       
273       if (--timeout > 0) {
274          Dmsg4(40, "Cannot get free space on device %s. free_space=%s, "
275             "free_space_errno=%d ERR=%s\n", dev->print_name(), 
276                edit_uint64(dev->free_space, ed1), dev->free_space_errno, 
277                dev->errmsg);
278          bmicrosleep(1, 0);
279          continue;
280       }
281
282       dev->dev_errno = dev->free_space_errno;
283       Dmsg4(40, "Cannot get free space on device %s. free_space=%s, "
284          "free_space_errno=%d ERR=%s\n",
285             dev->print_name(), edit_uint64(dev->free_space, ed1),
286             dev->free_space_errno, dev->errmsg);
287       break;
288    }
289    
290    free_pool_memory(results);
291    Dmsg4(29, "update_free_space_dev: free_space=%s freespace_ok=%d free_space_errno=%d have_media=%d\n", 
292       edit_uint64(dev->free_space, ed1), !!dev->is_freespace_ok(), dev->free_space_errno, !!dev->have_media());
293    sm_check(__FILE__, __LINE__, false);
294    return;
295 }
296
297 /*
298  * Write a part (Vol, Vol.1, ...) from the spool to the DVD   
299  * This routine does not update the part number, so normally, you
300  *  should call open_next_part()
301  * It is also called from truncate_dvd_dev to "blank" the medium, as
302  *  well as from block.c when the DVD is full to write the last part.
303  */
304 bool dvd_write_part(DCR *dcr) 
305 {
306    DEVICE *dev = dcr->dev;
307    POOL_MEM archive_name(PM_FNAME);
308    
309    /* Don't write empty part files.
310     * This is only useful when growisofs does not support write beyond
311     * the 4GB boundary.
312     * Example :
313     *   - 3.9 GB on the volume, dvd-freespace reports 0.4 GB free
314     *   - Write 0.2 GB on the volume, Bacula thinks it could still
315     *     append data, it creates a new empty part.
316     *   - dvd-freespace reports 0 GB free, as the 4GB boundary has
317     *     been crossed
318     *   - Bacula thinks he must finish to write to the device, so it
319     *     tries to write the last part (0-byte), but dvd-writepart fails...
320     *
321     * There is one exception: when recycling a volume, we write a blank part
322     * file, so, then, we need to accept to write it.
323     */
324    if ((dev->part_size == 0) && (dev->part > 0)) {
325       Dmsg2(29, "dvd_write_part: device is %s, won't write blank part %d\n", dev->print_name(), dev->part);
326       /* Delete spool file */
327       make_spooled_dvd_filename(dev, archive_name);
328       unlink(archive_name.c_str());
329       Dmsg1(29, "unlink(%s)\n", archive_name.c_str());
330       sm_check(__FILE__, __LINE__, false);
331       return true;
332    }
333    
334    POOL_MEM ocmd(PM_FNAME);
335    POOL_MEM results(PM_MESSAGE);
336    char* icmd;
337    int status;
338    int timeout;
339    char ed1[50];
340    
341    sm_check(__FILE__, __LINE__, false);
342    Dmsg3(29, "dvd_write_part: device is %s, part is %d, is_mounted=%d\n", dev->print_name(), dev->part, dev->is_mounted());
343    icmd = dev->device->write_part_command;
344    
345    edit_device_codes_dev(dev, ocmd, icmd);
346       
347    /*
348     * original line follows
349     * timeout = dev->max_open_wait + (dev->max_part_size/(1350*1024/2));
350     * I modified this for a longer timeout; pre-formatting, blanking and
351     * writing can take quite a while
352     *
353     * NB: Use part_size and not max_part_size, needed when you don't set max part size (so it defaults to 0)
354     */
355    timeout = dev->max_open_wait + (dev->part_size/(1350*1024)*8);
356
357    Dmsg2(29, "dvd_write_part: cmd=%s timeout=%d\n", ocmd.c_str(), timeout);
358       
359    status = run_program_full_output(ocmd.c_str(), timeout, results.c_str());
360    if (status != 0) {
361       Mmsg1(dev->errmsg, _("Error while writing current part to the DVD: %s"), 
362             results.c_str());
363       Dmsg1(000, "%s", dev->errmsg);
364       dev->dev_errno = EIO;
365       mark_volume_in_error(dcr);
366       sm_check(__FILE__, __LINE__, false);
367       return false;
368    } else {
369       dev->num_parts++;            /* there is now one more part on DVD */
370    }
371
372    /* Delete spool file */
373    make_spooled_dvd_filename(dev, archive_name);
374    unlink(archive_name.c_str());
375    Dmsg1(29, "unlink(%s)\n", archive_name.c_str());
376    sm_check(__FILE__, __LINE__, false);
377    
378    /* growisofs umounted the device, so remount it (it will update the free space) */
379    dev->clear_mounted();
380    mount_dev(dev, 1);
381    Jmsg(dcr->jcr, M_INFO, 0, _("Remaining free space %s on %s\n"), 
382       edit_uint64_with_commas(dev->free_space, ed1), dev->print_name());
383    sm_check(__FILE__, __LINE__, false);
384    return true;
385 }
386
387 /* Open the next part file.
388  *  - Close the fd
389  *  - Increment part number 
390  *  - Reopen the device
391  */
392 int dvd_open_next_part(DCR *dcr)
393 {
394    DEVICE *dev = dcr->dev;
395
396    Dmsg6(29, "Enter: ==== open_next_part part=%d npart=%d dev=%s vol=%s mode=%d file_addr=%d\n", 
397       dev->part, dev->num_parts, dev->print_name(),
398          dev->VolCatInfo.VolCatName, dev->openmode, dev->file_addr);
399    if (!dev->is_dvd()) {
400       Dmsg1(000, "Device %s is not dvd!!!!\n", dev->print_name()); 
401       return -1;
402    }
403    
404    /* When appending, do not open a new part if the current is empty */
405    if (dev->can_append() && (dev->part >= dev->num_parts) && 
406        (dev->part_size == 0)) {
407       Dmsg0(29, "open_next_part exited immediately (dev->part_size == 0).\n");
408       return dev->fd;
409    }
410    
411    if (dev->fd >= 0) {
412       close(dev->fd);
413    }
414    
415    dev->fd = -1;
416    dev->clear_opened();
417    
418    /*
419     * If we have a part open for write, then write it to
420     *  DVD before opening the next part.
421     */
422    if (dev->is_dvd() && (dev->part >= dev->num_parts) && dev->can_append()) {
423       if (!dvd_write_part(dcr)) {
424          Dmsg0(29, "Error in dvd_write part.\n");
425          return -1;
426       }
427    }
428      
429    if (dev->part > dev->num_parts) {
430       Dmsg2(000, "In open_next_part: part=%d nump=%d\n", dev->part, dev->num_parts);
431       ASSERT(dev->part <= dev->num_parts);
432    }
433    dev->part_start += dev->part_size;
434    dev->part++;
435    
436    Dmsg2(29, "part=%d num_parts=%d\n", dev->part, dev->num_parts);
437    /* I think this dev->can_append() should not be there */
438    if ((dev->num_parts < dev->part) && dev->can_append()) {
439       POOL_MEM archive_name(PM_FNAME);
440       struct stat buf;
441       /* 
442        * First check what is on DVD.  If our part is there, we
443        *   are in trouble, so bail out.
444        * NB: This is however not a problem if we are writing the first part.
445        * It simply means that we are overriding an existing volume...
446        */
447       if (dev->num_parts > 0) {
448          make_mounted_dvd_filename(dev, archive_name);   /* makes dvd name */
449          if (stat(archive_name.c_str(), &buf) == 0) {
450             /* bad news bail out */
451             Mmsg1(&dev->errmsg, _("Next Volume part already exists on DVD. Cannot continue: %s\n"),
452                archive_name.c_str());
453             return -1;
454          }
455       }
456
457       Dmsg2(100, "num_parts=%d part=%d\n", dev->num_parts, dev->part);
458       dev->VolCatInfo.VolCatParts = dev->part;
459       make_spooled_dvd_filename(dev, archive_name);   /* makes spool name */
460       
461       /* Check if the next part exists in spool directory . */
462       if ((stat(archive_name.c_str(), &buf) == 0) || (errno != ENOENT)) {
463          Dmsg1(29, "open_next_part %s is in the way, moving it away...\n", archive_name.c_str());
464          /* Then try to unlink it */
465          if (unlink(archive_name.c_str()) < 0) {
466             berrno be;
467             dev->dev_errno = errno;
468             Mmsg2(dev->errmsg, _("open_next_part can't unlink existing part %s, ERR=%s\n"), 
469                    archive_name.c_str(), be.strerror());
470             return -1;
471          }
472       }
473    }
474    /* KES.  It seems to me that this if should not be
475     *  needed. If num_parts represents what is on the DVD
476     *  we should only need to change it when writing a part
477     *  to the DVD.
478     */
479    if (dev->num_parts < dev->part) {
480       Dmsg2(100, "Set npart=%d to part=%d\n", dev->num_parts, dev->part);
481       dev->num_parts = dev->part;
482       dev->VolCatInfo.VolCatParts = dev->part;
483    }
484    Dmsg2(50, "Call dev->open(vol=%s, mode=%d\n", dev->VolCatInfo.VolCatName, 
485          dev->openmode);
486    /* Open next part */
487    
488    int append = dev->can_append();
489    if (dev->open(dcr, dev->openmode) < 0) {
490       return -1;
491    } 
492    dev->set_labeled();          /* all next parts are "labeled" */
493    if (append && (dev->part == dev->num_parts)) { /* If needed, set the append flag back */
494       dev->set_append();
495    }
496    
497    return dev->fd;
498 }
499
500 /* Open the first part file.
501  *  - Close the fd
502  *  - Reopen the device
503  */
504 int dvd_open_first_part(DCR *dcr, int mode)
505 {
506    DEVICE *dev = dcr->dev;
507
508    Dmsg5(29, "Enter: ==== open_first_part dev=%s Vol=%s mode=%d num_parts=%d append=%d\n", dev->print_name(), 
509          dev->VolCatInfo.VolCatName, dev->openmode, dev->num_parts, dev->can_append());
510
511    if (dev->fd >= 0) {
512       close(dev->fd);
513    }
514    dev->fd = -1;
515    dev->clear_opened();
516    
517    dev->part_start = 0;
518    dev->part = 0;
519    
520    Dmsg2(50, "Call dev->open(vol=%s, mode=%d)\n", dcr->VolCatInfo.VolCatName, 
521          mode);
522    int append = dev->can_append();
523    if (dev->open(dcr, mode) < 0) {
524       Dmsg0(50, "open dev() failed\n");
525       return -1;
526    }
527    if (append && (dev->part == dev->num_parts)) { /* If needed, set the append flag back */
528       dev->set_append();
529    }
530    Dmsg2(50, "Leave open_first_part state=%s append=%d\n", dev->is_open()?"open":"not open", dev->can_append());
531    
532    return dev->fd;
533 }
534
535
536 /* Protected version of lseek, which opens the right part if necessary */
537 off_t lseek_dev(DEVICE *dev, off_t offset, int whence)
538 {
539    DCR *dcr;
540    off_t pos;
541    char ed1[50], ed2[50];
542    
543    Dmsg3(100, "Enter lseek_dev fd=%d part=%d nparts=%d\n", dev->fd,
544       dev->part, dev->num_parts);
545    if (!dev->is_dvd()) { 
546       Dmsg0(100, "Using sys lseek\n");
547       return lseek(dev->fd, offset, whence);
548    }
549       
550    dcr = (DCR *)dev->attached_dcrs->first();  /* any dcr will do */
551    switch(whence) {
552    case SEEK_SET:
553       Dmsg2(100, "lseek_dev SEEK_SET to %s (part_start=%s)\n",
554          edit_uint64(offset, ed1), edit_uint64(dev->part_start, ed2));
555       if ((uint64_t)offset >= dev->part_start) {
556          if (((uint64_t)offset == dev->part_start) || ((uint64_t)offset < (dev->part_start+dev->part_size))) {
557             /* We are staying in the current part, just seek */
558             if ((pos = lseek(dev->fd, offset-dev->part_start, SEEK_SET)) < 0) {
559                return pos;
560             } else {
561                return pos + dev->part_start;
562             }
563          } else {
564             /* Load next part, and start again */
565             if (dvd_open_next_part(dcr) < 0) {
566                Dmsg0(100, "lseek_dev failed while trying to open the next part\n");
567                return -1;
568             }
569             return lseek_dev(dev, offset, SEEK_SET);
570          }
571       } else {
572          /*
573           * pos < dev->part_start :
574           * We need to access a previous part, 
575           * so just load the first one, and seek again
576           * until the right one is loaded
577           */
578          if (dvd_open_first_part(dcr, dev->openmode) < 0) {
579             Dmsg0(100, "lseek_dev failed while trying to open the first part\n");
580             return -1;
581          }
582          return lseek_dev(dev, offset, SEEK_SET);
583       }
584       break;
585    case SEEK_CUR:
586       Dmsg1(100, "lseek_dev SEEK_CUR to %s\n", edit_uint64(offset, ed1));
587       if ((pos = lseek(dev->fd, (off_t)0, SEEK_CUR)) < 0) {
588          return pos;   
589       }
590       pos += dev->part_start;
591       if (offset == 0) {
592          Dmsg1(100, "lseek_dev SEEK_CUR returns %s\n", edit_uint64(pos, ed1));
593          return pos;
594       } else { /* Not used in Bacula, but should work */
595          return lseek_dev(dev, pos, SEEK_SET);
596       }
597       break;
598    case SEEK_END:
599       Dmsg1(100, "lseek_dev SEEK_END to %s\n", edit_uint64(offset, ed1));
600       /*
601        * Bacula does not use offsets for SEEK_END
602        *  Also, Bacula uses seek_end only when it wants to
603        *  append to the volume, so for a dvd that means
604        *  that the volume must be spooled since the DVD
605        *  itself is read-only (as currently implemented).
606        */
607       if (offset > 0) { /* Not used by bacula */
608          Dmsg1(100, "lseek_dev SEEK_END called with an invalid offset %s\n", 
609             edit_uint64(offset, ed1));
610          errno = EINVAL;
611          return -1;
612       }
613       /* If we are already on a spooled part and have the
614        *  right part number, simply seek
615        */
616       if (dev->is_part_spooled() && dev->part == dev->num_parts) {
617          if ((pos = lseek(dev->fd, (off_t)0, SEEK_END)) < 0) {
618             return pos;   
619          } else {
620             Dmsg1(100, "lseek_dev SEEK_END returns %s\n", 
621                   edit_uint64(pos + dev->part_start, ed1));
622             return pos + dev->part_start;
623          }
624       } else {
625          /*
626           * Load the first part, then load the next until we reach the last one.
627           * This is the only way to be sure we compute the right file address.
628           *
629           * Save previous openmode, and open all but last part read-only 
630           * (useful for DVDs) 
631           */
632          int modesave = dev->openmode;
633          /* Works because num_parts > 0. */
634          if (dvd_open_first_part(dcr, OPEN_READ_ONLY) < 0) {
635             Dmsg0(100, "lseek_dev failed while trying to open the first part\n");
636             return -1;
637          }
638          if (dev->num_parts > 0) {
639             while (dev->part < (dev->num_parts-1)) {
640                if (dvd_open_next_part(dcr) < 0) {
641                   Dmsg0(100, "lseek_dev failed while trying to open the next part\n");
642                   return -1;
643                }
644             }
645             dev->openmode = modesave;
646             if (dvd_open_next_part(dcr) < 0) {
647                Dmsg0(100, "lseek_dev failed while trying to open the next part\n");
648                return -1;
649             }
650          }
651          return lseek_dev(dev, 0, SEEK_END);
652       }
653       break;
654    default:
655       errno = EINVAL;
656       return -1;
657    }
658 }
659
660 bool dvd_close_job(DCR *dcr)
661 {
662    DEVICE *dev = dcr->dev;
663    JCR *jcr = dcr->jcr;
664    bool ok = true;
665
666    /* If the device is a dvd and WritePartAfterJob
667     * is set to yes, open the next part, so, in case of a device
668     * that requires mount, it will be written to the device.
669     */
670    if (dev->is_dvd() && jcr->write_part_after_job && (dev->part_size > 0)) {
671       Dmsg1(100, "Writing last part=%d write_partafter_job is set.\n",
672          dev->part);
673       if (dev->part < dev->num_parts) {
674          Jmsg3(jcr, M_FATAL, 0, _("Error while writing, current part number is less than the total number of parts (%d/%d, device=%s)\n"),
675                dev->part, dev->num_parts, dev->print_name());
676          dev->dev_errno = EIO;
677          ok = false;
678       }
679       
680       /* This should be !dvd_write_part(dcr)
681          NB: No! If you call dvd_write_part, the part number is not updated.
682          You must open the next part, it will automatically write the part and
683          update the part number. */
684       if (ok && (dvd_open_next_part(dcr) < 0)) {
685          Jmsg2(jcr, M_FATAL, 0, _("Unable to write part %s: ERR=%s\n"),
686                dev->print_name(), strerror_dev(dev));
687          dev->dev_errno = EIO;
688          ok = false;
689       }
690    }
691    Dmsg1(200, "Set VolCatParts=%d\n", dev->num_parts);
692    dev->VolCatInfo.VolCatParts = dev->num_parts;
693    return ok;
694 }
695
696 bool truncate_dvd_dev(DCR *dcr) {
697    DEVICE* dev = dcr->dev;
698
699    /* Set num_parts to zero (on disk) */
700    dev->num_parts = 0;
701    dcr->VolCatInfo.VolCatParts = 0;
702    dev->VolCatInfo.VolCatParts = 0;
703    
704    Dmsg0(100, "truncate_dvd_dev: Opening first part (1)...\n");
705    
706    dev->truncating = true;
707    if (dvd_open_first_part(dcr, OPEN_READ_WRITE) < 0) {
708       Dmsg0(100, "truncate_dvd_dev: Error while opening first part (1).\n");
709       dev->truncating = false;
710       return false;
711    }
712    dev->truncating = false;
713
714    Dmsg0(100, "truncate_dvd_dev: Truncating...\n");
715
716    /* If necessary, truncate it. */
717    if (ftruncate(dev->fd, 0) != 0) {
718       berrno be;
719       Mmsg2(dev->errmsg, _("Unable to truncate device %s. ERR=%s\n"), 
720          dev->print_name(), be.strerror());
721       return false;
722    }
723    
724    close(dev->fd);
725    dev->fd = -1;
726    dev->clear_opened();
727    
728    Dmsg0(100, "truncate_dvd_dev: Opening first part (2)...\n");
729    
730    if (!dvd_write_part(dcr)) {
731       Dmsg0(100, "truncate_dvd_dev: Error while writing to DVD.\n");
732       return false;
733    }
734    
735    /* Set num_parts to zero (on disk) */
736    dev->num_parts = 0;
737    dcr->VolCatInfo.VolCatParts = 0;
738    dev->VolCatInfo.VolCatParts = 0;
739    
740    if (dvd_open_first_part(dcr, OPEN_READ_WRITE) < 0) {
741       Dmsg0(100, "truncate_dvd_dev: Error while opening first part (2).\n");
742       return false;
743    }
744
745    return true;
746 }
747
748 /* Checks if we can write on a non-blank DVD: meaning that it just have been
749  * truncated (there is only one zero-sized file on the DVD, with the right
750  * volume name). */
751 bool check_can_write_on_non_blank_dvd(DCR *dcr) {
752    DEVICE* dev = dcr->dev;
753    DIR* dp;
754    struct dirent *entry, *result;
755    int name_max;
756    int count = 0;
757    int matched = 0; /* We found an empty file with the right name. */
758    struct stat filestat;
759       
760    name_max = pathconf(".", _PC_NAME_MAX);
761    if (name_max < 1024) {
762       name_max = 1024;
763    }
764    
765    if (!(dp = opendir(dev->device->mount_point))) {
766       berrno be;
767       dev->dev_errno = errno;
768       Dmsg3(29, "check_can_write_on_non_blank_dvd: failed to open dir %s (dev=%s), ERR=%s\n", 
769             dev->device->mount_point, dev->print_name(), be.strerror());
770       return false;
771    }
772    
773    entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
774    while (1) {
775       if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
776          dev->dev_errno = EIO;
777          Dmsg2(129, "check_can_write_on_non_blank_dvd: failed to find suitable file in dir %s (dev=%s)\n", 
778                dev->device->mount_point, dev->print_name());
779          break;
780       }
781       else {
782          Dmsg2(99, "check_can_write_on_non_blank_dvd: found %s (versus %s)\n", 
783                result->d_name, dev->VolCatInfo.VolCatName);
784          if (strcmp(result->d_name, dev->VolCatInfo.VolCatName) == 0) {
785             /* Found the file, checking it is empty */
786             POOL_MEM filename(PM_FNAME);
787             pm_strcpy(filename, dev->device->mount_point);
788             if (filename.c_str()[strlen(filename.c_str())-1] != '/') {
789                pm_strcat(filename, "/");
790             }
791             pm_strcat(filename, dev->VolCatInfo.VolCatName);
792             if (stat(filename.c_str(), &filestat) < 0) {
793                berrno be;
794                dev->dev_errno = errno;
795                Dmsg2(29, "check_can_write_on_non_blank_dvd: cannot stat file (file=%s), ERR=%s\n", 
796                   filename.c_str(), be.strerror());
797                return false;
798             }
799             Dmsg2(99, "check_can_write_on_non_blank_dvd: size of %s is %d\n", 
800                filename.c_str(), filestat.st_size);
801             matched = (filestat.st_size == 0);
802          }
803       }
804       count++;
805    }
806    free(entry);
807    closedir(dp);
808    
809    Dmsg2(29, "check_can_write_on_non_blank_dvd: got %d files in the mount point (matched=%d)\n", count, matched);
810    
811    if (count != 3) {
812       /* There is more than 3 files (., .., and the volume file) */
813       return false;
814    }
815    
816    return matched;
817 }
818
819 /*
820  * Edit codes into (Un)MountCommand, Write(First)PartCommand
821  *  %% = %
822  *  %a = archive device name
823  *  %e = erase (set if cannot mount and first part)
824  *  %n = part number
825  *  %m = mount point
826  *  %v = last part name
827  *
828  *  omsg = edited output message
829  *  imsg = input string containing edit codes (%x)
830  *
831  */
832 static void edit_device_codes_dev(DEVICE* dev, POOL_MEM &omsg, const char *imsg)
833 {
834    const char *p;
835    const char *str;
836    char add[20];
837    
838    POOL_MEM archive_name(PM_FNAME);
839
840    omsg.c_str()[0] = 0;
841    Dmsg1(800, "edit_device_codes: %s\n", imsg);
842    for (p=imsg; *p; p++) {
843       if (*p == '%') {
844          switch (*++p) {
845          case '%':
846             str = "%";
847             break;
848          case 'a':
849             str = dev->dev_name;
850             break;
851          case 'e':
852             if (dev->num_parts == 0) {
853                str = "1";
854             } else {
855                str = "0";
856             }
857             break;
858          case 'n':
859             bsnprintf(add, sizeof(add), "%d", dev->part);
860             str = add;
861             break;
862          case 'm':
863             str = dev->device->mount_point;
864             break;
865          case 'v':
866             make_spooled_dvd_filename(dev, archive_name);
867             str = archive_name.c_str();
868             break;
869          default:
870             add[0] = '%';
871             add[1] = *p;
872             add[2] = 0;
873             str = add;
874             break;
875          }
876       } else {
877          add[0] = *p;
878          add[1] = 0;
879          str = add;
880       }
881       Dmsg1(1900, "add_str %s\n", str);
882       pm_strcat(omsg, (char *)str);
883       Dmsg1(1800, "omsg=%s\n", omsg.c_str());
884    }
885 }