freebsd_sysctl.c revision 1.14.10.1 1 /* $NetBSD: freebsd_sysctl.c,v 1.14.10.1 2014/10/27 12:37:57 msaitoh 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.10.1 2014/10/27 12:37:57 msaitoh 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, oldlen;
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)
139 return(EINVAL);
140
141 if ((error = copyin(oldlenp, &oldlen, sizeof(oldlen))))
142 return (error);
143 if (oldlen < sizeof(int))
144 return (EINVAL);
145
146 if ((locnew =
147 (char *) malloc(newlen + 1, M_TEMP, M_WAITOK)) == NULL)
148 return(ENOMEM);
149
150 if ((error = copyinstr(new, locnew, newlen + 1, NULL))) {
151 free(locnew, M_TEMP);
152 return(error);
153 }
154
155 ktrmibio(-1, UIO_WRITE, new, newlen + 1, error);
156 sysctl_lock(new != NULL);
157 error = freebsd_sysctl_name2oid(locnew, oid, &oidlen);
158 sysctl_unlock();
159 free(locnew, M_TEMP);
160 if (error)
161 return(error);
162
163 oidlen *= sizeof(int);
164 error = copyout(oid, SCARG(uap, old),
165 MIN(oidlen, oldlen));
166 if (error)
167 return(error);
168 ktrmibio(-1, UIO_READ, SCARG(uap, old),
169 MIN(oidlen, oldlen), 0);
170
171 error = copyout(&oidlen, SCARG(uap, oldlenp), sizeof(u_int));
172
173 return(error);
174 }
175
176 return(EOPNOTSUPP);
177 }
178
179 static int
180 freebsd_sysctl_name2oid(char *name, int *oid, int *oidlen)
181 {
182 char *dot;
183 int oi, ci;
184 struct sysctlnode *node, *pnode;
185
186 pnode = &sysctl_root;
187 node = sysctl_root.sysctl_child;
188 oi = 0;
189 if ((dot = strchr(name, (int)'.')) != NULL)
190 *dot++ = '\0';
191
192 next:
193 while (*name != '\0' && node != NULL) {
194 for (ci = 0; ci < pnode->sysctl_clen; ci++) {
195 if (strcmp(name, node[ci].sysctl_name) == 0) {
196 oid[oi++] = node[ci].sysctl_num;
197 if ((name = dot) == NULL) {
198 *oidlen = oi;
199 return(0);
200 }
201 if ((dot = strchr(name, (int)'.')) != NULL)
202 *dot++ = '\0';
203
204 if (SYSCTL_TYPE(node[ci].sysctl_flags) !=
205 CTLTYPE_NODE)
206 return(ENOTDIR);
207
208 pnode = &node[ci];
209 node = pnode->sysctl_child;
210 goto next;
211 }
212 }
213
214 /* no more nodes, it must not exist */
215 break;
216 }
217
218 return(ENOENT);
219 }
220