跳到内容

C 编程/stdlib.h/system

来自维基教科书,开放的书籍,开放的世界

在 C 标准库中,system 是一个用于执行子进程和命令的函数。它在 stdlib.h 头文件中定义。它与 exec/spawn 函数系列的不同之处在于,它不是将参数传递给执行的对象,而是将单个字符串传递给系统 shell,通常是 POSIX shell,/bin/sh -c

int system (const char *command);

system 函数是阻塞的;也就是说,调用将等待直到子进程终止并返回其退出值。在此期间,SIGCHLD 将被阻塞,因为 system 等待子进程死亡;此外,SIGINTSIGQUIT 被忽略,因此为了确保响应性,程序员应该检查返回值以查看用户是否试图终止进程。发生错误时,system 在 fork 之前或期间(例如,进程计数限制已达到)失败时将返回 -1,但在 fork 之后(例如,无法执行 sh)失败时将返回 127;这与命令以状态 127 退出无法区分。

在 POSIX 中,system 使用两个参数: “-c” 和 command 分叉并执行 /bin/sh。虽然 sh 的行为在其他地方有规定,但需要注意的是 command 不必是单个命令;它实际上可以是一个管道,甚至是一系列管道。例如,考虑一个希望显示屏幕截图的程序

system ("pngtopnm \"My Screenshot.png\" | pnmtoxwd > out.xwd && xwud out.xwd");

这行展示了一个重要的考虑因素:由于 command 将被解析为 shell 命令行,因此围绕例如文件名引号必须转义。然而,这会引发安全问题,因为如果 command 是从用户提供的 数据构建的,攻击者可能能够跳出任何引号并在父级上下文中执行任意命令;事实上,这几乎是规范的代码注入漏洞。因此,建议仅对预先确定的命令字符串使用 system,使用其他函数(spawn 等)在 argv 中传递用户提供的数据,或通过管道或临时文件传递此类数据。

system 生成的子进程继承其父进程的标准流;因此,子进程可以接收键盘输入并写入终端。请注意,这意味着父进程不会接收子进程的输出,除非使用重定向或 tee。

[编辑 | 编辑源代码]
华夏公益教科书