无法以正确的方式执行其他程序

Can't exec other programs in a proper way

我正在尝试从我自己的程序中执行另一个程序,但我不明白一些事情。所以我写了这段代码:

void run() {
  cout << "##Run" << endl;
  pid_t process_id = fork();

  if (process_id == 0) {
    char* args[] = {  "sudo", "ls", "-l" };
    auto i = execvp("sudo", args);
    cout << "#Result: " << i << endl;
    return;
  } else if (process_id < 0) {
    throw std::runtime_error("fork() failed");
  } else if (process_id > 0) {
    wait(&process_id);
  }
  return;
}

void run_decorator() {
  cout << "###Run decorator: " << endl;
  run();
}

int main() {
  run();
  run_decorator();
  return 0;
}

输出为

##Run
total 88
-rwxr-xr-x 1 bezik bezik 77560 Nov 29 19:53 colors
-rwxr-xr-x 1 bezik bezik    63 Nov 26 21:45 compile
drwxr-xr-x 2 bezik bezik  4096 Nov 26 20:46 headers
drwxr-xr-x 2 bezik bezik  4096 Nov 23 00:48 sources
###Run decorator:
##Run
#Result: -1

谁能给我解释一下,为什么从 run_decorator() 函数调用时 execvp 失败?

仔细阅读 execvp(3) 的文档。它说 execl 等...:

The first argument, by convention, should point to the filename associated with the file being executed. The list of arguments must be terminated by a null pointer, and, since these are variadic functions, this pointer must be cast (char *) NULL.

关于execvp

The array of pointers must be terminated by a null pointer.

所以你应该编码:

char* args[] = {  "sudo", "ls", "-l",  NULL };
execvp("sudo", args);

顺便说一句,execvp 根本不 return, 除了 失败。调用后无需保留其结果。

但是您需要在 execvp return 时(这只会在失败时发生)显示一些错误消息。我建议:

perror("execvp");
exit(EXIT_FAILURE);

你可以找到有效的调用参数,在那种情况下,_exit(2) instead of exit(3). I still prefer exit (because it would flush the stdio buffers and run atexit(3)-注册的处理程序)。

Can someone please explain to me, why execvp failed

是的,errno(3). Which is used by perror(3)

不要忘记仔细阅读每个使用函数的文档。对于系统调用(在 syscalls(2)) and standard C library functions (see intro(3) 中列出),您通常应该处理失败情况(通常使用 errno,至少通过 perror 然后 exit

我不明白你为什么需要 sudols。在少数情况下这可能有用,因为大多数时候你的 working directory is listable (then sudo is useless), and in that case you could even use opendir(3), readdir(3) with stat(2)(所以不需要 fork 然后 execvp /bin/ls 程序)。

另请阅读 setuid techniques in execve(2) and credentials(7) (and setreuid(2)). See this(您可以使用自己的 setuid 程序避免 sudo)。

顺便说一句,你应该编译 with all warnings and debug info (g++ -Wall -Wextra -g with GCC) and use the debugger gdb (and perhaps strace(1) and valgrind(1)).