| #!/bin/bash |
|
|
| function get_unit_file(){ |
| |
| local UNIT=$1 |
|
|
| for DIR in ${UNIT_PATHS[@]} ; do |
| if [ -f "${DIR}${UNIT}" ] ; then |
| echo "${DIR}${UNIT}" |
| break |
| fi |
| done |
|
|
| } |
|
|
| function read_option(){ |
| local OPTION="$1" |
| local UNIT_FILE="$2" |
| local UNIT_INSTANCE="$3" |
|
|
| local UNIT=`basename $UNIT_FILE` |
| local UNIT_FULL=`echo $UNIT | sed "s/@/@$UNIT_INSTANCE/"` |
|
|
| VALUE="$(grep '^'$OPTION'[= ]' "$UNIT_FILE" | cut -d '=' -f2- | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" |
|
|
| VALUE="` |
| echo $VALUE | |
| sed -e "s/%[i]/$UNIT_INSTANCE/g" \ |
| -e "s/%[I]/\"$UNIT_INSTANCE\"/g" \ |
| -e "s/%[n]/$UNIT_FULL/g" \ |
| -e "s/%[N]/\"$UNIT_FULL\"/g" |
| `" |
| |
| |
|
|
| echo $VALUE |
| } |
|
|
| function get_unit_wants() { |
|
|
| local UNIT_FILE=$1 |
| local UNIT=`basename $UNIT_FILE` |
|
|
| sort -u <<< `( |
| |
| for DIR in ${UNIT_PATHS[@]} ; do |
| if [ -d "${DIR}${UNIT}.wants" ] ; then |
| ls -1 "${DIR}${UNIT}.wants/" | tr '\n' ' ' |
| fi |
| done |
| |
| |
| read_option Wants $UNIT_FILE |
| )` |
| } |
|
|
| function action_start(){ |
|
|
| |
| local UNIT_FILE=$1 |
| local UNIT_WANTS=(`get_unit_wants $1`) |
| local UNIT_INSTANCE=$2 |
|
|
| |
| for UNIT in ${UNIT_WANTS[@]}; do |
| exec_action start $UNIT |
| done |
|
|
| |
| local User=`read_option User $UNIT_FILE $UNIT_INSTANCE` |
| local Type=`read_option Type $UNIT_FILE $UNIT_INSTANCE` |
| local EnvironmentFile=`read_option EnvironmentFile $UNIT_FILE $UNIT_INSTANCE` |
| local ExecStartPre=(`read_option ExecStartPre $UNIT_FILE $UNIT_INSTANCE`) |
| local ExecStart=`read_option ExecStart $UNIT_FILE $UNIT_INSTANCE` |
| local ExecStartPost=(`read_option ExecStartPost $UNIT_FILE $UNIT_INSTANCE`) |
| local Restart=(`read_option Restart $UNIT_FILE $UNIT_INSTANCE`) |
| local RestartSec=(`read_option RestartSec $UNIT_FILE $UNIT_INSTANCE`) |
| RestartSec=${RestartSec:=5} |
|
|
| [ -f "$EnvironmentFile" ] && source "$EnvironmentFile" |
|
|
| |
| if [ -z $Type ] || [[ "${Type,,}" == *"simple"* ]] ; then |
| if [ "$Restart" == "always" ]; then |
| COMMAND='nohup bash -c "while true ; do '"$ExecStart"'; sleep $RestartSec; done" &>/dev/null &' |
| else |
| COMMAND='nohup '"$ExecStart"' >>/dev/null 2>&1 &' |
| fi |
| elif [[ "${Type,,}" == *"forking"* ]] || [[ "${Type,,}" == *"oneshot"* ]] ; then |
| COMMAND="$ExecStart" |
| else |
| >&2 echo "Unknown service type $Type" |
| fi |
|
|
| |
|
|
| while IFS=$'\n' read -a i; do |
| eval $i |
| done <<< "${ExecStartPre[@]}" |
|
|
| eval "$COMMAND" |
|
|
| while IFS=$'\n' read -a i; do |
| eval $i |
| done <<< "${ExecStartPost[@]}" |
| } |
|
|
| function action_stop(){ |
|
|
| |
| local UNIT_FILE=$1 |
| local UNIT_WANTS=(`get_unit_wants $1`) |
| local UNIT_INSTANCE=$2 |
|
|
| |
| local User=`read_option User $UNIT_FILE $UNIT_INSTANCE` |
| local Type=`read_option Type $UNIT_FILE $UNIT_INSTANCE` |
| local EnvironmentFile=`read_option EnvironmentFile $UNIT_FILE $UNIT_INSTANCE` |
| local ExecStopPre=(`read_option ExecStartPre $UNIT_FILE $UNIT_INSTANCE`) |
| local ExecStop=`read_option ExecStop $UNIT_FILE $UNIT_INSTANCE` |
| local ExecStopPost=(`read_option ExecStartPost $UNIT_FILE $UNIT_INSTANCE`) |
| local ExecStart=`read_option ExecStart $UNIT_FILE $UNIT_INSTANCE` |
|
|
| [ -f "$EnvironmentFile" ] && source "$EnvironmentFile" |
|
|
| |
| if [ -z $ExecStop ] ; then |
| COMMAND="kill -TERM \$(pgrep -f \"$ExecStart\")" |
| else |
| COMMAND="$ExecStop" |
| fi |
|
|
| |
|
|
| while IFS=$'\n' read -a i; do |
| eval $i |
| done <<< "${ExecStopPre[@]}" |
|
|
| eval "$COMMAND" |
|
|
| while IFS=$'\n' read -a i; do |
| eval $i |
| done <<< "${ExecStopPost[@]}" |
| } |
|
|
| function action_restart(){ |
| local UNIT_FILE=$1 |
| local UNIT_INSTANCE=$2 |
|
|
| action_stop $UNIT_FILE $UNIT_INSTANCE |
| action_start $UNIT_FILE $UNIT_INSTANCE |
| } |
|
|
|
|
| function action_enable(){ |
|
|
| local UNIT_FILE=$1 |
| local UNIT=`basename $UNIT_FILE` |
| local UNIT_INSTANCE=$2 |
| local UNIT_FULL=`echo $UNIT | sed "s/@/@$UNIT_INSTANCE/"` |
|
|
| local WantedBy=`read_option WantedBy $UNIT_FILE` |
|
|
| if [ -z $WantedBy ] ; then |
| >&2 echo "Unit $UNIT have no WantedBy option." |
| exit 1 |
| fi |
| |
| local WANTEDBY_DIR="/etc/systemd/system/$WantedBy.wants" |
|
|
| if [ ! -f "$WANTEDBY_DIR/$UNIT_FULL" ] ; then |
| mkdir -p $WANTEDBY_DIR |
| echo Created symlink from $WANTEDBY_DIR/$UNIT_FULL to $UNIT_FILE. |
| ln -s $WANTEDBY_DIR/$UNIT_FULL $UNIT_FILE |
| fi |
| |
| } |
| |
| function action_disable(){ |
|
|
| local UNIT_FILE=$1 |
| local UNIT=`basename $UNIT_FILE` |
| local UNIT_INSTANCE=$2 |
| local UNIT_FULL=`echo $UNIT | sed "s/@/@$UNIT_INSTANCE/"` |
|
|
| local WantedBy=`read_option WantedBy $UNIT_FILE` |
|
|
| if [ -z $WantedBy ] ; then |
| >&2 echo "Unit $UNIT have no WantedBy option." |
| exit 1 |
| fi |
|
|
| local WANTEDBY_DIR="/etc/systemd/system/$WantedBy.wants" |
|
|
| if [ -f "$WANTEDBY_DIR/$UNIT_FULL" ] ; then |
| echo Removed $WANTEDBY_DIR/$UNIT_FULL. |
| rm -f $WANTEDBY_DIR/$UNIT_FULL. |
| rmdir --ignore-fail-on-non-empty $WANTEDBY_DIR |
| fi |
| |
| } |
|
|
| function action_status(){ |
|
|
| |
| local UNIT_FILE=$1 |
| local UNIT_WANTS=(`get_unit_wants $1`) |
| local UNIT_INSTANCE=$2 |
|
|
| local ExecStart=`read_option ExecStart $UNIT_FILE $UNIT_INSTANCE` |
|
|
|
|
| COMMAND="pgrep -f \"$ExecStart\" &>/dev/null" |
|
|
|
|
| if eval "$COMMAND"; then |
| exit 0 |
| fi |
|
|
| >&2 echo "Loaded: not-found" |
| exit 1 |
| } |
|
|
| function action_is_enabled(){ |
| exit 0 |
| } |
|
|
| function action_is_active(){ |
| local UNIT=`basename $1` |
| if systemctl status $UNIT ; then |
| >&2 echo "active" |
| exit 0 |
| fi |
|
|
| exit 1 |
|
|
| } |
|
|
| function exec_action(){ |
|
|
| local ACTION=$1 |
| local UNIT=$2 |
| |
| [[ $UNIT =~ '.' ]] || UNIT="$UNIT.service" |
|
|
| if [[ $UNIT =~ '@' ]] ; then |
| local UNIT_INSTANCE=`echo $UNIT | cut -d'@' -f2- | cut -d. -f1` |
| local UNIT=`echo $UNIT | sed "s/$UNIT_INSTANCE//"` |
| fi |
|
|
| UNIT_FILE=`get_unit_file $UNIT` |
|
|
| if [ -z $UNIT_FILE ] ; then |
| >&2 echo "Failed to $ACTION $UNIT: Unit $UNIT not found." |
| exit 1 |
| else |
| case "$ACTION" in |
| start ) action_start $UNIT_FILE $UNIT_INSTANCE ;; |
| stop ) action_stop $UNIT_FILE $UNIT_INSTANCE ;; |
| restart ) action_restart $UNIT_FILE $UNIT_INSTANCE ;; |
| enable ) action_enable $UNIT_FILE $UNIT_INSTANCE ;; |
| disable ) action_disable $UNIT_FILE $UNIT_INSTANCE ;; |
| status ) action_status $UNIT_FILE $UNIT_INSTANCE ;; |
| is-enabled ) action_is_enabled $UNIT_FILE $UNIT_INSTANCE ;; |
| is-active ) action_is_active $UNIT_FILE $UNIT_INSTANCE ;; |
| * ) >&2 echo "Unknown operation $ACTION." ; exit 1 ;; |
| esac |
| fi |
| } |
|
|
| ACTION="$1" |
| UNITS="${@:2}" |
| UNIT_PATHS=( |
| /etc/systemd/system/ |
| /usr/lib/systemd/system/ |
| ) |
|
|
|
|
| for UNIT in ${UNITS[@]}; do |
| exec_action $ACTION $UNIT |
| done |
|
|