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 2008 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 #include <sys/types.h>
  27 #include <sys/inttypes.h>
  28 #include <sys/param.h>
  29 #include <sys/systm.h>
  30 #include <sys/user.h>
  31 #include <sys/disp.h>
  32 #include <sys/conf.h>
  33 #include <sys/bootconf.h>
  34 #include <sys/sysconf.h>
  35 #include <sys/sunddi.h>
  36 #include <sys/esunddi.h>
  37 #include <sys/ddi_impldefs.h>
  38 #include <sys/kmem.h>
  39 #include <sys/vmem.h>
  40 #include <sys/fs/ufs_fsdir.h>
  41 #include <sys/hwconf.h>
  42 #include <sys/modctl.h>
  43 #include <sys/cmn_err.h>
  44 #include <sys/kobj.h>
  45 #include <sys/kobj_lex.h>
  46 #include <sys/errno.h>
  47 #include <sys/debug.h>
  48 #include <sys/autoconf.h>
  49 #include <sys/callb.h>
  50 #include <sys/sysmacros.h>
  51 #include <sys/dacf.h>
  52 #include <vm/seg_kmem.h>
  53 
  54 struct hwc_class *hcl_head;     /* head of list of classes */
  55 static kmutex_t hcl_lock;       /* for accessing list of classes */
  56 
  57 #define DAFILE          "/etc/driver_aliases"
  58 #define CLASSFILE       "/etc/driver_classes"
  59 #define DACFFILE        "/etc/dacf.conf"
  60 
  61 static char class_file[] = CLASSFILE;
  62 static char dafile[] = DAFILE;
  63 static char dacffile[] = DACFFILE;
  64 
  65 char *systemfile = "/etc/system";       /* name of ascii system file */
  66 
  67 static struct sysparam *sysparam_hd;    /* head of parameters list */
  68 static struct sysparam *sysparam_tl;    /* tail of parameters list */
  69 static vmem_t *mod_sysfile_arena;       /* parser memory */
  70 
  71 char obp_bootpath[BO_MAXOBJNAME];       /* bootpath from obp */
  72 char svm_bootpath[BO_MAXOBJNAME];       /* bootpath redirected via rootdev */
  73 
  74 #if defined(_PSM_MODULES)
  75 
  76 struct psm_mach {
  77         struct psm_mach *m_next;
  78         char            *m_machname;
  79 };
  80 
  81 static struct psm_mach *pmach_head;     /* head of list of classes */
  82 
  83 #define MACHFILE        "/etc/mach"
  84 static char mach_file[] = MACHFILE;
  85 
  86 #endif  /* _PSM_MODULES */
  87 
  88 #if defined(_RTC_CONFIG)
  89 static char rtc_config_file[] = "/etc/rtc_config";
  90 #endif
  91 
  92 static void sys_set_var(int, struct sysparam *, void *);
  93 
  94 static void setparams(void);
  95 
  96 /*
  97  * driver.conf parse thread control structure
  98  */
  99 struct hwc_parse_mt {
 100         ksema_t         sema;
 101         char            *name;          /* name of .conf files */
 102         struct par_list **pl;           /* parsed parent list */
 103         ddi_prop_t      **props;        /* parsed properties */
 104         int             rv;             /* return value */
 105 };
 106 
 107 static int hwc_parse_now(char *, struct par_list **, ddi_prop_t **);
 108 static void hwc_parse_thread(struct hwc_parse_mt *);
 109 static struct hwc_parse_mt *hwc_parse_mtalloc(char *, struct par_list **,
 110         ddi_prop_t **);
 111 static void hwc_parse_mtfree(struct hwc_parse_mt *);
 112 static void add_spec(struct hwc_spec *, struct par_list **);
 113 static void add_props(struct hwc_spec *, ddi_prop_t **);
 114 
 115 static void check_system_file(void);
 116 static int sysparam_compare_entry(struct sysparam *, struct sysparam *);
 117 static char *sysparam_type_to_str(int);
 118 static void sysparam_count_entry(struct sysparam *, int *, u_longlong_t *);
 119 static void sysparam_print_warning(struct sysparam *, u_longlong_t);
 120 
 121 #ifdef DEBUG
 122 static int parse_debug_on = 0;
 123 
 124 /*VARARGS1*/
 125 static void
 126 parse_debug(struct _buf *file, char *fmt, ...)
 127 {
 128         va_list adx;
 129 
 130         if (parse_debug_on) {
 131                 va_start(adx, fmt);
 132                 vprintf(fmt, adx);
 133                 if (file)
 134                         printf(" on line %d of %s\n", kobj_linenum(file),
 135                             kobj_filename(file));
 136                 va_end(adx);
 137         }
 138 }
 139 #endif /* DEBUG */
 140 
 141 #define FE_BUFLEN 256
 142 
 143 /*PRINTFLIKE3*/
 144 void
 145 kobj_file_err(int type,  struct _buf *file, char *fmt, ...)
 146 {
 147         va_list ap;
 148         /*
 149          * If we're in trouble, we might be short on stack... be paranoid
 150          */
 151         char *buf = kmem_alloc(FE_BUFLEN, KM_SLEEP);
 152         char *trailer = kmem_alloc(FE_BUFLEN, KM_SLEEP);
 153         char *fmt_str = kmem_alloc(FE_BUFLEN, KM_SLEEP);
 154         char prefix = '\0';
 155 
 156         va_start(ap, fmt);
 157         if (strchr("^!?", fmt[0]) != NULL) {
 158                 prefix = fmt[0];
 159                 fmt++;
 160         }
 161         (void) vsnprintf(buf, FE_BUFLEN, fmt, ap);
 162         va_end(ap);
 163         (void) snprintf(trailer, FE_BUFLEN, " on line %d of %s",
 164             kobj_linenum(file), kobj_filename(file));
 165 
 166         /*
 167          * If prefixed with !^?, prepend that character
 168          */
 169         if (prefix != '\0') {
 170                 (void) snprintf(fmt_str, FE_BUFLEN, "%c%%s%%s", prefix);
 171         } else {
 172                 (void) strncpy(fmt_str, "%s%s", FE_BUFLEN);
 173         }
 174 
 175         cmn_err(type, fmt_str, buf, trailer);
 176         kmem_free(buf, FE_BUFLEN);
 177         kmem_free(trailer, FE_BUFLEN);
 178         kmem_free(fmt_str, FE_BUFLEN);
 179 }
 180 
 181 #ifdef DEBUG
 182 char *tokennames[] = {
 183         "UNEXPECTED",
 184         "EQUALS",
 185         "AMPERSAND",
 186         "BIT_OR",
 187         "STAR",
 188         "POUND",
 189         "COLON",
 190         "SEMICOLON",
 191         "COMMA",
 192         "SLASH",
 193         "WHITE_SPACE",
 194         "NEWLINE",
 195         "EOF",
 196         "STRING",
 197         "HEXVAL",
 198         "DECVAL",
 199         "NAME"
 200 };
 201 #endif /* DEBUG */
 202 
 203 token_t
 204 kobj_lex(struct _buf *file, char *val, size_t size)
 205 {
 206         char    *cp;
 207         int     ch, oval, badquote;
 208         size_t  remain;
 209         token_t token = UNEXPECTED;
 210 
 211         if (size < 2)
 212                 return (token); /* this token is UNEXPECTED */
 213 
 214         cp = val;
 215         while ((ch = kobj_getc(file)) == ' ' || ch == '\t')
 216                 ;
 217 
 218         remain = size - 1;
 219         *cp++ = (char)ch;
 220         switch (ch) {
 221         case '=':
 222                 token = EQUALS;
 223                 break;
 224         case '&':
 225                 token = AMPERSAND;
 226                 break;
 227         case '|':
 228                 token = BIT_OR;
 229                 break;
 230         case '*':
 231                 token = STAR;
 232                 break;
 233         case '#':
 234                 token = POUND;
 235                 break;
 236         case ':':
 237                 token = COLON;
 238                 break;
 239         case ';':
 240                 token = SEMICOLON;
 241                 break;
 242         case ',':
 243                 token = COMMA;
 244                 break;
 245         case '/':
 246                 token = SLASH;
 247                 break;
 248         case ' ':
 249         case '\t':
 250         case '\f':
 251                 while ((ch = kobj_getc(file)) == ' ' ||
 252                     ch == '\t' || ch == '\f') {
 253                         if (--remain == 0) {
 254                                 token = UNEXPECTED;
 255                                 goto out;
 256                         }
 257                         *cp++ = (char)ch;
 258                 }
 259                 (void) kobj_ungetc(file);
 260                 token = WHITE_SPACE;
 261                 break;
 262         case '\n':
 263         case '\r':
 264                 token = NEWLINE;
 265                 break;
 266         case '"':
 267                 remain++;
 268                 cp--;
 269                 badquote = 0;
 270                 while (!badquote && (ch  = kobj_getc(file)) != '"') {
 271                         switch (ch) {
 272                         case '\n':
 273                         case -1:
 274                                 kobj_file_err(CE_WARN, file, "Missing \"");
 275                                 remain = size - 1;
 276                                 cp = val;
 277                                 *cp++ = '\n';
 278                                 badquote = 1;
 279                                 /* since we consumed the newline/EOF */
 280                                 (void) kobj_ungetc(file);
 281                                 break;
 282 
 283                         case '\\':
 284                                 if (--remain == 0) {
 285                                         token = UNEXPECTED;
 286                                         goto out;
 287                                 }
 288                                 ch = (char)kobj_getc(file);
 289                                 if (!isdigit(ch)) {
 290                                         /* escape the character */
 291                                         *cp++ = (char)ch;
 292                                         break;
 293                                 }
 294                                 oval = 0;
 295                                 while (ch >= '0' && ch <= '7') {
 296                                         ch -= '0';
 297                                         oval = (oval << 3) + ch;
 298                                         ch = (char)kobj_getc(file);
 299                                 }
 300                                 (void) kobj_ungetc(file);
 301                                 /* check for character overflow? */
 302                                 if (oval > 127) {
 303                                         cmn_err(CE_WARN,
 304                                             "Character "
 305                                             "overflow detected.");
 306                                 }
 307                                 *cp++ = (char)oval;
 308                                 break;
 309                         default:
 310                                 if (--remain == 0) {
 311                                         token = UNEXPECTED;
 312                                         goto out;
 313                                 }
 314                                 *cp++ = (char)ch;
 315                                 break;
 316                         }
 317                 }
 318                 token = STRING;
 319                 break;
 320 
 321         case -1:
 322                 token = EOF;
 323                 break;
 324 
 325         default:
 326                 /*
 327                  * detect a lone '-' (including at the end of a line), and
 328                  * identify it as a 'name'
 329                  */
 330                 if (ch == '-') {
 331                         if (--remain == 0) {
 332                                 token = UNEXPECTED;
 333                                 goto out;
 334                         }
 335                         *cp++ = (char)(ch = kobj_getc(file));
 336                         if (iswhite(ch) || (ch == '\n')) {
 337                                 (void) kobj_ungetc(file);
 338                                 remain++;
 339                                 cp--;
 340                                 token = NAME;
 341                                 break;
 342                         }
 343                 } else if (isunary(ch)) {
 344                         if (--remain == 0) {
 345                                 token = UNEXPECTED;
 346                                 goto out;
 347                         }
 348                         *cp++ = (char)(ch = kobj_getc(file));
 349                 }
 350 
 351 
 352                 if (isdigit(ch)) {
 353                         if (ch == '0') {
 354                                 if ((ch = kobj_getc(file)) == 'x') {
 355                                         if (--remain == 0) {
 356                                                 token = UNEXPECTED;
 357                                                 goto out;
 358                                         }
 359                                         *cp++ = (char)ch;
 360                                         ch = kobj_getc(file);
 361                                         while (isxdigit(ch)) {
 362                                                 if (--remain == 0) {
 363                                                         token = UNEXPECTED;
 364                                                         goto out;
 365                                                 }
 366                                                 *cp++ = (char)ch;
 367                                                 ch = kobj_getc(file);
 368                                         }
 369                                         (void) kobj_ungetc(file);
 370                                         token = HEXVAL;
 371                                 } else {
 372                                         goto digit;
 373                                 }
 374                         } else {
 375                                 ch = kobj_getc(file);
 376 digit:
 377                                 while (isdigit(ch)) {
 378                                         if (--remain == 0) {
 379                                                 token = UNEXPECTED;
 380                                                 goto out;
 381                                         }
 382                                         *cp++ = (char)ch;
 383                                         ch = kobj_getc(file);
 384                                 }
 385                                 (void) kobj_ungetc(file);
 386                                 token = DECVAL;
 387                         }
 388                 } else if (isalpha(ch) || ch == '\\' || ch == '_') {
 389                         if (ch != '\\') {
 390                                 ch = kobj_getc(file);
 391                         } else {
 392                                 /*
 393                                  * if the character was a backslash,
 394                                  * back up so we can overwrite it with
 395                                  * the next (i.e. escaped) character.
 396                                  */
 397                                 remain++;
 398                                 cp--;
 399                         }
 400                         while (isnamechar(ch) || ch == '\\') {
 401                                 if (ch == '\\')
 402                                         ch = kobj_getc(file);
 403                                 if (--remain == 0) {
 404                                         token = UNEXPECTED;
 405                                         goto out;
 406                                 }
 407                                 *cp++ = (char)ch;
 408                                 ch = kobj_getc(file);
 409                         }
 410                         (void) kobj_ungetc(file);
 411                         token = NAME;
 412                 } else {
 413                         token = UNEXPECTED;
 414                 }
 415                 break;
 416         }
 417 out:
 418         *cp = '\0';
 419 
 420 #ifdef DEBUG
 421         /*
 422          * The UNEXPECTED token is the first element of the tokennames array,
 423          * but its token value is -1.  Adjust the value by adding one to it
 424          * to change it to an index of the array.
 425          */
 426         parse_debug(NULL, "kobj_lex: token %s value '%s'\n",
 427             tokennames[token+1], val);
 428 #endif
 429         return (token);
 430 }
 431 
 432 /*
 433  * Leave NEWLINE as the next character.
 434  */
 435 
 436 void
 437 kobj_find_eol(struct _buf *file)
 438 {
 439         int ch;
 440 
 441         while ((ch = kobj_getc(file)) != -1) {
 442                 if (isnewline(ch)) {
 443                         (void) kobj_ungetc(file);
 444                         break;
 445                 }
 446         }
 447 }
 448 
 449 /*
 450  * The ascii system file is read and processed.
 451  *
 452  * The syntax of commands is as follows:
 453  *
 454  * '*' in column 1 is a comment line.
 455  * <command> : <value>
 456  *
 457  * command is EXCLUDE, INCLUDE, FORCELOAD, ROOTDEV, ROOTFS,
 458  *      SWAPDEV, SWAPFS, MODDIR, SET
 459  *
 460  * value is an ascii string meaningful for the command.
 461  */
 462 
 463 /*
 464  * Table of commands
 465  */
 466 static struct modcmd modcmd[] = {
 467         { "EXCLUDE",    MOD_EXCLUDE     },
 468         { "exclude",    MOD_EXCLUDE     },
 469         { "INCLUDE",    MOD_INCLUDE     },
 470         { "include",    MOD_INCLUDE     },
 471         { "FORCELOAD",  MOD_FORCELOAD   },
 472         { "forceload",  MOD_FORCELOAD   },
 473         { "ROOTDEV",    MOD_ROOTDEV     },
 474         { "rootdev",    MOD_ROOTDEV     },
 475         { "ROOTFS",     MOD_ROOTFS      },
 476         { "rootfs",     MOD_ROOTFS      },
 477         { "SWAPDEV",    MOD_SWAPDEV     },
 478         { "swapdev",    MOD_SWAPDEV     },
 479         { "SWAPFS",     MOD_SWAPFS      },
 480         { "swapfs",     MOD_SWAPFS      },
 481         { "MODDIR",     MOD_MODDIR      },
 482         { "moddir",     MOD_MODDIR      },
 483         { "SET",        MOD_SET         },
 484         { "set",        MOD_SET         },
 485         { "SET32",      MOD_SET32       },
 486         { "set32",      MOD_SET32       },
 487         { "SET64",      MOD_SET64       },
 488         { "set64",      MOD_SET64       },
 489         { NULL,         MOD_UNKNOWN     }
 490 };
 491 
 492 
 493 static char bad_op[] = "illegal operator '%s' used on a string";
 494 static char colon_err[] = "A colon (:) must follow the '%s' command";
 495 static char tok_err[] = "Unexpected token '%s'";
 496 static char extra_err[] = "extraneous input ignored starting at '%s'";
 497 static char oversize_err[] = "value too long";
 498 
 499 static struct sysparam *
 500 do_sysfile_cmd(struct _buf *file, const char *cmd)
 501 {
 502         struct sysparam *sysp;
 503         struct modcmd *mcp;
 504         token_t token, op;
 505         char *cp;
 506         int ch;
 507         char tok1[MOD_MAXPATH + 1]; /* used to read the path set by 'moddir' */
 508         char tok2[64];
 509 
 510         for (mcp = modcmd; mcp->mc_cmdname != NULL; mcp++) {
 511                 if (strcmp(mcp->mc_cmdname, cmd) == 0)
 512                         break;
 513         }
 514         sysp = vmem_alloc(mod_sysfile_arena, sizeof (struct sysparam),
 515             VM_SLEEP);
 516         bzero(sysp, sizeof (struct sysparam));
 517         sysp->sys_op = SETOP_NONE; /* set op to noop initially */
 518 
 519         switch (sysp->sys_type = mcp->mc_type) {
 520         case MOD_INCLUDE:
 521         case MOD_EXCLUDE:
 522         case MOD_FORCELOAD:
 523                 /*
 524                  * Are followed by colon.
 525                  */
 526         case MOD_ROOTFS:
 527         case MOD_SWAPFS:
 528                 if ((token = kobj_lex(file, tok1, sizeof (tok1))) == COLON) {
 529                         token = kobj_lex(file, tok1, sizeof (tok1));
 530                 } else {
 531                         kobj_file_err(CE_WARN, file, colon_err, cmd);
 532                 }
 533                 if (token != NAME) {
 534                         kobj_file_err(CE_WARN, file, "value expected");
 535                         goto bad;
 536                 }
 537 
 538                 cp = tok1 + strlen(tok1);
 539                 while ((ch = kobj_getc(file)) != -1 && !iswhite(ch) &&
 540                     !isnewline(ch)) {
 541                         if (cp - tok1 >= sizeof (tok1) - 1) {
 542                                 kobj_file_err(CE_WARN, file, oversize_err);
 543                                 goto bad;
 544                         }
 545                         *cp++ = (char)ch;
 546                 }
 547                 *cp = '\0';
 548 
 549                 if (ch != -1)
 550                         (void) kobj_ungetc(file);
 551                 if (sysp->sys_type == MOD_INCLUDE)
 552                         return (NULL);
 553                 sysp->sys_ptr = vmem_alloc(mod_sysfile_arena, strlen(tok1) + 1,
 554                     VM_SLEEP);
 555                 (void) strcpy(sysp->sys_ptr, tok1);
 556                 break;
 557         case MOD_SET:
 558         case MOD_SET64:
 559         case MOD_SET32:
 560         {
 561                 char *var;
 562                 token_t tok3;
 563 
 564                 if (kobj_lex(file, tok1, sizeof (tok1)) != NAME) {
 565                         kobj_file_err(CE_WARN, file, "value expected");
 566                         goto bad;
 567                 }
 568 
 569                 /*
 570                  * If the next token is a colon (:),
 571                  * we have the <modname>:<variable> construct.
 572                  */
 573                 if ((token = kobj_lex(file, tok2, sizeof (tok2))) == COLON) {
 574                         if ((token = kobj_lex(file, tok2,
 575                             sizeof (tok2))) == NAME) {
 576                                 var = tok2;
 577                                 /*
 578                                  * Save the module name.
 579                                  */
 580                                 sysp->sys_modnam = vmem_alloc(mod_sysfile_arena,
 581                                     strlen(tok1) + 1, VM_SLEEP);
 582                                 (void) strcpy(sysp->sys_modnam, tok1);
 583                                 op = kobj_lex(file, tok1, sizeof (tok1));
 584                         } else {
 585                                 kobj_file_err(CE_WARN, file, "value expected");
 586                                 goto bad;
 587                         }
 588                 } else {
 589                         /* otherwise, it was the op */
 590                         var = tok1;
 591                         op = token;
 592                 }
 593                 /*
 594                  * kernel param - place variable name in sys_ptr.
 595                  */
 596                 sysp->sys_ptr = vmem_alloc(mod_sysfile_arena, strlen(var) + 1,
 597                     VM_SLEEP);
 598                 (void) strcpy(sysp->sys_ptr, var);
 599                 /* set operation */
 600                 switch (op) {
 601                 case EQUALS:
 602                         /* simple assignment */
 603                         sysp->sys_op = SETOP_ASSIGN;
 604                         break;
 605                 case AMPERSAND:
 606                         /* bitwise AND */
 607                         sysp->sys_op = SETOP_AND;
 608                         break;
 609                 case BIT_OR:
 610                         /* bitwise OR */
 611                         sysp->sys_op = SETOP_OR;
 612                         break;
 613                 default:
 614                         /* unsupported operation */
 615                         kobj_file_err(CE_WARN, file,
 616                             "unsupported operator %s", tok2);
 617                         goto bad;
 618                 }
 619 
 620                 switch ((tok3 = kobj_lex(file, tok1, sizeof (tok1)))) {
 621                 case STRING:
 622                         /* string variable */
 623                         if (sysp->sys_op != SETOP_ASSIGN) {
 624                                 kobj_file_err(CE_WARN, file, bad_op, tok1);
 625                                 goto bad;
 626                         }
 627                         if (kobj_get_string(&sysp->sys_info, tok1) == 0) {
 628                                 kobj_file_err(CE_WARN, file, "string garbled");
 629                                 goto bad;
 630                         }
 631                         /*
 632                          * Set SYSPARAM_STR_TOKEN in sys_flags to notify
 633                          * sysparam_print_warning() that this is a string
 634                          * token.
 635                          */
 636                         sysp->sys_flags |= SYSPARAM_STR_TOKEN;
 637                         break;
 638                 case HEXVAL:
 639                 case DECVAL:
 640                         if (kobj_getvalue(tok1, &sysp->sys_info) == -1) {
 641                                 kobj_file_err(CE_WARN, file,
 642                                     "invalid number '%s'", tok1);
 643                                 goto bad;
 644                         }
 645 
 646                         /*
 647                          * Set the appropriate flag (hexadecimal or decimal)
 648                          * in sys_flags for sysparam_print_warning() to be
 649                          * able to print the number with the correct format.
 650                          */
 651                         if (tok3 == HEXVAL) {
 652                                 sysp->sys_flags |= SYSPARAM_HEX_TOKEN;
 653                         } else {
 654                                 sysp->sys_flags |= SYSPARAM_DEC_TOKEN;
 655                         }
 656                         break;
 657                 default:
 658                         kobj_file_err(CE_WARN, file, "bad rvalue '%s'", tok1);
 659                         goto bad;
 660                 } /* end switch */
 661 
 662                 /*
 663                  * Now that we've parsed it to check the syntax, consider
 664                  * discarding it (because it -doesn't- apply to this flavor
 665                  * of the kernel)
 666                  */
 667 #ifdef _LP64
 668                 if (sysp->sys_type == MOD_SET32)
 669                         return (NULL);
 670 #else
 671                 if (sysp->sys_type == MOD_SET64)
 672                         return (NULL);
 673 #endif
 674                 sysp->sys_type = MOD_SET;
 675                 break;
 676         }
 677         case MOD_MODDIR:
 678                 if ((token = kobj_lex(file, tok1, sizeof (tok1))) != COLON) {
 679                         kobj_file_err(CE_WARN, file, colon_err, cmd);
 680                         goto bad;
 681                 }
 682 
 683                 cp = tok1;
 684                 while ((token = kobj_lex(file, cp,
 685                     sizeof (tok1) - (cp - tok1))) != NEWLINE && token != EOF) {
 686                         if (token == -1) {
 687                                 kobj_file_err(CE_WARN, file, oversize_err);
 688                                 goto bad;
 689                         }
 690                         cp += strlen(cp);
 691                         while ((ch = kobj_getc(file)) != -1 && !iswhite(ch) &&
 692                             !isnewline(ch) && ch != ':') {
 693                                 if (cp - tok1 >= sizeof (tok1) - 1) {
 694                                         kobj_file_err(CE_WARN, file,
 695                                             oversize_err);
 696                                         goto bad;
 697                                 }
 698                                 *cp++ = (char)ch;
 699                         }
 700                         *cp++ = ' ';
 701                         if (isnewline(ch)) {
 702                                 cp--;
 703                                 (void) kobj_ungetc(file);
 704                         }
 705                 }
 706                 (void) kobj_ungetc(file);
 707                 *cp  = '\0';
 708                 sysp->sys_ptr = vmem_alloc(mod_sysfile_arena, strlen(tok1) + 1,
 709                     VM_SLEEP);
 710                 (void) strcpy(sysp->sys_ptr, tok1);
 711                 break;
 712 
 713         case MOD_SWAPDEV:
 714         case MOD_ROOTDEV:
 715                 if ((token = kobj_lex(file, tok1, sizeof (tok1))) != COLON) {
 716                         kobj_file_err(CE_WARN, file, colon_err, cmd);
 717                         goto bad;
 718                 }
 719                 while ((ch = kobj_getc(file)) == ' ' || ch == '\t')
 720                         ;
 721                 cp = tok1;
 722                 while (!iswhite(ch) && !isnewline(ch) && ch != -1) {
 723                         if (cp - tok1 >= sizeof (tok1) - 1) {
 724                                 kobj_file_err(CE_WARN, file, oversize_err);
 725                                 goto bad;
 726                         }
 727 
 728                         *cp++ = (char)ch;
 729                         ch = kobj_getc(file);
 730                 }
 731                 if (ch != -1)
 732                         (void) kobj_ungetc(file);
 733                 *cp = '\0';
 734 
 735                 sysp->sys_ptr = vmem_alloc(mod_sysfile_arena, strlen(tok1) + 1,
 736                     VM_SLEEP);
 737                 (void) strcpy(sysp->sys_ptr, tok1);
 738                 break;
 739 
 740         case MOD_UNKNOWN:
 741         default:
 742                 kobj_file_err(CE_WARN, file, "unknown command '%s'", cmd);
 743                 goto bad;
 744         }
 745 
 746         return (sysp);
 747 
 748 bad:
 749         kobj_find_eol(file);
 750         return (NULL);
 751 }
 752 
 753 void
 754 mod_read_system_file(int ask)
 755 {
 756         register struct sysparam *sp;
 757         register struct _buf *file;
 758         register token_t token, last_tok;
 759         char tokval[MAXLINESIZE];
 760 
 761         mod_sysfile_arena = vmem_create("mod_sysfile", NULL, 0, 8,
 762             segkmem_alloc, segkmem_free, heap_arena, 0, VM_SLEEP);
 763 
 764         if (ask)
 765                 mod_askparams();
 766 
 767         if (systemfile != NULL) {
 768 
 769                 if ((file = kobj_open_file(systemfile)) ==
 770                     (struct _buf *)-1) {
 771                         cmn_err(CE_WARN, "cannot open system file: %s",
 772                             systemfile);
 773                 } else {
 774                         sysparam_tl = (struct sysparam *)&sysparam_hd;
 775 
 776                         last_tok = NEWLINE;
 777                         while ((token = kobj_lex(file, tokval,
 778                             sizeof (tokval))) != EOF) {
 779                                 switch (token) {
 780                                 case STAR:
 781                                 case POUND:
 782                                         /*
 783                                          * Skip comments.
 784                                          */
 785                                         kobj_find_eol(file);
 786                                         break;
 787                                 case NEWLINE:
 788                                         kobj_newline(file);
 789                                         last_tok = NEWLINE;
 790                                         break;
 791                                 case NAME:
 792                                         if (last_tok != NEWLINE) {
 793                                                 kobj_file_err(CE_WARN, file,
 794                                                     extra_err, tokval);
 795                                                 kobj_find_eol(file);
 796                                         } else if ((sp = do_sysfile_cmd(file,
 797                                             tokval)) != NULL) {
 798                                                 sp->sys_next = NULL;
 799                                                 sysparam_tl->sys_next = sp;
 800                                                 sysparam_tl = sp;
 801                                         }
 802                                         last_tok = NAME;
 803                                         break;
 804                                 default:
 805                                         kobj_file_err(CE_WARN,
 806                                             file, tok_err, tokval);
 807                                         kobj_find_eol(file);
 808                                         break;
 809                                 }
 810                         }
 811                         kobj_close_file(file);
 812                 }
 813         }
 814 
 815         /*
 816          * Sanity check of /etc/system.
 817          */
 818         check_system_file();
 819 
 820         param_preset();
 821         (void) mod_sysctl(SYS_SET_KVAR, NULL);
 822         param_check();
 823 
 824         if (ask == 0)
 825                 setparams();
 826 }
 827 
 828 /*
 829  * Search for a specific module variable assignment in /etc/system.  If
 830  * successful, 1 is returned and the value is stored in '*value'.
 831  * Otherwise 0 is returned and '*value' isn't modified.  If 'module' is
 832  * NULL we look for global definitions.
 833  *
 834  * This is useful if the value of an assignment is needed before a
 835  * module is loaded (e.g. to obtain a default privileged rctl limit).
 836  */
 837 int
 838 mod_sysvar(const char *module, const char *name, u_longlong_t *value)
 839 {
 840         struct sysparam *sysp;
 841         int cnt = 0; /* dummy */
 842 
 843         ASSERT(name != NULL);
 844         ASSERT(value != NULL);
 845         for (sysp = sysparam_hd; sysp != NULL; sysp = sysp->sys_next) {
 846 
 847                 if ((sysp->sys_type == MOD_SET) &&
 848                     (((module == NULL) && (sysp->sys_modnam == NULL)) ||
 849                     ((module != NULL) && (sysp->sys_modnam != NULL) &&
 850                     (strcmp(module, sysp->sys_modnam) == 0)))) {
 851 
 852                         ASSERT(sysp->sys_ptr != NULL);
 853 
 854                         if (strcmp(name, sysp->sys_ptr) == 0) {
 855                                 sysparam_count_entry(sysp, &cnt, value);
 856                                 if ((sysp->sys_flags & SYSPARAM_TERM) != 0)
 857                                         return (1);
 858                                 continue;
 859                         }
 860                 }
 861         }
 862         ASSERT(cnt == 0);
 863         return (0);
 864 }
 865 
 866 /*
 867  * This function scans sysparam records, which are created from the
 868  * contents of /etc/system, for entries which are logical duplicates,
 869  * and prints warning messages as appropriate.  When multiple "set"
 870  * commands are encountered, the pileup of values with "&", "|"
 871  * and "=" operators results in the final value.
 872  */
 873 static void
 874 check_system_file(void)
 875 {
 876         struct sysparam *sysp;
 877 
 878         for (sysp = sysparam_hd; sysp != NULL; sysp = sysp->sys_next) {
 879                 struct sysparam *entry, *final;
 880                 u_longlong_t value = 0;
 881                 int cnt = 1;
 882                 /*
 883                  * If the entry is already checked, skip it.
 884                  */
 885                 if ((sysp->sys_flags & SYSPARAM_DUP) != 0)
 886                         continue;
 887                 /*
 888                  * Check if there is a duplicate entry by doing a linear
 889                  * search.
 890                  */
 891                 final = sysp;
 892                 for (entry = sysp->sys_next; entry != NULL;
 893                     entry = entry->sys_next) {
 894                         /*
 895                          * Check the entry. if it's different, skip this.
 896                          */
 897                         if (sysparam_compare_entry(sysp, entry) != 0)
 898                                 continue;
 899                         /*
 900                          * Count the entry and put the mark.
 901                          */
 902                         sysparam_count_entry(entry, &cnt, &value);
 903                         entry->sys_flags |= SYSPARAM_DUP;
 904                         final = entry;
 905                 }
 906                 final->sys_flags |= SYSPARAM_TERM;
 907                 /*
 908                  * Print the warning if it's duplicated.
 909                  */
 910                 if (cnt >= 2)
 911                         sysparam_print_warning(final, value);
 912         }
 913 }
 914 
 915 /*
 916  * Compare the sysparam records.
 917  * Return 0 if they are the same, return 1 if not.
 918  */
 919 static int
 920 sysparam_compare_entry(struct sysparam *sysp, struct sysparam *entry)
 921 {
 922         ASSERT(sysp->sys_ptr != NULL && entry->sys_ptr != NULL);
 923 
 924         /*
 925          * If the command is rootdev, rootfs, swapdev, swapfs or moddir,
 926          * the record with the same type is treated as a duplicate record.
 927          * In other cases, the record is treated as a duplicate record when
 928          * its type, its module name (if it exists), and its variable name
 929          * are the same.
 930          */
 931         switch (sysp->sys_type) {
 932         case MOD_ROOTDEV:
 933         case MOD_ROOTFS:
 934         case MOD_SWAPDEV:
 935         case MOD_SWAPFS:
 936         case MOD_MODDIR:
 937                 return (sysp->sys_type == entry->sys_type ? 0 : 1);
 938         default: /* In other cases, just go through it. */
 939                 break;
 940         }
 941 
 942         if (sysp->sys_type != entry->sys_type)
 943                 return (1);
 944 
 945         if (sysp->sys_modnam != NULL && entry->sys_modnam == NULL)
 946                 return (1);
 947 
 948         if (sysp->sys_modnam == NULL && entry->sys_modnam != NULL)
 949                 return (1);
 950 
 951         if (sysp->sys_modnam != NULL && entry->sys_modnam != NULL &&
 952             strcmp(sysp->sys_modnam, entry->sys_modnam) != 0)
 953                 return (1);
 954 
 955         return (strcmp(sysp->sys_ptr, entry->sys_ptr));
 956 }
 957 
 958 /*
 959  * Translate a sysparam type value to a string.
 960  */
 961 static char *
 962 sysparam_type_to_str(int type)
 963 {
 964         struct modcmd *mcp;
 965 
 966         for (mcp = modcmd; mcp->mc_cmdname != NULL; mcp++) {
 967                 if (mcp->mc_type == type)
 968                         break;
 969         }
 970         ASSERT(mcp->mc_type == type);
 971 
 972         if (type != MOD_UNKNOWN)
 973                 return ((++mcp)->mc_cmdname); /* lower case */
 974         else
 975                 return ("");    /* MOD_UNKNOWN */
 976 }
 977 
 978 /*
 979  * Check the entry and accumulate the number of entries.
 980  */
 981 static void
 982 sysparam_count_entry(struct sysparam *sysp, int *cnt, u_longlong_t *value)
 983 {
 984         u_longlong_t ul = sysp->sys_info;
 985 
 986         switch (sysp->sys_op) {
 987         case SETOP_ASSIGN:
 988                 *value = ul;
 989                 (*cnt)++;
 990                 return;
 991         case SETOP_AND:
 992                 *value &= ul;
 993                 return;
 994         case SETOP_OR:
 995                 *value |= ul;
 996                 return;
 997         default: /* Not MOD_SET */
 998                 (*cnt)++;
 999                 return;
1000         }
1001 }
1002 
1003 /*
1004  * Print out the warning if multiple entries are found in the system file.
1005  */
1006 static void
1007 sysparam_print_warning(struct sysparam *sysp, u_longlong_t value)
1008 {
1009         char *modnam = sysp->sys_modnam;
1010         char *varnam = sysp->sys_ptr;
1011         int type = sysp->sys_type;
1012         char *typenam = sysparam_type_to_str(type);
1013         boolean_t str_token = ((sysp->sys_flags & SYSPARAM_STR_TOKEN) != 0);
1014         boolean_t hex_number = ((sysp->sys_flags & SYSPARAM_HEX_TOKEN) != 0);
1015 #define warn_format1 " is set more than once in /%s. "
1016 #define warn_format2 " applied as the current setting.\n"
1017 
1018         ASSERT(varnam != NULL);
1019 
1020         if (type == MOD_SET) {
1021                 /*
1022                  * If a string token is set, print out the string
1023                  * instead of its pointer value. In other cases,
1024                  * print out the value with the appropriate format
1025                  * for a hexadecimal number or a decimal number.
1026                  */
1027                 if (modnam == NULL) {
1028                         if (str_token == B_TRUE) {
1029                                 cmn_err(CE_WARN, "%s" warn_format1
1030                                     "\"%s %s = %s\"" warn_format2,
1031                                     varnam, systemfile, typenam,
1032                                     varnam, (char *)(uintptr_t)value);
1033                         } else if (hex_number == B_TRUE) {
1034                                 cmn_err(CE_WARN, "%s" warn_format1
1035                                     "\"%s %s = 0x%llx\"" warn_format2,
1036                                     varnam, systemfile, typenam,
1037                                     varnam, value);
1038                         } else {
1039                                 cmn_err(CE_WARN, "%s" warn_format1
1040                                     "\"%s %s = %lld\"" warn_format2,
1041                                     varnam, systemfile, typenam,
1042                                     varnam, value);
1043                         }
1044                 } else {
1045                         if (str_token == B_TRUE) {
1046                                 cmn_err(CE_WARN, "%s:%s" warn_format1
1047                                     "\"%s %s:%s = %s\"" warn_format2,
1048                                     modnam, varnam, systemfile,
1049                                     typenam, modnam, varnam,
1050                                     (char *)(uintptr_t)value);
1051                         } else if (hex_number == B_TRUE) {
1052                                 cmn_err(CE_WARN, "%s:%s" warn_format1
1053                                     "\"%s %s:%s = 0x%llx\"" warn_format2,
1054                                     modnam, varnam, systemfile,
1055                                     typenam, modnam, varnam, value);
1056                         } else {
1057                                 cmn_err(CE_WARN, "%s:%s" warn_format1
1058                                     "\"%s %s:%s = %lld\"" warn_format2,
1059                                     modnam, varnam, systemfile,
1060                                     typenam, modnam, varnam, value);
1061                         }
1062                 }
1063         } else {
1064                 /*
1065                  * If the type is MOD_ROOTDEV, MOD_ROOTFS, MOD_SWAPDEV,
1066                  * MOD_SWAPFS or MOD_MODDIR, the entry is treated as
1067                  * a duplicate one if it has the same type regardless
1068                  * of its variable name.
1069                  */
1070                 switch (type) {
1071                 case MOD_ROOTDEV:
1072                 case MOD_ROOTFS:
1073                 case MOD_SWAPDEV:
1074                 case MOD_SWAPFS:
1075                 case MOD_MODDIR:
1076                         cmn_err(CE_WARN, "\"%s\" appears more than once "
1077                             "in /%s.", typenam, systemfile);
1078                         break;
1079                 default:
1080                         cmn_err(CE_NOTE, "\"%s: %s\" appears more than once "
1081                             "in /%s.", typenam, varnam, systemfile);
1082                         break;
1083                 }
1084         }
1085 }
1086 
1087 /*
1088  * Process the system file commands.
1089  */
1090 int
1091 mod_sysctl(int fcn, void *p)
1092 {
1093         static char wmesg[] = "forceload of %s failed";
1094         struct sysparam *sysp;
1095         char *name;
1096         struct modctl *modp;
1097 
1098         if (sysparam_hd == NULL)
1099                 return (0);
1100 
1101         for (sysp = sysparam_hd; sysp != NULL; sysp = sysp->sys_next) {
1102 
1103                 switch (fcn) {
1104 
1105                 case SYS_FORCELOAD:
1106                 if (sysp->sys_type == MOD_FORCELOAD) {
1107                         name = sysp->sys_ptr;
1108                         if (modload(NULL, name) == -1)
1109                                 cmn_err(CE_WARN, wmesg, name);
1110                         /*
1111                          * The following works because it
1112                          * runs before autounloading is started!!
1113                          */
1114                         modp = mod_find_by_filename(NULL, name);
1115                         if (modp != NULL)
1116                                 modp->mod_loadflags |= MOD_NOAUTOUNLOAD;
1117                         /*
1118                          * For drivers, attempt to install it.
1119                          */
1120                         if (strncmp(sysp->sys_ptr, "drv", 3) == 0) {
1121                                 (void) ddi_install_driver(name + 4);
1122                         }
1123                 }
1124                 break;
1125 
1126                 case SYS_SET_KVAR:
1127                 case SYS_SET_MVAR:
1128                         if (sysp->sys_type == MOD_SET)
1129                                 sys_set_var(fcn, sysp, p);
1130                         break;
1131 
1132                 case SYS_CHECK_EXCLUDE:
1133                         if (sysp->sys_type == MOD_EXCLUDE) {
1134                                 if (p == NULL || sysp->sys_ptr == NULL)
1135                                         return (0);
1136                                 if (strcmp((char *)p, sysp->sys_ptr) == 0)
1137                                         return (1);
1138                         }
1139                 }
1140         }
1141 
1142         return (0);
1143 }
1144 
1145 /*
1146  * Process the system file commands, by type.
1147  */
1148 int
1149 mod_sysctl_type(int type, int (*func)(struct sysparam *, void *), void *p)
1150 {
1151         struct sysparam *sysp;
1152         int     err;
1153 
1154         for (sysp = sysparam_hd; sysp != NULL; sysp = sysp->sys_next)
1155                 if (sysp->sys_type == type)
1156                         if (err = (*(func))(sysp, p))
1157                                 return (err);
1158         return (0);
1159 }
1160 
1161 
1162 static char seterr[] = "Symbol %s has size of 0 in symbol table. %s";
1163 static char assumption[] = "Assuming it is an 'int'";
1164 static char defmsg[] = "Trying to set a variable that is of size %d";
1165 
1166 static void set_int8_var(uintptr_t, struct sysparam *);
1167 static void set_int16_var(uintptr_t, struct sysparam *);
1168 static void set_int32_var(uintptr_t, struct sysparam *);
1169 static void set_int64_var(uintptr_t, struct sysparam *);
1170 
1171 static void
1172 sys_set_var(int fcn, struct sysparam *sysp, void *p)
1173 {
1174         uintptr_t symaddr;
1175         int size;
1176 
1177         if (fcn == SYS_SET_KVAR && sysp->sys_modnam == NULL) {
1178                 symaddr = kobj_getelfsym(sysp->sys_ptr, NULL, &size);
1179         } else if (fcn == SYS_SET_MVAR) {
1180                 if (sysp->sys_modnam == (char *)NULL ||
1181                     strcmp(((struct modctl *)p)->mod_modname,
1182                     sysp->sys_modnam) != 0)
1183                         return;
1184                 symaddr = kobj_getelfsym(sysp->sys_ptr,
1185                     ((struct modctl *)p)->mod_mp, &size);
1186         } else
1187                 return;
1188 
1189         if (symaddr != NULL) {
1190                 switch (size) {
1191                 case 1:
1192                         set_int8_var(symaddr, sysp);
1193                         break;
1194                 case 2:
1195                         set_int16_var(symaddr, sysp);
1196                         break;
1197                 case 0:
1198                         cmn_err(CE_WARN, seterr, sysp->sys_ptr, assumption);
1199                         /*FALLTHROUGH*/
1200                 case 4:
1201                         set_int32_var(symaddr, sysp);
1202                         break;
1203                 case 8:
1204                         set_int64_var(symaddr, sysp);
1205                         break;
1206                 default:
1207                         cmn_err(CE_WARN, defmsg, size);
1208                         break;
1209                 }
1210         } else {
1211                 printf("sorry, variable '%s' is not defined in the '%s' ",
1212                     sysp->sys_ptr,
1213                     sysp->sys_modnam ? sysp->sys_modnam : "kernel");
1214                 if (sysp->sys_modnam)
1215                         printf("module");
1216                 printf("\n");
1217         }
1218 }
1219 
1220 static void
1221 set_int8_var(uintptr_t symaddr, struct sysparam *sysp)
1222 {
1223         uint8_t uc = (uint8_t)sysp->sys_info;
1224 
1225         if (moddebug & MODDEBUG_LOADMSG)
1226                 printf("OP: %x: param '%s' was '0x%" PRIx8
1227                     "' in module: '%s'.\n", sysp->sys_op, sysp->sys_ptr,
1228                     *(uint8_t *)symaddr, sysp->sys_modnam);
1229 
1230         switch (sysp->sys_op) {
1231         case SETOP_ASSIGN:
1232                 *(uint8_t *)symaddr = uc;
1233                 break;
1234         case SETOP_AND:
1235                 *(uint8_t *)symaddr &= uc;
1236                 break;
1237         case SETOP_OR:
1238                 *(uint8_t *)symaddr |= uc;
1239                 break;
1240         }
1241 
1242         if (moddebug & MODDEBUG_LOADMSG)
1243                 printf("now it is set to '0x%" PRIx8 "'.\n",
1244                     *(uint8_t *)symaddr);
1245 }
1246 
1247 static void
1248 set_int16_var(uintptr_t symaddr, struct sysparam *sysp)
1249 {
1250         uint16_t us = (uint16_t)sysp->sys_info;
1251 
1252         if (moddebug & MODDEBUG_LOADMSG)
1253                 printf("OP: %x: param '%s' was '0x%" PRIx16
1254                     "' in module: '%s'.\n", sysp->sys_op, sysp->sys_ptr,
1255                     *(uint16_t *)symaddr, sysp->sys_modnam);
1256 
1257         switch (sysp->sys_op) {
1258         case SETOP_ASSIGN:
1259                 *(uint16_t *)symaddr = us;
1260                 break;
1261         case SETOP_AND:
1262                 *(uint16_t *)symaddr &= us;
1263                 break;
1264         case SETOP_OR:
1265                 *(uint16_t *)symaddr |= us;
1266                 break;
1267         }
1268 
1269         if (moddebug & MODDEBUG_LOADMSG)
1270                 printf("now it is set to '0x%" PRIx16 "'.\n",
1271                     *(uint16_t *)symaddr);
1272 }
1273 
1274 static void
1275 set_int32_var(uintptr_t symaddr, struct sysparam *sysp)
1276 {
1277         uint32_t ui = (uint32_t)sysp->sys_info;
1278 
1279         if (moddebug & MODDEBUG_LOADMSG)
1280                 printf("OP: %x: param '%s' was '0x%" PRIx32
1281                     "' in module: '%s'.\n", sysp->sys_op, sysp->sys_ptr,
1282                     *(uint32_t *)symaddr, sysp->sys_modnam);
1283 
1284         switch (sysp->sys_op) {
1285         case SETOP_ASSIGN:
1286                 *(uint32_t *)symaddr = ui;
1287                 break;
1288         case SETOP_AND:
1289                 *(uint32_t *)symaddr &= ui;
1290                 break;
1291         case SETOP_OR:
1292                 *(uint32_t *)symaddr |= ui;
1293                 break;
1294         }
1295 
1296         if (moddebug & MODDEBUG_LOADMSG)
1297                 printf("now it is set to '0x%" PRIx32 "'.\n",
1298                     *(uint32_t *)symaddr);
1299 }
1300 
1301 static void
1302 set_int64_var(uintptr_t symaddr, struct sysparam *sysp)
1303 {
1304         uint64_t ul = sysp->sys_info;
1305 
1306         if (moddebug & MODDEBUG_LOADMSG)
1307                 printf("OP: %x: param '%s' was '0x%" PRIx64
1308                     "' in module: '%s'.\n", sysp->sys_op, sysp->sys_ptr,
1309                     *(uint64_t *)symaddr, sysp->sys_modnam);
1310 
1311         switch (sysp->sys_op) {
1312         case SETOP_ASSIGN:
1313                 *(uint64_t *)symaddr = ul;
1314                 break;
1315         case SETOP_AND:
1316                 *(uint64_t *)symaddr &= ul;
1317                 break;
1318         case SETOP_OR:
1319                 *(uint64_t *)symaddr |= ul;
1320                 break;
1321         }
1322 
1323         if (moddebug & MODDEBUG_LOADMSG)
1324                 printf("now it is set to '0x%" PRIx64 "'.\n",
1325                     *(uint64_t *)symaddr);
1326 }
1327 
1328 /*
1329  * The next item on the line is a string value. Allocate memory for
1330  * it and copy the string. Return 1, and set arg ptr to newly allocated
1331  * and initialized buffer, or NULL if an error occurs.
1332  */
1333 int
1334 kobj_get_string(u_longlong_t *llptr, char *tchar)
1335 {
1336         char *cp;
1337         char *start = (char *)0;
1338         int len = 0;
1339 
1340         len = strlen(tchar);
1341         start = tchar;
1342         /* copy string */
1343         cp = vmem_alloc(mod_sysfile_arena, len + 1, VM_SLEEP);
1344         bzero(cp, len + 1);
1345         *llptr = (u_longlong_t)(uintptr_t)cp;
1346         for (; len > 0; len--) {
1347                 /* convert some common escape sequences */
1348                 if (*start == '\\') {
1349                         switch (*(start + 1)) {
1350                         case 't':
1351                                 /* tab */
1352                                 *cp++ = '\t';
1353                                 len--;
1354                                 start += 2;
1355                                 break;
1356                         case 'n':
1357                                 /* new line */
1358                                 *cp++ = '\n';
1359                                 len--;
1360                                 start += 2;
1361                                 break;
1362                         case 'b':
1363                                 /* back space */
1364                                 *cp++ = '\b';
1365                                 len--;
1366                                 start += 2;
1367                                 break;
1368                         default:
1369                                 /* simply copy it */
1370                                 *cp++ = *start++;
1371                                 break;
1372                         }
1373                 } else
1374                         *cp++ = *start++;
1375         }
1376         *cp = '\0';
1377         return (1);
1378 }
1379 
1380 
1381 /*
1382  * this function frees the memory allocated by kobj_get_string
1383  */
1384 void
1385 kobj_free_string(void *ptr, int len)
1386 {
1387         vmem_free(mod_sysfile_arena, ptr, len);
1388 }
1389 
1390 
1391 /*
1392  * get a decimal octal or hex number. Handle '~' for one's complement.
1393  */
1394 int
1395 kobj_getvalue(const char *token, u_longlong_t *valuep)
1396 {
1397         int radix;
1398         u_longlong_t retval = 0;
1399         int onescompl = 0;
1400         int negate = 0;
1401         char c;
1402 
1403         if (*token == '~') {
1404                 onescompl++; /* perform one's complement on result */
1405                 token++;
1406         } else if (*token == '-') {
1407                 negate++;
1408                 token++;
1409         }
1410         if (*token == '0') {
1411                 token++;
1412                 c = *token;
1413 
1414                 if (c == '\0') {
1415                         *valuep = 0;    /* value is 0 */
1416                         return (0);
1417                 }
1418 
1419                 if (c == 'x' || c == 'X') {
1420                         radix = 16;
1421                         token++;
1422                 } else
1423                         radix = 8;
1424         } else
1425                 radix = 10;
1426 
1427         while ((c = *token++)) {
1428                 switch (radix) {
1429                 case 8:
1430                         if (c >= '0' && c <= '7')
1431                                 c -= '0';
1432                         else
1433                                 return (-1);    /* invalid number */
1434                         retval = (retval << 3) + c;
1435                         break;
1436                 case 10:
1437                         if (c >= '0' && c <= '9')
1438                                 c -= '0';
1439                         else
1440                                 return (-1);    /* invalid number */
1441                         retval = (retval * 10) + c;
1442                         break;
1443                 case 16:
1444                         if (c >= 'a' && c <= 'f')
1445                                 c = c - 'a' + 10;
1446                         else if (c >= 'A' && c <= 'F')
1447                                 c = c - 'A' + 10;
1448                         else if (c >= '0' && c <= '9')
1449                                 c -= '0';
1450                         else
1451                                 return (-1);    /* invalid number */
1452                         retval = (retval << 4) + c;
1453                         break;
1454                 }
1455         }
1456         if (onescompl)
1457                 retval = ~retval;
1458         if (negate)
1459                 retval = -retval;
1460         *valuep = retval;
1461         return (0);
1462 }
1463 
1464 /*
1465  * Path to the root device and root filesystem type from
1466  * property information derived from the boot subsystem
1467  */
1468 void
1469 setbootpath(char *path)
1470 {
1471         rootfs.bo_flags |= BO_VALID;
1472         (void) copystr(path, rootfs.bo_name, BO_MAXOBJNAME, NULL);
1473         BMDPRINTF(("rootfs bootpath: %s\n", rootfs.bo_name));
1474 }
1475 
1476 void
1477 setbootfstype(char *fstype)
1478 {
1479         (void) copystr(fstype, rootfs.bo_fstype, BO_MAXFSNAME, NULL);
1480         BMDPRINTF(("rootfs fstype: %s\n", rootfs.bo_fstype));
1481 }
1482 
1483 /*
1484  * set parameters that can be set early during initialization.
1485  */
1486 static void
1487 setparams()
1488 {
1489         struct sysparam *sysp;
1490         struct bootobj *bootobjp;
1491 
1492         for (sysp = sysparam_hd; sysp != NULL; sysp = sysp->sys_next) {
1493 
1494                 if (sysp->sys_type == MOD_MODDIR) {
1495                         default_path = sysp->sys_ptr;
1496                         continue;
1497                 }
1498 
1499                 if (sysp->sys_type == MOD_SWAPDEV ||
1500                     sysp->sys_type == MOD_SWAPFS)
1501                         bootobjp = &swapfile;
1502                 else if (sysp->sys_type == MOD_ROOTFS)
1503                         bootobjp = &rootfs;
1504 
1505                 switch (sysp->sys_type) {
1506                 case MOD_ROOTDEV:
1507                         root_is_svm = 1;
1508                         (void) copystr(sysp->sys_ptr, svm_bootpath,
1509                             BO_MAXOBJNAME, NULL);
1510                         break;
1511                 case MOD_SWAPDEV:
1512                         bootobjp->bo_flags |= BO_VALID;
1513                         (void) copystr(sysp->sys_ptr, bootobjp->bo_name,
1514                             BO_MAXOBJNAME, NULL);
1515                         break;
1516                 case MOD_ROOTFS:
1517                 case MOD_SWAPFS:
1518                         bootobjp->bo_flags |= BO_VALID;
1519                         (void) copystr(sysp->sys_ptr, bootobjp->bo_fstype,
1520                             BO_MAXOBJNAME, NULL);
1521                         break;
1522                 default:
1523                         break;
1524                 }
1525         }
1526 }
1527 
1528 /*
1529  * clean up after an error.
1530  */
1531 static void
1532 hwc_free(struct hwc_spec *hwcp)
1533 {
1534         char *name;
1535 
1536         if ((name = hwcp->hwc_parent_name) != NULL)
1537                 kmem_free(name, strlen(name) + 1);
1538         if ((name = hwcp->hwc_class_name) != NULL)
1539                 kmem_free(name, strlen(name) + 1);
1540         if ((name = hwcp->hwc_devi_name) != NULL)
1541                 kmem_free(name, strlen(name) + 1);
1542         i_ddi_prop_list_delete(hwcp->hwc_devi_sys_prop_ptr);
1543         kmem_free(hwcp, sizeof (struct hwc_spec));
1544 }
1545 
1546 /*
1547  * Free a list of specs
1548  */
1549 void
1550 hwc_free_spec_list(struct hwc_spec *list)
1551 {
1552         while (list) {
1553                 struct hwc_spec *tmp = list;
1554                 list = tmp->hwc_next;
1555                 hwc_free(tmp);
1556         }
1557 }
1558 
1559 struct val_list {
1560         struct val_list *val_next;
1561         enum {
1562                 VAL_STRING,
1563                 VAL_INTEGER
1564         } val_type;
1565         int             val_size;
1566         union {
1567                 char *string;
1568                 int integer;
1569         } val;
1570 };
1571 
1572 static struct val_list *
1573 add_val(struct val_list **val_listp, struct val_list *tail,
1574     int val_type, caddr_t val)
1575 {
1576         struct val_list *new_val;
1577 #ifdef DEBUG
1578         struct val_list *listp = *val_listp;
1579 #endif
1580 
1581         new_val = kmem_alloc(sizeof (struct val_list), KM_SLEEP);
1582         new_val->val_next = NULL;
1583         if ((new_val->val_type = val_type) == VAL_STRING) {
1584                 new_val->val_size = strlen((char *)val) + 1;
1585                 new_val->val.string = kmem_alloc(new_val->val_size, KM_SLEEP);
1586                 (void) strcpy(new_val->val.string, (char *)val);
1587         } else {
1588                 new_val->val_size = sizeof (int);
1589                 new_val->val.integer = (int)(uintptr_t)val;
1590         }
1591 
1592         ASSERT((listp == NULL && tail == NULL) ||
1593             (listp != NULL && tail != NULL));
1594 
1595         if (tail != NULL) {
1596                 ASSERT(tail->val_next == NULL);
1597                 tail->val_next = new_val;
1598         } else {
1599                 *val_listp = new_val;
1600         }
1601 
1602         return (new_val);
1603 }
1604 
1605 static void
1606 free_val_list(struct val_list *head)
1607 {
1608         struct val_list *tval_list;
1609 
1610         for (/* CSTYLED */; head != NULL; /* CSTYLED */) {
1611                 tval_list = head;
1612                 head = head->val_next;
1613                 if (tval_list->val_type == VAL_STRING)
1614                         kmem_free(tval_list->val.string, tval_list->val_size);
1615                 kmem_free(tval_list, sizeof (struct val_list));
1616         }
1617 }
1618 
1619 /*
1620  * make sure there are no reserved IEEE 1275 characters (except
1621  * for uppercase characters).
1622  */
1623 static int
1624 valid_prop_name(char *name)
1625 {
1626         int i;
1627         int len = strlen(name);
1628 
1629         for (i = 0; i < len; i++) {
1630                 if (name[i] < 0x21 ||
1631                     name[i] == '/' ||
1632                     name[i] == '\\' ||
1633                     name[i] == ':' ||
1634                     name[i] == '[' ||
1635                     name[i] == ']' ||
1636                     name[i] == '@')
1637                         return (0);
1638         }
1639         return (1);
1640 }
1641 
1642 static void
1643 make_prop(struct _buf *file, dev_info_t *devi, char *name, struct val_list *val)
1644 {
1645         int propcnt = 0, val_type;
1646         struct val_list *vl, *tvl;
1647         caddr_t valbuf = NULL;
1648         char **valsp;
1649         int *valip;
1650 
1651         if (name == NULL)
1652                 return;
1653 
1654 #ifdef DEBUG
1655         parse_debug(NULL, "%s", name);
1656 #endif
1657         if (!valid_prop_name(name)) {
1658                 cmn_err(CE_WARN, "invalid property name '%s'", name);
1659                 return;
1660         }
1661         if (val) {
1662                 for (vl = val, val_type = vl->val_type; vl; vl = vl->val_next) {
1663                         if (val_type != vl->val_type) {
1664                                 cmn_err(CE_WARN, "Mixed types in value list");
1665                                 return;
1666                         }
1667                         propcnt++;
1668                 }
1669 
1670                 vl = val;
1671 
1672                 if (val_type == VAL_INTEGER) {
1673                         valip = (int *)kmem_alloc(
1674                             (propcnt * sizeof (int)), KM_SLEEP);
1675                         valbuf = (caddr_t)valip;
1676                         while (vl) {
1677                                 tvl = vl;
1678                                 vl = vl->val_next;
1679 #ifdef DEBUG
1680                                 parse_debug(NULL, " %x",  tvl->val.integer);
1681 #endif
1682                                 *valip = tvl->val.integer;
1683                                 valip++;
1684                         }
1685                         /* restore valip */
1686                         valip = (int *)valbuf;
1687 
1688                         /* create the property */
1689                         if (e_ddi_prop_update_int_array(DDI_DEV_T_NONE, devi,
1690                             name, valip, propcnt) != DDI_PROP_SUCCESS) {
1691                                 kobj_file_err(CE_WARN, file,
1692                                     "cannot create property %s", name);
1693                         }
1694                         /* cleanup */
1695                         kmem_free(valip, (propcnt * sizeof (int)));
1696                 } else if (val_type == VAL_STRING) {
1697                         valsp = (char **)kmem_alloc(
1698                             ((propcnt + 1) * sizeof (char *)), KM_SLEEP);
1699                         valbuf = (caddr_t)valsp;
1700                         while (vl) {
1701                                 tvl = vl;
1702                                 vl = vl->val_next;
1703 #ifdef DEBUG
1704                                 parse_debug(NULL, " %s", tvl->val.string);
1705 #endif
1706                                 *valsp = tvl->val.string;
1707                                 valsp++;
1708                         }
1709                         /* terminate array with NULL */
1710                         *valsp = NULL;
1711 
1712                         /* restore valsp */
1713                         valsp = (char **)valbuf;
1714 
1715                         /* create the property */
1716                         if (e_ddi_prop_update_string_array(DDI_DEV_T_NONE,
1717                             devi, name, valsp, propcnt)
1718                             != DDI_PROP_SUCCESS) {
1719                                 kobj_file_err(CE_WARN, file,
1720                                     "cannot create property %s", name);
1721                         }
1722                         /* Clean up */
1723                         kmem_free(valsp, ((propcnt + 1) * sizeof (char *)));
1724                 } else {
1725                         cmn_err(CE_WARN, "Invalid property type");
1726                         return;
1727                 }
1728         } else {
1729                 /*
1730                  * No value was passed in with property so we will assume
1731                  * it is a "boolean" property and create an integer
1732                  * property with 0 value.
1733                  */
1734 #ifdef DEBUG
1735                 parse_debug(NULL, "\n");
1736 #endif
1737                 if (e_ddi_prop_update_int(DDI_DEV_T_NONE, devi, name, 0)
1738                     != DDI_PROP_SUCCESS) {
1739                         kobj_file_err(CE_WARN, file,
1740                             "cannot create property %s", name);
1741                 }
1742         }
1743 }
1744 
1745 static char omit_err[] = "(the ';' may have been omitted on previous spec!)";
1746 static char prnt_err[] = "'parent' property already specified";
1747 static char nm_err[] = "'name' property already specified";
1748 static char class_err[] = "'class' property already specified";
1749 
1750 typedef enum {
1751         hwc_begin, parent, drvname, drvclass, prop,
1752         parent_equals, name_equals, drvclass_equals,
1753         parent_equals_string, name_equals_string,
1754         drvclass_equals_string,
1755         prop_equals, prop_equals_string, prop_equals_integer,
1756         prop_equals_string_comma, prop_equals_integer_comma
1757 } hwc_state_t;
1758 
1759 static struct hwc_spec *
1760 get_hwc_spec(struct _buf *file, char *tokbuf, size_t linesize)
1761 {
1762         char *prop_name;
1763         token_t token;
1764         struct hwc_spec *hwcp;
1765         struct dev_info *devi;
1766         struct val_list *val_list, *tail;
1767         hwc_state_t state;
1768         u_longlong_t ival;
1769 
1770         hwcp = kmem_zalloc(sizeof (*hwcp), KM_SLEEP);
1771         devi = kmem_zalloc(sizeof (*devi), KM_SLEEP);
1772 
1773         state = hwc_begin;
1774         token = NAME;
1775         prop_name = NULL;
1776         val_list = NULL;
1777         tail = NULL;
1778         do {
1779 #ifdef DEBUG
1780                 parse_debug(NULL, "state 0x%x\n", state);
1781 #endif
1782                 switch (token) {
1783                 case NAME:
1784                         switch (state) {
1785                         case prop:
1786                         case prop_equals_string:
1787                         case prop_equals_integer:
1788                                 make_prop(file, (dev_info_t *)devi,
1789                                     prop_name, val_list);
1790                                 if (prop_name) {
1791                                         kmem_free(prop_name,
1792                                             strlen(prop_name) + 1);
1793                                         prop_name = NULL;
1794                                 }
1795                                 if (val_list) {
1796                                         free_val_list(val_list);
1797                                         val_list = NULL;
1798                                 }
1799                                 tail = NULL;
1800                                 /*FALLTHROUGH*/
1801                         case hwc_begin:
1802                                 if (strcmp(tokbuf, "PARENT") == 0 ||
1803                                     strcmp(tokbuf, "parent") == 0) {
1804                                         state = parent;
1805                                 } else if (strcmp(tokbuf, "NAME") == 0 ||
1806                                     strcmp(tokbuf, "name") == 0) {
1807                                         state = drvname;
1808                                 } else if (strcmp(tokbuf, "CLASS") == 0 ||
1809                                     strcmp(tokbuf, "class") == 0) {
1810                                         state = drvclass;
1811                                         prop_name = kmem_alloc(strlen(tokbuf) +
1812                                             1, KM_SLEEP);
1813                                         (void) strcpy(prop_name, tokbuf);
1814                                 } else {
1815                                         state = prop;
1816                                         prop_name = kmem_alloc(strlen(tokbuf) +
1817                                             1, KM_SLEEP);
1818                                         (void) strcpy(prop_name, tokbuf);
1819                                 }
1820                                 break;
1821                         default:
1822                                 kobj_file_err(CE_WARN, file, tok_err, tokbuf);
1823                         }
1824                         break;
1825                 case EQUALS:
1826                         switch (state) {
1827                         case drvname:
1828                                 state = name_equals;
1829                                 break;
1830                         case parent:
1831                                 state = parent_equals;
1832                                 break;
1833                         case drvclass:
1834                                 state = drvclass_equals;
1835                                 break;
1836                         case prop:
1837                                 state = prop_equals;
1838                                 break;
1839                         default:
1840                                 kobj_file_err(CE_WARN, file, tok_err, tokbuf);
1841                         }
1842                         break;
1843                 case STRING:
1844                         switch (state) {
1845                         case name_equals:
1846                                 if (ddi_get_name((dev_info_t *)devi)) {
1847                                         kobj_file_err(CE_WARN, file, "%s %s",
1848                                             nm_err, omit_err);
1849                                         goto bad;
1850                                 }
1851                                 devi->devi_name = kmem_alloc(strlen(tokbuf) + 1,
1852                                     KM_SLEEP);
1853                                 (void) strcpy(devi->devi_name, tokbuf);
1854                                 state = hwc_begin;
1855                                 break;
1856                         case parent_equals:
1857                                 if (hwcp->hwc_parent_name) {
1858                                         kobj_file_err(CE_WARN, file, "%s %s",
1859                                             prnt_err, omit_err);
1860                                         goto bad;
1861                                 }
1862                                 hwcp->hwc_parent_name = kmem_alloc(strlen
1863                                     (tokbuf) + 1, KM_SLEEP);
1864                                 (void) strcpy(hwcp->hwc_parent_name, tokbuf);
1865                                 state = hwc_begin;
1866                                 break;
1867                         case drvclass_equals:
1868                                 if (hwcp->hwc_class_name) {
1869                                         kobj_file_err(CE_WARN, file, class_err);
1870                                         goto bad;
1871                                 }
1872                                 hwcp->hwc_class_name = kmem_alloc(
1873                                     strlen(tokbuf) + 1, KM_SLEEP);
1874                                 (void) strcpy(hwcp->hwc_class_name, tokbuf);
1875                                 /*FALLTHROUGH*/
1876                         case prop_equals:
1877                         case prop_equals_string_comma:
1878                                 tail = add_val(&val_list, tail, VAL_STRING,
1879                                     tokbuf);
1880                                 state = prop_equals_string;
1881                                 break;
1882                         default:
1883                                 kobj_file_err(CE_WARN, file, tok_err, tokbuf);
1884                         }
1885                         break;
1886                 case HEXVAL:
1887                 case DECVAL:
1888                         switch (state) {
1889                         case prop_equals:
1890                         case prop_equals_integer_comma:
1891                                 (void) kobj_getvalue(tokbuf, &ival);
1892                                 tail = add_val(&val_list, tail,
1893                                     VAL_INTEGER, (caddr_t)(uintptr_t)ival);
1894                                 state = prop_equals_integer;
1895                                 break;
1896                         default:
1897                                 kobj_file_err(CE_WARN, file, tok_err, tokbuf);
1898                         }
1899                         break;
1900                 case COMMA:
1901                         switch (state) {
1902                         case prop_equals_string:
1903                                 state = prop_equals_string_comma;
1904                                 break;
1905                         case prop_equals_integer:
1906                                 state = prop_equals_integer_comma;
1907                                 break;
1908                         default:
1909                                 kobj_file_err(CE_WARN, file, tok_err, tokbuf);
1910                         }
1911                         break;
1912                 case NEWLINE:
1913                         kobj_newline(file);
1914                         break;
1915                 case POUND:
1916                         /*
1917                          * Skip comments.
1918                          */
1919                         kobj_find_eol(file);
1920                         break;
1921                 case EOF:
1922                         kobj_file_err(CE_WARN, file, "Unexpected EOF");
1923                         goto bad;
1924                 default:
1925                         kobj_file_err(CE_WARN, file, tok_err, tokbuf);
1926                         goto bad;
1927                 }
1928         } while ((token = kobj_lex(file, tokbuf, linesize)) != SEMICOLON);
1929 
1930         switch (state) {
1931         case prop:
1932         case prop_equals_string:
1933         case prop_equals_integer:
1934                 make_prop(file, (dev_info_t *)devi,
1935                     prop_name, val_list);
1936                 break;
1937 
1938         case hwc_begin:
1939                 break;
1940         default:
1941                 kobj_file_err(CE_WARN, file, "Unexpected end of line");
1942                 break;
1943         }
1944 
1945         /* copy 2 relevant members of devi to hwcp */
1946         hwcp->hwc_devi_sys_prop_ptr = devi->devi_sys_prop_ptr;
1947         hwcp->hwc_devi_name = devi->devi_name;
1948 
1949         if (prop_name)
1950                 kmem_free(prop_name, strlen(prop_name) + 1);
1951         if (val_list)
1952                 free_val_list(val_list);
1953 
1954         kmem_free(devi, sizeof (struct dev_info));
1955 
1956         return (hwcp);
1957 
1958 bad:
1959         if (prop_name)
1960                 kmem_free(prop_name, strlen(prop_name) + 1);
1961         if (val_list)
1962                 free_val_list(val_list);
1963 
1964         hwc_free(hwcp);
1965 
1966         if (devi->devi_name)
1967                 kmem_free(devi->devi_name, strlen(devi->devi_name) + 1);
1968 
1969         kmem_free(devi, sizeof (struct dev_info));
1970 
1971         return (NULL);
1972 }
1973 
1974 /*
1975  * This is the primary kernel interface to parse driver.conf files.
1976  *
1977  * Yet another bigstk thread handoff due to deep kernel stacks when booting
1978  * cache-only-clients.
1979  */
1980 int
1981 hwc_parse(char *fname, struct par_list **pl, ddi_prop_t **props)
1982 {
1983         int ret;
1984         struct hwc_parse_mt *pltp = hwc_parse_mtalloc(fname, pl, props);
1985 
1986         if (curthread != &t0) {
1987                 (void) thread_create(NULL, DEFAULTSTKSZ * 2,
1988                     hwc_parse_thread, pltp, 0, &p0, TS_RUN, maxclsyspri);
1989                 sema_p(&pltp->sema);
1990         } else {
1991                 pltp->rv = hwc_parse_now(fname, pl, props);
1992         }
1993         ret = pltp->rv;
1994         hwc_parse_mtfree(pltp);
1995         return (ret);
1996 }
1997 
1998 /*
1999  * Calls to hwc_parse() are handled off to this routine in a separate
2000  * thread.
2001  */
2002 static void
2003 hwc_parse_thread(struct hwc_parse_mt *pltp)
2004 {
2005         kmutex_t        cpr_lk;
2006         callb_cpr_t     cpr_i;
2007 
2008         mutex_init(&cpr_lk, NULL, MUTEX_DEFAULT, NULL);
2009         CALLB_CPR_INIT(&cpr_i, &cpr_lk, callb_generic_cpr, "hwc_parse");
2010 
2011         /*
2012          * load and parse the .conf file
2013          * return the hwc_spec list (if any) to the creator of this thread
2014          */
2015         pltp->rv = hwc_parse_now(pltp->name, pltp->pl, pltp->props);
2016         sema_v(&pltp->sema);
2017         mutex_enter(&cpr_lk);
2018         CALLB_CPR_EXIT(&cpr_i);
2019         mutex_destroy(&cpr_lk);
2020         thread_exit();
2021 }
2022 
2023 /*
2024  * allocate and initialize a hwc_parse thread control structure
2025  */
2026 static struct hwc_parse_mt *
2027 hwc_parse_mtalloc(char *name, struct par_list **pl, ddi_prop_t **props)
2028 {
2029         struct hwc_parse_mt *pltp = kmem_zalloc(sizeof (*pltp), KM_SLEEP);
2030 
2031         ASSERT(name != NULL);
2032 
2033         pltp->name = kmem_alloc(strlen(name) + 1, KM_SLEEP);
2034         bcopy(name, pltp->name, strlen(name) + 1);
2035         pltp->pl = pl;
2036         pltp->props = props;
2037 
2038         sema_init(&pltp->sema, 0, NULL, SEMA_DEFAULT, NULL);
2039         return (pltp);
2040 }
2041 
2042 /*
2043  * free a hwc_parse thread control structure
2044  */
2045 static void
2046 hwc_parse_mtfree(struct hwc_parse_mt *pltp)
2047 {
2048         sema_destroy(&pltp->sema);
2049 
2050         kmem_free(pltp->name, strlen(pltp->name) + 1);
2051         kmem_free(pltp, sizeof (*pltp));
2052 }
2053 
2054 /*
2055  * hwc_parse -- parse an hwconf file.  Ignore error lines and parse
2056  * as much as possible.
2057  */
2058 static int
2059 hwc_parse_now(char *fname, struct par_list **pl, ddi_prop_t **props)
2060 {
2061         struct _buf *file;
2062         struct hwc_spec *hwcp;
2063         char *tokval;
2064         token_t token;
2065 
2066         /*
2067          * Don't use kobj_open_path's use_moddir_suffix option, we only
2068          * expect to find conf files in the base module directory, not
2069          * an ISA-specific subdirectory.
2070          */
2071         if ((file = kobj_open_path(fname, 1, 0)) == (struct _buf *)-1) {
2072                 if (moddebug & MODDEBUG_ERRMSG)
2073                         cmn_err(CE_WARN, "Cannot open %s", fname);
2074                 return (-1);
2075         }
2076 
2077         /*
2078          * Initialize variables
2079          */
2080         tokval = kmem_alloc(MAX_HWC_LINESIZE, KM_SLEEP);
2081 
2082         while ((token = kobj_lex(file, tokval, MAX_HWC_LINESIZE)) != EOF) {
2083                 switch (token) {
2084                 case POUND:
2085                         /*
2086                          * Skip comments.
2087                          */
2088                         kobj_find_eol(file);
2089                         break;
2090                 case NAME:
2091                         hwcp = get_hwc_spec(file, tokval, MAX_HWC_LINESIZE);
2092                         if (hwcp == NULL)
2093                                 break;
2094                         /*
2095                          * No devi_name indicates global property.
2096                          * Make sure parent and class not NULL.
2097                          */
2098                         if (hwcp->hwc_devi_name == NULL) {
2099                                 if (hwcp->hwc_parent_name ||
2100                                     hwcp->hwc_class_name) {
2101                                         kobj_file_err(CE_WARN, file,
2102                                             "missing name attribute");
2103                                         hwc_free(hwcp);
2104                                         continue;
2105                                 }
2106                                 /* Add to global property list */
2107                                 add_props(hwcp, props);
2108                                 break;
2109                         }
2110 
2111                         /*
2112                          * This is a node spec, either parent or class
2113                          * must be specified.
2114                          */
2115                         if ((hwcp->hwc_parent_name == NULL) &&
2116                             (hwcp->hwc_class_name == NULL)) {
2117                                 kobj_file_err(CE_WARN, file,
2118                                     "missing parent or class attribute");
2119                                 hwc_free(hwcp);
2120                                 continue;
2121                         }
2122 
2123                         /* add to node spec list */
2124                         add_spec(hwcp, pl);
2125                         break;
2126                 case NEWLINE:
2127                         kobj_newline(file);
2128                         break;
2129                 default:
2130                         kobj_file_err(CE_WARN, file, tok_err, tokval);
2131                         break;
2132                 }
2133         }
2134         /*
2135          * XXX - Check for clean termination.
2136          */
2137         kmem_free(tokval, MAX_HWC_LINESIZE);
2138         kobj_close_file(file);
2139         return (0);     /* always return success */
2140 }
2141 
2142 void
2143 make_aliases(struct bind **bhash)
2144 {
2145         enum {
2146                 AL_NEW, AL_DRVNAME, AL_DRVNAME_COMMA, AL_ALIAS, AL_ALIAS_COMMA
2147         } state;
2148 
2149         struct _buf *file;
2150         char tokbuf[MAXPATHLEN];
2151         char drvbuf[MAXPATHLEN];
2152         token_t token;
2153         major_t major;
2154         int done = 0;
2155         static char dupwarn[] = "!Driver alias \"%s\" conflicts with "
2156             "an existing driver name or alias.";
2157 
2158         if ((file = kobj_open_file(dafile)) == (struct _buf *)-1)
2159                 return;
2160 
2161         state = AL_NEW;
2162         major = DDI_MAJOR_T_NONE;
2163         while (!done) {
2164                 token = kobj_lex(file, tokbuf, sizeof (tokbuf));
2165                 switch (token) {
2166                 case POUND:
2167                         /*
2168                          * Skip comments.
2169                          */
2170                         kobj_find_eol(file);
2171                         break;
2172                 case NAME:
2173                 case STRING:
2174                         switch (state) {
2175                         case AL_NEW:
2176                                 (void) strcpy(drvbuf, tokbuf);
2177                                 state = AL_DRVNAME;
2178                                 break;
2179                         case AL_DRVNAME_COMMA:
2180                                 (void) strcat(drvbuf, tokbuf);
2181                                 state = AL_DRVNAME;
2182                                 break;
2183                         case AL_ALIAS_COMMA:
2184                                 (void) strcat(drvbuf, tokbuf);
2185                                 state = AL_ALIAS;
2186                                 break;
2187                         case AL_DRVNAME:
2188                                 major = mod_name_to_major(drvbuf);
2189                                 if (major == DDI_MAJOR_T_NONE) {
2190                                         kobj_find_eol(file);
2191                                         state = AL_NEW;
2192                                 } else {
2193                                         (void) strcpy(drvbuf, tokbuf);
2194                                         state = AL_ALIAS;
2195                                 }
2196                                 break;
2197                         case AL_ALIAS:
2198                                 if (make_mbind(drvbuf, major, NULL, bhash)
2199                                     != 0) {
2200                                         cmn_err(CE_WARN, dupwarn, drvbuf);
2201                                 }
2202                                 /*
2203                                  * copy this token just in case that there
2204                                  * are multiple names on the same line.
2205                                  */
2206                                 (void) strcpy(drvbuf, tokbuf);
2207                                 break;
2208                         }
2209                         break;
2210                 case COMMA:
2211                         (void) strcat(drvbuf, tokbuf);
2212                         switch (state) {
2213                         case AL_DRVNAME:
2214                                 state = AL_DRVNAME_COMMA;
2215                                 break;
2216                         case AL_ALIAS:
2217                                 state = AL_ALIAS_COMMA;
2218                                 break;
2219                         default:
2220                                 kobj_file_err(CE_WARN, file, tok_err, tokbuf);
2221                         }
2222                         break;
2223                 case EOF:
2224                         done = 1;
2225                         /*FALLTHROUGH*/
2226                 case NEWLINE:
2227                         if (state == AL_ALIAS) {
2228                                 if (make_mbind(drvbuf, major, NULL, bhash)
2229                                     != 0) {
2230                                         cmn_err(CE_WARN, dupwarn, drvbuf);
2231                                 }
2232                         } else if (state != AL_NEW) {
2233                                 kobj_file_err(CE_WARN, file,
2234                                     "Missing alias for %s", drvbuf);
2235                         }
2236 
2237                         kobj_newline(file);
2238                         state = AL_NEW;
2239                         major = DDI_MAJOR_T_NONE;
2240                         break;
2241                 default:
2242                         kobj_file_err(CE_WARN, file, tok_err, tokbuf);
2243                 }
2244         }
2245 
2246         kobj_close_file(file);
2247 }
2248 
2249 
2250 /*
2251  * It is called for parsing these files:
2252  * - /etc/path_to_inst
2253  * - /etc/name_to_major
2254  * - /etc/name_to_sysnum
2255  * A callback "int (*line_parser)(char *, int, char *, struct bind **)"
2256  * is invoked for each line of the file.
2257  * The callback can inhash the entry into a hashtable by supplying
2258  * a pre-allocated hashtable in "struct bind **hashtab".
2259  */
2260 int
2261 read_binding_file(char *bindfile, struct bind **hashtab,
2262     int (*line_parser)(char *, int, char *, struct bind **))
2263 {
2264         enum {
2265                 B_NEW, B_NAME, B_VAL, B_BIND_NAME
2266         } state;
2267         struct _buf *file;
2268         char tokbuf[MAXNAMELEN];
2269         token_t token;
2270         int maxnum = 0;
2271         char *bind_name = NULL, *name = NULL, *bn = NULL;
2272         u_longlong_t val;
2273         int done = 0;
2274 
2275         static char num_err[] = "Missing number on preceding line?";
2276         static char dupwarn[] = "!The binding file entry \"%s %u\" conflicts "
2277             "with a previous entry";
2278 
2279         if (hashtab != NULL) {
2280                 clear_binding_hash(hashtab);
2281         }
2282 
2283         if ((file = kobj_open_file(bindfile)) == (struct _buf *)-1)
2284                 panic("read_binding_file: %s file not found", bindfile);
2285 
2286         state = B_NEW;
2287 
2288         while (!done) {
2289                 token = kobj_lex(file, tokbuf, sizeof (tokbuf));
2290 
2291                 switch (token) {
2292                 case POUND:
2293                         /*
2294                          * Skip comments.
2295                          */
2296                         kobj_find_eol(file);
2297                         break;
2298                 case NAME:
2299                 case STRING:
2300                         switch (state) {
2301                         case B_NEW:
2302                                 /*
2303                                  * This case is for the first name and
2304                                  * possibly only name in an entry.
2305                                  */
2306                                 ASSERT(name == NULL);
2307                                 name = kmem_alloc(strlen(tokbuf) + 1, KM_SLEEP);
2308                                 (void) strcpy(name, tokbuf);
2309                                 state = B_NAME;
2310                                 break;
2311                         case B_VAL:
2312                                 /*
2313                                  * This case is for a second name, which
2314                                  * would be the binding name if the first
2315                                  * name was actually a generic name.
2316                                  */
2317                                 ASSERT(bind_name == NULL);
2318                                 bind_name = kmem_alloc(strlen(tokbuf) + 1,
2319                                     KM_SLEEP);
2320                                 (void) strcpy(bind_name, tokbuf);
2321                                 state = B_BIND_NAME;
2322                                 break;
2323                         default:
2324                                 kobj_file_err(CE_WARN, file, num_err);
2325                         }
2326                         break;
2327                 case HEXVAL:
2328                 case DECVAL:
2329                         if (state != B_NAME) {
2330                                 kobj_file_err(CE_WARN, file, "Missing name?");
2331                                 state = B_NEW;
2332                                 continue;
2333                         }
2334                         (void) kobj_getvalue(tokbuf, &val);
2335                         if (val > (u_longlong_t)INT_MAX) {
2336                                 kobj_file_err(CE_WARN, file,
2337                                     "value %llu too large", val);
2338                                 state = B_NEW;
2339                                 continue;
2340                         }
2341                         state = B_VAL;
2342                         break;
2343                 case EOF:
2344                         done = 1;
2345                         /*FALLTHROUGH*/
2346                 case NEWLINE:
2347                         if ((state == B_BIND_NAME) || (state == B_VAL)) {
2348                                 if (state == B_BIND_NAME)
2349                                         bn = bind_name;
2350                                 else
2351                                         bn = NULL;
2352 
2353                                 if (line_parser != NULL) {
2354                                         if ((*line_parser)(name, (int)val, bn,
2355                                             hashtab) == 0)
2356                                                 maxnum = MAX((int)val, maxnum);
2357                                         else
2358                                                 kobj_file_err(CE_WARN, file,
2359                                                     dupwarn, name, (uint_t)val);
2360                                 }
2361                         } else if (state != B_NEW)
2362                                 kobj_file_err(CE_WARN, file, "Syntax error?");
2363 
2364                         if (name) {
2365                                 kmem_free(name, strlen(name) + 1);
2366                                 name = NULL;
2367                         }
2368                         if (bind_name) {
2369                                 kmem_free(bind_name, strlen(bind_name) + 1);
2370                                 bind_name = NULL;
2371                         }
2372                         state = B_NEW;
2373                         kobj_newline(file);
2374                         break;
2375                 default:
2376                         kobj_file_err(CE_WARN, file, "Missing name/number?");
2377                         break;
2378                 }
2379         }
2380 
2381         ASSERT(name == NULL);           /* any leaks? */
2382         ASSERT(bind_name == NULL);
2383 
2384         kobj_close_file(file);
2385         return (maxnum);
2386 }
2387 
2388 /*
2389  * read_dacf_binding_file()
2390  *      Read the /etc/dacf.conf file and build the dacf_rule_t database from it.
2391  *
2392  * The syntax of a line in the dacf.conf file is:
2393  *   dev-spec   [module:]op-set operation options       [config-args];
2394  *
2395  * Where:
2396  *      1. dev-spec is of the format: name="data"
2397  *      2. operation is the operation that this rule matches. (i.e. pre-detach)
2398  *      3. options is a comma delimited list of options (i.e. debug,foobar)
2399  *      4. config-data is a whitespace delimited list of the format: name="data"
2400  */
2401 int
2402 read_dacf_binding_file(char *filename)
2403 {
2404         enum {
2405                 DACF_BEGIN,
2406                 /* minor_nodetype="ddi_mouse:serial" */
2407                 DACF_NT_SPEC, DACF_NT_EQUALS, DACF_NT_DATA,
2408                 /* consconfig:mouseconfig */
2409                 DACF_MN_MODNAME, DACF_MN_COLON, DACF_MN_OPSET,
2410                 /* op */
2411                 DACF_OP_NAME,
2412                 /* [ option1, option2, option3... | - ] */
2413                 DACF_OPT_OPTION, DACF_OPT_COMMA, DACF_OPT_END,
2414                 /* argname1="argval1" argname2="argval2" ... */
2415                 DACF_OPARG_SPEC, DACF_OPARG_EQUALS, DACF_OPARG_DATA,
2416                 DACF_ERR, DACF_ERR_NEWLINE, DACF_COMMENT
2417         } state = DACF_BEGIN;
2418 
2419         struct _buf *file;
2420         char *fname;
2421         token_t token;
2422 
2423         char tokbuf[MAXNAMELEN];
2424         char mn_modname_buf[MAXNAMELEN], *mn_modnamep = NULL;
2425         char mn_opset_buf[MAXNAMELEN], *mn_opsetp = NULL;
2426         char nt_data_buf[MAXNAMELEN], *nt_datap = NULL;
2427         char arg_spec_buf[MAXNAMELEN];
2428 
2429         uint_t opts = 0;
2430         dacf_devspec_t nt_spec_type = DACF_DS_ERROR;
2431 
2432         dacf_arg_t *arg_list = NULL;
2433         dacf_opid_t opid = DACF_OPID_ERROR;
2434         int done = 0;
2435 
2436         static char w_syntax[] = "'%s' unexpected";
2437         static char w_equals[] = "'=' is illegal in the current context";
2438         static char w_baddevspec[] = "device specification '%s' unrecognized";
2439         static char w_badop[] = "operation '%s' unrecognized";
2440         static char w_badopt[] = "option '%s' unrecognized, ignoring";
2441         static char w_newline[] = "rule is incomplete";
2442         static char w_insert[] = "failed to register rule";
2443         static char w_comment[] = "'#' not allowed except at start of line";
2444         static char w_dupargs[] =
2445             "argument '%s' duplicates a previous argument, skipping";
2446         static char w_nt_empty[] = "empty device specification not allowed";
2447 
2448         if (filename == NULL) {
2449                 fname = dacffile;       /* default binding file */
2450         } else {
2451                 fname = filename;       /* user specified */
2452         }
2453 
2454         if ((file = kobj_open_file(fname)) == (struct _buf *)-1) {
2455                 return (ENOENT);
2456         }
2457 
2458         if (dacfdebug & DACF_DBG_MSGS) {
2459                 printf("dacf debug: clearing rules database\n");
2460         }
2461 
2462         mutex_enter(&dacf_lock);
2463         dacf_clear_rules();
2464 
2465         if (dacfdebug & DACF_DBG_MSGS) {
2466                 printf("dacf debug: parsing %s\n", fname);
2467         }
2468 
2469         while (!done) {
2470                 token = kobj_lex(file, tokbuf, sizeof (tokbuf));
2471 
2472                 switch (token) {
2473                 case POUND:     /* comment line */
2474                         if (state != DACF_BEGIN) {
2475                                 kobj_file_err(CE_WARN, file, w_comment);
2476                                 state = DACF_ERR;
2477                                 break;
2478                         }
2479                         state = DACF_COMMENT;
2480                         kobj_find_eol(file);
2481                         break;
2482 
2483                 case EQUALS:
2484                         switch (state) {
2485                         case DACF_NT_SPEC:
2486                                 state = DACF_NT_EQUALS;
2487                                 break;
2488                         case DACF_OPARG_SPEC:
2489                                 state = DACF_OPARG_EQUALS;
2490                                 break;
2491                         default:
2492                                 kobj_file_err(CE_WARN, file, w_equals);
2493                                 state = DACF_ERR;
2494                         }
2495                         break;
2496 
2497                 case NAME:
2498                         switch (state) {
2499                         case DACF_BEGIN:
2500                                 nt_spec_type = dacf_get_devspec(tokbuf);
2501                                 if (nt_spec_type == DACF_DS_ERROR) {
2502                                         kobj_file_err(CE_WARN, file,
2503                                             w_baddevspec, tokbuf);
2504                                         state = DACF_ERR;
2505                                         break;
2506                                 }
2507                                 state = DACF_NT_SPEC;
2508                                 break;
2509                         case DACF_NT_DATA:
2510                                 (void) strncpy(mn_modname_buf, tokbuf,
2511                                     sizeof (mn_modname_buf));
2512                                 mn_modnamep = mn_modname_buf;
2513                                 state = DACF_MN_MODNAME;
2514                                 break;
2515                         case DACF_MN_MODNAME:
2516                                 /*
2517                                  * This handles the 'optional' modname.
2518                                  * What we thought was the modname is really
2519                                  * the op-set.  So it is copied over.
2520                                  */
2521                                 ASSERT(mn_modnamep);
2522                                 (void) strncpy(mn_opset_buf, mn_modnamep,
2523                                     sizeof (mn_opset_buf));
2524                                 mn_opsetp = mn_opset_buf;
2525                                 mn_modnamep = NULL;
2526                                 /*
2527                                  * Now, the token we just read is the opset,
2528                                  * so look that up and fill in opid
2529                                  */
2530                                 if ((opid = dacf_get_op(tokbuf)) ==
2531                                     DACF_OPID_ERROR) {
2532                                         kobj_file_err(CE_WARN, file, w_badop,
2533                                             tokbuf);
2534                                         state = DACF_ERR;
2535                                         break;
2536                                 }
2537                                 state = DACF_OP_NAME;
2538                                 break;
2539                         case DACF_MN_COLON:
2540                                 (void) strncpy(mn_opset_buf, tokbuf,
2541                                     sizeof (mn_opset_buf));
2542                                 mn_opsetp = mn_opset_buf;
2543                                 state = DACF_MN_OPSET;
2544                                 break;
2545                         case DACF_MN_OPSET:
2546                                 if ((opid = dacf_get_op(tokbuf)) ==
2547                                     DACF_OPID_ERROR) {
2548                                         kobj_file_err(CE_WARN, file, w_badop,
2549                                             tokbuf);
2550                                         state = DACF_ERR;
2551                                         break;
2552                                 }
2553                                 state = DACF_OP_NAME;
2554                                 break;
2555                         case DACF_OP_NAME:
2556                                 /*
2557                                  * This case is just like DACF_OPT_COMMA below,
2558                                  * but we check for the sole '-' argument
2559                                  */
2560                                 if (strcmp(tokbuf, "-") == 0) {
2561                                         state = DACF_OPT_END;
2562                                         break;
2563                                 }
2564                                 /*FALLTHROUGH*/
2565                         case DACF_OPT_COMMA:
2566                                 /*
2567                                  * figure out what option was given, but don't
2568                                  * make a federal case if invalid, just skip it
2569                                  */
2570                                 if (dacf_getopt(tokbuf, &opts) != 0) {
2571                                         kobj_file_err(CE_WARN, file, w_badopt,
2572                                             tokbuf);
2573                                 }
2574                                 state = DACF_OPT_OPTION;
2575                                 break;
2576                         case DACF_OPT_END:
2577                         case DACF_OPT_OPTION:
2578                         case DACF_OPARG_DATA:
2579                                 (void) strncpy(arg_spec_buf, tokbuf,
2580                                     sizeof (arg_spec_buf));
2581                                 state = DACF_OPARG_SPEC;
2582                                 break;
2583                         case DACF_OPARG_EQUALS:
2584                                 /*
2585                                  * Add the arg.  Warn if it's a duplicate
2586                                  */
2587                                 if (dacf_arg_insert(&arg_list, arg_spec_buf,
2588                                     tokbuf) != 0) {
2589                                         kobj_file_err(CE_WARN, file, w_dupargs,
2590                                             arg_spec_buf);
2591                                 }
2592                                 state = DACF_OPARG_DATA;
2593                                 break;
2594                         default:
2595                                 kobj_file_err(CE_WARN, file, w_syntax, tokbuf);
2596                                 state = DACF_ERR;
2597                                 break;
2598                         }
2599                         break;
2600 
2601                 case STRING:
2602                         /*
2603                          * We need to check to see if the string has a \n in it.
2604                          * If so, we had an unmatched " mark error, and lex has
2605                          * already emitted an error for us, so we need to enter
2606                          * the error state.  Stupid lex.
2607                          */
2608                         if (strchr(tokbuf, '\n')) {
2609                                 state = DACF_ERR;
2610                                 break;
2611                         }
2612                         switch (state) {
2613                         case DACF_NT_EQUALS:
2614                                 if (strlen(tokbuf) == 0) {
2615                                         kobj_file_err(CE_WARN, file,
2616                                             w_nt_empty);
2617                                         state = DACF_ERR;
2618                                         break;
2619                                 }
2620                                 state = DACF_NT_DATA;
2621                                 nt_datap = nt_data_buf;
2622                                 (void) strncpy(nt_datap, tokbuf,
2623                                     sizeof (nt_data_buf));
2624                                 break;
2625                         case DACF_OPARG_EQUALS:
2626                                 /*
2627                                  * Add the arg.  Warn if it's a duplicate
2628                                  */
2629                                 if (dacf_arg_insert(&arg_list, arg_spec_buf,
2630                                     tokbuf) != 0) {
2631                                         kobj_file_err(CE_WARN, file, w_dupargs,
2632                                             arg_spec_buf);
2633                                 }
2634                                 state = DACF_OPARG_DATA;
2635                                 break;
2636                         default:
2637                                 kobj_file_err(CE_WARN, file, w_syntax, tokbuf);
2638                                 state = DACF_ERR;
2639                                 break;
2640                         }
2641                         break;
2642 
2643                 case COMMA:
2644                         switch (state) {
2645                         case DACF_OPT_OPTION:
2646                                 state = DACF_OPT_COMMA;
2647                                 break;
2648                         default:
2649                                 kobj_file_err(CE_WARN, file, w_syntax, ",");
2650                                 state = DACF_ERR;
2651                                 break;
2652                         }
2653                         break;
2654 
2655                 case COLON:
2656                         if (state == DACF_MN_MODNAME)
2657                                 state = DACF_MN_COLON;
2658                         else {
2659                                 kobj_file_err(CE_WARN, file, w_syntax, ":");
2660                                 state = DACF_ERR;
2661                         }
2662                         break;
2663 
2664                 case EOF:
2665                         done = 1;
2666                         /*FALLTHROUGH*/
2667                 case NEWLINE:
2668                         if (state == DACF_COMMENT || state == DACF_BEGIN) {
2669                                 state = DACF_BEGIN;
2670                                 kobj_newline(file);
2671                                 break;
2672                         }
2673                         if ((state != DACF_OPT_OPTION) &&
2674                             (state != DACF_OPARG_DATA) &&
2675                             (state != DACF_OPT_END)) {
2676                                 kobj_file_err(CE_WARN, file, w_newline);
2677                                 /*
2678                                  * We can't just do DACF_ERR here, since we'll
2679                                  * wind up eating the _next_ newline if so.
2680                                  */
2681                                 state = DACF_ERR_NEWLINE;
2682                                 kobj_newline(file);
2683                                 break;
2684                         }
2685 
2686                         /*
2687                          * insert the rule.
2688                          */
2689                         if (dacf_rule_insert(nt_spec_type, nt_datap,
2690                             mn_modnamep, mn_opsetp, opid, opts, arg_list) < 0) {
2691                                 /*
2692                                  * We can't just do DACF_ERR here, since we'll
2693                                  * wind up eating the _next_ newline if so.
2694                                  */
2695                                 kobj_file_err(CE_WARN, file, w_insert);
2696                                 state = DACF_ERR_NEWLINE;
2697                                 kobj_newline(file);
2698                                 break;
2699                         }
2700 
2701                         state = DACF_BEGIN;
2702                         kobj_newline(file);
2703                         break;
2704 
2705                 default:
2706                         kobj_file_err(CE_WARN, file, w_syntax, tokbuf);
2707                         break;
2708                 } /* switch */
2709 
2710                 /*
2711                  * Clean up after ourselves, either after a line has terminated
2712                  * successfully or because of a syntax error; or when we reach
2713                  * EOF (remember, we may reach EOF without being 'done' with
2714                  * handling a particular line).
2715                  */
2716                 if (state == DACF_ERR) {
2717                         kobj_find_eol(file);
2718                 }
2719                 if ((state == DACF_BEGIN) || (state == DACF_ERR) ||
2720                     (state == DACF_ERR_NEWLINE) || done) {
2721                         nt_datap = NULL;
2722                         mn_modnamep = mn_opsetp = NULL;
2723                         opts = 0;
2724                         opid = DACF_OPID_ERROR;
2725                         nt_spec_type = DACF_DS_ERROR;
2726                         dacf_arglist_delete(&arg_list);
2727                         state = DACF_BEGIN;
2728                 }
2729         } /* while */
2730 
2731         if (dacfdebug & DACF_DBG_MSGS) {
2732                 printf("\ndacf debug: done!\n");
2733         }
2734 
2735         mutex_exit(&dacf_lock);
2736 
2737         kobj_close_file(file);
2738         return (0);
2739 }
2740 
2741 void
2742 lock_hw_class_list()
2743 {
2744         mutex_enter(&hcl_lock);
2745 }
2746 
2747 void
2748 unlock_hw_class_list()
2749 {
2750         mutex_exit(&hcl_lock);
2751 }
2752 
2753 void
2754 add_class(char *exporter, char *class)
2755 {
2756         struct hwc_class *hcl;
2757 
2758         /*
2759          * If exporter's major is not registered in /etc/name_to_major,
2760          * don't update hwc_class, but just return here.
2761          */
2762         if (ddi_name_to_major(exporter) >= devcnt) {
2763                 cmn_err(CE_WARN, "No major number for driver %s"
2764                     " in class %s", exporter, class);
2765                 return;
2766         }
2767         hcl = kmem_zalloc(sizeof (struct hwc_class), KM_SLEEP);
2768         hcl->class_exporter = kmem_alloc(strlen(exporter) + 1, KM_SLEEP);
2769         hcl->class_name = kmem_alloc(strlen(class) + 1, KM_SLEEP);
2770         (void) strcpy(hcl->class_exporter, exporter);
2771         (void) strcpy(hcl->class_name, class);
2772         lock_hw_class_list();
2773         hcl->class_next = hcl_head;
2774         hcl_head = hcl;
2775         unlock_hw_class_list();
2776 }
2777 
2778 /*
2779  * Return the number of classes exported. If buf is not NULL, fill in
2780  * the array of the class names as well.
2781  *
2782  * Caller must hold hcl_lock to ensure the class list unmodified while
2783  * it is accessed. A typical caller will get a count first and then
2784  * allocate buf. The lock should be held by the caller.
2785  */
2786 int
2787 get_class(const char *exporter, char **buf)
2788 {
2789         int n = 0;
2790         struct hwc_class *hcl;
2791 
2792         ASSERT(mutex_owned(&hcl_lock));
2793         for (hcl = hcl_head; hcl != NULL; hcl = hcl->class_next) {
2794                 if (strcmp(exporter, hcl->class_exporter) == 0) {
2795                         if (buf)
2796                                 buf[n] = hcl->class_name;
2797                         ++n;
2798                 }
2799         }
2800 
2801         return (n);
2802 }
2803 
2804 void
2805 read_class_file(void)
2806 {
2807         struct _buf *file;
2808         struct hwc_class *hcl, *hcl1;
2809         char tokbuf[MAXNAMELEN];
2810         enum {
2811                 C_BEGIN, C_EXPORTER, C_END
2812         } state;
2813         token_t token;
2814         int done = 0;
2815         char *exporter = NULL, *class = NULL, *name = NULL;
2816 
2817         if (hcl_head != NULL) {
2818                 hcl = hcl_head;
2819                 while (hcl != NULL) {
2820                         kmem_free(hcl->class_exporter,
2821                             strlen(hcl->class_exporter) + 1);
2822                         hcl1 = hcl;
2823                         hcl = hcl->class_next;
2824                         kmem_free(hcl1, sizeof (struct hwc_class));
2825                 }
2826                 hcl_head = NULL;
2827         }
2828 
2829         if ((file = kobj_open_file(class_file)) == (struct _buf *)-1)
2830                 return;
2831 
2832         state = C_BEGIN;
2833         while (!done) {
2834                 token = kobj_lex(file, tokbuf, sizeof (tokbuf));
2835 
2836                 switch (token) {
2837                 case POUND:
2838                         /*
2839                          * Skip comments.
2840                          */
2841                         kobj_find_eol(file);
2842                         break;
2843                 case NAME:
2844                 case STRING:
2845                         name = kmem_alloc(strlen(tokbuf) + 1, KM_SLEEP);
2846                         (void) strcpy(name, tokbuf);
2847                         switch (state) {
2848                         case C_BEGIN:
2849                                 exporter = name;
2850                                 state = C_EXPORTER;
2851                                 break;
2852                         case C_EXPORTER:
2853                                 class = name;
2854                                 add_class(exporter, class);
2855                                 state = C_END;
2856                                 break;
2857                         case C_END:
2858                                 kobj_file_err(CE_WARN, file,
2859                                     "Extra noise after entry");
2860                                 kmem_free(name, strlen(name) + 1);
2861                                 kobj_find_eol(file);
2862                                 break;
2863                         } /* End Switch */
2864                         break;
2865                 case EOF:
2866                         done = 1;
2867                         /*FALLTHROUGH*/
2868                 case NEWLINE:
2869                         kobj_newline(file);
2870                         if (state == C_EXPORTER)
2871                                 kobj_file_err(CE_WARN, file,
2872                                     "Partial entry ignored");
2873                         state = C_BEGIN;
2874                         if (exporter)
2875                                 kmem_free(exporter, strlen(exporter) + 1);
2876                         if (class)
2877                                 kmem_free(class, strlen(class) + 1);
2878                         exporter = NULL;
2879                         class = NULL;
2880                         break;
2881                 default:
2882                         kobj_file_err(CE_WARN, file, tok_err, tokbuf);
2883                         break;
2884                 }
2885         }
2886         kobj_close_file(file);
2887 }
2888 
2889 /*
2890  * Given par_list, get a list of parent major number
2891  */
2892 int
2893 impl_parlist_to_major(struct par_list *pl, char parents[])
2894 {
2895         struct hwc_spec *hwcp;
2896         struct hwc_class *hcl;
2897         major_t major;
2898         int nmajor = 0;
2899         extern int devcnt;
2900 
2901         for (; pl != NULL; pl = pl->par_next) {
2902                 if ((pl->par_major < devcnt) && (parents[pl->par_major] == 0)) {
2903                         parents[pl->par_major] = 1;
2904                         nmajor++;
2905                         continue;
2906                 }
2907 
2908                 /* parent specs cannot be mapped to a driver */
2909                 if (pl->par_major != DDI_MAJOR_T_NONE)
2910                         continue;
2911 
2912                 /* class spec */
2913                 hwcp = pl->par_specs;
2914                 ASSERT(hwcp->hwc_class_name);
2915                 ASSERT(hwcp->hwc_parent_name == NULL);
2916 
2917                 for (hcl = hcl_head; hcl != NULL; hcl = hcl->class_next) {
2918                         if (strcmp(hwcp->hwc_class_name, hcl->class_name) != 0)
2919                                 continue;
2920                         major = ddi_name_to_major(hcl->class_exporter);
2921                         ASSERT(major != DDI_MAJOR_T_NONE);
2922                         if (parents[major] == 0) {
2923                                 parents[major] = 1;
2924                                 nmajor++;
2925                         }
2926                 }
2927         }
2928         return (nmajor);
2929 }
2930 
2931 /*
2932  * delete a parent list and all its hwc specs
2933  */
2934 void
2935 impl_delete_par_list(struct par_list *pl)
2936 {
2937         struct par_list *saved_pl;
2938         struct hwc_spec *hp, *hp1;
2939 
2940         while (pl) {
2941                 hp = pl->par_specs;
2942                 while (hp) {
2943                         hp1 = hp;
2944                         hp = hp->hwc_next;
2945                         hwc_free(hp1);
2946                 }
2947                 saved_pl = pl;
2948                 pl = pl->par_next;
2949                 kmem_free(saved_pl, sizeof (*saved_pl));
2950         }
2951 }
2952 
2953 #if defined(_PSM_MODULES)
2954 void
2955 open_mach_list(void)
2956 {
2957         struct _buf *file;
2958         char tokbuf[MAXNAMELEN];
2959         token_t token;
2960         struct psm_mach *machp;
2961 
2962         if ((file = kobj_open_file(mach_file)) == (struct _buf *)-1)
2963                 return;
2964 
2965         while ((token = kobj_lex(file, tokbuf, sizeof (tokbuf))) != EOF) {
2966                 switch (token) {
2967                 case POUND:
2968                         /*
2969                          * Skip comments.
2970                          */
2971                         kobj_find_eol(file);
2972                         break;
2973                 case NAME:
2974                 case STRING:
2975                         machp = kmem_alloc((sizeof (struct psm_mach) +
2976                             strlen(tokbuf) + 1), KM_SLEEP);
2977                         machp->m_next = pmach_head;
2978                         machp->m_machname = (char *)(machp + 1);
2979                         (void) strcpy(machp->m_machname, tokbuf);
2980                         pmach_head = machp;
2981                         break;
2982                 case NEWLINE:
2983                         kobj_newline(file);
2984                         break;
2985                 default:
2986                         kobj_file_err(CE_WARN, file, tok_err, tokbuf);
2987                         break;
2988                 }
2989         }
2990         kobj_close_file(file);
2991 }
2992 
2993 void *
2994 get_next_mach(void *handle, char *buf)
2995 {
2996         struct psm_mach *machp;
2997 
2998         machp = (struct psm_mach *)handle;
2999         if (machp)
3000                 machp = machp->m_next;
3001         else
3002                 machp = pmach_head;
3003         if (machp)
3004                 (void) strcpy(buf, machp->m_machname);
3005         return (machp);
3006 }
3007 
3008 void
3009 close_mach_list(void)
3010 {
3011         struct psm_mach *machp;
3012 
3013         while (pmach_head) {
3014                 machp = pmach_head;
3015                 pmach_head = machp->m_next;
3016                 kmem_free(machp, sizeof (struct psm_mach) +
3017                     strlen(machp->m_machname) + 1);
3018         }
3019 }
3020 #endif  /* _PSM_MODULES */
3021 
3022 #if defined(_RTC_CONFIG)
3023 /*
3024  * Read in the 'zone_lag' value from the rtc configuration file,
3025  * and return the value to the caller.  Note that there is other information
3026  * in this file (zone_info), so we ignore unknown values.  We do spit out
3027  * warnings if the line doesn't begin with an identifier, or if we don't find
3028  * exactly "zone_lag=value".  No one should be editing this file by hand
3029  * (use the rtc command instead), but it's better to be careful.
3030  */
3031 long
3032 process_rtc_config_file(void)
3033 {
3034         enum {
3035                 R_NEW, R_NAME, R_EQUALS, R_VALUE
3036         } state;
3037         struct _buf *file;
3038         char tokbuf[MAXNAMELEN];
3039         token_t token;
3040         long zone_lag = 0;
3041         u_longlong_t tmp;
3042         int done = 0;
3043 
3044         if ((file = kobj_open_file(rtc_config_file)) == (struct _buf *)-1)
3045                 return (0);
3046 
3047         state = R_NEW;
3048 
3049         while (!done) {
3050                 token = kobj_lex(file, tokbuf, sizeof (tokbuf));
3051 
3052                 switch (token) {
3053                 case POUND:
3054                         /*
3055                          * Skip comments.
3056                          */
3057                         kobj_find_eol(file);
3058                         break;
3059                 case NAME:
3060                 case STRING:
3061                         if (state == R_NEW) {
3062                                 if (strcmp(tokbuf, "zone_lag") == 0)
3063                                         state = R_NAME;
3064                                 else
3065                                         kobj_find_eol(file);   /* Ignore */
3066                         } else
3067                                 kobj_file_err(CE_WARN, file, tok_err, tokbuf);
3068                         break;
3069                 case EQUALS:
3070                         if (state == R_NAME)
3071                                 state = R_EQUALS;
3072                         else
3073                                 kobj_file_err(CE_WARN, file, tok_err, tokbuf);
3074                         break;
3075                 case DECVAL:
3076                         if (state == R_EQUALS) {
3077                                 if (kobj_getvalue(tokbuf, &tmp) != 0)
3078                                         kobj_file_err(CE_WARN, file,
3079                                             "Bad value %s for zone_lag",
3080                                             tokbuf);
3081                                 else
3082                                         zone_lag = (long)tmp;
3083                                 state = R_VALUE;
3084                         } else
3085                                 kobj_file_err(CE_WARN, file, tok_err, tokbuf);
3086                         break;
3087                 case EOF:
3088                         done = 1;
3089                         /*FALLTHROUGH*/
3090                 case NEWLINE:
3091                         if (state != R_NEW && state != R_VALUE)
3092                                 kobj_file_err(CE_WARN, file,
3093                                     "Partial zone_lag entry ignored");
3094                         kobj_newline(file);
3095                         state = R_NEW;
3096                         break;
3097                 default:
3098                         kobj_file_err(CE_WARN, file, tok_err, tokbuf);
3099                         break;
3100                 }
3101         }
3102         kobj_close_file(file);
3103         return (zone_lag);
3104 }
3105 #endif /* _RTC_CONFIG */
3106 
3107 
3108 /*
3109  * Append node spec to the end of par_list
3110  */
3111 static void
3112 append(struct hwc_spec *spec, struct par_list *par)
3113 {
3114         struct hwc_spec *hwc, *last;
3115 
3116         ASSERT(par->par_specs);
3117         for (hwc = par->par_specs; hwc; hwc = hwc->hwc_next)
3118                 last = hwc;
3119         last->hwc_next = spec;
3120 }
3121 
3122 /*
3123  * Given a parent=/full-pathname, see if the platform
3124  * can resolve the pathname to driver, otherwise, try
3125  * the leaf node name.
3126  */
3127 static major_t
3128 get_major(char *parent)
3129 {
3130         major_t major = DDI_MAJOR_T_NONE;
3131         char *tmp, *driver = NULL;
3132 
3133         if (*parent == '/')
3134                 major = path_to_major(parent);
3135 
3136         if (major != DDI_MAJOR_T_NONE)
3137                 return (major);
3138 
3139         /* extract the name between '/' and '@' */
3140         if (*parent == '/')
3141                 driver = strrchr(parent, '/') + 1;
3142         else
3143                 driver = parent;
3144         if ((tmp = strchr(driver, '@')) != NULL)
3145                 *tmp = '\0';
3146         major = ddi_name_to_major(driver);
3147         if (tmp)
3148                 *tmp = '@';
3149         return (major);
3150 }
3151 
3152 /*
3153  * Chain together specs whose parent's module name is the same.
3154  */
3155 static void
3156 add_spec(struct hwc_spec *spec, struct par_list **par)
3157 {
3158         major_t maj;
3159         struct par_list *pl, *par_last = NULL;
3160         char *parent = spec->hwc_parent_name;
3161         char *class = spec->hwc_class_name;
3162 
3163         ASSERT(parent || class);
3164 
3165         /*
3166          * If given a parent=/full-pathname, see if the platform
3167          * can resolve the pathname to driver, otherwise, try
3168          * the leaf node name.
3169          *
3170          * If parent=/full-pathname doesn't resolve to a driver,
3171          * this could be cause by DR removal of the device.
3172          * We put it on the major=-2 list in case the device
3173          * is brought back into the system by DR.
3174          */
3175         if (parent) {
3176                 maj = get_major(parent);
3177                 if (maj == DDI_MAJOR_T_NONE) {
3178                         if ((*parent == '/') &&
3179                             (strncmp(parent, "/pseudo", 7) != 0)) {
3180                                 maj = (major_t)-2;
3181                         } else {
3182                                 cmn_err(CE_WARN,
3183                                     "add_spec: No major number for %s",
3184                                     parent);
3185                                 hwc_free(spec);
3186                                 return;
3187                         }
3188                 }
3189         } else
3190                 maj = DDI_MAJOR_T_NONE;
3191 
3192         /*
3193          * Scan the list looking for a matching parent. When parent is
3194          * not NULL, we match the parent by major. If parent is NULL but
3195          * class is not NULL, we mache the pl by class name.
3196          */
3197         for (pl = *par; pl; pl = pl->par_next) {
3198                 if ((parent && (maj == pl->par_major)) || ((parent == NULL) &&
3199                     class && pl->par_specs->hwc_class_name && (strncmp(class,
3200                     pl->par_specs->hwc_class_name, strlen(class)) == 0))) {
3201                         append(spec, pl);
3202                         return;
3203                 }
3204                 par_last = pl;
3205         }
3206 
3207         /*
3208          * Didn't find a match on the list.  Make a new parent list.
3209          */
3210         pl = kmem_zalloc(sizeof (*pl), KM_SLEEP);
3211         pl->par_major = maj;
3212         pl->par_specs = spec;
3213         if (*par == NULL) {     /* null par list */
3214                 *par = pl;
3215                 return;
3216         }
3217         /* put "class=" entries last (lower pri if dups) */
3218         if (maj == DDI_MAJOR_T_NONE) {
3219                 par_last->par_next = pl;
3220                 return;
3221         }
3222 
3223         /* ensure unresolved "parent=/full-path" goes first */
3224         if ((maj != (major_t)-2) && ((*par)->par_major == (major_t)-2))
3225                 par = &(*par)->par_next;
3226         pl->par_next = *par;
3227         *par = pl;
3228 }
3229 
3230 /*
3231  * Add property spec to property list in original order
3232  */
3233 static void
3234 add_props(struct hwc_spec *spec, ddi_prop_t **props)
3235 {
3236         ASSERT(spec->hwc_devi_name == NULL);
3237 
3238         if (spec->hwc_devi_sys_prop_ptr) {
3239                 while (*props)
3240                         props = &(*props)->prop_next;
3241                 *props = spec->hwc_devi_sys_prop_ptr;
3242 
3243                 /* remove these properties from the spec */
3244                 spec->hwc_devi_sys_prop_ptr = NULL;
3245         }
3246         hwc_free(spec);
3247 }