#include #include #include #include #include #include #include #include #include #define NARGS 64 int pipefd[2]; int execute(char **, char *, char *); int executepipe(char **, char **, char *, char *); int exit(int); int main(void) { char **cp; int n, status; char command[BUFSIZ]; char *infile, *outfile; char *args1[NARGS]; char **args2; int piping = 0; n=bufsplit(" \t\n", 0, NULL); for (;;) { args2 = args1; printf("pash: "); if (fgets(command, sizeof(command), stdin) == NULL) { putchar('\n'); exit(0); } n = bufsplit(command, NARGS, args1); args1[n] = NULL; if (**args1 == '\0') continue; infile = NULL; outfile = NULL; for (cp = args1; *cp != NULL; cp++) { if (strcmp(*cp, "<") == 0) { *cp++ = NULL; infile = *cp; } else if (strcmp(*cp, ">") == 0) { *cp++ = NULL; outfile = *cp; } else if (strcmp(*cp, "|") == 0) { *cp++ = NULL; args2 = cp; piping = 1; } } if (!piping) status = execute(args1, infile, outfile); else status = executepipe(args1, args2, infile, outfile); } } /* * execute - execute a command, possibly with input/output redirection */ int execute(char **args, char *infile, char *outfile) { int status; pid_t p, pid; int infd, outfd; extern int errno; infd = -1; outfd = -1; /* * If an input file was given, open it. */ if (infile != NULL) { if ((infd = open(infile, O_RDONLY)) < 0) { perror(infile); return (-1); } } /* * If an output file was given, create it. */ if (outfile != NULL) { if ((outfd = creat(outfile, 0666)) < 0) { perror(outfile); close(infd); return (-1); } } /* * Ignore keyboard signals; and SIG_CHLD signals. */ signal(SIGINT, SIG_IGN); signal(SIGQUIT, SIG_IGN); signal(SIGCHLD, SIG_IGN); /* * 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. */ signal(SIGINT, SIG_DFL); signal(SIGQUIT, SIG_DFL); signal(SIGCHLD, SIG_DFL); /* * Perform output redirection. */ if (infd > 0) { dup2(infd, 0); close(infd); } if (outfd > 0) { dup2(outfd, 1); close(outfd); } /* * Execute the command. */ execvp(*args, args); perror("exec"); _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. */ signal(SIGINT, SIG_DFL); signal(SIGQUIT, SIG_DFL); signal(SIGCHLD, SIG_DFL); /* * Close file descriptors. */ close(outfd); close(infd); /* * Return the child process' termination status. */ return (status); } int executepipe(char **args1, char **args2, char *infile, char *outfile) { int status; pid_t p, pid1, pid2; int infd, outfd; extern int errno; infd = -1; outfd = -1; if (infile != NULL) { if ((infd = open(infile, O_RDONLY)) < 0) { perror(infile); return (-1); } } if (outfile != NULL) { if ((outfd = creat(outfile, 0666)) < 0) { perror(outfile); close(infd); return (-1); } } signal(SIGINT, SIG_IGN); signal(SIGQUIT, SIG_IGN); signal(SIGCHLD, SIG_IGN); pipe(pipefd); pid2 = fork(); if (pid2 == 0) { signal(SIGINT, SIG_DFL); signal(SIGQUIT, SIG_DFL); signal(SIGCHLD, SIG_DFL); if (outfd > 0) { dup2(outfd, 1); close(outfd); } dup2(pipefd[0], 0); close(pipefd[0]); close(pipefd[1]); execvp(*args2, args2); exit(0); } else { pid1 == fork(); if (pid1 == 0) { signal(SIGINT, SIG_DFL); signal(SIGQUIT, SIG_DFL); signal(SIGCHLD, SIG_DFL); dup2(pipefd[1], 1); close(pipefd[1]); close(pipefd[0]); if (infd > 0) { dup2(infd, 0); close(infd); } execvp(*args1, args1); exit(0); } else { close(pipefd[0]); close(pipefd[1]); close(outfd); close(infd); while (waitpid(pid2, &status, 0) < 0) { if (errno != EINTR) { status = -1; break; } } } signal(SIGINT, SIG_DFL); signal(SIGQUIT, SIG_DFL); signal(SIGCHLD, SIG_DFL); return (status); } int bufsplit(char *buf, int n, char **a) { int i, nsplit; static char *splitch = "\t\n"; if (buf != NULL && n == 0) { splitch = buf; return (1); } nsplit = 0; while (nsplit < n) { a[nsplit++] = buf; if ((buf = strpbrk(buf, splitch)) == NULL) break; *(buf++) = '\0'; if (*buf == '\0') break; } buf = strrchr(a[nsplit - 1], '\0'); for (i = nsplit; i < n; i++) a[i] = buf; return (nsplit); }