[arch-projects] [INITSCRIPTS][PATCH] rc.d: handle a set of options

Sebastien Luttringer seblu at seblu.net
Sat Aug 27 13:18:38 EDT 2011


rc.d can now take --started, --stopped, --auto, --noauto as option which
help user to filter list of daemon for all actions

As a corollary list command can now take a list of dameon to display
All kind of arguments can be mixed to obtain the proper output.

zsh and bash completion are updated

Note: Output of help command exit 0 and is no more printed on stderr

Signed-off-by: Sebastien Luttringer <seblu at seblu.net>
---
 bash-completion |   20 ++++----
 rc.d            |  124 +++++++++++++++++++++++++++++++++++++++---------------
 zsh-completion  |    8 +---
 3 files changed, 101 insertions(+), 51 deletions(-)

diff --git a/bash-completion b/bash-completion
index d78484e..4b4593b 100644
--- a/bash-completion
+++ b/bash-completion
@@ -3,20 +3,20 @@
 _rc_d()
 {
 	local action cur prev
-	action="help list start stop reload restart"
+	actions='help list start stop reload restart'
+	options='-s --started -S --stopped -a --auto -A --noauto'
 	_get_comp_words_by_ref cur prev
-	if ((COMP_CWORD == 1)); then
-		COMPREPLY=($(compgen -W "${action}" -- "$cur"))
-	elif [[ "$prev" == help ]]; then
+	_get_first_arg
+	if [[ -z "$arg" ]]; then
+		COMPREPLY=($(compgen -W "${actions} ${options}" -- "$cur"))
+	elif [[ "$arg" == help ]]; then
 		COMPREPLY=()
-	elif [[ "$prev" == list ]]; then
-		((COMP_CWORD == 2)) && COMPREPLY=($(compgen -W "started stopped" -- "$cur")) || COMPREPLY=()
-	elif [[ "$prev" == start ]]; then
+	elif [[ "$arg" == start ]]; then
 		COMPREPLY=($(comm -23 <(cd /etc/rc.d && compgen -f -X 'functions*' "$cur"|sort) <(cd /run/daemons/ && compgen -f "$cur"|sort)))
-	elif [[ "$prev" =~ stop|restart|reload ]]; then
+	elif [[ "$arg" =~ stop|restart|reload ]]; then
 		COMPREPLY=($(cd /run/daemons/ && compgen -f "$cur"|sort))
-	elif ((COMP_CWORD > 1)); then
-		COMPREPLY=($(cd /etc/rc.d && compgen -f -X 'functions*' "$cur"|sort))
+	else
+		COMPREPLY=($(compgen -W "${options} $(cd /etc/rc.d && compgen -f -X 'functions*')" -- "$cur"))
 	fi
 }
 complete -F _rc_d rc.d
diff --git a/rc.d b/rc.d
index 9b0f092..3f2835e 100755
--- a/rc.d
+++ b/rc.d
@@ -4,74 +4,128 @@ NEED_ROOT=0 # this script can be run without be root
 . /etc/rc.conf
 . /etc/rc.d/functions
 
+# print usage and exit
 usage() {
 	local name=${0##*/}
 	cat >&2 << EOF
-usage: $name <action> <daemon> [daemon] ...
-       $name list [started|stopped]
-       $name help
+usage: $name <action> [options] [daemons]
 
-<daemon> is the name of a script in /etc/rc.d
+options:
+  -s, --started     Filter started daemons
+  -S, --stopped     Filter stopped daemons
+  -a, --auto        Filter auto started daemons
+  -A, --noauto      Filter manually started daemons
+
+<daemons> is a space separated list of script in /etc/rc.d
 <action> can be a start, stop, restart, reload, status, ...
 WARNING: initscripts are free to implement or not the above actions.
 
 e.g: $name list
-     $name list started
-     $name help
+     $name list sshd gpm
+     $name list --started gpm
      $name start sshd gpm
+     $name stop --noauto
+     $name help
 EOF
-	exit 1
+	exit ${1:-1}
+}
+
+# filter list of daemons
+filter_daemons() {
+	local -a new_daemons=()
+	for daemon in "${daemons[@]}"; do
+		# check if daemons is valid
+		if ! have_daemon "$daemon"; then
+			printf "${C_FAIL}:: ${C_DONE}Dameon script ${C_FAIL}${daemon}${C_DONE} does \
+not exist or is not executable.${C_CLEAR}\n" >&2
+			exit 2
+		fi
+		# check filter
+		((${filter[started]} == 1)) && ck_daemon "$daemon" && continue
+		((${filter[stopped]} == 1)) && ! ck_daemon "$daemon" && continue
+		((${filter[auto]} == 1)) && ck_autostart "$daemon" && continue
+		((${filter[noauto]} == 1)) && ! ck_autostart "$daemon" && continue
+		new_daemons+=("$daemon")
+	done
+	daemons=("${new_daemons[@]}")
 }
 
 (( $# < 1 )) && usage
 
+# ret store the return code of rc.d
 declare -i ret=0
-case $1 in
+# daemons store daemons on which action will be executed
+declare -a daemons=()
+# filter store current filter mode
+declare -A filter=([started]=0 [stopped]=0 [auto]=0 [noauto]=0)
+
+# parse options
+argv=$(getopt -l 'started,stopped,auto,noauto' -- 'sSaA' "$@") || usage
+eval set -- "$argv"
+
+# create an initial daemon list
+while [[ "$1" != -- ]]; do
+	case "$1" in
+		-s|--started)		filter[started]=1 ;;
+		-S|--stopped)		filter[stopped]=1 ;;
+		-a|--auto)			filter[auto]=1 ;;
+		-A|--noauto)		filter[noauto]=1 ;;
+	esac
+	shift
+done
+
+# remove --
+shift
+# get action
+action=$1
+shift
+
+# get initial daemons list
+for daemon; do
+	daemons+=("$daemon")
+done
+
+# going into script directory
+cd /etc/rc.d
+
+case $action in
 	help)
