【问题标题】:Shell in C: How to execute builtin command with fork() and execve()C 中的 Shell:如何使用 fork() 和 execve() 执行内置命令
【发布时间】:2018-03-25 11:28:45
【问题描述】:

我正在尝试在 C 中创建一个 shell,但我被困在使内置函数正常运行的地步。

这是我的代码:

int my_fork(char *line, char **env)
{
    /*char *line = arguments entered in getline() (like 'ls' for example)*/
    /*char **env = copy of the shell environment*/
    int i = 0;
    /*Get the PID for forking*/
    pid_t pid = getpid();
    /*Declaration of one string and one array*/
    char *path = malloc(sizeof(char) * 100);
    char **tmp = malloc(sizeof(char *) * 7);
    /* my_str_to_word_array transform a string into an array of word*/
    char **arg = my_str_to_word_array(line);

    for (int j = 0; j < 30; j++)
        tmp[j] = malloc(sizeof(char) * 100);
        /*my_getpath() search and found the PATH variable in the environment*/
    path = my_getpath(env);
    /*Then, we put the different paths in an array (paths are separated by ':')*/
    tmp = my_str_to_word_array(path);
    for (int j = 0; j < 7; j++) {
            /*my_strcat() put a string after another string*/
            /*Here, i put the entered command after all the paths*/
            my_strcat(tmp[j], "/");
            my_strcat(tmp[j], arg[0]);
            /*my_putstr() print a string, here, i try to print all the modified paths*/
            my_putstr(tmp[j]);
            write (1, "\n", 1);
    }
    /*i fork and exec the command*/
    pid = fork();
    execve(tmp[i], arg, env);
    /*i wait until the child process end*/
    wait(&pid);
        return (0);
}

输出给我一个 Segfault 信号,我不知道为什么。 Valgrind 不帮我,我现在不知道该怎么办......

我遇到的错误:“访问不在映射区域 0x0 内”。此错误发生在“my_strlen()”中,该函数用于计算字符串的长度。我已经搜索了为什么会出现此错误,但我不明白,因为在我的字符串末尾,我确定有'\0'。

my_strcat():

char    *my_strcat(char *dest, char *src)
{
    int i = 0;
    int len = my_strlen(dest);

    for (; src[i] != '\0'; i++)
        dest[len + i] = src[i];
    i++;
    dest[len + i] = '\0';
    return (dest);
}

my_strlen():

    int my_strlen (char *str)
    {
    int i = 0;
    while (str[i])
        i++;
    return (i);
    }

所以,总而言之,我想让内置函数正常运行,我在 my_strlen() 中有一个错误,这不是我唯一的错误,但现在,让我们关注这个。

【问题讨论】:

  • 您可能应该添加使用my_strlenmy_strcat。看起来您访问了不应该访问的内容。
  • 是的,我已经编辑了上一篇文章。谢谢。
  • 最后,my_str_to_word_array 呢?还要在您的程序中打印path(在my_getpath 之后)并在此处发布结果,以确保它符合您的预期,以便我们了解您正在处理什么以及如何处理。
  • 只是一个简短的说明,应该有零理由为 shell 内置调用 exec。除非您计划同时运行它,否则您甚至可能不需要 fork
  • 我正在用 C 编写一个 minishell,我必须让像 ls 这样的内置函数在其中工作。这是我学校的一个项目,我被授权只能使用 fork 和 execve能够做到这一点,我没有找到其他解决方案...... -_-

标签: c shell


【解决方案1】:

my_str_to_word_array():

char **my_str_to_word_array(char *str)
{
        int i = 0;
        int j = 0;
        int m = 0;
        int len = my_strlen(str);
        char **tmp = malloc(sizeof(char *) * 10);

        for (int n = 0; n < 10; n++)
                tmp[n] = malloc(sizeof(char) * 50);
        while (j < len) {
                m = 0;
                while ((str[j] == ':') || (str[j] == ' ') || (str[j] == '\n'))
                        j++;
                while ((str[j] != ':') && (str[j] != ' ') && (str[j] != '\n'))
                        tmp[i][m++] = str[j++];
                tmp[i][m + 1] = '\0';
                i++;
        }
        tmp[i] = NULL;
        return (tmp);
}

