Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

C program called minishell that creates two child processes: one to execute \'ls

ID: 3606204 • Letter: C

Question

C program called minishell that creates two child processes: one to execute 'ls' and the other to execute 'sort'. After the forks, the original parent process waits for both child processes to finish before it terminates. The standard output of 'ls' process should be piped to the input to the 'sort' process. Make sure you close the unnecessary open files for the three processes

*The program should fork off 2 children, one for ls and one for sort. The one for ls can have options if desired.

*The program should create a pipe using the pipe function and communications between the children should be through the pipe.

*Each child should use dup2 after the fork to set up the io for the pipe

*Each child should close the unused end of the pipe on its end

*One of the exec methods should be used to replace the code in each child

*The parent should close the unused ends of the pipe and should wait for the children to finish before ending. No output should happen after each child ends

Explanation / Answer

#ifndef STDERR_H_INCLUDED #define STDERR_H_INCLUDED static void err_setarg0(const char *argv0); static void err_sysexit(char const *fmt, ...); static void err_syswarn(char const *fmt, ...); #endif /* STDERR_H_INCLUDED */ /* pipeline.c */ #include #include #include #include #include /*#include "stderr.h"*/ typedef int Pipe[2]; /* exec_nth_command() and exec_pipe_command() are mutually recursive */ static void exec_pipe_command(int ncmds, char ***cmds, Pipe output); /* With the standard output plumbing sorted, execute Nth command */ static void exec_nth_command(int ncmds, char ***cmds) { assert(ncmds >= 1); if (ncmds > 1) { pid_t pid; Pipe input; if (pipe(input) != 0) err_sysexit("Failed to create pipe"); if ((pid = fork()) < 0) err_sysexit("Failed to fork"); if (pid == 0) { /* Child */ exec_pipe_command(ncmds-1, cmds, input); } /* Fix standard input to read end of pipe */ dup2(input[0], 0); close(input[0]); close(input[1]); } execvp(cmds[ncmds-1][0], cmds[ncmds-1]); err_sysexit("Failed to exec %s", cmds[ncmds-1][0]); /*NOTREACHED*/ } /* Given pipe, plumb it to standard output, then execute Nth command */ static void exec_pipe_command(int ncmds, char ***cmds, Pipe output) { assert(ncmds >= 1); /* Fix stdout to write end of pipe */ dup2(output[1], 1); close(output[0]); close(output[1]); exec_nth_command(ncmds, cmds); } /* Execute the N commands in the pipeline */ static void exec_pipeline(int ncmds, char ***cmds) { assert(ncmds >= 1); pid_t pid; if ((pid = fork()) < 0) err_syswarn("Failed to fork"); if (pid != 0) return; exec_nth_command(ncmds, cmds); } /* Collect dead children until there are none left */ static void corpse_collector(void) { pid_t parent = getpid(); pid_t corpse; int status; while ((corpse = waitpid(0, &status, 0)) != -1) { fprintf(stderr, "%d: child %d status 0x%.4X ", (int)parent, (int)corpse, status); } } /* who | awk '{print $1}' | sort | uniq -c | sort -n */ static char *cmd0[] = { "who", 0 }; static char *cmd1[] = { "awk", "{print $1}", 0 }; static char *cmd2[] = { "sort", 0 }; static char *cmd3[] = { "uniq", "-c", 0 }; static char *cmd4[] = { "sort", "-n", 0 }; static char **cmds[] = { cmd0, cmd1, cmd2, cmd3, cmd4 }; static int ncmds = sizeof(cmds) / sizeof(cmds[0]); static void exec_arguments(int argc, char **argv) { /* Split the command line into sequences of arguments */ /* Break at pipe symbols as arguments on their own */ char **cmdv[argc/2]; // Way too many char *args[argc+1]; int cmdn = 0; int argn = 0; cmdv[cmdn++] = &args[argn]; for (int i = 1; i