#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-playbook用法

    一.playbook用法 1.playbook的执行文件为YAML语言编写,所以文件名为xxx.yml.YAML语法可以参考https://docs.ansible.com/ansible/lates ...

  2. 使用cert-manager实现Ingress https

    什么是https 超文本传输协议HTTP协议被用于在Web浏览器和网站服务器之间传递信息,HTTP协议以明文方式发送内容,不提供任何方式的数据加密,如果攻击者截取了Web浏览器和网站服务器之间的传输报 ...

  3. Java 集合系列之一:JCF集合框架概述

    容器,就是可以容纳其他Java对象的对象.Java Collections Framework(JCF)为Java开发者提供了通用的容器 java集合主要划分为四个部分: Collection(Lis ...

  4. Angular记录(11)

    开始使用Angular写页面 使用WebStorm:版本2018.3.5 官网资料 资料大部分有中文翻译,很不错 速查表:https://www.angular.cn/guide/cheatsheet ...

  5. Ubuntu屏幕分辨率无1920 1080

    xrandr 没有1920X1080分辨率,所以手动添加一个1080P分辨率,先输入“cvt 1920 1080”命令,查询一下1080P分辨率的有效扫描频率 然后 sudo xrandr --new ...

  6. web 框架

    一个实际的案例介绍Spring Boot + Vue 前后端分离 https://www.cnblogs.com/nele/p/7858581.html#_caption_7 https://www. ...

  7. .NET面试题系列(十八)常用关键字

    序言 const和readonly关键字 private protected public internal的区别 out  ref out适合用在需要retrun多个返回值的地方,而ref则用在需要 ...

  8. Exp2 后门原理与实践 20164314 郭浏聿

    1.实践内容 (1)使用nc实现win,Linux间的后门连接. 热身 (2)使用netcat获取主机操作Shell,cron启动. (3)使用socat获取主机操作Shell, 任务计划启动. (4 ...

  9. exists,in的区别-mysql

    如说两张表一张是用户表TDefUser(userid,address,phone),一张是消费表TAccConsume(userid,time,amount),我要查消费超过5000的用户记录,那么我 ...

  10. Flsk-Bootstrap-2

    目录 Flsk-Bootstrap-2 结构 解压Bootstrap 制作基础模板 视图函数 初始文件 启动文件 浏览器 Flsk-Bootstrap-2 参考:Flask 项目中使用 bootstr ...