ISO C定义了system函数,但是其操作对系统的依赖性很强。POSIX.1包括了system接口,它扩展了ISO C定义,以描述system在POSIX.1环境中的运行行为。

#include <stdlib.h>
int system( const char *cmdstring );

如果cmdstring是一个空指针,则仅当命令处理程序可用时,system返回非0值,这一特征可以确定在一个给定的操作系统上是否支持system函数。在UNIX中,system总是可用的。

因为system在其实现中调用了fork、exec和waitpid,因此有三种返回值:

(1)如果fork失败或者waitpid返回除EINTR之外的出错,则system返回-1,并且在errno中设置相应的错误类型值。

(2)如果exec失败(表示不能执行shell),则其返回值如同shell执行了exit(127)一样。

(3)否则所有三个函数(fork、exec和waitpid)都执行成功,并且system的返回值是shell的终止状态,其格式已在waipid中说明(参见http://www.cnblogs.com/nufangrensheng/p/3510101.html)。

程序清单8-12 system函数(没有信号处理)

[root@localhost apue]# cat system_nosighandling.c
#include <sys/wait.h>
#include <errno.h>
#include <unistd.h> int
system(const char *cmdstring) /* version without signal handling */
{
pid_t pid;
int status; if (cmdstring == NULL)
return(1); /* always a command processor with UNIX */ if ((pid = fork()) < 0)
{
status = -1; /* probably out of processes */
}
else if (pid == 0) /* child */
{
/*
* execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);
* _exit(127); /* execl error */
* 此处程序原来是如上面所示,但我无法理解这里的逻辑(感觉是有问题的,但是执行也可获得正确结果)
* 改为了下面的形式
*/
if (execl("/bin/sh", "sh", "-c", cmdstring, (char *)0) < 0)
{
_exit(127); /* execl error */
}
}
else /* parent */
{
while (waitpid(pid, &status, 0) < 0)
{
if (errno != EINTR)
{
status = -1; /* error other than EINTR from waitpid() */
break;
}
}
} return(status);
}

shell的-c选项告诉shell程序取下一个命令行参数(在这里是cmdstring)作为命令输入(而不是标准输入或从一个给定的文件中读命令)。shell对以null字符终止的命令字符串进行语法分析,将它们分成命令行参数(如果不使用shell执行此命令,而是试图由我们自己去执行它,那么将相当困难)。传递给shell的实际命令字符串可以包含任一有效的shell命令。

注意,我们调用_exit而不是exit。这是为了防止任一标准I/O缓冲区(这些缓冲区会在fork中由父进程复制给子进程,详情请参考:http://www.cnblogs.com/nufangrensheng/p/3509492.html)在子进程中被冲洗。

程序清单8-13 调用system函数

[root@localhost apue]# cat prog8-13.c
#include "apue.h"
#include <sys/wait.h> int
main(void)
{
int status; if ((status = system("date")) < 0)
err_sys("system() error");
pr_exit(status); if ((status = system("nosuchcommand")) < 0)
err_sys("system() error");
pr_exit(status); if ((status = system("who; exit 44")) < 0)
err_sys("system() error");
pr_exit(status); exit(0);
}

运行程序清单8-13得到:

[root@localhost apue]# ./prog8-13
Wed Jan 8 23:06:53 PST 2014
normal termination, exit status = 0 对于date
sh: nosuchcommand: command not found
normal termination, exit status = 127 对于无此种命令
root pts/0 2014-01-03 22:57 (:0.0)
normal termination, exit status = 44 对于exit

使用system而不是直接使用fork和exec的优点是:system进行了所需的各种出错处理,以及各种信号处理(在带信号处理的system版本中)。

 

设置用户ID程序

如果在一个设置用户ID程序中调用system,那么会发生什么呢?这是一个安全性方面的漏洞,决不应当这样做。

如果一个进程正以特殊的权限(设置用户ID或设置组ID)运行,它又想生成另一个进程执行另一个程序,则它应当直接使用fork和exec,而且在fork之后、exec之前要改回到普通权限。设置用户ID或设置组ID程序决不应调用system函数。

 

本篇博文内容摘自《UNIX环境高级编程》(第二版),仅作个人学习记录所用。关于本书可参考:http://www.apuebook.com/

进程控制之system函数的更多相关文章

  1. 进程控制之fork函数

    一个现有进程可以调用fork函数创建一个新进程. #include <unistd.h> pid_t fork( void ); 返回值:子进程中返回0,父进程中返回子进程ID,出错返回- ...

  2. 进程控制之exec函数

    用fork函数创建子进程后,子进程往往要调用一种exec函数以执行另一个程序.当进程调用一种exec函数时,该进程执行的程序完全替换为新程序,而新程序则从其main函数开始执行.因为调用exec并不创 ...

  3. 二十六、Linux 进程与信号---system 函数 和进程状态切换

    26.1 system 函数 26.1.1 函数说明 system(执行shell 命令)相关函数 fork,execve,waitpid,popen #include <stdlib.h> ...

  4. UNIX环境编程学习笔记(22)——进程管理之system 函数执行命令行字符串

    lienhua342014-10-15 ISO C 定义了 system 函数,用于在程序中执行一个命令字符串.其声明如下, #include <stdlib.h> int system( ...

  5. Linux系统编程_8_进程控制之fork_wait_waitpid函数

    fork函数: #include <unistd.h>        pid_t fork(void); fork用来创建一个子进程: 特点: fork调用后会返回两次,子进程返回0,父进 ...

  6. linux c编程:进程控制(三)_exec函数

    fork()函数通过系统调用创建一个与原来进程(父进程)几乎完全相同的进程(子进程是父进程的副本,它将获得父进程数据空间.堆.栈等资源的副本.注意,子进程持有的是上述存储空间的“副本”,这意味着父子进 ...

  7. 进程控制之exit函数

    进程有下面5种正常终止方式: (1)在main函数内执行return语句.这等效于调用exit. (2)调用exit函数.此函数有ISO C定义,其操作包括调用各终止处理程序(终止处理程序在调用ate ...

  8. 进程控制之waitid函数

    Single UNIX Specification的XSI扩展包括了另一个取进程终止状态的函数--waitid,此函数类似于waitpid,但提供了更多的灵活性. #include <sys/w ...

  9. 进程控制之vfork函数

    vfork函数的调用序列和返回值与fork相同,但两者的语义不同. vfork用于创建一个新进程,而新进程的目的是exec一个新程序.vfork和fork一样都创建一个子进程,但是它并不将父进程的地址 ...

随机推荐

  1. codeforces 681D Gifts by the List dfs+构造

    题意:给你一个森林,表示其祖先关系(自己也是自己的祖先),每个人有一个礼物(要送给这个人的固定的一个祖先) 让你构造一个序列,使得的对于每个人,这个序列中第一个出现的他的祖先,是他要送礼物的的那个祖先 ...

  2. erp验收测试

    软件测试是为了发现错误而执行程序的过程.它不仅是软件开发阶段的有机组成部分,而且在整个软件工程(即软件定义.设计和开发过程)中占据相当大的比重.软件测试是软件质量保证的关键环节,直接影响着软件的质量评 ...

  3. 微信公众平台开发 ACCESS TOKEN

    获取access token 返回 access_token是公众号的全局唯一票据,公众号调用各接口时都需使用access_token.正常情况下access_token有效期为7200秒,重复获取将 ...

  4. CentOS安装XRDP实现远程桌面访问

    1.配置环境: yum install gcc pam-devel openssl-devel -y 2.进入指定目录下载并解压xrdp: 先安装 wget; sudo yum -y install ...

  5. Ubuntu 下安装 Oracle Java

    这只是一篇流水帐,记录如何安装Java. 在Ubuntu 下管理软件很方便,但安装的Java是opensdk.如果在某些条件下,需要安装Sun (Oracle)的Java,则需要自己手工安装. 一般情 ...

  6. Spring properties dependency checking

    In Spring,you can use dependency checking feature to make sure the required properties have been set ...

  7. HDU 5441 Travel (并查集+数学+计数)

    题意:给你一个带权的无向图,然后q(q≤5000)次询问,问有多少对城市(城市对(u,v)与(v,u)算不同的城市对,而且u≠v)之间的边的长度不超过d(如果城市u到城市v途经城市w, 那么需要城市u ...

  8. java 指导 (Java Tutorial)

    case1: site:docs.oracle.com -xmx -xms case2: site:docs.oracle.com thread case3: site:docs.oracle.com ...

  9. jeecms附件标签用法

    [#if content.attachments?size gt 0] [#list content.attachments as attach] <a id="attach${att ...

  10. Ubuntu12.04 使用中遇到的问题

    这个随笔回记录使用Ubuntu遇到的一些问题   不定期进行整理和分类 1.Question:   ubuntu 无法检测包或者源码包 Description:Ubuntu软件中心打开时报错  无法检 ...