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