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