#!/bin/sh
# copy original nvram executable to /tmp
cp /bin/nvram /tmp/_nvram
# create nvram wrapper that calls original nvram executable in /tmp
cat << 'EOF' > /tmp/nvram
#!/bin/sh
#set -x # comment/uncomment to disable/enable debug mode
# required for serialization when reentry is possible
LOCK="/tmp/$(basename "$0").lock"
acquire_lock() { until mkdir "$LOCK" &>/dev/null; do touch /tmp/nvram; done; }
release_lock() { rmdir "$LOCK" &>/dev/null; }
# one instance at a time
acquire_lock
# catch premature exit and cleanup
trap 'release_lock; exit 1' SIGHUP SIGINT SIGTERM
# make the new function accessible
#export PATH=/opt/bin:/opt/sbin:$PATH
# clear rc variable
rc=""
# keep count of total session usage
if [ ! -f "/tmp/nvramuse" ]; then
echo 0 > /tmp/nvramuse
fi
usecount=$(cat /tmp/nvramuse)
usecount=$((usecount + 1 ))
echo $usecount > /tmp/nvramuse
INTERVAL="10"
MAXCOUNT="3"
run_cmd () {
local to
local start
local child
# here as the interval number increases, the longer we wait.
to="$1"
to="$((to*INTERVAL))"; shift
$@ & local child="$!" start=0
touch /tmp/nvram
while { [ "$(kill -0 $child >/dev/null 2>&1; printf "%s" "$?")" = "0" ] && [ "$start" -le "$to" ]; }; do
# to account for killing too soon, as the number of tries required increases our count requirement increases before we attempt to kill the process.
touch /tmp/nvram
start="$((start+1))"
if [ $start -gt $to ]; then
kill -s 9 $child 2>/dev/null
wait $child
return 1
fi
done
return 0
}
# make the new function accessible, on the first run we want to exit right away if successful.
i="1"
if { run_cmd "$i" /tmp/_nvram "$@"; }; then rc="0"; else rc="1";fi
logger -t "nvram-override" "Executed nvram $@, use count: $usecount, exit status: $rc"
# here we add an interval check and allow up to 3 retries.
while [ "$i" -le "$MAXCOUNT" ] && [ "$rc" != "0" ]; do
touch /tmp/nvram
if { run_cmd "$i" /tmp/_nvram "$@"; }; then
rc="0";
else
rc="1";
errcount="$rc";
if [ ! -f "/tmp/nvramerr" ]; then echo 0 > /tmp/nvramerr; else errcount=$(cat /tmp/nvramerr); fi
errcount=$((errcount + 1 ));
echo $errcount > /tmp/nvramerr;
logger -t "nvram-override" "Error detected at use count: $usecount, error count: $errcount";
logger -t "nvram-override" "Couldn't execute nvram $@, exit status: $rc (124=timeout)";
fi
logger -t "nvram-override" "Retried executing nvram $@, attempt ${i}/${MAXCOUNT}, exit status: $rc";
i="$((i+1))";
done
[ "$rc" -eq "1" ] && logger -t "nvram-override" "NVRAM remained locked too long; continuing anyway."
# any concurrent instance(s) may now run
release_lock
exit $rc
EOF
chmod +x /tmp/nvram
# replace nvram in /usr/sbin w/ nvram wrapper in /tmp
mount -o bind /tmp/nvram /bin/nvram