【问题标题】:Perl IPC::Run3: How to emulate a pty for stdin to child process?Perl IPC::Run3:如何模拟一个 pty 的 stdin 到子进程?
【发布时间】:2017-01-05 00:24:32
【问题描述】:

这是IPC::Open3 and determining if child is waiting for input 的后续问题,尽管他们承认不相关。

获取以下示例代码:

use strict;
use warnings;
use IPC::Run3;

sub foo
{
    my $cmd = shift;
    my $CH_IN = "foo\n";
    run3($cmd, \$CH_IN, my $CH_OUT, my $CH_ERR);
    return 1;
}
my @LIST = ( 'command','arg1','arg2','arg3' );
foo \@LIST;

对于上面的代码command 是另一个perl 脚本。子脚本调用who -m 以从终端查找谁拥有标准输入,这是为了在使用root 或其他通用系统用户调用子脚本或父脚本的情况下使用。

当我被父母调用时,我从孩子那里得到的错误如下。

Use of uninitialized value in split at child.pl line 354.
WHOAMI is undef

下面的子代码。

第 354 行代码:

# Function Name:        'determine_user'
# Function Inputs:      'Optional Scalar: Username to login as'
# Function Returns:     'If username is provided: Scalar: the username provided, If username is not provided: The output of who -m'
# Function Description: 'Figures out the user to login as'
sub determine_user
{
    my $USER = shift;
    if (!defined $USER)
    {
        my $WHOAMI;
        open my $WHOPROC, q{-|}, 'who -m'                   or die "Unable to open 'who -m' for output.\n";
        $WHOAMI=<$WHOPROC>;
        close $WHOPROC                                      or die "Unable to close 'who -m'.\n";
        $USER       = split m{[\s]+}xms, $WHOAMI          or die "WHOAMI is undef\n";    # This is line 354
    }

    chomp $USER;

    return $USER;
}

当我从命令行调用子脚本时,上面的代码工作得很好,但是由于who -m 试图查看谁拥有终端的标准输入并且终端已被父脚本替换,我相信我需要找到一种在从父级运行时使用模拟 pty 调用 who -m 的方法。无论是通过修改孩子还是父母或两者都没有关系,因为我可以同时修改。

所以我的问题是:我怎样才能在父级内部运行子级并且仍然依赖who -m 的输出被喂给子级?

编辑:ikegami 在他的答案的 cmets 中提供了最佳解决方案。它没有回答问题,但确实解决了我的问题。

我的 ssh 守护进程设置了 env var SSH_TTY,所以你可以使用 perl -MFile::stat -E'say scalar(getpwuid(stat($ENV{SSH_TTY})-&gt;uid))'。如果未设置,则默认为scalar(getpwuid($&gt;))。

【问题讨论】:

  • 当我尝试从终端窗口运行who -m 时,它没有输出,但是当我ssh 进入另一台服务器然后运行who -m 时,它给了我用户名。我不确定这是否与您的问题有关..
  • 这很奇怪!什么发行版和版本?
  • 我使用的是 Ubuntu 16.10。我从gnome-terminal 窗口运行who -m
  • 有趣的是,当我在 gnome-terminal 的 CentOS7 上这样做时,它工作正常。我正在通过远程 x 会话运行 gnome-terminal,让我尝试物理会话。
  • 我终于通过scalar(getpwuid(stat(readlink("/proc/$PID/fd/1"))-&gt;uid)) 完成了这项工作,它消除了对who -m、ENV{$SSH_TTY} 和ENV{$USER} 的依赖,并避免了对被调用子进程模拟pty 的任何需要。

标签: perl input-buffer


【解决方案1】:

who -m 专门提供有关连接到其标准输入的终端的信息。

-m     only hostname and user associated with stdin

您已经更换了终端,因此无法从中获取信息。

$ who -m
ikegami  pts/1        ...

$ who -m </dev/null

$

您可以放弃-m,而只使用who。

$ who </dev/null
ikegami  pts/1        ...

或者,您可以改用$ENV{USER} 或getpwuid($&gt;)(进程正在执行的用户的名称)。

【讨论】:

  • 感谢您的建议,但不幸的是,它不会涵盖父级作为通用系统用户运行的情况,例如 root 或 oracle。我再次更新了问题以澄清这一点。
  • 为什么不呢?我认为你的意思是它是一个 setuid 脚本,因为 who -m 不适用于守护进程,在这种情况下 $ENV{USER} 和 getpwuid($&gt;) 或 getpwuid($&lt;) 应该可以工作。
  • 我的意思是替代品 $ENV{USER} 和 getpwuid($&gt;) 输出 root 和 who 没有任何选项标志输出所有用户,所以在多用户服务器上,这不会给出所需的输出。我意识到终端已被更换。当我研究我的第一个问题时,我看到了一些关于用open3 模拟标准输入的 pty 的东西,但是正如你正确指出的那样,应该使用 run3 而不是 open3 所以我希望找到一种方法来做run3.
  • 它不是一个 setuid 脚本。它旨在作为具有自己唯一 UID 的标准用户运行。但是,如果任何给定的 SA 或 DBA 在此人打开与服务器的 ssh 会话后将用户切换为通用用户,例如 oracle 或 root,我希望脚本仍然可以工作,而无需尝试以 root 或 oracle 身份登录到 webapp。因此,我希望它找出谁在没有 ps|grephackery 的情况下启动了 ssh 会话。
  • 我的 ssh 守护进程设置了环境变量SSH_TTY,所以你可以使用perl -MFile::stat -E'say scalar(getpwuid(stat($ENV{SSH_TTY})-&gt;uid))'。如果未设置,则默认为 scalar(getpwuid($&gt;))。
猜你喜欢
  • 2023-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-21
相关资源
最近更新 更多