| /** |
| * 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 <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 = 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); |
| } |