xref: /freebsd/sys/kern/subr_hints.c (revision 64de80195bba295c961a4cdf96dbe0e4979bdf2a)
12398f0cdSPeter Wemm /*-
22398f0cdSPeter Wemm  * Copyright (c) 2000,2001 Peter Wemm <peter@FreeBSD.org>
32398f0cdSPeter Wemm  * All rights reserved.
42398f0cdSPeter Wemm  *
52398f0cdSPeter Wemm  * Redistribution and use in source and binary forms, with or without
62398f0cdSPeter Wemm  * modification, are permitted provided that the following conditions
72398f0cdSPeter Wemm  * are met:
82398f0cdSPeter Wemm  * 1. Redistributions of source code must retain the above copyright
92398f0cdSPeter Wemm  *    notice, this list of conditions and the following disclaimer.
102398f0cdSPeter Wemm  * 2. Redistributions in binary form must reproduce the above copyright
112398f0cdSPeter Wemm  *    notice, this list of conditions and the following disclaimer in the
122398f0cdSPeter Wemm  *    documentation and/or other materials provided with the distribution.
132398f0cdSPeter Wemm  *
142398f0cdSPeter Wemm  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
152398f0cdSPeter Wemm  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
162398f0cdSPeter Wemm  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
172398f0cdSPeter Wemm  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
182398f0cdSPeter Wemm  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
192398f0cdSPeter Wemm  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
202398f0cdSPeter Wemm  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
212398f0cdSPeter Wemm  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
222398f0cdSPeter Wemm  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
232398f0cdSPeter Wemm  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
242398f0cdSPeter Wemm  * SUCH DAMAGE.
252398f0cdSPeter Wemm  */
262398f0cdSPeter Wemm 
27677b542eSDavid E. O'Brien #include <sys/cdefs.h>
28677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$");
29677b542eSDavid E. O'Brien 
302398f0cdSPeter Wemm #include <sys/param.h>
31d786139cSMaxime Henrion #include <sys/lock.h>
3270da14c4SAleksandr Rybalko #include <sys/malloc.h>
33e3546a75SScott Long #include <sys/mutex.h>
3470da14c4SAleksandr Rybalko #include <sys/sysctl.h>
351bccd863SAleksandr Rybalko #include <sys/systm.h>
362398f0cdSPeter Wemm #include <sys/bus.h>
372398f0cdSPeter Wemm 
382398f0cdSPeter Wemm /*
392398f0cdSPeter Wemm  * Access functions for device resources.
402398f0cdSPeter Wemm  */
412398f0cdSPeter Wemm 
42d786139cSMaxime Henrion static int checkmethod = 1;
434f033348SPeter Wemm static int use_kenv;
449516fbd6SPeter Wemm static char *hintp;
452398f0cdSPeter Wemm 
462398f0cdSPeter Wemm /*
4770da14c4SAleksandr Rybalko  * Define kern.hintmode sysctl, which only accept value 2, that cause to
4870da14c4SAleksandr Rybalko  * switch from Static KENV mode to Dynamic KENV. So systems that have hints
4970da14c4SAleksandr Rybalko  * compiled into kernel will be able to see/modify KENV (and hints too).
5070da14c4SAleksandr Rybalko  */
5170da14c4SAleksandr Rybalko 
5270da14c4SAleksandr Rybalko static int
5370da14c4SAleksandr Rybalko sysctl_hintmode(SYSCTL_HANDLER_ARGS)
5470da14c4SAleksandr Rybalko {
5570da14c4SAleksandr Rybalko 	const char *cp;
5670da14c4SAleksandr Rybalko 	char *line, *eq;
571bccd863SAleksandr Rybalko 	int eqidx, error, from_kenv, i, value;
5870da14c4SAleksandr Rybalko 
5970da14c4SAleksandr Rybalko 	from_kenv = 0;
6070da14c4SAleksandr Rybalko 	cp = kern_envp;
6170da14c4SAleksandr Rybalko 	value = hintmode;
6270da14c4SAleksandr Rybalko 
6370da14c4SAleksandr Rybalko 	/* Fetch candidate for new hintmode value */
6470da14c4SAleksandr Rybalko 	error = sysctl_handle_int(oidp, &value, 0, req);
651bccd863SAleksandr Rybalko 	if (error || req->newptr == NULL)
6670da14c4SAleksandr Rybalko 		return (error);
6770da14c4SAleksandr Rybalko 
6870da14c4SAleksandr Rybalko 	if (value != 2)
6970da14c4SAleksandr Rybalko 		/* Only accept swithing to hintmode 2 */
7070da14c4SAleksandr Rybalko 		return (EINVAL);
7170da14c4SAleksandr Rybalko 
7270da14c4SAleksandr Rybalko 	/* Migrate from static to dynamic hints */
7370da14c4SAleksandr Rybalko 	switch (hintmode) {
7470da14c4SAleksandr Rybalko 	case 0:
756a8dada2SAleksandr Rybalko 		if (dynamic_kenv) {
761bccd863SAleksandr Rybalko 			/*
771bccd863SAleksandr Rybalko 			 * Already here. But assign hintmode to 2, to not
781bccd863SAleksandr Rybalko 			 * check it in the future.
791bccd863SAleksandr Rybalko 			 */
801bccd863SAleksandr Rybalko 			hintmode = 2;
8170da14c4SAleksandr Rybalko 			return (0);
826a8dada2SAleksandr Rybalko 		}
8370da14c4SAleksandr Rybalko 		from_kenv = 1;
8470da14c4SAleksandr Rybalko 		cp = kern_envp;
8570da14c4SAleksandr Rybalko 		break;
8670da14c4SAleksandr Rybalko 	case 1:
8770da14c4SAleksandr Rybalko 		cp = static_hints;
8870da14c4SAleksandr Rybalko 		break;
8970da14c4SAleksandr Rybalko 	case 2:
9070da14c4SAleksandr Rybalko 		/* Nothing to do, hintmode already 2 */
9170da14c4SAleksandr Rybalko 		return (0);
9270da14c4SAleksandr Rybalko 	}
9370da14c4SAleksandr Rybalko 
9470da14c4SAleksandr Rybalko 	while (cp) {
9570da14c4SAleksandr Rybalko 		i = strlen(cp);
9670da14c4SAleksandr Rybalko 		if (i == 0)
9770da14c4SAleksandr Rybalko 			break;
9870da14c4SAleksandr Rybalko 		if (from_kenv) {
9970da14c4SAleksandr Rybalko 			if (strncmp(cp, "hint.", 5) != 0)
10070da14c4SAleksandr Rybalko 				/* kenv can have not only hints */
10170da14c4SAleksandr Rybalko 				continue;
10270da14c4SAleksandr Rybalko 		}
10370da14c4SAleksandr Rybalko 		eq = strchr(cp, '=');
1041bccd863SAleksandr Rybalko 		if (eq == NULL)
10570da14c4SAleksandr Rybalko 			/* Bad hint value */
10670da14c4SAleksandr Rybalko 			continue;
10770da14c4SAleksandr Rybalko 		eqidx = eq - cp;
10870da14c4SAleksandr Rybalko 
10970da14c4SAleksandr Rybalko 		line = malloc(i+1, M_TEMP, M_WAITOK);
11070da14c4SAleksandr Rybalko 		strcpy(line, cp);
11170da14c4SAleksandr Rybalko 		line[eqidx] = '\0';
1122be111bfSDavide Italiano 		kern_setenv(line, line + eqidx + 1);
11370da14c4SAleksandr Rybalko 		free(line, M_TEMP);
11470da14c4SAleksandr Rybalko 		cp += i + 1;
11570da14c4SAleksandr Rybalko 	}
11670da14c4SAleksandr Rybalko 
11770da14c4SAleksandr Rybalko 	hintmode = value;
11870da14c4SAleksandr Rybalko 	use_kenv = 1;
11970da14c4SAleksandr Rybalko 	return (0);
12070da14c4SAleksandr Rybalko }
12170da14c4SAleksandr Rybalko 
12270da14c4SAleksandr Rybalko SYSCTL_PROC(_kern, OID_AUTO, hintmode, CTLTYPE_INT|CTLFLAG_RW,
12370da14c4SAleksandr Rybalko     &hintmode, 0, sysctl_hintmode, "I", "Get/set current hintmode");
12470da14c4SAleksandr Rybalko 
12570da14c4SAleksandr Rybalko /*
1262398f0cdSPeter Wemm  * Evil wildcarding resource string lookup.
1272398f0cdSPeter Wemm  * This walks the supplied env string table and returns a match.
1282398f0cdSPeter Wemm  * The start point can be remembered for incremental searches.
1292398f0cdSPeter Wemm  */
1302398f0cdSPeter Wemm static int
1319516fbd6SPeter Wemm res_find(int *line, int *startln,
1322398f0cdSPeter Wemm     const char *name, int *unit, const char *resname, const char *value,
1332398f0cdSPeter Wemm     const char **ret_name, int *ret_namelen, int *ret_unit,
1342398f0cdSPeter Wemm     const char **ret_resname, int *ret_resnamelen, const char **ret_value)
1352398f0cdSPeter Wemm {
1364f033348SPeter Wemm 	int n = 0, hit, i = 0;
1372398f0cdSPeter Wemm 	char r_name[32];
1382398f0cdSPeter Wemm 	int r_unit;
1392398f0cdSPeter Wemm 	char r_resname[32];
1402398f0cdSPeter Wemm 	char r_value[128];
1419516fbd6SPeter Wemm 	const char *s, *cp;
1422398f0cdSPeter Wemm 	char *p;
1432398f0cdSPeter Wemm 
144d786139cSMaxime Henrion 	if (checkmethod) {
14532069af6SAlexander Leidinger 		hintp = NULL;
14632069af6SAlexander Leidinger 
1479516fbd6SPeter Wemm 		switch (hintmode) {
1486692ac66SPeter Wemm 		case 0:		/* loader hints in environment only */
1499516fbd6SPeter Wemm 			break;
1509516fbd6SPeter Wemm 		case 1:		/* static hints only */
1519516fbd6SPeter Wemm 			hintp = static_hints;
152d786139cSMaxime Henrion 			checkmethod = 0;
1539516fbd6SPeter Wemm 			break;
1549516fbd6SPeter Wemm 		case 2:		/* fallback mode */
155d786139cSMaxime Henrion 			if (dynamic_kenv) {
156e3546a75SScott Long 				mtx_lock(&kenv_lock);
157d786139cSMaxime Henrion 				cp = kenvp[0];
158d786139cSMaxime Henrion 				for (i = 0; cp != NULL; cp = kenvp[++i]) {
159d786139cSMaxime Henrion 					if (!strncmp(cp, "hint.", 5)) {
160d786139cSMaxime Henrion 						use_kenv = 1;
161d786139cSMaxime Henrion 						checkmethod = 0;
162d786139cSMaxime Henrion 						break;
163d786139cSMaxime Henrion 					}
164d786139cSMaxime Henrion 				}
165e3546a75SScott Long 				mtx_unlock(&kenv_lock);
166d786139cSMaxime Henrion 			} else {
1679516fbd6SPeter Wemm 				cp = kern_envp;
1689516fbd6SPeter Wemm 				while (cp) {
1699516fbd6SPeter Wemm 					if (strncmp(cp, "hint.", 5) == 0) {
1709516fbd6SPeter Wemm 						cp = NULL;
1719516fbd6SPeter Wemm 						hintp = kern_envp;
1729516fbd6SPeter Wemm 						break;
1739516fbd6SPeter Wemm 					}
1749516fbd6SPeter Wemm 					while (*cp != '\0')
1759516fbd6SPeter Wemm 						cp++;
1769516fbd6SPeter Wemm 					cp++;
1779516fbd6SPeter Wemm 					if (*cp == '\0') {
1789516fbd6SPeter Wemm 						cp = NULL;
1799516fbd6SPeter Wemm 						hintp = static_hints;
1809516fbd6SPeter Wemm 						break;
1819516fbd6SPeter Wemm 					}
1829516fbd6SPeter Wemm 				}
183d786139cSMaxime Henrion 			}
1849516fbd6SPeter Wemm 			break;
1859516fbd6SPeter Wemm 		default:
1869516fbd6SPeter Wemm 			break;
1879516fbd6SPeter Wemm 		}
188d786139cSMaxime Henrion 		if (hintp == NULL) {
189d786139cSMaxime Henrion 			if (dynamic_kenv) {
190d786139cSMaxime Henrion 				use_kenv = 1;
191d786139cSMaxime Henrion 				checkmethod = 0;
192d786139cSMaxime Henrion 			} else
1939516fbd6SPeter Wemm 				hintp = kern_envp;
1949516fbd6SPeter Wemm 		}
195d786139cSMaxime Henrion 	}
1969516fbd6SPeter Wemm 
197d786139cSMaxime Henrion 	if (use_kenv) {
198e3546a75SScott Long 		mtx_lock(&kenv_lock);
199d786139cSMaxime Henrion 		i = 0;
200d786139cSMaxime Henrion 		cp = kenvp[0];
201d786139cSMaxime Henrion 		if (cp == NULL) {
202e3546a75SScott Long 			mtx_unlock(&kenv_lock);
203d786139cSMaxime Henrion 			return (ENOENT);
204d786139cSMaxime Henrion 		}
2056692ac66SPeter Wemm 	} else
2069516fbd6SPeter Wemm 		cp = hintp;
2072398f0cdSPeter Wemm 	while (cp) {
2082398f0cdSPeter Wemm 		hit = 1;
2092398f0cdSPeter Wemm 		(*line)++;
2102398f0cdSPeter Wemm 		if (strncmp(cp, "hint.", 5) != 0)
2112398f0cdSPeter Wemm 			hit = 0;
2122398f0cdSPeter Wemm 		else
21354bb5530SSergey Kandaurov 			n = sscanf(cp, "hint.%32[^.].%d.%32[^=]=%127s",
2142398f0cdSPeter Wemm 			    r_name, &r_unit, r_resname, r_value);
2152398f0cdSPeter Wemm 		if (hit && n != 4) {
2162398f0cdSPeter Wemm 			printf("CONFIG: invalid hint '%s'\n", cp);
217dc15eac0SEd Schouten 			p = strchr(cp, 'h');
2182398f0cdSPeter Wemm 			*p = 'H';
2192398f0cdSPeter Wemm 			hit = 0;
2202398f0cdSPeter Wemm 		}
2212398f0cdSPeter Wemm 		if (hit && startln && *startln >= 0 && *line < *startln)
2222398f0cdSPeter Wemm 			hit = 0;
2232398f0cdSPeter Wemm 		if (hit && name && strcmp(name, r_name) != 0)
2242398f0cdSPeter Wemm 			hit = 0;
2252398f0cdSPeter Wemm 		if (hit && unit && *unit != r_unit)
2262398f0cdSPeter Wemm 			hit = 0;
2272398f0cdSPeter Wemm 		if (hit && resname && strcmp(resname, r_resname) != 0)
2282398f0cdSPeter Wemm 			hit = 0;
2292398f0cdSPeter Wemm 		if (hit && value && strcmp(value, r_value) != 0)
2302398f0cdSPeter Wemm 			hit = 0;
2312398f0cdSPeter Wemm 		if (hit)
2322398f0cdSPeter Wemm 			break;
2334f033348SPeter Wemm 		if (use_kenv) {
234d786139cSMaxime Henrion 			cp = kenvp[++i];
2354f033348SPeter Wemm 			if (cp == NULL)
2364f033348SPeter Wemm 				break;
2374f033348SPeter Wemm 		} else {
2382398f0cdSPeter Wemm 			while (*cp != '\0')
2392398f0cdSPeter Wemm 				cp++;
2402398f0cdSPeter Wemm 			cp++;
2412398f0cdSPeter Wemm 			if (*cp == '\0') {
2422398f0cdSPeter Wemm 				cp = NULL;
2432398f0cdSPeter Wemm 				break;
2442398f0cdSPeter Wemm 			}
2452398f0cdSPeter Wemm 		}
2464f033348SPeter Wemm 	}
247d786139cSMaxime Henrion 	if (use_kenv)
248e3546a75SScott Long 		mtx_unlock(&kenv_lock);
2492398f0cdSPeter Wemm 	if (cp == NULL)
2502398f0cdSPeter Wemm 		return ENOENT;
2512398f0cdSPeter Wemm 
2522398f0cdSPeter Wemm 	s = cp;
2532398f0cdSPeter Wemm 	/* This is a bit of a hack, but at least is reentrant */
2542398f0cdSPeter Wemm 	/* Note that it returns some !unterminated! strings. */
255dc15eac0SEd Schouten 	s = strchr(s, '.') + 1;		/* start of device */
2562398f0cdSPeter Wemm 	if (ret_name)
2572398f0cdSPeter Wemm 		*ret_name = s;
258dc15eac0SEd Schouten 	s = strchr(s, '.') + 1;		/* start of unit */
25985c36f3dSJohn Baldwin 	if (ret_namelen && ret_name)
2602398f0cdSPeter Wemm 		*ret_namelen = s - *ret_name - 1; /* device length */
2612398f0cdSPeter Wemm 	if (ret_unit)
2622398f0cdSPeter Wemm 		*ret_unit = r_unit;
263dc15eac0SEd Schouten 	s = strchr(s, '.') + 1;		/* start of resname */
2642398f0cdSPeter Wemm 	if (ret_resname)
2652398f0cdSPeter Wemm 		*ret_resname = s;
266dc15eac0SEd Schouten 	s = strchr(s, '=') + 1;		/* start of value */
26785c36f3dSJohn Baldwin 	if (ret_resnamelen && ret_resname)
2682398f0cdSPeter Wemm 		*ret_resnamelen = s - *ret_resname - 1; /* value len */
2692398f0cdSPeter Wemm 	if (ret_value)
2702398f0cdSPeter Wemm 		*ret_value = s;
2712398f0cdSPeter Wemm 	if (startln)			/* line number for anchor */
2722398f0cdSPeter Wemm 		*startln = *line + 1;
2732398f0cdSPeter Wemm 	return 0;
2742398f0cdSPeter Wemm }
2752398f0cdSPeter Wemm 
2762398f0cdSPeter Wemm /*
2772398f0cdSPeter Wemm  * Search all the data sources for matches to our query.  We look for
2782398f0cdSPeter Wemm  * dynamic hints first as overrides for static or fallback hints.
2792398f0cdSPeter Wemm  */
2802398f0cdSPeter Wemm static int
2812398f0cdSPeter Wemm resource_find(int *line, int *startln,
2822398f0cdSPeter Wemm     const char *name, int *unit, const char *resname, const char *value,
2832398f0cdSPeter Wemm     const char **ret_name, int *ret_namelen, int *ret_unit,
2842398f0cdSPeter Wemm     const char **ret_resname, int *ret_resnamelen, const char **ret_value)
2852398f0cdSPeter Wemm {
2862398f0cdSPeter Wemm 	int i;
2872398f0cdSPeter Wemm 	int un;
2882398f0cdSPeter Wemm 
2892398f0cdSPeter Wemm 	*line = 0;
2902398f0cdSPeter Wemm 
2912398f0cdSPeter Wemm 	/* Search for exact unit matches first */
2929516fbd6SPeter Wemm 	i = res_find(line, startln, name, unit, resname, value,
2932398f0cdSPeter Wemm 	    ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen,
2942398f0cdSPeter Wemm 	    ret_value);
2952398f0cdSPeter Wemm 	if (i == 0)
2962398f0cdSPeter Wemm 		return 0;
2972398f0cdSPeter Wemm 	if (unit == NULL)
2982398f0cdSPeter Wemm 		return ENOENT;
2992398f0cdSPeter Wemm 	/* If we are still here, search for wildcard matches */
3002398f0cdSPeter Wemm 	un = -1;
3019516fbd6SPeter Wemm 	i = res_find(line, startln, name, &un, resname, value,
3022398f0cdSPeter Wemm 	    ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen,
3032398f0cdSPeter Wemm 	    ret_value);
3042398f0cdSPeter Wemm 	if (i == 0)
3052398f0cdSPeter Wemm 		return 0;
3062398f0cdSPeter Wemm 	return ENOENT;
3072398f0cdSPeter Wemm }
3082398f0cdSPeter Wemm 
3092398f0cdSPeter Wemm int
3102398f0cdSPeter Wemm resource_int_value(const char *name, int unit, const char *resname, int *result)
3112398f0cdSPeter Wemm {
3122398f0cdSPeter Wemm 	int error;
3132398f0cdSPeter Wemm 	const char *str;
3142398f0cdSPeter Wemm 	char *op;
3152398f0cdSPeter Wemm 	unsigned long val;
3162398f0cdSPeter Wemm 	int line;
3172398f0cdSPeter Wemm 
3182398f0cdSPeter Wemm 	line = 0;
3192398f0cdSPeter Wemm 	error = resource_find(&line, NULL, name, &unit, resname, NULL,
3202398f0cdSPeter Wemm 	    NULL, NULL, NULL, NULL, NULL, &str);
3212398f0cdSPeter Wemm 	if (error)
3222398f0cdSPeter Wemm 		return error;
3232398f0cdSPeter Wemm 	if (*str == '\0')
3242398f0cdSPeter Wemm 		return EFTYPE;
3252398f0cdSPeter Wemm 	val = strtoul(str, &op, 0);
3262398f0cdSPeter Wemm 	if (*op != '\0')
3272398f0cdSPeter Wemm 		return EFTYPE;
3282398f0cdSPeter Wemm 	*result = val;
3292398f0cdSPeter Wemm 	return 0;
3302398f0cdSPeter Wemm }
3312398f0cdSPeter Wemm 
3322398f0cdSPeter Wemm int
3332398f0cdSPeter Wemm resource_long_value(const char *name, int unit, const char *resname,
3342398f0cdSPeter Wemm     long *result)
3352398f0cdSPeter Wemm {
3362398f0cdSPeter Wemm 	int error;
3372398f0cdSPeter Wemm 	const char *str;
3382398f0cdSPeter Wemm 	char *op;
3392398f0cdSPeter Wemm 	unsigned long val;
3402398f0cdSPeter Wemm 	int line;
3412398f0cdSPeter Wemm 
3422398f0cdSPeter Wemm 	line = 0;
3432398f0cdSPeter Wemm 	error = resource_find(&line, NULL, name, &unit, resname, NULL,
3442398f0cdSPeter Wemm 	    NULL, NULL, NULL, NULL, NULL, &str);
3452398f0cdSPeter Wemm 	if (error)
3462398f0cdSPeter Wemm 		return error;
3472398f0cdSPeter Wemm 	if (*str == '\0')
3482398f0cdSPeter Wemm 		return EFTYPE;
3492398f0cdSPeter Wemm 	val = strtoul(str, &op, 0);
3502398f0cdSPeter Wemm 	if (*op != '\0')
3512398f0cdSPeter Wemm 		return EFTYPE;
3522398f0cdSPeter Wemm 	*result = val;
3532398f0cdSPeter Wemm 	return 0;
3542398f0cdSPeter Wemm }
3552398f0cdSPeter Wemm 
3562398f0cdSPeter Wemm int
3572398f0cdSPeter Wemm resource_string_value(const char *name, int unit, const char *resname,
3582398f0cdSPeter Wemm     const char **result)
3592398f0cdSPeter Wemm {
3602398f0cdSPeter Wemm 	int error;
3612398f0cdSPeter Wemm 	const char *str;
3622398f0cdSPeter Wemm 	int line;
3632398f0cdSPeter Wemm 
3642398f0cdSPeter Wemm 	line = 0;
3652398f0cdSPeter Wemm 	error = resource_find(&line, NULL, name, &unit, resname, NULL,
3662398f0cdSPeter Wemm 	    NULL, NULL, NULL, NULL, NULL, &str);
3672398f0cdSPeter Wemm 	if (error)
3682398f0cdSPeter Wemm 		return error;
3692398f0cdSPeter Wemm 	*result = str;
3702398f0cdSPeter Wemm 	return 0;
3712398f0cdSPeter Wemm }
3722398f0cdSPeter Wemm 
3732398f0cdSPeter Wemm /*
3742398f0cdSPeter Wemm  * This is a bit nasty, but allows us to not modify the env strings.
3752398f0cdSPeter Wemm  */
3762398f0cdSPeter Wemm static const char *
3772398f0cdSPeter Wemm resource_string_copy(const char *s, int len)
3782398f0cdSPeter Wemm {
3792398f0cdSPeter Wemm 	static char stringbuf[256];
3802398f0cdSPeter Wemm 	static int offset = 0;
3812398f0cdSPeter Wemm 	const char *ret;
3822398f0cdSPeter Wemm 
3832398f0cdSPeter Wemm 	if (len == 0)
3842398f0cdSPeter Wemm 		len = strlen(s);
3852398f0cdSPeter Wemm 	if (len > 255)
3862398f0cdSPeter Wemm 		return NULL;
3872398f0cdSPeter Wemm 	if ((offset + len + 1) > 255)
3882398f0cdSPeter Wemm 		offset = 0;
3892398f0cdSPeter Wemm 	bcopy(s, &stringbuf[offset], len);
3902398f0cdSPeter Wemm 	stringbuf[offset + len] = '\0';
3912398f0cdSPeter Wemm 	ret = &stringbuf[offset];
3922398f0cdSPeter Wemm 	offset += len + 1;
3932398f0cdSPeter Wemm 	return ret;
3942398f0cdSPeter Wemm }
3952398f0cdSPeter Wemm 
3962398f0cdSPeter Wemm /*
39774e62047SJohn-Mark Gurney  * err = resource_find_match(&anchor, &name, &unit, resname, value)
3982398f0cdSPeter Wemm  * Iteratively fetch a list of devices wired "at" something
3992398f0cdSPeter Wemm  * res and value are restrictions.  eg: "at", "scbus0".
4002398f0cdSPeter Wemm  * For practical purposes, res = required, value = optional.
4012398f0cdSPeter Wemm  * *name and *unit are set.
4022398f0cdSPeter Wemm  * set *anchor to zero before starting.
4032398f0cdSPeter Wemm  */
4042398f0cdSPeter Wemm int
4052398f0cdSPeter Wemm resource_find_match(int *anchor, const char **name, int *unit,
4062398f0cdSPeter Wemm     const char *resname, const char *value)
4072398f0cdSPeter Wemm {
4082398f0cdSPeter Wemm 	const char *found_name;
4092398f0cdSPeter Wemm 	int found_namelen;
4102398f0cdSPeter Wemm 	int found_unit;
4112398f0cdSPeter Wemm 	int ret;
4122398f0cdSPeter Wemm 	int newln;
4132398f0cdSPeter Wemm 
4142398f0cdSPeter Wemm 	newln = *anchor;
4152398f0cdSPeter Wemm 	ret = resource_find(anchor, &newln, NULL, NULL, resname, value,
4162398f0cdSPeter Wemm 	    &found_name, &found_namelen, &found_unit, NULL, NULL, NULL);
4172398f0cdSPeter Wemm 	if (ret == 0) {
4182398f0cdSPeter Wemm 		*name = resource_string_copy(found_name, found_namelen);
4192398f0cdSPeter Wemm 		*unit = found_unit;
4202398f0cdSPeter Wemm 	}
4212398f0cdSPeter Wemm 	*anchor = newln;
4222398f0cdSPeter Wemm 	return ret;
4232398f0cdSPeter Wemm }
4242398f0cdSPeter Wemm 
4252398f0cdSPeter Wemm 
4262398f0cdSPeter Wemm /*
4272398f0cdSPeter Wemm  * err = resource_find_dev(&anchor, name, &unit, res, value);
4282398f0cdSPeter Wemm  * Iterate through a list of devices, returning their unit numbers.
4292398f0cdSPeter Wemm  * res and value are optional restrictions.  eg: "at", "scbus0".
4302398f0cdSPeter Wemm  * *unit is set to the value.
4312398f0cdSPeter Wemm  * set *anchor to zero before starting.
4322398f0cdSPeter Wemm  */
4332398f0cdSPeter Wemm int
4342398f0cdSPeter Wemm resource_find_dev(int *anchor, const char *name, int *unit,
4352398f0cdSPeter Wemm     const char *resname, const char *value)
4362398f0cdSPeter Wemm {
4372398f0cdSPeter Wemm 	int found_unit;
4382398f0cdSPeter Wemm 	int newln;
4392398f0cdSPeter Wemm 	int ret;
4402398f0cdSPeter Wemm 
4412398f0cdSPeter Wemm 	newln = *anchor;
4422398f0cdSPeter Wemm 	ret = resource_find(anchor, &newln, name, NULL, resname, value,
4432398f0cdSPeter Wemm 	    NULL, NULL, &found_unit, NULL, NULL, NULL);
4442398f0cdSPeter Wemm 	if (ret == 0) {
4452398f0cdSPeter Wemm 		*unit = found_unit;
4462398f0cdSPeter Wemm 	}
4472398f0cdSPeter Wemm 	*anchor = newln;
4482398f0cdSPeter Wemm 	return ret;
4492398f0cdSPeter Wemm }
4506591b310SJohn Baldwin 
4516591b310SJohn Baldwin /*
4526591b310SJohn Baldwin  * Check to see if a device is disabled via a disabled hint.
4536591b310SJohn Baldwin  */
4546591b310SJohn Baldwin int
4556591b310SJohn Baldwin resource_disabled(const char *name, int unit)
4566591b310SJohn Baldwin {
4576591b310SJohn Baldwin 	int error, value;
4586591b310SJohn Baldwin 
4596591b310SJohn Baldwin 	error = resource_int_value(name, unit, "disabled", &value);
4606591b310SJohn Baldwin 	if (error)
4616591b310SJohn Baldwin 	       return (0);
4626591b310SJohn Baldwin 	return (value);
4636591b310SJohn Baldwin }
464*64de8019SJohn Baldwin 
465*64de8019SJohn Baldwin /*
466*64de8019SJohn Baldwin  * Clear a value associated with a device by removing it from
467*64de8019SJohn Baldwin  * the kernel environment.  This only removes a hint for an
468*64de8019SJohn Baldwin  * exact unit.
469*64de8019SJohn Baldwin  */
470*64de8019SJohn Baldwin int
471*64de8019SJohn Baldwin resource_unset_value(const char *name, int unit, const char *resname)
472*64de8019SJohn Baldwin {
473*64de8019SJohn Baldwin 	char varname[128];
474*64de8019SJohn Baldwin 	const char *retname, *retvalue;
475*64de8019SJohn Baldwin 	int error, line;
476*64de8019SJohn Baldwin 	size_t len;
477*64de8019SJohn Baldwin 
478*64de8019SJohn Baldwin 	line = 0;
479*64de8019SJohn Baldwin 	error = resource_find(&line, NULL, name, &unit, resname, NULL,
480*64de8019SJohn Baldwin 	    &retname, NULL, NULL, NULL, NULL, &retvalue);
481*64de8019SJohn Baldwin 	if (error)
482*64de8019SJohn Baldwin 		return (error);
483*64de8019SJohn Baldwin 
484*64de8019SJohn Baldwin 	retname -= strlen("hint.");
485*64de8019SJohn Baldwin 	len = retvalue - retname - 1;
486*64de8019SJohn Baldwin 	if (len > sizeof(varname) - 1)
487*64de8019SJohn Baldwin 		return (ENAMETOOLONG);
488*64de8019SJohn Baldwin 	memcpy(varname, retname, len);
489*64de8019SJohn Baldwin 	varname[len] = '\0';
490*64de8019SJohn Baldwin 	return (kern_unsetenv(varname));
491*64de8019SJohn Baldwin }
492