1 /*-
2 * Copyright (c) 1982, 1986, 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Mike Karels at Berkeley Software Design, Inc.
7 *
8 * Quite extensively rewritten by Poul-Henning Kamp of the FreeBSD
9 * project, to make these variables more userfriendly.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 *
39 * @(#)kern_sysctl.c 8.4 (Berkeley) 4/14/94
40 * $FreeBSD$
41 */
42
43 #include "opt_compat.h"
44
45 #include <sys/param.h>
46 #include <sys/buf.h>
47 #include <sys/kernel.h>
48 #include <sys/sysctl.h>
49 #include <sys/malloc.h>
50 #include <sys/proc.h>
51 #include <sys/systm.h>
52 #include <sys/sysproto.h>
53 #include <vm/vm.h>
54 #include <vm/vm_extern.h>
55
56 static MALLOC_DEFINE(M_SYSCTL, "sysctl", "sysctl internal magic");
57
58 /*
59 * Locking and stats
60 */
61 static struct sysctl_lock {
62 int sl_lock;
63 int sl_want;
64 int sl_locked;
65 } memlock;
66
67 static int sysctl_root SYSCTL_HANDLER_ARGS;
68
69 extern struct linker_set sysctl_;
70
71 /*
72 * Initialization of the MIB tree.
73 *
74 * Order by number in each linker_set.
75 */
76
77 static int
78 sysctl_order_cmp(const void *a, const void *b)
79 {
80 struct sysctl_oid const * const *pa;
81 struct sysctl_oid const * const *pb;
82
83 pa = (struct sysctl_oid const * const *)a;
84 pb = (struct sysctl_oid const * const *)b;
85 if (*pa == NULL && *pb == NULL)
86 return 0;
87 if (*pa == NULL)
88 return (1);
89 if (*pb == NULL)
90 return (-1);
91 return ((*pa)->oid_number - (*pb)->oid_number);
92 }
93
94 static void
95 sysctl_order(void *arg)
96 {
97 int j, k;
98 struct linker_set *l = (struct linker_set *) arg;
99 struct sysctl_oid **oidpp;
100
101 /* First, find the highest oid we have */
102 j = l->ls_length;
103 oidpp = (struct sysctl_oid **) l->ls_items;
104 for (k = 0; j--; oidpp++) {
105 if (!*oidpp)
106 continue;
107 if ((*oidpp)->oid_arg1 == arg) {
108 *oidpp = 0;
109 continue;
110 }
111 if ((*oidpp)->oid_number > k)
112 k = (*oidpp)->oid_number;
113 }
114
115 /* Next, replace all OID_AUTO oids with new numbers */
116 j = l->ls_length;
117 oidpp = (struct sysctl_oid **) l->ls_items;
118 k += 100;
119 for (; j--; oidpp++)
120 if (*oidpp && (*oidpp)->oid_number == OID_AUTO)
121 (*oidpp)->oid_number = k++;
122
123 /* Finally: sort by oid */
124 j = l->ls_length;
125 oidpp = (struct sysctl_oid **) l->ls_items;
126 for (; j--; oidpp++) {
127 if (!*oidpp)
128 continue;
129 if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE)
130 if (!(*oidpp)->oid_handler)
131 sysctl_order((*oidpp)->oid_arg1);
132 }
133 qsort(l->ls_items, l->ls_length, sizeof l->ls_items[0],
134 sysctl_order_cmp);
135 }
136
137 SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_order, &sysctl_);
138
139 void
140 sysctl_order_all(void)
141 {
142 sysctl_order(&sysctl_);
143 }
144
145 /*
146 * "Staff-functions"
147 *
148 * These functions implement a presently undocumented interface
149 * used by the sysctl program to walk the tree, and get the type
150 * so it can print the value.
151 * This interface is under work and consideration, and should probably
152 * be killed with a big axe by the first person who can find the time.
153 * (be aware though, that the proper interface isn't as obvious as it
154 * may seem, there are various conflicting requirements.
155 *
156 * {0,0} printf the entire MIB-tree.
157 * {0,1,...} return the name of the "..." OID.
158 * {0,2,...} return the next OID.
159 * {0,3} return the OID of the name in "new"
160 * {0,4,...} return the kind & format info for the "..." OID.
161 */
162
163 static void
164 sysctl_sysctl_debug_dump_node(struct linker_set *l, int i)
165 {
166 int j, k;
167 struct sysctl_oid **oidpp;
168
169 j = l->ls_length;
170 oidpp = (struct sysctl_oid **) l->ls_items;
171 for (; j--; oidpp++) {
172
173 if (!*oidpp)
174 continue;
175
176 for (k=0; k<i; k++)
177 printf(" ");
178
179 printf("%d %s ", (*oidpp)->oid_number, (*oidpp)->oid_name);
180
181 printf("%c%c",
182 (*oidpp)->oid_kind & CTLFLAG_RD ? 'R':' ',
183 (*oidpp)->oid_kind & CTLFLAG_WR ? 'W':' ');
184
185 if ((*oidpp)->oid_handler)
186 printf(" *Handler");
187
188 switch ((*oidpp)->oid_kind & CTLTYPE) {
189 case CTLTYPE_NODE:
190 printf(" Node\n");
191 if (!(*oidpp)->oid_handler) {
192 sysctl_sysctl_debug_dump_node(
193 (*oidpp)->oid_arg1, i+2);
194 }
195 break;
196 case CTLTYPE_INT: printf(" Int\n"); break;
197 case CTLTYPE_STRING: printf(" String\n"); break;
198 case CTLTYPE_QUAD: printf(" Quad\n"); break;
199 case CTLTYPE_OPAQUE: printf(" Opaque/struct\n"); break;
200 default: printf("\n");
201 }
202
203 }
204 }
205
206 static int
207 sysctl_sysctl_debug SYSCTL_HANDLER_ARGS
208 {
209 sysctl_sysctl_debug_dump_node(&sysctl_, 0);
210 return ENOENT;
211 }
212
213 SYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD,
214 0, 0, sysctl_sysctl_debug, "-", "");
215
216 static int
217 sysctl_sysctl_name SYSCTL_HANDLER_ARGS
218 {
219 int *name = (int *) arg1;
220 u_int namelen = arg2;
221 int i, j, error = 0;
222 struct sysctl_oid **oidpp;
223 struct linker_set *lsp = &sysctl_;
224 char buf[10];
225
226 while (namelen) {
227 if (!lsp) {
228 snprintf(buf,sizeof(buf),"%d",*name);
229 if (req->oldidx)
230 error = SYSCTL_OUT(req, ".", 1);
231 if (!error)
232 error = SYSCTL_OUT(req, buf, strlen(buf));
233 if (error)
234 return (error);
235 namelen--;
236 name++;
237 continue;
238 }
239 oidpp = (struct sysctl_oid **) lsp->ls_items;
240 j = lsp->ls_length;
241 lsp = 0;
242 for (i = 0; i < j; i++, oidpp++) {
243 if (*oidpp && ((*oidpp)->oid_number != *name))
244 continue;
245
246 if (req->oldidx)
247 error = SYSCTL_OUT(req, ".", 1);
248 if (!error)
249 error = SYSCTL_OUT(req, (*oidpp)->oid_name,
250 strlen((*oidpp)->oid_name));
251 if (error)
252 return (error);
253
254 namelen--;
255 name++;
256
257 if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE)
258 break;
259
260 if ((*oidpp)->oid_handler)
261 break;
262
263 lsp = (struct linker_set*)(*oidpp)->oid_arg1;
264 break;
265 }
266 }
267 return (SYSCTL_OUT(req, "", 1));
268 }
269
270 SYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD, sysctl_sysctl_name, "");
271
272 static int
273 sysctl_sysctl_next_ls (struct linker_set *lsp, int *name, u_int namelen,
274 int *next, int *len, int level, struct sysctl_oid **oidp)
275 {
276 int i, j;
277 struct sysctl_oid **oidpp;
278
279 oidpp = (struct sysctl_oid **) lsp->ls_items;
280 j = lsp->ls_length;
281 *len = level;
282 for (i = 0; i < j; i++, oidpp++) {
283 if (!*oidpp)
284 continue;
285
286 *next = (*oidpp)->oid_number;
287 *oidp = *oidpp;
288
289 if (!namelen) {
290 if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE)
291 return 0;
292 if ((*oidpp)->oid_handler)
293 /* We really should call the handler here...*/
294 return 0;
295 lsp = (struct linker_set*)(*oidpp)->oid_arg1;
296 if (!sysctl_sysctl_next_ls (lsp, 0, 0, next+1,
297 len, level+1, oidp))
298 return 0;
299 goto next;
300 }
301
302 if ((*oidpp)->oid_number < *name)
303 continue;
304
305 if ((*oidpp)->oid_number > *name) {
306 if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE)
307 return 0;
308 if ((*oidpp)->oid_handler)
309 return 0;
310 lsp = (struct linker_set*)(*oidpp)->oid_arg1;
311 if (!sysctl_sysctl_next_ls (lsp, name+1, namelen-1,
312 next+1, len, level+1, oidp))
313 return (0);
314 goto next;
315 }
316 if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE)
317 continue;
318
319 if ((*oidpp)->oid_handler)
320 continue;
321
322 lsp = (struct linker_set*)(*oidpp)->oid_arg1;
323 if (!sysctl_sysctl_next_ls (lsp, name+1, namelen-1, next+1,
324 len, level+1, oidp))
325 return (0);
326 next:
327 namelen = 1;
328 *len = level;
329 }
330 return 1;
331 }
332
333 static int
334 sysctl_sysctl_next SYSCTL_HANDLER_ARGS
335 {
336 int *name = (int *) arg1;
337 u_int namelen = arg2;
338 int i, j, error;
339 struct sysctl_oid *oid;
340 struct linker_set *lsp = &sysctl_;
341 int newoid[CTL_MAXNAME];
342
343 i = sysctl_sysctl_next_ls (lsp, name, namelen, newoid, &j, 1, &oid);
344 if (i)
345 return ENOENT;
346 error = SYSCTL_OUT(req, newoid, j * sizeof (int));
347 return (error);
348 }
349
350 SYSCTL_NODE(_sysctl, 2, next, CTLFLAG_RD, sysctl_sysctl_next, "");
351
352 static int
353 name2oid (char *name, int *oid, int *len, struct sysctl_oid **oidp)
354 {
355 int i, j;
356 struct sysctl_oid **oidpp;
357 struct linker_set *lsp = &sysctl_;
358 char *p;
359
360 if (!*name)
361 return ENOENT;
362
363 p = name + strlen(name) - 1 ;
364 if (*p == '.')
365 *p = '\0';
366
367 *len = 0;
368
369 for (p = name; *p && *p != '.'; p++)
370 ;
371 i = *p;
372 if (i == '.')
373 *p = '\0';
374
375 j = lsp->ls_length;
376 oidpp = (struct sysctl_oid **) lsp->ls_items;
377
378 while (j-- && *len < CTL_MAXNAME) {
379 if (!*oidpp)
380 continue;
381 if (strcmp(name, (*oidpp)->oid_name)) {
382 oidpp++;
383 continue;
384 }
385 *oid++ = (*oidpp)->oid_number;
386 (*len)++;
387
388 if (!i) {
389 if (oidp)
390 *oidp = *oidpp;
391 return (0);
392 }
393
394 if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE)
395 break;
396
397 if ((*oidpp)->oid_handler)
398 break;
399
400 lsp = (struct linker_set*)(*oidpp)->oid_arg1;
401 j = lsp->ls_length;
402 oidpp = (struct sysctl_oid **)lsp->ls_items;
403 name = p+1;
404 for (p = name; *p && *p != '.'; p++)
405 ;
406 i = *p;
407 if (i == '.')
408 *p = '\0';
409 }
410 return ENOENT;
411 }
412
413 static int
414 sysctl_sysctl_name2oid SYSCTL_HANDLER_ARGS
415 {
416 char *p;
417 int error, oid[CTL_MAXNAME], len;
418 struct sysctl_oid *op = 0;
419
420 if (!req->newlen)
421 return ENOENT;
422 if (req->newlen >= MAXPATHLEN) /* XXX arbitrary, undocumented */
423 return (ENAMETOOLONG);
424
425 p = malloc(req->newlen+1, M_SYSCTL, M_WAITOK);
426
427 error = SYSCTL_IN(req, p, req->newlen);
428 if (error) {
429 free(p, M_SYSCTL);
430 return (error);
431 }
432
433 p [req->newlen] = '\0';
434
435 error = name2oid(p, oid, &len, &op);
436
437 free(p, M_SYSCTL);
438
439 if (error)
440 return (error);
441
442 error = SYSCTL_OUT(req, oid, len * sizeof *oid);
443 return (error);
444 }
445
446 SYSCTL_PROC(_sysctl, 3, name2oid, CTLFLAG_RW|CTLFLAG_ANYBODY, 0, 0,
447 sysctl_sysctl_name2oid, "I", "");
448
449 static int
450 sysctl_sysctl_oidfmt SYSCTL_HANDLER_ARGS
451 {
452 int *name = (int *) arg1, error;
453 u_int namelen = arg2;
454 int indx, j;
455 struct sysctl_oid **oidpp;
456 struct linker_set *lsp = &sysctl_;
457
458 j = lsp->ls_length;
459 oidpp = (struct sysctl_oid **) lsp->ls_items;
460
461 indx = 0;
462 while (j-- && indx < CTL_MAXNAME) {
463 if (*oidpp && ((*oidpp)->oid_number == name[indx])) {
464 indx++;
465 if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
466 if ((*oidpp)->oid_handler)
467 goto found;
468 if (indx == namelen)
469 goto found;
470 lsp = (struct linker_set*)(*oidpp)->oid_arg1;
471 j = lsp->ls_length;
472 oidpp = (struct sysctl_oid **)lsp->ls_items;
473 } else {
474 if (indx != namelen)
475 return EISDIR;
476 goto found;
477 }
478 } else {
479 oidpp++;
480 }
481 }
482 return ENOENT;
483 found:
484 if (!(*oidpp)->oid_fmt)
485 return ENOENT;
486 error = SYSCTL_OUT(req,
487 &(*oidpp)->oid_kind, sizeof((*oidpp)->oid_kind));
488 if (!error)
489 error = SYSCTL_OUT(req, (*oidpp)->oid_fmt,
490 strlen((*oidpp)->oid_fmt)+1);
491 return (error);
492 }
493
494
495 SYSCTL_NODE(_sysctl, 4, oidfmt, CTLFLAG_RD, sysctl_sysctl_oidfmt, "");
496
497 /*
498 * Default "handler" functions.
499 */
500
501 /*
502 * Handle an int, signed or unsigned.
503 * Two cases:
504 * a variable: point arg1 at it.
505 * a constant: pass it in arg2.
506 */
507
508 int
509 sysctl_handle_int SYSCTL_HANDLER_ARGS
510 {
511 int error = 0;
512
513 if (arg1)
514 error = SYSCTL_OUT(req, arg1, sizeof(int));
515 else
516 error = SYSCTL_OUT(req, &arg2, sizeof(int));
517
518 if (error || !req->newptr)
519 return (error);
520
521 if (!arg1)
522 error = EPERM;
523 else
524 error = SYSCTL_IN(req, arg1, sizeof(int));
525 return (error);
526 }
527
528 /*
529 * Handle a long, signed or unsigned. arg1 points to it.
530 */
531
532 int
533 sysctl_handle_long SYSCTL_HANDLER_ARGS
534 {
535 int error = 0;
536
537 if (!arg1)
538 return (EINVAL);
539 error = SYSCTL_OUT(req, arg1, sizeof(long));
540
541 if (error || !req->newptr)
542 return (error);
543
544 error = SYSCTL_IN(req, arg1, sizeof(long));
545 return (error);
546 }
547
548 /*
549 * Handle our generic '\0' terminated 'C' string.
550 * Two cases:
551 * a variable string: point arg1 at it, arg2 is max length.
552 * a constant string: point arg1 at it, arg2 is zero.
553 */
554
555 int
556 sysctl_handle_string SYSCTL_HANDLER_ARGS
557 {
558 int error=0;
559
560 error = SYSCTL_OUT(req, arg1, strlen((char *)arg1)+1);
561
562 if (error || !req->newptr)
563 return (error);
564
565 if ((req->newlen - req->newidx) >= arg2) {
566 error = EINVAL;
567 } else {
568 arg2 = (req->newlen - req->newidx);
569 error = SYSCTL_IN(req, arg1, arg2);
570 ((char *)arg1)[arg2] = '\0';
571 }
572
573 return (error);
574 }
575
576 /*
577 * Handle any kind of opaque data.
578 * arg1 points to it, arg2 is the size.
579 */
580
581 int
582 sysctl_handle_opaque SYSCTL_HANDLER_ARGS
583 {
584 int error;
585
586 error = SYSCTL_OUT(req, arg1, arg2);
587
588 if (error || !req->newptr)
589 return (error);
590
591 error = SYSCTL_IN(req, arg1, arg2);
592
593 return (error);
594 }
595
596 /*
597 * Transfer functions to/from kernel space.
598 * XXX: rather untested at this point
599 */
600 static int
601 sysctl_old_kernel(struct sysctl_req *req, const void *p, size_t l)
602 {
603 size_t i = 0;
604
605 if (req->oldptr) {
606 i = l;
607 if (i > req->oldlen - req->oldidx)
608 i = req->oldlen - req->oldidx;
609 if (i > 0)
610 bcopy(p, (char *)req->oldptr + req->oldidx, i);
611 }
612 req->oldidx += l;
613 if (req->oldptr && i != l)
614 return (ENOMEM);
615 return (0);
616 }
617
618 static int
619 sysctl_new_kernel(struct sysctl_req *req, void *p, size_t l)
620 {
621 if (!req->newptr)
622 return 0;
623 if (req->newlen - req->newidx < l)
624 return (EINVAL);
625 bcopy((char *)req->newptr + req->newidx, p, l);
626 req->newidx += l;
627 return (0);
628 }
629
630 int
631 kernel_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen, size_t *retval)
632 {
633 int error = 0;
634 struct sysctl_req req;
635
636 bzero(&req, sizeof req);
637
638 req.p = p;
639
640 if (oldlenp) {
641 req.oldlen = *oldlenp;
642 }
643
644 if (old) {
645 req.oldptr= old;
646 }
647
648 if (newlen) {
649 req.newlen = newlen;
650 req.newptr = new;
651 }
652
653 req.oldfunc = sysctl_old_kernel;
654 req.newfunc = sysctl_new_kernel;
655 req.lock = 1;
656
657 /* XXX this should probably be done in a general way */
658 while (memlock.sl_lock) {
659 memlock.sl_want = 1;
660 (void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0);
661 memlock.sl_locked++;
662 }
663 memlock.sl_lock = 1;
664
665 error = sysctl_root(0, name, namelen, &req);
666
667 if (req.lock == 2)
668 vsunlock(req.oldptr, req.oldlen, B_WRITE);
669
670 memlock.sl_lock = 0;
671
672 if (memlock.sl_want) {
673 memlock.sl_want = 0;
674 wakeup((caddr_t)&memlock);
675 }
676
677 if (error && error != ENOMEM)
678 return (error);
679
680 if (retval) {
681 if (req.oldptr && req.oldidx > req.oldlen)
682 *retval = req.oldlen;
683 else
684 *retval = req.oldidx;
685 }
686 return (error);
687 }
688
689 /*
690 * Transfer function to/from user space.
691 */
692 static int
693 sysctl_old_user(struct sysctl_req *req, const void *p, size_t l)
694 {
695 int error = 0;
696 size_t i = 0;
697
698 if (req->lock == 1 && req->oldptr) {
699 vslock(req->oldptr, req->oldlen);
700 req->lock = 2;
701 }
702 if (req->oldptr) {
703 i = l;
704 if (i > req->oldlen - req->oldidx)
705 i = req->oldlen - req->oldidx;
706 if (i > 0)
707 error = copyout(p, (char *)req->oldptr + req->oldidx,
708 i);
709 }
710 req->oldidx += l;
711 if (error)
712 return (error);
713 if (req->oldptr && i < l)
714 return (ENOMEM);
715 return (0);
716 }
717
718 static int
719 sysctl_new_user(struct sysctl_req *req, void *p, size_t l)
720 {
721 int error;
722
723 if (!req->newptr)
724 return 0;
725 if (req->newlen - req->newidx < l)
726 return (EINVAL);
727 error = copyin((char *)req->newptr + req->newidx, p, l);
728 req->newidx += l;
729 return (error);
730 }
731
732 /*
733 * Traverse our tree, and find the right node, execute whatever it points
734 * at, and return the resulting error code.
735 */
736
737 int
738 sysctl_root SYSCTL_HANDLER_ARGS
739 {
740 int *name = (int *) arg1;
741 u_int namelen = arg2;
742 int indx, i, j;
743 struct sysctl_oid **oidpp;
744 struct linker_set *lsp = &sysctl_;
745
746 j = lsp->ls_length;
747 oidpp = (struct sysctl_oid **) lsp->ls_items;
748
749 indx = 0;
750 while (j-- && indx < CTL_MAXNAME) {
751 if (*oidpp && ((*oidpp)->oid_number == name[indx])) {
752 indx++;
753 if ((*oidpp)->oid_kind & CTLFLAG_NOLOCK)
754 req->lock = 0;
755 if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
756 if ((*oidpp)->oid_handler)
757 goto found;
758 if (indx == namelen)
759 return ENOENT;
760 lsp = (struct linker_set*)(*oidpp)->oid_arg1;
761 j = lsp->ls_length;
762 oidpp = (struct sysctl_oid **)lsp->ls_items;
763 } else {
764 if (indx != namelen)
765 return EISDIR;
766 goto found;
767 }
768 } else {
769 oidpp++;
770 }
771 }
772 return ENOENT;
773 found:
774 /* If writing isn't allowed */
775 if (req->newptr && (!((*oidpp)->oid_kind & CTLFLAG_WR) ||
776 (((*oidpp)->oid_kind & CTLFLAG_SECURE) && securelevel > 0)))
777 return (EPERM);
778
779 /* Most likely only root can write */
780 if (!((*oidpp)->oid_kind & CTLFLAG_ANYBODY) &&
781 req->newptr && req->p &&
782 (i = suser(req->p->p_ucred, &req->p->p_acflag)))
783 return (i);
784
785 if (!(*oidpp)->oid_handler)
786 return EINVAL;
787
788 if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
789 i = ((*oidpp)->oid_handler) (*oidpp,
790 name + indx, namelen - indx,
791 req);
792 } else {
793 i = ((*oidpp)->oid_handler) (*oidpp,
794 (*oidpp)->oid_arg1, (*oidpp)->oid_arg2,
795 req);
796 }
797 return (i);
798 }
799
800 #ifndef _SYS_SYSPROTO_H_
801 struct sysctl_args {
802 int *name;
803 u_int namelen;
804 void *old;
805 size_t *oldlenp;
806 void *new;
807 size_t newlen;
808 };
809 #endif
810
811 int
812 __sysctl(struct proc *p, struct sysctl_args *uap)
813 {
814 int error, i, name[CTL_MAXNAME];
815 size_t j;
816
817 if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
818 return (EINVAL);
819
820 error = copyin(uap->name, &name, uap->namelen * sizeof(int));
821 if (error)
822 return (error);
823
824 error = userland_sysctl(p, name, uap->namelen,
825 uap->old, uap->oldlenp, 0,
826 uap->new, uap->newlen, &j);
827 if (error && error != ENOMEM)
828 return (error);
829 if (uap->oldlenp) {
830 i = copyout(&j, uap->oldlenp, sizeof(j));
831 if (i)
832 return (i);
833 }
834 return (error);
835 }
836
837 /*
838 * This is used from various compatibility syscalls too. That's why name
839 * must be in kernel space.
840 */
841 int
842 userland_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, int inkernel, void *new, size_t newlen, size_t *retval)
843 {
844 int error = 0;
845 struct sysctl_req req, req2;
846
847 bzero(&req, sizeof req);
848
849 req.p = p;
850
851 if (oldlenp) {
852 if (inkernel) {
853 req.oldlen = *oldlenp;
854 } else {
855 error = copyin(oldlenp, &req.oldlen, sizeof(*oldlenp));
856 if (error)
857 return (error);
858 }
859 }
860
861 if (old) {
862 if (!useracc(old, req.oldlen, B_WRITE))
863 return (EFAULT);
864 req.oldptr= old;
865 }
866
867 if (newlen) {
868 if (!useracc(new, req.newlen, B_READ))
869 return (EFAULT);
870 req.newlen = newlen;
871 req.newptr = new;
872 }
873
874 req.oldfunc = sysctl_old_user;
875 req.newfunc = sysctl_new_user;
876 req.lock = 1;
877
878 /* XXX this should probably be done in a general way */
879 while (memlock.sl_lock) {
880 memlock.sl_want = 1;
881 (void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0);
882 memlock.sl_locked++;
883 }
884 memlock.sl_lock = 1;
885
886 do {
887 req2 = req;
888 error = sysctl_root(0, name, namelen, &req2);
889 } while (error == EAGAIN);
890
891 req = req2;
892 if (req.lock == 2)
893 vsunlock(req.oldptr, req.oldlen, B_WRITE);
894
895 memlock.sl_lock = 0;
896
897 if (memlock.sl_want) {
898 memlock.sl_want = 0;
899 wakeup((caddr_t)&memlock);
900 }
901
902 if (error && error != ENOMEM)
903 return (error);
904
905 if (retval) {
906 if (req.oldptr && req.oldidx > req.oldlen)
907 *retval = req.oldlen;
908 else
909 *retval = req.oldidx;
910 }
911 return (error);
912 }
913
914 #ifdef COMPAT_43
915 #include <sys/socket.h>
916 #include <vm/vm_param.h>
917
918 #define KINFO_PROC (0<<8)
919 #define KINFO_RT (1<<8)
920 #define KINFO_VNODE (2<<8)
921 #define KINFO_FILE (3<<8)
922 #define KINFO_METER (4<<8)
923 #define KINFO_LOADAVG (5<<8)
924 #define KINFO_CLOCKRATE (6<<8)
925
926 /* Non-standard BSDI extension - only present on their 4.3 net-2 releases */
927 #define KINFO_BSDI_SYSINFO (101<<8)
928
929 /*
930 * XXX this is bloat, but I hope it's better here than on the potentially
931 * limited kernel stack... -Peter
932 */
933
934 static struct {
935 int bsdi_machine; /* "i386" on BSD/386 */
936 /* ^^^ this is an offset to the string, relative to the struct start */
937 char *pad0;
938 long pad1;
939 long pad2;
940 long pad3;
941 u_long pad4;
942 u_long pad5;
943 u_long pad6;
944
945 int bsdi_ostype; /* "BSD/386" on BSD/386 */
946 int bsdi_osrelease; /* "1.1" on BSD/386 */
947 long pad7;
948 long pad8;
949 char *pad9;
950
951 long pad10;
952 long pad11;
953 int pad12;
954 long pad13;
955 quad_t pad14;
956 long pad15;
957
958 struct timeval pad16;
959 /* we dont set this, because BSDI's uname used gethostname() instead */
960 int bsdi_hostname; /* hostname on BSD/386 */
961
962 /* the actual string data is appended here */
963
964 } bsdi_si;
965 /*
966 * this data is appended to the end of the bsdi_si structure during copyout.
967 * The "char *" offsets are relative to the base of the bsdi_si struct.
968 * This contains "FreeBSD\02.0-BUILT-nnnnnn\0i386\0", and these strings
969 * should not exceed the length of the buffer here... (or else!! :-)
970 */
971 static char bsdi_strings[80]; /* It had better be less than this! */
972
973 #ifndef _SYS_SYSPROTO_H_
974 struct getkerninfo_args {
975 int op;
976 char *where;
977 size_t *size;
978 int arg;
979 };
980 #endif
981
982 int
983 ogetkerninfo(struct proc *p, struct getkerninfo_args *uap)
984 {
985 int error, name[6];
986 size_t size;
987
988 switch (uap->op & 0xff00) {
989
990 case KINFO_RT:
991 name[0] = CTL_NET;
992 name[1] = PF_ROUTE;
993 name[2] = 0;
994 name[3] = (uap->op & 0xff0000) >> 16;
995 name[4] = uap->op & 0xff;
996 name[5] = uap->arg;
997 error = userland_sysctl(p, name, 6, uap->where, uap->size,
998 0, 0, 0, &size);
999 break;
1000
1001 case KINFO_VNODE:
1002 name[0] = CTL_KERN;
1003 name[1] = KERN_VNODE;
1004 error = userland_sysctl(p, name, 2, uap->where, uap->size,
1005 0, 0, 0, &size);
1006 break;
1007
1008 case KINFO_PROC:
1009 name[0] = CTL_KERN;
1010 name[1] = KERN_PROC;
1011 name[2] = uap->op & 0xff;
1012 name[3] = uap->arg;
1013 error = userland_sysctl(p, name, 4, uap->where, uap->size,
1014 0, 0, 0, &size);
1015 break;
1016
1017 case KINFO_FILE:
1018 name[0] = CTL_KERN;
1019 name[1] = KERN_FILE;
1020 error = userland_sysctl(p, name, 2, uap->where, uap->size,
1021 0, 0, 0, &size);
1022 break;
1023
1024 case KINFO_METER:
1025 name[0] = CTL_VM;
1026 name[1] = VM_METER;
1027 error = userland_sysctl(p, name, 2, uap->where, uap->size,
1028 0, 0, 0, &size);
1029 break;
1030
1031 case KINFO_LOADAVG:
1032 name[0] = CTL_VM;
1033 name[1] = VM_LOADAVG;
1034 error = userland_sysctl(p, name, 2, uap->where, uap->size,
1035 0, 0, 0, &size);
1036 break;
1037
1038 case KINFO_CLOCKRATE:
1039 name[0] = CTL_KERN;
1040 name[1] = KERN_CLOCKRATE;
1041 error = userland_sysctl(p, name, 2, uap->where, uap->size,
1042 0, 0, 0, &size);
1043 break;
1044
1045 case KINFO_BSDI_SYSINFO: {
1046 /*
1047 * this is pretty crude, but it's just enough for uname()
1048 * from BSDI's 1.x libc to work.
1049 *
1050 * In particular, it doesn't return the same results when
1051 * the supplied buffer is too small. BSDI's version apparently
1052 * will return the amount copied, and set the *size to how
1053 * much was needed. The emulation framework here isn't capable
1054 * of that, so we just set both to the amount copied.
1055 * BSDI's 2.x product apparently fails with ENOMEM in this
1056 * scenario.
1057 */
1058
1059 u_int needed;
1060 u_int left;
1061 char *s;
1062
1063 bzero((char *)&bsdi_si, sizeof(bsdi_si));
1064 bzero(bsdi_strings, sizeof(bsdi_strings));
1065
1066 s = bsdi_strings;
1067
1068 bsdi_si.bsdi_ostype = (s - bsdi_strings) + sizeof(bsdi_si);
1069 strcpy(s, ostype);
1070 s += strlen(s) + 1;
1071
1072 bsdi_si.bsdi_osrelease = (s - bsdi_strings) + sizeof(bsdi_si);
1073 strcpy(s, osrelease);
1074 s += strlen(s) + 1;
1075
1076 bsdi_si.bsdi_machine = (s - bsdi_strings) + sizeof(bsdi_si);
1077 strcpy(s, machine);
1078 s += strlen(s) + 1;
1079
1080 needed = sizeof(bsdi_si) + (s - bsdi_strings);
1081
1082 if (uap->where == NULL) {
1083 /* process is asking how much buffer to supply.. */
1084 size = needed;
1085 error = 0;
1086 break;
1087 }
1088
1089
1090 /* if too much buffer supplied, trim it down */
1091 if (size > needed)
1092 size = needed;
1093
1094 /* how much of the buffer is remaining */
1095 left = size;
1096
1097 if ((error = copyout((char *)&bsdi_si, uap->where, left)) != 0)
1098 break;
1099
1100 /* is there any point in continuing? */
1101 if (left > sizeof(bsdi_si)) {
1102 left -= sizeof(bsdi_si);
1103 error = copyout(&bsdi_strings,
1104 uap->where + sizeof(bsdi_si), left);
1105 }
1106 break;
1107 }
1108
1109 default:
1110 return (EOPNOTSUPP);
1111 }
1112 if (error)
1113 return (error);
1114 p->p_retval[0] = size;
1115 if (uap->size)
1116 error = copyout((caddr_t)&size, (caddr_t)uap->size,
1117 sizeof(size));
1118 return (error);
1119 }
1120 #endif /* COMPAT_43 */
Cache object: c875418348217cdccd52fc8a22b6a562
|