当在 C 中调用 execv("/bin/sh", NULL) 时,如何与子进程通信(例如 运行 通过写命令)?

how can I communicate (eg. run commands via write) with a child process when execv("/bin/sh", NULL) was called in C?

我正在尝试让我的程序能够与另一个接受输入的程序进行交互。我通过在子进程中执行 execv("/bin/sh", NULL) 来尝试使用 fork() 。现在它应该被新进程替换,/bin/sh。现在我希望我的父进程像发送命令一样与 /bin/sh 通信。我试过使用管道,但我想我做错了什么。这是我的代码:

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

int main() {
  int pipefd[2];
  pipe(pipefd);
  pid_t pid = fork();

  if(pid == 0) {               // child code
    close(0);                  // close stdin fd
    dup(pipefd[0]);            // duplicate the pipe fd (will return 0)
    close(pipefd[1]);          // close the pipefd 1 (I dont need to write for child now)
    execv("/bin/sh", NULL);    // execute /bin/sh
  } else {                     // parent code
    close(1);                  // close stdout fd
    dup(pipefd[1]);            // duplicate the pipe fd (will return 1)
    close(pipefd[0]);          // close the pipefd 0 (I dont need to read right now)
  }

  write(0, "touch xxx\n", 10); // try to run a command with the parent process
  waitpid(-1, WNOHANG, 0);     // wait for the child to exit
}

我试图从父级写入标准输入,因为我认为 /bin/sh 从标准输入获取输入我可以写入它。可悲的是我的命令没有被执行。之后我可以输入一些东西,但它什么也没做。这是 strace 的输出:

execve("./a.out", ["./a.out"], 0x7fffffffe870 /* 41 vars */) = 0
brk(NULL)                               = 0x555555559000
arch_prctl(0x3001 /* ARCH_??? */, 0x7fffffffe710) = -1 EINVAL (Das Argument ist ungültig)
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (Datei oder Verzeichnis nicht gefunden)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=210476, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 210476, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7ffff7f92000
close(3)                                = 0
openat(AT_FDCWD, "/usr/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "7ELF[=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=]>[=13=][=13=][=13=][=13=]`|[=13=][=13=][=13=][=13=][=13=]"..., 832) = 832
pread64(3, "[=13=][=13=][=13=][=13=][=13=][=13=]@[=13=][=13=][=13=][=13=][=13=][=13=][=13=]@[=13=][=13=][=13=][=13=][=13=][=13=][=13=]@[=13=][=13=][=13=][=13=][=13=][=13=][=13=]"..., 784, 64) = 784
pread64(3, "[=13=][=13=][=13=]@[=13=][=13=][=13=][=13=][=13=][=13=]GNU[=13=][=13=][=13=]0[=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=]"..., 80, 848) = 80
pread64(3, "[=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=]GNU[=13=]T647471CJ[=13=]7152"..., 68, 928) = 68
newfstatat(3, "", {st_mode=S_IFREG|0755, st_size=2154488, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ffff7f90000
pread64(3, "[=13=][=13=][=13=][=13=][=13=][=13=]@[=13=][=13=][=13=][=13=][=13=][=13=][=13=]@[=13=][=13=][=13=][=13=][=13=][=13=][=13=]@[=13=][=13=][=13=][=13=][=13=][=13=][=13=]"..., 784, 64) = 784
mmap(NULL, 1884632, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7ffff7dc3000
mmap(0x7ffff7de9000, 1359872, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x26000) = 0x7ffff7de9000
mmap(0x7ffff7f35000, 311296, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x172000) = 0x7ffff7f35000
mmap(0x7ffff7f81000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1bd000) = 0x7ffff7f81000
mmap(0x7ffff7f87000, 33240, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7ffff7f87000
close(3)                                = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ffff7dc1000
arch_prctl(ARCH_SET_FS, 0x7ffff7f91580) = 0
mprotect(0x7ffff7f81000, 12288, PROT_READ) = 0
mprotect(0x555555557000, 4096, PROT_READ) = 0
mprotect(0x7ffff7ffb000, 8192, PROT_READ) = 0
munmap(0x7ffff7f92000, 210476)          = 0
pipe([3, 4])                            = 0
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7ffff7f91850) = 29114
close(1)                                = 0
dup(4)                                  = 1
close(3)                                = 0
write(0, "touch xxx\n", 10touch xxx
)             = 10
wait4(-1,

希望有人能帮忙

您的 parent 进程(else 块)正在关闭并替换 fd 1,对应于 stdout,意思是写入它自己的 stdout将转到 child 的 stdin。但是你writeparent的未修改的fd0,stdin.

更改代码,使 parent 写入 fd 1stdout,它附加到通向 child 的 fd 0, stdin.

这里还有其他问题(在启用任何级别的警告的情况下进行编译会很清楚)。修正这些,这个 应该 工作(假设,正如你所说,你的系统允许 execv 接受 NULL 作为第二个参数)。