]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/dvd.c
kes Fix logic error in handling error return from mtx-changer
[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-2006 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 bool do_mount_dvd(DEVICE* dev, int mount, int dotimeout);
30 static void add_file_and_part_name(DEVICE *dev, POOL_MEM &archive_name);
31
32 /* 
33  * Write the current volume/part filename to archive_name.
34  */
35 void make_mounted_dvd_filename(DEVICE *dev, POOL_MEM &archive_name) 
36 {
37    pm_strcpy(archive_name, dev->device->mount_point);
38    add_file_and_part_name(dev, archive_name);
39 }
40
41 void make_spooled_dvd_filename(DEVICE *dev, POOL_MEM &archive_name)
42 {
43    /* Use the working directory if spool directory is not defined */
44    if (dev->device->spool_directory) {
45       pm_strcpy(archive_name, dev->device->spool_directory);
46    } else {
47       pm_strcpy(archive_name, working_directory);
48    }
49    add_file_and_part_name(dev, archive_name);
50 }      
51
52 static void add_file_and_part_name(DEVICE *dev, POOL_MEM &archive_name)
53 {
54    char partnumber[20];
55    if (archive_name.c_str()[strlen(archive_name.c_str())-1] != '/') {
56       pm_strcat(archive_name, "/");
57    }
58
59    pm_strcat(archive_name, dev->VolCatInfo.VolCatName);
60    /* if part > 1, append .# to the filename (where # is the part number) */
61    if (dev->part > 1) {
62       pm_strcat(archive_name, ".");
63       bsnprintf(partnumber, sizeof(partnumber), "%d", dev->part);
64       pm_strcat(archive_name, partnumber);
65    }
66    Dmsg2(400, "Exit add_file_part_name: arch=%s, part=%d\n",
67                   archive_name.c_str(), dev->part);
68 }  
69
70 /* Mount the device.
71  * If timeout, wait until the mount command returns 0.
72  * If !timeout, try to mount the device only once.
73  */
74 bool mount_dvd(DEVICE* dev, int timeout) 
75 {
76    Dmsg0(90, "Enter mount_dvd\n");
77    if (dev->is_mounted()) {
78       return true;
79    } else if (dev->requires_mount()) {
80       return do_mount_dvd(dev, 1, timeout);
81    }       
82    return true;
83 }
84
85 /* Unmount the device
86  * If timeout, wait until the unmount command returns 0.
87  * If !timeout, try to unmount the device only once.
88  */
89 bool unmount_dvd(DEVICE *dev, int timeout) 
90 {
91    if (!dev->is_dvd()) {
92       return true;
93    }
94    Dmsg0(90, "Enter unmount_dvd\n");
95    if (dev->is_mounted()) {
96       return do_mount_dvd(dev, 0, timeout);
97    }
98    return true;
99 }
100
101 /* (Un)mount the device */
102 static bool do_mount_dvd(DEVICE* dev, int mount, int dotimeout) 
103 {
104    POOL_MEM ocmd(PM_FNAME);
105    POOLMEM *results;
106    char *icmd;
107    int status, timeout;
108    
109    sm_check(__FILE__, __LINE__, false);
110    if (mount) {
111       if (dev->is_mounted()) {
112          Dmsg0(200, "======= DVD mount=1\n");
113          return true;
114       }
115       icmd = dev->device->mount_command;
116    } else {
117       if (!dev->is_mounted()) {
118          Dmsg0(200, "======= DVD mount=0\n");
119          return true;
120       }
121       icmd = dev->device->unmount_command;
122    }
123    
124    dev->edit_mount_codes(ocmd, icmd);
125    
126    Dmsg2(200, "do_mount_dvd: cmd=%s mounted=%d\n", ocmd.c_str(), !!dev->is_mounted());
127
128    if (dotimeout) {
129       /* Try at most 1 time to (un)mount the device. This should perhaps be configurable. */
130       timeout = 1;
131    } else {
132       timeout = 0;
133    }
134    results = get_memory(2000);
135    results[0] = 0;
136    /* If busy retry each second */
137    Dmsg1(20, "Run mount prog=%s\n", ocmd.c_str());
138    while ((status = run_program_full_output(ocmd.c_str(), 
139                        dev->max_open_wait/2, results)) != 0) {
140       Dmsg2(20, "Mount status=%d result=%s\n", status, results);
141       /* Doesn't work with internationalization (This is not a problem) */
142       if (mount && fnmatch("*is already mounted on*", results, 0) == 0) {
143          break;
144       }
145       if (!mount && fnmatch("* not mounted*", results, 0) == 0) {
146          break;
147       }
148       if (timeout-- > 0) {
149          /* Sometimes the device cannot be mounted because it is already mounted.
150           * Try to unmount it, then remount it */
151          if (mount) {
152             Dmsg1(400, "Trying to unmount the device %s...\n", dev->print_name());
153             do_mount_dvd(dev, 0, 0);
154          }
155          bmicrosleep(1, 0);
156          continue;
157       }
158       if (status != 0) {
159          berrno be;
160          Dmsg5(40, "Device %s cannot be %smounted. stat=%d result=%s ERR=%s\n", dev->print_name(),
161               (mount ? "" : "un"), status, results, be.strerror(status));
162          Mmsg(dev->errmsg, _("Device %s cannot be %smounted. ERR=%s\n"), 
163               dev->print_name(), (mount ? "" : "un"), be.strerror(status));
164       } else {
165          Dmsg4(40, "Device %s cannot be %smounted. stat=%d ERR=%s\n", dev->print_name(),
166               (mount ? "" : "un"), status, results);
167          Mmsg(dev->errmsg, _("Device %s cannot be %smounted. ERR=%s\n"), 
168               dev->print_name(), (mount ? "" : "un"), results);
169       }
170       /*
171        * Now, just to be sure it is not mounted, try to read the
172        *  filesystem.
173        */
174       DIR* dp;
175       struct dirent *entry, *result;
176       int name_max;
177       int count;
178       
179       name_max = pathconf(".", _PC_NAME_MAX);
180       if (name_max < 1024) {
181          name_max = 1024;
182       }
183          
184       if (!(dp = opendir(dev->device->mount_point))) {
185          berrno be;
186          dev->dev_errno = errno;
187          Dmsg3(29, "do_mount_dvd: failed to open dir %s (dev=%s), ERR=%s\n", 
188                dev->device->mount_point, dev->print_name(), be.strerror());
189          goto get_out;
190       }
191       
192       entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
193       count = 0;
194       while (1) {
195          if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
196             dev->dev_errno = EIO;
197             Dmsg2(129, "do_mount_dvd: failed to find suitable file in dir %s (dev=%s)\n", 
198                   dev->device->mount_point, dev->print_name());
199             break;
200          }
201          if (strcmp(result->d_name, ".") && strcmp(result->d_name, "..") && 
202              strcmp(result->d_name, ".keep")) {
203             count++; /* result->d_name != ., .. or .keep (Gentoo-specific) */
204             Dmsg1(100, "Inc count=%d\n", count);
205             break;
206          } else {
207             Dmsg2(129, "do_mount_dvd: ignoring %s in %s\n", 
208                   result->d_name, dev->device->mount_point);
209          }
210       }
211       free(entry);
212       closedir(dp);
213       
214       Dmsg1(29, "do_mount_dvd: got %d files in the mount point (not counting ., .. and .keep)\n", count);
215       
216       if (count > 0) {
217          /* If we got more than ., .. and .keep */
218          /*   there must be something mounted */
219          if (mount) {
220             Dmsg1(100, "Did Mount by count=%d\n", count);
221             break;
222          } else {
223             /* An unmount request. We failed to unmount - report an error */
224             dev->set_mounted(true);
225             free_pool_memory(results);
226             Dmsg0(200, "== DVD mount=1\n");
227             return false;
228          }
229       }
230 get_out:
231       dev->set_mounted(false);
232       sm_check(__FILE__, __LINE__, false);
233       free_pool_memory(results);
234       Dmsg0(200, "== DVD mount=0\n");
235       return false;
236    }
237    Dmsg0(100, "Out of mount/umount loop\n");
238    
239    dev->set_mounted(mount);              /* set/clear mounted flag */
240    free_pool_memory(results);
241    /* Do not check free space when unmounting */
242    if (mount) {
243       Dmsg0(100, "Calling update_free_space\n");
244       if (!update_free_space_dev(dev)) {
245          return false;
246       }
247    }
248    Dmsg1(200, "== DVD mount=%d\n", mount);
249    return true;
250 }
251
252 /* Update the free space on the device */
253 bool update_free_space_dev(DEVICE* dev) 
254 {
255    POOL_MEM ocmd(PM_FNAME);
256    POOLMEM* results;
257    char* icmd;
258    int timeout;
259    uint64_t free;
260    char ed1[50];
261    bool ok = false;
262    int status;
263
264    if (!dev->is_dvd() || dev->is_freespace_ok()) {
265       return true;
266    }
267    
268    /* The device must be mounted in order to dvd-freespace to work */
269    mount_dvd(dev, 1);
270    
271    sm_check(__FILE__, __LINE__, false);
272    icmd = dev->device->free_space_command;
273    
274    if (!icmd) {
275       dev->free_space = 0;
276       dev->free_space_errno = 0;
277       dev->clear_freespace_ok();              /* No valid freespace */
278       dev->clear_media();
279       Dmsg2(29, "ERROR: update_free_space_dev: free_space=%s, free_space_errno=%d (!icmd)\n", 
280             edit_uint64(dev->free_space, ed1), dev->free_space_errno);
281       Mmsg(dev->errmsg, _("No FreeSpace command defined.\n"));
282       return false;
283    }
284    
285    dev->edit_mount_codes(ocmd, icmd);
286    
287    Dmsg1(29, "update_free_space_dev: cmd=%s\n", ocmd.c_str());
288
289    results = get_pool_memory(PM_MESSAGE);
290    
291    /* Try at most 3 times to get the free space on the device. This should perhaps be configurable. */
292    timeout = 3;
293    
294    while (1) {
295       berrno be;
296       Dmsg1(20, "Run freespace prog=%s\n", ocmd.c_str());
297       status = run_program_full_output(ocmd.c_str(), dev->max_open_wait/2, results);
298       Dmsg2(20, "Freespace status=%d result=%s\n", status, results);
299       if (status == 0) {
300          free = str_to_int64(results);
301          Dmsg1(400, "Free space program run: Freespace=%s\n", results);
302          if (free >= 0) {
303             dev->free_space = free;
304             dev->free_space_errno = 0;
305             dev->set_freespace_ok();     /* have valid freespace */
306             dev->set_media();
307             Mmsg(dev->errmsg, "");
308             ok = true;
309             break;
310          }
311       }
312       dev->free_space = 0;
313       dev->free_space_errno = EPIPE;
314       dev->clear_freespace_ok();         /* no valid freespace */
315       Mmsg2(dev->errmsg, _("Cannot run free space command. Results=%s ERR=%s\n"), 
316             results, be.strerror(status));
317       
318       if (--timeout > 0) {
319          Dmsg4(40, "Cannot get free space on device %s. free_space=%s, "
320             "free_space_errno=%d ERR=%s\n", dev->print_name(), 
321                edit_uint64(dev->free_space, ed1), dev->free_space_errno, 
322                dev->errmsg);
323          bmicrosleep(1, 0);
324          continue;
325       }
326
327       dev->dev_errno = dev->free_space_errno;
328       Dmsg4(40, "Cannot get free space on device %s. free_space=%s, "
329          "free_space_errno=%d ERR=%s\n",
330             dev->print_name(), edit_uint64(dev->free_space, ed1),
331             dev->free_space_errno, dev->errmsg);
332       break;
333    }
334    
335    free_pool_memory(results);
336    Dmsg4(29, "leave update_free_space_dev: free_space=%s freespace_ok=%d free_space_errno=%d have_media=%d\n", 
337       edit_uint64(dev->free_space, ed1), !!dev->is_freespace_ok(), dev->free_space_errno, !!dev->have_media());
338    sm_check(__FILE__, __LINE__, false);
339    return ok;
340 }
341
342 /*
343  * Note!!!! Part numbers now begin at 1. The part number is
344  *  suppressed from the first part, which is just the Volume
345  *  name. Each subsequent part is the Volumename.partnumber.
346  *
347  * Write a part (Vol, Vol.2, ...) from the spool to the DVD   
348  * This routine does not update the part number, so normally, you
349  *  should call open_next_part()
350  *
351  * It is also called from truncate_dvd to "blank" the medium, as
352  *  well as from block.c when the DVD is full to write the last part.
353  */
354 bool dvd_write_part(DCR *dcr)
355 {
356    DEVICE *dev = dcr->dev;
357    POOL_MEM archive_name(PM_FNAME);
358    
359    dev->clear_freespace_ok();             /* need to update freespace */
360
361    /* Don't write empty part files.
362     * This is only useful when growisofs does not support write beyond
363     * the 4GB boundary.
364     * Example :
365     *   - 3.9 GB on the volume, dvd-freespace reports 0.4 GB free
366     *   - Write 0.2 GB on the volume, Bacula thinks it could still
367     *     append data, it creates a new empty part.
368     *   - dvd-freespace reports 0 GB free, as the 4GB boundary has
369     *     been crossed
370     *   - Bacula thinks he must finish to write to the device, so it
371     *     tries to write the last part (0-byte), but dvd-writepart fails...
372     *
373     *  ***FIXME****  we cannot write a blank part!!!!!!!
374     * There is one exception: when recycling a volume, we write a blank part
375     * file, so, then, we need to accept to write it.
376     */
377    if (dev->part_size == 0) {
378       Dmsg2(29, "dvd_write_part: device is %s, won't write blank part %d\n", dev->print_name(), dev->part);
379       /* Delete spool file */
380       make_spooled_dvd_filename(dev, archive_name);
381       unlink(archive_name.c_str());
382       dev->set_part_spooled(false);
383       Dmsg1(29, "unlink(%s)\n", archive_name.c_str());
384       sm_check(__FILE__, __LINE__, false);
385       return true;
386    }
387    
388    POOL_MEM ocmd(PM_FNAME);
389    POOL_MEM results(PM_MESSAGE);
390    char* icmd;
391    int status;
392    int timeout;
393    char ed1[50];
394    
395    sm_check(__FILE__, __LINE__, false);
396    Dmsg3(29, "dvd_write_part: device is %s, part is %d, is_mounted=%d\n", dev->print_name(), dev->part, dev->is_mounted());
397    icmd = dev->device->write_part_command;
398    
399    dev->edit_mount_codes(ocmd, icmd);
400       
401    /*
402     * original line follows
403     * timeout = dev->max_open_wait + (dev->max_part_size/(1350*1024/2));
404     * I modified this for a longer timeout; pre-formatting, blanking and
405     * writing can take quite a while
406     */
407
408    /* Explanation of the timeout value, when writing the first part,
409     *  by Arno Lehmann :
410     * 9 GB, write speed 1x: 6990 seconds (almost 2 hours...)
411     * Overhead: 900 seconds (starting, initializing, finalizing,probably 
412     *   reloading 15 minutes)
413     * Sum: 15780.
414     * A reasonable last-exit timeout would be 16000 seconds. Quite long - 
415     * almost 4.5 hours, but hopefully, that timeout will only ever be needed 
416     * in case of a serious emergency.
417     */
418
419    if (dev->part == 1) {
420       timeout = 16000;
421    } else {
422       timeout = dev->max_open_wait + (dev->part_size/(1350*1024/4));
423    }
424
425    Dmsg2(20, "Write part: cmd=%s timeout=%d\n", ocmd.c_str(), timeout);
426    status = run_program_full_output(ocmd.c_str(), timeout, results.c_str());
427    Dmsg2(20, "Write part status=%d result=%s\n", status, results.c_str());
428
429    dev->truncated_dvd = false;
430    if (status != 0) {
431       Jmsg2(dcr->jcr, M_FATAL, 0, _("Error writing part %d to the DVD: ERR=%s\n"),
432          dev->part, results.c_str());
433       Mmsg1(dev->errmsg, _("Error while writing current part to the DVD: %s"), 
434             results.c_str());
435       Dmsg1(000, "%s\n", dev->errmsg);
436       dev->dev_errno = EIO;
437       mark_volume_in_error(dcr);
438       sm_check(__FILE__, __LINE__, false);
439       return false;
440    }
441    Jmsg(dcr->jcr, M_INFO, 0, _("Part %d written to DVD.\n"), dev->part);
442    Dmsg2(400, "dvd_write_part: Part %d written to DVD\nResults: %s\n",
443             dev->part, results.c_str());
444     
445    dev->num_dvd_parts++;            /* there is now one more part on DVD */
446    dev->VolCatInfo.VolCatParts = dev->num_dvd_parts;
447    Dmsg1(000, "Update num_parts=%d\n", dev->num_dvd_parts);
448
449    /* Delete spool file */
450    make_spooled_dvd_filename(dev, archive_name);
451    unlink(archive_name.c_str());
452    dev->set_part_spooled(false);
453    Dmsg1(29, "unlink(%s)\n", archive_name.c_str());
454    sm_check(__FILE__, __LINE__, false);
455    
456    /* growisofs umounted the device, so remount it (it will update the free space) */
457    dev->clear_mounted();
458    mount_dvd(dev, 1);
459    Jmsg(dcr->jcr, M_INFO, 0, _("Remaining free space %s on %s\n"), 
460       edit_uint64_with_commas(dev->free_space, ed1), dev->print_name());
461    sm_check(__FILE__, __LINE__, false);
462    return true;
463 }
464
465 /*
466  * Open the next part file.
467  *  - Close the fd
468  *  - Increment part number 
469  *  - Reopen the device
470  */
471 int dvd_open_next_part(DCR *dcr)
472 {
473    DEVICE *dev = dcr->dev;
474
475    Dmsg6(29, "Enter: == open_next_part part=%d npart=%d dev=%s vol=%s mode=%d file_addr=%d\n", 
476       dev->part, dev->num_dvd_parts, dev->print_name(),
477          dev->VolCatInfo.VolCatName, dev->openmode, dev->file_addr);
478    if (!dev->is_dvd()) {
479       Dmsg1(000, "Device %s is not dvd!!!!\n", dev->print_name()); 
480       return -1;
481    }
482    
483    /* When appending, do not open a new part if the current is empty */
484    if (dev->can_append() && (dev->part > dev->num_dvd_parts) && 
485        (dev->part_size == 0)) {
486       Dmsg0(29, "open_next_part exited immediately (dev->part_size == 0).\n");
487       return dev->fd;
488    }
489
490    dev->close_part(dcr);               /* close current part */
491    
492    /*
493     * If we have a spooled part open, write it to the
494     *  DVD before opening the next part.
495     */
496    if (dev->is_part_spooled()) {
497       Dmsg2(100, "Before open next write previous. part=%d num_parts=%d\n",
498          dev->part, dev->num_dvd_parts);
499       if (!dvd_write_part(dcr)) {
500          Dmsg0(29, "Error in dvd_write part.\n");
501          return -1;
502       }
503    }
504      
505    dev->part_start += dev->part_size;
506    dev->part++;
507    Dmsg2(29, "Inc part=%d num_dvd_parts=%d\n", dev->part, dev->num_dvd_parts);
508
509    /* Are we working on a part past what is written in the DVD? */
510    if (dev->num_dvd_parts < dev->part) {
511       POOL_MEM archive_name(PM_FNAME);
512       struct stat buf;
513       /* 
514        * First check what is on DVD.  If our part is there, we
515        *   are in trouble, so bail out.
516        * NB: This is however not a problem if we are writing the first part.
517        * It simply means that we are over writing an existing volume...
518        */
519       if (dev->num_dvd_parts > 0) {
520          make_mounted_dvd_filename(dev, archive_name);   /* makes dvd name */
521          Dmsg1(100, "Check if part on DVD: %s\n", archive_name.c_str());
522          if (stat(archive_name.c_str(), &buf) == 0) {
523             /* bad news bail out */
524             dev->set_part_spooled(false);
525             Mmsg1(&dev->errmsg, _("Next Volume part already exists on DVD. Cannot continue: %s\n"),
526                archive_name.c_str());
527             return -1;
528          }
529       }
530
531 #ifdef neeeded
532       Dmsg2(400, "num_dvd_parts=%d part=%d\n", dev->num_dvd_parts, dev->part);
533       make_spooled_dvd_filename(dev, archive_name);   /* makes spool name */
534       
535       /* Check if the next part exists in spool directory . */
536       Dmsg1(100, "Check if part on spool: %s\n", archive_name.c_str());
537       if ((stat(archive_name.c_str(), &buf) == 0) || (errno != ENOENT)) {
538          Dmsg1(29, "======= Part %s is in the way, deleting it...\n", archive_name.c_str());
539          /* Then try to unlink it */
540          if (unlink(archive_name.c_str()) < 0) {
541             berrno be;
542             dev->set_part_spooled(false);
543             dev->dev_errno = errno;
544             Mmsg2(dev->errmsg, _("open_next_part can't unlink existing part %s, ERR=%s\n"), 
545                    archive_name.c_str(), be.strerror());
546             return -1;
547          }
548       }
549 #endif
550    }
551
552    Dmsg2(400, "Call dev->open(vol=%s, mode=%d)\n", dcr->VolCatInfo.VolCatName, 
553          dev->openmode);
554
555    /* Open next part.  Note, this sets part_size for part opened. */
556    if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
557       return -1;
558    } 
559    dev->set_labeled();                   /* all next parts are "labeled" */
560    
561    return dev->fd;
562 }
563
564 /*
565  * Open the first part file.
566  *  - Close the fd
567  *  - Reopen the device
568  */
569 int dvd_open_first_part(DCR *dcr, int mode)
570 {
571    DEVICE *dev = dcr->dev;
572
573    Dmsg5(29, "Enter: ==== open_first_part dev=%s Vol=%s mode=%d num_dvd_parts=%d append=%d\n", dev->print_name(), 
574          dev->VolCatInfo.VolCatName, dev->openmode, dev->num_dvd_parts, dev->can_append());
575
576
577    dev->close_part(dcr);
578
579    Dmsg2(400, "Call dev->open(vol=%s, mode=%d)\n", dcr->VolCatInfo.VolCatName, 
580          mode);
581    Dmsg0(100, "Set part=1\n");
582    dev->part = 1;
583    dev->part_start = 0;
584
585    if (dev->open(dcr, mode) < 0) {
586       Dmsg0(400, "open dev() failed\n");
587       return -1;
588    }
589    Dmsg2(400, "Leave open_first_part state=%s append=%d\n", dev->is_open()?"open":"not open", dev->can_append());
590    
591    return dev->fd;
592 }
593
594
595 /* Protected version of lseek, which opens the right part if necessary */
596 off_t lseek_dev(DEVICE *dev, off_t offset, int whence)
597 {
598    DCR *dcr;
599    off_t pos;
600    char ed1[50], ed2[50];
601    
602    Dmsg5(400, "Enter lseek_dev fd=%d off=%s w=%d part=%d nparts=%d\n", dev->fd,
603       edit_int64(offset, ed1), whence, dev->part, dev->num_dvd_parts);
604    if (!dev->is_dvd()) { 
605       Dmsg0(400, "Using sys lseek\n");
606       return lseek(dev->fd, offset, whence);
607    }
608
609    dcr = (DCR *)dev->attached_dcrs->first();  /* any dcr will do */
610    switch(whence) {
611    case SEEK_SET:
612       Dmsg2(400, "lseek_dev SEEK_SET to %s (part_start=%s)\n",
613          edit_int64(offset, ed1), edit_uint64(dev->part_start, ed2));
614       if ((uint64_t)offset >= dev->part_start) {
615          if ((uint64_t)offset == dev->part_start || 
616              (uint64_t)offset < dev->part_start+dev->part_size) {
617             /* We are staying in the current part, just seek */
618             if ((pos = lseek(dev->fd, offset-dev->part_start, SEEK_SET)) < 0) {
619                return pos;
620             } else {
621                return pos + dev->part_start;
622             }
623          } else {
624             /* Load next part, and start again */
625             Dmsg0(100, "lseek open next part\n");
626             if (dvd_open_next_part(dcr) < 0) {
627                Dmsg0(400, "lseek_dev failed while trying to open the next part\n");
628                return -1;
629             }
630             Dmsg2(100, "Recurse lseek after open next part=%d num_part=%d\n",
631                dev->part, dev->num_dvd_parts);
632             return lseek_dev(dev, offset, SEEK_SET);
633          }
634       } else {
635          /*
636           * pos < dev->part_start :
637           * We need to access a previous part, 
638           * so just load the first one, and seek again
639           * until the right one is loaded
640           */
641          Dmsg0(100, "lseek open first part\n");
642          if (dvd_open_first_part(dcr, dev->openmode) < 0) {
643             Dmsg0(400, "lseek_dev failed while trying to open the first part\n");
644             return -1;
645          }
646          Dmsg2(100, "Recurse lseek after open first part=%d num_part=%d\n",
647                dev->part, dev->num_dvd_parts);
648          return lseek_dev(dev, offset, SEEK_SET);
649       }
650       break;
651    case SEEK_CUR:
652       Dmsg1(400, "lseek_dev SEEK_CUR to %s\n", edit_int64(offset, ed1));
653       if ((pos = lseek(dev->fd, (off_t)0, SEEK_CUR)) < 0) {
654          Dmsg0(400, "Seek error.\n");
655          return pos;                  
656       }
657       pos += dev->part_start;
658       if (offset == 0) {
659          Dmsg1(400, "lseek_dev SEEK_CUR returns %s\n", edit_uint64(pos, ed1));
660          return pos;
661       } else { 
662          Dmsg1(400, "do lseek_dev SEEK_SET %s\n", edit_uint64(pos, ed1));
663          return lseek_dev(dev, pos, SEEK_SET);
664       }
665       break;
666    case SEEK_END:
667       Dmsg1(400, "lseek_dev SEEK_END to %s\n", edit_int64(offset, ed1));
668       /*
669        * Bacula does not use offsets for SEEK_END
670        *  Also, Bacula uses seek_end only when it wants to
671        *  append to the volume, so for a dvd that means
672        *  that the volume must be spooled since the DVD
673        *  itself is read-only (as currently implemented).
674        */
675       if (offset > 0) { /* Not used by bacula */
676          Dmsg1(400, "lseek_dev SEEK_END called with an invalid offset %s\n", 
677             edit_uint64(offset, ed1));
678          errno = EINVAL;
679          return -1;
680       }
681       /* If we are already on a spooled part and have the
682        *  right part number, simply seek
683        */
684       if (dev->is_part_spooled() && dev->part > dev->num_dvd_parts) {
685          if ((pos = lseek(dev->fd, (off_t)0, SEEK_END)) < 0) {
686             return pos;   
687          } else {
688             Dmsg1(400, "lseek_dev SEEK_END returns %s\n", 
689                   edit_uint64(pos + dev->part_start, ed1));
690             return pos + dev->part_start;
691          }
692       } else {
693          /*
694           * Load the first part, then load the next until we reach the last one.
695           * This is the only way to be sure we compute the right file address.
696           *
697           * Save previous openmode, and open all but last part read-only 
698           * (useful for DVDs) 
699           */
700          int modesave = dev->openmode;
701          if (dvd_open_first_part(dcr, OPEN_READ_ONLY) < 0) {
702             Dmsg0(400, "lseek_dev failed while trying to open the first part\n");
703             return -1;
704          }
705          if (dev->num_dvd_parts > 0) {
706             while (dev->part < dev->num_dvd_parts) {
707                if (dvd_open_next_part(dcr) < 0) {
708                   Dmsg0(400, "lseek_dev failed while trying to open the next part\n");
709                   return -1;
710                }
711             }
712             dev->openmode = modesave;
713             if (dvd_open_next_part(dcr) < 0) {
714                Dmsg0(400, "lseek_dev failed while trying to open the next part\n");
715                return -1;
716             }
717          }
718          return lseek_dev(dev, 0, SEEK_END);
719       }
720       break;
721    default:
722       Dmsg0(400, "Seek call error.\n");
723       errno = EINVAL;
724       return -1;
725    }
726 }
727
728 bool dvd_close_job(DCR *dcr)
729 {
730    DEVICE *dev = dcr->dev;
731    JCR *jcr = dcr->jcr;
732    bool ok = true;
733
734    /*
735     * If the device is a dvd and WritePartAfterJob
736     * is set to yes, open the next part, so, in case of a device
737     * that requires mount, it will be written to the device.
738     */
739    if (dev->is_dvd() && jcr->write_part_after_job && (dev->part_size > 0)) {
740       Dmsg1(400, "Writing last part=%d write_partafter_job is set.\n",
741          dev->part);
742       if (dev->part < dev->num_dvd_parts+1) {
743          Jmsg3(jcr, M_FATAL, 0, _("Error writing. Current part less than total number of parts (%d/%d, device=%s)\n"),
744                dev->part, dev->num_dvd_parts, dev->print_name());
745          dev->dev_errno = EIO;
746          ok = false;
747       }
748       
749       if (ok && !dvd_write_part(dcr)) {
750          Jmsg2(jcr, M_FATAL, 0, _("Unable to write last on %s: ERR=%s\n"),
751                dev->print_name(), dev->bstrerror());
752          dev->dev_errno = EIO;
753          ok = false;
754       }
755    }
756    return ok;
757 }
758
759 bool truncate_dvd(DCR *dcr) 
760 {
761    DEVICE* dev = dcr->dev;
762
763    dev->close_part(dcr);
764
765    if (!unmount_dvd(dev, 1)) {
766       Dmsg0(400, "truncate_dvd: Failed to unmount DVD\n");
767       return false;
768    }
769
770    /* Set num_dvd_parts to zero (on disk) */
771    dev->num_dvd_parts = 0;
772    dcr->VolCatInfo.VolCatParts = 0;
773    dev->VolCatInfo.VolCatParts = 0;
774    
775    Dmsg0(400, "truncate_dvd: Opening first part (1)...\n");
776    
777    dev->truncating = true;
778    if (dvd_open_first_part(dcr, CREATE_READ_WRITE) < 0) {
779       Dmsg0(400, "truncate_dvd: Error while opening first part (1).\n");
780       dev->truncating = false;
781       return false;
782    }
783
784    Dmsg0(400, "truncate_dvd: Truncating...\n");
785
786    /* If necessary, truncate it spool file. */
787    if (ftruncate(dev->fd, 0) != 0) {
788       berrno be;
789       Mmsg2(dev->errmsg, _("Unable to truncate device %s. ERR=%s\n"), 
790          dev->print_name(), be.strerror());
791       dev->truncating = false;
792       return false;
793    }
794    
795    dev->close_part(dcr);
796    
797    Dmsg0(400, "truncate_dvd: Opening first part (2)...\n");
798    
799    /* 
800     * Now actually truncate the DVD
801     *  This is really kludgy, why not an argument or a separate
802     *  subroutine?  KES
803     */
804    if (!dvd_write_part(dcr)) {
805       Dmsg0(400, "truncate_dvd: Error while writing to DVD.\n");
806       dev->truncating = false;
807       return false;
808    }
809    dev->truncating = false;
810    
811    /* Set num_dvd_parts to zero (on disk) */
812    dev->num_dvd_parts = 0;
813    dcr->VolCatInfo.VolCatParts = 0;
814    dev->VolCatInfo.VolCatParts = 0;
815
816    /* Update catalog */
817    if (!dir_update_volume_info(dcr, false)) {
818       return false;
819    }
820    
821    if (dvd_open_first_part(dcr, OPEN_READ_WRITE) < 0) {
822       Dmsg0(400, "truncate_dvd: Error while opening first part (2).\n");
823       return false;
824    }
825
826    return true;
827 }
828
829 /* Checks if we can write on a non-blank DVD: meaning that it just have been
830  * truncated (there is only one zero-sized file on the DVD, with the right
831  * volume name).   
832  *  
833  * Note!  Normally if we can mount the device, which should be the case
834  *   when we get here, it is not a blank DVD.  Hence we check if
835  *   there is a zero length file with the right name, in which case
836  *   we allow it.
837  * This seems terribly kludgie to me.  KES
838  */
839 bool check_can_write_on_non_blank_dvd(DCR *dcr) 
840 {
841    DEVICE* dev = dcr->dev;
842    DIR* dp;
843    struct dirent *entry, *result;
844    int name_max;
845    int count = 0;
846    bool matched = true;
847    struct stat filestat;
848       
849    name_max = pathconf(".", _PC_NAME_MAX);
850    if (name_max < 1024) {
851       name_max = 1024;
852    }
853    
854    if (!(dp = opendir(dev->device->mount_point))) {
855       berrno be;
856       dev->dev_errno = errno;
857       Dmsg3(29, "check_can_write_on_non_blank_dvd: failed to open dir %s (dev=%s), ERR=%s\n", 
858             dev->device->mount_point, dev->print_name(), be.strerror());
859       return false;
860    }
861    
862    entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
863    while (1) {
864       if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
865          dev->dev_errno = EIO;
866          Dmsg2(129, "check_can_write_on_non_blank_dvd: no more files in dir %s (dev=%s)\n", 
867                dev->device->mount_point, dev->print_name());
868          break;
869       } else {
870          Dmsg2(99, "check_can_write_on_non_blank_dvd: found %s (versus %s)\n", 
871                result->d_name, dev->VolCatInfo.VolCatName);
872          if (strcmp(result->d_name, dev->VolCatInfo.VolCatName) == 0) {
873             /* Found the file, checking it is empty */
874             POOL_MEM filename(PM_FNAME);
875             pm_strcpy(filename, dev->device->mount_point);
876             if (filename.c_str()[strlen(filename.c_str())-1] != '/') {
877                pm_strcat(filename, "/");
878             }
879             pm_strcat(filename, dev->VolCatInfo.VolCatName);
880             if (stat(filename.c_str(), &filestat) < 0) {
881                berrno be;
882                dev->dev_errno = errno;
883                Dmsg2(29, "check_can_write_on_non_blank_dvd: cannot stat file (file=%s), ERR=%s\n", 
884                   filename.c_str(), be.strerror());
885                return false;
886             }
887             Dmsg2(99, "check_can_write_on_non_blank_dvd: size of %s is %lld\n", 
888                filename.c_str(), filestat.st_size);
889             matched = filestat.st_size == 0;
890          }
891       }
892       count++;
893    }
894    free(entry);
895    closedir(dp);
896    
897    if (count > 3) {
898       /* There are more than 3 files (., .., and the volume file) */
899       Dmsg1(29, "Cannot write on blank DVD too many files %d greater than 3\n", count);
900       return false;
901    }
902    
903    Dmsg2(29, "OK  can_write_on_non_blank_dvd: got %d files in the mount point (matched=%d)\n", count, matched);
904    return matched;
905 }