1#!/bin/sh -e 2 3set -euo pipefail 4 5OPTS="bmcstate,bootprogress,chassiskill,chassisoff,chassison,chassisstate,hoststate,\ 6osstate,power,poweroff,poweron,state,status,rebootoff,rebooton" 7 8USAGE="Usage: obmcutil [-h] [--wait] [--verbose] 9 {$OPTS}" 10 11INTERFACE_ROOT=xyz.openbmc_project 12STATE_INTERFACE=$INTERFACE_ROOT.State 13CONTROL_INTERFACE=$INTERFACE_ROOT.Control 14 15OBJECT_ROOT=/xyz/openbmc_project 16STATE_OBJECT=$OBJECT_ROOT/state 17CONTROL_OBJECT=$OBJECT_ROOT/control 18 19## NOTE: The following global variables are used only in the run_timeout cmd. 20## By declaring these globally instead of passing them through the 21## intermediary functions, which may not be "best practice", the readability 22## and cleanliness of the code should at least be increased. 23 24# The command passed in to be executed (e.g. poweron/off, status, etc.) 25# This will be be used in some instances of error reporting 26G_ORIG_CMD= 27# The state an interface should be in after executing the requested command. 28G_REQUESTED_STATE= 29# The query to run during a poweron/off or chassison/off to check that 30# the requested state (G_REQUESTED_STATE) of the interface has been reached. 31G_QUERY= 32# Wait the set period of time for state transitions to be successful before 33# continuing on with the program or reporting an error if timeout reached. 34G_WAIT= 35# Print the journal to the console 36G_VERBOSE= 37 38print_help () 39{ 40 echo "$USAGE" 41 echo "" 42 echo "positional arguments:" 43 echo " {$OPTS}" 44 echo "" 45 echo "Examples:" 46 echo "" 47 echo "obmcutil rebootoff Disable auto reboot from Quiesce state" 48 echo "obmcutil rebooton Enable auto reboot from Quiesce state" 49 echo "" 50 echo "optional arguments:" 51 echo " -h, --help show this help message and exit" 52 echo " -w, --wait block until state transition succeeds or fails" 53 echo " -v, --verbose print the journal to stdout if --wait is supplied" 54 exit 0 55} 56 57run_timeout () 58{ 59 local timeout="$1"; shift 60 local cmd="$@" 61 local verbose_child= 62 63 if [ -n "$G_VERBOSE" ]; then 64 journalctl -f & 65 verbose_child=$! 66 fi 67 68 $cmd 69 70 # Run a background query for the transition to the expected state 71 # This will be killed if the transition doesn't succeed within 72 # a timeout period. 73 ( 74 while ! grep -q $G_REQUESTED_STATE <<< $(handle_cmd $G_QUERY) ; do 75 sleep 1 76 done 77 ) & 78 wait_child=$! 79 80 # Could be bad if process is killed before 'timeout' occurs if 81 # transition doesn't succeed. 82 trap -- "" SIGTERM 83 84 # Workaround for lack of 'timeout' command. 85 ( 86 sleep $timeout 87 kill $wait_child 88 ) > /dev/null 2>&1 & 89 90 if ! wait $wait_child; then 91 echo "Unable to confirm '$G_ORIG_CMD' success" \ 92 "within timeout period (${timeout}s)" 93 fi 94 95 if [ -n $verbose_child ]; then 96 kill $verbose_child 97 fi 98} 99 100run_cmd () 101{ 102 local cmd="$@"; 103 104 if [ -n "$G_WAIT" ]; then 105 run_timeout $G_WAIT "$cmd" 106 else 107 $cmd 108 fi 109} 110 111set_property () 112{ 113 run_cmd busctl set-property "$@" 114} 115 116get_property () 117{ 118 G_WAIT="" 119 run_cmd busctl get-property "$@" 120} 121 122state_query () 123{ 124 local state=$(get_property "$@" | cut -d '"' -f2) 125 printf "%-20s: %s\n" $4 $state 126} 127 128print_usage_err () 129{ 130 echo "ERROR: $1" >&2 131 echo "$USAGE" 132 exit 1 133} 134 135handle_cmd () 136{ 137 case "$1" in 138 chassisoff) 139 OBJECT=$STATE_OBJECT/chassis0 140 SERVICE=$(mapper get-service $OBJECT) 141 INTERFACE=$STATE_INTERFACE.Chassis 142 PROPERTY=RequestedPowerTransition 143 VALUE=$INTERFACE.Transition.Off 144 G_REQUESTED_STATE=$INTERFACE.PowerState.Off 145 G_QUERY="chassisstate" 146 set_property $SERVICE $OBJECT $INTERFACE $PROPERTY "s" $VALUE 147 ;; 148 chassison) 149 OBJECT=$STATE_OBJECT/chassis0 150 SERVICE=$(mapper get-service $OBJECT) 151 INTERFACE=$STATE_INTERFACE.Chassis 152 PROPERTY=RequestedPowerTransition 153 VALUE=$INTERFACE.Transition.On 154 G_REQUESTED_STATE=$INTERFACE.PowerState.On 155 G_QUERY="chassisstate" 156 set_property $SERVICE $OBJECT $INTERFACE $PROPERTY "s" $VALUE 157 ;; 158 poweroff) 159 OBJECT=$STATE_OBJECT/host0 160 SERVICE=$(mapper get-service $OBJECT) 161 INTERFACE=$STATE_INTERFACE.Host 162 PROPERTY=RequestedHostTransition 163 VALUE=$INTERFACE.Transition.Off 164 G_REQUESTED_STATE=$INTERFACE.HostState.Off 165 G_QUERY="hoststate" 166 set_property $SERVICE $OBJECT $INTERFACE $PROPERTY "s" $VALUE 167 ;; 168 poweron) 169 OBJECT=$STATE_OBJECT/host0 170 SERVICE=$(mapper get-service $OBJECT) 171 INTERFACE=$STATE_INTERFACE.Host 172 PROPERTY=RequestedHostTransition 173 VALUE=$INTERFACE.Transition.On 174 G_REQUESTED_STATE=$INTERFACE.HostState.Running 175 G_QUERY="hoststate" 176 set_property $SERVICE $OBJECT $INTERFACE $PROPERTY "s" $VALUE 177 ;; 178 bmcstate) 179 OBJECT=$STATE_OBJECT/bmc0 180 SERVICE=$(mapper get-service $OBJECT) 181 INTERFACE=$STATE_INTERFACE.BMC 182 PROPERTY=CurrentBMCState 183 state_query $SERVICE $OBJECT $INTERFACE $PROPERTY 184 ;; 185 chassisstate) 186 OBJECT=$STATE_OBJECT/chassis0 187 SERVICE=$(mapper get-service $OBJECT) 188 INTERFACE=$STATE_INTERFACE.Chassis 189 PROPERTY=CurrentPowerState 190 state_query $SERVICE $OBJECT $INTERFACE $PROPERTY 191 ;; 192 hoststate) 193 OBJECT=$STATE_OBJECT/host0 194 SERVICE=$(mapper get-service $OBJECT) 195 INTERFACE=$STATE_INTERFACE.Host 196 PROPERTY=CurrentHostState 197 state_query $SERVICE $OBJECT $INTERFACE $PROPERTY 198 ;; 199 osstate) 200 OBJECT=$STATE_OBJECT/host0 201 SERVICE=$(mapper get-service $OBJECT) 202 INTERFACE=$STATE_INTERFACE.OperatingSystem.Status 203 PROPERTY=OperatingSystemState 204 state_query $SERVICE $OBJECT $INTERFACE $PROPERTY 205 ;; 206 state|status) 207 for query in bmcstate chassisstate hoststate bootprogress osstate 208 do 209 handle_cmd $query 210 done 211 ;; 212 bootprogress) 213 OBJECT=$STATE_OBJECT/host0 214 SERVICE=$(mapper get-service $OBJECT) 215 INTERFACE=$STATE_INTERFACE.Boot.Progress 216 PROPERTY=BootProgress 217 state_query $SERVICE $OBJECT $INTERFACE $PROPERTY 218 ;; 219 power) 220 OBJECT=/org/openbmc/control/power0 221 SERVICE=$(mapper get-service $OBJECT) 222 INTERFACE=org.openbmc.control.Power 223 for property in pgood state pgood_timeout 224 do 225 # get_property can potentially return several 226 # different formats of values, so we do the parsing outside 227 # of get_property depending on the query. These queries 228 # return 'i VALUE' formatted strings. 229 STATE=$(get_property $SERVICE $OBJECT $INTERFACE $property \ 230 | sed 's/i[ ^I]*//') 231 printf "%s = %s\n" $property $STATE 232 done 233 ;; 234 chassiskill) 235 /usr/libexec/chassiskill 236 ;; 237 rebootoff) 238 OBJECT=$CONTROL_OBJECT/host0/auto_reboot 239 SERVICE=$(mapper get-service $OBJECT) 240 INTERFACE=$CONTROL_INTERFACE.Boot.RebootPolicy 241 PROPERTY=AutoReboot 242 VALUE=false 243 set_property $SERVICE $OBJECT $INTERFACE $PROPERTY "b" $VALUE 244 ;; 245 rebooton) 246 OBJECT=$CONTROL_OBJECT/host0/auto_reboot 247 SERVICE=$(mapper get-service $OBJECT) 248 INTERFACE=$CONTROL_INTERFACE.Boot.RebootPolicy 249 PROPERTY=AutoReboot 250 VALUE=true 251 set_property $SERVICE $OBJECT $INTERFACE $PROPERTY "b" $VALUE 252 ;; 253 *) 254 print_usage_err "Invalid command '$1'" 255 ;; 256 esac 257} 258 259for arg in "$@"; do 260 case $arg in 261 -w|--wait) 262 G_WAIT=30 263 continue 264 ;; 265 -h|--help) 266 print_help 267 ;; 268 -v|--verbose) 269 G_VERBOSE=y 270 ;; 271 -*) 272 print_usage_err "Unknown option: $arg" 273 ;; 274 *) 275 G_ORIG_CMD=$arg 276 handle_cmd $arg 277 break 278 ;; 279 esac 280done 281