Why doesn't "cat a b > foo" work?

Grant Edwards grant.b.edwards at gmail.com
Tue Jan 19 20:12:15 UTC 2021


We recently upgraded from an older version of busybox to 1.31.0, and
now there seems to be a problem with 'cat'. If I cat two files to
stdout it works fine, but if I redirect output into a file using ash,
the second file overwrites the first:

    # echo abcdefghijk > a
    # echo 12345 > b
    
    # cat a b
    abcdefghijk
    12345
    
    # cat a b > bar
    # cat bar
    12345
    ghijk
    
    # cat a b | cat > bar
    # cat bar
    abcdefghijk
    12345

If I trace system calls, they are virtually identical for the two cases above:

    # diff -U999 strace.works strace.broken
    --- strace.works
    +++ strace.broken
    @@ -1,33 +1,33 @@
     execve("/bin/cat", ["cat", "a", "b"], [/* 16 vars */]) = 0
     mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|0x4000000, -1, 0) = 0x40007000
    -stat("/etc/ld.so.cache", 0xbedc2a18)    = -1 ENOENT (No such file or directory)
    +stat("/etc/ld.so.cache", 0xbe9fca18)    = -1 ENOENT (No such file or directory)
     open("/apps/lib/libc.so.0", O_RDONLY)   = -1 ENOENT (No such file or directory)
     open("/lib/libc.so.0", O_RDONLY)        = 3
     fstat(3, {st_mode=S_IFREG|0755, st_size=331104, ...}) = 0
     mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|0x4000000, -1, 0) = 0x40008000
     read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0(\0\1\0\0\0\320\250\0\0004\0\0\0"..., 4096) = 4096
     mmap2(NULL, 385024, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40010000
     mmap2(0x40010000, 324524, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED, 3, 0) = 0x40010000
     mmap2(0x40067000, 5136, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0x4f000) = 0x40067000
     mmap2(0x40069000, 16432, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x40069000
     close(3)                                = 0
     munmap(0x40008000, 4096)                = 0
     stat("/lib/ld-uClibc.so.0", {st_mode=S_IFREG|0755, st_size=32664, ...}) = 0
     mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|0x4000000, -1, 0) = 0x40008000
     set_tls(0x400084a0, 0x40008b40, 0x40008b48, 0x400084a0, 0x4000ef74) = 0
     mprotect(0xc1000, 4096, PROT_READ)      = 0
     mprotect(0x40067000, 4096, PROT_READ)   = 0
     mprotect(0x4000e000, 4096, PROT_READ)   = 0
     ioctl(0, TCGETS, {B38400 opost isig icanon echo ...}) = 0
    -ioctl(1, TCGETS, {B38400 opost isig icanon echo ...}) = 0
    +ioctl(1, TCGETS, 0xbe9fc9cc)            = -1 ENOTTY (Inappropriate ioctl for device)
     getuid32()                              = 0
     open("a", O_RDONLY|O_LARGEFILE)         = 3
     sendfile64(1, 3, NULL, 16777216)        = 12
     sendfile64(1, 3, NULL, 16777216)        = 0
     close(3)                                = 0
     open("b", O_RDONLY|O_LARGEFILE)         = 3
     sendfile64(1, 3, NULL, 16777216)        = 6
     sendfile64(1, 3, NULL, 16777216)        = 0
     close(3)                                = 0
     exit_group(0)                           = ?
     +++ exited with 0 +++


I wonder if the use of sendfile64() is new, and sendfile64() doesn't
work right in our libc...

Any other suggestions?






More information about the busybox mailing list