simple shell in c: waitpid system call not working

2019-08-16 07:38发布

问题:

I have to make simple shell which read commands and execute them in order. condition is not changing the form of main function, and execute function should be recursive. main problem is that it seems waitpid doesn't work. but I know, there are so many problem in my code. please let me know where I should start from..

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

char cmmd[MAX][256];
int sp;
char *argv[10];
int size;

void ClearLineFromReadBuffer(void){
    while(getchar() != '\n');
}
void printCommands(){
    size = sp+1;
    //print by moving stack pointer
    while(1){
        if (sp==-1) break;
        printf("Command line : %s\n", cmmd[sp]);
        sp--;
    }
    printf("print end\n");
}



void readCommandLines(){
    int a = 0; //return of scanf
    while (1){ //write commends to cmmd untill get ctrl+d
        printf(">");
        a = (scanf("%[^\n]s", cmmd[sp])); //take input to str untill get enter(scanf returns -1)
        if (a==-1) {sp--; break;}
        if (a==1) ClearLineFromReadBuffer();
        if (a==0) {printf("error"); break;}
        sp++;
    }
    printf("\n");
}

void readACommand(char *line){ //line takes string's name.
    int i=0;

    argv[i]=strtok(line," "); //i==0
    while(strtok(line," ")!=NULL){
        i++;
        argv[i]=strtok(NULL," ");
    }
    printf("%s",argv[0]);
    printf("%s",argv[1]);
}

void executeCommands(){ //Recursive function
    int n = sp;
    n++;
    printf("%d",n);
    printf("%s",cmmd[n]);
    char *cmd_line = cmmd[n]; //command line which child process will execute

    unsigned int child_pid; //fork() returns process id of child in parents process
    int status; //status takes return of child's exit()
    child_pid=fork();
    if (child_pid != 0){ // Parents process
        printf("parents access");
        waitpid(child_pid,&status,0);
        printf("***Process %d Child process %d DONE with status %x\n\n",getpid(),child_pid,status);

        sp++;
        if(sp<size)
            executeCommands();
    }
    else if (child_pid == 0){ //fork() returns 0 in child process
        printf("***Process %d Executing Command %s",getpid(),cmd_line);
        readACommand(cmmd[n]);
        execve(argv[0],argv,NULL);
        printf("ERROR - not executing command \"%s\"\n",argv[0]); //can be printed because exec() failed
    }
}

int main(){
    readCommandLines();
    printCommands();
    executeCommands();
    return(0);
}

this is outcome. enter image description here

回答1:

the way you're tokenizing the string is very wrong. There's a lot of strtok calls, and your loop can be an infinite loop since you're calling strtok in the loop with the initialization string, not NULL

Plus you're not setting to NULL after the last argument, which is required by execv to know when the arguments have run out (no size is passed)

Here's a standalone example and a proper readACommand routine:

#include <stdio.h>
#include <string.h>

char *argv[100];

void readACommand(char *line){ //line takes string's name.
    int i=0;

    argv[i]=strtok(line," "); //i==0
    while(argv[i]!=NULL){
        argv[++i]=strtok(NULL," ");
    }
}

int main()
{
   char line[] = "this is a command";
   char **ptr=argv;

   readACommand(line);
   while(*ptr != NULL)
   {
      printf("Arg: %s\n",*ptr);
      ptr++;
   }
   return 0;
}

executing (detecting the NULL pointer in the end):

Arg: this
Arg: is
Arg: a
Arg: command