3 * Routines for handling the autochanger.
5 * Kern Sibbald, August MMII
10 Bacula® - The Network Backup Solution
12 Copyright (C) 2002-2006 Free Software Foundation Europe e.V.
14 The main author of Bacula is Kern Sibbald, with contributions from
15 many others, a complete list can be found in the file AUTHORS.
16 This program is Free Software; you can redistribute it and/or
17 modify it under the terms of version two of the GNU General Public
18 License as published by the Free Software Foundation plus additions
19 that are listed in the file LICENSE.
21 This program is distributed in the hope that it will be useful, but
22 WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 General Public License for more details.
26 You should have received a copy of the GNU General Public License
27 along with this program; if not, write to the Free Software
28 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
31 Bacula® is a registered trademark of John Walker.
32 The licensor of Bacula is the Free Software Foundation Europe
33 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
34 Switzerland, email:ftf@fsfeurope.org.
37 #include "bacula.h" /* pull in global headers */
38 #include "stored.h" /* pull in Storage Deamon headers */
40 /* Forward referenced functions */
41 static void lock_changer(DCR *dcr);
42 static void unlock_changer(DCR *dcr);
43 static bool unload_other_drive(DCR *dcr, int slot);
45 /* Init all the autochanger resources found */
46 bool init_autochangers()
50 /* Ensure that the media_type for each device is the same */
51 foreach_res(changer, R_AUTOCHANGER) {
53 foreach_alist(device, changer->device) {
55 * If the device does not have a changer name or changer command
56 * defined, used the one from the Autochanger resource
58 if (!device->changer_name && changer->changer_name) {
59 device->changer_name = bstrdup(changer->changer_name);
61 if (!device->changer_command && changer->changer_command) {
62 device->changer_command = bstrdup(changer->changer_command);
64 if (!device->changer_name) {
65 Jmsg(NULL, M_ERROR, 0,
66 _("No Changer Name given for device %s. Cannot continue.\n"),
70 if (!device->changer_command) {
71 Jmsg(NULL, M_ERROR, 0,
72 _("No Changer Command given for device %s. Cannot continue.\n"),
78 if (media_type == NULL) {
79 media_type = device->media_type; /* get Media Type of first device */
82 /* Ensure that other devices Media Types are the same */
83 if (strcmp(media_type, device->media_type) != 0) {
84 Jmsg(NULL, M_ERROR, 0,
85 _("Media Type not the same for all devices in changer %s. Cannot continue.\n"),
98 * Called here to do an autoload using the autochanger, if
99 * configured, and if a Slot has been defined for this Volume.
100 * On success this routine loads the indicated tape, but the
101 * label is not read, so it must be verified.
103 * Note if dir is not NULL, it is the console requesting the
104 * autoload for labeling, so we respond directly to the
107 * Returns: 1 on success
108 * 0 on failure (no changer available)
109 * -1 on error on autochanger
111 int autoload_device(DCR *dcr, int writing, BSOCK *dir)
114 DEVICE *dev = dcr->dev;
116 int drive = dev->drive_index;
117 int rtn_stat = -1; /* error status */
120 if (!dev->is_autochanger()) {
121 Dmsg1(200, "Device %s is not an autochanger\n", dev->print_name());
124 slot = dcr->VolCatInfo.InChanger ? dcr->VolCatInfo.Slot : 0;
126 * Handle autoloaders here. If we cannot autoload it, we
127 * will return 0 so that the sysop will be asked to load it.
129 if (writing && slot <= 0) {
131 return 0; /* For user, bail out right now */
133 if (dir_find_next_appendable_volume(dcr)) {
134 slot = dcr->VolCatInfo.InChanger ? dcr->VolCatInfo.Slot : 0;
139 Dmsg1(400, "Want changer slot=%d\n", slot);
141 changer = get_pool_memory(PM_FNAME);
143 Jmsg(jcr, M_INFO, 0, _("Invalid slot=%d defined, cannot autoload Volume.\n"), slot);
145 } else if (!dcr->device->changer_name) {
146 Jmsg(jcr, M_INFO, 0, _("No \"Changer Device\" given cannot autoload Volume.\n"));
148 } else if (!dcr->device->changer_command) {
149 Jmsg(jcr, M_INFO, 0, _("No \"Changer Command\" given cannot autoload Volume.\n"));
152 /* Attempt to load the Volume */
154 uint32_t timeout = dcr->device->max_changer_wait;
157 loaded = get_autochanger_loaded_slot(dcr);
159 if (loaded != slot) {
160 POOL_MEM results(PM_MESSAGE);
162 /* Unload anything in our drive */
163 if (!unload_autochanger(dcr, loaded)) {
167 /* Make sure desired slot is unloaded */
168 if (!unload_other_drive(dcr, slot)) {
173 * Load the desired cassette
176 Dmsg1(100, "Doing changer load slot %d\n", slot);
178 _("3304 Issuing autochanger \"load slot %d, drive %d\" command.\n"),
180 dcr->VolCatInfo.Slot = slot; /* slot to be loaded */
181 changer = edit_device_codes(dcr, changer, dcr->device->changer_command, "load");
183 Dmsg1(200, "Run program=%s\n", changer);
184 status = run_program_full_output(changer, timeout, results.c_str());
186 Jmsg(jcr, M_INFO, 0, _("3305 Autochanger \"load slot %d, drive %d\", status is OK.\n"),
188 Dmsg2(100, "load slot %d, drive %d, status is OK.\n", slot, drive);
189 dev->Slot = slot; /* set currently loaded slot */
192 be.set_errno(status);
193 Dmsg3(100, "load slot %d, drive %d, bad stats=%s.\n", slot, drive,
195 Jmsg(jcr, M_FATAL, 0, _("3992 Bad autochanger \"load slot %d, drive %d\": "
196 "ERR=%s.\nResults=%s\n"),
197 slot, drive, be.strerror(), results.c_str());
198 rtn_stat = -1; /* hard error */
199 dev->Slot = -1; /* mark unknown */
201 Dmsg2(100, "load slot %d status=%d\n", slot, status);
204 status = 0; /* we got what we want */
205 dev->Slot = slot; /* set currently loaded slot */
207 Dmsg1(100, "After changer, status=%d\n", status);
208 if (status == 0) { /* did we succeed? */
209 rtn_stat = 1; /* tape loaded by changer */
212 free_pool_memory(changer);
216 free_pool_memory(changer);
222 * Returns: -1 if error from changer command
224 * Note, this is safe to do without releasing the drive
225 * since it does not attempt load/unload a slot.
227 int get_autochanger_loaded_slot(DCR *dcr)
230 DEVICE *dev = dcr->dev;
232 uint32_t timeout = dcr->device->max_changer_wait;
233 int drive = dcr->dev->drive_index;
234 POOL_MEM results(PM_MESSAGE);
237 if (!dev->is_autochanger()) {
240 if (!dcr->device->changer_command) {
241 Jmsg(jcr, M_FATAL, 0, _("3992 Missing Changer command.\n"));
248 /* Find out what is loaded, zero means device is unloaded */
249 changer = get_pool_memory(PM_FNAME);
251 Jmsg(jcr, M_INFO, 0, _("3301 Issuing autochanger \"loaded? drive %d\" command.\n"),
253 changer = edit_device_codes(dcr, changer, dcr->device->changer_command, "loaded");
254 *results.c_str() = 0;
255 Dmsg1(100, "Run program=%s\n", changer);
256 status = run_program_full_output(changer, timeout, results.c_str());
257 Dmsg3(100, "run_prog: %s stat=%d result=%s\n", changer, status, results.c_str());
259 loaded = str_to_int32(results.c_str());
261 Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded? drive %d\", result is Slot %d.\n"),
265 Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded? drive %d\", result: nothing loaded.\n"),
267 dev->Slot = -1; /* unknown */
271 be.set_errno(status);
272 Jmsg(jcr, M_INFO, 0, _("3991 Bad autochanger \"loaded? drive %d\" command: "
273 "ERR=%s.\nResults=%s\n"), drive, be.strerror(), results.c_str());
274 loaded = -1; /* force unload */
277 free_pool_memory(changer);
281 static void lock_changer(DCR *dcr)
283 AUTOCHANGER *changer_res = dcr->device->changer_res;
285 Dmsg1(200, "Locking changer %s\n", changer_res->hdr.name);
286 P(changer_res->changer_mutex); /* Lock changer script */
290 static void unlock_changer(DCR *dcr)
292 AUTOCHANGER *changer_res = dcr->device->changer_res;
294 Dmsg1(200, "Unlocking changer %s\n", changer_res->hdr.name);
295 V(changer_res->changer_mutex); /* Unlock changer script */
300 * Unload the volume, if any, in this drive
301 * On entry: loaded == 0 -- nothing to do
302 * loaded < 0 -- check if anything to do
303 * loaded > 0 -- load slot == loaded
305 bool unload_autochanger(DCR *dcr, int loaded)
307 DEVICE *dev = dcr->dev;
310 uint32_t timeout = dcr->device->max_changer_wait;
317 if (!dev->is_autochanger() || !dcr->device->changer_name ||
318 !dcr->device->changer_command) {
323 loaded = get_autochanger_loaded_slot(dcr);
327 POOL_MEM results(PM_MESSAGE);
328 POOLMEM *changer = get_pool_memory(PM_FNAME);
331 _("3307 Issuing autochanger \"unload slot %d, drive %d\" command.\n"),
332 loaded, dev->drive_index);
333 slot = dcr->VolCatInfo.Slot;
334 dcr->VolCatInfo.Slot = loaded;
335 changer = edit_device_codes(dcr, changer,
336 dcr->device->changer_command, "unload");
338 Dmsg1(100, "Run program=%s\n", changer);
339 *results.c_str() = 0;
340 int stat = run_program_full_output(changer, timeout, results.c_str());
341 dcr->VolCatInfo.Slot = slot;
345 Jmsg(jcr, M_INFO, 0, _("3995 Bad autochanger \"unload slot %d, drive %d\": "
346 "ERR=%s\nResults=%s\n"),
347 loaded, dev->drive_index, be.strerror(), results.c_str());
349 dev->Slot = -1; /* unknown */
351 dev->Slot = 0; /* nothing loaded */
353 free_pool_memory(changer);
360 * Unload the slot if mounted in a different drive
362 static bool unload_other_drive(DCR *dcr, int slot)
368 uint32_t timeout = dcr->device->max_changer_wait;
370 AUTOCHANGER *changer = dcr->dev->device->changer_res;
378 if (changer->device->size() == 1) {
382 foreach_alist(device, changer->device) {
383 if (device->dev && device->dev->Slot == slot) {
393 /* The Volume we want is on another device. */
394 if (dev->is_busy()) {
395 Dmsg4(100, "Vol %s for dev=%s in use dev=%s slot=%d\n",
396 dcr->VolumeName, dcr->dev->print_name(),
397 dev->print_name(), slot);
399 for (int i=0; i < 3; i++) {
400 if (dev->is_busy()) {
401 wait_for_device(dcr->jcr, first);
408 if (dev->is_busy()) {
409 Jmsg(jcr, M_WARNING, 0, _("Volume \"%s\" is in use by device %s\n"),
410 dcr->VolumeName, dev->print_name());
411 Dmsg4(100, "Vol %s for dev=%s is busy dev=%s slot=%d\n",
412 dcr->VolumeName, dcr->dev->print_name(), dev->print_name(), slot);
413 Dmsg2(100, "num_writ=%d reserv=%d\n", dev->num_writers, dev->reserved_device);
418 POOLMEM *changer_cmd = get_pool_memory(PM_FNAME);
419 POOL_MEM results(PM_MESSAGE);
422 _("3307 Issuing autochanger \"unload slot %d, drive %d\" command.\n"),
423 slot, dev->drive_index);
425 Dmsg2(100, "Issuing autochanger \"unload slot %d, drive %d\" command.\n",
426 slot, dev->drive_index);
430 save_slot = dcr->VolCatInfo.Slot;
431 dcr->VolCatInfo.Slot = slot;
432 changer_cmd = edit_device_codes(dcr, changer_cmd,
433 dcr->device->changer_command, "unload");
435 Dmsg2(200, "close dev=%s reserve=%d\n", dev->print_name(),
436 dev->reserved_device);
437 Dmsg1(100, "Run program=%s\n", changer_cmd);
438 int stat = run_program_full_output(changer_cmd, timeout, results.c_str());
439 dcr->VolCatInfo.Slot = save_slot;
444 Jmsg(jcr, M_INFO, 0, _("3995 Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n"),
445 slot, dev->drive_index, be.strerror());
447 Dmsg3(100, "Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n",
448 slot, dev->drive_index, be.strerror());
450 dev->Slot = -1; /* unknown */
452 dev->Slot = 0; /* nothing loaded */
453 Dmsg0(100, "Slot unloaded\n");
457 free_pool_memory(changer_cmd);
464 * List the Volumes that are in the autoloader possibly
465 * with their barcodes.
466 * We assume that it is always the Console that is calling us.
468 bool autochanger_cmd(DCR *dcr, BSOCK *dir, const char *cmd)
470 DEVICE *dev = dcr->dev;
471 uint32_t timeout = dcr->device->max_changer_wait;
474 int len = sizeof_pool_memory(dir->msg) - 1;
478 if (!dev->is_autochanger() || !dcr->device->changer_name ||
479 !dcr->device->changer_command) {
480 if (strcmp(cmd, "drives") == 0) {
481 bnet_fsend(dir, "drives=1\n");
483 bnet_fsend(dir, _("3993 Device %s not an autochanger device.\n"),
488 if (strcmp(cmd, "drives") == 0) {
489 AUTOCHANGER *changer_res = dcr->device->changer_res;
492 drives = changer_res->device->size();
494 bnet_fsend(dir, "drives=%d\n", drives);
495 Dmsg1(100, "drives=%d\n", drives);
499 changer = get_pool_memory(PM_FNAME);
501 /* Now issue the command */
502 changer = edit_device_codes(dcr, changer,
503 dcr->device->changer_command, cmd);
504 bnet_fsend(dir, _("3306 Issuing autochanger \"%s\" command.\n"), cmd);
505 bpipe = open_bpipe(changer, timeout, "r");
507 bnet_fsend(dir, _("3996 Open bpipe failed.\n"));
510 if (strcmp(cmd, "list") == 0) {
511 /* Get output from changer */
512 while (fgets(dir->msg, len, bpipe->rfd)) {
513 dir->msglen = strlen(dir->msg);
514 Dmsg1(100, "<stored: %s\n", dir->msg);
517 } else if (strcmp(cmd, "slots") == 0 ) {
519 /* For slots command, read a single line */
521 fgets(buf, sizeof(buf)-1, bpipe->rfd);
522 buf[sizeof(buf)-1] = 0;
523 /* Strip any leading space in front of # of slots */
524 for (p=buf; B_ISSPACE(*p); p++)
526 bnet_fsend(dir, "slots=%s", p);
527 Dmsg1(100, "<stored: %s", dir->msg);
530 stat = close_bpipe(bpipe);
534 bnet_fsend(dir, _("Autochanger error: ERR=%s\n"), be.strerror());
536 bnet_sig(dir, BNET_EOD);
541 free_pool_memory(changer);
547 * Edit codes into ChangerCommand
549 * %a = archive device name
550 * %c = changer device name
551 * %d = changer drive index
560 * omsg = edited output message
561 * imsg = input string containing edit codes (%x)
562 * cmd = command string (load, unload, ...)
565 char *edit_device_codes(DCR *dcr, char *omsg, const char *imsg, const char *cmd)
572 Dmsg1(1800, "edit_device_codes: %s\n", imsg);
573 for (p=imsg; *p; p++) {
580 str = dcr->dev->archive_name();
583 str = NPRT(dcr->device->changer_name);
586 sprintf(add, "%d", dcr->dev->drive_index);
593 sprintf(add, "%d", dcr->VolCatInfo.Slot - 1);
597 sprintf(add, "%d", dcr->VolCatInfo.Slot);
600 case 'j': /* Job name */
604 str = NPRT(dcr->VolumeName);
607 str = NPRT(dcr->jcr->client_name);
622 Dmsg1(1900, "add_str %s\n", str);
623 pm_strcat(&omsg, (char *)str);
624 Dmsg1(1800, "omsg=%s\n", omsg);
626 Dmsg1(800, "omsg=%s\n", omsg);