kern/137482: script(1) doesn't read tail of program output,
pty is suspected
Valentin Nechayev
netch at segfault.kiev.ua
Thu Aug 6 11:00:14 UTC 2009
>Number: 137482
>Category: kern
>Synopsis: script(1) doesn't read tail of program output, pty is suspected
>Confidential: no
>Severity: non-critical
>Priority: medium
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: sw-bug
>Submitter-Id: current-users
>Arrival-Date: Thu Aug 06 11:00:14 UTC 2009
>Closed-Date:
>Last-Modified:
>Originator: Valentin Nechayev
>Release: FreeBSD 7.2-RELEASE-p1 i386
>Organization:
private
>Environment:
System: FreeBSD segfault.kiev.ua 7.2-RELEASE-p1 FreeBSD 7.2-RELEASE-p1 #1: Sun Jun 14 10:32:33 EEST 2009 root at segfault.kiev.ua:/usr/BSD/obj/usr/BSD/src/sys/sf72 i386
>Description:
script(1) doesn't read tail of program output when program in child process
finishes. On very quick & short output, this leads to empty output. In
other cases, this can give partial data loss.
I treat this as kernel issue, not userland, due to reasons explained below,
that's why category is "kern".
>How-To-Repeat:
Enter a directory with very few files (less than 10 and short named).
Run a few times:
script s01 ls
In most cases, script output is empty. Ktrace shows that ls(1) prints
its output, but script(1) ignores it.
Adding explicit timeout:
script s01 sh -c 'ls; sleep 1'
causes ls(1) output to be recorded in 100% runs.
With more long and complex cases, e.g.:
script s01 ls -lR /usr/lib
output contents are unstable and change from one run to another.
All this means race condition is reached.
But, detailed ktrace analysis shows this seems not to be happen in script(1),
but in pty(4). Essential parts of kdump:
97747 script CALL open(0xbfbfdea1,O_RDWR|O_NOCTTY,<unused>0x280897b8)
97747 script NAMI "/dev/ptyqa"
97747 script RET open 4
97747 script CALL fstat(0x4,0xbfbfddec)
97747 script STRU struct stat {dev=83951360, ino=186, mode=crw-rw-rw- , nlin
k=1, uid=0, gid=0, rdev=186, atime=1249554087, stime=1249511994, ctime=124951199
4, birthtime=-1, size=0, blksize=4096, blocks=0, flags=0x0 }
97747 script RET fstat 0
[...]
97749 ls CALL write(0x1,0x28216000,0x1d)
97749 ls GIO fd 1 wrote 29 bytes
"file1 file2 ktrace.out s01
"
97749 ls RET write 29/0x1d
97749 ls CALL sigprocmask(SIG_BLOCK,0x28074600,0xbfbfe12c)
97749 ls RET sigprocmask 0
97749 ls CALL sigprocmask(SIG_SETMASK,0x28074610,0)
97749 ls RET sigprocmask 0
97749 ls CALL sigprocmask(SIG_BLOCK,0x28074600,0xbfbfe0fc)
97749 ls RET sigprocmask 0
97749 ls CALL sigprocmask(SIG_SETMASK,0x28074610,0)
97749 ls RET sigprocmask 0
97749 ls CALL exit(0)
97747 script RET select 1
97747 script CALL read(0x4,0xbfbfe39c,0x400)
97747 script GIO fd 4 read 0 bytes
""
97747 script RET read 0
97747 script CALL wait4(0xffffffff,0xbfbfded8,WNOHANG,0)
97747 script RET wait4 97749/0x17dd5
97747 script CALL wait4(0xffffffff,0xbfbfded8,WNOHANG,0)
97747 script RET wait4 -1 errno 10 No child processes
So, read() from /dev/ptyqa gives 0 when data are written to slave side but
seems to be dropped because process terminated and pty is closed.
Earlier, they were kept in pty state until master side is closed.
>Fix:
>Release-Note:
>Audit-Trail:
>Unformatted:
More information about the freebsd-bugs
mailing list