]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/dvd.c
dfd20b751a08f78fcb56f5ad8ff11270b4376ec5
[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 (otherwise it will mount it again) */
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 ocmd(PM_FNAME);
308    POOL_MEM results(PM_MESSAGE);
309    POOL_MEM archive_name(PM_FNAME);
310    char* icmd;
311    int status;
312    int timeout;
313    char ed1[50];
314    
315    sm_check(__FILE__, __LINE__, false);
316    Dmsg3(29, "dvd_write_part: device is %s, part is %d, is_mounted=%d\n", dev->print_name(), dev->part, dev->is_mounted());
317    icmd = dev->device->write_part_command;
318    
319    edit_device_codes_dev(dev, ocmd, icmd);
320       
321    /*
322     * original line follows
323     * timeout = dev->max_open_wait + (dev->max_part_size/(1350*1024/2));
324     * I modified this for a longer timeout; pre-formatting, blanking and
325     * writing can take quite a while
326     *
327     * NB: Use part_size and not max_part_size, needed when you don't set max part size (so it defaults to 0)
328     */
329    timeout = dev->max_open_wait + (dev->part_size/(1350*1024)*8);
330
331    Dmsg2(29, "dvd_write_part: cmd=%s timeout=%d\n", ocmd.c_str(), timeout);
332       
333    status = run_program_full_output(ocmd.c_str(), timeout, results.c_str());
334    if (status != 0) {
335       Mmsg1(dev->errmsg, _("Error while writing current part to the DVD: %s"), 
336             results.c_str());
337       Dmsg1(000, "%s", dev->errmsg);
338       dev->dev_errno = EIO;
339       mark_volume_in_error(dcr);
340       sm_check(__FILE__, __LINE__, false);
341       return false;
342    } else {
343       dev->num_parts++;            /* there is no one more part on DVD */
344    }
345
346    /* Delete spool file */
347    make_spooled_dvd_filename(dev, archive_name);
348    unlink(archive_name.c_str());
349    Dmsg1(29, "unlink(%s)\n", archive_name.c_str());
350    sm_check(__FILE__, __LINE__, false);
351    
352    /* growisofs umounted the device, so remount it (it will update the free space) */
353    dev->clear_mounted();
354    mount_dev(dev, 1);
355    Jmsg(dcr->jcr, M_INFO, 0, _("Remaining free space %s on %s\n"), 
356       edit_uint64_with_commas(dev->free_space, ed1), dev->print_name());
357    sm_check(__FILE__, __LINE__, false);
358    return true;
359 }
360
361 /* Open the next part file.
362  *  - Close the fd
363  *  - Increment part number 
364  *  - Reopen the device
365  */
366 int dvd_open_next_part(DCR *dcr)
367 {
368    DEVICE *dev = dcr->dev;
369
370    Dmsg6(29, "Enter: ==== open_next_part part=%d npart=%d dev=%s vol=%s mode=%d file_addr=%d\n", 
371       dev->part, dev->num_parts, dev->print_name(),
372          dev->VolCatInfo.VolCatName, dev->openmode, dev->file_addr);
373    if (!dev->is_dvd()) {
374       Dmsg1(000, "Device %s is not dvd!!!!\n", dev->print_name()); 
375       return -1;
376    }
377    
378    /* When appending, do not open a new part if the current is empty */
379    if (dev->can_append() && (dev->part >= dev->num_parts) && 
380        (dev->part_size == 0)) {
381       Dmsg0(29, "open_next_part exited immediately (dev->part_size == 0).\n");
382       return dev->fd;
383    }
384    
385    if (dev->fd >= 0) {
386       close(dev->fd);
387    }
388    
389    dev->fd = -1;
390    dev->clear_opened();
391    
392    /*
393     * If we have a part open for write, then write it to
394     *  DVD before opening the next part.
395     */
396    if (dev->is_dvd() && (dev->part >= dev->num_parts) && dev->can_append()) {
397       if (!dvd_write_part(dcr)) {
398          Dmsg0(29, "Error in dvd_write part.\n");
399          return -1;
400       }
401    }
402      
403    if (dev->part > dev->num_parts) {
404       Dmsg2(000, "In open_next_part: part=%d nump=%d\n", dev->part, dev->num_parts);
405       ASSERT(dev->part <= dev->num_parts);
406    }
407    dev->part_start += dev->part_size;
408    dev->part++;
409    
410    Dmsg2(29, "part=%d num_parts=%d\n", dev->part, dev->num_parts);
411    /* I think this dev->can_append() should not be there */
412    if ((dev->num_parts < dev->part) && dev->can_append()) {
413       POOL_MEM archive_name(PM_FNAME);
414       struct stat buf;
415       /* 
416        * First check what is on DVD.  If our part is there, we
417        *   are in trouble, so bail out.
418        * NB: This is however not a problem if we are writing the first part.
419        * It simply means that we are overriding an existing volume...
420        */
421       if (dev->num_parts > 0) {
422          make_mounted_dvd_filename(dev, archive_name);   /* makes dvd name */
423          if (stat(archive_name.c_str(), &buf) == 0) {
424             /* bad news bail out */
425             Mmsg1(&dev->errmsg, _("Next Volume part already exists on DVD. Cannot continue: %s\n"),
426                archive_name.c_str());
427             return -1;
428          }
429       }
430
431       Dmsg2(100, "num_parts=%d part=%d\n", dev->num_parts, dev->part);
432       dev->VolCatInfo.VolCatParts = dev->part;
433       make_spooled_dvd_filename(dev, archive_name);   /* makes spool name */
434       
435       /* Check if the next part exists in spool directory . */
436       if ((stat(archive_name.c_str(), &buf) == 0) || (errno != ENOENT)) {
437          Dmsg1(29, "open_next_part %s is in the way, moving it away...\n", archive_name.c_str());
438          /* Then try to unlink it */
439          if (unlink(archive_name.c_str()) < 0) {
440             berrno be;
441             dev->dev_errno = errno;
442             Mmsg2(dev->errmsg, _("open_next_part can't unlink existing part %s, ERR=%s\n"), 
443                    archive_name.c_str(), be.strerror());
444             return -1;
445          }
446       }
447    }
448    /* KES.  It seems to me that this if should not be
449     *  needed. If num_parts represents what is on the DVD
450     *  we should only need to change it when writing a part
451     *  to the DVD.
452     */
453    if (dev->num_parts < dev->part) {
454       Dmsg2(100, "Set npart=%d to part=%d\n", dev->num_parts, dev->part);
455       dev->num_parts = dev->part;
456       dev->VolCatInfo.VolCatParts = dev->part;
457    }
458    Dmsg2(50, "Call dev->open(vol=%s, mode=%d\n", dev->VolCatInfo.VolCatName, 
459          dev->openmode);
460    /* Open next part */
461    
462    int append = dev->can_append();
463    if (dev->open(dcr, dev->openmode) < 0) {
464       return -1;
465    } 
466    dev->set_labeled();          /* all next parts are "labeled" */
467    if (append && (dev->part == dev->num_parts)) { /* If needed, set the append flag back */
468       dev->set_append();
469    }
470    
471    return dev->fd;
472 }
473
474 /* Open the first part file.
475  *  - Close the fd
476  *  - Reopen the device
477  */
478 int dvd_open_first_part(DCR *dcr, int mode)
479 {
480    DEVICE *dev = dcr->dev;
481
482    Dmsg4(29, "Enter: ==== open_first_part dev=%s Vol=%s mode=%d num_parts=%d\n", dev->print_name(), 
483          dev->VolCatInfo.VolCatName, dev->openmode, dev->num_parts);
484
485    if (dev->fd >= 0) {
486       close(dev->fd);
487    }
488    dev->fd = -1;
489    dev->clear_opened();
490    
491    dev->part_start = 0;
492    dev->part = 0;
493    
494    Dmsg2(50, "Call dev->open(vol=%s, mode=%d)\n", dcr->VolCatInfo.VolCatName, 
495          mode);
496    if (dev->open(dcr, mode) < 0) {
497       Dmsg0(50, "open dev() failed\n");
498       return -1;
499    }
500    Dmsg1(50, "Leave open_first_part state=%s\n", dev->is_open()?"open":"not open");
501    return dev->fd;
502 }
503
504
505 /* Protected version of lseek, which opens the right part if necessary */
506 off_t lseek_dev(DEVICE *dev, off_t offset, int whence)
507 {
508    DCR *dcr;
509    off_t pos;
510    char ed1[50], ed2[50];
511    
512    Dmsg3(100, "Enter lseek_dev fd=%d part=%d nparts=%d\n", dev->fd,
513       dev->part, dev->num_parts);
514    if (!dev->is_dvd()) { 
515       Dmsg0(100, "Using sys lseek\n");
516       return lseek(dev->fd, offset, whence);
517    }
518       
519    dcr = (DCR *)dev->attached_dcrs->first();  /* any dcr will do */
520    switch(whence) {
521    case SEEK_SET:
522       Dmsg2(100, "lseek_dev SEEK_SET to %s (part_start=%s)\n",
523          edit_uint64(offset, ed1), edit_uint64(dev->part_start, ed2));
524       if ((uint64_t)offset >= dev->part_start) {
525          if (((uint64_t)offset == dev->part_start) || ((uint64_t)offset < (dev->part_start+dev->part_size))) {
526             /* We are staying in the current part, just seek */
527             if ((pos = lseek(dev->fd, offset-dev->part_start, SEEK_SET)) < 0) {
528                return pos;
529             } else {
530                return pos + dev->part_start;
531             }
532          } else {
533             /* Load next part, and start again */
534             if (dvd_open_next_part(dcr) < 0) {
535                Dmsg0(100, "lseek_dev failed while trying to open the next part\n");
536                return -1;
537             }
538             return lseek_dev(dev, offset, SEEK_SET);
539          }
540       } else {
541          /*
542           * pos < dev->part_start :
543           * We need to access a previous part, 
544           * so just load the first one, and seek again
545           * until the right one is loaded
546           */
547          if (dvd_open_first_part(dcr, dev->openmode) < 0) {
548             Dmsg0(100, "lseek_dev failed while trying to open the first part\n");
549             return -1;
550          }
551          return lseek_dev(dev, offset, SEEK_SET);
552       }
553       break;
554    case SEEK_CUR:
555       Dmsg1(100, "lseek_dev SEEK_CUR to %s\n", edit_uint64(offset, ed1));
556       if ((pos = lseek(dev->fd, (off_t)0, SEEK_CUR)) < 0) {
557          return pos;   
558       }
559       pos += dev->part_start;
560       if (offset == 0) {
561          Dmsg1(100, "lseek_dev SEEK_CUR returns %s\n", edit_uint64(pos, ed1));
562          return pos;
563       } else { /* Not used in Bacula, but should work */
564          return lseek_dev(dev, pos, SEEK_SET);
565       }
566       break;
567    case SEEK_END:
568       Dmsg1(100, "lseek_dev SEEK_END to %s\n", edit_uint64(offset, ed1));
569       /*
570        * Bacula does not use offsets for SEEK_END
571        *  Also, Bacula uses seek_end only when it wants to
572        *  append to the volume, so for a dvd that means
573        *  that the volume must be spooled since the DVD
574        *  itself is read-only (as currently implemented).
575        */
576       if (offset > 0) { /* Not used by bacula */
577          Dmsg1(100, "lseek_dev SEEK_END called with an invalid offset %s\n", 
578             edit_uint64(offset, ed1));
579          errno = EINVAL;
580          return -1;
581       }
582       /* If we are already on a spooled part and have the
583        *  right part number, simply seek
584        */
585       if (dev->is_part_spooled() && dev->part == dev->num_parts) {
586          if ((pos = lseek(dev->fd, (off_t)0, SEEK_END)) < 0) {
587             return pos;   
588          } else {
589             Dmsg1(100, "lseek_dev SEEK_END returns %s\n", 
590                   edit_uint64(pos + dev->part_start, ed1));
591             return pos + dev->part_start;
592          }
593       } else {
594          /*
595           * Load the first part, then load the next until we reach the last one.
596           * This is the only way to be sure we compute the right file address.
597           *
598           * Save previous openmode, and open all but last part read-only 
599           * (useful for DVDs) 
600           */
601          int modesave = dev->openmode;
602          /* Works because num_parts > 0. */
603          if (dvd_open_first_part(dcr, OPEN_READ_ONLY) < 0) {
604             Dmsg0(100, "lseek_dev failed while trying to open the first part\n");
605             return -1;
606          }
607          if (dev->num_parts > 0) {
608             while (dev->part < (dev->num_parts-1)) {
609                if (dvd_open_next_part(dcr) < 0) {
610                   Dmsg0(100, "lseek_dev failed while trying to open the next part\n");
611                   return -1;
612                }
613             }
614             dev->openmode = modesave;
615             if (dvd_open_next_part(dcr) < 0) {
616                Dmsg0(100, "lseek_dev failed while trying to open the next part\n");
617                return -1;
618             }
619          }
620          return lseek_dev(dev, 0, SEEK_END);
621       }
622       break;
623    default:
624       errno = EINVAL;
625       return -1;
626    }
627 }
628
629 bool dvd_close_job(DCR *dcr)
630 {
631    DEVICE *dev = dcr->dev;
632    JCR *jcr = dcr->jcr;
633    bool ok = true;
634
635    /* If the device is a dvd and WritePartAfterJob
636     * is set to yes, open the next part, so, in case of a device
637     * that requires mount, it will be written to the device.
638     */
639    if (dev->is_dvd() && jcr->write_part_after_job && (dev->part_size > 0)) {
640       Dmsg1(100, "Writing last part=%d write_partafter_job is set.\n",
641          dev->part);
642       if (dev->part < dev->num_parts) {
643          Jmsg3(jcr, M_FATAL, 0, _("Error while writing, current part number is less than the total number of parts (%d/%d, device=%s)\n"),
644                dev->part, dev->num_parts, dev->print_name());
645          dev->dev_errno = EIO;
646          ok = false;
647       }
648       
649       /* This should be !dvd_write_part(dcr)
650          NB: No! If you call dvd_write_part, the part number is not updated.
651          You must open the next part, it will automatically write the part and
652          update the part number. */
653       if (ok && (dvd_open_next_part(dcr) < 0)) {
654          Jmsg2(jcr, M_FATAL, 0, _("Unable to write part %s: ERR=%s\n"),
655                dev->print_name(), strerror_dev(dev));
656          dev->dev_errno = EIO;
657          ok = false;
658       }
659    }
660    Dmsg1(200, "Set VolCatParts=%d\n", dev->num_parts);
661    dev->VolCatInfo.VolCatParts = dev->num_parts;
662    return ok;
663 }
664
665 bool truncate_dvd_dev(DCR *dcr) {
666    DEVICE* dev = dcr->dev;
667
668    /* Set num_parts to zero (on disk) */
669    dev->num_parts = 0;
670    dcr->VolCatInfo.VolCatParts = 0;
671    dev->VolCatInfo.VolCatParts = 0;
672    
673    Dmsg0(100, "truncate_dvd_dev: Opening first part (1)...\n");
674    
675    dev->truncating = true;
676    if (dvd_open_first_part(dcr, OPEN_READ_WRITE) < 0) {
677       Dmsg0(100, "truncate_dvd_dev: Error while opening first part (1).\n");
678       dev->truncating = false;
679       return false;
680    }
681    dev->truncating = false;
682
683    Dmsg0(100, "truncate_dvd_dev: Truncating...\n");
684
685    /* If necessary, truncate it. */
686    if (ftruncate(dev->fd, 0) != 0) {
687       berrno be;
688       Mmsg2(dev->errmsg, _("Unable to truncate device %s. ERR=%s\n"), 
689          dev->print_name(), be.strerror());
690       return false;
691    }
692    
693    close(dev->fd);
694    dev->fd = -1;
695    dev->clear_opened();
696    
697    Dmsg0(100, "truncate_dvd_dev: Opening first part (2)...\n");
698    
699    if (!dvd_write_part(dcr)) {
700       Dmsg0(100, "truncate_dvd_dev: Error while writing to DVD.\n");
701       return false;
702    }
703    
704    if (dvd_open_first_part(dcr, OPEN_READ_WRITE) < 0) {
705       Dmsg0(100, "truncate_dvd_dev: Error while opening first part (2).\n");
706       return false;
707    }
708
709    return true;
710 }
711
712 /* Checks if we can write on a non-blank DVD: meaning that it just have been
713  * truncated (there is only one zero-sized file on the DVD, with the right
714  * volume name). */
715 bool check_can_write_on_non_blank_dvd(DCR *dcr) {
716    DEVICE* dev = dcr->dev;
717    DIR* dp;
718    struct dirent *entry, *result;
719    int name_max;
720    int count = 0;
721    int matched = 0; /* We found an empty file with the right name. */
722    struct stat filestat;
723       
724    name_max = pathconf(".", _PC_NAME_MAX);
725    if (name_max < 1024) {
726       name_max = 1024;
727    }
728          
729    if (!(dp = opendir(dev->device->mount_point))) {
730       berrno be;
731       dev->dev_errno = errno;
732       Dmsg3(29, "check_can_write_on_non_blank_dvd: failed to open dir %s (dev=%s), ERR=%s\n", 
733             dev->device->mount_point, dev->print_name(), be.strerror());
734       return false;
735    }
736    
737    entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
738    while (1) {
739       if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
740          dev->dev_errno = EIO;
741          Dmsg2(129, "check_can_write_on_non_blank_dvd: failed to find suitable file in dir %s (dev=%s)\n", 
742                dev->device->mount_point, dev->print_name());
743          break;
744       }
745       else {
746          Dmsg2(99, "check_can_write_on_non_blank_dvd: found %s (versus %s)\n", 
747                result->d_name, dev->VolCatInfo.VolCatName);
748          if (strcmp(result->d_name, dev->VolCatInfo.VolCatName) == 0) {
749             /* Found the file, checking it is empty */
750             POOL_MEM filename(PM_FNAME);
751             pm_strcpy(filename, dev->device->mount_point);
752             if (filename.c_str()[strlen(filename.c_str())-1] != '/') {
753                pm_strcat(filename, "/");
754             }
755             pm_strcat(filename, dev->VolCatInfo.VolCatName);
756             if (stat(filename.c_str(), &filestat) < 0) {
757                berrno be;
758                dev->dev_errno = errno;
759                Dmsg2(29, "check_can_write_on_non_blank_dvd: cannot stat file (file=%s), ERR=%s\n", 
760                   filename.c_str(), be.strerror());
761                return false;
762             }
763             Dmsg2(99, "check_can_write_on_non_blank_dvd: size of %s is %d\n", 
764                filename.c_str(), filestat.st_size);
765             matched = (filestat.st_size == 0);
766          }
767       }
768       count++;
769    }
770    free(entry);
771    closedir(dp);
772    
773    Dmsg2(29, "check_can_write_on_non_blank_dvd: got %d files in the mount point (matched=%d)\n", count, matched);
774    
775    if (count != 3) {
776       /* There is more than 3 files (., .., and the volume file) */
777       return false;
778    }
779    
780    return matched;
781 }
782
783 /*
784  * Edit codes into (Un)MountCommand, Write(First)PartCommand
785  *  %% = %
786  *  %a = archive device name
787  *  %e = erase (set if cannot mount and first part)
788  *  %n = part number
789  *  %m = mount point
790  *  %v = last part name
791  *
792  *  omsg = edited output message
793  *  imsg = input string containing edit codes (%x)
794  *
795  */
796 static void edit_device_codes_dev(DEVICE* dev, POOL_MEM &omsg, const char *imsg)
797 {
798    const char *p;
799    const char *str;
800    char add[20];
801    
802    POOL_MEM archive_name(PM_FNAME);
803
804    omsg.c_str()[0] = 0;
805    Dmsg1(800, "edit_device_codes: %s\n", imsg);
806    for (p=imsg; *p; p++) {
807       if (*p == '%') {
808          switch (*++p) {
809          case '%':
810             str = "%";
811             break;
812          case 'a':
813             str = dev->dev_name;
814             break;
815          case 'e':
816             if (dev->num_parts == 0) {
817                str = "1";
818             } else {
819                str = "0";
820             }
821             break;
822          case 'n':
823             bsnprintf(add, sizeof(add), "%d", dev->part);
824             str = add;
825             break;
826          case 'm':
827             str = dev->device->mount_point;
828             break;
829          case 'v':
830             make_spooled_dvd_filename(dev, archive_name);
831             str = archive_name.c_str();
832             break;
833          default:
834             add[0] = '%';
835             add[1] = *p;
836             add[2] = 0;
837             str = add;
838             break;
839          }
840       } else {
841          add[0] = *p;
842          add[1] = 0;
843          str = add;
844       }
845       Dmsg1(1900, "add_str %s\n", str);
846       pm_strcat(omsg, (char *)str);
847       Dmsg1(1800, "omsg=%s\n", omsg.c_str());
848    }
849 }