source: rtems-libbsd/freebsd/sys/kern/subr_hints.c @ c40e45b

55-freebsd-126-freebsd-12
Last change on this file since c40e45b was c40e45b, checked in by Sebastian Huber <sebastian.huber@…>, on 10/07/16 at 13:10:20

Update to FreeBSD head 2016-08-23

Git mirror commit 9fe7c416e6abb28b1398fd3e5687099846800cfd.

  • Property mode set to 100644
File size: 11.9 KB
Line 
1#include <machine/rtems-bsd-kernel-space.h>
2
3/*-
4 * Copyright (c) 2000,2001 Peter Wemm <peter@FreeBSD.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD$");
31
32#include <rtems/bsd/sys/param.h>
33#include <rtems/bsd/sys/lock.h>
34#include <sys/malloc.h>
35#include <sys/mutex.h>
36#include <sys/sysctl.h>
37#include <sys/systm.h>
38#include <sys/bus.h>
39
40/*
41 * Access functions for device resources.
42 */
43
44#ifndef __rtems__
45static int checkmethod = 1;
46static int use_kenv;
47static char *hintp;
48#else /* __rtems__ */
49#define hintmode 1
50#define hintp static_hints
51#define use_kenv 0
52static char __used default_static_hints[] = "";
53__weak_reference(default_static_hints, static_hints);
54#endif /* __rtems__ */
55
56#ifndef __rtems__
57/*
58 * Define kern.hintmode sysctl, which only accept value 2, that cause to
59 * switch from Static KENV mode to Dynamic KENV. So systems that have hints
60 * compiled into kernel will be able to see/modify KENV (and hints too).
61 */
62
63static int
64sysctl_hintmode(SYSCTL_HANDLER_ARGS)
65{
66        const char *cp;
67        char *line, *eq;
68        int eqidx, error, from_kenv, i, value;
69
70        from_kenv = 0;
71        cp = kern_envp;
72        value = hintmode;
73
74        /* Fetch candidate for new hintmode value */
75        error = sysctl_handle_int(oidp, &value, 0, req);
76        if (error || req->newptr == NULL)
77                return (error);
78
79        if (value != 2)
80                /* Only accept swithing to hintmode 2 */
81                return (EINVAL);
82
83        /* Migrate from static to dynamic hints */
84        switch (hintmode) {
85        case 0:
86                if (dynamic_kenv) {
87                        /*
88                         * Already here. But assign hintmode to 2, to not
89                         * check it in the future.
90                         */
91                        hintmode = 2;
92                        return (0);
93                }
94                from_kenv = 1;
95                cp = kern_envp;
96                break;
97        case 1:
98                cp = static_hints;
99                break;
100        case 2:
101                /* Nothing to do, hintmode already 2 */
102                return (0);
103        }
104
105        while (cp) {
106                i = strlen(cp);
107                if (i == 0)
108                        break;
109                if (from_kenv) {
110                        if (strncmp(cp, "hint.", 5) != 0)
111                                /* kenv can have not only hints */
112                                continue;
113                }
114                eq = strchr(cp, '=');
115                if (eq == NULL)
116                        /* Bad hint value */
117                        continue;
118                eqidx = eq - cp;
119
120                line = malloc(i+1, M_TEMP, M_WAITOK);
121                strcpy(line, cp);
122                line[eqidx] = '\0';
123                kern_setenv(line, line + eqidx + 1);
124                free(line, M_TEMP);
125                cp += i + 1;
126        }
127
128        hintmode = value;
129        use_kenv = 1;
130        return (0);
131}
132
133SYSCTL_PROC(_kern, OID_AUTO, hintmode, CTLTYPE_INT|CTLFLAG_RW,
134    &hintmode, 0, sysctl_hintmode, "I", "Get/set current hintmode");
135#endif /* __rtems__ */
136
137/*
138 * Evil wildcarding resource string lookup.
139 * This walks the supplied env string table and returns a match.
140 * The start point can be remembered for incremental searches.
141 */
142static int
143res_find(int *line, int *startln,
144    const char *name, int *unit, const char *resname, const char *value,
145    const char **ret_name, int *ret_namelen, int *ret_unit,
146    const char **ret_resname, int *ret_resnamelen, const char **ret_value)
147{
148        int n = 0, hit, i = 0;
149        char r_name[32];
150        int r_unit;
151        char r_resname[32];
152        char r_value[128];
153        const char *s, *cp;
154        char *p;
155
156#ifndef __rtems__
157        if (checkmethod) {
158                hintp = NULL;
159
160                switch (hintmode) {
161                case 0:         /* loader hints in environment only */
162                        break;
163                case 1:         /* static hints only */
164                        hintp = static_hints;
165                        checkmethod = 0;
166                        break;
167                case 2:         /* fallback mode */
168                        if (dynamic_kenv) {
169                                mtx_lock(&kenv_lock);
170                                cp = kenvp[0];
171                                for (i = 0; cp != NULL; cp = kenvp[++i]) {
172                                        if (!strncmp(cp, "hint.", 5)) {
173                                                use_kenv = 1;
174                                                checkmethod = 0;
175                                                break;
176                                        }
177                                }
178                                mtx_unlock(&kenv_lock);
179                        } else {
180                                cp = kern_envp;
181                                while (cp) {
182                                        if (strncmp(cp, "hint.", 5) == 0) {
183                                                cp = NULL;
184                                                hintp = kern_envp;
185                                                break;
186                                        }
187                                        while (*cp != '\0')
188                                                cp++;
189                                        cp++;
190                                        if (*cp == '\0') {
191                                                cp = NULL;
192                                                hintp = static_hints;
193                                                break;
194                                        }
195                                }
196                        }
197                        break;
198                default:
199                        break;
200                }
201                if (hintp == NULL) {
202                        if (dynamic_kenv) {
203                                use_kenv = 1;
204                                checkmethod = 0;
205                        } else
206                                hintp = kern_envp;
207                }
208        }
209
210        if (use_kenv) {
211                mtx_lock(&kenv_lock);
212                i = 0;
213                cp = kenvp[0];
214                if (cp == NULL) {
215                        mtx_unlock(&kenv_lock);
216                        return (ENOENT);
217                }
218        } else
219#endif /* __rtems__ */
220                cp = hintp;
221        while (cp) {
222                hit = 1;
223                (*line)++;
224                if (strncmp(cp, "hint.", 5) != 0)
225                        hit = 0;
226                else
227                        n = sscanf(cp, "hint.%32[^.].%d.%32[^=]=%127s",
228                            r_name, &r_unit, r_resname, r_value);
229                if (hit && n != 4) {
230                        printf("CONFIG: invalid hint '%s'\n", cp);
231                        p = strchr(cp, 'h');
232                        *p = 'H';
233                        hit = 0;
234                }
235                if (hit && startln && *startln >= 0 && *line < *startln)
236                        hit = 0;
237                if (hit && name && strcmp(name, r_name) != 0)
238                        hit = 0;
239                if (hit && unit && *unit != r_unit)
240                        hit = 0;
241                if (hit && resname && strcmp(resname, r_resname) != 0)
242                        hit = 0;
243                if (hit && value && strcmp(value, r_value) != 0)
244                        hit = 0;
245                if (hit)
246                        break;
247                if (use_kenv) {
248#ifndef __rtems__
249                        cp = kenvp[++i];
250                        if (cp == NULL)
251                                break;
252#else /* __rtems__ */
253                        (void) i;
254#endif /* __rtems__ */
255                } else {
256                        while (*cp != '\0')
257                                cp++;
258                        cp++;
259                        if (*cp == '\0') {
260                                cp = NULL;
261                                break;
262                        }
263                }
264        }
265#ifndef __rtems__
266        if (use_kenv)
267                mtx_unlock(&kenv_lock);
268#endif /* __rtems__ */
269        if (cp == NULL)
270                return ENOENT;
271
272        s = cp;
273        /* This is a bit of a hack, but at least is reentrant */
274        /* Note that it returns some !unterminated! strings. */
275        s = strchr(s, '.') + 1;         /* start of device */
276        if (ret_name)
277                *ret_name = s;
278        s = strchr(s, '.') + 1;         /* start of unit */
279        if (ret_namelen && ret_name)
280                *ret_namelen = s - *ret_name - 1; /* device length */
281        if (ret_unit)
282                *ret_unit = r_unit;
283        s = strchr(s, '.') + 1;         /* start of resname */
284        if (ret_resname)
285                *ret_resname = s;
286        s = strchr(s, '=') + 1;         /* start of value */
287        if (ret_resnamelen && ret_resname)
288                *ret_resnamelen = s - *ret_resname - 1; /* value len */
289        if (ret_value)
290                *ret_value = s;
291        if (startln)                    /* line number for anchor */
292                *startln = *line + 1;
293        return 0;
294}
295
296/*
297 * Search all the data sources for matches to our query.  We look for
298 * dynamic hints first as overrides for static or fallback hints.
299 */
300static int
301resource_find(int *line, int *startln,
302    const char *name, int *unit, const char *resname, const char *value,
303    const char **ret_name, int *ret_namelen, int *ret_unit,
304    const char **ret_resname, int *ret_resnamelen, const char **ret_value)
305{
306        int i;
307        int un;
308
309        *line = 0;
310
311        /* Search for exact unit matches first */
312        i = res_find(line, startln, name, unit, resname, value,
313            ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen,
314            ret_value);
315        if (i == 0)
316                return 0;
317        if (unit == NULL)
318                return ENOENT;
319        /* If we are still here, search for wildcard matches */
320        un = -1;
321        i = res_find(line, startln, name, &un, resname, value,
322            ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen,
323            ret_value);
324        if (i == 0)
325                return 0;
326        return ENOENT;
327}
328
329int
330resource_int_value(const char *name, int unit, const char *resname, int *result)
331{
332        int error;
333        const char *str;
334        char *op;
335        unsigned long val;
336        int line;
337
338        line = 0;
339        error = resource_find(&line, NULL, name, &unit, resname, NULL,
340            NULL, NULL, NULL, NULL, NULL, &str);
341        if (error)
342                return error;
343        if (*str == '\0')
344                return EFTYPE;
345        val = strtoul(str, &op, 0);
346        if (*op != '\0')
347                return EFTYPE;
348        *result = val;
349        return 0;
350}
351
352#ifndef __rtems__
353int
354resource_long_value(const char *name, int unit, const char *resname,
355    long *result)
356{
357        int error;
358        const char *str;
359        char *op;
360        unsigned long val;
361        int line;
362
363        line = 0;
364        error = resource_find(&line, NULL, name, &unit, resname, NULL,
365            NULL, NULL, NULL, NULL, NULL, &str);
366        if (error)
367                return error;
368        if (*str == '\0')
369                return EFTYPE;
370        val = strtoul(str, &op, 0);
371        if (*op != '\0')
372                return EFTYPE;
373        *result = val;
374        return 0;
375}
376#endif /* __rtems__ */
377
378int
379resource_string_value(const char *name, int unit, const char *resname,
380    const char **result)
381{
382        int error;
383        const char *str;
384        int line;
385
386        line = 0;
387        error = resource_find(&line, NULL, name, &unit, resname, NULL,
388            NULL, NULL, NULL, NULL, NULL, &str);
389        if (error)
390                return error;
391        *result = str;
392        return 0;
393}
394
395/*
396 * This is a bit nasty, but allows us to not modify the env strings.
397 */
398static const char *
399resource_string_copy(const char *s, int len)
400{
401        static char stringbuf[256];
402        static int offset = 0;
403        const char *ret;
404
405        if (len == 0)
406                len = strlen(s);
407        if (len > 255)
408                return NULL;
409        if ((offset + len + 1) > 255)
410                offset = 0;
411        bcopy(s, &stringbuf[offset], len);
412        stringbuf[offset + len] = '\0';
413        ret = &stringbuf[offset];
414        offset += len + 1;
415        return ret;
416}
417
418/*
419 * err = resource_find_match(&anchor, &name, &unit, resname, value)
420 * Iteratively fetch a list of devices wired "at" something
421 * res and value are restrictions.  eg: "at", "scbus0".
422 * For practical purposes, res = required, value = optional.
423 * *name and *unit are set.
424 * set *anchor to zero before starting.
425 */
426int
427resource_find_match(int *anchor, const char **name, int *unit,
428    const char *resname, const char *value)
429{
430        const char *found_name;
431        int found_namelen;
432        int found_unit;
433        int ret;
434        int newln;
435
436        newln = *anchor;
437        ret = resource_find(anchor, &newln, NULL, NULL, resname, value,
438            &found_name, &found_namelen, &found_unit, NULL, NULL, NULL);
439        if (ret == 0) {
440                *name = resource_string_copy(found_name, found_namelen);
441                *unit = found_unit;
442        }
443        *anchor = newln;
444        return ret;
445}
446
447#ifndef __rtems__
448
449/*
450 * err = resource_find_dev(&anchor, name, &unit, res, value);
451 * Iterate through a list of devices, returning their unit numbers.
452 * res and value are optional restrictions.  eg: "at", "scbus0".
453 * *unit is set to the value.
454 * set *anchor to zero before starting.
455 */
456int
457resource_find_dev(int *anchor, const char *name, int *unit,
458    const char *resname, const char *value)
459{
460        int found_unit;
461        int newln;
462        int ret;
463
464        newln = *anchor;
465        ret = resource_find(anchor, &newln, name, NULL, resname, value,
466            NULL, NULL, &found_unit, NULL, NULL, NULL);
467        if (ret == 0) {
468                *unit = found_unit;
469        }
470        *anchor = newln;
471        return ret;
472}
473#endif /* __rtems__ */
474
475/*
476 * Check to see if a device is disabled via a disabled hint.
477 */
478int
479resource_disabled(const char *name, int unit)
480{
481        int error, value;
482
483        error = resource_int_value(name, unit, "disabled", &value);
484        if (error)
485               return (0);
486        return (value);
487}
488
489/*
490 * Clear a value associated with a device by removing it from
491 * the kernel environment.  This only removes a hint for an
492 * exact unit.
493 */
494int
495resource_unset_value(const char *name, int unit, const char *resname)
496{
497        char varname[128];
498        const char *retname, *retvalue;
499        int error, line;
500        size_t len;
501
502        line = 0;
503        error = resource_find(&line, NULL, name, &unit, resname, NULL,
504            &retname, NULL, NULL, NULL, NULL, &retvalue);
505        if (error)
506                return (error);
507
508        retname -= strlen("hint.");
509        len = retvalue - retname - 1;
510        if (len > sizeof(varname) - 1)
511                return (ENAMETOOLONG);
512        memcpy(varname, retname, len);
513        varname[len] = '\0';
514        return (kern_unsetenv(varname));
515}
Note: See TracBrowser for help on using the repository browser.