我对如何处理来自execvp()
的错误感到有些困惑。到目前为止我的代码看起来像这样:
int pid = fork();
if (pid < 0) {
// handle error.
}
else if (pid == 0) {
int status = execvp(myCommand,myArgumentVector); // status should be -1 because execvp
// only returns when an error occurs
// We only reach this point as a result of failure from execvp
exit(/* What goes here? */);
}
else {
int status;
int waitedForPid = waitpid(pid,&status,0);
//...
}
我正试图解决三种情况:
myCommand,myArgumentVector
有效且命令正确执行。myCommand,myArgumentVector
是有效参数,但执行myCommand
时出错。myCommand,myArgumentVector
是无效参数(例如无法找到myCommand
)且execvp()
来电失败。我主要关注的是父进程将拥有所需的所有信息,以便正确处理孩子的错误,而且我不完全确定如何做到这一点。
在第一种情况下,程序可能以退出状态0结束。这意味着如果我在宏中调用WIFEXITED(status)
,我应该得到true
。我认为这应该可以正常工作。
在第二种情况下,程序可能以0以外的退出状态结束。这意味着如果我要调用WEXITSTATUS(status)
,我应该获得myCommand
子调用的特定退出状态。 (如果不正确,请告知。)
第三种情况让我感到很困惑。因此,如果execvp()
失败,则错误将存储在全局变量errno
中。但是这个全局变量只能从子进程访问;父母作为一个完全独立的过程,我认为不能看到它。这是否意味着我应该致电exit(errno)
?或者我应该在这里做点其他事情?另外,如果我致电exit(errno)
,我怎样才能从父母的errno
获取status
的值?
我的掌握仍然有点脆弱,所以我正在寻找的是确认或纠正我对如何处理这三种情况的理解。
答案 0 :(得分:3)
这是一个我尝试过的简单代码。
if(fork() == 0){
//do child stuff here
execvp(cmd,arguments); /*since you want to return errno to parent
do a simple exit call with the errno*/
exit(errno);
}
else{
//parent stuff
int status;
wait(&status); /*you made a exit call in child you
need to wait on exit status of child*/
if(WIFEXITED(status))
printf("child exited with = %d\n",WEXITSTATUS(status));
//you should see the errno here
}
答案 1 :(得分:1)
在第三种情况下,也可以从父级访问errno,因此您可以退出(errno)。 但是,这不是最好的事情,因为errno的值可能会在您退出时发生变化。
如果你的exec()和exit()调用之间有代码,更确定你不会丢失errno,将errno分配给int:
execvp(<args>);
int errcode=errno;
/* other code */
exit(errcode);
至于你的另一个问题,退出状态不能与errno直接比较,你不应该尝试从errno(如上所述)以外的任何东西中检索errno。
此文档可能有所帮助: http://www.gnu.org/software/libc/manual/html_node/Exit-Status.html
答案 2 :(得分:1)
在案例1中,execvp()
不会返回。返回到父进程的状态将是子进程的退出状态 - 它提供给exit()
的内容或它从main()
返回的内容,或者可能是孩子死于信号,在这种情况下退出状态不同但可以检测到(WIFSIGNALED
等)。请注意,这意味着状态不必为零。
对于案例2,我不太清楚(对我而言)。如果命令启动但拒绝调用它的选项,则实际上是案例1,但退出状态为零的可能性应该很小(虽然已知程序在出错时以状态0退出)。或者,找不到该命令,或者找到该命令但该命令不可执行,在这种情况下execvp()
返回并且您有案例3.
在案例3中,execvp()
调用失败。你知道,因为它返回;成功的execvp()
永远不会回来。测试execvp()
的返回值没有意义;它返回的事实意味着它失败了。您可以通过errno
的设置告诉它失败的原因。 POSIX使用126和127的退出状态 - 例如,请参阅xargs
和system()
。您可以查看execvp()
中的错误代码,以确定何时应返回其中任何一个或其他非零值。
答案 3 :(得分:0)
这是我的代码: 它工作正常。子状态在waitpid中返回,因此它告诉子进程是否成功执行。 //声明进程id变量 pid_t pid,ret_pid;
//fork a child process is assigned
//to the process id
pid=fork();
DFG_STATUS("Forking and executing process in dfgrunufesimulator %d \n", pid);
//code to show that the fork failed
//if the process id is less than 0
if(pid<0)
{
return DFG_FAILURE;
}
else if(pid==0)
{
//this statement creates a specified child process
exec_ret = execvp(res[0],res); //child process
DFG_STATUS("Process failed ALERT exec_ret = %d\n", exec_ret);
exit(errno);
}
//code that exits only once a child
//process has been completed
else
{
ret_pid = waitpid(pid, &status, 0);
if ( ret_pid == -1)
{
perror("waitpid");
return DFG_FAILURE;
}
DFG_STATUS("ret_pid = %d, pid = %d, child status = %d\n",ret_pid,pid,status);
if (WIFEXITED(status)) {
DFG_STATUS("child exited, status=%d\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
DFG_STATUS("child killed (signal %d)\n", WTERMSIG(status));
} else if (WIFSTOPPED(status)) {
DFG_STATUS("child stopped (signal %d)\n", WSTOPSIG(status));
#ifdef WIFCONTINUED /* Not all implementations support this */
} else if (WIFCONTINUED(status)) {
DFG_STATUS("child continued\n");
#endif
} else { /* Non-standard case -- may never happen */
DFG_STATUS("Unexpected status (0x%x)\n", status);
}
if(status != 0) /* Child process failed to execute */
return DFG_FAILURE;
result = DFG_SUCCESS;
}