【问题标题】:Determine Original Exit Status Code确定原始退出状态代码
【发布时间】:2013-06-15 23:41:21
【问题描述】:

在我维护的软件基线中,有 150 条语句分布在各种 C 应用程序中,它们调用另一个 Linux 命令(例如 rm -rf ...)或使用 status = system(cmd)/256 的自定义应用程序。当任一被调用时,从 Linux 命令或自定义应用程序返回的状态代码除以 256。这样当状态码大于0时,我们就知道有问题了。但是,软件的编写方式并不总是记录哪个命令或应用程序返回了状态代码。因此,如果状态码是 32768,除以 256 时,报告的状态码是 128

软件很旧,虽然我可以进行更改,但如果调用的任何命令或调用的应用程序在其他地方报告其原始状态代码,那就太好了。

有没有办法确定标准 Linux 日志文件中的原始状态码以及返回该状态码的应用程序?

【问题讨论】:

  • 编写一个包装器(函数或宏),它调用原始的system() 并在返回之前记录完整的结果。
  • system 返回的状态码适合一个字节,除非命令收到信号(例如,与SIGSEGV 一起崩溃)
  • @BasileStarynkevitch:那为什么要除以 256?我看到诸如 32768 之类的错误代码。
  • 仔细阅读 waitpid(2) 手册页并在系统的 /usr/include/bits/waitstatus.h/usr/include/stdlib.h 中查找定义 WTERMSIG 等的宏。实际上,您的程序应该使用这样的宏WIFEXITED, WEXITSTATUS, WIFSIGNALED, WTERMSIG, 等等......关于system(3)库函数的结果。

标签: c linux error-code


【解决方案1】:

如何编写包装器

下面是一个关于如何在 libc 函数 system() 周围应用包装器的示例。

创建一个名为system_wrapper.c 的新模块(翻译单元),如下所示:

标头system_wrapper.h:

#ifndef _SYSTEM_WRAPPER
#define _SYSTEM_WRAPPER

#define system(cmd) system_wrapper(cmd)

int system_wrapper(const char *);

#endif

模块system_wrapper.c

#include <stdlib.h> /* to prototype the original function, that is libc's system() */
#include "system_wrapper.h"

#undef system

int system_wrapper(const char * cmd)
{
  int result = system(cmd);

  /* Log result here. */

  return result;
}

使用system()将此行添加到所有模块:

#include "system_wrapper.h"

【讨论】:

  • 好主意.. 看起来 system() 调用 /bin/sh -c。有没有办法强制它调用 /bin/sh -x -c 呢? linux.die.net/man/3/system
  • 我的意思是,在 C 程序中,它调用 stdlib system 并且根据我在上面评论中发布的链接,它调用 /垃圾箱/sh -c。我假设这是在stdlib 中硬编码的。不确定这是否可以在不强制重新编译的情况下进行更改
  • 我想说重新编译 libc 不应该是一种选择。
  • 传递-x -c &lt;cmd&gt;而不是-c &lt;cmd&gt;的目的是什么?
  • 您可以改为修改/bin/sh。或者在此级别上应用另一个包装器,将/bin/sh 链接到您自己的脚本,然后调用原始的 shell 程序。
【解决方案2】:

正如我所评论的,system(3) 库函数返回等待系统调用的结果,例如 waitpid(2)。 (请点击手册页的链接)。

所以你应该改进你的程序以在调用system的结果上使用WIFEXITEDWIFSIGNALEDWEXITSTATUSWTERMSIG标准(Posix)宏(除非结果是-1,然后使用errno)。

编码

 status = system(cmd)/256;

是不可读的(对于人类开发人员)并且不可移植。

我猜是那个想捕捉中断命令的程序员......

你应该用

替换它
 status = system(cmd);
 if (status < 0) /* e.g. fork failed */
   do_something_with_error_code (errno);
 else if (status == 0) /* cmd run without errors */
   do_something_to_tell_command_exited_ok ();
 else if (WIFEXITED(status)) /* cmd got an error */
   do_something_with_exit_code (WEXITSTATUS(status));
 else if (WIFSIGNALED(status))  /* cmd or the shell got a signal */
   do_something_with_terminating_signal (WTERMSIG(status));

顺便说一句,使用system("rm -rf /some/dir"); 被认为是不好的做法(如果用户在他的$PATH 中创建了自己的rm 怎么办)并且效率不高。 (例如,您可以使用 nftw(3)unlink(2))或至少使用 /bin/rm -rf ;但是目录名称中的空格或脏IFS tricks呢?)

【讨论】:

  • Basile,您能否澄清一下您最后一句话中的措辞?对其他人:当使用nftw(..., FTW_DEPTH)unlink() 用于文件,rmdir() 用于空目录时(这就是为什么你要进行深度优先搜索——首先删除文件),所有可能的文件名都被正确处理(只要您不设置语言环境,或设置CPOSIX 语言环境,因为UTF-8 语言环境中的非UTF-8 序列通常会中止C 库函数)。只有system() 才会出现空格或脏 IFS 技巧等问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-17
相关资源
最近更新 更多