首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >fork()和execvp()与sudo一起使用时出现意外结果

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

Stack Overflow用户
提问于 2020-04-30 21:52:55
回答 2查看 155关注 0票数 0

所以当我在没有sudo的情况下调用这个程序。它工作得很好。

代码语言:javascript
复制
#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 (当我需要输入密码时),它会给出一个奇怪的输出:

代码语言:javascript
复制
pasha@skynet:~$ sudo ./a.out bash
[sudo] password for pasha:         
pasha@skynet:~$ root@skynet:~# 

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

有人能解释一下原因吗?

EN

回答 2

Stack Overflow用户

发布于 2020-05-01 17:33:47

为什么会发生这种情况

你正在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之后运行)并等待输入。

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

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

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

票数 1
EN

Stack Overflow用户

发布于 2020-05-01 17:20:37

您的程序是正确的;尝试使用"ls“而不是"bash",

代码语言:javascript
复制
$ ./a.out ls -al /tmp

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

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

代码语言:javascript
复制
$ ./a.out frobozzzzz
$ # (hm)

这是我的化身。更长。处理错误。看看孩子生完孩子后的结果。

代码语言:javascript
复制
#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;
}
票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61525002

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档