Create a shell in C



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-------------------------------------------------------------- */


SHARE

Harsha Jayamanna

    Blogger Comment
    Facebook Comment

0 comments:

Post a Comment