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