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