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.14.4.6.4.1.2.3 2003/02/28 19:23:25 martinea Exp $
29 * interface routines for tape changers
38 * If we don't have the new-style wait access functions, use our own,
39 * compatible with old-style BSD systems at least. Note that we don't
40 * care about the case w_stopval == WSTOPPED since we don't ask to see
41 * stopped processes, so should never get them from wait.
44 # define WEXITSTATUS(r) (((union wait *) &(r))->w_retcode)
45 # define WTERMSIG(r) (((union wait *) &(r))->w_termsig)
48 # define WIFSIGNALED(r) (((union wait *) &(r))->w_termsig != 0)
52 int changer_debug = 0;
53 char *changer_resultstr = NULL;
55 static char *tapechanger = NULL;
58 static int changer_command P((char *cmd, char *arg));
62 tapechanger = getconf_str(CNF_TPCHANGER);
63 return strcmp(tapechanger, "") != 0;
67 static int report_bad_resultstr()
71 s = vstralloc("badly formed result from changer: ",
72 "\"", changer_resultstr, "\"",
74 amfree(changer_resultstr);
75 changer_resultstr = s;
79 static int run_changer_command(cmd, arg, slotstr, rest)
93 exitcode = changer_command(cmd, arg);
94 s = changer_resultstr;
97 skip_whitespace(s, ch);
98 if(ch == '\0') return report_bad_resultstr();
100 skip_non_whitespace(s, ch);
102 *slotstr = newstralloc(*slotstr, slot);
105 skip_whitespace(s, ch);
109 if(ch == '\0') return report_bad_resultstr();
110 result_copy = stralloc(s - 1);
111 amfree(changer_resultstr);
112 changer_resultstr = result_copy;
118 int changer_reset(slotstr)
123 return run_changer_command("-reset", (char *) NULL, slotstr, &rest);
126 int changer_clean(slotstr)
131 return run_changer_command("-clean", (char *) NULL, slotstr, &rest);
134 int changer_eject(slotstr)
139 return run_changer_command("-eject", (char *) NULL, slotstr, &rest);
142 int changer_loadslot(inslotstr, outslotstr, devicename)
143 char *inslotstr, **outslotstr, **devicename;
148 rc = run_changer_command("-slot", inslotstr, outslotstr, &rest);
151 if(*rest == '\0') return report_bad_resultstr();
153 *devicename = newstralloc(*devicename, rest);
157 /* This function is somewhat equal to changer_info with one additional
158 parameter, to get information, if the changer is able to search for
159 tapelabels himself. E.g. Barcodereader
160 The changer_script answers with an additional parameter, if it is able
161 to search. This one should be 1, if it is able to search, and 0 if it
162 knows about the extension. If the additional answer is omitted, the
163 changer is not able to search for a tape.
165 int changer_query(nslotsp, curslotstr, backwardsp, searchable)
166 int *nslotsp, *backwardsp, *searchable;
172 rc = run_changer_command("-info", (char *) NULL, curslotstr, &rest);
175 dbprintf(("changer_query: changer return was %s\n",rest));
176 if (sscanf(rest, "%d %d %d", nslotsp, backwardsp, searchable) != 3) {
177 if (sscanf(rest, "%d %d", nslotsp, backwardsp) != 2) {
178 return report_bad_resultstr();
183 dbprintf(("changer_query: searchable = %d\n",*searchable));
187 int changer_info(nslotsp, curslotstr, backwardsp)
188 int *nslotsp, *backwardsp;
194 rc = run_changer_command("-info", (char *) NULL, curslotstr, &rest);
197 if (sscanf(rest, "%d %d", nslotsp, backwardsp) != 2) {
198 return report_bad_resultstr();
204 /* ---------------------------- */
206 void changer_scan(user_init, user_slot)
207 int (*user_init) P((int rc, int nslots, int backwards));
208 int (*user_slot) P((int rc, char *slotstr, char *device));
210 char *slotstr, *device = NULL, *curslotstr = NULL;
211 int nslots, checked, backwards, rc, done;
213 rc = changer_info(&nslots, &curslotstr, &backwards);
214 done = user_init(rc, nslots, backwards);
220 while(!done && checked < nslots) {
221 rc = changer_loadslot(slotstr, &curslotstr, &device);
223 done = user_slot(rc, curslotstr, device);
225 done = user_slot(0, curslotstr, device);
234 /* This function first uses searchlabel and changer_search, if
235 the library is able to find a tape itself. If it is not, or if
236 the tape could not be found, then the normal scan is done like
239 void changer_find(user_init, user_slot, searchlabel)
240 int (*user_init) P((int rc, int nslots, int backwards));
241 int (*user_slot) P((int rc, char *slotstr, char *device));
244 char *slotstr, *device = NULL, *curslotstr = NULL;
245 int nslots, checked, backwards, rc, done, searchable;
247 rc = changer_query(&nslots, &curslotstr, &backwards, &searchable);
248 done = user_init(rc, nslots, backwards);
251 if (searchlabel != NULL)
253 dbprintf(("changer_find: looking for %s changer is searchable = %d\n",
254 searchlabel, searchable));
256 dbprintf(("changer_find: looking for NULL changer is searchable = %d\n",
260 if ((searchlabel!=NULL) && searchable && !done){
261 rc=changer_search(searchlabel,&curslotstr,&device);
263 done = user_slot(rc,curslotstr,device);
269 while(!done && checked < nslots) {
270 rc = changer_loadslot(slotstr, &curslotstr, &device);
272 done = user_slot(rc, curslotstr, device);
274 done = user_slot(0, curslotstr, device);
283 /* ---------------------------- */
285 void changer_current(user_init, user_slot)
286 int (*user_init) P((int rc, int nslots, int backwards));
287 int (*user_slot) P((int rc, char *slotstr, char *device));
289 char *device = NULL, *curslotstr = NULL;
290 int nslots, backwards, rc, done;
292 rc = changer_info(&nslots, &curslotstr, &backwards);
293 done = user_init(rc, nslots, backwards);
296 rc = changer_loadslot("current", &curslotstr, &device);
298 done = user_slot(rc, curslotstr, device);
300 done = user_slot(0, curslotstr, device);
306 /* ---------------------------- */
308 static int changer_command(cmd, arg)
313 amwait_t wait_exitcode;
315 char num1[NUM_STR_SIZE];
316 char num2[NUM_STR_SIZE];
318 pid_t pid, changer_pid;
320 if (*tapechanger != '/') {
321 tapechanger = vstralloc(libexecdir, "/", tapechanger, versionsuffix(),
323 malloc_mark(tapechanger);
325 cmdstr = vstralloc(tapechanger, " ",
331 fprintf(stderr, "changer: opening pipe to: %s\n", cmdstr);
335 amfree(changer_resultstr);
337 if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd) == -1) {
338 changer_resultstr = vstralloc ("<error> ",
339 "could not create pipe for \"",
347 if(fd[0] < 0 || fd[0] >= FD_SETSIZE) {
348 ap_snprintf(num1, sizeof(num1), "%d", fd[0]);
349 ap_snprintf(num2, sizeof(num2), "%d", FD_SETSIZE-1);
350 changer_resultstr = vstralloc ("<error> ",
351 "could not create pipe for \"",
354 "socketpair 0: descriptor ",
356 " out of range ( .. ",
363 if(fd[1] < 0 || fd[1] >= FD_SETSIZE) {
364 ap_snprintf(num1, sizeof(num1), "%d", fd[1]);
365 ap_snprintf(num2, sizeof(num2), "%d", FD_SETSIZE-1);
366 changer_resultstr = vstralloc ("<error> ",
367 "could not create pipe for \"",
370 "socketpair 1: descriptor ",
372 " out of range ( .. ",
380 switch(changer_pid = fork()) {
382 changer_resultstr = vstralloc ("<error> ",
383 "could not fork for \"",
391 if(dup2(fd[1], 1) == -1 || dup2(fd[1], 2) == -1) {
392 changer_resultstr = vstralloc ("<error> ",
393 "could not open pipe to \"",
398 (void)write(fd[1], changer_resultstr, strlen(changer_resultstr));
403 if(config_dir && chdir(config_dir) == -1) {
404 changer_resultstr = vstralloc ("<error> ",
405 "could not cd to \"",
410 (void)write(2, changer_resultstr, strlen(changer_resultstr));
414 execle(tapechanger, tapechanger, cmd, arg, NULL, safe_env());
416 execle(tapechanger, tapechanger, cmd, NULL, safe_env());
418 changer_resultstr = vstralloc ("<error> ",
424 (void)write(2, changer_resultstr, strlen(changer_resultstr));
430 if((changer_resultstr = areads(fd[0])) == NULL) {
431 changer_resultstr = vstralloc ("<error> ",
432 "could not read result from \"",
434 errno ? "\": " : "\"",
435 errno ? strerror(errno) : "",
440 if ((pid = wait(&wait_exitcode)) == -1) {
444 changer_resultstr = vstralloc ("<error> ",
453 } else if (pid != changer_pid) {
454 ap_snprintf(num1, sizeof(num1), "%ld", (long)pid);
455 changer_resultstr = vstralloc ("<error> ",
458 "\" returned unexpected pid ",
468 /* mark out-of-control changers as fatal error */
469 if(WIFSIGNALED(wait_exitcode)) {
470 ap_snprintf(num1, sizeof(num1), "%d", WTERMSIG(wait_exitcode));
471 changer_resultstr = newvstralloc (changer_resultstr,
474 " (got signal ", num1, ")",
478 exitcode = WEXITSTATUS(wait_exitcode);
486 dbprintf(("changer: got exit: %d str: %s\n", exitcode, changer_resultstr));
493 /* This function commands the changerscript to look for a tape named
494 searchlabel. If is found, the changerscript answers with the device,
495 in which the tape can be accessed.
497 int changer_search(searchlabel, outslotstr, devicename)
498 char *searchlabel, **outslotstr, **devicename;
503 dbprintf(("changer_search: %s\n",searchlabel));
504 rc = run_changer_command("-search", searchlabel, outslotstr, &rest);
507 if(*rest == '\0') return report_bad_resultstr();
509 *devicename = newstralloc(*devicename, rest);
513 /* Because barcodelabel are short, and may not be the same as the
514 amandalabels, the changerscript should be informed, which tapelabel
515 is associated with a tape. This function should be called after
516 giving a label for a tape. (Maybe also, when the label and the associated
517 slot is known. e.g. during library scan.
519 int changer_label (slotsp,labelstr)
526 char *curslotstr = NULL;
527 int nslots, backwards, searchable;
529 dbprintf(("changer_label: %s for slot %s\n",labelstr,slotsp));
530 rc = changer_query(&nslots, &curslotstr, &backwards,&searchable);
533 if ((rc == 0) && (searchable == 1)){
534 dbprintf(("changer_label: calling changer -label %s\n",labelstr));
535 rc = run_changer_command("-label", labelstr, &slotstr, &rest);