#include #include #include #include #include #include #include int shellcmd(char *); void prstat(int); int main(void) { int status; char command[BUFSIZ]; /* * Forever... */ for (;;) { /* * Prompt for a command. */ printf("Enter a command: "); /* * Read a command. If NULL is returned, the * user typed CTRL-D, so exit. */ if (fgets(command, sizeof(command), stdin) == NULL) { putchar('\n'); exit(0); } /* * Strip off the trailing newline character * left by fgets. */ command[strlen(command)-1] = '\0'; /* * Execute the command and print the termination * status. */ status = shellcmd(command); prstat(status); putchar('\n'); } } /* * shellcmd - start a child process, and pass command to the shell. */ int shellcmd(char *command) { int status; pid_t p, pid; extern int errno; sigset_t mask, savemask; struct sigaction ignore, saveint, savequit; /* * Set up a sigaction structure to ignore signals. */ sigemptyset(&ignore.sa_mask); ignore.sa_handler = SIG_IGN; ignore.sa_flags = 0; /* * Ignore keyboard signals; save old dispositions. */ sigaction(SIGINT, &ignore, &saveint); sigaction(SIGQUIT, &ignore, &savequit); /* * Block SIGCHLD. */ sigemptyset(&mask); sigaddset(&mask, SIGCHLD); sigprocmask(SIG_BLOCK, &mask, &savemask); /* * Start a child process. */ if ((pid = fork()) < 0) status = -1; /* * This code executes in the child process. */ if (pid == 0) { /* * Restore signals to their original dispositions, * and restore the signal mask. */ sigaction(SIGINT, &saveint, (struct sigaction *) 0); sigaction(SIGQUIT, &savequit, (struct sigaction *) 0); sigprocmask(SIG_SETMASK, &savemask, (sigset_t *) 0); /* * Execute a shell with the command as argument. */ execl("/bin/sh", "sh", "-c", command, 0); _exit(127); } /* * Wait for the child process to finish. */ while (waitpid(pid, &status, 0) < 0) { /* * EINTR (interrupted system call) is okay; otherwise, * we got some error that we need to report back. */ if (errno != EINTR) { status = -1; break; } } /* * Restore signals to their original dispositions, * and restore the signal mask. */ sigaction(SIGINT, &saveint, (struct sigaction *) 0); sigaction(SIGQUIT, &savequit, (struct sigaction *) 0); sigprocmask(SIG_SETMASK, &savemask, (sigset_t *) 0); /* * Return the child process' termination status. */ return(status); } /* * prstat - decode the termination status. */ void prstat(int status) { if (WIFEXITED(status)) { printf("Process terminated normally, exit status = %d.\n", WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { printf("Process terminated abnormally, signal = %d (%s)", WTERMSIG(status), strsignal(WTERMSIG(status))); if (WCOREDUMP(status)) printf(" -- core file generated.\n"); else printf(".\n"); } else if (WIFSTOPPED(status)) { printf("Process stopped, signal = %d (%s).\n", WSTOPSIG(status), strsignal(WSTOPSIG(status))); } else if (WIFCONTINUED(status)) { printf("Process continued.\n"); } }