#!/bin/sh set -eu repo_root=$(CDPATH= cd -- "$(dirname "$0")/../.." && pwd) guile_bin=${GUILE_BIN:-/tmp/guile-freebsd-validate-install/bin/guile} guile_extra_prefix=${GUILE_EXTRA_PREFIX:-/tmp/guile-gnutls-freebsd-validate-install} shepherd_prefix=${SHEPHERD_PREFIX:-/tmp/shepherd-freebsd-validate-install} shepherd_bin=$shepherd_prefix/bin/shepherd herd_bin=$shepherd_prefix/bin/herd metadata_target=${METADATA_OUT:-} if [ ! -x "$guile_bin" ]; then echo "Guile binary is not executable: $guile_bin" >&2 exit 1 fi ensure_built() { if [ ! -d "$guile_extra_prefix/share/guile/site" ] || \ ! GUILE_LOAD_PATH="$guile_extra_prefix/share/guile/site/3.0${GUILE_LOAD_PATH:+:$GUILE_LOAD_PATH}" \ GUILE_LOAD_COMPILED_PATH="$guile_extra_prefix/lib/guile/3.0/site-ccache${GUILE_LOAD_COMPILED_PATH:+:$GUILE_LOAD_COMPILED_PATH}" \ GUILE_EXTENSIONS_PATH="$guile_extra_prefix/lib/guile/3.0/extensions${GUILE_EXTENSIONS_PATH:+:$GUILE_EXTENSIONS_PATH}" \ LD_LIBRARY_PATH="$guile_extra_prefix/lib:/tmp/guile-freebsd-validate-install/lib:/usr/local/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" \ "$guile_bin" -c '(catch #t (lambda () (use-modules (fibers)) (display "ok") (newline)) (lambda _ (display "missing") (newline)))' | grep -qx ok; then METADATA_OUT= ENV_OUT= "$repo_root/tests/shepherd/build-local-guile-fibers.sh" fi if [ ! -x "$shepherd_bin" ] || [ ! -x "$herd_bin" ]; then METADATA_OUT= ENV_OUT= GUILE_EXTRA_PREFIX="$guile_extra_prefix" "$repo_root/tests/shepherd/build-local-shepherd.sh" fi } ensure_built run_root() { if [ "$(id -u)" -eq 0 ]; then "$@" else sudo "$@" fi } cleanup=0 if [ -n "${WORKDIR:-}" ]; then workdir=$WORKDIR mkdir -p "$workdir" else workdir=$(mktemp -d /tmp/freebsd-shepherd-init.XXXXXX) cleanup=1 fi if [ "${KEEP_WORKDIR:-0}" -eq 1 ]; then cleanup=0 fi chmod 0755 "$workdir" config_file=$workdir/init-config.scm boot_log=$workdir/boot-order.log pid_file=$workdir/shepherd.pid socket_file=$workdir/shepherd.sock shepherd_log=$workdir/shepherd.log shepherd_stdout=$workdir/shepherd.out metadata_file=$workdir/freebsd-shepherd-init-metadata.txt rc_name=fruix_shepherd_boot_$$ rc_script=/usr/local/etc/rc.d/$rc_name rc_template=$workdir/rc-template.in cleanup_workdir() { run_root service "$rc_name" onestop >/dev/null 2>&1 || true run_root rm -f "$rc_script" if [ "$cleanup" -eq 1 ]; then run_root rm -rf "$workdir" fi } trap cleanup_workdir EXIT INT TERM cat >"$config_file" <"$rc_template" <<'EOF' #!/bin/sh # PROVIDE: __RC_NAME__ # REQUIRE: LOGIN # KEYWORD: shutdown . /etc/rc.subr name=__RC_NAME__ rcvar="${name}_enable" : ${__RC_ENABLE_VAR__:=YES} pidfile=__PIDFILE__ socket=__SOCKET__ config=__CONFIG__ logfile=__LOGFILE__ command=__SHEPHERD_BIN__ start_cmd="__RC_START_FN__" stop_cmd="__RC_STOP_FN__" status_cmd="__RC_STATUS_FN__" __RC_START_FN__() { env LD_LIBRARY_PATH=__LD_LIBRARY_PATH__ \ GUILE_LOAD_PATH=__GUILE_LOAD_PATH__ \ GUILE_LOAD_COMPILED_PATH=__GUILE_LOAD_COMPILED_PATH__ \ GUILE_EXTENSIONS_PATH=__GUILE_EXTENSIONS_PATH__ \ __SHEPHERD_BIN__ -I -s "$socket" -c "$config" --pid="$pidfile" -l "$logfile" > "__STDOUT__" 2>&1 & for _try in 1 2 3 4 5 6 7 8 9 10; do [ -f "$pidfile" ] && [ -S "$socket" ] && return 0 sleep 1 done return 1 } __RC_STOP_FN__() { env LD_LIBRARY_PATH=__LD_LIBRARY_PATH__ \ GUILE_LOAD_PATH=__GUILE_LOAD_PATH__ \ GUILE_LOAD_COMPILED_PATH=__GUILE_LOAD_COMPILED_PATH__ \ GUILE_EXTENSIONS_PATH=__GUILE_EXTENSIONS_PATH__ \ __HERD_BIN__ -s "$socket" stop root >/dev/null 2>&1 || true for _try in 1 2 3 4 5 6 7 8 9 10; do [ ! -f "$pidfile" ] && return 0 sleep 1 done kill "$(cat "$pidfile")" >/dev/null 2>&1 || true rm -f "$pidfile" return 0 } __RC_STATUS_FN__() { [ -f "$pidfile" ] && kill -0 "$(cat "$pidfile")" >/dev/null 2>&1 } load_rc_config $name run_rc_command "$1" EOF rc_start_fn=${rc_name}_start rc_stop_fn=${rc_name}_stop rc_status_fn=${rc_name}_status rc_enable_var=${rc_name}_enable guile_bindir=$(CDPATH= cd -- "$(dirname "$guile_bin")" && pwd) guile_prefix=$(CDPATH= cd -- "$guile_bindir/.." && pwd) ld_library_path=$guile_extra_prefix/lib:$guile_prefix/lib:/usr/local/lib guile_load_path=$guile_extra_prefix/share/guile/site/3.0 guile_load_compiled_path=$guile_extra_prefix/lib/guile/3.0/site-ccache guile_extensions_path=$guile_extra_prefix/lib/guile/3.0/extensions sed \ -e "s|__RC_NAME__|$rc_name|g" \ -e "s|__RC_ENABLE_VAR__|$rc_enable_var|g" \ -e "s|__RC_START_FN__|$rc_start_fn|g" \ -e "s|__RC_STOP_FN__|$rc_stop_fn|g" \ -e "s|__RC_STATUS_FN__|$rc_status_fn|g" \ -e "s|__PIDFILE__|$pid_file|g" \ -e "s|__SOCKET__|$socket_file|g" \ -e "s|__CONFIG__|$config_file|g" \ -e "s|__LOGFILE__|$shepherd_log|g" \ -e "s|__STDOUT__|$shepherd_stdout|g" \ -e "s|__SHEPHERD_BIN__|$shepherd_bin|g" \ -e "s|__HERD_BIN__|$herd_bin|g" \ -e "s|__LD_LIBRARY_PATH__|$ld_library_path|g" \ -e "s|__GUILE_LOAD_PATH__|$guile_load_path|g" \ -e "s|__GUILE_LOAD_COMPILED_PATH__|$guile_load_compiled_path|g" \ -e "s|__GUILE_EXTENSIONS_PATH__|$guile_extensions_path|g" \ "$rc_template" | run_root tee "$rc_script" >/dev/null run_root chmod +x "$rc_script" run_root service "$rc_name" onestart for ready in filesystems.ready system-log.ready networking.ready login.ready; do [ -f "$workdir/$ready" ] || { echo "Expected boot marker missing: $workdir/$ready" >&2 exit 1 } done if run_root service "$rc_name" onestatus >/dev/null 2>&1; then rc_status=running else rc_status=stopped fi start_sequence=$(paste -sd, "$boot_log") expected_start_sequence=start:filesystems,start:system-log,start:networking,start:login if [ "$start_sequence" != "$expected_start_sequence" ]; then echo "Unexpected boot sequence: $start_sequence" >&2 exit 1 fi run_root service "$rc_name" onestop stop_sequence=$(tail -n 4 "$boot_log" | paste -sd, -) expected_stop_sequence=stop:login,stop:networking,stop:system-log,stop:filesystems if [ "$stop_sequence" != "$expected_stop_sequence" ]; then echo "Unexpected shutdown sequence: $stop_sequence" >&2 exit 1 fi if [ -f "$pid_file" ]; then echo "PID file still present after stop: $pid_file" >&2 exit 1 fi case $(cat "$shepherd_stdout") in *"System lacks support for 'signalfd'; using fallback mechanism."*) signalfd_fallback=yes ;; *) signalfd_fallback=no ;; esac cat >"$metadata_file" <