|
|
#!/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 |
|
|
|