xref: /freebsd/sys/kern/subr_hints.c (revision 770488d2026afd1b21c921be2c2100c12229ce0a)
12398f0cdSPeter Wemm /*-
28a36da99SPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
38a36da99SPedro F. Giffuni  *
42398f0cdSPeter Wemm  * Copyright (c) 2000,2001 Peter Wemm <peter@FreeBSD.org>
52398f0cdSPeter Wemm  * All rights reserved.
62398f0cdSPeter Wemm  *
72398f0cdSPeter Wemm  * Redistribution and use in source and binary forms, with or without
82398f0cdSPeter Wemm  * modification, are permitted provided that the following conditions
92398f0cdSPeter Wemm  * are met:
102398f0cdSPeter Wemm  * 1. Redistributions of source code must retain the above copyright
112398f0cdSPeter Wemm  *    notice, this list of conditions and the following disclaimer.
122398f0cdSPeter Wemm  * 2. Redistributions in binary form must reproduce the above copyright
132398f0cdSPeter Wemm  *    notice, this list of conditions and the following disclaimer in the
142398f0cdSPeter Wemm  *    documentation and/or other materials provided with the distribution.
152398f0cdSPeter Wemm  *
162398f0cdSPeter Wemm  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
172398f0cdSPeter Wemm  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
182398f0cdSPeter Wemm  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
192398f0cdSPeter Wemm  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
202398f0cdSPeter Wemm  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
212398f0cdSPeter Wemm  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
222398f0cdSPeter Wemm  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
232398f0cdSPeter Wemm  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
242398f0cdSPeter Wemm  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
252398f0cdSPeter Wemm  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
262398f0cdSPeter Wemm  * SUCH DAMAGE.
272398f0cdSPeter Wemm  */
282398f0cdSPeter Wemm 
29677b542eSDavid E. O'Brien #include <sys/cdefs.h>
30677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$");
31677b542eSDavid E. O'Brien 
322398f0cdSPeter Wemm #include <sys/param.h>
33d786139cSMaxime Henrion #include <sys/lock.h>
3470da14c4SAleksandr Rybalko #include <sys/malloc.h>
35e3546a75SScott Long #include <sys/mutex.h>
3670da14c4SAleksandr Rybalko #include <sys/sysctl.h>
371bccd863SAleksandr Rybalko #include <sys/systm.h>
382398f0cdSPeter Wemm #include <sys/bus.h>
392398f0cdSPeter Wemm 
40*770488d2SKyle Evans #define	HINTMODE_KENV		0
41*770488d2SKyle Evans #define	HINTMODE_STATIC		1
42*770488d2SKyle Evans #define	HINTMODE_FALLBACK	2
43*770488d2SKyle Evans 
442398f0cdSPeter Wemm /*
452398f0cdSPeter Wemm  * Access functions for device resources.
462398f0cdSPeter Wemm  */
472398f0cdSPeter Wemm 
48d786139cSMaxime Henrion static int checkmethod = 1;
499516fbd6SPeter Wemm static char *hintp;
502398f0cdSPeter Wemm 
512398f0cdSPeter Wemm /*
5270da14c4SAleksandr Rybalko  * Define kern.hintmode sysctl, which only accept value 2, that cause to
5370da14c4SAleksandr Rybalko  * switch from Static KENV mode to Dynamic KENV. So systems that have hints
5470da14c4SAleksandr Rybalko  * compiled into kernel will be able to see/modify KENV (and hints too).
5570da14c4SAleksandr Rybalko  */
5670da14c4SAleksandr Rybalko 
5770da14c4SAleksandr Rybalko static int
5870da14c4SAleksandr Rybalko sysctl_hintmode(SYSCTL_HANDLER_ARGS)
5970da14c4SAleksandr Rybalko {
6070da14c4SAleksandr Rybalko 	const char *cp;
6170da14c4SAleksandr Rybalko 	char *line, *eq;
62*770488d2SKyle Evans 	int eqidx, error, i, value;
6370da14c4SAleksandr Rybalko 
6470da14c4SAleksandr Rybalko 	value = hintmode;
6570da14c4SAleksandr Rybalko 
6670da14c4SAleksandr Rybalko 	/* Fetch candidate for new hintmode value */
6770da14c4SAleksandr Rybalko 	error = sysctl_handle_int(oidp, &value, 0, req);
681bccd863SAleksandr Rybalko 	if (error || req->newptr == NULL)
6970da14c4SAleksandr Rybalko 		return (error);
7070da14c4SAleksandr Rybalko 
71*770488d2SKyle Evans 	if (value != HINTMODE_FALLBACK)
7270da14c4SAleksandr Rybalko 		/* Only accept swithing to hintmode 2 */
7370da14c4SAleksandr Rybalko 		return (EINVAL);
7470da14c4SAleksandr Rybalko 
751bccd863SAleksandr Rybalko 	/*
76*770488d2SKyle Evans 	 * The rest of the sysctl handler is just making sure that our
77*770488d2SKyle Evans 	 * environment is consistent with the world we've already seen.
78*770488d2SKyle Evans 	 * If we came from kenv at all, then we have nothing to do: static
79*770488d2SKyle Evans 	 * kenv will get merged into dynamic kenv as soon as kmem becomes
80*770488d2SKyle Evans 	 * available, dynamic kenv is the environment we'd be setting these
81*770488d2SKyle Evans 	 * things in anyways. Therefore, we have nothing left to do unless
82*770488d2SKyle Evans 	 * we came from a static hints configuration.
831bccd863SAleksandr Rybalko 	 */
84*770488d2SKyle Evans 	if (hintmode != HINTMODE_STATIC) {
85*770488d2SKyle Evans 		hintmode = value;
8670da14c4SAleksandr Rybalko 		return (0);
8770da14c4SAleksandr Rybalko 	}
8870da14c4SAleksandr Rybalko 
89*770488d2SKyle Evans 	cp = static_hints;
90*770488d2SKyle Evans 	while (cp && *cp != '\0') {
9170da14c4SAleksandr Rybalko 		eq = strchr(cp, '=');
921bccd863SAleksandr Rybalko 		if (eq == NULL)
9370da14c4SAleksandr Rybalko 			/* Bad hint value */
9470da14c4SAleksandr Rybalko 			continue;
9570da14c4SAleksandr Rybalko 		eqidx = eq - cp;
9670da14c4SAleksandr Rybalko 
97*770488d2SKyle Evans 		i = strlen(cp);
9870da14c4SAleksandr Rybalko 		line = malloc(i+1, M_TEMP, M_WAITOK);
9970da14c4SAleksandr Rybalko 		strcpy(line, cp);
10070da14c4SAleksandr Rybalko 		line[eqidx] = '\0';
1012be111bfSDavide Italiano 		kern_setenv(line, line + eqidx + 1);
10270da14c4SAleksandr Rybalko 		free(line, M_TEMP);
10370da14c4SAleksandr Rybalko 		cp += i + 1;
10470da14c4SAleksandr Rybalko 	}
10570da14c4SAleksandr Rybalko 
10670da14c4SAleksandr Rybalko 	hintmode = value;
10770da14c4SAleksandr Rybalko 	return (0);
10870da14c4SAleksandr Rybalko }
10970da14c4SAleksandr Rybalko 
11070da14c4SAleksandr Rybalko SYSCTL_PROC(_kern, OID_AUTO, hintmode, CTLTYPE_INT|CTLFLAG_RW,
11170da14c4SAleksandr Rybalko     &hintmode, 0, sysctl_hintmode, "I", "Get/set current hintmode");
11270da14c4SAleksandr Rybalko 
11370da14c4SAleksandr Rybalko /*
1142398f0cdSPeter Wemm  * Evil wildcarding resource string lookup.
1152398f0cdSPeter Wemm  * This walks the supplied env string table and returns a match.
1162398f0cdSPeter Wemm  * The start point can be remembered for incremental searches.
1172398f0cdSPeter Wemm  */
1182398f0cdSPeter Wemm static int
1199516fbd6SPeter Wemm res_find(int *line, int *startln,
1202398f0cdSPeter Wemm     const char *name, int *unit, const char *resname, const char *value,
1212398f0cdSPeter Wemm     const char **ret_name, int *ret_namelen, int *ret_unit,
1222398f0cdSPeter Wemm     const char **ret_resname, int *ret_resnamelen, const char **ret_value)
1232398f0cdSPeter Wemm {
1244f033348SPeter Wemm 	int n = 0, hit, i = 0;
1252398f0cdSPeter Wemm 	char r_name[32];
126*770488d2SKyle Evans 	int r_unit, use_kenv = (hintmode == HINTMODE_FALLBACK);
1272398f0cdSPeter Wemm 	char r_resname[32];
1282398f0cdSPeter Wemm 	char r_value[128];
1299516fbd6SPeter Wemm 	const char *s, *cp;
1302398f0cdSPeter Wemm 	char *p;
1312398f0cdSPeter Wemm 
132d786139cSMaxime Henrion 	if (checkmethod) {
13332069af6SAlexander Leidinger 		hintp = NULL;
13432069af6SAlexander Leidinger 
1359516fbd6SPeter Wemm 		switch (hintmode) {
136*770488d2SKyle Evans 		case HINTMODE_KENV:	/* loader hints in environment only */
1379516fbd6SPeter Wemm 			break;
138*770488d2SKyle Evans 		case HINTMODE_STATIC:	/* static hints only */
1399516fbd6SPeter Wemm 			hintp = static_hints;
140d786139cSMaxime Henrion 			checkmethod = 0;
1419516fbd6SPeter Wemm 			break;
142*770488d2SKyle Evans 		case HINTMODE_FALLBACK:		/* fallback mode */
143d786139cSMaxime Henrion 			if (dynamic_kenv) {
144e3546a75SScott Long 				mtx_lock(&kenv_lock);
145d786139cSMaxime Henrion 				cp = kenvp[0];
146d786139cSMaxime Henrion 				for (i = 0; cp != NULL; cp = kenvp[++i]) {
147d786139cSMaxime Henrion 					if (!strncmp(cp, "hint.", 5)) {
148d786139cSMaxime Henrion 						use_kenv = 1;
149d786139cSMaxime Henrion 						checkmethod = 0;
150d786139cSMaxime Henrion 						break;
151d786139cSMaxime Henrion 					}
152d786139cSMaxime Henrion 				}
153e3546a75SScott Long 				mtx_unlock(&kenv_lock);
154d786139cSMaxime Henrion 			} else {
1559516fbd6SPeter Wemm 				cp = kern_envp;
1569516fbd6SPeter Wemm 				while (cp) {
1579516fbd6SPeter Wemm 					if (strncmp(cp, "hint.", 5) == 0) {
1589516fbd6SPeter Wemm 						cp = NULL;
1599516fbd6SPeter Wemm 						hintp = kern_envp;
1609516fbd6SPeter Wemm 						break;
1619516fbd6SPeter Wemm 					}
1629516fbd6SPeter Wemm 					while (*cp != '\0')
1639516fbd6SPeter Wemm 						cp++;
1649516fbd6SPeter Wemm 					cp++;
1659516fbd6SPeter Wemm 					if (*cp == '\0') {
1669516fbd6SPeter Wemm 						cp = NULL;
1679516fbd6SPeter Wemm 						hintp = static_hints;
1689516fbd6SPeter Wemm 						break;
1699516fbd6SPeter Wemm 					}
1709516fbd6SPeter Wemm 				}
171d786139cSMaxime Henrion 			}
1729516fbd6SPeter Wemm 			break;
1739516fbd6SPeter Wemm 		default:
1749516fbd6SPeter Wemm 			break;
1759516fbd6SPeter Wemm 		}
176d786139cSMaxime Henrion 		if (hintp == NULL) {
177d786139cSMaxime Henrion 			if (dynamic_kenv) {
178d786139cSMaxime Henrion 				use_kenv = 1;
179d786139cSMaxime Henrion 				checkmethod = 0;
180d786139cSMaxime Henrion 			} else
1819516fbd6SPeter Wemm 				hintp = kern_envp;
1829516fbd6SPeter Wemm 		}
183d786139cSMaxime Henrion 	}
1849516fbd6SPeter Wemm 
185d786139cSMaxime Henrion 	if (use_kenv) {
186e3546a75SScott Long 		mtx_lock(&kenv_lock);
187d786139cSMaxime Henrion 		i = 0;
188d786139cSMaxime Henrion 		cp = kenvp[0];
189d786139cSMaxime Henrion 		if (cp == NULL) {
190e3546a75SScott Long 			mtx_unlock(&kenv_lock);
191d786139cSMaxime Henrion 			return (ENOENT);
192d786139cSMaxime Henrion 		}
1936692ac66SPeter Wemm 	} else
1949516fbd6SPeter Wemm 		cp = hintp;
1952398f0cdSPeter Wemm 	while (cp) {
1962398f0cdSPeter Wemm 		hit = 1;
1972398f0cdSPeter Wemm 		(*line)++;
1982398f0cdSPeter Wemm 		if (strncmp(cp, "hint.", 5) != 0)
1992398f0cdSPeter Wemm 			hit = 0;
2002398f0cdSPeter Wemm 		else
20154bb5530SSergey Kandaurov 			n = sscanf(cp, "hint.%32[^.].%d.%32[^=]=%127s",
2022398f0cdSPeter Wemm 			    r_name, &r_unit, r_resname, r_value);
2032398f0cdSPeter Wemm 		if (hit && n != 4) {
2042398f0cdSPeter Wemm 			printf("CONFIG: invalid hint '%s'\n", cp);
205dc15eac0SEd Schouten 			p = strchr(cp, 'h');
2062398f0cdSPeter Wemm 			*p = 'H';
2072398f0cdSPeter Wemm 			hit = 0;
2082398f0cdSPeter Wemm 		}
2092398f0cdSPeter Wemm 		if (hit && startln && *startln >= 0 && *line < *startln)
2102398f0cdSPeter Wemm 			hit = 0;
2112398f0cdSPeter Wemm 		if (hit && name && strcmp(name, r_name) != 0)
2122398f0cdSPeter Wemm 			hit = 0;
2132398f0cdSPeter Wemm 		if (hit && unit && *unit != r_unit)
2142398f0cdSPeter Wemm 			hit = 0;
2152398f0cdSPeter Wemm 		if (hit && resname && strcmp(resname, r_resname) != 0)
2162398f0cdSPeter Wemm 			hit = 0;
2172398f0cdSPeter Wemm 		if (hit && value && strcmp(value, r_value) != 0)
2182398f0cdSPeter Wemm 			hit = 0;
2192398f0cdSPeter Wemm 		if (hit)
2202398f0cdSPeter Wemm 			break;
2214f033348SPeter Wemm 		if (use_kenv) {
222d786139cSMaxime Henrion 			cp = kenvp[++i];
2234f033348SPeter Wemm 			if (cp == NULL)
2244f033348SPeter Wemm 				break;
2254f033348SPeter Wemm 		} else {
2262398f0cdSPeter Wemm 			while (*cp != '\0')
2272398f0cdSPeter Wemm 				cp++;
2282398f0cdSPeter Wemm 			cp++;
2292398f0cdSPeter Wemm 			if (*cp == '\0') {
2302398f0cdSPeter Wemm 				cp = NULL;
2312398f0cdSPeter Wemm 				break;
2322398f0cdSPeter Wemm 			}
2332398f0cdSPeter Wemm 		}
2344f033348SPeter Wemm 	}
235d786139cSMaxime Henrion 	if (use_kenv)
236e3546a75SScott Long 		mtx_unlock(&kenv_lock);
2372398f0cdSPeter Wemm 	if (cp == NULL)
2382398f0cdSPeter Wemm 		return ENOENT;
2392398f0cdSPeter Wemm 
2402398f0cdSPeter Wemm 	s = cp;
2412398f0cdSPeter Wemm 	/* This is a bit of a hack, but at least is reentrant */
2422398f0cdSPeter Wemm 	/* Note that it returns some !unterminated! strings. */
243dc15eac0SEd Schouten 	s = strchr(s, '.') + 1;		/* start of device */
2442398f0cdSPeter Wemm 	if (ret_name)
2452398f0cdSPeter Wemm 		*ret_name = s;
246dc15eac0SEd Schouten 	s = strchr(s, '.') + 1;		/* start of unit */
24785c36f3dSJohn Baldwin 	if (ret_namelen && ret_name)
2482398f0cdSPeter Wemm 		*ret_namelen = s - *ret_name - 1; /* device length */
2492398f0cdSPeter Wemm 	if (ret_unit)
2502398f0cdSPeter Wemm 		*ret_unit = r_unit;
251dc15eac0SEd Schouten 	s = strchr(s, '.') + 1;		/* start of resname */
2522398f0cdSPeter Wemm 	if (ret_resname)
2532398f0cdSPeter Wemm 		*ret_resname = s;
254dc15eac0SEd Schouten 	s = strchr(s, '=') + 1;		/* start of value */
25585c36f3dSJohn Baldwin 	if (ret_resnamelen && ret_resname)
2562398f0cdSPeter Wemm 		*ret_resnamelen = s - *ret_resname - 1; /* value len */
2572398f0cdSPeter Wemm 	if (ret_value)
2582398f0cdSPeter Wemm 		*ret_value = s;
2592398f0cdSPeter Wemm 	if (startln)			/* line number for anchor */
2602398f0cdSPeter Wemm 		*startln = *line + 1;
2612398f0cdSPeter Wemm 	return 0;
2622398f0cdSPeter Wemm }
2632398f0cdSPeter Wemm 
2642398f0cdSPeter Wemm /*
2652398f0cdSPeter Wemm  * Search all the data sources for matches to our query.  We look for
2662398f0cdSPeter Wemm  * dynamic hints first as overrides for static or fallback hints.
2672398f0cdSPeter Wemm  */
2682398f0cdSPeter Wemm static int
2692398f0cdSPeter Wemm resource_find(int *line, int *startln,
2702398f0cdSPeter Wemm     const char *name, int *unit, const char *resname, const char *value,
2712398f0cdSPeter Wemm     const char **ret_name, int *ret_namelen, int *ret_unit,
2722398f0cdSPeter Wemm     const char **ret_resname, int *ret_resnamelen, const char **ret_value)
2732398f0cdSPeter Wemm {
2742398f0cdSPeter Wemm 	int i;
2752398f0cdSPeter Wemm 	int un;
2762398f0cdSPeter Wemm 
2772398f0cdSPeter Wemm 	*line = 0;
2782398f0cdSPeter Wemm 
2792398f0cdSPeter Wemm 	/* Search for exact unit matches first */
2809516fbd6SPeter Wemm 	i = res_find(line, startln, name, unit, resname, value,
2812398f0cdSPeter Wemm 	    ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen,
2822398f0cdSPeter Wemm 	    ret_value);
2832398f0cdSPeter Wemm 	if (i == 0)
2842398f0cdSPeter Wemm 		return 0;
2852398f0cdSPeter Wemm 	if (unit == NULL)
2862398f0cdSPeter Wemm 		return ENOENT;
2872398f0cdSPeter Wemm 	/* If we are still here, search for wildcard matches */
2882398f0cdSPeter Wemm 	un = -1;
2899516fbd6SPeter Wemm 	i = res_find(line, startln, name, &un, resname, value,
2902398f0cdSPeter Wemm 	    ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen,
2912398f0cdSPeter Wemm 	    ret_value);
2922398f0cdSPeter Wemm 	if (i == 0)
2932398f0cdSPeter Wemm 		return 0;
2942398f0cdSPeter Wemm 	return ENOENT;
2952398f0cdSPeter Wemm }
2962398f0cdSPeter Wemm 
2972398f0cdSPeter Wemm int
2982398f0cdSPeter Wemm resource_int_value(const char *name, int unit, const char *resname, int *result)
2992398f0cdSPeter Wemm {
3002398f0cdSPeter Wemm 	int error;
3012398f0cdSPeter Wemm 	const char *str;
3022398f0cdSPeter Wemm 	char *op;
3032398f0cdSPeter Wemm 	unsigned long val;
3042398f0cdSPeter Wemm 	int line;
3052398f0cdSPeter Wemm 
3062398f0cdSPeter Wemm 	line = 0;
3072398f0cdSPeter Wemm 	error = resource_find(&line, NULL, name, &unit, resname, NULL,
3082398f0cdSPeter Wemm 	    NULL, NULL, NULL, NULL, NULL, &str);
3092398f0cdSPeter Wemm 	if (error)
3102398f0cdSPeter Wemm 		return error;
3112398f0cdSPeter Wemm 	if (*str == '\0')
3122398f0cdSPeter Wemm 		return EFTYPE;
3132398f0cdSPeter Wemm 	val = strtoul(str, &op, 0);
3142398f0cdSPeter Wemm 	if (*op != '\0')
3152398f0cdSPeter Wemm 		return EFTYPE;
3162398f0cdSPeter Wemm 	*result = val;
3172398f0cdSPeter Wemm 	return 0;
3182398f0cdSPeter Wemm }
3192398f0cdSPeter Wemm 
3202398f0cdSPeter Wemm int
3212398f0cdSPeter Wemm resource_long_value(const char *name, int unit, const char *resname,
3222398f0cdSPeter Wemm     long *result)
3232398f0cdSPeter Wemm {
3242398f0cdSPeter Wemm 	int error;
3252398f0cdSPeter Wemm 	const char *str;
3262398f0cdSPeter Wemm 	char *op;
3272398f0cdSPeter Wemm 	unsigned long val;
3282398f0cdSPeter Wemm 	int line;
3292398f0cdSPeter Wemm 
3302398f0cdSPeter Wemm 	line = 0;
3312398f0cdSPeter Wemm 	error = resource_find(&line, NULL, name, &unit, resname, NULL,
3322398f0cdSPeter Wemm 	    NULL, NULL, NULL, NULL, NULL, &str);
3332398f0cdSPeter Wemm 	if (error)
3342398f0cdSPeter Wemm 		return error;
3352398f0cdSPeter Wemm 	if (*str == '\0')
3362398f0cdSPeter Wemm 		return EFTYPE;
3372398f0cdSPeter Wemm 	val = strtoul(str, &op, 0);
3382398f0cdSPeter Wemm 	if (*op != '\0')
3392398f0cdSPeter Wemm 		return EFTYPE;
3402398f0cdSPeter Wemm 	*result = val;
3412398f0cdSPeter Wemm 	return 0;
3422398f0cdSPeter Wemm }
3432398f0cdSPeter Wemm 
3442398f0cdSPeter Wemm int
3452398f0cdSPeter Wemm resource_string_value(const char *name, int unit, const char *resname,
3462398f0cdSPeter Wemm     const char **result)
3472398f0cdSPeter Wemm {
3482398f0cdSPeter Wemm 	int error;
3492398f0cdSPeter Wemm 	const char *str;
3502398f0cdSPeter Wemm 	int line;
3512398f0cdSPeter Wemm 
3522398f0cdSPeter Wemm 	line = 0;
3532398f0cdSPeter Wemm 	error = resource_find(&line, NULL, name, &unit, resname, NULL,
3542398f0cdSPeter Wemm 	    NULL, NULL, NULL, NULL, NULL, &str);
3552398f0cdSPeter Wemm 	if (error)
3562398f0cdSPeter Wemm 		return error;
3572398f0cdSPeter Wemm 	*result = str;
3582398f0cdSPeter Wemm 	return 0;
3592398f0cdSPeter Wemm }
3602398f0cdSPeter Wemm 
3612398f0cdSPeter Wemm /*
3622398f0cdSPeter Wemm  * This is a bit nasty, but allows us to not modify the env strings.
3632398f0cdSPeter Wemm  */
3642398f0cdSPeter Wemm static const char *
3652398f0cdSPeter Wemm resource_string_copy(const char *s, int len)
3662398f0cdSPeter Wemm {
3672398f0cdSPeter Wemm 	static char stringbuf[256];
3682398f0cdSPeter Wemm 	static int offset = 0;
3692398f0cdSPeter Wemm 	const char *ret;
3702398f0cdSPeter Wemm 
3712398f0cdSPeter Wemm 	if (len == 0)
3722398f0cdSPeter Wemm 		len = strlen(s);
3732398f0cdSPeter Wemm 	if (len > 255)
3742398f0cdSPeter Wemm 		return NULL;
3752398f0cdSPeter Wemm 	if ((offset + len + 1) > 255)
3762398f0cdSPeter Wemm 		offset = 0;
3772398f0cdSPeter Wemm 	bcopy(s, &stringbuf[offset], len);
3782398f0cdSPeter Wemm 	stringbuf[offset + len] = '\0';
3792398f0cdSPeter Wemm 	ret = &stringbuf[offset];
3802398f0cdSPeter Wemm 	offset += len + 1;
3812398f0cdSPeter Wemm 	return ret;
3822398f0cdSPeter Wemm }
3832398f0cdSPeter Wemm 
3842398f0cdSPeter Wemm /*
38574e62047SJohn-Mark Gurney  * err = resource_find_match(&anchor, &name, &unit, resname, value)
3862398f0cdSPeter Wemm  * Iteratively fetch a list of devices wired "at" something
3872398f0cdSPeter Wemm  * res and value are restrictions.  eg: "at", "scbus0".
3882398f0cdSPeter Wemm  * For practical purposes, res = required, value = optional.
3892398f0cdSPeter Wemm  * *name and *unit are set.
3902398f0cdSPeter Wemm  * set *anchor to zero before starting.
3912398f0cdSPeter Wemm  */
3922398f0cdSPeter Wemm int
3932398f0cdSPeter Wemm resource_find_match(int *anchor, const char **name, int *unit,
3942398f0cdSPeter Wemm     const char *resname, const char *value)
3952398f0cdSPeter Wemm {
3962398f0cdSPeter Wemm 	const char *found_name;
3972398f0cdSPeter Wemm 	int found_namelen;
3982398f0cdSPeter Wemm 	int found_unit;
3992398f0cdSPeter Wemm 	int ret;
4002398f0cdSPeter Wemm 	int newln;
4012398f0cdSPeter Wemm 
4022398f0cdSPeter Wemm 	newln = *anchor;
4032398f0cdSPeter Wemm 	ret = resource_find(anchor, &newln, NULL, NULL, resname, value,
4042398f0cdSPeter Wemm 	    &found_name, &found_namelen, &found_unit, NULL, NULL, NULL);
4052398f0cdSPeter Wemm 	if (ret == 0) {
4062398f0cdSPeter Wemm 		*name = resource_string_copy(found_name, found_namelen);
4072398f0cdSPeter Wemm 		*unit = found_unit;
4082398f0cdSPeter Wemm 	}
4092398f0cdSPeter Wemm 	*anchor = newln;
4102398f0cdSPeter Wemm 	return ret;
4112398f0cdSPeter Wemm }
4122398f0cdSPeter Wemm 
4132398f0cdSPeter Wemm 
4142398f0cdSPeter Wemm /*
4152398f0cdSPeter Wemm  * err = resource_find_dev(&anchor, name, &unit, res, value);
4162398f0cdSPeter Wemm  * Iterate through a list of devices, returning their unit numbers.
4172398f0cdSPeter Wemm  * res and value are optional restrictions.  eg: "at", "scbus0".
4182398f0cdSPeter Wemm  * *unit is set to the value.
4192398f0cdSPeter Wemm  * set *anchor to zero before starting.
4202398f0cdSPeter Wemm  */
4212398f0cdSPeter Wemm int
4222398f0cdSPeter Wemm resource_find_dev(int *anchor, const char *name, int *unit,
4232398f0cdSPeter Wemm     const char *resname, const char *value)
4242398f0cdSPeter Wemm {
4252398f0cdSPeter Wemm 	int found_unit;
4262398f0cdSPeter Wemm 	int newln;
4272398f0cdSPeter Wemm 	int ret;
4282398f0cdSPeter Wemm 
4292398f0cdSPeter Wemm 	newln = *anchor;
4302398f0cdSPeter Wemm 	ret = resource_find(anchor, &newln, name, NULL, resname, value,
4312398f0cdSPeter Wemm 	    NULL, NULL, &found_unit, NULL, NULL, NULL);
4322398f0cdSPeter Wemm 	if (ret == 0) {
4332398f0cdSPeter Wemm 		*unit = found_unit;
4342398f0cdSPeter Wemm 	}
4352398f0cdSPeter Wemm 	*anchor = newln;
4362398f0cdSPeter Wemm 	return ret;
4372398f0cdSPeter Wemm }
4386591b310SJohn Baldwin 
4396591b310SJohn Baldwin /*
4406591b310SJohn Baldwin  * Check to see if a device is disabled via a disabled hint.
4416591b310SJohn Baldwin  */
4426591b310SJohn Baldwin int
4436591b310SJohn Baldwin resource_disabled(const char *name, int unit)
4446591b310SJohn Baldwin {
4456591b310SJohn Baldwin 	int error, value;
4466591b310SJohn Baldwin 
4476591b310SJohn Baldwin 	error = resource_int_value(name, unit, "disabled", &value);
4486591b310SJohn Baldwin 	if (error)
4496591b310SJohn Baldwin 	       return (0);
4506591b310SJohn Baldwin 	return (value);
4516591b310SJohn Baldwin }
45264de8019SJohn Baldwin 
45364de8019SJohn Baldwin /*
45464de8019SJohn Baldwin  * Clear a value associated with a device by removing it from
45564de8019SJohn Baldwin  * the kernel environment.  This only removes a hint for an
45664de8019SJohn Baldwin  * exact unit.
45764de8019SJohn Baldwin  */
45864de8019SJohn Baldwin int
45964de8019SJohn Baldwin resource_unset_value(const char *name, int unit, const char *resname)
46064de8019SJohn Baldwin {
46164de8019SJohn Baldwin 	char varname[128];
46264de8019SJohn Baldwin 	const char *retname, *retvalue;
46364de8019SJohn Baldwin 	int error, line;
46464de8019SJohn Baldwin 	size_t len;
46564de8019SJohn Baldwin 
46664de8019SJohn Baldwin 	line = 0;
46764de8019SJohn Baldwin 	error = resource_find(&line, NULL, name, &unit, resname, NULL,
46864de8019SJohn Baldwin 	    &retname, NULL, NULL, NULL, NULL, &retvalue);
46964de8019SJohn Baldwin 	if (error)
47064de8019SJohn Baldwin 		return (error);
47164de8019SJohn Baldwin 
47264de8019SJohn Baldwin 	retname -= strlen("hint.");
47364de8019SJohn Baldwin 	len = retvalue - retname - 1;
47464de8019SJohn Baldwin 	if (len > sizeof(varname) - 1)
47564de8019SJohn Baldwin 		return (ENAMETOOLONG);
47664de8019SJohn Baldwin 	memcpy(varname, retname, len);
47764de8019SJohn Baldwin 	varname[len] = '\0';
47864de8019SJohn Baldwin 	return (kern_unsetenv(varname));
47964de8019SJohn Baldwin }
480