2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2016 Kern Sibbald
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
21 * Routines for handling the autochanger.
23 * Written by Kern Sibbald, August MMII
27 #include "bacula.h" /* pull in global headers */
28 #include "stored.h" /* pull in Storage Deamon headers */
30 static const int dbglvl = 60;
32 /* Forward referenced functions */
33 static void lock_changer(DCR *dcr);
34 static void unlock_changer(DCR *dcr);
35 static bool unload_other_drive(DCR *dcr, int slot);
37 bool DCR::is_virtual_autochanger()
39 return device->changer_command &&
40 (device->changer_command[0] == 0 ||
41 strcmp(device->changer_command, "/dev/null") == 0);
44 /* Init all the autochanger resources found */
45 bool init_autochangers()
49 /* Ensure that the media_type for each device is the same */
50 foreach_res(changer, R_AUTOCHANGER) {
52 foreach_alist(device, changer->device) {
54 * If the device does not have a changer name or changer command
55 * defined, used the one from the Autochanger resource
57 if (!device->changer_name && changer->changer_name) {
58 device->changer_name = bstrdup(changer->changer_name);
60 if (!device->changer_command && changer->changer_command) {
61 device->changer_command = bstrdup(changer->changer_command);
63 if (!device->changer_name) {
64 Jmsg(NULL, M_ERROR, 0,
65 _("No Changer Name given for device %s. Cannot continue.\n"),
69 if (!device->changer_command) {
70 Jmsg(NULL, M_ERROR, 0,
71 _("No Changer Command given for device %s. Cannot continue.\n"),
82 * Called here to do an autoload using the autochanger, if
83 * configured, and if a Slot has been defined for this Volume.
84 * On success this routine loads the indicated tape, but the
85 * label is not read, so it must be verified.
87 * Note if dir is not NULL, it is the console requesting the
88 * autoload for labeling, so we respond directly to the
91 * Returns: 1 on success
92 * 0 on failure (no changer available)
93 * -1 on error on autochanger
95 int autoload_device(DCR *dcr, bool writing, BSOCK *dir)
98 DEVICE * volatile dev = dcr->dev;
99 char *vol_name = dcr->VolumeName;
101 int drive = dev->drive_index;
102 int rtn_stat = -1; /* error status */
105 if (!dev->is_autochanger()) {
106 Dmsg1(dbglvl, "Device %s is not an autochanger\n", dev->print_name());
110 /* An empty ChangerCommand => virtual disk autochanger */
111 if (dcr->is_virtual_autochanger()) {
112 Dmsg0(dbglvl, "ChangerCommand=0, virtual disk changer\n");
113 return 1; /* nothing to load */
116 slot = dcr->VolCatInfo.InChanger ? dcr->VolCatInfo.Slot : 0;
118 * Handle autoloaders here. If we cannot autoload it, we
119 * will return 0 so that the sysop will be asked to load it.
121 if (writing && slot <= 0) {
123 return 0; /* For user, bail out right now */
125 /* ***FIXME*** this really should not be here */
126 if (dir_find_next_appendable_volume(dcr)) {
127 slot = dcr->VolCatInfo.InChanger ? dcr->VolCatInfo.Slot : 0;
133 Dmsg4(dbglvl, "Want slot=%d drive=%d InChgr=%d Vol=%s\n",
134 dcr->VolCatInfo.Slot, drive,
135 dcr->VolCatInfo.InChanger, dcr->getVolCatName());
137 changer = get_pool_memory(PM_FNAME);
139 /* Suppress info when polling */
141 Jmsg(jcr, M_INFO, 0, _("No slot defined in catalog (slot=%d) for Volume \"%s\" on %s.\n"),
142 slot, dcr->getVolCatName(), dev->print_name());
143 Jmsg(jcr, M_INFO, 0, _("Cartridge change or \"update slots\" may be required.\n"));
146 } else if (!dcr->device->changer_name) {
147 /* Suppress info when polling */
149 Jmsg(jcr, M_INFO, 0, _("No \"Changer Device\" for %s. Manual load of Volume may be required.\n"),
153 } else if (!dcr->device->changer_command) {
154 /* Suppress info when polling */
156 Jmsg(jcr, M_INFO, 0, _("No \"Changer Command\" for %s. Manual load of Volume may be requird.\n"),
161 /* Attempt to load the Volume */
162 uint32_t timeout = dcr->device->max_changer_wait;
165 loaded = get_autochanger_loaded_slot(dcr);
166 if (loaded < 0) { /* Autochanger error, try again */
167 loaded = get_autochanger_loaded_slot(dcr);
169 Dmsg2(dbglvl, "Found loaded=%d drive=%d\n", loaded, drive);
171 if (loaded <= 0 || loaded != slot) {
172 POOL_MEM results(PM_MESSAGE);
174 /* Unload anything in our drive */
175 if (!unload_autochanger(dcr, loaded)) {
179 /* Make sure desired slot is unloaded */
180 if (!unload_other_drive(dcr, slot)) {
185 * Load the desired cassette
188 Dmsg2(dbglvl, "Doing changer load slot %d %s\n", slot, dev->print_name());
190 _("3304 Issuing autochanger \"load slot %d, drive %d\" command for vol %s.\n"),
191 slot, drive, vol_name);
192 dcr->VolCatInfo.Slot = slot; /* slot to be loaded */
193 changer = edit_device_codes(dcr, changer, dcr->device->changer_command, "load");
195 Dmsg1(dbglvl, "Run program=%s\n", changer);
196 status = run_program_full_output(changer, timeout, results.addr());
198 Jmsg(jcr, M_INFO, 0, _("3305 Autochanger \"load slot %d, drive %d\", status is OK for vol %s.\n"),
199 slot, drive, vol_name);
200 Dmsg3(dbglvl, "OK: load slot %d, drive %d vol %s.\n", slot, drive, vol_name);
201 dev->set_slot(slot); /* set currently loaded slot */
203 /* We just swapped this Volume so it cannot be swapping any more */
204 dev->vol->clear_swapping();
208 be.set_errno(status);
209 Dmsg4(dbglvl, "Error: load slot %d, drive %d, bad stats=%s.\nResults=%s\n", slot, drive,
210 be.bstrerror(), results.c_str());
211 Jmsg(jcr, M_FATAL, 0, _("3992 Bad autochanger \"load slot %d, drive %d\": "
212 "ERR=%s.\nResults=%s\n"),
213 slot, drive, be.bstrerror(), results.c_str());
214 rtn_stat = -1; /* hard error */
215 dev->clear_slot(); /* mark unknown */
219 status = 0; /* we got what we want */
220 dev->set_slot(slot); /* set currently loaded slot */
222 Dmsg1(dbglvl, "After changer, status=%d\n", status);
223 if (status == 0) { /* did we succeed? */
224 rtn_stat = 1; /* tape loaded by changer */
227 free_pool_memory(changer);
231 free_pool_memory(changer);
237 * Returns: -1 if error from changer command
239 * Note, this is safe to do without releasing the drive
240 * since it does not attempt load/unload a slot.
242 int get_autochanger_loaded_slot(DCR *dcr)
245 DEVICE *dev = dcr->dev;
247 uint32_t timeout = dcr->device->max_changer_wait;
248 int drive = dcr->dev->drive_index;
249 POOL_MEM results(PM_MESSAGE);
252 if (!dev->is_autochanger()) {
255 if (!dcr->device->changer_command) {
259 if (dev->get_slot() > 0 && dev->has_cap(CAP_ALWAYSOPEN)) {
260 Dmsg1(dbglvl, "Return cached slot=%d\n", dev->get_slot());
261 return dev->get_slot();
264 /* Virtual disk autochanger */
265 if (dcr->is_virtual_autochanger()) {
269 /* Find out what is loaded, zero means device is unloaded */
270 changer = get_pool_memory(PM_FNAME);
272 /* Suppress info when polling */
273 if (!dev->poll && chk_dbglvl(1)) {
274 Jmsg(jcr, M_INFO, 0, _("3301 Issuing autochanger \"loaded? drive %d\" command.\n"),
277 changer = edit_device_codes(dcr, changer, dcr->device->changer_command, "loaded");
278 Dmsg1(dbglvl, "Run program=%s\n", changer);
279 status = run_program_full_output(changer, timeout, results.addr());
280 Dmsg3(dbglvl, "run_prog: %s stat=%d result=%s", changer, status, results.c_str());
282 loaded = str_to_int32(results.c_str());
284 /* Suppress info when polling */
285 if (!dev->poll && chk_dbglvl(1)) {
286 Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded? drive %d\", result is Slot %d.\n"),
289 dev->set_slot(loaded);
291 /* Suppress info when polling */
292 if (!dev->poll && chk_dbglvl(1)) {
293 Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded? drive %d\", result: nothing loaded.\n"),
296 if (loaded == 0) { /* no slot loaded */
298 } else { /* probably some error */
299 dev->clear_slot(); /* unknown */
304 be.set_errno(status);
305 Jmsg(jcr, M_INFO, 0, _("3991 Bad autochanger \"loaded? drive %d\" command: "
306 "ERR=%s.\nResults=%s\n"), drive, be.bstrerror(), results.c_str());
307 Dmsg3(dbglvl, "Error: autochanger loaded? drive %d "
308 "ERR=%s.\nResults=%s\n", drive, be.bstrerror(), results.c_str());
309 loaded = -1; /* force unload */
310 dev->clear_slot(); /* slot unknown */
313 free_pool_memory(changer);
317 static void lock_changer(DCR *dcr)
319 AUTOCHANGER *changer_res = dcr->device->changer_res;
322 Dmsg1(dbglvl, "Locking changer %s\n", changer_res->hdr.name);
323 if ((errstat=rwl_writelock(&changer_res->changer_lock)) != 0) {
325 Jmsg(dcr->jcr, M_ERROR_TERM, 0, _("Lock failure on autochanger. ERR=%s\n"),
326 be.bstrerror(errstat));
331 static void unlock_changer(DCR *dcr)
333 AUTOCHANGER *changer_res = dcr->device->changer_res;
336 Dmsg1(dbglvl, "Unlocking changer %s\n", changer_res->hdr.name);
337 if ((errstat=rwl_writeunlock(&changer_res->changer_lock)) != 0) {
339 Jmsg(dcr->jcr, M_ERROR_TERM, 0, _("Unlock failure on autochanger. ERR=%s\n"),
340 be.bstrerror(errstat));
346 * Unload the volume, if any, in this drive
347 * On entry: loaded == 0 -- nothing to do
348 * loaded < 0 -- check if anything to do
349 * loaded > 0 -- load slot == loaded
351 bool unload_autochanger(DCR *dcr, int loaded)
353 DEVICE *dev = dcr->dev;
355 const char *vol_name = dcr->VolumeName;
357 uint32_t timeout = dcr->device->max_changer_wait;
364 if (!dev->is_autochanger() || !dcr->device->changer_name ||
365 !dcr->device->changer_command) {
369 /* Virtual disk autochanger */
370 if (dcr->is_virtual_autochanger()) {
376 if (!vol_name || !vol_name[0]) {
377 vol_name = "unknown";
380 loaded = get_autochanger_loaded_slot(dcr);
381 if (loaded < 0) { /* try again, maybe autochanger error */
382 loaded = get_autochanger_loaded_slot(dcr);
387 POOL_MEM results(PM_MESSAGE);
388 POOLMEM *changer = get_pool_memory(PM_FNAME);
390 _("3307 Issuing autochanger \"unload slot %d, drive %d\" command for vol %s.\n"),
391 loaded, dev->drive_index, vol_name);
392 slot = dcr->VolCatInfo.Slot;
393 dcr->VolCatInfo.Slot = loaded;
394 changer = edit_device_codes(dcr, changer,
395 dcr->device->changer_command, "unload");
397 Dmsg1(dbglvl, "Run program=%s\n", changer);
398 int stat = run_program_full_output(changer, timeout, results.addr());
399 dcr->VolCatInfo.Slot = slot;
403 Jmsg(jcr, M_INFO, 0, _("3995 Bad autochanger \"unload slot %d, drive %d\": "
404 "ERR=%s\nResults=%s\n"),
405 loaded, dev->drive_index, be.bstrerror(), results.c_str());
406 Dmsg4(dbglvl, "Error: load slot %d, drive %d, bad stats=%s.\nResults=%s\n",
407 loaded, dev->drive_index,
408 be.bstrerror(), results.c_str());
410 dev->clear_slot(); /* unknown */
412 dev->set_slot(0); /* unload is OK, mark nothing loaded */
415 free_pool_memory(changer);
426 * Unload the slot if mounted in a different drive
428 static bool unload_other_drive(DCR *dcr, int slot)
433 AUTOCHANGER *changer = dcr->dev->device->changer_res;
435 int retries = 0; /* wait for device retries */
439 if (!changer || !changer->device) {
442 if (changer->device->size() == 1) {
447 * We look for the slot number corresponding to the tape
448 * we want in other drives, and if possible, unload
451 Dmsg1(dbglvl, "Begin wiffle through devices looking for slot=%d\n", slot);
453 * foreach_alist(device, changer->device) {
455 * The above fails to loop through all devices. It is
456 * probably a compiler bug.
458 for (i=0; i < changer->device->size(); i++) {
459 device = (DEVRES *)changer->device->get(i);
462 Dmsg0(dbglvl, "No dev attached to device\n");
468 loaded = get_autochanger_loaded_slot(dcr);
469 dcr->set_dev(dev_save);
472 Dmsg4(dbglvl, "Want slot=%d, drive=%d loaded=%d dev=%s\n",
473 slot, dev->drive_index, loaded, dev->print_name());
474 if (loaded == slot) {
479 Dmsg4(dbglvl, "After slot=%d drive=%d loaded=%d dev=%s\n",
480 slot, dev->drive_index, loaded, dev->print_name());
483 Dmsg1(dbglvl, "End wiffle through devices looking for slot=%d\n", slot);
485 Dmsg1(dbglvl, "Slot=%d not found in another device\n", slot);
488 Dmsg3(dbglvl, "Slot=%d drive=%d found in dev=%s\n", slot, dev->drive_index, dev->print_name());
491 /* The Volume we want is on another device. */
492 if (dev->is_busy()) {
493 Dmsg4(dbglvl, "Vol %s for dev=%s in use dev=%s slot=%d\n",
494 dcr->VolumeName, dcr->dev->print_name(),
495 dev->print_name(), slot);
497 for (int i=0; i < 3; i++) {
498 if (dev->is_busy()) {
499 Dmsg0(40, "Device is busy. Calling wait_for_device()\n");
500 wait_for_device(dcr, retries);
505 if (dev->is_busy()) {
506 Jmsg(dcr->jcr, M_WARNING, 0, _("Volume \"%s\" wanted on %s is in use by device %s\n"),
507 dcr->VolumeName, dcr->dev->print_name(), dev->print_name());
508 Dmsg4(dbglvl, "Vol %s for dev=%s is busy dev=%s slot=%d\n",
509 dcr->VolumeName, dcr->dev->print_name(), dev->print_name(), dev->get_slot());
510 Dmsg2(dbglvl, "num_writ=%d reserv=%d\n", dev->num_writers, dev->num_reserved());
514 return unload_dev(dcr, dev);
518 * Unconditionally unload a specified drive
520 bool unload_dev(DCR *dcr, DEVICE *dev)
524 uint32_t timeout = dcr->device->max_changer_wait;
525 AUTOCHANGER *changer = dcr->dev->device->changer_res;
526 const char *vol_name = dcr->VolumeName;
534 save_dev = dcr->dev; /* save dcr device */
535 dcr->set_dev(dev); /* temporarily point dcr at other device */
537 get_autochanger_loaded_slot(dcr);
539 /* Fail if we have no slot to unload */
540 if (dev->get_slot() <= 0) {
541 if (dev->get_slot() < 0) {
542 Dmsg1(dbglvl, "Cannot unload, slot not defined. dev=%s\n",
545 dcr->set_dev(save_dev);
549 save_slot = dcr->VolCatInfo.Slot;
550 dcr->VolCatInfo.Slot = dev->get_slot();
553 POOLMEM *changer_cmd = get_pool_memory(PM_FNAME);
554 POOL_MEM results(PM_MESSAGE);
556 if (!vol_name || !vol_name[0]) {
557 vol_name = "unknown";
560 _("3307 Issuing autochanger \"unload slot %d, drive %d\" command for vol %s.\n"),
561 dev->get_slot(), dev->drive_index, vol_name);
563 Dmsg3(dbglvl, "Issuing autochanger \"unload slot %d, drive %d\" command for vol %.\n",
564 dev->get_slot(), dev->drive_index, vol_name);
566 changer_cmd = edit_device_codes(dcr, changer_cmd,
567 dcr->device->changer_command, "unload");
569 Dmsg2(dbglvl, "close dev=%s reserve=%d\n", dev->print_name(),
570 dev->num_reserved());
571 Dmsg1(dbglvl, "Run program=%s\n", changer_cmd);
572 int stat = run_program_full_output(changer_cmd, timeout, results.addr());
573 dcr->VolCatInfo.Slot = save_slot;
577 Jmsg(jcr, M_INFO, 0, _("3997 Bad autochanger \"unload slot %d, drive %d\" for vol %s: ERR=%s.\n"),
578 dev->get_slot(), dev->drive_index, vol_name, be.bstrerror());
579 Dmsg5(dbglvl, "Error: load slot %d, drive %d, vol %s bad stats=%s.\nResults=%s\n",
580 dev->get_slot(), dev->drive_index, vol_name,
581 be.bstrerror(), results.c_str());
583 dev->clear_slot(); /* unknown */
585 Dmsg3(dbglvl, "Slot %d vol %s unloaded %s\n", dev->get_slot(), vol_name, dev->print_name());
586 dev->set_slot(0); /* unload OK, mark nothing loaded */
594 dcr->set_dev(save_dev);
595 free_pool_memory(changer_cmd);
602 * List the Volumes that are in the autoloader possibly
603 * with their barcodes.
604 * We assume that it is always the Console that is calling us.
606 bool autochanger_cmd(DCR *dcr, BSOCK *dir, const char *cmd)
608 DEVICE *dev = dcr->dev;
609 uint32_t timeout = dcr->device->max_changer_wait;
612 int len = sizeof_pool_memory(dir->msg) - 1;
615 if (!dev->is_autochanger() || !dcr->device->changer_name ||
616 !dcr->device->changer_command) {
617 if (strcasecmp(cmd, "drives") == 0) {
618 dir->fsend("drives=1\n");
620 dir->fsend(_("3993 Device %s not an autochanger device.\n"),
625 if (strcasecmp(cmd, "drives") == 0) {
626 AUTOCHANGER *changer_res = dcr->device->changer_res;
628 if (changer_res && changer_res->device) {
629 drives = changer_res->device->size();
631 dir->fsend("drives=%d\n", drives);
632 Dmsg1(dbglvl, "drives=%d\n", drives);
636 /* If listing, reprobe changer */
637 if (bstrcasecmp(cmd, "list") || bstrcasecmp(cmd, "listall")) {
638 dcr->dev->set_slot(0);
639 get_autochanger_loaded_slot(dcr);
642 changer = get_pool_memory(PM_FNAME);
644 /* Now issue the command */
645 changer = edit_device_codes(dcr, changer,
646 dcr->device->changer_command, cmd);
647 dir->fsend(_("3306 Issuing autochanger \"%s\" command.\n"), cmd);
648 bpipe = open_bpipe(changer, timeout, "r");
650 dir->fsend(_("3996 Open bpipe failed.\n"));
651 goto bail_out; /* TODO: check if we need to return false */
653 if (bstrcasecmp(cmd, "list") || bstrcasecmp(cmd, "listall")) {
654 /* Get output from changer */
655 while (fgets(dir->msg, len, bpipe->rfd)) {
656 dir->msglen = strlen(dir->msg);
657 Dmsg1(dbglvl, "<stored: %s\n", dir->msg);
660 } else if (strcasecmp(cmd, "slots") == 0 ) {
662 /* For slots command, read a single line */
664 fgets(buf, sizeof(buf)-1, bpipe->rfd);
665 buf[sizeof(buf)-1] = 0;
666 /* Strip any leading space in front of # of slots */
667 for (p=buf; B_ISSPACE(*p); p++)
669 dir->fsend("slots=%s", p);
670 Dmsg1(dbglvl, "<stored: %s", dir->msg);
673 stat = close_bpipe(bpipe);
677 dir->fsend(_("Autochanger error: ERR=%s\n"), be.bstrerror());
682 free_pool_memory(changer);
688 * Edit codes into ChangerCommand
690 * %a = archive device name
691 * %c = changer device name
692 * %d = changer drive index
695 * %l = archive control channel name
702 * omsg = edited output message
703 * imsg = input string containing edit codes (%x)
704 * cmd = command string (load, unload, ...)
707 char *edit_device_codes(DCR *dcr, char *omsg, const char *imsg, const char *cmd)
714 Dmsg1(1800, "edit_device_codes: %s\n", imsg);
715 for (p=imsg; *p; p++) {
722 str = dcr->dev->archive_name();
725 str = NPRT(dcr->device->changer_name);
728 str = NPRT(dcr->device->control_name);
731 sprintf(add, "%d", dcr->dev->drive_index);
738 sprintf(add, "%d", dcr->VolCatInfo.Slot - 1);
742 sprintf(add, "%d", dcr->VolCatInfo.Slot);
745 case 'j': /* Job name */
749 if (dcr->VolCatInfo.VolCatName[0]) {
750 str = dcr->VolCatInfo.VolCatName;
751 } else if (dcr->VolumeName[0]) {
752 str = dcr->VolumeName;
753 } else if (dcr->dev->vol && dcr->dev->vol->vol_name) {
754 str = dcr->dev->vol->vol_name;
756 str = dcr->dev->VolHdr.VolumeName;
760 str = NPRT(dcr->jcr->client_name);
775 Dmsg1(1900, "add_str %s\n", str);
776 pm_strcat(&omsg, (char *)str);
777 Dmsg1(1800, "omsg=%s\n", omsg);
779 Dmsg1(800, "omsg=%s\n", omsg);