exec系列函数和system函数
一、exec替换进程映象
在进程的创建上Unix采用了一个独特的方法,它将进程创建与加载一个新进程映象分离。这样的好处是有更多的余地对两种操作进行管理。当我们创建
了一个进程之后,通常将子进程替换成新的进程映象,这可以用exec系列的函数来进行。当然,exec系列的函数也可以将当前进程替换掉。
二、exec关联函数组
包含头文件<unistd.h>
功能用exec函数可以把当前进程替换为一个新进程。exec名下是由多个关联函数组成的一个完整系列,头文件<unistd.h>
原型
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg,
..., 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[]);
参数
path参数表示你要启动程序的名称包括路径名
arg参数表示启动程序所带的参数
返回值:成功返回0,失败返回-1
execl,execlp,execle(都带“l”)的参数个数是可变的,参数以一个空指针结束。
execv、execvp和execvpe的第二个参数是一个字符串数组,新程序在启动时会把在argv数组中给定的参数传递到main
名字含字母“p”的函数会搜索PATH环境变量去查找新程序的可执行文件。如果可执行文件不在PATH定义的路径上,就必须把包括子目录在内的绝对文件名做为一个参数传递给这些函数。
名字最后一个字母为"e"的函数可以自设环境变量。
这些函数通常都是用execve实现的,这是一种约定俗成的做法,并不是非这样不可。
int execve(const char *filename, char *const argv[], char *const envp[]);
注意,前面6个函数都是C库函数,而execve是一个系统调用。
三、执行exec函数,下面属性是不发生变化的:
- 进程ID和父进程ID(pid, ppid)
- 实际用户ID和实际组ID(ruid, rgid)
- 附加组ID(sgid)
- 会话ID
- 控制终端
- 闹钟余留时间
- 当前工作目录
- 根目录
- umask
- 文件锁
- 进程信号屏蔽
- 未处理信号
- 资源限制
- 进程时间
而下面属性是发生变化的:
- 文件描述符如果存在close-on-exec标记的话,那么打开的文件描述符会被关闭。
- 如果可执行程序文件存在SUID和SGID位的话,那么有效用户ID和组ID(euid, egid)会发生变化
程序启动的时候,所有的信号处理方式都是默认的。然后fork来说,因为子进程和父进程的地址空间是一样的,所以信号处理方式保留了下来。 接下来进行exec,会将所有设置成为捕捉的信号都修改成为默认处理,而原来已经设置成为忽略的信号就不发生改变。
示例程序:
为了演示自设环境变量的功能,先写个小程序,可以输出系统的环境变量
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
/*************************************************************************
> File Name: pid_env.c > Author: Simba > Mail: dameng34@163.com > Created Time: Sun 24 Feb 2013 07:52:09 PM CST ************************************************************************/ #include<stdio.h> extern char **environ; int main(void) |
其中environ是全局变量但没有在头文件中声明,所以使用前需要外部声明一下。输出如下:
simba@ubuntu:~/Documents/code/linux_programming/APUE/process$ ./pid_env
hello pid=5597
TERM=vt100
SHELL=/bin/bash
XDG_SESSION_COOKIE=0ba97773224d90f8e6cd57345132dfd0-1368605430.130657-1433620678
SSH_CLIENT=192.168.232.1 8740 22
SSH_TTY=/dev/pts/0
USER=simba
......................
即输出了一些系统环境的变量,变量较多,省略输出。
我们前面在讲到fcntl 函数时未讲到当cmd参数取F_SETFD时的情形,即设置文件描述符的标志,现结合exec系列函数讲解如下:
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
/*************************************************************************
> File Name: process_.c > Author: Simba > Mail: dameng34@163.com > Created Time: Sat 23 Feb 2013 02:34:02 PM CST ************************************************************************/ #include<sys/types.h> #include<sys/stat.h> #include<unistd.h> #include<fcntl.h> #include<stdio.h> #include<stdlib.h> #include<errno.h> #include<string.h> #define ERR_EXIT(m) \ int ret; char *const envp[] = {"AA=11", "BB=22", NULL}; return 0; |
我们使用了exec系列函数进行举例进程映像的替换,最后未被注释的execle函数需要替换的程序正是我们前面写的输出系统环境变量的小程序,但因为
execle可以自设环境变量,故被替换后的进程输出的环境变量不是系统的那些而是自设的,输出如下:
simba@ubuntu:~/Documents/code/linux_programming/APUE/process$ ./exec
Entering main ...
hello pid=5643
AA=11
BB=22
如果我们将上面 fcntl 函数的注释打开了,即设置当执行exec操作时,关闭标准输出(fd=1)的文件描述符,也就是说
因为如果替换进程映像成功,那么直接到替换进程的main函数开始执行,不会返回,故不会输出Exiting main ...
原型: int system(const char *command);
如果无法启动shell运行命令,system将返回127;出现不能执行system调用的其他错误时返回-1。如果system能够顺利执行,返回那个命令的退出
码。system函数执行时,会调用fork、execve、waitpid等函数。
我们可以自己实现一个my_system函数,如下:
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
/*************************************************************************
> File Name: process_.c > Author: Simba > Mail: dameng34@163.com > Created Time: Sat 23 Feb 2013 02:34:02 PM CST ************************************************************************/ #include<sys/types.h> #include<sys/stat.h> #include<unistd.h> #include<fcntl.h> #include<stdio.h> #include<stdlib.h> #include<errno.h> #include<string.h> #include<sys/wait.h> #define ERR_EXIT(m) \ int my_system(const char *command); int main(int argc, char *argv[]) int my_system(const char *command) if ((pid = fork()) < 0) return status; |
需要说明的是在while循环中,如果waitpid返回-1错误,则还需要判断一下是否被信号处理函数所中断,如果是则继续等待,否则跳出循环。man 7
signal 有如下解释:
If a signal handler is invoked while a system call or library function call is blocked, then either:
* the call is automatically restarted after the signal handler returns; or
* the call fails with the error EINTR.
参考:《APUE》
exec系列函数和system函数的更多相关文章
- 16、cgminer学习之:popen函数和system函数详解(执行系统命令)
1.popen函数我们先用man指令查一下popen函数: 函数说明: (1)popen()会调用fork()产生子进程,然后从子进程中调用/bin/sh -c来执行参数command的指令. (2) ...
- 一、进程与信号之exec函数system函数
exec函数: 子进程调用exec函数执行另一个程序,exec函数进程完全由新程序代替,替换原有程序正文,数据,堆,栈段 #include <unistd.h> extern char * ...
- 对于linux下system()函数的深度理解(整理)
原谅: http://blog.sina.com.cn/s/blog_8043547601017qk0.html 这几天调程序(嵌入式linux),发现程序有时就莫名其妙的死掉,每次都定位在程序中不同 ...
- 转:对于linux下system()函数的深度理解(整理)
这几天调程序(嵌入式linux),发现程序有时就莫名其妙的死掉,每次都定位在程序中不同的system()函数,直接在shell下输入system()函数中调用的命令也都一切正常.就没理这个bug,以为 ...
- system函数遇到的问题 - 程序死掉
system函数遇到的问题 解决方案见最下边 http://blog.csdn.net/yangzhenzhen/article/details/51505176 这几天调程序(嵌入式linux),发 ...
- system函数遇到的问题
这几天调程序(嵌入式linux),发现程序有时就莫名其妙的死掉,每次都定位在程序中不同的system()函数,直接在shell下输入system()函数中调用的命令也都一切正常.就没理这个bug,以 ...
- (笔记)Linux下system()函数的深度理解(整理)
注:从其它地方转的非常好的一篇文章,值得深究! 这几天调程序(嵌入式linux),发现程序有时就莫名其妙的死掉,每次都定位在程序中不同的system()函数,直接在shell下输入system()函数 ...
- linux系统编程之进程(七):system()函数使用
一,system()理解 功能:system()函数调用"/bin/sh -c command"执行特定的命令,阻塞当前进程直到command命令执行完毕 原型: int syst ...
- linux系统编程之进程(七):system()函数使用【转】
本文转载自:http://www.cnblogs.com/mickole/p/3187974.html 一,system()理解 功能:system()函数调用“/bin/sh -c command” ...
随机推荐
- Objective-C-Category类别
Object-C开发的时候有的时候会用到Category类,类似于Java和C#中扩展类,就是如果你觉得如果你觉得常用的方法在String中没有,可以根据业务需求和个人喜好写一个扩展类,然后在其中补充 ...
- Vue路由scrollBehavior滚动行为控制锚点
使用前端路由,当切换到新路由时,想要页面滚到顶部,或者是保持原先的滚动位置,就像重新加载页面那样. vue-router 能做到,而且更好,它让你可以自定义路由切换时页面如何滚动. 注意: 这个功能只 ...
- 关于C++ 中POD类型的解析
转自: http://liuqifly.spaces.live.com/blog/cns!216ae3a149106df9!221.entry (C++-98:1.8;5)给出的定义:将对象的各字节拷 ...
- Android -- 文件扫描
启动MediaScanner服务,扫描媒体文件,程序通过发送下面的Intent启动MediaScanner服务. 扫描指定文件 public void scanFile(Context ctx, St ...
- rapidxml修改节点的值
1.rapidxml修改节点的value,修改之后,序列化还是原来的值,具体原因是什么,要看rapidxml是怎么实现的.如下: void TestRapidXml() { ]; sprintf(xm ...
- SqlServer 之 系统视图
一.了解系统视图 1. 系统视图:从名字上看就知道,就是存放一些sqlserver系统的一些信息. 2. 存在位置: 下面截图看看,从截图中你可以看到,不管是“系统数据库”还是“用户数据库”都是有这些 ...
- JAVA中MD5加密实现
MD5加密实现 结 package com.pb; import java.io.UnsupportedEncodingException; import java.security.Message ...
- alias的使用
alias,即别名.可以通过较短的别名,来实现对应的真实的命令.将alias定义在.bash_profile文件中,即可在任意目录下执行自己定义的这些命令了. 1. 命令 alias myDir='c ...
- 关于csdn博客中案例效果的动态演示
在曾经一篇博文中,网友评论说要是案例效果是动态演示的就好了,我认为说的非常是有道理.由于一个简单的截图不能非常好的展示案例效果.要是有一张gif图能动态的播放案例效果就再好只是了.在这里提供一个小软件 ...
- PHP 循环
PHP 中的循环语句用于执行相同的代码块指定的次数. 循环 在您编写代码时,您经常需要让相同的代码块运行很多次.您可以在代码中使用循环语句来完成这个任务. 在 PHP 中,我们可以使用下列循环语句: ...