1#!/bin/sh -e 2 3set -euo pipefail 4 5OPTS="bmcstate,bootprogress,chassiskill,chassisoff,chassison,chassisstate,hoststate,\ 6osstate,power,poweroff,poweron,state,status" 7 8USAGE="Usage: obmcutil [-h] [--wait] 9 {$OPTS}" 10 11INTERFACE_ROOT=xyz.openbmc_project 12STATE_INTERFACE=$INTERFACE_ROOT.State 13 14OBJECT_ROOT=/xyz/openbmc_project 15STATE_OBJECT=$OBJECT_ROOT/state 16 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 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= 33 34print_help () 35{ 36 echo "$USAGE" 37 echo "" 38 echo "positional arguments:" 39 echo " {$OPTS}" 40 echo "" 41 echo "optional arguments:" 42 echo " -h, --help show this help message and exit" 43 echo " -w, --wait block until state transition succeeds or fails" 44 exit 0 45} 46 47run_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 80run_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 91set_property () 92{ 93 run_cmd busctl set-property "$@" 94} 95 96get_property () 97{ 98 G_WAIT="" 99 run_cmd busctl get-property "$@" 100} 101 102state_query () 103{ 104 local state=$(get_property "$@" | cut -d '"' -f2) 105 printf "%-20s: %s\n" $4 $state 106} 107 108print_usage_err () 109{ 110 echo "ERROR: $1" >&2 111 echo "$USAGE" 112 exit 1 113} 114 115handle_cmd () 116{ 117 case "$1" in 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 124 G_REQUESTED_STATE=$INTERFACE.PowerState.Off 125 G_QUERY="chassisstate" 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 134 G_REQUESTED_STATE=$INTERFACE.PowerState.On 135 G_QUERY="chassisstate" 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 144 G_REQUESTED_STATE=$INTERFACE.HostState.Off 145 G_QUERY="hoststate" 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 154 G_REQUESTED_STATE=$INTERFACE.HostState.Running 155 G_QUERY="hoststate" 156 set_property $SERVICE $OBJECT $INTERFACE $PROPERTY "s" $VALUE 157 ;; 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 osstate) 180 OBJECT=$STATE_OBJECT/host0 181 SERVICE=$(mapper get-service $OBJECT) 182 INTERFACE=$STATE_INTERFACE.OperatingSystem.Status 183 PROPERTY=OperatingSystemState 184 state_query $SERVICE $OBJECT $INTERFACE $PROPERTY 185 ;; 186 state|status) 187 for query in bmcstate chassisstate hoststate bootprogress osstate 188 do 189 handle_cmd $query 190 done 191 ;; 192 bootprogress) 193 OBJECT=$STATE_OBJECT/host0 194 SERVICE=$(mapper get-service $OBJECT) 195 INTERFACE=$STATE_INTERFACE.Boot.Progress 196 PROPERTY=BootProgress 197 state_query $SERVICE $OBJECT $INTERFACE $PROPERTY 198 ;; 199 power) 200 OBJECT=/org/openbmc/control/power0 201 SERVICE=$(mapper get-service $OBJECT) 202 INTERFACE=org.openbmc.control.Power 203 for property in pgood state pgood_timeout 204 do 205 # get_property can potentially return several 206 # different formats of values, so we do the parsing outside 207 # of get_property depending on the query. These queries 208 # return 'i VALUE' formatted strings. 209 STATE=$(get_property $SERVICE $OBJECT $INTERFACE $property \ 210 | sed 's/i[ ^I]*//') 211 printf "%s = %s\n" $property $STATE 212 done 213 ;; 214 chassiskill) 215 /usr/libexec/chassiskill 216 ;; 217 *) 218 print_usage_err "Invalid command '$1'" 219 ;; 220 esac 221} 222 223for arg in "$@"; do 224 case $arg in 225 -w|--wait) 226 G_WAIT=30 227 continue 228 ;; 229 -h|--help) 230 print_help 231 ;; 232 -*) 233 print_usage_err "Unknown option: $arg" 234 ;; 235 *) 236 G_ORIG_CMD=$arg 237 handle_cmd $arg 238 break 239 ;; 240 esac 241done 242