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, and there has been no si-hw-provider 345 * set in /etc/bootrc, default to Oracle. 346 */ 347 if (ret <= 1) { 348 (void) strncpy(hw_provider, "Oracle Corporation", 349 sizeof (hw_provider)); 350 } 351 (void) printf("System Configuration: %s %s\n", hw_provider, 352 opts.o_uts.machine); 353 354 pagesize = sysconf(_SC_PAGESIZE); 355 npages = sysconf(_SC_PHYS_PAGES); 356 (void) printf("Memory size: "); 357 if (pagesize == -1 || npages == -1) 358 (void) printf("unable to determine\n"); 359 else { 360 const int64_t kbyte = 1024; 361 const int64_t mbyte = 1024 * 1024; 362 int64_t ii = (int64_t)pagesize * npages; 363 364 if (ii >= mbyte) 365 (void) printf("%ld Megabytes\n", 366 (long)((ii+mbyte-1) / mbyte)); 367 else 368 (void) printf("%ld Kilobytes\n", 369 (long)((ii+kbyte-1) / kbyte)); 370 } 371 372 if (opts.o_prominfo) { 373 (void) printf("System Peripherals (PROM Nodes):\n\n"); 374 if (do_prominfo() == 0) 375 return (0); 376 (void) fprintf(stderr, "%s: Defaulting to non-PROM mode...\n", 377 opts.o_progname); 378 } 379 380 (void) printf("System Peripherals (Software Nodes):\n\n"); 381 382 (void) prtconf_devinfo(); 383 384 return (0); 385 }