簡體   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