You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

sshfs代码中poll在bash返回0超时,tcsh正常的原因与解决

SSHFS中poll系统调用在不同Shell下的异常问题分析与解决

问题描述

我在使用sshfs时遇到了poll系统调用的异常行为:以下代码在tcsh环境中可正常接收输入并继续处理,但在bash环境中无法接收输入,等待60秒后触发poll的超时返回0;在嵌套shell场景(如tcsh运行于bash之上再运行tcsh)下也无法正常工作。

相关代码

while (1) {
    struct pollfd fds[2];

    fds[0].fd = sshfs.rfd;
    fds[0].events = POLLIN;
    fds[1].fd = sshfs.ptyfd;
    fds[1].events = POLLIN;
    res = poll(fds, 2, timeout);
    if (res == -1) {
        perror("poll");
        return -1;
    }
    if (res == 0) {
        fprintf(stderr, "Timeout waiting for prompt\n");
        return -1;
    }
    if (fds[0].revents) {
        /*
         * Something happened on stdout of ssh, this
         * either means, that we are connected, or
         * that we are disconnected.  In any case the
         * password doesn't matter any more.
         */
        break;
    }

    res = read(sshfs.ptyfd, &c, 1);
    if (res == -1) {
        perror("read");
        return -1;
    }
    if (res == 0) {
        fprintf(stderr, "EOF while waiting for prompt\n");
        return -1;
    }
    buf[len] = c;
    len++;
    if (len == passwd_len) {
        if (memcmp(buf, passwd_str, passwd_len) == 0) {
            write(sshfs.ptyfd, sshfs.password,
                  strlen(sshfs.password));
        }
        memmove(buf, buf + 1, passwd_len - 1);
        len--;
    }
}

差异原因分析

1. Shell的PTY输出与缓冲策略不同

  • tcsh:连接到PTY后会立即输出密码提示,且输出缓冲策略更激进,无延迟输出,因此poll能快速检测到sshfs.ptyfd上的POLLIN事件,顺利执行后续读取和密码匹配逻辑。
  • bash:作为登录shell启动时,会加载~/.bash_profile、~/.bashrc等配置文件,可能输出大量初始化内容(如欢迎信息、别名提示等),且默认采用行缓冲模式,终端未完全初始化时不会输出密码提示;加上bash对PTY的初始化流程更复杂,导致密码提示输出时机延迟,超出了poll的超时时间。
  • 嵌套shell场景:外层bash已修改PTY的终端属性(如缓冲模式、终端模式),内层tcsh继承这些属性后,输出行为改变,无法像直接运行tcsh那样触发poll的POLLIN检测。

2. 代码逻辑的依赖限制

这段代码核心逻辑依赖poll先检测到sshfs.ptyfd的可读事件(即密码提示输出),才能进入读取匹配流程。如果bash无法在超时时间内输出密码提示,poll会因检测不到任何事件而超时返回。

无需修改代码的解决方法

1. 调整bash启动配置,禁用非必要输出

编辑~/.bash_profile(针对登录shell)或~/.bashrc(针对交互式shell),添加以下内容,让bash在非标准终端环境下跳过冗余输出:

# 当终端不是交互式时,禁用所有启动输出和提示
if [[ ! -t 0 ]]; then
    unset PROMPT_COMMAND
    PS1=""
    # 注释或删除所有启动时会产生输出的配置(如echo语句、fortune等)
fi

2. 强制bash以非交互式模式启动

修改sshfs的连接命令,指定bash以非交互式模式运行sftp-server,避免加载配置文件:

sshfs user@remote-host:/target/path /local/mount-point -o sftp_server="/bin/bash -c '/usr/lib/openssh/sftp-server'"

3. 临时调整终端属性

在启动sshfs前执行以下命令,修改终端缓冲模式,确保PTY输出能被及时检测:

stty -icanon -echo

执行完sshfs后可恢复终端属性:

stty icanon echo

内容的提问来源于stack exchange,提问作者user1818563

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 22:05:27