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