my_getpath():

char *my_getpath(char **env)
{
    int i = 0;
    char *tmp = NULL;
    int len = 0;

    while (my_strncmp(env[i], "PATH=", 5) != 0)
        i++;
    len = my_strlen(env[i]);
    env[i][len + 1] = '\0';
    tmp = malloc(sizeof(char) * my_strlen(env[i]));
    my_printf("Path found\nLen: %d\n", my_strlen(env[i]));
    my_printf("Path: ");
    my_putstr(env[i]);
    write(1, "\n", 1);
    tmp = my_strncpy(tmp, env[i], 5);
    return (tmp);
}

my_strncpy():

    char *my_strncpy (char *src, int n)
{
        int i = 0;
        char *dest = malloc(sizeof(char));
        int len = my_strlen(src);
        for (; n <= len; i++) {
                dest[i] = src[n];
                n++;
        }
        dest[i] = '\0';
    return (dest);
}

getpath() 之后的路径打印给了我一个 Segfault,当我用 valgrind 查看时,它告诉我这是因为 my_strlen()。

但是当我不打印它时,它可以工作,所以我不认为这是因为 my_strlen()。

输出:

找到路径
莱恩:124
路径:PATH=/usr/lib64/qt-3.3/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/home/tyrone/.local/ bin:/home/tyrone/bin

分段错误(核心转储)

当我看到这个时,我认为它在 my_strncpy 中,但我看不出错误可能在哪里。

【讨论】:

  • dest 的 malloc 错误我认为你的意思是 malloc(n*sizeof(char))
  • 它有什么改变吗?我已经把它改成了 malloc(sizeof(char) * my_strlen(src))
  • 如果没有 n*sizeof(char) 你只分配 1 个字符并尝试使用更多因此 seg 错误但如果它继续执行 segfault 可能该错误也在其他地方
【解决方案2】:

您的代码还有一些其他问题最终也会给您带来问题。

首先,这段代码对fork()的使用是不正确的:

/*i fork and exec the command*/
pid = fork();
execve(tmp[i], arg, env);
/*i wait until the child process end*/
wait(&pid);
    return (0);

fork()工作时,之后会有两个进程。 pid 中保存的返回值为零。那就是新创建的子进程。在原始父进程中,pid 将是新创建的子进程的进程 ID。 (如果pid 的值为( pid_t ) -1,则意味着对fork() 的调用失败 - 只会返回到原始父进程。

所以你的代码需要做这样的事情:

pid = fork();

// parent process
if ( pid == 0 )
{
    execve(tmp[i], arg, env);

    // if you get here, execve() failed and you need
    // to be really careful because you're now running
    // a copy of the parent process - you can corrupt
    // files open in the parent, for example, because
    // data can be buffered in FILE * streams.

    // this is safe, though.  Note the underscore!
    // exit(0) without the underscore is *not* safe here
    _exit(0);
}
// child process
else if ( pid > ( pid_t ) 0 )
{
    wait(&pid);
}
else
{
    // fork() failed - handle error
}

return (0);

另外,当你像这样分配一个字符串数组时:

char **tmp = malloc(sizeof(char *) * 7);

for (int j = 0; j < 30; j++)
    tmp[j] = malloc(sizeof(char) * 100);

然后这样做:

tmp = my_str_to_word_array(path);

您刚刚通过覆盖从char **tmp = malloc(...); 调用返回到malloc() 的值泄漏了您分配的所有内存。一旦泄漏,就会泄漏在循环中的 malloc() 调用中分配的所有内存。

【讨论】:

    猜你喜欢
    • 2013-10-13
    • 1970-01-01
    • 1970-01-01
    • 2021-04-06
    • 1970-01-01
    • 2022-11-13
    • 2011-08-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多