1 /* process.c
2 *
3 * Copyright (C) 2008 Till Kamppeter <till.kamppeter@gmail.com>
4 * Copyright (C) 2008 Lars Karlitski (formerly Uebernickel) <lars@karlitski.net>
5 *
6 * This file is part of foomatic-rip.
7 *
8 * Foomatic-rip is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * Foomatic-rip is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
22 */
23
24 #include "foomaticrip.h"
25 #include "process.h"
26 #include <unistd.h>
27 #include "util.h"
28 #include <sys/wait.h>
29 #include <errno.h>
30 #include <stdlib.h>
31 #include <signal.h>
32
33 int kidgeneration = 0;
34
35 struct process {
36 char name[64];
37 pid_t pid;
38 int isgroup;
39 };
40
41 #define MAX_CHILDS 4
42 struct process procs[MAX_CHILDS] = {
43 { "", -1, 0 },
44 { "", -1, 0 },
45 { "", -1, 0 },
46 { "", -1, 0 }
47 };
48
add_process(const char * name,int pid,int isgroup)49 void add_process(const char *name, int pid, int isgroup)
50 {
51 int i;
52 for (i = 0; i < MAX_CHILDS; i++) {
53 if (procs[i].pid == -1) {
54 strlcpy(procs[i].name, name, 64);
55 procs[i].pid = pid;
56 procs[i].isgroup = isgroup;
57 return;
58 }
59 }
60 rip_die(EXIT_PRNERR_NORETRY_BAD_SETTINGS, "Didn't think there would be that many child processes... Exiting.\n");
61 }
62
find_process(int pid)63 int find_process(int pid)
64 {
65 int i;
66 for (i = 0; i < MAX_CHILDS; i++)
67 if (procs[i].pid == pid)
68 return i;
69 return -1;
70 }
71
clear_proc_list()72 void clear_proc_list()
73 {
74 int i;
75 for (i = 0; i < MAX_CHILDS; i++)
76 procs[i].pid = -1;
77 }
78
kill_all_processes()79 void kill_all_processes()
80 {
81 int i;
82
83 for (i = 0; i < MAX_CHILDS; i++) {
84 if (procs[i].pid == -1)
85 continue;
86 _log("Killing %s\n", procs[i].name);
87 kill(procs[i].isgroup ? -procs[i].pid : procs[i].pid, 15);
88 sleep(1 << (3 - kidgeneration));
89 kill(procs[i].isgroup ? -procs[i].pid : procs[i].pid, 9);
90 }
91 clear_proc_list();
92 }
93
_start_process(const char * name,int (* proc_func)(FILE *,FILE *,void *),void * user_arg,FILE ** pipe_in,FILE ** pipe_out,int createprocessgroup)94 static pid_t _start_process(const char *name,
95 int (*proc_func)(FILE *, FILE *, void *),
96 void *user_arg, FILE **pipe_in, FILE **pipe_out,
97 int createprocessgroup)
98 {
99 pid_t pid;
100 int pfdin[2], pfdout[2];
101 int ret;
102 FILE *in, *out;
103
104 if (pipe_in)
105 if (pipe(pfdin) < 0)
106 return -1;
107 if (pipe_out)
108 if (pipe(pfdout) < 0)
109 return -1;
110
111 _log("Starting process \"%s\" (generation %d)\n", name, kidgeneration +1);
112
113 pid = fork();
114 if (pid < 0) {
115 _log("Could not fork for %s\n", name);
116 if (pipe_in) {
117 close(pfdin[0]);
118 close(pfdin[1]);
119 }
120 if (pipe_out) {
121 close(pfdout[0]);
122 close(pfdout[1]);
123 }
124 return -1;
125 }
126
127 if (pid == 0) { /* Child */
128
129 // Reset sigpipe behavior to default for all children
130 signal(SIGPIPE, SIG_DFL);
131
132 if (pipe_in) {
133 close(pfdin[1]);
134 in = fdopen(pfdin[0], "r");
135 }
136 else
137 in = NULL;
138
139 if (pipe_out) {
140 close(pfdout[0]);
141 out = fdopen(pfdout[1], "w");
142 }
143 else
144 out = NULL;
145
146 if (createprocessgroup)
147 setpgid(0, 0);
148
149 kidgeneration++;
150
151 /* The subprocess list is only valid for the parent. Clear it. */
152 clear_proc_list();
153
154 ret = proc_func(in, out, user_arg);
155 exit(ret);
156 }
157
158 /* Parent */
159 if (pipe_in) {
160 close(pfdin[0]);
161 *pipe_in = fdopen(pfdin[1], "w");
162 if (!*pipe_in)
163 _log("fdopen: %s\n", strerror(errno));
164 }
165 if (pipe_out) {
166 close(pfdout[1]);
167 *pipe_out = fdopen(pfdout[0], "r");
168 if (!*pipe_out)
169 _log("fdopen: %s\n", strerror(errno));
170 }
171
172 /* Add the child process to the list of open processes (to be able to kill
173 * them in case of a signal. */
174 add_process(name, pid, createprocessgroup);
175
176 return pid;
177 }
178
exec_command(FILE * in,FILE * out,void * cmd)179 int exec_command(FILE *in, FILE *out, void *cmd)
180 {
181 if (in && dup2(fileno(in), fileno(stdin)) < 0)
182 rip_die(EXIT_PRNERR_NORETRY_BAD_SETTINGS, "%s: Could not dup stdin\n", (const char *)cmd);
183 if (out && dup2(fileno(out), fileno(stdout)) < 0)
184 rip_die(EXIT_PRNERR_NORETRY_BAD_SETTINGS, "%s: Could not dup stdout\n", (const char *)cmd);
185
186 execl(get_modern_shell(), get_modern_shell(), "-e", "-c", (const char *)cmd, (char *)NULL);
187
188 _log("Error: Executing \"%s -c %s\" failed (%s).\n", get_modern_shell(), (const char *)cmd, strerror(errno));
189 return EXIT_PRNERR_NORETRY_BAD_SETTINGS;
190 }
191
start_system_process(const char * name,const char * command,FILE ** fdin,FILE ** fdout)192 pid_t start_system_process(const char *name, const char *command, FILE **fdin, FILE **fdout)
193 {
194 return _start_process(name, exec_command, (void*)command, fdin, fdout, 1);
195 }
196
start_process(const char * name,int (* proc_func)(FILE *,FILE *,void *),void * user_arg,FILE ** fdin,FILE ** fdout)197 pid_t start_process(const char *name, int (*proc_func)(FILE *, FILE *, void *), void *user_arg, FILE **fdin, FILE **fdout)
198 {
199 return _start_process(name, proc_func, user_arg, fdin, fdout, 0);
200 }
201
wait_for_process(int pid)202 int wait_for_process(int pid)
203 {
204 int i;
205 int status;
206
207 i = find_process(pid);
208 if (i < 0) {
209 _log("No such process \"%d\"", pid);
210 return -1;
211 }
212
213 waitpid(procs[i].pid, &status, 0);
214 if (WIFEXITED(status))
215 _log("%s exited with status %d\n", procs[i].name, WEXITSTATUS(status));
216 else if (WIFSIGNALED(status))
217 _log("%s received signal %d\n", procs[i].name, WTERMSIG(status));
218
219 /* remove from process list */
220 procs[i].pid = -1;
221 return status;
222 }
223
run_system_process(const char * name,const char * command)224 int run_system_process(const char *name, const char *command)
225 {
226 int pid = start_system_process(name, command, NULL, NULL);
227 return wait_for_process(pid);
228 }
229
230