]> git.itanic.dy.fi Git - rrdd/blob - process.c
process.c: Remove the rest of the printf() calls
[rrdd] / process.c
1 #include <unistd.h>
2 #include <sys/select.h>
3
4 #include "process.h"
5 #include "debug.h"
6
7 static int child_count = 0;
8 static int parent_count = 0;
9 static int process_count = 0;
10
11 int get_child_count(void)
12 {
13         return child_count;
14 }
15
16 int get_parent_count(void)
17 {
18         return parent_count;
19 }
20
21 int do_fork(void)
22 {
23         int child;
24         child = fork();
25         if (child < 0) {
26                 pr_err("fork() failed: %m\n");
27                 return -1;
28         }
29
30         if (child) {
31                 child_count++;
32                 pr_info("Fork %d, child %d\n", child_count, child);
33                 return child;
34         }
35
36         /* reset child's child count */
37         child_count = 0;
38         parent_count++;
39         return 0;
40 }
41
42 int harvest_zombies(int pid)
43 {
44         int status;
45
46         if (child_count == 0)
47                 return 0;
48
49         if (pid)
50                 pr_info("Waiting on pid %d, children left: %d\n", pid, 
51                         child_count);
52
53         pid = waitpid(pid, &status, 0);
54         if (pid < 0) {
55                 pr_err("Error on wait(): %m\n");
56                 child_count--; /* Decrement child count anyway */
57         }
58         else {
59                 child_count--;
60                 pr_info("pid %d: exit code %d. Children left: %d\n", pid,
61                         status, child_count);
62         }
63
64         return 1;
65 }
66
67 /*
68  * Runs a command cmd with params argv, connects stdin and stdout to
69  * readfd and writefd
70  *
71  * Returns the pid of the executed process
72  */
73 int run_piped(const char *cmd, char *const argv[],
74               int *stdinfd, int *stdoutfd, int *stderrfd)
75 {
76         int ifd[2], ofd[2], efd[2], pid;
77
78         pr_info("Running command %s\n", cmd);
79
80         if (stdinfd && pipe(ifd)) {
81                 pr_err("pipe() failed: %m\n");
82                 return -1;
83         }
84
85         if (stdoutfd && pipe(ofd)) {
86                 pr_err("pipe() failed: %m\n");
87                 return -1;
88         }
89
90         if (stderrfd && pipe(efd)) {
91                 pr_err("pipe() failed: %m\n");
92                 return -1;
93         }
94
95         pid = do_fork();
96         if (pid) { /* Parent side */
97                 if (stdinfd) {
98                         close(ifd[0]);
99                         *stdinfd = ifd[0];
100                 }
101
102                 if (stdoutfd) {
103                         close(ofd[1]);
104                         *stdoutfd = ofd[0];
105                 }
106
107                 if (stderrfd) {
108                         close(efd[1]);
109                         *stderrfd = efd[0];
110                 }
111
112                 return pid;
113         }
114
115         if (stdinfd) {
116                 close(ifd[1]);
117                 dup2(ifd[0], STDIN_FILENO);
118         }
119
120         if (stdoutfd) {
121                 close(ofd[0]);
122                 dup2(ofd[1], STDOUT_FILENO);
123         }
124
125         if (stderrfd) {
126                 close(efd[0]);
127                 dup2(efd[1], STDERR_FILENO);
128         }
129
130         /* Now we have redirected standard streams to parent process */
131         execvp(cmd, argv);
132         pr_err("Failed to execv command %s: %m\n", cmd);
133         exit(1);
134
135         return 0;
136 }
137
138 /*
139  * Runs a command cmd with params argv, connects stdin and stdout to
140  * readfd and writefd
141  *
142  * Returns the pid of the executed process
143  */
144 int run_piped_stream(const char *cmd, char *const argv[],
145                      FILE **stdinf, FILE **stdoutf, FILE **stderrf)
146 {
147         int ifd, ofd, efd, pid;
148         int *i, *o, *e;
149
150         if (stdinf)
151                 i = &ifd;
152         else 
153                 i = 0;
154         if (stdoutf)
155                 o = &ofd;
156         else 
157                 o = 0;
158         if (stderrf)
159                 e = &efd;
160         else 
161                 e = 0;
162
163         pid = run_piped(cmd, argv, i, o, e);
164
165         if (stdinf) {
166                 *stdinf = fdopen(ifd, "r");
167                 if (*stdinf == NULL) {
168                         pr_err("Error opening file stream for fd %d: %m\n",
169                                ifd);
170                         return -1;
171                 }
172         }
173
174         if (stdoutf) {
175                 *stdoutf = fdopen(ofd, "r");
176                 if (*stdoutf == NULL) {
177                         pr_err("Error opening file stream for fd %d: %m\n",
178                                ofd);
179                         return -1;
180                 }
181         }
182
183         if (stderrf) {
184                 *stderrf = fdopen(efd, "r");
185                 if (*stderrf == NULL) {
186                         pr_err("Error opening file stream for fd %d: %m\n",
187                                efd);
188                         return -1;
189                 }
190         }
191
192         return pid;
193 }
194
195 /*
196  * Forks a child and executes a command to run on parallel
197  */
198
199 #define max(a,b) (a) < (b) ? (b) : (a)
200 #define BUF_SIZE (128*1024)
201 int run(const char *cmd, char *const argv[])
202 {
203         int child, error;
204         int ofd, efd;
205         fd_set rfds;
206         int maxfd;
207         int eof = 0;
208         char stdoutstr[32], stderrstr[32], indent[16] = { "                " };
209
210         indent[get_parent_count() + 1] = 0;
211                 
212         if ((child = do_fork()))
213             return child;
214
215         child = run_piped(cmd, argv, NULL, &ofd, &efd);
216         snprintf(stdoutstr, 32, "%sstdout", green_color);
217         snprintf(stderrstr, 32, "%sstderr", red_color);
218
219         FD_ZERO(&rfds);
220         FD_SET(ofd, &rfds);
221         FD_SET(efd, &rfds);
222
223         while (!eof) {
224                 char *sptr , *eptr;
225                 char rbuf[BUF_SIZE];
226                 int bytes;
227                 char *typestr;
228
229                 maxfd = max(ofd, efd);
230                 error = select(maxfd, &rfds, NULL, NULL, NULL);
231
232                 if (error < 0) {
233                         pr_err("Error with select: %m\n");
234                         break;
235                 }
236
237                 if (FD_ISSET(ofd, &rfds)) {
238                         typestr = stdoutstr;
239                         bytes = read(ofd, rbuf, BUF_SIZE);
240                         goto print;
241                 }
242
243                 if (FD_ISSET(efd, &rfds)) {
244                         typestr = stderrstr;
245                         bytes = read(efd, rbuf, BUF_SIZE);
246                         goto print;
247                 }
248
249                 pr_err("select() returned unknown fd\n");
250                 break;
251
252 print:
253                 if (bytes < 0) {
254                         pr_err("read() failed: %m\n");
255                         break;
256                 }
257
258                 /*
259                  * Workaround: When a process had die and it has only
260                  * written to stderr, select() doesn't indicate that
261                  * there might be something to read in stderr fd. To
262                  * work around this issue, we try to read stderr just
263                  * in case in order to ensure everything gets read.
264                  */
265                 if (bytes == 0) {
266                         bytes = read(efd, rbuf, BUF_SIZE);
267                         typestr = stderrstr;
268                         eof = 1;
269                 }
270
271                 sptr = eptr = rbuf;
272                 while(bytes--) {
273                         if (*eptr == '\n') {
274                                 *eptr = 0;
275                                 fprintf(stderr, "%s[%5d %s] %s: %s%s\n", indent,
276                                        child, cmd, typestr, sptr, normal_color);
277                                 sptr = eptr;
278                         }
279                         eptr++;
280                 }
281         }
282
283         close(ofd);
284         close(efd);
285
286         harvest_zombies(child); 
287
288         exit(1);
289         return 0;
290 }