blob: 1741d9d6d928cb0bea58a8488a18622bc3890b0c [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 Geissler295ee4f2020-05-14 14:14:05 -05007bmcrebootoff, bmcrebooton, listbootblock listlogs"
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 ""
Anthony Wilsonf3f16fa2018-09-13 14:10:52 -050069 echo "optional arguments:"
70 echo " -h, --help show this help message and exit"
Anthony Wilsonacf54d02018-09-20 15:19:28 -050071 echo " -w, --wait block until state transition succeeds or fails"
Andrew Jeffery60c3ac82019-10-02 09:29:29 +093072 echo " -v, --verbose print the journal to stdout if --wait is supplied"
Anthony Wilsonf3f16fa2018-09-13 14:10:52 -050073 exit 0
74}
75
Anthony Wilsonacf54d02018-09-20 15:19:28 -050076run_timeout ()
77{
78 local timeout="$1"; shift
79 local cmd="$@"
Andrew Jeffery60c3ac82019-10-02 09:29:29 +093080 local verbose_child=
81
Andrew Jeffery2869a922019-10-18 14:42:34 +103082 if [ -n "$G_VERBOSE" ]; then
Andrew Jeffery60c3ac82019-10-02 09:29:29 +093083 journalctl -f &
84 verbose_child=$!
85 fi
Anthony Wilsonacf54d02018-09-20 15:19:28 -050086
87 $cmd
88
89 # Run a background query for the transition to the expected state
90 # This will be killed if the transition doesn't succeed within
91 # a timeout period.
92 (
93 while ! grep -q $G_REQUESTED_STATE <<< $(handle_cmd $G_QUERY) ; do
94 sleep 1
95 done
96 ) &
Andrew Jeffery60c3ac82019-10-02 09:29:29 +093097 wait_child=$!
Anthony Wilsonacf54d02018-09-20 15:19:28 -050098
99 # Could be bad if process is killed before 'timeout' occurs if
100 # transition doesn't succeed.
101 trap -- "" SIGTERM
102
103 # Workaround for lack of 'timeout' command.
104 (
105 sleep $timeout
Andrew Jeffery60c3ac82019-10-02 09:29:29 +0930106 kill $wait_child
Anthony Wilsonacf54d02018-09-20 15:19:28 -0500107 ) > /dev/null 2>&1 &
108
Andrew Jeffery60c3ac82019-10-02 09:29:29 +0930109 if ! wait $wait_child; then
Anthony Wilsonacf54d02018-09-20 15:19:28 -0500110 echo "Unable to confirm '$G_ORIG_CMD' success" \
111 "within timeout period (${timeout}s)"
112 fi
Andrew Jeffery60c3ac82019-10-02 09:29:29 +0930113
Andrew Jeffery8be70292019-11-01 08:56:49 +1030114 if [ -n "$verbose_child" ]; then
Andrew Jeffery60c3ac82019-10-02 09:29:29 +0930115 kill $verbose_child
116 fi
Anthony Wilsonacf54d02018-09-20 15:19:28 -0500117}
118
119run_cmd ()
120{
121 local cmd="$@";
122
123 if [ -n "$G_WAIT" ]; then
124 run_timeout $G_WAIT "$cmd"
125 else
126 $cmd
127 fi
128}
129
Anthony Wilson3ae0a352018-09-13 14:47:56 -0500130set_property ()
131{
Anthony Wilsonacf54d02018-09-20 15:19:28 -0500132 run_cmd busctl set-property "$@"
Anthony Wilson3ae0a352018-09-13 14:47:56 -0500133}
134
Anthony Wilson79f697e2018-09-13 13:48:52 -0500135get_property ()
136{
Anthony Wilsonacf54d02018-09-20 15:19:28 -0500137 G_WAIT=""
138 run_cmd busctl get-property "$@"
Anthony Wilson79f697e2018-09-13 13:48:52 -0500139}
140
141state_query ()
142{
143 local state=$(get_property "$@" | cut -d '"' -f2)
144 printf "%-20s: %s\n" $4 $state
145}
146
Anthony Wilsonea87db42018-09-26 16:06:38 -0500147print_usage_err ()
148{
149 echo "ERROR: $1" >&2
150 echo "$USAGE"
151 exit 1
152}
153
Vishwanatha Subbanna7a787dd2019-10-31 06:02:31 -0500154mask_systemd_target ()
155{
156 target="$@"
157 systemctl mask $target
158}
159
160unmask_systemd_target ()
161{
162 target="$@"
163 systemctl unmask $target
164}
165
Vishwanatha Subbannaa65d30d2019-11-13 01:26:12 -0600166disable_bmc_reboot ()
167{
168 dir="/run/systemd/system/"
169 file="reboot-guard.conf"
170 units=("reboot" "poweroff" "halt")
171
172 for unit in "${units[@]}"; do
173 mkdir -p ${dir}${unit}.target.d
174 echo -e "[Unit]\nRefuseManualStart=yes" >> ${dir}${unit}.target.d/${file}
175 done
176}
177
178enable_bmc_reboot ()
179{
180 dir="/run/systemd/system/"
181 file="reboot-guard.conf"
182 units=("reboot" "poweroff" "halt")
183
184 for unit in "${units[@]}"; do
185 rm -rf ${dir}${unit}.target.d/${file}
186 rm -rf ${dir}${unit}.target.d
187 done
188}
189
Andrew Geissler3b7b5612020-05-14 10:45:29 -0500190# will write blocking errors to stdout
191check_boot_block_errors ()
192{
193 # array of boot block objects
194 blockArray=()
195
196 # Look for any objects under logging that implement the
197 # xyz.openbmc_project.Logging.ErrorBlocksTransition
198 subtree="$(busctl call xyz.openbmc_project.ObjectMapper \
199 /xyz/openbmc_project/object_mapper \
200 xyz.openbmc_project.ObjectMapper \
201 GetSubTree sias "/xyz/openbmc_project/logging/" 0 1 \
202 xyz.openbmc_project.Logging.ErrorBlocksTransition)"
203
204 # remove quotation marks
205 subtree="$(echo $subtree | sed 's/\"//g')"
206
207 for entry in $subtree; do
208 if [[ ${entry} =~ "xyz/openbmc_project/logging/block"* ]]; then
209 blockArray+=( $entry )
210 fi
211 done
212
213 # now find associated error log for each boot block error
214 for berror in "${blockArray[@]}"; do
215 assocs="$(busctl call xyz.openbmc_project.Logging $berror \
216 org.freedesktop.DBus.Properties Get \
217 ss xyz.openbmc_project.Association.Definitions Associations)"
218
219 # remove quotation marks
220 assocs="$(echo $assocs | sed 's/\"//g')"
221
222 for entry in $assocs; do
223 if [[ ${entry} =~ "xyz/openbmc_project/logging/entry"* ]]; then
224 echo "Blocking Error: $entry"
225 fi
226 done
227 done
228}
229
Andrew Geisslerdeb6bb42020-05-14 13:44:57 -0500230# helper function to check for boot block errors and notify user
231check_and_warn_boot_block()
232{
233 blockingErrors=$(check_boot_block_errors)
234 if ! [ -z "$blockingErrors" ]; then
235 echo !!!!!!!!!!
236 echo "WARNING! System has blocking errors that will prevent boot"
237 echo "$blockingErrors"
238 echo !!!!!!!!!!
239 fi
240}
241
Andrew Geissler295ee4f2020-05-14 14:14:05 -0500242# list all phosphor-logging entries
243list_logs()
244{
245 # Look for any objects under logging that implement the
246 # xyz.openbmc_project.Logging.Entry
247 busctl -j call xyz.openbmc_project.ObjectMapper \
248 /xyz/openbmc_project/object_mapper \
249 xyz.openbmc_project.ObjectMapper \
250 GetSubTreePaths sias "/xyz/openbmc_project/logging/" 0 1 \
251 xyz.openbmc_project.Logging.Entry
252}
253
Anthony Wilson79f697e2018-09-13 13:48:52 -0500254handle_cmd ()
255{
256 case "$1" in
Anthony Wilson3ae0a352018-09-13 14:47:56 -0500257 chassisoff)
258 OBJECT=$STATE_OBJECT/chassis0
259 SERVICE=$(mapper get-service $OBJECT)
260 INTERFACE=$STATE_INTERFACE.Chassis
261 PROPERTY=RequestedPowerTransition
262 VALUE=$INTERFACE.Transition.Off
Anthony Wilsonacf54d02018-09-20 15:19:28 -0500263 G_REQUESTED_STATE=$INTERFACE.PowerState.Off
264 G_QUERY="chassisstate"
Anthony Wilson3ae0a352018-09-13 14:47:56 -0500265 set_property $SERVICE $OBJECT $INTERFACE $PROPERTY "s" $VALUE
266 ;;
267 chassison)
Andrew Geisslerdeb6bb42020-05-14 13:44:57 -0500268 check_and_warn_boot_block
Anthony Wilson3ae0a352018-09-13 14:47:56 -0500269 OBJECT=$STATE_OBJECT/chassis0
270 SERVICE=$(mapper get-service $OBJECT)
271 INTERFACE=$STATE_INTERFACE.Chassis
272 PROPERTY=RequestedPowerTransition
273 VALUE=$INTERFACE.Transition.On
Anthony Wilsonacf54d02018-09-20 15:19:28 -0500274 G_REQUESTED_STATE=$INTERFACE.PowerState.On
275 G_QUERY="chassisstate"
Anthony Wilson3ae0a352018-09-13 14:47:56 -0500276 set_property $SERVICE $OBJECT $INTERFACE $PROPERTY "s" $VALUE
277 ;;
278 poweroff)
279 OBJECT=$STATE_OBJECT/host0
280 SERVICE=$(mapper get-service $OBJECT)
281 INTERFACE=$STATE_INTERFACE.Host
282 PROPERTY=RequestedHostTransition
283 VALUE=$INTERFACE.Transition.Off
Anthony Wilsonacf54d02018-09-20 15:19:28 -0500284 G_REQUESTED_STATE=$INTERFACE.HostState.Off
285 G_QUERY="hoststate"
Anthony Wilson3ae0a352018-09-13 14:47:56 -0500286 set_property $SERVICE $OBJECT $INTERFACE $PROPERTY "s" $VALUE
287 ;;
288 poweron)
Andrew Geisslerdeb6bb42020-05-14 13:44:57 -0500289 check_and_warn_boot_block
Anthony Wilson3ae0a352018-09-13 14:47:56 -0500290 OBJECT=$STATE_OBJECT/host0
291 SERVICE=$(mapper get-service $OBJECT)
292 INTERFACE=$STATE_INTERFACE.Host
293 PROPERTY=RequestedHostTransition
294 VALUE=$INTERFACE.Transition.On
Anthony Wilsonacf54d02018-09-20 15:19:28 -0500295 G_REQUESTED_STATE=$INTERFACE.HostState.Running
296 G_QUERY="hoststate"
Anthony Wilson3ae0a352018-09-13 14:47:56 -0500297 set_property $SERVICE $OBJECT $INTERFACE $PROPERTY "s" $VALUE
298 ;;
Anthony Wilson79f697e2018-09-13 13:48:52 -0500299 bmcstate)
300 OBJECT=$STATE_OBJECT/bmc0
301 SERVICE=$(mapper get-service $OBJECT)
302 INTERFACE=$STATE_INTERFACE.BMC
303 PROPERTY=CurrentBMCState
304 state_query $SERVICE $OBJECT $INTERFACE $PROPERTY
305 ;;
306 chassisstate)
307 OBJECT=$STATE_OBJECT/chassis0
308 SERVICE=$(mapper get-service $OBJECT)
309 INTERFACE=$STATE_INTERFACE.Chassis
310 PROPERTY=CurrentPowerState
311 state_query $SERVICE $OBJECT $INTERFACE $PROPERTY
312 ;;
313 hoststate)
314 OBJECT=$STATE_OBJECT/host0
315 SERVICE=$(mapper get-service $OBJECT)
316 INTERFACE=$STATE_INTERFACE.Host
317 PROPERTY=CurrentHostState
318 state_query $SERVICE $OBJECT $INTERFACE $PROPERTY
319 ;;
Alexander Filippov86cffd92019-04-03 16:29:57 +0300320 osstate)
321 OBJECT=$STATE_OBJECT/host0
322 SERVICE=$(mapper get-service $OBJECT)
323 INTERFACE=$STATE_INTERFACE.OperatingSystem.Status
324 PROPERTY=OperatingSystemState
325 state_query $SERVICE $OBJECT $INTERFACE $PROPERTY
326 ;;
Anthony Wilson79f697e2018-09-13 13:48:52 -0500327 state|status)
Alexander Filippov86cffd92019-04-03 16:29:57 +0300328 for query in bmcstate chassisstate hoststate bootprogress osstate
Anthony Wilson79f697e2018-09-13 13:48:52 -0500329 do
330 handle_cmd $query
331 done
Andrew Geisslerdeb6bb42020-05-14 13:44:57 -0500332 check_and_warn_boot_block
Anthony Wilson79f697e2018-09-13 13:48:52 -0500333 ;;
Anthony Wilson50c5f882018-09-13 14:19:37 -0500334 bootprogress)
335 OBJECT=$STATE_OBJECT/host0
336 SERVICE=$(mapper get-service $OBJECT)
337 INTERFACE=$STATE_INTERFACE.Boot.Progress
338 PROPERTY=BootProgress
339 state_query $SERVICE $OBJECT $INTERFACE $PROPERTY
340 ;;
Anthony Wilson0f359832018-09-13 14:28:07 -0500341 power)
342 OBJECT=/org/openbmc/control/power0
343 SERVICE=$(mapper get-service $OBJECT)
344 INTERFACE=org.openbmc.control.Power
345 for property in pgood state pgood_timeout
346 do
347 # get_property can potentially return several
348 # different formats of values, so we do the parsing outside
349 # of get_property depending on the query. These queries
350 # return 'i VALUE' formatted strings.
351 STATE=$(get_property $SERVICE $OBJECT $INTERFACE $property \
352 | sed 's/i[ ^I]*//')
353 printf "%s = %s\n" $property $STATE
354 done
355 ;;
Anthony Wilson189cf242018-10-23 01:18:21 -0500356 chassiskill)
357 /usr/libexec/chassiskill
358 ;;
Vishwanatha Subbannaa65d30d2019-11-13 01:26:12 -0600359 hostrebootoff)
Vishwanatha Subbanna6d3a2c52019-10-24 07:21:30 -0500360 OBJECT=$CONTROL_OBJECT/host0/auto_reboot
361 SERVICE=$(mapper get-service $OBJECT)
362 INTERFACE=$CONTROL_INTERFACE.Boot.RebootPolicy
363 PROPERTY=AutoReboot
364 VALUE=false
365 set_property $SERVICE $OBJECT $INTERFACE $PROPERTY "b" $VALUE
366 ;;
Vishwanatha Subbannaa65d30d2019-11-13 01:26:12 -0600367 hostrebooton)
Vishwanatha Subbanna6d3a2c52019-10-24 07:21:30 -0500368 OBJECT=$CONTROL_OBJECT/host0/auto_reboot
369 SERVICE=$(mapper get-service $OBJECT)
370 INTERFACE=$CONTROL_INTERFACE.Boot.RebootPolicy
371 PROPERTY=AutoReboot
372 VALUE=true
373 set_property $SERVICE $OBJECT $INTERFACE $PROPERTY "b" $VALUE
374 ;;
Vishwanatha Subbannaa65d30d2019-11-13 01:26:12 -0600375 bmcrebootoff)
376 disable_bmc_reboot
377 ;;
378 bmcrebooton)
379 enable_bmc_reboot
380 ;;
Vishwanatha Subbanna7a787dd2019-10-31 06:02:31 -0500381 recoveryoff)
Vishwanatha Subbannaa65d30d2019-11-13 01:26:12 -0600382 handle_cmd hostrebootoff
383 handle_cmd bmcrebootoff
Vishwanatha Subbanna7a787dd2019-10-31 06:02:31 -0500384 mask_systemd_target $HOST_TIMEOUT_TARGET
Vishwanatha Subbanna84b3b292019-11-04 05:43:19 -0600385 mask_systemd_target $HOST_CRASH_TARGET
Vishwanatha Subbanna7a787dd2019-10-31 06:02:31 -0500386 ;;
387 recoveryon)
Vishwanatha Subbannaa65d30d2019-11-13 01:26:12 -0600388 handle_cmd hostrebooton
389 handle_cmd bmcrebooton
Vishwanatha Subbanna7a787dd2019-10-31 06:02:31 -0500390 unmask_systemd_target $HOST_TIMEOUT_TARGET
Vishwanatha Subbanna84b3b292019-11-04 05:43:19 -0600391 unmask_systemd_target $HOST_CRASH_TARGET
Vishwanatha Subbanna7a787dd2019-10-31 06:02:31 -0500392 ;;
Andrew Geissler3b7b5612020-05-14 10:45:29 -0500393 listbootblock)
394 blockingErrors=$(check_boot_block_errors)
395 if [ -z "$blockingErrors" ]; then
396 echo "No blocking errors present"
397 else
398 echo "$blockingErrors"
399 fi
400 ;;
Andrew Geissler295ee4f2020-05-14 14:14:05 -0500401 listlogs)
402 list_logs
403 ;;
Anthony Wilson79f697e2018-09-13 13:48:52 -0500404 *)
Anthony Wilsonea87db42018-09-26 16:06:38 -0500405 print_usage_err "Invalid command '$1'"
Anthony Wilson79f697e2018-09-13 13:48:52 -0500406 ;;
407 esac
408}
409
Anthony Wilsonea87db42018-09-26 16:06:38 -0500410for arg in "$@"; do
411 case $arg in
Anthony Wilsonacf54d02018-09-20 15:19:28 -0500412 -w|--wait)
413 G_WAIT=30
414 continue
415 ;;
Anthony Wilsonea87db42018-09-26 16:06:38 -0500416 -h|--help)
417 print_help
418 ;;
Andrew Jeffery60c3ac82019-10-02 09:29:29 +0930419 -v|--verbose)
420 G_VERBOSE=y
421 ;;
Anthony Wilsonea87db42018-09-26 16:06:38 -0500422 -*)
423 print_usage_err "Unknown option: $arg"
424 ;;
425 *)
Anthony Wilsonacf54d02018-09-20 15:19:28 -0500426 G_ORIG_CMD=$arg
Anthony Wilsonea87db42018-09-26 16:06:38 -0500427 handle_cmd $arg
428 break
429 ;;
430 esac
431done