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 ammended 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 int get_autochanger_loaded_slot(DCR *dcr);
29 static void lock_changer(DCR *dcr);
30 static void unlock_changer(DCR *dcr);
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->device->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_cap(dev, CAP_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);
79 /* If tape we want is not loaded, load it. */
81 offline_or_rewind_dev(dev);
82 /* We are going to load a new tape, so close the device */
85 if (loaded != 0 && loaded != -1) { /* must unload drive */
86 Dmsg0(400, "Doing changer unload.\n");
88 _("3303 Issuing autochanger \"unload slot %d, drive %d\" command.\n"),
90 dcr->VolCatInfo.Slot = loaded; /* slot to be unloaded */
91 changer = edit_device_codes(dcr, changer,
92 dcr->device->changer_command, "unload");
93 status = run_program(changer, timeout, NULL);
97 Jmsg(jcr, M_FATAL, 0, _("3992 Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n"),
98 slot, drive, be.strerror());
101 dev->Slot = 0; /* nothing loaded now */
103 Dmsg1(400, "unload status=%d\n", status);
106 * Load the desired cassette
108 Dmsg1(400, "Doing changer load slot %d\n", slot);
110 _("3304 Issuing autochanger \"load slot %d, drive %d\" command.\n"),
112 dcr->VolCatInfo.Slot = slot; /* slot to be loaded */
113 changer = edit_device_codes(dcr, changer,
114 dcr->device->changer_command, "load");
115 status = run_program(changer, timeout, NULL);
117 Jmsg(jcr, M_INFO, 0, _("3305 Autochanger \"load slot %d, drive %d\", status is OK.\n"),
119 dev->Slot = slot; /* set currently loaded slot */
122 be.set_errno(status);
123 Jmsg(jcr, M_FATAL, 0, _("3992 Bad autochanger \"load slot %d, drive %d\": ERR=%s.\n"),
124 slot, drive, be.strerror());
128 Dmsg2(400, "load slot %d status=%d\n", slot, status);
130 status = 0; /* we got what we want */
131 dev->Slot = slot; /* set currently loaded slot */
133 Dmsg1(400, "After changer, status=%d\n", status);
134 if (status == 0) { /* did we succeed? */
135 rtn_stat = 1; /* tape loaded by changer */
138 rtn_stat = 0; /* no changer found */
140 free_pool_memory(changer);
144 free_pool_memory(changer);
150 static int get_autochanger_loaded_slot(DCR *dcr)
153 POOLMEM *changer, *results;
155 uint32_t timeout = dcr->device->max_changer_wait;
156 int drive = dcr->device->drive_index;
158 results = get_pool_memory(PM_MESSAGE);
159 changer = get_pool_memory(PM_FNAME);
163 /* Find out what is loaded, zero means device is unloaded */
164 Jmsg(jcr, M_INFO, 0, _("3301 Issuing autochanger \"loaded drive %d\" command.\n"),
166 changer = edit_device_codes(dcr, changer,
167 dcr->device->changer_command, "loaded");
168 status = run_program(changer, timeout, results);
169 Dmsg3(50, "run_prog: %s stat=%d result=%s", changer, status, results);
171 loaded = atoi(results);
173 Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded drive %d\", result is Slot %d.\n"),
175 dcr->dev->Slot = loaded;
177 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 dev->Slot = 0; /* nothing loaded */
267 dcr->VolCatInfo.Slot = slot;
271 /* Now issue the command */
272 changer = edit_device_codes(dcr, changer,
273 dcr->device->changer_command, cmd);
274 bnet_fsend(dir, _("3306 Issuing autochanger \"%s\" command.\n"), cmd);
276 bpipe = open_bpipe(changer, timeout, "r");
279 bnet_fsend(dir, _("3996 Open bpipe failed.\n"));
282 if (strcmp(cmd, "list") == 0) {
283 /* Get output from changer */
284 while (fgets(dir->msg, len, bpipe->rfd)) {
285 dir->msglen = strlen(dir->msg);
286 Dmsg1(100, "<stored: %s\n", dir->msg);
290 /* For slots command, read a single line */
291 bstrncpy(dir->msg, "slots=", len);
292 fgets(dir->msg+6, len-6, bpipe->rfd);
293 dir->msglen = strlen(dir->msg);
294 Dmsg1(100, "<stored: %s", dir->msg);
298 stat = close_bpipe(bpipe);
303 bnet_fsend(dir, "Autochanger error: ERR=%s\n", be.strerror());
305 bnet_sig(dir, BNET_EOD);
309 free_pool_memory(changer);
315 * Edit codes into ChangerCommand
317 * %a = archive device name
318 * %c = changer device name
319 * %d = changer drive index
328 * omsg = edited output message
329 * imsg = input string containing edit codes (%x)
330 * cmd = command string (load, unload, ...)
333 char *edit_device_codes(DCR *dcr, char *omsg, const char *imsg, const char *cmd)
340 Dmsg1(1800, "edit_device_codes: %s\n", imsg);
341 for (p=imsg; *p; p++) {
348 str = dcr->dev->archive_name();
351 str = NPRT(dcr->device->changer_name);
354 sprintf(add, "%d", dcr->dev->drive_index);
361 sprintf(add, "%d", dcr->VolCatInfo.Slot - 1);
365 sprintf(add, "%d", dcr->VolCatInfo.Slot);
368 case 'j': /* Job name */
372 str = NPRT(dcr->VolumeName);
375 str = NPRT(dcr->jcr->client_name);
390 Dmsg1(1900, "add_str %s\n", str);
391 pm_strcat(&omsg, (char *)str);
392 Dmsg1(1800, "omsg=%s\n", omsg);
394 Dmsg1(800, "omsg=%s\n", omsg);