使用posix而不是fork/execv运行bash [英] Running bash using posix instead of fork/execv
问题描述
我有一个CLI,其中一个命令正在输入Linux bash shell. 这是使用fork&执行的代码. execv:
I have a CLI, one of the commands is entering into Linux bash shell. This is the code which does it using 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);
}
我想替换fork/execv并改用posix_spawn:
I want to replace the fork/execv and to use posix_spawn instead:
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);
但是它不起作用. 有帮助吗?
But it doesn't work. Any help?
推荐答案
让我们看一下原始fork/exec中的代码是做什么的:
Let's look at what the code in the original fork/exec does:
- 关闭所有文件描述符
- 打开tty,它会同时获得fd
0
,即它是stdin - 将此文件复制两次(
dup(0)
),将其放入stdout和stderr - 执行shell命令
- close all file descriptors
- open the tty, which will coincidentally get an fd of
0
, i.e. it's stdin - duplicate this fd twice (
dup(0)
), which puts them into stdout and stderr - exec the shell command
您的新代码完全没有遵循相同的模式.您想要做的就是重复该过程,但要更加明确:
Your new code doesn't follow the same pattern at all. What you want to do is repeat the process, but be more explicit:
关闭所有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
应该在正确的上下文中发生.
Then the posix_spawn
should take place in the correct context.
对于旧的fork/exec流程,您应该执行以下操作:
For the old fork/exec process, you should have done something like:
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
,因为此时您没有打开任何其他文件描述符.
The reason for the ifs is to prevent the accidental
dup2
of the originalfd
into the new fd number. The only one that really should have that problem is the first one becausefd
==STDIN_FILENO
because you don't have any other file descriptors open at that point.
要使用echo something
而不是调用bash
将此代码组合成一小段代码,我们可以:
To combine this into a small piece of code, with echo something
rather than an invocation of bash
we have:
#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
.
This needs to be compiled with -D_GNU_SOURCE
, as otherwise POSIX_SPAWN_USEVFORK
is not defined.
这篇关于使用posix而不是fork/execv运行bash的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!