]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/kern/subr_hints.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / 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
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/param.h>
31 #include <sys/lock.h>
32 #include <sys/mutex.h>
33 #include <sys/systm.h>
34 #include <sys/bus.h>
35
36 /*
37  * Access functions for device resources.
38  */
39
40 static int checkmethod = 1;
41 static int use_kenv;
42 static char *hintp;
43
44 /*
45  * Evil wildcarding resource string lookup.
46  * This walks the supplied env string table and returns a match.
47  * The start point can be remembered for incremental searches.
48  */
49 static int
50 res_find(int *line, int *startln,
51     const char *name, int *unit, const char *resname, const char *value,
52     const char **ret_name, int *ret_namelen, int *ret_unit,
53     const char **ret_resname, int *ret_resnamelen, const char **ret_value)
54 {
55         int n = 0, hit, i = 0;
56         char r_name[32];
57         int r_unit;
58         char r_resname[32];
59         char r_value[128];
60         const char *s, *cp;
61         char *p;
62
63         if (checkmethod) {
64                 hintp = NULL;
65
66                 switch (hintmode) {
67                 case 0:         /* loader hints in environment only */
68                         break;
69                 case 1:         /* static hints only */
70                         hintp = static_hints;
71                         checkmethod = 0;
72                         break;
73                 case 2:         /* fallback mode */
74                         if (dynamic_kenv) {
75                                 mtx_lock(&kenv_lock);
76                                 cp = kenvp[0];
77                                 for (i = 0; cp != NULL; cp = kenvp[++i]) {
78                                         if (!strncmp(cp, "hint.", 5)) {
79                                                 use_kenv = 1;
80                                                 checkmethod = 0;
81                                                 break;
82                                         }
83                                 }
84                                 mtx_unlock(&kenv_lock);
85                         } else {
86                                 cp = kern_envp;
87                                 while (cp) {
88                                         if (strncmp(cp, "hint.", 5) == 0) {
89                                                 cp = NULL;
90                                                 hintp = kern_envp;
91                                                 break;
92                                         }
93                                         while (*cp != '\0')
94                                                 cp++;
95                                         cp++;
96                                         if (*cp == '\0') {
97                                                 cp = NULL;
98                                                 hintp = static_hints;
99                                                 break;
100                                         }
101                                 }
102                         }
103                         break;
104                 default:
105                         break;
106                 }
107                 if (hintp == NULL) {
108                         if (dynamic_kenv) {
109                                 use_kenv = 1;
110                                 checkmethod = 0;
111                         } else
112                                 hintp = kern_envp;
113                 }
114         }
115
116         if (use_kenv) {
117                 mtx_lock(&kenv_lock);
118                 i = 0;
119                 cp = kenvp[0];
120                 if (cp == NULL) {
121                         mtx_unlock(&kenv_lock);
122                         return (ENOENT);
123                 }
124         } else
125                 cp = hintp;
126         while (cp) {
127                 hit = 1;
128                 (*line)++;
129                 if (strncmp(cp, "hint.", 5) != 0)
130                         hit = 0;
131                 else
132                         n = sscanf(cp, "hint.%32[^.].%d.%32[^=]=%128s",
133                             r_name, &r_unit, r_resname, r_value);
134                 if (hit && n != 4) {
135                         printf("CONFIG: invalid hint '%s'\n", cp);
136                         /* XXX: abuse bogus index() declaration */
137                         p = index(cp, 'h');
138                         *p = 'H';
139                         hit = 0;
140                 }
141                 if (hit && startln && *startln >= 0 && *line < *startln)
142                         hit = 0;
143                 if (hit && name && strcmp(name, r_name) != 0)
144                         hit = 0;
145                 if (hit && unit && *unit != r_unit)
146                         hit = 0;
147                 if (hit && resname && strcmp(resname, r_resname) != 0)
148                         hit = 0;
149                 if (hit && value && strcmp(value, r_value) != 0)
150                         hit = 0;
151                 if (hit)
152                         break;
153                 if (use_kenv) {
154                         cp = kenvp[++i];
155                         if (cp == NULL)
156                                 break;
157                 } else {
158                         while (*cp != '\0')
159                                 cp++;
160                         cp++;
161                         if (*cp == '\0') {
162                                 cp = NULL;
163                                 break;
164                         }
165                 }
166         }
167         if (use_kenv)
168                 mtx_unlock(&kenv_lock);
169         if (cp == NULL)
170                 return ENOENT;
171
172         s = cp;
173         /* This is a bit of a hack, but at least is reentrant */
174         /* Note that it returns some !unterminated! strings. */
175         s = index(s, '.') + 1;          /* start of device */
176         if (ret_name)
177                 *ret_name = s;
178         s = index(s, '.') + 1;          /* start of unit */
179         if (ret_namelen && ret_name)
180                 *ret_namelen = s - *ret_name - 1; /* device length */
181         if (ret_unit)
182                 *ret_unit = r_unit;
183         s = index(s, '.') + 1;          /* start of resname */
184         if (ret_resname)
185                 *ret_resname = s;
186         s = index(s, '=') + 1;          /* start of value */
187         if (ret_resnamelen && ret_resname)
188                 *ret_resnamelen = s - *ret_resname - 1; /* value len */
189         if (ret_value)
190                 *ret_value = s;
191         if (startln)                    /* line number for anchor */
192                 *startln = *line + 1;
193         return 0;
194 }
195
196 /*
197  * Search all the data sources for matches to our query.  We look for
198  * dynamic hints first as overrides for static or fallback hints.
199  */
200 static int
201 resource_find(int *line, int *startln,
202     const char *name, int *unit, const char *resname, const char *value,
203     const char **ret_name, int *ret_namelen, int *ret_unit,
204     const char **ret_resname, int *ret_resnamelen, const char **ret_value)
205 {
206         int i;
207         int un;
208
209         *line = 0;
210
211         /* Search for exact unit matches first */
212         i = res_find(line, startln, name, unit, resname, value,
213             ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen,
214             ret_value);
215         if (i == 0)
216                 return 0;
217         if (unit == NULL)
218                 return ENOENT;
219         /* If we are still here, search for wildcard matches */
220         un = -1;
221         i = res_find(line, startln, name, &un, resname, value,
222             ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen,
223             ret_value);
224         if (i == 0)
225                 return 0;
226         return ENOENT;
227 }
228
229 int
230 resource_int_value(const char *name, int unit, const char *resname, int *result)
231 {
232         int error;
233         const char *str;
234         char *op;
235         unsigned long val;
236         int line;
237
238         line = 0;
239         error = resource_find(&line, NULL, name, &unit, resname, NULL,
240             NULL, NULL, NULL, NULL, NULL, &str);
241         if (error)
242                 return error;
243         if (*str == '\0') 
244                 return EFTYPE;
245         val = strtoul(str, &op, 0);
246         if (*op != '\0') 
247                 return EFTYPE;
248         *result = val;
249         return 0;
250 }
251
252 int
253 resource_long_value(const char *name, int unit, const char *resname,
254     long *result)
255 {
256         int error;
257         const char *str;
258         char *op;
259         unsigned long val;
260         int line;
261
262         line = 0;
263         error = resource_find(&line, NULL, name, &unit, resname, NULL,
264             NULL, NULL, NULL, NULL, NULL, &str);
265         if (error)
266                 return error;
267         if (*str == '\0') 
268                 return EFTYPE;
269         val = strtoul(str, &op, 0);
270         if (*op != '\0') 
271                 return EFTYPE;
272         *result = val;
273         return 0;
274 }
275
276 int
277 resource_string_value(const char *name, int unit, const char *resname,
278     const char **result)
279 {
280         int error;
281         const char *str;
282         int line;
283
284         line = 0;
285         error = resource_find(&line, NULL, name, &unit, resname, NULL,
286             NULL, NULL, NULL, NULL, NULL, &str);
287         if (error)
288                 return error;
289         *result = str;
290         return 0;
291 }
292
293 /*
294  * This is a bit nasty, but allows us to not modify the env strings.
295  */
296 static const char *
297 resource_string_copy(const char *s, int len)
298 {
299         static char stringbuf[256];
300         static int offset = 0;
301         const char *ret;
302
303         if (len == 0)
304                 len = strlen(s);
305         if (len > 255)
306                 return NULL;
307         if ((offset + len + 1) > 255)
308                 offset = 0;
309         bcopy(s, &stringbuf[offset], len);
310         stringbuf[offset + len] = '\0';
311         ret = &stringbuf[offset];
312         offset += len + 1;
313         return ret;
314 }
315
316 /*
317  * err = resource_find_match(&anchor, &name, &unit, resname, value)
318  * Iteratively fetch a list of devices wired "at" something
319  * res and value are restrictions.  eg: "at", "scbus0".
320  * For practical purposes, res = required, value = optional.
321  * *name and *unit are set.
322  * set *anchor to zero before starting.
323  */
324 int
325 resource_find_match(int *anchor, const char **name, int *unit,
326     const char *resname, const char *value)
327 {
328         const char *found_name;
329         int found_namelen;
330         int found_unit;
331         int ret;
332         int newln;
333
334         newln = *anchor;
335         ret = resource_find(anchor, &newln, NULL, NULL, resname, value,
336             &found_name, &found_namelen, &found_unit, NULL, NULL, NULL);
337         if (ret == 0) {
338                 *name = resource_string_copy(found_name, found_namelen);
339                 *unit = found_unit;
340         }
341         *anchor = newln;
342         return ret;
343 }
344
345
346 /*
347  * err = resource_find_dev(&anchor, name, &unit, res, value);
348  * Iterate through a list of devices, returning their unit numbers.
349  * res and value are optional restrictions.  eg: "at", "scbus0".
350  * *unit is set to the value.
351  * set *anchor to zero before starting.
352  */
353 int
354 resource_find_dev(int *anchor, const char *name, int *unit,
355     const char *resname, const char *value)
356 {
357         int found_unit;
358         int newln;
359         int ret;
360
361         newln = *anchor;
362         ret = resource_find(anchor, &newln, name, NULL, resname, value,
363             NULL, NULL, &found_unit, NULL, NULL, NULL);
364         if (ret == 0) {
365                 *unit = found_unit;
366         }
367         *anchor = newln;
368         return ret;
369 }
370
371 /*
372  * Check to see if a device is disabled via a disabled hint.
373  */
374 int
375 resource_disabled(const char *name, int unit)
376 {
377         int error, value;
378
379         error = resource_int_value(name, unit, "disabled", &value);
380         if (error)
381                return (0);
382         return (value);
383 }