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

Lukas Fleischer archlinux at cryptocrack.de
Tue Aug 23 10:58:33 EDT 2011


On Tue, Aug 23, 2011 at 03:32:32PM +0200, Sebastien Luttringer wrote:
> rc.d can now take --started, --stopped, --auto, --noauto as option which
> help user to populate 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            |  109 ++++++++++++++++++++++++++++++++++++++-----------------
>  zsh-completion  |    5 +--
>  3 files changed, 86 insertions(+), 48 deletions(-)
> 
> diff --git a/bash-completion b/bash-completion
> index d78484e..1df229e 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='--started --stopped --auto --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..907439b 100755
> --- a/rc.d
> +++ b/rc.d
> @@ -4,74 +4,115 @@ 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 [options] <action> [daemons]

"usage: $name <action> [options] [daemons]". Although it doesn't really
matter, `rc.d list --started` should be the default way of specifying
arguments, see your examples further below.

>  
> -<daemon> is the name of a script in /etc/rc.d
> +options:
> +  --started     Append started daemons to the list
> +  --stopped     Append stopped dameons to the list
> +  --auto        Append autostarted daemons to the list
> +  --noauto      Append not autostarted daemons to the list
> +
> +<daemons> is space separated list of script in /etc/rc.d

... is *a* space separated list of script*s*.

>  <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}
>  }
>  
>  (( $# < 1 )) && usage
>  
> +# parse options
> +argv=$(getopt -l 'started,stopped,auto,noauto' -- '' "$@")
> +(( $? )) && usage

`argv=$(getopt -l 'started,stopped,auto,noauto' -- '' "$@") || usage`.

> +eval set -- "$argv"
> +
> +# going into script directory
> +cd /etc/rc.d
> +
> +# create an initial daemon list
> +declare -a daemons=()
> +while [[ "$1" != -- ]]; do
> +	case "$1" in
> +		--started)
> +			for d in *; do have_daemon "$d" && ! ck_daemon "$d" && daemons+=("$d"); done
> +		;;
> +		--stopped)
> +			for d in *; do have_daemon "$d" && ck_daemon "$d" && daemons+=("$d"); done
> +		;;
> +		--auto)
> +			for d in *; do have_daemon "$d" && ! ck_autostart "$d" && daemons+=("$d"); done
> +		;;
> +		--noauto)
> +			for d in *; do have_daemon "$d" && ck_autostart "$d" && daemons+=("$d"); done
> +		;;

Oh. I thought of an implicit conjunction over the single filter options
here. This is advantageous if you want to list running auto-started
daemons (`rc.d list --started --auto`) etc. I would just set some flag
when parsing the options and filter the daemon list in a single loop
later on (which is faster, also).

> +	esac
> +	shift
> +done
> +
> +# remove --
> +shift
> +# get action
> +action=$1
> +shift
> +
> +# add daemons
> +for daemon; do
> +	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
> +	daemons+=("$daemon")
> +done

Same here. Explicitly specified daemons should not be added to the list,
but used as input to the filter options (if any). I would suggest
following procedure:

Iterate over the daemons specified on the command line if any,
"/etc/rc.d/*" otherwise:

* Set some flag to 1 (indicating whether the daemon will be included in
  the list or not).

* If "--started" or "--stopped" are specified (you stored this in some
  other flag earlier), possibly reset the flag to 0, depending on what
  ck_daemon() returns.

* Do the same thing with "--auto" or "--noauto" (and ck_autostart()).

* Add the daemon to some array if the flag is still set to 1.

This removes the need for special treatment in any of the action cases
below, also.

> +
>  declare -i ret=0
> -case $1 in
> +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
> +		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
> +		[[ -z $daemons ]] && usage
>  		# 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..69b3896 100644
> --- a/zsh-completion
> +++ b/zsh-completion
> @@ -4,7 +4,7 @@ _rc.d () {
>  	local curcontext="$curcontext" state line
>  	typeset -A opt_args
>  
> -	 _arguments "1: :->action" "*: :->service"
> +	 _arguments "1: :->action" "*: :->service" "--started" "--stopped" "--auto" "--noauto"
>  
>  	case $state in
>  		action)
> @@ -18,9 +18,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