7

I have a long running Bash script that I don't want to run as root, but it needs root access periodically throughout. I solved this by asking for the user for the root password using

sudo -v

and then I backgrounded a process that would loop and reset the sudo timer using

sudo -n true

I then started to have weird problems when using read in the main process. Here is a minimal script exhibiting this problem. If you run it and don't input anything before the sudo -n true is run, the read gets a read error: 0: Resource temporarily unavailable

#!/usr/bin/env bash

sudo -v  # ask user for password

sleep 1 && sudo -n true &  # background a process to reset sudo

printf "Reading text: "
read -n 1 TEXT
echo "Read text: $TEXT"

I haven't been able to replicate this behavior with any other command besides sudo. How can I run sudo -n true in the background without interfering with read?

Edit:

I only get this problem on Ubuntu not macOS.

  • Does it work any better if you use sudo -v again instead of sudo -n true? – Stephen Kitt Feb 8 at 8:57
  • No it gives the identical behavior. – Ross MacArthur Feb 8 at 8:58
  • I'm unable to reproduce this issue on Arch Linux. – Alexander Feb 8 at 9:10
10

I get the same behaviour with:

sleep 1 && true < /dev/tty &
read var

sudo opens /dev/tty to query the current foreground process group, that causes the read() system call made by bash's read to return with EAGAIN with Ubuntu 18.04's Linux kernel 4.15.0-45-generic and 4.18.0-14-generic at least causing the read utility to return with that error.

That seems to be caused by a bug in recent versions of the Ubuntu variants of the Linux kernel. I can't reproduce it on Solaris nor FreeBSD, nor in any version of Linux on Debian (though I can reproduce it if I boot Debian on Ubuntu's 4.18 kernel).

https://bugs.launchpad.net/ubuntu/+source/linux-signed-hwe/+bug/1815021 seems to be another manifestation of that bug.

That's introduced by https://lkml.org/lkml/2018/11/1/663 which ubuntu backported to both its 4.15 and 4.18 kernels at least. But Ubuntu had not backported another change that fixes a regression introduced by that patch until 2 hours ago.

4.18.0-15-generic has now landed in the Ubuntu repositories and fixes the issue. I suppose the one for 4.15 will follow shortly.

ksh93 doesn't have the problem for that same code as its read builtin uses select() first to wait for input, and select() doesn't return when the other process opens /dev/tty.

So here you could use ksh93 instead of bash or wait for the fixed kernel or go back to 4.15.0-43 until 4.15.0-46 is released.

Alternatively, you could use zsh which has builtin support for changing uids (via the EUID/UID/USERNAME special variables) provided you start the script as root so you wouldn't need to run sudo within the script (it's also potentially dangerous to extend the life of the sudo token longer than the user would expect).

  • 1
    I'm not able to reproduce that testcase (what bash version is that?) -- but I don't see how another process opening /dev/tty could cause a read to return with EAGAIN; surely isn't it because of a SIGCHLD with CLD_STOPPED (itself caused by a SIGTTIN)? Is there some known bug explaining that? – mosvy Feb 8 at 9:58
  • 1
    @mosvy, no, as confirmed by strace, it's definitely the open() on /dev/tty that triggers the read() to return with EAGAIN. On that system, I can reproduce with any shell or utility that does a read() on the terminal device. – Stéphane Chazelas Feb 8 at 10:23
  • Hmm, the only way I could make a blocking read return EAGAIN is by setting O_NONBLOCK on the same file object -- but opening /dev/tty will not return the same file object as eg. /dev/pts/4. eg sleep 1 && perl -MFcntl=F_SETFL,F_GETFL,O_NONBLOCK -e 'fcntl STDIN, F_SETFL, fcntl(STDIN, F_GETFL, 0) | O_NONBLOCK' & read foo will not cause the read to fail with EAGAIN if perl's input is redirected from /dev/tty instead. – mosvy Feb 8 at 10:29
  • 1
    @mosvy, note that I get that error with bash -c 'sleep 1 && true < /dev/tty & read var' with 4.18 on Ubuntu but not on Debian, it may also be down to sysctl options. I'm going to try and narrow down what causes it on Ubuntu. In any case while EAGAIN is meant to be returned from non-blocking open file descriptions, it's not the case here, it looks like a specific behaviour of the pty driver with those kernels. – Stéphane Chazelas Feb 8 at 10:44
  • 1
    @mosvy, I can reproduce the problem if I boot Debian on the Ubuntu kernel. It looks like a kernel bug. bugs.launchpad.net/ubuntu/+source/linux-signed-hwe/+bug/1815021 seems related. Ubuntu has backported lkml.org/lkml/2018/11/1/663 – Stéphane Chazelas Feb 8 at 13:37

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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