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
23typedef 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
34const 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
45static ofmt_cb_t print_field;
46
47static 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
60static void
61usage(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 */
73static void
74die(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
82static boolean_t
83print_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
105static int
106list(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
192int
193main(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