【问题标题】:Does it make sense to exit(0) after a call to execl()?调用 execl() 后 exit(0) 有意义吗?
【发布时间】:2018-01-03 03:40:41
【问题描述】:

考虑以下代码:

close(channel_data->pty_master);

if (login_tty(channel_data->pty_slave) != 0) // new terminal session
{
    exit(1); // fail
}

execl("/bin/sh", "sh", mode, command, NULL); // replace process image
exit(0);

根据execl() 的文档,当前过程映像正在被替换,调用仅在错误时返回。

但是,如果进程映像被替换,为什么还要在调用execl() 之后再调用exit()

【问题讨论】:

    标签: c linux


    【解决方案1】:

    Exec 调用可能会失败。一个常见的结语是:

    perror("Some eror message");
    _exit(127); /*or _exit(1); (127 is what shells return) */
    

    您通常会在此处运行_exit 而不是exit,以跳过atexit 挂钩和stdio 缓冲区刷新。

    【讨论】:

    • A common epilogue would be -- 我认为这就是为什么使用注释来解释代码中的技术是不好的风格。请记住,有时这肯定会被复制。 ;)
    【解决方案2】:

    在某些exec(3) 函数之后调用exit 确实有意义,因为它们可能会失败(例如,当execve(2) 失败时)。 execve(2) 页面列出了一些失败的原因。

    最好是 exit(EXIT_FAILURE) 或其他一些(非 0)退出代码(通常会使用 127 或 126 等高退出代码用于该用途,以将 exec 的失败与程序中的错误分开运行),我建议在 exit 之前调用 perror。作为explained by PSKocick,调用_exit 是有充分理由的(但他的论点可能会颠倒过来,人们可能希望通过使用exit 来运行atexit 和标准fflushs)。

    在您的情况下,失败的可能性不大,但是想象一下,如果其他进程删除了/bin/sh(例如,系统管理员犯了在根目录或/bin/ 中运行/bin/rm -rf . 的愚蠢错误,也许在某些其他终端窗口)。

    当系统资源(暂时)耗尽时,execve 也可能会失败,例如

    ENOMEM 可用内核内存不足。

    而且(在极少数情况下)/bin/sh 甚至可能发生这种情况;

    顺便说一句,如果(错误地)command 是一百万个非空字节的字符串,您的 exec 使用可能会失败(使用 E2BIG)。

    作为一般编码规则,应检查所有重要的system calls 是否失败。

    【讨论】:

    • 在这种情况下,“失败”究竟是什么意思?
    • 表示您尝试运行的程序无法启动,例如如果 /bin/sh 不存在,或者它没有适当的权限来执行,或者系统不允许您运行程序(例如,您已达到某些系统限制或不允许您创建更多进程的策略
    • @Shuzheng exec()family 函数失败的原因有很多,但结果都是一样的:不会替换当前进程的图像,会设置errno。因此,在exec*() 调用之后放置的代码将被执行。
    • fall 还是“失败”(在第一行)?
    【解决方案3】:

    您需要调用exit,因为您未能exec 有问题的程序,并且您通常不希望该进程挂起,因为它没有运行您希望它运行的程序。由于execl只在失败时返回,所以不需要检查返回状态。

    在许多情况下,打印错误消息以查看失败的原因也很有意义。您还应该使用 0 以外的退出代码。非零退出代码用于指示异常退出,并且父进程可以在调用 wait 时捕获。

    execl("/bin/sh", "sh", mode, command, NULL);
    perror("command failed");
    exit(1);
    

    所以是的,调用exit 是有意义的,但不一定是exit(0)

    【讨论】:

      【解决方案4】:

      但是如果进程映像被替换,为什么在调用 execl() 之后调用 exit()?

      正如你所说,execl() 仅在错误时返回:

      execl("/bin/sh", "sh", mode, command, NULL); // replace process image
      exit(0);
      

      在上面的代码中,只有在execl() 调用失败时才会调用exit()


      作为Jonathan Leffler suggested in his comment,返回以外的值可能是个好主意,因为零表示成功,而代码确实失败 如果程序的控制流曾经到达上面代码中的exit() 调用。

      【讨论】:

      • 退出状态为 0 表示“成功”——但代码失败。
      猜你喜欢
      • 1970-01-01
      • 2011-04-02
      • 1970-01-01
      • 2012-02-03
      • 2012-01-19
      相关资源
      最近更新 更多