| /** | |
| * 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 <errno.h> | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <systemd/sd-bus.h> | |
| #include <systemd/sd-event.h> | |
| #include <unistd.h> | |
| #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 = 20; | |
| 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(&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 1s\n"); | |
| sleep(1); | |
| 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(&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(&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); | |
| } |