1 /**
2  * Copyright © 2016 IBM Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <errno.h>
19 #include <systemd/sd-bus.h>
20 #include <systemd/sd-event.h>
21 #include <mapper.h>
22 
23 static void quit(int r, void *loop)
24 {
25 	sd_event_exit((sd_event *)loop, r);
26 }
27 
28 static int callback(sd_bus_message *m, void *user, sd_bus_error *error)
29 {
30 	sd_event *loop = user;
31 	int r;
32 	char *property = NULL;
33 
34 	r = sd_bus_message_skip(m, "s");
35 	if (r < 0) {
36 		fprintf(stderr, "Error skipping message fields: %s\n",
37 				strerror(-r));
38 		quit(r, loop);
39 		return r;
40 	}
41 
42 	r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
43 	if (r < 0) {
44 		fprintf(stderr, "Error entering container: %s\n",
45 				strerror(-r));
46 		quit(r, loop);
47 		return r;
48 	}
49 
50 	while((r = sd_bus_message_enter_container(
51 					m,
52 					SD_BUS_TYPE_DICT_ENTRY,
53 					"sv")) > 0) {
54 		r = sd_bus_message_read(m, "s", &property);
55 		if (r < 0) {
56 			fprintf(stderr, "Error reading message: %s\n",
57 					strerror(-r));
58 			quit(r, loop);
59 			return r;
60 		}
61 
62 		if(strcmp(property, "pgood"))
63 			continue;
64 
65 		quit(0, loop);
66 		break;
67 	}
68 
69 	return 0;
70 }
71 
72 int main(int argc, char *argv[])
73 {
74 	static const char *matchfmt =
75 		"type='signal',"
76 		"interface='org.freedesktop.DBus.Properties',"
77 		"member='PropertiesChanged',"
78 		"arg0='org.openbmc.control.Power',"
79 		"path='%s',"
80 		"sender='%s'";
81 	static const char *usage =
82 		"Usage: %s OBJECTPATH on|off\n";
83 	static const size_t LEN = 256;
84 
85 	sd_bus *conn = NULL;
86 	sd_event *loop = NULL;
87 	sd_bus_slot *slot = NULL;
88 	sd_bus_error error = SD_BUS_ERROR_NULL;
89 	char *service = NULL;
90 	int r, dest = -1, state;
91 	char match[LEN];
92 
93 	if(argc < 3) {
94 		fprintf(stderr, usage, argv[0]);
95 		exit(EXIT_FAILURE);
96 	}
97 
98 	if(!strcmp(argv[2], "on"))
99 		dest = 1;
100 	if(!strcmp(argv[2], "off"))
101 		dest = 0;
102 
103 	if(dest != 0 && dest != 1) {
104 		fprintf(stderr, usage, argv[0]);
105 		exit(EXIT_FAILURE);
106 	}
107 
108 	r = sd_bus_default_system(&conn);
109 	if(r < 0) {
110 		fprintf(stderr, "Error connecting to system bus: %s\n",
111 				strerror(-r));
112 		goto finish;
113 	}
114 
115 	r = mapper_get_service(conn, argv[1], &service);
116 	if (r < 0) {
117 		fprintf(stderr, "Error obtaining host service: %s\n",
118 				strerror(-r));
119 		goto finish;
120 	}
121 
122 	r = sd_event_default(&loop);
123 	if (r < 0) {
124 		fprintf(stderr, "Error obtaining event loop: %s\n",
125 				strerror(-r));
126 		goto finish;
127 	}
128 
129 	r = sd_bus_attach_event(conn, loop, SD_EVENT_PRIORITY_NORMAL);
130 	if (r < 0) {
131 		fprintf(stderr, "Failed to attach system "
132 				"bus to event loop: %s\n",
133 				strerror(-r));
134 		goto finish;
135 	}
136 
137 	if(strlen(matchfmt) + strnlen(argv[1], LEN) > LEN) {
138 		r = -E2BIG;
139 		fprintf(stderr, "Error adding match rule: %s\n",
140 				strerror(-r));
141 		goto finish;
142 	}
143 
144 	sprintf(match, matchfmt, argv[1], service);
145 
146 	r = sd_bus_add_match(conn,
147 			&slot,
148 			match,
149 			callback,
150 			loop);
151 	if(r < 0) {
152 		fprintf(stderr, "Error adding match rule: %s\n",
153 				strerror(-r));
154 		goto finish;
155 	}
156 
157 	r = sd_bus_get_property_trivial(conn,
158 			service,
159 			argv[1],
160 			"org.openbmc.control.Power",
161 			"pgood",
162 			&error,
163 			'i',
164 			&state);
165 	if(r < 0) {
166 		fprintf(stderr, "Error getting property: %s\n",
167 				strerror(-r));
168 		goto finish;
169 	}
170 
171 	if(dest == state)
172 		goto finish;
173 
174 	r = sd_event_loop(loop);
175 	if(r < 0) {
176 		fprintf(stderr, "Error starting event loop: %s\n",
177 				strerror(-r));
178 		goto finish;
179 	}
180 
181 finish:
182 	exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
183 }
184