-		usage
-		;;
+		usage 0 2>&1
+	;;
 	list)
-		shift
-		cd /etc/rc.d/
-		for d in *; do
-			have_daemon "$d" || continue
+		# list take all daemons by default
+		[[ -z $daemons ]] && for d in *; do have_daemon "$d" && daemons+=("$d"); done
+		filter_daemons
+		for daemon in "${daemons[@]}"; do
 			# print running / stopped satus
-			if ! ck_daemon "$d"; then
-				[[ "$1" == stopped ]] && continue
-				printf "${C_OTHER}[${C_DONE}STARTED${C_OTHER}]"
+			if ! ck_daemon "$daemon"; then
+				s_status="${C_OTHER}[${C_DONE}STARTED${C_OTHER}]"
 			else
-				[[ "$1" == started ]] && continue
-				printf "${C_OTHER}[${C_FAIL}STOPPED${C_OTHER}]"
+				s_status="${C_OTHER}[${C_FAIL}STOPPED${C_OTHER}]"
 			fi
 			# print auto / manual status
-			if ! ck_autostart "$d"; then
-				printf "${C_OTHER}[${C_DONE}AUTO${C_OTHER}]"
+			if ! ck_autostart "$daemon"; then
+				s_auto="${C_OTHER}[${C_DONE}AUTO${C_OTHER}]"
 			else
-				printf "${C_OTHER}[${C_FAIL}    ${C_OTHER}]"
+				s_auto="${C_OTHER}[${C_FAIL}    ${C_OTHER}]"
 			fi
-			printf " ${C_CLEAR}$d\n"
+			printf "$s_status$s_auto${C_CLEAR} $daemon\n"
 		done
 	;;
 	*)
-		# check min args count
-		(( $# < 2 )) && usage
-		action=$1
-		shift
+		# other actions need an explicit daemons list
+		[[ -z $daemons ]] && usage
+		filter_daemons
 		# set same environment variables as init
 		runlevel=$(/sbin/runlevel)
-		ENV=("PATH=/bin:/usr/bin:/sbin:/usr/sbin"
+		ENV=('PATH=/bin:/usr/bin:/sbin:/usr/sbin'
 			"PREVLEVEL=${runlevel%% *}"
 			"RUNLEVEL=${runlevel##* }"
 			"CONSOLE=${CONSOLE:-/dev/console}"
 			"TERM=$TERM")
 		cd /
-		for i; do
-			if [[ -x "/etc/rc.d/$i" ]]; then
-				env -i "${ENV[@]}" "/etc/rc.d/$i" "$action"
-			else
-				printf "${C_FAIL}:: ${C_DONE}Daemon ${C_FAIL}$i${C_DONE} does not exist \
-or is not executable${C_CLEAR}\n"
-			fi
+		for daemon in "${daemons[@]}"; do
+			env -i "${ENV[@]}" "/etc/rc.d/$daemon" "$action"
 			(( ret += !! $? ))  # clamp exit value to 0/1
 		done
 	;;
diff --git a/zsh-completion b/zsh-completion
index e5c2850..58fdfab 100644
--- a/zsh-completion
+++ b/zsh-completion
@@ -4,11 +4,10 @@ _rc.d () {
 	local curcontext="$curcontext" state line
 	typeset -A opt_args
 
-	 _arguments "1: :->action" "*: :->service"
-
+	_arguments "1: :->action" "*: :->service" {-s,--started} {-S,--stopped} {-a,--auto} {-A,--noauto}
 	case $state in
 		action)
-			_arguments "1:action:(list help start stop restart)"
+			_arguments "*:action:(list help start stop restart)"
 			;;
 		service)
 			local action="$words[2]"
@@ -18,9 +17,6 @@ _rc.d () {
 				help)
 					_arguments "*: :"
 					;;
-				list)
-					_arguments "2: :(started stopped)"
-					;;
 				start)
 					_arguments "*: :($(comm -23 <(echo /etc/rc.d/*(N-*:t)|tr ' ' '\n') <(echo /run/daemons/*(N:t)|tr ' ' '\n')))"
 					;;
-- 
Sebastien "Seblu" Luttringer



More information about the arch-projects mailing list