/* mush.c * by Douglas Jones * a Minimally Usable SHell * augmented with use of $PATH as the search path * augmented with redirection of standard input and output * * comments added only in augmented code. */ /* Note: the logic for envp was not immediately apparent and is * outside the scope of this assignment. Getting it right is * needed to use this shell to launch cc and other utilities that * need to access the environment. */ #include #include #include #include #include #include char command[100]; char *argv[100]; char *infile; /* pointer to input file name, if redirected */ char *outfile; /* pointer to output file name, if redirected */ char *opath; /* pointer to $PATH (the original) */ char *path; /* a copy of the path */ char *patha[100];/* NULL terminated array of pointers to path components */ char **myenvp; /* the environment passed to the main program */ /* as documented in the execve man page */ void getpath(){ /* initialize patha from $PATH */ /* the logic here is cribbed from parseargv */ int i = 0; /* patha index */ int j = 0; /* text index */ opath = getenv( "PATH" ); path = strcpy( malloc( strlen( opath ) + 1 ), opath ); for (;;) { /* no need to skip blanks */ if (path[j] == '\000') break; patha[i] = &path[j]; i++; while ((path[j] != ':') /* path delimiter is colon */ &&(path[j] != '\000')) { j++; } if (path[j] == '\000') break; path[j] = '\000'; j++; } patha[i] = NULL; } void getcommand(){ char ch; int i = 0; putchar('>'); do { ch = getchar(); command[i] = ch; i++; } while (ch != '\n'); command[i-1] = '\000'; } void parseargv(){ /* parse command arguments and find redirected file names, if any */ int i = 0; /* argv index */ int j = 0; /* text index */ infile = NULL; /* no redirection is the default */ outfile = NULL; /* no redirection is the default */ for (;;) { while (command[j] == ' ') j++; if (command[j] == '\000') break; if (command[j] == '>' ) { /* found output redirection */ j++; /* skip over the > and any blanks */ while (command[j] == ' ') j++; if (command[j] != '\000') outfile = &command[j]; } else if (command[j] == '<' ) { /* found input redirection */ j++; /* skip over the < and any blanks */ while (command[j] == ' ') j++; if (command[j] != '\000') infile = &command[j]; } else { /* found a command line argument */ argv[i] = &command[j]; i++; } while ((command[j] != ' ') &&(command[j] != '\000')) { j++; } if (command[j] == '\000') break; command[j] = '\000'; j++; } argv[i] = NULL; } void launch(){ if (fork() == 0) { /*child*/ int i = 0; /* patha index */ if (infile != NULL) { /* redirect input */ int fd; /* file descriptor returned by open */ close( 0 ); /* close standard input for reopening */ fd = open( infile, O_RDONLY ); /* try to reopen */ if (fd != 0) { /* gripe if redirect failed */ fputs( "can't open ", stderr ); fputs( infile, stderr ); fputs( " for input\n", stderr ); exit( EXIT_FAILURE ); } } if (outfile != NULL) { /* redirect input */ int fd; /* file descriptor returned by open */ close( 1 ); /* close standard input for reopening */ fd = open( outfile, /* try to reopen */ O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | /* on file creation, */ S_IROTH | S_IWOTH /* it is read/write */ ); if (fd != 1) { /* gripe if redirect failed */ fputs( "can't open ", stderr ); fputs( outfile, stderr ); fputs( " for output\n", stderr ); exit( EXIT_FAILURE ); } } /* note: control only reaches this point if standard * input and output remain well defined. Failed redirection * causes the child process to terminate */ execve( argv[0], argv, myenvp ); /* first, try it as itself */ while (patha[i] != NULL) { /* try successive path prefixes */ char filename[100]; strncpy( filename, patha[i], 99 ); filename[99] = '\000'; /* insurance */ strncat( filename, "/", 99 - strlen( filename ) ); strncat( filename, argv[0], 99 - strlen( filename ) ); execve( filename, argv, myenvp ); /* try one prefix */ i = i + 1; } printf("no such command\n"); exit( EXIT_FAILURE ); /* a minor bug fix */ } else { /*parent*/ wait( NULL ); } } main( int argc, char *argv[], char *envp[] ){ myenvp = envp; getpath(); for (;;) { getcommand(); parseargv(); launch(); } }