4

Certain commands start to consistently fail in a given terminal window:

$ sudo apt-get install ipython
...
After this operation, 3,826 kB of additional disk space will be used.
Do you want to continue? [Y/n] Abort.
$ 

$ kinit -f <username>
Password for <username>@<domain>: 
kinit: Pre-authentication failed: Cannot read password while getting initial credentials
$

$ passwd
Changing password for <username>.
(current) UNIX password: 
passwd: Authentication token manipulation error
passwd: password unchanged
$ 

$ crontab -e
Too many errors from stdincrontab: "/usr/bin/sensible-editor" exited with status 1
$ 

$ sudo docker run -it ubuntu bash
(hangs forever)

In searching for the cause, strace revealed that the programs attempt to read from STDIN but receive an error:

read(0, 0x7fffe1205cc7, 1) = -1 EAGAIN (Resource temporarily unavailable)

From the read(2) man page:

ERRORS
    EAGAIN The file descriptor fd refers to a file other than a socket and has been marked nonblocking (O_NONBLOCK), and the read would block.

Sure enough, STDIN is marked non-blocking for that terminal window (indicated by the 4 in flags):

$ cat /proc/self/fdinfo/0 
pos:    0
flags:  0104002
mnt_id: 25

I'm assuming that some program I was using set STDIN to non-blocking mode and then didn't set it back upon exiting (or it was killed before it could.)

I couldn't figure out how to fix this issue from the command line, so I wrote the following program to do it (and it also lets you change STDIN to non-blocking mode to see what breaks.)

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int makeStdinNonblocking(int flags) {
    if (fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK) < 0) { 
        printf("Error calling fcntl in %s: %s\n", __FUNCTION__, strerror(errno));
        return EXIT_FAILURE;
    } 
    return EXIT_SUCCESS;
}
int makeStdinBlocking(int flags) {
    if (fcntl(STDIN_FILENO, F_SETFL, flags & ~(O_NONBLOCK)) < 0) { 
        printf("Error calling fcntl in %s: %s\n", __FUNCTION__, strerror(errno));
        return EXIT_FAILURE;
    } 
    return EXIT_SUCCESS;
}
int main(int argc, char *argv[]) {
    int flags;
    if (argc != 2) {
        goto usage;
    }
    if ((flags = fcntl(STDIN_FILENO, F_GETFL, 0)) < 0) {
        printf("Error calling fcntl in %s: %s\n", __FUNCTION__, strerror(errno));
        return EXIT_FAILURE;
    }
    if (0 == strncmp(argv[1], "nonblock", 9)) {
        return makeStdinNonblocking(flags);
    }
    else if ( 0 == strncmp(argv[1], "block", 6)) {
        return makeStdinBlocking(flags);
    }
usage:
    printf("Usage: %s <nonblock|block>\n", argv[0]);
    return EXIT_FAILURE;
}

Anyway, I was wondering:

  1. Is there a way to make STDIN not non-blocking with standard command line utilities?
  2. Should the shell (in my case, bash) automatically restore the flags on STDIN (and/or STDOUT/STDERR) between commands? Is there a use case for one command relying on STDIN changes made by another program?
  3. Is it a bug for a program to assume that STDIN will be in blocking mode when the program starts, and should each program have to specifically turn-off non-blocking mode if it would cause things to break (see the examples above)?

For reference, I'm using Ubuntu 17.10 and GNU bash, version 4.4.12(1)-release (x86_64-pc-linux-gnu)

Update: It looks like this issue was addressed for Fedora with a patch to bash:

https://bugzilla.redhat.com/show_bug.cgi?id=1068697

The fix doesn't appear to have been applied upstream, though, at least with version 4.4.18(1)-release (from January 2018.) Also, the bash maintainer mentions that bash shouldn't really be responsible for this:

https://lists.gnu.org/archive/html/bug-bash/2017-01/msg00043.html

It sounds like applications should be responsible for restoring the original flags of STDIN if it changes them, so I'm using the following program to check STDIN:

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main() {
    int flags;
    if ((flags = fcntl(STDIN_FILENO, F_GETFL, 0)) < 0) {
        printf("Error calling fcntl in %s: %s\n", __FUNCTION__, strerror(errno));
    }
    if (0 != (flags & (O_NONBLOCK))) {
        printf("Warning, STDIN in nonblock mode\n");
    }
    return EXIT_SUCCESS;
}

I compiled the program (gcc -o checkstdin checkstdin.c) and then put the following in my .bashrc to get it to run after every command:

PROMPT_COMMAND+="/path/to/checkstdin"

It will print a warning to STDOUT if it detects that STDIN is now in non-blocking mode.

2

When this happens, run bash from the command line, then exit (to return the first bash). Should work again. Somewhat interesting details here: https://stackoverflow.com/questions/19895185/bash-shell-read-error-0-resource-temporarily-unavailable.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.