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 * Copyright (c) 2022 Sachidananda Urs <sacchi@gmail.com> 27 */ 28 29 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 30 /* All Rights Reserved */ 31 32 #include <stdio.h> 33 #include <stdarg.h> 34 #include <stdlib.h> 35 #include <unistd.h> 36 #include <strings.h> 37 #include <sys/systeminfo.h> 38 #include <sys/types.h> 39 #include <sys/stat.h> 40 #include "prtconf.h" 41 42 struct prt_opts opts; 43 struct prt_dbg dbg; 44 static char new_path[MAXPATHLEN]; 45 46 #define INDENT_LENGTH 4 47 48 static const char *usage = 49 "%s [ -F | -m | -V | -x | -abcdvpPD ] [ <device_path > ]\n"; 50 51 static void 52 setpname(const char *name) 53 { 54 char *p; 55 56 if (name == NULL) 57 opts.o_progname = "prtconf"; 58 else if (p = strrchr(name, '/')) 59 opts.o_progname = (const char *) p + 1; 60 else 61 opts.o_progname = name; 62 } 63 64 /*PRINTFLIKE1*/ 65 void 66 dprintf(const char *fmt, ...) 67 { 68 if (dbg.d_debug) { 69 va_list ap; 70 va_start(ap, fmt); 71 (void) vfprintf(stderr, fmt, ap); 72 va_end(ap); 73 } 74 } 75 76 void 77 indent_to_level(int ilev) 78 { 79 (void) printf("%*s", INDENT_LENGTH * ilev, ""); 80 } 81 82 /* 83 * debug version has two more flags: 84 * -L force load driver 85 * -M: print per driver list 86 */ 87 88 #ifdef DEBUG 89 static const char *optstring = "abcdDvVxmpPFf:M:LuC"; 90 #else 91 static const char *optstring = "abcdDvVxmpPFf:uC"; 92 #endif /* DEBUG */ 93 94 int 95 main(int argc, char *argv[]) 96 { 97 long pagesize, npages; 98 int c, ret; 99 char hw_provider[SYS_NMLN]; 100 101 setpname(argv[0]); 102 opts.o_promdev = "/dev/openprom"; 103 104 while ((c = getopt(argc, argv, optstring)) != -1) { 105 switch (c) { 106 case 'a': 107 ++opts.o_ancestors; 108 break; 109 case 'b': 110 ++opts.o_productinfo; 111 break; 112 case 'c': 113 ++opts.o_children; 114 break; 115 case 'd': 116 ++opts.o_pciid; 117 break; 118 case 'D': 119 ++opts.o_drv_name; 120 break; 121 case 'v': 122 ++opts.o_verbose; 123 break; 124 case 'm': 125 ++opts.o_memory; 126 break; 127 case 'p': 128 ++opts.o_prominfo; 129 break; 130 case 'f': 131 opts.o_promdev = optarg; 132 break; 133 case 'V': 134 ++opts.o_promversion; 135 break; 136 case 'x': 137 ++opts.o_prom_ready64; 138 break; 139 case 'F': 140 ++opts.o_fbname; 141 ++opts.o_noheader; 142 break; 143 case 'P': 144 ++opts.o_pseudodevs; 145 break; 146 case 'C': 147 ++opts.o_forcecache; 148 break; 149 #ifdef DEBUG 150 case 'M': 151 dbg.d_drivername = optarg; 152 ++dbg.d_bydriver; 153 break; 154 case 'L': 155 ++dbg.d_forceload; 156 break; 157 #endif /* DEBUG */ 158 159 default: 160 (void) fprintf(stderr, usage, opts.o_progname); 161 return (1); 162 } 163 } 164 165 (void) uname(&opts.o_uts); 166 167 if (opts.o_fbname) 168 return (do_fbname()); 169 170 if (opts.o_promversion) 171 return (do_promversion()); 172 173 if (opts.o_prom_ready64) 174 return (0); 175 176 if (opts.o_productinfo) 177 return (do_productinfo()); 178 179 opts.o_devices_path = NULL; 180 opts.o_devt = DDI_DEV_T_NONE; 181 opts.o_target = 0; 182 if (optind < argc) { 183 struct stat sinfo; 184 char *path = argv[optind]; 185 int error; 186 187 if (opts.o_prominfo) { 188 /* PROM tree cannot be used with path */ 189 (void) fprintf(stderr, "%s: path and -p option are " 190 "mutually exclusive\n", opts.o_progname); 191 return (1); 192 } 193 194 if (strlen(path) >= MAXPATHLEN) { 195 (void) fprintf(stderr, "%s: " 196 "path specified is too long\n", opts.o_progname); 197 return (1); 198 } 199 200 if (error = stat(path, &sinfo)) { 201 202 /* an invalid path was specified */ 203 (void) fprintf(stderr, "%s: invalid path specified\n", 204 opts.o_progname); 205 return (1); 206 207 } else if (((sinfo.st_mode & S_IFMT) == S_IFCHR) || 208 ((sinfo.st_mode & S_IFMT) == S_IFBLK)) { 209 210 opts.o_devt = sinfo.st_rdev; 211 error = 0; 212 213 } else if ((sinfo.st_mode & S_IFMT) == S_IFDIR) { 214 size_t len, plen; 215 216 if (realpath(path, new_path) == NULL) { 217 (void) fprintf(stderr, "%s: invalid device" 218 " path specified\n", 219 opts.o_progname); 220 return (1); 221 } 222 223 len = strlen(new_path); 224 plen = strlen("/devices"); 225 if (len < plen) { 226 /* This is not a valid /devices path */ 227 error = 1; 228 } else if ((len == plen) && 229 (strcmp(new_path, "/devices") == 0)) { 230 /* /devices is the root nexus */ 231 opts.o_devices_path = "/"; 232 error = 0; 233 } else if (strncmp(new_path, "/devices/", plen + 1)) { 234 /* This is not a valid /devices path */ 235 error = 1; 236 } else { 237 /* a /devices/ path was specified */ 238 opts.o_devices_path = new_path + plen; 239 error = 0; 240 } 241 242 } else { 243 /* an invalid device path was specified */ 244 error = 1; 245 } 246 247 if (error) { 248 (void) fprintf(stderr, "%s: " 249 "invalid device path specified\n", 250 opts.o_progname); 251 return (1); 252 } 253 254 opts.o_target = 1; 255 } 256 257 if ((opts.o_ancestors || opts.o_children) && (!opts.o_target)) { 258 (void) fprintf(stderr, "%s: options require a device path\n", 259 opts.o_progname); 260 return (1); 261 } 262 263 if (opts.o_target) { 264 prtconf_devinfo(); 265 return (0); 266 } 267 268 if (!opts.o_memory) { 269 ret = sysinfo(SI_HW_PROVIDER, hw_provider, 270 sizeof (hw_provider)); 271 /* 272 * If 0 bytes are returned (the system returns '1', for the \0), 273 * we're probably on x86, default to "Unknown Hardware Vendor". 274 */ 275 if (ret <= 1) { 276 (void) strncpy(hw_provider, "Unknown Hardware Vendor", 277 sizeof (hw_provider)); 278 } 279 (void) printf("System Configuration: %s %s\n", hw_provider, 280 opts.o_uts.machine); 281 } 282 283 pagesize = sysconf(_SC_PAGESIZE); 284 npages = sysconf(_SC_PHYS_PAGES); 285 if (pagesize == -1 || npages == -1) { 286 if (opts.o_memory) { 287 (void) printf("0\n"); 288 return (1); 289 } else { 290 (void) printf("Memory size: unable to determine\n"); 291 } 292 } else { 293 const int64_t mbyte = 1024 * 1024; 294 int64_t ii = (int64_t)pagesize * npages; 295 296 if (opts.o_memory) { 297 (void) printf("%ld\n", (long)((ii+mbyte-1) / mbyte)); 298 return (0); 299 } else { 300 (void) printf("Memory size: %ld Megabytes\n", 301 (long)((ii+mbyte-1) / mbyte)); 302 } 303 } 304 305 if (opts.o_prominfo) { 306 (void) printf("System Peripherals (PROM Nodes):\n\n"); 307 if (do_prominfo() == 0) 308 return (0); 309 (void) fprintf(stderr, "%s: Defaulting to non-PROM mode...\n", 310 opts.o_progname); 311 } 312 313 (void) printf("System Peripherals (Software Nodes):\n\n"); 314 315 (void) prtconf_devinfo(); 316 317 return (0); 318 } 319