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 * Copyright 2011, Joyent, Inc. All rights reserved. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 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 setpname(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 = "abcdDvVxmpPFf:M:dLuC"; 171 #else 172 static const char *optstring = "abcdDvVxmpPFf: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 setpname(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 'm': 206 ++opts.o_memory; 207 break; 208 case 'p': 209 ++opts.o_prominfo; 210 break; 211 case 'f': 212 opts.o_promdev = optarg; 213 break; 214 case 'V': 215 ++opts.o_promversion; 216 break; 217 case 'x': 218 ++opts.o_prom_ready64; 219 break; 220 case 'F': 221 ++opts.o_fbname; 222 ++opts.o_noheader; 223 break; 224 case 'P': 225 ++opts.o_pseudodevs; 226 break; 227 case 'C': 228 ++opts.o_forcecache; 229 break; 230 #ifdef DEBUG 231 case 'M': 232 dbg.d_drivername = optarg; 233 ++dbg.d_bydriver; 234 break; 235 case 'L': 236 ++dbg.d_forceload; 237 break; 238 #endif /* DEBUG */ 239 240 default: 241 (void) fprintf(stderr, usage, opts.o_progname); 242 return (1); 243 } 244 } 245 246 (void) uname(&opts.o_uts); 247 248 if (opts.o_fbname) 249 return (do_fbname()); 250 251 if (opts.o_promversion) 252 return (do_promversion()); 253 254 if (opts.o_prom_ready64) 255 return (do_prom_version64()); 256 257 if (opts.o_productinfo) 258 return (do_productinfo()); 259 260 opts.o_devices_path = NULL; 261 opts.o_devt = DDI_DEV_T_NONE; 262 opts.o_target = 0; 263 if (optind < argc) { 264 struct stat sinfo; 265 char *path = argv[optind]; 266 int error; 267 268 if (opts.o_prominfo) { 269 /* PROM tree cannot be used with path */ 270 (void) fprintf(stderr, "%s: path and -p option are " 271 "mutually exclusive\n", opts.o_progname); 272 return (1); 273 } 274 275 if (strlen(path) >= MAXPATHLEN) { 276 (void) fprintf(stderr, "%s: " 277 "path specified is too long\n", opts.o_progname); 278 return (1); 279 } 280 281 if (error = stat(path, &sinfo)) { 282 283 /* an invalid path was specified */ 284 (void) fprintf(stderr, "%s: invalid path specified\n", 285 opts.o_progname); 286 return (1); 287 288 } else if (((sinfo.st_mode & S_IFMT) == S_IFCHR) || 289 ((sinfo.st_mode & S_IFMT) == S_IFBLK)) { 290 291 opts.o_devt = sinfo.st_rdev; 292 error = 0; 293 294 } else if ((sinfo.st_mode & S_IFMT) == S_IFDIR) { 295 size_t len, plen; 296 297 /* clean up the path */ 298 cleanup_path(path, new_path); 299 300 len = strlen(new_path); 301 plen = strlen("/devices"); 302 if (len < plen) { 303 /* This is not a valid /devices path */ 304 error = 1; 305 } else if ((len == plen) && 306 (strcmp(new_path, "/devices") == 0)) { 307 /* /devices is the root nexus */ 308 opts.o_devices_path = "/"; 309 error = 0; 310 } else if (strncmp(new_path, "/devices/", plen + 1)) { 311 /* This is not a valid /devices path */ 312 error = 1; 313 } else { 314 /* a /devices/ path was specified */ 315 opts.o_devices_path = new_path + plen; 316 error = 0; 317 } 318 319 } else { 320 /* an invalid device path was specified */ 321 error = 1; 322 } 323 324 if (error) { 325 (void) fprintf(stderr, "%s: " 326 "invalid device path specified\n", 327 opts.o_progname); 328 return (1); 329 } 330 331 opts.o_target = 1; 332 } 333 334 if ((opts.o_ancestors || opts.o_children) && (!opts.o_target)) { 335 (void) fprintf(stderr, "%s: options require a device path\n", 336 opts.o_progname); 337 return (1); 338 } 339 340 if (opts.o_target) { 341 prtconf_devinfo(); 342 return (0); 343 } 344 345 if (!opts.o_memory) { 346 ret = sysinfo(SI_HW_PROVIDER, hw_provider, 347 sizeof (hw_provider)); 348 /* 349 * If 0 bytes are returned (the system returns '1', for the \0), 350 * we're probably on x86, default to "Unknown Hardware Vendor". 351 */ 352 if (ret <= 1) { 353 (void) strncpy(hw_provider, "Unknown Hardware Vendor", 354 sizeof (hw_provider)); 355 } 356 (void) printf("System Configuration: %s %s\n", hw_provider, 357 opts.o_uts.machine); 358 } 359 360 pagesize = sysconf(_SC_PAGESIZE); 361 npages = sysconf(_SC_PHYS_PAGES); 362 if (pagesize == -1 || npages == -1) { 363 if (opts.o_memory) { 364 (void) printf("0\n"); 365 return (1); 366 } else { 367 (void) printf("Memory size: unable to determine\n"); 368 } 369 } else { 370 const int64_t mbyte = 1024 * 1024; 371 int64_t ii = (int64_t)pagesize * npages; 372 373 if (opts.o_memory) { 374 (void) printf("%ld\n", (long)((ii+mbyte-1) / mbyte)); 375 return (0); 376 } else { 377 (void) printf("Memory size: %ld Megabytes\n", 378 (long)((ii+mbyte-1) / mbyte)); 379 } 380 } 381 382 if (opts.o_prominfo) { 383 (void) printf("System Peripherals (PROM Nodes):\n\n"); 384 if (do_prominfo() == 0) 385 return (0); 386 (void) fprintf(stderr, "%s: Defaulting to non-PROM mode...\n", 387 opts.o_progname); 388 } 389 390 (void) printf("System Peripherals (Software Nodes):\n\n"); 391 392 (void) prtconf_devinfo(); 393 394 return (0); 395 } 396