subr_hints.c revision 95592
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 95592 2002-04-27 22:25:13Z peter $
2778135Speter */
2878135Speter
2978135Speter#include <sys/param.h>
3094936Smux#include <sys/lock.h>
3194936Smux#include <sys/sx.h>
3278135Speter#include <sys/systm.h>
3378135Speter#include <sys/bus.h>
3478135Speter
3578135Speter/*
3678135Speter * Access functions for device resources.
3778135Speter */
3878135Speter
3994936Smuxstatic int checkmethod = 1;
4079696Speterstatic char *hintp;
4178135Speter
4278135Speter/*
4378135Speter * Evil wildcarding resource string lookup.
4478135Speter * This walks the supplied env string table and returns a match.
4578135Speter * The start point can be remembered for incremental searches.
4678135Speter */
4778135Speterstatic int
4879696Speterres_find(int *line, int *startln,
4978135Speter    const char *name, int *unit, const char *resname, const char *value,
5078135Speter    const char **ret_name, int *ret_namelen, int *ret_unit,
5178135Speter    const char **ret_resname, int *ret_resnamelen, const char **ret_value)
5278135Speter{
5394936Smux	int n = 0, hit, use_kenv, i = 0;
5478135Speter	char r_name[32];
5578135Speter	int r_unit;
5678135Speter	char r_resname[32];
5778135Speter	char r_value[128];
5879696Speter	const char *s, *cp;
5978135Speter	char *p;
6078135Speter
6194936Smux	use_kenv = 0;
6294936Smux	if (checkmethod) {
6379696Speter		switch (hintmode) {
6479696Speter		case 0:		/* config supplied nothing */
6579696Speter			break;
6679696Speter		case 1:		/* static hints only */
6779696Speter			hintp = static_hints;
6894936Smux			checkmethod = 0;
6979696Speter			break;
7079696Speter		case 2:		/* fallback mode */
7194936Smux			if (dynamic_kenv) {
7294936Smux				sx_slock(&kenv_lock);
7394936Smux				cp = kenvp[0];
7494936Smux				for (i = 0; cp != NULL; cp = kenvp[++i]) {
7594936Smux					if (!strncmp(cp, "hint.", 5)) {
7694936Smux						use_kenv = 1;
7794936Smux						checkmethod = 0;
7894936Smux						break;
7994936Smux					}
8079696Speter				}
8194936Smux				sx_sunlock(&kenv_lock);
8294936Smux			} else {
8394936Smux				cp = kern_envp;
8494936Smux				while (cp) {
8594936Smux					if (strncmp(cp, "hint.", 5) == 0) {
8694936Smux						cp = NULL;
8794936Smux						hintp = kern_envp;
8894936Smux						break;
8994936Smux					}
9094936Smux					while (*cp != '\0')
9194936Smux						cp++;
9279696Speter					cp++;
9394936Smux					if (*cp == '\0') {
9494936Smux						cp = NULL;
9594936Smux						hintp = static_hints;
9694936Smux						break;
9794936Smux					}
9879696Speter				}
9979696Speter			}
10079696Speter			break;
10179696Speter		default:
10279696Speter			break;
10379696Speter		}
10494936Smux		if (hintp == NULL) {
10594936Smux			if (dynamic_kenv) {
10694936Smux				use_kenv = 1;
10794936Smux				checkmethod = 0;
10894936Smux			} else
10994936Smux				hintp = kern_envp;
11094936Smux		}
11179696Speter	}
11279696Speter
11394936Smux	if (use_kenv) {
11494936Smux		sx_slock(&kenv_lock);
11594936Smux		i = 0;
11694936Smux		cp = kenvp[0];
11794936Smux		if (cp == NULL) {
11894936Smux			sx_sunlock(&kenv_lock);
11994936Smux			return (ENOENT);
12094936Smux		}
12194936Smux	} else {
12294936Smux		cp = hintp;
12394936Smux	}
12478135Speter	while (cp) {
12578135Speter		hit = 1;
12678135Speter		(*line)++;
12778135Speter		if (strncmp(cp, "hint.", 5) != 0)
12878135Speter			hit = 0;
12978135Speter		else
13078135Speter			n = sscanf(cp, "hint.%32[^.].%d.%32[^=]=%128s",
13178135Speter			    r_name, &r_unit, r_resname, r_value);
13278135Speter		if (hit && n != 4) {
13378135Speter			printf("CONFIG: invalid hint '%s'\n", cp);
13478135Speter			/* XXX: abuse bogus index() declaration */
13578135Speter			p = index(cp, 'h');
13678135Speter			*p = 'H';
13778135Speter			hit = 0;
13878135Speter		}
13978135Speter		if (hit && startln && *startln >= 0 && *line < *startln)
14078135Speter			hit = 0;
14178135Speter		if (hit && name && strcmp(name, r_name) != 0)
14278135Speter			hit = 0;
14378135Speter		if (hit && unit && *unit != r_unit)
14478135Speter			hit = 0;
14578135Speter		if (hit && resname && strcmp(resname, r_resname) != 0)
14678135Speter			hit = 0;
14778135Speter		if (hit && value && strcmp(value, r_value) != 0)
14878135Speter			hit = 0;
14978135Speter		if (hit)
15078135Speter			break;
15194936Smux		if (use_kenv)
15294936Smux			cp = kenvp[++i];
15395592Speter		else {
15495592Speter			while (*cp != '\0')
15595592Speter				cp++;
15678135Speter			cp++;
15795592Speter		}
15878135Speter		if (*cp == '\0') {
15978135Speter			cp = NULL;
16078135Speter			break;
16178135Speter		}
16278135Speter	}
16394936Smux	if (use_kenv)
16494936Smux		sx_sunlock(&kenv_lock);
16578135Speter	if (cp == NULL)
16678135Speter		return ENOENT;
16778135Speter
16878135Speter	s = cp;
16978135Speter	/* This is a bit of a hack, but at least is reentrant */
17078135Speter	/* Note that it returns some !unterminated! strings. */
17178135Speter	s = index(s, '.') + 1;		/* start of device */
17278135Speter	if (ret_name)
17378135Speter		*ret_name = s;
17478135Speter	s = index(s, '.') + 1;		/* start of unit */
17578135Speter	if (ret_namelen)
17678135Speter		*ret_namelen = s - *ret_name - 1; /* device length */
17778135Speter	if (ret_unit)
17878135Speter		*ret_unit = r_unit;
17978135Speter	s = index(s, '.') + 1;		/* start of resname */
18078135Speter	if (ret_resname)
18178135Speter		*ret_resname = s;
18278135Speter	s = index(s, '=') + 1;		/* start of value */
18378135Speter	if (ret_resnamelen)
18478135Speter		*ret_resnamelen = s - *ret_resname - 1; /* value len */
18578135Speter	if (ret_value)
18678135Speter		*ret_value = s;
18778135Speter	if (startln)			/* line number for anchor */
18878135Speter		*startln = *line + 1;
18978135Speter	return 0;
19078135Speter}
19178135Speter
19278135Speter/*
19378135Speter * Search all the data sources for matches to our query.  We look for
19478135Speter * dynamic hints first as overrides for static or fallback hints.
19578135Speter */
19678135Speterstatic int
19778135Speterresource_find(int *line, int *startln,
19878135Speter    const char *name, int *unit, const char *resname, const char *value,
19978135Speter    const char **ret_name, int *ret_namelen, int *ret_unit,
20078135Speter    const char **ret_resname, int *ret_resnamelen, const char **ret_value)
20178135Speter{
20278135Speter	int i;
20378135Speter	int un;
20478135Speter
20578135Speter	*line = 0;
20678135Speter
20778135Speter	/* Search for exact unit matches first */
20879696Speter	i = res_find(line, startln, name, unit, resname, value,
20978135Speter	    ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen,
21078135Speter	    ret_value);
21178135Speter	if (i == 0)
21278135Speter		return 0;
21378135Speter	if (unit == NULL)
21478135Speter		return ENOENT;
21578135Speter	/* If we are still here, search for wildcard matches */
21678135Speter	un = -1;
21779696Speter	i = res_find(line, startln, name, &un, resname, value,
21878135Speter	    ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen,
21978135Speter	    ret_value);
22078135Speter	if (i == 0)
22178135Speter		return 0;
22278135Speter	return ENOENT;
22378135Speter}
22478135Speter
22578135Speterint
22678135Speterresource_int_value(const char *name, int unit, const char *resname, int *result)
22778135Speter{
22878135Speter	int error;
22978135Speter	const char *str;
23078135Speter	char *op;
23178135Speter	unsigned long val;
23278135Speter	int line;
23378135Speter
23478135Speter	line = 0;
23578135Speter	error = resource_find(&line, NULL, name, &unit, resname, NULL,
23678135Speter	    NULL, NULL, NULL, NULL, NULL, &str);
23778135Speter	if (error)
23878135Speter		return error;
23978135Speter	if (*str == '\0')
24078135Speter		return EFTYPE;
24178135Speter	val = strtoul(str, &op, 0);
24278135Speter	if (*op != '\0')
24378135Speter		return EFTYPE;
24478135Speter	*result = val;
24578135Speter	return 0;
24678135Speter}
24778135Speter
24878135Speterint
24978135Speterresource_long_value(const char *name, int unit, const char *resname,
25078135Speter    long *result)
25178135Speter{
25278135Speter	int error;
25378135Speter	const char *str;
25478135Speter	char *op;
25578135Speter	unsigned long val;
25678135Speter	int line;
25778135Speter
25878135Speter	line = 0;
25978135Speter	error = resource_find(&line, NULL, name, &unit, resname, NULL,
26078135Speter	    NULL, NULL, NULL, NULL, NULL, &str);
26178135Speter	if (error)
26278135Speter		return error;
26378135Speter	if (*str == '\0')
26478135Speter		return EFTYPE;
26578135Speter	val = strtoul(str, &op, 0);
26678135Speter	if (*op != '\0')
26778135Speter		return EFTYPE;
26878135Speter	*result = val;
26978135Speter	return 0;
27078135Speter}
27178135Speter
27278135Speterint
27378135Speterresource_string_value(const char *name, int unit, const char *resname,
27478135Speter    const char **result)
27578135Speter{
27678135Speter	int error;
27778135Speter	const char *str;
27878135Speter	int line;
27978135Speter
28078135Speter	line = 0;
28178135Speter	error = resource_find(&line, NULL, name, &unit, resname, NULL,
28278135Speter	    NULL, NULL, NULL, NULL, NULL, &str);
28378135Speter	if (error)
28478135Speter		return error;
28578135Speter	*result = str;
28678135Speter	return 0;
28778135Speter}
28878135Speter
28978135Speter/*
29078135Speter * This is a bit nasty, but allows us to not modify the env strings.
29178135Speter */
29278135Speterstatic const char *
29378135Speterresource_string_copy(const char *s, int len)
29478135Speter{
29578135Speter	static char stringbuf[256];
29678135Speter	static int offset = 0;
29778135Speter	const char *ret;
29878135Speter
29978135Speter	if (len == 0)
30078135Speter		len = strlen(s);
30178135Speter	if (len > 255)
30278135Speter		return NULL;
30378135Speter	if ((offset + len + 1) > 255)
30478135Speter		offset = 0;
30578135Speter	bcopy(s, &stringbuf[offset], len);
30678135Speter	stringbuf[offset + len] = '\0';
30778135Speter	ret = &stringbuf[offset];
30878135Speter	offset += len + 1;
30978135Speter	return ret;
31078135Speter}
31178135Speter
31278135Speter/*
31378135Speter * err = resource_find_at(&anchor, &name, &unit, resname, value)
31478135Speter * Iteratively fetch a list of devices wired "at" something
31578135Speter * res and value are restrictions.  eg: "at", "scbus0".
31678135Speter * For practical purposes, res = required, value = optional.
31778135Speter * *name and *unit are set.
31878135Speter * set *anchor to zero before starting.
31978135Speter */
32078135Speterint
32178135Speterresource_find_match(int *anchor, const char **name, int *unit,
32278135Speter    const char *resname, const char *value)
32378135Speter{
32478135Speter	const char *found_name;
32578135Speter	int found_namelen;
32678135Speter	int found_unit;
32778135Speter	int ret;
32878135Speter	int newln;
32978135Speter
33078135Speter	newln = *anchor;
33178135Speter	ret = resource_find(anchor, &newln, NULL, NULL, resname, value,
33278135Speter	    &found_name, &found_namelen, &found_unit, NULL, NULL, NULL);
33378135Speter	if (ret == 0) {
33478135Speter		*name = resource_string_copy(found_name, found_namelen);
33578135Speter		*unit = found_unit;
33678135Speter	}
33778135Speter	*anchor = newln;
33878135Speter	return ret;
33978135Speter}
34078135Speter
34178135Speter
34278135Speter/*
34378135Speter * err = resource_find_dev(&anchor, name, &unit, res, value);
34478135Speter * Iterate through a list of devices, returning their unit numbers.
34578135Speter * res and value are optional restrictions.  eg: "at", "scbus0".
34678135Speter * *unit is set to the value.
34778135Speter * set *anchor to zero before starting.
34878135Speter */
34978135Speterint
35078135Speterresource_find_dev(int *anchor, const char *name, int *unit,
35178135Speter    const char *resname, const char *value)
35278135Speter{
35378135Speter	int found_unit;
35478135Speter	int newln;
35578135Speter	int ret;
35678135Speter
35778135Speter	newln = *anchor;
35878135Speter	ret = resource_find(anchor, &newln, name, NULL, resname, value,
35978135Speter	    NULL, NULL, &found_unit, NULL, NULL, NULL);
36078135Speter	if (ret == 0) {
36178135Speter		*unit = found_unit;
36278135Speter	}
36378135Speter	*anchor = newln;
36478135Speter	return ret;
36578135Speter}
366