RCPotatoSoup
RCPotatoSoup

Reputation: 19

exec failed with fork() and execvp()

I am currently working on a program in which I have to write a shell in C. I am having trouble getting the fork() section of my program to work. Here is my code:

void execute_func(char** tok)
{
    pid_t pid = fork();
    
    if (pid == -1)
    {
        printf("\nERROR: forking child process failed\n");
        return;
    }
    else if (pid == 0)
    {
        if (execvp(tok[0], tok) < 0)
        {
            printf("ERROR: exec failed\n");
        }
        exit(0);
    }
    else
    {
        wait(NULL);
        return;
    }
}

for example, if I am to type in any sort of function such as "ls" or "wc" it gives me the "ERROR: exec failed" message, which means that the fork() is not running correctly. This could be a small issue in my understanding of fork() but I am completely stumped.

here is my whole program:

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

char str[129];
enum {NOT_FOUND=0,FOUND};
enum {false=0,true};
static char *ptr;
const char *del;
int ReadLine(char *, int , FILE *);




char *mystrtok(char* string,const char *delim)
{
    int j,flag=NOT_FOUND;
    char *p;
    if(string != NULL)
    {
        ptr=string;
        p=string;
    }
    else
    {
        if(*ptr == '\0')
        return NULL;

        p=ptr;
    }

    while(*ptr != '\0')
    {
        del=delim;
        while(*del != '\0')
        {
            if(*ptr == *del)
            {
                if(ptr == p)
                {
                    p++;
                    ptr++;
                }
                else
                {
                    *ptr='\0';
                    ptr++;

                    return p;
                }
            }
            else
            {
                del++;
            }
        }
        ptr++;
    }
    return p;
}

void execute_func(char** tok)
{
    pid_t pid = fork();
    
    if (pid == -1)
    {
        printf("\nERROR: forking child process failed\n");
        return;
    }
    else if (pid == 0)
    {
        if (execvp(tok[0], tok) < 0)
        {
            printf("ERROR: exec failed\n");
        }
        exit(0);
    }
    else
    {
        wait(NULL);
        return;
    }
}
    


int main()
{
    int i;
    char *p_str,*token;
    char delim[10];
    delim[0] = ' ';
    delim[1] = '\t';
    delim[2] = '\n';
    delim[3] = '\0';
    char cwd[1024];
    char *tok[129];

    while(1)
    {
        tok[0] = NULL;
        fflush(stdin);
        fflush(stdout);
        printf("\n Enter a string to tokenize: ");
        //    printf("\n before scan");
        fflush(stdin);
        //    printf("\n fflush");
        ReadLine(str, 128, stdin);
        /*    scanf("%[^\n]",str); */
        printf("\n after scan");

        for (i = 1, p_str = str; ; i++, p_str = NULL)
        {
            token = mystrtok(p_str,delim);
            if (token == NULL)
            break;
            printf("%d: %s\n",i,token);
            tok[i-1] = token;
            printf("%s\n",tok[i-1]);
        }
        if(tok[0] != NULL)
        {
            if(strcmp(tok[0],"cd") == 0)
            {
                if (chdir(tok[1]) != 0)
                    perror("chdir() error()");

                getcwd(cwd, sizeof(cwd));
                printf("current working directory is: %s\n", cwd);
            }

            else if(strcmp(tok[0],"pwd") == 0)
                if (getcwd(cwd, sizeof(cwd)) == NULL)
                    perror("getcwd() error");
                else
                    printf("current working directory is: %s\n", cwd);

            else if(strcmp(tok[0],"exit") == 0)
                exit(3);

            else
            {
                execute_func(tok);
            }
        }
    }       
}


int ReadLine(char *buff, int size, FILE *fp)
{
    buff[0] = '\0';
    buff[size - 1] = '\0';             /* mark end of buffer */
    char *tmp;

    if (fgets(buff, size, fp) == NULL) 
    {
        *buff = '\0';                   /* EOF */
        return false;
    }
    else 
    {
        /* remove newline */
        if ((tmp = strrchr(buff, '\n')) != NULL) 
        {
            *tmp = '\0';
        }
    }
return true;
}

Upvotes: 1

Views: 397

Answers (1)

Joshua
Joshua

Reputation: 43327

Problem appears to be here:

        if (token == NULL)
        break;
        printf("%d: %s\n",i,token);
        tok[i-1] = token;

The trailing NULL never gets set in tok thus resulting in execve not finding the end of the list. Like this should fix it:

        tok[i-1] = token;
        if (token == NULL)
        break;
        printf("%d: %s\n",i,token);

Upvotes: 3

Related Questions