[英]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.