使用posix而不是fork / execv运行bash

我有一个CLI,其中一个命令正在进入Linux bash shell。 这是使用fork&execv的代码:

if ((pid = fork()) < 0) { syslog_debug(LOG_ERR, "Could not fork"); } if (pid == 0) { /* In child, open the child's side of the tty. */ int i; for(i = 0; i <= maxfd; i++) { close(i); } /* make new process group */ setsid(); if ((fd[0] = open(tty_name, O_RDWR /*| O_NOCTTY*/)) < 0) { syslog_debug(LOG_ERR, "Could not open tty"); exit(1); } fd[1] = dup(0); fd[2] = dup(0); /* exec shell, with correct argv and env */ execv("/bin/sh", (char *const *)argv_init); exit(1); } 

我想要replacefork / execv并使用posix_spawn来代替:

 ret = posix_spawn_file_actions_init(&action); pipe(fd); for(i = 0; i <= maxfd; i++) { ret = posix_spawn_file_actions_addclose (&action, i); } ret = posix_spawn_file_actions_adddup2 (&action, fd[1], 0); ret = posix_spawn_file_actions_adddup2 (&action, fd[2], 0); ret = posix_spawn_file_actions_addopen (&action, STDOUT_FILENO, tty_name, O_RDWR, 0); char* argv[] = { "/bin/sh", "-c", "bash", NULL }; int status; extern char **environ; posix_spawnattr_t attr = { 0 }; snprintf( cmd, sizeof(cmd), "bash"); status = posix_spawn( &pid, argv[0], action /*__file_actions*/, &attr, argv, environ ); posix_spawn_file_actions_destroy(&action); 

但它不起作用。 任何帮助?

我们来看看原始fork / exec中的代码:

  • 关闭所有文件描述符
  • 打开tty,它将巧合地获得0的fd,即它是stdin
  • 重复这个fd两次( dup(0) ),把它们放到stdout和stderr中
  • 执行shell命令

您的新代码根本不遵循相同的模式。 你想要做的是重复这个过程,但要更加明确:

关闭所有的FD:

 for(i = 0; i <= maxfd; i++) { ret = posix_spawn_file_actions_addclose (&action, i); } 

打开tty到STDIN_FILENO

 ret = posix_spawn_file_actions_addopen (&action, STDIN_FILENO, tty_name, O_RDWR, 0); 

STDIN_FILENO复制到STDOUT_FILENOSTDERR_FILENO

 ret = posix_spawn_file_actions_adddup2 (&action, STDIN_FILENO, STDOUT_FILENO); ret = posix_spawn_file_actions_adddup2 (&action, STDIN_FILENO, STDERR_FILENO); 

那么posix_spawn应该在正确的上下文中进行。

对于旧的fork / exec进程,你应该做一些事情:

 int fd = open(tty_name, O_RDWR /*| O_NOCTTY*/); if (fd != STDIN_FILENO) dup2(fd, STDIN_FILENO); if (fd != STDOUT_FILENO) dup2(fd, STDOUT_FILENO); if (fd != STDERR_FILENO) dup2(fd, STDERR_FILENO); 

意图更明确。

ifs的原因是为了防止原来fd的偶然dup2变成新的fd号码。 唯一真正应该有这个问题的是第一个,因为fd == STDIN_FILENO因为你没有任何其他的文件描述符在这一点上打开。

要将这些代码合并成一小段代码,使用echo something而不是bash的调用,我们有:

 #include <stdio.h> #include <spawn.h> #include <unistd.h> #include <fcntl.h> #include <sys/types.h> #include <sys/wait.h> void do_spawn() { int ret; posix_spawn_file_actions_t action; int i; pid_t pid; int maxfd = 1024; char *tty_name = ttyname (0); ret = posix_spawn_file_actions_init (&action); for (i = 0; i <= maxfd; i++) { ret = posix_spawn_file_actions_addclose (&action, i); } ret = posix_spawn_file_actions_addopen (&action, STDIN_FILENO, tty_name, O_RDWR, 0); ret = posix_spawn_file_actions_adddup2 (&action, STDIN_FILENO, STDOUT_FILENO); ret = posix_spawn_file_actions_adddup2 (&action, STDIN_FILENO, STDERR_FILENO); char *argv[] = { "/bin/sh", "-c", "echo something", NULL }; int status; extern char **environ; posix_spawnattr_t attr = { 0 }; posix_spawnattr_init(&attr); posix_spawnattr_setflags(&attr, POSIX_SPAWN_USEVFORK); status = posix_spawn(&pid, argv[0], &action /*__file_actions*/ , &attr, argv, environ); printf ("%d %ld\n", status, pid); wait (0); posix_spawn_file_actions_destroy (&action); } int main(int argc, char **argv) { do_spawn(); } 

这需要使用-D_GNU_SOURCE进行编译,否则POSIX_SPAWN_USEVFORK未定义。