subr_hints.c revision 79696
178135Speter/*-
278135Speter * Copyright (c) 2000,2001 Peter Wemm <peter@FreeBSD.org>
378135Speter * All rights reserved.
478135Speter *
578135Speter * Redistribution and use in source and binary forms, with or without
678135Speter * modification, are permitted provided that the following conditions
778135Speter * are met:
878135Speter * 1. Redistributions of source code must retain the above copyright
978135Speter *    notice, this list of conditions and the following disclaimer.
1078135Speter * 2. Redistributions in binary form must reproduce the above copyright
1178135Speter *    notice, this list of conditions and the following disclaimer in the
1278135Speter *    documentation and/or other materials provided with the distribution.
1378135Speter *
1478135Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1578135Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1678135Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1778135Speter * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1878135Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1978135Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2078135Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2178135Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2278135Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2378135Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2478135Speter * SUCH DAMAGE.
2578135Speter *
2678135Speter * $FreeBSD: head/sys/kern/subr_hints.c 79696 2001-07-14 00:23:10Z peter $
2778135Speter */
2878135Speter
2978135Speter#include <sys/param.h>
3078135Speter#include <sys/systm.h>
3178135Speter#include <sys/bus.h>
3278135Speter
3378135Speter/*
3478135Speter * Access functions for device resources.
3578135Speter */
3678135Speter
3778135Speterextern char static_hints[];		/* by config for now */
3879696Speterextern int hintmode;			/* 0 = off. 1 = config, 2 = fallback */
3979696Speterstatic char *hintp;
4078135Speter
4178135Speter/*
4278135Speter * Evil wildcarding resource string lookup.
4378135Speter * This walks the supplied env string table and returns a match.
4478135Speter * The start point can be remembered for incremental searches.
4578135Speter */
4678135Speterstatic int
4779696Speterres_find(int *line, int *startln,
4878135Speter    const char *name, int *unit, const char *resname, const char *value,
4978135Speter    const char **ret_name, int *ret_namelen, int *ret_unit,
5078135Speter    const char **ret_resname, int *ret_resnamelen, const char **ret_value)
5178135Speter{
5278135Speter	int n = 0, hit;
5378135Speter	char r_name[32];
5478135Speter	int r_unit;
5578135Speter	char r_resname[32];
5678135Speter	char r_value[128];
5779696Speter	const char *s, *cp;
5878135Speter	char *p;
5978135Speter
6079696Speter	if (hintp == NULL) {
6179696Speter		switch (hintmode) {
6279696Speter		case 0:		/* config supplied nothing */
6379696Speter			hintp = kern_envp;
6479696Speter			break;
6579696Speter		case 1:		/* static hints only */
6679696Speter			hintp = static_hints;
6779696Speter			break;
6879696Speter		case 2:		/* fallback mode */
6979696Speter			cp = kern_envp;
7079696Speter			while (cp) {
7179696Speter				if (strncmp(cp, "hint.", 5) == 0) {
7279696Speter					cp = NULL;
7379696Speter					hintp = kern_envp;
7479696Speter					break;
7579696Speter				}
7679696Speter				while (*cp != '\0')
7779696Speter					cp++;
7879696Speter				cp++;
7979696Speter				if (*cp == '\0') {
8079696Speter					cp = NULL;
8179696Speter					hintp = static_hints;
8279696Speter					break;
8379696Speter				}
8479696Speter			}
8579696Speter			break;
8679696Speter		default:
8779696Speter			break;
8879696Speter		}
8979696Speter		if (hintp == NULL)
9079696Speter			hintp = kern_envp;
9179696Speter	}
9279696Speter
9379696Speter	cp = hintp;
9478135Speter	while (cp) {
9578135Speter		hit = 1;
9678135Speter		(*line)++;
9778135Speter		if (strncmp(cp, "hint.", 5) != 0)
9878135Speter			hit = 0;
9978135Speter		else
10078135Speter			n = sscanf(cp, "hint.%32[^.].%d.%32[^=]=%128s",
10178135Speter			    r_name, &r_unit, r_resname, r_value);
10278135Speter		if (hit && n != 4) {
10378135Speter			printf("CONFIG: invalid hint '%s'\n", cp);
10478135Speter			/* XXX: abuse bogus index() declaration */
10578135Speter			p = index(cp, 'h');
10678135Speter			*p = 'H';
10778135Speter			hit = 0;
10878135Speter		}
10978135Speter		if (hit && startln && *startln >= 0 && *line < *startln)
11078135Speter			hit = 0;
11178135Speter		if (hit && name && strcmp(name, r_name) != 0)
11278135Speter			hit = 0;
11378135Speter		if (hit && unit && *unit != r_unit)
11478135Speter			hit = 0;
11578135Speter		if (hit && resname && strcmp(resname, r_resname) != 0)
11678135Speter			hit = 0;
11778135Speter		if (hit && value && strcmp(value, r_value) != 0)
11878135Speter			hit = 0;
11978135Speter		if (hit)
12078135Speter			break;
12178135Speter		while (*cp != '\0')
12278135Speter			cp++;
12378135Speter		cp++;
12478135Speter		if (*cp == '\0') {
12578135Speter			cp = NULL;
12678135Speter			break;
12778135Speter		}
12878135Speter	}
12978135Speter	if (cp == NULL)
13078135Speter		return ENOENT;
13178135Speter
13278135Speter	s = cp;
13378135Speter	/* This is a bit of a hack, but at least is reentrant */
13478135Speter	/* Note that it returns some !unterminated! strings. */
13578135Speter	s = index(s, '.') + 1;		/* start of device */
13678135Speter	if (ret_name)
13778135Speter		*ret_name = s;
13878135Speter	s = index(s, '.') + 1;		/* start of unit */
13978135Speter	if (ret_namelen)
14078135Speter		*ret_namelen = s - *ret_name - 1; /* device length */
14178135Speter	if (ret_unit)
14278135Speter		*ret_unit = r_unit;
14378135Speter	s = index(s, '.') + 1;		/* start of resname */
14478135Speter	if (ret_resname)
14578135Speter		*ret_resname = s;
14678135Speter	s = index(s, '=') + 1;		/* start of value */
14778135Speter	if (ret_resnamelen)
14878135Speter		*ret_resnamelen = s - *ret_resname - 1; /* value len */
14978135Speter	if (ret_value)
15078135Speter		*ret_value = s;
15178135Speter	if (startln)			/* line number for anchor */
15278135Speter		*startln = *line + 1;
15378135Speter	return 0;
15478135Speter}
15578135Speter
15678135Speter/*
15778135Speter * Search all the data sources for matches to our query.  We look for
15878135Speter * dynamic hints first as overrides for static or fallback hints.
15978135Speter */
16078135Speterstatic int
16178135Speterresource_find(int *line, int *startln,
16278135Speter    const char *name, int *unit, const char *resname, const char *value,
16378135Speter    const char **ret_name, int *ret_namelen, int *ret_unit,
16478135Speter    const char **ret_resname, int *ret_resnamelen, const char **ret_value)
16578135Speter{
16678135Speter	int i;
16778135Speter	int un;
16878135Speter
16978135Speter	*line = 0;
17078135Speter
17178135Speter	/* Search for exact unit matches first */
17279696Speter	i = res_find(line, startln, name, unit, resname, value,
17378135Speter	    ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen,
17478135Speter	    ret_value);
17578135Speter	if (i == 0)
17678135Speter		return 0;
17778135Speter	if (unit == NULL)
17878135Speter		return ENOENT;
17978135Speter	/* If we are still here, search for wildcard matches */
18078135Speter	un = -1;
18179696Speter	i = res_find(line, startln, name, &un, resname, value,
18278135Speter	    ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen,
18378135Speter	    ret_value);
18478135Speter	if (i == 0)
18578135Speter		return 0;
18678135Speter	return ENOENT;
18778135Speter}
18878135Speter
18978135Speterint
19078135Speterresource_int_value(const char *name, int unit, const char *resname, int *result)
19178135Speter{
19278135Speter	int error;
19378135Speter	const char *str;
19478135Speter	char *op;
19578135Speter	unsigned long val;
19678135Speter	int line;
19778135Speter
19878135Speter	line = 0;
19978135Speter	error = resource_find(&line, NULL, name, &unit, resname, NULL,
20078135Speter	    NULL, NULL, NULL, NULL, NULL, &str);
20178135Speter	if (error)
20278135Speter		return error;
20378135Speter	if (*str == '\0')
20478135Speter		return EFTYPE;
20578135Speter	val = strtoul(str, &op, 0);
20678135Speter	if (*op != '\0')
20778135Speter		return EFTYPE;
20878135Speter	*result = val;
20978135Speter	return 0;
21078135Speter}
21178135Speter
21278135Speterint
21378135Speterresource_long_value(const char *name, int unit, const char *resname,
21478135Speter    long *result)
21578135Speter{
21678135Speter	int error;
21778135Speter	const char *str;
21878135Speter	char *op;
21978135Speter	unsigned long val;
22078135Speter	int line;
22178135Speter
22278135Speter	line = 0;
22378135Speter	error = resource_find(&line, NULL, name, &unit, resname, NULL,
22478135Speter	    NULL, NULL, NULL, NULL, NULL, &str);
22578135Speter	if (error)
22678135Speter		return error;
22778135Speter	if (*str == '\0')
22878135Speter		return EFTYPE;
22978135Speter	val = strtoul(str, &op, 0);
23078135Speter	if (*op != '\0')
23178135Speter		return EFTYPE;
23278135Speter	*result = val;
23378135Speter	return 0;
23478135Speter}
23578135Speter
23678135Speterint
23778135Speterresource_string_value(const char *name, int unit, const char *resname,
23878135Speter    const char **result)
23978135Speter{
24078135Speter	int error;
24178135Speter	const char *str;
24278135Speter	int line;
24378135Speter
24478135Speter	line = 0;
24578135Speter	error = resource_find(&line, NULL, name, &unit, resname, NULL,
24678135Speter	    NULL, NULL, NULL, NULL, NULL, &str);
24778135Speter	if (error)
24878135Speter		return error;
24978135Speter	*result = str;
25078135Speter	return 0;
25178135Speter}
25278135Speter
25378135Speter/*
25478135Speter * This is a bit nasty, but allows us to not modify the env strings.
25578135Speter */
25678135Speterstatic const char *
25778135Speterresource_string_copy(const char *s, int len)
25878135Speter{
25978135Speter	static char stringbuf[256];
26078135Speter	static int offset = 0;
26178135Speter	const char *ret;
26278135Speter
26378135Speter	if (len == 0)
26478135Speter		len = strlen(s);
26578135Speter	if (len > 255)
26678135Speter		return NULL;
26778135Speter	if ((offset + len + 1) > 255)
26878135Speter		offset = 0;
26978135Speter	bcopy(s, &stringbuf[offset], len);
27078135Speter	stringbuf[offset + len] = '\0';
27178135Speter	ret = &stringbuf[offset];
27278135Speter	offset += len + 1;
27378135Speter	return ret;
27478135Speter}
27578135Speter
27678135Speter/*
27778135Speter * err = resource_find_at(&anchor, &name, &unit, resname, value)
27878135Speter * Iteratively fetch a list of devices wired "at" something
27978135Speter * res and value are restrictions.  eg: "at", "scbus0".
28078135Speter * For practical purposes, res = required, value = optional.
28178135Speter * *name and *unit are set.
28278135Speter * set *anchor to zero before starting.
28378135Speter */
28478135Speterint
28578135Speterresource_find_match(int *anchor, const char **name, int *unit,
28678135Speter    const char *resname, const char *value)
28778135Speter{
28878135Speter	const char *found_name;
28978135Speter	int found_namelen;
29078135Speter	int found_unit;
29178135Speter	int ret;
29278135Speter	int newln;
29378135Speter
29478135Speter	newln = *anchor;
29578135Speter	ret = resource_find(anchor, &newln, NULL, NULL, resname, value,
29678135Speter	    &found_name, &found_namelen, &found_unit, NULL, NULL, NULL);
29778135Speter	if (ret == 0) {
29878135Speter		*name = resource_string_copy(found_name, found_namelen);
29978135Speter		*unit = found_unit;
30078135Speter	}
30178135Speter	*anchor = newln;
30278135Speter	return ret;
30378135Speter}
30478135Speter
30578135Speter
30678135Speter/*
30778135Speter * err = resource_find_dev(&anchor, name, &unit, res, value);
30878135Speter * Iterate through a list of devices, returning their unit numbers.
30978135Speter * res and value are optional restrictions.  eg: "at", "scbus0".
31078135Speter * *unit is set to the value.
31178135Speter * set *anchor to zero before starting.
31278135Speter */
31378135Speterint
31478135Speterresource_find_dev(int *anchor, const char *name, int *unit,
31578135Speter    const char *resname, const char *value)
31678135Speter{
31778135Speter	int found_unit;
31878135Speter	int newln;
31978135Speter	int ret;
32078135Speter
32178135Speter	newln = *anchor;
32278135Speter	ret = resource_find(anchor, &newln, name, NULL, resname, value,
32378135Speter	    NULL, NULL, &found_unit, NULL, NULL, NULL);
32478135Speter	if (ret == 0) {
32578135Speter		*unit = found_unit;
32678135Speter	}
32778135Speter	*anchor = newln;
32878135Speter	return ret;
32978135Speter}
330