引入
如何在某进程内部启动一个外部程序,由内核将该外部程序读入内存,使其执行成为一个进程?
使用exec函数族实现。
exec函数族
#include<unistd.h>
extern char** environ;
int execl(const char* path, const char* arg, .../* (char*) NULL*/);
int execlp(const char* file, const char* arg, .../* (char*) NULL*/);
int execle(const char* path, const char* arg, .../* , (char*) NULL, char* const envp[]*/);
int execv(const char* path, char* const argv[]);
int execvp(const char* file, char* const argv[]);
int execvpe(const char* file, char* const argv[], char* const envp[]);
int execve(const char* filename, char* const argv[], char* const envp[]);
/*
只有execve是真正意义上的系统调用,其他都是在此基础上包装过的库函数
功能:
根据文件名file找到可执行文件来取代调用进程的内容,即在调用进程内部执行一个可执行文件。
进程调用exec函数时,该进程完全由新程序替换,新程序从其main函数开始执行。
调用exec函数不会创建新进程,因此进程pid、父进程号、进程组号、当前工作目录不会改变。
exec只是用一个新程序替换当前进程的正文、数据、堆栈。
参数:
path:可执行程序的完整路径名;若不以/开头,则会到当前工作目录查找;
file:可执行程序文件名,若不以/开头,则会根据PATH环境变量查找。
envp:传递给新程序环境变量数组,必须以NULL结尾。若无此参数,则新程序会继承原程序的环境变量。
返回值:
成功:不会返回,因为进程地址空间已被新程序替换;
失败:-1,并设置errno
*/
execlp使用示例1,使用进程回收示例程序替换当前程序:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int main(void) {
printf("Before exec.\n");
/*
int execlp(const char* file, const char* arg, .../* (char*) NULL*/);
file是可执行程序文件名,若不以/开头,则会根据PATH环境变量查找,
arg0是可执行程序名;
arg1及后面是可执行文件的参数;
最后一个参数是NULL;
*/
execlp("./a.out", "./a.out", NULL); // a.out为进程回收示例程序
printf("After exec.\n"); // 不会执行,因为被替换了
return 0;
}
运行结果:
execlp使用示例2,使用ls -l /home命令替换:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int main(void) {
printf("Before exec.\n");
/*
int execlp(const char* file, const char* arg, .../* (char*) NULL*/);
file是可执行程序文件名,若不以/开头,则会根据PATH环境变量查找,
arg0是可执行程序名;
arg1及后面是可执行文件的参数;
最后一个参数是NULL。
*/
execlp("ls", "ls", "-l", "/home", NULL); // 等价于ls -l /home
printf("After exec.\n"); // 不会执行,因为被替换了
return 0;
}
运行结果:
执行到exec函数,使用其中指定的可执行程序将原程序全部替换,并从新程序的主函数执行,所以原程序中exec的后续程序不会执行。
execl使用示例:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int main(void) {
printf("Before exec.\n");
/*
int execl(const char* path, const char* arg, .../* (char*) NULL*/);
path是可执行程序的绝对路径或相对路径;
arg0是可执行程序名;
arg1及后面是可执行文件的参数;
最后一个参数是NULL。
*/
execl("/bin/ls", "ls", "-l", "/home", NULL);
printf("After exec.\n"); // 不会执行,因为被替换了
return 0;
}
运行结果:
execv使用示例:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
int main() {
printf("before exec.\n");
char* argv[] = { "ls", "/home", NULL }; // execv的第二个参数
execv("/bin/ls", argv);
printf("after exec");
return 0;
}
运行结果:
execvp使用示例:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
int main() {
printf("before exec.\n");
char* argv[] = { "ls", "/home", NULL }; // execvp的第二个参数
execvp("ls", argv);
printf("after exec");
return 0;
}
运行结果:
execle示例:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
int main() {
printf("before exec.\n");
char* argv[] = { "ls", "/home", NULL }; // execvp的第二个参数
char* envp[] = { "ADDR=BEIJING",NULL }; // 环境变量指针数组
execle("/bin/ls", "ls", "-l", "/home", NULL, envp);
printf("after exec");
return 0;
}
运行结果: