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