【问题标题】:Strange redirection behaviour allowing output truncation允许输出截断的奇怪重定向行为
【发布时间】:2019-08-29 03:06:54
【问题描述】:

我们有一个构建脚本,可以为多种板卡类型构建嵌入式系统,当以一种方式捕获输出时,它似乎工作正常。另一种方式,它会部分通过输出,然后在继续之前截断文件。

工作方式:

time ( cd ~ ; builder.sh 2>&1 | tee ~/builder.out )

以及似乎截断的方式:

time ( cd ~ ; builder.sh > ~/builder.out 2>&1 )

截断似乎发生在一个非常特定的点,截断后文件中的第一行始终是来自qmakeDEFAULT_INCDIRS=...。它位于过程中的特定点而不是文件达到一定大小时这一事实似乎表明它不是某些外部文件检查器进行截断。

在任何情况下,如果它被删除,脚本将继续写入已删除文件的 inode,直到它被关闭,然后它会删除该 inode。

实际发生的情况是文件似乎被截断,然后在开始时继续写入。但是如果程序实际上没有访问文件句柄本身,我就无法做到这一点。

在上述两种情况下,构建器脚本实际上并不知道它的输出文件,它只是将输出和错误消息写入stdout 并让shell 重定向处理它。

所以我的问题是:有没有办法在文件 I/O 的 UNIX 模型中做到这一点(比如来自 C 文件 API 调用)?换句话说,您可以在通过重定向设置时截断正在写入的文件吗?为什么tee 变体有效?是什么阻止它被截断?

【问题讨论】:

    标签: c file unix


    【解决方案1】:

    是的,正如您已经注意到的那样,显然有人在 stdout 上调用 lseek()ftruncate()

    要追查罪犯,strace -f 肯定会有所帮助。当做像这样的异国情调时,您可能需要做strace -f sh -c 'build.sh 2>&1 | cat > output' > log 2>&1,因为否则它也会很高兴地吞噬您的 strace 输出。

    获得日志后,找到对lseek(1,lseek(2,ftruncate(1,ftruncate(2, 的调用。从那里向后搜索到以前的exec,你应该知道了。

    一个合法地使用stdout 进行游戏的程序是cdrecord,其中至少有一些版本希望您的 CD 刻录机在标准输出上。

    【讨论】:

    • 我们的构建过程每块板需要 40 分钟,我不确定我们是否有能力存储 40 分钟的 strace,但我会看看我能找到什么 :-)
    • @paxdiablo:如果需要,请使用 ssh 并将其流式传输到您的工作站等其他地方。
    【解决方案2】:

    好吧,事实证明程序可以在标准输出上寻找(尽管我想知道这样做的程序的理智)。

    以下程序说明了这一点:

    #include <stdio.h>
    
    int main(void){
        for (int i = 3; i > 0; --i) {
            //rewind(stdout);
            printf("Hello, world %d !\n", i);
        }
        return 0;
    }
    

    运行这个捕获输出,你会得到一个文件,其中包含:

    Hello, world 3 !
    Hello, world 2 !
    Hello, world 1 !
    

    但是,如果您取消注释 rewind 行,您最终只会在输出文件中看到 final 行。

    有趣的是,由于我无法控制截断stdout 的程序,这实际上可能是“无用使用猫”奖的有用使用猫。而不是执行:

    myprog >outfile 2>&1
    

    myProg 截断文件,我可以这样做:

    myprog 2>&1 | cat >outfile
    

    管道将保护cat 输出文件不被截断。


    就实际问题而言,qt5basebuildroot 的一部分)似乎出于某种原因正在对输出文件句柄进行某种恶作剧。我们已经通过使用上面的cat 方法解决了这个问题,因为我们没有时间追查 buildroot(或创建补丁文件)来正确修复它。

    【讨论】:

    • 你也可以试试myprog &gt;&gt; outfile 2&gt;&amp;1。大多数 shell 通过以仅附加模式打开 outfile 来实现这一点,在这种模式下,无论 lseek 做了什么,所有写入都被强制在文件末尾。
    猜你喜欢
    • 2014-06-14
    • 2012-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-30
    • 2010-12-08
    相关资源
    最近更新 更多