1

I am implementing a simple version of a linux shell in c.

I have succesfully written the parser, but I am having some trouble forking out the child process. However, I think the problem is due to arrays, pointers and such, because just started C with this project and am not still very knowledgable with them.

I am getting a segmentation fault and don't know where from. Any help is greatly appreciated.

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

#define MAX_COMMAND_LENGTH 250
#define MAX_ARG_LENGTH 250

typedef enum {false, true} bool;

typedef struct {
    char **arg;     
    char *infile;   
    char *outfile;  
    int background; 
} Command_Info;

int parse_cmd(char *cmd_line, Command_Info *cmd_info)
{
    char *arg;
    char *args[MAX_ARG_LENGTH]; 

    int i = 0;
    arg = strtok(cmd_line, " ");
    while (arg != NULL) {
        args[i] = arg;
        arg = strtok(NULL, " ");
        i++;
    }

    int num_elems = i;
    if (num_elems == 0)
        return -1;

    cmd_info->infile = NULL;
    cmd_info->outfile = NULL;
    cmd_info->background = 0;

    int iarg = 0;
    for (i = 0; i < num_elems-1; i++)
    {                   
        if (!strcmp(args[i], "<"))
        {
            if (args[i+1] != NULL)
                cmd_info->infile = args[++i];
            else
                return -1;                      
        }

        else if (!strcmp(args[i], ">"))
        {
            if (args[i+1] != NULL)
                cmd_info->outfile = args[++i];
            else 
                return -1;                          
        }

        else
            cmd_info->arg[iarg++] = args[i];
    }

    if (!strcmp(args[i], "&"))
        cmd_info->background = true;
    else
        cmd_info->arg[iarg++] = args[i];

    cmd_info->arg[iarg] = NULL; 

    return 0;   
}


void print_cmd(Command_Info *cmd_info)
{
    int i;  
    for (i = 0; cmd_info->arg[i] != NULL; i++)
        printf("arg[%d]=\"%s\"\n", i, cmd_info->arg[i]);
    printf("arg[%d]=\"%s\"\n", i, cmd_info->arg[i]);    
    printf("infile=\"%s\"\n", cmd_info->infile);
    printf("outfile=\"%s\"\n", cmd_info->outfile);
    printf("background=\"%d\"\n", cmd_info->background);
}

void get_cmd(char* str)
{
    fgets(str, MAX_COMMAND_LENGTH, stdin);
    str[strlen(str)-1] = '\0'; //apaga o '\n' do fim
}

pid_t exec_simple(Command_Info *cmd_info)

{
    pid_t pid = fork();


    if (pid < 0)
    {
        perror("Fork Error");
        return -1;
    }



    if (pid == 0)

    {
        execvp(cmd_info->arg[0], cmd_info->arg);

        perror(cmd_info->arg[0]);
        exit(1);
    }


    return pid;

}

int main(int argc, char* argv[])
{

    while (true)
    {
        char cmd_line[MAX_COMMAND_LENGTH];
        Command_Info cmd_info;

        printf(">>> ");

        get_cmd(cmd_line);

        if ( (parse_cmd(cmd_line, &cmd_info) == -1) )   
            return -1;

        parse_cmd(cmd_line, &cmd_info);



        if (!strcmp(cmd_info.arg[0], "exit"))
            exit(0);

        pid_t pid = exec_simple(&cmd_info);

        waitpid(pid, NULL, 0);  
    }

    return 0;
} 

Thanks.

4
  • 1
    You can run your program with gdb and when it seg-faults, you can type bt to get a back-trace of the stack. This should help you identify exactly where you are crashing. Commented Apr 15, 2010 at 17:41
  • 1
    str[strlen(str)-1] = '\0'; is unsafe, what if str = ""; Commented Apr 15, 2010 at 17:43
  • 1
    Indeed, this is a perfect task for gdb... and, more importantly, it's a perfect task with which to familiarize yourself with gdb. Being able to use gdb to track down segfault locations will is one of the most important debugging skills, particularly so for new C developers. Commented Apr 15, 2010 at 17:48
  • Please also consider using strtok_r() by default, it will save you lots of headaches if/when you handle commands in threads. It only costs a single additional pointer for strtok() to save its work in progress in thread local storage. Commented Apr 16, 2010 at 6:30

1 Answer 1

4

The problem is with cmd_info->arg, which is declared as char **arg and you never allocate memory for it.

So, when you try to access it to save the arguments like this cmd_info->arg[iarg++] = args[i], you are dereferencing an uninitialized pointer, causing the segmentation fault.

A solution would be to change the Command_Info structure to declare arg like this :

char *arg[MAX_ARG_LENGTH];
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.