2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1998 University of Maryland at College Park
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of U.M. not be used in advertising or
11 * publicity pertaining to distribution of the software without specific,
12 * written prior permission. U.M. makes no representations about the
13 * suitability of this software for any purpose. It is provided "as is"
14 * without express or implied warranty.
16 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 * Authors: the Amanda Development Team. Its members are listed in a
24 * file named AUTHORS, in the root directory of this distribution.
27 * $Id: changer.c,v 1.36 2006/08/24 01:57:16 paddy_s Exp $
29 * interface routines for tape changers
39 * If we don't have the new-style wait access functions, use our own,
40 * compatible with old-style BSD systems at least. Note that we don't
41 * care about the case w_stopval == WSTOPPED since we don't ask to see
42 * stopped processes, so should never get them from wait.
45 # define WEXITSTATUS(r) (((union wait *) &(r))->w_retcode)
46 # define WTERMSIG(r) (((union wait *) &(r))->w_termsig)
49 # define WIFSIGNALED(r) (((union wait *) &(r))->w_termsig != 0)
53 int changer_debug = 0;
54 char *changer_resultstr = NULL;
56 static pid_t tpchanger_pid = -1;
57 static int tpchanger_stdout = -1;
58 static int tpchanger_stdin = -1;
61 static int changer_command(char *cmd, char *arg);
62 static int report_bad_resultstr(char *cmd);
63 static int run_changer_command(char *cmd, char *arg, char **slotstr, char **rest);
68 return strcmp(getconf_str(CNF_TPCHANGER), "") != 0;
73 report_bad_resultstr(char *cmd)
77 s = vstrallocf(_("<error> badly formed result from changer command %s: \"%s\""),
78 cmd, changer_resultstr);
79 amfree(changer_resultstr);
80 changer_resultstr = s;
103 exitcode = changer_command(cmd, arg);
104 s = changer_resultstr;
107 skip_whitespace(s, ch);
108 if(ch == '\0') return report_bad_resultstr(cmd);
110 skip_non_whitespace(s, ch);
113 *slotstr = newstralloc(*slotstr, slot);
117 skip_whitespace(s, ch);
123 if(ch == '\0') return report_bad_resultstr(cmd);
124 result_copy = stralloc(s - 1);
125 amfree(changer_resultstr);
126 changer_resultstr = result_copy;
138 return run_changer_command("-reset", (char *) NULL, slotstr, &rest);
147 return run_changer_command("-clean", (char *) NULL, slotstr, &rest);
156 return run_changer_command("-eject", (char *) NULL, slotstr, &rest);
168 rc = run_changer_command("-slot", inslotstr, outslotstr, &rest);
171 if(*rest == '\0') return report_bad_resultstr("-slot");
173 *devicename = newstralloc(*devicename, rest);
179 * This function is somewhat equal to changer_info with one additional
180 * parameter, to get information, if the changer is able to search for
181 * tapelabels himself. E.g. Barcodereader
182 * The changer_script answers with an additional parameter, if it is able
183 * to search. This one should be 1, if it is able to search, and 0 if it
184 * knows about the extension. If the additional answer is omitted, the
185 * changer is not able to search for a tape.
198 rc = run_changer_command("-info", (char *) NULL, curslotstr, &rest);
201 dbprintf(_("changer_query: changer return was %s\n"),rest);
202 if (sscanf(rest, "%d %d %d", nslotsp, backwardsp, searchable) != 3) {
203 if (sscanf(rest, "%d %d", nslotsp, backwardsp) != 2) {
204 return report_bad_resultstr("-info");
209 dbprintf(_("changer_query: searchable = %d\n"),*searchable);
222 rc = run_changer_command("-info", (char *) NULL, curslotstr, &rest);
225 if (sscanf(rest, "%d %d", nslotsp, backwardsp) != 2) {
226 return report_bad_resultstr("-info");
232 /* ---------------------------- */
235 * This function first uses searchlabel and changer_search, if
236 * the library is able to find a tape itself. If it is not, or if
237 * the tape could not be found, then the normal scan is done.
239 * See interface documentation in changer.h.
245 int (*user_init)(void *, int, int, int, int),
246 int (*user_slot)(void *, int, char *, char *),
249 char *slotstr, *device = NULL, *curslotstr = NULL;
250 int nslots, checked, backwards, rc, done, searchable;
252 rc = changer_query(&nslots, &curslotstr, &backwards, &searchable);
255 /* Problem with the changer script. Bail. */
256 g_fprintf(stderr, _("Changer problem: %s\n"), changer_resultstr);
261 done = user_init(user_data, rc, nslots, backwards, searchable);
264 if (searchlabel != NULL)
266 dbprintf(_("changer_find: looking for %s changer is searchable = %d\n"),
267 searchlabel, searchable);
269 dbprintf(_("changer_find: looking for NULL changer is searchable = %d\n"),
273 if ((searchlabel!=NULL) && searchable && !done){
274 rc=changer_search(searchlabel, &curslotstr, &device);
276 done = user_slot(user_data, rc, curslotstr, device);
282 while(!done && checked < nslots) {
283 rc = changer_loadslot(slotstr, &curslotstr, &device);
285 done = user_slot(user_data, rc, curslotstr, device);
287 done = user_slot(user_data, 0, curslotstr, device);
296 /* ---------------------------- */
301 int (*user_init)(void *, int, int, int, int),
302 int (*user_slot)(void *, int, char *, char *))
304 char *device = NULL, *curslotstr = NULL;
305 int nslots, backwards, rc, done, searchable;
307 rc = changer_query(&nslots, &curslotstr, &backwards, &searchable);
308 done = user_init(user_data, rc, nslots, backwards, searchable);
311 rc = changer_loadslot("current", &curslotstr, &device);
313 done = user_slot(user_data, rc, curslotstr, device);
315 done = user_slot(user_data, 0, curslotstr, device);
321 /* ---------------------------- */
326 int stdin_pipe[2] = { -1, -1 };
327 int stdout_pipe[2] = { -1, -1 };
330 /* is it already running? */
331 if (tpchanger_pid != -1)
334 if (pipe(stdin_pipe) == -1 || pipe(stdout_pipe) == -1) {
335 changer_resultstr = vstrallocf(
336 _("<error> could not make pipe: %s"), strerror(errno));
340 switch(tpchanger_pid = fork()) {
342 changer_resultstr = vstrallocf(
343 _("<error> could not fork: %s"), strerror(errno));
347 debug_dup_stderr_to_debug();
348 if(dup2(stdin_pipe[0], 0) == -1) {
349 changer_resultstr = vstrallocf(
350 _("<error> could not dup2: %s"), strerror(errno));
354 if(dup2(stdout_pipe[1], 1) == -1) {
355 changer_resultstr = vstrallocf(
356 _("<error> could not dup2: %s"), strerror(errno));
361 chg_glue = g_strdup_printf("%s/chg-glue", amlibexecdir);
363 execl(chg_glue, chg_glue, get_config_name(), NULL);
364 changer_resultstr = vstrallocf(
365 _("<error> could not exec \"chg-glue\": %s"), strerror(errno));
369 (void)full_write(stdout_pipe[1], changer_resultstr, strlen(changer_resultstr));
373 aclose(stdin_pipe[0]);
374 aclose(stdout_pipe[1]);
376 tpchanger_stdout = stdout_pipe[0];
377 tpchanger_stdin = stdin_pipe[1];
383 aclose(stdin_pipe[0]);
384 aclose(stdin_pipe[1]);
385 aclose(stdout_pipe[0]);
386 aclose(stdout_pipe[1]);
399 amfree(changer_resultstr);
401 if (!start_chg_glue()) {
406 cmdstr = vstralloc(cmd,
412 g_debug("changer: >> %s %s", cmd, arg? arg : "");
414 /* write the command to chg_glue */
415 if (full_write(tpchanger_stdin, cmdstr, strlen(cmdstr)) != strlen(cmdstr)) {
416 changer_resultstr = g_strdup("<error> chg-glue exited unexpectedly");
421 /* read the first line of the response */
422 changer_resultstr = areads(tpchanger_stdout);
423 if (!changer_resultstr || !*changer_resultstr) {
424 changer_resultstr = g_strdup("<error> unexpected EOF");
428 g_debug("changer: << %s", changer_resultstr);
430 if (strncmp_const(changer_resultstr, "EXITSTATUS ") != 0) {
431 report_bad_resultstr(cmd);
435 exitcode = atoi(changer_resultstr + strlen("EXITSTATUS "));
438 changer_resultstr = areads(tpchanger_stdout);
439 if (!changer_resultstr) {
440 changer_resultstr = g_strdup("<error> unexpected EOF");
444 g_debug("changer: << %s", changer_resultstr);
448 g_debug("changer: ERROR %s", changer_resultstr);
458 * This function commands the changerscript to look for a tape named
459 * searchlabel. If is found, the changerscript answers with the device,
460 * in which the tape can be accessed.
472 dbprintf("changer_search: %s\n",searchlabel);
473 rc = run_changer_command("-search", searchlabel, outslotstr, &rest);
476 if(*rest == '\0') return report_bad_resultstr("-search");
478 *devicename = newstralloc(*devicename, rest);
484 * Because barcodelabel are short, and may not be the same as the
485 * amandalabels, the changerscript should be informed, which tapelabel
486 * is associated with a tape. This function should be called after
487 * giving a label for a tape. (Maybe also, when the label and the associated
488 * slot is known. e.g. during library scan.
499 char *curslotstr = NULL;
500 int nslots, backwards, searchable;
502 dbprintf(_("changer_label: %s for slot %s\n"),labelstr,slotsp);
503 rc = changer_query(&nslots, &curslotstr, &backwards,&searchable);
506 if ((rc == 0) && (searchable == 1)){
507 dbprintf(_("changer_label: calling changer -label %s\n"),labelstr);
508 rc = run_changer_command("-label", labelstr, &slotstr, &rest);