summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/kern/subr_hints.c
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2016-10-07 15:10:20 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2017-01-10 09:53:31 +0100
commitc40e45b75eb76d79a05c7fa85c1fa9b5c728a12f (patch)
treead4f2519067709f00ab98b3c591186c26dc3a21f /freebsd/sys/kern/subr_hints.c
parentuserspace-header-gen.py: Simplify program ports (diff)
downloadrtems-libbsd-c40e45b75eb76d79a05c7fa85c1fa9b5c728a12f.tar.bz2
Update to FreeBSD head 2016-08-23
Git mirror commit 9fe7c416e6abb28b1398fd3e5687099846800cfd.
Diffstat (limited to 'freebsd/sys/kern/subr_hints.c')
-rw-r--r--freebsd/sys/kern/subr_hints.c122
1 files changed, 116 insertions, 6 deletions
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 <rtems/bsd/sys/param.h>
#include <rtems/bsd/sys/lock.h>
+#include <sys/malloc.h>
#include <sys/mutex.h>
+#include <sys/sysctl.h>
#include <sys/systm.h>
#include <sys/bus.h>
@@ -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));
+}