diff options
author | B Stack <bgstack15@gmail.com> | 2020-01-12 18:42:10 -0500 |
---|---|---|
committer | B Stack <bgstack15@gmail.com> | 2020-01-12 18:42:10 -0500 |
commit | 595982218707cbbe30e7920d3a6af8f9398e32b0 (patch) | |
tree | 0b7071723719121a6cae63e403b05b63e4773101 /src/sbin/systemctl | |
parent | WIP: initial commit, 5% done (diff) | |
download | systemdtl-595982218707cbbe30e7920d3a6af8f9398e32b0.tar.gz systemdtl-595982218707cbbe30e7920d3a6af8f9398e32b0.tar.bz2 systemdtl-595982218707cbbe30e7920d3a6af8f9398e32b0.zip |
WIP: add most parsing
Still need to add the commands to execute the action list.
Diffstat (limited to 'src/sbin/systemctl')
-rwxr-xr-x | src/sbin/systemctl | 388 |
1 files changed, 388 insertions, 0 deletions
diff --git a/src/sbin/systemctl b/src/sbin/systemctl new file mode 100755 index 0000000..3f13c9d --- /dev/null +++ b/src/sbin/systemctl @@ -0,0 +1,388 @@ +#!/bin/sh +# Filename: systemctl +# Location: /usr/sbin/ +# Author: bgstack15@gmail.com +# Startdate: 2020-01-10 13:02:14 +# Title: +# Purpose: +# Package: systemdtl +# History: +# Usage: +# Should be mostly like systemctl from systemd. +# Reference: ftemplate.sh 2019-05-02a ; framework.sh 2018-05-02a +# man 1 systemctl +# Improve: +# x restart X(.service)? +# x start +# x stop +# x enable +# x status +# x disable +# x mask +# x unmask +# x is-enabled +# x is-active +# x list-unit-files --full +# x reload-or-try-restart X +# x condrestart X +# x daemon-reload --system +# x --now +fiversion="2019-05-02a" +systemctlversion="2020-01-10a" + +usage() { + ${PAGER:-/usr/bin/less -F} >&2 <<ENDUSAGE +usage: systemctl [-duV] [-c conffile] +Provides a systemctl-like interface to sysvinit. Simulates (poorly) +various actions on services: start, stop, restart, enable, disable, +status, mask, unmask, is-enabled, is-active, condrestart +version ${systemctlversion} + -d debug Show debugging info, including parsed variables. + -u usage Show this usage block. + -V version Show script version number. + -c conf Read in this config file. +Return values: + 0 Normal + 1 Queried service is disabled/inactive + 2 Count or type of flaglessvals is incorrect + 3 Incorrect OS type + 4 Unable to find dependency + 5 Not run as root or sudo +ENDUSAGE +} + +# DEFINE FUNCTIONS + +# DEFINE TRAPS + +clean_systemctl() { + # use at end of entire script if you need to clean up tmpfiles + # rm -f "${tmpfile1}" "${tmpfile2}" 2>/dev/null + + # Delayed cleanup + if test -z "${SYSTEMCTL_NO_CLEAN}" ; + then +# nohup /bin/bash <<EOF 1>/dev/null 2>&1 & +#sleep "${SYSTEMCTL_CLEANUP_SEC:-300}" ; /bin/rm -r "${SYSTEMCTL_TMPDIR:-NOTHINGTODELETE}" 1>/dev/null 2>&1 ; +#EOF + /bin/rm -r "${SYSTEMCTL_TMPDIR:-NOTHINGTODELETE}" 1>/dev/null 2>&1 ; + fi +} + +CTRLC() { + # use with: trap "CTRLC" 2 + # useful for controlling the ctrl+c keystroke + : +} + +CTRLZ() { + # use with: trap "CTRLZ" 18 + # useful for controlling the ctrl+z keystroke + : +} + +parseFlag() { + flag="$1" + hasval=0 + case ${flag} in + # INSERT FLAGS HERE + "d" | "debug" | "DEBUG" | "dd" ) setdebug ; ferror "debug level ${debug}" ; __debug_set_by_param=1 ;; + "u" | "usage" | "help" | "h" ) usage ; exit 0 ;; + "V" | "fcheck" | "version" ) ferror "${scriptfile} version ${systemctlversion}" ; exit 0 ;; + #"i" | "infile" | "inputfile" ) getval ; infile1=${tempval} ;; + "c" | "conf" | "conffile" | "config" ) getval ; conffile="${tempval}" ;; + "now" ) export SYSTEMCTL_NOW=1 ;; + "full") export SYSTEMCTL_FULL=1 ;; + "system") export SYSTEMCTL_SYSTEM=1 ;; + esac + + debuglev 10 && { test ${hasval} -eq 1 && ferror "flag: ${flag} = ${tempval}" || ferror "flag: ${flag}" ; } +} + +# DETERMINE LOCATION OF FRAMEWORK +f_needed=20181030 +___frameworkpath="$( find $( echo "${FRAMEWORKPATH}" | tr ':' ' ' ) -maxdepth 1 -mindepth 0 -name 'framework.sh' 2>/dev/null )" +while read flocation ; do if test -e ${flocation} ; then __thisfver="$( sh ${flocation} --fcheck 2>/dev/null )" ; if test ${__thisfver:-0} -ge ${f_needed} ; then frameworkscript="${flocation}" ; break ; elif test -n "${___thisfver}" ; then printf "Obsolete: %s %s\n" "${flocation}" "${__thisfver}" 1>&2 ; fi ; fi ; done <<EOFLOCATIONS +${FRAMEWORKBIN:-/bin/false} +${___frameworkpath:-/bin/false} +./framework.sh +${scriptdir}/framework.sh +$HOME/bin/bgscripts/framework.sh +$HOME/bin/framework.sh +$HOME/bgscripts/framework.sh +$HOME/framework.sh +$HOME/.local/share/bgscripts/framework.sh +/usr/local/bin/bgscripts/framework.sh +/usr/local/bin/framework.sh +/usr/bin/bgscripts/framework.sh +/usr/bin/framework.sh +/bin/bgscripts/framework.sh +/usr/local/share/bgscripts/framework.sh +/usr/share/bgscripts/framework.sh +EOFLOCATIONS +test -z "${frameworkscript}" && echo "$0: framework ${f_needed} not found. Try setting FRAMEWORKPATH. Aborted." 1>&2 && exit 4 + +# INITIALIZE VARIABLES +# variables set in framework: +# today server thistty scriptdir scriptfile scripttrim +# is_cronjob stdin_piped stdout_piped stderr_piped sendsh sendopts +. ${frameworkscript} || echo "$0: framework did not run properly. Continuing..." 1>&2 +infile1= +outfile1= +define_if_new logfile "/var/log/systemctl.log" +define_if_new interestedparties "bgstack15@gmail.com" +# SIMPLECONF +define_if_new default_conffile "/etc/systemdtl.conf" +#define_if_new defuser_conffile ~/.config/systemctl/systemctl.conf +#define_if_new SYSTEMCTL_TMPDIR "$( mktemp -d )" +#tmpfile1="$( TMPDIR="${SYSTEMCTL_TMPDIR}" mktemp )" +#tmpfile2="$( TMPDIR="${SYSTEMCTL_TMPDIR}" mktemp )" + +# REACT TO OPERATING SYSTEM TYPE +case $( uname -s ) in + Linux) : ;; + FreeBSD) : ;; + *) echo "${scriptfile}: 3. Indeterminate OS: $( uname -s )" 1>&2 && exit 3 ;; +esac + +## REACT TO ROOT STATUS +#case ${is_root} in +# 1) # proper root +# : ;; +# sudo) # sudo to root +# : ;; +# "") # not root at all +# #ferror "${scriptfile}: 5. Please run as root or sudo. Aborted." +# #exit 5 +# : +# ;; +#esac + +# SET CUSTOM SCRIPT AND VALUES +#setval 1 sendsh sendopts<<EOFSENDSH # if $1="1" then setvalout="critical-fail" on failure +#/usr/local/share/bgscripts/send.sh -hs # setvalout maybe be "fail" otherwise +#/usr/share/bgscripts/send.sh -hs # on success, setvalout="valid-sendsh" +#/usr/local/bin/send.sh -hs +#/usr/bin/mail -s +#EOFSENDSH +#test "${setvalout}" = "critical-fail" && ferror "${scriptfile}: 4. mailer not found. Aborted." && exit 4 + +# VALIDATE PARAMETERS +# objects before the dash are options, which get filled with the optvals +# to debug flags, use option DEBUG. Variables set in framework: fallopts +validateparams action - "$@" + +# LEARN EX_DEBUG +test -z "${__debug_set_by_param}" && fisnum "${SYSTEMCTL_DEBUG}" && debug="${SYSTEMCTL_DEBUG}" + +# CONFIRM TOTAL NUMBER OF FLAGLESSVALS IS CORRECT +#if test ${thiscount} -lt 2 ; +#then +# ferror "${scriptfile}: 2. Fewer than 2 flaglessvals. Aborted." +# exit 2 +#fi + +# LOAD CONFIG FROM SIMPLECONF +# This section follows a simple hierarchy of precedence, with first being used: +# 1. parameters and flags +# 2. environment +# 3. config file +# 4. default user config: ~/.config/script/script.conf +# 5. default config: /etc/script/script.conf +if test -f "${conffile}" ; +then + get_conf "${conffile}" +else + if test "${conffile}" = "${default_conffile}" || test "${conffile}" = "${defuser_conffile}" ; then : ; else test -n "${conffile}" && ferror "${scriptfile}: Ignoring conf file which is not found: ${conffile}." ; fi +fi +test -f "${defuser_conffile}" && get_conf "${defuser_conffile}" +test -f "${default_conffile}" && get_conf "${default_conffile}" + +# CONFIGURE VARIABLES AFTER PARAMETERS + +## START READ CONFIG FILE TEMPLATE +#oIFS="${IFS}" ; IFS="$( printf '\n' )" +#infiledata=$( ${sed} ':loop;/^\/\*/{s/.//;:ccom;s,^.[^*]*,,;/^$/n;/^\*\//{s/..//;bloop;};bccom;}' "${infile1}") #the crazy sed removes c style multiline comments +#IFS="${oIFS}" ; infilelines=$( echo "${infiledata}" | wc -l ) +#{ echo "${infiledata}" ; echo "ENDOFFILE" ; } | { +# while read line ; do +# # the crazy sed removes leading and trailing whitespace, blank lines, and comments +# if test ! "${line}" = "ENDOFFILE" ; +# then +# line=$( echo "${line}" | sed -e 's/^\s*//;s/\s*$//;/^[#$]/d;s/\s*[^\]#.*$//;' ) +# if test -n "${line}" ; +# then +# debuglev 8 && ferror "line=\"${line}\"" +# if echo "${line}" | grep -qiE "\[.*\]" ; +# then +# # new zone +# zone=$( echo "${line}" | tr -d '[]' ) +# debuglev 7 && ferror "zone=${zone}" +# else +# # directive +# varname=$( echo "${line}" | awk -F= '{print $1}' ) +# varval=$( echo "${line}" | awk -F= '{$1="" ; printf "%s", $0}' | sed 's/^ //;' ) +# debuglev 7 && ferror "${zone}${varname}=\"${varval}\"" +# # simple define variable +# eval "${zone}${varname}=\${varval}" +# fi +# ## this part is untested +# #read -p "Please type something here:" response < ${thistty} +# #echo "${response}" +# fi +# else + +## REACT TO BEING A CRONJOB +#if test ${is_cronjob} -eq 1 ; +#then +# : +#else +# : +#fi + +# SET TRAPS +#trap "CTRLC" 2 +#trap "CTRLZ" 18 +#trap '__ec=$? ; clean_systemctl ; trap "" 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ; exit ${__ec} ;' 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 + +# DEBUG SIMPLECONF +debuglev 5 && { + ferror "Using values" + # used values: EX_(OPT1|OPT2|VERBOSE) + set | grep -iE "^SYSTEMCTL_" 1>&2 +} + +# MAIN LOOP +#{ + printf "%s\n" "${*}" >> "${logfile}" + #echo "thiscount=${thiscount}" + #x=1 + #while test ${x:-${thiscount}} -le $(( thiscount - 1 )) && test ${thiscount} -gt 1 ; + #do + # eval thisopt="\${opt${x}}" + # echo "thisopt${x}=${thisopt}" + # x=$(( x + 1 )) + #done + + # actions + actionlist="" + case "${action}" in + + restart|start|stop|status|reload|condrestart|try-restart|reload-or-try-restart) + # re-map a few actions + case "${action}" in + "reload-or-try-restart") action=restart ;; + esac + x=1 + while test ${x:-${thiscount}} -le $(( thiscount - 1 )) && test ${thiscount} -gt 1 ; + do + eval thisopt="\${opt${x}}" + thisopt="$( echo "${thisopt}" | sed -r -e 's/\.service$//;' )" + actionstatement="$( printf "%s" "service ${thisopt} ${action};" )" + actionlist="${actionlist:+${actionlist} }${actionstatement}" + x=$(( x + 1 )) + done + ;; + + enable|disable|mask|unmask) + case "${action}" in + mask) action=disable ;; + unmask) action=enable ;; + esac + x=1 + while test ${x:-${thiscount}} -le $(( thiscount - 1 )) && test ${thiscount} -gt 1 ; + do + eval thisopt="\${opt${x}}" + thisopt="$( echo "${thisopt}" | sed -r -e 's/\.service$//;' )" + actionstatement="$( printf "%s" "update-rc.d ${thisopt} ${action};" )" + actionlist="${actionlist:+${actionlist} }${actionstatement}" + test "${SYSTEMCTL_NOW}" = "1" && { + case "${action}" in + enable) + nowaction=start + ;; + disable) + nowaction=stop + ;; + esac + actionstatement="$( printf "%s" "service ${thisopt} ${nowaction:-stop};" )" + actionlist="${actionlist:+${actionlist} }${actionstatement}" + } + x=$(( x + 1 )) + done + ;; + + daemon-reload) + debuglev 1 && echo "${action} is a NOP." + ;; + + list-unit-files) + # Future improvement: can consume --full, but I do not care enough to deal with it now. + ls -Al /etc/init.d + ;; + + is-enabled) + currentrunlevel="$( who -r | grep -oE 'run-level\s+[[:digit:]]+' | awk '{print $NF}' )" + responsenumber=1 + + # loop through each service on the command line + x=1 + while test ${x:-${thiscount}} -le $(( thiscount - 1 )) && test ${thiscount} -gt 1 ; + do + eval thisopt="\${opt${x}}" + thisopt="$( echo "${thisopt}" | sed -r -e 's/\.service$//;' )" + #actionstatement="$( printf "%s" "service ${thisopt} ${action};" )" + scriptfile="$( find "/etc/rc${currentrunlevel}.d" -mindepth 1 -maxdepth 1 -name "S??${thisopt}" 2>/dev/null )" + responsetext="disabled" + # if file exists, let us return 0. + if test -n "${scriptfile}" ; + then + debuglev 2 && echo "${scriptfile}" + responsenumber=0 # any "enabled" response makes systemctl return 0 + responsetext="enabled" + fi + echo "${responsetext:-UNKNOWN}" + x=$(( x + 1 )) + done + exit "${responsenumber}" + ;; + + is-active) + responsenumber=3 + x=1 + while test ${x:-${thiscount}} -le $(( thiscount - 1 )) && test ${thiscount} -gt 1 ; + do + eval thisopt="\${opt${x}}" + thisopt="$( echo "${thisopt}" | sed -r -e 's/\.service$//;' )" + #actionstatement="$( printf "%s" "service ${thisopt} ${action};" )" + servicestatus="$( service "${thisopt}" status 1>/dev/null 2>&1 ; echo "${?}" )" + responsetext="stopped" + # if file exists, let us return 0. + if test ${servicestatus:-1} -eq 0 ; + then + responsenumber=0 + responsetext="active" + fi + echo "${responsetext:-unknown}" + x=$(( x + 1 )) + done + exit "${responsenumber}" + ;; + + *) + ferror "Fatal! 2. Unable to understand action ${action}. Aborted." + exit 2 + ;; + esac + + # list of actions + echo "Need to perform these commands:" + echo "${actionlist}" +#} | tee -a ${logfile} + +# EMAIL LOGFILE +#${sendsh} ${sendopts} "${server} ${scriptfile} out" ${logfile} ${interestedparties} + +## STOP THE READ CONFIG FILE +#return_code 0 +#fi ; done ; } |