CSC 357 Lecture Notes Week 9
Additional Pipe Topics Additional Signal Topics Shells and Programming
Assignment 6
1 /* 2 * This program explores what's going on when dup2 is used to redirect stdout 3 * to a pipe. The key aspect of the exploration is that the normal stdout 4 * stream is closed after the dup2. This means that system calls like printf 5 * do not send data to the normal stdout stream, but rather to the pipe. 6 * 7 * The "normal" stdout stream is the terminal, for programs like this that are 8 * run from a shell. Hence, before the dup2, printf output appears on the 9 * terminal. After dup2, it does not appear on the terminal. 10 * 11 * To be able to restore normal printing, we must save a copy of STDOUT_FILENO 12 * before the dup2. When can then use dup2 again, to copy the saved value back 13 * into STDOUT_FILENO. Subsequently, the stdout stream is restored to its 14 * original value, i.e., the terminal when we're running from a shell. 15 * 16 * See the code comments for further explanatory details. 17 */ 18 19 #include <unistd.h> 20 #include <stdio.h> 21 #include <fcntl.h> 22 #include <string.h> 23 24 int main() { 25 int stdout_save; /* saved copy of stdout fd */ 26 int stdout_open; /* fd for explicitly opened /dev/stdout */ 27 int pfds[2]; /* pipe fds */ 28 FILE* fp; /* file pointer to attempt stdout reopen */ 29 30 /* Print a message explaining what the output should look like. */ 31 printf("\n\ 32 The output that follows should be five lines containing the string\n\ 33 \"Can see this.\"\n\ 34 and no lines containing the string\n\ 35 \"CanNOT see this.\"\n"); 36 37 /* Save a duplicate of STDOUT_FILENO. This will allow the restoration of 38 * writing to the normal stdout stream, via printf and write. */ 39 stdout_save = dup(STDOUT_FILENO); 40 41 /* Get another fd for stdout by explicitly opening /dev/stdout. Note that 42 this only works before STDOUT_FILENO is closed, since after closure, 43 this process does not have permission to open /dev/stdout. */ 44 stdout_open = open("/dev/stdout", 0, 0); 45 46 /* Create a pipe and dup2 stdout onto the pipe's output end. What this 47 does is redirect stdout from its normal location to the pipe. This 48 means that system calls that use stdout will not write to the normal 49 stdout stream, but rather to the pipe. So, for example, a printf from 50 this program will not appear on the terminal, when this program is run 51 from the shell. 52 53 Furthermore, since dup2 closes its second argument, this means that this 54 program cannot write to the normal stdout stream unless the saved stdout 55 descriptor is dup'd back into STDOUT_FILENO. */ 56 pipe(pfds); 57 dup2(pfds[1], STDOUT_FILENO); 58 59 /* At this point, output from printf will not show up on the terminal; 60 rather, it's going to the pipe. Since we're not doing anything with 61 the pipe, it's going in the bit bucket, i.e., nowhere. */ 62 printf("CanNOT see this.\n"); 63 fflush(stdout); 64 65 /* The same goes for output from write. */ 66 write(STDOUT_FILENO, "CanNOT see this.\n", strlen("CanNOT see this.\n")); 67 68 /* Also, confirm that /dev/stdout is not now openable. */ 69 if (open("/dev/stdout", 0, 0) != -1) { 70 fprintf(stderr, "CanNOT see this.\n"); 71 } 72 73 /* If we write explicitly to the saved stdout fd, or to the fd obtained from 74 opening /dev/stdout, output will appear on the normal fd stream, i.e., 75 the terminal if we're running from the shell. */ 76 write(stdout_save, "Can see this.\n", strlen("Can see this.\n")); 77 write(stdout_open, "Can see this.\n", strlen("Can see this.\n")); 78 79 /* We can also do terminal output through a FILE* obtained from fdopen on 80 the saved stdout fd. */ 81 fprintf(fdopen(stdout_save, "w+"), "Can see this.\n"); 82 83 /* If we restore the normal value of STDOUT_FILENO by dup'ing the saved 84 value, printf will now go to the terminal, again assuming we're running 85 from the shell. */ 86 dup2(stdout_save, STDOUT_FILENO); 87 printf("Can see this.\n"); 88 write(STDOUT_FILENO, "Can see this.\n", strlen("Can see this.\n")); 89 90 /* The following code demonstrates that the FILE* named "stdout" is 91 disabled when the STDOUT_FILENO fd is closed or redirected. In 92 particular, an attempt to reopen stdout onto another file pointer will 93 fail. */ 94 dup2(pfds[1], STDOUT_FILENO); 95 write(STDOUT_FILENO, "CanNOT see this.\n", strlen("CanNOT see this.\n")); 96 printf("CanNOT see this.\n"); 97 if ((fp = freopen(NULL, "w+", stdout)) != NULL) { 98 printf("CanNOT see this.\n"); 99 } 100 }
towhile (getchar() != 'q') {}
getchar();
toaction.sa_flags = 0;
action.sa_flags = SA_RESTART;
1 #include <signal.h> 2 #include <setjmp.h> 3 #include <stdlib.h> 4 #include <stdio.h> 5 6 #ifdef SOLARIS 7 typedef void Sigfunc(int); 8 9 Sigfunc* signal(int signo, Sigfunc* func) { 10 struct sigaction act, oact; 11 act.sa_handler = func; 12 sigemptyset(&act.sa_mask); 13 act.sa_flags = 0; 14 if (signo == SIGALRM) { 15 #ifdef SA_INTERRUPT 16 act.sa_flags |= SA_INTERRUPT; 17 #endif 18 } 19 else { 20 #ifdef SA_RESTART 21 act.sa_flags |= SA_RESTART; 22 #endif 23 } 24 if (sigaction(signo, &act, &oact) < 0) { 25 return(SIG_ERR); 26 } 27 return(oact.sa_handler); 28 } 29 #endif 30 31 static sigjmp_buf jbuf; 32 33 void bus_handler(int signum) { 34 printf("Oops, I just bus erred.\n"); 35 siglongjmp(jbuf, 0); 36 } 37 38 void segv_handler(int signum) { 39 printf("Oops, I just seg faulted.\n"); 40 siglongjmp(jbuf, 0); 41 } 42 43 void alrm_handler(int signum) { 44 printf("Got an alarm.\n"); 45 } 46 47 int main(int argc, char** argv) { 48 char* p = 0; 49 char c; 50 51 signal(SIGBUS, bus_handler); 52 signal(SIGSEGV, segv_handler); 53 signal(SIGALRM, alrm_handler); 54 55 if (sigsetjmp(jbuf, 0)) { 56 printf("End of main after error.\n"); 57 printf("exit status: %d\n", EXIT_FAILURE); 58 exit(EXIT_FAILURE); 59 } 60 61 /* 62 * If there is any command-line arg, cause an error. 63 */ 64 if (argc > 1) { 65 c = *p; 66 } 67 68 kill(getpid(), SIGALRM); 69 70 printf("End of main without error.\n"); 71 printf("exit status: %d\n", EXIT_SUCCESS); 72 exit(EXIT_SUCCESS); 73 }
Now onto Programming Assignment 6, which entails the implementation of a very simple shell