| Anthony Wilson | 79f697e | 2018-09-13 13:48:52 -0500 | [diff] [blame] | 1 | #!/bin/sh -e | 
|  | 2 |  | 
|  | 3 | set -euo pipefail | 
|  | 4 |  | 
| Anthony Wilson | 189cf24 | 2018-10-23 01:18:21 -0500 | [diff] [blame^] | 5 | OPTS="bmcstate,bootprogress,chassiskill,chassisoff,chassison,chassisstate,hoststate,\ | 
| Anthony Wilson | 3ae0a35 | 2018-09-13 14:47:56 -0500 | [diff] [blame] | 6 | power,poweroff,poweron,state,status" | 
| Anthony Wilson | 0f35983 | 2018-09-13 14:28:07 -0500 | [diff] [blame] | 7 |  | 
| Anthony Wilson | acf54d0 | 2018-09-20 15:19:28 -0500 | [diff] [blame] | 8 | USAGE="Usage: obmcutil [-h] [--wait] | 
| Anthony Wilson | 0f35983 | 2018-09-13 14:28:07 -0500 | [diff] [blame] | 9 | {$OPTS}" | 
| Anthony Wilson | 79f697e | 2018-09-13 13:48:52 -0500 | [diff] [blame] | 10 |  | 
|  | 11 | INTERFACE_ROOT=xyz.openbmc_project | 
|  | 12 | STATE_INTERFACE=$INTERFACE_ROOT.State | 
|  | 13 |  | 
|  | 14 | OBJECT_ROOT=/xyz/openbmc_project | 
|  | 15 | STATE_OBJECT=$OBJECT_ROOT/state | 
|  | 16 |  | 
| Anthony Wilson | acf54d0 | 2018-09-20 15:19:28 -0500 | [diff] [blame] | 17 | ## 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 | 
|  | 24 | G_ORIG_CMD= | 
|  | 25 | # The state an interface should be in after executing the requested command. | 
|  | 26 | G_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. | 
|  | 29 | G_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. | 
|  | 32 | G_WAIT= | 
|  | 33 |  | 
| Anthony Wilson | f3f16fa | 2018-09-13 14:10:52 -0500 | [diff] [blame] | 34 | print_help () | 
|  | 35 | { | 
|  | 36 | echo "$USAGE" | 
|  | 37 | echo "" | 
|  | 38 | echo "positional arguments:" | 
| Anthony Wilson | 0f35983 | 2018-09-13 14:28:07 -0500 | [diff] [blame] | 39 | echo "  {$OPTS}" | 
| Anthony Wilson | f3f16fa | 2018-09-13 14:10:52 -0500 | [diff] [blame] | 40 | echo "" | 
|  | 41 | echo "optional arguments:" | 
|  | 42 | echo "  -h, --help          show this help message and exit" | 
| Anthony Wilson | acf54d0 | 2018-09-20 15:19:28 -0500 | [diff] [blame] | 43 | echo "  -w, --wait          block until state transition succeeds or fails" | 
| Anthony Wilson | f3f16fa | 2018-09-13 14:10:52 -0500 | [diff] [blame] | 44 | exit 0 | 
|  | 45 | } | 
|  | 46 |  | 
| Anthony Wilson | acf54d0 | 2018-09-20 15:19:28 -0500 | [diff] [blame] | 47 | run_timeout () | 
|  | 48 | { | 
|  | 49 | local timeout="$1"; shift | 
|  | 50 | local cmd="$@" | 
|  | 51 |  | 
|  | 52 | $cmd | 
|  | 53 |  | 
|  | 54 | # Run a background query for the transition to the expected state | 
|  | 55 | # This will be killed if the transition doesn't succeed within | 
|  | 56 | # a timeout period. | 
|  | 57 | ( | 
|  | 58 | while ! grep -q $G_REQUESTED_STATE <<< $(handle_cmd $G_QUERY) ; do | 
|  | 59 | sleep 1 | 
|  | 60 | done | 
|  | 61 | ) & | 
|  | 62 | child=$! | 
|  | 63 |  | 
|  | 64 | # Could be bad if process is killed before 'timeout' occurs if | 
|  | 65 | # transition doesn't succeed. | 
|  | 66 | trap -- "" SIGTERM | 
|  | 67 |  | 
|  | 68 | # Workaround for lack of 'timeout' command. | 
|  | 69 | ( | 
|  | 70 | sleep $timeout | 
|  | 71 | kill $child | 
|  | 72 | ) > /dev/null 2>&1 & | 
|  | 73 |  | 
|  | 74 | if ! wait $child; then | 
|  | 75 | echo "Unable to confirm '$G_ORIG_CMD' success" \ | 
|  | 76 | "within timeout period (${timeout}s)" | 
|  | 77 | fi | 
|  | 78 | } | 
|  | 79 |  | 
|  | 80 | run_cmd () | 
|  | 81 | { | 
|  | 82 | local cmd="$@"; | 
|  | 83 |  | 
|  | 84 | if [ -n "$G_WAIT" ]; then | 
|  | 85 | run_timeout $G_WAIT "$cmd" | 
|  | 86 | else | 
|  | 87 | $cmd | 
|  | 88 | fi | 
|  | 89 | } | 
|  | 90 |  | 
| Anthony Wilson | 3ae0a35 | 2018-09-13 14:47:56 -0500 | [diff] [blame] | 91 | set_property () | 
|  | 92 | { | 
| Anthony Wilson | acf54d0 | 2018-09-20 15:19:28 -0500 | [diff] [blame] | 93 | run_cmd busctl set-property "$@" | 
| Anthony Wilson | 3ae0a35 | 2018-09-13 14:47:56 -0500 | [diff] [blame] | 94 | } | 
|  | 95 |  | 
| Anthony Wilson | 79f697e | 2018-09-13 13:48:52 -0500 | [diff] [blame] | 96 | get_property () | 
|  | 97 | { | 
| Anthony Wilson | acf54d0 | 2018-09-20 15:19:28 -0500 | [diff] [blame] | 98 | G_WAIT="" | 
|  | 99 | run_cmd busctl get-property "$@" | 
| Anthony Wilson | 79f697e | 2018-09-13 13:48:52 -0500 | [diff] [blame] | 100 | } | 
|  | 101 |  | 
|  | 102 | state_query () | 
|  | 103 | { | 
|  | 104 | local state=$(get_property "$@" | cut -d '"' -f2) | 
|  | 105 | printf "%-20s: %s\n" $4 $state | 
|  | 106 | } | 
|  | 107 |  | 
| Anthony Wilson | ea87db4 | 2018-09-26 16:06:38 -0500 | [diff] [blame] | 108 | print_usage_err () | 
|  | 109 | { | 
|  | 110 | echo "ERROR: $1" >&2 | 
|  | 111 | echo "$USAGE" | 
|  | 112 | exit 1 | 
|  | 113 | } | 
|  | 114 |  | 
| Anthony Wilson | 79f697e | 2018-09-13 13:48:52 -0500 | [diff] [blame] | 115 | handle_cmd () | 
|  | 116 | { | 
|  | 117 | case "$1" in | 
| Anthony Wilson | 3ae0a35 | 2018-09-13 14:47:56 -0500 | [diff] [blame] | 118 | chassisoff) | 
|  | 119 | OBJECT=$STATE_OBJECT/chassis0 | 
|  | 120 | SERVICE=$(mapper get-service $OBJECT) | 
|  | 121 | INTERFACE=$STATE_INTERFACE.Chassis | 
|  | 122 | PROPERTY=RequestedPowerTransition | 
|  | 123 | VALUE=$INTERFACE.Transition.Off | 
| Anthony Wilson | acf54d0 | 2018-09-20 15:19:28 -0500 | [diff] [blame] | 124 | G_REQUESTED_STATE=$INTERFACE.PowerState.Off | 
|  | 125 | G_QUERY="chassisstate" | 
| Anthony Wilson | 3ae0a35 | 2018-09-13 14:47:56 -0500 | [diff] [blame] | 126 | set_property $SERVICE $OBJECT $INTERFACE $PROPERTY "s" $VALUE | 
|  | 127 | ;; | 
|  | 128 | chassison) | 
|  | 129 | OBJECT=$STATE_OBJECT/chassis0 | 
|  | 130 | SERVICE=$(mapper get-service $OBJECT) | 
|  | 131 | INTERFACE=$STATE_INTERFACE.Chassis | 
|  | 132 | PROPERTY=RequestedPowerTransition | 
|  | 133 | VALUE=$INTERFACE.Transition.On | 
| Anthony Wilson | acf54d0 | 2018-09-20 15:19:28 -0500 | [diff] [blame] | 134 | G_REQUESTED_STATE=$INTERFACE.PowerState.On | 
|  | 135 | G_QUERY="chassisstate" | 
| Anthony Wilson | 3ae0a35 | 2018-09-13 14:47:56 -0500 | [diff] [blame] | 136 | set_property $SERVICE $OBJECT $INTERFACE $PROPERTY "s" $VALUE | 
|  | 137 | ;; | 
|  | 138 | poweroff) | 
|  | 139 | OBJECT=$STATE_OBJECT/host0 | 
|  | 140 | SERVICE=$(mapper get-service $OBJECT) | 
|  | 141 | INTERFACE=$STATE_INTERFACE.Host | 
|  | 142 | PROPERTY=RequestedHostTransition | 
|  | 143 | VALUE=$INTERFACE.Transition.Off | 
| Anthony Wilson | acf54d0 | 2018-09-20 15:19:28 -0500 | [diff] [blame] | 144 | G_REQUESTED_STATE=$INTERFACE.HostState.Off | 
|  | 145 | G_QUERY="hoststate" | 
| Anthony Wilson | 3ae0a35 | 2018-09-13 14:47:56 -0500 | [diff] [blame] | 146 | set_property $SERVICE $OBJECT $INTERFACE $PROPERTY "s" $VALUE | 
|  | 147 | ;; | 
|  | 148 | poweron) | 
|  | 149 | OBJECT=$STATE_OBJECT/host0 | 
|  | 150 | SERVICE=$(mapper get-service $OBJECT) | 
|  | 151 | INTERFACE=$STATE_INTERFACE.Host | 
|  | 152 | PROPERTY=RequestedHostTransition | 
|  | 153 | VALUE=$INTERFACE.Transition.On | 
| Anthony Wilson | acf54d0 | 2018-09-20 15:19:28 -0500 | [diff] [blame] | 154 | G_REQUESTED_STATE=$INTERFACE.HostState.Running | 
|  | 155 | G_QUERY="hoststate" | 
| Anthony Wilson | 3ae0a35 | 2018-09-13 14:47:56 -0500 | [diff] [blame] | 156 | set_property $SERVICE $OBJECT $INTERFACE $PROPERTY "s" $VALUE | 
|  | 157 | ;; | 
| Anthony Wilson | 79f697e | 2018-09-13 13:48:52 -0500 | [diff] [blame] | 158 | bmcstate) | 
|  | 159 | OBJECT=$STATE_OBJECT/bmc0 | 
|  | 160 | SERVICE=$(mapper get-service $OBJECT) | 
|  | 161 | INTERFACE=$STATE_INTERFACE.BMC | 
|  | 162 | PROPERTY=CurrentBMCState | 
|  | 163 | state_query $SERVICE $OBJECT $INTERFACE $PROPERTY | 
|  | 164 | ;; | 
|  | 165 | chassisstate) | 
|  | 166 | OBJECT=$STATE_OBJECT/chassis0 | 
|  | 167 | SERVICE=$(mapper get-service $OBJECT) | 
|  | 168 | INTERFACE=$STATE_INTERFACE.Chassis | 
|  | 169 | PROPERTY=CurrentPowerState | 
|  | 170 | state_query $SERVICE $OBJECT $INTERFACE $PROPERTY | 
|  | 171 | ;; | 
|  | 172 | hoststate) | 
|  | 173 | OBJECT=$STATE_OBJECT/host0 | 
|  | 174 | SERVICE=$(mapper get-service $OBJECT) | 
|  | 175 | INTERFACE=$STATE_INTERFACE.Host | 
|  | 176 | PROPERTY=CurrentHostState | 
|  | 177 | state_query $SERVICE $OBJECT $INTERFACE $PROPERTY | 
|  | 178 | ;; | 
|  | 179 | state|status) | 
|  | 180 | for query in bmcstate chassisstate hoststate | 
|  | 181 | do | 
|  | 182 | handle_cmd $query | 
|  | 183 | done | 
|  | 184 | ;; | 
| Anthony Wilson | 50c5f88 | 2018-09-13 14:19:37 -0500 | [diff] [blame] | 185 | bootprogress) | 
|  | 186 | OBJECT=$STATE_OBJECT/host0 | 
|  | 187 | SERVICE=$(mapper get-service $OBJECT) | 
|  | 188 | INTERFACE=$STATE_INTERFACE.Boot.Progress | 
|  | 189 | PROPERTY=BootProgress | 
|  | 190 | state_query $SERVICE $OBJECT $INTERFACE $PROPERTY | 
|  | 191 | ;; | 
| Anthony Wilson | 0f35983 | 2018-09-13 14:28:07 -0500 | [diff] [blame] | 192 | power) | 
|  | 193 | OBJECT=/org/openbmc/control/power0 | 
|  | 194 | SERVICE=$(mapper get-service $OBJECT) | 
|  | 195 | INTERFACE=org.openbmc.control.Power | 
|  | 196 | for property in pgood state pgood_timeout | 
|  | 197 | do | 
|  | 198 | # get_property can potentially return several | 
|  | 199 | # different formats of values, so we do the parsing outside | 
|  | 200 | # of get_property depending on the query. These queries | 
|  | 201 | # return 'i VALUE' formatted strings. | 
|  | 202 | STATE=$(get_property $SERVICE $OBJECT $INTERFACE $property \ | 
|  | 203 | | sed 's/i[ ^I]*//') | 
|  | 204 | printf "%s = %s\n" $property $STATE | 
|  | 205 | done | 
|  | 206 | ;; | 
| Anthony Wilson | 189cf24 | 2018-10-23 01:18:21 -0500 | [diff] [blame^] | 207 | chassiskill) | 
|  | 208 | /usr/libexec/chassiskill | 
|  | 209 | ;; | 
| Anthony Wilson | 79f697e | 2018-09-13 13:48:52 -0500 | [diff] [blame] | 210 | *) | 
| Anthony Wilson | ea87db4 | 2018-09-26 16:06:38 -0500 | [diff] [blame] | 211 | print_usage_err "Invalid command '$1'" | 
| Anthony Wilson | 79f697e | 2018-09-13 13:48:52 -0500 | [diff] [blame] | 212 | ;; | 
|  | 213 | esac | 
|  | 214 | } | 
|  | 215 |  | 
| Anthony Wilson | ea87db4 | 2018-09-26 16:06:38 -0500 | [diff] [blame] | 216 | for arg in "$@"; do | 
|  | 217 | case $arg in | 
| Anthony Wilson | acf54d0 | 2018-09-20 15:19:28 -0500 | [diff] [blame] | 218 | -w|--wait) | 
|  | 219 | G_WAIT=30 | 
|  | 220 | continue | 
|  | 221 | ;; | 
| Anthony Wilson | ea87db4 | 2018-09-26 16:06:38 -0500 | [diff] [blame] | 222 | -h|--help) | 
|  | 223 | print_help | 
|  | 224 | ;; | 
|  | 225 | -*) | 
|  | 226 | print_usage_err "Unknown option: $arg" | 
|  | 227 | ;; | 
|  | 228 | *) | 
| Anthony Wilson | acf54d0 | 2018-09-20 15:19:28 -0500 | [diff] [blame] | 229 | G_ORIG_CMD=$arg | 
| Anthony Wilson | ea87db4 | 2018-09-26 16:06:38 -0500 | [diff] [blame] | 230 | handle_cmd $arg | 
|  | 231 | break | 
|  | 232 | ;; | 
|  | 233 | esac | 
|  | 234 | done |