sysctl.c revision 1.16 1 /* $NetBSD: sysctl.c,v 1.16 2004/03/24 15:34:56 atatat Exp $ */
2
3 /*-
4 * Copyright (c) 1993
5 * The Regents of the University of California. 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
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 #if defined(LIBC_SCCS) && !defined(lint)
34 #if 0
35 static char sccsid[] = "@(#)sysctl.c 8.2 (Berkeley) 1/4/94";
36 #else
37 __RCSID("$NetBSD: sysctl.c,v 1.16 2004/03/24 15:34:56 atatat Exp $");
38 #endif
39 #endif /* LIBC_SCCS and not lint */
40
41 #include "namespace.h"
42 #include <sys/param.h>
43 #include <sys/sysctl.h>
44
45 #include <errno.h>
46 #include <paths.h>
47 #include <stdio.h>
48 #include <string.h>
49 #include <unistd.h>
50 #include "extern.h"
51
52 #ifdef __weak_alias
53 __weak_alias(sysctl,_sysctl)
54 #endif
55
56 /*
57 * handles requests off the user subtree
58 */
59 static int user_sysctl(int *, u_int, void *, size_t *, const void *, size_t);
60
61 #include <stdlib.h>
62
63 int
64 sysctl(name, namelen, oldp, oldlenp, newp, newlen)
65 int *name;
66 unsigned int namelen;
67 void *oldp;
68 const void *newp;
69 size_t *oldlenp, newlen;
70 {
71 size_t oldlen, savelen;
72 int error;
73
74 if (getenv("SYSCTL_TRACE") != NULL) {
75 char trb[128];
76 uint l, i;
77
78 l = snprintf(trb, sizeof(trb), "sysctl(%p {", name);
79 write(2, &trb[0], l);
80 for (i = 0; i < namelen; i++) {
81 l = snprintf(trb, sizeof(trb), "%s%d", i ? "." : "",
82 name[i]);
83 write(2, &trb[0], l);
84 }
85 l = snprintf(trb, sizeof(trb), "}, %d, %p, %p (%lu), %p, %lu)\n",
86 namelen,
87 oldp,
88 oldlenp, (ulong)(oldlenp ? *oldlenp : 0),
89 newp,
90 (ulong)newlen);
91 write(2, &trb[0], l);
92 }
93
94 if (name[0] != CTL_USER)
95 /* LINTED will fix when sysctl interface gets corrected */
96 /* XXX when will that be? */
97 return (__sysctl(name, namelen, oldp, oldlenp,
98 (void *)newp, newlen));
99
100 oldlen = (oldlenp == NULL) ? 0 : *oldlenp;
101 savelen = oldlen;
102 error = user_sysctl(name + 1, namelen - 1, oldp, &oldlen, newp, newlen);
103
104 if (error != 0) {
105 errno = error;
106 return (-1);
107 }
108
109 if (oldlenp != NULL) {
110 *oldlenp = oldlen;
111 if (oldp != NULL && oldlen > savelen) {
112 errno = ENOMEM;
113 return (-1);
114 }
115 }
116
117 return (0);
118 }
119
120 static int
121 user_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
122 int *name;
123 unsigned int namelen;
124 void *oldp;
125 const void *newp;
126 size_t *oldlenp, newlen;
127 {
128 #define _INT(s, n, v) { \
129 .sysctl_flags = CTLFLAG_IMMEDIATE|CTLFLAG_PERMANENT| \
130 CTLTYPE_INT|SYSCTL_VERSION, \
131 .sysctl_size = sizeof(int), \
132 .sysctl_name = (s), \
133 .sysctl_num = (n), \
134 .sysctl_un = { .scu_idata = (v), }, }
135
136 /*
137 * the nodes under the "user" node
138 */
139 static const struct sysctlnode sysctl_usermib[] = {
140 #if defined(lint)
141 /*
142 * lint doesn't like my initializers
143 */
144 0
145 #else /* !lint */
146 {
147 .sysctl_flags = SYSCTL_VERSION|CTLFLAG_PERMANENT|
148 CTLTYPE_STRING,
149 .sysctl_size = sizeof(_PATH_STDPATH),
150 .sysctl_name = "cs_path",
151 .sysctl_num = USER_CS_PATH,
152 .sysctl_un = { .scu_data = _PATH_STDPATH, },
153 },
154 _INT("bc_base_max", USER_BC_BASE_MAX, BC_BASE_MAX),
155 _INT("bc_dim_max", USER_BC_DIM_MAX, BC_DIM_MAX),
156 _INT("bc_scale_max", USER_BC_SCALE_MAX, BC_SCALE_MAX),
157 _INT("bc_string_max", USER_BC_STRING_MAX, BC_STRING_MAX),
158 _INT("coll_weights_max", USER_COLL_WEIGHTS_MAX,
159 COLL_WEIGHTS_MAX),
160 _INT("expr_nest_max", USER_EXPR_NEST_MAX, EXPR_NEST_MAX),
161 _INT("line_max", USER_LINE_MAX, LINE_MAX),
162 _INT("re_dup_max", USER_RE_DUP_MAX, RE_DUP_MAX),
163 _INT("posix2_version", USER_POSIX2_VERSION, _POSIX2_VERSION),
164 #ifdef POSIX2_C_BIND
165 _INT("posix2_c_bind", USER_POSIX2_C_BIND, 1),
166 #else
167 _INT("posix2_c_bind", USER_POSIX2_C_BIND, 0),
168 #endif
169 #ifdef POSIX2_C_DEV
170 _INT("posix2_c_dev", USER_POSIX2_C_DEV, 1),
171 #else
172 _INT("posix2_c_dev", USER_POSIX2_C_DEV, 0),
173 #endif
174 #ifdef POSIX2_CHAR_TERM
175 _INT("posix2_char_term", USER_POSIX2_CHAR_TERM, 1),
176 #else
177 _INT("posix2_char_term", USER_POSIX2_CHAR_TERM, 0),
178 #endif
179 #ifdef POSIX2_FORT_DEV
180 _INT("posix2_fort_dev", USER_POSIX2_FORT_DEV, 1),
181 #else
182 _INT("posix2_fort_dev", USER_POSIX2_FORT_DEV, 0),
183 #endif
184 #ifdef POSIX2_FORT_RUN
185 _INT("posix2_fort_run", USER_POSIX2_FORT_RUN, 1),
186 #else
187 _INT("posix2_fort_run", USER_POSIX2_FORT_RUN, 0),
188 #endif
189 #ifdef POSIX2_LOCALEDEF
190 _INT("posix2_localedef", USER_POSIX2_LOCALEDEF, 1),
191 #else
192 _INT("posix2_localedef", USER_POSIX2_LOCALEDEF, 0),
193 #endif
194 #ifdef POSIX2_SW_DEV
195 _INT("posix2_sw_dev", USER_POSIX2_SW_DEV, 1),
196 #else
197 _INT("posix2_sw_dev", USER_POSIX2_SW_DEV, 0),
198 #endif
199 #ifdef POSIX2_UPE
200 _INT("posix2_upe", USER_POSIX2_UPE, 1),
201 #else
202 _INT("posix2_upe", USER_POSIX2_UPE, 0),
203 #endif
204 _INT("stream_max", USER_STREAM_MAX, FOPEN_MAX),
205 _INT("tzname_max", USER_TZNAME_MAX, NAME_MAX),
206 _INT("atexit_max", USER_ATEXIT_MAX, -1),
207 #endif /* !lint */
208 };
209 #undef _INT
210
211 static const int clen = sizeof(sysctl_usermib) /
212 sizeof(sysctl_usermib[0]);
213
214 const struct sysctlnode *node;
215 int ni;
216 size_t l, sz;
217
218 /*
219 * none of these nodes are writable and they're all terminal (for now)
220 */
221 if (newp != NULL || newlen != 0)
222 return (EPERM);
223 if (namelen != 1)
224 return (EINVAL);
225
226 l = *oldlenp;
227 if (name[0] == CTL_QUERY) {
228 sz = clen * sizeof(struct sysctlnode);
229 l = MIN(l, sz);
230 if (oldp != NULL)
231 memcpy(oldp, &sysctl_usermib[0], l);
232 *oldlenp = sz;
233 return (0);
234 }
235
236 node = &sysctl_usermib[0];
237 for (ni = 0; ni < clen; ni++)
238 if (name[0] == node[ni].sysctl_num)
239 break;
240 if (ni == clen)
241 return (EOPNOTSUPP);
242
243 node = &node[ni];
244 if (node->sysctl_flags & CTLFLAG_IMMEDIATE) {
245 switch (SYSCTL_TYPE(node->sysctl_flags)) {
246 case CTLTYPE_INT:
247 newp = &node->sysctl_idata;
248 break;
249 case CTLTYPE_QUAD:
250 newp = &node->sysctl_qdata;
251 break;
252 default:
253 return (EINVAL);
254 }
255 }
256 else
257 newp = node->sysctl_data;
258
259 l = MIN(l, node->sysctl_size);
260 if (oldp != NULL)
261 memcpy(oldp, newp, l);
262 *oldlenp = node->sysctl_size;
263
264 return (0);
265 }
266