/* Shawn Nematbakhsh * login: cs153be * lab section: wed. night * cs153 as1 - shell */ #define INPUT_LENGTH 500 #define MAX_ARGS 50 #include #include #include #include #include #include #include #include // data structure for history record struct hist_t { char *commands[10]; int on; }; // carries out pipe int init_pipe(char line[INPUT_LENGTH],char **envp); // checks for redirection int checks(char line[INPUT_LENGTH],int *oldstream,int *oldfid); // packs input into args void pack(char *args[MAX_ARGS],char line[INPUT_LENGTH]); // executes a command void run_command(char *args[MAX_ARGS],char **envp); // initializes the history void hist_init(struct hist_t *history); //inserts into history void hist_update(struct hist_t *history,char *command); //prints history void hist_print(struct hist_t *history); // mallocs the history void hist_free(struct hist_t *history); // gets a given command in the history char *hist_get(struct hist_t *history,int num); int main(int argc,char **argv,char **envp) { // holds user input char line[INPUT_LENGTH]; // line gets spliced up by strtok so we need another copy for history char line2[INPUT_LENGTH]; // I sprintf to this when searching the path char cwd[INPUT_LENGTH]; // args for the input char *args[MAX_ARGS]; // the history struct hist_t history; // signals a redirect int redir=0; // old stdin/stdout fid's int oldfid; int oldstream; // initialize history hist_init(&history); // repeat until exit while(1) { // if we just did a reditect then set stdio/in back to normal if(redir>0) { close(oldstream); close(redir); dup(oldfid); redir=0; } // print prompt, get input printf("shell>"); fgets(line,INPUT_LENGTH-1,stdin); // make copy for history later strcpy(line2,line); // check for a redirect op, and change stdio/in redir=checks(line,&oldstream,&oldfid); // check for invalid redirection if(redir==-1) { printf("Invalid redirection\n"); continue; } // check for pipe if(strchr(line,'|')) { if(init_pipe(line,envp)) hist_update(&history,line2); continue; } // divide the input into args pack(args,line); // blank input case if(!args[0]) continue; // check for history command if(args[0][0]=='!') { // execute previous command if(strcmp(args[0],"!!")==0) { if(!hist_get(&history,history.on)) { printf("Event not found\n"); continue; } strcpy(line,hist_get(&history,history.on)); } else { // one of the last ten commands if(!hist_get(&history,atoi(args[0]+1))) { printf("Event not found\n"); continue; } strcpy(line,hist_get(&history,atoi(args[0]+1))); } // we have do all this again if we took a command from // the history strcpy(line2,line); redir=checks(line,&oldstream,&oldfid); if(redir==-1) { printf("Invalid redirection\n"); continue; } if(strchr(line,'|')) { if(init_pipe(line,envp)); hist_update(&history,line2); continue; } pack(args,line); } // update the history hist_update(&history,line2); // internal exit if(strcmp(args[0],"exit")==0) { hist_free(&history); return 0; } // internal cd else if(strcmp(args[0],"cd")==0) { if(!args[1]) chdir(getenv("HOME")); else { if(args[1][0]!='/') { sprintf(cwd,"%s/%s",getcwd(cwd,INPUT_LENGTH),args[1]); if(chdir(cwd)==-1) printf("Can't access directory %s\n",cwd); } else if(chdir(args[1])==-1) printf("Can't access directory %s\n",args[1]); } } // internal history else if(strcmp(args[0],"history")==0) hist_print(&history); // otherwise run an external command else run_command(args,envp); } return 0; } // this function carries out a pipe int init_pipe(char line[INPUT_LENGTH],char **envp) { int test; char pipeD[INPUT_LENGTH]; int fileID[2]; char *args[MAX_ARGS]; // empty pipe case if(line[strlen(line)-1]=='|') { printf("Invalid pipe\n"); return 0; } // create pipe and divide input in two pipe(fileID); strcpy(pipeD,strchr(line,'|')+1); *(strchr(line,'|'))='\0'; test=dup(1); // redirect output of left command if(fork()==0) { close(fileID[0]); close(1); printf("foo\n"); dup(fileID[1]); close(fileID[1]); pack(args,line); run_command(args,envp); exit(0); } // ...to the input of right command if(fork()==0) { close(fileID[1]); close(0); dup(fileID[0]); close(fileID[0]); pack(args,pipeD); run_command(args,envp); exit(0); } close(fileID[0]); close(fileID[1]); wait(NULL); return 1; } // this function checks for a redirect op int checks(char line[INPUT_LENGTH],int *oldstream,int *oldfid) { char *tok; int redir; // append if(strstr(line,">>")) { // seperate op from redirected file tok=strtok(strstr(line,">>")+2," \t\n"); *(strstr(line,">>"))='\0'; if(tok) { // change streams *oldfid=dup(1); redir=open(tok,O_WRONLY | O_CREAT | O_APPEND,S_IWRITE | S_IREAD); close(1); *oldstream=1; dup(redir); return redir; } } // output redirect else if(strstr(line,">")) { tok=strtok(strstr(line,">")+1," \t\n"); *(strstr(line,">"))='\0'; if(tok) { *oldfid=dup(1); redir=open(tok,O_WRONLY | O_CREAT | O_TRUNC,S_IWRITE | S_IREAD); *oldstream=1; close(1); dup(redir); return redir; } } // input redirect else if(strstr(line,"<")) { tok=strtok(strstr(line,"<")+1," \t\n"); *(strstr(line,"<"))='\0'; if(tok) { // case where file doesn't exist if(access(tok,R_OK)) return -1; *oldfid=dup(0); redir=open(tok,O_RDONLY); *oldstream=0; close(0); dup(redir); return redir; } } else return 0; return -1; } // seperates a line into args void pack(char *args[MAX_ARGS],char line[INPUT_LENGTH]) { int on=0; args[on++]=strtok(line," \t\n"); if(!args[0]) return; while((args[on++]=strtok(NULL," \t\n"))); } // carries out execution of a command void run_command(char *args[MAX_ARGS],char **envp) { char bigPath[INPUT_LENGTH]; char path[INPUT_LENGTH]; char *dir; if(fork()) // parent wait(NULL); else { // chile if(*args[0]=='.' || *args[0] =='/') { if(!access(args[0],X_OK)) execve(args[0],args,envp); fprintf(stderr,"%s: No such file or directory\n",args[0]); } else { // search path for executable strcpy(bigPath,getenv("PATH")); dir=strtok(bigPath,":"); while(dir) { sprintf(path,"%s/%s",dir,args[0]); if(!access(path,X_OK)) { execve(path,args,envp); } dir=strtok(NULL,":"); } fprintf(stderr,"%s: command not found\n",args[0]); } exit(0); } } // initialize the history void hist_init(struct hist_t *history) { int i; for(i=0;i<10;++i) history->commands[i]=NULL; history->on=0; } // add an item to the history void hist_update(struct hist_t *history,char *command) { if(history->commands[history->on%10]) free(history->commands[history->on%10]); history->commands[history->on%10]=malloc(strlen(command)+1); strcpy(history->commands[history->on%10],command); history->on++; } // prints out teh history void hist_print(struct hist_t *history) { int i; for(i=0;i<10;++i) if(history->on-10+i > -1) printf("%5d %s",history->on-9+i,history->commands[(history->on-10+i)%10]); } // frees up memory once we are done void hist_free(struct hist_t *history) { int i; for(i=0;i<10;++i) if(history->commands[i]) free(history->commands[i]); } // gets an iten from teh history char *hist_get(struct hist_t *history,int num) { if(num < 1 || num > history->on || num < history->on - 10) return NULL; return history->commands[(num-1)%10]; }