1a9643ea8Slogwang /*
2a9643ea8Slogwang * Copyright (c) 1998 Michael Smith. All rights reserved.
3a9643ea8Slogwang * Copyright (c) 2013 Patrick Kelsey. All rights reserved.
4*2317ada5Sfengbojiang * Copyright (C) 2017-2021 THL A29 Limited, a Tencent company.
5a9643ea8Slogwang * All rights reserved.
6a9643ea8Slogwang *
7a9643ea8Slogwang * Redistribution and use in source and binary forms, with or without
8a9643ea8Slogwang * modification, are permitted provided that the following conditions are met:
9a9643ea8Slogwang *
10a9643ea8Slogwang * 1. Redistributions of source code must retain the above copyright notice, this
11a9643ea8Slogwang * list of conditions and the following disclaimer.
12a9643ea8Slogwang * 2. Redistributions in binary form must reproduce the above copyright notice,
13a9643ea8Slogwang * this list of conditions and the following disclaimer in the documentation
14a9643ea8Slogwang * and/or other materials provided with the distribution.
15a9643ea8Slogwang *
16a9643ea8Slogwang * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17a9643ea8Slogwang * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18a9643ea8Slogwang * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19a9643ea8Slogwang * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20a9643ea8Slogwang * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21a9643ea8Slogwang * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22a9643ea8Slogwang * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23a9643ea8Slogwang * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24a9643ea8Slogwang * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25a9643ea8Slogwang * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26a9643ea8Slogwang *
27a9643ea8Slogwang * Derived from libuinet's uinet_kern_environment.c.
28a9643ea8Slogwang */
29a9643ea8Slogwang
30a9643ea8Slogwang /*
31a9643ea8Slogwang * This is an override of ken_environment.c so that get/set/put/unsetenv()
32a9643ea8Slogwang * from libc will be used, and the extended kernel environment API will
33a9643ea8Slogwang * still be available.
34a9643ea8Slogwang */
35a9643ea8Slogwang
36a9643ea8Slogwang #include <sys/cdefs.h>
37a9643ea8Slogwang __FBSDID("$FreeBSD: release/9.1.0/sys/kern/kern_environment.c 225617 2011-09-16 13:58:51Z kmacy $");
38a9643ea8Slogwang
39a9643ea8Slogwang #include <sys/types.h>
40a9643ea8Slogwang #include <sys/param.h>
41a9643ea8Slogwang #include <sys/proc.h>
42a9643ea8Slogwang #include <sys/queue.h>
43a9643ea8Slogwang #include <sys/lock.h>
44a9643ea8Slogwang #include <sys/malloc.h>
45a9643ea8Slogwang #include <sys/mutex.h>
46a9643ea8Slogwang #include <sys/priv.h>
47a9643ea8Slogwang #include <sys/kernel.h>
48a9643ea8Slogwang #include <sys/systm.h>
49a9643ea8Slogwang #include <sys/sysent.h>
50a9643ea8Slogwang #include <sys/sysproto.h>
51a9643ea8Slogwang #include <sys/libkern.h>
52a9643ea8Slogwang #include <sys/kenv.h>
5322ce4affSfengbojiang #include <sys/limits.h>
54a9643ea8Slogwang
55a9643ea8Slogwang #include "ff_host_interface.h"
56a9643ea8Slogwang
57a9643ea8Slogwang static MALLOC_DEFINE(M_KENV, "kenv", "kernel environment");
58a9643ea8Slogwang
59a9643ea8Slogwang #define KENV_SIZE 512 /* Maximum number of environment strings */
60a9643ea8Slogwang
6122ce4affSfengbojiang /* pointer to the config-generated static environment */
6222ce4affSfengbojiang char *kern_envp;
6322ce4affSfengbojiang
6422ce4affSfengbojiang /* pointer to the md-static environment */
6522ce4affSfengbojiang char *md_envp;
66a9643ea8Slogwang
67a9643ea8Slogwang /* dynamic environment variables */
68a9643ea8Slogwang char **kenvp = &kern_envp; /* points to a pointer to NULL */
69a9643ea8Slogwang struct mtx kenv_lock; /* does not need initialization - it will not be used as dynamic_kenv == 0 */
70a9643ea8Slogwang
71a9643ea8Slogwang /*
72a9643ea8Slogwang * No need to protect this with a mutex since SYSINITS are single threaded.
73a9643ea8Slogwang */
7422ce4affSfengbojiang bool dynamic_kenv = 0;
75a9643ea8Slogwang
76a9643ea8Slogwang char *
kern_getenv(const char * name)77a9643ea8Slogwang kern_getenv(const char *name)
78a9643ea8Slogwang {
79a9643ea8Slogwang return ff_getenv(name);
80a9643ea8Slogwang }
81a9643ea8Slogwang
82a9643ea8Slogwang int
kern_setenv(const char * name,const char * value)83a9643ea8Slogwang kern_setenv(const char *name, const char *value)
84a9643ea8Slogwang {
85a9643ea8Slogwang return ff_setenv(name, value);
86a9643ea8Slogwang }
87a9643ea8Slogwang
88a9643ea8Slogwang void
freeenv(char * env)89a9643ea8Slogwang freeenv(char *env)
90a9643ea8Slogwang {
91a9643ea8Slogwang ;
92a9643ea8Slogwang }
93a9643ea8Slogwang
94a9643ea8Slogwang
95a9643ea8Slogwang /*
96a9643ea8Slogwang * Test if an environment variable is defined.
97a9643ea8Slogwang */
98a9643ea8Slogwang int
testenv(const char * name)99a9643ea8Slogwang testenv(const char *name)
100a9643ea8Slogwang {
101a9643ea8Slogwang return (kern_getenv(name) != NULL);
102a9643ea8Slogwang }
103a9643ea8Slogwang
104a9643ea8Slogwang
105a9643ea8Slogwang
106a9643ea8Slogwang /*
107a9643ea8Slogwang * Return a string value from an environment variable.
108a9643ea8Slogwang */
109a9643ea8Slogwang int
getenv_string(const char * name,char * data,int size)110a9643ea8Slogwang getenv_string(const char *name, char *data, int size)
111a9643ea8Slogwang {
112a9643ea8Slogwang char *tmp;
113a9643ea8Slogwang
114a9643ea8Slogwang tmp = kern_getenv(name);
115a9643ea8Slogwang if (tmp != NULL) {
116a9643ea8Slogwang strlcpy(data, tmp, size);
117a9643ea8Slogwang freeenv(tmp);
118a9643ea8Slogwang return (1);
119a9643ea8Slogwang } else
120a9643ea8Slogwang return (0);
121a9643ea8Slogwang }
122a9643ea8Slogwang
123a9643ea8Slogwang /*
124a9643ea8Slogwang * Return an integer value from an environment variable.
125a9643ea8Slogwang */
126a9643ea8Slogwang int
getenv_int(const char * name,int * data)127a9643ea8Slogwang getenv_int(const char *name, int *data)
128a9643ea8Slogwang {
129a9643ea8Slogwang quad_t tmp;
130a9643ea8Slogwang int rval;
131a9643ea8Slogwang
132a9643ea8Slogwang rval = getenv_quad(name, &tmp);
133a9643ea8Slogwang if (rval)
134a9643ea8Slogwang *data = (int) tmp;
135a9643ea8Slogwang return (rval);
136a9643ea8Slogwang }
137a9643ea8Slogwang
138a9643ea8Slogwang /*
139a9643ea8Slogwang * Return an unsigned integer value from an environment variable.
140a9643ea8Slogwang */
141a9643ea8Slogwang int
getenv_uint(const char * name,unsigned int * data)142a9643ea8Slogwang getenv_uint(const char *name, unsigned int *data)
143a9643ea8Slogwang {
144a9643ea8Slogwang quad_t tmp;
145a9643ea8Slogwang int rval;
146a9643ea8Slogwang
147a9643ea8Slogwang rval = getenv_quad(name, &tmp);
148a9643ea8Slogwang if (rval)
149a9643ea8Slogwang *data = (unsigned int) tmp;
150a9643ea8Slogwang return (rval);
151a9643ea8Slogwang }
152a9643ea8Slogwang
153a9643ea8Slogwang /*
154a9643ea8Slogwang * Return a long value from an environment variable.
155a9643ea8Slogwang */
156a9643ea8Slogwang int
getenv_long(const char * name,long * data)157a9643ea8Slogwang getenv_long(const char *name, long *data)
158a9643ea8Slogwang {
159a9643ea8Slogwang quad_t tmp;
160a9643ea8Slogwang int rval;
161a9643ea8Slogwang
162a9643ea8Slogwang rval = getenv_quad(name, &tmp);
163a9643ea8Slogwang if (rval)
164a9643ea8Slogwang *data = (long) tmp;
165a9643ea8Slogwang return (rval);
166a9643ea8Slogwang }
167a9643ea8Slogwang
168a9643ea8Slogwang /*
169a9643ea8Slogwang * Return an unsigned long value from an environment variable.
170a9643ea8Slogwang */
171a9643ea8Slogwang int
getenv_ulong(const char * name,unsigned long * data)172a9643ea8Slogwang getenv_ulong(const char *name, unsigned long *data)
173a9643ea8Slogwang {
174a9643ea8Slogwang quad_t tmp;
175a9643ea8Slogwang int rval;
176a9643ea8Slogwang
177a9643ea8Slogwang rval = getenv_quad(name, &tmp);
178a9643ea8Slogwang if (rval)
179a9643ea8Slogwang *data = (unsigned long) tmp;
180a9643ea8Slogwang return (rval);
181a9643ea8Slogwang }
182a9643ea8Slogwang
183a9643ea8Slogwang /*
184a9643ea8Slogwang * Return a quad_t value from an environment variable.
185a9643ea8Slogwang */
186a9643ea8Slogwang int
getenv_quad(const char * name,quad_t * data)187a9643ea8Slogwang getenv_quad(const char *name, quad_t *data)
188a9643ea8Slogwang {
189a9643ea8Slogwang char *value;
190a9643ea8Slogwang char *vtp;
191a9643ea8Slogwang quad_t iv;
192a9643ea8Slogwang
193a9643ea8Slogwang value = kern_getenv(name);
194a9643ea8Slogwang if (value == NULL)
195a9643ea8Slogwang return (0);
196a9643ea8Slogwang iv = strtoq(value, &vtp, 0);
197a9643ea8Slogwang if (vtp == value || (vtp[0] != '\0' && vtp[1] != '\0')) {
198a9643ea8Slogwang freeenv(value);
199a9643ea8Slogwang return (0);
200a9643ea8Slogwang }
201a9643ea8Slogwang switch (vtp[0]) {
202a9643ea8Slogwang case 't': case 'T':
203a9643ea8Slogwang iv *= 1024;
204a9643ea8Slogwang case 'g': case 'G':
205a9643ea8Slogwang iv *= 1024;
206a9643ea8Slogwang case 'm': case 'M':
207a9643ea8Slogwang iv *= 1024;
208a9643ea8Slogwang case 'k': case 'K':
209a9643ea8Slogwang iv *= 1024;
210a9643ea8Slogwang case '\0':
211a9643ea8Slogwang break;
212a9643ea8Slogwang default:
213a9643ea8Slogwang freeenv(value);
214a9643ea8Slogwang return (0);
215a9643ea8Slogwang }
216a9643ea8Slogwang *data = iv;
217a9643ea8Slogwang freeenv(value);
218a9643ea8Slogwang return (1);
219a9643ea8Slogwang }
220a9643ea8Slogwang
22122ce4affSfengbojiang /*
22222ce4affSfengbojiang * Internal functions for string lookup.
22322ce4affSfengbojiang */
22422ce4affSfengbojiang static char *
_getenv_dynamic_locked(const char * name,int * idx)22522ce4affSfengbojiang _getenv_dynamic_locked(const char *name, int *idx)
22622ce4affSfengbojiang {
22722ce4affSfengbojiang char *cp;
22822ce4affSfengbojiang int len, i;
22922ce4affSfengbojiang
23022ce4affSfengbojiang len = strlen(name);
23122ce4affSfengbojiang for (cp = kenvp[0], i = 0; cp != NULL; cp = kenvp[++i]) {
23222ce4affSfengbojiang if ((strncmp(cp, name, len) == 0) &&
23322ce4affSfengbojiang (cp[len] == '=')) {
23422ce4affSfengbojiang if (idx != NULL)
23522ce4affSfengbojiang *idx = i;
23622ce4affSfengbojiang return (cp + len + 1);
23722ce4affSfengbojiang }
23822ce4affSfengbojiang }
23922ce4affSfengbojiang return (NULL);
24022ce4affSfengbojiang }
24122ce4affSfengbojiang
24222ce4affSfengbojiang static char *
_getenv_dynamic(const char * name,int * idx)24322ce4affSfengbojiang _getenv_dynamic(const char *name, int *idx)
24422ce4affSfengbojiang {
24522ce4affSfengbojiang
24622ce4affSfengbojiang mtx_assert(&kenv_lock, MA_OWNED);
24722ce4affSfengbojiang return (_getenv_dynamic_locked(name, idx));
24822ce4affSfengbojiang }
24922ce4affSfengbojiang
25022ce4affSfengbojiang /*
25122ce4affSfengbojiang * Find the next entry after the one which (cp) falls within, return a
25222ce4affSfengbojiang * pointer to its start or NULL if there are no more.
25322ce4affSfengbojiang */
25422ce4affSfengbojiang static char *
kernenv_next(char * cp)25522ce4affSfengbojiang kernenv_next(char *cp)
25622ce4affSfengbojiang {
25722ce4affSfengbojiang
25822ce4affSfengbojiang if (cp != NULL) {
25922ce4affSfengbojiang while (*cp != 0)
26022ce4affSfengbojiang cp++;
26122ce4affSfengbojiang cp++;
26222ce4affSfengbojiang if (*cp == 0)
26322ce4affSfengbojiang cp = NULL;
26422ce4affSfengbojiang }
26522ce4affSfengbojiang return (cp);
26622ce4affSfengbojiang }
26722ce4affSfengbojiang
26822ce4affSfengbojiang static char *
_getenv_static_from(char * chkenv,const char * name)26922ce4affSfengbojiang _getenv_static_from(char *chkenv, const char *name)
27022ce4affSfengbojiang {
27122ce4affSfengbojiang char *cp, *ep;
27222ce4affSfengbojiang int len;
27322ce4affSfengbojiang
27422ce4affSfengbojiang for (cp = chkenv; cp != NULL; cp = kernenv_next(cp)) {
27522ce4affSfengbojiang for (ep = cp; (*ep != '=') && (*ep != 0); ep++)
27622ce4affSfengbojiang ;
27722ce4affSfengbojiang if (*ep != '=')
27822ce4affSfengbojiang continue;
27922ce4affSfengbojiang len = ep - cp;
28022ce4affSfengbojiang ep++;
28122ce4affSfengbojiang if (!strncmp(name, cp, len) && name[len] == 0)
28222ce4affSfengbojiang return (ep);
28322ce4affSfengbojiang }
28422ce4affSfengbojiang return (NULL);
28522ce4affSfengbojiang }
28622ce4affSfengbojiang
28722ce4affSfengbojiang static char *
_getenv_static(const char * name)28822ce4affSfengbojiang _getenv_static(const char *name)
28922ce4affSfengbojiang {
29022ce4affSfengbojiang char *val;
29122ce4affSfengbojiang
29222ce4affSfengbojiang val = _getenv_static_from(md_envp, name);
29322ce4affSfengbojiang if (val != NULL)
29422ce4affSfengbojiang return (val);
29522ce4affSfengbojiang val = _getenv_static_from(kern_envp, name);
29622ce4affSfengbojiang if (val != NULL)
29722ce4affSfengbojiang return (val);
29822ce4affSfengbojiang return (NULL);
29922ce4affSfengbojiang }
30022ce4affSfengbojiang
30122ce4affSfengbojiang /*
30222ce4affSfengbojiang * Return the internal kenv buffer for the variable name, if it exists.
30322ce4affSfengbojiang * If the dynamic kenv is initialized and the name is present, return
30422ce4affSfengbojiang * with kenv_lock held.
30522ce4affSfengbojiang */
30622ce4affSfengbojiang static char *
kenv_acquire(const char * name)30722ce4affSfengbojiang kenv_acquire(const char *name)
30822ce4affSfengbojiang {
30922ce4affSfengbojiang char *value;
31022ce4affSfengbojiang
31122ce4affSfengbojiang if (dynamic_kenv) {
31222ce4affSfengbojiang mtx_lock(&kenv_lock);
31322ce4affSfengbojiang value = _getenv_dynamic(name, NULL);
31422ce4affSfengbojiang if (value == NULL)
31522ce4affSfengbojiang mtx_unlock(&kenv_lock);
31622ce4affSfengbojiang return (value);
31722ce4affSfengbojiang } else
31822ce4affSfengbojiang return (_getenv_static(name));
31922ce4affSfengbojiang }
32022ce4affSfengbojiang
32122ce4affSfengbojiang /*
32222ce4affSfengbojiang * Undo a previous kenv_acquire() operation
32322ce4affSfengbojiang */
32422ce4affSfengbojiang static void
kenv_release(const char * buf)32522ce4affSfengbojiang kenv_release(const char *buf)
32622ce4affSfengbojiang {
32722ce4affSfengbojiang if ((buf != NULL) && dynamic_kenv)
32822ce4affSfengbojiang mtx_unlock(&kenv_lock);
32922ce4affSfengbojiang }
33022ce4affSfengbojiang
33122ce4affSfengbojiang /*
33222ce4affSfengbojiang * Return an array of integers at the given type size and signedness.
33322ce4affSfengbojiang */
33422ce4affSfengbojiang int
getenv_array(const char * name,void * pdata,int size,int * psize,int type_size,bool allow_signed)33522ce4affSfengbojiang getenv_array(const char *name, void *pdata, int size, int *psize,
33622ce4affSfengbojiang int type_size, bool allow_signed)
33722ce4affSfengbojiang {
33822ce4affSfengbojiang uint8_t shift;
33922ce4affSfengbojiang int64_t value;
34022ce4affSfengbojiang int64_t old;
34122ce4affSfengbojiang const char *buf;
34222ce4affSfengbojiang char *end;
34322ce4affSfengbojiang const char *ptr;
34422ce4affSfengbojiang int n;
34522ce4affSfengbojiang int rc;
34622ce4affSfengbojiang
34722ce4affSfengbojiang rc = 0; /* assume failure */
34822ce4affSfengbojiang
34922ce4affSfengbojiang buf = kenv_acquire(name);
35022ce4affSfengbojiang if (buf == NULL)
35122ce4affSfengbojiang goto error;
35222ce4affSfengbojiang
35322ce4affSfengbojiang /* get maximum number of elements */
35422ce4affSfengbojiang size /= type_size;
35522ce4affSfengbojiang
35622ce4affSfengbojiang n = 0;
35722ce4affSfengbojiang
35822ce4affSfengbojiang for (ptr = buf; *ptr != 0; ) {
35922ce4affSfengbojiang value = strtoq(ptr, &end, 0);
36022ce4affSfengbojiang
36122ce4affSfengbojiang /* check if signed numbers are allowed */
36222ce4affSfengbojiang if (value < 0 && !allow_signed)
36322ce4affSfengbojiang goto error;
36422ce4affSfengbojiang
36522ce4affSfengbojiang /* check for invalid value */
36622ce4affSfengbojiang if (ptr == end)
36722ce4affSfengbojiang goto error;
36822ce4affSfengbojiang
36922ce4affSfengbojiang /* check for valid suffix */
37022ce4affSfengbojiang switch (*end) {
37122ce4affSfengbojiang case 't':
37222ce4affSfengbojiang case 'T':
37322ce4affSfengbojiang shift = 40;
37422ce4affSfengbojiang end++;
37522ce4affSfengbojiang break;
37622ce4affSfengbojiang case 'g':
37722ce4affSfengbojiang case 'G':
37822ce4affSfengbojiang shift = 30;
37922ce4affSfengbojiang end++;
38022ce4affSfengbojiang break;
38122ce4affSfengbojiang case 'm':
38222ce4affSfengbojiang case 'M':
38322ce4affSfengbojiang shift = 20;
38422ce4affSfengbojiang end++;
38522ce4affSfengbojiang break;
38622ce4affSfengbojiang case 'k':
38722ce4affSfengbojiang case 'K':
38822ce4affSfengbojiang shift = 10;
38922ce4affSfengbojiang end++;
39022ce4affSfengbojiang break;
39122ce4affSfengbojiang case ' ':
39222ce4affSfengbojiang case '\t':
39322ce4affSfengbojiang case ',':
39422ce4affSfengbojiang case 0:
39522ce4affSfengbojiang shift = 0;
39622ce4affSfengbojiang break;
39722ce4affSfengbojiang default:
39822ce4affSfengbojiang /* garbage after numeric value */
39922ce4affSfengbojiang goto error;
40022ce4affSfengbojiang }
40122ce4affSfengbojiang
40222ce4affSfengbojiang /* skip till next value, if any */
40322ce4affSfengbojiang while (*end == '\t' || *end == ',' || *end == ' ')
40422ce4affSfengbojiang end++;
40522ce4affSfengbojiang
40622ce4affSfengbojiang /* update pointer */
40722ce4affSfengbojiang ptr = end;
40822ce4affSfengbojiang
40922ce4affSfengbojiang /* apply shift */
41022ce4affSfengbojiang old = value;
41122ce4affSfengbojiang value <<= shift;
41222ce4affSfengbojiang
41322ce4affSfengbojiang /* overflow check */
41422ce4affSfengbojiang if ((value >> shift) != old)
41522ce4affSfengbojiang goto error;
41622ce4affSfengbojiang
41722ce4affSfengbojiang /* check for buffer overflow */
41822ce4affSfengbojiang if (n >= size)
41922ce4affSfengbojiang goto error;
42022ce4affSfengbojiang
42122ce4affSfengbojiang /* store value according to type size */
42222ce4affSfengbojiang switch (type_size) {
42322ce4affSfengbojiang case 1:
42422ce4affSfengbojiang if (allow_signed) {
42522ce4affSfengbojiang if (value < SCHAR_MIN || value > SCHAR_MAX)
42622ce4affSfengbojiang goto error;
42722ce4affSfengbojiang } else {
42822ce4affSfengbojiang if (value < 0 || value > UCHAR_MAX)
42922ce4affSfengbojiang goto error;
43022ce4affSfengbojiang }
43122ce4affSfengbojiang ((uint8_t *)pdata)[n] = (uint8_t)value;
43222ce4affSfengbojiang break;
43322ce4affSfengbojiang case 2:
43422ce4affSfengbojiang if (allow_signed) {
43522ce4affSfengbojiang if (value < SHRT_MIN || value > SHRT_MAX)
43622ce4affSfengbojiang goto error;
43722ce4affSfengbojiang } else {
43822ce4affSfengbojiang if (value < 0 || value > USHRT_MAX)
43922ce4affSfengbojiang goto error;
44022ce4affSfengbojiang }
44122ce4affSfengbojiang ((uint16_t *)pdata)[n] = (uint16_t)value;
44222ce4affSfengbojiang break;
44322ce4affSfengbojiang case 4:
44422ce4affSfengbojiang if (allow_signed) {
44522ce4affSfengbojiang if (value < INT_MIN || value > INT_MAX)
44622ce4affSfengbojiang goto error;
44722ce4affSfengbojiang } else {
44822ce4affSfengbojiang if (value > UINT_MAX)
44922ce4affSfengbojiang goto error;
45022ce4affSfengbojiang }
45122ce4affSfengbojiang ((uint32_t *)pdata)[n] = (uint32_t)value;
45222ce4affSfengbojiang break;
45322ce4affSfengbojiang case 8:
45422ce4affSfengbojiang ((uint64_t *)pdata)[n] = (uint64_t)value;
45522ce4affSfengbojiang break;
45622ce4affSfengbojiang default:
45722ce4affSfengbojiang goto error;
45822ce4affSfengbojiang }
45922ce4affSfengbojiang n++;
46022ce4affSfengbojiang }
46122ce4affSfengbojiang *psize = n * type_size;
46222ce4affSfengbojiang
46322ce4affSfengbojiang if (n != 0)
46422ce4affSfengbojiang rc = 1; /* success */
46522ce4affSfengbojiang error:
46622ce4affSfengbojiang kenv_release(buf);
46722ce4affSfengbojiang return (rc);
46822ce4affSfengbojiang }
469a9643ea8Slogwang
470a9643ea8Slogwang void
tunable_int_init(void * data)471a9643ea8Slogwang tunable_int_init(void *data)
472a9643ea8Slogwang {
473a9643ea8Slogwang struct tunable_int *d = (struct tunable_int *)data;
474a9643ea8Slogwang
475a9643ea8Slogwang TUNABLE_INT_FETCH(d->path, d->var);
476a9643ea8Slogwang }
477a9643ea8Slogwang
478a9643ea8Slogwang void
tunable_long_init(void * data)479a9643ea8Slogwang tunable_long_init(void *data)
480a9643ea8Slogwang {
481a9643ea8Slogwang struct tunable_long *d = (struct tunable_long *)data;
482a9643ea8Slogwang
483a9643ea8Slogwang TUNABLE_LONG_FETCH(d->path, d->var);
484a9643ea8Slogwang }
485a9643ea8Slogwang
486a9643ea8Slogwang void
tunable_ulong_init(void * data)487a9643ea8Slogwang tunable_ulong_init(void *data)
488a9643ea8Slogwang {
489a9643ea8Slogwang struct tunable_ulong *d = (struct tunable_ulong *)data;
490a9643ea8Slogwang
491a9643ea8Slogwang TUNABLE_ULONG_FETCH(d->path, d->var);
492a9643ea8Slogwang }
493a9643ea8Slogwang
494a9643ea8Slogwang void
tunable_quad_init(void * data)495a9643ea8Slogwang tunable_quad_init(void *data)
496a9643ea8Slogwang {
497a9643ea8Slogwang struct tunable_quad *d = (struct tunable_quad *)data;
498a9643ea8Slogwang
499a9643ea8Slogwang TUNABLE_QUAD_FETCH(d->path, d->var);
500a9643ea8Slogwang }
501a9643ea8Slogwang
502a9643ea8Slogwang void
tunable_str_init(void * data)503a9643ea8Slogwang tunable_str_init(void *data)
504a9643ea8Slogwang {
505a9643ea8Slogwang struct tunable_str *d = (struct tunable_str *)data;
506a9643ea8Slogwang
507a9643ea8Slogwang TUNABLE_STR_FETCH(d->path, d->var, d->size);
508a9643ea8Slogwang }
509a9643ea8Slogwang
510