将 execve 与命令和 2 个参数一起使用

using execve with command and 2 arguments

提问人:AlCo2 提问时间:11/8/2023 更新时间:11/9/2023 访问量:80

问:

我正在创建自己的 shell,在此函数中传递带有 2 参数的命令时遇到问题:

    void executeCMD(char **av)
{
        int status;
        pid_t pid;

        pid = fork();
        if (pid == -1)
        {
                perror("error");
                exit(1);
        }
        if (pid == 0)
        {

                if (execve(av[0], av, NULL) == -1)
                {
                        perror("Error");
                        exit(1);
                }
        }
        else
        {
                wait(&status);
        }
}

如果我传递了类似的东西:/bin/ls 或 /bin/ls -l,它工作正常,但使用类似的东西:

/bin/ls -l /tmp

我明白了:

$ ls -l /tmp
Error: Bad address

问题出在所有命令中,特别是当我添加第三个参数时。

我如何创建命令,将缓冲区作为命令和参数传递给 **av:

char **split_string(char *input, char *delim)
{
        char **list = NULL;
        int i = 0;
        char* token = strtok(input, delim);

        while (token != NULL)
        {
                list = realloc(list, (i + 1) * sizeof(char *));
                if (list == NULL)
                {
                        perror("out of memory");
                        exit(1);
                }
                list[i] = realloc(list[i], strlen(token) + 1);
                if (list[i] == NULL)
                {
                        perror("out of memory");
                        exit(1);
                }
                strcpy(list[i], strdup(token));
                token = strtok(NULL, delim);
                i++;
        }
        return (list);
}
C Linux shell 内存管理 执行

评论

2赞 Shawn 11/8/2023
这会导致内存泄漏(这没什么大不了的,这要归功于之后的执行官,但无论如何形式都很糟糕)。传递给的命令参数数组在其最后一个元素中需要一个空指针。strdup()execve()
1赞 Shawn 11/8/2023
在调用它之前,您还需要设置为 null;当您使用第一个数组增长数组时,末尾的新内存不会初始化为任何内容。 实际上更有意义。(不过我还是会这样做)list[i]realloc()realloc()malloc()list[i] = strdup(token);
1赞 John Bollinger 11/8/2023
第三个参数不应为 null。在极少数情况下,你真的想提供一个完全空的环境,你应该提供一个指向 1 的数组的指针,而这个元素是 null。execve()char *
4赞 Shawn 11/8/2023
要么 + 要么只是 .但不是两者兼而有之。malloc()strcpy()strdup()
1赞 Andrew Henle 11/8/2023
根据 @JohnBollinger 的注释,参数指定为“该参数是指向以 null 结尾的字符串的字符指针数组。这些字符串应构成新进程映像的环境。数组由 null 指针终止。它没有任何地方说明可以.您可能应该使用 .envpexecve()envpenvpenvpNULLexecv()

答:

0赞 Nick Brendholdt Rasmussen 11/9/2023 #1

我认为您也为 argv 提供了路径 av[0]。也许可以尝试: execve(av[0], av+1, NULL)。

并确保 av 以 null 结尾

评论

0赞 user1934428 11/9/2023
但是参数 0 应该是程序名称(或者我们希望被调用程序相信它的程序名称是什么)。 对我来说没有意义。av+1
0赞 Nick Brendholdt Rasmussen 11/10/2023
av + 1 只是从第一个标志“-i”开始数组并向前。所以“av + 1”作为“-i”和“/tmp”存在的数组,可能在数组末尾有“0”
0赞 user1934428 11/10/2023
根据 execve-man 页面,第二个参数是被调用程序将在其 .但按照惯例,(即)的第一个参数应该是所谓的程序调用名称。如果传递 ,main's 将包含标志,而不是程序名称。execvemainargvargvargv[0]av +1argv[0]
0赞 Nick Brendholdt Rasmussen 11/10/2023
execve(av[0], av+1, NULL)。第一个参数是 /ls,exec 的第二个参数是不包括 /ls 的数组,不是吗?
0赞 user1934428 11/10/2023
不。 是正在执行的程序。第二个参数的第一个元素是我们想让程序相信它被执行的东西。例如,如果您执行并让第二个参数 be ,则 sh 运行,但认为它的名称是 。这将产生 shell 充当登录 shell 的效果。av[0]/bin/sh foo['-sh', 'foo']-sh