zoukankan      html  css  js  c++  java
  • 8.12 system函数

    8.12 system函数

    在程序中执行一个命令字符串很方便。例如,假定要将时间和日期放到一个文件中,则可使用6 . 9节中的函数实现这一点。调用time得到当前日历时间,接着调用localtime将日历时间变换为年、月、日、时、分、秒、周日形式,然后调用strftime对上面的结果进行格式化处理,最后将结果写到文件中。但是用下面的system函数则更容易做到这一点。

    system("date > file");

    ISO C定义了system函数,但是其操作对系统的依赖性很强。

    #include <stdlib.h>

    int system(const char *cmdstring) ;

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

    因为system在其实现中调用了forkexecwaitpid,因此有三种返回值:

    (1) 如果fork失败或者waitpid返回除E I N T R之外的出错,则system返回-1,而且errno中设置了错误类型。

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

    (3) 否则所有三个函数( fork , execwaitpid )都成功,并且system的返回值是shell的终止状态,其格式已在waitpid中说明。

    程序8 - 1 2system函数的一种实现。它对信号没有进行处理。1 0 . 1 8节中将修改此函数使其进行信号处理。

    #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 */

    } 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作为命令输入而不是从标准输入或从一个给定的文件中读取命令。

          注意,我们调用_exit而不是exit。这是为了防止任何一个标准IO缓冲区(这些缓存区会在fork中由父进程复制到子进程)在子进程中被冲洗。

          下述程序8-13system的这种版本进行了测试。

    #include <stdio.h>

    #include <stdlib.h>

    #include <sys/wait.h>



    void pr_exit(int status)

    {

    if (WIFEXITED(status))

    printf("normal termination, exit status = %d\n",

    WEXITSTATUS(status));

    else if (WIFSIGNALED(status))

    printf("abnormal termination, signal number = %d%s\n",

    WTERMSIG(status),

    #ifdef WCOREDUMP

    WCOREDUMP(status) ? " (core file generated)" : "");

    #else

    "");

    #endif

    else if (WIFSTOPPED(status))

    printf("child stopped, signal number = %d\n",

    WSTOPSIG(status));

    }





    int main(void)

    {

    int status;



    if ((status = system("date")) < 0)

    printf("system() error");

    pr_exit(status);



    if ((status = system("nosuchcommand")) < 0)

    printf("system() error");

    pr_exit(status);



    if ((status = system("who; exit 44")) < 0)

    printf("system() error");

    pr_exit(status);



    exit(0);

    }


    程序运行输出为:

    Tue Oct 23 00:32:42 PDT 2012

    normal termination, exit status = 0

    sh: nosuchcommand: not found

    normal termination, exit status = 127

    leo      tty7         2012-10-23 00:29 (:0)

    leo      pts/0        2012-10-23 00:31 (:0.0)

    normal termination, exit status = 44

          使用system而不是直接使用forkexec的优点是:system进行了所需的各种出错处理,以及各种信号处理。

    设置用户ID程序

          如果在一个设置用户ID程序中调用system,会产生一个安全性方面的漏洞。绝不应当这样做。

          程序8-14system执行命令行参数

    #include <stdio.h>

    #include <stdlib.h>

    #include <sys/wait.h>



    void pr_exit(int status)

    {

    if (WIFEXITED(status))

    printf("normal termination, exit status = %d\n",

    WEXITSTATUS(status));

    else if (WIFSIGNALED(status))

    printf("abnormal termination, signal number = %d%s\n",

    WTERMSIG(status),

    #ifdef WCOREDUMP

    WCOREDUMP(status) ? " (core file generated)" : "");

    #else

    "");

    #endif

    else if (WIFSTOPPED(status))

    printf("child stopped, signal number = %d\n",

    WSTOPSIG(status));

    }





    int main(int argc, char *argv[])

    {

    int status;



    if (argc < 2)

    printf("command-line argument required");



    if ((status = system(argv[1])) < 0)

    printf("system() error");

    pr_exit(status);



    exit(0);

    }


    程序8-15打印实际和有效用户ID

    #include <stdlib.h>

    #include <stdio.h>



    int main(void)

    {

    printf("real uid = %d, effective uid = %d\n", getuid(), geteuid());

    exit(0);

    }


          如果一个进程正以特殊的权限运行(设置用户ID或者设置组ID),它又想生成另一个进程执行另一个程序,则它应当直接使用forkexec,而且在fork之后,exec之前要改回到普通权限。设置用户ID或者设置组ID程序决不应调用system函数。这种警告的一个理由是:system调用shell对命令字符串进行语法分析,而shell使用IFS变量作为其输入字段分隔符。早期的shell版本在被调用时不将此变量恢复为普通字符集。这就允许一个有恶意的用户在调用system之前设置IFS,造成system执行一个不同的程序。其中IFSInternal Field Seperator)Linuxshell中预设的分隔符,用来把command line分解成word(字段)。IFS可以是White Space(空白键)、Tab( 表格键)、Enter( 回车键)中的一个或几个。

  • 相关阅读:
    【数据库功能测试】之shell脚本执行sql命令
    【数据库使用】 mysql服务启动脚本
    【数据库功能测试】之存储过程
    各类排序算法实现
    Poj1830开关问题,高斯消元
    Poj3370Halloween treats鸽巢原理
    Poj2356Find a multiple鸽巢原理
    Poj3145Harmony Forever线段树+鸽巢原理
    hiho16动态lca
    hiho15周离线lca
  • 原文地址:https://www.cnblogs.com/shaoguangleo/p/2806023.html
Copyright © 2011-2022 走看看