1#!/bin/ksh 2# 3# $OpenBSD: rcctl.sh,v 1.116 2023/04/24 14:31:15 kn Exp $ 4# 5# Copyright (c) 2014, 2015-2022 Antoine Jacoutot <ajacoutot@openbsd.org> 6# Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org> 7# 8# Permission to use, copy, modify, and distribute this software for any 9# purpose with or without fee is hereby granted, provided that the above 10# copyright notice and this permission notice appear in all copies. 11# 12# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 20_special_svcs="accounting check_quotas ipsec library_aslr multicast pf 21 spamd_black" 22readonly _special_svcs 23 24# get local functions from rc.subr(8) 25FUNCS_ONLY=1 26. /etc/rc.d/rc.subr 27_rc_parse_conf 28 29usage() 30{ 31 local _a _i 32 for _i in ${_rc_actions}; do _a="$(echo -n ${_i}${_a:+|${_a}})"; done 33 34 _rc_err \ 35 "usage: rcctl get|getdef|set service | daemon [variable [argument ...]] 36 rcctl [-df] ${_a} daemon ... 37 rcctl disable|enable|order [daemon ...] 38 rcctl ls all|failed|off|on|rogue|started|stopped" 39} 40 41needs_root() 42{ 43 [ "$(id -u)" -ne 0 ] && _rc_err "${0##*/}: \"$*\" needs root privileges" 44} 45 46rcctl_err() 47{ 48 _rc_err "${0##*/}: ${1}" ${2} 49} 50 51ls_rcscripts() 52{ 53 local _s 54 55 cd /etc/rc.d && set -- * 56 for _s; do 57 [[ ${_s} == +([[:alnum:]_]) ]] || continue 58 [ ! -d "${_s}" ] && echo "${_s}" 59 done 60} 61 62pkg_scripts_append() 63{ 64 local _svc=$1 65 [ -n "${_svc}" ] || return 66 67 rcconf_edit_begin 68 if [ -z "${pkg_scripts}" ]; then 69 echo pkg_scripts="${_svc}" >>${_TMP_RCCONF} 70 elif ! echo ${pkg_scripts} | grep -qw -- ${_svc}; then 71 grep -v "^pkg_scripts.*=" /etc/rc.conf.local >${_TMP_RCCONF} 72 echo pkg_scripts="${pkg_scripts} ${_svc}" >>${_TMP_RCCONF} 73 fi 74 rcconf_edit_end 75} 76 77pkg_scripts_order() 78{ 79 local _svcs="$*" 80 [ -n "${_svcs}" ] || return 81 82 needs_root ${action} 83 local _pkg_scripts _svc 84 for _svc in ${_svcs}; do 85 if svc_is_base ${_svc} || svc_is_special ${_svc}; then 86 rcctl_err "${_svc} is not a pkg script" 87 elif ! svc_get ${_svc} status; then 88 rcctl_err "${_svc} is not enabled" 89 fi 90 done 91 _pkg_scripts=$(echo "${_svcs} ${pkg_scripts}" | tr "[:blank:]" "\n" | \ 92 awk -v ORS=' ' '!x[$0]++') 93 rcconf_edit_begin 94 grep -v "^pkg_scripts.*=" /etc/rc.conf.local >${_TMP_RCCONF} 95 echo pkg_scripts=${_pkg_scripts} >>${_TMP_RCCONF} 96 rcconf_edit_end 97} 98 99pkg_scripts_rm() 100{ 101 local _svc=$1 102 [ -n "${_svc}" ] || return 103 104 [ -z "${pkg_scripts}" ] && return 105 106 rcconf_edit_begin 107 sed "/^pkg_scripts[[:>:]]/{s/[[:<:]]${_svc}[[:>:]]//g 108 s/['\"]//g;s/ *= */=/;s/ */ /g;s/ $//;/=$/d;}" \ 109 /etc/rc.conf.local >${_TMP_RCCONF} 110 rcconf_edit_end 111} 112 113rcconf_edit_begin() 114{ 115 _TMP_RCCONF=$(mktemp -p /etc -t rc.conf.local.XXXXXXXXXX) || \ 116 rcctl_err "cannot create temporary file under /etc" 117 if [ -f /etc/rc.conf.local ]; then 118 cat /etc/rc.conf.local >${_TMP_RCCONF} || \ 119 rcctl_err "cannot append to ${_TMP_RCCONF}" 120 else 121 touch /etc/rc.conf.local || \ 122 rcctl_err "cannot create /etc/rc.conf.local" 123 fi 124} 125 126rcconf_edit_end() 127{ 128 sort -u -o ${_TMP_RCCONF} ${_TMP_RCCONF} || \ 129 rcctl_err "cannot modify ${_TMP_RCCONF}" 130 cat ${_TMP_RCCONF} >/etc/rc.conf.local || \ 131 rcctl_err "cannot append to /etc/rc.conf.local" 132 if [ ! -s /etc/rc.conf.local ]; then 133 rm /etc/rc.conf.local || \ 134 rcctl_err "cannot remove /etc/rc.conf.local" 135 fi 136 rm -f ${_TMP_RCCONF} 137 _rc_parse_conf # reload new values 138} 139 140svc_is_avail() 141{ 142 local _svc=$1 143 _rc_check_name "${_svc}" || return 144 145 [ -x "/etc/rc.d/${_svc}" ] && return 146 svc_is_special ${_svc} 147} 148 149svc_is_base() 150{ 151 local _svc=$1 152 [ -n "${_svc}" ] || return 153 154 local _cached _ret 155 156 _cached=$(eval echo \${cached_svc_is_base_${_svc}}) 157 [ "${_cached}" ] && return "${_cached}" 158 159 grep -qw "^${_svc}_flags" /etc/rc.conf 160 _ret=$? 161 162 set -A cached_svc_is_base_${_svc} -- ${_ret} 163 return ${_ret} 164} 165 166svc_is_meta() 167{ 168 local _svc=$1 169 [ -n "${_svc}" ] || return 170 171 local _cached _ret 172 173 _cached=$(eval echo \${cached_svc_is_meta_${_svc}}) 174 [ "${_cached}" ] && return "${_cached}" 175 176 [ -r "/etc/rc.d/${_svc}" ] && ! grep -qw "^rc_cmd" /etc/rc.d/${_svc} 177 _ret=$? 178 179 set -A cached_svc_is_meta_${_svc} -- ${_ret} 180 return ${_ret} 181} 182 183svc_is_special() 184{ 185 local _svc=$1 186 [ -n "${_svc}" ] || return 187 188 local _cached _ret 189 190 _cached=$(eval echo \${cached_svc_is_special_${_svc}}) 191 [ "${_cached}" ] && return "${_cached}" 192 193 echo ${_special_svcs} | grep -qw -- ${_svc} 194 _ret=$? 195 196 set -A cached_svc_is_special_${_svc} -- ${_ret} 197 return ${_ret} 198} 199 200svc_ls() 201{ 202 local _lsarg=$1 203 [ -n "${_lsarg}" ] || return 204 205 # we do not want to return the "status" nor the rc.d(8) script retcode 206 local _ret=0 _on _svc _started 207 208 case ${_lsarg} in 209 all) 210 ( 211 ls_rcscripts 212 echo ${_special_svcs} | tr "[:blank:]" "\n" 213 ) | sort 214 ;; 215 failed) 216 for _svc in $(svc_ls on); do 217 ! svc_is_special ${_svc} && \ 218 ! /etc/rc.d/${_svc} check >/dev/null && \ 219 echo ${_svc} && _ret=1 220 done 221 ;; 222 off|on) 223 for _svc in $(svc_ls all); do 224 svc_get ${_svc} status && _on=1 225 [ "${_lsarg}" = "on" -a -n "${_on}" ] || \ 226 [ "${_lsarg}" = "off" -a -z "${_on}" ] && \ 227 echo ${_svc} 228 unset _on 229 done 230 ;; 231 rogue) 232 for _svc in $(svc_ls off); do 233 ! svc_is_special ${_svc} && \ 234 /etc/rc.d/${_svc} check >/dev/null && \ 235 echo ${_svc} && _ret=1 236 done 237 ;; 238 started|stopped) 239 for _svc in $(ls_rcscripts); do 240 /etc/rc.d/${_svc} check >/dev/null && _started=1 241 [ "${_lsarg}" = "started" -a -n "${_started}" ] || \ 242 [ "${_lsarg}" = "stopped" -a -z "${_started}" ] && \ 243 echo ${_svc} 244 unset _started 245 done 246 ;; 247 *) 248 _ret=1 249 ;; 250 esac 251 252 return ${_ret} 253} 254 255svc_get() 256{ 257 local _svc=$1 258 [ -n "${_svc}" ] || return 259 260 local _status=0 _val _var=$2 261 local daemon_class daemon_execdir daemon_flags daemon_logger 262 local daemon_rtable daemon_timeout daemon_user 263 264 if svc_is_special ${_svc}; then 265 daemon_flags="$(eval echo \${${_svc}})" 266 else 267 # set pkg daemon_flags to "NO" to match base svc 268 if ! svc_is_base ${_svc}; then 269 if ! echo ${pkg_scripts} | grep -qw -- ${_svc}; then 270 daemon_flags="NO" 271 fi 272 fi 273 274 if ! svc_is_meta ${_svc}; then 275 # these are expensive, make sure they are explicitly requested 276 if [ -z "${_var}" -o "${_var}" = "class" ]; then 277 getcap -f /etc/login.conf.d/${_svc}:/etc/login.conf \ 278 ${_svc} 1>/dev/null 2>&1 && daemon_class=${_svc} 279 [ -z "${daemon_class}" ] && \ 280 daemon_class="$(svc_getdef ${_svc} class)" 281 fi 282 if [ -z "${_var}" -o "${_var}" = "execdir" ]; then 283 [ -z "${daemon_execdir}" ] && \ 284 daemon_execdir="$(eval echo \"\${${_svc}_execdir}\")" 285 [ -z "${daemon_execdir}" ] && \ 286 daemon_execdir="$(svc_getdef ${_svc} execdir)" 287 fi 288 if [[ -z ${_var} || ${_var} == @(flags|status) ]]; then 289 [ -z "${daemon_flags}" ] && \ 290 daemon_flags="$(eval echo \"\${${_svc}_flags}\")" 291 [ -z "${daemon_flags}" ] && \ 292 daemon_flags="$(svc_getdef ${_svc} flags)" 293 fi 294 if [ -z "${_var}" -o "${_var}" = "logger" ]; then 295 [ -z "${daemon_logger}" ] && \ 296 daemon_logger="$(eval echo \"\${${_svc}_logger}\")" 297 [ -z "${daemon_logger}" ] && \ 298 daemon_logger="$(svc_getdef ${_svc} logger)" 299 fi 300 if [ -z "${_var}" -o "${_var}" = "rtable" ]; then 301 [ -z "${daemon_rtable}" ] && \ 302 daemon_rtable="$(eval echo \"\${${_svc}_rtable}\")" 303 [ -z "${daemon_rtable}" ] && \ 304 daemon_rtable="$(svc_getdef ${_svc} rtable)" 305 fi 306 if [ -z "${_var}" -o "${_var}" = "timeout" ]; then 307 [ -z "${daemon_timeout}" ] && \ 308 daemon_timeout="$(eval echo \"\${${_svc}_timeout}\")" 309 [ -z "${daemon_timeout}" ] && \ 310 daemon_timeout="$(svc_getdef ${_svc} timeout)" 311 fi 312 if [ -z "${_var}" -o "${_var}" = "user" ]; then 313 [ -z "${daemon_user}" ] && \ 314 daemon_user="$(eval echo \"\${${_svc}_user}\")" 315 [ -z "${daemon_user}" ] && \ 316 daemon_user="$(svc_getdef ${_svc} user)" 317 fi 318 fi 319 fi 320 321 [ "${daemon_flags}" = "NO" ] && _status=1 322 323 if [ -n "${_var}" ]; then 324 [ "${_var}" = "status" ] && return ${_status} 325 eval _val=\${daemon_${_var}} 326 [ -z "${_val}" ] || print -r -- "${_val}" 327 else 328 svc_is_meta ${_svc} && return ${_status} 329 if svc_is_special ${_svc}; then 330 echo "${_svc}=${daemon_flags}" 331 else 332 echo "${_svc}_class=${daemon_class}" 333 echo "${_svc}_execdir=${daemon_execdir}" 334 echo "${_svc}_flags=${daemon_flags}" 335 echo "${_svc}_logger=${daemon_logger}" 336 echo "${_svc}_rtable=${daemon_rtable}" 337 echo "${_svc}_timeout=${daemon_timeout}" 338 echo "${_svc}_user=${daemon_user}" 339 fi 340 return ${_status} 341 fi 342} 343 344# to prevent namespace pollution, only call in a subshell 345svc_getdef() 346{ 347 local _svc=$1 348 [ -n "${_svc}" ] || return 349 350 local _status=0 _val _var=$2 351 local daemon_class daemon_execdir daemon_flags daemon_logger 352 local daemon_rtable daemon_timeout daemon_user 353 354 if svc_is_special ${_svc}; then 355 # unconditionally parse: we always output flags and/or status 356 _rc_parse_conf /etc/rc.conf 357 daemon_flags="$(eval echo \${${_svc}})" 358 [ "${daemon_flags}" = "NO" ] && _status=1 359 else 360 if ! svc_is_base ${_svc}; then 361 _status=1 # all pkg_scripts are off by default 362 else 363 # abuse /etc/rc.conf behavior of only setting flags 364 # to empty or "NO" to get our default status; 365 # we'll get our default flags from the rc.d script 366 [[ -z ${_var} || ${_var} == status ]] && \ 367 _rc_parse_conf /etc/rc.conf 368 [ "$(eval echo \${${_svc}_flags})" = "NO" ] && _status=1 369 fi 370 371 if ! svc_is_meta ${_svc}; then 372 rc_cmd() { } 373 . /etc/rc.d/${_svc} >/dev/null 2>&1 374 375 daemon_class=daemon 376 [ -z "${daemon_rtable}" ] && daemon_rtable=0 377 [ -z "${daemon_timeout}" ] && daemon_timeout=30 378 [ -z "${daemon_user}" ] && daemon_user=root 379 fi 380 fi 381 382 if [ -n "${_var}" ]; then 383 [ "${_var}" = "status" ] && return ${_status} 384 eval _val=\${daemon_${_var}} 385 [ -z "${_val}" ] || print -r -- "${_val}" 386 else 387 svc_is_meta ${_svc} && return ${_status} 388 if svc_is_special ${_svc}; then 389 echo "${_svc}=${daemon_flags}" 390 else 391 echo "${_svc}_class=${daemon_class}" 392 echo "${_svc}_execdir=${daemon_execdir}" 393 echo "${_svc}_flags=${daemon_flags}" 394 echo "${_svc}_logger=${daemon_logger}" 395 echo "${_svc}_rtable=${daemon_rtable}" 396 echo "${_svc}_timeout=${daemon_timeout}" 397 echo "${_svc}_user=${daemon_user}" 398 fi 399 return ${_status} 400 fi 401} 402 403svc_rm() 404{ 405 local _svc=$1 406 [ -n "${_svc}" ] || return 407 408 rcconf_edit_begin 409 if svc_is_special ${_svc}; then 410 grep -v "^${_svc}.*=" /etc/rc.conf.local >${_TMP_RCCONF} 411 ( svc_getdef ${_svc} status ) && \ 412 echo "${_svc}=NO" >>${_TMP_RCCONF} 413 else 414 grep -Ev "^${_svc}_(execdir|flags|logger|rtable|timeout|user).*=" \ 415 /etc/rc.conf.local >${_TMP_RCCONF} 416 ( svc_getdef ${_svc} status ) && \ 417 echo "${_svc}_flags=NO" >>${_TMP_RCCONF} 418 fi 419 rcconf_edit_end 420} 421 422svc_set() 423{ 424 local _svc=$1 _var=$2 425 [ -n "${_svc}" -a -n "${_var}" ] || return 426 427 shift 2 428 local _args="$*" 429 430 # don't check if we are already enabled or disabled because rc.conf(8) 431 # defaults may have changed in which case we may have a matching 432 # redundant entry in rc.conf.local that we can drop 433 if [ "${_var}" = "status" ]; then 434 if [ "${_args}" = "on" ]; then 435 _var="flags" 436 # keep our flags if we're already enabled 437 eval "_args=\"\${${_svc}_${_var}}\"" 438 [ "${_args}" = "NO" ] && unset _args 439 if ! svc_is_base ${_svc} && ! svc_is_special ${_svc}; then 440 pkg_scripts_append ${_svc} 441 fi 442 elif [ "${_args}" = "off" ]; then 443 if ! svc_is_base ${_svc} && ! svc_is_special ${_svc}; then 444 pkg_scripts_rm ${_svc} 445 fi 446 svc_rm ${_svc} 447 return 448 else 449 rcctl_err "invalid status \"${_args}\"" 450 fi 451 else 452 svc_get ${_svc} status || \ 453 rcctl_err "${svc} is not enabled" 454 fi 455 456 if svc_is_special ${_svc}; then 457 [ "${_var}" = "flags" ] || return 458 rcconf_edit_begin 459 grep -v "^${_svc}.*=" /etc/rc.conf.local >${_TMP_RCCONF} 460 ( svc_getdef ${_svc} status ) || \ 461 echo "${_svc}=YES" >>${_TMP_RCCONF} 462 rcconf_edit_end 463 return 464 fi 465 466 if [ -n "${_args}" ]; then 467 if [ "${_var}" = "execdir" ]; then 468 [[ ${_args%${_args#?}} == / ]] || 469 rcctl_err "\"${_args}\" must be an absolute path" 470 fi 471 if [ "${_var}" = "logger" ]; then 472 logger -p "${_args}" </dev/null >/dev/null 2>&1 || 473 rcctl_err "unknown priority name: \"${_args}\"" 474 fi 475 if [ "${_var}" = "rtable" ]; then 476 [[ ${_args} != +([[:digit:]]) || ${_args} -lt 0 ]] && \ 477 rcctl_err "\"${_args}\" is not an integer" 478 fi 479 if [ "${_var}" = "timeout" ]; then 480 [[ ${_args} != +([[:digit:]]) || ${_args} -le 0 ]] && \ 481 rcctl_err "\"${_args}\" is not a positive integer" 482 fi 483 if [ "${_var}" = "user" ]; then 484 getent passwd "${_args}" >/dev/null || \ 485 rcctl_err "user \"${_args}\" does not exist" 486 fi 487 # unset flags if they match the default enabled ones 488 [ "${_args}" = "$(svc_getdef ${_svc} ${_var})" ] && \ 489 unset _args 490 fi 491 492 # protect leading whitespace 493 [ "${_args}" = "${_args# }" ] || _args="\"${_args}\"" 494 495 # reset: value may have changed 496 unset ${_svc}_${_var} 497 498 rcconf_edit_begin 499 grep -v "^${_svc}_${_var}.*=" /etc/rc.conf.local >${_TMP_RCCONF} 500 if [ -n "${_args}" ] || \ 501 ( svc_is_base ${_svc} && ! svc_getdef ${_svc} status && [ "${_var}" == "flags" ] ); then 502 echo "${_svc}_${_var}=${_args}" >>${_TMP_RCCONF} 503 fi 504 rcconf_edit_end 505} 506 507unset _RC_DEBUG _RC_FORCE 508while getopts "df" c; do 509 case "$c" in 510 d) _RC_DEBUG=-d;; 511 f) _RC_FORCE=-f;; 512 *) usage;; 513 esac 514done 515shift $((OPTIND-1)) 516[ $# -gt 0 ] || usage 517 518action=$1 519ret=0 520 521case ${action} in 522 ls) 523 lsarg=$2 524 [[ ${lsarg} == @(all|failed|off|on|rogue|started|stopped) ]] || usage 525 ;; 526 order) 527 shift 1 528 svcs="$*" 529 for svc in ${svcs}; do 530 svc_is_avail ${svc} || \ 531 rcctl_err "service ${svc} does not exist" 2 532 done 533 ;; 534 disable|enable|start|stop|restart|reload|check|configtest) 535 shift 1 536 svcs="$*" 537 [ -z "${svcs}" ] && usage 538 # it's ok to disable a non-existing daemon 539 if [ "${action}" != "disable" ]; then 540 for svc in ${svcs}; do 541 svc_is_avail ${svc} || \ 542 rcctl_err "service ${svc} does not exist" 2 543 done 544 fi 545 ;; 546 get|getdef) 547 svc=$2 548 var=$3 549 [ -z "${svc}" ] && usage 550 [ "${svc}" = "all" ] || svc_is_avail ${svc} || \ 551 rcctl_err "service ${svc} does not exist" 2 552 if [ -n "${var}" ]; then 553 [ "${svc}" = "all" ] && usage 554 [[ ${var} != @(class|execdir|flags|logger|rtable|status|timeout|user) ]] && usage 555 if svc_is_meta ${svc}; then 556 [ "${var}" != "status" ] && \ 557 rcctl_err "/etc/rc.d/${svc} is a meta script, cannot \"${action} ${var}\"" 558 fi 559 if svc_is_special ${svc}; then 560 [[ ${var} == @(class|execdir|logger|rtable|timeout|user) ]] && \ 561 rcctl_err "\"${svc}\" is a special variable, cannot \"${action} ${var}\"" 562 fi 563 fi 564 ;; 565 set) 566 svc=$2 567 var=$3 568 [ $# -ge 3 ] && shift 3 || shift $# 569 args="$*" 570 [ -z "${svc}" ] && usage 571 # it's ok to disable a non-existing daemon 572 if [ "${action} ${var} ${args}" != "set status off" ]; then 573 svc_is_avail ${svc} || \ 574 rcctl_err "service ${svc} does not exist" 2 575 fi 576 [[ ${var} != @(class|execdir|flags|logger|rtable|status|timeout|user) ]] && usage 577 svc_is_meta ${svc} && [ "${var}" != "status" ] && \ 578 rcctl_err "/etc/rc.d/${svc} is a meta script, cannot \"${action} ${var}\"" 579 [[ ${var} = flags && ${args} = NO ]] && \ 580 rcctl_err "\"flags NO\" contradicts \"${action}\"" 581 if svc_is_special ${svc}; then 582 [[ ${var} != status ]] && \ 583 rcctl_err "\"${svc}\" is a special variable, cannot \"${action} ${var}\"" 584 fi 585 [[ ${var} == class ]] && \ 586 rcctl_err "\"${svc}_class\" is a read-only variable set in login.conf(5)" 587 ;; 588 *) 589 usage 590 ;; 591esac 592 593case ${action} in 594 disable) 595 needs_root ${action} 596 for svc in ${svcs}; do 597 svc_set ${svc} status off || ret=$?; 598 done 599 exit ${ret} 600 ;; 601 enable) 602 needs_root ${action} 603 for svc in ${svcs}; do 604 svc_set ${svc} status on || ret=$?; 605 done 606 exit ${ret} 607 ;; 608 get|getdef) 609 if [ "${svc}" = "all" ]; then 610 for svc in $(svc_ls all); do 611 ( svc_${action} ${svc} "${var}" ) 612 done 613 return 0 # we do not want the svc status 614 else 615 ( svc_${action} ${svc} "${var}" ) 616 fi 617 ;; 618 ls) 619 # some rc.d(8) scripts need root for rc_check() 620 [[ ${lsarg} == @(started|stopped|failed|rogue) ]] && needs_root ${action} ${lsarg} 621 svc_ls ${lsarg} 622 ;; 623 order) 624 if [ -n "${svcs}" ]; then 625 needs_root ${action} 626 pkg_scripts_order ${svcs} 627 else 628 [[ -z ${pkg_scripts} ]] || echo ${pkg_scripts} 629 fi 630 ;; 631 set) 632 needs_root ${action} 633 svc_set ${svc} "${var}" "${args}" 634 ;; 635 start|stop|restart|reload|check|configtest) 636 for svc in ${svcs}; do 637 if svc_is_special ${svc}; then 638 rcctl_err "\"${svc}\" is a special variable, no rc.d(8) script" 639 fi 640 /etc/rc.d/${svc} ${_RC_DEBUG} ${_RC_FORCE} ${action} || ret=$?; 641 done 642 exit ${ret} 643 ;; 644 *) 645 usage 646 ;; 647esac 648