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);
32 * Called here to do an autoload using the autochanger, if
33 * configured, and if a Slot has been defined for this Volume.
34 * On success this routine loads the indicated tape, but the
35 * label is not read, so it must be verified.
37 * Note if dir is not NULL, it is the console requesting the
38 * autoload for labeling, so we respond directly to the
41 * Returns: 1 on success
42 * 0 on failure (no changer available)
43 * -1 on error on autochanger
45 int autoload_device(DCR *dcr, int writing, BSOCK *dir)
48 DEVICE *dev = dcr->dev;
50 int drive = dev->device->drive_index;
51 int rtn_stat = -1; /* error status */
54 slot = dcr->VolCatInfo.InChanger ? dcr->VolCatInfo.Slot : 0;
56 * Handle autoloaders here. If we cannot autoload it, we
57 * will return 0 so that the sysop will be asked to load it.
59 if (writing && dev->is_autochanger() && slot <= 0) {
61 return 0; /* For user, bail out right now */
63 if (dir_find_next_appendable_volume(dcr)) {
64 slot = dcr->VolCatInfo.InChanger ? dcr->VolCatInfo.Slot : 0;
69 Dmsg1(400, "Want changer slot=%d\n", slot);
71 changer = get_pool_memory(PM_FNAME);
72 if (slot > 0 && dcr->device->changer_name && dcr->device->changer_command) {
73 uint32_t timeout = dcr->device->max_changer_wait;
76 loaded = get_autochanger_loaded_slot(dcr);
78 /* If tape we want is not loaded, load it. */
80 offline_or_rewind_dev(dev);
81 /* We are going to load a new tape, so close the device */
82 force_close_device(dev);
84 if (loaded != 0 && loaded != -1) { /* must unload drive */
85 Dmsg0(400, "Doing changer unload.\n");
87 _("3303 Issuing autochanger \"unload slot %d, drive %d\" command.\n"),
89 dcr->VolCatInfo.Slot = loaded; /* slot to be unloaded */
90 changer = edit_device_codes(dcr, changer,
91 dcr->device->changer_command, "unload");
92 status = run_program(changer, timeout, NULL);
96 Jmsg(jcr, M_FATAL, 0, _("3992 Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n"),
97 slot, drive, be.strerror());
100 dev->Slot = 0; /* nothing loaded now */
102 Dmsg1(400, "unload status=%d\n", status);
105 * Load the desired cassette
107 Dmsg1(400, "Doing changer load slot %d\n", slot);
109 _("3304 Issuing autochanger \"load slot %d, drive %d\" command.\n"),
111 dcr->VolCatInfo.Slot = slot; /* slot to be loaded */
112 changer = edit_device_codes(dcr, changer,
113 dcr->device->changer_command, "load");
114 status = run_program(changer, timeout, NULL);
116 Jmsg(jcr, M_INFO, 0, _("3305 Autochanger \"load slot %d, drive %d\", status is OK.\n"),
118 dev->Slot = slot; /* set currently loaded slot */
121 be.set_errno(status);
122 Jmsg(jcr, M_FATAL, 0, _("3992 Bad autochanger \"load slot %d, drive %d\": ERR=%s.\n"),
123 slot, drive, be.strerror());
127 Dmsg2(400, "load slot %d status=%d\n", slot, status);
129 status = 0; /* we got what we want */
130 dev->Slot = slot; /* set currently loaded slot */
132 Dmsg1(400, "After changer, status=%d\n", status);
133 if (status == 0) { /* did we succeed? */
134 rtn_stat = 1; /* tape loaded by changer */
137 rtn_stat = 0; /* no changer found */
139 free_pool_memory(changer);
143 free_pool_memory(changer);
150 * Returns: -1 if error from changer command
153 int get_autochanger_loaded_slot(DCR *dcr)
156 POOLMEM *changer, *results;
158 uint32_t timeout = dcr->device->max_changer_wait;
159 int drive = dcr->dev->drive_index;
161 results = get_pool_memory(PM_MESSAGE);
162 changer = get_pool_memory(PM_FNAME);
166 /* Find out what is loaded, zero means device is unloaded */
167 Jmsg(jcr, M_INFO, 0, _("3301 Issuing autochanger \"loaded drive %d\" command.\n"),
169 changer = edit_device_codes(dcr, changer, dcr->device->changer_command, "loaded");
171 status = run_program(changer, timeout, results);
172 Dmsg3(50, "run_prog: %s stat=%d result=%s\n", changer, status, results);
174 loaded = atoi(results);
176 Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded drive %d\", result is Slot %d.\n"),
178 dcr->dev->Slot = loaded;
180 Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded drive %d\", result: nothing loaded.\n"),
186 be.set_errno(status);
187 Jmsg(jcr, M_INFO, 0, _("3991 Bad autochanger \"loaded drive %d\" command: ERR=%s.\n"),
188 drive, be.strerror());
189 loaded = -1; /* force unload */
192 free_pool_memory(changer);
193 free_pool_memory(results);
197 static void lock_changer(DCR *dcr)
199 AUTOCHANGER *changer_res = dcr->device->changer_res;
201 Dmsg1(100, "Locking changer %s\n", changer_res->hdr.name);
202 P(changer_res->changer_mutex); /* Lock changer script */
206 static void unlock_changer(DCR *dcr)
208 AUTOCHANGER *changer_res = dcr->device->changer_res;
210 Dmsg1(100, "Unlocking changer %s\n", changer_res->hdr.name);
211 V(changer_res->changer_mutex); /* Unlock changer script */
217 * List the Volumes that are in the autoloader possibly
218 * with their barcodes.
219 * We assume that it is always the Console that is calling us.
221 bool autochanger_cmd(DCR *dcr, BSOCK *dir, const char *cmd)
223 DEVICE *dev = dcr->dev;
225 uint32_t timeout = dcr->device->max_changer_wait;
229 int len = sizeof_pool_memory(dir->msg) - 1;
233 if (!dev->is_autochanger() || !dcr->device->changer_name ||
234 !dcr->device->changer_command) {
235 bnet_fsend(dir, _("3993 Device %s not an autochanger device.\n"),
240 changer = get_pool_memory(PM_FNAME);
242 if (strcmp(cmd, "list") == 0) {
243 int drive = dev->device->drive_index;
244 /* Yes, to get a good listing, we unload any volumes */
245 offline_or_rewind_dev(dev);
246 /* We are going to load a new tape, so close the device */
247 force_close_device(dev);
249 /* First unload any tape */
250 loaded = get_autochanger_loaded_slot(dcr);
253 _("3307 Issuing autochanger \"unload slot %d, drive %d\" command.\n"),
255 slot = dcr->VolCatInfo.Slot;
256 dcr->VolCatInfo.Slot = loaded;
257 changer = edit_device_codes(dcr, changer,
258 dcr->device->changer_command, "unload");
260 int stat = run_program(changer, timeout, NULL);
265 Jmsg(jcr, M_INFO, 0, _("3995 Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n"),
266 slot, drive, be.strerror());
268 dev->Slot = 0; /* nothing loaded */
270 dcr->VolCatInfo.Slot = slot;
274 /* Now issue the command */
275 changer = edit_device_codes(dcr, changer,
276 dcr->device->changer_command, cmd);
277 bnet_fsend(dir, _("3306 Issuing autochanger \"%s\" command.\n"), cmd);
279 bpipe = open_bpipe(changer, timeout, "r");
282 bnet_fsend(dir, _("3996 Open bpipe failed.\n"));
285 if (strcmp(cmd, "list") == 0) {
286 /* Get output from changer */
287 while (fgets(dir->msg, len, bpipe->rfd)) {
288 dir->msglen = strlen(dir->msg);
289 Dmsg1(100, "<stored: %s\n", dir->msg);
293 /* For slots command, read a single line */
294 bstrncpy(dir->msg, "slots=", len);
295 fgets(dir->msg+6, len-6, bpipe->rfd);
296 dir->msglen = strlen(dir->msg);
297 Dmsg1(100, "<stored: %s", dir->msg);
301 stat = close_bpipe(bpipe);
306 bnet_fsend(dir, "Autochanger error: ERR=%s\n", be.strerror());
308 bnet_sig(dir, BNET_EOD);
312 free_pool_memory(changer);
318 * Edit codes into ChangerCommand
320 * %a = archive device name
321 * %c = changer device name
322 * %d = changer drive index
331 * omsg = edited output message
332 * imsg = input string containing edit codes (%x)
333 * cmd = command string (load, unload, ...)
336 char *edit_device_codes(DCR *dcr, char *omsg, const char *imsg, const char *cmd)
343 Dmsg1(1800, "edit_device_codes: %s\n", imsg);
344 for (p=imsg; *p; p++) {
351 str = dcr->dev->archive_name();
354 str = NPRT(dcr->device->changer_name);
357 sprintf(add, "%d", dcr->dev->drive_index);
364 sprintf(add, "%d", dcr->VolCatInfo.Slot - 1);
368 sprintf(add, "%d", dcr->VolCatInfo.Slot);
371 case 'j': /* Job name */
375 str = NPRT(dcr->VolumeName);
378 str = NPRT(dcr->jcr->client_name);
393 Dmsg1(1900, "add_str %s\n", str);
394 pm_strcat(&omsg, (char *)str);
395 Dmsg1(1800, "omsg=%s\n", omsg);
397 Dmsg1(800, "omsg=%s\n", omsg);