2017-10-08 205 views
1

我试图通过C程序运行BASH命令,但我正在用函数execv挣扎。我真的不知道如何编写该函数的第一个参数。我试图用strcat函数将字符串“/ bin /”追加到argv选项卡的第一个元素,这是我在运行程序时编写的命令,但它不起作用。我收到“分段错误”。我没有使用strcat函数,而是尝试了strdup,但我不知道如何正确使用它。通过C程序运行BASH命令

任何帮助,将不胜感激。我的计划在下面。

#include <stdio.h> 
#include <stdlib.h> 
#include <sys/types.h> 
#include <unistd.h> 
#include <string.h> 

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

char *tab[] = {argv[1],NULL}; 

if(execve(strcat("/bin/",argv[1]), tab, envp)==-1) 
{ 
    perror("execve"); 
    return EXIT_FAILURE; 
} 

return EXIT_SUCCESS; 
} 
+2

所以基本上你只是问如何连接C中的两个字符串?你有没有试过阅读C教程? – melpomene

+0

我不问如何连接,如果这是所有关于连接的函数strcat就足够了。但事实并非如此。所以我想要求助另一种使用execv函数来使我的程序工作的方法。 – TheScientist

+4

如果这不是你要求的,那么这就是你*应该*所要求的。很明显,你不明白'strcat'的作用或C字符串的工作方式。 (作为'strcat'的第一个参数传递一个字符串文字是没有道理的。) – melpomene

回答

0

Melpomene是正确的 - 你不能使用strcat那样的。在C中,你不能返回字符串。你所做的就是传递一个内存地址(指针)作为strcat中的第一个参数,然后strcat修改它所指向的内存,使它也包含第二个参数strcat。这是一个你会在C中一再重复的过程,所以你应该理解它。此外,该strcat不看起来安全,我敢打赌有一个strcatn功能或类似的东西。

+1

有'strncat',但它很容易出错,因为它的'n'参数指定了多少字节从第二个参数读取(至多),而不是目标缓冲区有多大。 – melpomene

+0

LOL stdlib从来没有得到它的权利。 –

1

要从C程序运行shell命令,应该使用system(3)。 如果你想得到它的标准输出(或给它的标准输入,但不是两个)使用popen(3)(不要忘记pclose这样的流)。

使用的shell(由systempopen)是不完全bash,但标准的POSIX /bin/sh(神似bash有一些限制)。

要构建该shell命令(但要注意其中的code injections),可以使用常见的字符串函数,如snprintfasprintf

请注意,execve(2)成功时不会返回,它不会通过shell运行命令,而是直接执行可执行程序。实际上Unix shells(如bash/bin/sh)经常使用fork(2),execve(2),waitpid(2)并正在实施globbing。 BTW system & popen也在/bin/sh -c上使用forkexecve

strcat("/bin/",argv[1])

是可怕的错误,第一个参数strcat是覆盖目标缓冲区(因此不能是一个字符串常量),并且不核对buffer overflow

你可能想代码:

char progbuf[80]; 
int ln = snprintf(progbuf, sizeof(progbuf), "/bin/%s", argv[1]); 

,你应该检查晚些时候ln<(int)sizeof(progbuf)

顺便说一句,你的程序的时候,你会改善它,不使用bash;它直接执行一些命令。


我试着用的strdup,但我不知道如何使用它的权利。

使用任何功能之前,你需要仔细阅读它的文档,例如strdup(3)(或在终端中输入man strdup)。

1

有关:

if(execve(strcat("/bin/",argv[1]), tab, envp)==-1) 

这是行不通的,

  1. 文字“/斌/”是只读存储器,所以不能改变(需要一个字符缓冲区大到足以容纳完整的字符串,类似于`字符串[100] = “/ bin中/”;

推荐:

#include <stdio.h>  // perror() 
#include <stdlib.h>  // exit(), EXIT_FAILURE 
#include <sys/types.h> 
#include <sys/wait.h> // waitpid() 

#include <unistd.h>  // fork(), execvp() 
#include <string.h>  // strlen(), strcpy(), strcat() 

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

    char *tab[] = { argv[1], NULL }; 

    char string[strlen(argv[1]) + strlen("/bin/") +1 ]; 
    strcpy(string, "/bin/"); 
    strcat(string, argv[1]); 

    int status; 

    pid_t pid = fork(); 
    switch(pid) 
    { 
     case -1: // fork failed 
      perror("fork failed"); 
      exit(EXIT_FAILURE); 
      break; 

     case 0: // child process 
      execve(string, tab, env); // does not return unless an error 
      perror("execve failed"); 
      exit(EXIT_FAILURE); 
      break; 

     default: 
      waitpid(pid, &status, 0); 
      break; 
    } 

} 

警告:建议的代码只隐藏参数:argc而不是正确检查它以确保命令行包含参数。

警告:主要参数:env[]不可移植,不应使用。建议使用:

extern char *environ[]; 
0

我终于找到了一种方法来做我想要的东西。感谢你们所有人的帮助&意见!这是解决方案!

#include <stdio.h> 
#include <stdlib.h> 
#include <sys/types.h> 
#include <unistd.h> 
#include <string.h> 

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

char *tab[] = {argv[1],argv[2],NULL}; 

char test[20] = "/bin/"; 

if(execve(strcat(test,argv[1]), tab, envp)==-1) 
{ 
    perror("execve"); 
    return EXIT_FAILURE; 
} 

return EXIT_SUCCESS; 
}