2 #include <sys/select.h>
7 static int child_count = 0;
8 static int parent_count = 0;
10 int get_child_count(void)
15 int get_parent_count(void)
26 pr_err("fork() failed: %s\n", strerror(error));
32 pr_info("Fork %d, child %d\n", child_count, child);
36 /* reset child's child count */
42 int harvest_zombies(int pid)
50 pr_info("Waiting on pid %d, children left: %d\n", pid,
53 pid = waitpid(pid, &status, 0);
56 pr_err("Error on wait(): %s\n", strerror(error));
57 child_count--; /* Decrement child count anyway */
61 pr_info("pid %d: exit code %d. Children left: %d\n", pid,
69 * Runs a command cmd with params argv, connects stdin and stdout to
72 * Returns the pid of the executed process
74 int run_piped(const char *cmd, char *const argv[],
75 int *stdinfd, int *stdoutfd, int *stderrfd)
77 int ifd[2], ofd[2], efd[2], error, pid;
79 if (stdinfd && pipe(ifd)) {
81 pr_err("pipe() failed: %s\n", strerror(error));
85 if (stdoutfd && pipe(ofd)) {
87 pr_err("pipe() failed: %s\n", strerror(error));
91 if (stderrfd && pipe(efd)) {
93 pr_err("pipe() failed: %s\n", strerror(error));
98 if (pid) { /* Parent side */
119 dup2(ifd[0], STDIN_FILENO);
124 dup2(ofd[1], STDOUT_FILENO);
129 dup2(efd[1], STDERR_FILENO);
132 /* Now we have redirected standard streams to parent process */
135 pr_err("Failed to execv command %s: %s\n", cmd, strerror(error));
142 * Runs a command cmd with params argv, connects stdin and stdout to
145 * Returns the pid of the executed process
147 int run_piped_stream(const char *cmd, char *const argv[],
148 FILE **stdinf, FILE **stdoutf, FILE **stderrf)
150 int ifd, ofd, efd, pid, error;
166 pid = run_piped(cmd, argv, i, o, e);
169 *stdinf = fdopen(ifd, "r");
170 if (*stdinf == NULL) {
172 pr_err("Error opening file stream for fd %d: %s\n",
173 ifd, strerror(error));
179 *stdoutf = fdopen(ofd, "w");
180 if (*stdoutf == NULL) {
182 pr_err("Error opening file stream for fd %d: %s\n",
183 ofd, strerror(error));
189 *stderrf = fdopen(efd, "w");
190 if (*stderrf == NULL) {
192 pr_err("Error opening file stream for fd %d: %s\n",
193 efd, strerror(error));
202 * Forks a child and executes a command to run on parallel
205 #define max(a,b) (a) < (b) ? (b) : (a)
206 #define BUF_SIZE (128*1024)
207 int run(const char *cmd, char *const argv[])
213 char stdoutstr[32], stderrstr[16];
215 if ((child = do_fork()))
218 child = run_piped(cmd, argv, NULL, &ofd, &efd);
219 snprintf(stdoutstr, 32, "%sstdout", green_color);
220 snprintf(stderrstr, 32, "%sstderr", red_color);
228 char rbuf[BUF_SIZE], indent[16] = { ' ' };
232 indent[get_parent_count()] = 0;
234 maxfd = max(ofd, efd);
235 error = select(maxfd, &rfds, NULL, NULL, NULL);
237 if (FD_ISSET(ofd, &rfds)) {
239 bytes = read(ofd, rbuf, BUF_SIZE);
243 if (FD_ISSET(efd, &rfds)) {
245 bytes = read(efd, rbuf, BUF_SIZE);
249 pr_err("select() returned unknown fd\n");
255 pr_err("read() failed: %s\n", strerror(error));
265 printf("%s[%5d %s] %s: %s%s\n", indent,
266 child, cmd, typestr, sptr, normal_color);
273 harvest_zombies(child);