我正在尝试在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);
}
答案 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
并在获取状态之前阻止父级中的SIGCHLD
。 posix_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);