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
setpname(const char * name)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
dprintf(const char * fmt,...)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
indent_to_level(int ilev)78 indent_to_level(int ilev)
79 {
80 (void) printf("%*s", INDENT_LENGTH * ilev, "");
81 }
82
83 static void
cleanup_path(const char * input_path,char * path)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
main(int argc,char * argv[])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