繁体   English   中英

与 sudo 一起使用时,fork() 和 execvp() 出现意外结果

[英]fork() and execvp() unexpected outcome when used with sudo

所以当我在没有 sudo 的情况下调用这个程序时。 它工作正常。

#include <unistd.h>
#include <sys/wait.h>

int main(int argc, char** argv)
{
    if(fork() == 0) execvp(argv[1], &argv[1]);
    // else wait(NULL);
}

但是使用 sudo(当我需要输入密码时)它给出了一个奇怪的 output:

pasha@skynet:~$ sudo ./a.out bash
[sudo] password for pasha:         
pasha@skynet:~$ root@skynet:~# 

然后在任何输入上终端终止。 此外,它只发生在新生成的终端上。 当父母等待孩子时,sudo 的问题就消失了。

有人可以解释为什么吗?

为什么会这样

你正在fork你的进程,所以现在有两个进程。

一个进程是父进程,由您的 shell 运行,例如shell -> fork() -> exec(sudo) -> exec(./a.out) 父级终止,因为fork返回非零,然后main()到达关闭} main默认返回0 因此 shell 看到您的程序以退出状态 0 终止。您的 shell 在程序完成后以新的pasha@skynet:~$提示行迎接您。

另一个进程是子进程,从fork返回零的程序运行,例如shell -> fork() -> exec(sudo) -> exec(./a.out) -> fork() -> exec(bash) . 子进程是bash ,它打印root@skynet:~# (它在sudo之后运行)并等待输入。

这两个进程同时运行 - 即。 您的 shell (您从中执行sudo./a.out )和新的bash从您的程序运行。 这两个程序都尝试同时读取和写入相同的输入和 output。

子进程,即。 bash ,需要对终端的输入进行独占控制。 所以子进程bash执行tcsetpgrp 但是您的 shell 是控制您的终端的那个,而不是子进程。 因此,子进程在尝试从输入中读取时,要么接收信号 SIGTTOU ,要么接收信号 SIGTTIN。 然后子 bash 执行信号的默认处理程序 - 它终止。

从 shell 运行sudo bash &会导致与程序导致的问题类似的问题。

你的程序是正确的; 用“ls”代替“bash”试试,

$ ./a.out ls -al /tmp

它似乎不适用于bash的原因是 bash 希望该进程成为终端前台进程组的组长,但事实并非如此。

也就是说,虽然程序是正确的,但严重缺乏错误处理是有问题的:-)。 例如,当调用一个不存在的程序时, execvp()返回一个错误(而不是根本不返回),该错误被忽略。 效果是……嗯……你只能猜测它是否有效。

$ ./a.out frobozzzzz
$ # (hm)

这是我的化身。 更长。 处理错误。 看看孩子终止后的情况。

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


int main(int argc, char** argv)
{
    int status;
    pid_t pid, terminated;

    pid = fork();
    if (pid == -1 /*unlikely*/) {
        perror("fork()");
        exit(EXIT_FAILURE);
    }
    if (pid == 0 /*child*/) {
        if (execvp(argv[1], &argv[1]) != 0) { // when argv[1] is no
                                              // progrm in path
            perror("execvp()");
            exit(EXIT_FAILURE);
        }
        else
            assert(!"not getting here because successful exec() never returns");
    }

    // optional: wait for child to terminate, and print diagnostics
    terminated = waitpid(pid, &status, 0);
    if (terminated == -1) {
        perror("waitpid()");
        exit(EXIT_FAILURE);
    }

    if (terminated == pid) { // how come those not be equal?
        if (WIFEXITED(status))
            fprintf(stderr, "child terminated with exit status %d\n", WEXITSTATUS(status));
        else if (WIFSIGNALED(status))
            fprintf(stderr, "child terminated by %d\n", WTERMSIG(status));
        else
            fprintf(stderr, "see \"man waidpid\" for what that could be\n");
    }

    return 0;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM