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