2 Bacula® - The Network Backup Solution
4 Copyright (C) 2002-2008 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 two of the GNU 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 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 John Walker.
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
37 #include "bacula.h" /* pull in global headers */
38 #include "stored.h" /* pull in Storage Deamon headers */
40 /* Forward referenced functions */
41 static void lock_changer(DCR *dcr);
42 static void unlock_changer(DCR *dcr);
43 static bool unload_other_drive(DCR *dcr, int slot);
45 /* Init all the autochanger resources found */
46 bool init_autochangers()
50 /* Ensure that the media_type for each device is the same */
51 foreach_res(changer, R_AUTOCHANGER) {
53 foreach_alist(device, changer->device) {
55 * If the device does not have a changer name or changer command
56 * defined, used the one from the Autochanger resource
58 if (!device->changer_name && changer->changer_name) {
59 device->changer_name = bstrdup(changer->changer_name);
61 if (!device->changer_command && changer->changer_command) {
62 device->changer_command = bstrdup(changer->changer_command);
64 if (!device->changer_name) {
65 Jmsg(NULL, M_ERROR, 0,
66 _("No Changer Name given for device %s. Cannot continue.\n"),
70 if (!device->changer_command) {
71 Jmsg(NULL, M_ERROR, 0,
72 _("No Changer Command given for device %s. Cannot continue.\n"),
78 if (media_type == NULL) {
79 media_type = device->media_type; /* get Media Type of first device */
82 /* Ensure that other devices Media Types are the same */
83 if (strcmp(media_type, device->media_type) != 0) {
84 Jmsg(NULL, M_ERROR, 0,
85 _("Media Type not the same for all devices in changer %s. Cannot continue.\n"),
98 * Called here to do an autoload using the autochanger, if
99 * configured, and if a Slot has been defined for this Volume.
100 * On success this routine loads the indicated tape, but the
101 * label is not read, so it must be verified.
103 * Note if dir is not NULL, it is the console requesting the
104 * autoload for labeling, so we respond directly to the
107 * Returns: 1 on success
108 * 0 on failure (no changer available)
109 * -1 on error on autochanger
111 int autoload_device(DCR *dcr, int writing, BSOCK *dir)
114 DEVICE * volatile dev = dcr->dev;
116 int drive = dev->drive_index;
117 int rtn_stat = -1; /* error status */
120 if (!dev->is_autochanger()) {
121 Dmsg1(200, "Device %s is not an autochanger\n", dev->print_name());
125 /* An empty ChangerCommand => virtual disk autochanger */
126 if (dcr->device->changer_command && dcr->device->changer_command[0] == 0) {
127 return 1; /* nothing to load */
130 slot = dcr->VolCatInfo.InChanger ? dcr->VolCatInfo.Slot : 0;
132 * Handle autoloaders here. If we cannot autoload it, we
133 * will return 0 so that the sysop will be asked to load it.
135 if (writing && slot <= 0) {
137 return 0; /* For user, bail out right now */
139 if (dir_find_next_appendable_volume(dcr)) {
140 slot = dcr->VolCatInfo.InChanger ? dcr->VolCatInfo.Slot : 0;
145 Dmsg1(400, "Want changer slot=%d\n", slot);
147 changer = get_pool_memory(PM_FNAME);
149 Jmsg(jcr, M_INFO, 0, _("Invalid slot=%d defined in catalog for Volume \"%s\" "
150 "on %s. Manual load may be required.\n"), slot, dcr->VolCatInfo.VolCatName,
153 } else if (!dcr->device->changer_name) {
154 Jmsg(jcr, M_INFO, 0, _("No \"Changer Device\" for %s. Manual load of Volume may be required.\n"),
157 } else if (!dcr->device->changer_command) {
158 Jmsg(jcr, M_INFO, 0, _("No \"Changer Command\" for %s. Manual load of Volume may be requird.\n"),
162 /* Attempt to load the Volume */
164 uint32_t timeout = dcr->device->max_changer_wait;
167 loaded = get_autochanger_loaded_slot(dcr);
169 if (loaded != slot) {
170 POOL_MEM results(PM_MESSAGE);
172 /* Unload anything in our drive */
173 if (!unload_autochanger(dcr, loaded)) {
177 /* Make sure desired slot is unloaded */
178 if (!unload_other_drive(dcr, slot)) {
183 * Load the desired cassette
186 Dmsg1(100, "Doing changer load slot %d\n", slot);
188 _("3304 Issuing autochanger \"load slot %d, drive %d\" command.\n"),
190 dcr->VolCatInfo.Slot = slot; /* slot to be loaded */
191 changer = edit_device_codes(dcr, changer, dcr->device->changer_command, "load");
193 Dmsg1(200, "Run program=%s\n", changer);
194 status = run_program_full_output(changer, timeout, results.addr());
196 Jmsg(jcr, M_INFO, 0, _("3305 Autochanger \"load slot %d, drive %d\", status is OK.\n"),
198 Dmsg2(100, "load slot %d, drive %d, status is OK.\n", slot, drive);
199 dev->Slot = slot; /* set currently loaded slot */
202 be.set_errno(status);
203 Dmsg3(100, "load slot %d, drive %d, bad stats=%s.\n", slot, drive,
205 Jmsg(jcr, M_FATAL, 0, _("3992 Bad autochanger \"load slot %d, drive %d\": "
206 "ERR=%s.\nResults=%s\n"),
207 slot, drive, be.bstrerror(), results.c_str());
208 rtn_stat = -1; /* hard error */
209 dev->Slot = -1; /* mark unknown */
211 Dmsg2(100, "load slot %d status=%d\n", slot, status);
214 status = 0; /* we got what we want */
215 dev->Slot = slot; /* set currently loaded slot */
217 Dmsg1(100, "After changer, status=%d\n", status);
218 if (status == 0) { /* did we succeed? */
219 rtn_stat = 1; /* tape loaded by changer */
222 free_pool_memory(changer);
226 free_pool_memory(changer);
232 * Returns: -1 if error from changer command
234 * Note, this is safe to do without releasing the drive
235 * since it does not attempt load/unload a slot.
237 int get_autochanger_loaded_slot(DCR *dcr)
240 DEVICE *dev = dcr->dev;
242 uint32_t timeout = dcr->device->max_changer_wait;
243 int drive = dcr->dev->drive_index;
244 POOL_MEM results(PM_MESSAGE);
247 if (!dev->is_autochanger()) {
250 if (!dcr->device->changer_command) {
251 Jmsg(jcr, M_FATAL, 0, _("3992 Missing Changer command.\n"));
257 /* Virtual disk autochanger */
258 if (dcr->device->changer_command[0] == 0) {
262 /* Find out what is loaded, zero means device is unloaded */
263 changer = get_pool_memory(PM_FNAME);
265 Jmsg(jcr, M_INFO, 0, _("3301 Issuing autochanger \"loaded? drive %d\" command.\n"),
267 changer = edit_device_codes(dcr, changer, dcr->device->changer_command, "loaded");
268 Dmsg1(100, "Run program=%s\n", changer);
269 status = run_program_full_output(changer, timeout, results.addr());
270 Dmsg3(100, "run_prog: %s stat=%d result=%s", changer, status, results.c_str());
272 loaded = str_to_int32(results.c_str());
274 Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded? drive %d\", result is Slot %d.\n"),
278 Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded? drive %d\", result: nothing loaded.\n"),
280 dev->Slot = -1; /* unknown */
284 be.set_errno(status);
285 Jmsg(jcr, M_INFO, 0, _("3991 Bad autochanger \"loaded? drive %d\" command: "
286 "ERR=%s.\nResults=%s\n"), drive, be.bstrerror(), results.c_str());
287 loaded = -1; /* force unload */
290 free_pool_memory(changer);
294 static void lock_changer(DCR *dcr)
296 AUTOCHANGER *changer_res = dcr->device->changer_res;
298 Dmsg1(200, "Locking changer %s\n", changer_res->hdr.name);
299 P(changer_res->changer_mutex); /* Lock changer script */
303 static void unlock_changer(DCR *dcr)
305 AUTOCHANGER *changer_res = dcr->device->changer_res;
307 Dmsg1(200, "Unlocking changer %s\n", changer_res->hdr.name);
308 V(changer_res->changer_mutex); /* Unlock changer script */
313 * Unload the volume, if any, in this drive
314 * On entry: loaded == 0 -- nothing to do
315 * loaded < 0 -- check if anything to do
316 * loaded > 0 -- load slot == loaded
318 bool unload_autochanger(DCR *dcr, int loaded)
320 DEVICE *dev = dcr->dev;
323 uint32_t timeout = dcr->device->max_changer_wait;
330 if (!dev->is_autochanger() || !dcr->device->changer_name ||
331 !dcr->device->changer_command) {
335 /* Virtual disk autochanger */
336 if (dcr->device->changer_command[0] == 0) {
341 loaded = get_autochanger_loaded_slot(dcr);
345 POOL_MEM results(PM_MESSAGE);
346 POOLMEM *changer = get_pool_memory(PM_FNAME);
349 _("3307 Issuing autochanger \"unload slot %d, drive %d\" command.\n"),
350 loaded, dev->drive_index);
351 slot = dcr->VolCatInfo.Slot;
352 dcr->VolCatInfo.Slot = loaded;
353 changer = edit_device_codes(dcr, changer,
354 dcr->device->changer_command, "unload");
356 Dmsg1(100, "Run program=%s\n", changer);
357 int stat = run_program_full_output(changer, timeout, results.addr());
358 dcr->VolCatInfo.Slot = slot;
362 Jmsg(jcr, M_INFO, 0, _("3995 Bad autochanger \"unload slot %d, drive %d\": "
363 "ERR=%s\nResults=%s\n"),
364 loaded, dev->drive_index, be.bstrerror(), results.c_str());
366 dev->Slot = -1; /* unknown */
368 dev->Slot = 0; /* nothing loaded */
370 free_volume(dev); /* Free any volume associated with this drive */
371 free_pool_memory(changer);
378 * Unload the slot if mounted in a different drive
380 static bool unload_other_drive(DCR *dcr, int slot)
384 AUTOCHANGER *changer = dcr->dev->device->changer_res;
386 int retries = 0; /* wait for device retries */
391 if (changer->device->size() == 1) {
395 foreach_alist(device, changer->device) {
396 if (device->dev && device->dev->Slot == slot) {
406 /* The Volume we want is on another device. */
407 if (dev->is_busy()) {
408 Dmsg4(100, "Vol %s for dev=%s in use dev=%s slot=%d\n",
409 dcr->VolumeName, dcr->dev->print_name(),
410 dev->print_name(), slot);
412 for (int i=0; i < 3; i++) {
413 if (dev->is_busy()) {
414 wait_for_device(dcr->jcr, retries);
419 if (dev->is_busy()) {
420 Jmsg(dcr->jcr, M_WARNING, 0, _("Volume \"%s\" is in use by device %s\n"),
421 dcr->VolumeName, dev->print_name());
422 Dmsg4(100, "Vol %s for dev=%s is busy dev=%s slot=%d\n",
423 dcr->VolumeName, dcr->dev->print_name(), dev->print_name(), dev->Slot);
424 Dmsg2(100, "num_writ=%d reserv=%d\n", dev->num_writers, dev->reserved_device);
427 return unload_dev(dcr, dev);
430 bool unload_dev(DCR *dcr, DEVICE *dev)
434 uint32_t timeout = dcr->device->max_changer_wait;
435 AUTOCHANGER *changer = dcr->dev->device->changer_res;
444 POOLMEM *changer_cmd = get_pool_memory(PM_FNAME);
445 POOL_MEM results(PM_MESSAGE);
448 _("3307 Issuing autochanger \"unload slot %d, drive %d\" command.\n"),
449 dev->Slot, dev->drive_index);
451 Dmsg2(100, "Issuing autochanger \"unload slot %d, drive %d\" command.\n",
452 dev->Slot, dev->drive_index);
456 save_slot = dcr->VolCatInfo.Slot;
457 dcr->VolCatInfo.Slot = dev->Slot;
458 changer_cmd = edit_device_codes(dcr, changer_cmd,
459 dcr->device->changer_command, "unload");
461 Dmsg2(200, "close dev=%s reserve=%d\n", dev->print_name(),
462 dev->reserved_device);
463 Dmsg1(100, "Run program=%s\n", changer_cmd);
464 int stat = run_program_full_output(changer_cmd, timeout, results.addr());
465 dcr->VolCatInfo.Slot = save_slot;
470 Jmsg(jcr, M_INFO, 0, _("3995 Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n"),
471 dev->Slot, dev->drive_index, be.bstrerror());
473 Dmsg3(100, "Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n",
474 dev->Slot, dev->drive_index, be.bstrerror());
476 dev->Slot = -1; /* unknown */
478 dev->Slot = 0; /* nothing loaded */
479 Dmsg0(100, "Slot unloaded\n");
481 free_volume(dev); /* Free any volume associated with this drive */
484 free_pool_memory(changer_cmd);
491 * List the Volumes that are in the autoloader possibly
492 * with their barcodes.
493 * We assume that it is always the Console that is calling us.
495 bool autochanger_cmd(DCR *dcr, BSOCK *dir, const char *cmd)
497 DEVICE *dev = dcr->dev;
498 uint32_t timeout = dcr->device->max_changer_wait;
501 int len = sizeof_pool_memory(dir->msg) - 1;
505 if (!dev->is_autochanger() || !dcr->device->changer_name ||
506 !dcr->device->changer_command) {
507 if (strcmp(cmd, "drives") == 0) {
508 dir->fsend("drives=1\n");
510 dir->fsend(_("3993 Device %s not an autochanger device.\n"),
515 if (strcmp(cmd, "drives") == 0) {
516 AUTOCHANGER *changer_res = dcr->device->changer_res;
519 drives = changer_res->device->size();
521 dir->fsend("drives=%d\n", drives);
522 Dmsg1(100, "drives=%d\n", drives);
526 changer = get_pool_memory(PM_FNAME);
528 /* Now issue the command */
529 changer = edit_device_codes(dcr, changer,
530 dcr->device->changer_command, cmd);
531 dir->fsend(_("3306 Issuing autochanger \"%s\" command.\n"), cmd);
532 bpipe = open_bpipe(changer, timeout, "r");
534 dir->fsend(_("3996 Open bpipe failed.\n"));
537 if (strcmp(cmd, "list") == 0) {
538 /* Get output from changer */
539 while (fgets(dir->msg, len, bpipe->rfd)) {
540 dir->msglen = strlen(dir->msg);
541 Dmsg1(100, "<stored: %s\n", dir->msg);
544 } else if (strcmp(cmd, "slots") == 0 ) {
546 /* For slots command, read a single line */
548 fgets(buf, sizeof(buf)-1, bpipe->rfd);
549 buf[sizeof(buf)-1] = 0;
550 /* Strip any leading space in front of # of slots */
551 for (p=buf; B_ISSPACE(*p); p++)
553 dir->fsend("slots=%s", p);
554 Dmsg1(100, "<stored: %s", dir->msg);
557 stat = close_bpipe(bpipe);
561 dir->fsend(_("Autochanger error: ERR=%s\n"), be.bstrerror());
563 bnet_sig(dir, BNET_EOD);
568 free_pool_memory(changer);
574 * Edit codes into ChangerCommand
576 * %a = archive device name
577 * %c = changer device name
578 * %d = changer drive index
587 * omsg = edited output message
588 * imsg = input string containing edit codes (%x)
589 * cmd = command string (load, unload, ...)
592 char *edit_device_codes(DCR *dcr, char *omsg, const char *imsg, const char *cmd)
599 Dmsg1(1800, "edit_device_codes: %s\n", imsg);
600 for (p=imsg; *p; p++) {
607 str = dcr->dev->archive_name();
610 str = NPRT(dcr->device->changer_name);
613 sprintf(add, "%d", dcr->dev->drive_index);
620 sprintf(add, "%d", dcr->VolCatInfo.Slot - 1);
624 sprintf(add, "%d", dcr->VolCatInfo.Slot);
627 case 'j': /* Job name */
631 str = NPRT(dcr->VolumeName);
634 str = NPRT(dcr->jcr->client_name);
649 Dmsg1(1900, "add_str %s\n", str);
650 pm_strcat(&omsg, (char *)str);
651 Dmsg1(1800, "omsg=%s\n", omsg);
653 Dmsg1(800, "omsg=%s\n", omsg);