使用posix而不是fork/execv运行bash [英] Running bash using posix instead of fork/execv

查看:373
本文介绍了使用posix而不是fork/execv运行bash的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个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_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应该在正确的上下文中发生.

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 original fd into the new fd number. The only one that really should have that problem is the first one because fd == 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