#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. python第九天

    复习内容: 文件处理 1. 操作文件的三步骤: ---打开文件:硬盘的空间被操作系统持有  |  文件对象被应用程序持有 ---操作文件:读写操作 ---释放文件:释放操作系统对硬盘空间的持有 2. ...

  2. Vue(小案例_vue+axios仿手机app)_Vuex优化购物车功能

    一.前言         1.用vuex实现加入购物车操作 2.购物车详情页面          3.点击删除按钮,删除购物详情页面里的对应商品 二.主要内容 1.用vuex加入购物车 (1)在src ...

  3. IntelliJ IDEA 2017新工具

    IntelliJ IDEA 2017 教程之概述 图文详解如何安装 Intellij IDEA 2017 深入剖析 IntelliJ IDEA 2017 的目录结构 图文详解如何配置 IntelliJ ...

  4. codeforces-1132 (div2)

    A.发现b的个数没有意义,a不等于d一定不可行,c不管多少都算一个,如果只有c没有ad也不可行 #include <map> #include <set> #include & ...

  5. Synchronized与ReentrantLock区别总结(简单粗暴,一目了然)

    这篇文章是关于这两个同步锁的简单总结比较,关于底层源码实现原理没有过多涉及,后面会有关于这两个同步锁的底层原理篇幅去介绍. 相似点:这两种同步方式有很多相似之处,它们都是加锁方式同步,而且都是阻塞式的 ...

  6. 04-oracle中的视图

    1.创建视图 介绍: 视图(View)通过SELECT查询语句定义,它是从一个或多个表(或视图)导出的,用来导出视图的表称为基表(Base Table),导出的视图称为虚表.在数据库中,只存储视图的定 ...

  7. js 遍历集合删除元素

    js 遍历集合删除元素 /** * 有效的方式 - 改变下标,控制遍历 */ for (var i = 0; i < arr.length; i++) { if (...) { arr.spli ...

  8. 【AGC 005F】Many Easy Problems

    Description One day, Takahashi was given the following problem from Aoki: You are given a tree with ...

  9. 背景上实现阴影——linear-gradient

    /*从元素顶部有条阴影,两种方式,第二种更好,能控制阴影的宽度*/background-image: linear-gradient(0deg, rgba(226, 226, 226, 0) 97%, ...

  10. setLocale(java.util.Locale), setCharacterEncoding(java.lang.String),setContentType(java.lang.String type)

    对于setCharacterEncoding(java.lang.String),这个方法是javax.servlet.ServletRequest和javax.servlet.ServletResp ...