#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> #include <sys/types.h>
#include <sys/wait.h>
#include <signal.h> /* 参考 glibc sysdeps/posix/system.c: __libc_system/do_system */
int test_system(char* cmd)
{
int status;
pid_t pid;
struct sigaction sa;
struct sigaction intr, quit;
sigset_t omask; if (NULL == cmd) {/* glibc中当cmd为空时, 将cmd赋值为 'exit 0' */
return 0;
} sa.sa_handler = SIG_IGN; /* 对捕获的信号采取忽略操作 */
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask); /* 清空信号集, 不包含任何信号 */ /* 忽略 SIGINT 和 SIGQUIT 信号, 为什么?
有谁知道吗?
参考:https://www.cons.org/cracauer/sigint.html */
sigaction(SIGINT, &sa, &intr); /* 原有 SIGINT 处理存储到 intr 中, 用于恢复 */
sigaction(SIGQUIT, &sa, &quit); /* 原有 SIGQUIT 处理存储到 quit 中,用于恢复 */ /* 阻塞SIGCHLD信号,为什么?
子进程结束后,内核会给父进程发送SIGCHLD信号, 如果你注册了该信号的处理函数,并且
在其中也用waipid获取了子进程结束的状态, 当信号处理函数先于system中waitpid执行,
随后system函数中的waipid就会返回 No child processes 错误,无法获取到shell命令执行的结果, 只能返回 -1.
阻塞SIGCHLD可以确保system中waitpid先执行, 以获取子进程结束状态,
阻塞SIGCHLD期间, 如果还有其他子进程退出, 那么他们产生的SIGCHLD信号也会阻塞,
但是阻塞解除后你只会收到一个SIGCHLD通知,如果你需要使用waitpid获取所以子进程状态,那么需要循环调用waitpid */
sigaddset(&sa.sa_mask, SIGCHLD); /* 复用面前的信号集(空的), 将SIGCHLD信号加入信号集 */
sigprocmask(SIG_BLOCK, &sa.sa_mask, &omask); /* 阻塞信号集中的信号(其实信号集中只有SIGCHLD信号) */ pid = fork();
if (pid == (pid_t)0) {/* 子进程 */
const char *new_argv[4];
new_argv[0] = "sh";
new_argv[1] = "-c";
new_argv[2] = cmd;
new_argv[3] = NULL; /* 子进程继承父进程的信号掩码, 恢复SIGINT和SIGQUIT的信号处理操作. */
sigaction(SIGINT, &intr, (struct sigaction *)NULL);
sigaction(SIGQUIT, &quit, (struct sigaction *)NULL);
sigprocmask(SIG_SETMASK, &omask, (sigset_t *)NULL); /* Exec the shell. */
(void)execve("/bin/sh", (char *const *) new_argv, __environ);
/* execve通常不会返回, 返回就说明发生错误 */
_exit(127); /* 子进程返回状态码127 */
}
else if (pid < (pid_t) 0) {
/* fork()失败返回 -1 */
status = -1; /* 错误查看 errno */
}
else { /* 父进程 */
/* Note the system() is a cancellation point. But since we call
waitpid() which itself is a cancellation point we do not have to do anything here. */
if (waitpid(pid, &status, 0) != pid) {/* 子进程回收 */
status = -1; /* 错误查看 errno */
}
} /* 父进程信号处理恢复 */
sigaction(SIGINT, &intr, (struct sigaction *)NULL);
sigaction(SIGQUIT, &quit, (struct sigaction *)NULL);
sigprocmask(SIG_SETMASK, &omask, (sigset_t *)NULL); return status;
}

