执行execve的返回状态

6
我想从execve进程向启动它的进程发送退出状态0。因为成功的execve永远不会返回,所以在此之后我将无法执行任何操作。但是如果execve运行成功,我希望能够发送退出状态0。

1
这个链接可能会对你有所帮助:http://stackoverflow.com/questions/13532391/how-to-get-error-of-execvp-in-the-fork - MOHAMED
OP希望父进程知道子进程的exec成功执行。exec失败可以通过多种方式向父进程报告(通过管道或特殊退出状态),但是确认exec成功更加困难,因为成功的exec定义意味着我们的进程不再运行。 - user4815162342
你的意思是 "... a child's exec ..." 指的是创建子进程本身的 exec 还是由子进程执行的 exec(该子进程又是由父进程执行 exec 创建的)? - alk
@alk exec 不会创建子进程,而是 fork。所谓“子进程的 exec”指的是在子进程中执行的 exec - user4815162342
@user4815162342: 噢,是的,当然,脑抽了一下...对不起。 - alk
@alk 没问题。这是一个好问题,但表达不够流畅,看起来像噪音。 - user4815162342
2个回答

6
您可以使用FD_CLOEXEC验证执行成功

  • 创建一个管道。

  • 分叉。

  • 在子进程中,关闭管道的读端并在管道的写端上设置FD_CLOEXEC标志。然后继续执行exec。如果exec成功,则由于FD_CLOEXEC,管道将自动关闭。如果exec失败,则向管道写入一个字节并退出。

  • 在父进程中,关闭管道的写端并从读端读取。如果您读取0个字节(EOF),则表示exec成功。如果您在管道中读取一个字节,则表示exec失败。

失败时在管道上写入的数据可用于传输错误信息,例如exec后的errno值。

出于简洁起见,省略了错误检查的代码如下:

int pipe_fds[2];
pipe(pipe_fds);
if (!fork()) {
  close(pipe_fds[0]);
  fcntl(pipe_fds[1], F_SETFD, F_CLOEXEC);
  execve(...);
  write(pipe_fds[1], "", 1);
  _exit(1);
}
else {
  int n;
  char out;
  close(pipe_fds[1]);
  n = read(pipe_fds[0], &out, 1);
  if (n == 0)
    printf("exec successful\n");
  else
    printf("exec failed\n");
  close(pipe_fds[0]);
}

请注意,如果其他线程可能会并行执行自己的进程,则此技术可能不安全。问题在于,在创建管道和设置close-on-exec标志之间存在延迟。如果在这个关键窗口期间有一个无关的线程fork并execs,则子进程将继承pipe_fds [1]并且不会关闭它,导致父进程挂起。可以使用Linux特定的pipe2调用来解决此问题,该调用允许原子地创建具有close-on-exec标志的管道。

exec失败时,是否保证在子进程关闭管道导致EOF通知之前会传递SIGCHLD信号?我喜欢这种技术背后的想法;我只是想知道是否存在竞争条件。 - Jonathan Leffler
@JonathanLeffler 我不认为有这样的保证,但这并不是必要的。如果exec失败,通过管道发送一些数据就足够消除歧义了。 - user4815162342
@JonathanLeffler 我已经编辑了答案,不再依赖于 SIGCHLD - user4815162342
如果这段代码在两个线程中执行会发生什么?我猜CLOEXEC会在第一次成功的exec上关闭文件描述符。如果另一个线程上的exec成功了,它看起来就像是exec成功了。 - user877329
@user877329 我不确定这是否真的是一个问题。从另一个线程发生的 exec 首先必须进行 fork,然后它只会关闭其文件描述符的视图。第一个线程的父进程只有在两个子进程都关闭管道后才会观察到 EOF,所以一切都会正常工作。 - user4815162342
@user877329 我认为反向可能是一个问题:如果在创建管道后但在设置close-on-exec之前,一个不相关的线程fork并执行,那么它通过fork()创建的文件描述符视图将不会关闭,因此父进程中的read()实际上会挂起!这可以使用Linux特定的pipe2调用来修复,该调用允许原子地创建带有close-on-exec标志的管道。 - user4815162342

2

如果你想要等待通过fork()启动的进程完成,可以使用wait()

/* parent */
int status;
while (wait(&status) != uproc.pid) {
    printf("waiting for child to exit");
    }

根据这个问题

wait函数提供了子进程的退出状态,存储在status变量中。

使用WEXITSTATUS宏可以获取退出状态,但仅当程序正常退出(即调用exit或从其main函数返回)时才可用:

if (WIFEXITED(status))
    printf("Child exit status: %d\n", WEXITSTATUS(status));
else
    printf("Child exited abnormally\n");

这并不会验证 exec 是否成功,只是程序以成功的状态退出。当执行长时间运行的程序时,这可能会有所不同。 - user4815162342

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接