3 * Routines for handling the autochanger.
5 * Kern Sibbald, August MMII
10 Copyright (C) 2002-2006 Kern Sibbald
12 This program is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License
14 version 2 as amended with additional clauses defined in the
15 file LICENSE in the main source directory.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 the file LICENSE for additional details.
24 #include "bacula.h" /* pull in global headers */
25 #include "stored.h" /* pull in Storage Deamon headers */
27 /* Forward referenced functions */
28 static void lock_changer(DCR *dcr);
29 static void unlock_changer(DCR *dcr);
30 static bool unload_other_drive(DCR *dcr, int slot);
32 /* Init all the autochanger resources found */
33 bool init_autochangers()
37 /* Ensure that the media_type for each device is the same */
38 foreach_res(changer, R_AUTOCHANGER) {
40 foreach_alist(device, changer->device) {
42 * If the device does not have a changer name or changer command
43 * defined, used the one from the Autochanger resource
45 if (!device->changer_name && changer->changer_name) {
46 device->changer_name = bstrdup(changer->changer_name);
48 if (!device->changer_command && changer->changer_command) {
49 device->changer_command = bstrdup(changer->changer_command);
51 if (!device->changer_name) {
52 Jmsg(NULL, M_ERROR, 0,
53 _("No Changer Name given for device %s. Cannot continue.\n"),
57 if (!device->changer_command) {
58 Jmsg(NULL, M_ERROR, 0,
59 _("No Changer Command given for device %s. Cannot continue.\n"),
65 if (media_type == NULL) {
66 media_type = device->media_type; /* get Media Type of first device */
69 /* Ensure that other devices Media Types are the same */
70 if (strcmp(media_type, device->media_type) != 0) {
71 Jmsg(NULL, M_ERROR, 0,
72 _("Media Type not the same for all devices in changer %s. Cannot continue.\n"),
85 * Called here to do an autoload using the autochanger, if
86 * configured, and if a Slot has been defined for this Volume.
87 * On success this routine loads the indicated tape, but the
88 * label is not read, so it must be verified.
90 * Note if dir is not NULL, it is the console requesting the
91 * autoload for labeling, so we respond directly to the
94 * Returns: 1 on success
95 * 0 on failure (no changer available)
96 * -1 on error on autochanger
98 int autoload_device(DCR *dcr, int writing, BSOCK *dir)
101 DEVICE *dev = dcr->dev;
103 int drive = dev->drive_index;
104 int rtn_stat = -1; /* error status */
107 slot = dcr->VolCatInfo.InChanger ? dcr->VolCatInfo.Slot : 0;
109 * Handle autoloaders here. If we cannot autoload it, we
110 * will return 0 so that the sysop will be asked to load it.
112 if (writing && dev->is_autochanger() && slot <= 0) {
114 return 0; /* For user, bail out right now */
116 if (dir_find_next_appendable_volume(dcr)) {
117 slot = dcr->VolCatInfo.InChanger ? dcr->VolCatInfo.Slot : 0;
122 Dmsg1(400, "Want changer slot=%d\n", slot);
124 changer = get_pool_memory(PM_FNAME);
125 if (slot > 0 && dcr->device->changer_name && dcr->device->changer_command) {
126 uint32_t timeout = dcr->device->max_changer_wait;
129 loaded = get_autochanger_loaded_slot(dcr);
131 if (loaded != slot) {
133 /* Unload anything in our drive */
134 if (!unload_autochanger(dcr, loaded)) {
138 /* Make sure desired slot is unloaded */
139 if (!unload_other_drive(dcr, slot)) {
144 * Load the desired cassette
147 Dmsg1(400, "Doing changer load slot %d\n", slot);
149 _("3304 Issuing autochanger \"load slot %d, drive %d\" command.\n"),
151 dcr->VolCatInfo.Slot = slot; /* slot to be loaded */
152 changer = edit_device_codes(dcr, changer,
153 dcr->device->changer_command, "load");
154 offline_or_rewind_dev(dev);
155 force_close_device(dev);
156 status = run_program(changer, timeout, NULL);
158 Jmsg(jcr, M_INFO, 0, _("3305 Autochanger \"load slot %d, drive %d\", status is OK.\n"),
160 dev->Slot = slot; /* set currently loaded slot */
163 be.set_errno(status);
164 Jmsg(jcr, M_FATAL, 0, _("3992 Bad autochanger \"load slot %d, drive %d\": ERR=%s.\n"),
165 slot, drive, be.strerror());
166 rtn_stat = -1; /* hard error */
168 Dmsg2(400, "load slot %d status=%d\n", slot, status);
171 status = 0; /* we got what we want */
172 dev->Slot = slot; /* set currently loaded slot */
174 Dmsg1(400, "After changer, status=%d\n", status);
175 if (status == 0) { /* did we succeed? */
176 rtn_stat = 1; /* tape loaded by changer */
179 rtn_stat = 0; /* no changer found */
181 free_pool_memory(changer);
185 free_pool_memory(changer);
191 * Returns: -1 if error from changer command
193 * Note, this is safe to do without releasing the drive
194 * since it does not attempt load/unload a slot.
196 int get_autochanger_loaded_slot(DCR *dcr)
199 POOLMEM *changer, *results;
201 uint32_t timeout = dcr->device->max_changer_wait;
202 int drive = dcr->dev->drive_index;
204 if (!dcr->device->changer_command) {
205 Jmsg(jcr, M_FATAL, 0, _("3992 Missing Changer command.\n"));
209 results = get_pool_memory(PM_MESSAGE);
210 changer = get_pool_memory(PM_FNAME);
213 /* Find out what is loaded, zero means device is unloaded */
215 Jmsg(jcr, M_INFO, 0, _("3301 Issuing autochanger \"loaded drive %d\" command.\n"),
217 changer = edit_device_codes(dcr, changer, dcr->device->changer_command, "loaded");
219 status = run_program(changer, timeout, results);
220 Dmsg3(50, "run_prog: %s stat=%d result=%s\n", changer, status, results);
222 loaded = str_to_int32(results);
224 Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded drive %d\", result is Slot %d.\n"),
226 dcr->dev->Slot = loaded;
228 Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded drive %d\", result: nothing loaded.\n"),
234 be.set_errno(status);
235 Jmsg(jcr, M_INFO, 0, _("3991 Bad autochanger \"loaded drive %d\" command: ERR=%s.\n"),
236 drive, be.strerror());
237 loaded = -1; /* force unload */
240 free_pool_memory(changer);
241 free_pool_memory(results);
245 static void lock_changer(DCR *dcr)
247 AUTOCHANGER *changer_res = dcr->device->changer_res;
249 Dmsg1(100, "Locking changer %s\n", changer_res->hdr.name);
250 P(changer_res->changer_mutex); /* Lock changer script */
254 static void unlock_changer(DCR *dcr)
256 AUTOCHANGER *changer_res = dcr->device->changer_res;
258 Dmsg1(100, "Unlocking changer %s\n", changer_res->hdr.name);
259 V(changer_res->changer_mutex); /* Unlock changer script */
264 * Unload the volume, if any, in this drive
265 * On entry: loaded == 0 -- nothing to do
266 * loaded < 0 -- check if anything to do
267 * loaded > 0 -- load slot == loaded
269 bool unload_autochanger(DCR *dcr, int loaded)
271 DEVICE *dev = dcr->dev;
274 uint32_t timeout = dcr->device->max_changer_wait;
281 if (!dev->is_autochanger() || !dcr->device->changer_name ||
282 !dcr->device->changer_command) {
287 loaded = get_autochanger_loaded_slot(dcr);
291 POOLMEM *changer = get_pool_memory(PM_FNAME);
294 _("3307 Issuing autochanger \"unload slot %d, drive %d\" command.\n"),
295 loaded, dev->drive_index);
296 slot = dcr->VolCatInfo.Slot;
297 dcr->VolCatInfo.Slot = loaded;
298 changer = edit_device_codes(dcr, changer,
299 dcr->device->changer_command, "unload");
300 offline_or_rewind_dev(dev);
301 force_close_device(dev);
302 int stat = run_program(changer, timeout, NULL);
303 dcr->VolCatInfo.Slot = slot;
307 Jmsg(jcr, M_INFO, 0, _("3995 Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n"),
308 slot, dev->drive_index, be.strerror());
311 dev->Slot = 0; /* nothing loaded */
313 free_pool_memory(changer);
320 * Unload the slot if mounted in a different drive
322 static bool unload_other_drive(DCR *dcr, int slot)
328 uint32_t timeout = dcr->device->max_changer_wait;
330 AUTOCHANGER *changer = dcr->dev->device->changer_res;
337 if (changer->device->size() == 1) {
341 foreach_alist(device, changer->device) {
342 if (device->dev && device->dev->Slot == slot) {
351 if (dev->is_busy()) {
352 Jmsg(jcr, M_WARNING, 0, _("Volume %s is in use by device %s\n"),
353 dcr->VolumeName, dev->print_name());
354 Dmsg2(200, "Volume %s is in use by device %s\n",
355 dcr->VolumeName, dev->print_name());
360 POOLMEM *changer_cmd = get_pool_memory(PM_FNAME);
363 _("3307 Issuing autochanger \"unload slot %d, drive %d\" command.\n"),
364 slot, dev->drive_index);
366 Dmsg2(200, "Issuing autochanger \"unload slot %d, drive %d\" command.\n",
367 slot, dev->drive_index);
369 save_slot = dcr->VolCatInfo.Slot;
372 dcr->VolCatInfo.Slot = slot;
373 changer_cmd = edit_device_codes(dcr, changer_cmd,
374 dcr->device->changer_command, "unload");
375 Dmsg1(200, "Run program=%s\n", changer_cmd);
376 offline_or_rewind_dev(dev);
377 force_close_device(dev);
378 int stat = run_program(changer_cmd, timeout, NULL);
379 dcr->VolCatInfo.Slot = save_slot;
384 Jmsg(jcr, M_INFO, 0, _("3995 Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n"),
385 slot, dev->drive_index, be.strerror());
387 Dmsg3(200, "Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n",
388 slot, dev->drive_index, be.strerror());
391 dev->Slot = 0; /* nothing loaded */
392 Dmsg0(200, "Slot unloaded\n");
395 free_pool_memory(changer_cmd);
402 * List the Volumes that are in the autoloader possibly
403 * with their barcodes.
404 * We assume that it is always the Console that is calling us.
406 bool autochanger_cmd(DCR *dcr, BSOCK *dir, const char *cmd)
408 DEVICE *dev = dcr->dev;
409 uint32_t timeout = dcr->device->max_changer_wait;
412 int len = sizeof_pool_memory(dir->msg) - 1;
416 if (!dev->is_autochanger() || !dcr->device->changer_name ||
417 !dcr->device->changer_command) {
418 if (strcmp(cmd, "drives") == 0) {
419 bnet_fsend(dir, "drives=1\n");
421 bnet_fsend(dir, _("3993 Device %s not an autochanger device.\n"),
427 if (strcmp(cmd, "list") == 0) {
428 unload_autochanger(dcr, -1);
430 if (strcmp(cmd, "drives") == 0) {
431 AUTOCHANGER *changer_res = dcr->device->changer_res;
434 drives = changer_res->device->size();
436 bnet_fsend(dir, "drives=%d\n", drives);
437 Dmsg1(100, "drives=%d\n", drives);
441 changer = get_pool_memory(PM_FNAME);
443 /* Now issue the command */
444 changer = edit_device_codes(dcr, changer,
445 dcr->device->changer_command, cmd);
446 bnet_fsend(dir, _("3306 Issuing autochanger \"%s\" command.\n"), cmd);
447 bpipe = open_bpipe(changer, timeout, "r");
449 bnet_fsend(dir, _("3996 Open bpipe failed.\n"));
452 if (strcmp(cmd, "list") == 0) {
453 /* Get output from changer */
454 while (fgets(dir->msg, len, bpipe->rfd)) {
455 dir->msglen = strlen(dir->msg);
456 Dmsg1(100, "<stored: %s\n", dir->msg);
459 } else if (strcmp(cmd, "slots") == 0 ) {
461 /* For slots command, read a single line */
463 fgets(buf, sizeof(buf)-1, bpipe->rfd);
464 buf[sizeof(buf)-1] = 0;
465 /* Strip any leading space in front of # of slots */
466 for (p=buf; B_ISSPACE(*p); p++)
468 bnet_fsend(dir, "slots=%s", p);
469 Dmsg1(100, "<stored: %s", dir->msg);
472 stat = close_bpipe(bpipe);
476 bnet_fsend(dir, _("Autochanger error: ERR=%s\n"), be.strerror());
478 bnet_sig(dir, BNET_EOD);
483 free_pool_memory(changer);
489 * Edit codes into ChangerCommand
491 * %a = archive device name
492 * %c = changer device name
493 * %d = changer drive index
502 * omsg = edited output message
503 * imsg = input string containing edit codes (%x)
504 * cmd = command string (load, unload, ...)
507 char *edit_device_codes(DCR *dcr, char *omsg, const char *imsg, const char *cmd)
514 Dmsg1(1800, "edit_device_codes: %s\n", imsg);
515 for (p=imsg; *p; p++) {
522 str = dcr->dev->archive_name();
525 str = NPRT(dcr->device->changer_name);
528 sprintf(add, "%d", dcr->dev->drive_index);
535 sprintf(add, "%d", dcr->VolCatInfo.Slot - 1);
539 sprintf(add, "%d", dcr->VolCatInfo.Slot);
542 case 'j': /* Job name */
546 str = NPRT(dcr->VolumeName);
549 str = NPRT(dcr->jcr->client_name);
564 Dmsg1(1900, "add_str %s\n", str);
565 pm_strcat(&omsg, (char *)str);
566 Dmsg1(1800, "omsg=%s\n", omsg);
568 Dmsg1(800, "omsg=%s\n", omsg);