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