]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/dvd.c
kes Rework a lot of subroutines in dev.c to take dcr as an
[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 && !dev->truncating) {
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->blank_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       if (!dev->truncating) {
438          mark_volume_in_error(dcr);
439       }
440       sm_check(__FILE__, __LINE__, false);
441       return false;
442    }
443    Jmsg(dcr->jcr, M_INFO, 0, _("Part %d (%lld bytes) written to DVD.\n"), dev->part, dev->part_size);
444    Dmsg3(400, "dvd_write_part: Part %d (%lld bytes) written to DVD\nResults: %s\n",
445             dev->part, dev->part_size, results.c_str());
446     
447    dev->num_dvd_parts++;            /* there is now one more part on DVD */
448    dev->VolCatInfo.VolCatParts = dev->num_dvd_parts;
449    dcr->VolCatInfo.VolCatParts = dev->num_dvd_parts;
450    Dmsg1(000, "Update num_parts=%d\n", dev->num_dvd_parts);
451
452    /* Delete spool file */
453    make_spooled_dvd_filename(dev, archive_name);
454    unlink(archive_name.c_str());
455    dev->set_part_spooled(false);
456    Dmsg1(29, "unlink(%s)\n", archive_name.c_str());
457    sm_check(__FILE__, __LINE__, false);
458    
459    /* growisofs umounted the device, so remount it (it will update the free space) */
460    dev->clear_mounted();
461    mount_dvd(dev, 1);
462    Jmsg(dcr->jcr, M_INFO, 0, _("Remaining free space %s on %s\n"), 
463       edit_uint64_with_commas(dev->free_space, ed1), dev->print_name());
464    sm_check(__FILE__, __LINE__, false);
465    return true;
466 }
467
468 /*
469  * Open the next part file.
470  *  - Close the fd
471  *  - Increment part number 
472  *  - Reopen the device
473  */
474 int dvd_open_next_part(DCR *dcr)
475 {
476    DEVICE *dev = dcr->dev;
477
478    Dmsg6(29, "Enter: == open_next_part part=%d npart=%d dev=%s vol=%s mode=%d file_addr=%d\n", 
479       dev->part, dev->num_dvd_parts, dev->print_name(),
480          dev->VolCatInfo.VolCatName, dev->openmode, dev->file_addr);
481    if (!dev->is_dvd()) {
482       Dmsg1(000, "Device %s is not dvd!!!!\n", dev->print_name()); 
483       return -1;
484    }
485    
486    /* When appending, do not open a new part if the current is empty */
487    if (dev->can_append() && (dev->part > dev->num_dvd_parts) && 
488        (dev->part_size == 0)) {
489       Dmsg0(29, "open_next_part exited immediately (dev->part_size == 0).\n");
490       return dev->fd;
491    }
492
493    dev->close_part(dcr);               /* close current part */
494    
495    /*
496     * If we have a spooled part open, write it to the
497     *  DVD before opening the next part.
498     */
499    if (dev->is_part_spooled()) {
500       Dmsg2(100, "Before open next write previous. part=%d num_parts=%d\n",
501          dev->part, dev->num_dvd_parts);
502       if (!dvd_write_part(dcr)) {
503          Dmsg0(29, "Error in dvd_write part.\n");
504          return -1;
505       }
506    }
507      
508    dev->part_start += dev->part_size;
509    dev->part++;
510    Dmsg2(29, "Inc part=%d num_dvd_parts=%d\n", dev->part, dev->num_dvd_parts);
511
512    /* Are we working on a part past what is written in the DVD? */
513    if (dev->num_dvd_parts < dev->part) {
514       POOL_MEM archive_name(PM_FNAME);
515       struct stat buf;
516       /* 
517        * First check what is on DVD.  If our part is there, we
518        *   are in trouble, so bail out.
519        * NB: This is however not a problem if we are writing the first part.
520        * It simply means that we are over writing an existing volume...
521        */
522       if (dev->num_dvd_parts > 0) {
523          make_mounted_dvd_filename(dev, archive_name);   /* makes dvd name */
524          Dmsg1(100, "Check if part on DVD: %s\n", archive_name.c_str());
525          if (stat(archive_name.c_str(), &buf) == 0) {
526             /* bad news bail out */
527             dev->set_part_spooled(false);
528             Mmsg1(&dev->errmsg, _("Next Volume part already exists on DVD. Cannot continue: %s\n"),
529                archive_name.c_str());
530             return -1;
531          }
532       }
533
534 #ifdef neeeded
535       Dmsg2(400, "num_dvd_parts=%d part=%d\n", dev->num_dvd_parts, dev->part);
536       make_spooled_dvd_filename(dev, archive_name);   /* makes spool name */
537       
538       /* Check if the next part exists in spool directory . */
539       Dmsg1(100, "Check if part on spool: %s\n", archive_name.c_str());
540       if ((stat(archive_name.c_str(), &buf) == 0) || (errno != ENOENT)) {
541          Dmsg1(29, "======= Part %s is in the way, deleting it...\n", archive_name.c_str());
542          /* Then try to unlink it */
543          if (unlink(archive_name.c_str()) < 0) {
544             berrno be;
545             dev->set_part_spooled(false);
546             dev->dev_errno = errno;
547             Mmsg2(dev->errmsg, _("open_next_part can't unlink existing part %s, ERR=%s\n"), 
548                    archive_name.c_str(), be.strerror());
549             return -1;
550          }
551       }
552 #endif
553    }
554
555    Dmsg2(400, "Call dev->open(vol=%s, mode=%d)\n", dcr->VolCatInfo.VolCatName, 
556          dev->openmode);
557
558    /* Open next part.  Note, this sets part_size for part opened. */
559    if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
560       return -1;
561    } 
562    dev->set_labeled();                   /* all next parts are "labeled" */
563    
564    return dev->fd;
565 }
566
567 /*
568  * Open the first part file.
569  *  - Close the fd
570  *  - Reopen the device
571  */
572 int dvd_open_first_part(DCR *dcr, int mode)
573 {
574    DEVICE *dev = dcr->dev;
575
576    Dmsg5(29, "Enter: ==== open_first_part dev=%s Vol=%s mode=%d num_dvd_parts=%d append=%d\n", dev->print_name(), 
577          dev->VolCatInfo.VolCatName, dev->openmode, dev->num_dvd_parts, dev->can_append());
578
579
580    dev->close_part(dcr);
581
582    Dmsg2(400, "Call dev->open(vol=%s, mode=%d)\n", dcr->VolCatInfo.VolCatName, 
583          mode);
584    Dmsg0(100, "Set part=1\n");
585    dev->part = 1;
586    dev->part_start = 0;
587
588    if (dev->open(dcr, mode) < 0) {
589       Dmsg0(400, "open dev() failed\n");
590       return -1;
591    }
592    Dmsg2(400, "Leave open_first_part state=%s append=%d\n", dev->is_open()?"open":"not open", dev->can_append());
593    
594    return dev->fd;
595 }
596
597
598 /* 
599  * Do an lseek on a DVD handling all the different parts
600  */
601 off_t lseek_dvd(DCR *dcr, off_t offset, int whence)
602 {
603    DEVICE *dev = dcr->dev;
604    off_t pos;
605    char ed1[50], ed2[50];
606    
607    Dmsg5(400, "Enter lseek_dvd fd=%d off=%s w=%d part=%d nparts=%d\n", dev->fd,
608       edit_int64(offset, ed1), whence, dev->part, dev->num_dvd_parts);
609
610    switch(whence) {
611    case SEEK_SET:
612       Dmsg2(400, "lseek_dvd 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_dvd 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_dvd(dcr, 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_dvd 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_dvd(dcr, offset, SEEK_SET); /* system lseek */
649       }
650       break;
651    case SEEK_CUR:
652       Dmsg1(400, "lseek_dvd 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_dvd SEEK_CUR returns %s\n", edit_uint64(pos, ed1));
660          return pos;
661       } else { 
662          Dmsg1(400, "do lseek_dvd SEEK_SET %s\n", edit_uint64(pos, ed1));
663          return lseek_dvd(dcr, pos, SEEK_SET);
664       }
665       break;
666    case SEEK_END:
667       Dmsg1(400, "lseek_dvd 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_dvd 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_dvd 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_dvd 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_dvd 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_dvd failed while trying to open the next part\n");
715                return -1;
716             }
717          }
718          return lseek_dvd(dcr, 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    /* Clear the size of the volume */
816    dev->VolCatInfo.VolCatBytes = 0;
817    dcr->VolCatInfo.VolCatBytes = 0;
818
819 #ifdef xxx
820    /* Update catalog */
821    if (!dir_update_volume_info(dcr, false)) {
822       return false;
823    }
824 #endif
825    
826    if (dvd_open_first_part(dcr, OPEN_READ_WRITE) < 0) {
827       Dmsg0(400, "truncate_dvd: Error while opening first part (2).\n");
828       return false;
829    }
830
831    return true;
832 }
833
834 /* Checks if we can write on a non-blank DVD: meaning that it just have been
835  * truncated (there is only one zero-sized file on the DVD, with the right
836  * volume name).   
837  *  
838  * Note!  Normally if we can mount the device, which should be the case
839  *   when we get here, it is not a blank DVD.  Hence we check if
840  *   there is a zero length file with the right name, in which case
841  *   we allow it.
842  * This seems terribly kludgie to me.  KES
843  */
844 bool check_can_write_on_non_blank_dvd(DCR *dcr) 
845 {
846    DEVICE* dev = dcr->dev;
847    DIR* dp;
848    struct dirent *entry, *result;
849    int name_max;
850    int count = 0;
851    bool matched = true;
852    struct stat filestat;
853       
854    name_max = pathconf(".", _PC_NAME_MAX);
855    if (name_max < 1024) {
856       name_max = 1024;
857    }
858    
859    if (!(dp = opendir(dev->device->mount_point))) {
860       berrno be;
861       dev->dev_errno = errno;
862       Dmsg3(29, "check_can_write_on_non_blank_dvd: failed to open dir %s (dev=%s), ERR=%s\n", 
863             dev->device->mount_point, dev->print_name(), be.strerror());
864       return false;
865    }
866    
867    entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
868    while (1) {
869       if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
870          dev->dev_errno = EIO;
871          Dmsg2(129, "check_can_write_on_non_blank_dvd: no more files in dir %s (dev=%s)\n", 
872                dev->device->mount_point, dev->print_name());
873          break;
874       } else {
875          Dmsg2(99, "check_can_write_on_non_blank_dvd: found %s (versus %s)\n", 
876                result->d_name, dev->VolCatInfo.VolCatName);
877          if (strcmp(result->d_name, dev->VolCatInfo.VolCatName) == 0) {
878             /* Found the file, checking it is empty */
879             POOL_MEM filename(PM_FNAME);
880             pm_strcpy(filename, dev->device->mount_point);
881             if (filename.c_str()[strlen(filename.c_str())-1] != '/') {
882                pm_strcat(filename, "/");
883             }
884             pm_strcat(filename, dev->VolCatInfo.VolCatName);
885             if (stat(filename.c_str(), &filestat) < 0) {
886                berrno be;
887                dev->dev_errno = errno;
888                Dmsg2(29, "check_can_write_on_non_blank_dvd: cannot stat file (file=%s), ERR=%s\n", 
889                   filename.c_str(), be.strerror());
890                return false;
891             }
892             Dmsg2(99, "check_can_write_on_non_blank_dvd: size of %s is %lld\n", 
893                filename.c_str(), filestat.st_size);
894             matched = filestat.st_size == 0;
895          }
896       }
897       count++;
898    }
899    free(entry);
900    closedir(dp);
901    
902    if (count > 3) {
903       /* There are more than 3 files (., .., and the volume file) */
904       Dmsg1(29, "Cannot write on blank DVD too many files %d greater than 3\n", count);
905       return false;
906    }
907    
908    Dmsg2(29, "OK  can_write_on_non_blank_dvd: got %d files in the mount point (matched=%d)\n", count, matched);
909    return matched;
910 }
911
912 /* 
913  * Mount a DVD device, then scan to find out how many parts
914  *  there are.
915  */
916 int find_num_dvd_parts(DCR *dcr)
917 {
918    DEVICE *dev = dcr->dev;
919    int num_parts = 0;
920
921    if (!dev->is_dvd()) {
922       return 0;
923    }
924    
925    if (dev->mount(1)) {
926       DIR* dp;
927       struct dirent *entry, *result;
928       int name_max;
929       int len = strlen(dcr->VolCatInfo.VolCatName);
930
931       /* Now count the number of parts */
932       name_max = pathconf(".", _PC_NAME_MAX);
933       if (name_max < 1024) {
934          name_max = 1024;
935       }
936          
937       if (!(dp = opendir(dev->device->mount_point))) {
938          berrno be;
939          dev->dev_errno = errno;
940          Dmsg3(29, "find_num_dvd_parts: failed to open dir %s (dev=%s), ERR=%s\n", 
941                dev->device->mount_point, dev->print_name(), be.strerror());
942          goto get_out;
943       }
944       
945       entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
946
947       Dmsg1(100, "Looking for Vol=%s\n", dcr->VolCatInfo.VolCatName);
948       for ( ;; ) {
949          int flen;
950          bool ignore;
951          if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
952             dev->dev_errno = EIO;
953             Dmsg2(129, "find_num_dvd_parts: failed to find suitable file in dir %s (dev=%s)\n", 
954                   dev->device->mount_point, dev->print_name());
955             break;
956          }
957          flen = strlen(result->d_name);
958          ignore = true;
959          if (flen >= len) {
960             result->d_name[len] = 0;
961             if (strcmp(dcr->VolCatInfo.VolCatName, result->d_name) == 0) {
962                num_parts++;
963                Dmsg1(100, "find_num_dvd_parts: found part: %s\n", result->d_name);
964                ignore = false;
965             }
966          }
967          if (ignore) {
968             Dmsg2(129, "find_num_dvd_parts: ignoring %s in %s\n", 
969                   result->d_name, dev->device->mount_point);
970          }
971       }
972       free(entry);
973       closedir(dp);
974       Dmsg1(29, "find_num_dvd_parts = %d\n", num_parts);
975    }
976    
977 get_out:
978    dev->set_freespace_ok();
979    if (dev->is_mounted()) {
980       dev->unmount(0);
981    }
982    return num_parts;
983 }