179f697e0SAnthony Wilson#!/bin/sh -e
279f697e0SAnthony Wilson
379f697e0SAnthony Wilsonset -euo pipefail
479f697e0SAnthony Wilson
53ae0a354SAnthony WilsonOPTS="bmcstate,bootprogress,chassisoff,chassison,chassisstate,hoststate,\
63ae0a354SAnthony Wilsonpower,poweroff,poweron,state,status"
70f35983dSAnthony Wilson
8*acf54d08SAnthony WilsonUSAGE="Usage: obmcutil [-h] [--wait]
90f35983dSAnthony Wilson                {$OPTS}"
1079f697e0SAnthony Wilson
1179f697e0SAnthony WilsonINTERFACE_ROOT=xyz.openbmc_project
1279f697e0SAnthony WilsonSTATE_INTERFACE=$INTERFACE_ROOT.State
1379f697e0SAnthony Wilson
1479f697e0SAnthony WilsonOBJECT_ROOT=/xyz/openbmc_project
1579f697e0SAnthony WilsonSTATE_OBJECT=$OBJECT_ROOT/state
1679f697e0SAnthony Wilson
17*acf54d08SAnthony Wilson## NOTE: The following global variables are used only in the run_timeout cmd.
18*acf54d08SAnthony Wilson## By declaring these globally instead of passing them through the
19*acf54d08SAnthony Wilson## intermediary functions, which may not be "best practice", the readability
20*acf54d08SAnthony Wilson## and cleanliness of the code should at least be increased.
21*acf54d08SAnthony Wilson
22*acf54d08SAnthony Wilson# The command passed in to be executed (e.g. poweron/off, status, etc.)
23*acf54d08SAnthony Wilson# This will be be used in some instances of error reporting
24*acf54d08SAnthony WilsonG_ORIG_CMD=
25*acf54d08SAnthony Wilson# The state an interface should be in after executing the requested command.
26*acf54d08SAnthony WilsonG_REQUESTED_STATE=
27*acf54d08SAnthony Wilson# The query to run during a poweron/off or chassison/off to check that
28*acf54d08SAnthony Wilson# the requested state (G_REQUESTED_STATE) of the interface has been reached.
29*acf54d08SAnthony WilsonG_QUERY=
30*acf54d08SAnthony Wilson# Wait the set period of time for state transitions to be successful before
31*acf54d08SAnthony Wilson# continuing on with the program or reporting an error if timeout reached.
32*acf54d08SAnthony WilsonG_WAIT=
33*acf54d08SAnthony Wilson
34f3f16fa9SAnthony Wilsonprint_help ()
35f3f16fa9SAnthony Wilson{
36f3f16fa9SAnthony Wilson    echo "$USAGE"
37f3f16fa9SAnthony Wilson    echo ""
38f3f16fa9SAnthony Wilson    echo "positional arguments:"
390f35983dSAnthony Wilson    echo "  {$OPTS}"
40f3f16fa9SAnthony Wilson    echo ""
41f3f16fa9SAnthony Wilson    echo "optional arguments:"
42f3f16fa9SAnthony Wilson    echo "  -h, --help          show this help message and exit"
43*acf54d08SAnthony Wilson    echo "  -w, --wait          block until state transition succeeds or fails"
44f3f16fa9SAnthony Wilson    exit 0
45f3f16fa9SAnthony Wilson}
46f3f16fa9SAnthony Wilson
47*acf54d08SAnthony Wilsonrun_timeout ()
48*acf54d08SAnthony Wilson{
49*acf54d08SAnthony Wilson    local timeout="$1"; shift
50*acf54d08SAnthony Wilson    local cmd="$@"
51*acf54d08SAnthony Wilson
52*acf54d08SAnthony Wilson    $cmd
53*acf54d08SAnthony Wilson
54*acf54d08SAnthony Wilson    # Run a background query for the transition to the expected state
55*acf54d08SAnthony Wilson    # This will be killed if the transition doesn't succeed within
56*acf54d08SAnthony Wilson    # a timeout period.
57*acf54d08SAnthony Wilson    (
58*acf54d08SAnthony Wilson        while ! grep -q $G_REQUESTED_STATE <<< $(handle_cmd $G_QUERY) ; do
59*acf54d08SAnthony Wilson            sleep 1
60*acf54d08SAnthony Wilson        done
61*acf54d08SAnthony Wilson    ) &
62*acf54d08SAnthony Wilson    child=$!
63*acf54d08SAnthony Wilson
64*acf54d08SAnthony Wilson    # Could be bad if process is killed before 'timeout' occurs if
65*acf54d08SAnthony Wilson    # transition doesn't succeed.
66*acf54d08SAnthony Wilson    trap -- "" SIGTERM
67*acf54d08SAnthony Wilson
68*acf54d08SAnthony Wilson    # Workaround for lack of 'timeout' command.
69*acf54d08SAnthony Wilson    (
70*acf54d08SAnthony Wilson        sleep $timeout
71*acf54d08SAnthony Wilson        kill $child
72*acf54d08SAnthony Wilson    ) > /dev/null 2>&1 &
73*acf54d08SAnthony Wilson
74*acf54d08SAnthony Wilson    if ! wait $child; then
75*acf54d08SAnthony Wilson        echo "Unable to confirm '$G_ORIG_CMD' success" \
76*acf54d08SAnthony Wilson        "within timeout period (${timeout}s)"
77*acf54d08SAnthony Wilson    fi
78*acf54d08SAnthony Wilson}
79*acf54d08SAnthony Wilson
80*acf54d08SAnthony Wilsonrun_cmd ()
81*acf54d08SAnthony Wilson{
82*acf54d08SAnthony Wilson    local cmd="$@";
83*acf54d08SAnthony Wilson
84*acf54d08SAnthony Wilson    if [ -n "$G_WAIT" ]; then
85*acf54d08SAnthony Wilson        run_timeout $G_WAIT "$cmd"
86*acf54d08SAnthony Wilson    else
87*acf54d08SAnthony Wilson        $cmd
88*acf54d08SAnthony Wilson    fi
89*acf54d08SAnthony Wilson}
90*acf54d08SAnthony Wilson
913ae0a354SAnthony Wilsonset_property ()
923ae0a354SAnthony Wilson{
93*acf54d08SAnthony Wilson    run_cmd busctl set-property "$@"
943ae0a354SAnthony Wilson}
953ae0a354SAnthony Wilson
9679f697e0SAnthony Wilsonget_property ()
9779f697e0SAnthony Wilson{
98*acf54d08SAnthony Wilson    G_WAIT=""
99*acf54d08SAnthony Wilson    run_cmd busctl get-property "$@"
10079f697e0SAnthony Wilson}
10179f697e0SAnthony Wilson
10279f697e0SAnthony Wilsonstate_query ()
10379f697e0SAnthony Wilson{
10479f697e0SAnthony Wilson    local state=$(get_property "$@" | cut -d '"' -f2)
10579f697e0SAnthony Wilson    printf "%-20s: %s\n" $4 $state
10679f697e0SAnthony Wilson}
10779f697e0SAnthony Wilson
108ea87db40SAnthony Wilsonprint_usage_err ()
109ea87db40SAnthony Wilson{
110ea87db40SAnthony Wilson    echo "ERROR: $1" >&2
111ea87db40SAnthony Wilson    echo "$USAGE"
112ea87db40SAnthony Wilson    exit 1
113ea87db40SAnthony Wilson}
114ea87db40SAnthony Wilson
11579f697e0SAnthony Wilsonhandle_cmd ()
11679f697e0SAnthony Wilson{
11779f697e0SAnthony Wilson    case "$1" in
1183ae0a354SAnthony Wilson        chassisoff)
1193ae0a354SAnthony Wilson            OBJECT=$STATE_OBJECT/chassis0
1203ae0a354SAnthony Wilson            SERVICE=$(mapper get-service $OBJECT)
1213ae0a354SAnthony Wilson            INTERFACE=$STATE_INTERFACE.Chassis
1223ae0a354SAnthony Wilson            PROPERTY=RequestedPowerTransition
1233ae0a354SAnthony Wilson            VALUE=$INTERFACE.Transition.Off
124*acf54d08SAnthony Wilson            G_REQUESTED_STATE=$INTERFACE.PowerState.Off
125*acf54d08SAnthony Wilson            G_QUERY="chassisstate"
1263ae0a354SAnthony Wilson            set_property $SERVICE $OBJECT $INTERFACE $PROPERTY "s" $VALUE
1273ae0a354SAnthony Wilson            ;;
1283ae0a354SAnthony Wilson        chassison)
1293ae0a354SAnthony Wilson            OBJECT=$STATE_OBJECT/chassis0
1303ae0a354SAnthony Wilson            SERVICE=$(mapper get-service $OBJECT)
1313ae0a354SAnthony Wilson            INTERFACE=$STATE_INTERFACE.Chassis
1323ae0a354SAnthony Wilson            PROPERTY=RequestedPowerTransition
1333ae0a354SAnthony Wilson            VALUE=$INTERFACE.Transition.On
134*acf54d08SAnthony Wilson            G_REQUESTED_STATE=$INTERFACE.PowerState.On
135*acf54d08SAnthony Wilson            G_QUERY="chassisstate"
1363ae0a354SAnthony Wilson            set_property $SERVICE $OBJECT $INTERFACE $PROPERTY "s" $VALUE
1373ae0a354SAnthony Wilson            ;;
1383ae0a354SAnthony Wilson        poweroff)
1393ae0a354SAnthony Wilson            OBJECT=$STATE_OBJECT/host0
1403ae0a354SAnthony Wilson            SERVICE=$(mapper get-service $OBJECT)
1413ae0a354SAnthony Wilson            INTERFACE=$STATE_INTERFACE.Host
1423ae0a354SAnthony Wilson            PROPERTY=RequestedHostTransition
1433ae0a354SAnthony Wilson            VALUE=$INTERFACE.Transition.Off
144*acf54d08SAnthony Wilson            G_REQUESTED_STATE=$INTERFACE.HostState.Off
145*acf54d08SAnthony Wilson            G_QUERY="hoststate"
1463ae0a354SAnthony Wilson            set_property $SERVICE $OBJECT $INTERFACE $PROPERTY "s" $VALUE
1473ae0a354SAnthony Wilson            ;;
1483ae0a354SAnthony Wilson        poweron)
1493ae0a354SAnthony Wilson            OBJECT=$STATE_OBJECT/host0
1503ae0a354SAnthony Wilson            SERVICE=$(mapper get-service $OBJECT)
1513ae0a354SAnthony Wilson            INTERFACE=$STATE_INTERFACE.Host
1523ae0a354SAnthony Wilson            PROPERTY=RequestedHostTransition
1533ae0a354SAnthony Wilson            VALUE=$INTERFACE.Transition.On
154*acf54d08SAnthony Wilson            G_REQUESTED_STATE=$INTERFACE.HostState.Running
155*acf54d08SAnthony Wilson            G_QUERY="hoststate"
1563ae0a354SAnthony Wilson            set_property $SERVICE $OBJECT $INTERFACE $PROPERTY "s" $VALUE
1573ae0a354SAnthony Wilson            ;;
15879f697e0SAnthony Wilson        bmcstate)
15979f697e0SAnthony Wilson            OBJECT=$STATE_OBJECT/bmc0
16079f697e0SAnthony Wilson            SERVICE=$(mapper get-service $OBJECT)
16179f697e0SAnthony Wilson            INTERFACE=$STATE_INTERFACE.BMC
16279f697e0SAnthony Wilson            PROPERTY=CurrentBMCState
16379f697e0SAnthony Wilson            state_query $SERVICE $OBJECT $INTERFACE $PROPERTY
16479f697e0SAnthony Wilson            ;;
16579f697e0SAnthony Wilson        chassisstate)
16679f697e0SAnthony Wilson            OBJECT=$STATE_OBJECT/chassis0
16779f697e0SAnthony Wilson            SERVICE=$(mapper get-service $OBJECT)
16879f697e0SAnthony Wilson            INTERFACE=$STATE_INTERFACE.Chassis
16979f697e0SAnthony Wilson            PROPERTY=CurrentPowerState
17079f697e0SAnthony Wilson            state_query $SERVICE $OBJECT $INTERFACE $PROPERTY
17179f697e0SAnthony Wilson            ;;
17279f697e0SAnthony Wilson        hoststate)
17379f697e0SAnthony Wilson            OBJECT=$STATE_OBJECT/host0
17479f697e0SAnthony Wilson            SERVICE=$(mapper get-service $OBJECT)
17579f697e0SAnthony Wilson            INTERFACE=$STATE_INTERFACE.Host
17679f697e0SAnthony Wilson            PROPERTY=CurrentHostState
17779f697e0SAnthony Wilson            state_query $SERVICE $OBJECT $INTERFACE $PROPERTY
17879f697e0SAnthony Wilson            ;;
17979f697e0SAnthony Wilson        state|status)
18079f697e0SAnthony Wilson            for query in bmcstate chassisstate hoststate
18179f697e0SAnthony Wilson            do
18279f697e0SAnthony Wilson                handle_cmd $query
18379f697e0SAnthony Wilson            done
18479f697e0SAnthony Wilson            ;;
18550c5f88dSAnthony Wilson        bootprogress)
18650c5f88dSAnthony Wilson            OBJECT=$STATE_OBJECT/host0
18750c5f88dSAnthony Wilson            SERVICE=$(mapper get-service $OBJECT)
18850c5f88dSAnthony Wilson            INTERFACE=$STATE_INTERFACE.Boot.Progress
18950c5f88dSAnthony Wilson            PROPERTY=BootProgress
19050c5f88dSAnthony Wilson            state_query $SERVICE $OBJECT $INTERFACE $PROPERTY
19150c5f88dSAnthony Wilson            ;;
1920f35983dSAnthony Wilson        power)
1930f35983dSAnthony Wilson            OBJECT=/org/openbmc/control/power0
1940f35983dSAnthony Wilson            SERVICE=$(mapper get-service $OBJECT)
1950f35983dSAnthony Wilson            INTERFACE=org.openbmc.control.Power
1960f35983dSAnthony Wilson            for property in pgood state pgood_timeout
1970f35983dSAnthony Wilson            do
1980f35983dSAnthony Wilson                # get_property can potentially return several
1990f35983dSAnthony Wilson                # different formats of values, so we do the parsing outside
2000f35983dSAnthony Wilson                # of get_property depending on the query. These queries
2010f35983dSAnthony Wilson                # return 'i VALUE' formatted strings.
2020f35983dSAnthony Wilson                STATE=$(get_property $SERVICE $OBJECT $INTERFACE $property \
2030f35983dSAnthony Wilson                    | sed 's/i[ ^I]*//')
2040f35983dSAnthony Wilson                printf "%s = %s\n" $property $STATE
2050f35983dSAnthony Wilson            done
2060f35983dSAnthony Wilson            ;;
20779f697e0SAnthony Wilson        *)
208ea87db40SAnthony Wilson            print_usage_err "Invalid command '$1'"
20979f697e0SAnthony Wilson            ;;
21079f697e0SAnthony Wilson    esac
21179f697e0SAnthony Wilson}
21279f697e0SAnthony Wilson
213ea87db40SAnthony Wilsonfor arg in "$@"; do
214ea87db40SAnthony Wilson    case $arg in
215*acf54d08SAnthony Wilson        -w|--wait)
216*acf54d08SAnthony Wilson            G_WAIT=30
217*acf54d08SAnthony Wilson            continue
218*acf54d08SAnthony Wilson            ;;
219ea87db40SAnthony Wilson        -h|--help)
220ea87db40SAnthony Wilson            print_help
221ea87db40SAnthony Wilson            ;;
222ea87db40SAnthony Wilson        -*)
223ea87db40SAnthony Wilson            print_usage_err "Unknown option: $arg"
224ea87db40SAnthony Wilson            ;;
225ea87db40SAnthony Wilson        *)
226*acf54d08SAnthony Wilson            G_ORIG_CMD=$arg
227ea87db40SAnthony Wilson            handle_cmd $arg
228ea87db40SAnthony Wilson            break
229ea87db40SAnthony Wilson            ;;
230ea87db40SAnthony Wilson    esac
231ea87db40SAnthony Wilsondone
232