Temporarily increasing sudo's timeout for the duration of an install script
Solution 1:
You can setup a loop that runs in the background to periodically execute "sudo -v", the trick of course is getting the loop to cleanly terminate when your script terminates. So there has to be some type of communication between the two processes; tmp files are fine for this, and they can easily be cleaned up after the script runs, too. (An install script usually does this, anyway.)
For example (remove the 'echo' statements to use this; these just show it "working"):
#!/bin/bash
log=running_setup.txt
sudo_stat=sudo_status.txt
echo "========= running script $$ ========"
echo $$ >> $sudo_stat
trap 'rm -f $sudo_stat >/dev/null 2>&1' 0
trap "exit 2" 1 2 3 15
sudo_me() {
while [ -f $sudo_stat ]; do
echo "checking $$ ...$(date)"
sudo -v
sleep 5
done &
}
echo "=setting up sudo heartbeat="
sudo -v
sudo_me
echo "=running setup=" | tee $log
while [ -f $log ]
do
echo "running setup $$ ...$(date) ===" | tee -a $log
sleep 2
done
# finish sudo loop
rm $sudo_stat
Then you'll see... (note: the pid is put into the tmp file, just so you can easily kill it. It's not necessary, though):
$ ./do_it.sh
========= running script 6776 ========
=setting up sudo heartbeat=
[sudo] password for user:
=running setup=
checking 6776 ...Wed May 4 16:31:47 PDT 2011
running setup 6776 ...Wed May 4 16:31:48 PDT 2011 ===
running setup 6776 ...Wed May 4 16:31:50 PDT 2011 ===
running setup 6776 ...Wed May 4 16:31:52 PDT 2011 ===
checking 6776 ...Wed May 4 16:31:53 PDT 2011
running setup 6776 ...Wed May 4 16:31:54 PDT 2011 ===
<ctrl-c> (cleans up files, then exits)
Solution 2:
I liked michael_n's answer, but had the most irrational desire not to use a temp file. Maybe this can provide some perspective.
My solution was:
#!/bin/bash
function sudo_ping() {
if [[ ! -z $SUDO_PID ]]; then
if [[ $1 -eq stop ]]; then
echo "Stopping sudo ping in PID = $SUDO_PID"
kill $SUDO_PID
return
else
echo "Already sudo pinging in PID = $SUDO_PID"
return
fi
fi
echo "Starting background sudo ping..."
sudo -v
if [[ $? -eq 1 ]]; then
echo "Oops, wrong password."
return
fi
sudo echo "ok"
while true; do
echo 'Sudo ping!'
sudo -v
sleep 1
done &
SUDO_PID=$!
sudo echo "Sudo pinging in PID = $SUDO_PID"
# Make sure we don't orphan our pinger
trap "sudo_ping stop" 0
trap "exit 2" 1 2 3 15
}
sudo_ping
sleep 5
echo "Goodbye!"
Again, the echo
's are extraneous...
$ ./sudoping.sh
Starting background sudo ping...
Password:
ok
Sudo ping!
Sudo pinging in PID = 47531
Sudo ping!
Sudo ping!
Sudo ping!
Sudo ping!
Goodbye!
Stopping sudo ping in PID = 47531
Again, ctrl-c works too...
$ ./sudoping.sh
Starting background sudo ping...
ok
Sudo ping!
Sudo pinging in PID = 47599
Sudo ping!
^CStopping sudo ping in PID = 47599
Solution 3:
Based on this gist, I've made a concise and clean version:
# Prevent sudo timeout
sudo -v # ask for sudo password up-front
while true; do
# Update user's timestamp without running a command
sudo -nv; sleep 1m
# Exit when the parent process is not running any more. In fact this loop
# would be killed anyway after being an orphan(when the parent process
# exits). But this ensures that and probably exit sooner.
kill -0 $$ 2>/dev/null || exit
done &