FreeBSD/Linux Kernel Cross Reference
sys/kern/subr_hints.c
1 /*-
2 * Copyright (c) 2000,2001 Peter Wemm <peter@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: releng/5.1/sys/kern/subr_hints.c 95839 2002-05-01 02:51:50Z peter $
27 */
28
29 #include <sys/param.h>
30 #include <sys/lock.h>
31 #include <sys/sx.h>
32 #include <sys/systm.h>
33 #include <sys/bus.h>
34
35 /*
36 * Access functions for device resources.
37 */
38
39 static int checkmethod = 1;
40 static int use_kenv;
41 static char *hintp;
42
43 /*
44 * Evil wildcarding resource string lookup.
45 * This walks the supplied env string table and returns a match.
46 * The start point can be remembered for incremental searches.
47 */
48 static int
49 res_find(int *line, int *startln,
50 const char *name, int *unit, const char *resname, const char *value,
51 const char **ret_name, int *ret_namelen, int *ret_unit,
52 const char **ret_resname, int *ret_resnamelen, const char **ret_value)
53 {
54 int n = 0, hit, i = 0;
55 char r_name[32];
56 int r_unit;
57 char r_resname[32];
58 char r_value[128];
59 const char *s, *cp;
60 char *p;
61
62 if (checkmethod) {
63 switch (hintmode) {
64 case 0: /* loader hints in environment only */
65 break;
66 case 1: /* static hints only */
67 hintp = static_hints;
68 checkmethod = 0;
69 break;
70 case 2: /* fallback mode */
71 if (dynamic_kenv) {
72 sx_slock(&kenv_lock);
73 cp = kenvp[0];
74 for (i = 0; cp != NULL; cp = kenvp[++i]) {
75 if (!strncmp(cp, "hint.", 5)) {
76 use_kenv = 1;
77 checkmethod = 0;
78 break;
79 }
80 }
81 sx_sunlock(&kenv_lock);
82 } else {
83 cp = kern_envp;
84 while (cp) {
85 if (strncmp(cp, "hint.", 5) == 0) {
86 cp = NULL;
87 hintp = kern_envp;
88 break;
89 }
90 while (*cp != '\0')
91 cp++;
92 cp++;
93 if (*cp == '\0') {
94 cp = NULL;
95 hintp = static_hints;
96 break;
97 }
98 }
99 }
100 break;
101 default:
102 break;
103 }
104 if (hintp == NULL) {
105 if (dynamic_kenv) {
106 use_kenv = 1;
107 checkmethod = 0;
108 } else
109 hintp = kern_envp;
110 }
111 }
112
113 if (use_kenv) {
114 sx_slock(&kenv_lock);
115 i = 0;
116 cp = kenvp[0];
117 if (cp == NULL) {
118 sx_sunlock(&kenv_lock);
119 return (ENOENT);
120 }
121 } else
122 cp = hintp;
123 while (cp) {
124 hit = 1;
125 (*line)++;
126 if (strncmp(cp, "hint.", 5) != 0)
127 hit = 0;
128 else
129 n = sscanf(cp, "hint.%32[^.].%d.%32[^=]=%128s",
130 r_name, &r_unit, r_resname, r_value);
131 if (hit && n != 4) {
132 printf("CONFIG: invalid hint '%s'\n", cp);
133 /* XXX: abuse bogus index() declaration */
134 p = index(cp, 'h');
135 *p = 'H';
136 hit = 0;
137 }
138 if (hit && startln && *startln >= 0 && *line < *startln)
139 hit = 0;
140 if (hit && name && strcmp(name, r_name) != 0)
141 hit = 0;
142 if (hit && unit && *unit != r_unit)
143 hit = 0;
144 if (hit && resname && strcmp(resname, r_resname) != 0)
145 hit = 0;
146 if (hit && value && strcmp(value, r_value) != 0)
147 hit = 0;
148 if (hit)
149 break;
150 if (use_kenv) {
151 cp = kenvp[++i];
152 if (cp == NULL)
153 break;
154 } else {
155 while (*cp != '\0')
156 cp++;
157 cp++;
158 if (*cp == '\0') {
159 cp = NULL;
160 break;
161 }
162 }
163 }
164 if (use_kenv)
165 sx_sunlock(&kenv_lock);
166 if (cp == NULL)
167 return ENOENT;
168
169 s = cp;
170 /* This is a bit of a hack, but at least is reentrant */
171 /* Note that it returns some !unterminated! strings. */
172 s = index(s, '.') + 1; /* start of device */
173 if (ret_name)
174 *ret_name = s;
175 s = index(s, '.') + 1; /* start of unit */
176 if (ret_namelen)
177 *ret_namelen = s - *ret_name - 1; /* device length */
178 if (ret_unit)
179 *ret_unit = r_unit;
180 s = index(s, '.') + 1; /* start of resname */
181 if (ret_resname)
182 *ret_resname = s;
183 s = index(s, '=') + 1; /* start of value */
184 if (ret_resnamelen)
185 *ret_resnamelen = s - *ret_resname - 1; /* value len */
186 if (ret_value)
187 *ret_value = s;
188 if (startln) /* line number for anchor */
189 *startln = *line + 1;
190 return 0;
191 }
192
193 /*
194 * Search all the data sources for matches to our query. We look for
195 * dynamic hints first as overrides for static or fallback hints.
196 */
197 static int
198 resource_find(int *line, int *startln,
199 const char *name, int *unit, const char *resname, const char *value,
200 const char **ret_name, int *ret_namelen, int *ret_unit,
201 const char **ret_resname, int *ret_resnamelen, const char **ret_value)
202 {
203 int i;
204 int un;
205
206 *line = 0;
207
208 /* Search for exact unit matches first */
209 i = res_find(line, startln, name, unit, resname, value,
210 ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen,
211 ret_value);
212 if (i == 0)
213 return 0;
214 if (unit == NULL)
215 return ENOENT;
216 /* If we are still here, search for wildcard matches */
217 un = -1;
218 i = res_find(line, startln, name, &un, resname, value,
219 ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen,
220 ret_value);
221 if (i == 0)
222 return 0;
223 return ENOENT;
224 }
225
226 int
227 resource_int_value(const char *name, int unit, const char *resname, int *result)
228 {
229 int error;
230 const char *str;
231 char *op;
232 unsigned long val;
233 int line;
234
235 line = 0;
236 error = resource_find(&line, NULL, name, &unit, resname, NULL,
237 NULL, NULL, NULL, NULL, NULL, &str);
238 if (error)
239 return error;
240 if (*str == '\0')
241 return EFTYPE;
242 val = strtoul(str, &op, 0);
243 if (*op != '\0')
244 return EFTYPE;
245 *result = val;
246 return 0;
247 }
248
249 int
250 resource_long_value(const char *name, int unit, const char *resname,
251 long *result)
252 {
253 int error;
254 const char *str;
255 char *op;
256 unsigned long val;
257 int line;
258
259 line = 0;
260 error = resource_find(&line, NULL, name, &unit, resname, NULL,
261 NULL, NULL, NULL, NULL, NULL, &str);
262 if (error)
263 return error;
264 if (*str == '\0')
265 return EFTYPE;
266 val = strtoul(str, &op, 0);
267 if (*op != '\0')
268 return EFTYPE;
269 *result = val;
270 return 0;
271 }
272
273 int
274 resource_string_value(const char *name, int unit, const char *resname,
275 const char **result)
276 {
277 int error;
278 const char *str;
279 int line;
280
281 line = 0;
282 error = resource_find(&line, NULL, name, &unit, resname, NULL,
283 NULL, NULL, NULL, NULL, NULL, &str);
284 if (error)
285 return error;
286 *result = str;
287 return 0;
288 }
289
290 /*
291 * This is a bit nasty, but allows us to not modify the env strings.
292 */
293 static const char *
294 resource_string_copy(const char *s, int len)
295 {
296 static char stringbuf[256];
297 static int offset = 0;
298 const char *ret;
299
300 if (len == 0)
301 len = strlen(s);
302 if (len > 255)
303 return NULL;
304 if ((offset + len + 1) > 255)
305 offset = 0;
306 bcopy(s, &stringbuf[offset], len);
307 stringbuf[offset + len] = '\0';
308 ret = &stringbuf[offset];
309 offset += len + 1;
310 return ret;
311 }
312
313 /*
314 * err = resource_find_at(&anchor, &name, &unit, resname, value)
315 * Iteratively fetch a list of devices wired "at" something
316 * res and value are restrictions. eg: "at", "scbus0".
317 * For practical purposes, res = required, value = optional.
318 * *name and *unit are set.
319 * set *anchor to zero before starting.
320 */
321 int
322 resource_find_match(int *anchor, const char **name, int *unit,
323 const char *resname, const char *value)
324 {
325 const char *found_name;
326 int found_namelen;
327 int found_unit;
328 int ret;
329 int newln;
330
331 newln = *anchor;
332 ret = resource_find(anchor, &newln, NULL, NULL, resname, value,
333 &found_name, &found_namelen, &found_unit, NULL, NULL, NULL);
334 if (ret == 0) {
335 *name = resource_string_copy(found_name, found_namelen);
336 *unit = found_unit;
337 }
338 *anchor = newln;
339 return ret;
340 }
341
342
343 /*
344 * err = resource_find_dev(&anchor, name, &unit, res, value);
345 * Iterate through a list of devices, returning their unit numbers.
346 * res and value are optional restrictions. eg: "at", "scbus0".
347 * *unit is set to the value.
348 * set *anchor to zero before starting.
349 */
350 int
351 resource_find_dev(int *anchor, const char *name, int *unit,
352 const char *resname, const char *value)
353 {
354 int found_unit;
355 int newln;
356 int ret;
357
358 newln = *anchor;
359 ret = resource_find(anchor, &newln, name, NULL, resname, value,
360 NULL, NULL, &found_unit, NULL, NULL, NULL);
361 if (ret == 0) {
362 *unit = found_unit;
363 }
364 *anchor = newln;
365 return ret;
366 }
Cache object: 1fec026c5d00cb970fd89168d2470fcd
|