I have a script like this (written for /bin/sh
on OpenBSD) which first updates a local copy of some CVS repositories using rsync
, and then updates the checked-out version of these on my machine. The script is run as root through OpenBSD's doas
(a sudo
"equivalent" on OpenBSD):
#!/bin/sh
int_handler () {
echo 'Wait...' >&2
quit=1
}
quit=0
trap int_handler INT
for r in CVSROOT src xenocara ports; do
su cvsuser -c 'rsync --archive --itemize-changes --delete --omit-dir-times \
"rsync://anoncvs.eu.openbsd.org/OpenBSD-cvs/$r/" \
"/extra/cvs/$r/"'
done
trap - INT
[ "$quit" -eq 1 ] && exit
# rest of script updates checked-out CVS repositories from local copy
The idea is that I may press Ctrl+C while the rsync
loop is running to later skip the second part of the script (which I may not always want to run, depending on what has been updated in the repositories) without interrupting the loop and its su
+rsync
processes.
This does not work and the rsync
process receives the signal and terminates (and the next iteration of the for
loop continues). rsync
says (when pressing Ctrl+C multiple times until the script terminates):
^Crsync error: received SIGINT, SIGTERM, or SIGHUP (code 20) at rsync.c(642) [generator=3.1.3]
rsync error: received SIGINT, SIGTERM, or SIGHUP (code 20) at io.c(504) [receiver=3.1.3]
Wait...
rsync: [receiver] write error: Broken pipe (32)
rsync error: received SIGINT, SIGTERM, or SIGHUP (code 20) at io.c(1633) [sender=3.1.3]
^Crsync error: received SIGINT, SIGTERM, or SIGHUP (code 20) at rsync.c(642) [generator=3.1.3]rsync error: received SIGINT, SIGTERM, or SIGHUP (code 20) at io.c(504) [receiver=3.1.3
]
rsync: [receiver] write error: Broken pipe (32)
Wait...
^Crsync error: received SIGINT, SIGTERM, or SIGHUP (code 20) at rsync.c(642) [generator=3.1.3]
rsync error: received SIGUSR1 (code 19) at main.c(1440) [receiver=3.1.3]
Wait...
According to an answer to the question "How to make ctrl+c /not/ interrupt the while-loop?", at least when running bash
, one should be able to ignore the INT
signal, which will make child processes also ignore that signal. This is not ideal, but I'd be happy to try.
So, second try in the light of that:
#!/usr/local/bin/bash
trap '' INT
for r in CVSROOT src xenocara ports; do
su cvsuser -c 'rsync --archive --itemize-changes --delete --omit-dir-times \
"rsync://anoncvs.eu.openbsd.org/OpenBSD-cvs/$r/" \
"/extra/cvs/$r/"'
done
trap - INT
read -p 'Press enter or interrupt...' junk
# rest of script updates checked-out CVS repositories from local copy
This likewise allows the rsync
process to be interrupted by Ctrl+C.
Ok, so maybe it's the su
that resets the signal mask? A third try:
#!/usr/local/bin/bash
trap '' INT
for r in CVSROOT src xenocara ports; do
su -s /usr/local/bin/bash cvsuser -c \
'trap "" INT; rsync --archive --itemize-changes --delete --omit-dir-times \
"rsync://anoncvs.eu.openbsd.org/OpenBSD-cvs/$r/" \
"/extra/cvs/$r/"'
done
trap - INT
read -p 'Press enter or interrupt...' junk
# rest of script updates checked-out CVS repositories from local copy
Nope, no joy. The rsync
process is still interruptible in the same way.
Is there a way to get the script working the way I (initially) intended?
bash
on my machine is release 4.4.23. The /bin/sh
is the native pdksh
variant on OpenBSD running in POSIX mode.
Best Answer
So, since you don't really want an interrupt, how about disabling it on the terminal level, with
stty intr ""
? That would make the^C
appear in the input buffer as any ordinary character, and we can read it from there.This works for me on Linux:
(I can't test on OpenBSD, but I suppose the terminal setup stuff is standard.)