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