【问题标题】:How to log all commands run By system() System Call如何记录所有通过 system() 系统调用运行的命令
【发布时间】:2011-03-31 12:40:56
【问题描述】:

我正在尝试调试一个 C++ 应用程序,该应用程序通过 system() 系统调用调用许多命令行应用程序,例如 grep 等。我需要通过 system() 调用查看应用程序正在执行的所有命令。

我尝试通过启用历史记录来查看这些命令并查看 .history 文件。但是这些命令不是通过终端执行的。历史文件只有交互执行的命令。

知道如何做到这一点吗?

【问题讨论】:

    标签: c++ unix system solaris


    【解决方案1】:

    定义一个具有相似名称的新宏:

    #define system(_x) std::cout << _x << std::endl; (system)(_x);
    

    system 宏替换了system 函数并且:

    1. 它将命令打印到标准输出(或其他地方)。
    2. 它调用system函数。

    感谢Hasturkun的建议,以下更好:

    #define system(_x) (std::cout << (_x) << std::endl, system(_x))
    

    这也返回了system函数调用的结果;-)

    【讨论】:

    • 你可能想把它改成#define system(_x) (std::cout &lt;&lt; (_x) &lt;&lt; std::endl, system(_x)) 这样它仍然返回一个值。
    • @Hasturkun:谢谢。我忘了system函数调用的结果可以在代码中请求。
    • @Hasturkun:在system宏的定义中,system函数调用应该用括号括起来,以防止system宏递归调用自身。
    • @PC2st:这不是必需的——C++ 标准禁止预处理器递归扩展 system 宏。
    • 一个相当侵入性的解决方案,尽管无论操作系统如何都能正常工作。 Solaris 提供了更简单的方法来做同样的事情。
    【解决方案2】:

    跟踪“yourProgram”执行的每个命令:

    truss -s!all -daDf -t exec yourProgram
    

    例如:

    $ truss -s!all -daDf -t exec sh -c "/bin/echo hello world;/bin/date" 
    Base time stamp:  1282164973.7245  [ Wed Aug 18 22:56:13 CEST 2010 ]
    5664:    0.0000  0.0000 execve("/usr/bin/i86/ksh93", 0x080471DC, 0x080471EC)  argc = 3
    5664:    argv: sh -c /bin/echo hello world;/bin/date
    5665:    0.0106  0.0106 execve("/bin/echo", 0x08067484, 0x080674F8)  argc = 3
    5665:    argv: /bin/echo hello world
    hello world
    5664:    0.0126  0.0126 execve("/bin/date", 0x080674E0, 0x080674F8)  argc = 1
    5664:    argv: /bin/date
    Wed Aug 18 22:56:13 CEST 2010
    

    如果您想将这些 exec 与 system() 调用相关联,您可以使用该命令:

    truss -t execve -f -u 'libc:system' yourProgram
    

    例如:

    $ cat a.c
    main()
    {
    system("echo a b c");
    system("pwd");
    }
    
    $ truss -t execve -f -u 'libc:system' ./a
    20073:  execve("a", 0x08047240, 0x08047248)  argc = 1
    20073/1@1:  -> libc:system(0x8050a5c, 0x0)
    20074/1:    execve("/bin/sh", 0x080471BC, 0x08047248)  argc = 3
    a b c
    20073/1@1:  <- libc:system() = 0
    20073/1@1:  -> libc:system(0x8050a68, 0x0)
    20076/1:    execve("/bin/sh", 0x080471BC, 0x08047248)  argc = 3
    /tmp
    20073/1@1:  <- libc:system() = 0
    

    最后,如果您使用的是 Solaris 10 或更新版本,您可以使用 Dtrace 执行此任务,如下所示:

    dtrace -Z -q -c yourProgram -n ' pid$target:libc:system:entry { printf("system(\"%s\")\n", copyinstr(arg0)); } '
    

    这将使用相同的“a”代码给出该输出:

    a b c
    /tmp
    system("echo a b c")
    system("pwd")
    

    PS:顺便说一下,system() 不是系统调用,而是标准库函数。

    【讨论】:

    • @jlliagre 正是我想要的!注意 system() 谢谢:)
    【解决方案3】:

    您可以使用 truss 或 strace(不确定 Solaris 自带哪一个)来运行程序并跟踪对系统的调用。

    对于 truss,相关命令类似于 truss -caf program_name

    【讨论】:

    • 将 truss 处理 system() 调用本身,还是会像 Linux 的 strace 一样显示组成系统调用(例如,fork()exec() )?
    • @pilcrow。你是对的,它会显示底层系统调用,你可以使用一些 truss 参数过滤到 exec 调用。自从我使用它已经很长时间了,但是您可以很容易地获得所有执行程序的列表以及传递给它的参数。虽然 OP 要求调用 system() 我不完全确定,在不知道上下文的情况下,他们是否想要包含特定的“fork/exec”实例。
    • Solaris truss 实际上也可以跟踪库函数调用,尽管它不会显示它们的参数。详情见我的另一条回复。
    • @jiiagre。感谢那。我从 1993 年左右就没有使用过 truss,所以我对语法的回忆不是很好。
    猜你喜欢
    • 2021-05-13
    • 2012-05-29
    • 1970-01-01
    • 2019-10-25
    • 1970-01-01
    • 2015-10-15
    • 1970-01-01
    • 2019-03-29
    • 2017-10-13
    相关资源
    最近更新 更多