From 79f09f3ffc7b21a7bfead83d62bd8421f27caf60 Mon Sep 17 00:00:00 2001 From: ajacoutot Date: Tue, 19 Aug 2014 14:08:20 +0000 Subject: [PATCH] Introduce rcctl(8), a simple utility for maintaining rc.conf.local(8). # rcctl usage: rcctl enable|disable|status|action [service [flags [...]]] Lots of man page improvement from the usual suspects (jmc@ and schwarze@) not hooked up yet but committing now so work can continue in-tree agreed by several --- usr.sbin/rcctl/Makefile | 11 ++ usr.sbin/rcctl/rcctl.8 | 146 ++++++++++++++++++ usr.sbin/rcctl/rcctl.sh | 332 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 489 insertions(+) create mode 100644 usr.sbin/rcctl/Makefile create mode 100644 usr.sbin/rcctl/rcctl.8 create mode 100644 usr.sbin/rcctl/rcctl.sh diff --git a/usr.sbin/rcctl/Makefile b/usr.sbin/rcctl/Makefile new file mode 100644 index 00000000000..53f124ce696 --- /dev/null +++ b/usr.sbin/rcctl/Makefile @@ -0,0 +1,11 @@ +# $OpenBSD: Makefile,v 1.1 2014/08/19 14:08:20 ajacoutot Exp $ + +MAN= rcctl.8 + +SCRIPT= rcctl.sh + +realinstall: + ${INSTALL} ${INSTALL_COPY} -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \ + ${.CURDIR}/${SCRIPT} ${DESTDIR}${BINDIR}/rcctl + +.include diff --git a/usr.sbin/rcctl/rcctl.8 b/usr.sbin/rcctl/rcctl.8 new file mode 100644 index 00000000000..924204f71fe --- /dev/null +++ b/usr.sbin/rcctl/rcctl.8 @@ -0,0 +1,146 @@ +.\" $OpenBSD: rcctl.8,v 1.1 2014/08/19 14:08:20 ajacoutot Exp $ +.\" +.\" Copyright (c) 2014 Antoine Jacoutot +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: August 19 2014 $ +.Dt RCCTL 8 +.Os +.Sh NAME +.Nm rcctl +.Nd configure and control services +.Sh SYNOPSIS +.Nm rcctl +.Sm off +.Cm enable | disable | status | Ar action +.Sm on +.Op Ar service Op Cm flags Op Ar arguments +.Sh DESCRIPTION +.Nm +is a simple utility for maintaining +.Xr rc.conf.local 8 . +It can enable or disable +.Xr rc 8 +services and get/set their status and flags. +It can also be used to interact with +.Xr rc.d 8 +scripts. +.Pp +The following +.Ar actions +are available. +.Pp +.Bl -tag -width disable +.It Cm enable +Enable +.Ar service +in +.Xr rc.conf.local 8 . +Optionally set +.Ar service Ns _flags +to the specified +.Cm flags +.Ar arguments . +If +.Cm flags +is appended without any +.Ar arguments , +.Ar service Ns _flags +is reset to its default value. +.It Cm disable +Disable +.Ar service +in +.Xr rc.conf.local 8 . +.It Cm status +Display the value of +.Ar service Ns _flags +or +.Ar service . +If none is provided, list all services with their current status and +flags. +.It Ar action +Run the +.Xr rc.d 8 +.Ar service +script with the +.Ar action +argument. +.El +.Pp +These services have no corresponding +.Xr rc.d 8 +script and have no +.Cm flags : +accounting, check_quotas, ipsec, multicast_host, multicast_router, +pf, spamd_black. +.Sh EXIT STATUS +.Nm Ar action +returns with the exit status of the +.Xr rc.d 8 +.Ar service +script. +.Nm Cm status +exits with 0 if the service is enabled and 1 if it is not. +Otherwise, the +.Nm +utility exits 0 on success, and >0 if an error occurs. +.Sh EXAMPLES +Disable +.Xr ntpd 8 +and check its status: +.Pp +.Bd -literal -offset indent +# rcctl disable ntpd +# rcctl status ntpd +NO +# echo $? +1 +.Ed +.Pp +Enable and set +.Xr ntpd 8 +flags: +.Pp +.Bd -literal -offset indent +# rcctl enable ntpd flags -s +# rcctl status ntpd +-s +# echo $? +0 +.Ed +.Pp +Start +.Xr ntpd 8 +and check that it is running: +.Pp +.Bd -literal -offset indent +# rcctl start ntpd +ntpd(ok) +# rcctl check ntpd +ntpd(ok) +# echo $? +0 +.Ed +.Sh SEE ALSO +.Xr rc.conf.local 8 , +.Xr rc.d 8 +.Sh HISTORY +.Nm +first appeared in +.Ox 5.7 . +.Sh AUTHORS +.Nm +was written by +.An Antoine Jacoutot Aq Mt ajacoutot@openbsd.org . diff --git a/usr.sbin/rcctl/rcctl.sh b/usr.sbin/rcctl/rcctl.sh new file mode 100644 index 00000000000..2f7ede52fdc --- /dev/null +++ b/usr.sbin/rcctl/rcctl.sh @@ -0,0 +1,332 @@ +#!/bin/sh +# +# Copyright (c) 2014 Antoine Jacoutot +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +# get local functions from rc.subr(8) +FUNCS_ONLY=1 +. /etc/rc.d/rc.subr +_rc_parse_conf + +usage() { + _rc_err "usage: ${0##*/} enable|disable|status|action [service [flags [...]]]" +} + +needs_root() +{ + if [ "$(id -u)" -ne 0 ]; then + _rc_err "${0##*/} ${1:+$1: }need root privileges" + fi +} + +rcconf_edit_begin() { + _TMP_RCCONF=$(mktemp -p /etc -t rc.conf.local.XXXXXXXXXX) || exit 1 + if [ -f /etc/rc.conf.local ]; then + cp -p /etc/rc.conf.local ${_TMP_RCCONF} || exit 1 + else + touch /etc/rc.conf.local || exit 1 + fi +} + +rcconf_edit_end() { + mv ${_TMP_RCCONF} /etc/rc.conf.local || exit 1 + if [ ! -s /etc/rc.conf.local ]; then + rm /etc/rc.conf.local || exit 1 + fi +} + +svc_default_enabled() { + local _ret=1 + local _svc=$1 + [ -n "${_svc}" ] || return + + # get _defaults_ values only + _rc_parse_conf /etc/rc.conf + + svc_is_enabled ${_svc} && _ret=0 + + # reparse _all_ values + svc_is_base ${_svc} && _rc_parse_conf + + return ${_ret} +} + +svc_get_all() +{ + local _i + + ( + ls -A /etc/rc.d | grep -v rc.subr + for _i in ${_allowed_keys[@]}; do + echo ${_i} + done | grep -Ev '(nfs_server|savecore_flag|amd_master|pf_rules|ipsec_rules|shlib_dirs|pkg_scripts)' + ) | sort +} + +svc_get_flags() { + local daemon_flags + local _svc=$1 + [ -n "${_svc}" ] || return + + if svc_is_special ${_svc}; then + echo "$(eval echo \${${_svc}})" + elif ! svc_is_base ${_svc}; then + daemon_flags="$(eval echo \${${_svc}_flags})" + if [ -z "${daemon_flags}" ]; then + eval $(grep '^daemon_flags=' /etc/rc.d/${_svc}) + fi + echo ${daemon_flags} + else + echo "$(eval echo \${${_svc}_flags})" + fi +} + +svc_get_status() { + local _svc=$1 + + if [ -n "${_svc}" ]; then + svc_get_flags ${_svc} | sed '/^$/d' + svc_is_enabled ${_svc} + else + for _i in $(svc_get_all); do + printf "%18s" ${_i} + svc_is_enabled ${_i} && echo -n "(enabled)" || echo -n "(disabled)" + echo -n "\tflags=" + svc_get_flags ${_i} + done + fi +} + +svc_is_avail() +{ + local _i + + for _i in $(svc_get_all); do + if [ ${_i} = "$1" ]; then + return 0 + fi + done + return 1 +} + +svc_is_base() +{ + local _svc=$1 + [ -n "${_svc}" ] || return + + grep "^start_daemon " /etc/rc | cut -d ' ' -f2- | grep -qw ${_svc} +} + +svc_is_enabled() +{ + local _flags _i + local _svc=$1 + [ -n "${_svc}" ] || return + + if svc_is_base ${_svc}; then + eval _flags=\${${_svc}_flags} + if [ "${_flags}" != "NO" ]; then + return + fi + elif svc_is_special ${_svc}; then + eval _flags=\${${_svc}} + if [ "${_flags}" != "NO" ]; then + return + fi + else + echo ${pkg_scripts} | grep -qw ${_svc} && return + fi + + return 1 +} + +svc_is_special() +{ + local _svc=$1 + [ -n "${_svc}" ] || return + + echo ${_allowed_keys[@]} | grep -qw ${_svc} +} + +append_to_pkg_scripts() +{ + local _svc=$1 + [ -n "${_svc}" ] || return + + svc_is_enabled ${_svc} && return + + rcconf_edit_begin + if [ -n "${pkg_scripts}" ]; then + grep -v "^pkg_scripts.*=" /etc/rc.conf.local >${_TMP_RCCONF} + echo pkg_scripts="${pkg_scripts} ${_svc}" >>${_TMP_RCCONF} + else + echo pkg_scripts="${_svc}" >>${_TMP_RCCONF} + fi + rcconf_edit_end +} + +rm_from_pkg_scripts() +{ + local _i _pkg_scripts + local _svc=$1 + [ -n "${_svc}" ] || return + + [ -z "${pkg_scripts}" ] && return + + for _i in ${pkg_scripts}; do + if [ ${_i} != ${_svc} ]; then + _pkg_scripts="${_pkg_scripts} ${_i}" + fi + done + pkg_scripts=$(printf ' %s' ${_pkg_scripts}) + pkg_scripts=${_pkg_scripts## } + + rcconf_edit_begin + grep -v "^pkg_scripts.*=" /etc/rc.conf.local >${_TMP_RCCONF} + if [ -n "${pkg_scripts}" ]; then + echo pkg_scripts="${pkg_scripts}" >>${_TMP_RCCONF} + fi + rcconf_edit_end +} + +add_flags() +{ + local _flags _numargs=$# + local _svc=$2 + [ -n "${_svc}" ] || return + + # svc is already enabled and we did not (re)set the flags + #if svc_is_enabled "${_svc}" && test -z "$3"; then + # return + #fi + + #if [ -n "$3" -a "$3" = "flags" -a -n "$4" ]; then + if [ -n "$3" -a "$3" = "flags" ]; then + if [ -n "$4" ]; then + while [ "${_numargs}" -ge 4 ] + do + eval _flags=\"\$${_numargs} ${_flags}\" + let _numargs-- + done + set -A _flags -- ${_flags} + fi + elif svc_is_base ${_svc}; then + # base svc: save current flags because they are reset below + set -A _flags -- $(eval echo \${${_svc}_flags}) + fi + + # special var + if svc_is_special ${_svc}; then + rcconf_edit_begin + grep -v "^${_svc}.*=" /etc/rc.conf.local >${_TMP_RCCONF} + if ! svc_default_enabled ${_svc}; then + echo "${_svc}=YES" >>${_TMP_RCCONF} + fi + rcconf_edit_end + return + fi + + # base-system script + if svc_is_base ${_svc}; then + rcconf_edit_begin + grep -v "^${_svc}_flags.*=" /etc/rc.conf.local >${_TMP_RCCONF} + if ! svc_default_enabled ${_svc} || test "${#_flags[*]}" -gt 0; then + echo ${_svc}_flags=${_flags[@]} >>${_TMP_RCCONF} + fi + rcconf_edit_end + return + fi + + # pkg script + if [ -n "$3" -a "$3" = "flags" ]; then + rcconf_edit_begin + grep -v "^${_svc}_flags.*=" /etc/rc.conf.local >${_TMP_RCCONF} + if [ "${#_flags[*]}" -gt 0 ]; then + echo ${_svc}_flags=${_flags[@]} >>${_TMP_RCCONF} + fi + rcconf_edit_end + fi +} + +rm_flags() +{ + local _svc=$1 + [ -n "${_svc}" ] || return + + rcconf_edit_begin + if svc_is_special ${_svc}; then + grep -v "^${_svc}.*=" /etc/rc.conf.local >${_TMP_RCCONF} + if svc_default_enabled ${_svc}; then + echo "${_svc}=NO" >>${_TMP_RCCONF} + fi + else + grep -v "^${_svc}_flags.*=" /etc/rc.conf.local >${_TMP_RCCONF} + if svc_default_enabled ${_svc}; then + echo "${_svc}_flags=NO" >>${_TMP_RCCONF} + fi + fi + rcconf_edit_end +} + +if [ $# -gt 0 ]; then + if [ -n "$2" ]; then + if ! svc_is_avail $2; then + _rc_err "service $2 does not exist" + fi + elif [ "$1" != "status" ]; then + usage + fi + if [ -n "$3" ]; then + if [ "$3" = "flags" ]; then + if [ "$1" != "enable" ]; then + _rc_err "\"flags\" can only be set with \"enable\"" + fi + if svc_is_special $2; then + _rc_err "\"$2\" is a special variable, cannot set \"flags\"" + fi + else + usage + fi + fi + case $1 in + disable) + needs_root $1 + if ! svc_is_base $2 && ! svc_is_special $2; then + rm_from_pkg_scripts $2 + fi + rm_flags $2 + ;; + enable) + needs_root $1 + add_flags $* + if ! svc_is_base $2 && ! svc_is_special $2; then + append_to_pkg_scripts $2 + fi + ;; + status) + svc_get_status $2 + ;; + start|stop|restart|reload|check) + if svc_is_special $2; then + _rc_err "\"$2\" is a special variable, no rc.d(8) script" + fi + /etc/rc.d/$2 $1 + ;; + *) + usage + ;; + esac +else + usage +fi -- 2.20.1