David van Moolenbroek c58da9fbc3 Rename MINIX service(8) to minix-service(8)
IMPORTANT: this change has a docs/UPDATING entry!

This rename is unfortunately necessary because NetBSD has decided to
create its own service(8) utility, and we will want to import theirs
as well.  The two can obviously not coexist.

Also move ours from /bin to /sbin, as it is a superuser-only utility.

Change-Id: Ic6e46ffb3a84b4747d2fdcb0d74e62dbea065039
2017-02-22 17:16:21 +00:00

137 lines
4.2 KiB
Bash

#!/bin/sh
# ASR live update script by David van Moolenbroek <david@minix3.org>
# The path to the initial, standard system service binaries.
SERVICE_PATH=/service
# The path to the alternative, ASR-rerandomized system service binaries.
# The path used here is typically a symlink into /usr for size reasons.
SERVICE_ASR_PATH=$SERVICE_PATH/asr
# A space-separated list of labels not to update in any case. The list
# includes the memory service, which is currently not compiled with bitcode
# and therefore also not instrumented. It also contains the VM service,
# for which ASR is possible but too dangerous: much of its address space is
# deliberately ignored by the instrumentation, and ASR would invalidate any
# pointers from the ignored memory to the relocated memory. Note that
# skipped services may still have rerandomized binaries on disk.
SKIP="memory vm"
# Custom live update states to use for certain label prefixes. This list is
# made up of space-separated tokens, each token consisting of a label prefix,
# followed by a colon, followed by the state number to use for those labels.
# Currently it contains all services that make use of worker threads. This
# setting should not need to exist; see the corresponding TODO item below.
STATES="vfs:2 ahci_:2 virtio_blk_:2"
# If this variable is set, it is used as timeout for the live updates. The
# minix-service(8) argument takes a number of click ticks, or a number of
# seconds if the value ends with "HZ".
TIMEOUT=300HZ
# Configuration ends here.
debug() {
if [ $verbose -eq 1 ]; then
echo "$@"
fi
}
verbose=0
ret=0
while getopts 'v' opt; do
case $opt in
v) verbose=1
;;
?) echo "Usage: $0 [-v] [label [label..]]" >&2
exit 1
esac
done
shift $(($OPTIND - 1))
if [ $# -eq 0 ]; then
services=$(echo /proc/service/*)
else
services=
for label in $@; do
services="$services /proc/service/$label"
done
fi
for service in $services; do
label=$(basename $service)
filename=$(grep filename: $service | cut -d' ' -f2)
count=$(grep ASRcount: $service | cut -d' ' -f2)
# Start by making sure we are not supposed to skip this service.
if echo " $SKIP " | grep -q " $label "; then
debug "skipping $label: found in skip list"
continue
fi
# The base binary of the program has number 0 and must be present.
if [ ! -f $SERVICE_PATH/$filename ]; then
debug "skipping $label: no base binary found"
continue
fi
# Count the ASR binaries for this program, starting from number 1.
# There must be at least one, so that we can switch between versions.
# By counting using a number rather than using a directory iterator,
# we avoid potential problems with gaps between the numbers by
# stopping at the first number for which no binary is present.
total=1
while [ -f $SERVICE_ASR_PATH/$filename-$total ]; do
total=$(($total + 1))
done
if [ $total -eq 1 ]; then
debug "skipping $label: no ASR binaries found"
continue
fi
# Determine the path name of the binary to use for this update.
# TODO: pick the next binary at random rather than round-robin.
count=$((($count + 1) % $total))
if [ $count -eq 0 ]; then
binary=$SERVICE_PATH/$filename
else
binary=$SERVICE_ASR_PATH/$filename-$count
fi
# Check whether the live update should use a state other than the
# default (namely state 1, which is "work free"). In particular, any
# programs that use threads typically need another state (namely state
# 2, which is "request free". TODO: allow services to specify their
# own default state, thus avoiding the redundancy introduced here.
state=
for token in $STATES; do
prefix=$(echo $token | cut -d: -f1)
if echo "$label" | grep -q -e "^$prefix"; then
state="-state $(echo $token | cut -d: -f2)"
fi
done
# Apply a custom timeout if present. This may be necessary in VMs.
maxtime=
if [ -n "$TIMEOUT" ]; then
maxtime="-maxtime $TIMEOUT"
fi
# Perform the live update. The update may legitimately fail if the
# service is not in the right state. TODO: report transient errors
# as debugging output only.
minix-service -a update $binary -progname $filename -label $label \
-asr-count $count $state $maxtime
error=$?
if [ $error -eq 0 ]; then
debug "updated $label to number $count, total $total"
else
echo "failed updating $label: error $error" >&2
ret=1
fi
done
exit $ret