我有一个CLI,其中一个命令正在进入Linux bash shell。 这是使用fork& amp; 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);
}
我想替换fork / 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);
但它不起作用。 有什么帮助吗?
答案 0 :(得分:4)
让我们看一下原始fork / exec中的代码:
0
的fd,即它的标准dup(0)
),将它们放入stdout和stderr 您的新代码根本不遵循相同的模式。你想要做的是重复这个过程,但要更明确:
关闭所有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_FILENO
和STDERR_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的原因是为了防止原始
dup2
的意外fd
进入新的fd号码。真正应该遇到这个问题的唯一问题是第一个因为fd
==STDIN_FILENO
,因为您此时没有打开任何其他文件描述符。
要将其合并为一小段代码,而不是echo something
bash
,我们有:{/ p>
#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
未定义。