Index: head/share/man/man9/Makefile =================================================================== --- head/share/man/man9/Makefile +++ head/share/man/man9/Makefile @@ -1092,6 +1092,9 @@ getenv.9 getenv_quad.9 \ getenv.9 getenv_uint.9 \ getenv.9 getenv_ulong.9 \ + getenv.9 getenv_bool.9 \ + getenv.9 getenv_is_true.9 \ + getenv.9 getenv_is_false.9 \ getenv.9 kern_getenv.9 \ getenv.9 kern_setenv.9 \ getenv.9 kern_unsetenv.9 \ Index: head/share/man/man9/getenv.9 =================================================================== --- head/share/man/man9/getenv.9 +++ head/share/man/man9/getenv.9 @@ -27,7 +27,7 @@ .\" .\" $FreeBSD$ .\" -.Dd June 1, 2017 +.Dd September 21, 2020 .Dt GETENV 9 .Os .Sh NAME @@ -39,6 +39,9 @@ .Nm getenv_quad , .Nm getenv_uint , .Nm getenv_ulong , +.Nm getenv_bool , +.Nm getenv_is_true , +.Nm getenv_is_false , .Nm kern_setenv , .Nm testenv , .Nm kern_unsetenv @@ -63,6 +66,12 @@ .Ft int .Fn getenv_ulong "const char *name" "unsigned long *data" .Ft int +.Fn getenv_bool "const char *name" "bool *data" +.Ft bool +.Fn getenv_is_true "const char *name" +.Ft bool +.Fn getenv_is_false "const char *name" +.Ft int .Fn kern_setenv "const char *name" "const char *value" .Ft int .Fn testenv "const char *name" @@ -194,6 +203,28 @@ characters of its value are copied to the buffer pointed to by .Fa data followed by a null character and a non-zero value is returned. +.Pp +The +.Fn getenv_bool +function interprets the value of the kernel environment variable +.Fa name +as a boolean value by performing a case-insensitive comparison against the +strings "1", +"0", +"true", +and "false". +If the environment variable exists and has a valid boolean value, then that +value will be copied to the variable pointed to by +.Fa data . +If the environment variable exists but is not a boolean value, then a warning +will be printed to the kernel message buffer. +The +.Fn getenv_is_true +and +.Fn getenv_is_false +functions are wrappers around +.Fn getenv_bool +that simplify testing for a desired boolean value. .Sh RETURN VALUES The .Fn kern_getenv @@ -211,12 +242,25 @@ .Fn testenv function returns zero if the specified environment variable does not exist and a non-zero value if it does exist. +.Pp The .Fn getenv_int , .Fn getenv_long , .Fn getenv_string , .Fn getenv_quad , .Fn getenv_uint , +.Fn getenv_ulong , and -.Fn getenv_ulong +.Fn getenv_bool functions return a non-zero value on success and zero on failure. +.Pp +The +.Fn getenv_is_true +and +.Fn getenv_is_false +functions return +.Dv true +if the specified environment variable exists and its value matches the desired +boolean condition, and +.Dv false +otherwise. Index: head/sys/kern/kern_environment.c =================================================================== --- head/sys/kern/kern_environment.c +++ head/sys/kern/kern_environment.c @@ -942,6 +942,65 @@ } /* + * Return a boolean value from an environment variable. This can be in + * numerical or string form, i.e. "1" or "true". + */ +int +getenv_bool(const char *name, bool *data) +{ + char *val; + int ret = 0; + + if (name == NULL) + return (0); + + val = kern_getenv(name); + if (val == NULL) + return (0); + + if ((strcmp(val, "1") == 0) || (strcasecmp(val, "true") == 0)) { + *data = true; + ret = 1; + } else if ((strcmp(val, "0") == 0) || (strcasecmp(val, "false") == 0)) { + *data = false; + ret = 1; + } else { + /* Spit out a warning for malformed boolean variables. */ + printf("Environment variable %s has non-boolean value \"%s\"\n", + name, val); + } + freeenv(val); + + return (ret); +} + +/* + * Wrapper around getenv_bool to easily check for true. + */ +bool +getenv_is_true(const char *name) +{ + bool val; + + if (getenv_bool(name, &val) != 0) + return (val); + return (false); +} + +/* + * Wrapper around getenv_bool to easily check for false. + */ +bool +getenv_is_false(const char *name) +{ + bool val; + + if (getenv_bool(name, &val) != 0) + return (!val); + return (false); +} + +/* * Find the next entry after the one which (cp) falls within, return a * pointer to its start or NULL if there are no more. */ @@ -1005,6 +1064,14 @@ struct tunable_quad *d = (struct tunable_quad *)data; TUNABLE_QUAD_FETCH(d->path, d->var); +} + +void +tunable_bool_init(void *data) +{ + struct tunable_bool *d = (struct tunable_bool *)data; + + TUNABLE_BOOL_FETCH(d->path, d->var); } void Index: head/sys/sys/kernel.h =================================================================== --- head/sys/sys/kernel.h +++ head/sys/sys/kernel.h @@ -421,6 +421,25 @@ #define TUNABLE_QUAD_FETCH(path, var) getenv_quad((path), (var)) +/* + * bool + */ +extern void tunable_bool_init(void *); +struct tunable_bool { + const char *path; + bool *var; +}; +#define TUNABLE_BOOL(path, var) \ + static struct tunable_bool __CONCAT(__tunable_bool_, __LINE__) = { \ + (path), \ + (var), \ + }; \ + SYSINIT(__CONCAT(__Tunable_init_, __LINE__), \ + SI_SUB_TUNABLES, SI_ORDER_MIDDLE, tunable_bool_init, \ + &__CONCAT(__tunable_bool_, __LINE__)) + +#define TUNABLE_BOOL_FETCH(path, var) getenv_bool((path), (var)) + extern void tunable_str_init(void *); struct tunable_str { const char *path; Index: head/sys/sys/systm.h =================================================================== --- head/sys/sys/systm.h +++ head/sys/sys/systm.h @@ -461,6 +461,9 @@ int getenv_int64(const char *name, int64_t *data); int getenv_uint64(const char *name, uint64_t *data); int getenv_quad(const char *name, quad_t *data); +int getenv_bool(const char *name, bool *data); +bool getenv_is_true(const char *name); +bool getenv_is_false(const char *name); int kern_setenv(const char *name, const char *value); int kern_unsetenv(const char *name); int testenv(const char *name);