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