Simple shell with fork and exec

I am trying to make a simple shell running any command from PATH, lets say ls or pwd du gedit etc. I am having trouble with exec.I require that if i enter space nothing happens and if i type exit it terminates.Any help is appreciated

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <string.h>

#define BUFFER 1024

int main() {
    char line[BUFFER];
    char* args[100];
    char* path = "";
    char program[20];


while(1){
    printf("$ ");
         if(!fgets(line, BUFFER, stdin))
          break;
          size_t length = strlen(line);
         if (line[length - 1] == '\n')
         line[length - 1] = '\0';
     if(strcmp(line, "exit")==0)  break;
         strcpy(program,path);           
         strcat(program,line);
    int pid= fork();              //fork child

        if(pid==0){               //Child
        execlp(program,line,(char *)NULL);    
    }else{                    //Parent
        wait(NULL);
}
}
}   

Upvotes: 2

Views: 10502

Answers (2)

P.P
P.P

Reputation: 121387

  1. You have 2 fgets() call. Remove the first one fgets(line, BUFFER, stdin);.

  2. fgets() will read in the newline if there's space in buffer. You need to remove it because when you input exit, you'll actually input exit\n and there's no command as /bin/exit\n.

The below code demonstrates removing newline character:

    if(!fgets(line, BUFFER, stdin))
        break;
    char *p = strchr(line, '\n');
    if (p) *p = 0;
  1. Your usage is wrong. Check the manual of execl. You need to pass the arguments: execl(program, line, (char *)NULL); Notice the cast of last argument of NULL. In case, NULL is defined as 0 then the cast becomes necessary because execl is a variadic function.

A modified example using execvp:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <string.h>

#define BUFFER 1024

int main(void) {
    char line[BUFFER];

    while(1) {
        printf("$ ");
        if(!fgets(line, BUFFER, stdin)) break;
        char *p = strchr(line, '\n');
        if (p) *p = 0;
        if(strcmp(line, "exit")==0) break;
        char *args[] = {line, (char*)0};
        int pid= fork();              //fork child
        if(pid==0) {               //Child
            execvp(line, args);
            perror("exec");
            exit(1);
        } else {                    //Parent
            wait(NULL);
        }
    }

    return 0;
}

Upvotes: 2

Abhijit Pritam Dutta
Abhijit Pritam Dutta

Reputation: 5591

Hi See my correction below and see my comment as well.

int main() {
char line[BUFFER];
char* args[100];
char* path = "/bin/";
char program[20];
char command[50];

while(1){
    printf("$ ");
    if(!fgets(line, BUFFER, stdin))
        break;
    memset(command,0,sizeof(command));
    if(strncmp(line, "exit", (strlen(line)-1))==0)  break;
    strncpy(command,line,(strlen(line)-1));
    strcpy(program, path);
    strcat(program,command);
    int pid= fork();              //fork child
    if(pid==0){               //Child
        execl(program,command,NULL);
        exit(0);// you must exit from the child because now you are inside while loop of child. Otherwise you have to type exit twice to exit from the application. Because your while loop also became the part of every child and from the child again it will call fork and create a child again
    }else{
        wait(NULL);
    }
 }
}

Also to support all command execution see the function execl how you need to pass the parameters in it. Accordingly you need to split your command and create the parameter list properly for execl.

Upvotes: 1

Related Questions