【问题标题】:Running a shell command with execlp() from a string使用 execlp() 从字符串运行 shell 命令
【发布时间】:2014-02-05 04:15:04
【问题描述】:

我试图让我的程序使用 exelp() 运行 shell 命令。用户基本上输入了一个 shell 命令,该命令由exelp() 在新的 shell 中存储然后执行。

假设用户输入了“ls -l /bin/??”,它又被变量command[] 捕获。如何让这个文本字符串在 shell 环境中执行。

我最接近了解如何做到这一点的方法是 execlp("/bin/sh", "-c", command, (char *)NULL); ,其中 /bin/sh 启动一个迷你外壳,-c 启用外壳接受字符串,倒数第二个参数只是捕获的字符串早些时候。我知道system() 是这里的一个选项,但出于教育目的,我想用 execlp 来做这件事。

我在这里缺少什么?提前致谢。

【问题讨论】:

  • exec 系列中没有调用单个参数字符串。您的选项是字符串列表或字符串数​​组。这意味着在使用 exec 调用之一之前,您需要自己将输入字符串解析为单独的参数。你在上面手工做到了。现在您需要以编程方式进行。
  • 您只能在非常有限的情况下使用execlp();您必须在编译时知道参数的数量。您通常使用 execvp() 代替。

标签: c linux shell


【解决方案1】:

也许您在问如何在您的 C 程序中将 shell 字扩展为参数子序列。见glob(7)

然后考虑glob(3)wordexp(3)

您应该意识到,当您键入ls -l /bin/?? 时,shell 有责任扩展??/bin/ls 程序是 execve(2)-ed 与 result 由 shell 完成的 扩展 ...

或者,您可以将其留给由system(3)popen(3) 函数启动的/bin/sh -c shell。如果您将一些用户输入传递给这些函数,请注意code injection 并适当引用任何用户输入。想象一下,您运行一个由ls -l 和一些用户输入组成的字符串;如果恶意用户将a; rm -rf $HOME 作为文件名,如果你不引用它,你会很抱歉(因为没有预防措施,你的程序将构建ls -l a; rm -rf $HOME 命令字符串,然后将该字符串传递给system 或@987654336 @ 然后灾难发生)。

【讨论】:

    【解决方案2】:

    您将 const char** 而不是 const char * 作为 tird 参数

    试试execlp("/bin/sh", "-c", "ls", "-l", "/bin/", 0) 或者创建一个带有“-c”作为第一个参数的其他字符**,然后使用execv

    我猜它正在编译,因为这两个参数是指针但它们的类型错误

    编辑

    当你调用 execlp 时。 正如你所说的命令是const char[],但在定义中你只需要输入const char* 就好像你这样调用函数

    execlp(const char*, const char*, const char **, char*) //wrong obviously
    

    所以你有两个解决方案。 第一个使用 bin/sh -c 是连接所有参数并将其传递给 execlp

    int main(int argc, char **av)
    {
      char  **args;
      int   i;
      char  *cmd;
      size_t size;
    
      args = malloc(sizeof(char*) * (4));
      args[0] = "sh";
      args[1] = "-c";
      i = 1;
      size = 0;
      cmd = malloc(1);
      *cmd = '\0';
      while (i < argc)
        {
          cmd = realloc(cmd, strlen(cmd) + 1 + strlen(av[i]));
          strcat(&(cmd[size]), av[i]);
          size += strlen(cmd);
          strcat(&(cmd[size]), " ");
          size++;
          i++;
        }
      args[2] = cmd;
      execvp("/bin/sh", args);
    }
    

    但不是很干净

    最好的方法(对我来说更合乎逻辑)我认为它是找到二进制文件的地址,所以在你的情况下 /bin/ls 然后使用 execvp 传递它

    类似:

    char *get_binary_addr(const char* fct)
    {
      return "/bin/ls"; //ofc you will parse your /bin to find binary addr
    }
    
    int main(int argc, char **av)
    {
      char  **args;
    
      args = malloc(sizeof(char*) * argc);
      memcpy(&(args[0]), &(av[1]), argc * sizeof(char*));
      execvp(get_binary_addr(av[0]), args);
    }
    

    【讨论】:

    • 谢谢@Alexis。你是什​​么意思我在第三个参数中使用const char**?你的意思是NULL指针吗?此外,我明确需要从包含整个命令的单个字符串运行命令。因此,“ls”、“-l”……不适合我。
    • 第一个 sn-p 未命中设置args[3] = NULL;
    • 第二个 sn-p 错过了传递 NULL 指针 args[argc+1] 作为哨兵的作用。
    • 除此之外,execlp() 需要将(char*) 0 作为最后一个参数传递。演员阵容很重要。
    猜你喜欢
    • 1970-01-01
    • 2023-04-11
    • 2020-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多