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