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 * Copyright 2018 Joyent, Inc.
12 */
13
14 #include <stdlib.h>
15 #include <stdarg.h>
16 #include <getopt.h>
17 #include <string.h>
18 #include <ofmt.h>
19 #include <err.h>
20
21 #include <libppt.h>
22
23 typedef enum field {
24 PPT_DEV,
25 PPT_VENDOR,
26 PPT_DEVICE,
27 PPT_SUBVENDOR,
28 PPT_SUBDEVICE,
29 PPT_REV,
30 PPT_PATH,
31 PPT_LABEL
32 } field_t;
33
34 const char *valname[] = {
35 "dev",
36 "vendor-id",
37 "device-id",
38 "subsystem-vendor-id",
39 "subsystem-id",
40 "revision-id",
41 "path",
42 "label"
43 };
44
45 static ofmt_cb_t print_field;
46
47 static ofmt_field_t fields[] = {
48 /* name, field width, index, callback */
49 { "DEV", sizeof ("/dev/pptXX"), PPT_DEV, print_field },
50 { "VENDOR", sizeof ("VENDOR"), PPT_VENDOR, print_field },
51 { "DEVICE", sizeof ("DEVICE"), PPT_DEVICE, print_field },
52 { "SUBVENDOR", sizeof ("SUBVENDOR"), PPT_SUBVENDOR, print_field },
53 { "SUBDEVICE", sizeof ("SUBDEVICE"), PPT_SUBDEVICE, print_field },
54 { "REV", sizeof ("REV"), PPT_REV, print_field },
55 { "PATH", 50, PPT_PATH, print_field },
56 { "LABEL", 60, PPT_LABEL, print_field },
57 { NULL, 0, 0, NULL },
58 };
59
60 static void
usage(const char * errmsg)61 usage(const char *errmsg)
62 {
63 if (errmsg != NULL)
64 (void) fprintf(stderr, "pptadm: %s\n", errmsg);
65 (void) fprintf(errmsg != NULL ? stderr : stdout,
66 "Usage:\n"
67 "pptadm list [ -j ]\n"
68 "pptadm list [-ap] [-o fields]\n");
69 exit(errmsg != NULL ? EXIT_FAILURE : EXIT_SUCCESS);
70 }
71
72 /* PRINTFLIKE1 */
73 static void
die(const char * fmt,...)74 die(const char *fmt, ...)
75 {
76 va_list ap;
77 va_start(ap, fmt);
78 verrx(EXIT_FAILURE, fmt, ap);
79 va_end(ap);
80 }
81
82 static boolean_t
print_field(ofmt_arg_t * arg,char * buf,uint_t bufsize)83 print_field(ofmt_arg_t *arg, char *buf, uint_t bufsize)
84 {
85 nvlist_t *nvl = arg->ofmt_cbarg;
86 nvpair_t *nvp = NULL;
87
88 while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
89 const char *name = nvpair_name(nvp);
90 char *val = NULL;
91
92 (void) nvpair_value_string(nvp, &val);
93
94 if (strcmp(name, valname[arg->ofmt_id]) != 0)
95 continue;
96
97 (void) snprintf(buf, bufsize, "%s", val);
98 return (B_TRUE);
99 }
100
101 (void) snprintf(buf, bufsize, "--");
102 return (B_TRUE);
103 }
104
105 static int
list(int argc,char * argv[])106 list(int argc, char *argv[])
107 {
108 const char *fields_str = NULL;
109 boolean_t parsable = B_FALSE;
110 boolean_t json = B_FALSE;
111 boolean_t all = B_FALSE;
112 uint_t ofmtflags = 0;
113 ofmt_status_t oferr;
114 ofmt_handle_t ofmt;
115 int opt;
116
117 while ((opt = getopt(argc, argv, "ahjo:p")) != -1) {
118 switch (opt) {
119 case 'a':
120 all = B_TRUE;
121 break;
122 case 'h':
123 usage(NULL);
124 break;
125 case 'j':
126 json = B_TRUE;
127 break;
128 case 'o':
129 fields_str = optarg;
130 break;
131 case 'p':
132 ofmtflags |= OFMT_PARSABLE;
133 parsable = B_TRUE;
134 break;
135 default:
136 usage("unrecognized option");
137 break;
138 }
139 }
140
141 if (optind == (argc - 1))
142 usage("unused arguments");
143
144 if (json && (parsable || fields_str != NULL))
145 usage("-j option cannot be used with -p or -o options");
146
147 if (fields_str == NULL) {
148 if (parsable)
149 usage("-o must be provided when using -p option");
150 fields_str = "dev,vendor,device,path";
151 }
152
153 oferr = ofmt_open(fields_str, fields, ofmtflags, 0, &ofmt);
154
155 ofmt_check(oferr, parsable, ofmt, die, warn);
156
157 nvlist_t *nvl = all ? ppt_list() : ppt_list_assigned();
158 nvpair_t *nvp = NULL;
159
160 if (json) {
161 if (printf("{\n\t\"devices\": [\n") < 0)
162 err(EXIT_FAILURE, "failed to write JSON");
163 }
164
165 while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
166 nvlist_t *props;
167
168 (void) nvpair_value_nvlist(nvp, &props);
169
170 if (json) {
171 if (printf("\t\t") < 0)
172 err(EXIT_FAILURE, "failed to write JSON");
173 if (nvlist_print_json(stdout, props) < 0)
174 err(EXIT_FAILURE, "failed to write JSON");
175 if (nvlist_next_nvpair(nvl, nvp) != NULL)
176 (void) printf(",\n");
177 } else {
178 ofmt_print(ofmt, props);
179 }
180 }
181
182 if (json) {
183 if (printf("\n\t]\n}\n") < 0)
184 err(EXIT_FAILURE, "failed to write JSON");
185 }
186
187 nvlist_free(nvl);
188 ofmt_close(ofmt);
189 return (EXIT_SUCCESS);
190 }
191
192 int
main(int argc,char * argv[])193 main(int argc, char *argv[])
194 {
195 if (argc == 1)
196 return (list(argc - 1, argv));
197
198 if (strcmp(argv[1], "list") == 0) {
199 return (list(argc - 1, &argv[1]));
200 } else {
201 usage("unknown sub-command");
202 }
203
204 return (EXIT_SUCCESS);
205 }
206