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 char *tapechanger = NULL;
59 static int changer_command(char *cmd, char *arg);
60 static int report_bad_resultstr(char *cmd);
61 static int run_changer_command(char *cmd, char *arg, char **slotstr, char **rest);
66 if (tapechanger == NULL)
67 tapechanger = getconf_str(CNF_TPCHANGER);
68 if (*tapechanger != '\0' && *tapechanger != '/') {
69 tapechanger = vstralloc(amlibexecdir, "/", tapechanger, versionsuffix(),
72 return strcmp(tapechanger, "") != 0;
77 report_bad_resultstr(char *cmd)
81 s = vstrallocf(_("badly formed result from changer command %s: \"%s\""),
82 cmd, changer_resultstr);
83 amfree(changer_resultstr);
84 changer_resultstr = s;
107 exitcode = changer_command(cmd, arg);
108 s = changer_resultstr;
111 skip_whitespace(s, ch);
112 if(ch == '\0') return report_bad_resultstr(cmd);
114 skip_non_whitespace(s, ch);
117 *slotstr = newstralloc(*slotstr, slot);
121 skip_whitespace(s, ch);
127 if(ch == '\0') return report_bad_resultstr(cmd);
128 result_copy = stralloc(s - 1);
129 amfree(changer_resultstr);
130 changer_resultstr = result_copy;
142 return run_changer_command("-reset", (char *) NULL, slotstr, &rest);
151 return run_changer_command("-clean", (char *) NULL, slotstr, &rest);
160 return run_changer_command("-eject", (char *) NULL, slotstr, &rest);
172 rc = run_changer_command("-slot", inslotstr, outslotstr, &rest);
175 if(*rest == '\0') return report_bad_resultstr("-slot");
177 *devicename = newstralloc(*devicename, rest);
183 * This function is somewhat equal to changer_info with one additional
184 * parameter, to get information, if the changer is able to search for
185 * tapelabels himself. E.g. Barcodereader
186 * The changer_script answers with an additional parameter, if it is able
187 * to search. This one should be 1, if it is able to search, and 0 if it
188 * knows about the extension. If the additional answer is omitted, the
189 * changer is not able to search for a tape.
202 rc = run_changer_command("-info", (char *) NULL, curslotstr, &rest);
205 dbprintf(_("changer_query: changer return was %s\n"),rest);
206 if (sscanf(rest, "%d %d %d", nslotsp, backwardsp, searchable) != 3) {
207 if (sscanf(rest, "%d %d", nslotsp, backwardsp) != 2) {
208 return report_bad_resultstr("-info");
213 dbprintf(_("changer_query: searchable = %d\n"),*searchable);
226 rc = run_changer_command("-info", (char *) NULL, curslotstr, &rest);
229 if (sscanf(rest, "%d %d", nslotsp, backwardsp) != 2) {
230 return report_bad_resultstr("-info");
236 /* ---------------------------- */
239 * This function first uses searchlabel and changer_search, if
240 * the library is able to find a tape itself. If it is not, or if
241 * the tape could not be found, then the normal scan is done.
243 * See interface documentation in changer.h.
249 int (*user_init)(void *, int, int, int, int),
250 int (*user_slot)(void *, int, char *, char *),
253 char *slotstr, *device = NULL, *curslotstr = NULL;
254 int nslots, checked, backwards, rc, done, searchable;
256 rc = changer_query(&nslots, &curslotstr, &backwards, &searchable);
259 /* Problem with the changer script. Bail. */
260 g_fprintf(stderr, _("Changer problem: %s\n"), changer_resultstr);
264 done = user_init(user_data, rc, nslots, backwards, searchable);
267 if (searchlabel != NULL)
269 dbprintf(_("changer_find: looking for %s changer is searchable = %d\n"),
270 searchlabel, searchable);
272 dbprintf(_("changer_find: looking for NULL changer is searchable = %d\n"),
276 if ((searchlabel!=NULL) && searchable && !done){
277 rc=changer_search(searchlabel, &curslotstr, &device);
279 done = user_slot(user_data, rc, curslotstr, device);
285 while(!done && checked < nslots) {
286 rc = changer_loadslot(slotstr, &curslotstr, &device);
288 done = user_slot(user_data, rc, curslotstr, device);
290 done = user_slot(user_data, 0, curslotstr, device);
299 /* ---------------------------- */
304 int (*user_init)(void *, int, int, int, int),
305 int (*user_slot)(void *, int, char *, char *))
307 char *device = NULL, *curslotstr = NULL;
308 int nslots, backwards, rc, done, searchable;
310 rc = changer_query(&nslots, &curslotstr, &backwards, &searchable);
311 done = user_init(user_data, rc, nslots, backwards, searchable);
314 rc = changer_loadslot("current", &curslotstr, &device);
316 done = user_slot(user_data, rc, curslotstr, device);
318 done = user_slot(user_data, 0, curslotstr, device);
324 /* ---------------------------- */
332 amwait_t wait_exitcode = 1;
335 pid_t pid, changer_pid = 0;
336 int fd_to_close[4], *pfd_to_close = fd_to_close;
338 cmdstr = vstralloc(tapechanger, " ",
344 g_fprintf(stderr, _("changer: opening pipe to: %s\n"), cmdstr);
348 amfree(changer_resultstr);
350 if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd) == -1) {
351 changer_resultstr = vstrallocf(
352 _("<error> could not create pipe for \"%s\": %s"),
353 cmdstr, strerror(errno));
358 /* make sure fd[0] > 2 && fd[1] > 2 */
359 pfd_to_close = fd_to_close;
362 *pfd_to_close++ = fd[0];
367 *pfd_to_close++ = fd[1];
370 while (pfd_to_close > fd_to_close) {
371 close(*--pfd_to_close);
374 if(fd[0] < 0 || fd[0] >= (int)FD_SETSIZE) {
375 changer_resultstr = vstrallocf(
376 _("<error> could not create pipe for \"%s\":"
377 "socketpair 0: descriptor %d out of range ( 0 .. %d)"),
378 cmdstr, fd[0], (int)FD_SETSIZE-1);
382 if(fd[1] < 0 || fd[1] >= (int)FD_SETSIZE) {
383 changer_resultstr = vstrallocf(
384 _("<error> could not create pipe for \"%s\":"
385 "socketpair 1: descriptor %d out of range ( 0 .. %d)"),
386 cmdstr, fd[1], (int)FD_SETSIZE-1);
391 switch(changer_pid = fork()) {
393 changer_resultstr = vstrallocf(
394 _("<error> could not fork for \"%s\": %s"),
395 cmdstr, strerror(errno));
399 debug_dup_stderr_to_debug();
400 if(dup2(fd[1], 1) == -1) {
401 changer_resultstr = vstrallocf(
402 _("<error> could not open pipe to \"%s\": %s"),
403 cmdstr, strerror(errno));
404 (void)fullwrite(fd[1], changer_resultstr, strlen(changer_resultstr));
409 if(config_dir && chdir(config_dir) == -1) {
410 changer_resultstr = vstrallocf(
411 _("<error> could not cd to \"%s\": %s"),
412 config_dir, strerror(errno));
413 (void)fullwrite(STDOUT_FILENO, changer_resultstr, strlen(changer_resultstr));
418 execle(tapechanger, tapechanger, cmd, arg, (char *)NULL,
421 execle(tapechanger, tapechanger, cmd, (char *)NULL, safe_env());
423 changer_resultstr = vstrallocf(
424 _("<error> could not exec \"%s\": %s"),
425 tapechanger, strerror(errno));
426 (void)fullwrite(STDOUT_FILENO, changer_resultstr, strlen(changer_resultstr));
432 if((changer_resultstr = areads(fd[0])) == NULL) {
434 changer_resultstr = vstrallocf(
435 _("<error> could not read result from \"%s\": Premature end of file, see %s"),
436 tapechanger, dbfn());
438 changer_resultstr = vstrallocf(
439 _("<error> could not read result from \"%s\": %s"),
440 tapechanger, strerror(errno));
445 if ((pid = wait(&wait_exitcode)) == -1) {
449 changer_resultstr = vstrallocf(
450 _("<error> wait for \"%s\" failed: %s"),
451 tapechanger, strerror(errno));
455 } else if (pid != changer_pid) {
456 changer_resultstr = vstrallocf(
457 _("<error> wait for \"%s\" returned unexpected pid %ld"),
458 tapechanger, (long)pid);
466 /* mark out-of-control changers as fatal error */
467 if(WIFSIGNALED(wait_exitcode)) {
468 changer_resultstr = newvstrallocf(changer_resultstr,
469 _("<error> %s (got signal %d)"),
470 changer_resultstr, WTERMSIG(wait_exitcode));
473 exitcode = WEXITSTATUS(wait_exitcode);
482 dbprintf(_("changer: got exit: %d str: %s\n"), exitcode, changer_resultstr);
492 * This function commands the changerscript to look for a tape named
493 * searchlabel. If is found, the changerscript answers with the device,
494 * in which the tape can be accessed.
506 dbprintf("changer_search: %s\n",searchlabel);
507 rc = run_changer_command("-search", searchlabel, outslotstr, &rest);
510 if(*rest == '\0') return report_bad_resultstr("-search");
512 *devicename = newstralloc(*devicename, rest);
518 * Because barcodelabel are short, and may not be the same as the
519 * amandalabels, the changerscript should be informed, which tapelabel
520 * is associated with a tape. This function should be called after
521 * giving a label for a tape. (Maybe also, when the label and the associated
522 * slot is known. e.g. during library scan.
533 char *curslotstr = NULL;
534 int nslots, backwards, searchable;
536 dbprintf(_("changer_label: %s for slot %s\n"),labelstr,slotsp);
537 rc = changer_query(&nslots, &curslotstr, &backwards,&searchable);
540 if ((rc == 0) && (searchable == 1)){
541 dbprintf(_("changer_label: calling changer -label %s\n"),labelstr);
542 rc = run_changer_command("-label", labelstr, &slotstr, &rest);