]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/autochanger.c
f3438f326dab01f066cb1ab66de27a1d0419259b
[bacula/bacula] / bacula / src / stored / autochanger.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2002-2010 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version three of the GNU Affero General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU Affero General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of Kern Sibbald.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  *
30  *  Routines for handling the autochanger.
31  *
32  *   Kern Sibbald, August MMII
33  *                            
34  */
35
36 #include "bacula.h"                   /* pull in global headers */
37 #include "stored.h"                   /* pull in Storage Deamon headers */
38
39 /* Forward referenced functions */
40 static void lock_changer(DCR *dcr);
41 static void unlock_changer(DCR *dcr);
42 static bool unload_other_drive(DCR *dcr, int slot);
43
44 /* Init all the autochanger resources found */
45 bool init_autochangers()
46 {
47    bool OK = true;
48    AUTOCHANGER *changer;
49    /* Ensure that the media_type for each device is the same */
50    foreach_res(changer, R_AUTOCHANGER) {
51       DEVRES *device;
52       foreach_alist(device, changer->device) {
53          /*
54           * If the device does not have a changer name or changer command
55           *   defined, used the one from the Autochanger resource 
56           */
57          if (!device->changer_name && changer->changer_name) {
58             device->changer_name = bstrdup(changer->changer_name);
59          }
60          if (!device->changer_command && changer->changer_command) {
61             device->changer_command = bstrdup(changer->changer_command);
62          }
63          if (!device->changer_name) {
64             Jmsg(NULL, M_ERROR, 0, 
65                _("No Changer Name given for device %s. Cannot continue.\n"),
66                device->hdr.name);
67             OK = false;
68          }   
69          if (!device->changer_command) {
70             Jmsg(NULL, M_ERROR, 0, 
71                _("No Changer Command given for device %s. Cannot continue.\n"),
72                device->hdr.name);
73             OK = false;
74          }   
75
76 #ifdef xxx_needed
77          if (media_type == NULL) {
78             media_type = device->media_type;     /* get Media Type of first device */
79             continue;
80          }     
81          /* Ensure that other devices Media Types are the same */
82          if (strcmp(media_type, device->media_type) != 0) {
83             Jmsg(NULL, M_ERROR, 0, 
84                _("Media Type not the same for all devices in changer %s. Cannot continue.\n"),
85                changer->hdr.name);
86             OK = false;
87             continue;
88          }
89 #endif
90       }
91    }
92    return OK;
93 }
94
95
96 /*
97  * Called here to do an autoload using the autochanger, if
98  *  configured, and if a Slot has been defined for this Volume.
99  *  On success this routine loads the indicated tape, but the
100  *  label is not read, so it must be verified.
101  *
102  *  Note if dir is not NULL, it is the console requesting the
103  *   autoload for labeling, so we respond directly to the
104  *   dir bsock.
105  *
106  *  Returns: 1 on success
107  *           0 on failure (no changer available)
108  *          -1 on error on autochanger
109  */
110 int autoload_device(DCR *dcr, int writing, BSOCK *dir)
111 {
112    JCR *jcr = dcr->jcr;
113    DEVICE * volatile dev = dcr->dev;
114    int slot;
115    int drive = dev->drive_index;
116    int rtn_stat = -1;                 /* error status */
117    POOLMEM *changer;
118
119    if (!dev->is_autochanger()) {
120       Dmsg1(100, "Device %s is not an autochanger\n", dev->print_name());
121       return 0;
122    }
123
124    /* An empty ChangerCommand => virtual disk autochanger */
125    if (dcr->device->changer_command && dcr->device->changer_command[0] == 0) {
126       Dmsg0(100, "ChangerCommand=0, virtual disk changer\n");
127       return 1;                       /* nothing to load */
128    }
129
130    slot = dcr->VolCatInfo.InChanger ? dcr->VolCatInfo.Slot : 0;
131    Dmsg3(100, "autoload: slot=%d InChgr=%d Vol=%s\n", dcr->VolCatInfo.Slot,
132          dcr->VolCatInfo.InChanger, dcr->getVolCatName());
133    /*
134     * Handle autoloaders here.  If we cannot autoload it, we
135     *  will return 0 so that the sysop will be asked to load it.
136     */
137    if (writing && slot <= 0) {
138       if (dir) {
139          return 0;                    /* For user, bail out right now */
140       }
141       /* ***FIXME*** this really should not be here */
142       if (dir_find_next_appendable_volume(dcr)) {
143          slot = dcr->VolCatInfo.InChanger ? dcr->VolCatInfo.Slot : 0;
144       } else {
145          slot = 0;
146       }
147    }
148    Dmsg1(400, "Want changer slot=%d\n", slot);
149
150    changer = get_pool_memory(PM_FNAME);
151    if (slot <= 0) {
152       /* Suppress info when polling */
153       if (!dev->poll) {
154          Jmsg(jcr, M_INFO, 0, _("No slot defined in catalog (slot=%d) for Volume \"%s\" on %s.\n"), 
155               slot, dcr->getVolCatName(), dev->print_name());
156          Jmsg(jcr, M_INFO, 0, _("Cartridge change or \"update slots\" may be required.\n"));
157       }
158       rtn_stat = 0;
159    } else if (!dcr->device->changer_name) {
160       /* Suppress info when polling */
161       if (!dev->poll) {
162          Jmsg(jcr, M_INFO, 0, _("No \"Changer Device\" for %s. Manual load of Volume may be required.\n"),
163               dev->print_name());
164       }
165       rtn_stat = 0;
166   } else if (!dcr->device->changer_command) {
167       /* Suppress info when polling */
168       if (!dev->poll) {
169          Jmsg(jcr, M_INFO, 0, _("No \"Changer Command\" for %s. Manual load of Volume may be requird.\n"),
170               dev->print_name());
171       }
172       rtn_stat = 0;
173   } else {
174       /* Attempt to load the Volume */
175
176       uint32_t timeout = dcr->device->max_changer_wait;
177       int loaded, status;
178
179       loaded = get_autochanger_loaded_slot(dcr);
180
181       if (loaded != slot) {
182          POOL_MEM results(PM_MESSAGE);
183
184          /* Unload anything in our drive */
185          if (!unload_autochanger(dcr, loaded)) {
186             goto bail_out;
187          }
188             
189          /* Make sure desired slot is unloaded */
190          if (!unload_other_drive(dcr, slot)) {
191             goto bail_out;
192          }
193
194          /*
195           * Load the desired cassette
196           */
197          lock_changer(dcr);
198          Dmsg2(100, "Doing changer load slot %d %s\n", slot, dev->print_name());
199          Jmsg(jcr, M_INFO, 0,
200               _("3304 Issuing autochanger \"load slot %d, drive %d\" command.\n"),
201               slot, drive);
202          dcr->VolCatInfo.Slot = slot;    /* slot to be loaded */
203          changer = edit_device_codes(dcr, changer, dcr->device->changer_command, "load");
204          dev->close();
205          Dmsg1(200, "Run program=%s\n", changer);
206          status = run_program_full_output(changer, timeout, results.addr());
207          if (status == 0) {
208             Jmsg(jcr, M_INFO, 0, _("3305 Autochanger \"load slot %d, drive %d\", status is OK.\n"),
209                     slot, drive);
210             Dmsg2(100, "load slot %d, drive %d, status is OK.\n", slot, drive);
211             dev->set_slot(slot);      /* set currently loaded slot */
212          } else {
213             berrno be;
214             be.set_errno(status);
215             Dmsg3(100, "load slot %d, drive %d, bad stats=%s.\n", slot, drive,
216                be.bstrerror());
217             Jmsg(jcr, M_FATAL, 0, _("3992 Bad autochanger \"load slot %d, drive %d\": "
218                  "ERR=%s.\nResults=%s\n"),
219                     slot, drive, be.bstrerror(), results.c_str());
220             rtn_stat = -1;            /* hard error */
221             dev->set_slot(-1);        /* mark unknown */
222          }
223          Dmsg2(100, "load slot %d status=%d\n", slot, status);
224          unlock_changer(dcr);
225       } else {
226          status = 0;                  /* we got what we want */
227          dev->set_slot(slot);         /* set currently loaded slot */
228       }
229       Dmsg1(100, "After changer, status=%d\n", status);
230       if (status == 0) {              /* did we succeed? */
231          rtn_stat = 1;                /* tape loaded by changer */
232       }
233    }
234    free_pool_memory(changer);
235    return rtn_stat;
236
237 bail_out:
238    free_pool_memory(changer);
239    return -1;
240
241 }
242
243 /*
244  * Returns: -1 if error from changer command
245  *          slot otherwise
246  *  Note, this is safe to do without releasing the drive
247  *   since it does not attempt load/unload a slot.
248  */
249 int get_autochanger_loaded_slot(DCR *dcr)
250 {
251    JCR *jcr = dcr->jcr;
252    DEVICE *dev = dcr->dev;
253    int status, loaded;
254    uint32_t timeout = dcr->device->max_changer_wait;
255    int drive = dcr->dev->drive_index;
256    POOL_MEM results(PM_MESSAGE);
257    POOLMEM *changer;
258
259    if (!dev->is_autochanger()) {
260       return -1;
261    }
262    if (!dcr->device->changer_command) {
263 //    Jmsg(jcr, M_FATAL, 0, _("3992 Missing Changer command.\n"));
264       return -1;
265    }
266    if (dev->get_slot() > 0) {
267       return dev->get_slot();
268    }
269
270    /* Virtual disk autochanger */
271    if (dcr->device->changer_command[0] == 0) {
272       return 1;
273    }
274
275    /* Find out what is loaded, zero means device is unloaded */
276    changer = get_pool_memory(PM_FNAME);
277    lock_changer(dcr);
278    /* Suppress info when polling */
279    if (!dev->poll) {
280       Jmsg(jcr, M_INFO, 0, _("3301 Issuing autochanger \"loaded? drive %d\" command.\n"),
281            drive);
282    }
283    changer = edit_device_codes(dcr, changer, dcr->device->changer_command, "loaded");
284    Dmsg1(100, "Run program=%s\n", changer);
285    status = run_program_full_output(changer, timeout, results.addr());
286    Dmsg3(100, "run_prog: %s stat=%d result=%s", changer, status, results.c_str());
287    if (status == 0) {
288       loaded = str_to_int32(results.c_str());
289       if (loaded > 0) {
290          /* Suppress info when polling */
291          if (!dev->poll) {
292             Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded? drive %d\", result is Slot %d.\n"),
293                  drive, loaded);
294          }
295          dev->set_slot(loaded);
296       } else {
297          /* Suppress info when polling */
298          if (!dev->poll) {
299             Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded? drive %d\", result: nothing loaded.\n"),
300                  drive);
301          }
302          dev->clear_slot();   /* unknown */
303       }
304    } else {
305       berrno be;
306       be.set_errno(status);
307       Jmsg(jcr, M_INFO, 0, _("3991 Bad autochanger \"loaded? drive %d\" command: "
308            "ERR=%s.\nResults=%s\n"), drive, be.bstrerror(), results.c_str());
309       loaded = -1;              /* force unload */
310    }
311    unlock_changer(dcr);
312    free_pool_memory(changer);
313    return loaded;
314 }
315
316 static void lock_changer(DCR *dcr)
317 {
318    AUTOCHANGER *changer_res = dcr->device->changer_res;
319    if (changer_res) {
320       Dmsg1(200, "Locking changer %s\n", changer_res->hdr.name);
321       P(changer_res->changer_mutex);  /* Lock changer script */
322    }
323 }
324
325 static void unlock_changer(DCR *dcr)
326 {
327    AUTOCHANGER *changer_res = dcr->device->changer_res;
328    if (changer_res) {
329       Dmsg1(200, "Unlocking changer %s\n", changer_res->hdr.name);
330       V(changer_res->changer_mutex);  /* Unlock changer script */
331    }
332 }
333
334 /*
335  * Unload the volume, if any, in this drive
336  *  On entry: loaded == 0 -- nothing to do
337  *            loaded  < 0 -- check if anything to do
338  *            loaded  > 0 -- load slot == loaded
339  */
340 bool unload_autochanger(DCR *dcr, int loaded)
341 {
342    DEVICE *dev = dcr->dev;
343    JCR *jcr = dcr->jcr;
344    int slot;
345    uint32_t timeout = dcr->device->max_changer_wait;
346    bool ok = true;
347
348    if (loaded == 0) {
349       return true;
350    }
351
352    if (!dev->is_autochanger() || !dcr->device->changer_name ||
353        !dcr->device->changer_command) {
354       return false;
355    }
356
357    /* Virtual disk autochanger */
358    if (dcr->device->changer_command[0] == 0) {
359       dev->clear_unload();
360       return true;
361    }
362
363    if (loaded < 0) {
364       loaded = get_autochanger_loaded_slot(dcr);
365    }
366
367    if (loaded > 0) {
368       POOL_MEM results(PM_MESSAGE);
369       POOLMEM *changer = get_pool_memory(PM_FNAME);
370       lock_changer(dcr);
371       Jmsg(jcr, M_INFO, 0,
372            _("3307 Issuing autochanger \"unload slot %d, drive %d\" command.\n"),
373            loaded, dev->drive_index);
374       slot = dcr->VolCatInfo.Slot;
375       dcr->VolCatInfo.Slot = loaded;
376       changer = edit_device_codes(dcr, changer, 
377                    dcr->device->changer_command, "unload");
378       dev->close();
379       Dmsg1(100, "Run program=%s\n", changer);
380       int stat = run_program_full_output(changer, timeout, results.addr());
381       dcr->VolCatInfo.Slot = slot;
382       if (stat != 0) {
383          berrno be;
384          be.set_errno(stat);
385          Jmsg(jcr, M_INFO, 0, _("3995 Bad autochanger \"unload slot %d, drive %d\": "
386               "ERR=%s\nResults=%s\n"),
387                  loaded, dev->drive_index, be.bstrerror(), results.c_str());
388          ok = false;
389          dev->clear_slot();        /* unknown */
390       } else {
391          dev->set_slot(0);         /* nothing loaded */
392       }
393       unlock_changer(dcr);
394
395       free_volume(dev);            /* Free any volume associated with this drive */
396       free_pool_memory(changer);
397    }
398    if (ok) {
399       dev->clear_unload();
400    }
401    return ok;
402 }
403
404 /*
405  * Unload the slot if mounted in a different drive
406  */
407 static bool unload_other_drive(DCR *dcr, int slot)
408 {
409    DEVICE *dev = NULL;
410    bool found = false;
411    AUTOCHANGER *changer = dcr->dev->device->changer_res;
412    DEVRES *device;
413    int retries = 0;                /* wait for device retries */
414
415    if (!changer) {
416       return false;
417    }
418    if (changer->device->size() == 1) {
419       return true;
420    }
421
422    foreach_alist(device, changer->device) {
423       if (device->dev && device->dev->get_slot() == slot) {
424          found = true;
425          dev = device->dev;
426          break;
427       }
428    }
429    if (!found) {
430       return true;
431    }
432
433    /* The Volume we want is on another device. */
434    if (dev->is_busy()) {
435       Dmsg4(100, "Vol %s for dev=%s in use dev=%s slot=%d\n",
436            dcr->VolumeName, dcr->dev->print_name(),
437            dev->print_name(), slot);
438    }   
439    for (int i=0; i < 3; i++) {
440       if (dev->is_busy()) {
441          wait_for_device(dcr->jcr, retries);
442          continue;
443       }
444       break;
445    }
446    if (dev->is_busy()) {
447       Jmsg(dcr->jcr, M_WARNING, 0, _("Volume \"%s\" wanted on %s is in use by device %s\n"),
448            dcr->VolumeName, dcr->dev->print_name(), dev->print_name());
449       Dmsg4(100, "Vol %s for dev=%s is busy dev=%s slot=%d\n",
450            dcr->VolumeName, dcr->dev->print_name(), dev->print_name(), dev->get_slot());
451       Dmsg2(100, "num_writ=%d reserv=%d\n", dev->num_writers, dev->num_reserved());
452       volume_unused(dcr);
453       return false;
454    }
455    return unload_dev(dcr, dev);
456 }
457
458 /*
459  * Unconditionally unload a specified drive
460  */
461 bool unload_dev(DCR *dcr, DEVICE *dev)
462 {
463    JCR *jcr = dcr->jcr;
464    bool ok = true;
465    uint32_t timeout = dcr->device->max_changer_wait;
466    AUTOCHANGER *changer = dcr->dev->device->changer_res;
467    DEVICE *save_dev;
468    int save_slot;
469
470    if (!changer) {
471       return false;
472    }
473
474    save_dev = dcr->dev;               /* save dcr device */
475    dcr->dev = dev;                    /* temporarily point dcr at other device */
476
477    if (dev->get_slot() <= 0 && get_autochanger_loaded_slot(dcr) <= 0) {
478       dcr->dev = save_dev;
479       return false;
480    }
481    save_slot = dcr->VolCatInfo.Slot;
482    dcr->VolCatInfo.Slot = dev->get_slot();
483
484 //   dev->dlock();
485
486    POOLMEM *changer_cmd = get_pool_memory(PM_FNAME);
487    POOL_MEM results(PM_MESSAGE);
488    lock_changer(dcr);
489    Jmsg(jcr, M_INFO, 0,
490         _("3307 Issuing autochanger \"unload slot %d, drive %d\" command.\n"),
491         dev->get_slot(), dev->drive_index);
492
493    Dmsg2(100, "Issuing autochanger \"unload slot %d, drive %d\" command.\n",
494         dev->get_slot(), dev->drive_index);
495
496    changer_cmd = edit_device_codes(dcr, changer_cmd, 
497                 dcr->device->changer_command, "unload");
498    dev->close();
499    Dmsg2(200, "close dev=%s reserve=%d\n", dev->print_name(), 
500       dev->num_reserved());
501    Dmsg1(100, "Run program=%s\n", changer_cmd);
502    int stat = run_program_full_output(changer_cmd, timeout, results.addr());
503    dcr->VolCatInfo.Slot = save_slot;
504    dcr->dev = save_dev;
505    if (stat != 0) {
506       berrno be;
507       be.set_errno(stat);
508       Jmsg(jcr, M_INFO, 0, _("3995 Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n"),
509               dev->get_slot(), dev->drive_index, be.bstrerror());
510
511       Dmsg3(100, "Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n",
512               dev->get_slot(), dev->drive_index, be.bstrerror());
513       ok = false;
514       dev->clear_slot();          /* unknown */
515    } else {
516       Dmsg2(100, "Slot %d unloaded %s\n", dev->get_slot(), dev->print_name());
517       dev->set_slot(0);           /* nothing loaded */
518    }
519    if (ok) {
520       dev->clear_unload();
521    }
522    unlock_changer(dcr);
523
524 //   dev->dunlock();
525
526    free_volume(dev);               /* Free any volume associated with this drive */
527    free_pool_memory(changer_cmd);
528    return ok;
529 }
530
531
532
533 /*
534  * List the Volumes that are in the autoloader possibly
535  *   with their barcodes.
536  *   We assume that it is always the Console that is calling us.
537  */
538 bool autochanger_cmd(DCR *dcr, BSOCK *dir, const char *cmd)  
539 {
540    DEVICE *dev = dcr->dev;
541    uint32_t timeout = dcr->device->max_changer_wait;
542    POOLMEM *changer;
543    BPIPE *bpipe;
544    int len = sizeof_pool_memory(dir->msg) - 1;
545    bool ok = false;
546    int stat;
547
548    if (!dev->is_autochanger() || !dcr->device->changer_name ||
549        !dcr->device->changer_command) {
550       if (strcmp(cmd, "drives") == 0) {
551          dir->fsend("drives=1\n");
552       }
553       dir->fsend(_("3993 Device %s not an autochanger device.\n"),
554          dev->print_name());
555       return false;
556    }
557
558    if (strcmp(cmd, "drives") == 0) {
559       AUTOCHANGER *changer_res = dcr->device->changer_res;
560       int drives = 1;
561       if (changer_res) {
562          drives = changer_res->device->size();
563       }
564       dir->fsend("drives=%d\n", drives);
565       Dmsg1(100, "drives=%d\n", drives);
566       return true;
567    }
568
569    changer = get_pool_memory(PM_FNAME);
570    lock_changer(dcr);
571    /* Now issue the command */
572    changer = edit_device_codes(dcr, changer, 
573                  dcr->device->changer_command, cmd);
574    dir->fsend(_("3306 Issuing autochanger \"%s\" command.\n"), cmd);
575    bpipe = open_bpipe(changer, timeout, "r");
576    if (!bpipe) {
577       dir->fsend(_("3996 Open bpipe failed.\n"));
578       goto bail_out;
579    }
580    if (bstrcmp(cmd, "list") || bstrcmp(cmd, "listall")) {
581       /* Get output from changer */
582       while (fgets(dir->msg, len, bpipe->rfd)) {
583          dir->msglen = strlen(dir->msg);
584          Dmsg1(100, "<stored: %s\n", dir->msg);
585          bnet_send(dir);
586       }
587    } else if (strcmp(cmd, "slots") == 0 ) {
588       char buf[100], *p;
589       /* For slots command, read a single line */
590       buf[0] = 0;
591       fgets(buf, sizeof(buf)-1, bpipe->rfd);
592       buf[sizeof(buf)-1] = 0;
593       /* Strip any leading space in front of # of slots */
594       for (p=buf; B_ISSPACE(*p); p++)
595         { }
596       dir->fsend("slots=%s", p);
597       Dmsg1(100, "<stored: %s", dir->msg);
598    } 
599                  
600    stat = close_bpipe(bpipe);
601    if (stat != 0) {
602       berrno be;
603       be.set_errno(stat);
604       dir->fsend(_("Autochanger error: ERR=%s\n"), be.bstrerror());
605    }
606    bnet_sig(dir, BNET_EOD);
607    ok = true;
608
609 bail_out:
610    unlock_changer(dcr);
611    free_pool_memory(changer);
612    return true;
613 }
614
615
616 /*
617  * Edit codes into ChangerCommand
618  *  %% = %
619  *  %a = archive device name
620  *  %c = changer device name
621  *  %d = changer drive index
622  *  %f = Client's name
623  *  %j = Job name
624  *  %o = command
625  *  %s = Slot base 0
626  *  %S = Slot base 1
627  *  %v = Volume name
628  *
629  *
630  *  omsg = edited output message
631  *  imsg = input string containing edit codes (%x)
632  *  cmd = command string (load, unload, ...)
633  *
634  */
635 char *edit_device_codes(DCR *dcr, char *omsg, const char *imsg, const char *cmd)
636 {
637    const char *p;
638    const char *str;
639    char add[20];
640
641    *omsg = 0;
642    Dmsg1(1800, "edit_device_codes: %s\n", imsg);
643    for (p=imsg; *p; p++) {
644       if (*p == '%') {
645          switch (*++p) {
646          case '%':
647             str = "%";
648             break;
649          case 'a':
650             str = dcr->dev->archive_name();
651             break;
652          case 'c':
653             str = NPRT(dcr->device->changer_name);
654             break;
655          case 'd':
656             sprintf(add, "%d", dcr->dev->drive_index);
657             str = add;
658             break;
659          case 'o':
660             str = NPRT(cmd);
661             break;
662          case 's':
663             sprintf(add, "%d", dcr->VolCatInfo.Slot - 1);
664             str = add;
665             break;
666          case 'S':
667             sprintf(add, "%d", dcr->VolCatInfo.Slot);
668             str = add;
669             break;
670          case 'j':                    /* Job name */
671             str = dcr->jcr->Job;
672             break;
673          case 'v':
674             if (dcr->VolCatInfo.VolCatName[0]) {
675                str = dcr->VolCatInfo.VolCatName;
676             } else if (dcr->VolumeName[0]) {
677                str = dcr->VolumeName;
678             } else if (dcr->dev->vol && dcr->dev->vol->vol_name) {
679                str = dcr->dev->vol->vol_name;
680             } else {
681                str = dcr->dev->VolHdr.VolumeName;
682             }
683             break;
684          case 'f':
685             str = NPRT(dcr->jcr->client_name);
686             break;
687
688          default:
689             add[0] = '%';
690             add[1] = *p;
691             add[2] = 0;
692             str = add;
693             break;
694          }
695       } else {
696          add[0] = *p;
697          add[1] = 0;
698          str = add;
699       }
700       Dmsg1(1900, "add_str %s\n", str);
701       pm_strcat(&omsg, (char *)str);
702       Dmsg1(1800, "omsg=%s\n", omsg);
703    }
704    Dmsg1(800, "omsg=%s\n", omsg);
705    return omsg;
706 }