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