blob: 016cfa24262012899cefaa25610b158321ae635b [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 Geisslerd8c63202020-05-14 15:06:31 -05007bmcrebootoff, bmcrebooton, listbootblock listlogs showlog"
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 ""
Anthony Wilsonf3f16fa2018-09-13 14:10:52 -050072 echo "optional arguments:"
73 echo " -h, --help show this help message and exit"
Anthony Wilsonacf54d02018-09-20 15:19:28 -050074 echo " -w, --wait block until state transition succeeds or fails"
Andrew Jeffery60c3ac82019-10-02 09:29:29 +093075 echo " -v, --verbose print the journal to stdout if --wait is supplied"
Anthony Wilsonf3f16fa2018-09-13 14:10:52 -050076 exit 0
77}
78
Anthony Wilsonacf54d02018-09-20 15:19:28 -050079run_timeout ()
80{
81 local timeout="$1"; shift
82 local cmd="$@"
Andrew Jeffery60c3ac82019-10-02 09:29:29 +093083 local verbose_child=
84
Andrew Jeffery2869a922019-10-18 14:42:34 +103085 if [ -n "$G_VERBOSE" ]; then
Andrew Jeffery60c3ac82019-10-02 09:29:29 +093086 journalctl -f &
87 verbose_child=$!
88 fi
Anthony Wilsonacf54d02018-09-20 15:19:28 -050089
90 $cmd
91
92 # Run a background query for the transition to the expected state
93 # This will be killed if the transition doesn't succeed within
94 # a timeout period.
95 (
96 while ! grep -q $G_REQUESTED_STATE <<< $(handle_cmd $G_QUERY) ; do
97 sleep 1
98 done
99 ) &
Andrew Jeffery60c3ac82019-10-02 09:29:29 +0930100 wait_child=$!
Anthony Wilsonacf54d02018-09-20 15:19:28 -0500101
102 # Could be bad if process is killed before 'timeout' occurs if
103 # transition doesn't succeed.
104 trap -- "" SIGTERM
105
106 # Workaround for lack of 'timeout' command.
107 (
108 sleep $timeout
Andrew Jeffery60c3ac82019-10-02 09:29:29 +0930109 kill $wait_child
Anthony Wilsonacf54d02018-09-20 15:19:28 -0500110 ) > /dev/null 2>&1 &
111
Andrew Jeffery60c3ac82019-10-02 09:29:29 +0930112 if ! wait $wait_child; then
Anthony Wilsonacf54d02018-09-20 15:19:28 -0500113 echo "Unable to confirm '$G_ORIG_CMD' success" \
114 "within timeout period (${timeout}s)"
115 fi
Andrew Jeffery60c3ac82019-10-02 09:29:29 +0930116
Andrew Jeffery8be70292019-11-01 08:56:49 +1030117 if [ -n "$verbose_child" ]; then
Andrew Jeffery60c3ac82019-10-02 09:29:29 +0930118 kill $verbose_child
119 fi
Anthony Wilsonacf54d02018-09-20 15:19:28 -0500120}
121
122run_cmd ()
123{
124 local cmd="$@";
125
126 if [ -n "$G_WAIT" ]; then
127 run_timeout $G_WAIT "$cmd"
128 else
129 $cmd
130 fi
131}
132
Anthony Wilson3ae0a352018-09-13 14:47:56 -0500133set_property ()
134{
Anthony Wilsonacf54d02018-09-20 15:19:28 -0500135 run_cmd busctl set-property "$@"
Anthony Wilson3ae0a352018-09-13 14:47:56 -0500136}
137
Anthony Wilson79f697e2018-09-13 13:48:52 -0500138get_property ()
139{
Anthony Wilsonacf54d02018-09-20 15:19:28 -0500140 G_WAIT=""
141 run_cmd busctl get-property "$@"
Anthony Wilson79f697e2018-09-13 13:48:52 -0500142}
143
144state_query ()
145{
146 local state=$(get_property "$@" | cut -d '"' -f2)
147 printf "%-20s: %s\n" $4 $state
148}
149
Anthony Wilsonea87db42018-09-26 16:06:38 -0500150print_usage_err ()
151{
152 echo "ERROR: $1" >&2
153 echo "$USAGE"
154 exit 1
155}
156
Vishwanatha Subbanna7a787dd2019-10-31 06:02:31 -0500157mask_systemd_target ()
158{
159 target="$@"
160 systemctl mask $target
161}
162
163unmask_systemd_target ()
164{
165 target="$@"
166 systemctl unmask $target
167}
168
Vishwanatha Subbannaa65d30d2019-11-13 01:26:12 -0600169disable_bmc_reboot ()
170{
171 dir="/run/systemd/system/"
172 file="reboot-guard.conf"
173 units=("reboot" "poweroff" "halt")
174
175 for unit in "${units[@]}"; do
176 mkdir -p ${dir}${unit}.target.d
177 echo -e "[Unit]\nRefuseManualStart=yes" >> ${dir}${unit}.target.d/${file}
178 done
179}
180
181enable_bmc_reboot ()
182{
183 dir="/run/systemd/system/"
184 file="reboot-guard.conf"
185 units=("reboot" "poweroff" "halt")
186
187 for unit in "${units[@]}"; do
188 rm -rf ${dir}${unit}.target.d/${file}
189 rm -rf ${dir}${unit}.target.d
190 done
191}
192
Andrew Geissler3b7b5612020-05-14 10:45:29 -0500193# will write blocking errors to stdout
194check_boot_block_errors ()
195{
196 # array of boot block objects
197 blockArray=()
198
199 # Look for any objects under logging that implement the
200 # xyz.openbmc_project.Logging.ErrorBlocksTransition
201 subtree="$(busctl call xyz.openbmc_project.ObjectMapper \
202 /xyz/openbmc_project/object_mapper \
203 xyz.openbmc_project.ObjectMapper \
204 GetSubTree sias "/xyz/openbmc_project/logging/" 0 1 \
205 xyz.openbmc_project.Logging.ErrorBlocksTransition)"
206
207 # remove quotation marks
208 subtree="$(echo $subtree | sed 's/\"//g')"
209
210 for entry in $subtree; do
211 if [[ ${entry} =~ "xyz/openbmc_project/logging/block"* ]]; then
212 blockArray+=( $entry )
213 fi
214 done
215
216 # now find associated error log for each boot block error
217 for berror in "${blockArray[@]}"; do
218 assocs="$(busctl call xyz.openbmc_project.Logging $berror \
219 org.freedesktop.DBus.Properties Get \
220 ss xyz.openbmc_project.Association.Definitions Associations)"
221
222 # remove quotation marks
223 assocs="$(echo $assocs | sed 's/\"//g')"
224
225 for entry in $assocs; do
226 if [[ ${entry} =~ "xyz/openbmc_project/logging/entry"* ]]; then
227 echo "Blocking Error: $entry"
228 fi
229 done
230 done
231}
232
Andrew Geisslerdeb6bb42020-05-14 13:44:57 -0500233# helper function to check for boot block errors and notify user
234check_and_warn_boot_block()
235{
236 blockingErrors=$(check_boot_block_errors)
237 if ! [ -z "$blockingErrors" ]; then
238 echo !!!!!!!!!!
239 echo "WARNING! System has blocking errors that will prevent boot"
240 echo "$blockingErrors"
241 echo !!!!!!!!!!
242 fi
243}
244
Andrew Geissler295ee4f2020-05-14 14:14:05 -0500245# list all phosphor-logging entries
246list_logs()
247{
248 # Look for any objects under logging that implement the
249 # xyz.openbmc_project.Logging.Entry
250 busctl -j call xyz.openbmc_project.ObjectMapper \
251 /xyz/openbmc_project/object_mapper \
252 xyz.openbmc_project.ObjectMapper \
253 GetSubTreePaths sias "/xyz/openbmc_project/logging/" 0 1 \
254 xyz.openbmc_project.Logging.Entry
255}
256
Andrew Geisslerd8c63202020-05-14 15:06:31 -0500257# display input log details
258show_log()
259{
260 busctl -j call xyz.openbmc_project.Logging \
261 $1 \
262 org.freedesktop.DBus.Properties \
263 GetAll s xyz.openbmc_project.Logging.Entry
264}
265
Anthony Wilson79f697e2018-09-13 13:48:52 -0500266handle_cmd ()
267{
268 case "$1" in
Anthony Wilson3ae0a352018-09-13 14:47:56 -0500269 chassisoff)
270 OBJECT=$STATE_OBJECT/chassis0
271 SERVICE=$(mapper get-service $OBJECT)
272 INTERFACE=$STATE_INTERFACE.Chassis
273 PROPERTY=RequestedPowerTransition
274 VALUE=$INTERFACE.Transition.Off
Anthony Wilsonacf54d02018-09-20 15:19:28 -0500275 G_REQUESTED_STATE=$INTERFACE.PowerState.Off
276 G_QUERY="chassisstate"
Anthony Wilson3ae0a352018-09-13 14:47:56 -0500277 set_property $SERVICE $OBJECT $INTERFACE $PROPERTY "s" $VALUE
278 ;;
279 chassison)
Andrew Geisslerdeb6bb42020-05-14 13:44:57 -0500280 check_and_warn_boot_block
Anthony Wilson3ae0a352018-09-13 14:47:56 -0500281 OBJECT=$STATE_OBJECT/chassis0
282 SERVICE=$(mapper get-service $OBJECT)
283 INTERFACE=$STATE_INTERFACE.Chassis
284 PROPERTY=RequestedPowerTransition
285 VALUE=$INTERFACE.Transition.On
Anthony Wilsonacf54d02018-09-20 15:19:28 -0500286 G_REQUESTED_STATE=$INTERFACE.PowerState.On
287 G_QUERY="chassisstate"
Anthony Wilson3ae0a352018-09-13 14:47:56 -0500288 set_property $SERVICE $OBJECT $INTERFACE $PROPERTY "s" $VALUE
289 ;;
290 poweroff)
291 OBJECT=$STATE_OBJECT/host0
292 SERVICE=$(mapper get-service $OBJECT)
293 INTERFACE=$STATE_INTERFACE.Host
294 PROPERTY=RequestedHostTransition
295 VALUE=$INTERFACE.Transition.Off
Anthony Wilsonacf54d02018-09-20 15:19:28 -0500296 G_REQUESTED_STATE=$INTERFACE.HostState.Off
297 G_QUERY="hoststate"
Anthony Wilson3ae0a352018-09-13 14:47:56 -0500298 set_property $SERVICE $OBJECT $INTERFACE $PROPERTY "s" $VALUE
299 ;;
300 poweron)
Andrew Geisslerdeb6bb42020-05-14 13:44:57 -0500301 check_and_warn_boot_block
Anthony Wilson3ae0a352018-09-13 14:47:56 -0500302 OBJECT=$STATE_OBJECT/host0
303 SERVICE=$(mapper get-service $OBJECT)
304 INTERFACE=$STATE_INTERFACE.Host
305 PROPERTY=RequestedHostTransition
306 VALUE=$INTERFACE.Transition.On
Anthony Wilsonacf54d02018-09-20 15:19:28 -0500307 G_REQUESTED_STATE=$INTERFACE.HostState.Running
308 G_QUERY="hoststate"
Anthony Wilson3ae0a352018-09-13 14:47:56 -0500309 set_property $SERVICE $OBJECT $INTERFACE $PROPERTY "s" $VALUE
310 ;;
Anthony Wilson79f697e2018-09-13 13:48:52 -0500311 bmcstate)
312 OBJECT=$STATE_OBJECT/bmc0
313 SERVICE=$(mapper get-service $OBJECT)
314 INTERFACE=$STATE_INTERFACE.BMC
315 PROPERTY=CurrentBMCState
316 state_query $SERVICE $OBJECT $INTERFACE $PROPERTY
317 ;;
318 chassisstate)
319 OBJECT=$STATE_OBJECT/chassis0
320 SERVICE=$(mapper get-service $OBJECT)
321 INTERFACE=$STATE_INTERFACE.Chassis
322 PROPERTY=CurrentPowerState
323 state_query $SERVICE $OBJECT $INTERFACE $PROPERTY
324 ;;
325 hoststate)
326 OBJECT=$STATE_OBJECT/host0
327 SERVICE=$(mapper get-service $OBJECT)
328 INTERFACE=$STATE_INTERFACE.Host
329 PROPERTY=CurrentHostState
330 state_query $SERVICE $OBJECT $INTERFACE $PROPERTY
331 ;;
Alexander Filippov86cffd92019-04-03 16:29:57 +0300332 osstate)
333 OBJECT=$STATE_OBJECT/host0
334 SERVICE=$(mapper get-service $OBJECT)
335 INTERFACE=$STATE_INTERFACE.OperatingSystem.Status
336 PROPERTY=OperatingSystemState
337 state_query $SERVICE $OBJECT $INTERFACE $PROPERTY
338 ;;
Anthony Wilson79f697e2018-09-13 13:48:52 -0500339 state|status)
Alexander Filippov86cffd92019-04-03 16:29:57 +0300340 for query in bmcstate chassisstate hoststate bootprogress osstate
Anthony Wilson79f697e2018-09-13 13:48:52 -0500341 do
342 handle_cmd $query
343 done
Andrew Geisslerdeb6bb42020-05-14 13:44:57 -0500344 check_and_warn_boot_block
Anthony Wilson79f697e2018-09-13 13:48:52 -0500345 ;;
Anthony Wilson50c5f882018-09-13 14:19:37 -0500346 bootprogress)
347 OBJECT=$STATE_OBJECT/host0
348 SERVICE=$(mapper get-service $OBJECT)
349 INTERFACE=$STATE_INTERFACE.Boot.Progress
350 PROPERTY=BootProgress
351 state_query $SERVICE $OBJECT $INTERFACE $PROPERTY
352 ;;
Anthony Wilson0f359832018-09-13 14:28:07 -0500353 power)
354 OBJECT=/org/openbmc/control/power0
355 SERVICE=$(mapper get-service $OBJECT)
356 INTERFACE=org.openbmc.control.Power
357 for property in pgood state pgood_timeout
358 do
359 # get_property can potentially return several
360 # different formats of values, so we do the parsing outside
361 # of get_property depending on the query. These queries
362 # return 'i VALUE' formatted strings.
363 STATE=$(get_property $SERVICE $OBJECT $INTERFACE $property \
364 | sed 's/i[ ^I]*//')
365 printf "%s = %s\n" $property $STATE
366 done
367 ;;
Anthony Wilson189cf242018-10-23 01:18:21 -0500368 chassiskill)
369 /usr/libexec/chassiskill
370 ;;
Vishwanatha Subbannaa65d30d2019-11-13 01:26:12 -0600371 hostrebootoff)
Vishwanatha Subbanna6d3a2c52019-10-24 07:21:30 -0500372 OBJECT=$CONTROL_OBJECT/host0/auto_reboot
373 SERVICE=$(mapper get-service $OBJECT)
374 INTERFACE=$CONTROL_INTERFACE.Boot.RebootPolicy
375 PROPERTY=AutoReboot
376 VALUE=false
377 set_property $SERVICE $OBJECT $INTERFACE $PROPERTY "b" $VALUE
378 ;;
Vishwanatha Subbannaa65d30d2019-11-13 01:26:12 -0600379 hostrebooton)
Vishwanatha Subbanna6d3a2c52019-10-24 07:21:30 -0500380 OBJECT=$CONTROL_OBJECT/host0/auto_reboot
381 SERVICE=$(mapper get-service $OBJECT)
382 INTERFACE=$CONTROL_INTERFACE.Boot.RebootPolicy
383 PROPERTY=AutoReboot
384 VALUE=true
385 set_property $SERVICE $OBJECT $INTERFACE $PROPERTY "b" $VALUE
386 ;;
Vishwanatha Subbannaa65d30d2019-11-13 01:26:12 -0600387 bmcrebootoff)
388 disable_bmc_reboot
389 ;;
390 bmcrebooton)
391 enable_bmc_reboot
392 ;;
Vishwanatha Subbanna7a787dd2019-10-31 06:02:31 -0500393 recoveryoff)
Vishwanatha Subbannaa65d30d2019-11-13 01:26:12 -0600394 handle_cmd hostrebootoff
395 handle_cmd bmcrebootoff
Vishwanatha Subbanna7a787dd2019-10-31 06:02:31 -0500396 mask_systemd_target $HOST_TIMEOUT_TARGET
Vishwanatha Subbanna84b3b292019-11-04 05:43:19 -0600397 mask_systemd_target $HOST_CRASH_TARGET
Vishwanatha Subbanna7a787dd2019-10-31 06:02:31 -0500398 ;;
399 recoveryon)
Vishwanatha Subbannaa65d30d2019-11-13 01:26:12 -0600400 handle_cmd hostrebooton
401 handle_cmd bmcrebooton
Vishwanatha Subbanna7a787dd2019-10-31 06:02:31 -0500402 unmask_systemd_target $HOST_TIMEOUT_TARGET
Vishwanatha Subbanna84b3b292019-11-04 05:43:19 -0600403 unmask_systemd_target $HOST_CRASH_TARGET
Vishwanatha Subbanna7a787dd2019-10-31 06:02:31 -0500404 ;;
Andrew Geissler3b7b5612020-05-14 10:45:29 -0500405 listbootblock)
406 blockingErrors=$(check_boot_block_errors)
407 if [ -z "$blockingErrors" ]; then
408 echo "No blocking errors present"
409 else
410 echo "$blockingErrors"
411 fi
412 ;;
Andrew Geissler295ee4f2020-05-14 14:14:05 -0500413 listlogs)
414 list_logs
415 ;;
Andrew Geisslerd8c63202020-05-14 15:06:31 -0500416 showlog)
417 show_log $2
418 ;;
Anthony Wilson79f697e2018-09-13 13:48:52 -0500419 *)
Anthony Wilsonea87db42018-09-26 16:06:38 -0500420 print_usage_err "Invalid command '$1'"
Anthony Wilson79f697e2018-09-13 13:48:52 -0500421 ;;
422 esac
423}
424
Anthony Wilsonea87db42018-09-26 16:06:38 -0500425for arg in "$@"; do
426 case $arg in
Anthony Wilsonacf54d02018-09-20 15:19:28 -0500427 -w|--wait)
428 G_WAIT=30
429 continue
430 ;;
Anthony Wilsonea87db42018-09-26 16:06:38 -0500431 -h|--help)
432 print_help
433 ;;
Andrew Jeffery60c3ac82019-10-02 09:29:29 +0930434 -v|--verbose)
435 G_VERBOSE=y
436 ;;
Anthony Wilsonea87db42018-09-26 16:06:38 -0500437 -*)
438 print_usage_err "Unknown option: $arg"
439 ;;
440 *)
Anthony Wilsonacf54d02018-09-20 15:19:28 -0500441 G_ORIG_CMD=$arg
Andrew Geisslerd8c63202020-05-14 15:06:31 -0500442 # pass all arguments to handle_cmd in case command takes additional
443 # parameters
444 handle_cmd "$@"
Anthony Wilsonea87db42018-09-26 16:06:38 -0500445 break
446 ;;
447 esac
448done