Helpful packages for the Devuan system
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

575 lines
17 KiB

  1. #!/bin/sh
  2. # Filename: systemctl
  3. # Location: /usr/bin/systemctl
  4. # /usr/bin/hostnamectl
  5. # /usr/bin/systemd-detect-virt
  6. # Author: bgstack15@gmail.com
  7. # Startdate: 2020-01-10 13:02:14
  8. # SPDX-License-Identifier: CC-BY-SA-4.0
  9. # Title:
  10. # Purpose:
  11. # Package: devuan-sanity
  12. # History:
  13. # 2020-05-14 place framework.sh contents inline so as not to depend on it.
  14. # 2021-01-10 adapted for inclusion in devuan-sanity
  15. # Usage:
  16. # Should be mostly like systemctl from systemd.
  17. # Reference: ftemplate.sh 2019-05-02a ; framework.sh 2018-05-02a
  18. # man 1 systemctl
  19. # Improve:
  20. # add preset
  21. # Documentation:
  22. # Be aware that real systemd systemctl is file /bin/systemctl but
  23. # this systemdtl is file /usr/bin/systemctl to prevent a recursive loop
  24. # in some service scripts that look for /bin/systemctl
  25. fiversion="2019-05-02a"
  26. systemctlversion="2021-01-10a"
  27. usage() {
  28. ${PAGER:-/usr/bin/less -F} >&2 <<ENDUSAGE
  29. usage: systemctl [-duV] [-c conffile]
  30. Provides a systemctl-like interface to sysvinit. Simulates (poorly)
  31. various actions on services: start, stop, restart, enable, disable,
  32. status, mask, unmask, is-enabled, is-active, condrestart
  33. version ${systemctlversion}
  34. -d debug Show debugging info, including parsed variables.
  35. -u usage Show this usage block.
  36. -V version Show script version number.
  37. -c conf Read in this config file.
  38. Return values:
  39. 0 Normal
  40. 1 Queried service is disabled/inactive
  41. 2 Count or type of flaglessvals is incorrect
  42. 3 Incorrect OS type
  43. 4 Unable to find dependency
  44. 5 Not run as root or sudo
  45. ENDUSAGE
  46. }
  47. # DEFINE FUNCTIONS
  48. log_to_file() {
  49. flecho "${@}" >> "${logfile}"
  50. }
  51. parseFlag() {
  52. flag="$1"
  53. hasval=0
  54. case ${flag} in
  55. # INSERT FLAGS HERE
  56. "d" | "debug" | "DEBUG" | "dd" ) setdebug ; ferror "debug level ${debug}" ; __debug_set_by_param=1 ;;
  57. "u" | "usage" | "help" | "h" ) usage ; exit 0 ;;
  58. "V" | "fcheck" | "version" ) ferror "${scriptfile} version ${systemctlversion}" ; exit 0 ;;
  59. #"i" | "infile" | "inputfile" ) getval ; infile1=${tempval} ;;
  60. "c" | "conf" | "conffile" | "config" ) getval ; conffile="${tempval}" ;;
  61. "now" ) export SYSTEMCTL_NOW=1 ;;
  62. "full") export SYSTEMCTL_FULL=1 ;;
  63. "system") export SYSTEMCTL_SYSTEM=1 ;;
  64. esac
  65. debuglev 10 && { test ${hasval} -eq 1 && ferror "flag: ${flag} = ${tempval}" || ferror "flag: ${flag}" ; }
  66. }
  67. # INITIALIZE VARIABLES
  68. # variables set in framework:
  69. # server scriptdir scriptfile scripttrim
  70. ### BEGIN IMPORT OF FRAMEWORK.SH
  71. fversion="2020-04-24a"
  72. # DEFINE FUNCTIONS
  73. isflag() {
  74. # input: $1=word to parse
  75. case "$1" in
  76. --*) retval=2 ;;
  77. -*) retval=1 ;;
  78. *) retval=0 ;;
  79. esac
  80. echo $retval
  81. }
  82. parseParam() {
  83. # determines if --longname or -shortflagS that need individual parsing
  84. trimParam=$( printf '%s' "${param}" | sed -n 's/--//p' )
  85. _rest=
  86. if test -n "$trimParam" ;
  87. then
  88. parseFlag $trimParam
  89. else
  90. #splitShortStrings
  91. _i=2
  92. while test ${_i} -le ${#param} ;
  93. do
  94. _j=$( expr ${_i} + 1)
  95. #_char=$(expr substr "$param" $_i 1)
  96. #_rest=$(expr substr "$param" $_j 255)
  97. _char=$( printf '%s' "${param}" | cut -c ${_i})
  98. _rest=$( printf '%s' "${param}" | cut -c ${_j}-255)
  99. parseFlag $_char
  100. _i=$( expr ${_i} + 1)
  101. done
  102. fi
  103. }
  104. getval() {
  105. tempval=
  106. if test -n "${_rest}" ;
  107. then
  108. tempval="${_rest}"
  109. hasval=1
  110. _i=255 # skip rest of splitShortStrings because found the value!
  111. elif test -n "$nextparam" && test $(isflag "$nextparam") -eq 0 ;
  112. then
  113. tempval="$nextparam"
  114. hasval=1 #DNE ; is affected by ftemplate!
  115. paramnum=$nextparamnum
  116. fi
  117. }
  118. debuglev() {
  119. # call: debuglev 5 && ferror "debug level is at least a five!"
  120. # added 2015-11-17
  121. localdebug=0 ; localcheck=0 ;
  122. fisnum ${debug} && localdebug=${debug}
  123. fisnum ${1} && localcheck=${1}
  124. test $localdebug -ge $localcheck && return 0 || return 1
  125. }
  126. debuglevoutput() {
  127. # call: commandthatgeneratesstdout | debuglevoutput 8
  128. # output: output to standard error prepended with "debug8: " the contents of the pipe
  129. ___dlo_threshold="${1}"
  130. ___dlo_silent="${2}"
  131. if debuglev "${___dlo_threshold}" ;
  132. then
  133. if test -n "${___dlo_silent}" ;
  134. then
  135. cat 1>&2
  136. else
  137. sed -r -e "s/^/debug${___dlo_threshold}: /;" 1>&2
  138. fi
  139. else
  140. cat 1>/dev/null 2>&1
  141. fi
  142. }
  143. fisnum() {
  144. # call: fisnum $1 && debug=$1 || debug=10
  145. fisnum= ;
  146. case $1 in
  147. ''|*[!0-9]*) fisnum=1 ;; # invalid
  148. *) fisnum=0 ;; # valid number
  149. esac
  150. return ${fisnum}
  151. }
  152. fistruthy() {
  153. # call: if fistruthy "$val" ; then
  154. local _return=
  155. case "$( echo "${1}" | tr '[:upper:]' '[:lower:]' )" in
  156. yes|1|y|true|always) _return=true ;;
  157. esac
  158. test -n "${_return}" ; return $?
  159. }
  160. setval() {
  161. # call: setval 0 value1 value2 value3 ... <<EOFOPTIONS
  162. # /bin/foo1 --optforfoo1
  163. # /usr/bin/foo2 --optforfoo2
  164. # EOFOPTIONS
  165. # ^ 0 = soft fail, 1 = critical-fail
  166. quitonfail="${1}" ; shift
  167. _vars="${@}"
  168. #echo "_vars=${_vars}"
  169. _varcount=0
  170. for _word in ${_vars} ; do _varcount=$( expr $_varcount + 1 ) ; eval "_var${_varcount}=${_word}" ; done
  171. _usethis=0
  172. while read line ;
  173. do
  174. _varcount=0
  175. if test ! "${_usethis}x" = "0x" ; then break ; fi
  176. #echo "line=${line}" ;
  177. for _word in ${line} ;
  178. do
  179. _varcount=$( expr $_varcount + 1 )
  180. #echo "word ${_varcount}=${_word}" ;
  181. case "${_varcount}" in
  182. 1)
  183. #echo "Testing for existence of file ${_word}"
  184. if test -f "${_word}" ;
  185. then
  186. _usethis=1
  187. #echo "${_var1}=${_word}"
  188. eval "${_var1}=${_word}"
  189. fi
  190. ;;
  191. *)
  192. #echo "just an option: ${_word}"
  193. if test "${_usethis}x" = "1x" ;
  194. then
  195. #eval echo "\${_var${_varcount}}=${_word}"
  196. eval eval "\${_var${_varcount}}=${_word}"
  197. fi
  198. ;;
  199. esac
  200. done
  201. done
  202. #eval echo "testfile=\$${_var1}"
  203. eval _testfile=\$${_var1}
  204. if test ! -f "${_testfile}" ;
  205. then
  206. case "${quitonfail}" in 1) _failval="critical-fail" ;; *) _failval="fail" ;; esac
  207. eval "${_var1}=${_failval}"
  208. setvalout=${_failval}
  209. else
  210. eval setvalout="valid-${_var1}"
  211. fi
  212. }
  213. flecho() {
  214. if test "$lechoscript" = "" ; #so only run the first time!
  215. then
  216. setval 0 lechoscript << EOFLECHOSCRIPTS
  217. ./plecho.sh
  218. ${scriptdir}/plecho.sh
  219. ~/bin/bgscripts/plecho.sh
  220. ~/bin/plecho.sh
  221. ~/bgscripts/plecho.sh
  222. ~/plecho.sh
  223. /usr/local/bin/bgscripts/plecho.sh
  224. /usr/local/bin/plecho.sh
  225. /usr/bin/bgscripts/plecho.sh
  226. /usr/bin/plecho.sh
  227. /usr/bin/plecho
  228. /bin/bgscripts/plecho.sh
  229. /usr/local/share/bgscripts/plecho.sh
  230. /usr/share/bgscripts/plecho.sh
  231. /usr/libexec/bgscripts/plecho.sh
  232. EOFLECHOSCRIPTS
  233. lechoscriptvalid="${setvalout}"
  234. fi
  235. if test "$lechoscriptvalid" = "valid-lechoscript" ;
  236. then
  237. $lechoscript "$@"
  238. else
  239. myflecho() {
  240. mflnow=$( date '+%Y-%m-%d %T' )
  241. while test -z "$1" && test -n "$@" ; do shift ; done
  242. sisko="$@"
  243. test -z "$sisko" && \
  244. printf "[%19s]%s@%s\n" "$mflnow" "$USER" "$server" || \
  245. printf "[%19s]%s@%s: %s\n" "$mflnow" "$USER" "$server" "${sisko#" *"}" ;
  246. }
  247. if test ! -t 0 ; # observe that this is different from plecho
  248. then
  249. _x=0
  250. while read line ;
  251. do
  252. _x=1
  253. myflecho "$@" "$line"
  254. done
  255. test $_x -eq 0 && myflecho "$@" "$line"
  256. else
  257. myflecho "$@"
  258. fi
  259. fi
  260. }
  261. ferror() {
  262. # call: ferror "$scriptfile: 2. Something bad happened-- error message 2."
  263. echo "$@" 1>&2
  264. }
  265. setdebug() {
  266. # call: setdebug
  267. debug=10
  268. getval
  269. if test $hasval -eq 1 ;
  270. then
  271. if fisnum ${tempval} ;
  272. then
  273. debug=${tempval}
  274. else
  275. #test paramnum -le paramcount && paramnum=$( expr ${paramnum} - 1 )
  276. hasval=0
  277. fi
  278. elif fisnum ${_rest} ;
  279. then
  280. debug=${_rest}
  281. _i=255
  282. else
  283. test $paramnum -le $paramcount && test -z ${nextparam} && paramnum=$( expr ${paramnum} - 1 )
  284. fi
  285. }
  286. define_if_new() {
  287. # call: define_if_new IFW_IN_LOG_FILE "/var/log/messages"
  288. eval thisval="\${${1}}"
  289. test -z "${thisval}" && eval "$1"=\"$2\"
  290. }
  291. # INITIALIZE VARIABLES
  292. #infile1=
  293. #outfile1=
  294. #logfile=
  295. server=$( hostname -s )
  296. thisos="$( uname -s )"
  297. # get thisflavor and thisflavorversion. Examples: centos, ubuntu, redhat
  298. if test -f /etc/os-release ;
  299. then
  300. eval thisflavor=$( grep -iE "^\s*ID=" /etc/os-release 2>/dev/null | sed 's/^.*=//;' | tr 'A-Z' 'a-z' )
  301. eval thisflavorversion=$( grep -iE "^\s*PRETTY_NAME=" /etc/os-release 2>/dev/null | sed -e 's/^.*=//;' | tr -dc '0-9.' )
  302. elif test -f /etc/system-release && test $( wc -l < /etc/system-release 2>/dev/null ) -eq 1 ;
  303. then
  304. eval thisflavor=$( awk '{print $1}' < /etc/system-release 2>/dev/null | tr 'A-Z' 'a-z' )
  305. eval thisflavorversion=$( </etc/system-release sed -e 's/^.*=//;' 2>/dev/null | tr -dc '0-9.' )
  306. else
  307. if test "${thisos}" = "FreeBSD" ; then
  308. thisflavor="$( uname -i )" ; thisflavorversion="$( uname -r )" ;
  309. else
  310. thisflavor="other"
  311. thisflavorversion="unknown"
  312. fi
  313. fi
  314. case "${thisos}" in FreeBSD) sed=gsed ;; *) sed=sed ;; esac
  315. # if framework is dot sourced then $0 will be "-bash" and screw things up
  316. case ${0} in
  317. "-bash")
  318. scriptdir="$( pwd )"
  319. scriptfile="dot-sourced" ;;
  320. *)
  321. scriptdir="$( cd $( dirname ${0} ) ; pwd )"
  322. scriptfile="$( basename ${0} | sed 's!/./!/!g;s!\./!!g' )"
  323. scripttrim="${scriptfile%%.sh}"
  324. ;;
  325. esac
  326. # SPECIAL RUNTIME-RELATED VARIABLES
  327. { test "$USER" = "root" || test "$( stat -c '%u' /proc/$$/exe 2>/dev/null )" = 0 ; } && is_root=1
  328. test -n "$SUDO_USER" && is_root="sudo"
  329. nullflagcount=0
  330. validateparams() {
  331. # VALIDATE PARAMETERS
  332. # scroll through all parameters and check for isflag.
  333. # if isflag, get all flags listed. Also grab param#.
  334. paramcount=$#
  335. thiscount=0 ;thisopt=0 ;freeopt=0 ;
  336. varsyet=0
  337. paramnum=0
  338. debug=0
  339. fallopts=
  340. while test $paramnum -lt $paramcount ;
  341. do
  342. paramnum=$( expr ${paramnum} + 1 )
  343. eval param=\${$paramnum}
  344. nextparamnum=$( expr ${paramnum} + 1 )
  345. eval nextparam=\${$nextparamnum}
  346. case $param in
  347. "-")
  348. if test "$varsyet" = "0" ;
  349. then
  350. # first instance marks beginning of flags and parameters.
  351. #Until then it was the names of variables to fill.
  352. varsyet=1
  353. else
  354. nullflagcount=$( expr ${nullflagcount} + 1 ) #useful for separating flags from something else?
  355. debuglev 10 && ferror "null flag!" # second instance is null flag.
  356. fi
  357. ;;
  358. esac
  359. if test -n "$param" ;
  360. then
  361. # parameter $param exists.
  362. if test $(isflag $param) -gt 0 ;
  363. then
  364. # IS FLAG
  365. parseParam
  366. else
  367. # IS VALUE
  368. if test "$varsyet" = "0" ;
  369. then
  370. thisopt=$( expr ${thisopt} + 1 )
  371. test "${param}" = "DEBUG" && debug=10 && thisopt=$( expr ${thisopt} - 1 ) || \
  372. eval "varname${thisopt}=${param}"
  373. #varname[${thisopt}]="${param}"
  374. debuglev 10 && ferror "var \"${param}\" named"
  375. else
  376. thiscount=$( expr ${thiscount} + 1 )
  377. test $thiscount -gt $thisopt && freeopt=$( expr ${freeopt} + 1 )
  378. #eval ${varname[${thiscount}]:-opt${freeopt}}="\"${param}\""
  379. eval "thisvarname=\${varname${thiscount}}"
  380. test -z "${thisvarname}" && eval "thisvarname=opt${freeopt}"
  381. eval "${thisvarname}=\"${param}\""
  382. eval fallopts=\"${fallopts} ${param}\"
  383. debuglev 10 && ferror "${thisvarname} value: ${param}"
  384. fi
  385. fi
  386. fi
  387. done
  388. fallopts="${fallopts# }"
  389. if debuglev 10 ;
  390. then
  391. ferror "thiscount=$thiscount"
  392. ferror "fallopts=$fallopts"
  393. ferror "Framework $fversion"
  394. ferror "Finput $fiversion"
  395. fi
  396. }
  397. ### END IMPORT
  398. define_if_new logfile "/var/log/systemctl.log"
  399. # REACT TO OPERATING SYSTEM TYPE
  400. case $( uname -s ) in
  401. Linux) : ;;
  402. FreeBSD) : ;;
  403. *) echo "${scriptfile}: 3. Indeterminate OS: $( uname -s )" 1>&2 && exit 3 ;;
  404. esac
  405. # VALIDATE PARAMETERS
  406. # objects before the dash are options, which get filled with the optvals
  407. # to debug flags, use option DEBUG. Variables set in framework: fallopts
  408. validateparams action - "$@"
  409. # LEARN EX_DEBUG
  410. test -z "${__debug_set_by_param}" && fisnum "${SYSTEMCTL_DEBUG}" && debug="${SYSTEMCTL_DEBUG}"
  411. debug=10
  412. # CONFIGURE VARIABLES AFTER PARAMETERS
  413. log_to_file "${0} ${@}"
  414. case "${0}" in
  415. *hostnamectl|*systemd-detect-virt) exit 0 ;;
  416. esac
  417. # MAIN LOOP
  418. # actions
  419. actionlist=""
  420. case "${action}" in
  421. restart|start|stop|status|reload|condrestart|try-restart|reload-or-try-restart)
  422. # re-map a few actions
  423. case "${action}" in
  424. "reload-or-try-restart") action=restart ;;
  425. esac
  426. x=1
  427. while test ${x:-${thiscount}} -le $(( thiscount - 1 )) && test ${thiscount} -gt 1 ;
  428. do
  429. eval thisopt="\${opt${x}}"
  430. thisopt="$( echo "${thisopt}" | sed -r -e 's/\.service$//;' )"
  431. actionstatement="$( printf "%s" "service ${thisopt} ${action};" )"
  432. actionlist="${actionlist:+${actionlist} }${actionstatement}"
  433. x=$(( x + 1 ))
  434. done
  435. ;;
  436. enable|disable|mask|unmask)
  437. case "${action}" in
  438. mask) action=disable ;;
  439. unmask) action=enable ;;
  440. esac
  441. x=1
  442. while test ${x:-${thiscount}} -le $(( thiscount - 1 )) && test ${thiscount} -gt 1 ;
  443. do
  444. eval thisopt="\${opt${x}}"
  445. thisopt="$( echo "${thisopt}" | sed -r -e 's/\.service$//;' )"
  446. actionstatement="$( printf "%s" "update-rc.d ${thisopt} ${action};" )"
  447. actionlist="${actionlist:+${actionlist} }${actionstatement}"
  448. test "${SYSTEMCTL_NOW}" = "1" && {
  449. case "${action}" in
  450. enable)
  451. nowaction=start
  452. ;;
  453. disable)
  454. nowaction=stop
  455. ;;
  456. esac
  457. actionstatement="$( printf "%s" "service ${thisopt} ${nowaction:-stop};" )"
  458. actionlist="${actionlist:+${actionlist} }${actionstatement}"
  459. }
  460. x=$(( x + 1 ))
  461. done
  462. ;;
  463. daemon-reload)
  464. debuglev 1 && echo "${action} is a NOP."
  465. ;;
  466. list-unit-files)
  467. # Future improvement: can consume --full, but I do not care enough to deal with it now.
  468. ls -Al /etc/init.d
  469. ;;
  470. is-enabled)
  471. currentrunlevel="$( who -r | grep -oE 'run-level\s+[[:digit:]]+' | awk '{print $NF}' )"
  472. responsenumber=1
  473. # loop through each service on the command line
  474. x=1
  475. while test ${x:-${thiscount}} -le $(( thiscount - 1 )) && test ${thiscount} -gt 1 ;
  476. do
  477. eval thisopt="\${opt${x}}"
  478. thisopt="$( echo "${thisopt}" | sed -r -e 's/\.service$//;' )"
  479. #actionstatement="$( printf "%s" "service ${thisopt} ${action};" )"
  480. scriptfile="$( find "/etc/rc${currentrunlevel}.d" -mindepth 1 -maxdepth 1 -name "S??${thisopt}" 2>/dev/null )"
  481. responsetext="disabled"
  482. # if file exists, let us return 0.
  483. if test -n "${scriptfile}" ;
  484. then
  485. debuglev 2 && echo "${scriptfile}"
  486. responsenumber=0 # any "enabled" response makes systemctl return 0
  487. responsetext="enabled"
  488. fi
  489. echo "${responsetext:-UNKNOWN}"
  490. x=$(( x + 1 ))
  491. done
  492. exit "${responsenumber}"
  493. ;;
  494. is-active)
  495. responsenumber=3
  496. x=1
  497. while test ${x:-${thiscount}} -le $(( thiscount - 1 )) && test ${thiscount} -gt 1 ;
  498. do
  499. eval thisopt="\${opt${x}}"
  500. thisopt="$( echo "${thisopt}" | sed -r -e 's/\.service$//;' )"
  501. #actionstatement="$( printf "%s" "service ${thisopt} ${action};" )"
  502. servicestatus="$( service "${thisopt}" status 1>/dev/null 2>&1 ; echo "${?}" )"
  503. responsetext="stopped"
  504. # if file exists, let us return 0.
  505. if test ${servicestatus:-1} -eq 0 ;
  506. then
  507. responsenumber=0
  508. responsetext="active"
  509. fi
  510. echo "${responsetext:-unknown}"
  511. x=$(( x + 1 ))
  512. done
  513. exit "${responsenumber}"
  514. ;;
  515. *)
  516. ferror "Fatal! 2. Unable to understand action ${action}. Aborted."
  517. exit 2
  518. ;;
  519. esac
  520. # list of actions
  521. if test -n "${actionlist}" ;
  522. then
  523. #debuglev 1 && ferror "Full list: ${actionlist}"
  524. printf "%s" "${actionlist}" | tr ';' '\n' | while read thisaction ;
  525. do
  526. log_to_file "ACTION: ${thisaction}"
  527. debuglev 5 && ferror "${thisaction}"
  528. eval "${thisaction}"
  529. done
  530. fi
  531. # exit cleanly
  532. :