相关函数
fork,execv e,waitpid,
popen
表头文件
#i nclude<std lib.h>
定义函数
int system(con st char * string);
函数说明
system()会调 用
fork()产生子 进程,由子进程来调用
/bin/sh-c string来执行参
数string字符串
所代表的命令,此命>
令
执行完后随即返回原 调用的进程。在调用s
ystem()期间
S IGCHLD 信号会被暂时搁置,S IGINT和SIGQ UIT 信号则会被忽略。
返回值
=-1:出现错误
=0:调用成功
=1:入参字符串为空
fork,execv
表头文件
#i nclude<std
定义函数
int system(con
函数说明
system()会调
返回值
=-1:出现错误
=0:调用成功
=1:入参字符串为空
=127:execl执行失败
如果system() 在
调用/bin/sh 时失败则返回127,
其他失败原因返回-1
。若参数string
为空指针(NULL)
,则返回非零值1。
如果system()
如
果system()调
用成功则最后会返回执
行shell命令后的
返回值,但是此返回值
也有可能为 system()调用
/bin/sh失败所
返回的127,因此最
好能再检查errno
来确认执行成功。
附加说明
在编写具有SUID/ SGID权限的程序时
请勿使用system
(),system(
)会继承环境变量,通
过环境变量可能会造成
系统安全的问题。
范例
#include<std lib.h>
main()
{
system(“ls -al /etc/passw
d /etc/shado
w”);
}
执行结果:
附加说明
在编写具有SUID/
范例
#include<std
main()
{
system(“ls
}
执行结果:
-rw-r--r--
1 root root 705 Sep 3 13 :52 /etc/passw
d
-r-------- - 1 root root 572 Sep 2 15 :34 /etc/shado
-r--------
例2:
char tmp[];
sprintf(tm p,"/bin/mo
unt -t vfat %s /mnt/usb",
dev);
system(tmp );
其中dev是/dev /sda1。
sprintf(tm
system(tmp
其中dev是/dev
system源码
#include
#include
#include
#include
#include
#include
#include
int system(con
st char * cmdstring)
{
pid_t pid;
int status;
{
}
先分析一下原理,然后
再看上面的代码大家估
计就能看懂了:
当system接受的
命令为NULL时直接
返回,否则fork出
一个子进程,因为fo
rk出两个进程:父进
程和子进程中都返回,
这里要检查返回的pi
d,fork在子进程
中返回0,在父进程中
返回子进程的pid,
父进程使用waitp
id等待子进程结束,
子进程则是调用exe
cl来启动一个程序代
替自己,execl(
"/bin/sh",
"sh", "-c", cmdstring,
(char*)0)是
调用shell,这个
shell的路径是/
bin/sh,后面的
字符串都是参数,然后
子进程就变成了一个s
hell进程,这个s
hell的参数是cm
dstring,就是
system接受的参
数。
如果上面的你没有看懂 ,那我再解释下for
k的原理:当一个进程
A调用fork时,系
统内核创建一个新的进
程B,并将A的内存映
像复制到B的进程空间
中,因为A和B是一样
的,那么他们怎么知道
自己是父进程还是子进
程呢,看fork的返
回值就知道,上面也说
了fork在子进程中
返回0,在父进程中返
回子进程的pid。
如果上面的你没有看懂
execl是编译器的
函数(在一定程度上隐
藏具体系统实现),在
linux中它会接着
产生一个linux系
统的调用execve
, 原型见下:
int execve(con
st char * file,const
char **argv,con
st char **envp);
看到这里你就会明白为 什么system()
会接受父进程的环境变
量,但是用syste
m改变环境变量后,s
ystem一返回主函
数还是没变,原因从s
ystem的实现可以
看到,它是通过产生新
进程实现的,从我的分
析中可以看到父进程和
子进程间没有进程通信
,子进程自然改变不了
父进程的环境变量。
看到这里你就会明白为