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