1、system系统调用
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()会继承环境变量,通过环境变量可能会造成系统安全的问题。
eg:
#include<stdlib.h>
int main()
{
system("clear");
return 1;
}
2、popen(建立管道I/O)
FILE *popen(const char *command, const char *type);
int pclose(FILE *stream);
popen()会调用fork()产生子进程,然后从子进程中调用/bin/sh -c command来执行参数command的指令。依照此type(r,w)值,popen()会建立管道连到子进程的标准输出设备或标准输入设备,然后返回一个文件指针。随后进程便可利用此文件指针来读取子进程的输出设备或是写入到子进程的标准输入设备中。此外,所有使用文件指针(FILE*)操作的函数也都可以使用,除了fclose()以外。
返回值,若成功则返回文件指针,否则返回NULL,错误原因存于errno中。
在编写具SUID/SGID权限的程序时请尽量避免使用popen(),popen()会继承环境变量,通过环境变量可能会造成系统安全的问题。
#include<stdio.h>
int main()
{
FILE *fp;
char buffer[80];
fp=popen("cat /etc/passwd","r");
fgets(buffer,sizeof(buffer),fp);
printf("%s",buffer);
pclose(fp);
return 0;
}
3、exec函数族
exec函数
调用一种exec函数时,该进程完全由新程序代换,而新程序则从其main函数开始执行。
因为调用exec并不创建新进程,所以前后的进程I D并未改变。
exec只是用另一个新程序替换了当前进程的正文、数据、堆和栈段。
进程ID没有改变。执行新程序的进程还保持了原进程的下列特征:
.进程ID和父进程ID。
.实际用户ID和实际组ID。
.添加组ID。
.进程组ID。
.会话ID。
.控制终端。
.闹钟尚余留的时间。
.当前工作目录。
.根目录。
.文件方式创建屏蔽字。
.文件锁。
.进程信号屏蔽。
.未决信号。
.资源限制。
.tms_utime, tms_stime, tms_cutime以及t m s u s t i m e值。
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execle(const char *path, const char *arg,..., char * const envp[]);
int execve(const char *filename, char *const argv[],char *const envp[]);
3.1、execv
使用vfork()新建子进程,然后调用execv
eg:
#include "unistd.h"
#include "stdio.h"
int main()
{
char *argv[] = {"ls", "-al", "/etc/passwd", "char*"};
if(vfork() == 0)
{
execv("/bin/ls", argv);
}
else
{
printf("parent.\n")
}
return 0;}
3.2、execl
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int main(void)
{
pid_t pid;
char *ttargv[]={"tt","123456",NULL};
char *lsargv[]={"ls","-lh","/home",NULL};
pid=fork();
if(pid==-1) return 1;
else if(pid==0) //child
{
printf("child process start:%d\n",getpid());
#if 0
//execl("./tt","tt","123456",NULL);//执行外部程序
execl("/bin/ls","ls","-l","-h","/home",NULL);
#else
//execv("./tt",ttargv);
execv("/bin/ls",lsargv);
#endif //
perror("execl");
exit(2);
}
printf("parent wait child\n");
int val;
wait(&val);
printf("return code:%d\n",WEXITSTATUS(val));
return 0;
}
3.3、execle
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int main(void)
{
pid_t pid;
char *ttargv[]={"tt","123456",NULL};
char *myenv[]={"PATH=./:/tmp:/usr/bin","NAME=king","USER=OOOO",NULL};
pid=fork();
if(pid==-1) return 1;
else if(pid==0) //child
{
printf("child process start:%d\n",getpid());
#if 0
#if 0
execl("./tt","tt","123456",NULL);//执行外部程序
#else
execle("./tt","tt","45678",NULL,myenv);
#endif //
#else
execve("./tt",ttargv,myenv);
#endif //
perror("execl");
exit(2);
}
printf("parent wait child\n");
int val;
wait(&val);
printf("return code:%d\n",WEXITSTATUS(val));
return 0;
}
3.4、execlp
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int main(void)
{
pid_t pid;
char *ttargv[]={"tt","123456",NULL};
char *lsargv[]={"ls","-lh","/home",NULL};
pid=fork();
if(pid==-1) return 1;
else if(pid==0) //child
{
printf("child process start:%d\n",getpid());
#if 1
#if 0
//execl("./tt","tt","123456",NULL);//执行外部程序
//execl("/bin/ls","ls","-l","-h","/home",NULL);
#else //如果没给路径时根据环境PATH找可执行程序
//execlp("tt","tt","123456",NULL);//执行外部程序
execlp("ls","ls","-l","-h","/home",NULL);
#endif //
#else
//execv("./tt",ttargv);
execv("/bin/ls",lsargv);
#endif //
perror("execl");
exit(2);
}
printf("parent wait child\n");
int val;
wait(&val);
printf("return code:%d\n",WEXITSTATUS(val));
return 0;
}
4、总结
a、system()和exec()都可以执行进程外的命令,system是在原进程上开辟了一个新的进程,但是exec是用新进程(命令)覆盖了原有的进程
b、system()和exec()都有能产生返回值,system的返回值并不影响原有进程,但是exec的返回值影响了原进程