]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/kern/subr_hints.c
Style fixes and simplifications.
[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/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                         p = strchr(cp, 'h');
137                         *p = 'H';
138                         hit = 0;
139                 }
140                 if (hit && startln && *startln >= 0 && *line < *startln)
141                         hit = 0;
142                 if (hit && name && strcmp(name, r_name) != 0)
143                         hit = 0;
144                 if (hit && unit && *unit != r_unit)
145                         hit = 0;
146                 if (hit && resname && strcmp(resname, r_resname) != 0)
147                         hit = 0;
148                 if (hit && value && strcmp(value, r_value) != 0)
149                         hit = 0;
150                 if (hit)
151                         break;
152                 if (use_kenv) {
153                         cp = kenvp[++i];
154                         if (cp == NULL)
155                                 break;
156                 } else {
157                         while (*cp != '\0')
158                                 cp++;
159                         cp++;
160                         if (*cp == '\0') {
161                                 cp = NULL;
162                                 break;
163                         }
164                 }
165         }
166         if (use_kenv)
167                 mtx_unlock(&kenv_lock);
168         if (cp == NULL)
169                 return ENOENT;
170
171         s = cp;
172         /* This is a bit of a hack, but at least is reentrant */
173         /* Note that it returns some !unterminated! strings. */
174         s = strchr(s, '.') + 1;         /* start of device */
175         if (ret_name)
176                 *ret_name = s;
177         s = strchr(s, '.') + 1;         /* start of unit */
178         if (ret_namelen && ret_name)
179                 *ret_namelen = s - *ret_name - 1; /* device length */
180         if (ret_unit)
181                 *ret_unit = r_unit;
182         s = strchr(s, '.') + 1;         /* start of resname */
183         if (ret_resname)
184                 *ret_resname = s;
185         s = strchr(s, '=') + 1;         /* start of value */
186         if (ret_resnamelen && ret_resname)
187                 *ret_resnamelen = s - *ret_resname - 1; /* value len */
188         if (ret_value)
189                 *ret_value = s;
190         if (startln)                    /* line number for anchor */
191                 *startln = *line + 1;
192         return 0;
193 }
194
195 /*
196  * Search all the data sources for matches to our query.  We look for
197  * dynamic hints first as overrides for static or fallback hints.
198  */
199 static int
200 resource_find(int *line, int *startln,
201     const char *name, int *unit, const char *resname, const char *value,
202     const char **ret_name, int *ret_namelen, int *ret_unit,
203     const char **ret_resname, int *ret_resnamelen, const char **ret_value)
204 {
205         int i;
206         int un;
207
208         *line = 0;
209
210         /* Search for exact unit matches first */
211         i = res_find(line, startln, name, unit, resname, value,
212             ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen,
213             ret_value);
214         if (i == 0)
215                 return 0;
216         if (unit == NULL)
217                 return ENOENT;
218         /* If we are still here, search for wildcard matches */
219         un = -1;
220         i = res_find(line, startln, name, &un, resname, value,
221             ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen,
222             ret_value);
223         if (i == 0)
224                 return 0;
225         return ENOENT;
226 }
227
228 int
229 resource_int_value(const char *name, int unit, const char *resname, int *result)
230 {
231         int error;
232         const char *str;
233         char *op;
234         unsigned long val;
235         int line;
236
237         line = 0;
238         error = resource_find(&line, NULL, name, &unit, resname, NULL,
239             NULL, NULL, NULL, NULL, NULL, &str);
240         if (error)
241                 return error;
242         if (*str == '\0') 
243                 return EFTYPE;
244         val = strtoul(str, &op, 0);
245         if (*op != '\0') 
246                 return EFTYPE;
247         *result = val;
248         return 0;
249 }
250
251 int
252 resource_long_value(const char *name, int unit, const char *resname,
253     long *result)
254 {
255         int error;
256         const char *str;
257         char *op;
258         unsigned long val;
259         int line;
260
261         line = 0;
262         error = resource_find(&line, NULL, name, &unit, resname, NULL,
263             NULL, NULL, NULL, NULL, NULL, &str);
264         if (error)
265                 return error;
266         if (*str == '\0') 
267                 return EFTYPE;
268         val = strtoul(str, &op, 0);
269         if (*op != '\0') 
270                 return EFTYPE;
271         *result = val;
272         return 0;
273 }
274
275 int
276 resource_string_value(const char *name, int unit, const char *resname,
277     const char **result)
278 {
279         int error;
280         const char *str;
281         int line;
282
283         line = 0;
284         error = resource_find(&line, NULL, name, &unit, resname, NULL,
285             NULL, NULL, NULL, NULL, NULL, &str);
286         if (error)
287                 return error;
288         *result = str;
289         return 0;
290 }
291
292 /*
293  * This is a bit nasty, but allows us to not modify the env strings.
294  */
295 static const char *
296 resource_string_copy(const char *s, int len)
297 {
298         static char stringbuf[256];
299         static int offset = 0;
300         const char *ret;
301
302         if (len == 0)
303                 len = strlen(s);
304         if (len > 255)
305                 return NULL;
306         if ((offset + len + 1) > 255)
307                 offset = 0;
308         bcopy(s, &stringbuf[offset], len);
309         stringbuf[offset + len] = '\0';
310         ret = &stringbuf[offset];
311         offset += len + 1;
312         return ret;
313 }
314
315 /*
316  * err = resource_find_match(&anchor, &name, &unit, resname, value)
317  * Iteratively fetch a list of devices wired "at" something
318  * res and value are restrictions.  eg: "at", "scbus0".
319  * For practical purposes, res = required, value = optional.
320  * *name and *unit are set.
321  * set *anchor to zero before starting.
322  */
323 int
324 resource_find_match(int *anchor, const char **name, int *unit,
325     const char *resname, const char *value)
326 {
327         const char *found_name;
328         int found_namelen;
329         int found_unit;
330         int ret;
331         int newln;
332
333         newln = *anchor;
334         ret = resource_find(anchor, &newln, NULL, NULL, resname, value,
335             &found_name, &found_namelen, &found_unit, NULL, NULL, NULL);
336         if (ret == 0) {
337                 *name = resource_string_copy(found_name, found_namelen);
338                 *unit = found_unit;
339         }
340         *anchor = newln;
341         return ret;
342 }
343
344
345 /*
346  * err = resource_find_dev(&anchor, name, &unit, res, value);
347  * Iterate through a list of devices, returning their unit numbers.
348  * res and value are optional restrictions.  eg: "at", "scbus0".
349  * *unit is set to the value.
350  * set *anchor to zero before starting.
351  */
352 int
353 resource_find_dev(int *anchor, const char *name, int *unit,
354     const char *resname, const char *value)
355 {
356         int found_unit;
357         int newln;
358         int ret;
359
360         newln = *anchor;
361         ret = resource_find(anchor, &newln, name, NULL, resname, value,
362             NULL, NULL, &found_unit, NULL, NULL, NULL);
363         if (ret == 0) {
364                 *unit = found_unit;
365         }
366         *anchor = newln;
367         return ret;
368 }
369
370 /*
371  * Check to see if a device is disabled via a disabled hint.
372  */
373 int
374 resource_disabled(const char *name, int unit)
375 {
376         int error, value;
377
378         error = resource_int_value(name, unit, "disabled", &value);
379         if (error)
380                return (0);
381         return (value);
382 }