从execvp()处理错误

时间:2013-11-19 05:21:21

标签: c unix fork wait execvp

我对如何处理来自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);
    //...
}

我正试图解决三种情况:

  1. myCommand,myArgumentVector有效且命令正确执行。
  2. myCommand,myArgumentVector是有效参数,但执行myCommand时出错。
  3. myCommand,myArgumentVector是无效参数(例如无法找到myCommand)且execvp()来电失败。
  4. 我主要关注的是父进程将拥有所需的所有信息,以便正确处理孩子的错误,而且我不完全确定如何做到这一点。

    在第一种情况下,程序可能以退出状态0结束。这意味着如果我在宏中调用WIFEXITED(status),我应该得到true。我认为这应该可以正常工作。

    在第二种情况下,程序可能以0以外的退出状态结束。这意味着如果我要调用WEXITSTATUS(status),我应该获得myCommand子调用的特定退出状态。 (如果不正确,请告知。)

    第三种情况让我感到很困惑。因此,如果execvp()失败,则错误将存储在全局变量errno中。但是这个全局变量只能从子进程访问;父母作为一个完全独立的过程,我认为不能看到它。这是否意味着我应该致电exit(errno)?或者我应该在这里做点其他事情?另外,如果我致电exit(errno),我怎样才能从父母的errno获取status的值?

    我的掌握仍然有点脆弱,所以我正在寻找的是确认或纠正我对如何处理这三种情况的理解。

4 个答案:

答案 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的退出状态 - 例如,请参阅xargssystem()。您可以查看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;
}