R..*_*R.. 35
处理exec失败的问题通常exec是在子进程中执行,并且您希望在父进程中执行错误处理.但你不能仅仅exit(errno)因为(1)你不知道错误代码是否适合退出代码,而且(2),你无法区分exec新程序中的失败和失败退出代码exec.
我所知道的最佳解决方案是使用管道来传达以下方面的成功或失败exec:
exec,则父级读取eof(零长度读取),因为close-on-exec成功exec关闭管道的写入端.或者,如果exec失败,父母将读取错误代码并可以相应地继续.无论哪种方式,父母都会阻止,直到孩子打电话exec.Car*_*rum 20
的
execl(),execle(),execlp(),execvp(),和execvP()功能可能会失败并置errno为库函数指定的错误的设定execve(2)和malloc(3).该
execv()函数可能会失败,并为库函数指定的任何错误设置errnoexecve(2).
然后从execve(2)手册页:
错误
Execve()如果出现以下情况,将失败并返回调用进程:
[E2BIG]- 新进程参数列表中的字节数大于系统强制限制.此限制由sysctl(3)MIB变量指定KERN_ARGMAX.[EACCES]- 拒绝路径前缀的组件的搜索权限.[EACCES]- 新进程文件不是普通文件.[EACCES]- 新进程文件模式拒绝执行权限.[EACCES]- 新进程文件位于已禁用执行(MNT_NOEXECin<sys/mount.h>)的文件系统上.[EFAULT]- 新进程文件的长度不能超过其标头中的大小值.[EFAULT]- Path,argv或envp指向非法地址.[EIO]- 从文件系统读取时发生I/O错误.[ELOOP]- 转换路径名时遇到太多符号链接.这被认为是循环符号链接的指示.[ENAMETOOLONG]- 路径名的组件超出{NAME_MAX}字符,或者整个路径名超出{PATH_MAX}字符.[ENOENT]- 新的流程文件不存在.[ENOEXEC]- 新进程文件具有相应的访问权限,但具有无法识别的格式(例如,其标头中的无效幻数).[ENOMEM]- 新进程需要的虚拟内存超过强制最大值(getrlimit(2))所允许的数量.[ENOTDIR]- 路径前缀的组件不是目录.[ETXTBSY]- 新的进程文件是一个纯过程(共享文本)文件,当前可供某些进程写入或读取.
malloc()很简单,只使用ENOMEM.来自malloc(3) man page:
如果成功的话,
calloc(),malloc(),realloc(),reallocf(),和valloc()函数返回一个指向分配的内存.如果有错误,则返回NULL指针并设置errno为ENOMEM.
在exec()调用返回后执行的操作取决于上下文 - 程序应该执行的操作,错误是什么以及您可以采取哪些措施来解决问题.
麻烦的一个原因可能是您指定了一个简单的程序名而不是路径名; 也许你可以重试execvp(),或将命令转换为调用sh -c 'what you originally specified'.这些是否合理取决于应用.如果涉及重大安全问题,您可能不会再试一次.
如果您指定了路径名并且存在问题(ENOTDIR,ENOENT,EPERM),那么您可能没有任何合理的回退,但您可以有意义地报告错误.
在过去(10多年前),有些系统不支持'#!' shebang表示法,如果您不确定是否正在执行可执行文件或shell脚本,则将其作为可执行文件进行尝试,然后将其作为shell脚本重试.如果您运行的是Perl脚本,那可能会也可能不会起作用,但在那些日子里,您编写了Perl脚本以检测它们是由shell运行并使用Perl重新执行.幸运的是,那些日子已经结束了.
在可能的范围内,重要的是确保进程报告问题以便可以跟踪它 - 将其消息写入日志文件或仅写入stderr(或甚至可能syslog()),以便那些必须解决问题的人除了倒霉的最终用户的报告"我试过X而且它不起作用"之外,还有更多信息可以帮助他们.至关重要的是,如果没有任何作用,则退出状态不为0,因为这表示成功.即使这可能会被忽略 - 但你做到了你能做到的.