Bantuan dengan implementasi shell linux sederhana

Saya menerapkan versi sederhana dari shell linux di c.

Saya telah berhasil menulis parser, tetapi saya mengalami kesulitan dalam melakukan proses anak. Namun, menurut saya masalahnya adalah karena array, pointer dan semacamnya, karena baru saja memulai C dengan proyek ini dan saya masih belum terlalu paham dengan mereka.

Saya mendapatkan kesalahan segmentasi dan tidak tahu dari mana. Bantuan apa pun sangat dihargai.

#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;
} 

Terima kasih.


person nunos    schedule 15.04.2010    source sumber
comment
Anda dapat menjalankan program Anda dengan gdb dan ketika terjadi kesalahan seg, Anda dapat mengetik bt untuk mendapatkan jejak kembali dari tumpukan. Ini akan membantu Anda mengidentifikasi dengan tepat di mana Anda mengalami error.   -  person i_am_jorf    schedule 15.04.2010
comment
str[strlen(str)-1] = '\0'; tidak aman, bagaimana jika str = ;   -  person Ernelli    schedule 15.04.2010
comment
Memang, ini adalah tugas yang sempurna untuk gdb... dan, yang lebih penting, ini adalah tugas yang sempurna untuk membiasakan diri Anda dengan gdb. Mampu menggunakan gdb untuk melacak lokasi segfault adalah salah satu keterampilan debugging yang paling penting, khususnya bagi pengembang C baru.   -  person Rakis    schedule 15.04.2010
comment
Harap pertimbangkan juga untuk menggunakan strtok_r() secara default, ini akan menghemat banyak sakit kepala jika/ketika Anda menangani perintah di utas. Hanya diperlukan satu penunjuk tambahan untuk strtok() untuk menyimpan pekerjaannya yang sedang berlangsung di penyimpanan lokal thread.   -  person Tim Post♦    schedule 16.04.2010


Jawaban (1)


Masalahnya ada pada cmd_info->arg, yang dinyatakan sebagai char **arg dan Anda tidak pernah mengalokasikan memori untuk itu.

Jadi, ketika Anda mencoba mengaksesnya untuk menyimpan argumen seperti ini cmd_info->arg[iarg++] = args[i], Anda melakukan dereferensi pointer yang tidak diinisialisasi, menyebabkan kesalahan segmentasi.

Solusinya adalah mengubah struktur Command_Info menjadi mendeklarasikan arg seperti ini :

char *arg[MAX_ARG_LENGTH];
person Laurent Parenteau    schedule 15.04.2010