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);
33 * Called here to do an autoload using the autochanger, if
34 * configured, and if a Slot has been defined for this Volume.
35 * On success this routine loads the indicated tape, but the
36 * label is not read, so it must be verified.
38 * Note if dir is not NULL, it is the console requesting the
39 * autoload for labeling, so we respond directly to the
42 * Returns: 1 on success
43 * 0 on failure (no changer available)
44 * -1 on error on autochanger
46 int autoload_device(DCR *dcr, int writing, BSOCK *dir)
49 DEVICE *dev = dcr->dev;
51 int drive = dev->drive_index;
52 int rtn_stat = -1; /* error status */
55 slot = dcr->VolCatInfo.InChanger ? dcr->VolCatInfo.Slot : 0;
57 * Handle autoloaders here. If we cannot autoload it, we
58 * will return 0 so that the sysop will be asked to load it.
60 if (writing && dev->is_autochanger() && slot <= 0) {
62 return 0; /* For user, bail out right now */
64 if (dir_find_next_appendable_volume(dcr)) {
65 slot = dcr->VolCatInfo.InChanger ? dcr->VolCatInfo.Slot : 0;
70 Dmsg1(400, "Want changer slot=%d\n", slot);
72 changer = get_pool_memory(PM_FNAME);
73 if (slot > 0 && dcr->device->changer_name && dcr->device->changer_command) {
74 uint32_t timeout = dcr->device->max_changer_wait;
77 loaded = get_autochanger_loaded_slot(dcr);
80 /* Unload anything in our drive */
81 if (!unload_autochanger(dcr, loaded)) {
85 /* Make sure desired slot is unloaded */
86 if (!unload_other_drive(dcr, slot)) {
90 /* We are going to load a new tape, so close the device */
91 offline_or_rewind_dev(dev);
92 force_close_device(dev);
95 * Load the desired cassette
97 Dmsg1(400, "Doing changer load slot %d\n", slot);
99 _("3304 Issuing autochanger \"load slot %d, drive %d\" command.\n"),
101 dcr->VolCatInfo.Slot = slot; /* slot to be loaded */
102 changer = edit_device_codes(dcr, changer,
103 dcr->device->changer_command, "load");
104 status = run_program(changer, timeout, NULL);
106 Jmsg(jcr, M_INFO, 0, _("3305 Autochanger \"load slot %d, drive %d\", status is OK.\n"),
108 dev->Slot = slot; /* set currently loaded slot */
111 be.set_errno(status);
112 Jmsg(jcr, M_FATAL, 0, _("3992 Bad autochanger \"load slot %d, drive %d\": ERR=%s.\n"),
113 slot, drive, be.strerror());
117 Dmsg2(400, "load slot %d status=%d\n", slot, status);
119 status = 0; /* we got what we want */
120 dev->Slot = slot; /* set currently loaded slot */
122 Dmsg1(400, "After changer, status=%d\n", status);
123 if (status == 0) { /* did we succeed? */
124 rtn_stat = 1; /* tape loaded by changer */
127 rtn_stat = 0; /* no changer found */
129 free_pool_memory(changer);
133 free_pool_memory(changer);
140 * Returns: -1 if error from changer command
143 int get_autochanger_loaded_slot(DCR *dcr)
146 POOLMEM *changer, *results;
148 uint32_t timeout = dcr->device->max_changer_wait;
149 int drive = dcr->dev->drive_index;
151 if (!dcr->device->changer_command) {
152 Jmsg(jcr, M_FATAL, 0, _("3992 Missing Changer command.\n"));
156 results = get_pool_memory(PM_MESSAGE);
157 changer = get_pool_memory(PM_FNAME);
161 /* Find out what is loaded, zero means device is unloaded */
162 Jmsg(jcr, M_INFO, 0, _("3301 Issuing autochanger \"loaded drive %d\" command.\n"),
164 changer = edit_device_codes(dcr, changer, dcr->device->changer_command, "loaded");
166 status = run_program(changer, timeout, results);
167 Dmsg3(50, "run_prog: %s stat=%d result=%s\n", changer, status, results);
169 loaded = atoi(results);
171 Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded drive %d\", result is Slot %d.\n"),
173 dcr->dev->Slot = loaded;
175 Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded drive %d\", result: nothing loaded.\n"),
181 be.set_errno(status);
182 Jmsg(jcr, M_INFO, 0, _("3991 Bad autochanger \"loaded drive %d\" command: ERR=%s.\n"),
183 drive, be.strerror());
184 loaded = -1; /* force unload */
187 free_pool_memory(changer);
188 free_pool_memory(results);
192 static void lock_changer(DCR *dcr)
194 AUTOCHANGER *changer_res = dcr->device->changer_res;
196 Dmsg1(100, "Locking changer %s\n", changer_res->hdr.name);
197 P(changer_res->changer_mutex); /* Lock changer script */
201 static void unlock_changer(DCR *dcr)
203 AUTOCHANGER *changer_res = dcr->device->changer_res;
205 Dmsg1(100, "Unlocking changer %s\n", changer_res->hdr.name);
206 V(changer_res->changer_mutex); /* Unlock changer script */
211 * Unload the volume, if any, in this drive
212 * On entry: loaded == 0 -- nothing to do
213 * loaded < 0 -- check if anything to do
214 * loaded > 0 -- load slot == loaded
216 bool unload_autochanger(DCR *dcr, int loaded)
218 DEVICE *dev = dcr->dev;
221 uint32_t timeout = dcr->device->max_changer_wait;
228 if (!dev->is_autochanger() || !dcr->device->changer_name ||
229 !dcr->device->changer_command) {
233 /* We are going to load a new tape, so close the device */
234 offline_or_rewind_dev(dev);
235 force_close_device(dev);
238 loaded = get_autochanger_loaded_slot(dcr);
241 POOLMEM *changer = get_pool_memory(PM_FNAME);
243 _("3307 Issuing autochanger \"unload slot %d, drive %d\" command.\n"),
244 loaded, dev->drive_index);
245 slot = dcr->VolCatInfo.Slot;
246 dcr->VolCatInfo.Slot = loaded;
247 changer = edit_device_codes(dcr, changer,
248 dcr->device->changer_command, "unload");
250 int stat = run_program(changer, timeout, NULL);
252 dcr->VolCatInfo.Slot = slot;
256 Jmsg(jcr, M_INFO, 0, _("3995 Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n"),
257 slot, dev->drive_index, be.strerror());
260 dev->Slot = 0; /* nothing loaded */
262 free_pool_memory(changer);
268 * Unload the slot if mounted in a different drive
270 static bool unload_other_drive(DCR *dcr, int slot)
276 uint32_t timeout = dcr->device->max_changer_wait;
278 AUTOCHANGER *changer = dcr->dev->device->changer_res;
285 if (changer->device->size() == 1) {
289 foreach_alist(device, changer->device) {
290 if (device->dev && device->dev->Slot == slot) {
299 if (dev->is_busy()) {
300 Jmsg(jcr, M_WARNING, 0, _("Volume %s is in use by device %s\n"),
301 dcr->VolumeName, dev->print_name());
302 Dmsg2(200, "Volume %s is in use by device %s\n",
303 dcr->VolumeName, dev->print_name());
308 /* We are going to unload a tape, so close the device */
309 offline_or_rewind_dev(dev);
310 force_close_device(dev);
312 POOLMEM *changer_cmd = get_pool_memory(PM_FNAME);
314 _("3307 Issuing autochanger \"unload slot %d, drive %d\" command.\n"),
315 slot, dev->drive_index);
317 Dmsg2(200, "Issuing autochanger \"unload slot %d, drive %d\" command.\n",
318 slot, dev->drive_index);
320 save_slot = dcr->VolCatInfo.Slot;
323 dcr->VolCatInfo.Slot = slot;
324 changer_cmd = edit_device_codes(dcr, changer_cmd,
325 dcr->device->changer_command, "unload");
327 Dmsg1(200, "Run program=%s\n", changer_cmd);
328 int stat = run_program(changer_cmd, timeout, NULL);
330 dcr->VolCatInfo.Slot = save_slot;
335 Jmsg(jcr, M_INFO, 0, _("3995 Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n"),
336 slot, dev->drive_index, be.strerror());
338 Dmsg3(200, "Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n",
339 slot, dev->drive_index, be.strerror());
342 dev->Slot = 0; /* nothing loaded */
343 Dmsg0(200, "Slot unloaded\n");
345 free_pool_memory(changer_cmd);
352 * List the Volumes that are in the autoloader possibly
353 * with their barcodes.
354 * We assume that it is always the Console that is calling us.
356 bool autochanger_cmd(DCR *dcr, BSOCK *dir, const char *cmd)
358 DEVICE *dev = dcr->dev;
359 uint32_t timeout = dcr->device->max_changer_wait;
362 int len = sizeof_pool_memory(dir->msg) - 1;
366 if (!dev->is_autochanger() || !dcr->device->changer_name ||
367 !dcr->device->changer_command) {
368 bnet_fsend(dir, _("3993 Device %s not an autochanger device.\n"),
373 changer = get_pool_memory(PM_FNAME);
375 if (strcmp(cmd, "list") == 0) {
376 unload_autochanger(dcr, -1);
379 /* Now issue the command */
380 changer = edit_device_codes(dcr, changer,
381 dcr->device->changer_command, cmd);
382 bnet_fsend(dir, _("3306 Issuing autochanger \"%s\" command.\n"), cmd);
384 bpipe = open_bpipe(changer, timeout, "r");
387 bnet_fsend(dir, _("3996 Open bpipe failed.\n"));
390 if (strcmp(cmd, "list") == 0) {
391 /* Get output from changer */
392 while (fgets(dir->msg, len, bpipe->rfd)) {
393 dir->msglen = strlen(dir->msg);
394 Dmsg1(100, "<stored: %s\n", dir->msg);
398 /* For slots command, read a single line */
399 bstrncpy(dir->msg, "slots=", len);
400 fgets(dir->msg+6, len-6, bpipe->rfd);
401 dir->msglen = strlen(dir->msg);
402 Dmsg1(100, "<stored: %s", dir->msg);
406 stat = close_bpipe(bpipe);
411 bnet_fsend(dir, _("Autochanger error: ERR=%s\n"), be.strerror());
413 bnet_sig(dir, BNET_EOD);
417 free_pool_memory(changer);
423 * Edit codes into ChangerCommand
425 * %a = archive device name
426 * %c = changer device name
427 * %d = changer drive index
436 * omsg = edited output message
437 * imsg = input string containing edit codes (%x)
438 * cmd = command string (load, unload, ...)
441 char *edit_device_codes(DCR *dcr, char *omsg, const char *imsg, const char *cmd)
448 Dmsg1(1800, "edit_device_codes: %s\n", imsg);
449 for (p=imsg; *p; p++) {
456 str = dcr->dev->archive_name();
459 str = NPRT(dcr->device->changer_name);
462 sprintf(add, "%d", dcr->dev->drive_index);
469 sprintf(add, "%d", dcr->VolCatInfo.Slot - 1);
473 sprintf(add, "%d", dcr->VolCatInfo.Slot);
476 case 'j': /* Job name */
480 str = NPRT(dcr->VolumeName);
483 str = NPRT(dcr->jcr->client_name);
498 Dmsg1(1900, "add_str %s\n", str);
499 pm_strcat(&omsg, (char *)str);
500 Dmsg1(1800, "omsg=%s\n", omsg);
502 Dmsg1(800, "omsg=%s\n", omsg);