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