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