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