From 2587acda28156f50149a15cad67d0c0bc1eb0bb4 Mon Sep 17 00:00:00 2001 From: Jouke Witteveen Date: Sun, 5 May 2013 23:07:06 +0200 Subject: Use pkg-config to obtain the systemd system unit directory This ensures the units are installed correctly if systemd is installed in an alternate location like /lib/systemd. Idem for the location of profile-based units. Based on a proposal by: Mike Gilbert --- src/netctl.in | 181 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 src/netctl.in (limited to 'src/netctl.in') diff --git a/src/netctl.in b/src/netctl.in new file mode 100644 index 0000000..2d04d28 --- /dev/null +++ b/src/netctl.in @@ -0,0 +1,181 @@ +#! /bin/bash + +. /usr/lib/network/globals + +NETCTL_VERSION=notpackaged + + +usage() { + cat << END +Usage: netctl {COMMAND} [PROFILE] + [--help|--version] + +Commands: + list List available profiles + store Save which profiles are active + restore Load saved profiles + stop-all Stops all profiles + start [PROFILE] Start a profile + stop [PROFILE] Stop a profile + restart [PROFILE] Restart a profile + switch-to [PROFILE] Switch to a profile + status [PROFILE] Show runtime status of a profile + enable [PROFILE] Enable the systemd unit for a profile + disable [PROFILE] Disable the systemd unit for a profile + reenable [PROFILE] Reenable the systemd unit for a profile +END +} + +sd_escape() { + local IFS='' + # Prevent a recursion loop on backspaces + set -- "${@//\\/\\x5c}" + while [[ "$*" =~ [^[:alnum:].:_/\\] ]]; do + set -- "${@//$BASH_REMATCH/$(printf '\\x%x' "'$BASH_REMATCH")}" + done + printf '%s\n' "${@//\//-}" +} + +# Wrapper around systemctl to convert profile names to unit names +sd_call() { + local command=$1 + shift + set -- $(sd_escape "$@") + systemctl $command $(printf 'netctl@%s.service\n' "$@") +} + +list() { + local indicators=( '*' ' ' ) + list_profiles | while read -r Profile; do + sd_call "is-active --quiet" "$Profile" &> /dev/null + # Make the return variable boolean + [[ $? -eq 0 ]]; printf '%s %s\n' "${indicators[$?]}" "$Profile" + done +} + +store() { + mkdir -p "$(dirname "$STATE_FILE")" + list_profiles | while read -r Profile; do + if sd_call "is-active --quiet" "$Profile" &> /dev/null; then + printf "%s\n" "$Profile" + fi + done > "$STATE_FILE" +} + +restore() { + if [[ ! -r $STATE_FILE ]]; then + exit_error "Could not read state file '$STATE_FILE'" + elif [[ ! -s $STATE_FILE ]]; then + report_debug "No profiles to restore in state file '$STATE_FILE'" + else + mapfile -t Profiles < "$STATE_FILE" + do_debug sd_call start "${Profiles[@]}" + fi +} + +stop_all() { + # We cannot pipe to mapfile, as the end of a pipe is inside a subshell + mapfile -t Profiles < <(list_profiles) + [[ $Profiles ]] && do_debug sd_call stop "${Profiles[@]}" 2> \ + >(grep -Fv "not loaded" >&2) +} + +switch_to() { + cd "$PROFILE_DIR" + if [[ ! -r $1 ]]; then + exit_error "Profile '$1' does not exist or is not readable" + fi + # We assume interface names are not quoted + # Using read removes leading whitespace + read InterfaceLine < \ + <(grep -om1 "^[[:space:]]*Interface=[[:alnum:]:._-]\+" "$1") + if [[ -z $InterfaceLine ]]; then + exit_error "Profile '$1' does not specify an interface" + fi + mapfile -t AllProfiles < <(list_profiles) + mapfile -t Profiles < <(grep -Fl "$InterfaceLine" "${AllProfiles[@]}") + [[ $Profiles ]] && do_debug sd_call stop "${Profiles[@]}" 2> \ + >(grep -Fv "not loaded" >&2) + do_debug sd_call start "$1" +} + +unit_enable() { + local unit="@systemdsystemconfdir@/netctl@$(sd_escape "$1").service" + if [[ -e $unit ]]; then + report_error "A unit file for profile '$1' already exists" + return 1 + fi + load_profile "$1" + echo ".include @systemdsystemunitdir@/netctl@.service" > "$unit" + echo -e "\n[Unit]" >> "$unit" + [[ -n $Description ]] && echo "Description=$Description" >> "$unit" + if [[ -n ${BindsToInterfaces=$Interface} ]]; then + : ${InterfaceRoot=sys/subsystem/net/devices/} + printf "BindsTo=$(sd_escape "$InterfaceRoot")%s.device\n" \ + $(sd_escape "${BindsToInterfaces[@]}") >> "$unit" + printf "After=$(sd_escape "$InterfaceRoot")%s.device\n" \ + $(sd_escape "${BindsToInterfaces[@]}") >> "$unit" + fi + if [[ -n $After ]]; then + printf 'After="netctl@%s.service"\n' \ + $(sd_escape "${After[@]}") >> "$unit" + fi + echo "ln -s '$unit' '${unit/system\//system/multi-user.target.wants/}'" + ln -s "$unit" "${unit/system\//system/multi-user.target.wants/}" + systemctl daemon-reload +} + +unit_disable() { + local unit="@systemdsystemconfdir@/netctl@$(sd_escape "$1").service" + if sd_call "is-enabled --quiet" "$1" &> /dev/null; then + sd_call disable "$1" + fi + if [[ ! -f $unit ]]; then + report_error "No regular unit file found for profile '$1'" + return 1 + fi + do_debug rm "$unit" + systemctl daemon-reload +} + + +case $# in + 1) + case $1 in + --version) + report_notice "netctl version $NETCTL_VERSION";; + --help) + usage;; + list) + list;; + store|restore) + ensure_root "$(basename "$0")" + "$1";; + stop-all) + stop_all;; + *) + exit_error "$(usage)";; + esac;; + 2) + case $1 in + start|stop|restart|status) + sd_call "$1" "$2";; + switch-to) + ensure_root "$(basename "$0")" + switch_to "$2";; + enable|disable) + ensure_root "$(basename "$0")" + "unit_$1" "$2";; + reenable) + ensure_root "$(basename "$0")" + unit_disable "$2" + unit_enable "$2";; + *) + exit_error "$(usage)";; + esac;; + *) + exit_error "$(usage)";; +esac + + +# vim: ft=sh ts=4 et sw=4: -- cgit v1.2.3-24-g4f1b