
Passing in labels of specific services did not actually work at all. Change-Id: I9501bc0206f0ce5cf064f1453fdf171c4c930aae
139 lines
4.3 KiB
Bash
139 lines
4.3 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.
|
|
# As of writing, the only way to create these sets of binaries is by means
|
|
# of the host-side "minix/llvm/clientctl buildasr" command.
|
|
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
|
|
# 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/$total/$filename ]; 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/$count/$filename
|
|
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.
|
|
service -a update $binary -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
|