1 /* process.c
2 *
3 * Copyright (C) 2008 Till Kamppeter <till.kamppeter@gmail.com>
4 * Copyright (C) 2008 Lars Uebernickel <larsuebernickel@gmx.de>
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
32 int kidgeneration = 0;
33
34 struct process {
35 char name[64];
36 pid_t pid;
37 int isgroup;
38 };
39
40 #define MAX_CHILDS 4
41 struct process procs[MAX_CHILDS] = {
42 { "", -1, 0 },
43 { "", -1, 0 },
44 { "", -1, 0 },
45 { "", -1, 0 }
46 };
47
add_process(const char * name,int pid,int isgroup)48 void add_process(const char *name, int pid, int isgroup)
49 {
50 int i;
51 for (i = 0; i < MAX_CHILDS; i++) {
52 if (procs[i].pid == -1) {
53 strlcpy(procs[i].name, name, 64);
54 procs[i].pid = pid;
55 procs[i].isgroup = isgroup;
56 return;
57 }
58 }
59 rip_die(EXIT_PRNERR_NORETRY_BAD_SETTINGS, "Didn't think there would be that many child processes... Exiting.\n");
60 }
61
find_process(int pid)62 int find_process(int pid)
63 {
64 int i;
65 for (i = 0; i < MAX_CHILDS; i++)
66 if (procs[i].pid == pid)
67 return i;
68 return -1;
69 }
70
clear_proc_list()71 void clear_proc_list()
72 {
73 int i;
74 for (i = 0; i < MAX_CHILDS; i++)
75 procs[i].pid = -1;
76 }
77
kill_all_processes()78 void kill_all_processes()
79 {
80 int i;
81
82 for (i = 0; i < MAX_CHILDS; i++) {
83 if (procs[i].pid == -1)
84 continue;
85 _log("Killing %s\n", procs[i].name);
86 kill(procs[i].isgroup ? -procs[i].pid : procs[i].pid, 15);
87 sleep(1 << (3 - kidgeneration));
88 kill(procs[i].isgroup ? -procs[i].pid : procs[i].pid, 9);
89 }
90 clear_proc_list();
91 }
92
_start_process(const char * name,int (* proc_func)(FILE *,FILE *,void *),void * user_arg,FILE ** pipe_in,FILE ** pipe_out,int createprocessgroup)93 static int _start_process(const char *name,
94 int (*proc_func)(FILE *, FILE *, void *),
95 void *user_arg, FILE **pipe_in, FILE **pipe_out,
96 int createprocessgroup)
97 {
98 pid_t pid;
99 int pfdin[2], pfdout[2];
100 int ret;
101 FILE *in, *out;
102
103 if (pipe_in)
104 pipe(pfdin);
105 if (pipe_out)
106 pipe(pfdout);
107
108 _log("Starting process \"%s\" (generation %d)\n", name, kidgeneration +1);
109
110 pid = fork();
111 if (pid < 0) {
112 _log("Could not fork for %s\n", name);
113 if (pipe_in) {
114 close(pfdin[0]);
115 close(pfdin[1]);
116 }
117 if (pipe_out) {
118 close(pfdout[0]);
119 close(pfdout[1]);
120 }
121 return -1;
122 }
123
124 if (pid == 0) { /* Child */
125 if (pipe_in) {
126 close(pfdin[1]);
127 in = fdopen(pfdin[0], "r");
128 }
129 else
130 in = NULL;
131
132 if (pipe_out) {
133 close(pfdout[0]);
134 out = fdopen(pfdout[1], "w");
135 }
136 else
137 out = NULL;
138
139 if (createprocessgroup)
140 setpgid(0, 0);
141
142 kidgeneration++;
143
144 /* The subprocess list is only valid for the parent. Clear it. */
145 clear_proc_list();
146
147 ret = proc_func(in, out, user_arg);
148 exit(ret);
149 }
150
151 /* Parent */
152 if (pipe_in) {
153 close(pfdin[0]);
154 *pipe_in = fdopen(pfdin[1], "w");
155 if (!*pipe_in)
156 _log("fdopen: %s\n", strerror(errno));
157 }
158 if (pipe_out) {
159 close(pfdout[1]);
160 *pipe_out = fdopen(pfdout[0], "r");
161 if (!*pipe_out)
162 _log("fdopen: %s\n", strerror(errno));
163 }
164
165 /* Add the child process to the list of open processes (to be able to kill
166 * them in case of a signal. */
167 add_process(name, pid, createprocessgroup);
168
169 return pid;
170 }
171
exec_command(FILE * in,FILE * out,void * cmd)172 int exec_command(FILE *in, FILE *out, void *cmd)
173 {
174 if (in && dup2(fileno(in), fileno(stdin)) < 0)
175 rip_die(EXIT_PRNERR_NORETRY_BAD_SETTINGS, "%s: Could not dup stdin\n", (const char *)cmd);
176 if (out && dup2(fileno(out), fileno(stdout)) < 0)
177 rip_die(EXIT_PRNERR_NORETRY_BAD_SETTINGS, "%s: Could not dup stdout\n", (const char *)cmd);
178
179 execl(get_modern_shell(), get_modern_shell(), "-c", (const char *)cmd, (char *)NULL);
180
181 _log("Error: Executing \"%s -c %s\" failed (%s).\n", get_modern_shell(), (const char *)cmd, strerror(errno));
182 return EXIT_PRNERR_NORETRY_BAD_SETTINGS;
183 }
184
start_system_process(const char * name,const char * command,FILE ** fdin,FILE ** fdout)185 int start_system_process(const char *name, const char *command, FILE **fdin, FILE **fdout)
186 {
187 return _start_process(name, exec_command, (void*)command, fdin, fdout, 1);
188 }
189
start_process(const char * name,int (* proc_func)(FILE *,FILE *,void *),void * user_arg,FILE ** fdin,FILE ** fdout)190 int start_process(const char *name, int (*proc_func)(FILE *, FILE *, void *), void *user_arg, FILE **fdin, FILE **fdout)
191 {
192 return _start_process(name, proc_func, user_arg, fdin, fdout, 0);
193 }
194
wait_for_process(int pid)195 int wait_for_process(int pid)
196 {
197 int i;
198 int status;
199
200 i = find_process(pid);
201 if (i < 0) {
202 _log("No such process \"%d\"", pid);
203 return -1;
204 }
205
206 waitpid(procs[i].pid, &status, 0);
207 if (WIFEXITED(status))
208 _log("%s exited with status %d\n", procs[i].name, WEXITSTATUS(status));
209 else if (WIFSIGNALED(status))
210 _log("%s received signal %d\n", procs[i].name, WTERMSIG(status));
211
212 /* remove from process list */
213 procs[i].pid = -1;
214 return status;
215 }
216
run_system_process(const char * name,const char * command)217 int run_system_process(const char *name, const char *command)
218 {
219 int pid = start_system_process(name, command, NULL, NULL);
220 return wait_for_process(pid);
221 }
222
223