summaryrefslogtreecommitdiff
path: root/process.c
diff options
context:
space:
mode:
authorDidier Raboud <didier@raboud.com>2010-05-23 00:07:10 +0200
committerDidier Raboud <didier@raboud.com>2010-05-23 00:07:10 +0200
commitf56211f0ff4ddf9371ebc4c31e8f95df1fc81a5c (patch)
treea24f15ea2fc96e0688e96c58e35dde7adeaef3fb /process.c
parentb834bd56528993fa05a5645da808227aee3e9de7 (diff)
parent014f0e14a3c6a044d99a67c8f4e1c4065452479e (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.c200
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);
+}
+