pwrctl: add pgood state switching application
pgood_wait simply blocks until the power state changes to
the requested state.
The intent is for use from a systemd unit similar to nm-online.
Change-Id: Icf1e18f5d47d6eb2fc424b4614fd196ef3dfd6ee
Signed-off-by: Brad Bishop <bradleyb@fuzziesquirrel.com>
diff --git a/op-pwrctl/pgood_wait/.gitignore b/op-pwrctl/pgood_wait/.gitignore
new file mode 100644
index 0000000..fbc938c
--- /dev/null
+++ b/op-pwrctl/pgood_wait/.gitignore
@@ -0,0 +1 @@
+pgood_wait
diff --git a/op-pwrctl/pgood_wait/Makefile b/op-pwrctl/pgood_wait/Makefile
new file mode 100644
index 0000000..c54382e
--- /dev/null
+++ b/op-pwrctl/pgood_wait/Makefile
@@ -0,0 +1,5 @@
+BINS=pgood_wait
+BIN_SUFFIX=""
+LDLIBS=-lmapper
+include ../../sdbus.mk
+include ../../rules.mk
diff --git a/op-pwrctl/pgood_wait/pgood_wait.c b/op-pwrctl/pgood_wait/pgood_wait.c
new file mode 100644
index 0000000..949776d
--- /dev/null
+++ b/op-pwrctl/pgood_wait/pgood_wait.c
@@ -0,0 +1,183 @@
+/**
+ * Copyright © 2016 IBM Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <systemd/sd-bus.h>
+#include <systemd/sd-event.h>
+#include <mapper.h>
+
+static void quit(int r, void *loop)
+{
+ sd_event_exit((sd_event *)loop, r);
+}
+
+static int callback(sd_bus_message *m, void *user, sd_bus_error *error)
+{
+ sd_event *loop = user;
+ int r;
+ char *property = NULL;
+
+ r = sd_bus_message_skip(m, "s");
+ if (r < 0) {
+ fprintf(stderr, "Error skipping message fields: %s\n",
+ strerror(-r));
+ quit(r, loop);
+ return r;
+ }
+
+ r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
+ if (r < 0) {
+ fprintf(stderr, "Error entering container: %s\n",
+ strerror(-r));
+ quit(r, loop);
+ return r;
+ }
+
+ while((r = sd_bus_message_enter_container(
+ m,
+ SD_BUS_TYPE_DICT_ENTRY,
+ "sv")) > 0) {
+ r = sd_bus_message_read(m, "s", &property);
+ if (r < 0) {
+ fprintf(stderr, "Error reading message: %s\n",
+ strerror(-r));
+ quit(r, loop);
+ return r;
+ }
+
+ if(strcmp(property, "pgood"))
+ continue;
+
+ quit(0, loop);
+ break;
+ }
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ static const char *matchfmt =
+ "type='signal',"
+ "interface='org.freedesktop.DBus.Properties',"
+ "member='PropertiesChanged',"
+ "arg0='org.openbmc.control.Power',"
+ "path='%s',"
+ "sender='%s'";
+ static const char *usage =
+ "Usage: %s OBJECTPATH on|off\n";
+ static const size_t LEN = 256;
+
+ sd_bus *conn = NULL;
+ sd_event *loop = NULL;
+ sd_bus_slot *slot = NULL;
+ sd_bus_error error = SD_BUS_ERROR_NULL;
+ char *service = NULL;
+ int r, dest = -1, state;
+ char match[LEN];
+
+ if(argc < 3) {
+ fprintf(stderr, usage, argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ if(!strcmp(argv[2], "on"))
+ dest = 1;
+ if(!strcmp(argv[2], "off"))
+ dest = 0;
+
+ if(dest != 0 && dest != 1) {
+ fprintf(stderr, usage, argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ r = sd_bus_default_system(&conn);
+ if(r < 0) {
+ fprintf(stderr, "Error connecting to system bus: %s\n",
+ strerror(-r));
+ goto finish;
+ }
+
+ r = mapper_get_service(conn, argv[1], &service);
+ if (r < 0) {
+ fprintf(stderr, "Error obtaining host service: %s\n",
+ strerror(-r));
+ goto finish;
+ }
+
+ r = sd_event_default(&loop);
+ if (r < 0) {
+ fprintf(stderr, "Error obtaining event loop: %s\n",
+ strerror(-r));
+ goto finish;
+ }
+
+ r = sd_bus_attach_event(conn, loop, SD_EVENT_PRIORITY_NORMAL);
+ if (r < 0) {
+ fprintf(stderr, "Failed to attach system "
+ "bus to event loop: %s\n",
+ strerror(-r));
+ goto finish;
+ }
+
+ if(strlen(matchfmt) + strnlen(argv[1], LEN) > LEN) {
+ r = -E2BIG;
+ fprintf(stderr, "Error adding match rule: %s\n",
+ strerror(-r));
+ goto finish;
+ }
+
+ sprintf(match, matchfmt, argv[1], service);
+
+ r = sd_bus_add_match(conn,
+ &slot,
+ match,
+ callback,
+ loop);
+ if(r < 0) {
+ fprintf(stderr, "Error adding match rule: %s\n",
+ strerror(-r));
+ goto finish;
+ }
+
+ r = sd_bus_get_property_trivial(conn,
+ service,
+ argv[1],
+ "org.openbmc.control.Power",
+ "pgood",
+ &error,
+ 'i',
+ &state);
+ if(r < 0) {
+ fprintf(stderr, "Error getting property: %s\n",
+ strerror(-r));
+ goto finish;
+ }
+
+ if(dest == state)
+ goto finish;
+
+ r = sd_event_loop(loop);
+ if(r < 0) {
+ fprintf(stderr, "Error starting event loop: %s\n",
+ strerror(-r));
+ goto finish;
+ }
+
+finish:
+ exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
+}