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