1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2022 Oxide Computer Company
14 */
15
16 #include <string.h>
17 #include <err.h>
18 #include <stdlib.h>
19 #include <stdarg.h>
20 #include <ofmt.h>
21 #include <libdevinfo.h>
22 #include <strings.h>
23 #include <sys/debug.h>
24
25 #include "gpioadm.h"
26
27 static void
gpioadm_gpio_attr_get_usage(FILE * f)28 gpioadm_gpio_attr_get_usage(FILE *f)
29 {
30 (void) fprintf(f, "\tgpioadm gpio attr get [-H] [-o field[,...] [-p]] "
31 "controller/gpio [filter...]\n");
32 }
33
34 static void __PRINTFLIKE(1)
gpioadm_gpio_attr_get_help(const char * fmt,...)35 gpioadm_gpio_attr_get_help(const char *fmt, ...)
36 {
37 if (fmt != NULL) {
38 va_list ap;
39
40 va_start(ap, fmt);
41 vwarnx(fmt, ap);
42 va_end(ap);
43 }
44
45 (void) fprintf(stderr, "Usage: gpioadm gpio attr get [-H] "
46 "[-o field[,...] [-p]] controller/gpio\n\t\t\t [filter...]\n");
47 (void) fprintf(stderr, "\nList attributes of a specific GPIO\n\n"
48 "\t-H\t\tomit the column header\n"
49 "\t-o field\toutput fields to print\n"
50 "\t-p\t\tparsable output (requires -o)\n\n"
51 "The following fields are supported:\n"
52 "\tattr\t\tthe name of the attribute\n"
53 "\tvalue\t\tthe human-readable value of the attribute\n"
54 "\traw\t\tan untranslated value of the attribute (e.g. "
55 "underlying\n\t\t\tenum)\n"
56 "\tperm\t\tthe permissions of the attribute\n"
57 "\tpossible\tthe possible values the attribute may take\n\n"
58 "Supported filters are the names of attributes. An attribute "
59 "will be printed\nas long as it matches a single filter (they "
60 "function as an OR). If any\nfilter does not match, then a non-"
61 "zero exit status is returned.\n");
62 }
63
64 typedef enum gpioadm_gpio_attr_get_otype {
65 GPIOADM_GPIO_ATTR_GET_ATTR,
66 GPIOADM_GPIO_ATTR_GET_VALUE,
67 GPIOADM_GPIO_ATTR_GET_RAW,
68 GPIOADM_GPIO_ATTR_GET_PERM,
69 GPIOADM_GPIO_ATTR_GET_POSSIBLE,
70 } gpioadm_gpio_attr_get_otype_t;
71
72 typedef struct gpioadm_gpio_attr_get_ofmt {
73 xpio_gpio_info_t *ggag_info;
74 xpio_gpio_attr_t *ggag_attr;
75 } gpioadm_gpio_attr_get_ofmt_t;
76
77 static boolean_t
gpioadm_gpio_attr_get_ofmt_cb(ofmt_arg_t * ofarg,char * buf,uint_t buflen)78 gpioadm_gpio_attr_get_ofmt_cb(ofmt_arg_t *ofarg, char *buf, uint_t buflen)
79 {
80 const char *str;
81 uint32_t u32;
82 uint32_t *u32_arr;
83 const char **str_arr;
84 uint_t count;
85 uintptr_t off = 0;
86
87 gpioadm_gpio_attr_get_ofmt_t *ggag = ofarg->ofmt_cbarg;
88 xpio_gpio_info_t *info = ggag->ggag_info;
89 xpio_gpio_attr_t *attr = ggag->ggag_attr;
90
91 switch (ofarg->ofmt_id) {
92 case GPIOADM_GPIO_ATTR_GET_ATTR:
93 if (strlcpy(buf, xpio_gpio_attr_name(info, attr), buflen) >=
94 buflen) {
95 return (B_FALSE);
96 }
97 break;
98 case GPIOADM_GPIO_ATTR_GET_VALUE:
99 switch (xpio_gpio_attr_type(info, attr)) {
100 case XPIO_ATTR_TYPE_STRING:
101 if (!xpio_gpio_attr_value_string(attr, &str)) {
102 return (B_FALSE);
103 }
104
105 if (strlcpy(buf, str, buflen) >= buflen) {
106 return (B_FALSE);
107 }
108 break;
109 case XPIO_ATTR_TYPE_UINT32:
110 if (!xpio_gpio_attr_xlate_to_str(info, attr, buf,
111 buflen)) {
112 return (B_FALSE);
113 }
114 break;
115 }
116 break;
117 case GPIOADM_GPIO_ATTR_GET_RAW:
118 switch (xpio_gpio_attr_type(info, attr)) {
119 case XPIO_ATTR_TYPE_STRING:
120 if (!xpio_gpio_attr_value_string(attr, &str)) {
121 return (B_FALSE);
122 }
123
124 if (strlcpy(buf, str, buflen) >= buflen) {
125 return (B_FALSE);
126 }
127 break;
128 case XPIO_ATTR_TYPE_UINT32:
129 if (!xpio_gpio_attr_value_uint32(attr, &u32)) {
130 return (B_FALSE);
131 }
132
133 if (snprintf(buf, buflen, "0x%x", u32) >= buflen) {
134 return (B_FALSE);
135 }
136 break;
137 }
138 break;
139 case GPIOADM_GPIO_ATTR_GET_PERM:
140 switch (xpio_gpio_attr_prot(info, attr)) {
141 case XPIO_ATTR_PROT_RO:
142 if (strlcpy(buf, "r-", buflen) >= buflen) {
143 return (B_FALSE);
144 }
145 break;
146 case XPIO_ATTR_PROT_RW:
147 if (strlcpy(buf, "rw", buflen) >= buflen) {
148 return (B_FALSE);
149 }
150 break;
151 }
152 break;
153 case GPIOADM_GPIO_ATTR_GET_POSSIBLE:
154 switch (xpio_gpio_attr_type(info, attr)) {
155 case XPIO_ATTR_TYPE_STRING:
156 xpio_gpio_attr_possible_string(info, attr, &str_arr,
157 &count);
158 for (uint_t i = 0; i < count; i++) {
159 int len = snprintf(buf + off, buflen - off,
160 "%s%s", i > 0 ? "," : "", str_arr[i]);
161 if (len >= (buflen - off)) {
162 return (B_FALSE);
163 }
164 off += len;
165 }
166 break;
167 case XPIO_ATTR_TYPE_UINT32:
168 xpio_gpio_attr_possible_uint32(info, attr, &u32_arr,
169 &count);
170 for (uint_t i = 0; i < count; i++) {
171 char xlate[512];
172 if (!xpio_gpio_attr_xlate_uint32_to_str(info,
173 attr, u32_arr[i], xlate, sizeof (xlate))) {
174 return (B_FALSE);
175 }
176 int len = snprintf(buf + off, buflen - off,
177 "%s%s", i > 0 ? "," : "", xlate);
178 if (len >= (buflen - off)) {
179 return (B_FALSE);
180 }
181 off += len;
182 }
183 break;
184 }
185 break;
186 default:
187 abort();
188 }
189
190 return (B_TRUE);
191 }
192
193 static const char *gpioadm_gpio_attr_get_fields = "attr,perm,value,possible";
194 static const ofmt_field_t gpioadm_gpio_attr_get_ofmt[] = {
195 { "ATTR", 22, GPIOADM_GPIO_ATTR_GET_ATTR,
196 gpioadm_gpio_attr_get_ofmt_cb },
197 { "PERM", 6, GPIOADM_GPIO_ATTR_GET_PERM,
198 gpioadm_gpio_attr_get_ofmt_cb },
199 { "VALUE", 24, GPIOADM_GPIO_ATTR_GET_VALUE,
200 gpioadm_gpio_attr_get_ofmt_cb },
201 { "RAW", 16, GPIOADM_GPIO_ATTR_GET_RAW,
202 gpioadm_gpio_attr_get_ofmt_cb },
203 { "POSSIBLE", 24, GPIOADM_GPIO_ATTR_GET_POSSIBLE,
204 gpioadm_gpio_attr_get_ofmt_cb },
205 { NULL, 0, 0, NULL }
206 };
207
208 static int
gpioadm_gpio_attr_get(int argc,char * argv[])209 gpioadm_gpio_attr_get(int argc, char *argv[])
210 {
211 int c, ret;
212 uint_t flags = 0;
213 boolean_t parse = B_FALSE;
214 const char *fields = NULL, *target = NULL;
215 ofmt_status_t oferr;
216 ofmt_handle_t ofmt;
217 xpio_ctrl_t *ctrl;
218 xpio_gpio_info_t *gpio;
219 bool *filts = NULL;
220
221 while ((c = getopt(argc, argv, ":Ho:p")) != -1) {
222 switch (c) {
223 case 'H':
224 flags |= OFMT_NOHEADER;
225 break;
226 case 'o':
227 fields = optarg;
228 break;
229 case 'p':
230 parse = B_TRUE;
231 flags |= OFMT_PARSABLE;
232 break;
233 case ':':
234 gpioadm_gpio_attr_get_help("option -%c requires an "
235 "argument", optopt);
236 exit(EXIT_USAGE);
237 case '?':
238 gpioadm_gpio_attr_get_help("unknown option: -%c",
239 optopt);
240 exit(EXIT_USAGE);
241 }
242 }
243
244 if (parse && fields == NULL) {
245 errx(EXIT_USAGE, "-p requires fields specified with -o");
246 }
247
248 if (!parse) {
249 flags |= OFMT_WRAP;
250 }
251
252 if (fields == NULL) {
253 fields = gpioadm_gpio_attr_get_fields;
254 }
255
256 argc -= optind;
257 argv += optind;
258 if (argc == 0) {
259 errx(EXIT_FAILURE, "missing required controller and gpio");
260 }
261 target = argv[0];
262 argc--;
263 argv++;
264
265 if (argc > 0) {
266 filts = calloc(argc, sizeof (bool));
267 if (filts == NULL) {
268 err(EXIT_FAILURE, "failed to allocate memory for "
269 "filter tracking");
270 }
271 }
272 oferr = ofmt_open(fields, gpioadm_gpio_attr_get_ofmt, flags, 0,
273 &ofmt);
274 ofmt_check(oferr, parse, ofmt, gpioadm_ofmt_errx, warnx);
275
276 gpioadm_ctrl_gpio_init(target, &ctrl, &gpio);
277
278 for (xpio_gpio_attr_t *attr = xpio_gpio_attr_next(gpio, NULL);
279 attr != NULL; attr = xpio_gpio_attr_next(gpio, attr)) {
280 gpioadm_gpio_attr_get_ofmt_t ggag;
281
282 if (argc > 0) {
283 const char *aname = xpio_gpio_attr_name(gpio, attr);
284 bool match = false;
285 for (int i = 0; i < argc; i++) {
286 if (strcmp(argv[i], aname) == 0) {
287 match = true;
288 filts[i] = true;
289 }
290 }
291
292 if (!match) {
293 continue;
294 }
295 }
296
297 ggag.ggag_info = gpio;
298 ggag.ggag_attr = attr;
299 ofmt_print(ofmt, &ggag);
300 }
301
302 ret = EXIT_SUCCESS;
303 for (int i = 0; i < argc; i++) {
304 if (!filts[i]) {
305 warnx("filter '%s' did not match any attributes",
306 argv[i]);
307 ret = EXIT_FAILURE;
308 }
309 }
310
311 free(filts);
312 return (ret);
313 }
314
315 static void
gpioadm_gpio_attr_set_usage(FILE * f)316 gpioadm_gpio_attr_set_usage(FILE *f)
317 {
318 (void) fprintf(f, "\tgpioadm gpio attr set controller/gpio attr=value "
319 "[attr=value...]\n");
320 }
321
322 static void __PRINTFLIKE(1)
gpioadm_gpio_attr_set_help(const char * fmt,...)323 gpioadm_gpio_attr_set_help(const char *fmt, ...)
324 {
325 if (fmt != NULL) {
326 va_list ap;
327
328 va_start(ap, fmt);
329 vwarnx(fmt, ap);
330 va_end(ap);
331 }
332
333 (void) fprintf(stderr, "Usage: gpioadm gpio attr set controller/gpio "
334 "attr=value [attr=value...]\n");
335 (void) fprintf(stderr, "\nSets the attributes of a single GPIO. "
336 "All specified attributes are\napplied at once.\n");
337 }
338
339 static int
gpioadm_gpio_attr_set(int argc,char * argv[])340 gpioadm_gpio_attr_set(int argc, char *argv[])
341 {
342 int c;
343 const char *target;
344 xpio_ctrl_t *ctrl;
345 xpio_gpio_info_t *gpio;
346 xpio_gpio_update_t *update;
347
348 while ((c = getopt(argc, argv, ":")) != -1) {
349 switch (c) {
350 case ':':
351 gpioadm_gpio_attr_set_help("option -%c requires an "
352 "argument", optopt);
353 exit(EXIT_USAGE);
354 case '?':
355 gpioadm_gpio_attr_set_help("unknown option: -%c",
356 optopt);
357 exit(EXIT_USAGE);
358 }
359 }
360
361 argc -= optind;
362 argv += optind;
363
364 if (argc == 0) {
365 errx(EXIT_USAGE, "missing required controller/gpio target");
366 }
367
368 if (argc == 1) {
369 errx(EXIT_USAGE, "missing required attribute settings");
370 }
371
372 target = argv[0];
373 gpioadm_ctrl_gpio_init(target, &ctrl, &gpio);
374 if (!xpio_gpio_update_init(gpioadm.gpio_xpio, gpio, &update)) {
375 gpioadm_fatal("failed to initialize update");
376 }
377
378 for (int i = 1; i < argc; i++) {
379 char *eq = strchr(argv[i], '=');
380 const char *name, *value;
381 xpio_gpio_attr_t *attr;
382
383 if (eq == NULL) {
384 errx(EXIT_FAILURE, "invalid attribute: missing equals "
385 "sign for value: %s", argv[i]);
386 }
387 name = argv[i];
388 value = eq + 1;
389 *eq = '\0';
390
391 attr = xpio_gpio_attr_find(gpio, name);
392 if (attr == NULL) {
393 errx(EXIT_FAILURE, "invalid attribute: no attribute "
394 "named %s exists for GPIO %s", name, target);
395 }
396
397 if (!xpio_gpio_attr_from_str(update, attr, value)) {
398 gpioadm_update_fatal(update, "failed to set attribute "
399 "%s to %s on GPIO %s", name, value, target);
400 }
401 }
402
403 if (!xpio_gpio_update(ctrl, update)) {
404 if (xpio_err(gpioadm.gpio_xpio) != XPIO_ERR_BAD_UPDATE) {
405 gpioadm_fatal("failed to update GPIO %s", target);
406 }
407
408 gpioadm_warn("failed to update GPIO %s", target);
409
410 for (xpio_gpio_attr_err_t *err =
411 xpio_gpio_attr_err_next(update, NULL); err != NULL;
412 err = xpio_gpio_attr_err_next(update, err)) {
413 xpio_update_err_t uerr = xpio_gpio_attr_err_err(err);
414
415 (void) fprintf(stderr, "\tattribute %s -- %s (0x%x)\n",
416 xpio_gpio_attr_err_name(err),
417 xpio_update_err2str(update, uerr), uerr);
418 }
419 }
420
421 return (EXIT_SUCCESS);
422 }
423
424 static const gpioadm_cmdtab_t gpioadm_cmds_gpio_attr[] = {
425 { "get", gpioadm_gpio_attr_get, gpioadm_gpio_attr_get_usage },
426 { "set", gpioadm_gpio_attr_set, gpioadm_gpio_attr_set_usage },
427 { NULL, NULL, NULL }
428 };
429
430 static void
gpioadm_gpio_attr_usage(FILE * f)431 gpioadm_gpio_attr_usage(FILE *f)
432 {
433 gpioadm_walk_usage(gpioadm_cmds_gpio_attr, f);
434 }
435
436 static int
gpioadm_gpio_attr(int argc,char * argv[])437 gpioadm_gpio_attr(int argc, char *argv[])
438 {
439 return (gpioadm_walk_tab(gpioadm_cmds_gpio_attr, argc, argv));
440 }
441
442 static void
gpioadm_gpio_list_usage(FILE * f)443 gpioadm_gpio_list_usage(FILE *f)
444 {
445 (void) fprintf(f, "\tgpioadm gpio list [-H] [-o field[,...] [-p]] "
446 "[-1] [filter...]\n");
447 }
448
449 static void __PRINTFLIKE(1)
gpioadm_gpio_list_help(const char * fmt,...)450 gpioadm_gpio_list_help(const char *fmt, ...)
451 {
452 if (fmt != NULL) {
453 va_list ap;
454
455 va_start(ap, fmt);
456 vwarnx(fmt, ap);
457 va_end(ap);
458 }
459
460 (void) fprintf(stderr, "Usage: gpioadm gpio list [-H] [-o "
461 "field[,...] [-p]] [-1] [filter...]\n");
462 (void) fprintf(stderr, "\nList GPIOs in the system.\n\n"
463 "\t-H\t\tomit the column header\n"
464 "\t-o field\toutput fields to print\n"
465 "\t-p\t\tparsable output (requires -o)\n"
466 "\t-1\t\terror if more than one GPIO is listed\n\n"
467 "The following fields are supported:\n"
468 "\tcontroller\tthe name of the controller\n"
469 "\tgpio\t\tthe name of the gpio\n"
470 "\tid\t\tthe GPIO's numeric id\n"
471 "Filters can be used to constrain the GPIOs that are listed. If a "
472 "filter is\npresent, it will be an error if it is unused. Filters "
473 "can specify either an\nentire controller, a specific GPIO on a "
474 "controller, or all GPIOs with a given\nname. The controller and "
475 "GPIO are separated with a '/' character. For example:\n\n"
476 "\tgpio_sim0\t\tThis would match all GPIOs on the controller\n"
477 "\t\t\t\t'gpio_sim0'.\n"
478 "\tzen_gpio0/EGPIO9_3\tThis would match the specific GPIO, "
479 "EGPIO9_3,\n\t\t\t\ton the specified controller, zen_gpio0.\n"
480 "\t*/gpio3\t\t\tThis would match all GPIOs named 'gpio3' on any\n"
481 "\t\t\t\tcontroller.\n");
482 }
483
484 typedef enum gpioadm_gpio_list_otype {
485 GPIOADM_GPIO_LIST_CTRL,
486 GPIOADM_GPIO_LIST_NAME,
487 GPIOADM_GPIO_LIST_ID
488 } gpioadm_gpio_list_otype_t;
489
490 typedef struct gpioadm_gpio_list_ofmt {
491 const char *gglo_minor;
492 const char *gglo_name;
493 uint32_t gglo_id;
494 uint32_t gglo_flags;
495 } gpioadm_gpio_list_ofmt_t;
496
497 static boolean_t
gpioadm_gpio_list_ofmt_cb(ofmt_arg_t * ofarg,char * buf,uint_t buflen)498 gpioadm_gpio_list_ofmt_cb(ofmt_arg_t *ofarg, char *buf, uint_t buflen)
499 {
500 gpioadm_gpio_list_ofmt_t *gglo = ofarg->ofmt_cbarg;
501
502 switch (ofarg->ofmt_id) {
503 case GPIOADM_GPIO_LIST_CTRL:
504 if (strlcpy(buf, gglo->gglo_minor, buflen) >= buflen) {
505 return (B_FALSE);
506 }
507 break;
508 case GPIOADM_GPIO_LIST_NAME:
509 if (strlcpy(buf, gglo->gglo_name, buflen) >= buflen) {
510 return (B_FALSE);
511 }
512 break;
513 case GPIOADM_GPIO_LIST_ID:
514 if (snprintf(buf, buflen, "%u", gglo->gglo_id) >= buflen) {
515 return (B_FALSE);
516 }
517 break;
518 default:
519 abort();
520 }
521 return (B_TRUE);
522 }
523
524 static const char *gpioadm_gpio_list_fields = "controller,gpio,id";
525 static const ofmt_field_t gpioadm_gpio_list_ofmt[] = {
526 { "CONTROLLER", 16, GPIOADM_GPIO_LIST_CTRL,
527 gpioadm_gpio_list_ofmt_cb },
528 { "GPIO", 20, GPIOADM_GPIO_LIST_NAME,
529 gpioadm_gpio_list_ofmt_cb },
530 { "ID", 8, GPIOADM_GPIO_LIST_ID,
531 gpioadm_gpio_list_ofmt_cb },
532 { NULL, 0, 0, NULL }
533 };
534
535 typedef struct {
536 bool ggl_err;
537 bool ggl_one;
538 uint_t ggl_nprint;
539 ofmt_handle_t ggl_ofmt;
540 int ggl_nfilts;
541 char *const *ggl_filts;
542 bool *ggl_used;
543 } gpioadm_gpio_list_t;
544
545 static bool
gpioadm_gpio_list_match(const char * ctrl,const char * gpio,gpioadm_gpio_list_t * ggl)546 gpioadm_gpio_list_match(const char *ctrl, const char *gpio,
547 gpioadm_gpio_list_t *ggl)
548 {
549 if (ggl->ggl_nfilts <= 0) {
550 return (true);
551 }
552
553 for (int i = 0; i < ggl->ggl_nfilts; i++) {
554 const char *filt = ggl->ggl_filts[i];
555 const char *slash = strchr(filt, '/');
556 bool all_ctrls;
557 size_t ctrl_len;
558
559 /*
560 * This is just a controller filter.
561 */
562 if (slash == NULL) {
563 if (strcmp(ctrl, filt) == 0) {
564 ggl->ggl_used[i] = true;
565 return (true);
566 }
567 }
568
569 ctrl_len = (uintptr_t)slash - (uintptr_t)filt;
570 if (ctrl_len == 0) {
571 return (false);
572 }
573
574 all_ctrls = ctrl_len == 1 && filt[0] == '*';
575 if (!all_ctrls && (strlen(ctrl) != ctrl_len ||
576 strncmp(ctrl, filt, ctrl_len) != 0)) {
577 continue;
578 }
579
580 if (strcmp(slash + 1, gpio) == 0) {
581 ggl->ggl_used[i] = true;
582 return (true);
583 }
584 }
585
586 return (false);
587 }
588
589 static bool
gpioadm_gpio_list_cb(xpio_t * xpio,xpio_ctrl_disc_t * disc,void * arg)590 gpioadm_gpio_list_cb(xpio_t *xpio, xpio_ctrl_disc_t *disc, void *arg)
591 {
592 xpio_ctrl_t *ctrl;
593 xpio_ctrl_info_t *info;
594 uint32_t ngpios;
595 const char *mname = di_minor_name(disc->xcd_minor);
596 gpioadm_gpio_list_t *ggl = arg;
597
598 if (!xpio_ctrl_init(xpio, disc->xcd_minor, &ctrl)) {
599 gpioadm_warn("failed to initialize controller %s", mname);
600 ggl->ggl_err = true;
601 return (true);
602 }
603
604 if (!xpio_ctrl_info(ctrl, &info)) {
605 gpioadm_warn("failed to get controller info for %s", mname);
606 xpio_ctrl_fini(ctrl);
607 ggl->ggl_err = true;
608 return (true);
609 }
610
611 ngpios = xpio_ctrl_info_ngpios(info);
612 for (uint32_t i = 0; i < ngpios; i++) {
613 gpioadm_gpio_list_ofmt_t list;
614 xpio_gpio_info_t *gpio_info;
615 xpio_gpio_attr_t *attr;
616
617 if (!xpio_gpio_info(ctrl, i, &gpio_info)) {
618 ggl->ggl_err = true;
619 gpioadm_warn("failed to get gpio info for %s:%u",
620 mname, i);
621 continue;
622 }
623
624 attr = xpio_gpio_attr_find(gpio_info, KGPIO_ATTR_NAME);
625 if (attr == NULL || !xpio_gpio_attr_value_string(attr,
626 &list.gglo_name)) {
627 warnx("GPIO %s/%u missing name attribute",
628 mname, i);
629 goto skip;
630 }
631 list.gglo_minor = mname;
632 list.gglo_id = i;
633 list.gglo_flags = 0;
634
635 if (!gpioadm_gpio_list_match(mname, list.gglo_name, ggl)) {
636 goto skip;
637 }
638
639 ggl->ggl_nprint++;
640 ofmt_print(ggl->ggl_ofmt, &list);
641
642 skip:
643 xpio_gpio_info_free(gpio_info);
644 }
645
646 xpio_ctrl_fini(ctrl);
647 return (true);
648 }
649
650 static int
gpioadm_gpio_list(int argc,char * argv[])651 gpioadm_gpio_list(int argc, char *argv[])
652 {
653 int c;
654 uint_t flags = 0;
655 boolean_t parse = B_FALSE;
656 const char *fields = NULL;
657 ofmt_status_t oferr;
658 ofmt_handle_t ofmt;
659 gpioadm_gpio_list_t ggl;
660
661 (void) memset(&ggl, 0, sizeof (ggl));
662 while ((c = getopt(argc, argv, ":Ho:p1")) != -1) {
663 switch (c) {
664 case 'H':
665 flags |= OFMT_NOHEADER;
666 break;
667 case 'o':
668 fields = optarg;
669 break;
670 case 'p':
671 parse = B_TRUE;
672 flags |= OFMT_PARSABLE;
673 break;
674 case '1':
675 ggl.ggl_one = true;
676 break;
677 case ':':
678 gpioadm_gpio_list_help("option -%c requires an "
679 "argument", optopt);
680 exit(EXIT_USAGE);
681 case '?':
682 gpioadm_gpio_list_help("unknown option: -%c", optopt);
683 exit(EXIT_USAGE);
684 }
685 }
686
687 if (parse && fields == NULL) {
688 errx(EXIT_USAGE, "-p requires fields specified with -o");
689 }
690
691 if (fields == NULL) {
692 fields = gpioadm_gpio_list_fields;
693 }
694
695 argc -= optind;
696 argv += optind;
697 if (argc > 0) {
698 ggl.ggl_nfilts = argc;
699 ggl.ggl_filts = argv;
700 ggl.ggl_used = calloc(argc, sizeof (bool));
701 if (ggl.ggl_used == NULL) {
702 err(EXIT_FAILURE, "failed to allocate memory for "
703 "filter tracking");
704 }
705 }
706 oferr = ofmt_open(fields, gpioadm_gpio_list_ofmt, flags, 0, &ofmt);
707 ofmt_check(oferr, parse, ofmt, gpioadm_ofmt_errx, warnx);
708
709 ggl.ggl_err = false;
710 ggl.ggl_ofmt = ofmt;
711 xpio_ctrl_discover(gpioadm.gpio_xpio, gpioadm_gpio_list_cb, &ggl);
712
713 for (int i = 0; i < ggl.ggl_nfilts; i++) {
714 if (!ggl.ggl_used[i]) {
715 warnx("filter '%s' did not match any GPIOs",
716 ggl.ggl_filts[i]);
717 ggl.ggl_err = true;
718 }
719 }
720
721 if (ggl.ggl_one && ggl.ggl_nprint > 1) {
722 warnx("-1 specified, but %u GPIOs printed", ggl.ggl_nprint);
723 ggl.ggl_err = true;
724 }
725
726 if (ggl.ggl_nprint == 0) {
727 if (ggl.ggl_nfilts == 0) {
728 warnx("no GPIOs found");
729 }
730 ggl.ggl_err = true;
731 }
732
733 return (ggl.ggl_err ? EXIT_FAILURE : EXIT_SUCCESS);
734 }
735
736 static const gpioadm_cmdtab_t gpioadm_cmds_gpio[] = {
737 { "attr", gpioadm_gpio_attr, gpioadm_gpio_attr_usage },
738 { "list", gpioadm_gpio_list, gpioadm_gpio_list_usage },
739 { NULL, NULL, NULL }
740 };
741
742 int
gpioadm_gpio(int argc,char * argv[])743 gpioadm_gpio(int argc, char *argv[])
744 {
745 return (gpioadm_walk_tab(gpioadm_cmds_gpio, argc, argv));
746 }
747
748 void
gpioadm_gpio_usage(FILE * f)749 gpioadm_gpio_usage(FILE *f)
750 {
751 gpioadm_walk_usage(gpioadm_cmds_gpio, f);
752 }
753