Search code examples
cmultiprocessingfork

I have implemented simple bash like shell using c program but its not working as expected


I have created one bash like program but when i tried to execute it's working fine at 1st time only then after it's not working as expected

The last executed output is repeatedly showing instead of asking new input

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

 char full_cmd[20];

 void command_source(char *cmd)
 {

    FILE *fp;
    char output[20];
    char *token;
    token = strtok(cmd," ");
    strcpy(full_cmd,"which ");
    strcat(full_cmd,token);
    fp = popen(full_cmd,"r");
    while (fgets(output, 20, fp) != NULL) {
            strcpy(full_cmd,output);
    }
    full_cmd[strlen(full_cmd)-1] = '\0';

    token = strtok(NULL," ");
    while (token != NULL)
    {
            strcat(full_cmd,token);
            token = strtok(NULL," ");
    }

  }

  void get_input(char input[10])
  { 
    printf("Enter the command:");
    scanf("%[^\n]s",input);
  }

  int launch_shell(char *buff[50],int status)
  {
    pid_t pid = fork();
    if( pid == 0 )
    {
            execv(buff[0],buff);
    }
    else if (pid > 0)
    {
            pid_t wpid = waitpid(pid, &status, 0);
    }
    else
            return 0;
    return 1;
  }

  int main()
  {
    char *buff[50];
    int status;
    char input[10];
    int count=0,ret=1;
    while(ret == 1)
    {
            get_input(input);
            command_source(input);
            strcpy(buff[0],full_cmd);
            buff[1] = NULL;
            int ret = launch_shell(buff,status);
    }
  }

Expected:

Enter the command:ls 
server.c server
Enter the command:ls -l
server.c
server

Actual results:

Enter the command:ls
server  server.c
server  server.c
server  server.c
server  server.c
server  server.c
server  server.c
server  server.c
server  server.c
server  server.c
server  server.c
server  server.c
server  server.c
server  server.c
server  server.c
...

Please help me guys to find out the issue in this. I spend whole day to slove this. But I couldn't.


Solution

  • With the statement

    scanf("%[^\n]s",input);
    

    you are saying "read until there's a newline". So after the first input, the newline character is left in the input stream which prevents stops subsequent input reading immediately. Better idea would be to use fgets() instead of scanf().

    You could pass the size argument to get_input function such as:

      void get_input(char input[10], size_t size)
      { 
        printf("Enter the command:");
        if (fgets(input, size, stdin) != NULL) {
            char *p = strchr(input, '\n');
            if (p) *p = '\0';
        } else {
            fprintf(stderr, "fgets failed\n");
            exit(1);
        }
      }
    

    and call it:

        get_input(input, sizeof input);
    

    You also have a number of issues:

    1.

    strcpy(buff[0],full_cmd);
    

    isn't correcr because buff[0] isn't initialized. You can instead just assign:

    buff[0] = full_cmd;
    
    1. You can't have arguments to command in your current approach. Because each of the arguments and command need to be passed as different parameters of the array buff to execv.

      So you need to split the input based on whitespace and put them into the array buff before calling launch_shell. For example, "ls -l" would be a single argument to execv (passed via buff[0]). But that's not what execv accepts. You need to put "ls" into buff[0] and "-l" into buff[1] and NULL into buff[2] and then call execv.