Re: Bug#1003095: /usr/bin/script: hangs when child doesn't read input fast enough

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



[adding util-linux@xxxxxxxxxxxxxxx to CC:]

Dear наб,

thank you for your report.

* наб <nabijaczleweli@xxxxxxxxxxxxxxxxxx> [220104 00:06]:
> Package: bsdutils
> Version: 1:2.37.2-5
> Severity: normal
> File: /usr/bin/script
> 
> Dear Maintainer,
> 
> Consider the following:
>   $ script -c 'for i in $(seq 10); do echo $i; done; read -r a; echo a=$a' < term-utils/script.c
> 
> What do you expect to happen here? Well, numbers 1-10, of course, then
> "a=/*" from the heading, right?
> 
> This is, of course, a trick question: that holds on 4.4BSD-Lite script.
>
> However, util-linux script returns:
>   Script started, output log file is 'typescript'.
>
> That's it, it hangs. Due to the funny nature of signal handling here,
> you have to terminate it from a different terminal.
> 
> Stracing it reveals the nature of this beast:
>   $ strace -eread,write,poll script -c 'for i in $(seq 10); do echo a; sleep 0.1; done; read -r a; echo a=$a' < term-utils/script.c
>   read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20\22\0\0\0\0\0\0"..., 832) = 832
>   read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0@n\2\0\0\0\0\0"..., 832) = 832
>   read(3, "# Locale name alias data base.\n#"..., 3072) = 2996
>   read(3, "", 3072)                       = 0
>   write(1, "Script started, output log file "..., 49Script started, output log file is 'typescript'.
>   ) = 49
>   read(4, "# /etc/nsswitch.conf\n#\n# Example"..., 512) = 510
>   read(4, "", 512)                        = 0
>   read(4, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0003\0\0\0\0\0\0"..., 832) = 832
>   read(4, "root:x:0:\ndaemon:x:1:\nbin:x:2:\ns"..., 2048) = 1768
>   read(7, "TZif2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\v\0\0\0\v\0\0\0\0"..., 3072) = 2696
>   read(7, "TZif2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\v\0\0\0\v\0\0\0\0"..., 3072) = 1698
>   poll([{fd=5, events=POLLIN|POLLERR|POLLHUP}, {fd=3, events=POLLIN|POLLERR|POLLHUP}, {fd=0, events=POLLIN|POLLERR|POLLHUP}], 3, -1) = 1 ([{fd=0, revents=POLLIN}])
>   read(0, "/*\n * Copyright (C) 1980      Re"..., 8192) = 8192
>   write(3, "/*\n * Copyright (C) 1980      Re"..., 8192) = 8192
>   poll([{fd=5, events=POLLIN|POLLERR|POLLHUP}, {fd=3, events=POLLIN|POLLERR|POLLHUP}, {fd=0, events=POLLIN|POLLERR|POLLHUP}], 3, -1) = 2 ([{fd=3, revents=POLLIN}, {fd=0, revents=POLLIN}])
>   read(3, "/*\r\n * Copyright (C) 1980      R"..., 8192) = 499
>   write(1, "/*\r\n * Copyright (C) 1980      R"..., 499/*
>    * Copyright (C) 1980      Regents of the University of California.
>    * Copyright (C) 2013-2019 Karel Zak <kzak@xxxxxxxxxx>
>    *
>    * All rights reserved.
>    *
>    * Redistribution and use in source and binary forms, with or without
>    * modification, are permitted provided that the following conditions
>    * are met:
>    * 1. Redistributions of source code must retain the above copyright
>    *    notice, this list of conditions and the following disclaimer.
>    * 2. Redistributions in binary form must r) = 499
>   read(0, "n log;\t/* already defined */\n\n\tl"..., 8192) = 8192
>   write(3, "n log;\t/* already defined */\n\n\tl"..., 8192
> 
> (This, at least, responds to ^\, but it also seems to function
>  slightly differently. Also, this is a race and you're more
>  likely to lose it under strace. The loopy thing seems
>  like it's pretty good at hitting it 100% of the time.)
> 
> script is deadlocked on writing to the master pty
> against the child writing its data.
> 
> I've found this when re-writing NetBSD script(1) to use a single process
> and poll(2), because I saw poll() in this implementation's strace.
> There are a few ways I see to potentially work around this:
>   1. poll() the master PTY on POLLOUT, too; this doesn't work on NetBSD,
>      because writes to ptys don't seem to shard there ‒ even if the
>      master pty is POLLOUT, writing 1024 bytes to it will block forever,
>      but maybe it will on Linux;
>   2. Forcibly interrupt the write call with an alarm. This sucks ass,
>      of course, but it's the least intrusive if it does work.
>   3. In the original implementation, there's two controlling processes:
>        leader       ‒ main()     ‒ copies stdin to the master pty
>          child      ‒ dooutput() ‒ copies master pty to stdout/fscript
>            subchild ‒ doshell()  ‒ execs $SHELL -i/sh -c "command"
> 
> The original implementation is fundamentally not susceptible to this,
> techically making this the rare "regression against 4.4BSD-Lite".


Alright. Some questions:

1) is this Debian-specific or already present upstream?

2) did this work with previous versions of util-linux?

> Best,
> наб

Best,
Chris




[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux