1 /* $NetBSD: drvctl.c,v 1.23 2024/11/03 10:43:26 rillig Exp $ */ 2 3 /* 4 * Copyright (c) 2004 5 * Matthias Drochner. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions, and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <inttypes.h> 30 #include <stdbool.h> 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <unistd.h> 34 #include <err.h> 35 #include <fcntl.h> 36 #include <string.h> 37 #include <sys/ioctl.h> 38 #include <sys/drvctlio.h> 39 40 41 #define OPEN_MODE(mode) \ 42 (((mode) == 'd' || (mode) == 'r') ? O_RDWR \ 43 : O_RDONLY) 44 45 __dead static void usage(void); 46 static void extract_property(prop_dictionary_t, const char *, bool); 47 static void display_object(prop_object_t, bool); 48 static void list_children(int, char *, bool, bool, int); 49 50 static void 51 usage(void) 52 { 53 const char *p = getprogname(); 54 55 fprintf(stderr, "Usage: %s -r [-a attribute] busdevice [locator ...]\n" 56 " %s -d device\n" 57 " %s [-nt] -l [device]\n" 58 " %s [-n] -p device [property]\n" 59 " %s -Q device\n" 60 " %s -R device\n" 61 " %s -S device\n", p, p, p, p, p, p, p); 62 exit(EXIT_FAILURE); 63 } 64 65 int 66 main(int argc, char **argv) 67 { 68 bool nflag = false, tflag = false; 69 int c, mode; 70 char *attr = 0; 71 int fd, res; 72 struct devpmargs paa = { .devname = "", .flags = 0 }; 73 struct devdetachargs daa; 74 struct devrescanargs raa; 75 int *locs, i; 76 prop_dictionary_t command_dict, args_dict, results_dict, data_dict; 77 char *xml; 78 int drvctl_error; 79 80 mode = 0; 81 while ((c = getopt(argc, argv, "QRSa:dlnprt")) != -1) { 82 switch (c) { 83 case 'Q': 84 case 'R': 85 case 'S': 86 case 'd': 87 case 'l': 88 case 'p': 89 case 'r': 90 mode = c; 91 break; 92 case 'a': 93 attr = optarg; 94 break; 95 case 'n': 96 nflag = true; 97 break; 98 case 't': 99 tflag = nflag = true; 100 break; 101 case '?': 102 default: 103 usage(); 104 } 105 } 106 107 argc -= optind; 108 argv += optind; 109 110 if ((argc < 1 && mode != 'l') || mode == 0) 111 usage(); 112 113 fd = open(DRVCTLDEV, OPEN_MODE(mode), 0); 114 if (fd == -1) 115 err(EXIT_FAILURE, "open %s", DRVCTLDEV); 116 117 switch (mode) { 118 case 'Q': 119 paa.flags = DEVPM_F_SUBTREE; 120 /*FALLTHROUGH*/ 121 case 'R': 122 strlcpy(paa.devname, argv[0], sizeof(paa.devname)); 123 124 if (ioctl(fd, DRVRESUMEDEV, &paa) == -1) 125 err(EXIT_FAILURE, "DRVRESUMEDEV"); 126 break; 127 case 'S': 128 strlcpy(paa.devname, argv[0], sizeof(paa.devname)); 129 130 if (ioctl(fd, DRVSUSPENDDEV, &paa) == -1) 131 err(EXIT_FAILURE, "DRVSUSPENDDEV"); 132 break; 133 case 'd': 134 strlcpy(daa.devname, argv[0], sizeof(daa.devname)); 135 136 if (ioctl(fd, DRVDETACHDEV, &daa) == -1) 137 err(EXIT_FAILURE, "DRVDETACHDEV"); 138 break; 139 case 'l': 140 list_children(fd, argc ? argv[0] : NULL, nflag, tflag, 0); 141 break; 142 case 'r': 143 memset(&raa, 0, sizeof(raa)); 144 strlcpy(raa.busname, argv[0], sizeof(raa.busname)); 145 if (attr) 146 strlcpy(raa.ifattr, attr, sizeof(raa.ifattr)); 147 if (argc > 1) { 148 locs = malloc((argc - 1) * sizeof(int)); 149 if (!locs) 150 err(EXIT_FAILURE, "malloc int[%d]", argc - 1); 151 for (i = 0; i < argc - 1; i++) 152 locs[i] = atoi(argv[i + 1]); 153 raa.numlocators = argc - 1; 154 raa.locators = locs; 155 } 156 157 if (ioctl(fd, DRVRESCANBUS, &raa) == -1) 158 err(EXIT_FAILURE, "DRVRESCANBUS"); 159 break; 160 case 'p': 161 command_dict = prop_dictionary_create(); 162 args_dict = prop_dictionary_create(); 163 164 prop_dictionary_set_string_nocopy(command_dict, 165 "drvctl-command", "get-properties"); 166 prop_dictionary_set_string(args_dict, "device-name", 167 argv[0]); 168 prop_dictionary_set_and_rel(command_dict, "drvctl-arguments", 169 args_dict); 170 171 res = prop_dictionary_sendrecv_ioctl(command_dict, fd, 172 DRVCTLCOMMAND, &results_dict); 173 prop_object_release(command_dict); 174 if (res) 175 errc(EXIT_FAILURE, res, "DRVCTLCOMMAND"); 176 177 if (prop_dictionary_get_int(results_dict, "drvctl-error", 178 &drvctl_error) && 179 drvctl_error != 0) { 180 errc(EXIT_FAILURE, drvctl_error, "get-properties"); 181 } 182 183 data_dict = prop_dictionary_get(results_dict, 184 "drvctl-result-data"); 185 if (data_dict == NULL) { 186 errx(EXIT_FAILURE, 187 "get-properties: failed to return result data"); 188 } 189 190 if (argc == 1) { 191 xml = prop_dictionary_externalize(data_dict); 192 if (!nflag) { 193 printf("Properties for device `%s':\n", 194 argv[0]); 195 } 196 printf("%s", xml); 197 free(xml); 198 } else { 199 for (i = 1; i < argc; i++) 200 extract_property(data_dict, argv[i], nflag); 201 } 202 203 prop_object_release(results_dict); 204 break; 205 default: 206 errx(EXIT_FAILURE, "unknown command `%c'", mode); 207 } 208 209 return EXIT_SUCCESS; 210 } 211 212 static void 213 extract_property(prop_dictionary_t dict, const char *prop, bool nflag) 214 { 215 char *s, *p, *cur, *ep = NULL; 216 prop_object_t obj; 217 unsigned long ind; 218 219 obj = dict; 220 cur = NULL; 221 s = strdup(prop); 222 p = strtok_r(s, "/", &ep); 223 while (p) { 224 cur = p; 225 p = strtok_r(NULL, "/", &ep); 226 227 switch (prop_object_type(obj)) { 228 case PROP_TYPE_DICTIONARY: 229 obj = prop_dictionary_get(obj, cur); 230 if (obj == NULL) 231 p = NULL; 232 break; 233 case PROP_TYPE_ARRAY: 234 ind = strtoul(cur, NULL, 0); 235 obj = prop_array_get(obj, ind); 236 if (obj == NULL) 237 p = NULL; 238 break; 239 default: 240 fprintf(stderr, "Select neither dict nor array with" 241 " `%s'\n", cur); 242 obj = NULL; 243 p = NULL; 244 break; 245 } 246 } 247 248 if (obj != NULL && cur != NULL) 249 display_object(obj, nflag); 250 251 free(s); 252 } 253 254 static void 255 display_object(prop_object_t obj, bool nflag) 256 { 257 char *xml; 258 prop_object_t next_obj; 259 prop_object_iterator_t iter; 260 261 if (obj == NULL) 262 exit(EXIT_FAILURE); 263 switch (prop_object_type(obj)) { 264 case PROP_TYPE_BOOL: 265 printf("%s\n", prop_bool_true(obj) ? "true" : "false"); 266 break; 267 case PROP_TYPE_NUMBER: 268 printf("%" PRId64 "\n", prop_number_signed_value(obj)); 269 break; 270 case PROP_TYPE_STRING: 271 printf("%s\n", prop_string_value(obj)); 272 break; 273 case PROP_TYPE_DICTIONARY: 274 xml = prop_dictionary_externalize(obj); 275 printf("%s", xml); 276 free(xml); 277 break; 278 case PROP_TYPE_ARRAY: 279 iter = prop_array_iterator(obj); 280 if (!nflag) 281 printf("Array:\n"); 282 while ((next_obj = prop_object_iterator_next(iter)) != NULL) 283 display_object(next_obj, nflag); 284 break; 285 default: 286 errx(EXIT_FAILURE, "Unhandled type %d", prop_object_type(obj)); 287 } 288 } 289 290 static void 291 list_children(int fd, char *dvname, bool nflag, bool tflag, int depth) 292 { 293 struct devlistargs laa = { 294 .l_devname = "", .l_childname = NULL, .l_children = 0 295 }; 296 size_t children; 297 int i, n; 298 299 if (dvname == NULL) { 300 if (depth > 0) 301 return; 302 *laa.l_devname = '\0'; 303 } else { 304 strlcpy(laa.l_devname, dvname, sizeof(laa.l_devname)); 305 } 306 307 if (ioctl(fd, DRVLISTDEV, &laa) == -1) 308 err(EXIT_FAILURE, "DRVLISTDEV"); 309 310 children = laa.l_children; 311 312 laa.l_childname = malloc(children * sizeof(laa.l_childname[0])); 313 if (laa.l_childname == NULL) 314 err(EXIT_FAILURE, "DRVLISTDEV"); 315 if (ioctl(fd, DRVLISTDEV, &laa) == -1) 316 err(EXIT_FAILURE, "DRVLISTDEV"); 317 if (laa.l_children > children) 318 err(EXIT_FAILURE, "DRVLISTDEV: number of children grew"); 319 320 for (i = 0; i < (int)laa.l_children; i++) { 321 for (n = 0; n < depth; n++) 322 printf(" "); 323 if (!nflag) { 324 printf("%s ", 325 (dvname == NULL) ? "root" : laa.l_devname); 326 } 327 printf("%s\n", laa.l_childname[i]); 328 if (tflag) { 329 list_children(fd, laa.l_childname[i], nflag, 330 tflag, depth + 1); 331 } 332 } 333 334 free(laa.l_childname); 335 } 336