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