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