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 }