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 && 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");
157 offline_or_rewind_dev(dev);
158 force_close_device(dev);
159 status = run_program(changer, timeout, NULL);
161 Jmsg(jcr, M_INFO, 0, _("3305 Autochanger \"load slot %d, drive %d\", status is OK.\n"),
163 dev->Slot = slot; /* set currently loaded slot */
166 be.set_errno(status);
167 Jmsg(jcr, M_FATAL, 0, _("3992 Bad autochanger \"load slot %d, drive %d\": ERR=%s.\n"),
168 slot, drive, be.strerror());
169 rtn_stat = -1; /* hard error */
171 Dmsg2(400, "load slot %d status=%d\n", slot, status);
174 status = 0; /* we got what we want */
175 dev->Slot = slot; /* set currently loaded slot */
177 Dmsg1(400, "After changer, status=%d\n", status);
178 if (status == 0) { /* did we succeed? */
179 rtn_stat = 1; /* tape loaded by changer */
182 rtn_stat = 0; /* no changer found */
184 free_pool_memory(changer);
188 free_pool_memory(changer);
194 * Returns: -1 if error from changer command
196 * Note, this is safe to do without releasing the drive
197 * since it does not attempt load/unload a slot.
199 int get_autochanger_loaded_slot(DCR *dcr)
202 POOLMEM *changer, *results;
204 uint32_t timeout = dcr->device->max_changer_wait;
205 int drive = dcr->dev->drive_index;
207 if (!dcr->device->changer_command) {
208 Jmsg(jcr, M_FATAL, 0, _("3992 Missing Changer command.\n"));
212 results = get_pool_memory(PM_MESSAGE);
213 changer = get_pool_memory(PM_FNAME);
216 /* Find out what is loaded, zero means device is unloaded */
218 Jmsg(jcr, M_INFO, 0, _("3301 Issuing autochanger \"loaded drive %d\" command.\n"),
220 changer = edit_device_codes(dcr, changer, dcr->device->changer_command, "loaded");
222 status = run_program(changer, timeout, results);
223 Dmsg3(50, "run_prog: %s stat=%d result=%s\n", changer, status, results);
225 loaded = str_to_int32(results);
227 Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded drive %d\", result is Slot %d.\n"),
229 dcr->dev->Slot = loaded;
231 Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded drive %d\", result: nothing loaded.\n"),
237 be.set_errno(status);
238 Jmsg(jcr, M_INFO, 0, _("3991 Bad autochanger \"loaded drive %d\" command: ERR=%s.\n"),
239 drive, be.strerror());
240 loaded = -1; /* force unload */
243 free_pool_memory(changer);
244 free_pool_memory(results);
248 static void lock_changer(DCR *dcr)
250 AUTOCHANGER *changer_res = dcr->device->changer_res;
252 Dmsg1(100, "Locking changer %s\n", changer_res->hdr.name);
253 P(changer_res->changer_mutex); /* Lock changer script */
257 static void unlock_changer(DCR *dcr)
259 AUTOCHANGER *changer_res = dcr->device->changer_res;
261 Dmsg1(100, "Unlocking changer %s\n", changer_res->hdr.name);
262 V(changer_res->changer_mutex); /* Unlock changer script */
267 * Unload the volume, if any, in this drive
268 * On entry: loaded == 0 -- nothing to do
269 * loaded < 0 -- check if anything to do
270 * loaded > 0 -- load slot == loaded
272 bool unload_autochanger(DCR *dcr, int loaded)
274 DEVICE *dev = dcr->dev;
277 uint32_t timeout = dcr->device->max_changer_wait;
284 if (!dev->is_autochanger() || !dcr->device->changer_name ||
285 !dcr->device->changer_command) {
290 loaded = get_autochanger_loaded_slot(dcr);
294 POOLMEM *changer = get_pool_memory(PM_FNAME);
297 _("3307 Issuing autochanger \"unload slot %d, drive %d\" command.\n"),
298 loaded, dev->drive_index);
299 slot = dcr->VolCatInfo.Slot;
300 dcr->VolCatInfo.Slot = loaded;
301 changer = edit_device_codes(dcr, changer,
302 dcr->device->changer_command, "unload");
303 offline_or_rewind_dev(dev);
304 force_close_device(dev);
305 int stat = run_program(changer, timeout, NULL);
306 dcr->VolCatInfo.Slot = slot;
310 Jmsg(jcr, M_INFO, 0, _("3995 Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n"),
311 slot, dev->drive_index, be.strerror());
314 dev->Slot = 0; /* nothing loaded */
316 free_pool_memory(changer);
323 * Unload the slot if mounted in a different drive
325 static bool unload_other_drive(DCR *dcr, int slot)
331 uint32_t timeout = dcr->device->max_changer_wait;
333 AUTOCHANGER *changer = dcr->dev->device->changer_res;
342 if (changer->device->size() == 1) {
346 foreach_alist(device, changer->device) {
347 if (device->dev && device->dev->Slot == slot) {
357 /* The Volume we want is on another device. */
359 for (int i=0; i < 3; i++) {
360 if (dev->is_busy()) {
361 wait_for_device(dcr->jcr, first);
368 if (dev->is_busy()) {
369 Jmsg(jcr, M_WARNING, 0, _("Volume %s is in use by device %s\n"),
370 dcr->VolumeName, dev->print_name());
371 Dmsg2(200, "Volume %s is in use by device %s\n",
372 dcr->VolumeName, dev->print_name());
377 POOLMEM *changer_cmd = get_pool_memory(PM_FNAME);
380 _("3307 Issuing autochanger \"unload slot %d, drive %d\" command.\n"),
381 slot, dev->drive_index);
383 Dmsg2(200, "Issuing autochanger \"unload slot %d, drive %d\" command.\n",
384 slot, dev->drive_index);
386 save_slot = dcr->VolCatInfo.Slot;
389 dcr->VolCatInfo.Slot = slot;
390 changer_cmd = edit_device_codes(dcr, changer_cmd,
391 dcr->device->changer_command, "unload");
392 Dmsg1(200, "Run program=%s\n", changer_cmd);
393 offline_or_rewind_dev(dev);
394 force_close_device(dev);
395 int stat = run_program(changer_cmd, timeout, NULL);
396 dcr->VolCatInfo.Slot = save_slot;
401 Jmsg(jcr, M_INFO, 0, _("3995 Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n"),
402 slot, dev->drive_index, be.strerror());
404 Dmsg3(200, "Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n",
405 slot, dev->drive_index, be.strerror());
408 dev->Slot = 0; /* nothing loaded */
409 Dmsg0(200, "Slot unloaded\n");
413 free_pool_memory(changer_cmd);
420 * List the Volumes that are in the autoloader possibly
421 * with their barcodes.
422 * We assume that it is always the Console that is calling us.
424 bool autochanger_cmd(DCR *dcr, BSOCK *dir, const char *cmd)
426 DEVICE *dev = dcr->dev;
427 uint32_t timeout = dcr->device->max_changer_wait;
430 int len = sizeof_pool_memory(dir->msg) - 1;
434 if (!dev->is_autochanger() || !dcr->device->changer_name ||
435 !dcr->device->changer_command) {
436 if (strcmp(cmd, "drives") == 0) {
437 bnet_fsend(dir, "drives=1\n");
439 bnet_fsend(dir, _("3993 Device %s not an autochanger device.\n"),
445 if (strcmp(cmd, "list") == 0) {
446 unload_autochanger(dcr, -1);
448 if (strcmp(cmd, "drives") == 0) {
449 AUTOCHANGER *changer_res = dcr->device->changer_res;
452 drives = changer_res->device->size();
454 bnet_fsend(dir, "drives=%d\n", drives);
455 Dmsg1(100, "drives=%d\n", drives);
459 changer = get_pool_memory(PM_FNAME);
461 /* Now issue the command */
462 changer = edit_device_codes(dcr, changer,
463 dcr->device->changer_command, cmd);
464 bnet_fsend(dir, _("3306 Issuing autochanger \"%s\" command.\n"), cmd);
465 bpipe = open_bpipe(changer, timeout, "r");
467 bnet_fsend(dir, _("3996 Open bpipe failed.\n"));
470 if (strcmp(cmd, "list") == 0) {
471 /* Get output from changer */
472 while (fgets(dir->msg, len, bpipe->rfd)) {
473 dir->msglen = strlen(dir->msg);
474 Dmsg1(100, "<stored: %s\n", dir->msg);
477 } else if (strcmp(cmd, "slots") == 0 ) {
479 /* For slots command, read a single line */
481 fgets(buf, sizeof(buf)-1, bpipe->rfd);
482 buf[sizeof(buf)-1] = 0;
483 /* Strip any leading space in front of # of slots */
484 for (p=buf; B_ISSPACE(*p); p++)
486 bnet_fsend(dir, "slots=%s", p);
487 Dmsg1(100, "<stored: %s", dir->msg);
490 stat = close_bpipe(bpipe);
494 bnet_fsend(dir, _("Autochanger error: ERR=%s\n"), be.strerror());
496 bnet_sig(dir, BNET_EOD);
501 free_pool_memory(changer);
507 * Edit codes into ChangerCommand
509 * %a = archive device name
510 * %c = changer device name
511 * %d = changer drive index
520 * omsg = edited output message
521 * imsg = input string containing edit codes (%x)
522 * cmd = command string (load, unload, ...)
525 char *edit_device_codes(DCR *dcr, char *omsg, const char *imsg, const char *cmd)
532 Dmsg1(1800, "edit_device_codes: %s\n", imsg);
533 for (p=imsg; *p; p++) {
540 str = dcr->dev->archive_name();
543 str = NPRT(dcr->device->changer_name);
546 sprintf(add, "%d", dcr->dev->drive_index);
553 sprintf(add, "%d", dcr->VolCatInfo.Slot - 1);
557 sprintf(add, "%d", dcr->VolCatInfo.Slot);
560 case 'j': /* Job name */
564 str = NPRT(dcr->VolumeName);
567 str = NPRT(dcr->jcr->client_name);
582 Dmsg1(1900, "add_str %s\n", str);
583 pm_strcat(&omsg, (char *)str);
584 Dmsg1(1800, "omsg=%s\n", omsg);
586 Dmsg1(800, "omsg=%s\n", omsg);