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 if (!dev->is_autochanger()) {
110 slot = dcr->VolCatInfo.InChanger ? dcr->VolCatInfo.Slot : 0;
112 * Handle autoloaders here. If we cannot autoload it, we
113 * will return 0 so that the sysop will be asked to load it.
115 if (writing && dev->is_autochanger() && slot <= 0) {
117 return 0; /* For user, bail out right now */
119 if (dir_find_next_appendable_volume(dcr)) {
120 slot = dcr->VolCatInfo.InChanger ? dcr->VolCatInfo.Slot : 0;
125 Dmsg1(400, "Want changer slot=%d\n", slot);
127 changer = get_pool_memory(PM_FNAME);
128 if (slot > 0 && dcr->device->changer_name && dcr->device->changer_command) {
129 uint32_t timeout = dcr->device->max_changer_wait;
132 loaded = get_autochanger_loaded_slot(dcr);
134 if (loaded != slot) {
136 /* Unload anything in our drive */
137 if (!unload_autochanger(dcr, loaded)) {
141 /* Make sure desired slot is unloaded */
142 if (!unload_other_drive(dcr, slot)) {
147 * Load the desired cassette
150 Dmsg1(400, "Doing changer load slot %d\n", slot);
152 _("3304 Issuing autochanger \"load slot %d, drive %d\" command.\n"),
154 dcr->VolCatInfo.Slot = slot; /* slot to be loaded */
155 changer = edit_device_codes(dcr, changer,
156 dcr->device->changer_command, "load");
158 status = run_program(changer, timeout, NULL);
160 Jmsg(jcr, M_INFO, 0, _("3305 Autochanger \"load slot %d, drive %d\", status is OK.\n"),
162 dev->Slot = slot; /* set currently loaded slot */
165 be.set_errno(status);
166 Jmsg(jcr, M_FATAL, 0, _("3992 Bad autochanger \"load slot %d, drive %d\": ERR=%s.\n"),
167 slot, drive, be.strerror());
168 rtn_stat = -1; /* hard error */
170 Dmsg2(400, "load slot %d status=%d\n", slot, status);
173 status = 0; /* we got what we want */
174 dev->Slot = slot; /* set currently loaded slot */
176 Dmsg1(400, "After changer, status=%d\n", status);
177 if (status == 0) { /* did we succeed? */
178 rtn_stat = 1; /* tape loaded by changer */
181 rtn_stat = 0; /* no changer found */
183 free_pool_memory(changer);
187 free_pool_memory(changer);
193 * Returns: -1 if error from changer command
195 * Note, this is safe to do without releasing the drive
196 * since it does not attempt load/unload a slot.
198 int get_autochanger_loaded_slot(DCR *dcr)
201 POOLMEM *changer, *results;
203 uint32_t timeout = dcr->device->max_changer_wait;
204 int drive = dcr->dev->drive_index;
206 if (!dcr->device->changer_command) {
207 Jmsg(jcr, M_FATAL, 0, _("3992 Missing Changer command.\n"));
211 results = get_pool_memory(PM_MESSAGE);
212 changer = get_pool_memory(PM_FNAME);
215 /* Find out what is loaded, zero means device is unloaded */
217 Jmsg(jcr, M_INFO, 0, _("3301 Issuing autochanger \"loaded drive %d\" command.\n"),
219 changer = edit_device_codes(dcr, changer, dcr->device->changer_command, "loaded");
221 status = run_program(changer, timeout, results);
222 Dmsg3(50, "run_prog: %s stat=%d result=%s\n", changer, status, results);
224 loaded = str_to_int32(results);
226 Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded drive %d\", result is Slot %d.\n"),
228 dcr->dev->Slot = loaded;
230 Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded drive %d\", result: nothing loaded.\n"),
236 be.set_errno(status);
237 Jmsg(jcr, M_INFO, 0, _("3991 Bad autochanger \"loaded drive %d\" command: ERR=%s.\n"),
238 drive, be.strerror());
239 loaded = -1; /* force unload */
242 free_pool_memory(changer);
243 free_pool_memory(results);
247 static void lock_changer(DCR *dcr)
249 AUTOCHANGER *changer_res = dcr->device->changer_res;
251 Dmsg1(100, "Locking changer %s\n", changer_res->hdr.name);
252 P(changer_res->changer_mutex); /* Lock changer script */
256 static void unlock_changer(DCR *dcr)
258 AUTOCHANGER *changer_res = dcr->device->changer_res;
260 Dmsg1(100, "Unlocking changer %s\n", changer_res->hdr.name);
261 V(changer_res->changer_mutex); /* Unlock changer script */
266 * Unload the volume, if any, in this drive
267 * On entry: loaded == 0 -- nothing to do
268 * loaded < 0 -- check if anything to do
269 * loaded > 0 -- load slot == loaded
271 bool unload_autochanger(DCR *dcr, int loaded)
273 DEVICE *dev = dcr->dev;
276 uint32_t timeout = dcr->device->max_changer_wait;
283 if (!dev->is_autochanger() || !dcr->device->changer_name ||
284 !dcr->device->changer_command) {
289 loaded = get_autochanger_loaded_slot(dcr);
293 POOLMEM *changer = get_pool_memory(PM_FNAME);
296 _("3307 Issuing autochanger \"unload slot %d, drive %d\" command.\n"),
297 loaded, dev->drive_index);
298 slot = dcr->VolCatInfo.Slot;
299 dcr->VolCatInfo.Slot = loaded;
300 changer = edit_device_codes(dcr, changer,
301 dcr->device->changer_command, "unload");
303 int stat = run_program(changer, timeout, NULL);
304 dcr->VolCatInfo.Slot = slot;
308 Jmsg(jcr, M_INFO, 0, _("3995 Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n"),
309 slot, dev->drive_index, be.strerror());
312 dev->Slot = 0; /* nothing loaded */
314 free_pool_memory(changer);
321 * Unload the slot if mounted in a different drive
323 static bool unload_other_drive(DCR *dcr, int slot)
329 uint32_t timeout = dcr->device->max_changer_wait;
331 AUTOCHANGER *changer = dcr->dev->device->changer_res;
338 if (changer->device->size() == 1) {
342 foreach_alist(device, changer->device) {
343 if (device->dev && device->dev->Slot == slot) {
352 if (dev->is_busy()) {
353 Jmsg(jcr, M_WARNING, 0, _("Volume %s is in use by device %s\n"),
354 dcr->VolumeName, dev->print_name());
355 Dmsg2(200, "Volume %s is in use by device %s\n",
356 dcr->VolumeName, dev->print_name());
361 POOLMEM *changer_cmd = get_pool_memory(PM_FNAME);
364 _("3307 Issuing autochanger \"unload slot %d, drive %d\" command.\n"),
365 slot, dev->drive_index);
367 Dmsg2(200, "Issuing autochanger \"unload slot %d, drive %d\" command.\n",
368 slot, dev->drive_index);
370 save_slot = dcr->VolCatInfo.Slot;
373 dcr->VolCatInfo.Slot = slot;
374 changer_cmd = edit_device_codes(dcr, changer_cmd,
375 dcr->device->changer_command, "unload");
376 Dmsg1(200, "Run program=%s\n", changer_cmd);
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);