1 /* $NetBSD: freebsd_sysctl.c,v 1.14 2008/04/28 20:23:41 martin Exp $ */
2
3 /*-
4 * Copyright (c) 2005 The NetBSD Foundation, Inc.
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
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 *
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /*
30 * FreeBSD compatibility module. Try to deal with various FreeBSD sysctl calls.
31 */
32
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: freebsd_sysctl.c,v 1.14 2008/04/28 20:23:41 martin Exp $");
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/proc.h>
39 #include <sys/mount.h>
40 #include <sys/signal.h>
41 #include <sys/signalvar.h>
42 #include <sys/malloc.h>
43 #include <sys/mman.h>
44 #include <sys/sysctl.h>
45 #include <sys/ktrace.h>
46
47 #include <sys/syscallargs.h>
48
49 #include <compat/freebsd/freebsd_syscallargs.h>
50 #include <compat/common/compat_util.h>
51 #include <compat/freebsd/freebsd_rtprio.h>
52 #include <compat/freebsd/freebsd_timex.h>
53 #include <compat/freebsd/freebsd_signal.h>
54 #include <compat/freebsd/freebsd_mman.h>
55
56 static int freebsd_sysctl_name2oid(char *, int *, int *);
57
58 SYSCTL_SETUP_PROTO(freebsd_sysctl_setup);
59 SYSCTL_SETUP(freebsd_sysctl_setup, "freebsd emulated sysctl setup")
60 {
61 sysctl_createv(clog, 0, NULL, NULL,
62 CTLFLAG_PERMANENT,
63 CTLTYPE_NODE, "kern", NULL,
64 NULL, 0, NULL, 0,
65 CTL_KERN, CTL_EOL);
66 sysctl_createv(clog, 0, NULL, NULL,
67 CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE,
68 CTLTYPE_INT, "osreldate",
69 SYSCTL_DESCR("Operating system revision"),
70 NULL, __NetBSD_Version__, NULL, 0,
71 CTL_KERN, CTL_CREATE, CTL_EOL);
72 }
73
74 int
75 freebsd_sys_sysctl(struct lwp *l, const struct freebsd_sys_sysctl_args *uap, register_t *retval)
76 {
77 /* {
78 syscallarg(int *) name;
79 syscallarg(u_int) namelen;
80 syscallarg(void *) old;
81 syscallarg(size_t *) oldlenp;
82 syscallarg(void *) new;
83 syscallarg(size_t) newlen;
84 } */
85 int error;
86 int name[CTL_MAXNAME];
87 size_t newlen, *oldlenp;
88 u_int namelen;
89 void *new, *old;
90
91 namelen = SCARG(uap, namelen);
92
93 if ((namelen > CTL_MAXNAME) || (namelen < 1))
94 return EINVAL;
95
96 if ((error = copyin(SCARG(uap, name), name,
97 namelen * sizeof(*name))) != 0)
98 return error;
99
100 if (namelen > 0 && name[0] != 0)
101 return(sys___sysctl(l, (const void *)uap, retval));
102
103 ktrmib(name, namelen);
104
105 /*
106 * FreeBSD sysctl uses an undocumented set of special OIDs in it's
107 * sysctl MIB whose tree is rooted at oid 0. These OIDs are
108 * interpretted by their sysctl to implement functions that NetBSD
109 * performs in libc, such as sysctlgetmibinfo.
110 *
111 * From the FreeBSD kern_sysctl.c, these OIDs are:
112 * {0,0} printf the entire MIB-tree.
113 * {0,1,...} return the name of the "..." OID.
114 * {0,2,...} return the next OID.
115 * {0,3} return the OID of the name in "new"
116 * {0,4,...} return the kind & format info for the "..." OID.
117 * {0,5,...} return the description the "..." OID.
118 *
119 * Only implement {0,3} for now.
120 */
121
122 if (namelen < 2 || namelen > CTL_MAXNAME)
123 return(EINVAL);
124
125 if (name[1] == 3) {
126 char *locnew;
127 int oid[CTL_MAXNAME];
128 u_int oidlen = CTL_MAXNAME;
129
130 new = SCARG(uap, new);
131 newlen = SCARG(uap, newlen);
132 if (new == NULL || newlen < 1 ||
133 newlen > (SYSCTL_NAMELEN * CTL_MAXNAME))
134 return(EINVAL);
135
136 old = SCARG(uap, old);
137 oldlenp = SCARG(uap, oldlenp);
138 if (old == NULL || oldlenp == NULL || *oldlenp < sizeof(int))
139 return(EINVAL);
140
141 if ((locnew =
142 (char *) malloc(newlen + 1, M_TEMP, M_WAITOK)) == NULL)
143 return(ENOMEM);
144
145 if ((error = copyinstr(new, locnew, newlen + 1, NULL))) {
146 free(locnew, M_TEMP);
147 return(error);
148 }
149
150 ktrmibio(-1, UIO_WRITE, new, newlen + 1, error);
151 sysctl_lock(new != NULL);
152 error = freebsd_sysctl_name2oid(locnew, oid, &oidlen);
153 sysctl_unlock();
154 free(locnew, M_TEMP);
155 if (error)
156 return(error);
157
158 oidlen *= sizeof(int);
159 error = copyout(oid, SCARG(uap, old),
160 MIN(oidlen, *SCARG(uap, oldlenp)));
161 if (error)
162 return(error);
163 ktrmibio(-1, UIO_READ, SCARG(uap, old),
164 MIN(oidlen, *SCARG(uap, oldlenp)), 0);
165
166 error = copyout(&oidlen, SCARG(uap, oldlenp), sizeof(u_int));
167
168 return(error);
169 }
170
171 return(EOPNOTSUPP);
172 }
173
174 static int
175 freebsd_sysctl_name2oid(char *name, int *oid, int *oidlen)
176 {
177 char *dot;
178 int oi, ci;
179 struct sysctlnode *node, *pnode;
180
181 pnode = &sysctl_root;
182 node = sysctl_root.sysctl_child;
183 oi = 0;
184 if ((dot = strchr(name, (int)'.')) != NULL)
185 *dot++ = '\0';
186
187 next:
188 while (*name != '\0' && node != NULL) {
189 for (ci = 0; ci < pnode->sysctl_clen; ci++) {
190 if (strcmp(name, node[ci].sysctl_name) == 0) {
191 oid[oi++] = node[ci].sysctl_num;
192 if ((name = dot) == NULL) {
193 *oidlen = oi;
194 return(0);
195 }
196 if ((dot = strchr(name, (int)'.')) != NULL)
197 *dot++ = '\0';
198
199 if (SYSCTL_TYPE(node[ci].sysctl_flags) !=
200 CTLTYPE_NODE)
201 return(ENOTDIR);
202
203 pnode = &node[ci];
204 node = pnode->sysctl_child;
205 goto next;
206 }
207 }
208
209 /* no more nodes, it must not exist */
210 break;
211 }
212
213 return(ENOENT);
214 }
Cache object: 841964a16413d3dd633172c21ebc74a8
|