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