blob: d8463d54fe62b05840dff3425b4ce00ad6aeae3a [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,\
Alexander Filippov86cffd92019-04-03 16:29:57 +03006osstate,power,poweroff,poweron,state,status"
Anthony Wilson0f359832018-09-13 14:28:07 -05007
Andrew Jeffery60c3ac82019-10-02 09:29:29 +09308USAGE="Usage: obmcutil [-h] [--wait] [--verbose]
Anthony Wilson0f359832018-09-13 14:28:07 -05009 {$OPTS}"
Anthony Wilson79f697e2018-09-13 13:48:52 -050010
11INTERFACE_ROOT=xyz.openbmc_project
12STATE_INTERFACE=$INTERFACE_ROOT.State
13
14OBJECT_ROOT=/xyz/openbmc_project
15STATE_OBJECT=$OBJECT_ROOT/state
16
Anthony Wilsonacf54d02018-09-20 15:19:28 -050017## NOTE: The following global variables are used only in the run_timeout cmd.
18## By declaring these globally instead of passing them through the
19## intermediary functions, which may not be "best practice", the readability
20## and cleanliness of the code should at least be increased.
21
22# The command passed in to be executed (e.g. poweron/off, status, etc.)
23# This will be be used in some instances of error reporting
24G_ORIG_CMD=
25# The state an interface should be in after executing the requested command.
26G_REQUESTED_STATE=
27# The query to run during a poweron/off or chassison/off to check that
28# the requested state (G_REQUESTED_STATE) of the interface has been reached.
29G_QUERY=
30# Wait the set period of time for state transitions to be successful before
31# continuing on with the program or reporting an error if timeout reached.
32G_WAIT=
Andrew Jeffery60c3ac82019-10-02 09:29:29 +093033# Print the journal to the console
34G_VERBOSE=
Anthony Wilsonacf54d02018-09-20 15:19:28 -050035
Anthony Wilsonf3f16fa2018-09-13 14:10:52 -050036print_help ()
37{
38 echo "$USAGE"
39 echo ""
40 echo "positional arguments:"
Anthony Wilson0f359832018-09-13 14:28:07 -050041 echo " {$OPTS}"
Anthony Wilsonf3f16fa2018-09-13 14:10:52 -050042 echo ""
43 echo "optional arguments:"
44 echo " -h, --help show this help message and exit"
Anthony Wilsonacf54d02018-09-20 15:19:28 -050045 echo " -w, --wait block until state transition succeeds or fails"
Andrew Jeffery60c3ac82019-10-02 09:29:29 +093046 echo " -v, --verbose print the journal to stdout if --wait is supplied"
Anthony Wilsonf3f16fa2018-09-13 14:10:52 -050047 exit 0
48}
49
Anthony Wilsonacf54d02018-09-20 15:19:28 -050050run_timeout ()
51{
52 local timeout="$1"; shift
53 local cmd="$@"
Andrew Jeffery60c3ac82019-10-02 09:29:29 +093054 local verbose_child=
55
56 if [ -n $G_VERBOSE ]; then
57 journalctl -f &
58 verbose_child=$!
59 fi
Anthony Wilsonacf54d02018-09-20 15:19:28 -050060
61 $cmd
62
63 # Run a background query for the transition to the expected state
64 # This will be killed if the transition doesn't succeed within
65 # a timeout period.
66 (
67 while ! grep -q $G_REQUESTED_STATE <<< $(handle_cmd $G_QUERY) ; do
68 sleep 1
69 done
70 ) &
Andrew Jeffery60c3ac82019-10-02 09:29:29 +093071 wait_child=$!
Anthony Wilsonacf54d02018-09-20 15:19:28 -050072
73 # Could be bad if process is killed before 'timeout' occurs if
74 # transition doesn't succeed.
75 trap -- "" SIGTERM
76
77 # Workaround for lack of 'timeout' command.
78 (
79 sleep $timeout
Andrew Jeffery60c3ac82019-10-02 09:29:29 +093080 kill $wait_child
Anthony Wilsonacf54d02018-09-20 15:19:28 -050081 ) > /dev/null 2>&1 &
82
Andrew Jeffery60c3ac82019-10-02 09:29:29 +093083 if ! wait $wait_child; then
Anthony Wilsonacf54d02018-09-20 15:19:28 -050084 echo "Unable to confirm '$G_ORIG_CMD' success" \
85 "within timeout period (${timeout}s)"
86 fi
Andrew Jeffery60c3ac82019-10-02 09:29:29 +093087
88 if [ -n $verbose_child ]; then
89 kill $verbose_child
90 fi
Anthony Wilsonacf54d02018-09-20 15:19:28 -050091}
92
93run_cmd ()
94{
95 local cmd="$@";
96
97 if [ -n "$G_WAIT" ]; then
98 run_timeout $G_WAIT "$cmd"
99 else
100 $cmd
101 fi
102}
103
Anthony Wilson3ae0a352018-09-13 14:47:56 -0500104set_property ()
105{
Anthony Wilsonacf54d02018-09-20 15:19:28 -0500106 run_cmd busctl set-property "$@"
Anthony Wilson3ae0a352018-09-13 14:47:56 -0500107}
108
Anthony Wilson79f697e2018-09-13 13:48:52 -0500109get_property ()
110{
Anthony Wilsonacf54d02018-09-20 15:19:28 -0500111 G_WAIT=""
112 run_cmd busctl get-property "$@"
Anthony Wilson79f697e2018-09-13 13:48:52 -0500113}
114
115state_query ()
116{
117 local state=$(get_property "$@" | cut -d '"' -f2)
118 printf "%-20s: %s\n" $4 $state
119}
120
Anthony Wilsonea87db42018-09-26 16:06:38 -0500121print_usage_err ()
122{
123 echo "ERROR: $1" >&2
124 echo "$USAGE"
125 exit 1
126}
127
Anthony Wilson79f697e2018-09-13 13:48:52 -0500128handle_cmd ()
129{
130 case "$1" in
Anthony Wilson3ae0a352018-09-13 14:47:56 -0500131 chassisoff)
132 OBJECT=$STATE_OBJECT/chassis0
133 SERVICE=$(mapper get-service $OBJECT)
134 INTERFACE=$STATE_INTERFACE.Chassis
135 PROPERTY=RequestedPowerTransition
136 VALUE=$INTERFACE.Transition.Off
Anthony Wilsonacf54d02018-09-20 15:19:28 -0500137 G_REQUESTED_STATE=$INTERFACE.PowerState.Off
138 G_QUERY="chassisstate"
Anthony Wilson3ae0a352018-09-13 14:47:56 -0500139 set_property $SERVICE $OBJECT $INTERFACE $PROPERTY "s" $VALUE
140 ;;
141 chassison)
142 OBJECT=$STATE_OBJECT/chassis0
143 SERVICE=$(mapper get-service $OBJECT)
144 INTERFACE=$STATE_INTERFACE.Chassis
145 PROPERTY=RequestedPowerTransition
146 VALUE=$INTERFACE.Transition.On
Anthony Wilsonacf54d02018-09-20 15:19:28 -0500147 G_REQUESTED_STATE=$INTERFACE.PowerState.On
148 G_QUERY="chassisstate"
Anthony Wilson3ae0a352018-09-13 14:47:56 -0500149 set_property $SERVICE $OBJECT $INTERFACE $PROPERTY "s" $VALUE
150 ;;
151 poweroff)
152 OBJECT=$STATE_OBJECT/host0
153 SERVICE=$(mapper get-service $OBJECT)
154 INTERFACE=$STATE_INTERFACE.Host
155 PROPERTY=RequestedHostTransition
156 VALUE=$INTERFACE.Transition.Off
Anthony Wilsonacf54d02018-09-20 15:19:28 -0500157 G_REQUESTED_STATE=$INTERFACE.HostState.Off
158 G_QUERY="hoststate"
Anthony Wilson3ae0a352018-09-13 14:47:56 -0500159 set_property $SERVICE $OBJECT $INTERFACE $PROPERTY "s" $VALUE
160 ;;
161 poweron)
162 OBJECT=$STATE_OBJECT/host0
163 SERVICE=$(mapper get-service $OBJECT)
164 INTERFACE=$STATE_INTERFACE.Host
165 PROPERTY=RequestedHostTransition
166 VALUE=$INTERFACE.Transition.On
Anthony Wilsonacf54d02018-09-20 15:19:28 -0500167 G_REQUESTED_STATE=$INTERFACE.HostState.Running
168 G_QUERY="hoststate"
Anthony Wilson3ae0a352018-09-13 14:47:56 -0500169 set_property $SERVICE $OBJECT $INTERFACE $PROPERTY "s" $VALUE
170 ;;
Anthony Wilson79f697e2018-09-13 13:48:52 -0500171 bmcstate)
172 OBJECT=$STATE_OBJECT/bmc0
173 SERVICE=$(mapper get-service $OBJECT)
174 INTERFACE=$STATE_INTERFACE.BMC
175 PROPERTY=CurrentBMCState
176 state_query $SERVICE $OBJECT $INTERFACE $PROPERTY
177 ;;
178 chassisstate)
179 OBJECT=$STATE_OBJECT/chassis0
180 SERVICE=$(mapper get-service $OBJECT)
181 INTERFACE=$STATE_INTERFACE.Chassis
182 PROPERTY=CurrentPowerState
183 state_query $SERVICE $OBJECT $INTERFACE $PROPERTY
184 ;;
185 hoststate)
186 OBJECT=$STATE_OBJECT/host0
187 SERVICE=$(mapper get-service $OBJECT)
188 INTERFACE=$STATE_INTERFACE.Host
189 PROPERTY=CurrentHostState
190 state_query $SERVICE $OBJECT $INTERFACE $PROPERTY
191 ;;
Alexander Filippov86cffd92019-04-03 16:29:57 +0300192 osstate)
193 OBJECT=$STATE_OBJECT/host0
194 SERVICE=$(mapper get-service $OBJECT)
195 INTERFACE=$STATE_INTERFACE.OperatingSystem.Status
196 PROPERTY=OperatingSystemState
197 state_query $SERVICE $OBJECT $INTERFACE $PROPERTY
198 ;;
Anthony Wilson79f697e2018-09-13 13:48:52 -0500199 state|status)
Alexander Filippov86cffd92019-04-03 16:29:57 +0300200 for query in bmcstate chassisstate hoststate bootprogress osstate
Anthony Wilson79f697e2018-09-13 13:48:52 -0500201 do
202 handle_cmd $query
203 done
204 ;;
Anthony Wilson50c5f882018-09-13 14:19:37 -0500205 bootprogress)
206 OBJECT=$STATE_OBJECT/host0
207 SERVICE=$(mapper get-service $OBJECT)
208 INTERFACE=$STATE_INTERFACE.Boot.Progress
209 PROPERTY=BootProgress
210 state_query $SERVICE $OBJECT $INTERFACE $PROPERTY
211 ;;
Anthony Wilson0f359832018-09-13 14:28:07 -0500212 power)
213 OBJECT=/org/openbmc/control/power0
214 SERVICE=$(mapper get-service $OBJECT)
215 INTERFACE=org.openbmc.control.Power
216 for property in pgood state pgood_timeout
217 do
218 # get_property can potentially return several
219 # different formats of values, so we do the parsing outside
220 # of get_property depending on the query. These queries
221 # return 'i VALUE' formatted strings.
222 STATE=$(get_property $SERVICE $OBJECT $INTERFACE $property \
223 | sed 's/i[ ^I]*//')
224 printf "%s = %s\n" $property $STATE
225 done
226 ;;
Anthony Wilson189cf242018-10-23 01:18:21 -0500227 chassiskill)
228 /usr/libexec/chassiskill
229 ;;
Anthony Wilson79f697e2018-09-13 13:48:52 -0500230 *)
Anthony Wilsonea87db42018-09-26 16:06:38 -0500231 print_usage_err "Invalid command '$1'"
Anthony Wilson79f697e2018-09-13 13:48:52 -0500232 ;;
233 esac
234}
235
Anthony Wilsonea87db42018-09-26 16:06:38 -0500236for arg in "$@"; do
237 case $arg in
Anthony Wilsonacf54d02018-09-20 15:19:28 -0500238 -w|--wait)
239 G_WAIT=30
240 continue
241 ;;
Anthony Wilsonea87db42018-09-26 16:06:38 -0500242 -h|--help)
243 print_help
244 ;;
Andrew Jeffery60c3ac82019-10-02 09:29:29 +0930245 -v|--verbose)
246 G_VERBOSE=y
247 ;;
Anthony Wilsonea87db42018-09-26 16:06:38 -0500248 -*)
249 print_usage_err "Unknown option: $arg"
250 ;;
251 *)
Anthony Wilsonacf54d02018-09-20 15:19:28 -0500252 G_ORIG_CMD=$arg
Anthony Wilsonea87db42018-09-26 16:06:38 -0500253 handle_cmd $arg
254 break
255 ;;
256 esac
257done