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(char *cmd, char *arg);
int
changer_init(void)
{
- if (tapechanger == NULL)
- tapechanger = getconf_str(CNF_TPCHANGER);
- if (*tapechanger != '\0' && *tapechanger != '/') {
- tapechanger = vstralloc(amlibexecdir, "/", tapechanger, versionsuffix(),
- NULL);
- }
- return strcmp(tapechanger, "") != 0;
+ return strcmp(getconf_str(CNF_TPCHANGER), "") != 0;
}
{
char *s;
- s = vstrallocf(_("badly formed result from changer command %s: \"%s\""),
+ s = vstrallocf(_("<error> badly formed result from changer command %s: \"%s\""),
cmd, changer_resultstr);
amfree(changer_resultstr);
changer_resultstr = s;
if (rc != 0) {
/* Problem with the changer script. Bail. */
g_fprintf(stderr, _("Changer problem: %s\n"), changer_resultstr);
+ amfree(curslotstr);
return;
}
/* ---------------------------- */
static int
-changer_command(
- char *cmd,
- char *arg)
+start_chg_glue(void)
{
- int fd[2];
- amwait_t wait_exitcode = 1;
- int exitcode;
- char *cmdstr;
- pid_t pid, changer_pid = 0;
- int fd_to_close[4], *pfd_to_close = fd_to_close;
+ int stdin_pipe[2] = { -1, -1 };
+ int stdout_pipe[2] = { -1, -1 };
+ char *chg_glue;
- cmdstr = vstralloc(tapechanger, " ",
- cmd, arg ? " " : "",
- arg ? arg : "",
- NULL);
-
- if(changer_debug) {
- g_fprintf(stderr, _("changer: opening pipe to: %s\n"), cmdstr);
- fflush(stderr);
- }
+ /* is it already running? */
+ if (tpchanger_pid != -1)
+ return 1;
- amfree(changer_resultstr);
-
- if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd) == -1) {
+ if (pipe(stdin_pipe) == -1 || pipe(stdout_pipe) == -1) {
changer_resultstr = vstrallocf(
- _("<error> could not create pipe for \"%s\": %s"),
- cmdstr, strerror(errno));
- exitcode = 2;
- goto failed;
- }
-
- /* make sure fd[0] > 2 && fd[1] > 2 */
- pfd_to_close = fd_to_close;
- while(fd[0] <= 2) {
- int a = dup(fd[0]);
- *pfd_to_close++ = fd[0];
- fd[0] = a;
- }
- while(fd[1] <= 2) {
- int a = dup(fd[1]);
- *pfd_to_close++ = fd[1];
- fd[1] = a;
- }
- while (pfd_to_close > fd_to_close) {
- close(*--pfd_to_close);
+ _("<error> could not make pipe: %s"), strerror(errno));
+ goto error;
}
- if(fd[0] < 0 || fd[0] >= (int)FD_SETSIZE) {
- changer_resultstr = vstrallocf(
- _("<error> could not create pipe for \"%s\":"
- "socketpair 0: descriptor %d out of range ( 0 .. %d)"),
- cmdstr, fd[0], (int)FD_SETSIZE-1);
- exitcode = 2;
- goto done;
- }
- if(fd[1] < 0 || fd[1] >= (int)FD_SETSIZE) {
- changer_resultstr = vstrallocf(
- _("<error> could not create pipe for \"%s\":"
- "socketpair 1: descriptor %d out of range ( 0 .. %d)"),
- cmdstr, fd[1], (int)FD_SETSIZE-1);
- exitcode = 2;
- goto done;
- }
-
- switch(changer_pid = fork()) {
+ switch(tpchanger_pid = fork()) {
case -1:
changer_resultstr = vstrallocf(
- _("<error> could not fork for \"%s\": %s"),
- cmdstr, strerror(errno));
- exitcode = 2;
- goto done;
+ _("<error> could not fork: %s"), strerror(errno));
+ goto error;
+
case 0:
debug_dup_stderr_to_debug();
- if(dup2(fd[1], 1) == -1) {
+ if(dup2(stdin_pipe[0], 0) == -1) {
changer_resultstr = vstrallocf(
- _("<error> could not open pipe to \"%s\": %s"),
- cmdstr, strerror(errno));
- (void)fullwrite(fd[1], changer_resultstr, strlen(changer_resultstr));
- exit(1);
+ _("<error> could not dup2: %s"), strerror(errno));
+ goto child_err;
}
- aclose(fd[0]);
- aclose(fd[1]);
- if(config_dir && chdir(config_dir) == -1) {
+
+ if(dup2(stdout_pipe[1], 1) == -1) {
changer_resultstr = vstrallocf(
- _("<error> could not cd to \"%s\": %s"),
- config_dir, strerror(errno));
- (void)fullwrite(STDOUT_FILENO, changer_resultstr, strlen(changer_resultstr));
- exit(1);
+ _("<error> could not dup2: %s"), strerror(errno));
+ goto child_err;
}
safe_fd(-1, 0);
- if(arg) {
- execle(tapechanger, tapechanger, cmd, arg, (char *)NULL,
- safe_env());
- } else {
- execle(tapechanger, tapechanger, cmd, (char *)NULL, safe_env());
- }
+
+ 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 \"%s\": %s"),
- tapechanger, strerror(errno));
- (void)fullwrite(STDOUT_FILENO, changer_resultstr, strlen(changer_resultstr));
+ _("<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(fd[1]);
- }
+ aclose(stdin_pipe[0]);
+ aclose(stdout_pipe[1]);
- if((changer_resultstr = areads(fd[0])) == NULL) {
- if (errno == 0) {
- changer_resultstr = vstrallocf(
- _("<error> could not read result from \"%s\": Premature end of file, see %s"),
- tapechanger, dbfn());
- } else {
- changer_resultstr = vstrallocf(
- _("<error> could not read result from \"%s\": %s"),
- tapechanger, strerror(errno));
- }
+ tpchanger_stdout = stdout_pipe[0];
+ tpchanger_stdin = stdin_pipe[1];
+
+ return 1;
}
- while(1) {
- if ((pid = wait(&wait_exitcode)) == -1) {
- if(errno == EINTR) {
- continue;
- } else {
- changer_resultstr = vstrallocf(
- _("<error> wait for \"%s\" failed: %s"),
- tapechanger, strerror(errno));
- exitcode = 2;
- goto done;
- }
- } else if (pid != changer_pid) {
- changer_resultstr = vstrallocf(
- _("<error> wait for \"%s\" returned unexpected pid %ld"),
- tapechanger, (long)pid);
- exitcode = 2;
- goto done;
- } else {
- break;
- }
+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 (!start_chg_glue()) {
+ exitcode = 2;
+ goto failed;
}
- /* mark out-of-control changers as fatal error */
- if(WIFSIGNALED(wait_exitcode)) {
- changer_resultstr = newvstrallocf(changer_resultstr,
- _("<error> %s (got signal %d)"),
- changer_resultstr, WTERMSIG(wait_exitcode));
+ cmdstr = vstralloc(cmd,
+ arg ? " " : "",
+ arg ? arg : "",
+ "\n",
+ 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;
- } else {
- exitcode = WEXITSTATUS(wait_exitcode);
+ goto failed;
+ }
+
+ /* 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);
-done:
- aclose(fd[0]);
- aclose(fd[1]);
+ if (strncmp_const(changer_resultstr, "EXITSTATUS ") != 0) {
+ report_bad_resultstr(cmd);
+ exitcode = 2;
+ goto failed;
+ }
+ 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:
if (exitcode != 0) {
- dbprintf(_("changer: got exit: %d str: %s\n"), exitcode, changer_resultstr);
+ g_debug("changer: ERROR %s", changer_resultstr);
}
amfree(cmdstr);