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