Write a simple shell in C(for ubuntu). This shell is called mosh (My Own Shell). When invoked it should be able to read a command typed on its prompt ($) and execute it in a new process. It should also have a shell variable similar to PATH in bash. Shell variables are set as follows:
PATH=/usr/bin:/bin
The executable for the command is searched in the directories in the path and the first one found should be executed.
mosh should also be able to handle pipes (not more than one pipe) similar to bash.
/* ----------------------------------------------------------------- */ /* */ /* This program reads in an input line, parses the input line */ /* into tokens, and use execvp() to execute the command. */ /* ----------------------------------------------------------------- */ #include <sys/types.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/wait.h> typedef void (*sighandler_t)(int); char *argv[2][256]; int size; char buf[]="command error\n"; char buf1[]="error\n"; void splitAgain(char arg[],int x); int split(char c[]); void execute(); void handle_signal(int signo); /* ----------------------------------------------------------------- */ /* The main program starts here */ /*===================================================================*/ /* ----------------------------------------------------------------- */ int main(void){ char c[256]; int i=0; int cnt; pid_t pid; int l=0; int status=1; char *quit="quit"; setenv("PATH","/home/harsha/Desktop/049:/bin:usr/bin",1); //handlin the signal signal(SIGINT, SIG_IGN); signal(SIGINT, handle_signal); while(1){//infinite loop printf("[SHELL] >>"); fgets(c,sizeof(c),stdin); //read the command line and assign it to c l=strlen(c); //get the command length if(c[0]!='\n'){ //check if the first character is equal to "\n" if(strncmp(c,quit,4)==0) exit(0); //if c equal to quit then exit l--; c[l]=' '; //adding a space to the end of the c c[l++]='|'; //adding a "|" character to the end of the c cnt = split(c); /* split the c and return the size of arguments devided by "|",cnt==size+1 */ if(cnt<3){ //check if the size+1 is less than 3 pid = fork(); // creatina a nem process if( pid != -1){ //check if the process creation has failed if (pid == 0){ //chilled process if( size == 0){ //if size == 0 then execute using execvp if(execvp(argv[0][0],argv[0])<0){ write(1, buf, strlen(buf)); exit(0); } } else{ //if size is not equal to 0, then go to the execute method execute(); } exit(status); }else{ wait(&status); } } else{ write(1, buf1, strlen(buf)); //if the process creation has failed display error } } else{ write(1, buf, strlen(buf)); //if the size+1 is not less than 3 display errror } } } return 0; } /* ----------------------------------------------------------------- */ /* FUNCTION split: */ /* This function receives a commend line argument. */ /* and the argument is splited and tokenised using "|" as the */ /* devider.and those tokens are being send to splitAgain function */ /* ----------------------------------------------------------------- */ int split(char c[]){ char *parts[2]; char *nextchar; char nxt; int count=0; int i=0; nextchar = strtok(c,"|"); // split using "|" as divider while(nextchar != NULL){ parts[count] = nextchar; //adding the the tokens to the array count++; if(count>2) break; //if the command line has more than 1 pipe break the loop nextchar = strtok(NULL,"|"); } if(count<3){ for( i=0 ; i < count ; i++){ splitAgain(parts[i],i); } } return count; } /* -------------------------------------------------------------------- */ /* FUNCTION splitAgain: */ /* This function receives string and a interger. the string is */ /* splited and tokenised using the space as the devider and adds a */ /* null character at the end of the array */ /* -------------------------------------------------------------------- */ void splitAgain(char arg[],int x){ int wordCount = 0; size = x; char * nextWordPtr; nextWordPtr = strtok(arg," "); // split using space as divider while (nextWordPtr != NULL) { argv[x][wordCount]=nextWordPtr; //ading the tokens to the array wordCount++; nextWordPtr = strtok(NULL," "); } argv[x][wordCount]=(char *) 0; //adding a null character at the end of the array } /* ----------------------------------------------------------------- */ /* FUNCTION execute: */ /* This function receives a commend line argument list with the */ /* first one being a file name followed by its arguments. Then, */ /* this function forks a child process to execute the command using */ /* system call execvp(). */ /* ----------------------------------------------------------------- */ void execute(){ pid_t pid; int fd[2]; pipe(fd); int status=1; pid = fork(); if(pid == -1){ write(1, buf1, strlen(buf)); exit(1); } if( pid == 0){ //chiled process close(1); //close normal stdout dup(fd[1]); //make stdout same as fd[1] close(fd[0]); if(execvp(argv[0][0],argv[0])<0){ write(1, buf, strlen(buf));} exit(1); } else{ //parent pprocess close(0); //close normal stdin dup(fd[0]); //make stdin same as fd[0] close(fd[1]); if(execvp(argv[1][0],argv[1])<0){ write(1, buf, strlen(buf));} exit(0); } } /* ----------------------------------------------------------------- */ /* FUNCTION handle_signal: */ /* when you press ctrl+c it will dispaly the shell program */ /* ----------------------------------------------------------------- */ void handle_signal(int signo) { printf("\n[SHELL] >>"); fflush(stdout); } /* END-------------------------------------------------------------- */
0 comments:
Post a Comment