/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <sys/inttypes.h>
#include <sys/bootconf.h>
#include <sys/ddi_impldefs.h>
#include <sys/kobj_lex.h>
#include <sys/autoconf.h>
#include <sys/sysmacros.h>
#include <vm/seg_kmem.h>
#if defined(_PSM_MODULES)
struct psm_mach {
char *m_machname;
};
#endif /* _PSM_MODULES */
#if defined(_RTC_CONFIG)
#endif
static void sys_set_var(int, struct sysparam *, void *);
static void setparams(void);
/*
* driver.conf parse thread control structure
*/
struct hwc_parse_mt {
};
static void hwc_parse_thread(struct hwc_parse_mt *);
ddi_prop_t **);
static void hwc_parse_mtfree(struct hwc_parse_mt *);
static void check_system_file(void);
static char *sysparam_type_to_str(int);
#ifdef DEBUG
static int parse_debug_on = 0;
/*VARARGS1*/
static void
{
if (parse_debug_on) {
if (file)
}
}
#endif /* DEBUG */
/*PRINTFLIKE3*/
void
{
/*
* If we're in trouble, we might be short on stack... be paranoid
*/
fmt++;
}
/*
* If prefixed with !^?, prepend that character
*/
if (prefix != '\0') {
} else {
}
}
#ifdef DEBUG
char *tokennames[] = {
"UNEXPECTED",
"EQUALS",
"AMPERSAND",
"BIT_OR",
"STAR",
"POUND",
"COLON",
"SEMICOLON",
"COMMA",
"SLASH",
"WHITE_SPACE",
"NEWLINE",
"EOF",
"STRING",
"HEXVAL",
"DECVAL",
"NAME"
};
#endif /* DEBUG */
{
char *cp;
if (size < 2)
return (token); /* this token is UNEXPECTED */
;
switch (ch) {
case '=':
break;
case '&':
break;
case '|':
break;
case '*':
break;
case '#':
break;
case ':':
break;
case ';':
break;
case ',':
break;
case '/':
break;
case ' ':
case '\t':
case '\f':
if (--remain == 0) {
token = UNEXPECTED;
goto out;
}
}
(void) kobj_ungetc(file);
token = WHITE_SPACE;
break;
case '\n':
case '\r':
break;
case '"':
remain++;
cp--;
badquote = 0;
switch (ch) {
case '\n':
case -1:
*cp++ = '\n';
badquote = 1;
(void) kobj_ungetc(file);
break;
case '\\':
if (--remain == 0) {
token = UNEXPECTED;
goto out;
}
/* escape the character */
break;
}
oval = 0;
ch -= '0';
}
(void) kobj_ungetc(file);
/* check for character overflow? */
if (oval > 127) {
"Character "
"overflow detected.");
}
break;
default:
if (--remain == 0) {
token = UNEXPECTED;
goto out;
}
break;
}
}
break;
case -1:
break;
default:
/*
* detect a lone '-' (including at the end of a line), and
* identify it as a 'name'
*/
if (ch == '-') {
if (--remain == 0) {
token = UNEXPECTED;
goto out;
}
(void) kobj_ungetc(file);
remain++;
cp--;
break;
}
if (--remain == 0) {
token = UNEXPECTED;
goto out;
}
}
if (ch == '0') {
if (--remain == 0) {
token = UNEXPECTED;
goto out;
}
if (--remain == 0) {
token = UNEXPECTED;
goto out;
}
}
(void) kobj_ungetc(file);
} else {
goto digit;
}
} else {
if (--remain == 0) {
token = UNEXPECTED;
goto out;
}
}
(void) kobj_ungetc(file);
}
if (ch != '\\') {
} else {
/*
* if the character was a backslash,
* back up so we can overwrite it with
* the next (i.e. escaped) character.
*/
remain++;
cp--;
}
if (ch == '\\')
if (--remain == 0) {
token = UNEXPECTED;
goto out;
}
}
(void) kobj_ungetc(file);
} else {
token = UNEXPECTED;
}
break;
}
out:
*cp = '\0';
#ifdef DEBUG
/*
* The UNEXPECTED token is the first element of the tokennames array,
* but its token value is -1. Adjust the value by adding one to it
* to change it to an index of the array.
*/
#endif
return (token);
}
/*
* Leave NEWLINE as the next character.
*/
void
{
int ch;
(void) kobj_ungetc(file);
break;
}
}
}
/*
* The ascii system file is read and processed.
*
* The syntax of commands is as follows:
*
* '*' in column 1 is a comment line.
* <command> : <value>
*
* command is EXCLUDE, INCLUDE, FORCELOAD, ROOTDEV, ROOTFS,
* SWAPDEV, SWAPFS, MODDIR, SET
*
* value is an ascii string meaningful for the command.
*/
/*
* Table of commands
*/
{ "EXCLUDE", MOD_EXCLUDE },
{ "exclude", MOD_EXCLUDE },
{ "INCLUDE", MOD_INCLUDE },
{ "include", MOD_INCLUDE },
{ "FORCELOAD", MOD_FORCELOAD },
{ "forceload", MOD_FORCELOAD },
{ "ROOTDEV", MOD_ROOTDEV },
{ "rootdev", MOD_ROOTDEV },
{ "ROOTFS", MOD_ROOTFS },
{ "rootfs", MOD_ROOTFS },
{ "SWAPDEV", MOD_SWAPDEV },
{ "swapdev", MOD_SWAPDEV },
{ "SWAPFS", MOD_SWAPFS },
{ "swapfs", MOD_SWAPFS },
{ "MODDIR", MOD_MODDIR },
{ "moddir", MOD_MODDIR },
{ "SET", MOD_SET },
{ "set", MOD_SET },
{ "SET32", MOD_SET32 },
{ "set32", MOD_SET32 },
{ "SET64", MOD_SET64 },
{ "set64", MOD_SET64 },
{ NULL, MOD_UNKNOWN }
};
static struct sysparam *
{
char *cp;
int ch;
break;
}
VM_SLEEP);
case MOD_INCLUDE:
case MOD_EXCLUDE:
case MOD_FORCELOAD:
/*
* Are followed by colon.
*/
case MOD_ROOTFS:
case MOD_SWAPFS:
} else {
}
goto bad;
}
goto bad;
}
}
*cp = '\0';
if (ch != -1)
(void) kobj_ungetc(file);
return (NULL);
VM_SLEEP);
break;
case MOD_SET:
case MOD_SET64:
case MOD_SET32:
{
char *var;
goto bad;
}
/*
* If the next token is a colon (:),
* we have the <modname>:<variable> construct.
*/
/*
* Save the module name.
*/
} else {
goto bad;
}
} else {
/* otherwise, it was the op */
}
/*
* kernel param - place variable name in sys_ptr.
*/
VM_SLEEP);
/* set operation */
switch (op) {
case EQUALS:
/* simple assignment */
break;
case AMPERSAND:
/* bitwise AND */
break;
case BIT_OR:
/* bitwise OR */
break;
default:
/* unsupported operation */
"unsupported operator %s", tok2);
goto bad;
}
case STRING:
/* string variable */
goto bad;
}
goto bad;
}
/*
* Set SYSPARAM_STR_TOKEN in sys_flags to notify
* sysparam_print_warning() that this is a string
* token.
*/
break;
case HEXVAL:
case DECVAL:
"invalid number '%s'", tok1);
goto bad;
}
/*
* Set the appropriate flag (hexadecimal or decimal)
* in sys_flags for sysparam_print_warning() to be
* able to print the number with the correct format.
*/
} else {
}
break;
default:
goto bad;
} /* end switch */
/*
* Now that we've parsed it to check the syntax, consider
* discarding it (because it -doesn't- apply to this flavor
* of the kernel)
*/
#ifdef _LP64
return (NULL);
#else
return (NULL);
#endif
break;
}
case MOD_MODDIR:
goto bad;
}
if (token == -1) {
goto bad;
}
goto bad;
}
}
*cp++ = ' ';
cp--;
(void) kobj_ungetc(file);
}
}
(void) kobj_ungetc(file);
*cp = '\0';
VM_SLEEP);
break;
case MOD_SWAPDEV:
case MOD_ROOTDEV:
goto bad;
}
;
goto bad;
}
}
if (ch != -1)
(void) kobj_ungetc(file);
*cp = '\0';
VM_SLEEP);
break;
case MOD_UNKNOWN:
default:
goto bad;
}
return (sysp);
bad:
return (NULL);
}
void
{
if (ask)
if (systemfile != NULL) {
(struct _buf *)-1) {
} else {
switch (token) {
case STAR:
case POUND:
/*
* Skip comments.
*/
break;
case NEWLINE:
break;
case NAME:
sysparam_tl = sp;
}
break;
default:
break;
}
}
}
}
/*
*/
param_preset();
param_check();
if (ask == 0)
setparams();
}
/*
* successful, 1 is returned and the value is stored in '*value'.
* Otherwise 0 is returned and '*value' isn't modified. If 'module' is
* NULL we look for global definitions.
*
* This is useful if the value of an assignment is needed before a
* module is loaded (e.g. to obtain a default privileged rctl limit).
*/
int
{
return (1);
continue;
}
}
}
return (0);
}
/*
* This function scans sysparam records, which are created from the
* and prints warning messages as appropriate. When multiple "set"
* commands are encountered, the pileup of values with "&", "|"
* and "=" operators results in the final value.
*/
static void
check_system_file(void)
{
/*
* If the entry is already checked, skip it.
*/
continue;
/*
* Check if there is a duplicate entry by doing a linear
* search.
*/
/*
* Check the entry. if it's different, skip this.
*/
continue;
/*
* Count the entry and put the mark.
*/
}
/*
* Print the warning if it's duplicated.
*/
if (cnt >= 2)
}
}
/*
* Compare the sysparam records.
* Return 0 if they are the same, return 1 if not.
*/
static int
{
/*
* If the command is rootdev, rootfs, swapdev, swapfs or moddir,
* the record with the same type is treated as a duplicate record.
* In other cases, the record is treated as a duplicate record when
* its type, its module name (if it exists), and its variable name
* are the same.
*/
case MOD_ROOTDEV:
case MOD_ROOTFS:
case MOD_SWAPDEV:
case MOD_SWAPFS:
case MOD_MODDIR:
default: /* In other cases, just go through it. */
break;
}
return (1);
return (1);
return (1);
return (1);
}
/*
* Translate a sysparam type value to a string.
*/
static char *
{
break;
}
if (type != MOD_UNKNOWN)
else
return (""); /* MOD_UNKNOWN */
}
/*
* Check the entry and accumulate the number of entries.
*/
static void
{
case SETOP_ASSIGN:
(*cnt)++;
return;
case SETOP_AND:
return;
case SETOP_OR:
return;
default: /* Not MOD_SET */
(*cnt)++;
return;
}
}
/*
* Print out the warning if multiple entries are found in the system file.
*/
static void
{
/*
* If a string token is set, print out the string
* instead of its pointer value. In other cases,
* print out the value with the appropriate format
* for a hexadecimal number or a decimal number.
*/
"\"%s %s = %s\"" warn_format2,
} else if (hex_number == B_TRUE) {
"\"%s %s = 0x%llx\"" warn_format2,
} else {
"\"%s %s = %lld\"" warn_format2,
}
} else {
"\"%s %s:%s = %s\"" warn_format2,
} else if (hex_number == B_TRUE) {
"\"%s %s:%s = 0x%llx\"" warn_format2,
} else {
"\"%s %s:%s = %lld\"" warn_format2,
}
}
} else {
/*
* If the type is MOD_ROOTDEV, MOD_ROOTFS, MOD_SWAPDEV,
* MOD_SWAPFS or MOD_MODDIR, the entry is treated as
* a duplicate one if it has the same type regardless
* of its variable name.
*/
switch (type) {
case MOD_ROOTDEV:
case MOD_ROOTFS:
case MOD_SWAPDEV:
case MOD_SWAPFS:
case MOD_MODDIR:
break;
default:
break;
}
}
}
/*
* Process the system file commands.
*/
int
{
char *name;
if (sysparam_hd == NULL)
return (0);
switch (fcn) {
case SYS_FORCELOAD:
/*
* The following works because it
* runs before autounloading is started!!
*/
/*
* For drivers, attempt to install it.
*/
}
}
break;
case SYS_SET_KVAR:
case SYS_SET_MVAR:
break;
case SYS_CHECK_EXCLUDE:
return (0);
return (1);
}
}
}
return (0);
}
/*
* Process the system file commands, by type.
*/
int
{
int err;
return (err);
return (0);
}
static void
{
int size;
} else if (fcn == SYS_SET_MVAR) {
sysp->sys_modnam) != 0)
return;
} else
return;
switch (size) {
case 1:
break;
case 2:
break;
case 0:
/*FALLTHROUGH*/
case 4:
break;
case 8:
break;
default:
break;
}
} else {
printf("sorry, variable '%s' is not defined in the '%s' ",
if (sysp->sys_modnam)
printf("module");
printf("\n");
}
}
static void
{
if (moddebug & MODDEBUG_LOADMSG)
case SETOP_ASSIGN:
break;
case SETOP_AND:
break;
case SETOP_OR:
break;
}
if (moddebug & MODDEBUG_LOADMSG)
}
static void
{
if (moddebug & MODDEBUG_LOADMSG)
case SETOP_ASSIGN:
break;
case SETOP_AND:
break;
case SETOP_OR:
break;
}
if (moddebug & MODDEBUG_LOADMSG)
}
static void
{
if (moddebug & MODDEBUG_LOADMSG)
case SETOP_ASSIGN:
break;
case SETOP_AND:
break;
case SETOP_OR:
break;
}
if (moddebug & MODDEBUG_LOADMSG)
}
static void
{
if (moddebug & MODDEBUG_LOADMSG)
case SETOP_ASSIGN:
break;
case SETOP_AND:
break;
case SETOP_OR:
break;
}
if (moddebug & MODDEBUG_LOADMSG)
}
/*
* The next item on the line is a string value. Allocate memory for
* it and copy the string. Return 1, and set arg ptr to newly allocated
* and initialized buffer, or NULL if an error occurs.
*/
int
{
char *cp;
char *start = (char *)0;
int len = 0;
/* copy string */
/* convert some common escape sequences */
if (*start == '\\') {
switch (*(start + 1)) {
case 't':
/* tab */
*cp++ = '\t';
len--;
start += 2;
break;
case 'n':
/* new line */
*cp++ = '\n';
len--;
start += 2;
break;
case 'b':
/* back space */
*cp++ = '\b';
len--;
start += 2;
break;
default:
/* simply copy it */
break;
}
} else
}
*cp = '\0';
return (1);
}
/*
* this function frees the memory allocated by kobj_get_string
*/
void
{
}
/*
* get a decimal octal or hex number. Handle '~' for one's complement.
*/
int
{
int radix;
int onescompl = 0;
int negate = 0;
char c;
if (*token == '~') {
onescompl++; /* perform one's complement on result */
token++;
} else if (*token == '-') {
negate++;
token++;
}
if (*token == '0') {
token++;
c = *token;
if (c == '\0') {
*valuep = 0; /* value is 0 */
return (0);
}
if (c == 'x' || c == 'X') {
radix = 16;
token++;
} else
radix = 8;
} else
radix = 10;
while ((c = *token++)) {
switch (radix) {
case 8:
if (c >= '0' && c <= '7')
c -= '0';
else
return (-1); /* invalid number */
break;
case 10:
if (c >= '0' && c <= '9')
c -= '0';
else
return (-1); /* invalid number */
break;
case 16:
if (c >= 'a' && c <= 'f')
c = c - 'a' + 10;
else if (c >= 'A' && c <= 'F')
c = c - 'A' + 10;
else if (c >= '0' && c <= '9')
c -= '0';
else
return (-1); /* invalid number */
break;
}
}
if (onescompl)
if (negate)
return (0);
}
/*
* Path to the root device and root filesystem type from
* property information derived from the boot subsystem
*/
void
{
}
void
{
}
/*
* set parameters that can be set early during initialization.
*/
static void
{
continue;
}
case MOD_ROOTDEV:
root_is_svm = 1;
break;
case MOD_SWAPDEV:
break;
case MOD_ROOTFS:
case MOD_SWAPFS:
break;
default:
break;
}
}
}
/*
* clean up after an error.
*/
static void
{
char *name;
}
/*
* Free a list of specs
*/
void
{
while (list) {
}
}
struct val_list {
enum {
} val_type;
int val_size;
union {
char *string;
int integer;
} val;
};
static struct val_list *
{
#ifdef DEBUG
#endif
} else {
}
} else {
}
return (new_val);
}
static void
{
}
}
/*
* make sure there are no reserved IEEE 1275 characters (except
* for uppercase characters).
*/
static int
{
int i;
for (i = 0; i < len; i++) {
if (name[i] < 0x21 ||
name[i] == '/' ||
name[i] == '\\' ||
name[i] == ':' ||
name[i] == '[' ||
name[i] == ']' ||
name[i] == '@')
return (0);
}
return (1);
}
static void
{
char **valsp;
int *valip;
return;
#ifdef DEBUG
#endif
if (!valid_prop_name(name)) {
return;
}
if (val) {
return;
}
propcnt++;
}
if (val_type == VAL_INTEGER) {
valip = (int *)kmem_alloc(
while (vl) {
#ifdef DEBUG
#endif
valip++;
}
/* restore valip */
/* create the property */
"cannot create property %s", name);
}
/* cleanup */
} else if (val_type == VAL_STRING) {
valsp = (char **)kmem_alloc(
while (vl) {
#ifdef DEBUG
#endif
valsp++;
}
/* terminate array with NULL */
/* restore valsp */
/* create the property */
!= DDI_PROP_SUCCESS) {
"cannot create property %s", name);
}
/* Clean up */
} else {
return;
}
} else {
/*
* No value was passed in with property so we will assume
* it is a "boolean" property and create an integer
* property with 0 value.
*/
#ifdef DEBUG
#endif
!= DDI_PROP_SUCCESS) {
"cannot create property %s", name);
}
}
}
typedef enum {
} hwc_state_t;
static struct hwc_spec *
{
char *prop_name;
do {
#ifdef DEBUG
#endif
switch (token) {
case NAME:
switch (state) {
case prop:
case prop_equals_string:
case prop_equals_integer:
if (prop_name) {
}
if (val_list) {
}
/*FALLTHROUGH*/
case hwc_begin:
1, KM_SLEEP);
} else {
1, KM_SLEEP);
}
break;
default:
}
break;
case EQUALS:
switch (state) {
case drvname:
state = name_equals;
break;
case parent:
break;
case drvclass:
break;
case prop:
state = prop_equals;
break;
default:
}
break;
case STRING:
switch (state) {
case name_equals:
goto bad;
}
KM_SLEEP);
break;
case parent_equals:
if (hwcp->hwc_parent_name) {
goto bad;
}
break;
case drvclass_equals:
if (hwcp->hwc_class_name) {
goto bad;
}
/*FALLTHROUGH*/
case prop_equals:
case prop_equals_string_comma:
tokbuf);
break;
default:
}
break;
case HEXVAL:
case DECVAL:
switch (state) {
case prop_equals:
break;
default:
}
break;
case COMMA:
switch (state) {
case prop_equals_string:
break;
case prop_equals_integer:
break;
default:
}
break;
case NEWLINE:
break;
case POUND:
/*
* Skip comments.
*/
break;
case EOF:
goto bad;
default:
goto bad;
}
switch (state) {
case prop:
case prop_equals_string:
case prop_equals_integer:
break;
case hwc_begin:
break;
default:
break;
}
/* copy 2 relevant members of devi to hwcp */
if (prop_name)
if (val_list)
return (hwcp);
bad:
if (prop_name)
if (val_list)
return (NULL);
}
/*
* This is the primary kernel interface to parse driver.conf files.
*
* Yet another bigstk thread handoff due to deep kernel stacks when booting
* cache-only-clients.
*/
int
{
int ret;
} else {
}
return (ret);
}
/*
* Calls to hwc_parse() are handled off to this routine in a separate
* thread.
*/
static void
{
/*
* load and parse the .conf file
* return the hwc_spec list (if any) to the creator of this thread
*/
thread_exit();
}
/*
* allocate and initialize a hwc_parse thread control structure
*/
static struct hwc_parse_mt *
{
return (pltp);
}
/*
* free a hwc_parse thread control structure
*/
static void
{
}
/*
* hwc_parse -- parse an hwconf file. Ignore error lines and parse
* as much as possible.
*/
static int
{
char *tokval;
/*
* Don't use kobj_open_path's use_moddir_suffix option, we only
* expect to find conf files in the base module directory, not
* an ISA-specific subdirectory.
*/
if (moddebug & MODDEBUG_ERRMSG)
return (-1);
}
/*
* Initialize variables
*/
switch (token) {
case POUND:
/*
* Skip comments.
*/
break;
case NAME:
break;
/*
* No devi_name indicates global property.
* Make sure parent and class not NULL.
*/
if (hwcp->hwc_parent_name ||
hwcp->hwc_class_name) {
"missing name attribute");
continue;
}
/* Add to global property list */
break;
}
/*
* This is a node spec, either parent or class
* must be specified.
*/
"missing parent or class attribute");
continue;
}
/* add to node spec list */
break;
case NEWLINE:
break;
default:
break;
}
}
/*
* XXX - Check for clean termination.
*/
return (0); /* always return success */
}
void
{
enum {
} state;
int done = 0;
"an existing driver name or alias.";
return;
while (!done) {
switch (token) {
case POUND:
/*
* Skip comments.
*/
break;
case NAME:
case STRING:
switch (state) {
case AL_NEW:
state = AL_DRVNAME;
break;
case AL_DRVNAME_COMMA:
state = AL_DRVNAME;
break;
case AL_ALIAS_COMMA:
break;
case AL_DRVNAME:
if (major == DDI_MAJOR_T_NONE) {
} else {
}
break;
case AL_ALIAS:
!= 0) {
}
/*
* copy this token just in case that there
* are multiple names on the same line.
*/
break;
}
break;
case COMMA:
switch (state) {
case AL_DRVNAME:
break;
case AL_ALIAS:
break;
default:
}
break;
case EOF:
done = 1;
/*FALLTHROUGH*/
case NEWLINE:
!= 0) {
}
"Missing alias for %s", drvbuf);
}
break;
default:
}
}
}
/*
* It is called for parsing these files:
* - /etc/path_to_inst
* - /etc/name_to_major
* - /etc/name_to_sysnum
* A callback "int (*line_parser)(char *, int, char *, struct bind **)"
* is invoked for each line of the file.
* The callback can inhash the entry into a hashtable by supplying
* a pre-allocated hashtable in "struct bind **hashtab".
*/
int
int (*line_parser)(char *, int, char *, struct bind **))
{
enum {
} state;
int maxnum = 0;
int done = 0;
"with a previous entry";
}
while (!done) {
switch (token) {
case POUND:
/*
* Skip comments.
*/
break;
case NAME:
case STRING:
switch (state) {
case B_NEW:
/*
* This case is for the first name and
* possibly only name in an entry.
*/
break;
case B_VAL:
/*
* This case is for a second name, which
* would be the binding name if the first
* name was actually a generic name.
*/
KM_SLEEP);
state = B_BIND_NAME;
break;
default:
}
break;
case HEXVAL:
case DECVAL:
continue;
}
"value %llu too large", val);
continue;
}
break;
case EOF:
done = 1;
/*FALLTHROUGH*/
case NEWLINE:
if (state == B_BIND_NAME)
else
if (line_parser != NULL) {
hashtab) == 0)
else
}
if (name) {
}
if (bind_name) {
}
break;
default:
break;
}
}
return (maxnum);
}
/*
* read_dacf_binding_file()
*
* The syntax of a line in the dacf.conf file is:
* dev-spec [module:]op-set operation options [config-args];
*
* Where:
* 1. dev-spec is of the format: name="data"
* 2. operation is the operation that this rule matches. (i.e. pre-detach)
* 3. options is a comma delimited list of options (i.e. debug,foobar)
* 4. config-data is a whitespace delimited list of the format: name="data"
*/
int
{
enum {
/* minor_nodetype="ddi_mouse:serial" */
/* consconfig:mouseconfig */
/* op */
/* [ option1, option2, option3... | - ] */
/* argname1="argval1" argname2="argval2" ... */
char *fname;
int done = 0;
static char w_dupargs[] =
"argument '%s' duplicates a previous argument, skipping";
} else {
}
return (ENOENT);
}
if (dacfdebug & DACF_DBG_MSGS) {
printf("dacf debug: clearing rules database\n");
}
if (dacfdebug & DACF_DBG_MSGS) {
}
while (!done) {
switch (token) {
case POUND: /* comment line */
if (state != DACF_BEGIN) {
break;
}
break;
case EQUALS:
switch (state) {
case DACF_NT_SPEC:
break;
case DACF_OPARG_SPEC:
break;
default:
}
break;
case NAME:
switch (state) {
case DACF_BEGIN:
if (nt_spec_type == DACF_DS_ERROR) {
break;
}
break;
case DACF_NT_DATA:
sizeof (mn_modname_buf));
break;
case DACF_MN_MODNAME:
/*
* This handles the 'optional' modname.
* What we thought was the modname is really
* the op-set. So it is copied over.
*/
sizeof (mn_opset_buf));
mn_modnamep = NULL;
/*
* Now, the token we just read is the opset,
* so look that up and fill in opid
*/
tokbuf);
break;
}
break;
case DACF_MN_COLON:
sizeof (mn_opset_buf));
break;
case DACF_MN_OPSET:
tokbuf);
break;
}
break;
case DACF_OP_NAME:
/*
* This case is just like DACF_OPT_COMMA below,
* but we check for the sole '-' argument
*/
break;
}
/*FALLTHROUGH*/
case DACF_OPT_COMMA:
/*
* figure out what option was given, but don't
* make a federal case if invalid, just skip it
*/
tokbuf);
}
break;
case DACF_OPT_END:
case DACF_OPT_OPTION:
case DACF_OPARG_DATA:
sizeof (arg_spec_buf));
break;
case DACF_OPARG_EQUALS:
/*
* Add the arg. Warn if it's a duplicate
*/
tokbuf) != 0) {
}
break;
default:
break;
}
break;
case STRING:
/*
* We need to check to see if the string has a \n in it.
* If so, we had an unmatched " mark error, and lex has
* already emitted an error for us, so we need to enter
* the error state. Stupid lex.
*/
break;
}
switch (state) {
case DACF_NT_EQUALS:
break;
}
sizeof (nt_data_buf));
break;
case DACF_OPARG_EQUALS:
/*
* Add the arg. Warn if it's a duplicate
*/
tokbuf) != 0) {
}
break;
default:
break;
}
break;
case COMMA:
switch (state) {
case DACF_OPT_OPTION:
break;
default:
break;
}
break;
case COLON:
if (state == DACF_MN_MODNAME)
else {
}
break;
case EOF:
done = 1;
/*FALLTHROUGH*/
case NEWLINE:
state = DACF_BEGIN;
break;
}
if ((state != DACF_OPT_OPTION) &&
(state != DACF_OPARG_DATA) &&
(state != DACF_OPT_END)) {
/*
* We can't just do DACF_ERR here, since we'll
* wind up eating the _next_ newline if so.
*/
break;
}
/*
* insert the rule.
*/
/*
* We can't just do DACF_ERR here, since we'll
* wind up eating the _next_ newline if so.
*/
break;
}
state = DACF_BEGIN;
break;
default:
break;
} /* switch */
/*
* Clean up after ourselves, either after a line has terminated
* successfully or because of a syntax error; or when we reach
* EOF (remember, we may reach EOF without being 'done' with
* handling a particular line).
*/
}
opts = 0;
state = DACF_BEGIN;
}
} /* while */
if (dacfdebug & DACF_DBG_MSGS) {
printf("\ndacf debug: done!\n");
}
return (0);
}
void
{
}
void
{
}
void
{
/*
* If exporter's major is not registered in /etc/name_to_major,
* don't update hwc_class, but just return here.
*/
return;
}
}
/*
* Return the number of classes exported. If buf is not NULL, fill in
* the array of the class names as well.
*
* Caller must hold hcl_lock to ensure the class list unmodified while
* it is accessed. A typical caller will get a count first and then
* allocate buf. The lock should be held by the caller.
*/
int
{
int n = 0;
if (buf)
++n;
}
}
return (n);
}
void
read_class_file(void)
{
enum {
} state;
int done = 0;
}
}
return;
while (!done) {
switch (token) {
case POUND:
/*
* Skip comments.
*/
break;
case NAME:
case STRING:
switch (state) {
case C_BEGIN:
state = C_EXPORTER;
break;
case C_EXPORTER:
break;
case C_END:
"Extra noise after entry");
break;
} /* End Switch */
break;
case EOF:
done = 1;
/*FALLTHROUGH*/
case NEWLINE:
if (state == C_EXPORTER)
"Partial entry ignored");
if (exporter)
if (class)
break;
default:
break;
}
}
}
/*
* Given par_list, get a list of parent major number
*/
int
{
int nmajor = 0;
extern int devcnt;
nmajor++;
continue;
}
/* parent specs cannot be mapped to a driver */
continue;
/* class spec */
continue;
nmajor++;
}
}
}
return (nmajor);
}
/*
* delete a parent list and all its hwc specs
*/
void
{
while (pl) {
while (hp) {
}
}
}
#if defined(_PSM_MODULES)
void
open_mach_list(void)
{
return;
switch (token) {
case POUND:
/*
* Skip comments.
*/
break;
case NAME:
case STRING:
pmach_head = machp;
break;
case NEWLINE:
break;
default:
break;
}
}
}
void *
{
if (machp)
else
machp = pmach_head;
if (machp)
return (machp);
}
void
close_mach_list(void)
{
while (pmach_head) {
machp = pmach_head;
}
}
#endif /* _PSM_MODULES */
#if defined(_RTC_CONFIG)
/*
* Read in the 'zone_lag' value from the rtc configuration file,
* and return the value to the caller. Note that there is other information
* in this file (zone_info), so we ignore unknown values. We do spit out
* warnings if the line doesn't begin with an identifier, or if we don't find
* exactly "zone_lag=value". No one should be editing this file by hand
* (use the rtc command instead), but it's better to be careful.
*/
long
process_rtc_config_file(void)
{
enum {
} state;
long zone_lag = 0;
int done = 0;
return (0);
while (!done) {
switch (token) {
case POUND:
/*
* Skip comments.
*/
break;
case NAME:
case STRING:
else
} else
break;
case EQUALS:
else
break;
case DECVAL:
"Bad value %s for zone_lag",
tokbuf);
else
} else
break;
case EOF:
done = 1;
/*FALLTHROUGH*/
case NEWLINE:
"Partial zone_lag entry ignored");
break;
default:
break;
}
}
return (zone_lag);
}
#endif /* _RTC_CONFIG */
/*
* Append node spec to the end of par_list
*/
static void
{
}
/*
* Given a parent=/full-pathname, see if the platform
* can resolve the pathname to driver, otherwise, try
* the leaf node name.
*/
static major_t
{
if (*parent == '/')
if (major != DDI_MAJOR_T_NONE)
return (major);
/* extract the name between '/' and '@' */
if (*parent == '/')
else
*tmp = '\0';
if (tmp)
*tmp = '@';
return (major);
}
/*
* Chain together specs whose parent's module name is the same.
*/
static void
{
/*
* If given a parent=/full-pathname, see if the platform
* can resolve the pathname to driver, otherwise, try
* the leaf node name.
*
* If parent=/full-pathname doesn't resolve to a driver,
* this could be cause by DR removal of the device.
* We put it on the major=-2 list in case the device
* is brought back into the system by DR.
*/
if (parent) {
if (maj == DDI_MAJOR_T_NONE) {
if ((*parent == '/') &&
} else {
"add_spec: No major number for %s",
parent);
return;
}
}
} else
/*
* Scan the list looking for a matching parent. When parent is
* not NULL, we match the parent by major. If parent is NULL but
* class is not NULL, we mache the pl by class name.
*/
return;
}
}
/*
* Didn't find a match on the list. Make a new parent list.
*/
return;
}
/* put "class=" entries last (lower pri if dups) */
if (maj == DDI_MAJOR_T_NONE) {
return;
}
/* ensure unresolved "parent=/full-path" goes first */
}
/*
* Add property spec to property list in original order
*/
static void
{
if (spec->hwc_devi_sys_prop_ptr) {
while (*props)
/* remove these properties from the spec */
}
}