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.
Best Answer
I get the same behaviour with:
sudo
opens/dev/tty
to query the current foreground process group, that causes theread()
system call made by bash'sread
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 theread
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 itsread
builtin usesselect()
first to wait for input, andselect()
doesn't return when the other process opens/dev/tty
.So here you could use
ksh93
instead ofbash
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 asroot
so you wouldn't need to runsudo
within the script (it's also potentially dangerous to extend the life of the sudo token longer than the user would expect).