12afe718fSBrad Bishop /**
2981f2661SAndrew Geissler * Copyright 2016 IBM Corporation
32afe718fSBrad Bishop *
42afe718fSBrad Bishop * Licensed under the Apache License, Version 2.0 (the "License");
52afe718fSBrad Bishop * you may not use this file except in compliance with the License.
62afe718fSBrad Bishop * You may obtain a copy of the License at
72afe718fSBrad Bishop *
82afe718fSBrad Bishop * http://www.apache.org/licenses/LICENSE-2.0
92afe718fSBrad Bishop *
102afe718fSBrad Bishop * Unless required by applicable law or agreed to in writing, software
112afe718fSBrad Bishop * distributed under the License is distributed on an "AS IS" BASIS,
122afe718fSBrad Bishop * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132afe718fSBrad Bishop * See the License for the specific language governing permissions and
142afe718fSBrad Bishop * limitations under the License.
152afe718fSBrad Bishop */
16*cf72403dSGeorge Liu #include "mapper.h"
17*cf72403dSGeorge Liu
1859cbf346SMatt Spinler #include <errno.h>
192afe718fSBrad Bishop #include <stdio.h>
20cc6ee9cbSMatt Spinler #include <stdlib.h>
212afe718fSBrad Bishop #include <systemd/sd-bus.h>
222afe718fSBrad Bishop #include <systemd/sd-event.h>
235592202fSMatt Spinler #include <unistd.h>
24cc6ee9cbSMatt Spinler
quit(int r,void * loop)252afe718fSBrad Bishop static void quit(int r, void* loop)
262afe718fSBrad Bishop {
272afe718fSBrad Bishop sd_event_exit((sd_event*)loop, r);
282afe718fSBrad Bishop }
292afe718fSBrad Bishop
wait_main(int argc,char * argv[])302afe718fSBrad Bishop static int wait_main(int argc, char* argv[])
312afe718fSBrad Bishop {
322afe718fSBrad Bishop int r;
332afe718fSBrad Bishop sd_bus* conn = NULL;
342afe718fSBrad Bishop sd_event* loop = NULL;
352afe718fSBrad Bishop mapper_async_wait* wait = NULL;
365592202fSMatt Spinler size_t attempts = 0;
37af3d797bSPatrick Williams const size_t max_attempts = 20;
382afe718fSBrad Bishop
39167e2379SEd Tanous if (argc < 3)
40167e2379SEd Tanous {
412afe718fSBrad Bishop fprintf(stderr, "Usage: %s wait OBJECTPATH...\n", argv[0]);
422afe718fSBrad Bishop exit(EXIT_FAILURE);
432afe718fSBrad Bishop }
442afe718fSBrad Bishop
455592202fSMatt Spinler /* Mapper waits are typically run early in the boot process, and in some
465592202fSMatt Spinler * cases the CPU and/or object manager daemon are so busy that the
475592202fSMatt Spinler * GetObject call may fail with a timeout and cause the event loop to exit.
485592202fSMatt Spinler * If this happens, retry a few times. Don't retry on other failures.
495592202fSMatt Spinler */
505592202fSMatt Spinler while (1)
515592202fSMatt Spinler {
525592202fSMatt Spinler attempts++;
535592202fSMatt Spinler
54f15b06ceSBrad Bishop r = sd_bus_default(&conn);
55167e2379SEd Tanous if (r < 0)
56167e2379SEd Tanous {
575592202fSMatt Spinler fprintf(stderr, "Error connecting to system bus: %s\n",
585592202fSMatt Spinler strerror(-r));
592afe718fSBrad Bishop goto finish;
602afe718fSBrad Bishop }
612afe718fSBrad Bishop
622afe718fSBrad Bishop r = sd_event_default(&loop);
63167e2379SEd Tanous if (r < 0)
64167e2379SEd Tanous {
65167e2379SEd Tanous fprintf(stderr, "Error obtaining event loop: %s\n", strerror(-r));
662afe718fSBrad Bishop
672afe718fSBrad Bishop goto finish;
682afe718fSBrad Bishop }
692afe718fSBrad Bishop
702afe718fSBrad Bishop r = sd_bus_attach_event(conn, loop, SD_EVENT_PRIORITY_NORMAL);
71167e2379SEd Tanous if (r < 0)
72167e2379SEd Tanous {
73167e2379SEd Tanous fprintf(stderr,
74167e2379SEd Tanous "Failed to attach system "
752afe718fSBrad Bishop "bus to event loop: %s\n",
762afe718fSBrad Bishop strerror(-r));
772afe718fSBrad Bishop goto finish;
782afe718fSBrad Bishop }
792afe718fSBrad Bishop
80c7a7c45fSAdriana Kobylak r = mapper_wait_async(conn, loop, argv + 2, quit, loop, &wait);
81167e2379SEd Tanous if (r < 0)
82167e2379SEd Tanous {
83167e2379SEd Tanous fprintf(stderr, "Error configuring waitlist: %s\n", strerror(-r));
842afe718fSBrad Bishop goto finish;
852afe718fSBrad Bishop }
862afe718fSBrad Bishop
872afe718fSBrad Bishop r = sd_event_loop(loop);
88167e2379SEd Tanous if (r < 0)
89167e2379SEd Tanous {
905592202fSMatt Spinler fprintf(stderr, "Event loop exited: %s\n", strerror(-r));
915592202fSMatt Spinler
92551fafbcSWilliam A. Kennington III if (-r == ETIMEDOUT || -r == EHOSTUNREACH)
935592202fSMatt Spinler {
945592202fSMatt Spinler if (attempts <= max_attempts)
955592202fSMatt Spinler {
96af3d797bSPatrick Williams fprintf(stderr, "Retrying in 1s\n");
97af3d797bSPatrick Williams sleep(1);
985592202fSMatt Spinler sd_event_unref(loop);
995592202fSMatt Spinler sd_bus_unref(conn);
1005592202fSMatt Spinler continue;
1015592202fSMatt Spinler }
1025592202fSMatt Spinler else
1035592202fSMatt Spinler {
1045592202fSMatt Spinler fprintf(stderr, "Giving up\n");
1055592202fSMatt Spinler }
1065592202fSMatt Spinler }
1075592202fSMatt Spinler else
1085592202fSMatt Spinler {
1092afe718fSBrad Bishop goto finish;
1102afe718fSBrad Bishop }
1115592202fSMatt Spinler }
1125592202fSMatt Spinler
1135592202fSMatt Spinler break;
1145592202fSMatt Spinler }
1152afe718fSBrad Bishop
1162afe718fSBrad Bishop finish:
1172afe718fSBrad Bishop exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
1182afe718fSBrad Bishop }
1192afe718fSBrad Bishop
subtree_main(int argc,char * argv[])12004d7c7d9SAdriana Kobylak static int subtree_main(int argc, char* argv[])
12104d7c7d9SAdriana Kobylak {
12204d7c7d9SAdriana Kobylak int r = 0;
1232a8bfc96SAdriana Kobylak int op = 0;
1246a8688f4SAdriana Kobylak static const char* token = ":";
1256a8688f4SAdriana Kobylak char* tmp = NULL;
1266a8688f4SAdriana Kobylak char* namespace = NULL;
1276a8688f4SAdriana Kobylak char* interface = NULL;
1282a8bfc96SAdriana Kobylak sd_bus* conn = NULL;
1292a8bfc96SAdriana Kobylak sd_event* loop = NULL;
1302a8bfc96SAdriana Kobylak mapper_async_subtree* subtree = NULL;
13104d7c7d9SAdriana Kobylak
132167e2379SEd Tanous if (argc != 3)
133167e2379SEd Tanous {
134167e2379SEd Tanous fprintf(stderr,
135167e2379SEd Tanous "Usage: %s subtree-remove "
136167e2379SEd Tanous "NAMESPACE%sINTERFACE\n",
137167e2379SEd Tanous argv[0], token);
1386a8688f4SAdriana Kobylak exit(EXIT_FAILURE);
1396a8688f4SAdriana Kobylak }
1406a8688f4SAdriana Kobylak
1412a8bfc96SAdriana Kobylak op = MAPPER_OP_REMOVE;
1422a8bfc96SAdriana Kobylak
1436a8688f4SAdriana Kobylak namespace = strtok_r(argv[2], token, &tmp);
1446a8688f4SAdriana Kobylak interface = strtok_r(NULL, token, &tmp);
145167e2379SEd Tanous if ((namespace == NULL) || (interface == NULL))
146167e2379SEd Tanous {
1476a8688f4SAdriana Kobylak fprintf(stderr, "Token '%s' was not found in '%s'\n", token, argv[2]);
14804d7c7d9SAdriana Kobylak exit(EXIT_FAILURE);
14904d7c7d9SAdriana Kobylak }
15004d7c7d9SAdriana Kobylak
151f15b06ceSBrad Bishop r = sd_bus_default(&conn);
152167e2379SEd Tanous if (r < 0)
153167e2379SEd Tanous {
154167e2379SEd Tanous fprintf(stderr, "Error connecting to system bus: %s\n", strerror(-r));
1552a8bfc96SAdriana Kobylak goto finish;
1562a8bfc96SAdriana Kobylak }
1572a8bfc96SAdriana Kobylak
1582a8bfc96SAdriana Kobylak r = sd_event_default(&loop);
159167e2379SEd Tanous if (r < 0)
160167e2379SEd Tanous {
161167e2379SEd Tanous fprintf(stderr, "Error obtaining event loop: %s\n", strerror(-r));
1622a8bfc96SAdriana Kobylak goto finish;
1632a8bfc96SAdriana Kobylak }
1642a8bfc96SAdriana Kobylak
1652a8bfc96SAdriana Kobylak r = sd_bus_attach_event(conn, loop, SD_EVENT_PRIORITY_NORMAL);
166167e2379SEd Tanous if (r < 0)
167167e2379SEd Tanous {
1682a8bfc96SAdriana Kobylak fprintf(stderr, "Failed to attach system bus to event loop: %s\n",
1692a8bfc96SAdriana Kobylak strerror(-r));
1702a8bfc96SAdriana Kobylak goto finish;
1712a8bfc96SAdriana Kobylak }
1722a8bfc96SAdriana Kobylak
1732a8bfc96SAdriana Kobylak r = mapper_subtree_async(conn, loop, namespace, interface, quit, loop,
1742a8bfc96SAdriana Kobylak &subtree, op);
175167e2379SEd Tanous if (r < 0)
176167e2379SEd Tanous {
177167e2379SEd Tanous fprintf(stderr, "Error configuring subtree list: %s\n", strerror(-r));
1782a8bfc96SAdriana Kobylak goto finish;
1792a8bfc96SAdriana Kobylak }
1802a8bfc96SAdriana Kobylak
1812a8bfc96SAdriana Kobylak r = sd_event_loop(loop);
182167e2379SEd Tanous if (r < 0)
183167e2379SEd Tanous {
18459cbf346SMatt Spinler /* If this function has been called after the interface in */
18559cbf346SMatt Spinler /* question has already been removed, then GetSubTree will */
18659cbf346SMatt Spinler /* fail and it will show up here. Treat as success instead. */
18759cbf346SMatt Spinler if (r == -ENXIO)
18859cbf346SMatt Spinler {
18959cbf346SMatt Spinler r = 0;
19059cbf346SMatt Spinler }
19159cbf346SMatt Spinler else
19259cbf346SMatt Spinler {
19359cbf346SMatt Spinler fprintf(stderr, "Error starting event loop: %d(%s)\n", r,
19459cbf346SMatt Spinler strerror(-r));
1952a8bfc96SAdriana Kobylak goto finish;
1962a8bfc96SAdriana Kobylak }
19759cbf346SMatt Spinler }
1982a8bfc96SAdriana Kobylak
1992a8bfc96SAdriana Kobylak finish:
20004d7c7d9SAdriana Kobylak exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
20104d7c7d9SAdriana Kobylak }
20204d7c7d9SAdriana Kobylak
203981f2661SAndrew Geissler /* print out the distinct dbus service name for the input dbus path */
get_service_main(int argc,char * argv[])204981f2661SAndrew Geissler static int get_service_main(int argc, char* argv[])
205981f2661SAndrew Geissler {
206981f2661SAndrew Geissler int r;
207981f2661SAndrew Geissler sd_bus* conn = NULL;
208981f2661SAndrew Geissler char* service = NULL;
209981f2661SAndrew Geissler
210167e2379SEd Tanous if (argc != 3)
211167e2379SEd Tanous {
212167e2379SEd Tanous fprintf(stderr, "Usage: %s get-service OBJECTPATH\n", argv[0]);
213981f2661SAndrew Geissler exit(EXIT_FAILURE);
214981f2661SAndrew Geissler }
215981f2661SAndrew Geissler
216f15b06ceSBrad Bishop r = sd_bus_default(&conn);
217167e2379SEd Tanous if (r < 0)
218167e2379SEd Tanous {
219167e2379SEd Tanous fprintf(stderr, "Error connecting to system bus: %s\n", strerror(-r));
220981f2661SAndrew Geissler goto finish;
221981f2661SAndrew Geissler }
222981f2661SAndrew Geissler
223981f2661SAndrew Geissler r = mapper_get_service(conn, argv[2], &service);
224167e2379SEd Tanous if (r < 0)
225167e2379SEd Tanous {
226167e2379SEd Tanous fprintf(stderr, "Error finding '%s' service: %s\n", argv[2],
227167e2379SEd Tanous strerror(-r));
228981f2661SAndrew Geissler goto finish;
229981f2661SAndrew Geissler }
230981f2661SAndrew Geissler
231981f2661SAndrew Geissler printf("%s\n", service);
232981f2661SAndrew Geissler
233981f2661SAndrew Geissler finish:
234981f2661SAndrew Geissler exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
235981f2661SAndrew Geissler }
236981f2661SAndrew Geissler
main(int argc,char * argv[])2372afe718fSBrad Bishop int main(int argc, char* argv[])
2382afe718fSBrad Bishop {
2392afe718fSBrad Bishop static const char* usage =
2402afe718fSBrad Bishop "Usage: %s {COMMAND} ...\n"
2412afe718fSBrad Bishop "\nCOMMANDS:\n"
242167e2379SEd Tanous " wait wait for the specified objects to appear on the "
243167e2379SEd Tanous "DBus\n"
24404d7c7d9SAdriana Kobylak " subtree-remove\n"
24504d7c7d9SAdriana Kobylak " wait until the specified interface is not present\n"
24604d7c7d9SAdriana Kobylak " in any of the subtrees of the specified namespace\n"
247981f2661SAndrew Geissler " get-service return the service identifier for input path\n";
2482afe718fSBrad Bishop
249167e2379SEd Tanous if (argc < 2)
250167e2379SEd Tanous {
2512afe718fSBrad Bishop fprintf(stderr, usage, argv[0]);
2522afe718fSBrad Bishop exit(EXIT_FAILURE);
2532afe718fSBrad Bishop }
2542afe718fSBrad Bishop
255c7a7c45fSAdriana Kobylak if (!strcmp(argv[1], "wait"))
256*cf72403dSGeorge Liu {
2572afe718fSBrad Bishop wait_main(argc, argv);
258*cf72403dSGeorge Liu }
259*cf72403dSGeorge Liu
26004d7c7d9SAdriana Kobylak if (!strcmp(argv[1], "subtree-remove"))
261*cf72403dSGeorge Liu {
26204d7c7d9SAdriana Kobylak subtree_main(argc, argv);
263*cf72403dSGeorge Liu }
264*cf72403dSGeorge Liu
265981f2661SAndrew Geissler if (!strcmp(argv[1], "get-service"))
266*cf72403dSGeorge Liu {
267981f2661SAndrew Geissler get_service_main(argc, argv);
268*cf72403dSGeorge Liu }
2692afe718fSBrad Bishop
2702afe718fSBrad Bishop fprintf(stderr, usage, argv[0]);
2712afe718fSBrad Bishop exit(EXIT_FAILURE);
2722afe718fSBrad Bishop }
273