/*! * \author Matthew Toia * \file shell.c * \par * This file contains all of the functions and code realted to * the simpleshell executable. It contains the functionality * to read input, execute programs, and run built in commands * (ls, cd, host, exit). * \date 03.10.2004 */ /* this code is copyright of Matthew Toia * it was written to fulfill a programming * project and should not be used for anything * serious. */ #include #include #include #include #include #include #include #include #include /*** * Function Declarations ***/ int splitInStr(char *str); int do_args(char *str, char **args); void do_ls(int count, char **args); void signalHandler(int signum); char *interpolate(char *str); /*** * Global Variables ***/ int pid; /*! * \author Matthew Toia * \par * The main functions will sit in an infinite loop reading in * commands from a prompt using the readline() library command. It * it checks for the built-in commands ls, hostname, and exit * and will handle them internally. Otherwise it forks and execs * an external program * \date 03.10.2004 */ int main(int argc, char **argv) { char *line, prompt[16], *args[128], buffer[256]; int count, status; short cmd_no; signal(SIGINT, signalHandler); cmd_no=0; sprintf(prompt, "%% (%d) > ", cmd_no); /* set up prompt */ printf("Starting Shell: PID = %d\n", getpid()); while(line=readline(prompt)) { if(line[0]=='\0') continue; /* ignore blank lines */ sprintf(prompt, "%% (%d) > ", ++cmd_no); /* update prompt */ add_history(line); count=do_args(line, args); /*** * Check for built-in commands or fork and exec ***/ if(!strcmp(line, "exit")) { exit(0); } else if(!strcmp(args[0],"host")) { /* built-in host command */ printf("Command: PID = %d\n", getpid()); gethostname(buffer,256); printf("%s\n", buffer); } else if(!strcmp(args[0], "ls")) { /* built-in ls command */ printf("Command: PID = %d\n", getpid()); do_ls(count,args); } else if(!strcmp(args[0], "cd")) { /* built-in cd command */ printf("Command: PID = %d\n", getpid()); if(count==1) { /* default arg is $HOME */ args[1] = (char *)getenv("HOME"); args[2]=NULL; } if(chdir(args[1])==-1) perror(NULL); } else { /* no built-in exists */ pid=fork(); if(pid == 0) { /* in child process */ printf("Command: PID = %d\n", getpid()); execvp(args[0], args); /***************************************************************** * If control reaches this point, there was an error in the exec * *****************************************************************/ if(errno==ENOENT) /* No Such File */ printf("%s: Command not found\n", args[0]); else perror(args[0]); exit(0); } else if(pid == -1) { /* there was an error forking */ perror(NULL); } else { waitpid(pid, &status, 0); /* wait for child */ } } free(line); /* free memory alloc'd by * * readline */ } return 0; } /*! * \author Matthew Toia * \brief Splits strings by replacing whitespace with string terminators * \param str The string to be split * \return The number of splits in the string * \date 03.10.2004 */ int splitInStr(char *str) { char *c=str; int count=1; for(c;*c;c++) { /* cycle through the whole string */ if(*c==' ') { /* split whitespace */ *c='\0'; count++; } } return count; } /*! * \author Matthew Toia * \brief Will take a string and turn it into a null terminated array of args * \param str The string to be made into args * \param args The array to be filled * \return The number of args put in the array * \date 03.14.2004 */ int do_args(char *str, char **args) { int count, i; char *s; count=splitInStr(str); for(i=0, s=str; id_name); } } else { /* multiple dirs */ while(args[i]) { dir=opendir(args[i]); printf("\n%s:\n", args[i]); /* print directory name */ while(ent=readdir(dir)) { printf("%s", ent->d_name); } i++; closedir(dir); } } } /*! * \author Matthew Toia * \brief Handles the interrupt signal, making it kill the appropriate process * \param signum The signal that was caught * \date 03.14.2004 */ void signalHandler(int signum) { if(signum == SIGINT) { kill(pid, signum); } } /*! * \author Matthew Toia * \brief Performs variable substitution on strings * \param str The string to be interpolated * \return The interpolated value * \date 03.10.2004 */ char * interpolate(char *str) { if(str[0]=='$') { return (char *)getenv(str+1); /* varible substitution */ } else { return str; /* no changes made */ } }