--- /dev/null
+#!/bin/sh
+
+MEAS_DIR=/usr/lib/ripe-atlas/measurement
+SCRIPT_DIR=/usr/lib/ripe-atlas/scripts
+SHARE_DIR=/usr/share/ripe-atlas
+BUSYBOX="$MEAS_DIR/busybox"
+
+# Atlas measurement applets. Standard busybox applets are deliberately not
+# built in, so only these plus the patched telnetd are expected.
+APPLETS="atlasinit buddyinfo condmv date dfrm eooqd eperd evhttpget evntp \
+evping evsslgetcert evtdig evtraceroute httppost onlyuptime perd rchoose \
+rptaddrs rptra6 rptuptime rxtxrpt telnetd"
+
+check_applets() {
+ for applet in $APPLETS; do
+ path="$MEAS_DIR/$applet"
+ [ -e "$path" ] || { echo "FAIL: missing applet: $applet"; exit 1; }
+ if [ -L "$path" ]; then
+ target=$(readlink "$path")
+ case "$target" in
+ busybox|./busybox|"$BUSYBOX") ;;
+ *) echo "FAIL: applet $applet -> unexpected target: $target"; exit 1 ;;
+ esac
+ elif [ -f "$path" ]; then
+ bb_inode=$(ls -i "$BUSYBOX" | awk '{print $1}')
+ ap_inode=$(ls -i "$path" | awk '{print $1}')
+ [ "$bb_inode" = "$ap_inode" ] || {
+ echo "FAIL: applet $applet is not a busybox hardlink"; exit 1; }
+ else
+ echo "FAIL: applet $applet is neither symlink nor regular file"
+ exit 1
+ fi
+ done
+
+ applet_list=$("$BUSYBOX" --list 2>/dev/null) || {
+ echo "FAIL: 'busybox --list' failed"; exit 1; }
+ for applet in $APPLETS; do
+ echo "$applet_list" | grep -qx "$applet" || {
+ echo "FAIL: applet '$applet' missing from 'busybox --list'"; exit 1; }
+ done
+}
+
+# Catch crash signals (132/134/137/139) and hangs. Output is not asserted
+# because the applet CLIs vary across Atlas releases.
+run_applet_smoke() {
+ name="$1"; shift
+ out=$(timeout 5 "$BUSYBOX" "$name" "$@" 2>&1); rc=$?
+ case "$rc" in
+ 124) echo "FAIL: applet $name timed out"; exit 1 ;;
+ 132|134|137|139)
+ echo "FAIL: applet $name crashed (rc=$rc)"; echo "$out"; exit 1 ;;
+ esac
+}
+
+case "$1" in
+ripe-atlas-common)
+ [ -x "$BUSYBOX" ] || { echo "FAIL: $BUSYBOX not installed"; exit 1; }
+ [ -s "$BUSYBOX" ] || { echo "FAIL: $BUSYBOX is empty"; exit 1; }
+ check_applets
+
+ # The probe drops to this user, so it must exist with a matching group.
+ uid=$(awk -F: '$1=="ripe-atlas" {print $3}' /etc/passwd)
+ [ -n "$uid" ] || { echo "FAIL: user 'ripe-atlas' missing from /etc/passwd"; exit 1; }
+ gid=$(awk -F: '$1=="ripe-atlas" {print $3}' /etc/group)
+ [ -n "$gid" ] || { echo "FAIL: group 'ripe-atlas' missing from /etc/group"; exit 1; }
+
+ # Exercise the applets that need no network peer.
+ run_applet_smoke rptuptime
+ run_applet_smoke dfrm -A 9018 /tmp 1 /tmp /tmp
+ run_applet_smoke condmv /tmp/atlas-no-such-src /tmp/atlas-no-such-dst
+ [ -r /proc/uptime ] && run_applet_smoke onlyuptime
+ [ -r /proc/buddyinfo ] && run_applet_smoke buddyinfo 1 /dev/null
+ [ -r /proc/net/dev ] && run_applet_smoke rxtxrpt -A 9999
+
+ # The shell libraries the init and reginit source at runtime.
+ for f in common.sh config.sh paths.lib.sh json.lib.sh support.lib.sh \
+ linux-functions.sh reginit.sh; do
+ [ -s "$SCRIPT_DIR/$f" ] || { echo "FAIL: $SCRIPT_DIR/$f missing or empty"; exit 1; }
+ done
+ for f in $(ls "$SCRIPT_DIR"/*.sh 2>/dev/null); do
+ sh -n "$f" || { echo "FAIL: $f is not valid shell"; exit 1; }
+ done
+
+ [ -s "$SHARE_DIR/capabilities.json" ] || {
+ echo "FAIL: $SHARE_DIR/capabilities.json missing or empty"; exit 1; }
+ jsonfilter -i "$SHARE_DIR/capabilities.json" -e '@.effective' >/dev/null || {
+ echo "FAIL: capabilities.json is not valid JSON"; exit 1; }
+ jsonfilter -i "$SHARE_DIR/capabilities.json" -e '@.effective[*]' | grep -qx CAP_NET_RAW || {
+ echo "FAIL: capabilities.json does not grant CAP_NET_RAW"; exit 1; }
+
+ [ -x /etc/init.d/ripe-atlas ] || { echo "FAIL: /etc/init.d/ripe-atlas not installed"; exit 1; }
+ sh -n /etc/init.d/ripe-atlas || { echo "FAIL: init script is not valid shell"; exit 1; }
+ [ -s /etc/config/ripe-atlas ] || { echo "FAIL: /etc/config/ripe-atlas missing or empty"; exit 1; }
+ uci -q show ripe-atlas >/dev/null || { echo "FAIL: uci cannot parse ripe-atlas config"; exit 1; }
+
+ [ -x /usr/sbin/ripe-atlas ] || { echo "FAIL: /usr/sbin/ripe-atlas not installed"; exit 1; }
+ ;;
+
+ripe-atlas-probe|ripe-atlas-anchor)
+ # Each variant ships the registration servers and host keys for its own
+ # environment; without them the probe cannot register.
+ [ -s "$SCRIPT_DIR/reg_servers.sh.prod" ] || {
+ echo "FAIL: $SCRIPT_DIR/reg_servers.sh.prod missing or empty"; exit 1; }
+ sh -n "$SCRIPT_DIR/reg_servers.sh.prod" || {
+ echo "FAIL: reg_servers.sh.prod is not valid shell"; exit 1; }
+ grep -qE '^REG_[0-9]+_HOST=[^[:space:]]' "$SCRIPT_DIR/reg_servers.sh.prod" || {
+ echo "FAIL: reg_servers.sh.prod defines no REG_*_HOST entries"; exit 1; }
+
+ [ -s "$SHARE_DIR/known_hosts.reg" ] || {
+ echo "FAIL: $SHARE_DIR/known_hosts.reg missing or empty"; exit 1; }
+ grep -q 'ssh-\|ecdsa-' "$SHARE_DIR/known_hosts.reg" || {
+ echo "FAIL: known_hosts.reg holds no host keys"; exit 1; }
+ ;;
+esac
+
+exit 0