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