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