]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/dvd.c
466bf0716b782ac372b19ab75f585ecec4d03604
[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 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 ammended 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 char *edit_device_codes_dev(DEVICE *dev, char *omsg, const char *imsg);
30 static bool do_mount_dev(DEVICE* dev, int mount, int dotimeout);
31 static int dvd_write_part(DEVICE *dev);
32
33
34 /* 
35  * Write the current volume/part filename to archive_name.
36  */
37 void get_filename(DEVICE *dev, char *VolumeName, POOL_MEM& archive_name) 
38 {
39    char partnumber[20];
40    
41    if (dev->is_dvd()) {
42       /* If we try to open the last part, just open it from disk, 
43        * otherwise, open it from the spooling directory.
44        */
45       Dmsg2(100, "DVD part=%d num_parts=%d\n", dev->part, dev->num_parts);
46       if (dev->num_parts == 0 || dev->part < dev->num_parts) {
47          Dmsg1(100, "Arch = mount point: %s\n", dev->device->mount_point);
48          pm_strcpy(archive_name, dev->device->mount_point);
49       } else {
50          /* Use the working directory if spool directory is not defined */
51          if (dev->device->spool_directory) {
52             Dmsg1(100, "Arch = spool: %s\n", dev->device->spool_directory);
53             pm_strcpy(archive_name, dev->device->spool_directory);
54          } else {
55             Dmsg1(100, "Arch = working: %s\n", working_directory);
56             pm_strcpy(archive_name, working_directory);
57          }
58       }
59    } else {
60       pm_strcpy(archive_name, dev->dev_name);
61    }
62       
63    if (archive_name.c_str()[strlen(archive_name.c_str())-1] != '/') {
64       pm_strcat(archive_name, "/");
65    }
66    pm_strcat(archive_name, VolumeName);
67    /* if part != 0, append .# to the filename (where # is the part number) */
68    if (dev->is_dvd() && dev->part != 0) {
69       pm_strcat(archive_name, ".");
70       bsnprintf(partnumber, sizeof(partnumber), "%d", dev->part);
71       pm_strcat(archive_name, partnumber);
72    }
73    Dmsg1(100, "Exit get_filename: arch=%s\n", archive_name.c_str());
74 }  
75
76 /* Mount the device.
77  * If timeout, wait until the mount command returns 0.
78  * If !timeout, try to mount the device only once.
79  */
80 bool mount_dev(DEVICE* dev, int timeout) 
81 {
82    Dmsg0(900, "Enter mount_dev\n");
83    if (dev->is_mounted()) {
84       return true;
85    } else if (dev->requires_mount()) {
86       return do_mount_dev(dev, 1, timeout);
87    }       
88    return true;
89 }
90
91 /* Unmount the device
92  * If timeout, wait until the unmount command returns 0.
93  * If !timeout, try to unmount the device only once.
94  */
95 bool unmount_dev(DEVICE *dev, int timeout) 
96 {
97    Dmsg0(900, "Enter unmount_dev\n");
98    if (dev->is_mounted()) {
99       return do_mount_dev(dev, 0, timeout);
100    }
101    return true;
102 }
103
104 /* (Un)mount the device */
105 static bool do_mount_dev(DEVICE* dev, int mount, int dotimeout) 
106 {
107    POOL_MEM ocmd(PM_FNAME);
108    POOLMEM* results;
109    char* icmd;
110    int status, timeout;
111    
112    if (mount) {
113       if (dev->is_mounted()) {
114          goto get_out;
115       }
116       icmd = dev->device->mount_command;
117    } else {
118       if (!dev->is_mounted()) {
119          goto get_out;
120       }
121       icmd = dev->device->unmount_command;
122    }
123    
124    edit_device_codes_dev(dev, ocmd.c_str(), icmd);
125    
126    Dmsg2(200, "do_mount_dev: cmd=%s mounted=%d\n", ocmd.c_str(), !!dev->is_mounted());
127
128    if (dotimeout) {
129       /* Try at most 1 time to (un)mount the device. This should perhaps be configurable. */
130       timeout = 1;
131    } else {
132       timeout = 0;
133    }
134    results = get_pool_memory(PM_MESSAGE);
135    /* If busy retry each second */
136    while ((status = run_program_full_output(ocmd.c_str(), 
137                        dev->max_open_wait/2, results)) != 0) {
138       if (timeout-- > 0) {
139          Dmsg2(400, "Device %s cannot be (un)mounted. Retrying... ERR=%s\n", dev->dev_name, results);
140          /* Sometimes the device cannot be mounted because it is already mounted.
141           * Try to unmount it, then remount it */
142          if (mount) {
143             Dmsg1(400, "Trying to unmount the device %s...\n", dev->dev_name);
144             do_mount_dev(dev, 0, 0);
145          }
146          bmicrosleep(1, 0);
147          continue;
148       }
149       Dmsg2(40, "Device %s cannot be mounted. ERR=%s\n", dev->print_name(), results);
150       Mmsg(dev->errmsg, "Device %s cannot be mounted. ERR=%s\n", 
151            dev->print_name(), results);
152       free_pool_memory(results);
153       return false;
154    }
155    
156    dev->set_mounted(mount);              /* set/clear mounted flag */
157    free_pool_memory(results);
158
159 get_out:
160    Dmsg1(29, "Exit do_mount_dev: mounted=%d\n", !!dev->is_mounted());
161    return true;
162 }
163
164 /* Only for devices that require a mount -- currently DVDs only
165  *
166  * Try to find the Volume name of the loaded device.
167  *
168  * Returns true  if read_dev_volume_label can now read the label,
169  *               NOTE!!! at this point the device may not be
170  *               opened.
171  *               Maybe it should open the first part.  ***FIXME***
172  *
173  *         false if an error occured, and read_dvd_volume_label
174  *               must abort with an IO_ERROR.
175  *
176  * To find the Volume name, it lists all the files on the DVD,
177  * and searches for a file which has a minimum size (500 bytes).
178  * If this file has a numeric extension, like part files, try to
179  * open the file which has no extension (e.g.  the first part
180  * file).
181  *
182  * So, if the DVD does not contains a Bacula volume, a random file is opened,
183  * and no valid label could be read from this file.
184  *
185  * It is useful, so the operator can be told that a wrong volume is mounted, with
186  * the label name of the current volume. We can also check that the currently
187  * mounted disk is writable. (See also read_dev_volume_label_guess in label.c).
188  *
189  */
190 bool can_open_mounted_dev(DEVICE *dev) 
191 {
192    Dmsg1(29, "Enter: dev=%s\n", dev->dev_name);
193    POOL_MEM guessedname(PM_FNAME);
194    DIR* dp;
195    struct dirent *entry, *result;
196    struct stat statp;
197    int index;
198    int name_max;
199    
200    if (!dev->is_dvd()) {
201       Dmsg1(100, "device does not require mount, returning 0. dev=%s\n", dev->dev_name);
202       return true;
203    }
204
205 #ifndef HAVE_DIRENT_H
206    Dmsg0(29, "readdir not available, cannot guess volume name\n");
207    return true; 
208 #endif
209    
210    update_free_space_dev(dev);
211
212    if (mount_dev(dev, 1) < 0) {
213       /* If the device cannot be mounted, check if it is writable */
214       if (dev->have_media()) {
215          Dmsg1(100, "device cannot be mounted, but it seems to be writable, returning 0. dev=%s\n", dev->dev_name);
216          return true;
217       } else {
218          Dmsg1(100, "device cannot be mounted, and is not writable, returning -1. dev=%s\n", dev->dev_name);
219          return false;
220       }
221    }
222       
223    name_max = pathconf(".", _PC_NAME_MAX);
224    if (name_max < 1024) {
225       name_max = 1024;
226    }
227       
228    if (!(dp = opendir(dev->device->mount_point))) {
229       berrno be;
230       dev->dev_errno = errno;
231       Dmsg3(29, "failed to open dir %s (dev=%s), ERR=%s\n", dev->device->mount_point, dev->dev_name, be.strerror());
232       return false;
233    }
234    
235    entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 100);
236    while (1) {
237       if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
238          dev->dev_errno = ENOENT;
239          Dmsg2(29, "failed to find suitable file in dir %s (dev=%s)\n", dev->device->mount_point, dev->dev_name);
240          closedir(dp);
241          free(entry);
242          return false;
243       }
244       
245       ASSERT(name_max+1 > (int)sizeof(struct dirent) + (int)NAMELEN(entry));
246       
247       if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
248          continue;
249       }
250       
251       pm_strcpy(guessedname, dev->device->mount_point);
252       if (guessedname.c_str()[strlen(guessedname.c_str())-1] != '/') {
253          pm_strcat(guessedname, "/");
254       }
255       pm_strcat(guessedname, entry->d_name);
256       
257       if (stat(guessedname.c_str(), &statp) < 0) {
258          berrno be;
259          Dmsg3(29, "failed to stat %s (dev=%s), ERR=%s\n",
260                guessedname.c_str(), dev->dev_name, be.strerror());
261          continue;
262       }
263       
264       if (!S_ISREG(statp.st_mode) || (statp.st_size < 500)) {
265          Dmsg2(100, "%s is not a regular file, or less than 500 bytes (dev=%s)\n", 
266                guessedname.c_str(), dev->dev_name);
267          continue;
268       }
269       
270       /* Ok, we found a good file, remove the part extension if possible. */
271       for (index = strlen(guessedname.c_str())-1; index >= 0; index--) {
272          if ((guessedname.c_str()[index] == '/') || 
273              (guessedname.c_str()[index] < '0') || 
274              (guessedname.c_str()[index] > '9')) {
275             break;
276          }
277          if (guessedname.c_str()[index] == '.') {
278             guessedname.c_str()[index] = '\0';
279             break;
280          }
281       }
282       
283       if ((stat(guessedname.c_str(), &statp) < 0) || (statp.st_size < 500)) {
284          /* The file with extension truncated does not exists or is too small, so use it with its extension. */
285          berrno be;
286          Dmsg3(100, "failed to stat %s (dev=%s), using the file with its extension, ERR=%s\n", 
287                guessedname.c_str(), dev->dev_name, be.strerror());
288          pm_strcpy(guessedname, dev->device->mount_point);
289          if (guessedname.c_str()[strlen(guessedname.c_str())-1] != '/') {
290             pm_strcat(guessedname, "/");
291          }
292          pm_strcat(guessedname, entry->d_name);
293          continue;
294       }
295       break;
296    }
297    closedir(dp);
298    free(entry);
299    
300    if (dev->fd >= 0) {
301       close(dev->fd);
302    }
303      
304    Dmsg1(100, "open(%s) read-only\n", guessedname.c_str());
305    if ((dev->fd = open(guessedname.c_str(), O_RDONLY | O_BINARY)) < 0) {
306       berrno be;
307       dev->dev_errno = errno;
308       Dmsg3(29, "failed to open %s (dev=%s), ERR=%s\n", 
309             guessedname.c_str(), dev->dev_name, be.strerror());
310       Dmsg0(100, "Call open_first_part\n");
311       if (open_first_part(dev, OPEN_READ_ONLY) < 0) {
312          berrno be;
313          dev->dev_errno = errno;
314          Mmsg1(&dev->errmsg, _("Could not open_first_part, ERR=%s\n"), be.strerror());
315          Emsg0(M_FATAL, 0, dev->errmsg);         
316       }
317       return false;
318    }
319    dev->part_start = 0;
320    dev->part_size = statp.st_size;
321    dev->part = 0;
322    dev->set_opened();
323    dev->use_count = 1;
324    Dmsg2(29, "Exit: %s opened (dev=%s)\n", guessedname.c_str(), dev->dev_name);
325    
326    return true;
327 }
328
329
330 /* Update the free space on the device */
331 void update_free_space_dev(DEVICE* dev) 
332 {
333    POOL_MEM ocmd(PM_FNAME);
334    POOLMEM* results;
335    char* icmd;
336    int timeout;
337    long long int free;
338    char ed1[50];
339    
340    icmd = dev->device->free_space_command;
341    
342    if (!icmd) {
343       dev->free_space = 0;
344       dev->free_space_errno = 0;
345       dev->clear_media();
346       Dmsg2(29, "update_free_space_dev: free_space=%d, free_space_errno=%d (!icmd)\n", dev->free_space, dev->free_space_errno);
347       return;
348    }
349    
350    edit_device_codes_dev(dev, ocmd.c_str(), icmd);
351    
352    Dmsg1(29, "update_free_space_dev: cmd=%s\n", ocmd.c_str());
353
354    results = get_pool_memory(PM_MESSAGE);
355    
356    /* Try at most 3 times to get the free space on the device. This should perhaps be configurable. */
357    timeout = 3;
358    
359    while (1) {
360       if (run_program_full_output(ocmd.c_str(), dev->max_open_wait/2, results) == 0) {
361          Dmsg1(100, "Free space program run : %s\n", results);
362          free = str_to_int64(results);
363          if (free >= 0) {
364             dev->free_space = free;
365             dev->free_space_errno = 1;
366             dev->set_media();
367             Mmsg0(dev->errmsg, "");
368             break;
369          }
370       }
371       dev->free_space = 0;
372       dev->free_space_errno = -EPIPE;
373       Mmsg1(dev->errmsg, "Cannot run free space command (%s)\n", results);
374       
375       if (--timeout > 0) {
376          Dmsg4(40, "Cannot get free space on device %s. free_space=%s, "
377             "free_space_errno=%d ERR=%s\n", dev->dev_name, 
378                edit_uint64(dev->free_space, ed1), dev->free_space_errno, 
379                dev->errmsg);
380          bmicrosleep(1, 0);
381          continue;
382       }
383
384       dev->dev_errno = -dev->free_space_errno;
385       Dmsg4(40, "Cannot get free space on device %s. free_space=%s, "
386          "free_space_errno=%d ERR=%s\n",
387             dev->dev_name, edit_uint64(dev->free_space, ed1),
388             dev->free_space_errno, dev->errmsg);
389       break;
390    }
391    
392    free_pool_memory(results);
393    Dmsg3(29, "update_free_space_dev: free_space=%s, free_space_errno=%d have_media=%d\n", 
394       edit_uint64(dev->free_space, ed1), dev->free_space_errno, dev->have_media());
395    return;
396 }
397
398 static int dvd_write_part(DEVICE *dev) 
399 {
400    Dmsg1(29, "dvd_write_part: device is %s\n", dev->dev_name);
401    
402    if (unmount_dev(dev, 1) < 0) {
403       Dmsg0(29, "dvd_write_part: unable to unmount the device\n");
404    }
405    
406    POOL_MEM ocmd(PM_FNAME);
407    POOLMEM *results;
408    results = get_pool_memory(PM_MESSAGE);
409    char* icmd;
410    int status;
411    int timeout;
412    
413    icmd = dev->device->write_part_command;
414    
415    edit_device_codes_dev(dev, ocmd.c_str(), icmd);
416       
417    /* Wait at most the time a maximum size part is written in DVD 0.5x speed
418     * FIXME: Minimum speed should be in device configuration 
419     */
420    timeout = dev->max_open_wait + (dev->max_part_size/(1350*1024/2));
421    
422    Dmsg2(29, "dvd_write_part: cmd=%s timeout=%d\n", ocmd.c_str(), timeout);
423       
424    status = run_program_full_output(ocmd.c_str(), timeout, results);
425    if (status != 0) {
426       Mmsg1(dev->errmsg, "Error while writing current part to the DVD: %s", results);
427       dev->dev_errno = EIO;
428       free_pool_memory(results);
429       return -1;
430    } else {
431       Dmsg1(29, "dvd_write_part: command output=%s\n", results);
432       POOL_MEM archive_name(PM_FNAME);
433       Dmsg1(100, "Call get_filename. Vol=%s\n", dev->VolCatInfo.VolCatName);
434       get_filename(dev, dev->VolCatInfo.VolCatName, archive_name);
435       unlink(archive_name.c_str());
436       free_pool_memory(results);
437       return 0;
438    }
439 }
440
441 /* Open the next part file.
442  *  - Close the fd
443  *  - Increment part number 
444  *  - Reopen the device
445  */
446 int open_next_part(DEVICE *dev)
447 {
448       
449    Dmsg3(29, "Enter: open_next_part %s %s %d\n", dev->dev_name, 
450          dev->VolCatInfo.VolCatName, dev->openmode);
451    /* When appending, do not open a new part if the current is empty */
452    if (dev->can_append() && (dev->part == dev->num_parts) && 
453        (dev->part_size == 0)) {
454       Dmsg0(29, "open_next_part exited immediately (dev->part_size == 0).\n");
455       return dev->fd;
456    }
457    
458    if (dev->fd >= 0) {
459       close(dev->fd);
460    }
461    
462    dev->fd = -1;
463    dev->clear_opened();
464    
465    if (dev->is_dvd() && (dev->part == dev->num_parts) && dev->can_append()) {
466       if (dvd_write_part(dev) < 0) {
467          return -1;
468       }
469    }
470      
471    dev->part_start += dev->part_size;
472    dev->part++;
473    
474    if ((dev->num_parts < dev->part) && dev->can_append()) {
475       dev->num_parts = dev->part;
476       
477       /* Check that the next part file does not exists.
478        * If it does, move it away... */
479       POOL_MEM archive_name(PM_FNAME);
480       POOL_MEM archive_bkp_name(PM_FNAME);
481       struct stat buf;
482       
483       Dmsg1(100, "Call get_filename. Vol=%s\n", dev->VolCatInfo.VolCatName);
484       get_filename(dev, dev->VolCatInfo.VolCatName, archive_name);
485       
486       /* Check if the next part exists. */
487       if ((stat(archive_name.c_str(), &buf) == 0) || (errno != ENOENT)) {
488          Dmsg1(29, "open_next_part %s is in the way, moving it away...\n", archive_name.c_str());
489          pm_strcpy(archive_bkp_name, archive_name.c_str());
490          pm_strcat(archive_bkp_name, ".bak");
491          unlink(archive_bkp_name.c_str()); 
492          
493          /* First try to rename it */
494          if (rename(archive_name.c_str(), archive_bkp_name.c_str()) < 0) {
495             berrno be;
496             Dmsg3(29, "open_next_part can't rename %s to %s, ERR=%s\n", 
497                   archive_name.c_str(), archive_bkp_name.c_str(), be.strerror());
498             /* Then try to unlink it */
499             if (unlink(archive_name.c_str()) < 0) {
500                berrno be;
501                dev->dev_errno = errno;
502                Mmsg2(&dev->errmsg, _("open_next_part can't unlink existing part %s, ERR=%s\n"), 
503                       archive_name.c_str(), be.strerror());
504                Emsg0(M_FATAL, 0, dev->errmsg);
505                return -1;
506             }
507          }
508       }
509    }
510    
511    Dmsg2(50, "Call dev->open(vol=%s, mode=%d", dev->VolCatInfo.VolCatName, 
512          dev->openmode);
513    if (dev->open(dev->VolCatInfo.VolCatName, dev->openmode) < 0) {
514       return -1;
515    } 
516    return dev->fd;
517 }
518
519 /* Open the first part file.
520  *  - Close the fd
521  *  - Reopen the device
522  */
523 int open_first_part(DEVICE *dev, int mode)
524 {
525    Dmsg3(29, "Enter: open_first_part dev=%s Vol=%s mode=%d\n", dev->dev_name, 
526          dev->VolCatInfo.VolCatName, dev->openmode);
527    if (dev->fd >= 0) {
528       close(dev->fd);
529    }
530    dev->fd = -1;
531    dev->clear_opened();
532    
533    dev->part_start = 0;
534    dev->part = 0;
535    
536    Dmsg2(50, "Call dev->open(vol=%s, mode=%d)\n", dev->VolCatInfo.VolCatName, 
537          mode);
538    if (dev->open(dev->VolCatInfo.VolCatName, mode) < 0) {
539       Dmsg0(50, "open dev() failed\n");
540       return -1;
541    }
542    Dmsg1(50, "Leave open_first_part state=%s\n", dev->is_open()?"open":"not open");
543    return dev->fd;
544 }
545
546
547 /* Protected version of lseek, which opens the right part if necessary */
548 off_t lseek_dev(DEVICE *dev, off_t offset, int whence)
549 {
550    int pos, openmode;
551    
552    if (dev->num_parts == 0) { /* If there is only one part, simply call lseek. */
553       return lseek(dev->fd, offset, whence);
554    }
555       
556    switch(whence) {
557    case SEEK_SET:
558       Dmsg1(100, "lseek_dev SEEK_SET called %d\n", offset);
559       if ((uint64_t)offset >= dev->part_start) {
560          if ((uint64_t)(offset - dev->part_start) < dev->part_size) {
561             /* We are staying in the current part, just seek */
562             if ((pos = lseek(dev->fd, (off_t)(offset-dev->part_start), SEEK_SET)) < 0) {
563                return pos;   
564             } else {
565                return pos + dev->part_start;
566             }
567          } else {
568             /* Load next part, and start again */
569             if (open_next_part(dev) < 0) {
570                Dmsg0(100, "lseek_dev failed while trying to open the next part\n");
571                return -1;
572             }
573             return lseek_dev(dev, offset, SEEK_SET);
574          }
575       } else {
576          /* pos < dev->part_start :
577           * We need to access a previous part, 
578           * so just load the first one, and seek again
579           * until the right one is loaded */
580          if (open_first_part(dev, dev->openmode) < 0) {
581             Dmsg0(100, "lseek_dev failed while trying to open the first part\n");
582             return -1;
583          }
584          return lseek_dev(dev, offset, SEEK_SET);
585       }
586       break;
587    case SEEK_CUR:
588       Dmsg1(100, "lseek_dev SEEK_CUR called %d\n", offset);
589       if ((pos = lseek(dev->fd, (off_t)0, SEEK_CUR)) < 0) {
590          return pos;   
591       }
592       pos += dev->part_start;
593       if (offset == 0) {
594          return pos;
595       }
596       else { /* Not used in Bacula, but should work */
597          return lseek_dev(dev, pos, SEEK_SET);
598       }
599       break;
600    case SEEK_END:
601       Dmsg1(100, "lseek_dev SEEK_END called %d\n", offset);
602       if (offset > 0) { /* Not used by bacula */
603          Dmsg1(100, "lseek_dev SEEK_END called with an invalid offset %d\n", offset);
604          errno = EINVAL;
605          return -1;
606       }
607       
608       if (dev->part == dev->num_parts) { /* The right part is already loaded */
609          if ((pos = lseek(dev->fd, (off_t)0, SEEK_END)) < 0) {
610             return pos;   
611          } else {
612             return pos + dev->part_start;
613          }
614       } else {
615          /* Load the first part, then load the next until we reach the last one.
616           * This is the only way to be sure we compute the right file address. */
617          /* Save previous openmode, and open all but last part read-only (useful for DVDs) */
618          openmode = dev->openmode;
619          
620          /* Works because num_parts > 0. */
621          if (open_first_part(dev, OPEN_READ_ONLY) < 0) {
622             Dmsg0(100, "lseek_dev failed while trying to open the first part\n");
623             return -1;
624          }
625          while (dev->part < (dev->num_parts-1)) {
626             if (open_next_part(dev) < 0) {
627                Dmsg0(100, "lseek_dev failed while trying to open the next part\n");
628                return -1;
629             }
630          }
631          dev->openmode = openmode;
632          if (open_next_part(dev) < 0) {
633             Dmsg0(100, "lseek_dev failed while trying to open the next part\n");
634             return -1;
635          }
636          return lseek_dev(dev, 0, SEEK_END);
637       }
638       break;
639    default:
640       errno = EINVAL;
641       return -1;
642    }
643 }
644
645 bool dvd_close_job(DCR *dcr)
646 {
647    DEVICE *dev = dcr->dev;
648    JCR *jcr = dcr->jcr;
649    bool ok = true;
650
651    /* If the device is a dvd and WritePartAfterJob
652     * is set to yes, open the next part, so, in case of a device
653     * that requires mount, it will be written to the device.
654     */
655    if (dev->is_dvd() && jcr->write_part_after_job && (dev->part_size > 0)) {
656       Dmsg0(100, "Writing last part because write_part_after_job is set.\n");
657       if (dev->part < dev->num_parts) {
658          Jmsg3(jcr, M_FATAL, 0, _("Error while writing, current part number is less than the total number of parts (%d/%d, device=%s)\n"),
659                dev->part, dev->num_parts, dev->print_name());
660          dev->dev_errno = EIO;
661          ok = false;
662       }
663       
664       if (ok && (open_next_part(dev) < 0)) {
665          Jmsg2(jcr, M_FATAL, 0, _("Unable to open device next part %s: ERR=%s\n"),
666                dev->print_name(), strerror_dev(dev));
667          dev->dev_errno = EIO;
668          ok = false;
669       }
670       
671       dev->VolCatInfo.VolCatParts = dev->num_parts;
672    }
673    return ok;
674 }
675
676
677 /*
678  * Edit codes into (Un)MountCommand, Write(First)PartCommand
679  *  %% = %
680  *  %a = archive device name
681  *  %m = mount point
682  *  %v = last part name
683  *
684  *  omsg = edited output message
685  *  imsg = input string containing edit codes (%x)
686  *
687  */
688 static char *edit_device_codes_dev(DEVICE* dev, char *omsg, const char *imsg)
689 {
690    const char *p;
691    const char *str;
692    char add[20];
693    
694    POOL_MEM archive_name(PM_FNAME);
695    get_filename(dev, dev->VolCatInfo.VolCatName, archive_name);
696
697    *omsg = 0;
698    Dmsg1(800, "edit_device_codes: %s\n", imsg);
699    for (p=imsg; *p; p++) {
700       if (*p == '%') {
701          switch (*++p) {
702          case '%':
703             str = "%";
704             break;
705          case 'n':
706             bsnprintf(add, sizeof(add), "%d", dev->part);
707             str = add;
708             break;
709          case 'a':
710             str = dev->dev_name;
711             break;
712          case 'm':
713             str = dev->device->mount_point;
714             break;
715          case 'v':
716             str = archive_name.c_str();
717             break;
718          default:
719             add[0] = '%';
720             add[1] = *p;
721             add[2] = 0;
722             str = add;
723             break;
724          }
725       } else {
726          add[0] = *p;
727          add[1] = 0;
728          str = add;
729       }
730       Dmsg1(900, "add_str %s\n", str);
731       pm_strcat(&omsg, (char *)str);
732       Dmsg1(800, "omsg=%s\n", omsg);
733    }
734    return omsg;
735 }