diff options
author | Didier Raboud <didier@raboud.com> | 2010-05-23 00:07:10 +0200 |
---|---|---|
committer | Didier Raboud <didier@raboud.com> | 2010-05-23 00:07:10 +0200 |
commit | f56211f0ff4ddf9371ebc4c31e8f95df1fc81a5c (patch) | |
tree | a24f15ea2fc96e0688e96c58e35dde7adeaef3fb /process.c | |
parent | b834bd56528993fa05a5645da808227aee3e9de7 (diff) | |
parent | 014f0e14a3c6a044d99a67c8f4e1c4065452479e (diff) |
Merge branch 'upstream'
Conflicts:
debian/README.Debian
debian/changelog
debian/control
debian/copyright
debian/foomatic-filters.config
debian/foomatic-filters.postinst
debian/foomatic-filters.postrm
debian/foomatic-filters.templates
debian/parseconfig.pl
debian/po/de.po
debian/po/fr.po
debian/po/ja.po
debian/po/nl.po
debian/po/pt_BR.po
debian/po/templates.pot
debian/po/tr.po
debian/rules
Diffstat (limited to 'process.c')
-rw-r--r-- | process.c | 200 |
1 files changed, 200 insertions, 0 deletions
diff --git a/process.c b/process.c new file mode 100644 index 0000000..9808cda --- /dev/null +++ b/process.c @@ -0,0 +1,200 @@ + +#include "foomaticrip.h" +#include "process.h" +#include <unistd.h> +#include "util.h" +#include <sys/wait.h> +#include <errno.h> +#include <stdlib.h> + +int kidgeneration = 0; + +struct process { + char name[64]; + pid_t pid; + int isgroup; +}; + +#define MAX_CHILDS 4 +struct process procs[MAX_CHILDS] = { + { "", -1, 0 }, + { "", -1, 0 }, + { "", -1, 0 }, + { "", -1, 0 } +}; + +void add_process(const char *name, int pid, int isgroup) +{ + int i; + for (i = 0; i < MAX_CHILDS; i++) { + if (procs[i].pid == -1) { + strlcpy(procs[i].name, name, 64); + procs[i].pid = pid; + procs[i].isgroup = isgroup; + return; + } + } + rip_die(EXIT_PRNERR_NORETRY_BAD_SETTINGS, "Didn't think there would be that many child processes... Exiting.\n"); +} + +int find_process(int pid) +{ + int i; + for (i = 0; i < MAX_CHILDS; i++) + if (procs[i].pid == pid) + return i; + return -1; +} + +void clear_proc_list() +{ + int i; + for (i = 0; i < MAX_CHILDS; i++) + procs[i].pid = -1; +} + +void kill_all_processes() +{ + int i; + + for (i = 0; i < MAX_CHILDS; i++) { + if (procs[i].pid == -1) + continue; + _log("Killing %s\n", procs[i].name); + kill(procs[i].isgroup ? -procs[i].pid : procs[i].pid, 15); + sleep(1 << (3 - kidgeneration)); + kill(procs[i].isgroup ? -procs[i].pid : procs[i].pid, 9); + } + clear_proc_list(); +} + +static int _start_process(const char *name, + int (*proc_func)(FILE *, FILE *, void *), + void *user_arg, FILE **pipe_in, FILE **pipe_out, + int createprocessgroup) +{ + pid_t pid; + int pfdin[2], pfdout[2]; + int ret; + FILE *in, *out; + + if (pipe_in) + pipe(pfdin); + if (pipe_out) + pipe(pfdout); + + _log("Starting process \"%s\" (generation %d)\n", name, kidgeneration +1); + + pid = fork(); + if (pid < 0) { + _log("Could not fork for %s\n", name); + if (pipe_in) { + close(pfdin[0]); + close(pfdin[1]); + } + if (pipe_out) { + close(pfdout[0]); + close(pfdout[1]); + } + return -1; + } + + if (pid == 0) { /* Child */ + if (pipe_in) { + close(pfdin[1]); + in = fdopen(pfdin[0], "r"); + } + else + in = NULL; + + if (pipe_out) { + close(pfdout[0]); + out = fdopen(pfdout[1], "w"); + } + else + out = NULL; + + if (createprocessgroup) + setpgid(0, 0); + + kidgeneration++; + + /* The subprocess list is only valid for the parent. Clear it. */ + clear_proc_list(); + + ret = proc_func(in, out, user_arg); + exit(ret); + } + + /* Parent */ + if (pipe_in) { + close(pfdin[0]); + *pipe_in = fdopen(pfdin[1], "w"); + if (!*pipe_in) + _log("fdopen: %s\n", strerror(errno)); + } + if (pipe_out) { + close(pfdout[1]); + *pipe_out = fdopen(pfdout[0], "r"); + if (!*pipe_out) + _log("fdopen: %s\n", strerror(errno)); + } + + /* Add the child process to the list of open processes (to be able to kill + * them in case of a signal. */ + add_process(name, pid, createprocessgroup); + + return pid; +} + +int exec_command(FILE *in, FILE *out, void *cmd) +{ + if (in && dup2(fileno(in), fileno(stdin)) < 0) + rip_die(EXIT_PRNERR_NORETRY_BAD_SETTINGS, "%s: Could not dup stdin\n", (const char *)cmd); + if (out && dup2(fileno(out), fileno(stdout)) < 0) + rip_die(EXIT_PRNERR_NORETRY_BAD_SETTINGS, "%s: Could not dup stdout\n", (const char *)cmd); + + execl(get_modern_shell(), get_modern_shell(), "-c", (const char *)cmd, (char *)NULL); + + _log("Error: Executing \"%s -c %s\" failed (%s).\n", get_modern_shell(), (const char *)cmd, strerror(errno)); + return EXIT_PRNERR_NORETRY_BAD_SETTINGS; +} + +int start_system_process(const char *name, const char *command, FILE **fdin, FILE **fdout) +{ + return _start_process(name, exec_command, (void*)command, fdin, fdout, 1); +} + +int start_process(const char *name, int (*proc_func)(FILE *, FILE *, void *), void *user_arg, FILE **fdin, FILE **fdout) +{ + return _start_process(name, proc_func, user_arg, fdin, fdout, 0); +} + +int wait_for_process(int pid) +{ + int i; + int status; + + i = find_process(pid); + if (i < 0) { + _log("No such process \"%d\"", pid); + return -1; + } + + waitpid(procs[i].pid, &status, 0); + if (WIFEXITED(status)) + _log("%s exited with status %d\n", procs[i].name, WEXITSTATUS(status)); + else if (WIFSIGNALED(status)) + _log("%s received signal %d\n", procs[i].name, WTERMSIG(status)); + + /* remove from process list */ + procs[i].pid = -1; + return status; +} + +int run_system_process(const char *name, const char *command) +{ + int pid = start_system_process(name, command, NULL, NULL); + return wait_for_process(pid); +} + |