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) {
132 /* Unload anything in our drive */
133 if (!unload_autochanger(dcr, loaded)) {
137 /* Make sure desired slot is unloaded */
138 if (!unload_other_drive(dcr, slot)) {
143 * Load the desired cassette
146 Dmsg1(400, "Doing changer load slot %d\n", slot);
148 _("3304 Issuing autochanger \"load slot %d, drive %d\" command.\n"),
150 dcr->VolCatInfo.Slot = slot; /* slot to be loaded */
151 changer = edit_device_codes(dcr, changer,
152 dcr->device->changer_command, "load");
153 status = run_program(changer, timeout, NULL);
155 Jmsg(jcr, M_INFO, 0, _("3305 Autochanger \"load slot %d, drive %d\", status is OK.\n"),
157 dev->Slot = slot; /* set currently loaded slot */
160 be.set_errno(status);
161 Jmsg(jcr, M_FATAL, 0, _("3992 Bad autochanger \"load slot %d, drive %d\": ERR=%s.\n"),
162 slot, drive, be.strerror());
163 rtn_stat = -1; /* hard error */
165 Dmsg2(400, "load slot %d status=%d\n", slot, status);
167 status = 0; /* we got what we want */
168 dev->Slot = slot; /* set currently loaded slot */
170 Dmsg1(400, "After changer, status=%d\n", status);
171 if (status == 0) { /* did we succeed? */
172 rtn_stat = 1; /* tape loaded by changer */
175 rtn_stat = 0; /* no changer found */
178 free_pool_memory(changer);
182 free_pool_memory(changer);
188 * Returns: -1 if error from changer command
190 * Note, this is safe to do without releasing the drive
191 * since it does not attempt load/unload a slot.
193 int get_autochanger_loaded_slot(DCR *dcr)
196 POOLMEM *changer, *results;
198 uint32_t timeout = dcr->device->max_changer_wait;
199 int drive = dcr->dev->drive_index;
201 if (!dcr->device->changer_command) {
202 Jmsg(jcr, M_FATAL, 0, _("3992 Missing Changer command.\n"));
206 results = get_pool_memory(PM_MESSAGE);
207 changer = get_pool_memory(PM_FNAME);
210 /* Find out what is loaded, zero means device is unloaded */
212 Jmsg(jcr, M_INFO, 0, _("3301 Issuing autochanger \"loaded drive %d\" command.\n"),
214 changer = edit_device_codes(dcr, changer, dcr->device->changer_command, "loaded");
216 status = run_program(changer, timeout, results);
217 Dmsg3(50, "run_prog: %s stat=%d result=%s\n", changer, status, results);
219 loaded = atoi(results);
221 Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded drive %d\", result is Slot %d.\n"),
223 dcr->dev->Slot = loaded;
225 Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded drive %d\", result: nothing loaded.\n"),
231 be.set_errno(status);
232 Jmsg(jcr, M_INFO, 0, _("3991 Bad autochanger \"loaded drive %d\" command: ERR=%s.\n"),
233 drive, be.strerror());
234 loaded = -1; /* force unload */
237 free_pool_memory(changer);
238 free_pool_memory(results);
242 static void lock_changer(DCR *dcr)
244 AUTOCHANGER *changer_res = dcr->device->changer_res;
246 Dmsg1(100, "Locking changer %s\n", changer_res->hdr.name);
247 P(changer_res->changer_mutex); /* Lock changer script */
251 static void unlock_changer(DCR *dcr)
253 AUTOCHANGER *changer_res = dcr->device->changer_res;
255 Dmsg1(100, "Unlocking changer %s\n", changer_res->hdr.name);
256 V(changer_res->changer_mutex); /* Unlock changer script */
261 * Unload the volume, if any, in this drive
262 * On entry: loaded == 0 -- nothing to do
263 * loaded < 0 -- check if anything to do
264 * loaded > 0 -- load slot == loaded
266 bool unload_autochanger(DCR *dcr, int loaded)
268 DEVICE *dev = dcr->dev;
271 uint32_t timeout = dcr->device->max_changer_wait;
278 if (!dev->is_autochanger() || !dcr->device->changer_name ||
279 !dcr->device->changer_command) {
284 loaded = get_autochanger_loaded_slot(dcr);
287 /* We are going to load a new tape, so close the device */
288 offline_or_rewind_dev(dev);
289 force_close_device(dev);
292 POOLMEM *changer = get_pool_memory(PM_FNAME);
295 _("3307 Issuing autochanger \"unload slot %d, drive %d\" command.\n"),
296 loaded, dev->drive_index);
297 slot = dcr->VolCatInfo.Slot;
298 dcr->VolCatInfo.Slot = loaded;
299 changer = edit_device_codes(dcr, changer,
300 dcr->device->changer_command, "unload");
301 int stat = run_program(changer, timeout, NULL);
302 dcr->VolCatInfo.Slot = slot;
306 Jmsg(jcr, M_INFO, 0, _("3995 Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n"),
307 slot, dev->drive_index, be.strerror());
310 dev->Slot = 0; /* nothing loaded */
312 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);
366 _("3307 Issuing autochanger \"unload slot %d, drive %d\" command.\n"),
367 slot, dev->drive_index);
369 Dmsg2(200, "Issuing autochanger \"unload slot %d, drive %d\" command.\n",
370 slot, dev->drive_index);
372 save_slot = dcr->VolCatInfo.Slot;
375 dcr->VolCatInfo.Slot = slot;
376 changer_cmd = edit_device_codes(dcr, changer_cmd,
377 dcr->device->changer_command, "unload");
378 Dmsg1(200, "Run program=%s\n", changer_cmd);
379 int stat = run_program(changer_cmd, timeout, NULL);
380 dcr->VolCatInfo.Slot = save_slot;
385 Jmsg(jcr, M_INFO, 0, _("3995 Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n"),
386 slot, dev->drive_index, be.strerror());
388 Dmsg3(200, "Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n",
389 slot, dev->drive_index, be.strerror());
392 dev->Slot = 0; /* nothing loaded */
393 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"),
425 if (strcmp(cmd, "list") == 0) {
426 unload_autochanger(dcr, -1);
428 if (strcmp(cmd, "drives") == 0) {
429 AUTOCHANGER *changer_res = dcr->device->changer_res;
430 bnet_fsend(dir, "drives=%d\n", changer_res->device->size());
431 Dmsg1(100, "drives=%d\n", changer_res->device->size());
435 changer = get_pool_memory(PM_FNAME);
437 /* Now issue the command */
438 changer = edit_device_codes(dcr, changer,
439 dcr->device->changer_command, cmd);
440 bnet_fsend(dir, _("3306 Issuing autochanger \"%s\" command.\n"), cmd);
441 bpipe = open_bpipe(changer, timeout, "r");
443 bnet_fsend(dir, _("3996 Open bpipe failed.\n"));
446 if (strcmp(cmd, "list") == 0) {
447 /* Get output from changer */
448 while (fgets(dir->msg, len, bpipe->rfd)) {
449 dir->msglen = strlen(dir->msg);
450 Dmsg1(100, "<stored: %s\n", dir->msg);
453 } else if (strcmp(cmd, "slots") == 0 ) {
454 /* For slots command, read a single line */
455 bstrncpy(dir->msg, "slots=", len);
456 fgets(dir->msg+6, len-6, bpipe->rfd);
457 dir->msglen = strlen(dir->msg);
458 Dmsg1(100, "<stored: %s", dir->msg);
462 stat = close_bpipe(bpipe);
466 bnet_fsend(dir, _("Autochanger error: ERR=%s\n"), be.strerror());
468 bnet_sig(dir, BNET_EOD);
473 free_pool_memory(changer);
479 * Edit codes into ChangerCommand
481 * %a = archive device name
482 * %c = changer device name
483 * %d = changer drive index
492 * omsg = edited output message
493 * imsg = input string containing edit codes (%x)
494 * cmd = command string (load, unload, ...)
497 char *edit_device_codes(DCR *dcr, char *omsg, const char *imsg, const char *cmd)
504 Dmsg1(1800, "edit_device_codes: %s\n", imsg);
505 for (p=imsg; *p; p++) {
512 str = dcr->dev->archive_name();
515 str = NPRT(dcr->device->changer_name);
518 sprintf(add, "%d", dcr->dev->drive_index);
525 sprintf(add, "%d", dcr->VolCatInfo.Slot - 1);
529 sprintf(add, "%d", dcr->VolCatInfo.Slot);
532 case 'j': /* Job name */
536 str = NPRT(dcr->VolumeName);
539 str = NPRT(dcr->jcr->client_name);
554 Dmsg1(1900, "add_str %s\n", str);
555 pm_strcat(&omsg, (char *)str);
556 Dmsg1(1800, "omsg=%s\n", omsg);
558 Dmsg1(800, "omsg=%s\n", omsg);