xref: /illumos-gate/usr/src/cmd/prtconf/prtconf.c (revision 3db86aab)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved	*/
29 
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
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 "prtconf.h"
42 
43 struct prt_opts	opts;
44 struct prt_dbg	dbg;
45 static char	new_path[MAXPATHLEN];
46 
47 #define	INDENT_LENGTH	4
48 
49 #ifdef	__x86
50 static const char *usage = "%s [ -V | -x | -abcvpPD ] [ <device_path > ]\n";
51 #else
52 static const char *usage = "%s [ -F | -V | -x | -abcvpPD ][ <device_path > ]\n";
53 #endif	/* __x86 */
54 
55 static void
56 setprogname(const char *name)
57 {
58 	char *p;
59 
60 	if (name == NULL)
61 		opts.o_progname = "prtconf";
62 	else if (p = strrchr(name, '/'))
63 		opts.o_progname = (const char *) p + 1;
64 	else
65 		opts.o_progname = name;
66 }
67 
68 /*PRINTFLIKE1*/
69 void
70 dprintf(const char *fmt, ...)
71 {
72 	if (dbg.d_debug) {
73 		va_list ap;
74 		va_start(ap, fmt);
75 		(void) vfprintf(stderr, fmt, ap);
76 		va_end(ap);
77 	}
78 }
79 
80 void
81 indent_to_level(int ilev)
82 {
83 	(void) printf("%*s", INDENT_LENGTH * ilev, "");
84 }
85 
86 static void
87 cleanup_path(const char *input_path, char *path)
88 {
89 	char	*ptr, *ptr2;
90 	size_t	len;
91 
92 	if ((input_path == NULL) || (path == NULL))
93 		return;
94 
95 	(void) strcpy(path, input_path);
96 
97 	/*LINTED*/
98 	while (1) {
99 		len = strlen(path);
100 		if (len == 0)
101 			break;
102 
103 		/* change substring "//" into "/" */
104 		if (ptr = strstr(path, "//")) {
105 			len = strlen(ptr + 1);
106 			(void) memmove(ptr, ptr + 1, len + 1);
107 			continue;
108 		}
109 		/* change substring "/./" into "/" */
110 		if (ptr = strstr(path, "/./")) {
111 			len = strlen(ptr + 2);
112 			(void) memmove(ptr, ptr + 2, len + 1);
113 			continue;
114 		}
115 
116 		/* change substring "/<foo>/../" into "/" */
117 		if (ptr = strstr(path, "/../")) {
118 			len = strlen(ptr + 3);
119 			*ptr = '\0';
120 			ptr2 = strrchr(path, (int)'/');
121 			if (ptr2 == NULL) {
122 				/* path had a leading "/../" */
123 				ptr2 = path;
124 			}
125 			(void) memmove(ptr2, ptr + 3, len + 1);
126 			continue;
127 		}
128 
129 		/* change trailing "/<foo>/.." into "/" */
130 		if ((len >= 3) &&
131 		    (path[len - 3] == '/') &&
132 		    (path[len - 2] == '.') &&
133 		    (path[len - 1] == '.')) {
134 			path[len - 3] = '\0';
135 			ptr2 = strrchr(path, (int)'/');
136 			if (ptr2 != NULL) {
137 				ptr2[1] = '\0';
138 			} else {
139 				/* path was "/.." */
140 				path[0] = '/';
141 				path[1] = '\0';
142 			}
143 			continue;
144 		}
145 
146 		/* change trailing "/." into "/" */
147 		if ((len >= 2) &&
148 		    (path[len - 2] == '/') &&
149 		    (path[len - 1] == '.')) {
150 			path[len - 1] = '\0';
151 			continue;
152 		}
153 
154 		/* remove trailing "/" unless it's the root */
155 		if ((len > 1) && (path[len - 1] == '/')) {
156 			path[len - 1] = '\0';
157 			continue;
158 		}
159 
160 		break;
161 	}
162 }
163 
164 
165 /*
166  * debug version has two more flags:
167  *	-L force load driver
168  *	-M: print per driver list
169  */
170 
171 #ifdef	DEBUG
172 static const char *optstring = "abcDvVxpPFf:M:dLuC";
173 #else
174 static const char *optstring = "abcDvVxpPFf:uC";
175 #endif	/* DEBUG */
176 
177 int
178 main(int argc, char *argv[])
179 {
180 	long pagesize, npages;
181 	int c, ret;
182 	char hw_provider[SYS_NMLN];
183 
184 	setprogname(argv[0]);
185 	opts.o_promdev = "/dev/openprom";
186 
187 	while ((c = getopt(argc, argv, optstring)) != -1)  {
188 		switch (c)  {
189 		case 'a':
190 			++opts.o_ancestors;
191 			break;
192 		case 'b':
193 			++opts.o_productinfo;
194 			break;
195 		case 'c':
196 			++opts.o_children;
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 (strlen(path) >= MAXPATHLEN) {
265 			(void) fprintf(stderr, "%s: "
266 			    "path specified is too long\n", opts.o_progname);
267 			return (1);
268 		}
269 
270 		if (error = stat(path, &sinfo)) {
271 
272 			/* an invalid path was specified */
273 			(void) fprintf(stderr, "%s: invalid path specified\n",
274 					opts.o_progname);
275 			return (1);
276 
277 		} else if (((sinfo.st_mode & S_IFMT) == S_IFCHR) ||
278 				((sinfo.st_mode & S_IFMT) == S_IFBLK)) {
279 
280 			opts.o_devt = sinfo.st_rdev;
281 			error = 0;
282 
283 		} else if ((sinfo.st_mode & S_IFMT) == S_IFDIR) {
284 			size_t	len, plen;
285 
286 			/* clean up the path */
287 			cleanup_path(path, new_path);
288 
289 			len = strlen(new_path);
290 			plen = strlen("/devices");
291 			if (len < plen) {
292 				/* This is not a valid /devices path */
293 				error = 1;
294 			} else if ((len == plen) &&
295 			    (strcmp(new_path, "/devices") == 0)) {
296 				/* /devices is the root nexus */
297 				opts.o_devices_path = "/";
298 				error = 0;
299 			} else if (strncmp(new_path, "/devices/", plen + 1)) {
300 				/* This is not a valid /devices path */
301 				error = 1;
302 			} else {
303 				/* a /devices/ path was specified */
304 				opts.o_devices_path = new_path + plen;
305 				error = 0;
306 			}
307 
308 		} else {
309 			/* an invalid device path was specified */
310 			error = 1;
311 		}
312 
313 		if (error) {
314 			(void) fprintf(stderr, "%s: "
315 			    "invalid device path specified\n",
316 			    opts.o_progname);
317 			return (1);
318 		}
319 
320 		opts.o_target = 1;
321 	}
322 
323 	if ((opts.o_ancestors || opts.o_children) && (!opts.o_target)) {
324 		(void) fprintf(stderr, "%s: options require a device path\n",
325 		    opts.o_progname);
326 		return (1);
327 	}
328 
329 	if (opts.o_target) {
330 		prtconf_devinfo();
331 		return (0);
332 	}
333 
334 	ret = sysinfo(SI_HW_PROVIDER, hw_provider, sizeof (hw_provider));
335 	/*
336 	 * If 0 bytes are returned (the system returns '1', for the \0),
337 	 * we're probably on x86, and there has been no si-hw-provider
338 	 * set in /etc/bootrc, so just default to Sun.
339 	 */
340 	if (ret <= 1) {
341 		(void) strncpy(hw_provider, "Sun Microsystems",
342 		    sizeof (hw_provider));
343 	} else {
344 		/*
345 		 * Provide backward compatibility by stripping out the _.
346 		 */
347 		if (strcmp(hw_provider, "Sun_Microsystems") == 0)
348 			hw_provider[3] = ' ';
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