• 进程控制之system函数


    ISO C定义了system函数,但是其操作对系统的依赖性很强。POSIX.1包括了system接口,它扩展了ISO C定义,以描述system在POSIX.1环境中的运行行为。

    #include <stdlib.h>
    int system( const char *cmdstring );

    如果cmdstring是一个空指针,则仅当命令处理程序可用时,system返回非0值,这一特征可以确定在一个给定的操作系统上是否支持system函数。在UNIX中,system总是可用的。

    因为system在其实现中调用了fork、exec和waitpid,因此有三种返回值:

    (1)如果fork失败或者waitpid返回除EINTR之外的出错,则system返回-1,并且在errno中设置相应的错误类型值。

    (2)如果exec失败(表示不能执行shell),则其返回值如同shell执行了exit(127)一样。

    (3)否则所有三个函数(fork、exec和waitpid)都执行成功,并且system的返回值是shell的终止状态,其格式已在waipid中说明(参见http://www.cnblogs.com/nufangrensheng/p/3510101.html)。

    程序清单8-12 system函数(没有信号处理)

    [root@localhost apue]# cat system_nosighandling.c
    #include <sys/wait.h>
    #include <errno.h>
    #include <unistd.h>
    
    int
    system(const char *cmdstring)   /* version without signal handling */
    {
            pid_t   pid;
            int     status;
    
            if (cmdstring == NULL)
                    return(1);      /* always a command processor with UNIX */
    
            if ((pid = fork()) < 0)
            {
                    status = -1;    /* probably out of processes */
            }
            else if (pid == 0)      /* child */
            {
                   /*
                    *  execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);
                    * _exit(127);     /* execl error */ 
                    * 此处程序原来是如上面所示,但我无法理解这里的逻辑(感觉是有问题的,但是执行也可获得正确结果)
                       * 改为了下面的形式
                       */
                    if (execl("/bin/sh", "sh", "-c", cmdstring, (char *)0) < 0)
                    {
                            _exit(127);     /* execl error */            
                    }
            }
            else                    /* parent */
            {
                    while (waitpid(pid, &status, 0) < 0)
                    {
                            if (errno != EINTR)
                            {
                                    status = -1; /* error other than EINTR from waitpid() */
                                    break;
                            }
                    }
            }
    
            return(status);
    }

    shell的-c选项告诉shell程序取下一个命令行参数(在这里是cmdstring)作为命令输入(而不是标准输入或从一个给定的文件中读命令)。shell对以null字符终止的命令字符串进行语法分析,将它们分成命令行参数(如果不使用shell执行此命令,而是试图由我们自己去执行它,那么将相当困难。传递给shell的实际命令字符串可以包含任一有效的shell命令。

    注意,我们调用_exit而不是exit。这是为了防止任一标准I/O缓冲区(这些缓冲区会在fork中由父进程复制给子进程,详情请参考:http://www.cnblogs.com/nufangrensheng/p/3509492.html)在子进程中被冲洗。

    程序清单8-13 调用system函数

    [root@localhost apue]# cat prog8-13.c
    #include "apue.h"
    #include <sys/wait.h>
    
    int
    main(void)
    {
            int     status;
    
            if ((status = system("date")) < 0)
                    err_sys("system() error");
            pr_exit(status);
    
            if ((status = system("nosuchcommand")) < 0)
                    err_sys("system() error");
            pr_exit(status);
    
            if ((status = system("who; exit 44")) < 0)
                    err_sys("system() error");
            pr_exit(status);
    
            exit(0);
    }

    运行程序清单8-13得到:

    [root@localhost apue]# ./prog8-13
    Wed Jan  8 23:06:53 PST 2014
    normal termination, exit status = 0             对于date
    sh: nosuchcommand: command not found
    normal termination, exit status = 127           对于无此种命令
    root     pts/0        2014-01-03 22:57 (:0.0)
    normal termination, exit status = 44            对于exit

    使用system而不是直接使用fork和exec的优点是:system进行了所需的各种出错处理,以及各种信号处理(在带信号处理的system版本中)。

     

    设置用户ID程序

    如果在一个设置用户ID程序中调用system,那么会发生什么呢?这是一个安全性方面的漏洞,决不应当这样做。

    如果一个进程正以特殊的权限(设置用户ID或设置组ID)运行,它又想生成另一个进程执行另一个程序,则它应当直接使用fork和exec,而且在fork之后、exec之前要改回到普通权限。设置用户ID或设置组ID程序决不应调用system函数。

     

    本篇博文内容摘自《UNIX环境高级编程》(第二版),仅作个人学习记录所用。关于本书可参考:http://www.apuebook.com/

  • 相关阅读:
    Struts2的配置中:Could not find action or result 问题的解决方法
    Oracle 数据库 Record is locked by another user 问题解决办法
    设计模式六大原则(2):里氏替换原则
    在PL/SQL中 自动复制转换StringBuffer的SQL
    反射setAccessible()方法
    对允许任意图片上传的发布内容模式的啊哈的想法
    如果你真的想做一件事,你一定会找到一个方法;如果你不想做一件事,你一定会找到一个借口.
    xaml 的 intellisense失效的解决办法
    Blog技术词汇之Rss篇 什么是Rss以及其定义[翻译]
    多个存储过程之间相互调用的原子性问题
  • 原文地址:https://www.cnblogs.com/nufangrensheng/p/3512291.html
Copyright © 2020-2023  润新知