xref: /illumos-gate/usr/src/cmd/prtconf/prtconf.c (revision 1c7f36ec)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Copyright 2011, Joyent, Inc. All rights reserved.
25  * Copyright (c) 2019 Peter Tribble.
26  * Copyright (c) 2022 Sachidananda Urs <sacchi@gmail.com>
27  * Copyright 2022 Oxide Computer Company
28  */
29 
30 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
31 /*	  All Rights Reserved	*/
32 
33 #include <stdio.h>
34 #include <stdarg.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37 #include <strings.h>
38 #include <sys/systeminfo.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <err.h>
42 #include "prtconf.h"
43 
44 struct prt_opts	opts;
45 struct prt_dbg	dbg;
46 static char	new_path[MAXPATHLEN];
47 
48 #define	INDENT_LENGTH	4
49 
50 static const char *usage =
51 	"%s [ -F | -m | -V | -x | -abcdvpPD ] [ <device_path > ]\n";
52 
53 static void
setpname(const char * name)54 setpname(const char *name)
55 {
56 	char *p;
57 
58 	if (name == NULL)
59 		opts.o_progname = "prtconf";
60 	else if ((p = strrchr(name, '/')) != NULL)
61 		opts.o_progname = (const char *) p + 1;
62 	else
63 		opts.o_progname = name;
64 }
65 
66 /*PRINTFLIKE1*/
67 void
dprintf(const char * fmt,...)68 dprintf(const char *fmt, ...)
69 {
70 	if (dbg.d_debug) {
71 		va_list ap;
72 		va_start(ap, fmt);
73 		(void) vfprintf(stderr, fmt, ap);
74 		va_end(ap);
75 	}
76 }
77 
78 void
indent_to_level(int ilev)79 indent_to_level(int ilev)
80 {
81 	(void) printf("%*s", INDENT_LENGTH * ilev, "");
82 }
83 
84 /*
85  * debug version has two more flags:
86  *	-L force load driver
87  *	-M: print per driver list
88  */
89 
90 #ifdef	DEBUG
91 static const char *optstring = "abcdDvVxmpPFf:M:LuC";
92 #else
93 static const char *optstring = "abcdDvVxmpPFf:uC";
94 #endif	/* DEBUG */
95 
96 int
main(int argc,char * argv[])97 main(int argc, char *argv[])
98 {
99 	long pagesize, npages;
100 	int c, ret;
101 	char hw_provider[SYS_NMLN];
102 
103 	setpname(argv[0]);
104 	opts.o_promdev = "/dev/openprom";
105 
106 	while ((c = getopt(argc, argv, optstring)) != -1)  {
107 		switch (c)  {
108 		case 'a':
109 			++opts.o_ancestors;
110 			break;
111 		case 'b':
112 			++opts.o_productinfo;
113 			break;
114 		case 'c':
115 			++opts.o_children;
116 			break;
117 		case 'd':
118 			++opts.o_pciid;
119 			break;
120 		case 'D':
121 			++opts.o_drv_name;
122 			break;
123 		case 'v':
124 			++opts.o_verbose;
125 			break;
126 		case 'm':
127 			++opts.o_memory;
128 			break;
129 		case 'p':
130 			++opts.o_prominfo;
131 			break;
132 		case 'f':
133 			opts.o_promdev = optarg;
134 			break;
135 		case 'V':
136 			++opts.o_promversion;
137 			break;
138 		case 'x':
139 			++opts.o_prom_ready64;
140 			break;
141 		case 'F':
142 			++opts.o_fbname;
143 			++opts.o_noheader;
144 			break;
145 		case 'P':
146 			++opts.o_pseudodevs;
147 			break;
148 		case 'C':
149 			++opts.o_forcecache;
150 			break;
151 #ifdef	DEBUG
152 		case 'M':
153 			dbg.d_drivername = optarg;
154 			++dbg.d_bydriver;
155 			break;
156 		case 'L':
157 			++dbg.d_forceload;
158 			break;
159 #endif	/* DEBUG */
160 
161 		default:
162 			(void) fprintf(stderr, usage, opts.o_progname);
163 			return (1);
164 		}
165 	}
166 
167 	(void) uname(&opts.o_uts);
168 
169 	if (opts.o_verbose || opts.o_pciid) {
170 		opts.o_pcidb = pcidb_open(PCIDB_VERSION);
171 		if (opts.o_pcidb == NULL) {
172 			warn("pcidb facility not available, PCI names will "
173 			    "not be translated");
174 		}
175 	}
176 
177 	if (opts.o_fbname)
178 		return (do_fbname());
179 
180 	if (opts.o_promversion)
181 		return (do_promversion());
182 
183 	if (opts.o_prom_ready64)
184 		return (0);
185 
186 	if (opts.o_productinfo)
187 		return (do_productinfo());
188 
189 	opts.o_devices_path = NULL;
190 	opts.o_devt = DDI_DEV_T_NONE;
191 	opts.o_target = 0;
192 	if (optind < argc) {
193 		struct stat	sinfo;
194 		char		*path = argv[optind];
195 		int		error;
196 
197 		if (opts.o_prominfo) {
198 			/* PROM tree cannot be used with path */
199 			(void) fprintf(stderr, "%s: path and -p option are "
200 			    "mutually exclusive\n", opts.o_progname);
201 			return (1);
202 		}
203 
204 		if (strlen(path) >= MAXPATHLEN) {
205 			(void) fprintf(stderr, "%s: "
206 			    "path specified is too long\n", opts.o_progname);
207 			return (1);
208 		}
209 
210 		if ((error = stat(path, &sinfo)) != 0) {
211 
212 			/* an invalid path was specified */
213 			(void) fprintf(stderr, "%s: invalid path specified\n",
214 			    opts.o_progname);
215 			return (1);
216 
217 		} else if (((sinfo.st_mode & S_IFMT) == S_IFCHR) ||
218 		    ((sinfo.st_mode & S_IFMT) == S_IFBLK)) {
219 
220 			opts.o_devt = sinfo.st_rdev;
221 			error = 0;
222 
223 		} else if ((sinfo.st_mode & S_IFMT) == S_IFDIR) {
224 			size_t	len, plen;
225 
226 			if (realpath(path, new_path) == NULL) {
227 				(void) fprintf(stderr, "%s: invalid device"
228 				    " path specified\n",
229 				    opts.o_progname);
230 				return (1);
231 			}
232 
233 			len = strlen(new_path);
234 			plen = strlen("/devices");
235 			if (len < plen) {
236 				/* This is not a valid /devices path */
237 				error = 1;
238 			} else if ((len == plen) &&
239 			    (strcmp(new_path, "/devices") == 0)) {
240 				/* /devices is the root nexus */
241 				opts.o_devices_path = "/";
242 				error = 0;
243 			} else if (strncmp(new_path, "/devices/", plen + 1)) {
244 				/* This is not a valid /devices path */
245 				error = 1;
246 			} else {
247 				/* a /devices/ path was specified */
248 				opts.o_devices_path = new_path + plen;
249 				error = 0;
250 			}
251 
252 		} else {
253 			/* an invalid device path was specified */
254 			error = 1;
255 		}
256 
257 		if (error) {
258 			(void) fprintf(stderr, "%s: "
259 			    "invalid device path specified\n",
260 			    opts.o_progname);
261 			return (1);
262 		}
263 
264 		opts.o_target = 1;
265 	}
266 
267 	if ((opts.o_ancestors || opts.o_children) && (!opts.o_target)) {
268 		(void) fprintf(stderr, "%s: options require a device path\n",
269 		    opts.o_progname);
270 		return (1);
271 	}
272 
273 	if (opts.o_target) {
274 		prtconf_devinfo();
275 		return (0);
276 	}
277 
278 	if (!opts.o_memory) {
279 		ret = sysinfo(SI_HW_PROVIDER, hw_provider,
280 		    sizeof (hw_provider));
281 		/*
282 		 * If 0 bytes are returned (the system returns '1', for the \0),
283 		 * we're probably on x86, default to "Unknown Hardware Vendor".
284 		 */
285 		if (ret <= 1) {
286 			(void) strncpy(hw_provider, "Unknown Hardware Vendor",
287 			    sizeof (hw_provider));
288 		}
289 		(void) printf("System Configuration:  %s  %s\n", hw_provider,
290 		    opts.o_uts.machine);
291 	}
292 
293 	pagesize = sysconf(_SC_PAGESIZE);
294 	npages = sysconf(_SC_PHYS_PAGES);
295 	if (pagesize == -1 || npages == -1) {
296 		if (opts.o_memory) {
297 			(void) printf("0\n");
298 			return (1);
299 		} else {
300 			(void) printf("Memory size: unable to determine\n");
301 		}
302 	} else {
303 		const int64_t mbyte = 1024 * 1024;
304 		int64_t ii = (int64_t)pagesize * npages;
305 
306 		if (opts.o_memory) {
307 			(void) printf("%ld\n", (long)((ii+mbyte-1) / mbyte));
308 			return (0);
309 		} else {
310 			(void) printf("Memory size: %ld Megabytes\n",
311 			    (long)((ii+mbyte-1) / mbyte));
312 		}
313 	}
314 
315 	if (opts.o_prominfo) {
316 		(void) printf("System Peripherals (PROM Nodes):\n\n");
317 		if (do_prominfo() == 0)
318 			return (0);
319 		(void) fprintf(stderr, "%s: Defaulting to non-PROM mode...\n",
320 		    opts.o_progname);
321 	}
322 
323 	(void) printf("System Peripherals (Software Nodes):\n\n");
324 
325 	(void) prtconf_devinfo();
326 
327 	return (0);
328 }
329