在C中使用system()和命令行参数

时间:2018-10-21 11:05:55

标签: c

我正在尝试在Linux中制作一个程序,其中要执行的命令作为命令行参数传递。我已经编写了代码,但是有时会运行文件,有时却无法运行,而且我不知道问题出在哪里。

这是我的代码:

#include<stdio.h>
#include<string.h>
#include<unistd.h>

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

    char com[60];
    int i;

    for(i = 1 ; i < argc ; i++){

        strcat(com, argv[i]);
        strcat(com, " ");
    }

    system(com);
}

2 个答案:

答案 0 :(得分:2)

您的程序有未定义的行为。

如果用户不传递任何参数,则永远不会输入循环,而您会这样做

char com[60];
// ...
system(com);

此时com的内容尚未初始化,因此对system的调用具有未定义的行为。

如果用户传递参数,则可以

strcat(com, argv[i]);

此时com的内容尚未初始化,因此对strcat的调用具有未定义的行为。


要解决此问题,请在循环之前使com为有效字符串:

char com[60];
com[0] = '\0';

答案 1 :(得分:0)

有时会溢出缓冲区(非常糟糕),有时会引用错误,并且不带任何参数,缓冲区将未初始化(=>未定义行为)。

当Shell运行程序时,它将取消对字符串的引用并内插$-variables。为了可靠地执行此转发,除了检查缓冲区溢出之外,您还需要重新报价。在一个简短的程序中,这将有些乏味。

更简单的方法是直接使用argv数组直接posix_spawn或fork / exec:

int status;
pid_t pid;

if (0>(pid=fork())) return -1;
if(0==pid){
    execvp(argv[1],argv+1);
    _exit(127);
}
while(0>(waitpid(pid,&status,0)))
    if (EINTR==errno) continue; else abort(); /*shouldn't happen*/

现在,真实的system()将另外忽略父级中的SIGINT/SIGQUIT并在获取状态之前阻止父级中的SIGCHLDposix_spawnp也将是首选。

要复制该权利,您可以从musl libc的system实现开始,然后对其进行修改以创建

int my_system(char const *file, char *argv[i]);

这将跳过外壳程序(随之而来的是,需要使用正确的引号和缓冲区溢出检查来创建一个字符串):

#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/wait.h>
#include <spawn.h>
#include <errno.h>
#include <pthread.h>

//extern char **__environ;
extern char **environ;

int my_system(char const *file, char *argv[])
{
    pid_t pid;
    sigset_t old, reset;
    struct sigaction sa = { .sa_handler = SIG_IGN }, oldint, oldquit;
    int status = -1, ret;
    posix_spawnattr_t attr;

    //pthread_testcancel();

    //if (!cmd) return 1;

    sigaction(SIGINT, &sa, &oldint);
    sigaction(SIGQUIT, &sa, &oldquit);
    sigaddset(&sa.sa_mask, SIGCHLD);
    sigprocmask(SIG_BLOCK, &sa.sa_mask, &old);

    sigemptyset(&reset);
    if (oldint.sa_handler != SIG_IGN) sigaddset(&reset, SIGINT);
    if (oldquit.sa_handler != SIG_IGN) sigaddset(&reset, SIGQUIT);
    posix_spawnattr_init(&attr);
    posix_spawnattr_setsigmask(&attr, &old);
    posix_spawnattr_setsigdefault(&attr, &reset);
    posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGDEF|POSIX_SPAWN_SETSIGMASK);

#if 0
    ret = posix_spawn(&pid, "/bin/sh", 0, &attr,
        (char *[]){"sh", "-c", (char *)cmd, 0}, environ);
#else
    ret = posix_spawnp(&pid, file, 0, &attr, argv, environ);
#endif

    posix_spawnattr_destroy(&attr);

    if (!ret) while (waitpid(pid, &status, 0)<0 && errno == EINTR);
    sigaction(SIGINT, &oldint, NULL);
    sigaction(SIGQUIT, &oldquit, NULL);
    sigprocmask(SIG_SETMASK, &old, NULL);

    if (ret) errno = ret;
    return status;
}

现在使用my_system,您无需引用,只需使用

即可调用
my_system(argv[1], argv+1);