3 * Routines for handling the autochanger.
5 * Kern Sibbald, August MMII
10 Copyright (C) 2000-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 as
14 published by the Free Software Foundation; either version 2 of
15 the License, or (at your option) any later version.
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 GNU
20 General Public License for more details.
22 You should have received a copy of the GNU General Public
23 License along with this program; if not, write to the Free
24 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
29 #include "bacula.h" /* pull in global headers */
30 #include "stored.h" /* pull in Storage Deamon headers */
32 /* Forward referenced functions */
33 static int get_autochanger_loaded_slot(DCR *dcr);
34 static void lock_changer(DCR *dcr);
35 static void unlock_changer(DCR *dcr);
38 * Called here to do an autoload using the autochanger, if
39 * configured, and if a Slot has been defined for this Volume.
40 * On success this routine loads the indicated tape, but the
41 * label is not read, so it must be verified.
43 * Note if dir is not NULL, it is the console requesting the
44 * autoload for labeling, so we respond directly to the
47 * Returns: 1 on success
48 * 0 on failure (no changer available)
49 * -1 on error on autochanger
51 int autoload_device(DCR *dcr, int writing, BSOCK *dir)
54 DEVICE *dev = dcr->dev;
56 int drive = dev->device->drive_index;
57 int rtn_stat = -1; /* error status */
60 slot = dcr->VolCatInfo.InChanger ? dcr->VolCatInfo.Slot : 0;
62 * Handle autoloaders here. If we cannot autoload it, we
63 * will return FALSE to ask the sysop.
65 if (writing && dev_cap(dev, CAP_AUTOCHANGER) && slot <= 0) {
67 return 0; /* For user, bail out right now */
69 if (dir_find_next_appendable_volume(dcr)) {
70 slot = dcr->VolCatInfo.InChanger ? dcr->VolCatInfo.Slot : 0;
75 Dmsg1(400, "Want changer slot=%d\n", slot);
77 changer = get_pool_memory(PM_FNAME);
78 if (slot > 0 && dcr->device->changer_name && dcr->device->changer_command) {
79 uint32_t timeout = dcr->device->max_changer_wait;
82 loaded = get_autochanger_loaded_slot(dcr);
84 /* If tape we want is not loaded, load it. */
86 offline_or_rewind_dev(dev);
87 /* We are going to load a new tape, so close the device */
90 if (loaded != 0 && loaded != -1) { /* must unload drive */
91 Dmsg0(400, "Doing changer unload.\n");
93 _("3303 Issuing autochanger \"unload slot %d, drive %d\" command.\n"),
95 dcr->VolCatInfo.Slot = loaded; /* slot to be unloaded */
96 changer = edit_device_codes(dcr, changer,
97 dcr->device->changer_command, "unload");
98 status = run_program(changer, timeout, NULL);
101 be.set_errno(status);
102 Jmsg(jcr, M_FATAL, 0, _("3992 Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n"),
103 slot, drive, be.strerror());
107 Dmsg1(400, "unload status=%d\n", status);
110 * Load the desired cassette
112 Dmsg1(400, "Doing changer load slot %d\n", slot);
114 _("3304 Issuing autochanger \"load slot %d, drive %d\" command.\n"),
116 dcr->VolCatInfo.Slot = slot; /* slot to be loaded */
117 changer = edit_device_codes(dcr, changer,
118 dcr->device->changer_command, "load");
119 status = run_program(changer, timeout, NULL);
121 Jmsg(jcr, M_INFO, 0, _("3305 Autochanger \"load slot %d, drive %d\", status is OK.\n"),
125 be.set_errno(status);
126 Jmsg(jcr, M_FATAL, 0, _("3992 Bad autochanger \"load slot %d, drive %d\": ERR=%s.\n"),
127 slot, drive, be.strerror());
131 Dmsg2(400, "load slot %d status=%d\n", slot, status);
133 status = 0; /* we got what we want */
135 Dmsg1(400, "After changer, status=%d\n", status);
136 if (status == 0) { /* did we succeed? */
137 rtn_stat = 1; /* tape loaded by changer */
140 rtn_stat = 0; /* no changer found */
142 free_pool_memory(changer);
146 free_pool_memory(changer);
152 static int get_autochanger_loaded_slot(DCR *dcr)
155 POOLMEM *changer, *results;
157 uint32_t timeout = dcr->device->max_changer_wait;
158 int drive = dcr->device->drive_index;
160 results = get_pool_memory(PM_MESSAGE);
161 changer = get_pool_memory(PM_FNAME);
165 /* Find out what is loaded, zero means device is unloaded */
166 Jmsg(jcr, M_INFO, 0, _("3301 Issuing autochanger \"loaded drive %d\" command.\n"),
168 changer = edit_device_codes(dcr, changer,
169 dcr->device->changer_command, "loaded");
170 status = run_program(changer, timeout, results);
171 Dmsg3(50, "run_prog: %s stat=%d result=%s", changer, status, results);
173 loaded = atoi(results);
175 Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded drive %d\", result is Slot %d.\n"),
178 Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded drive %d\", result: nothing loaded.\n"),
183 be.set_errno(status);
184 Jmsg(jcr, M_INFO, 0, _("3991 Bad autochanger \"loaded drive %d\" command: ERR=%s.\n"),
185 drive, be.strerror());
186 loaded = -1; /* force unload */
189 free_pool_memory(changer);
190 free_pool_memory(results);
194 static void lock_changer(DCR *dcr)
196 AUTOCHANGER *changer_res = dcr->device->changer_res;
198 Dmsg1(100, "Locking changer %s\n", changer_res->hdr.name);
199 P(changer_res->changer_mutex); /* Lock changer script */
203 static void unlock_changer(DCR *dcr)
205 AUTOCHANGER *changer_res = dcr->device->changer_res;
207 Dmsg1(100, "Unlocking changer %s\n", changer_res->hdr.name);
208 V(changer_res->changer_mutex); /* Unlock changer script */
214 * List the Volumes that are in the autoloader possibly
215 * with their barcodes.
216 * We assume that it is always the Console that is calling us.
218 bool autochanger_cmd(DCR *dcr, BSOCK *dir, const char *cmd)
220 DEVICE *dev = dcr->dev;
222 uint32_t timeout = dcr->device->max_changer_wait;
226 int len = sizeof_pool_memory(dir->msg) - 1;
230 if (!dev_cap(dev, CAP_AUTOCHANGER) || !dcr->device->changer_name ||
231 !dcr->device->changer_command) {
232 bnet_fsend(dir, _("3993 Device %s not an autochanger device.\n"),
237 changer = get_pool_memory(PM_FNAME);
239 if (strcmp(cmd, "list") == 0) {
240 int drive = dev->device->drive_index;
241 /* Yes, to get a good listing, we unload any volumes */
242 offline_or_rewind_dev(dev);
243 /* We are going to load a new tape, so close the device */
244 force_close_dev(dev);
246 /* First unload any tape */
247 loaded = get_autochanger_loaded_slot(dcr);
250 _("3307 Issuing autochanger \"unload slot %d, drive %d\" command.\n"),
252 slot = dcr->VolCatInfo.Slot;
253 dcr->VolCatInfo.Slot = loaded;
254 changer = edit_device_codes(dcr, changer,
255 dcr->device->changer_command, "unload");
257 int stat = run_program(changer, timeout, NULL);
262 Jmsg(jcr, M_INFO, 0, _("3995 Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n"),
263 slot, drive, be.strerror());
265 dcr->VolCatInfo.Slot = slot;
269 /* Now issue the command */
270 changer = edit_device_codes(dcr, changer,
271 dcr->device->changer_command, cmd);
272 bnet_fsend(dir, _("3306 Issuing autochanger \"%s\" command.\n"), cmd);
274 bpipe = open_bpipe(changer, timeout, "r");
277 bnet_fsend(dir, _("3996 Open bpipe failed.\n"));
280 if (strcmp(cmd, "list") == 0) {
281 /* Get output from changer */
282 while (fgets(dir->msg, len, bpipe->rfd)) {
283 dir->msglen = strlen(dir->msg);
284 Dmsg1(100, "<stored: %s\n", dir->msg);
288 /* For slots command, read a single line */
289 bstrncpy(dir->msg, "slots=", len);
290 fgets(dir->msg+6, len-6, bpipe->rfd);
291 dir->msglen = strlen(dir->msg);
292 Dmsg1(100, "<stored: %s", dir->msg);
296 stat = close_bpipe(bpipe);
301 bnet_fsend(dir, "Autochanger error: ERR=%s\n", be.strerror());
303 bnet_sig(dir, BNET_EOD);
307 free_pool_memory(changer);
313 * Edit codes into ChangerCommand
315 * %a = archive device name
316 * %c = changer device name
317 * %d = changer drive index
326 * omsg = edited output message
327 * imsg = input string containing edit codes (%x)
328 * cmd = command string (load, unload, ...)
331 char *edit_device_codes(DCR *dcr, char *omsg, const char *imsg, const char *cmd)
338 Dmsg1(1800, "edit_device_codes: %s\n", imsg);
339 for (p=imsg; *p; p++) {
346 str = dcr->dev->archive_name();
349 str = NPRT(dcr->device->changer_name);
352 sprintf(add, "%d", dcr->dev->drive_index);
359 sprintf(add, "%d", dcr->VolCatInfo.Slot - 1);
363 sprintf(add, "%d", dcr->VolCatInfo.Slot);
366 case 'j': /* Job name */
370 str = NPRT(dcr->VolumeName);
373 str = NPRT(dcr->jcr->client_name);
388 Dmsg1(1900, "add_str %s\n", str);
389 pm_strcat(&omsg, (char *)str);
390 Dmsg1(1800, "omsg=%s\n", omsg);
392 Dmsg1(800, "omsg=%s\n", omsg);