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)) {
91 * Load the desired cassette
93 Dmsg1(400, "Doing changer load slot %d\n", slot);
95 _("3304 Issuing autochanger \"load slot %d, drive %d\" command.\n"),
97 dcr->VolCatInfo.Slot = slot; /* slot to be loaded */
98 changer = edit_device_codes(dcr, changer,
99 dcr->device->changer_command, "load");
100 status = run_program(changer, timeout, NULL);
102 Jmsg(jcr, M_INFO, 0, _("3305 Autochanger \"load slot %d, drive %d\", status is OK.\n"),
104 dev->Slot = slot; /* set currently loaded slot */
107 be.set_errno(status);
108 Jmsg(jcr, M_FATAL, 0, _("3992 Bad autochanger \"load slot %d, drive %d\": ERR=%s.\n"),
109 slot, drive, be.strerror());
113 Dmsg2(400, "load slot %d status=%d\n", slot, status);
115 status = 0; /* we got what we want */
116 dev->Slot = slot; /* set currently loaded slot */
118 Dmsg1(400, "After changer, status=%d\n", status);
119 if (status == 0) { /* did we succeed? */
120 rtn_stat = 1; /* tape loaded by changer */
123 rtn_stat = 0; /* no changer found */
125 free_pool_memory(changer);
129 free_pool_memory(changer);
136 * Returns: -1 if error from changer command
139 int get_autochanger_loaded_slot(DCR *dcr)
142 POOLMEM *changer, *results;
144 uint32_t timeout = dcr->device->max_changer_wait;
145 int drive = dcr->dev->drive_index;
147 results = get_pool_memory(PM_MESSAGE);
148 changer = get_pool_memory(PM_FNAME);
152 /* Find out what is loaded, zero means device is unloaded */
153 Jmsg(jcr, M_INFO, 0, _("3301 Issuing autochanger \"loaded drive %d\" command.\n"),
155 changer = edit_device_codes(dcr, changer, dcr->device->changer_command, "loaded");
157 status = run_program(changer, timeout, results);
158 Dmsg3(50, "run_prog: %s stat=%d result=%s\n", changer, status, results);
160 loaded = atoi(results);
162 Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded drive %d\", result is Slot %d.\n"),
164 dcr->dev->Slot = loaded;
166 Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded drive %d\", result: nothing loaded.\n"),
172 be.set_errno(status);
173 Jmsg(jcr, M_INFO, 0, _("3991 Bad autochanger \"loaded drive %d\" command: ERR=%s.\n"),
174 drive, be.strerror());
175 loaded = -1; /* force unload */
178 free_pool_memory(changer);
179 free_pool_memory(results);
183 static void lock_changer(DCR *dcr)
185 AUTOCHANGER *changer_res = dcr->device->changer_res;
187 Dmsg1(100, "Locking changer %s\n", changer_res->hdr.name);
188 P(changer_res->changer_mutex); /* Lock changer script */
192 static void unlock_changer(DCR *dcr)
194 AUTOCHANGER *changer_res = dcr->device->changer_res;
196 Dmsg1(100, "Unlocking changer %s\n", changer_res->hdr.name);
197 V(changer_res->changer_mutex); /* Unlock changer script */
202 * Unload the volume, if any, in this drive
203 * On entry: loaded == 0 -- nothing to do
204 * loaded < 0 -- check if anything to do
205 * loaded > 0 -- load slot == loaded
207 bool unload_autochanger(DCR *dcr, int loaded)
209 DEVICE *dev = dcr->dev;
212 uint32_t timeout = dcr->device->max_changer_wait;
219 if (!dev->is_autochanger() || !dcr->device->changer_name ||
220 !dcr->device->changer_command) {
224 offline_or_rewind_dev(dev);
225 /* We are going to load a new tape, so close the device */
226 force_close_device(dev);
229 loaded = get_autochanger_loaded_slot(dcr);
232 POOLMEM *changer = get_pool_memory(PM_FNAME);
234 _("3307 Issuing autochanger \"unload slot %d, drive %d\" command.\n"),
235 loaded, dev->drive_index);
236 slot = dcr->VolCatInfo.Slot;
237 dcr->VolCatInfo.Slot = loaded;
238 changer = edit_device_codes(dcr, changer,
239 dcr->device->changer_command, "unload");
241 int stat = run_program(changer, timeout, NULL);
243 dcr->VolCatInfo.Slot = slot;
247 Jmsg(jcr, M_INFO, 0, _("3995 Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n"),
248 slot, dev->drive_index, be.strerror());
251 dev->Slot = 0; /* nothing loaded */
253 free_pool_memory(changer);
259 * Unload the slot if mounted in a different drive
261 static bool unload_other_drive(DCR *dcr, int slot)
263 DEVICE *dev, *save_dev;
266 uint32_t timeout = dcr->device->max_changer_wait;
268 AUTOCHANGER *changer = dcr->dev->device->changer_res;
275 if (changer->device->size() == 1) {
279 foreach_alist(device, changer->device) {
280 if (device->dev && device->dev->Slot == slot) {
289 if (dev->is_busy()) {
290 Jmsg(jcr, M_WARNING, 0, _("Volume %s is in use by device %s\n"),
291 dcr->VolumeName, dev->print_name());
292 Dmsg2(200, "Volume %s is in use by device %s\n",
293 dcr->VolumeName, dev->print_name());
298 offline_or_rewind_dev(dev);
299 /* We are going to load a new tape, so close the device */
300 force_close_device(dev);
302 POOLMEM *changer_cmd = get_pool_memory(PM_FNAME);
304 _("3307 Issuing autochanger \"unload slot %d, drive %d\" command.\n"),
305 slot, dev->drive_index);
307 Dmsg2(200, "Issuing autochanger \"unload slot %d, drive %d\" command.\n",
308 slot, dev->drive_index);
310 save_slot = dcr->VolCatInfo.Slot;
313 dcr->VolCatInfo.Slot = slot;
314 changer_cmd = edit_device_codes(dcr, changer_cmd,
315 dcr->device->changer_command, "unload");
317 Dmsg1(200, "Run program=%s\n", changer_cmd);
318 int stat = run_program(changer_cmd, timeout, NULL);
320 dcr->VolCatInfo.Slot = save_slot;
325 Jmsg(jcr, M_INFO, 0, _("3995 Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n"),
326 slot, dev->drive_index, be.strerror());
328 Dmsg3(200, "Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n",
329 slot, dev->drive_index, be.strerror());
332 dev->Slot = 0; /* nothing loaded */
333 Dmsg0(200, "Slot unloaded\n");
335 free_pool_memory(changer_cmd);
342 * List the Volumes that are in the autoloader possibly
343 * with their barcodes.
344 * We assume that it is always the Console that is calling us.
346 bool autochanger_cmd(DCR *dcr, BSOCK *dir, const char *cmd)
348 DEVICE *dev = dcr->dev;
349 uint32_t timeout = dcr->device->max_changer_wait;
352 int len = sizeof_pool_memory(dir->msg) - 1;
356 if (!dev->is_autochanger() || !dcr->device->changer_name ||
357 !dcr->device->changer_command) {
358 bnet_fsend(dir, _("3993 Device %s not an autochanger device.\n"),
363 changer = get_pool_memory(PM_FNAME);
365 if (strcmp(cmd, "list") == 0) {
366 unload_autochanger(dcr, -1);
369 /* Now issue the command */
370 changer = edit_device_codes(dcr, changer,
371 dcr->device->changer_command, cmd);
372 bnet_fsend(dir, _("3306 Issuing autochanger \"%s\" command.\n"), cmd);
374 bpipe = open_bpipe(changer, timeout, "r");
377 bnet_fsend(dir, _("3996 Open bpipe failed.\n"));
380 if (strcmp(cmd, "list") == 0) {
381 /* Get output from changer */
382 while (fgets(dir->msg, len, bpipe->rfd)) {
383 dir->msglen = strlen(dir->msg);
384 Dmsg1(100, "<stored: %s\n", dir->msg);
388 /* For slots command, read a single line */
389 bstrncpy(dir->msg, "slots=", len);
390 fgets(dir->msg+6, len-6, bpipe->rfd);
391 dir->msglen = strlen(dir->msg);
392 Dmsg1(100, "<stored: %s", dir->msg);
396 stat = close_bpipe(bpipe);
401 bnet_fsend(dir, _("Autochanger error: ERR=%s\n"), be.strerror());
403 bnet_sig(dir, BNET_EOD);
407 free_pool_memory(changer);
413 * Edit codes into ChangerCommand
415 * %a = archive device name
416 * %c = changer device name
417 * %d = changer drive index
426 * omsg = edited output message
427 * imsg = input string containing edit codes (%x)
428 * cmd = command string (load, unload, ...)
431 char *edit_device_codes(DCR *dcr, char *omsg, const char *imsg, const char *cmd)
438 Dmsg1(1800, "edit_device_codes: %s\n", imsg);
439 for (p=imsg; *p; p++) {
446 str = dcr->dev->archive_name();
449 str = NPRT(dcr->device->changer_name);
452 sprintf(add, "%d", dcr->dev->drive_index);
459 sprintf(add, "%d", dcr->VolCatInfo.Slot - 1);
463 sprintf(add, "%d", dcr->VolCatInfo.Slot);
466 case 'j': /* Job name */
470 str = NPRT(dcr->VolumeName);
473 str = NPRT(dcr->jcr->client_name);
488 Dmsg1(1900, "add_str %s\n", str);
489 pm_strcat(&omsg, (char *)str);
490 Dmsg1(1800, "omsg=%s\n", omsg);
492 Dmsg1(800, "omsg=%s\n", omsg);