如何正确使用fork、exec、wait

32

我正在编写的shell需要执行用户提供的程序。以下是我的程序的缩短和简化版本。

int main()
{
    pid_t pid = getpid(); // this is the parents pid

    char *user_input = NULL;
    size_t line_sz = 0;
    ssize_t  line_ct = 0; 

    line_ct = getline(&user_input, &line_sz, stdin); //so get user input, store in user_input

    for (;;)
    {
        pid_t child_pid = fork(); //fork a duplicate process

        pid_t child_ppid = getppid(); //get the child's parent pid

        if (child_ppid == pid) //if the current process is a child of the main process
        {
            exec(); //here I need to execute whatever program was given to user_input
            exit(1); //making sure to avoid fork bomb
        }

        wait(); //so if it's the parent process we need to wait for the child process to finish, right?

    }
}
  1. 我是否正确地分叉了新进程并检查它是否是子进程?
  2. 我可以在这里使用哪个exec以实现我要做的事情?最简单的方法是什么?
  3. 我等待的参数是什么?我正在查看的文档没有太多帮助。

假设用户可能会输入类似于ls、ps、pwd的内容。

谢谢。

编辑:

const char* hold = strdup(input_line);
char* argv[2]; 

argv[0] = input_line;
argv[1] = NULL;

char* envp[1];
envp[0] = NULL;

execve(hold, argv, envp);

2
这里在Stackoverflow上有许多类似的问题。 - alk
1个回答

64

这是一个简单易懂的解决方案:

pid_t parent = getpid();
pid_t pid = fork();

if (pid == -1)
{
    // error, failed to fork()
} 
else if (pid > 0)
{
    int status;
    waitpid(pid, &status, 0);
}
else 
{
    // we are the child
    execve(...);
    _exit(EXIT_FAILURE);   // exec never returns
}

如果需要知道父进程的PID,子进程可以使用存储的值parent(尽管在这个例子中我不需要)。父进程只需等待子进程完成即可。实际上,子进程在父进程内部“同步”运行,不存在并行性。父进程可以查询status以查看子进程是如何退出的(成功、不成功或带有信号)。


好的,从Linux手册页上来看:int execve(const char *filename, char *const argv[], char *const envp[]); 你能解释一下这些参数在我的程序上下文中的含义吗? - Collin
@user2079802:man手册难道没有解释execve的工作原理吗?你也可以使用其他exec接口 - Kerrek SB
@user2079802:不需要使用strdup。只需要使用execve(argv[0], argv, envp)即可。 - Kerrek SB
实际上,子进程可以调用 getppid() 函数来获取父进程的 ID,无需事先保存。 :-) - Alan Haggai Alavi
@AlanHaggaiAlavi: 少了一个系统调用 :-) - Kerrek SB
当子进程说“exec永远不会返回”时 - 这并不完全正确,文档说“成功时,execve()不返回任何值,出错时返回-1,并适当设置errno。” 因此,代码应该是: if (execve(...) == -1) _exit(errno) else _exit(EXIT_SUCCESS); - parsley72

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接