system函数
#include <stdlib.h>
int system(const char *command);
返回值:成功,则返回进程的状态值,
当sh不能执行时,返回127
失败返回-1
linux版system函数的源码:
int system(const char * cmdstring)
{
pid_t pid;
int status;
if(cmdstring == NULL){
return (1);
}
if((pid = fork())<0){
status = -1;
}
else if(pid == 0){ //子进程调用execl函数
execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);
-exit(127); //子进程正常执行则不会执行此语句
}
else{ //父进程等待子进程
while(waitpid(pid, &status, 0) < 0){
if(errno != EINTER){
status = -1;
break;
}
}
}
return status;
}
当system接受的命令为NULL时直接返回,否则fork出一个子进程,因为fork在两个进程:父进程和子进程中都返回,这里要检查返回的 pid,fork在子进程中返回0,在父进程中返回子进程的pid,父进程使用waitpid等待子进程结束,子进程则是调用execl来启动一个程序代替自己,execl("/bin/sh", “sh”, “-c”, cmdstring,(char*)0)是调用shell,这个shell的路径是/bin/sh,后面的字符串都是参数,然后子进程就变成了一个 shell进程,这个shell的参数是cmdstring,就是system接受的参数。在windows中的shell是command,想必大家很熟悉shell接受命令之后做的事了。
fork的原理:
当一个进程A调用fork时,系统内核创建一个新的进程B,并将A的内存映像复制到B的进程空间中,因为A和B是一样的,那么他们怎么知道自己是父进程还是子进程呢,看fork的返回值就知道,上面也说了fork在子进程中返回0,在父进程中返回子进程的pid。
//文件demo.c//gcc编译成a.out
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
//函数原型:int execl(const char *path, const char *arg, ...);
int main(void)
{
printf("before execl\n");
//if(execl("./bin/echoarg","echoarg","abc",NULL) == -1)
if(system("echoarg abc") == -1)//system函数直接调用另一个程序编程指令
{
printf("execl failed!\n");
}
printf("after execl\n");
return 0;
}
//文件echoarg.c//gcc编译成echoarg文件
#include <stdio.h>
int main(int argc,char *argv[])
{
int i = 0;
for(i = 0; i < argc; i++)
{
printf("argv[%d]: %s\n",i,argv[i]);
}
return 0;
}
运行结果:
ubuntu:~/test/exec_test$ ./a.out
before execl
argv[0]: echoarg
argv[1]: abc
after execl
exec族函数和system函数区别
我们先用gcc编译echoarg.c,生成可执行文件echoarg。文件echoarg的作用是打印命令行参数。然后再编译demo.c并执行system(指令)执行文件。与exec族函数不同的是不会把当前进程main替换掉,所以”after execl” 还会在在终端被打印出来。
system(执行shell 命令)
相关函数
fork,execve,waitpid,popen
表头文件
#include<stdlib.h>
定义函数
int system(const char * string);
函数说明
system()会调用fork()产生子进程,由子进程来调用/bin/sh-c string来执行参数string字符串所代表的命令,此命令执行完后随即返回原调用的进程。在调用system()期间SIGCHLD 信号会被暂时搁置,SIGINT和SIGQUIT 信号则会被忽略。
返回值
如果system()在调用/bin/sh时失败则返回127,其他失败原因返回-1。若参数string为空指针(NULL),则返回非零值。如果 system()调用成功则最后会返回执行shell命令后的返回值,但是此返回值也有可能为system()调用/bin/sh失败所返回的127,因此最好能再检查errno 来确认执行成功。
附加说明
在编写具有SUID/SGID权限的程序时请勿使用system(),system()会继承环境变量,通过环境变量可能会造成系统安全的问题。