X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=server-src%2Fchanger.c;h=ad9a83224f9c08ab3c357e1eeb1f6dd6a2675a91;hb=2627875b7d18858bc1f9f7652811e4d8c15a23eb;hp=c49319a2ec507abcb45c346424c7af37af6be92c;hpb=94a044f90357edefa6f4ae9f0b1d5885b0e34aee;p=debian%2Famanda diff --git a/server-src/changer.c b/server-src/changer.c index c49319a..ad9a832 100644 --- a/server-src/changer.c +++ b/server-src/changer.c @@ -53,7 +53,9 @@ 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); @@ -63,13 +65,7 @@ static int run_changer_command(char *cmd, char *arg, char **slotstr, char **rest 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; } @@ -78,7 +74,7 @@ report_bad_resultstr(char *cmd) { char *s; - s = vstrallocf(_("badly formed result from changer command %s: \"%s\""), + s = vstrallocf(_(" badly formed result from changer command %s: \"%s\""), cmd, changer_resultstr); amfree(changer_resultstr); changer_resultstr = s; @@ -258,6 +254,7 @@ changer_find( if (rc != 0) { /* Problem with the changer script. Bail. */ g_fprintf(stderr, _("Changer problem: %s\n"), changer_resultstr); + amfree(curslotstr); return; } @@ -324,162 +321,131 @@ changer_current( /* ---------------------------- */ 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( - _(" 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); + _(" could not make pipe: %s"), strerror(errno)); + goto error; } - if(fd[0] < 0 || fd[0] >= (int)FD_SETSIZE) { - changer_resultstr = vstrallocf( - _(" 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( - _(" 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( - _(" could not fork for \"%s\": %s"), - cmdstr, strerror(errno)); - exitcode = 2; - goto done; + _(" 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( - _(" could not open pipe to \"%s\": %s"), - cmdstr, strerror(errno)); - (void)fullwrite(fd[1], changer_resultstr, strlen(changer_resultstr)); - exit(1); + _(" 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( - _(" could not cd to \"%s\": %s"), - config_dir, strerror(errno)); - (void)fullwrite(STDOUT_FILENO, changer_resultstr, strlen(changer_resultstr)); - exit(1); + _(" 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( - _(" could not exec \"%s\": %s"), - tapechanger, strerror(errno)); - (void)fullwrite(STDOUT_FILENO, changer_resultstr, strlen(changer_resultstr)); + _(" 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( - _(" could not read result from \"%s\": Premature end of file, see %s"), - tapechanger, dbfn()); - } else { - changer_resultstr = vstrallocf( - _(" 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( - _(" wait for \"%s\" failed: %s"), - tapechanger, strerror(errno)); - exitcode = 2; - goto done; - } - } else if (pid != changer_pid) { - changer_resultstr = vstrallocf( - _(" 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, - _(" %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(" 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(" 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(" 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);