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;
100 int drive = dev->drive_index;
101 int rtn_stat = -1; /* error status */
104 if (!dev->is_autochanger()) {
105 Dmsg1(dbglvl, "Device %s is not an autochanger\n", dev->print_name());
109 /* An empty ChangerCommand => virtual disk autochanger */
110 if (dcr->is_virtual_autochanger()) {
111 Dmsg0(dbglvl, "ChangerCommand=0, virtual disk changer\n");
112 return 1; /* nothing to load */
115 slot = dcr->VolCatInfo.InChanger ? dcr->VolCatInfo.Slot : 0;
117 * Handle autoloaders here. If we cannot autoload it, we
118 * will return 0 so that the sysop will be asked to load it.
120 if (writing && slot <= 0) {
122 return 0; /* For user, bail out right now */
124 /* ***FIXME*** this really should not be here */
125 if (dir_find_next_appendable_volume(dcr)) {
126 slot = dcr->VolCatInfo.InChanger ? dcr->VolCatInfo.Slot : 0;
132 Dmsg4(dbglvl, "Want slot=%d drive=%d InChgr=%d Vol=%s\n",
133 dcr->VolCatInfo.Slot, drive,
134 dcr->VolCatInfo.InChanger, dcr->getVolCatName());
136 changer = get_pool_memory(PM_FNAME);
138 /* Suppress info when polling */
140 Jmsg(jcr, M_INFO, 0, _("No slot defined in catalog (slot=%d) for Volume \"%s\" on %s.\n"),
141 slot, dcr->getVolCatName(), dev->print_name());
142 Jmsg(jcr, M_INFO, 0, _("Cartridge change or \"update slots\" may be required.\n"));
145 } else if (!dcr->device->changer_name) {
146 /* Suppress info when polling */
148 Jmsg(jcr, M_INFO, 0, _("No \"Changer Device\" for %s. Manual load of Volume may be required.\n"),
152 } else if (!dcr->device->changer_command) {
153 /* Suppress info when polling */
155 Jmsg(jcr, M_INFO, 0, _("No \"Changer Command\" for %s. Manual load of Volume may be requird.\n"),
160 /* Attempt to load the Volume */
161 uint32_t timeout = dcr->device->max_changer_wait;
164 loaded = get_autochanger_loaded_slot(dcr);
165 if (loaded < 0) { /* Autochanger error, try again */
166 loaded = get_autochanger_loaded_slot(dcr);
168 Dmsg2(dbglvl, "Found loaded=%d drive=%d\n", loaded, drive);
170 if (loaded <= 0 || loaded != slot) {
171 POOL_MEM results(PM_MESSAGE);
173 /* Unload anything in our drive */
174 if (!unload_autochanger(dcr, loaded)) {
178 /* Make sure desired slot is unloaded */
179 if (!unload_other_drive(dcr, slot)) {
184 * Load the desired cassette
187 Dmsg2(dbglvl, "Doing changer load slot %d %s\n", slot, dev->print_name());
189 _("3304 Issuing autochanger \"load slot %d, drive %d\" command.\n"),
191 dcr->VolCatInfo.Slot = slot; /* slot to be loaded */
192 changer = edit_device_codes(dcr, changer, dcr->device->changer_command, "load");
194 Dmsg1(dbglvl, "Run program=%s\n", changer);
195 status = run_program_full_output(changer, timeout, results.addr());
197 Jmsg(jcr, M_INFO, 0, _("3305 Autochanger \"load slot %d, drive %d\", status is OK.\n"),
199 Dmsg2(dbglvl, "OK: load slot %d, drive %d.\n", slot, drive);
200 dev->set_slot(slot); /* set currently loaded slot */
202 /* We just swapped this Volume so it cannot be swapping any more */
203 dev->vol->clear_swapping();
207 be.set_errno(status);
208 Dmsg4(dbglvl, "Error: load slot %d, drive %d, bad stats=%s.\nResults=%s\n", slot, drive,
209 be.bstrerror(), results.c_str());
210 Jmsg(jcr, M_FATAL, 0, _("3992 Bad autochanger \"load slot %d, drive %d\": "
211 "ERR=%s.\nResults=%s\n"),
212 slot, drive, be.bstrerror(), results.c_str());
213 rtn_stat = -1; /* hard error */
214 dev->clear_slot(); /* mark unknown */
218 status = 0; /* we got what we want */
219 dev->set_slot(slot); /* set currently loaded slot */
221 Dmsg1(dbglvl, "After changer, status=%d\n", status);
222 if (status == 0) { /* did we succeed? */
223 rtn_stat = 1; /* tape loaded by changer */
226 free_pool_memory(changer);
230 free_pool_memory(changer);
236 * Returns: -1 if error from changer command
238 * Note, this is safe to do without releasing the drive
239 * since it does not attempt load/unload a slot.
241 int get_autochanger_loaded_slot(DCR *dcr)
244 DEVICE *dev = dcr->dev;
246 uint32_t timeout = dcr->device->max_changer_wait;
247 int drive = dcr->dev->drive_index;
248 POOL_MEM results(PM_MESSAGE);
251 if (!dev->is_autochanger()) {
254 if (!dcr->device->changer_command) {
258 if (dev->get_slot() > 0 && dev->has_cap(CAP_ALWAYSOPEN)) {
259 Dmsg1(dbglvl, "Return cached slot=%d\n", dev->get_slot());
260 return dev->get_slot();
263 /* Virtual disk autochanger */
264 if (dcr->is_virtual_autochanger()) {
268 /* Find out what is loaded, zero means device is unloaded */
269 changer = get_pool_memory(PM_FNAME);
271 /* Suppress info when polling */
272 if (!dev->poll && chk_dbglvl(1)) {
273 Jmsg(jcr, M_INFO, 0, _("3301 Issuing autochanger \"loaded? drive %d\" command.\n"),
276 changer = edit_device_codes(dcr, changer, dcr->device->changer_command, "loaded");
277 Dmsg1(dbglvl, "Run program=%s\n", changer);
278 status = run_program_full_output(changer, timeout, results.addr());
279 Dmsg3(dbglvl, "run_prog: %s stat=%d result=%s", changer, status, results.c_str());
281 loaded = str_to_int32(results.c_str());
283 /* Suppress info when polling */
284 if (!dev->poll && chk_dbglvl(1)) {
285 Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded? drive %d\", result is Slot %d.\n"),
288 dev->set_slot(loaded);
290 /* Suppress info when polling */
291 if (!dev->poll && chk_dbglvl(1)) {
292 Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded? drive %d\", result: nothing loaded.\n"),
295 if (loaded == 0) { /* no slot loaded */
297 } else { /* probably some error */
298 dev->clear_slot(); /* unknown */
303 be.set_errno(status);
304 Jmsg(jcr, M_INFO, 0, _("3991 Bad autochanger \"loaded? drive %d\" command: "
305 "ERR=%s.\nResults=%s\n"), drive, be.bstrerror(), results.c_str());
306 Dmsg3(dbglvl, "Error: autochanger loaded? drive %d "
307 "ERR=%s.\nResults=%s\n", drive, be.bstrerror(), results.c_str());
308 loaded = -1; /* force unload */
309 dev->clear_slot(); /* slot unknown */
312 free_pool_memory(changer);
316 static void lock_changer(DCR *dcr)
318 AUTOCHANGER *changer_res = dcr->device->changer_res;
321 Dmsg1(dbglvl, "Locking changer %s\n", changer_res->hdr.name);
322 if ((errstat=rwl_writelock(&changer_res->changer_lock)) != 0) {
324 Jmsg(dcr->jcr, M_ERROR_TERM, 0, _("Lock failure on autochanger. ERR=%s\n"),
325 be.bstrerror(errstat));
330 static void unlock_changer(DCR *dcr)
332 AUTOCHANGER *changer_res = dcr->device->changer_res;
335 Dmsg1(dbglvl, "Unlocking changer %s\n", changer_res->hdr.name);
336 if ((errstat=rwl_writeunlock(&changer_res->changer_lock)) != 0) {
338 Jmsg(dcr->jcr, M_ERROR_TERM, 0, _("Unlock failure on autochanger. ERR=%s\n"),
339 be.bstrerror(errstat));
345 * Unload the volume, if any, in this drive
346 * On entry: loaded == 0 -- nothing to do
347 * loaded < 0 -- check if anything to do
348 * loaded > 0 -- load slot == loaded
350 bool unload_autochanger(DCR *dcr, int loaded)
352 DEVICE *dev = dcr->dev;
355 uint32_t timeout = dcr->device->max_changer_wait;
362 if (!dev->is_autochanger() || !dcr->device->changer_name ||
363 !dcr->device->changer_command) {
367 /* Virtual disk autochanger */
368 if (dcr->is_virtual_autochanger()) {
375 loaded = get_autochanger_loaded_slot(dcr);
376 if (loaded < 0) { /* try again, maybe autochanger error */
377 loaded = get_autochanger_loaded_slot(dcr);
382 POOL_MEM results(PM_MESSAGE);
383 POOLMEM *changer = get_pool_memory(PM_FNAME);
385 _("3307 Issuing autochanger \"unload slot %d, drive %d\" command.\n"),
386 loaded, dev->drive_index);
387 slot = dcr->VolCatInfo.Slot;
388 dcr->VolCatInfo.Slot = loaded;
389 changer = edit_device_codes(dcr, changer,
390 dcr->device->changer_command, "unload");
392 Dmsg1(dbglvl, "Run program=%s\n", changer);
393 int stat = run_program_full_output(changer, timeout, results.addr());
394 dcr->VolCatInfo.Slot = slot;
398 Jmsg(jcr, M_INFO, 0, _("3995 Bad autochanger \"unload slot %d, drive %d\": "
399 "ERR=%s\nResults=%s\n"),
400 loaded, dev->drive_index, be.bstrerror(), results.c_str());
401 Dmsg4(dbglvl, "Error: load slot %d, drive %d, bad stats=%s.\nResults=%s\n",
402 loaded, dev->drive_index,
403 be.bstrerror(), results.c_str());
405 dev->clear_slot(); /* unknown */
407 dev->set_slot(0); /* unload is OK, mark nothing loaded */
410 free_pool_memory(changer);
421 * Unload the slot if mounted in a different drive
423 static bool unload_other_drive(DCR *dcr, int slot)
428 AUTOCHANGER *changer = dcr->dev->device->changer_res;
430 int retries = 0; /* wait for device retries */
437 if (changer->device->size() == 1) {
442 * We look for the slot number corresponding to the tape
443 * we want in other drives, and if possible, unload
446 Dmsg1(dbglvl, "Begin wiffle through devices looking for slot=%d\n", slot);
448 * foreach_alist(device, changer->device) {
450 * The above fails to loop through all devices. It is
451 * probably a compiler bug.
453 for (i=0; i < changer->device->size(); i++) {
454 device = (DEVRES *)changer->device->get(i);
457 Dmsg0(dbglvl, "No dev attached to device\n");
463 loaded = get_autochanger_loaded_slot(dcr);
464 dcr->set_dev(dev_save);
467 Dmsg4(dbglvl, "Want slot=%d, drive=%d loaded=%d dev=%s\n",
468 slot, dev->drive_index, loaded, dev->print_name());
469 if (loaded == slot) {
474 Dmsg4(dbglvl, "After slot=%d drive=%d loaded=%d dev=%s\n",
475 slot, dev->drive_index, loaded, dev->print_name());
478 Dmsg1(dbglvl, "End wiffle through devices looking for slot=%d\n", slot);
480 Dmsg1(dbglvl, "Slot=%d not found in another device\n", slot);
483 Dmsg3(dbglvl, "Slot=%d drive=%d found in dev=%s\n", slot, dev->drive_index, dev->print_name());
486 /* The Volume we want is on another device. */
487 if (dev->is_busy()) {
488 Dmsg4(dbglvl, "Vol %s for dev=%s in use dev=%s slot=%d\n",
489 dcr->VolumeName, dcr->dev->print_name(),
490 dev->print_name(), slot);
492 for (int i=0; i < 3; i++) {
493 if (dev->is_busy()) {
494 Dmsg0(40, "Device is busy. Calling wait_for_device()\n");
495 wait_for_device(dcr, retries);
500 if (dev->is_busy()) {
501 Jmsg(dcr->jcr, M_WARNING, 0, _("Volume \"%s\" wanted on %s is in use by device %s\n"),
502 dcr->VolumeName, dcr->dev->print_name(), dev->print_name());
503 Dmsg4(dbglvl, "Vol %s for dev=%s is busy dev=%s slot=%d\n",
504 dcr->VolumeName, dcr->dev->print_name(), dev->print_name(), dev->get_slot());
505 Dmsg2(dbglvl, "num_writ=%d reserv=%d\n", dev->num_writers, dev->num_reserved());
509 return unload_dev(dcr, dev);
513 * Unconditionally unload a specified drive
515 bool unload_dev(DCR *dcr, DEVICE *dev)
519 uint32_t timeout = dcr->device->max_changer_wait;
520 AUTOCHANGER *changer = dcr->dev->device->changer_res;
528 save_dev = dcr->dev; /* save dcr device */
529 dcr->set_dev(dev); /* temporarily point dcr at other device */
531 get_autochanger_loaded_slot(dcr);
533 /* Fail if we have no slot to unload */
534 if (dev->get_slot() <= 0) {
535 if (dev->get_slot() < 0) {
536 Dmsg1(dbglvl, "Cannot unload, slot not defined. dev=%s\n",
539 dcr->set_dev(save_dev);
543 save_slot = dcr->VolCatInfo.Slot;
544 dcr->VolCatInfo.Slot = dev->get_slot();
547 POOLMEM *changer_cmd = get_pool_memory(PM_FNAME);
548 POOL_MEM results(PM_MESSAGE);
551 _("3307 Issuing autochanger \"unload slot %d, drive %d\" command.\n"),
552 dev->get_slot(), dev->drive_index);
554 Dmsg2(dbglvl, "Issuing autochanger \"unload slot %d, drive %d\" command.\n",
555 dev->get_slot(), dev->drive_index);
557 changer_cmd = edit_device_codes(dcr, changer_cmd,
558 dcr->device->changer_command, "unload");
560 Dmsg2(dbglvl, "close dev=%s reserve=%d\n", dev->print_name(),
561 dev->num_reserved());
562 Dmsg1(dbglvl, "Run program=%s\n", changer_cmd);
563 int stat = run_program_full_output(changer_cmd, timeout, results.addr());
564 dcr->VolCatInfo.Slot = save_slot;
568 Jmsg(jcr, M_INFO, 0, _("3997 Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n"),
569 dev->get_slot(), dev->drive_index, be.bstrerror());
570 Dmsg4(dbglvl, "Error: load slot %d, drive %d, bad stats=%s.\nResults=%s\n",
571 dev->get_slot(), dev->drive_index,
572 be.bstrerror(), results.c_str());
574 dev->clear_slot(); /* unknown */
576 Dmsg2(dbglvl, "Slot %d unloaded %s\n", dev->get_slot(), dev->print_name());
577 dev->set_slot(0); /* unload OK, mark nothing loaded */
585 dcr->set_dev(save_dev);
586 free_pool_memory(changer_cmd);
593 * List the Volumes that are in the autoloader possibly
594 * with their barcodes.
595 * We assume that it is always the Console that is calling us.
597 bool autochanger_cmd(DCR *dcr, BSOCK *dir, const char *cmd)
599 DEVICE *dev = dcr->dev;
600 uint32_t timeout = dcr->device->max_changer_wait;
603 int len = sizeof_pool_memory(dir->msg) - 1;
606 if (!dev->is_autochanger() || !dcr->device->changer_name ||
607 !dcr->device->changer_command) {
608 if (strcasecmp(cmd, "drives") == 0) {
609 dir->fsend("drives=1\n");
611 dir->fsend(_("3993 Device %s not an autochanger device.\n"),
616 if (strcasecmp(cmd, "drives") == 0) {
617 AUTOCHANGER *changer_res = dcr->device->changer_res;
620 drives = changer_res->device->size();
622 dir->fsend("drives=%d\n", drives);
623 Dmsg1(dbglvl, "drives=%d\n", drives);
627 /* If listing, reprobe changer */
628 if (bstrcasecmp(cmd, "list") || bstrcasecmp(cmd, "listall")) {
629 dcr->dev->set_slot(0);
630 get_autochanger_loaded_slot(dcr);
633 changer = get_pool_memory(PM_FNAME);
635 /* Now issue the command */
636 changer = edit_device_codes(dcr, changer,
637 dcr->device->changer_command, cmd);
638 dir->fsend(_("3306 Issuing autochanger \"%s\" command.\n"), cmd);
639 bpipe = open_bpipe(changer, timeout, "r");
641 dir->fsend(_("3996 Open bpipe failed.\n"));
642 goto bail_out; /* TODO: check if we need to return false */
644 if (bstrcasecmp(cmd, "list") || bstrcasecmp(cmd, "listall")) {
645 /* Get output from changer */
646 while (fgets(dir->msg, len, bpipe->rfd)) {
647 dir->msglen = strlen(dir->msg);
648 Dmsg1(dbglvl, "<stored: %s\n", dir->msg);
651 } else if (strcasecmp(cmd, "slots") == 0 ) {
653 /* For slots command, read a single line */
655 fgets(buf, sizeof(buf)-1, bpipe->rfd);
656 buf[sizeof(buf)-1] = 0;
657 /* Strip any leading space in front of # of slots */
658 for (p=buf; B_ISSPACE(*p); p++)
660 dir->fsend("slots=%s", p);
661 Dmsg1(dbglvl, "<stored: %s", dir->msg);
664 stat = close_bpipe(bpipe);
668 dir->fsend(_("Autochanger error: ERR=%s\n"), be.bstrerror());
673 free_pool_memory(changer);
679 * Edit codes into ChangerCommand
681 * %a = archive device name
682 * %c = changer device name
683 * %d = changer drive index
686 * %l = archive control channel name
693 * omsg = edited output message
694 * imsg = input string containing edit codes (%x)
695 * cmd = command string (load, unload, ...)
698 char *edit_device_codes(DCR *dcr, char *omsg, const char *imsg, const char *cmd)
705 Dmsg1(1800, "edit_device_codes: %s\n", imsg);
706 for (p=imsg; *p; p++) {
713 str = dcr->dev->archive_name();
716 str = NPRT(dcr->device->changer_name);
719 str = NPRT(dcr->device->control_name);
722 sprintf(add, "%d", dcr->dev->drive_index);
729 sprintf(add, "%d", dcr->VolCatInfo.Slot - 1);
733 sprintf(add, "%d", dcr->VolCatInfo.Slot);
736 case 'j': /* Job name */
740 if (dcr->VolCatInfo.VolCatName[0]) {
741 str = dcr->VolCatInfo.VolCatName;
742 } else if (dcr->VolumeName[0]) {
743 str = dcr->VolumeName;
744 } else if (dcr->dev->vol && dcr->dev->vol->vol_name) {
745 str = dcr->dev->vol->vol_name;
747 str = dcr->dev->VolHdr.VolumeName;
751 str = NPRT(dcr->jcr->client_name);
766 Dmsg1(1900, "add_str %s\n", str);
767 pm_strcat(&omsg, (char *)str);
768 Dmsg1(1800, "omsg=%s\n", omsg);
770 Dmsg1(800, "omsg=%s\n", omsg);