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