int dna_helper_start() { if (!config.dna.helper.executable[0]) { /* Check if we have a helper configured. If not, then set dna_helper_pid to magic value of 0 so that we don't waste time in future looking up the dna helper configuration value. */ INFO("DNAHELPER none configured"); dna_helper_pid = 0; return 0; } if (!my_subscriber) return WHY("Unable to lookup my SID"); const char *mysid = alloca_tohex_sid_t(my_subscriber->sid); dna_helper_close_pipes(); int stdin_fds[2], stdout_fds[2], stderr_fds[2]; if (pipe(stdin_fds) == -1) return WHY_perror("pipe"); if (pipe(stdout_fds) == -1) { WHY_perror("pipe"); close(stdin_fds[0]); close(stdin_fds[1]); return -1; } if (pipe(stderr_fds) == -1) { WHY_perror("pipe"); close(stdin_fds[0]); close(stdin_fds[1]); close(stdout_fds[0]); close(stdout_fds[1]); return -1; } // Construct argv[] for execv() and log messages. const char *argv[config.dna.helper.argv.ac + 2]; argv[0] = config.dna.helper.executable; unsigned i; for (i = 0; i < config.dna.helper.argv.ac; ++i) argv[i + 1] = config.dna.helper.argv.av[i].value; argv[i + 1] = NULL; strbuf argv_sb = strbuf_append_argv(strbuf_alloca(1024), config.dna.helper.argv.ac + 1, argv); switch (dna_helper_pid = fork()) { case 0: /* Child, should exec() to become helper after installing file descriptors. */ close_log_file(); setenv("MYSID", mysid, 1); signal(SIGTERM, SIG_DFL); close(stdin_fds[1]); close(stdout_fds[0]); close(stderr_fds[0]); if (dup2(stderr_fds[1], 2) == -1 || dup2(stdout_fds[1], 1) == -1 || dup2(stdin_fds[0], 0) == -1) { LOG_perror(LOG_LEVEL_FATAL, "dup2"); _exit(-1); } { execv(config.dna.helper.executable, (char **)argv); LOGF_perror(LOG_LEVEL_FATAL, "execv(%s, [%s])", alloca_str_toprint(config.dna.helper.executable), strbuf_str(argv_sb) ); } do { _exit(-1); } while (1); break; case -1: /* fork failed */ WHY_perror("fork"); close(stdin_fds[0]); close(stdin_fds[1]); close(stdout_fds[0]); close(stdout_fds[1]); close(stderr_fds[0]); close(stderr_fds[1]); return -1; default: /* Parent, should put file descriptors into place for use */ close(stdin_fds[0]); close(stdout_fds[1]); close(stderr_fds[1]); dna_helper_started = 0; dna_helper_stdin = stdin_fds[1]; dna_helper_stdout = stdout_fds[0]; dna_helper_stderr = stderr_fds[0]; INFOF("STARTED DNA HELPER pid=%u stdin=%d stdout=%d stderr=%d executable=%s argv=[%s]", dna_helper_pid, dna_helper_stdin, dna_helper_stdout, dna_helper_stderr, alloca_str_toprint(config.dna.helper.executable), strbuf_str(argv_sb) ); sched_replies.poll.fd = dna_helper_stdout; sched_replies.poll.events = POLLIN; sched_errors.poll.fd = dna_helper_stderr; sched_errors.poll.events = POLLIN; sched_requests.poll.fd = -1; sched_requests.poll.events = POLLOUT; sched_harvester.alarm = gettime_ms() + 1000; sched_harvester.deadline = sched_harvester.alarm + 1000; reply_bufend = reply_buffer; discarding_until_nl = 0; awaiting_reply = 0; watch(&sched_replies); watch(&sched_errors); schedule(&sched_harvester); return 0; } return -1; }
int dna_helper_start() { const char *command = confValueGet("dna.helper.executable", NULL); const char *arg = confValueGet("dna.helper.argv.1", NULL); if (!command || !command[0]) { /* Check if we have a helper configured. If not, then set dna_helper_pid to magic value of 0 so that we don't waste time in future looking up the dna helper configuration value. */ INFO("DNAHELPER none configured"); dna_helper_pid = 0; return 0; } if (!my_subscriber) return WHY("Unable to lookup my SID"); const char *mysid = alloca_tohex_sid(my_subscriber->sid); dna_helper_close_pipes(); int stdin_fds[2], stdout_fds[2], stderr_fds[2]; if (pipe(stdin_fds) == -1) return WHY_perror("pipe"); if (pipe(stdout_fds) == -1) { WHY_perror("pipe"); close(stdin_fds[0]); close(stdin_fds[1]); return -1; } if (pipe(stderr_fds) == -1) { WHY_perror("pipe"); close(stdin_fds[0]); close(stdin_fds[1]); close(stdout_fds[0]); close(stdout_fds[1]); return -1; } switch (dna_helper_pid = fork()) { case 0: /* Child, should exec() to become helper after installing file descriptors. */ setenv("MYSID", mysid, 1); set_logging(stderr); signal(SIGTERM, SIG_DFL); close(stdin_fds[1]); close(stdout_fds[0]); close(stderr_fds[0]); if (dup2(stderr_fds[1], 2) == -1 || dup2(stdout_fds[1], 1) == -1 || dup2(stdin_fds[0], 0) == -1) { LOG_perror(LOG_LEVEL_FATAL, "dup2"); fflush(stderr); _exit(-1); } /* XXX: Need the cast on Solaris because it defins NULL as 0L and gcc doesn't * see it as a sentinal */ execl(command, command, arg, (void *)NULL); LOGF_perror(LOG_LEVEL_FATAL, "execl(%s, %s, %s, NULL)", command, command, arg ? arg : "NULL"); fflush(stderr); do { _exit(-1); } while (1); break; case -1: /* fork failed */ WHY_perror("fork"); close(stdin_fds[0]); close(stdin_fds[1]); close(stdout_fds[0]); close(stdout_fds[1]); close(stderr_fds[0]); close(stderr_fds[1]); return -1; default: /* Parent, should put file descriptors into place for use */ close(stdin_fds[0]); close(stdout_fds[1]); close(stderr_fds[1]); dna_helper_started = 0; dna_helper_stdin = stdin_fds[1]; dna_helper_stdout = stdout_fds[0]; dna_helper_stderr = stderr_fds[0]; INFOF("STARTED DNA HELPER pid=%u stdin=%d stdout=%d stderr=%d executable=%s arg=%s", dna_helper_pid, dna_helper_stdin, dna_helper_stdout, dna_helper_stderr, command, arg ? arg : "NULL" ); sched_requests.function = monitor_requests; sched_requests.context = NULL; sched_requests.poll.fd = -1; sched_requests.poll.events = POLLOUT; sched_requests.stats = NULL; sched_timeout.function = reply_timeout; sched_timeout.context = NULL; sched_timeout.stats = NULL; sched_replies.function = monitor_replies; sched_replies.context = NULL; sched_replies.poll.fd = dna_helper_stdout; sched_replies.poll.events = POLLIN; sched_replies.stats = NULL; sched_errors.function = monitor_errors; sched_errors.context = NULL; sched_errors.poll.fd = dna_helper_stderr; sched_errors.poll.events = POLLIN; sched_errors.stats = NULL; sched_harvester.function = harvester; sched_harvester.stats = NULL; sched_harvester.alarm = gettime_ms() + 1000; sched_harvester.deadline = sched_harvester.alarm + 1000; reply_bufend = reply_buffer; discarding_until_nl = 0; awaiting_reply = 0; watch(&sched_replies); watch(&sched_errors); schedule(&sched_harvester); return 0; } return -1; }