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 * Copyright (c) 2019 Peter Tribble. 26 */ 27 28 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 29 /* All Rights Reserved */ 30 31 #include <stdio.h> 32 #include <stdarg.h> 33 #include <stdlib.h> 34 #include <unistd.h> 35 #include <strings.h> 36 #include <sys/systeminfo.h> 37 #include <sys/types.h> 38 #include <sys/stat.h> 39 #include "prtconf.h" 40 41 struct prt_opts opts; 42 struct prt_dbg dbg; 43 static char new_path[MAXPATHLEN]; 44 45 #define INDENT_LENGTH 4 46 47 static const char *usage = 48 "%s [ -F | -m | -V | -x | -abcdvpPD ] [ <device_path > ]\n"; 49 50 static void 51 setpname(const char *name) 52 { 53 char *p; 54 55 if (name == NULL) 56 opts.o_progname = "prtconf"; 57 else if (p = strrchr(name, '/')) 58 opts.o_progname = (const char *) p + 1; 59 else 60 opts.o_progname = name; 61 } 62 63 /*PRINTFLIKE1*/ 64 void 65 dprintf(const char *fmt, ...) 66 { 67 if (dbg.d_debug) { 68 va_list ap; 69 va_start(ap, fmt); 70 (void) vfprintf(stderr, fmt, ap); 71 va_end(ap); 72 } 73 } 74 75 void 76 indent_to_level(int ilev) 77 { 78 (void) printf("%*s", INDENT_LENGTH * ilev, ""); 79 } 80 81 static void 82 cleanup_path(const char *input_path, char *path) 83 { 84 char *ptr, *ptr2; 85 size_t len; 86 87 if ((input_path == NULL) || (path == NULL)) 88 return; 89 90 (void) strcpy(path, input_path); 91 92 /*LINTED*/ 93 while (1) { 94 len = strlen(path); 95 if (len == 0) 96 break; 97 98 /* change substring "//" into "/" */ 99 if (ptr = strstr(path, "//")) { 100 len = strlen(ptr + 1); 101 (void) memmove(ptr, ptr + 1, len + 1); 102 continue; 103 } 104 /* change substring "/./" into "/" */ 105 if (ptr = strstr(path, "/./")) { 106 len = strlen(ptr + 2); 107 (void) memmove(ptr, ptr + 2, len + 1); 108 continue; 109 } 110 111 /* change substring "/<foo>/../" into "/" */ 112 if (ptr = strstr(path, "/../")) { 113 len = strlen(ptr + 3); 114 *ptr = '\0'; 115 ptr2 = strrchr(path, (int)'/'); 116 if (ptr2 == NULL) { 117 /* path had a leading "/../" */ 118 ptr2 = path; 119 } 120 (void) memmove(ptr2, ptr + 3, len + 1); 121 continue; 122 } 123 124 /* change trailing "/<foo>/.." into "/" */ 125 if ((len >= 3) && 126 (path[len - 3] == '/') && 127 (path[len - 2] == '.') && 128 (path[len - 1] == '.')) { 129 path[len - 3] = '\0'; 130 ptr2 = strrchr(path, (int)'/'); 131 if (ptr2 != NULL) { 132 ptr2[1] = '\0'; 133 } else { 134 /* path was "/.." */ 135 path[0] = '/'; 136 path[1] = '\0'; 137 } 138 continue; 139 } 140 141 /* change trailing "/." into "/" */ 142 if ((len >= 2) && 143 (path[len - 2] == '/') && 144 (path[len - 1] == '.')) { 145 path[len - 1] = '\0'; 146 continue; 147 } 148 149 /* remove trailing "/" unless it's the root */ 150 if ((len > 1) && (path[len - 1] == '/')) { 151 path[len - 1] = '\0'; 152 continue; 153 } 154 155 break; 156 } 157 } 158 159 160 /* 161 * debug version has two more flags: 162 * -L force load driver 163 * -M: print per driver list 164 */ 165 166 #ifdef DEBUG 167 static const char *optstring = "abcdDvVxmpPFf:M:LuC"; 168 #else 169 static const char *optstring = "abcdDvVxmpPFf:uC"; 170 #endif /* DEBUG */ 171 172 int 173 main(int argc, char *argv[]) 174 { 175 long pagesize, npages; 176 int c, ret; 177 char hw_provider[SYS_NMLN]; 178 179 setpname(argv[0]); 180 opts.o_promdev = "/dev/openprom"; 181 182 while ((c = getopt(argc, argv, optstring)) != -1) { 183 switch (c) { 184 case 'a': 185 ++opts.o_ancestors; 186 break; 187 case 'b': 188 ++opts.o_productinfo; 189 break; 190 case 'c': 191 ++opts.o_children; 192 break; 193 case 'd': 194 ++opts.o_pciid; 195 break; 196 case 'D': 197 ++opts.o_drv_name; 198 break; 199 case 'v': 200 ++opts.o_verbose; 201 break; 202 case 'm': 203 ++opts.o_memory; 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 (0); 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 if (!opts.o_memory) { 343 ret = sysinfo(SI_HW_PROVIDER, hw_provider, 344 sizeof (hw_provider)); 345 /* 346 * If 0 bytes are returned (the system returns '1', for the \0), 347 * we're probably on x86, default to "Unknown Hardware Vendor". 348 */ 349 if (ret <= 1) { 350 (void) strncpy(hw_provider, "Unknown Hardware Vendor", 351 sizeof (hw_provider)); 352 } 353 (void) printf("System Configuration: %s %s\n", hw_provider, 354 opts.o_uts.machine); 355 } 356 357 pagesize = sysconf(_SC_PAGESIZE); 358 npages = sysconf(_SC_PHYS_PAGES); 359 if (pagesize == -1 || npages == -1) { 360 if (opts.o_memory) { 361 (void) printf("0\n"); 362 return (1); 363 } else { 364 (void) printf("Memory size: unable to determine\n"); 365 } 366 } else { 367 const int64_t mbyte = 1024 * 1024; 368 int64_t ii = (int64_t)pagesize * npages; 369 370 if (opts.o_memory) { 371 (void) printf("%ld\n", (long)((ii+mbyte-1) / mbyte)); 372 return (0); 373 } else { 374 (void) printf("Memory size: %ld Megabytes\n", 375 (long)((ii+mbyte-1) / mbyte)); 376 } 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