文章大部分为摘抄,有些没有标明出处,请谅解。
通过popen查看selinux是否打开:
#include <stdio.h>
#include <stdlib.h>
int main () {
char cmd[64] = {0};
char buf[64] = {0};
FILE *fd;
sprintf(cmd,"getenforce\n");
fd = popen(cmd, "r" );
if(NULL == fd) {
LOGD("%s: popen error.\n", __FUNCTION__);
return 0;
}
fread(buf, sizeof(char), sizeof(buf), fd);
LOGD("chenpuo popen buf=%s",buf);
rc= pclose(fd2);
if(-1==rc){
ALOGD("getenforce close file failed");
if(ECHILD==errno) {
ALOGD("cyx pclose cannot obtain the child status.\n");
} else {
ALOGD( "getenforce Close file failed. %s, with errno %d.\n", strerror(errno), errno);
}
}else{
ALOGD("cmd getenforce child proccess %d status=%d strerr=%s\r\n", rc, WEXITSTATUS(rc), strerror(errno));
}
}
注意:这里cmd只要执行成功,则errno就为success;
奇怪的ls /data/test.log命令,如果文件不存在errno居然也是success,此时 No such file or directory 信息似乎打印不出来,buf为空。如果存在则buf为正常,为/data/test.log
#include “stdio.h”
#include “stdlib.h”
int main()
{
FILE *fp;
char buf[200] = {0};
if((fp = popen(“cat > test1″, “w”)) == NULL) {
perror(“Fail to popen\n”);
exit(1);
}
fwrite(“Read pipe successfully !”, 1, sizeof(“Read pipe successfully !”), fp);
pclose(fp);
return 0;
}
int main()
{
FILE * fp;
char buf[40] = {0};
fp = popen(NULL, "w");
if(NULL == fp)
{
perror("popen error.\n");
return -1;
}
printf("Input command:");
fgets(buf, 40, stdin);
fputs(buf, fp);
pclose(fp);
return 0;
}
执行结果:
[root@localhost codetest]# ./a.out
sh: -c: option requires an argument
Input command:pwd
==============================system函数====================================
看到popen就很容易想到system, system这个函数在老的平台里经常看到。现在很少看到使用了。 究其原因:
1)system 缺点:
12 | #include <stdlib.h> int system ( const char *command); |
system()函数执行过程为:fork()->exec()->waitpid()。
system() executes a command specified in command by calling /bin/sh -c command, and returns after the command has been completed. During execution of the command, SIGCHLD will be blocked, and SIGINT and SIGQUIT will be ignored.
system()函数调用/bin/sh来执行参数指定的命令,/bin/sh 一般是一个软连接,指向某个具体的shell,比如bash,-c选项是告诉shell从字符串command中读取命令; 在该command执行期间,SIGCHLD是被阻塞的,好比在说:hi,内核,这会不要给我送SIGCHLD信号,等我忙完再说; 在该command执行期间,SIGINT和SIGQUIT是被忽略的,意思是进程收到这两个信号后没有任何动作。
system()函数用起来很容易出错,返回值太多,而且返回值很容易跟command的返回值混淆
system的实际问题:
转自 http://my.oschina.net/renhc/blog/54582 这里自己看后比较有感受,遂简单转述了下。
简单概括就是:系统的同事在LIBGEN 里新增加了SIGCHLD的处理。将其ignore。为了避免僵尸进程的产生。 于是我们调用system就会出错ECHILD 即No child processes 。man手册查找system函数,没有此errno;再看waitpid里正好有此errno。
ECHILD (for waitpid() or waitid()) The process specified by pid (waitpid()) or idtype and id (waitid()) does not exist or is not a child of the calling process. (This can happen for one's own child if the action for SIGCHLD is set to SIG_IGN. See also the Linux Notes section about threads.) 果然有料,如果SIGCHLD信号行为被设置为SIG_IGN时,waitpid()函数有可能因为找不到子进程而报ECHILD错误。似乎我们找到了问题的解决方案:在调用system()函数前重新设置SIGCHLD信号为缺省值,即signal(SIGCHLD, SIG_DFL)。
最好如下修改可以:
typedef void (*sighandler_t)( int ); int pox_system( const char *cmd_line) { int ret = 0; sighandler_t old_handler; ++ old_handler = signal (SIGCHLD, SIG_DFL); ret = system (cmd_line); ++ signal (SIGCHLD, old_handler); return ret; } |
这里推荐使用popen()函数替代,关于popen()函数的简单使用也可以通过上面的链接查看。
popen()函数较于system()函数的优势在于使用简单,popen()函数只返回两个值:
成功返回子进程的status,使用WIFEXITED相关宏就可以取得command的返回结果;
失败返回-1,我们可以使用perro()函数或strerror()函数得到有用的错误信息。
=================================最后PS================================
在特权(setuid、setgid)进程中千万注意不要使用system和popen
popen()、popen()会继承环境变量,通过环境变量可能会造成系统安全的问题。