* file named AUTHORS, in the root directory of this distribution.
*/
/*
- * $Id: changer.c,v 1.29.2.1 2006/04/24 14:43:01 martinea Exp $
+ * $Id: changer.c,v 1.36 2006/08/24 01:57:16 paddy_s Exp $
*
* interface routines for tape changers
*/
int changer_debug = 0;
char *changer_resultstr = NULL;
-static char *tapechanger = NULL;
+static pid_t tpchanger_pid = -1;
+static int tpchanger_stdout = -1;
+static int tpchanger_stdin = -1;
/* local functions */
-static int changer_command P((char *cmd, char *arg));
+static int changer_command(char *cmd, char *arg);
+static int report_bad_resultstr(char *cmd);
+static int run_changer_command(char *cmd, char *arg, char **slotstr, char **rest);
-int changer_init()
+int
+changer_init(void)
{
- tapechanger = getconf_str(CNF_TPCHANGER);
- return strcmp(tapechanger, "") != 0;
+ return strcmp(getconf_str(CNF_TPCHANGER), "") != 0;
}
-static int report_bad_resultstr()
+static int
+report_bad_resultstr(char *cmd)
{
char *s;
- s = vstralloc("badly formed result from changer: ",
- "\"", changer_resultstr, "\"",
- NULL);
+ s = vstrallocf(_("<error> badly formed result from changer command %s: \"%s\""),
+ cmd, changer_resultstr);
amfree(changer_resultstr);
changer_resultstr = s;
return 2;
}
-static int run_changer_command(cmd, arg, slotstr, rest)
-char *cmd;
-char *arg;
-char **slotstr;
-char **rest;
+static int
+run_changer_command(
+ char * cmd,
+ char * arg,
+ char ** slotstr,
+ char ** rest)
{
int exitcode;
char *result_copy;
int ch;
if (slotstr) {
- *slotstr = NULL;
+ *slotstr = NULL;
}
if (rest) {
- *rest = NULL;
+ *rest = NULL;
}
exitcode = changer_command(cmd, arg);
s = changer_resultstr;
ch = *s++;
skip_whitespace(s, ch);
- if(ch == '\0') return report_bad_resultstr();
+ if(ch == '\0') return report_bad_resultstr(cmd);
slot = s - 1;
skip_non_whitespace(s, ch);
s[-1] = '\0';
if (slotstr) {
- *slotstr = newstralloc(*slotstr, slot);
+ *slotstr = newstralloc(*slotstr, slot);
}
- s[-1] = ch;
+ s[-1] = (char)ch;
skip_whitespace(s, ch);
- if(rest) {
- *rest = s - 1;
+ if (rest) {
+ *rest = s - 1;
}
if(exitcode) {
- if(ch == '\0') return report_bad_resultstr();
+ if(ch == '\0') return report_bad_resultstr(cmd);
result_copy = stralloc(s - 1);
amfree(changer_resultstr);
changer_resultstr = result_copy;
return 0;
}
-int changer_reset(slotstr)
-char **slotstr;
+int
+changer_reset(
+ char ** slotstr)
{
char *rest;
return run_changer_command("-reset", (char *) NULL, slotstr, &rest);
}
-int changer_clean(slotstr)
-char **slotstr;
+int
+changer_clean(
+ char ** slotstr)
{
char *rest;
return run_changer_command("-clean", (char *) NULL, slotstr, &rest);
}
-int changer_eject(slotstr)
-char **slotstr;
+int
+changer_eject(
+ char ** slotstr)
{
char *rest;
return run_changer_command("-eject", (char *) NULL, slotstr, &rest);
}
-int changer_loadslot(inslotstr, outslotstr, devicename)
-char *inslotstr, **outslotstr, **devicename;
+int
+changer_loadslot(
+ char *inslotstr,
+ char **outslotstr,
+ char **devicename)
{
char *rest;
int rc;
rc = run_changer_command("-slot", inslotstr, outslotstr, &rest);
if(rc) return rc;
- if(*rest == '\0') return report_bad_resultstr();
+ if(*rest == '\0') return report_bad_resultstr("-slot");
*devicename = newstralloc(*devicename, rest);
return 0;
}
-/* This function is somewhat equal to changer_info with one additional
- parameter, to get information, if the changer is able to search for
- tapelabels himself. E.g. Barcodereader
- The changer_script answers with an additional parameter, if it is able
- to search. This one should be 1, if it is able to search, and 0 if it
- knows about the extension. If the additional answer is omitted, the
- changer is not able to search for a tape.
-*/
-int changer_query(nslotsp, curslotstr, backwardsp, searchable)
-int *nslotsp, *backwardsp, *searchable;
-char **curslotstr;
+
+/*
+ * This function is somewhat equal to changer_info with one additional
+ * parameter, to get information, if the changer is able to search for
+ * tapelabels himself. E.g. Barcodereader
+ * The changer_script answers with an additional parameter, if it is able
+ * to search. This one should be 1, if it is able to search, and 0 if it
+ * knows about the extension. If the additional answer is omitted, the
+ * changer is not able to search for a tape.
+ */
+
+int
+changer_query(
+ int * nslotsp,
+ char ** curslotstr,
+ int * backwardsp,
+ int * searchable)
{
char *rest;
int rc;
rc = run_changer_command("-info", (char *) NULL, curslotstr, &rest);
if(rc) return rc;
- dbprintf(("changer_query: changer return was %s\n",rest));
+ dbprintf(_("changer_query: changer return was %s\n"),rest);
if (sscanf(rest, "%d %d %d", nslotsp, backwardsp, searchable) != 3) {
if (sscanf(rest, "%d %d", nslotsp, backwardsp) != 2) {
- return report_bad_resultstr();
+ return report_bad_resultstr("-info");
} else {
*searchable = 0;
}
}
- dbprintf(("changer_query: searchable = %d\n",*searchable));
+ dbprintf(_("changer_query: searchable = %d\n"),*searchable);
return 0;
}
-int changer_info(nslotsp, curslotstr, backwardsp)
-int *nslotsp, *backwardsp;
-char **curslotstr;
+int
+changer_info(
+ int * nslotsp,
+ char ** curslotstr,
+ int * backwardsp)
{
char *rest;
int rc;
if(rc) return rc;
if (sscanf(rest, "%d %d", nslotsp, backwardsp) != 2) {
- return report_bad_resultstr();
+ return report_bad_resultstr("-info");
}
return 0;
}
/* ---------------------------- */
-/* This function first uses searchlabel and changer_search, if
- the library is able to find a tape itself. If it is not, or if
- the tape could not be found, then the normal scan is done.
-
- See interface documentation in changer.h.
-*/
-void changer_find(user_data, user_init, user_slot, searchlabel)
- void *user_data;
- int (*user_init) P((void *user_data, int rc, int nslots, int backwards,
- int searchable));
- int (*user_slot) P((void *user_data, int rc, char *slotstr,
- char *device));
- char *searchlabel;
+/*
+ * This function first uses searchlabel and changer_search, if
+ * the library is able to find a tape itself. If it is not, or if
+ * the tape could not be found, then the normal scan is done.
+ *
+ * See interface documentation in changer.h.
+ */
+
+void
+changer_find(
+ void * user_data,
+ int (*user_init)(void *, int, int, int, int),
+ int (*user_slot)(void *, int, char *, char *),
+ char * searchlabel)
{
char *slotstr, *device = NULL, *curslotstr = NULL;
int nslots, checked, backwards, rc, done, searchable;
rc = changer_query(&nslots, &curslotstr, &backwards, &searchable);
+
+ if (rc != 0) {
+ /* Problem with the changer script. Bail. */
+ g_fprintf(stderr, _("Changer problem: %s\n"), changer_resultstr);
+ amfree(curslotstr);
+ return;
+ }
+
done = user_init(user_data, rc, nslots, backwards, searchable);
amfree(curslotstr);
if (searchlabel != NULL)
{
- dbprintf(("changer_find: looking for %s changer is searchable = %d\n",
- searchlabel, searchable));
+ dbprintf(_("changer_find: looking for %s changer is searchable = %d\n"),
+ searchlabel, searchable);
} else {
- dbprintf(("changer_find: looking for NULL changer is searchable = %d\n",
- searchable));
+ dbprintf(_("changer_find: looking for NULL changer is searchable = %d\n"),
+ searchable);
}
if ((searchlabel!=NULL) && searchable && !done){
- rc=changer_search(searchlabel,&curslotstr,&device);
+ rc=changer_search(searchlabel, &curslotstr, &device);
if(rc == 0)
- done = user_slot(user_data, rc,curslotstr,device);
+ done = user_slot(user_data, rc, curslotstr, device);
}
slotstr = "current";
/* ---------------------------- */
-void changer_current(user_data, user_init, user_slot)
- void *user_data;
-int (*user_init) P((void *ud, int rc, int nslots, int backwards, int searchable));
-int (*user_slot) P((void *ud, int rc, char *slotstr, char *device));
+void
+changer_current(
+ void * user_data,
+ int (*user_init)(void *, int, int, int, int),
+ int (*user_slot)(void *, int, char *, char *))
{
char *device = NULL, *curslotstr = NULL;
int nslots, backwards, rc, done, searchable;
/* ---------------------------- */
-static int changer_command(cmd, arg)
- char *cmd;
- char *arg;
+static int
+start_chg_glue(void)
{
- int fd[2];
- amwait_t wait_exitcode;
- int exitcode;
- char num1[NUM_STR_SIZE];
- char num2[NUM_STR_SIZE];
- char *cmdstr;
- pid_t pid, changer_pid = 0;
-
- if (*tapechanger != '/') {
- tapechanger = vstralloc(libexecdir, "/", tapechanger, versionsuffix(),
- NULL);
- malloc_mark(tapechanger);
+ int stdin_pipe[2] = { -1, -1 };
+ int stdout_pipe[2] = { -1, -1 };
+ char *chg_glue;
+
+ /* is it already running? */
+ if (tpchanger_pid != -1)
+ return 1;
+
+ if (pipe(stdin_pipe) == -1 || pipe(stdout_pipe) == -1) {
+ changer_resultstr = vstrallocf(
+ _("<error> could not make pipe: %s"), strerror(errno));
+ goto error;
}
- cmdstr = vstralloc(tapechanger, " ",
- cmd, arg ? " " : "",
- arg ? arg : "",
- NULL);
- if(changer_debug) {
- fprintf(stderr, "changer: opening pipe to: %s\n", cmdstr);
- fflush(stderr);
+ switch(tpchanger_pid = fork()) {
+ case -1:
+ changer_resultstr = vstrallocf(
+ _("<error> could not fork: %s"), strerror(errno));
+ goto error;
+
+ case 0:
+ debug_dup_stderr_to_debug();
+ if(dup2(stdin_pipe[0], 0) == -1) {
+ changer_resultstr = vstrallocf(
+ _("<error> could not dup2: %s"), strerror(errno));
+ goto child_err;
+ }
+
+ if(dup2(stdout_pipe[1], 1) == -1) {
+ changer_resultstr = vstrallocf(
+ _("<error> could not dup2: %s"), strerror(errno));
+ goto child_err;
+ }
+ safe_fd(-1, 0);
+
+ chg_glue = g_strdup_printf("%s/chg-glue", amlibexecdir);
+
+ execl(chg_glue, chg_glue, get_config_name(), NULL);
+ changer_resultstr = vstrallocf(
+ _("<error> could not exec \"chg-glue\": %s"), strerror(errno));
+ goto child_err;
+
+child_err:
+ (void)full_write(stdout_pipe[1], changer_resultstr, strlen(changer_resultstr));
+ exit(1);
+
+ default:
+ aclose(stdin_pipe[0]);
+ aclose(stdout_pipe[1]);
+
+ tpchanger_stdout = stdout_pipe[0];
+ tpchanger_stdin = stdin_pipe[1];
+
+ return 1;
}
+error:
+ aclose(stdin_pipe[0]);
+ aclose(stdin_pipe[1]);
+ aclose(stdout_pipe[0]);
+ aclose(stdout_pipe[1]);
+
+ return 0;
+}
+
+static int
+changer_command(
+ char *cmd,
+ char *arg)
+{
+ int exitcode = 0;
+ char *cmdstr = NULL;
+
amfree(changer_resultstr);
- if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd) == -1) {
- changer_resultstr = vstralloc ("<error> ",
- "could not create pipe for \"",
- cmdstr,
- "\": ",
- strerror(errno),
- NULL);
+ if (!start_chg_glue()) {
exitcode = 2;
goto failed;
}
- if(fd[0] < 0 || fd[0] >= FD_SETSIZE) {
- snprintf(num1, sizeof(num1), "%d", fd[0]);
- snprintf(num2, sizeof(num2), "%d", FD_SETSIZE-1);
- changer_resultstr = vstralloc ("<error> ",
- "could not create pipe for \"",
- cmdstr,
- "\": ",
- "socketpair 0: descriptor ",
- num1,
- " out of range ( .. ",
- num2,
- ")",
- NULL);
- exitcode = 2;
- goto done;
- }
- if(fd[1] < 0 || fd[1] >= FD_SETSIZE) {
- snprintf(num1, sizeof(num1), "%d", fd[1]);
- snprintf(num2, sizeof(num2), "%d", FD_SETSIZE-1);
- changer_resultstr = vstralloc ("<error> ",
- "could not create pipe for \"",
- cmdstr,
- "\": ",
- "socketpair 1: descriptor ",
- num1,
- " out of range ( .. ",
- num2,
- ")",
- NULL);
- exitcode = 2;
- goto done;
- }
- switch(changer_pid = fork()) {
- case -1:
- changer_resultstr = vstralloc ("<error> ",
- "could not fork for \"",
- cmdstr,
- "\": ",
- strerror(errno),
- NULL);
- exitcode = 2;
- goto done;
- case 0:
- if(dup2(fd[1], 1) == -1 || dup2(fd[1], 2) == -1) {
- changer_resultstr = vstralloc ("<error> ",
- "could not open pipe to \"",
- cmdstr,
- "\": ",
- strerror(errno),
- NULL);
- (void)fullwrite(fd[1], changer_resultstr, strlen(changer_resultstr));
- exit(1);
- }
- aclose(fd[0]);
- aclose(fd[1]);
- if(config_dir && chdir(config_dir) == -1) {
- changer_resultstr = vstralloc ("<error> ",
- "could not cd to \"",
- config_dir,
- "\": ",
- strerror(errno),
- NULL);
- (void)fullwrite(2, changer_resultstr, strlen(changer_resultstr));
- exit(1);
- }
- if(arg) {
- execle(tapechanger, tapechanger, cmd, arg, NULL, safe_env());
- } else {
- execle(tapechanger, tapechanger, cmd, NULL, safe_env());
- }
- changer_resultstr = vstralloc ("<error> ",
- "could not exec \"",
- tapechanger,
- "\": ",
- strerror(errno),
- NULL);
- (void)fullwrite(2, changer_resultstr, strlen(changer_resultstr));
- exit(1);
- default:
- aclose(fd[1]);
- }
+ cmdstr = vstralloc(cmd,
+ arg ? " " : "",
+ arg ? arg : "",
+ "\n",
+ NULL);
- if((changer_resultstr = areads(fd[0])) == NULL) {
- changer_resultstr = vstralloc ("<error> ",
- "could not read result from \"",
- tapechanger,
- errno ? "\": " : "\"",
- errno ? strerror(errno) : "",
- NULL);
+ g_debug("changer: >> %s %s", cmd, arg? arg : "");
+
+ /* write the command to chg_glue */
+ if (full_write(tpchanger_stdin, cmdstr, strlen(cmdstr)) != strlen(cmdstr)) {
+ changer_resultstr = g_strdup("<error> chg-glue exited unexpectedly");
+ exitcode = 2;
+ goto failed;
}
- while(1) {
- if ((pid = wait(&wait_exitcode)) == -1) {
- if(errno == EINTR) {
- continue;
- } else {
- changer_resultstr = vstralloc ("<error> ",
- "wait for \"",
- tapechanger,
- "\" failed: ",
- strerror(errno),
- NULL);
- exitcode = 2;
- goto done;
- }
- } else if (pid != changer_pid) {
- snprintf(num1, sizeof(num1), "%ld", (long)pid);
- changer_resultstr = vstralloc ("<error> ",
- "wait for \"",
- tapechanger,
- "\" returned unexpected pid ",
- num1,
- NULL);
- exitcode = 2;
- goto done;
- } else {
- break;
- }
+ /* read the first line of the response */
+ changer_resultstr = areads(tpchanger_stdout);
+ if (!changer_resultstr || !*changer_resultstr) {
+ changer_resultstr = g_strdup("<error> unexpected EOF");
+ exitcode = 2;
+ goto failed;
}
+ g_debug("changer: << %s", changer_resultstr);
- /* mark out-of-control changers as fatal error */
- if(WIFSIGNALED(wait_exitcode)) {
- snprintf(num1, sizeof(num1), "%d", WTERMSIG(wait_exitcode));
- changer_resultstr = newvstralloc (changer_resultstr,
- "<error> ",
- changer_resultstr,
- " (got signal ", num1, ")",
- NULL);
+ if (strncmp_const(changer_resultstr, "EXITSTATUS ") != 0) {
+ report_bad_resultstr(cmd);
exitcode = 2;
- } else {
- exitcode = WEXITSTATUS(wait_exitcode);
+ goto failed;
}
-
-done:
- aclose(fd[0]);
- aclose(fd[1]);
+ exitcode = atoi(changer_resultstr + strlen("EXITSTATUS "));
+
+ /* and the second */
+ changer_resultstr = areads(tpchanger_stdout);
+ if (!changer_resultstr) {
+ changer_resultstr = g_strdup("<error> unexpected EOF");
+ exitcode = 2;
+ goto failed;
+ }
+ g_debug("changer: << %s", changer_resultstr);
failed:
- dbprintf(("changer: got exit: %d str: %s\n", exitcode, changer_resultstr));
+ if (exitcode != 0) {
+ g_debug("changer: ERROR %s", changer_resultstr);
+ }
amfree(cmdstr);
return exitcode;
}
-/* This function commands the changerscript to look for a tape named
- searchlabel. If is found, the changerscript answers with the device,
- in which the tape can be accessed.
-*/
-int changer_search(searchlabel, outslotstr, devicename)
-char *searchlabel, **outslotstr, **devicename;
+
+/*
+ * This function commands the changerscript to look for a tape named
+ * searchlabel. If is found, the changerscript answers with the device,
+ * in which the tape can be accessed.
+ */
+
+int
+changer_search(
+ char * searchlabel,
+ char ** outslotstr,
+ char ** devicename)
{
char *rest;
int rc;
- dbprintf(("changer_search: %s\n",searchlabel));
+ dbprintf("changer_search: %s\n",searchlabel);
rc = run_changer_command("-search", searchlabel, outslotstr, &rest);
if(rc) return rc;
- if(*rest == '\0') return report_bad_resultstr();
+ if(*rest == '\0') return report_bad_resultstr("-search");
*devicename = newstralloc(*devicename, rest);
return 0;
}
-/* Because barcodelabel are short, and may not be the same as the
- amandalabels, the changerscript should be informed, which tapelabel
- is associated with a tape. This function should be called after
- giving a label for a tape. (Maybe also, when the label and the associated
- slot is known. e.g. during library scan.
-*/
-int changer_label (slotsp,labelstr)
-char *slotsp;
-char *labelstr;
+
+/*
+ * Because barcodelabel are short, and may not be the same as the
+ * amandalabels, the changerscript should be informed, which tapelabel
+ * is associated with a tape. This function should be called after
+ * giving a label for a tape. (Maybe also, when the label and the associated
+ * slot is known. e.g. during library scan.
+ */
+
+int
+changer_label(
+ char * slotsp,
+ char * labelstr)
{
int rc;
char *rest=NULL;
char *curslotstr = NULL;
int nslots, backwards, searchable;
- dbprintf(("changer_label: %s for slot %s\n",labelstr,slotsp));
+ dbprintf(_("changer_label: %s for slot %s\n"),labelstr,slotsp);
rc = changer_query(&nslots, &curslotstr, &backwards,&searchable);
amfree(curslotstr);
if ((rc == 0) && (searchable == 1)){
- dbprintf(("changer_label: calling changer -label %s\n",labelstr));
+ dbprintf(_("changer_label: calling changer -label %s\n"),labelstr);
rc = run_changer_command("-label", labelstr, &slotstr, &rest);
amfree(slotstr);
}