2 Bacula® - The Network Backup Solution
4 Copyright (C) 2002-2007 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 *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. Manual load my be required.\n"), slot);
151 } else if (!dcr->device->changer_name) {
152 Jmsg(jcr, M_INFO, 0, _("No \"Changer Device\" manual load of Volume may be required.\n"));
154 } else if (!dcr->device->changer_command) {
155 Jmsg(jcr, M_INFO, 0, _("No \"Changer Command\" manual load of Volume may be requird.\n"));
158 /* Attempt to load the Volume */
160 uint32_t timeout = dcr->device->max_changer_wait;
163 loaded = get_autochanger_loaded_slot(dcr);
165 if (loaded != slot) {
166 POOL_MEM results(PM_MESSAGE);
168 /* Unload anything in our drive */
169 if (!unload_autochanger(dcr, loaded)) {
173 /* Make sure desired slot is unloaded */
174 if (!unload_other_drive(dcr, slot)) {
179 * Load the desired cassette
182 Dmsg1(100, "Doing changer load slot %d\n", slot);
184 _("3304 Issuing autochanger \"load slot %d, drive %d\" command.\n"),
186 dcr->VolCatInfo.Slot = slot; /* slot to be loaded */
187 changer = edit_device_codes(dcr, changer, dcr->device->changer_command, "load");
189 Dmsg1(200, "Run program=%s\n", changer);
190 status = run_program_full_output(changer, timeout, results.c_str());
192 Jmsg(jcr, M_INFO, 0, _("3305 Autochanger \"load slot %d, drive %d\", status is OK.\n"),
194 Dmsg2(100, "load slot %d, drive %d, status is OK.\n", slot, drive);
195 dev->Slot = slot; /* set currently loaded slot */
198 be.set_errno(status);
199 Dmsg3(100, "load slot %d, drive %d, bad stats=%s.\n", slot, drive,
201 Jmsg(jcr, M_FATAL, 0, _("3992 Bad autochanger \"load slot %d, drive %d\": "
202 "ERR=%s.\nResults=%s\n"),
203 slot, drive, be.bstrerror(), results.c_str());
204 rtn_stat = -1; /* hard error */
205 dev->Slot = -1; /* mark unknown */
207 Dmsg2(100, "load slot %d status=%d\n", slot, status);
210 status = 0; /* we got what we want */
211 dev->Slot = slot; /* set currently loaded slot */
213 Dmsg1(100, "After changer, status=%d\n", status);
214 if (status == 0) { /* did we succeed? */
215 rtn_stat = 1; /* tape loaded by changer */
218 free_pool_memory(changer);
222 free_pool_memory(changer);
228 * Returns: -1 if error from changer command
230 * Note, this is safe to do without releasing the drive
231 * since it does not attempt load/unload a slot.
233 int get_autochanger_loaded_slot(DCR *dcr)
236 DEVICE *dev = dcr->dev;
238 uint32_t timeout = dcr->device->max_changer_wait;
239 int drive = dcr->dev->drive_index;
240 POOL_MEM results(PM_MESSAGE);
243 if (!dev->is_autochanger()) {
246 if (!dcr->device->changer_command) {
247 Jmsg(jcr, M_FATAL, 0, _("3992 Missing Changer command.\n"));
253 /* Virtual disk autochanger */
254 if (dcr->device->changer_command[0] == 0) {
258 /* Find out what is loaded, zero means device is unloaded */
259 changer = get_pool_memory(PM_FNAME);
261 Jmsg(jcr, M_INFO, 0, _("3301 Issuing autochanger \"loaded? drive %d\" command.\n"),
263 changer = edit_device_codes(dcr, changer, dcr->device->changer_command, "loaded");
264 *results.c_str() = 0;
265 Dmsg1(100, "Run program=%s\n", changer);
266 status = run_program_full_output(changer, timeout, results.c_str());
267 Dmsg3(100, "run_prog: %s stat=%d result=%s", changer, status, results.c_str());
269 loaded = str_to_int32(results.c_str());
271 Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded? drive %d\", result is Slot %d.\n"),
275 Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded? drive %d\", result: nothing loaded.\n"),
277 dev->Slot = -1; /* unknown */
281 be.set_errno(status);
282 Jmsg(jcr, M_INFO, 0, _("3991 Bad autochanger \"loaded? drive %d\" command: "
283 "ERR=%s.\nResults=%s\n"), drive, be.bstrerror(), results.c_str());
284 loaded = -1; /* force unload */
287 free_pool_memory(changer);
291 static void lock_changer(DCR *dcr)
293 AUTOCHANGER *changer_res = dcr->device->changer_res;
295 Dmsg1(200, "Locking changer %s\n", changer_res->hdr.name);
296 P(changer_res->changer_mutex); /* Lock changer script */
300 static void unlock_changer(DCR *dcr)
302 AUTOCHANGER *changer_res = dcr->device->changer_res;
304 Dmsg1(200, "Unlocking changer %s\n", changer_res->hdr.name);
305 V(changer_res->changer_mutex); /* Unlock changer script */
310 * Unload the volume, if any, in this drive
311 * On entry: loaded == 0 -- nothing to do
312 * loaded < 0 -- check if anything to do
313 * loaded > 0 -- load slot == loaded
315 bool unload_autochanger(DCR *dcr, int loaded)
317 DEVICE *dev = dcr->dev;
320 uint32_t timeout = dcr->device->max_changer_wait;
327 if (!dev->is_autochanger() || !dcr->device->changer_name ||
328 !dcr->device->changer_command) {
333 loaded = get_autochanger_loaded_slot(dcr);
337 POOL_MEM results(PM_MESSAGE);
338 POOLMEM *changer = get_pool_memory(PM_FNAME);
341 _("3307 Issuing autochanger \"unload slot %d, drive %d\" command.\n"),
342 loaded, dev->drive_index);
343 slot = dcr->VolCatInfo.Slot;
344 dcr->VolCatInfo.Slot = loaded;
345 changer = edit_device_codes(dcr, changer,
346 dcr->device->changer_command, "unload");
348 Dmsg1(100, "Run program=%s\n", changer);
349 *results.c_str() = 0;
350 int stat = run_program_full_output(changer, timeout, results.c_str());
351 dcr->VolCatInfo.Slot = slot;
355 Jmsg(jcr, M_INFO, 0, _("3995 Bad autochanger \"unload slot %d, drive %d\": "
356 "ERR=%s\nResults=%s\n"),
357 loaded, dev->drive_index, be.bstrerror(), results.c_str());
359 dev->Slot = -1; /* unknown */
361 dev->Slot = 0; /* nothing loaded */
363 free_volume(dev); /* Free any volume associated with this drive */
364 free_pool_memory(changer);
371 * Unload the slot if mounted in a different drive
373 static bool unload_other_drive(DCR *dcr, int slot)
379 uint32_t timeout = dcr->device->max_changer_wait;
381 AUTOCHANGER *changer = dcr->dev->device->changer_res;
384 int retries = 0; /* wait for device retries */
389 if (changer->device->size() == 1) {
393 foreach_alist(device, changer->device) {
394 if (device->dev && device->dev->Slot == slot) {
404 /* The Volume we want is on another device. */
405 if (dev->is_busy()) {
406 Dmsg4(100, "Vol %s for dev=%s in use dev=%s slot=%d\n",
407 dcr->VolumeName, dcr->dev->print_name(),
408 dev->print_name(), slot);
410 for (int i=0; i < 3; i++) {
411 if (dev->is_busy()) {
412 wait_for_device(dcr->jcr, retries);
418 if (dev->is_busy()) {
419 Jmsg(jcr, M_WARNING, 0, _("Volume \"%s\" is in use by device %s\n"),
420 dcr->VolumeName, dev->print_name());
421 Dmsg4(100, "Vol %s for dev=%s is busy dev=%s slot=%d\n",
422 dcr->VolumeName, dcr->dev->print_name(), dev->print_name(), slot);
423 Dmsg2(100, "num_writ=%d reserv=%d\n", dev->num_writers, dev->reserved_device);
428 POOLMEM *changer_cmd = get_pool_memory(PM_FNAME);
429 POOL_MEM results(PM_MESSAGE);
432 _("3307 Issuing autochanger \"unload slot %d, drive %d\" command.\n"),
433 slot, dev->drive_index);
435 Dmsg2(100, "Issuing autochanger \"unload slot %d, drive %d\" command.\n",
436 slot, dev->drive_index);
440 save_slot = dcr->VolCatInfo.Slot;
441 dcr->VolCatInfo.Slot = slot;
442 changer_cmd = edit_device_codes(dcr, changer_cmd,
443 dcr->device->changer_command, "unload");
445 Dmsg2(200, "close dev=%s reserve=%d\n", dev->print_name(),
446 dev->reserved_device);
447 Dmsg1(100, "Run program=%s\n", changer_cmd);
448 int stat = run_program_full_output(changer_cmd, timeout, results.c_str());
449 dcr->VolCatInfo.Slot = save_slot;
454 Jmsg(jcr, M_INFO, 0, _("3995 Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n"),
455 slot, dev->drive_index, be.bstrerror());
457 Dmsg3(100, "Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n",
458 slot, dev->drive_index, be.bstrerror());
460 dev->Slot = -1; /* unknown */
462 dev->Slot = 0; /* nothing loaded */
463 Dmsg0(100, "Slot unloaded\n");
465 free_volume(dev); /* Free any volume associated with this drive */
468 free_pool_memory(changer_cmd);
475 * List the Volumes that are in the autoloader possibly
476 * with their barcodes.
477 * We assume that it is always the Console that is calling us.
479 bool autochanger_cmd(DCR *dcr, BSOCK *dir, const char *cmd)
481 DEVICE *dev = dcr->dev;
482 uint32_t timeout = dcr->device->max_changer_wait;
485 int len = sizeof_pool_memory(dir->msg) - 1;
489 if (!dev->is_autochanger() || !dcr->device->changer_name ||
490 !dcr->device->changer_command) {
491 if (strcmp(cmd, "drives") == 0) {
492 bnet_fsend(dir, "drives=1\n");
494 bnet_fsend(dir, _("3993 Device %s not an autochanger device.\n"),
499 if (strcmp(cmd, "drives") == 0) {
500 AUTOCHANGER *changer_res = dcr->device->changer_res;
503 drives = changer_res->device->size();
505 bnet_fsend(dir, "drives=%d\n", drives);
506 Dmsg1(100, "drives=%d\n", drives);
510 changer = get_pool_memory(PM_FNAME);
512 /* Now issue the command */
513 changer = edit_device_codes(dcr, changer,
514 dcr->device->changer_command, cmd);
515 bnet_fsend(dir, _("3306 Issuing autochanger \"%s\" command.\n"), cmd);
516 bpipe = open_bpipe(changer, timeout, "r");
518 bnet_fsend(dir, _("3996 Open bpipe failed.\n"));
521 if (strcmp(cmd, "list") == 0) {
522 /* Get output from changer */
523 while (fgets(dir->msg, len, bpipe->rfd)) {
524 dir->msglen = strlen(dir->msg);
525 Dmsg1(100, "<stored: %s\n", dir->msg);
528 } else if (strcmp(cmd, "slots") == 0 ) {
530 /* For slots command, read a single line */
532 fgets(buf, sizeof(buf)-1, bpipe->rfd);
533 buf[sizeof(buf)-1] = 0;
534 /* Strip any leading space in front of # of slots */
535 for (p=buf; B_ISSPACE(*p); p++)
537 bnet_fsend(dir, "slots=%s", p);
538 Dmsg1(100, "<stored: %s", dir->msg);
541 stat = close_bpipe(bpipe);
545 bnet_fsend(dir, _("Autochanger error: ERR=%s\n"), be.bstrerror());
547 bnet_sig(dir, BNET_EOD);
552 free_pool_memory(changer);
558 * Edit codes into ChangerCommand
560 * %a = archive device name
561 * %c = changer device name
562 * %d = changer drive index
571 * omsg = edited output message
572 * imsg = input string containing edit codes (%x)
573 * cmd = command string (load, unload, ...)
576 char *edit_device_codes(DCR *dcr, char *omsg, const char *imsg, const char *cmd)
583 Dmsg1(1800, "edit_device_codes: %s\n", imsg);
584 for (p=imsg; *p; p++) {
591 str = dcr->dev->archive_name();
594 str = NPRT(dcr->device->changer_name);
597 sprintf(add, "%d", dcr->dev->drive_index);
604 sprintf(add, "%d", dcr->VolCatInfo.Slot - 1);
608 sprintf(add, "%d", dcr->VolCatInfo.Slot);
611 case 'j': /* Job name */
615 str = NPRT(dcr->VolumeName);
618 str = NPRT(dcr->jcr->client_name);
633 Dmsg1(1900, "add_str %s\n", str);
634 pm_strcat(&omsg, (char *)str);
635 Dmsg1(1800, "omsg=%s\n", omsg);
637 Dmsg1(800, "omsg=%s\n", omsg);