blob: b9c5b18434c51f516bc1f957983885d4b6e74374 [file] [log] [blame]
Anthony Wilson79f697e2018-09-13 13:48:52 -05001#!/bin/sh -e
2
3set -euo pipefail
4
Anthony Wilson189cf242018-10-23 01:18:21 -05005OPTS="bmcstate,bootprogress,chassiskill,chassisoff,chassison,chassisstate,hoststate,\
Vishwanatha Subbannaa65d30d2019-11-13 01:26:12 -06006osstate,power,poweroff,poweron,state,status,hostrebootoff,hostrebooton,recoveryoff,recoveryon,\
Andrew Geissler42f28982020-05-14 15:12:42 -05007bmcrebootoff, bmcrebooton, listbootblock listlogs showlog deletelogs"
Anthony Wilson0f359832018-09-13 14:28:07 -05008
Andrew Jeffery60c3ac82019-10-02 09:29:29 +09309USAGE="Usage: obmcutil [-h] [--wait] [--verbose]
Anthony Wilson0f359832018-09-13 14:28:07 -050010 {$OPTS}"
Anthony Wilson79f697e2018-09-13 13:48:52 -050011
12INTERFACE_ROOT=xyz.openbmc_project
13STATE_INTERFACE=$INTERFACE_ROOT.State
Vishwanatha Subbanna6d3a2c52019-10-24 07:21:30 -050014CONTROL_INTERFACE=$INTERFACE_ROOT.Control
Anthony Wilson79f697e2018-09-13 13:48:52 -050015
16OBJECT_ROOT=/xyz/openbmc_project
17STATE_OBJECT=$OBJECT_ROOT/state
Vishwanatha Subbanna6d3a2c52019-10-24 07:21:30 -050018CONTROL_OBJECT=$OBJECT_ROOT/control
Anthony Wilson79f697e2018-09-13 13:48:52 -050019
Vishwanatha Subbanna7a787dd2019-10-31 06:02:31 -050020HOST_TIMEOUT_TARGET=obmc-host-timeout@0.target
Vishwanatha Subbanna84b3b292019-11-04 05:43:19 -060021HOST_CRASH_TARGET=obmc-host-crash@0.target
Vishwanatha Subbanna7a787dd2019-10-31 06:02:31 -050022
Anthony Wilsonacf54d02018-09-20 15:19:28 -050023## NOTE: The following global variables are used only in the run_timeout cmd.
24## By declaring these globally instead of passing them through the
25## intermediary functions, which may not be "best practice", the readability
26## and cleanliness of the code should at least be increased.
27
28# The command passed in to be executed (e.g. poweron/off, status, etc.)
29# This will be be used in some instances of error reporting
30G_ORIG_CMD=
31# The state an interface should be in after executing the requested command.
32G_REQUESTED_STATE=
33# The query to run during a poweron/off or chassison/off to check that
34# the requested state (G_REQUESTED_STATE) of the interface has been reached.
35G_QUERY=
36# Wait the set period of time for state transitions to be successful before
37# continuing on with the program or reporting an error if timeout reached.
38G_WAIT=
Andrew Jeffery60c3ac82019-10-02 09:29:29 +093039# Print the journal to the console
40G_VERBOSE=
Anthony Wilsonacf54d02018-09-20 15:19:28 -050041
Anthony Wilsonf3f16fa2018-09-13 14:10:52 -050042print_help ()
43{
44 echo "$USAGE"
45 echo ""
46 echo "positional arguments:"
Anthony Wilson0f359832018-09-13 14:28:07 -050047 echo " {$OPTS}"
Anthony Wilsonf3f16fa2018-09-13 14:10:52 -050048 echo ""
Vishwanatha Subbanna6d3a2c52019-10-24 07:21:30 -050049 echo "Examples:"
50 echo ""
Vishwanatha Subbannaa65d30d2019-11-13 01:26:12 -060051 echo "obmcutil hostrebootoff Disable auto reboot of Host from Quiesce state"
52 echo "obmcutil hostrebooton Enable auto reboot of Host from Quiesce state"
Vishwanatha Subbanna6d3a2c52019-10-24 07:21:30 -050053 echo ""
Vishwanatha Subbannaa65d30d2019-11-13 01:26:12 -060054 echo "obmcutil bmcrebootoff Disable reboot of BMC"
55 echo "obmcutil bmcrebooton Enable reboot of BMC"
56 echo ""
57 echo "obmcutil recoveryoff Disable handling boot watchdog timeout and host crash"
58 echo " Also, disable BMC and Host auto reboots"
59 echo ""
60 echo "obmcutil recoveryon Enable handling boot watchdog timeout and host crash"
61 echo " Also, enable BMC and Host auto reboots"
Vishwanatha Subbanna7a787dd2019-10-31 06:02:31 -050062 echo ""
Andrew Geissler3b7b5612020-05-14 10:45:29 -050063 echo "obmcutil listbootblock Check for and list any errors blocking the boot"
64 echo " of the system"
65 echo ""
Andrew Geissler295ee4f2020-05-14 14:14:05 -050066 echo "obmcutil listlogs List all phosphor-logging entries on the"
67 echo " system"
68 echo ""
Andrew Geisslerd8c63202020-05-14 15:06:31 -050069 echo "obmcutil showlog <log> Display details of input log. Format of <log>"
70 echo " should match listlogs output"
71 echo ""
Andrew Geissler42f28982020-05-14 15:12:42 -050072 echo "obmcutil deletelogs Delete all phosphor-logging entries from"
73 echo " system"
74 echo ""
Andrew Geisslerd8779cd2020-06-11 10:48:40 -050075 echo "optional arguments (must precede the positional options above):"
Anthony Wilsonf3f16fa2018-09-13 14:10:52 -050076 echo " -h, --help show this help message and exit"
Anthony Wilsonacf54d02018-09-20 15:19:28 -050077 echo " -w, --wait block until state transition succeeds or fails"
Andrew Jeffery60c3ac82019-10-02 09:29:29 +093078 echo " -v, --verbose print the journal to stdout if --wait is supplied"
Anthony Wilsonf3f16fa2018-09-13 14:10:52 -050079 exit 0
80}
81
Anthony Wilsonacf54d02018-09-20 15:19:28 -050082run_timeout ()
83{
84 local timeout="$1"; shift
85 local cmd="$@"
Andrew Jeffery60c3ac82019-10-02 09:29:29 +093086 local verbose_child=
87
Andrew Jeffery2869a922019-10-18 14:42:34 +103088 if [ -n "$G_VERBOSE" ]; then
Andrew Jeffery60c3ac82019-10-02 09:29:29 +093089 journalctl -f &
90 verbose_child=$!
91 fi
Anthony Wilsonacf54d02018-09-20 15:19:28 -050092
93 $cmd
94
95 # Run a background query for the transition to the expected state
96 # This will be killed if the transition doesn't succeed within
97 # a timeout period.
98 (
99 while ! grep -q $G_REQUESTED_STATE <<< $(handle_cmd $G_QUERY) ; do
100 sleep 1
101 done
102 ) &
Andrew Jeffery60c3ac82019-10-02 09:29:29 +0930103 wait_child=$!
Anthony Wilsonacf54d02018-09-20 15:19:28 -0500104
105 # Could be bad if process is killed before 'timeout' occurs if
106 # transition doesn't succeed.
107 trap -- "" SIGTERM
108
109 # Workaround for lack of 'timeout' command.
110 (
111 sleep $timeout
Andrew Jeffery60c3ac82019-10-02 09:29:29 +0930112 kill $wait_child
Anthony Wilsonacf54d02018-09-20 15:19:28 -0500113 ) > /dev/null 2>&1 &
114
Andrew Jeffery60c3ac82019-10-02 09:29:29 +0930115 if ! wait $wait_child; then
Anthony Wilsonacf54d02018-09-20 15:19:28 -0500116 echo "Unable to confirm '$G_ORIG_CMD' success" \
117 "within timeout period (${timeout}s)"
118 fi
Andrew Jeffery60c3ac82019-10-02 09:29:29 +0930119
Andrew Jeffery8be70292019-11-01 08:56:49 +1030120 if [ -n "$verbose_child" ]; then
Andrew Jeffery60c3ac82019-10-02 09:29:29 +0930121 kill $verbose_child
122 fi
Anthony Wilsonacf54d02018-09-20 15:19:28 -0500123}
124
125run_cmd ()
126{
127 local cmd="$@";
128
129 if [ -n "$G_WAIT" ]; then
130 run_timeout $G_WAIT "$cmd"
131 else
132 $cmd
133 fi
134}
135
Anthony Wilson3ae0a352018-09-13 14:47:56 -0500136set_property ()
137{
Anthony Wilsonacf54d02018-09-20 15:19:28 -0500138 run_cmd busctl set-property "$@"
Anthony Wilson3ae0a352018-09-13 14:47:56 -0500139}
140
Anthony Wilson79f697e2018-09-13 13:48:52 -0500141get_property ()
142{
Anthony Wilsonacf54d02018-09-20 15:19:28 -0500143 G_WAIT=""
144 run_cmd busctl get-property "$@"
Anthony Wilson79f697e2018-09-13 13:48:52 -0500145}
146
147state_query ()
148{
149 local state=$(get_property "$@" | cut -d '"' -f2)
150 printf "%-20s: %s\n" $4 $state
151}
152
Anthony Wilsonea87db42018-09-26 16:06:38 -0500153print_usage_err ()
154{
155 echo "ERROR: $1" >&2
156 echo "$USAGE"
157 exit 1
158}
159
Vishwanatha Subbanna7a787dd2019-10-31 06:02:31 -0500160mask_systemd_target ()
161{
162 target="$@"
163 systemctl mask $target
164}
165
166unmask_systemd_target ()
167{
168 target="$@"
169 systemctl unmask $target
170}
171
Vishwanatha Subbannaa65d30d2019-11-13 01:26:12 -0600172disable_bmc_reboot ()
173{
174 dir="/run/systemd/system/"
175 file="reboot-guard.conf"
176 units=("reboot" "poweroff" "halt")
177
178 for unit in "${units[@]}"; do
179 mkdir -p ${dir}${unit}.target.d
180 echo -e "[Unit]\nRefuseManualStart=yes" >> ${dir}${unit}.target.d/${file}
181 done
182}
183
184enable_bmc_reboot ()
185{
186 dir="/run/systemd/system/"
187 file="reboot-guard.conf"
188 units=("reboot" "poweroff" "halt")
189
190 for unit in "${units[@]}"; do
191 rm -rf ${dir}${unit}.target.d/${file}
192 rm -rf ${dir}${unit}.target.d
193 done
194}
195
Andrew Geissler3b7b5612020-05-14 10:45:29 -0500196# will write blocking errors to stdout
197check_boot_block_errors ()
198{
199 # array of boot block objects
200 blockArray=()
201
202 # Look for any objects under logging that implement the
203 # xyz.openbmc_project.Logging.ErrorBlocksTransition
204 subtree="$(busctl call xyz.openbmc_project.ObjectMapper \
205 /xyz/openbmc_project/object_mapper \
206 xyz.openbmc_project.ObjectMapper \
207 GetSubTree sias "/xyz/openbmc_project/logging/" 0 1 \
208 xyz.openbmc_project.Logging.ErrorBlocksTransition)"
209
210 # remove quotation marks
211 subtree="$(echo $subtree | sed 's/\"//g')"
212
213 for entry in $subtree; do
214 if [[ ${entry} =~ "xyz/openbmc_project/logging/block"* ]]; then
215 blockArray+=( $entry )
216 fi
217 done
218
219 # now find associated error log for each boot block error
220 for berror in "${blockArray[@]}"; do
221 assocs="$(busctl call xyz.openbmc_project.Logging $berror \
222 org.freedesktop.DBus.Properties Get \
223 ss xyz.openbmc_project.Association.Definitions Associations)"
224
225 # remove quotation marks
226 assocs="$(echo $assocs | sed 's/\"//g')"
227
228 for entry in $assocs; do
229 if [[ ${entry} =~ "xyz/openbmc_project/logging/entry"* ]]; then
230 echo "Blocking Error: $entry"
231 fi
232 done
233 done
234}
235
Andrew Geisslerdeb6bb42020-05-14 13:44:57 -0500236# helper function to check for boot block errors and notify user
237check_and_warn_boot_block()
238{
239 blockingErrors=$(check_boot_block_errors)
240 if ! [ -z "$blockingErrors" ]; then
241 echo !!!!!!!!!!
242 echo "WARNING! System has blocking errors that will prevent boot"
243 echo "$blockingErrors"
244 echo !!!!!!!!!!
245 fi
246}
247
Andrew Geissler295ee4f2020-05-14 14:14:05 -0500248# list all phosphor-logging entries
249list_logs()
250{
251 # Look for any objects under logging that implement the
252 # xyz.openbmc_project.Logging.Entry
253 busctl -j call xyz.openbmc_project.ObjectMapper \
254 /xyz/openbmc_project/object_mapper \
255 xyz.openbmc_project.ObjectMapper \
256 GetSubTreePaths sias "/xyz/openbmc_project/logging/" 0 1 \
257 xyz.openbmc_project.Logging.Entry
258}
259
Andrew Geisslerd8c63202020-05-14 15:06:31 -0500260# display input log details
261show_log()
262{
263 busctl -j call xyz.openbmc_project.Logging \
264 $1 \
265 org.freedesktop.DBus.Properties \
266 GetAll s xyz.openbmc_project.Logging.Entry
267}
268
Andrew Geissler42f28982020-05-14 15:12:42 -0500269# delete all phosphor-logging entries
270delete_logs()
271{
272 busctl call xyz.openbmc_project.Logging \
273 /xyz/openbmc_project/logging \
274 xyz.openbmc_project.Collection.DeleteAll DeleteAll
275}
276
Anthony Wilson79f697e2018-09-13 13:48:52 -0500277handle_cmd ()
278{
279 case "$1" in
Anthony Wilson3ae0a352018-09-13 14:47:56 -0500280 chassisoff)
281 OBJECT=$STATE_OBJECT/chassis0
282 SERVICE=$(mapper get-service $OBJECT)
283 INTERFACE=$STATE_INTERFACE.Chassis
284 PROPERTY=RequestedPowerTransition
285 VALUE=$INTERFACE.Transition.Off
Anthony Wilsonacf54d02018-09-20 15:19:28 -0500286 G_REQUESTED_STATE=$INTERFACE.PowerState.Off
287 G_QUERY="chassisstate"
Anthony Wilson3ae0a352018-09-13 14:47:56 -0500288 set_property $SERVICE $OBJECT $INTERFACE $PROPERTY "s" $VALUE
289 ;;
290 chassison)
Andrew Geisslerdeb6bb42020-05-14 13:44:57 -0500291 check_and_warn_boot_block
Anthony Wilson3ae0a352018-09-13 14:47:56 -0500292 OBJECT=$STATE_OBJECT/chassis0
293 SERVICE=$(mapper get-service $OBJECT)
294 INTERFACE=$STATE_INTERFACE.Chassis
295 PROPERTY=RequestedPowerTransition
296 VALUE=$INTERFACE.Transition.On
Anthony Wilsonacf54d02018-09-20 15:19:28 -0500297 G_REQUESTED_STATE=$INTERFACE.PowerState.On
298 G_QUERY="chassisstate"
Anthony Wilson3ae0a352018-09-13 14:47:56 -0500299 set_property $SERVICE $OBJECT $INTERFACE $PROPERTY "s" $VALUE
300 ;;
301 poweroff)
302 OBJECT=$STATE_OBJECT/host0
303 SERVICE=$(mapper get-service $OBJECT)
304 INTERFACE=$STATE_INTERFACE.Host
305 PROPERTY=RequestedHostTransition
306 VALUE=$INTERFACE.Transition.Off
Anthony Wilsonacf54d02018-09-20 15:19:28 -0500307 G_REQUESTED_STATE=$INTERFACE.HostState.Off
308 G_QUERY="hoststate"
Anthony Wilson3ae0a352018-09-13 14:47:56 -0500309 set_property $SERVICE $OBJECT $INTERFACE $PROPERTY "s" $VALUE
310 ;;
311 poweron)
Andrew Geisslerdeb6bb42020-05-14 13:44:57 -0500312 check_and_warn_boot_block
Anthony Wilson3ae0a352018-09-13 14:47:56 -0500313 OBJECT=$STATE_OBJECT/host0
314 SERVICE=$(mapper get-service $OBJECT)
315 INTERFACE=$STATE_INTERFACE.Host
316 PROPERTY=RequestedHostTransition
317 VALUE=$INTERFACE.Transition.On
Anthony Wilsonacf54d02018-09-20 15:19:28 -0500318 G_REQUESTED_STATE=$INTERFACE.HostState.Running
319 G_QUERY="hoststate"
Anthony Wilson3ae0a352018-09-13 14:47:56 -0500320 set_property $SERVICE $OBJECT $INTERFACE $PROPERTY "s" $VALUE
321 ;;
Anthony Wilson79f697e2018-09-13 13:48:52 -0500322 bmcstate)
323 OBJECT=$STATE_OBJECT/bmc0
324 SERVICE=$(mapper get-service $OBJECT)
325 INTERFACE=$STATE_INTERFACE.BMC
326 PROPERTY=CurrentBMCState
327 state_query $SERVICE $OBJECT $INTERFACE $PROPERTY
328 ;;
329 chassisstate)
330 OBJECT=$STATE_OBJECT/chassis0
331 SERVICE=$(mapper get-service $OBJECT)
332 INTERFACE=$STATE_INTERFACE.Chassis
333 PROPERTY=CurrentPowerState
334 state_query $SERVICE $OBJECT $INTERFACE $PROPERTY
335 ;;
336 hoststate)
337 OBJECT=$STATE_OBJECT/host0
338 SERVICE=$(mapper get-service $OBJECT)
339 INTERFACE=$STATE_INTERFACE.Host
340 PROPERTY=CurrentHostState
341 state_query $SERVICE $OBJECT $INTERFACE $PROPERTY
342 ;;
Alexander Filippov86cffd92019-04-03 16:29:57 +0300343 osstate)
344 OBJECT=$STATE_OBJECT/host0
345 SERVICE=$(mapper get-service $OBJECT)
346 INTERFACE=$STATE_INTERFACE.OperatingSystem.Status
347 PROPERTY=OperatingSystemState
348 state_query $SERVICE $OBJECT $INTERFACE $PROPERTY
349 ;;
Anthony Wilson79f697e2018-09-13 13:48:52 -0500350 state|status)
Alexander Filippov86cffd92019-04-03 16:29:57 +0300351 for query in bmcstate chassisstate hoststate bootprogress osstate
Anthony Wilson79f697e2018-09-13 13:48:52 -0500352 do
353 handle_cmd $query
354 done
Andrew Geisslerdeb6bb42020-05-14 13:44:57 -0500355 check_and_warn_boot_block
Anthony Wilson79f697e2018-09-13 13:48:52 -0500356 ;;
Anthony Wilson50c5f882018-09-13 14:19:37 -0500357 bootprogress)
358 OBJECT=$STATE_OBJECT/host0
359 SERVICE=$(mapper get-service $OBJECT)
360 INTERFACE=$STATE_INTERFACE.Boot.Progress
361 PROPERTY=BootProgress
362 state_query $SERVICE $OBJECT $INTERFACE $PROPERTY
363 ;;
Anthony Wilson0f359832018-09-13 14:28:07 -0500364 power)
365 OBJECT=/org/openbmc/control/power0
366 SERVICE=$(mapper get-service $OBJECT)
367 INTERFACE=org.openbmc.control.Power
368 for property in pgood state pgood_timeout
369 do
370 # get_property can potentially return several
371 # different formats of values, so we do the parsing outside
372 # of get_property depending on the query. These queries
373 # return 'i VALUE' formatted strings.
374 STATE=$(get_property $SERVICE $OBJECT $INTERFACE $property \
375 | sed 's/i[ ^I]*//')
376 printf "%s = %s\n" $property $STATE
377 done
378 ;;
Anthony Wilson189cf242018-10-23 01:18:21 -0500379 chassiskill)
380 /usr/libexec/chassiskill
381 ;;
Vishwanatha Subbannaa65d30d2019-11-13 01:26:12 -0600382 hostrebootoff)
Vishwanatha Subbanna6d3a2c52019-10-24 07:21:30 -0500383 OBJECT=$CONTROL_OBJECT/host0/auto_reboot
384 SERVICE=$(mapper get-service $OBJECT)
385 INTERFACE=$CONTROL_INTERFACE.Boot.RebootPolicy
386 PROPERTY=AutoReboot
387 VALUE=false
388 set_property $SERVICE $OBJECT $INTERFACE $PROPERTY "b" $VALUE
389 ;;
Vishwanatha Subbannaa65d30d2019-11-13 01:26:12 -0600390 hostrebooton)
Vishwanatha Subbanna6d3a2c52019-10-24 07:21:30 -0500391 OBJECT=$CONTROL_OBJECT/host0/auto_reboot
392 SERVICE=$(mapper get-service $OBJECT)
393 INTERFACE=$CONTROL_INTERFACE.Boot.RebootPolicy
394 PROPERTY=AutoReboot
395 VALUE=true
396 set_property $SERVICE $OBJECT $INTERFACE $PROPERTY "b" $VALUE
397 ;;
Vishwanatha Subbannaa65d30d2019-11-13 01:26:12 -0600398 bmcrebootoff)
399 disable_bmc_reboot
400 ;;
401 bmcrebooton)
402 enable_bmc_reboot
403 ;;
Vishwanatha Subbanna7a787dd2019-10-31 06:02:31 -0500404 recoveryoff)
Vishwanatha Subbannaa65d30d2019-11-13 01:26:12 -0600405 handle_cmd hostrebootoff
406 handle_cmd bmcrebootoff
Vishwanatha Subbanna7a787dd2019-10-31 06:02:31 -0500407 mask_systemd_target $HOST_TIMEOUT_TARGET
Vishwanatha Subbanna84b3b292019-11-04 05:43:19 -0600408 mask_systemd_target $HOST_CRASH_TARGET
Vishwanatha Subbanna7a787dd2019-10-31 06:02:31 -0500409 ;;
410 recoveryon)
Vishwanatha Subbannaa65d30d2019-11-13 01:26:12 -0600411 handle_cmd hostrebooton
412 handle_cmd bmcrebooton
Vishwanatha Subbanna7a787dd2019-10-31 06:02:31 -0500413 unmask_systemd_target $HOST_TIMEOUT_TARGET
Vishwanatha Subbanna84b3b292019-11-04 05:43:19 -0600414 unmask_systemd_target $HOST_CRASH_TARGET
Vishwanatha Subbanna7a787dd2019-10-31 06:02:31 -0500415 ;;
Andrew Geissler3b7b5612020-05-14 10:45:29 -0500416 listbootblock)
417 blockingErrors=$(check_boot_block_errors)
418 if [ -z "$blockingErrors" ]; then
419 echo "No blocking errors present"
420 else
421 echo "$blockingErrors"
422 fi
423 ;;
Andrew Geissler295ee4f2020-05-14 14:14:05 -0500424 listlogs)
425 list_logs
426 ;;
Andrew Geisslerd8c63202020-05-14 15:06:31 -0500427 showlog)
428 show_log $2
429 ;;
Andrew Geissler42f28982020-05-14 15:12:42 -0500430 deletelogs)
431 delete_logs
432 ;;
Anthony Wilson79f697e2018-09-13 13:48:52 -0500433 *)
Anthony Wilsonea87db42018-09-26 16:06:38 -0500434 print_usage_err "Invalid command '$1'"
Anthony Wilson79f697e2018-09-13 13:48:52 -0500435 ;;
436 esac
437}
438
Andrew Geisslerd8779cd2020-06-11 10:48:40 -0500439shiftcnt=0
Anthony Wilsonea87db42018-09-26 16:06:38 -0500440for arg in "$@"; do
441 case $arg in
Anthony Wilsonacf54d02018-09-20 15:19:28 -0500442 -w|--wait)
443 G_WAIT=30
Andrew Geisslerd8779cd2020-06-11 10:48:40 -0500444 shiftcnt=$((shiftcnt+1))
Anthony Wilsonacf54d02018-09-20 15:19:28 -0500445 continue
446 ;;
Anthony Wilsonea87db42018-09-26 16:06:38 -0500447 -h|--help)
448 print_help
449 ;;
Andrew Jeffery60c3ac82019-10-02 09:29:29 +0930450 -v|--verbose)
451 G_VERBOSE=y
Andrew Geisslerd8779cd2020-06-11 10:48:40 -0500452 shiftcnt=$((shiftcnt+1))
Andrew Jeffery60c3ac82019-10-02 09:29:29 +0930453 ;;
Anthony Wilsonea87db42018-09-26 16:06:38 -0500454 -*)
455 print_usage_err "Unknown option: $arg"
456 ;;
457 *)
Anthony Wilsonacf54d02018-09-20 15:19:28 -0500458 G_ORIG_CMD=$arg
Andrew Geisslerd8779cd2020-06-11 10:48:40 -0500459 # shift out the optional parameters
460 shift $shiftcnt
Andrew Geisslerd8c63202020-05-14 15:06:31 -0500461 # pass all arguments to handle_cmd in case command takes additional
462 # parameters
463 handle_cmd "$@"
Anthony Wilsonea87db42018-09-26 16:06:38 -0500464 break
465 ;;
466 esac
467done