1 /* 2 * Copyright (c) 1998 Michael Smith. All rights reserved. 3 * Copyright (c) 2013 Patrick Kelsey. All rights reserved. 4 * Copyright (C) 2017-2021 THL A29 Limited, a Tencent company. 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 are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright notice, this 11 * list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright notice, 13 * this list of conditions and the following disclaimer in the documentation 14 * and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 * 27 * Derived from libuinet's uinet_kern_environment.c. 28 */ 29 30 /* 31 * This is an override of ken_environment.c so that get/set/put/unsetenv() 32 * from libc will be used, and the extended kernel environment API will 33 * still be available. 34 */ 35 36 #include <sys/cdefs.h> 37 __FBSDID("$FreeBSD: release/9.1.0/sys/kern/kern_environment.c 225617 2011-09-16 13:58:51Z kmacy $"); 38 39 #include <sys/types.h> 40 #include <sys/param.h> 41 #include <sys/proc.h> 42 #include <sys/queue.h> 43 #include <sys/lock.h> 44 #include <sys/malloc.h> 45 #include <sys/mutex.h> 46 #include <sys/priv.h> 47 #include <sys/kernel.h> 48 #include <sys/systm.h> 49 #include <sys/sysent.h> 50 #include <sys/sysproto.h> 51 #include <sys/libkern.h> 52 #include <sys/kenv.h> 53 #include <sys/limits.h> 54 55 #include "ff_host_interface.h" 56 57 static MALLOC_DEFINE(M_KENV, "kenv", "kernel environment"); 58 59 #define KENV_SIZE 512 /* Maximum number of environment strings */ 60 61 /* pointer to the config-generated static environment */ 62 char *kern_envp; 63 64 /* pointer to the md-static environment */ 65 char *md_envp; 66 67 /* dynamic environment variables */ 68 char **kenvp = &kern_envp; /* points to a pointer to NULL */ 69 struct mtx kenv_lock; /* does not need initialization - it will not be used as dynamic_kenv == 0 */ 70 71 /* 72 * No need to protect this with a mutex since SYSINITS are single threaded. 73 */ 74 bool dynamic_kenv = 0; 75 76 char * 77 kern_getenv(const char *name) 78 { 79 return ff_getenv(name); 80 } 81 82 int 83 kern_setenv(const char *name, const char *value) 84 { 85 return ff_setenv(name, value); 86 } 87 88 void 89 freeenv(char *env) 90 { 91 ; 92 } 93 94 95 /* 96 * Test if an environment variable is defined. 97 */ 98 int 99 testenv(const char *name) 100 { 101 return (kern_getenv(name) != NULL); 102 } 103 104 105 106 /* 107 * Return a string value from an environment variable. 108 */ 109 int 110 getenv_string(const char *name, char *data, int size) 111 { 112 char *tmp; 113 114 tmp = kern_getenv(name); 115 if (tmp != NULL) { 116 strlcpy(data, tmp, size); 117 freeenv(tmp); 118 return (1); 119 } else 120 return (0); 121 } 122 123 /* 124 * Return an integer value from an environment variable. 125 */ 126 int 127 getenv_int(const char *name, int *data) 128 { 129 quad_t tmp; 130 int rval; 131 132 rval = getenv_quad(name, &tmp); 133 if (rval) 134 *data = (int) tmp; 135 return (rval); 136 } 137 138 /* 139 * Return an unsigned integer value from an environment variable. 140 */ 141 int 142 getenv_uint(const char *name, unsigned int *data) 143 { 144 quad_t tmp; 145 int rval; 146 147 rval = getenv_quad(name, &tmp); 148 if (rval) 149 *data = (unsigned int) tmp; 150 return (rval); 151 } 152 153 /* 154 * Return a long value from an environment variable. 155 */ 156 int 157 getenv_long(const char *name, long *data) 158 { 159 quad_t tmp; 160 int rval; 161 162 rval = getenv_quad(name, &tmp); 163 if (rval) 164 *data = (long) tmp; 165 return (rval); 166 } 167 168 /* 169 * Return an unsigned long value from an environment variable. 170 */ 171 int 172 getenv_ulong(const char *name, unsigned long *data) 173 { 174 quad_t tmp; 175 int rval; 176 177 rval = getenv_quad(name, &tmp); 178 if (rval) 179 *data = (unsigned long) tmp; 180 return (rval); 181 } 182 183 /* 184 * Return a quad_t value from an environment variable. 185 */ 186 int 187 getenv_quad(const char *name, quad_t *data) 188 { 189 char *value; 190 char *vtp; 191 quad_t iv; 192 193 value = kern_getenv(name); 194 if (value == NULL) 195 return (0); 196 iv = strtoq(value, &vtp, 0); 197 if (vtp == value || (vtp[0] != '\0' && vtp[1] != '\0')) { 198 freeenv(value); 199 return (0); 200 } 201 switch (vtp[0]) { 202 case 't': case 'T': 203 iv *= 1024; 204 case 'g': case 'G': 205 iv *= 1024; 206 case 'm': case 'M': 207 iv *= 1024; 208 case 'k': case 'K': 209 iv *= 1024; 210 case '\0': 211 break; 212 default: 213 freeenv(value); 214 return (0); 215 } 216 *data = iv; 217 freeenv(value); 218 return (1); 219 } 220 221 /* 222 * Internal functions for string lookup. 223 */ 224 static char * 225 _getenv_dynamic_locked(const char *name, int *idx) 226 { 227 char *cp; 228 int len, i; 229 230 len = strlen(name); 231 for (cp = kenvp[0], i = 0; cp != NULL; cp = kenvp[++i]) { 232 if ((strncmp(cp, name, len) == 0) && 233 (cp[len] == '=')) { 234 if (idx != NULL) 235 *idx = i; 236 return (cp + len + 1); 237 } 238 } 239 return (NULL); 240 } 241 242 static char * 243 _getenv_dynamic(const char *name, int *idx) 244 { 245 246 mtx_assert(&kenv_lock, MA_OWNED); 247 return (_getenv_dynamic_locked(name, idx)); 248 } 249 250 /* 251 * Find the next entry after the one which (cp) falls within, return a 252 * pointer to its start or NULL if there are no more. 253 */ 254 static char * 255 kernenv_next(char *cp) 256 { 257 258 if (cp != NULL) { 259 while (*cp != 0) 260 cp++; 261 cp++; 262 if (*cp == 0) 263 cp = NULL; 264 } 265 return (cp); 266 } 267 268 static char * 269 _getenv_static_from(char *chkenv, const char *name) 270 { 271 char *cp, *ep; 272 int len; 273 274 for (cp = chkenv; cp != NULL; cp = kernenv_next(cp)) { 275 for (ep = cp; (*ep != '=') && (*ep != 0); ep++) 276 ; 277 if (*ep != '=') 278 continue; 279 len = ep - cp; 280 ep++; 281 if (!strncmp(name, cp, len) && name[len] == 0) 282 return (ep); 283 } 284 return (NULL); 285 } 286 287 static char * 288 _getenv_static(const char *name) 289 { 290 char *val; 291 292 val = _getenv_static_from(md_envp, name); 293 if (val != NULL) 294 return (val); 295 val = _getenv_static_from(kern_envp, name); 296 if (val != NULL) 297 return (val); 298 return (NULL); 299 } 300 301 /* 302 * Return the internal kenv buffer for the variable name, if it exists. 303 * If the dynamic kenv is initialized and the name is present, return 304 * with kenv_lock held. 305 */ 306 static char * 307 kenv_acquire(const char *name) 308 { 309 char *value; 310 311 if (dynamic_kenv) { 312 mtx_lock(&kenv_lock); 313 value = _getenv_dynamic(name, NULL); 314 if (value == NULL) 315 mtx_unlock(&kenv_lock); 316 return (value); 317 } else 318 return (_getenv_static(name)); 319 } 320 321 /* 322 * Undo a previous kenv_acquire() operation 323 */ 324 static void 325 kenv_release(const char *buf) 326 { 327 if ((buf != NULL) && dynamic_kenv) 328 mtx_unlock(&kenv_lock); 329 } 330 331 /* 332 * Return an array of integers at the given type size and signedness. 333 */ 334 int 335 getenv_array(const char *name, void *pdata, int size, int *psize, 336 int type_size, bool allow_signed) 337 { 338 uint8_t shift; 339 int64_t value; 340 int64_t old; 341 const char *buf; 342 char *end; 343 const char *ptr; 344 int n; 345 int rc; 346 347 rc = 0; /* assume failure */ 348 349 buf = kenv_acquire(name); 350 if (buf == NULL) 351 goto error; 352 353 /* get maximum number of elements */ 354 size /= type_size; 355 356 n = 0; 357 358 for (ptr = buf; *ptr != 0; ) { 359 value = strtoq(ptr, &end, 0); 360 361 /* check if signed numbers are allowed */ 362 if (value < 0 && !allow_signed) 363 goto error; 364 365 /* check for invalid value */ 366 if (ptr == end) 367 goto error; 368 369 /* check for valid suffix */ 370 switch (*end) { 371 case 't': 372 case 'T': 373 shift = 40; 374 end++; 375 break; 376 case 'g': 377 case 'G': 378 shift = 30; 379 end++; 380 break; 381 case 'm': 382 case 'M': 383 shift = 20; 384 end++; 385 break; 386 case 'k': 387 case 'K': 388 shift = 10; 389 end++; 390 break; 391 case ' ': 392 case '\t': 393 case ',': 394 case 0: 395 shift = 0; 396 break; 397 default: 398 /* garbage after numeric value */ 399 goto error; 400 } 401 402 /* skip till next value, if any */ 403 while (*end == '\t' || *end == ',' || *end == ' ') 404 end++; 405 406 /* update pointer */ 407 ptr = end; 408 409 /* apply shift */ 410 old = value; 411 value <<= shift; 412 413 /* overflow check */ 414 if ((value >> shift) != old) 415 goto error; 416 417 /* check for buffer overflow */ 418 if (n >= size) 419 goto error; 420 421 /* store value according to type size */ 422 switch (type_size) { 423 case 1: 424 if (allow_signed) { 425 if (value < SCHAR_MIN || value > SCHAR_MAX) 426 goto error; 427 } else { 428 if (value < 0 || value > UCHAR_MAX) 429 goto error; 430 } 431 ((uint8_t *)pdata)[n] = (uint8_t)value; 432 break; 433 case 2: 434 if (allow_signed) { 435 if (value < SHRT_MIN || value > SHRT_MAX) 436 goto error; 437 } else { 438 if (value < 0 || value > USHRT_MAX) 439 goto error; 440 } 441 ((uint16_t *)pdata)[n] = (uint16_t)value; 442 break; 443 case 4: 444 if (allow_signed) { 445 if (value < INT_MIN || value > INT_MAX) 446 goto error; 447 } else { 448 if (value > UINT_MAX) 449 goto error; 450 } 451 ((uint32_t *)pdata)[n] = (uint32_t)value; 452 break; 453 case 8: 454 ((uint64_t *)pdata)[n] = (uint64_t)value; 455 break; 456 default: 457 goto error; 458 } 459 n++; 460 } 461 *psize = n * type_size; 462 463 if (n != 0) 464 rc = 1; /* success */ 465 error: 466 kenv_release(buf); 467 return (rc); 468 } 469 470 void 471 tunable_int_init(void *data) 472 { 473 struct tunable_int *d = (struct tunable_int *)data; 474 475 TUNABLE_INT_FETCH(d->path, d->var); 476 } 477 478 void 479 tunable_long_init(void *data) 480 { 481 struct tunable_long *d = (struct tunable_long *)data; 482 483 TUNABLE_LONG_FETCH(d->path, d->var); 484 } 485 486 void 487 tunable_ulong_init(void *data) 488 { 489 struct tunable_ulong *d = (struct tunable_ulong *)data; 490 491 TUNABLE_ULONG_FETCH(d->path, d->var); 492 } 493 494 void 495 tunable_quad_init(void *data) 496 { 497 struct tunable_quad *d = (struct tunable_quad *)data; 498 499 TUNABLE_QUAD_FETCH(d->path, d->var); 500 } 501 502 void 503 tunable_str_init(void *data) 504 { 505 struct tunable_str *d = (struct tunable_str *)data; 506 507 TUNABLE_STR_FETCH(d->path, d->var, d->size); 508 } 509 510