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