Linux下system()函数的实现的更多相关文章

  1. 对于linux下system()函数的深度理解(整理)

    原谅: http://blog.sina.com.cn/s/blog_8043547601017qk0.html 这几天调程序(嵌入式linux),发现程序有时就莫名其妙的死掉,每次都定位在程序中不同 ...

  2. 转:对于linux下system()函数的深度理解(整理)

    这几天调程序(嵌入式linux),发现程序有时就莫名其妙的死掉,每次都定位在程序中不同的system()函数,直接在shell下输入system()函数中调用的命令也都一切正常.就没理这个bug,以为 ...

  3. 【C/C++】Linux下system()函数引发的错误

    http://my.oschina.net/renhc/blog/54582 [C/C++]Linux下system()函数引发的错误 恋恋美食  恋恋美食 发布时间: 2012/04/21 11:3 ...

  4. (笔记)Linux下system()函数的深度理解(整理)

    注:从其它地方转的非常好的一篇文章,值得深究! 这几天调程序(嵌入式linux),发现程序有时就莫名其妙的死掉,每次都定位在程序中不同的system()函数,直接在shell下输入system()函数 ...

  5. 关于linux下system()函数的总结

    导读 曾经的曾经,被system()函数折磨过,之所以这样,是因为对system()函数了解不够深入.这里必须要搞懂system()函数,因为有时你不得不面对它. 先来看一下system()函数的简单 ...

  6. [转载]关于linux下system()函数的总结

    1.曾经的曾经,被system()函数折磨过,之所以这样,是因为对system()函数了解不够深入.这里必须要搞懂system()函数,因为有时你不得不面对它. 2.先来看一下system()函数的简 ...

  7. Linux下system函数

    http://www.jb51.net/article/40517.htm   浅析如何在c语言中调用Linux脚本 http://blog.csdn.net/koches/article/detai ...

  8. linux下syscall函数,SYS_gettid,SYS_tgkill

    出处:http://blog.chinaunix.net/uid-28458801-id-4630215.html     linux下syscall函数,SYS_gettid,SYS_tgkill  ...

  9. Linux下c函数dlopen实现加载动态库so文件代码举例

    dlopen()是一个强大的库函数.该函数将打开一个新库,并把它装入内存.该函数主要用来加载库中的符号,这些符号在编译的时候是不知道的.这种机制使得在系统中添加或者删除一个模块时,都不需要重新编译了. ...

随机推荐

  1. ansible迭代/迭代嵌套/同步异步/特殊topic说明

    tasks直接举例说明: ---- host: docker  remote_user: root  gather_facts: yes  serial: 3 #表示同一时间控制主机数量(值可以是数值 ...

  2. (Python)自动生成代码(方法一)

    在写某个平台的自动化脚本时,笔者把全部的操作都封装到了两个类中,page.py和commonpage.py: page.py部分代码: class BasePage(object): ''' 页面基础 ...

  3. HIS(LIS、PACS、RIS、EMR)系统简介

    HIS(LIS.PACS.RIS.EMR)系统简介 HIS:医院信息系统(Hospital Information System, HIS),利用电子计算机和通讯设备,为医院所属各部 门提供病人诊疗信 ...

  4. python之路(3)函数和匿名函数

    函数 函数与过程 过程 def test(): "注释" print('1 am chen') test() : 过程调用 def : 定义函数的关键字 test : 函数名 pr ...

  5. 五十六、linux 编程——UDP 编程模型

    56.1 UDP 编程模型 56.1.1 编程模型 UDP 协议称为用户数据报文协议,可靠性比 TCP 低,但执行效率高 56.1.2 API (1)发送数据 函数参数: sockfs:套接字文件描述 ...

  6. D. Vanya and Treasure Codeforces Round #355 (Div. 2)

    http://codeforces.com/contest/677/problem/D 建颗新树,节点元素包含r.c.dis,第i层包含拥有编号为i的钥匙的所有节点.用i-1层更新i层,逐层更新到底层 ...

  7. 在Windows2008r2 安装.net4.5

    WebApi 是比较高的环境下面开发 需要的环境是net4.5 或以上. Windows2008r2 里面没有这个环境必须自己安装.安装net4.5 必须sp1环境以上才能安装. 将Windows20 ...

  8. Nginx开启gzip压缩解决react打包文件过大

    用create-react-app创建的react应用打包之后的build js有1M之多. 采用gzip打包传输,可以节约70%左右的带宽 nginx采用gzip打包方式 在nginx配置中添加如下 ...

  9. flask学习(二)

    一.蓝图 作用:给开发者提供目录结构 功能:1.自定义模板.静态文件目录 2.给一类url加前缀    3.给一类url添加before_request 目录结构 from flask_werkzur ...

  10. MailKit系列之附件分离

    本文主要谈谈实现思路,不提供完整代码 一.分离基础 1.MIME邮件的multipart类型 引用文章:https://blog.csdn.net/wangyu13476969128/article/ ...