From c40e45b75eb76d79a05c7fa85c1fa9b5c728a12f Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Fri, 7 Oct 2016 15:10:20 +0200 Subject: Update to FreeBSD head 2016-08-23 Git mirror commit 9fe7c416e6abb28b1398fd3e5687099846800cfd. --- freebsd/sys/kern/subr_hints.c | 122 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 116 insertions(+), 6 deletions(-) (limited to 'freebsd/sys/kern/subr_hints.c') diff --git a/freebsd/sys/kern/subr_hints.c b/freebsd/sys/kern/subr_hints.c index 13fb3934..7fcf3275 100644 --- a/freebsd/sys/kern/subr_hints.c +++ b/freebsd/sys/kern/subr_hints.c @@ -31,7 +31,9 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include +#include #include #include @@ -51,6 +53,87 @@ static char __used default_static_hints[] = ""; __weak_reference(default_static_hints, static_hints); #endif /* __rtems__ */ +#ifndef __rtems__ +/* + * Define kern.hintmode sysctl, which only accept value 2, that cause to + * switch from Static KENV mode to Dynamic KENV. So systems that have hints + * compiled into kernel will be able to see/modify KENV (and hints too). + */ + +static int +sysctl_hintmode(SYSCTL_HANDLER_ARGS) +{ + const char *cp; + char *line, *eq; + int eqidx, error, from_kenv, i, value; + + from_kenv = 0; + cp = kern_envp; + value = hintmode; + + /* Fetch candidate for new hintmode value */ + error = sysctl_handle_int(oidp, &value, 0, req); + if (error || req->newptr == NULL) + return (error); + + if (value != 2) + /* Only accept swithing to hintmode 2 */ + return (EINVAL); + + /* Migrate from static to dynamic hints */ + switch (hintmode) { + case 0: + if (dynamic_kenv) { + /* + * Already here. But assign hintmode to 2, to not + * check it in the future. + */ + hintmode = 2; + return (0); + } + from_kenv = 1; + cp = kern_envp; + break; + case 1: + cp = static_hints; + break; + case 2: + /* Nothing to do, hintmode already 2 */ + return (0); + } + + while (cp) { + i = strlen(cp); + if (i == 0) + break; + if (from_kenv) { + if (strncmp(cp, "hint.", 5) != 0) + /* kenv can have not only hints */ + continue; + } + eq = strchr(cp, '='); + if (eq == NULL) + /* Bad hint value */ + continue; + eqidx = eq - cp; + + line = malloc(i+1, M_TEMP, M_WAITOK); + strcpy(line, cp); + line[eqidx] = '\0'; + kern_setenv(line, line + eqidx + 1); + free(line, M_TEMP); + cp += i + 1; + } + + hintmode = value; + use_kenv = 1; + return (0); +} + +SYSCTL_PROC(_kern, OID_AUTO, hintmode, CTLTYPE_INT|CTLFLAG_RW, + &hintmode, 0, sysctl_hintmode, "I", "Get/set current hintmode"); +#endif /* __rtems__ */ + /* * Evil wildcarding resource string lookup. * This walks the supplied env string table and returns a match. @@ -145,8 +228,7 @@ res_find(int *line, int *startln, r_name, &r_unit, r_resname, r_value); if (hit && n != 4) { printf("CONFIG: invalid hint '%s'\n", cp); - /* XXX: abuse bogus index() declaration */ - p = index(cp, 'h'); + p = strchr(cp, 'h'); *p = 'H'; hit = 0; } @@ -190,18 +272,18 @@ res_find(int *line, int *startln, s = cp; /* This is a bit of a hack, but at least is reentrant */ /* Note that it returns some !unterminated! strings. */ - s = index(s, '.') + 1; /* start of device */ + s = strchr(s, '.') + 1; /* start of device */ if (ret_name) *ret_name = s; - s = index(s, '.') + 1; /* start of unit */ + s = strchr(s, '.') + 1; /* start of unit */ if (ret_namelen && ret_name) *ret_namelen = s - *ret_name - 1; /* device length */ if (ret_unit) *ret_unit = r_unit; - s = index(s, '.') + 1; /* start of resname */ + s = strchr(s, '.') + 1; /* start of resname */ if (ret_resname) *ret_resname = s; - s = index(s, '=') + 1; /* start of value */ + s = strchr(s, '=') + 1; /* start of value */ if (ret_resnamelen && ret_resname) *ret_resnamelen = s - *ret_resname - 1; /* value len */ if (ret_value) @@ -403,3 +485,31 @@ resource_disabled(const char *name, int unit) return (0); return (value); } + +/* + * Clear a value associated with a device by removing it from + * the kernel environment. This only removes a hint for an + * exact unit. + */ +int +resource_unset_value(const char *name, int unit, const char *resname) +{ + char varname[128]; + const char *retname, *retvalue; + int error, line; + size_t len; + + line = 0; + error = resource_find(&line, NULL, name, &unit, resname, NULL, + &retname, NULL, NULL, NULL, NULL, &retvalue); + if (error) + return (error); + + retname -= strlen("hint."); + len = retvalue - retname - 1; + if (len > sizeof(varname) - 1) + return (ENAMETOOLONG); + memcpy(varname, retname, len); + varname[len] = '\0'; + return (kern_unsetenv(varname)); +} -- cgit v1.2.3