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 /* ***FIXME*** this really should not be here */
140 if (dir_find_next_appendable_volume(dcr)) {
141 slot = dcr->VolCatInfo.InChanger ? dcr->VolCatInfo.Slot : 0;
146 Dmsg1(400, "Want changer slot=%d\n", slot);
148 changer = get_pool_memory(PM_FNAME);
150 Jmsg(jcr, M_INFO, 0, _("Invalid slot=%d defined in catalog for Volume \"%s\" "
151 "on %s. Manual load may be required.\n"), slot, dcr->VolCatInfo.VolCatName,
154 } else if (!dcr->device->changer_name) {
155 Jmsg(jcr, M_INFO, 0, _("No \"Changer Device\" for %s. Manual load of Volume may be required.\n"),
158 } else if (!dcr->device->changer_command) {
159 Jmsg(jcr, M_INFO, 0, _("No \"Changer Command\" for %s. Manual load of Volume may be requird.\n"),
163 /* Attempt to load the Volume */
165 uint32_t timeout = dcr->device->max_changer_wait;
168 loaded = get_autochanger_loaded_slot(dcr);
170 if (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 Dmsg1(100, "Doing changer load slot %d\n", slot);
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(200, "Run program=%s\n", changer);
195 status = run_program_full_output(changer, timeout, results.c_str());
197 Jmsg(jcr, M_INFO, 0, _("3305 Autochanger \"load slot %d, drive %d\", status is OK.\n"),
199 Dmsg2(100, "load slot %d, drive %d, status is OK.\n", slot, drive);
200 dev->Slot = slot; /* set currently loaded slot */
203 be.set_errno(status);
204 Dmsg3(100, "load slot %d, drive %d, bad stats=%s.\n", slot, drive,
206 Jmsg(jcr, M_FATAL, 0, _("3992 Bad autochanger \"load slot %d, drive %d\": "
207 "ERR=%s.\nResults=%s\n"),
208 slot, drive, be.bstrerror(), results.c_str());
209 rtn_stat = -1; /* hard error */
210 dev->Slot = -1; /* mark unknown */
212 Dmsg2(100, "load slot %d status=%d\n", slot, status);
215 status = 0; /* we got what we want */
216 dev->Slot = slot; /* set currently loaded slot */
218 Dmsg1(100, "After changer, status=%d\n", status);
219 if (status == 0) { /* did we succeed? */
220 rtn_stat = 1; /* tape loaded by changer */
223 free_pool_memory(changer);
227 free_pool_memory(changer);
233 * Returns: -1 if error from changer command
235 * Note, this is safe to do without releasing the drive
236 * since it does not attempt load/unload a slot.
238 int get_autochanger_loaded_slot(DCR *dcr)
241 DEVICE *dev = dcr->dev;
243 uint32_t timeout = dcr->device->max_changer_wait;
244 int drive = dcr->dev->drive_index;
245 POOL_MEM results(PM_MESSAGE);
248 if (!dev->is_autochanger()) {
251 if (!dcr->device->changer_command) {
252 Jmsg(jcr, M_FATAL, 0, _("3992 Missing Changer command.\n"));
258 /* Virtual disk autochanger */
259 if (dcr->device->changer_command[0] == 0) {
263 /* Find out what is loaded, zero means device is unloaded */
264 changer = get_pool_memory(PM_FNAME);
266 Jmsg(jcr, M_INFO, 0, _("3301 Issuing autochanger \"loaded? drive %d\" command.\n"),
268 changer = edit_device_codes(dcr, changer, dcr->device->changer_command, "loaded");
269 Dmsg1(100, "Run program=%s\n", changer);
270 status = run_program_full_output(changer, timeout, results.c_str());
271 Dmsg3(100, "run_prog: %s stat=%d result=%s", changer, status, results.c_str());
273 loaded = str_to_int32(results.c_str());
275 Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded? drive %d\", result is Slot %d.\n"),
279 Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded? drive %d\", result: nothing loaded.\n"),
281 dev->Slot = -1; /* unknown */
285 be.set_errno(status);
286 Jmsg(jcr, M_INFO, 0, _("3991 Bad autochanger \"loaded? drive %d\" command: "
287 "ERR=%s.\nResults=%s\n"), drive, be.bstrerror(), results.c_str());
288 loaded = -1; /* force unload */
291 free_pool_memory(changer);
295 static void lock_changer(DCR *dcr)
297 AUTOCHANGER *changer_res = dcr->device->changer_res;
299 Dmsg1(200, "Locking changer %s\n", changer_res->hdr.name);
300 P(changer_res->changer_mutex); /* Lock changer script */
304 static void unlock_changer(DCR *dcr)
306 AUTOCHANGER *changer_res = dcr->device->changer_res;
308 Dmsg1(200, "Unlocking changer %s\n", changer_res->hdr.name);
309 V(changer_res->changer_mutex); /* Unlock changer script */
314 * Unload the volume, if any, in this drive
315 * On entry: loaded == 0 -- nothing to do
316 * loaded < 0 -- check if anything to do
317 * loaded > 0 -- load slot == loaded
319 bool unload_autochanger(DCR *dcr, int loaded)
321 DEVICE *dev = dcr->dev;
324 uint32_t timeout = dcr->device->max_changer_wait;
331 if (!dev->is_autochanger() || !dcr->device->changer_name ||
332 !dcr->device->changer_command) {
336 /* Virtual disk autochanger */
337 if (dcr->device->changer_command[0] == 0) {
342 loaded = get_autochanger_loaded_slot(dcr);
346 POOL_MEM results(PM_MESSAGE);
347 POOLMEM *changer = get_pool_memory(PM_FNAME);
350 _("3307 Issuing autochanger \"unload slot %d, drive %d\" command.\n"),
351 loaded, dev->drive_index);
352 slot = dcr->VolCatInfo.Slot;
353 dcr->VolCatInfo.Slot = loaded;
354 changer = edit_device_codes(dcr, changer,
355 dcr->device->changer_command, "unload");
357 Dmsg1(100, "Run program=%s\n", changer);
358 int stat = run_program_full_output(changer, timeout, results.c_str());
359 dcr->VolCatInfo.Slot = slot;
363 Jmsg(jcr, M_INFO, 0, _("3995 Bad autochanger \"unload slot %d, drive %d\": "
364 "ERR=%s\nResults=%s\n"),
365 loaded, dev->drive_index, be.bstrerror(), results.c_str());
367 dev->Slot = -1; /* unknown */
369 dev->Slot = 0; /* nothing loaded */
372 free_volume(dev); /* Free any volume associated with this drive */
373 free_pool_memory(changer);
380 * Unload the slot if mounted in a different drive
382 static bool unload_other_drive(DCR *dcr, int slot)
386 AUTOCHANGER *changer = dcr->dev->device->changer_res;
388 int retries = 0; /* wait for device retries */
393 if (changer->device->size() == 1) {
397 foreach_alist(device, changer->device) {
398 if (device->dev && device->dev->Slot == slot) {
408 /* The Volume we want is on another device. */
409 if (dev->is_busy()) {
410 Dmsg4(100, "Vol %s for dev=%s in use dev=%s slot=%d\n",
411 dcr->VolumeName, dcr->dev->print_name(),
412 dev->print_name(), slot);
414 for (int i=0; i < 3; i++) {
415 if (dev->is_busy()) {
416 wait_for_device(dcr->jcr, retries);
421 if (dev->is_busy()) {
422 Jmsg(dcr->jcr, M_WARNING, 0, _("Volume \"%s\" is in use by device %s\n"),
423 dcr->VolumeName, dev->print_name());
424 Dmsg4(100, "Vol %s for dev=%s is busy dev=%s slot=%d\n",
425 dcr->VolumeName, dcr->dev->print_name(), dev->print_name(), dev->Slot);
426 Dmsg2(100, "num_writ=%d reserv=%d\n", dev->num_writers, dev->num_reserved());
429 return unload_dev(dcr, dev);
432 bool unload_dev(DCR *dcr, DEVICE *dev)
436 uint32_t timeout = dcr->device->max_changer_wait;
437 AUTOCHANGER *changer = dcr->dev->device->changer_res;
441 if (!changer || dev->Slot <= 0) {
446 POOLMEM *changer_cmd = get_pool_memory(PM_FNAME);
447 POOL_MEM results(PM_MESSAGE);
450 _("3307 Issuing autochanger \"unload slot %d, drive %d\" command.\n"),
451 dev->Slot, dev->drive_index);
453 Dmsg2(100, "Issuing autochanger \"unload slot %d, drive %d\" command.\n",
454 dev->Slot, dev->drive_index);
458 save_slot = dcr->VolCatInfo.Slot;
459 dcr->VolCatInfo.Slot = dev->Slot;
460 changer_cmd = edit_device_codes(dcr, changer_cmd,
461 dcr->device->changer_command, "unload");
463 Dmsg2(200, "close dev=%s reserve=%d\n", dev->print_name(),
464 dev->num_reserved());
465 Dmsg1(100, "Run program=%s\n", changer_cmd);
466 int stat = run_program_full_output(changer_cmd, timeout, results.c_str());
467 dcr->VolCatInfo.Slot = save_slot;
472 Jmsg(jcr, M_INFO, 0, _("3995 Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n"),
473 dev->Slot, dev->drive_index, be.bstrerror());
475 Dmsg3(100, "Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n",
476 dev->Slot, dev->drive_index, be.bstrerror());
478 dev->Slot = -1; /* unknown */
480 dev->Slot = 0; /* nothing loaded */
481 Dmsg0(100, "Slot unloaded\n");
483 free_volume(dev); /* Free any volume associated with this drive */
487 free_pool_memory(changer_cmd);
494 * List the Volumes that are in the autoloader possibly
495 * with their barcodes.
496 * We assume that it is always the Console that is calling us.
498 bool autochanger_cmd(DCR *dcr, BSOCK *dir, const char *cmd)
500 DEVICE *dev = dcr->dev;
501 uint32_t timeout = dcr->device->max_changer_wait;
504 int len = sizeof_pool_memory(dir->msg) - 1;
508 if (!dev->is_autochanger() || !dcr->device->changer_name ||
509 !dcr->device->changer_command) {
510 if (strcmp(cmd, "drives") == 0) {
511 dir->fsend("drives=1\n");
513 dir->fsend(_("3993 Device %s not an autochanger device.\n"),
518 if (strcmp(cmd, "drives") == 0) {
519 AUTOCHANGER *changer_res = dcr->device->changer_res;
522 drives = changer_res->device->size();
524 dir->fsend("drives=%d\n", drives);
525 Dmsg1(100, "drives=%d\n", drives);
529 changer = get_pool_memory(PM_FNAME);
531 /* Now issue the command */
532 changer = edit_device_codes(dcr, changer,
533 dcr->device->changer_command, cmd);
534 dir->fsend(_("3306 Issuing autochanger \"%s\" command.\n"), cmd);
535 bpipe = open_bpipe(changer, timeout, "r");
537 dir->fsend(_("3996 Open bpipe failed.\n"));
540 if (strcmp(cmd, "list") == 0) {
541 /* Get output from changer */
542 while (fgets(dir->msg, len, bpipe->rfd)) {
543 dir->msglen = strlen(dir->msg);
544 Dmsg1(100, "<stored: %s\n", dir->msg);
547 } else if (strcmp(cmd, "slots") == 0 ) {
549 /* For slots command, read a single line */
551 fgets(buf, sizeof(buf)-1, bpipe->rfd);
552 buf[sizeof(buf)-1] = 0;
553 /* Strip any leading space in front of # of slots */
554 for (p=buf; B_ISSPACE(*p); p++)
556 dir->fsend("slots=%s", p);
557 Dmsg1(100, "<stored: %s", dir->msg);
560 stat = close_bpipe(bpipe);
564 dir->fsend(_("Autochanger error: ERR=%s\n"), be.bstrerror());
566 bnet_sig(dir, BNET_EOD);
571 free_pool_memory(changer);
577 * Edit codes into ChangerCommand
579 * %a = archive device name
580 * %c = changer device name
581 * %d = changer drive index
590 * omsg = edited output message
591 * imsg = input string containing edit codes (%x)
592 * cmd = command string (load, unload, ...)
595 char *edit_device_codes(DCR *dcr, char *omsg, const char *imsg, const char *cmd)
602 Dmsg1(1800, "edit_device_codes: %s\n", imsg);
603 for (p=imsg; *p; p++) {
610 str = dcr->dev->archive_name();
613 str = NPRT(dcr->device->changer_name);
616 sprintf(add, "%d", dcr->dev->drive_index);
623 sprintf(add, "%d", dcr->VolCatInfo.Slot - 1);
627 sprintf(add, "%d", dcr->VolCatInfo.Slot);
630 case 'j': /* Job name */
634 str = NPRT(dcr->VolumeName);
637 str = NPRT(dcr->jcr->client_name);
652 Dmsg1(1900, "add_str %s\n", str);
653 pm_strcat(&omsg, (char *)str);
654 Dmsg1(1800, "omsg=%s\n", omsg);
656 Dmsg1(800, "omsg=%s\n", omsg);