/** * 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 "config.h" #include #include #include #include #include #include #include "mapper.h" static void quit(int r, void* loop) { sd_event_exit((sd_event*)loop, r); } static int wait_main(int argc, char* argv[]) { int r; sd_bus* conn = NULL; sd_event* loop = NULL; mapper_async_wait* wait = NULL; size_t attempts = 0; const size_t max_attempts = 4; if (argc < 3) { fprintf(stderr, "Usage: %s wait OBJECTPATH...\n", argv[0]); exit(EXIT_FAILURE); } /* Mapper waits are typically run early in the boot process, and in some * cases the CPU and/or object manager daemon are so busy that the * GetObject call may fail with a timeout and cause the event loop to exit. * If this happens, retry a few times. Don't retry on other failures. */ while (1) { attempts++; r = sd_bus_default_system(&conn); if (r < 0) { fprintf(stderr, "Error connecting to system bus: %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; } r = mapper_wait_async(conn, loop, argv + 2, quit, loop, &wait); if (r < 0) { fprintf(stderr, "Error configuring waitlist: %s\n", strerror(-r)); goto finish; } r = sd_event_loop(loop); if (r < 0) { fprintf(stderr, "Event loop exited: %s\n", strerror(-r)); if (-r == ETIMEDOUT || -r == EHOSTUNREACH) { if (attempts <= max_attempts) { fprintf(stderr, "Retrying in 5s\n"); sleep(5); sd_event_unref(loop); sd_bus_unref(conn); continue; } else { fprintf(stderr, "Giving up\n"); } } else { goto finish; } } break; } finish: exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS); } static int subtree_main(int argc, char* argv[]) { int r = 0; int op = 0; static const char* token = ":"; char* tmp = NULL; char* namespace = NULL; char* interface = NULL; sd_bus* conn = NULL; sd_event* loop = NULL; mapper_async_subtree* subtree = NULL; if (argc != 3) { fprintf(stderr, "Usage: %s subtree-remove " "NAMESPACE%sINTERFACE\n", argv[0], token); exit(EXIT_FAILURE); } op = MAPPER_OP_REMOVE; namespace = strtok_r(argv[2], token, &tmp); interface = strtok_r(NULL, token, &tmp); if ((namespace == NULL) || (interface == NULL)) { fprintf(stderr, "Token '%s' was not found in '%s'\n", token, argv[2]); 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 = 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; } r = mapper_subtree_async(conn, loop, namespace, interface, quit, loop, &subtree, op); if (r < 0) { fprintf(stderr, "Error configuring subtree list: %s\n", strerror(-r)); goto finish; } r = sd_event_loop(loop); if (r < 0) { /* If this function has been called after the interface in */ /* question has already been removed, then GetSubTree will */ /* fail and it will show up here. Treat as success instead. */ if (r == -ENXIO) { r = 0; } else { fprintf(stderr, "Error starting event loop: %d(%s)\n", r, strerror(-r)); goto finish; } } finish: exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS); } /* print out the distinct dbus service name for the input dbus path */ static int get_service_main(int argc, char* argv[]) { int r; sd_bus* conn = NULL; char* service = NULL; if (argc != 3) { fprintf(stderr, "Usage: %s get-service OBJECTPATH\n", 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[2], &service); if (r < 0) { fprintf(stderr, "Error finding '%s' service: %s\n", argv[2], strerror(-r)); goto finish; } printf("%s\n", service); finish: exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS); } int main(int argc, char* argv[]) { static const char* usage = "Usage: %s {COMMAND} ...\n" "\nCOMMANDS:\n" " wait wait for the specified objects to appear on the " "DBus\n" " subtree-remove\n" " wait until the specified interface is not present\n" " in any of the subtrees of the specified namespace\n" " get-service return the service identifier for input path\n"; if (argc < 2) { fprintf(stderr, usage, argv[0]); exit(EXIT_FAILURE); } if (!strcmp(argv[1], "wait")) wait_main(argc, argv); if (!strcmp(argv[1], "subtree-remove")) subtree_main(argc, argv); if (!strcmp(argv[1], "get-service")) get_service_main(argc, argv); fprintf(stderr, usage, argv[0]); exit(EXIT_FAILURE); }