2 Bacula® - The Network Backup Solution
4 Copyright (C) 2002-2011 Free Software Foundation Europe e.V.
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
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.
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
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.
30 * Routines for handling the autochanger.
32 * Kern Sibbald, August MMII
36 #include "bacula.h" /* pull in global headers */
37 #include "stored.h" /* pull in Storage Deamon headers */
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);
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"),
77 if (media_type == NULL) {
78 media_type = device->media_type; /* get Media Type of first device */
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"),
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.
102 * Note if dir is not NULL, it is the console requesting the
103 * autoload for labeling, so we respond directly to the
106 * Returns: 1 on success
107 * 0 on failure (no changer available)
108 * -1 on error on autochanger
110 int autoload_device(DCR *dcr, int writing, BSOCK *dir)
113 DEVICE * volatile dev = dcr->dev;
115 int drive = dev->drive_index;
116 int rtn_stat = -1; /* error status */
119 if (!dev->is_autochanger()) {
120 Dmsg1(100, "Device %s is not an autochanger\n", dev->print_name());
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 */
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());
134 * Handle autoloaders here. If we cannot autoload it, we
135 * will return 0 so that the sysop will be asked to load it.
137 if (writing && slot <= 0) {
139 return 0; /* For user, bail out right now */
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;
148 Dmsg1(400, "Want changer slot=%d\n", slot);
150 changer = get_pool_memory(PM_FNAME);
152 /* Suppress info when polling */
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"));
159 } else if (!dcr->device->changer_name) {
160 /* Suppress info when polling */
162 Jmsg(jcr, M_INFO, 0, _("No \"Changer Device\" for %s. Manual load of Volume may be required.\n"),
166 } else if (!dcr->device->changer_command) {
167 /* Suppress info when polling */
169 Jmsg(jcr, M_INFO, 0, _("No \"Changer Command\" for %s. Manual load of Volume may be requird.\n"),
174 /* Attempt to load the Volume */
176 uint32_t timeout = dcr->device->max_changer_wait;
179 loaded = get_autochanger_loaded_slot(dcr);
181 if (loaded != slot) {
182 POOL_MEM results(PM_MESSAGE);
184 /* Unload anything in our drive */
185 if (!unload_autochanger(dcr, loaded)) {
189 /* Make sure desired slot is unloaded */
190 if (!unload_other_drive(dcr, slot)) {
195 * Load the desired cassette
198 Dmsg2(100, "Doing changer load slot %d %s\n", slot, dev->print_name());
200 _("3304 Issuing autochanger \"load slot %d, drive %d\" command.\n"),
202 dcr->VolCatInfo.Slot = slot; /* slot to be loaded */
203 changer = edit_device_codes(dcr, changer, dcr->device->changer_command, "load");
205 Dmsg1(200, "Run program=%s\n", changer);
206 status = run_program_full_output(changer, timeout, results.addr());
208 Jmsg(jcr, M_INFO, 0, _("3305 Autochanger \"load slot %d, drive %d\", status is OK.\n"),
210 Dmsg2(100, "load slot %d, drive %d, status is OK.\n", slot, drive);
211 dev->set_slot(slot); /* set currently loaded slot */
214 be.set_errno(status);
215 Dmsg3(100, "load slot %d, drive %d, bad stats=%s.\n", slot, drive,
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 */
223 Dmsg2(100, "load slot %d status=%d\n", slot, status);
226 status = 0; /* we got what we want */
227 dev->set_slot(slot); /* set currently loaded slot */
229 Dmsg1(100, "After changer, status=%d\n", status);
230 if (status == 0) { /* did we succeed? */
231 rtn_stat = 1; /* tape loaded by changer */
234 free_pool_memory(changer);
238 free_pool_memory(changer);
244 * Returns: -1 if error from changer command
246 * Note, this is safe to do without releasing the drive
247 * since it does not attempt load/unload a slot.
249 int get_autochanger_loaded_slot(DCR *dcr)
252 DEVICE *dev = dcr->dev;
254 uint32_t timeout = dcr->device->max_changer_wait;
255 int drive = dcr->dev->drive_index;
256 POOL_MEM results(PM_MESSAGE);
259 if (!dev->is_autochanger()) {
262 if (!dcr->device->changer_command) {
263 // Jmsg(jcr, M_FATAL, 0, _("3992 Missing Changer command.\n"));
266 if (dev->get_slot() > 0) {
267 return dev->get_slot();
270 /* Virtual disk autochanger */
271 if (dcr->device->changer_command[0] == 0) {
275 /* Find out what is loaded, zero means device is unloaded */
276 changer = get_pool_memory(PM_FNAME);
278 /* Suppress info when polling */
280 Jmsg(jcr, M_INFO, 0, _("3301 Issuing autochanger \"loaded? drive %d\" command.\n"),
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());
288 loaded = str_to_int32(results.c_str());
290 /* Suppress info when polling */
292 Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded? drive %d\", result is Slot %d.\n"),
295 dev->set_slot(loaded);
297 /* Suppress info when polling */
299 Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded? drive %d\", result: nothing loaded.\n"),
302 if (loaded == 0) { /* no slot loaded */
304 } else { /* probably some error */
305 dev->clear_slot(); /* unknown */
310 be.set_errno(status);
311 Jmsg(jcr, M_INFO, 0, _("3991 Bad autochanger \"loaded? drive %d\" command: "
312 "ERR=%s.\nResults=%s\n"), drive, be.bstrerror(), results.c_str());
313 loaded = -1; /* force unload */
316 free_pool_memory(changer);
320 static void lock_changer(DCR *dcr)
322 AUTOCHANGER *changer_res = dcr->device->changer_res;
325 Dmsg1(200, "Locking changer %s\n", changer_res->hdr.name);
326 if ((errstat=rwl_writelock(&changer_res->changer_lock)) != 0) {
328 Jmsg(dcr->jcr, M_ERROR_TERM, 0, _("Lock failure on autochanger. ERR=%s\n"),
329 be.bstrerror(errstat));
334 static void unlock_changer(DCR *dcr)
336 AUTOCHANGER *changer_res = dcr->device->changer_res;
339 Dmsg1(200, "Unlocking changer %s\n", changer_res->hdr.name);
340 if ((errstat=rwl_writeunlock(&changer_res->changer_lock)) != 0) {
342 Jmsg(dcr->jcr, M_ERROR_TERM, 0, _("Unlock failure on autochanger. ERR=%s\n"),
343 be.bstrerror(errstat));
349 * Unload the volume, if any, in this drive
350 * On entry: loaded == 0 -- nothing to do
351 * loaded < 0 -- check if anything to do
352 * loaded > 0 -- load slot == loaded
354 bool unload_autochanger(DCR *dcr, int loaded)
356 DEVICE *dev = dcr->dev;
359 uint32_t timeout = dcr->device->max_changer_wait;
366 if (!dev->is_autochanger() || !dcr->device->changer_name ||
367 !dcr->device->changer_command) {
371 /* Virtual disk autochanger */
372 if (dcr->device->changer_command[0] == 0) {
379 loaded = get_autochanger_loaded_slot(dcr);
383 POOL_MEM results(PM_MESSAGE);
384 POOLMEM *changer = get_pool_memory(PM_FNAME);
386 _("3307 Issuing autochanger \"unload slot %d, drive %d\" command.\n"),
387 loaded, dev->drive_index);
388 slot = dcr->VolCatInfo.Slot;
389 dcr->VolCatInfo.Slot = loaded;
390 changer = edit_device_codes(dcr, changer,
391 dcr->device->changer_command, "unload");
393 Dmsg1(100, "Run program=%s\n", changer);
394 int stat = run_program_full_output(changer, timeout, results.addr());
395 dcr->VolCatInfo.Slot = slot;
399 Jmsg(jcr, M_INFO, 0, _("3995 Bad autochanger \"unload slot %d, drive %d\": "
400 "ERR=%s\nResults=%s\n"),
401 loaded, dev->drive_index, be.bstrerror(), results.c_str());
403 dev->clear_slot(); /* unknown */
405 dev->set_slot(0); /* nothing loaded */
408 free_pool_memory(changer);
412 if (loaded > 0) { /* free_volume outside from changer lock */
413 free_volume(dev); /* Free any volume associated with this drive */
423 * Unload the slot if mounted in a different drive
425 static bool unload_other_drive(DCR *dcr, int slot)
430 AUTOCHANGER *changer = dcr->dev->device->changer_res;
432 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 Dmsg0(100, "Wiffle through devices looking for slot\n");
447 foreach_alist(device, changer->device) {
454 if (dev->get_slot() <= 0 && get_autochanger_loaded_slot(dcr) <= 0) {
459 if (dev->get_slot() == slot) {
465 Dmsg1(100, "Slot=%d not found in another device\n", slot);
468 Dmsg1(100, "Slot=%d found in another device\n", slot);
471 /* The Volume we want is on another device. */
472 if (dev->is_busy()) {
473 Dmsg4(100, "Vol %s for dev=%s in use dev=%s slot=%d\n",
474 dcr->VolumeName, dcr->dev->print_name(),
475 dev->print_name(), slot);
477 for (int i=0; i < 3; i++) {
478 if (dev->is_busy()) {
479 wait_for_device(dcr->jcr, retries);
484 if (dev->is_busy()) {
485 Jmsg(dcr->jcr, M_WARNING, 0, _("Volume \"%s\" wanted on %s is in use by device %s\n"),
486 dcr->VolumeName, dcr->dev->print_name(), dev->print_name());
487 Dmsg4(100, "Vol %s for dev=%s is busy dev=%s slot=%d\n",
488 dcr->VolumeName, dcr->dev->print_name(), dev->print_name(), dev->get_slot());
489 Dmsg2(100, "num_writ=%d reserv=%d\n", dev->num_writers, dev->num_reserved());
493 return unload_dev(dcr, dev);
497 * Unconditionally unload a specified drive
499 bool unload_dev(DCR *dcr, DEVICE *dev)
503 uint32_t timeout = dcr->device->max_changer_wait;
504 AUTOCHANGER *changer = dcr->dev->device->changer_res;
512 save_dev = dcr->dev; /* save dcr device */
513 dcr->dev = dev; /* temporarily point dcr at other device */
515 /* Update slot if not set or not always_open */
516 if (dev->get_slot() <= 0 || !dev->has_cap(CAP_ALWAYSOPEN)) {
517 get_autochanger_loaded_slot(dcr);
520 /* Fail if we have no slot to unload */
521 if (dev->get_slot() <= 0) {
526 save_slot = dcr->VolCatInfo.Slot;
527 dcr->VolCatInfo.Slot = dev->get_slot();
531 POOLMEM *changer_cmd = get_pool_memory(PM_FNAME);
532 POOL_MEM results(PM_MESSAGE);
535 _("3307 Issuing autochanger \"unload slot %d, drive %d\" command.\n"),
536 dev->get_slot(), dev->drive_index);
538 Dmsg2(100, "Issuing autochanger \"unload slot %d, drive %d\" command.\n",
539 dev->get_slot(), dev->drive_index);
541 changer_cmd = edit_device_codes(dcr, changer_cmd,
542 dcr->device->changer_command, "unload");
544 Dmsg2(200, "close dev=%s reserve=%d\n", dev->print_name(),
545 dev->num_reserved());
546 Dmsg1(100, "Run program=%s\n", changer_cmd);
547 int stat = run_program_full_output(changer_cmd, timeout, results.addr());
548 dcr->VolCatInfo.Slot = save_slot;
553 Jmsg(jcr, M_INFO, 0, _("3997 Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n"),
554 dev->get_slot(), dev->drive_index, be.bstrerror());
556 Dmsg3(100, "Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n",
557 dev->get_slot(), dev->drive_index, be.bstrerror());
559 dev->clear_slot(); /* unknown */
561 Dmsg2(100, "Slot %d unloaded %s\n", dev->get_slot(), dev->print_name());
562 dev->set_slot(0); /* nothing loaded */
571 free_volume(dev); /* Free any volume associated with this drive */
572 free_pool_memory(changer_cmd);
579 * List the Volumes that are in the autoloader possibly
580 * with their barcodes.
581 * We assume that it is always the Console that is calling us.
583 bool autochanger_cmd(DCR *dcr, BSOCK *dir, const char *cmd)
585 DEVICE *dev = dcr->dev;
586 uint32_t timeout = dcr->device->max_changer_wait;
589 int len = sizeof_pool_memory(dir->msg) - 1;
592 if (!dev->is_autochanger() || !dcr->device->changer_name ||
593 !dcr->device->changer_command) {
594 if (strcmp(cmd, "drives") == 0) {
595 dir->fsend("drives=1\n");
597 dir->fsend(_("3993 Device %s not an autochanger device.\n"),
602 if (strcmp(cmd, "drives") == 0) {
603 AUTOCHANGER *changer_res = dcr->device->changer_res;
606 drives = changer_res->device->size();
608 dir->fsend("drives=%d\n", drives);
609 Dmsg1(100, "drives=%d\n", drives);
613 changer = get_pool_memory(PM_FNAME);
615 /* Now issue the command */
616 changer = edit_device_codes(dcr, changer,
617 dcr->device->changer_command, cmd);
618 dir->fsend(_("3306 Issuing autochanger \"%s\" command.\n"), cmd);
619 bpipe = open_bpipe(changer, timeout, "r");
621 dir->fsend(_("3996 Open bpipe failed.\n"));
622 goto bail_out; /* TODO: check if we need to return false */
624 if (bstrcmp(cmd, "list") || bstrcmp(cmd, "listall")) {
625 /* Get output from changer */
626 while (fgets(dir->msg, len, bpipe->rfd)) {
627 dir->msglen = strlen(dir->msg);
628 Dmsg1(100, "<stored: %s\n", dir->msg);
631 } else if (strcmp(cmd, "slots") == 0 ) {
633 /* For slots command, read a single line */
635 fgets(buf, sizeof(buf)-1, bpipe->rfd);
636 buf[sizeof(buf)-1] = 0;
637 /* Strip any leading space in front of # of slots */
638 for (p=buf; B_ISSPACE(*p); p++)
640 dir->fsend("slots=%s", p);
641 Dmsg1(100, "<stored: %s", dir->msg);
644 stat = close_bpipe(bpipe);
648 dir->fsend(_("Autochanger error: ERR=%s\n"), be.bstrerror());
653 free_pool_memory(changer);
659 * Edit codes into ChangerCommand
661 * %a = archive device name
662 * %c = changer device name
663 * %d = changer drive index
672 * omsg = edited output message
673 * imsg = input string containing edit codes (%x)
674 * cmd = command string (load, unload, ...)
677 char *edit_device_codes(DCR *dcr, char *omsg, const char *imsg, const char *cmd)
684 Dmsg1(1800, "edit_device_codes: %s\n", imsg);
685 for (p=imsg; *p; p++) {
692 str = dcr->dev->archive_name();
695 str = NPRT(dcr->device->changer_name);
698 sprintf(add, "%d", dcr->dev->drive_index);
705 sprintf(add, "%d", dcr->VolCatInfo.Slot - 1);
709 sprintf(add, "%d", dcr->VolCatInfo.Slot);
712 case 'j': /* Job name */
716 if (dcr->VolCatInfo.VolCatName[0]) {
717 str = dcr->VolCatInfo.VolCatName;
718 } else if (dcr->VolumeName[0]) {
719 str = dcr->VolumeName;
720 } else if (dcr->dev->vol && dcr->dev->vol->vol_name) {
721 str = dcr->dev->vol->vol_name;
723 str = dcr->dev->VolHdr.VolumeName;
727 str = NPRT(dcr->jcr->client_name);
742 Dmsg1(1900, "add_str %s\n", str);
743 pm_strcat(&omsg, (char *)str);
744 Dmsg1(1800, "omsg=%s\n", omsg);
746 Dmsg1(800, "omsg=%s\n", omsg);