Problem with cat

Grant Edwards grant.b.edwards at gmail.com
Mon Mar 13 18:06:42 UTC 2017


After upgrading to a new version of busybox (1.25.1), I now have an
odd problem with 'cat'.  When stdout is a file, it _appears_ to be
doing a seek to the beginning of the output file between input files.

  # ls -l
  total 8
  -rw-r--r--    1 root     root          1034 Mar 13 17:32 serverRsaCert.pem
  -rw-r--r--    1 root     root           887 Mar 13 17:32 serverRsaKey.pem

  # cat serverRsaCert.pem serverRsaKey.pem > foo

  # ls -l
  total 12
  -rw-r--r--    1 root     root          1034 Mar 13 17:38 foo
  -rw-r--r--    1 root     root          1034 Mar 13 17:32 serverRsaCert.pem
  -rw-r--r--    1 root     root           887 Mar 13 17:32 serverRsaKey.pem

In the output file, the contents of serverRsaKey.pem are written over
the beginning of the contents of serverRsaCert.pem.

Piping the output of 'cat' to another instance of cat fixes the
problem (presumably because a pipe isn't seekable?).

  # cat serverRsaCert.pem serverRsaKey.pem > foo
  # cat serverRsaCert.pem serverRsaKey.pem | cat > bar
  # ls -l
  total 16
  -rw-r--r--    1 root     root          1921 Mar 13 17:43 bar
  -rw-r--r--    1 root     root          1034 Mar 13 17:43 foo
  -rw-r--r--    1 root     root          1034 Mar 13 17:32 serverRsaCert.pem
  -rw-r--r--    1 root     root           887 Mar 13 17:32 serverRsaKey.pem

The same thing happens with more than two files:

  # ls -l
  total 12
  -rw-r--r--    1 root     root            29 Mar 13 17:44 d1
  -rw-r--r--    1 root     root            29 Mar 13 17:44 d2
  -rw-r--r--    1 root     root            29 Mar 13 17:44 d3

  # cat d1 d2 d3
  Mon Mar 13 17:44:35 UTC 2017
  Mon Mar 13 17:44:40 UTC 2017
  Mon Mar 13 17:44:43 UTC 2017

  # cat d1 d2 d3 >foo

  # ls -l
  total 16
  -rw-r--r--    1 root     root            29 Mar 13 17:44 d1
  -rw-r--r--    1 root     root            29 Mar 13 17:44 d2
  -rw-r--r--    1 root     root            29 Mar 13 17:44 d3
  -rw-r--r--    1 root     root            29 Mar 13 17:46 foo

  # cat foo
  Mon Mar 13 17:44:43 UTC 2017

But, strace doesn't show any seeks.  I see that 'cat' is using
sendfile mutiple times.  According to sendfile(2):

   In Linux kernels before 2.6.33, out_fd must refer to a  socket.   Since
   Linux  2.6.33  it can be any file.  If it is a regular file, then send‐
   file() changes the file offset appropriately.

Apparently "change file file offset apprpriatly" means it gets reset
to zero after every call to sendfile().  I take it this implementation
of 'cat' works for other people?


  execve("/bin/cat", ["cat", "serverRsaCert.pem", "serverRsaKey.pem"], [/* 13 vars */]) = 0
  mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|0x4000000, -1, 0) = 0x40007000
  stat("/etc/ld.so.cache", 0xbea37a68)    = -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(0xbc000, 4096, PROT_READ)      = 0
  mprotect(0x40067000, 4096, PROT_READ)   = 0
  mprotect(0x4000e000, 4096, PROT_READ)   = 0
  ioctl(0, TCGETS, {B115200 opost isig icanon echo ...}) = 0
  ioctl(1, TCGETS, 0xbea37a1c)            = -1 ENOTTY (Inappropriate ioctl for device)
  getuid32()                              = 0
  open("serverRsaCert.pem", O_RDONLY|O_LARGEFILE) = 3
  sendfile64(1, 3, NULL, 16777216)        = 1034
  sendfile64(1, 3, NULL, 16777216)        = 0
  close(3)                                = 0
  open("serverRsaKey.pem", O_RDONLY|O_LARGEFILE) = 3
  sendfile64(1, 3, NULL, 16777216)        = 887
  sendfile64(1, 3, NULL, 16777216)        = 0
  close(3)                                = 0
  exit_group(0)                           = ?
  +++ exited with 0 +++

-- 
Grant Edwards               grant.b.edwards        Yow! !  I'm in a very
                                  at               clever and adorable INSANE
                              gmail.com            ASYLUM!!



More information about the busybox mailing list