| 1 |
#!/bin/bash |
| 2 |
################################################################################ |
| 3 |
# # |
| 4 |
# Author: Sean E. Russell <ser@germane-software.com> # |
| 5 |
# Version: 1.0 # |
| 6 |
# Date: Jun 26, 2002 # |
| 7 |
# Adaptation: Mike Frysinger [SpanKY] <vapier@gentoo.org> # |
| 8 |
# Original code was in Ruby ... recoded into bash (at syntax level) # |
| 9 |
# # |
| 10 |
# This application displays information about the RC system used by Gentoo. # |
| 11 |
# In particular, it displays a tree-like format of a run level, showing # |
| 12 |
# all of the services that are installed at that level, and what each # |
| 13 |
# service's status is (running, stopped, etc.) # |
| 14 |
# # |
| 15 |
# -a can be used to display all runlevels # |
| 16 |
# -d can be used to display service dependancies # |
| 17 |
# -u will display all unassigned services # |
| 18 |
# -s will display all services # |
| 19 |
# -h will display help # |
| 20 |
# <runlevel> is used to choose the run level for which information is # |
| 21 |
# displayed # |
| 22 |
# # |
| 23 |
# By default, rc-status only displays information about the current # |
| 24 |
# runlevel; services installed and services running. # |
| 25 |
# # |
| 26 |
################################################################################ |
| 27 |
|
| 28 |
# grab code from functions.sh so we don't have to reproduce it |
| 29 |
source /sbin/functions.sh |
| 30 |
runleveldir=/etc/runlevels |
| 31 |
|
| 32 |
# grab settings from conf.d/rc |
| 33 |
source /etc/conf.d/rc |
| 34 |
|
| 35 |
################################################################################ |
| 36 |
# Parse command line options # |
| 37 |
################################################################################ |
| 38 |
do_opt() { |
| 39 |
case $1 in |
| 40 |
--all|-a) |
| 41 |
ALL=true |
| 42 |
;; |
| 43 |
--depend) |
| 44 |
DEPEND=true |
| 45 |
;; |
| 46 |
--unused|-u) |
| 47 |
ALL=true |
| 48 |
UNUSED=true |
| 49 |
;; |
| 50 |
--list|-l) |
| 51 |
ls -1 ${runleveldir} |
| 52 |
exit 0 |
| 53 |
;; |
| 54 |
--servicelist|-s) |
| 55 |
ALL=true |
| 56 |
SERVICELIST=true |
| 57 |
;; |
| 58 |
--nocolor|-nc) |
| 59 |
;; |
| 60 |
--help|-h|-*) |
| 61 |
echo "USAGE: $0 [command | <runlevel>]" |
| 62 |
echo |
| 63 |
echo "Commands:" |
| 64 |
echo " -a, --all Show services at all run levels" |
| 65 |
echo " -l, --list Show list of run levels" |
| 66 |
echo " -u, --unused Show services not assigned to any run level" |
| 67 |
echo " -s, --servicelist Show service list" |
| 68 |
echo " -nc,--nocolor Monochrome output only" |
| 69 |
echo " <runlevel> Show services assigned to <runlevel>" |
| 70 |
echo |
| 71 |
echo "If no arguments are supplied, shows services for current run level." |
| 72 |
exit 0 |
| 73 |
;; |
| 74 |
*) |
| 75 |
runlevel=$1 |
| 76 |
;; |
| 77 |
esac |
| 78 |
} |
| 79 |
for opt in "$@" ; do |
| 80 |
do_opt ${opt} |
| 81 |
[[ -n $2 ]] && shift |
| 82 |
done |
| 83 |
|
| 84 |
################################################################################ |
| 85 |
# Find the current runlevel being queried. This is either something supplied # |
| 86 |
# on the command line, or pulled from softlevel # |
| 87 |
################################################################################ |
| 88 |
if [[ -z "${runlevel}" ]] ; then |
| 89 |
if [[ -e "${svcdir}/softlevel" ]] ; then |
| 90 |
runlevel="$( <${svcdir}/softlevel )" |
| 91 |
else |
| 92 |
ewarn "Could not local current runlevel in ${svcdir}/softlevel" |
| 93 |
if [[ -d "${runleveldir}/single" ]] ; then |
| 94 |
runlevel=single |
| 95 |
elif [[ -d "${runleveldir}/default" ]] ; then |
| 96 |
runlevel=default |
| 97 |
else |
| 98 |
eerror "Your installation is probably broken ... please \`emerge baselayout\`" |
| 99 |
exit 1 |
| 100 |
fi |
| 101 |
ewarn "Assuming current runrevel is '${runlevel}'" |
| 102 |
fi |
| 103 |
fi |
| 104 |
if [[ ! -d "${runleveldir}/${runlevel}" ]] ; then |
| 105 |
eerror "${runlevel} is not a valid run level !" |
| 106 |
eerror "Valid runlevels (obtained from \`rc-status --list\`):" |
| 107 |
rc-status --list |
| 108 |
exit 1 |
| 109 |
fi |
| 110 |
|
| 111 |
################################################################################ |
| 112 |
# Build up a hash of the services associated with each run level. In the most # |
| 113 |
# trivial case, this is simply the current runlevel. If --all was specified, # |
| 114 |
# we gather information about all of the runlevels. If --unused was # |
| 115 |
# specified, we pull info about all of the services and filter for the ones # |
| 116 |
# that don't appear in any runlevel. # |
| 117 |
################################################################################ |
| 118 |
runlevelidxs=$( ls ${runleveldir} ) |
| 119 |
declare -a runlevels |
| 120 |
# For each directory in /etc/runlevels, do ... |
| 121 |
arridx=0 |
| 122 |
for level in ${runlevelidxs} ; do |
| 123 |
if [[ ${level} == ${runlevel} || -n ${ALL} ]] ; then |
| 124 |
runlevels[${arridx}]=$( find ${runleveldir}/${level} -maxdepth 1 -type l -printf '%f ' ) |
| 125 |
let "arridx += 1" |
| 126 |
fi |
| 127 |
done |
| 128 |
|
| 129 |
# In case --all was specified, get a list of all the services set up in |
| 130 |
# /etc/init.d; services can be added, but not enabled, and we need to |
| 131 |
# identify these 'orphan' services. |
| 132 |
in_list() { #$1=list $2=find |
| 133 |
for ele in $1 ; do |
| 134 |
if [[ ${ele} == $2 ]] ; then |
| 135 |
echo 1 |
| 136 |
return 0 |
| 137 |
fi |
| 138 |
done |
| 139 |
echo 0 |
| 140 |
return 0 |
| 141 |
} |
| 142 |
if [[ -n ${ALL} ]] ; then |
| 143 |
unassigned= |
| 144 |
allservices= |
| 145 |
for service in $( ls -1 /etc/init.d | grep -v '\.sh$' ) ; do |
| 146 |
if [[ $( in_list "${runlevels[*]}" "${service}" ) -eq 0 ]] ; then |
| 147 |
unassigned="${unassigned} ${service}" |
| 148 |
fi |
| 149 |
allservices="${allservices} ${service}" |
| 150 |
done |
| 151 |
runlevelidxs="${runlevelidxs} UNASSIGNED" |
| 152 |
runlevels[${arridx}]="${unassigned}" |
| 153 |
runlevels[${arridx}+1]="${allservices}" |
| 154 |
fi |
| 155 |
|
| 156 |
################################################################################ |
| 157 |
# Now collect information about the status of the various services; whether # |
| 158 |
# they're started, broken, or failed. Put all of this into arrays. # |
| 159 |
################################################################################ |
| 160 |
# Read services from ${svcdir}/{started,failed,broken} |
| 161 |
[[ -x "${svcdir}/starting" ]] && starting=$( ls ${svcdir}/starting ) |
| 162 |
[[ -x "${svcdir}/inactive" ]] && inactive=$( ls ${svcdir}/inactive ) |
| 163 |
[[ -x "${svcdir}/started" ]] && started=$( ls ${svcdir}/started ) |
| 164 |
[[ -x "${svcdir}/stopping" ]] && stopping=$( ls ${svcdir}/stopping ) |
| 165 |
[[ -x "${svcdir}/failed" ]] && failed=$( ls ${svcdir}/failed ) |
| 166 |
[[ -x "${svcdir}/broken" ]] && broken=$( ls ${svcdir}/broken ) |
| 167 |
|
| 168 |
################################################################################ |
| 169 |
# Now print out the information we've gathered. We do this by going through # |
| 170 |
# the hash of 'runlevels' information, and for each String key/Array value # |
| 171 |
# pair, print the runlevel; then for each service in that runlevel, print the # |
| 172 |
# service name and its status. # |
| 173 |
################################################################################ |
| 174 |
# Define a helper method for printing the status of a service; '[ xxx ]' |
| 175 |
print_msg() { |
| 176 |
printf " %-$((COLS - 5 - ${#3}))s%s\n" "$1" "${BRACKET}[ $2$3 ${BRACKET}]${NORMAL}" |
| 177 |
} |
| 178 |
|
| 179 |
# if --all wasnt specified, dont print everything |
| 180 |
[[ -z ${ALL} ]] && runlevelidxs=${runlevel} |
| 181 |
if [[ -z ${UNUSED} ]] ; then |
| 182 |
if [[ -z ${SERVICELIST} ]] ; then |
| 183 |
arridx=0 |
| 184 |
else |
| 185 |
runlevelidxs="all" |
| 186 |
let "arridx += 1" |
| 187 |
fi |
| 188 |
else |
| 189 |
runlevelidxs="unused" |
| 190 |
fi |
| 191 |
|
| 192 |
for level in ${runlevelidxs} ; do |
| 193 |
echo "Runlevel: ${HILITE}${level}${NORMAL}" |
| 194 |
for service in ${runlevels[${arridx}]} ; do |
| 195 |
if [[ -n ${inactive} && $( in_list "${inactive}" "${service}" ) -eq 1 ]] ; then |
| 196 |
print_msg "${service}" "${WARN}" 'inactive' |
| 197 |
elif [[ $(in_list "${started}" "${service}") -eq 1 ]] ; then |
| 198 |
print_msg "${service}" "${GOOD}" 'started' |
| 199 |
elif [[ -n ${starting} && $( in_list "${starting}" "${service}" ) -eq 1 ]] ; then |
| 200 |
print_msg "${service}" "${GOOD}" 'starting' |
| 201 |
elif [[ -n ${stopping} && $( in_list "${stopping}" "${service}" ) -eq 1 ]] ; then |
| 202 |
print_msg "${service}" "${BAD}" 'stopping' |
| 203 |
elif [[ -n ${failed} && $( in_list "${failed}" "${service}" ) -eq 1 ]] ; then |
| 204 |
print_msg "${service}" "${BAD}" 'failed' |
| 205 |
elif [[ -n ${broken} && $( in_list "${broken}" "${service}" ) -eq 1 ]] ; then |
| 206 |
print_msg "${service}" "${BAD}" 'broken' |
| 207 |
else |
| 208 |
print_msg "${service}" "${WARN}" ' off' |
| 209 |
fi |
| 210 |
done |
| 211 |
let "arridx += 1" |
| 212 |
[ -n "${UNUSED}" ] && exit 0 |
| 213 |
done |