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 "mapper.h"
17
18 #include <errno.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <systemd/sd-bus.h>
22 #include <systemd/sd-event.h>
23 #include <unistd.h>
24
quit(int r,void * loop)25 static void quit(int r, void* loop)
26 {
27 sd_event_exit((sd_event*)loop, r);
28 }
29
wait_main(int argc,char * argv[])30 static int wait_main(int argc, char* argv[])
31 {
32 int r;
33 sd_bus* conn = NULL;
34 sd_event* loop = NULL;
35 mapper_async_wait* wait = NULL;
36 size_t attempts = 0;
37 const size_t max_attempts = 20;
38
39 if (argc < 3)
40 {
41 fprintf(stderr, "Usage: %s wait OBJECTPATH...\n", argv[0]);
42 exit(EXIT_FAILURE);
43 }
44
45 /* Mapper waits are typically run early in the boot process, and in some
46 * cases the CPU and/or object manager daemon are so busy that the
47 * GetObject call may fail with a timeout and cause the event loop to exit.
48 * If this happens, retry a few times. Don't retry on other failures.
49 */
50 while (1)
51 {
52 attempts++;
53
54 r = sd_bus_default(&conn);
55 if (r < 0)
56 {
57 fprintf(stderr, "Error connecting to system bus: %s\n",
58 strerror(-r));
59 goto finish;
60 }
61
62 r = sd_event_default(&loop);
63 if (r < 0)
64 {
65 fprintf(stderr, "Error obtaining event loop: %s\n", strerror(-r));
66
67 goto finish;
68 }
69
70 r = sd_bus_attach_event(conn, loop, SD_EVENT_PRIORITY_NORMAL);
71 if (r < 0)
72 {
73 fprintf(stderr,
74 "Failed to attach system "
75 "bus to event loop: %s\n",
76 strerror(-r));
77 goto finish;
78 }
79
80 r = mapper_wait_async(conn, loop, argv + 2, quit, loop, &wait);
81 if (r < 0)
82 {
83 fprintf(stderr, "Error configuring waitlist: %s\n", strerror(-r));
84 goto finish;
85 }
86
87 r = sd_event_loop(loop);
88 if (r < 0)
89 {
90 fprintf(stderr, "Event loop exited: %s\n", strerror(-r));
91
92 if (-r == ETIMEDOUT || -r == EHOSTUNREACH)
93 {
94 if (attempts <= max_attempts)
95 {
96 fprintf(stderr, "Retrying in 1s\n");
97 sleep(1);
98 sd_event_unref(loop);
99 sd_bus_unref(conn);
100 continue;
101 }
102 else
103 {
104 fprintf(stderr, "Giving up\n");
105 }
106 }
107 else
108 {
109 goto finish;
110 }
111 }
112
113 break;
114 }
115
116 finish:
117 exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
118 }
119
subtree_main(int argc,char * argv[])120 static int subtree_main(int argc, char* argv[])
121 {
122 int r = 0;
123 int op = 0;
124 static const char* token = ":";
125 char* tmp = NULL;
126 char* namespace = NULL;
127 char* interface = NULL;
128 sd_bus* conn = NULL;
129 sd_event* loop = NULL;
130 mapper_async_subtree* subtree = NULL;
131
132 if (argc != 3)
133 {
134 fprintf(stderr,
135 "Usage: %s subtree-remove "
136 "NAMESPACE%sINTERFACE\n",
137 argv[0], token);
138 exit(EXIT_FAILURE);
139 }
140
141 op = MAPPER_OP_REMOVE;
142
143 namespace = strtok_r(argv[2], token, &tmp);
144 interface = strtok_r(NULL, token, &tmp);
145 if ((namespace == NULL) || (interface == NULL))
146 {
147 fprintf(stderr, "Token '%s' was not found in '%s'\n", token, argv[2]);
148 exit(EXIT_FAILURE);
149 }
150
151 r = sd_bus_default(&conn);
152 if (r < 0)
153 {
154 fprintf(stderr, "Error connecting to system bus: %s\n", strerror(-r));
155 goto finish;
156 }
157
158 r = sd_event_default(&loop);
159 if (r < 0)
160 {
161 fprintf(stderr, "Error obtaining event loop: %s\n", strerror(-r));
162 goto finish;
163 }
164
165 r = sd_bus_attach_event(conn, loop, SD_EVENT_PRIORITY_NORMAL);
166 if (r < 0)
167 {
168 fprintf(stderr, "Failed to attach system bus to event loop: %s\n",
169 strerror(-r));
170 goto finish;
171 }
172
173 r = mapper_subtree_async(conn, loop, namespace, interface, quit, loop,
174 &subtree, op);
175 if (r < 0)
176 {
177 fprintf(stderr, "Error configuring subtree list: %s\n", strerror(-r));
178 goto finish;
179 }
180
181 r = sd_event_loop(loop);
182 if (r < 0)
183 {
184 /* If this function has been called after the interface in */
185 /* question has already been removed, then GetSubTree will */
186 /* fail and it will show up here. Treat as success instead. */
187 if (r == -ENXIO)
188 {
189 r = 0;
190 }
191 else
192 {
193 fprintf(stderr, "Error starting event loop: %d(%s)\n", r,
194 strerror(-r));
195 goto finish;
196 }
197 }
198
199 finish:
200 exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
201 }
202
203 /* print out the distinct dbus service name for the input dbus path */
get_service_main(int argc,char * argv[])204 static int get_service_main(int argc, char* argv[])
205 {
206 int r;
207 sd_bus* conn = NULL;
208 char* service = NULL;
209
210 if (argc != 3)
211 {
212 fprintf(stderr, "Usage: %s get-service OBJECTPATH\n", argv[0]);
213 exit(EXIT_FAILURE);
214 }
215
216 r = sd_bus_default(&conn);
217 if (r < 0)
218 {
219 fprintf(stderr, "Error connecting to system bus: %s\n", strerror(-r));
220 goto finish;
221 }
222
223 r = mapper_get_service(conn, argv[2], &service);
224 if (r < 0)
225 {
226 fprintf(stderr, "Error finding '%s' service: %s\n", argv[2],
227 strerror(-r));
228 goto finish;
229 }
230
231 printf("%s\n", service);
232
233 finish:
234 exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
235 }
236
main(int argc,char * argv[])237 int main(int argc, char* argv[])
238 {
239 static const char* usage =
240 "Usage: %s {COMMAND} ...\n"
241 "\nCOMMANDS:\n"
242 " wait wait for the specified objects to appear on the "
243 "DBus\n"
244 " subtree-remove\n"
245 " wait until the specified interface is not present\n"
246 " in any of the subtrees of the specified namespace\n"
247 " get-service return the service identifier for input path\n";
248
249 if (argc < 2)
250 {
251 fprintf(stderr, usage, argv[0]);
252 exit(EXIT_FAILURE);
253 }
254
255 if (!strcmp(argv[1], "wait"))
256 {
257 wait_main(argc, argv);
258 }
259
260 if (!strcmp(argv[1], "subtree-remove"))
261 {
262 subtree_main(argc, argv);
263 }
264
265 if (!strcmp(argv[1], "get-service"))
266 {
267 get_service_main(argc, argv);
268 }
269
270 fprintf(stderr, usage, argv[0]);
271 exit(EXIT_FAILURE);
272 }
273