Why splice syscall fails when my program runs on Linux but succeeds when it runs in gdb?

Viewed 163

I try to run a book's sample code. Its function is to accept a line of input and output it to the standard output and operation parameters specified file. Here is the code:

#include <assert.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>

int main( int argc, char* argv[] )
{
    if ( argc != 2 )
    {
        printf( "usage: %s <file>\n", argv[0] );
        return 1;
    }
    int filefd = open( argv[1], O_CREAT | O_WRONLY | O_TRUNC, 0666 );
    assert( filefd > 0 );

    int pipefd_stdout[2];
        int ret = pipe( pipefd_stdout );
    assert( ret != -1 );

    int pipefd_file[2];
        ret = pipe( pipefd_file );
    assert( ret != -1 );

    //the first splice()
    ret = splice( STDIN_FILENO, NULL, pipefd_stdout[1], NULL, 32768, SPLICE_F_MORE | SPLICE_F_MOVE );
    assert( ret != -1 );

    ret = tee( pipefd_stdout[0], pipefd_file[1], 32768, SPLICE_F_NONBLOCK ); 
    assert( ret != -1 );

    //the second splice()       
    ret = splice( pipefd_file[0], NULL, filefd, NULL, 32768, SPLICE_F_MORE | SPLICE_F_MOVE );
    assert( ret != -1 );

    //the third splice()
    ret = splice( pipefd_stdout[0], NULL, STDOUT_FILENO, NULL, 32768, SPLICE_F_MORE | SPLICE_F_MOVE );
    printf("errno:%d\n",errno);
    assert( ret != -1 );


    close( filefd );
        close( pipefd_stdout[0] );
        close( pipefd_stdout[1] );
        close( pipefd_file[0] );
        close( pipefd_file[1] );
    return 0;
}

After i compiled the code, i ran it and typed "123", it can't output to stdout, the third splice() fails and errno is 22. here is the screenshot of result: p1

And when i use gdb to run the code, it works normally. Here is the screeshot: p2

kernel version: 4.19.163-1

gcc version: 10.2.0

gdb version: 10.1

my compile command: g++ test.cpp -g -o LinuxServer

my run command: ./LinuxServer test.txt

my gdb command: gdb LinuxServer

So why the splice syscall fails when my program runs on Linux but succeeds when it runs in gdb?

1 Answers

In linux manual splice(2), there is a description of ERRORS: EINVAL The target file is opened in append mode.

The stdout in my terminal is at append mode, that's why the third splice syscall fail.

And to solve this problem, we can add fcntl(STDOUT_FILENO, F_SETFL, fcntl(STDOUT_FILENO, F_GETFL) & ~O_APPEND);before the splice syscall.

Related