Homework 8 Due Tues., Apr. 16 [ This assignment adds to the shell that you built in hw4, and built again in Python in hw6. You can re-use your Python mini-shell, or you can use hw8-minishell.py (in the instructor's directory). ] Add stdin/stdout redirection to myshell. [ Due to limited time, you do not need to implement pipes. ] You should be able to do things like: < myfile wc wc < myfile ls > FILES.txt For extra credit, you may implement pipes sufficient to execute "ls | wc". You must achieve at least 905 to get the extra credit. If you get the extra credit, the grade for this assignment will also replace your lowest homework grade (as well as being averaged into hw8). ==== The example below illustrates stdin, stdout, and pipe. Most of it is about pipes, which is relevant only if you attempt the extra credit. The examples (in C) for redirecting stdin and stdout appear at the end of this example. NOTE: Most of you do not need the material on pipes. This is only for those wishing to attempl to implement pipes in your mini-shell. Under Linux, man pipe provides this example for the pipe command. EXAMPLE The following program creates a pipe, and then fork(2)s to create a child process. After the fork(2), each process closes the descriptors that it doesn't need for the pipe (see pipe(7)). The parent then writes the string contained in the program's command-line argument to the pipe, and the child reads this string a byte at a time from the pipe and echoes it on standard output. #include #include #include #include #include #include int main(int argc, char *argv[]) { int pfd[2]; pid_t cpid; char buf; assert(argc == 2); if (pipe(pfd) == -1) { perror("pipe"); exit(EXIT_FAILURE); } cpid = fork(); if (cpid == -1) { perror("fork"); exit(EXIT_FAILURE); } if (cpid == 0) { /* Child reads from pipe */ close(pfd[1]); /* Close unused write end */ while (read(pfd[0], &buf, 1) > 0) write(STDOUT_FILENO, &buf, 1); write(STDOUT_FILENO, "\n", 1); close(pfd[0]); _exit(EXIT_SUCCESS); } else { /* Parent writes argv[1] to pipe */ close(pfd[0]); /* Close unused read end */ write(pfd[1], argv[1], strlen(argv[1])); close(pfd[1]); /* Reader will see EOF */ wait(NULL); /* Wait for child */ exit(EXIT_SUCCESS); } } ======================================================================= SUGGESTIONS FOR IMPLEMENTATION: (These are suggestions only, not the spec. If you prefer another way to do this, you may do so.) MODIFY getargs(): Change parsing in getargs() to recognize pipe character '|', and stdin and stdout characters, '<' and '>'. The characters '<' and '>' can occur anywhere, and the next word to be read is saved as file_input and file_output. PIPE EXAMPLE: Create the pipe before fork(). Then both parent and children will share it. FIRST PROCESS AND SECOND PROCESS WILL BOTH BE CHILDREN OF myshell PROCESS. DO THE STUFF BELOW AFTER fork(), BUT BEFORE execvp(). FIRST PROCESS: close(STDOUT_FILENO); dup2(pdf[1], STDOUT_FILENO); /* Now any output to stdout goes to pipe. */ SECOND PROCESS: close(STDIN_FILENO); dup2(pdf[0], STDIN_FILENO); /* Now any read from stdin reads from pipe. */ FILE OUTPUT REDIRECT: DO THE STUFF BELOW AFTER fork(), BUT BEFORE execvp(). close(STDOUT_FILENO); /* This causes any output to stdout goes to output_file: see 'man open' */ fd = open("output_file", O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); if (fd == -1) perror("open for writing"); FILE INPUT REDIRECT: DO THE STUFF BELOW AFTER fork(), BUT BEFORE execvp(). close(STDIN_FILENO); /* This causes any input from stdin to comre from input_file: see 'man open' */ fd = open("input_file", O_RDONLY); /* Now any read from stdin reads from input_file. */ if (fd == -1) perror("open for reading");