O_NONBLOCK on stdin left set by child (using ash shell)

Denys Vlasenko vda.linux at googlemail.com
Tue Nov 10 19:32:48 UTC 2009


On Tue, Nov 10, 2009 at 7:33 PM, Johns Daniel <johns.daniel at gmail.com> wrote:
> On Tue, Nov 10, 2009 at 11:41 AM, Denys Vlasenko
> <vda.linux at googlemail.com> wrote:
>> On Tue, Nov 10, 2009 at 5:43 PM, Johns Daniel <johns.daniel at gmail.com> wrote:
>>> We just upgraded to BusyBox v1.14.4 (w/ built-in ash shell),
>>
>> ...where ash got a workaround to not require O_NONBLOCK
>> to be cleared on stdin (it used to reset it)...
>>
>>> and we
>>> have noticed what seems to be a bug.
>>
>> Yes, this is a design bug *in Unix API*. O_NONBLOCK had to be
>> a flag associated with a file descriptor, not a file,
>> like FD_CLOEXEC.
>>
>> Or it should be possible to use recv(fd, buf, size, MSG_DONTWAIT)
>> on non-sockets.
>>
>>> When we exit from one of our user apps that sets stdin to O_NONBLOCK,
>>> O_NONBLOCK remains set on stdin in the shell. So, any subsequent app
>>> not expecting O_NONBLOCK on stdin gets an unexpected EAGAIN. For
>>> example,
>>
>> How ash can know that it was not your *intention* to switch
>> O_NONBLOCK ob by one app and use it by other app?
>>
>
> It seems to me that it would be bad design to have such an intent.
> IOW, one app is changing the *parent shell* in order to pass a
> non-standard state on to the next app.
>
> The shell needs to be shared by many apps in the system. So, to work
> around the Unix issue, I think the shell should default to a "standard
> environment" each time it spawns a new app. If the new app wants
> O_NONBLOCK, then it should set it.
>
> My guess is that this is how most shells behave. I could be wrong; I
> might be missing some corner cases.
>
> Assuming we don't care about one app passing O_NONBLOCK to another
> app, are either of our patches a good solution to the problem?

If you can't fix the app which screws up stdin's nonblock bit,
then you can build and use a tiny helper program which fixes
stdin up:

nonblock_off.c
==============

#include <unistd.h>
#include <fcntl.h>
int main()
{
    fcntl(0, F_SETFL, fcntl(0, F_GETFL) & ~O_NONBLOCK);
    return 0;
}

--
vda


More information about the busybox mailing list