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