1. execv()
1.1函数原型
#include <
unistd.h>
int execv(const char *progname, char *const argv[]);
1.2 用法介绍
execv会停止执行当前的进程,并且以progname应用进程替换被停止执行的进程,进程ID没有改变。
progname: 被执行的应用程序。
argv: 传递给应用程序的参数列表, 注意这个数组的第一个参数应该是应用程序名字本身(即argv[0] = progname),并且最后一个参数应该为NULL,不能将多个参数合并为一个参数放入数组。
1.3 返回值
如果应用程序正常执行完毕,那么execv是永远不会返回的;当execv在调用进程中返回时,那么这个应用程序应该出错了(可能是程序本身没找到,权限不够等), 此时它的返回值应该是-1,具体的错误代码可以通过全局变量errno查看,还可以通过stderr得到具体的错误描述字符串。
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
main(void)
{
pid_t pid = fork();
if( pid == 0 ) // this is the child process
{
char *arg1 = "system/bin/sh";
char *arg2 = "-c";
char *arg3 = "mkdir mydir";
char *arg4 = NULL;
char *arg[] = {arg1, arg2, arg3, arg4};
execv(arg[0], &arg[0]);
// the program should not reach here, or it means error occurs during execute the ls command.
printf("command ls is not found, error code: %d(%s)", errno, strerror(errno);
}
}
2. wait(等待子进程中断或结束)
2.1 函数原型
#include<sys/types.h>
#include<sys/wait.h>
pid_t wait (int * status);
2.2 函数说明:
(1) wait()会暂时停止目前进程的执行,直到有信号来到或子进程结束。如
果在调用 wait()时子进程已经结束,则 wait()会立即返回子进程结束状态值。
(2) 子进程的结束状态值会由参数 status 返回,而子进程的进程识别码也会一起返回。状态值status的具体含义请参考 waitpid()。
(3) 如果执行成功则返回子进程PID,如果有错误发生则返回返回值-1,失败原因存于 errno 中。
(4) 如果不需要status状态值,则参数 status 可以设成 NULL。
#include<sys/types.h>
#include<sys/wait.h>
pid_t waitpid(pid_t pid, int * status, int options);
3.2 函数说明:
(1) waitpid()会暂时停止目前进程的执行,直到有信号来到或子进程结束。
如果在调用waitpid()时子进程已经结束,则 waitpid()会立即返回子进程结束状态值。
(2) 子进程的结束状态值会由参数 status 返回,而子进程的进程识别码也会一快返回。
(3) 如果执行成功则返回子进程PID,如果有错误发生则返回返回值-1,失败原因存于 errno 中。
(4) 如果不在意结束状态值,则参数 status 可以设成 NULL。
(5)
参数 pid 为欲等待的子进程识别码,其他数值意义如下:
pid<-1 等待进程组识别码为 pid 绝对值的任何子进程。
pid=-1 等待任何子进程,相当于 wait()。
pid=0 等待进程组识别码与目前进程相同的任何子进程。
pid>0 等待任何子进程识别码为 pid 的子进程。
(6)
参数 option 可以为 0 或下面的 OR 组合:
WNOHANG 如果没有任何已经结束的子进程则马上返回, 不予以等待。
WUNTRACED 如果子进程进入暂停执行情况则马上返回,但结束状态不予以理会。
(7) 子进程的结束状态返回后存于 status, 底下有几个宏可判别结束情况:
//Linux <sys/wait.h>
#define WEXITSTATUS(s) (((s) & 0xff00) >> 8)
#define WCOREDUMP(s) ((s) & 0x80)
#define WTERMSIG(s) ((s) & 0x7f)
#define WSTOPSIG(s) WEXITSTATUS(s)
#define WIFEXITED(s) (WTERMSIG(s) == 0)
#define WIFSTOPPED(s) (WTERMSIG(s) == 0x7f)
#define WIFSIGNALED(s) (WTERMSIG((s)+1) >= 2)
a. WIFEXITED(status) 如果子进程正常结束则为true。exit(0), exit(-1), 都是正常结束。例如 exit(0), status = 0; exit(-1), status = 0xFF00; exit(-10), status = 0xF600
b. WEXITSTATUS(status) 取得子进程 exit()返回的结束代码,一般会先用 WIFEXITED 来判断是否正常结束才能使用此宏。
c. WIFSIGNALED(status) 如果子进程是因为信号而结束则此宏值为真。
d. WTERMSIG(status) 取得子进程因信号而中止的信号代码,一般会先用 WIFSIGNALED 来判断后才使用此宏。
e. WIFSTOPPED(status) 如果子进程处于暂停执行情况则此宏值为真。一般只有使用 WUNTRACED 时才会有此情况。
f. WSTOPSIG(status) 取得引发子进程暂停的信号代码,一般会先用 WIFSTOPPED 来判断后才使用此宏。
3.3 调用举例
int main() {
int cpid = fork();
if (cpid < 0) {
return -1;
} else if (cpid == 0) {
char *arg1 = "system/bin/sh";
char *arg2 = "-c";
char *arg3 = "mkdir mydir";
char *arg4 = NULL;
char *arg[] = {arg1, arg2, arg3, arg4};
execv(arg[0], &arg[0]);
printf("########## exec_command(): error code: %d(%s) ##########", errno, strerror(errno));
exit(-1);
} else {
int status = -1;
int count = 0;
while(1)
{
//int ret = waitpid(cpid, &status, 0); 如果子进程不结束会一直死等
int ret = waitpid(cpid, &status, WNOHANG);//WNOHANG 配合while 循环可以实现超时机制
if (ret) {
if (WIFEXITED(status)) {
//子进程正常结束: exit(任意值无论正负), execv()执行结束没有崩溃
//1. execv()执行成功结束: status = 0
//2. execv()执行结束,但可能没有执行成功,内部调用了exit(-1): status = 0xFF00
//3. 子进程直接调用 exit(-1): status = 0xFF00
//4. 子进程直接调用 exit(-10): status = 0xF600
if (WEXITSTATUS(status) == 0xFF) {
//TODO
} else if (WEXITSTATUS(status) == 0xF6) {
//TODO
} else {
//TODO
}
} else {
//子进程非正常结束:子进程执行execv()发生崩溃,子进程是因为信号signal而结束
//TODO
}
break;
}
if (++count >= 60) {
//timeout = 60s
break;
}
sleep(1);
}
}
return 0;
}