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