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