3 * Routines for handling the autochanger.
5 * Kern Sibbald, August MMII
10 Copyright (C) 2002-2005 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 char *media_type = NULL;
41 foreach_alist(device, changer->device) {
43 * If the device does not have a changer name or changer command
44 * defined, used the one from the Autochanger resource
46 if (!device->changer_name && changer->changer_name) {
47 device->changer_name = bstrdup(changer->changer_name);
49 if (!device->changer_command && changer->changer_command) {
50 device->changer_command = bstrdup(changer->changer_command);
52 if (!device->changer_name) {
53 Jmsg(NULL, M_ERROR, 0,
54 _("No Changer Name given for device %s. Cannot continue.\n"),
58 if (!device->changer_command) {
59 Jmsg(NULL, M_ERROR, 0,
60 _("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"),
84 * Called here to do an autoload using the autochanger, if
85 * configured, and if a Slot has been defined for this Volume.
86 * On success this routine loads the indicated tape, but the
87 * label is not read, so it must be verified.
89 * Note if dir is not NULL, it is the console requesting the
90 * autoload for labeling, so we respond directly to the
93 * Returns: 1 on success
94 * 0 on failure (no changer available)
95 * -1 on error on autochanger
97 int autoload_device(DCR *dcr, int writing, BSOCK *dir)
100 DEVICE *dev = dcr->dev;
102 int drive = dev->drive_index;
103 int rtn_stat = -1; /* error status */
106 slot = dcr->VolCatInfo.InChanger ? dcr->VolCatInfo.Slot : 0;
108 * Handle autoloaders here. If we cannot autoload it, we
109 * will return 0 so that the sysop will be asked to load it.
111 if (writing && dev->is_autochanger() && slot <= 0) {
113 return 0; /* For user, bail out right now */
115 if (dir_find_next_appendable_volume(dcr)) {
116 slot = dcr->VolCatInfo.InChanger ? dcr->VolCatInfo.Slot : 0;
121 Dmsg1(400, "Want changer slot=%d\n", slot);
123 changer = get_pool_memory(PM_FNAME);
124 if (slot > 0 && dcr->device->changer_name && dcr->device->changer_command) {
125 uint32_t timeout = dcr->device->max_changer_wait;
128 loaded = get_autochanger_loaded_slot(dcr);
130 if (loaded != slot) {
131 /* Unload anything in our drive */
132 if (!unload_autochanger(dcr, loaded)) {
136 /* Make sure desired slot is unloaded */
137 if (!unload_other_drive(dcr, slot)) {
141 /* We are going to load a new tape, so close the device */
142 offline_or_rewind_dev(dev);
143 force_close_device(dev);
146 * Load the desired cassette
148 Dmsg1(400, "Doing changer load slot %d\n", slot);
150 _("3304 Issuing autochanger \"load slot %d, drive %d\" command.\n"),
152 dcr->VolCatInfo.Slot = slot; /* slot to be loaded */
153 changer = edit_device_codes(dcr, changer,
154 dcr->device->changer_command, "load");
155 status = run_program(changer, timeout, NULL);
157 Jmsg(jcr, M_INFO, 0, _("3305 Autochanger \"load slot %d, drive %d\", status is OK.\n"),
159 dev->Slot = slot; /* set currently loaded slot */
162 be.set_errno(status);
163 Jmsg(jcr, M_FATAL, 0, _("3992 Bad autochanger \"load slot %d, drive %d\": ERR=%s.\n"),
164 slot, drive, be.strerror());
168 Dmsg2(400, "load slot %d status=%d\n", slot, status);
170 status = 0; /* we got what we want */
171 dev->Slot = slot; /* set currently loaded slot */
173 Dmsg1(400, "After changer, status=%d\n", status);
174 if (status == 0) { /* did we succeed? */
175 rtn_stat = 1; /* tape loaded by changer */
178 rtn_stat = 0; /* no changer found */
180 free_pool_memory(changer);
184 free_pool_memory(changer);
191 * Returns: -1 if error from changer command
194 int get_autochanger_loaded_slot(DCR *dcr)
197 POOLMEM *changer, *results;
199 uint32_t timeout = dcr->device->max_changer_wait;
200 int drive = dcr->dev->drive_index;
202 if (!dcr->device->changer_command) {
203 Jmsg(jcr, M_FATAL, 0, _("3992 Missing Changer command.\n"));
207 results = get_pool_memory(PM_MESSAGE);
208 changer = get_pool_memory(PM_FNAME);
212 /* Find out what is loaded, zero means device is unloaded */
213 Jmsg(jcr, M_INFO, 0, _("3301 Issuing autochanger \"loaded drive %d\" command.\n"),
215 changer = edit_device_codes(dcr, changer, dcr->device->changer_command, "loaded");
217 status = run_program(changer, timeout, results);
218 Dmsg3(50, "run_prog: %s stat=%d result=%s\n", changer, status, results);
220 loaded = atoi(results);
222 Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded drive %d\", result is Slot %d.\n"),
224 dcr->dev->Slot = loaded;
226 Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded drive %d\", result: nothing loaded.\n"),
232 be.set_errno(status);
233 Jmsg(jcr, M_INFO, 0, _("3991 Bad autochanger \"loaded drive %d\" command: ERR=%s.\n"),
234 drive, be.strerror());
235 loaded = -1; /* force unload */
238 free_pool_memory(changer);
239 free_pool_memory(results);
243 static void lock_changer(DCR *dcr)
245 AUTOCHANGER *changer_res = dcr->device->changer_res;
247 Dmsg1(100, "Locking changer %s\n", changer_res->hdr.name);
248 P(changer_res->changer_mutex); /* Lock changer script */
252 static void unlock_changer(DCR *dcr)
254 AUTOCHANGER *changer_res = dcr->device->changer_res;
256 Dmsg1(100, "Unlocking changer %s\n", changer_res->hdr.name);
257 V(changer_res->changer_mutex); /* Unlock changer script */
262 * Unload the volume, if any, in this drive
263 * On entry: loaded == 0 -- nothing to do
264 * loaded < 0 -- check if anything to do
265 * loaded > 0 -- load slot == loaded
267 bool unload_autochanger(DCR *dcr, int loaded)
269 DEVICE *dev = dcr->dev;
272 uint32_t timeout = dcr->device->max_changer_wait;
279 if (!dev->is_autochanger() || !dcr->device->changer_name ||
280 !dcr->device->changer_command) {
284 /* We are going to load a new tape, so close the device */
285 offline_or_rewind_dev(dev);
286 force_close_device(dev);
289 loaded = get_autochanger_loaded_slot(dcr);
292 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");
301 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);
319 * Unload the slot if mounted in a different drive
321 static bool unload_other_drive(DCR *dcr, int slot)
327 uint32_t timeout = dcr->device->max_changer_wait;
329 AUTOCHANGER *changer = dcr->dev->device->changer_res;
336 if (changer->device->size() == 1) {
340 foreach_alist(device, changer->device) {
341 if (device->dev && device->dev->Slot == slot) {
350 if (dev->is_busy()) {
351 Jmsg(jcr, M_WARNING, 0, _("Volume %s is in use by device %s\n"),
352 dcr->VolumeName, dev->print_name());
353 Dmsg2(200, "Volume %s is in use by device %s\n",
354 dcr->VolumeName, dev->print_name());
359 /* We are going to unload a tape, so close the device */
360 offline_or_rewind_dev(dev);
361 force_close_device(dev);
363 POOLMEM *changer_cmd = get_pool_memory(PM_FNAME);
365 _("3307 Issuing autochanger \"unload slot %d, drive %d\" command.\n"),
366 slot, dev->drive_index);
368 Dmsg2(200, "Issuing autochanger \"unload slot %d, drive %d\" command.\n",
369 slot, dev->drive_index);
371 save_slot = dcr->VolCatInfo.Slot;
374 dcr->VolCatInfo.Slot = slot;
375 changer_cmd = edit_device_codes(dcr, changer_cmd,
376 dcr->device->changer_command, "unload");
378 Dmsg1(200, "Run program=%s\n", changer_cmd);
379 int stat = run_program(changer_cmd, timeout, NULL);
381 dcr->VolCatInfo.Slot = save_slot;
386 Jmsg(jcr, M_INFO, 0, _("3995 Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n"),
387 slot, dev->drive_index, be.strerror());
389 Dmsg3(200, "Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n",
390 slot, dev->drive_index, be.strerror());
393 dev->Slot = 0; /* nothing loaded */
394 Dmsg0(200, "Slot unloaded\n");
396 free_pool_memory(changer_cmd);
403 * List the Volumes that are in the autoloader possibly
404 * with their barcodes.
405 * We assume that it is always the Console that is calling us.
407 bool autochanger_cmd(DCR *dcr, BSOCK *dir, const char *cmd)
409 DEVICE *dev = dcr->dev;
410 uint32_t timeout = dcr->device->max_changer_wait;
413 int len = sizeof_pool_memory(dir->msg) - 1;
417 if (!dev->is_autochanger() || !dcr->device->changer_name ||
418 !dcr->device->changer_command) {
419 bnet_fsend(dir, _("3993 Device %s not an autochanger device.\n"),
424 changer = get_pool_memory(PM_FNAME);
426 if (strcmp(cmd, "list") == 0) {
427 unload_autochanger(dcr, -1);
430 /* Now issue the command */
431 changer = edit_device_codes(dcr, changer,
432 dcr->device->changer_command, cmd);
433 bnet_fsend(dir, _("3306 Issuing autochanger \"%s\" command.\n"), cmd);
435 bpipe = open_bpipe(changer, timeout, "r");
438 bnet_fsend(dir, _("3996 Open bpipe failed.\n"));
441 if (strcmp(cmd, "list") == 0) {
442 /* Get output from changer */
443 while (fgets(dir->msg, len, bpipe->rfd)) {
444 dir->msglen = strlen(dir->msg);
445 Dmsg1(100, "<stored: %s\n", dir->msg);
449 /* For slots command, read a single line */
450 bstrncpy(dir->msg, "slots=", len);
451 fgets(dir->msg+6, len-6, bpipe->rfd);
452 dir->msglen = strlen(dir->msg);
453 Dmsg1(100, "<stored: %s", dir->msg);
457 stat = close_bpipe(bpipe);
462 bnet_fsend(dir, _("Autochanger error: ERR=%s\n"), be.strerror());
464 bnet_sig(dir, BNET_EOD);
468 free_pool_memory(changer);
474 * Edit codes into ChangerCommand
476 * %a = archive device name
477 * %c = changer device name
478 * %d = changer drive index
487 * omsg = edited output message
488 * imsg = input string containing edit codes (%x)
489 * cmd = command string (load, unload, ...)
492 char *edit_device_codes(DCR *dcr, char *omsg, const char *imsg, const char *cmd)
499 Dmsg1(1800, "edit_device_codes: %s\n", imsg);
500 for (p=imsg; *p; p++) {
507 str = dcr->dev->archive_name();
510 str = NPRT(dcr->device->changer_name);
513 sprintf(add, "%d", dcr->dev->drive_index);
520 sprintf(add, "%d", dcr->VolCatInfo.Slot - 1);
524 sprintf(add, "%d", dcr->VolCatInfo.Slot);
527 case 'j': /* Job name */
531 str = NPRT(dcr->VolumeName);
534 str = NPRT(dcr->jcr->client_name);
549 Dmsg1(1900, "add_str %s\n", str);
550 pm_strcat(&omsg, (char *)str);
551 Dmsg1(1800, "omsg=%s\n", omsg);
553 Dmsg1(800, "omsg=%s\n", omsg);