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