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 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * @(#)kern_sysctl.c 8.4 (Berkeley) 4/14/94
36 */
37
38 #include <sys/cdefs.h>
39 __FBSDID("$FreeBSD$");
40
41 #include "opt_compat.h"
42 #include "opt_mac.h"
43
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/kernel.h>
47 #include <sys/sysctl.h>
48 #include <sys/mac.h>
49 #include <sys/malloc.h>
50 #include <sys/proc.h>
51 #include <sys/lock.h>
52 #include <sys/mutex.h>
53 #include <sys/sx.h>
54 #include <sys/sysproto.h>
55 #include <sys/uio.h>
56 #include <vm/vm.h>
57 #include <vm/vm_extern.h>
58
59 static MALLOC_DEFINE(M_SYSCTL, "sysctl", "sysctl internal magic");
60 static MALLOC_DEFINE(M_SYSCTLOID, "sysctloid", "sysctl dynamic oids");
61 static MALLOC_DEFINE(M_SYSCTLTMP, "sysctltmp", "sysctl temp output buffer");
62
63 /*
64 * Locking - this locks the sysctl tree in memory.
65 */
66 static struct sx sysctllock;
67
68 #define SYSCTL_LOCK() sx_xlock(&sysctllock)
69 #define SYSCTL_UNLOCK() sx_xunlock(&sysctllock)
70 #define SYSCTL_INIT() sx_init(&sysctllock, "sysctl lock")
71
72 static int sysctl_root(SYSCTL_HANDLER_ARGS);
73
74 struct sysctl_oid_list sysctl__children; /* root list */
75
76 static struct sysctl_oid *
77 sysctl_find_oidname(const char *name, struct sysctl_oid_list *list)
78 {
79 struct sysctl_oid *oidp;
80
81 SLIST_FOREACH(oidp, list, oid_link) {
82 if (strcmp(oidp->oid_name, name) == 0) {
83 return (oidp);
84 }
85 }
86 return (NULL);
87 }
88
89 /*
90 * Initialization of the MIB tree.
91 *
92 * Order by number in each list.
93 */
94
95 void
96 sysctl_register_oid(struct sysctl_oid *oidp)
97 {
98 struct sysctl_oid_list *parent = oidp->oid_parent;
99 struct sysctl_oid *p;
100 struct sysctl_oid *q;
101
102 /*
103 * First check if another oid with the same name already
104 * exists in the parent's list.
105 */
106 p = sysctl_find_oidname(oidp->oid_name, parent);
107 if (p != NULL) {
108 if ((p->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
109 p->oid_refcnt++;
110 return;
111 } else {
112 printf("can't re-use a leaf (%s)!\n", p->oid_name);
113 return;
114 }
115 }
116 /*
117 * If this oid has a number OID_AUTO, give it a number which
118 * is greater than any current oid.
119 * NOTE: DO NOT change the starting value here, change it in
120 * <sys/sysctl.h>, and make sure it is at least 256 to
121 * accomodate e.g. net.inet.raw as a static sysctl node.
122 */
123 if (oidp->oid_number == OID_AUTO) {
124 static int newoid = CTL_AUTO_START;
125
126 oidp->oid_number = newoid++;
127 if (newoid == 0x7fffffff)
128 panic("out of oids");
129 }
130 #if 0
131 else if (oidp->oid_number >= CTL_AUTO_START) {
132 /* do not panic; this happens when unregistering sysctl sets */
133 printf("static sysctl oid too high: %d", oidp->oid_number);
134 }
135 #endif
136
137 /*
138 * Insert the oid into the parent's list in order.
139 */
140 q = NULL;
141 SLIST_FOREACH(p, parent, oid_link) {
142 if (oidp->oid_number < p->oid_number)
143 break;
144 q = p;
145 }
146 if (q)
147 SLIST_INSERT_AFTER(q, oidp, oid_link);
148 else
149 SLIST_INSERT_HEAD(parent, oidp, oid_link);
150 }
151
152 void
153 sysctl_unregister_oid(struct sysctl_oid *oidp)
154 {
155 struct sysctl_oid *p;
156 int error;
157
158 error = ENOENT;
159 if (oidp->oid_number == OID_AUTO) {
160 error = EINVAL;
161 } else {
162 SLIST_FOREACH(p, oidp->oid_parent, oid_link) {
163 if (p == oidp) {
164 SLIST_REMOVE(oidp->oid_parent, oidp,
165 sysctl_oid, oid_link);
166 error = 0;
167 break;
168 }
169 }
170 }
171
172 /*
173 * This can happen when a module fails to register and is
174 * being unloaded afterwards. It should not be a panic()
175 * for normal use.
176 */
177 if (error)
178 printf("%s: failed to unregister sysctl\n", __func__);
179 }
180
181 /* Initialize a new context to keep track of dynamically added sysctls. */
182 int
183 sysctl_ctx_init(struct sysctl_ctx_list *c)
184 {
185
186 if (c == NULL) {
187 return (EINVAL);
188 }
189 TAILQ_INIT(c);
190 return (0);
191 }
192
193 /* Free the context, and destroy all dynamic oids registered in this context */
194 int
195 sysctl_ctx_free(struct sysctl_ctx_list *clist)
196 {
197 struct sysctl_ctx_entry *e, *e1;
198 int error;
199
200 error = 0;
201 /*
202 * First perform a "dry run" to check if it's ok to remove oids.
203 * XXX FIXME
204 * XXX This algorithm is a hack. But I don't know any
205 * XXX better solution for now...
206 */
207 TAILQ_FOREACH(e, clist, link) {
208 error = sysctl_remove_oid(e->entry, 0, 0);
209 if (error)
210 break;
211 }
212 /*
213 * Restore deregistered entries, either from the end,
214 * or from the place where error occured.
215 * e contains the entry that was not unregistered
216 */
217 if (error)
218 e1 = TAILQ_PREV(e, sysctl_ctx_list, link);
219 else
220 e1 = TAILQ_LAST(clist, sysctl_ctx_list);
221 while (e1 != NULL) {
222 sysctl_register_oid(e1->entry);
223 e1 = TAILQ_PREV(e1, sysctl_ctx_list, link);
224 }
225 if (error)
226 return(EBUSY);
227 /* Now really delete the entries */
228 e = TAILQ_FIRST(clist);
229 while (e != NULL) {
230 e1 = TAILQ_NEXT(e, link);
231 error = sysctl_remove_oid(e->entry, 1, 0);
232 if (error)
233 panic("sysctl_remove_oid: corrupt tree, entry: %s",
234 e->entry->oid_name);
235 free(e, M_SYSCTLOID);
236 e = e1;
237 }
238 return (error);
239 }
240
241 /* Add an entry to the context */
242 struct sysctl_ctx_entry *
243 sysctl_ctx_entry_add(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp)
244 {
245 struct sysctl_ctx_entry *e;
246
247 if (clist == NULL || oidp == NULL)
248 return(NULL);
249 e = malloc(sizeof(struct sysctl_ctx_entry), M_SYSCTLOID, M_WAITOK);
250 e->entry = oidp;
251 TAILQ_INSERT_HEAD(clist, e, link);
252 return (e);
253 }
254
255 /* Find an entry in the context */
256 struct sysctl_ctx_entry *
257 sysctl_ctx_entry_find(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp)
258 {
259 struct sysctl_ctx_entry *e;
260
261 if (clist == NULL || oidp == NULL)
262 return(NULL);
263 TAILQ_FOREACH(e, clist, link) {
264 if(e->entry == oidp)
265 return(e);
266 }
267 return (e);
268 }
269
270 /*
271 * Delete an entry from the context.
272 * NOTE: this function doesn't free oidp! You have to remove it
273 * with sysctl_remove_oid().
274 */
275 int
276 sysctl_ctx_entry_del(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp)
277 {
278 struct sysctl_ctx_entry *e;
279
280 if (clist == NULL || oidp == NULL)
281 return (EINVAL);
282 e = sysctl_ctx_entry_find(clist, oidp);
283 if (e != NULL) {
284 TAILQ_REMOVE(clist, e, link);
285 free(e, M_SYSCTLOID);
286 return (0);
287 } else
288 return (ENOENT);
289 }
290
291 /*
292 * Remove dynamically created sysctl trees.
293 * oidp - top of the tree to be removed
294 * del - if 0 - just deregister, otherwise free up entries as well
295 * recurse - if != 0 traverse the subtree to be deleted
296 */
297 int
298 sysctl_remove_oid(struct sysctl_oid *oidp, int del, int recurse)
299 {
300 struct sysctl_oid *p;
301 int error;
302
303 if (oidp == NULL)
304 return(EINVAL);
305 if ((oidp->oid_kind & CTLFLAG_DYN) == 0) {
306 printf("can't remove non-dynamic nodes!\n");
307 return (EINVAL);
308 }
309 /*
310 * WARNING: normal method to do this should be through
311 * sysctl_ctx_free(). Use recursing as the last resort
312 * method to purge your sysctl tree of leftovers...
313 * However, if some other code still references these nodes,
314 * it will panic.
315 */
316 if ((oidp->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
317 if (oidp->oid_refcnt == 1) {
318 SLIST_FOREACH(p, SYSCTL_CHILDREN(oidp), oid_link) {
319 if (!recurse)
320 return (ENOTEMPTY);
321 error = sysctl_remove_oid(p, del, recurse);
322 if (error)
323 return (error);
324 }
325 if (del)
326 free(SYSCTL_CHILDREN(oidp), M_SYSCTLOID);
327 }
328 }
329 if (oidp->oid_refcnt > 1 ) {
330 oidp->oid_refcnt--;
331 } else {
332 if (oidp->oid_refcnt == 0) {
333 printf("Warning: bad oid_refcnt=%u (%s)!\n",
334 oidp->oid_refcnt, oidp->oid_name);
335 return (EINVAL);
336 }
337 sysctl_unregister_oid(oidp);
338 if (del) {
339 if (oidp->oid_descr)
340 free((void *)(uintptr_t)(const void *)oidp->oid_descr, M_SYSCTLOID);
341 free((void *)(uintptr_t)(const void *)oidp->oid_name,
342 M_SYSCTLOID);
343 free(oidp, M_SYSCTLOID);
344 }
345 }
346 return (0);
347 }
348
349 /*
350 * Create new sysctls at run time.
351 * clist may point to a valid context initialized with sysctl_ctx_init().
352 */
353 struct sysctl_oid *
354 sysctl_add_oid(struct sysctl_ctx_list *clist, struct sysctl_oid_list *parent,
355 int number, const char *name, int kind, void *arg1, int arg2,
356 int (*handler)(SYSCTL_HANDLER_ARGS), const char *fmt, const char *descr)
357 {
358 struct sysctl_oid *oidp;
359 ssize_t len;
360 char *newname;
361
362 /* You have to hook up somewhere.. */
363 if (parent == NULL)
364 return(NULL);
365 /* Check if the node already exists, otherwise create it */
366 oidp = sysctl_find_oidname(name, parent);
367 if (oidp != NULL) {
368 if ((oidp->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
369 oidp->oid_refcnt++;
370 /* Update the context */
371 if (clist != NULL)
372 sysctl_ctx_entry_add(clist, oidp);
373 return (oidp);
374 } else {
375 printf("can't re-use a leaf (%s)!\n", name);
376 return (NULL);
377 }
378 }
379 oidp = malloc(sizeof(struct sysctl_oid), M_SYSCTLOID, M_WAITOK|M_ZERO);
380 oidp->oid_parent = parent;
381 SLIST_NEXT(oidp, oid_link) = NULL;
382 oidp->oid_number = number;
383 oidp->oid_refcnt = 1;
384 len = strlen(name);
385 newname = malloc(len + 1, M_SYSCTLOID, M_WAITOK);
386 bcopy(name, newname, len + 1);
387 newname[len] = '\0';
388 oidp->oid_name = newname;
389 oidp->oid_handler = handler;
390 oidp->oid_kind = CTLFLAG_DYN | kind;
391 if ((kind & CTLTYPE) == CTLTYPE_NODE) {
392 /* Allocate space for children */
393 SYSCTL_CHILDREN_SET(oidp, malloc(sizeof(struct sysctl_oid_list),
394 M_SYSCTLOID, M_WAITOK));
395 SLIST_INIT(SYSCTL_CHILDREN(oidp));
396 } else {
397 oidp->oid_arg1 = arg1;
398 oidp->oid_arg2 = arg2;
399 }
400 oidp->oid_fmt = fmt;
401 if (descr) {
402 int len = strlen(descr) + 1;
403 oidp->oid_descr = malloc(len, M_SYSCTLOID, M_WAITOK);
404 if (oidp->oid_descr)
405 strcpy((char *)(uintptr_t)(const void *)oidp->oid_descr, descr);
406 }
407 /* Update the context, if used */
408 if (clist != NULL)
409 sysctl_ctx_entry_add(clist, oidp);
410 /* Register this oid */
411 sysctl_register_oid(oidp);
412 return (oidp);
413 }
414
415 /*
416 * Reparent an existing oid.
417 */
418 int
419 sysctl_move_oid(struct sysctl_oid *oid, struct sysctl_oid_list *parent)
420 {
421 struct sysctl_oid *oidp;
422
423 if (oid->oid_parent == parent)
424 return (0);
425 oidp = sysctl_find_oidname(oid->oid_name, parent);
426 if (oidp != NULL)
427 return (EEXIST);
428 sysctl_unregister_oid(oid);
429 oid->oid_parent = parent;
430 oid->oid_number = OID_AUTO;
431 sysctl_register_oid(oid);
432 return (0);
433 }
434
435 /*
436 * Register the kernel's oids on startup.
437 */
438 SET_DECLARE(sysctl_set, struct sysctl_oid);
439
440 static void
441 sysctl_register_all(void *arg)
442 {
443 struct sysctl_oid **oidp;
444
445 SYSCTL_INIT();
446 SET_FOREACH(oidp, sysctl_set)
447 sysctl_register_oid(*oidp);
448 }
449 SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_register_all, 0);
450
451 /*
452 * "Staff-functions"
453 *
454 * These functions implement a presently undocumented interface
455 * used by the sysctl program to walk the tree, and get the type
456 * so it can print the value.
457 * This interface is under work and consideration, and should probably
458 * be killed with a big axe by the first person who can find the time.
459 * (be aware though, that the proper interface isn't as obvious as it
460 * may seem, there are various conflicting requirements.
461 *
462 * {0,0} printf the entire MIB-tree.
463 * {0,1,...} return the name of the "..." OID.
464 * {0,2,...} return the next OID.
465 * {0,3} return the OID of the name in "new"
466 * {0,4,...} return the kind & format info for the "..." OID.
467 * {0,5,...} return the description the "..." OID.
468 */
469
470 #ifdef SYSCTL_DEBUG
471 static void
472 sysctl_sysctl_debug_dump_node(struct sysctl_oid_list *l, int i)
473 {
474 int k;
475 struct sysctl_oid *oidp;
476
477 SLIST_FOREACH(oidp, l, oid_link) {
478
479 for (k=0; k<i; k++)
480 printf(" ");
481
482 printf("%d %s ", oidp->oid_number, oidp->oid_name);
483
484 printf("%c%c",
485 oidp->oid_kind & CTLFLAG_RD ? 'R':' ',
486 oidp->oid_kind & CTLFLAG_WR ? 'W':' ');
487
488 if (oidp->oid_handler)
489 printf(" *Handler");
490
491 switch (oidp->oid_kind & CTLTYPE) {
492 case CTLTYPE_NODE:
493 printf(" Node\n");
494 if (!oidp->oid_handler) {
495 sysctl_sysctl_debug_dump_node(
496 oidp->oid_arg1, i+2);
497 }
498 break;
499 case CTLTYPE_INT: printf(" Int\n"); break;
500 case CTLTYPE_STRING: printf(" String\n"); break;
501 case CTLTYPE_QUAD: printf(" Quad\n"); break;
502 case CTLTYPE_OPAQUE: printf(" Opaque/struct\n"); break;
503 default: printf("\n");
504 }
505
506 }
507 }
508
509 static int
510 sysctl_sysctl_debug(SYSCTL_HANDLER_ARGS)
511 {
512 int error;
513
514 error = suser(req->td);
515 if (error)
516 return (error);
517 sysctl_sysctl_debug_dump_node(&sysctl__children, 0);
518 return (ENOENT);
519 }
520
521 SYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD,
522 0, 0, sysctl_sysctl_debug, "-", "");
523 #endif
524
525 static int
526 sysctl_sysctl_name(SYSCTL_HANDLER_ARGS)
527 {
528 int *name = (int *) arg1;
529 u_int namelen = arg2;
530 int error = 0;
531 struct sysctl_oid *oid;
532 struct sysctl_oid_list *lsp = &sysctl__children, *lsp2;
533 char buf[10];
534
535 while (namelen) {
536 if (!lsp) {
537 snprintf(buf,sizeof(buf),"%d",*name);
538 if (req->oldidx)
539 error = SYSCTL_OUT(req, ".", 1);
540 if (!error)
541 error = SYSCTL_OUT(req, buf, strlen(buf));
542 if (error)
543 return (error);
544 namelen--;
545 name++;
546 continue;
547 }
548 lsp2 = 0;
549 SLIST_FOREACH(oid, lsp, oid_link) {
550 if (oid->oid_number != *name)
551 continue;
552
553 if (req->oldidx)
554 error = SYSCTL_OUT(req, ".", 1);
555 if (!error)
556 error = SYSCTL_OUT(req, oid->oid_name,
557 strlen(oid->oid_name));
558 if (error)
559 return (error);
560
561 namelen--;
562 name++;
563
564 if ((oid->oid_kind & CTLTYPE) != CTLTYPE_NODE)
565 break;
566
567 if (oid->oid_handler)
568 break;
569
570 lsp2 = (struct sysctl_oid_list *)oid->oid_arg1;
571 break;
572 }
573 lsp = lsp2;
574 }
575 return (SYSCTL_OUT(req, "", 1));
576 }
577
578 static SYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD, sysctl_sysctl_name, "");
579
580 static int
581 sysctl_sysctl_next_ls(struct sysctl_oid_list *lsp, int *name, u_int namelen,
582 int *next, int *len, int level, struct sysctl_oid **oidpp)
583 {
584 struct sysctl_oid *oidp;
585
586 *len = level;
587 SLIST_FOREACH(oidp, lsp, oid_link) {
588 *next = oidp->oid_number;
589 *oidpp = oidp;
590
591 if (oidp->oid_kind & CTLFLAG_SKIP)
592 continue;
593
594 if (!namelen) {
595 if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
596 return (0);
597 if (oidp->oid_handler)
598 /* We really should call the handler here...*/
599 return (0);
600 lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
601 if (!sysctl_sysctl_next_ls(lsp, 0, 0, next+1,
602 len, level+1, oidpp))
603 return (0);
604 goto emptynode;
605 }
606
607 if (oidp->oid_number < *name)
608 continue;
609
610 if (oidp->oid_number > *name) {
611 if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
612 return (0);
613 if (oidp->oid_handler)
614 return (0);
615 lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
616 if (!sysctl_sysctl_next_ls(lsp, name+1, namelen-1,
617 next+1, len, level+1, oidpp))
618 return (0);
619 goto next;
620 }
621 if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
622 continue;
623
624 if (oidp->oid_handler)
625 continue;
626
627 lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
628 if (!sysctl_sysctl_next_ls(lsp, name+1, namelen-1, next+1,
629 len, level+1, oidpp))
630 return (0);
631 next:
632 namelen = 1;
633 emptynode:
634 *len = level;
635 }
636 return (1);
637 }
638
639 static int
640 sysctl_sysctl_next(SYSCTL_HANDLER_ARGS)
641 {
642 int *name = (int *) arg1;
643 u_int namelen = arg2;
644 int i, j, error;
645 struct sysctl_oid *oid;
646 struct sysctl_oid_list *lsp = &sysctl__children;
647 int newoid[CTL_MAXNAME];
648
649 i = sysctl_sysctl_next_ls(lsp, name, namelen, newoid, &j, 1, &oid);
650 if (i)
651 return (ENOENT);
652 error = SYSCTL_OUT(req, newoid, j * sizeof (int));
653 return (error);
654 }
655
656 static SYSCTL_NODE(_sysctl, 2, next, CTLFLAG_RD, sysctl_sysctl_next, "");
657
658 static int
659 name2oid (char *name, int *oid, int *len, struct sysctl_oid **oidpp)
660 {
661 int i;
662 struct sysctl_oid *oidp;
663 struct sysctl_oid_list *lsp = &sysctl__children;
664 char *p;
665
666 if (!*name)
667 return (ENOENT);
668
669 p = name + strlen(name) - 1 ;
670 if (*p == '.')
671 *p = '\0';
672
673 *len = 0;
674
675 for (p = name; *p && *p != '.'; p++)
676 ;
677 i = *p;
678 if (i == '.')
679 *p = '\0';
680
681 oidp = SLIST_FIRST(lsp);
682
683 while (oidp && *len < CTL_MAXNAME) {
684 if (strcmp(name, oidp->oid_name)) {
685 oidp = SLIST_NEXT(oidp, oid_link);
686 continue;
687 }
688 *oid++ = oidp->oid_number;
689 (*len)++;
690
691 if (!i) {
692 if (oidpp)
693 *oidpp = oidp;
694 return (0);
695 }
696
697 if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
698 break;
699
700 if (oidp->oid_handler)
701 break;
702
703 lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
704 oidp = SLIST_FIRST(lsp);
705 name = p+1;
706 for (p = name; *p && *p != '.'; p++)
707 ;
708 i = *p;
709 if (i == '.')
710 *p = '\0';
711 }
712 return (ENOENT);
713 }
714
715 static int
716 sysctl_sysctl_name2oid(SYSCTL_HANDLER_ARGS)
717 {
718 char *p;
719 int error, oid[CTL_MAXNAME], len;
720 struct sysctl_oid *op = 0;
721
722 if (!req->newlen)
723 return (ENOENT);
724 if (req->newlen >= MAXPATHLEN) /* XXX arbitrary, undocumented */
725 return (ENAMETOOLONG);
726
727 p = malloc(req->newlen+1, M_SYSCTL, M_WAITOK);
728
729 error = SYSCTL_IN(req, p, req->newlen);
730 if (error) {
731 free(p, M_SYSCTL);
732 return (error);
733 }
734
735 p [req->newlen] = '\0';
736
737 error = name2oid(p, oid, &len, &op);
738
739 free(p, M_SYSCTL);
740
741 if (error)
742 return (error);
743
744 error = SYSCTL_OUT(req, oid, len * sizeof *oid);
745 return (error);
746 }
747
748 SYSCTL_PROC(_sysctl, 3, name2oid, CTLFLAG_RW|CTLFLAG_ANYBODY, 0, 0,
749 sysctl_sysctl_name2oid, "I", "");
750
751 static int
752 sysctl_sysctl_oidfmt(SYSCTL_HANDLER_ARGS)
753 {
754 struct sysctl_oid *oid;
755 int error;
756
757 error = sysctl_find_oid(arg1, arg2, &oid, NULL, req);
758 if (error)
759 return (error);
760
761 if (!oid->oid_fmt)
762 return (ENOENT);
763 error = SYSCTL_OUT(req, &oid->oid_kind, sizeof(oid->oid_kind));
764 if (error)
765 return (error);
766 error = SYSCTL_OUT(req, oid->oid_fmt, strlen(oid->oid_fmt) + 1);
767 return (error);
768 }
769
770
771 static SYSCTL_NODE(_sysctl, 4, oidfmt, CTLFLAG_RD, sysctl_sysctl_oidfmt, "");
772
773 static int
774 sysctl_sysctl_oiddescr(SYSCTL_HANDLER_ARGS)
775 {
776 struct sysctl_oid *oid;
777 int error;
778
779 error = sysctl_find_oid(arg1, arg2, &oid, NULL, req);
780 if (error)
781 return (error);
782
783 if (!oid->oid_descr)
784 return (ENOENT);
785 error = SYSCTL_OUT(req, oid->oid_descr, strlen(oid->oid_descr) + 1);
786 return (error);
787 }
788
789 static SYSCTL_NODE(_sysctl, 5, oiddescr, CTLFLAG_RD, sysctl_sysctl_oiddescr, "");
790
791 /*
792 * Default "handler" functions.
793 */
794
795 /*
796 * Handle an int, signed or unsigned.
797 * Two cases:
798 * a variable: point arg1 at it.
799 * a constant: pass it in arg2.
800 */
801
802 int
803 sysctl_handle_int(SYSCTL_HANDLER_ARGS)
804 {
805 int tmpout, error = 0;
806
807 /*
808 * Attempt to get a coherent snapshot by making a copy of the data.
809 */
810 if (arg1)
811 tmpout = *(int *)arg1;
812 else
813 tmpout = arg2;
814 error = SYSCTL_OUT(req, &tmpout, sizeof(int));
815
816 if (error || !req->newptr)
817 return (error);
818
819 if (!arg1)
820 error = EPERM;
821 else
822 error = SYSCTL_IN(req, arg1, sizeof(int));
823 return (error);
824 }
825
826
827 /*
828 * Based on on sysctl_handle_int() convert milliseconds into ticks.
829 */
830
831 int
832 sysctl_msec_to_ticks(SYSCTL_HANDLER_ARGS)
833 {
834 int error, s, tt;
835
836 tt = *(int *)oidp->oid_arg1;
837 s = (int)((int64_t)tt * 1000 / hz);
838
839 error = sysctl_handle_int(oidp, &s, 0, req);
840 if (error || !req->newptr)
841 return (error);
842
843 tt = (int)((int64_t)s * hz / 1000);
844 if (tt < 1)
845 return (EINVAL);
846
847 *(int *)oidp->oid_arg1 = tt;
848 return (0);
849 }
850
851
852 /*
853 * Handle a long, signed or unsigned. arg1 points to it.
854 */
855
856 int
857 sysctl_handle_long(SYSCTL_HANDLER_ARGS)
858 {
859 int error = 0;
860 long tmplong;
861 #ifdef SCTL_MASK32
862 int tmpint;
863 #endif
864
865 /*
866 * Attempt to get a coherent snapshot by making a copy of the data.
867 */
868 if (!arg1)
869 return (EINVAL);
870 tmplong = *(long *)arg1;
871 #ifdef SCTL_MASK32
872 if (req->flags & SCTL_MASK32) {
873 tmpint = tmplong;
874 error = SYSCTL_OUT(req, &tmpint, sizeof(int));
875 } else
876 #endif
877 error = SYSCTL_OUT(req, &tmplong, sizeof(long));
878
879 if (error || !req->newptr)
880 return (error);
881
882 #ifdef SCTL_MASK32
883 if (req->flags & SCTL_MASK32) {
884 error = SYSCTL_IN(req, &tmpint, sizeof(int));
885 *(long *)arg1 = (long)tmpint;
886 } else
887 #endif
888 error = SYSCTL_IN(req, arg1, sizeof(long));
889 return (error);
890 }
891
892 /*
893 * Handle our generic '\0' terminated 'C' string.
894 * Two cases:
895 * a variable string: point arg1 at it, arg2 is max length.
896 * a constant string: point arg1 at it, arg2 is zero.
897 */
898
899 int
900 sysctl_handle_string(SYSCTL_HANDLER_ARGS)
901 {
902 int error=0;
903 char *tmparg;
904 size_t outlen;
905
906 /*
907 * Attempt to get a coherent snapshot by copying to a
908 * temporary kernel buffer.
909 */
910 retry:
911 outlen = strlen((char *)arg1)+1;
912 tmparg = malloc(outlen, M_SYSCTLTMP, M_WAITOK);
913
914 if (strlcpy(tmparg, (char *)arg1, outlen) >= outlen) {
915 free(tmparg, M_SYSCTLTMP);
916 goto retry;
917 }
918
919 error = SYSCTL_OUT(req, tmparg, outlen);
920 free(tmparg, M_SYSCTLTMP);
921
922 if (error || !req->newptr)
923 return (error);
924
925 if ((req->newlen - req->newidx) >= arg2) {
926 error = EINVAL;
927 } else {
928 arg2 = (req->newlen - req->newidx);
929 error = SYSCTL_IN(req, arg1, arg2);
930 ((char *)arg1)[arg2] = '\0';
931 }
932
933 return (error);
934 }
935
936 /*
937 * Handle any kind of opaque data.
938 * arg1 points to it, arg2 is the size.
939 */
940
941 int
942 sysctl_handle_opaque(SYSCTL_HANDLER_ARGS)
943 {
944 int error, tries;
945 u_int generation;
946 struct sysctl_req req2;
947
948 /*
949 * Attempt to get a coherent snapshot, by using the thread
950 * pre-emption counter updated from within mi_switch() to
951 * determine if we were pre-empted during a bcopy() or
952 * copyout(). Make 3 attempts at doing this before giving up.
953 * If we encounter an error, stop immediately.
954 */
955 tries = 0;
956 req2 = *req;
957 retry:
958 generation = curthread->td_generation;
959 error = SYSCTL_OUT(req, arg1, arg2);
960 if (error)
961 return (error);
962 tries++;
963 if (generation != curthread->td_generation && tries < 3) {
964 *req = req2;
965 goto retry;
966 }
967
968 error = SYSCTL_IN(req, arg1, arg2);
969
970 return (error);
971 }
972
973 /*
974 * Transfer functions to/from kernel space.
975 * XXX: rather untested at this point
976 */
977 static int
978 sysctl_old_kernel(struct sysctl_req *req, const void *p, size_t l)
979 {
980 size_t i = 0;
981
982 if (req->oldptr) {
983 i = l;
984 if (req->oldlen <= req->oldidx)
985 i = 0;
986 else
987 if (i > req->oldlen - req->oldidx)
988 i = req->oldlen - req->oldidx;
989 if (i > 0)
990 bcopy(p, (char *)req->oldptr + req->oldidx, i);
991 }
992 req->oldidx += l;
993 if (req->oldptr && i != l)
994 return (ENOMEM);
995 return (0);
996 }
997
998 static int
999 sysctl_new_kernel(struct sysctl_req *req, void *p, size_t l)
1000 {
1001 if (!req->newptr)
1002 return (0);
1003 if (req->newlen - req->newidx < l)
1004 return (EINVAL);
1005 bcopy((char *)req->newptr + req->newidx, p, l);
1006 req->newidx += l;
1007 return (0);
1008 }
1009
1010 int
1011 kernel_sysctl(struct thread *td, int *name, u_int namelen, void *old,
1012 size_t *oldlenp, void *new, size_t newlen, size_t *retval, int flags)
1013 {
1014 int error = 0;
1015 struct sysctl_req req;
1016
1017 bzero(&req, sizeof req);
1018
1019 req.td = td;
1020 req.flags = flags;
1021
1022 if (oldlenp) {
1023 req.oldlen = *oldlenp;
1024 }
1025 req.validlen = req.oldlen;
1026
1027 if (old) {
1028 req.oldptr= old;
1029 }
1030
1031 if (new != NULL) {
1032 req.newlen = newlen;
1033 req.newptr = new;
1034 }
1035
1036 req.oldfunc = sysctl_old_kernel;
1037 req.newfunc = sysctl_new_kernel;
1038 req.lock = REQ_LOCKED;
1039
1040 SYSCTL_LOCK();
1041
1042 error = sysctl_root(0, name, namelen, &req);
1043
1044 if (req.lock == REQ_WIRED && req.validlen > 0)
1045 vsunlock(req.oldptr, req.validlen);
1046
1047 SYSCTL_UNLOCK();
1048
1049 if (error && error != ENOMEM)
1050 return (error);
1051
1052 if (retval) {
1053 if (req.oldptr && req.oldidx > req.validlen)
1054 *retval = req.validlen;
1055 else
1056 *retval = req.oldidx;
1057 }
1058 return (error);
1059 }
1060
1061 int
1062 kernel_sysctlbyname(struct thread *td, char *name, void *old, size_t *oldlenp,
1063 void *new, size_t newlen, size_t *retval, int flags)
1064 {
1065 int oid[CTL_MAXNAME];
1066 size_t oidlen, plen;
1067 int error;
1068
1069 oid[0] = 0; /* sysctl internal magic */
1070 oid[1] = 3; /* name2oid */
1071 oidlen = sizeof(oid);
1072
1073 error = kernel_sysctl(td, oid, 2, oid, &oidlen,
1074 (void *)name, strlen(name), &plen, flags);
1075 if (error)
1076 return (error);
1077
1078 error = kernel_sysctl(td, oid, plen / sizeof(int), old, oldlenp,
1079 new, newlen, retval, flags);
1080 return (error);
1081 }
1082
1083 /*
1084 * Transfer function to/from user space.
1085 */
1086 static int
1087 sysctl_old_user(struct sysctl_req *req, const void *p, size_t l)
1088 {
1089 int error = 0;
1090 size_t i, len, origidx;
1091
1092 origidx = req->oldidx;
1093 req->oldidx += l;
1094 if (req->oldptr == NULL)
1095 return (0);
1096 /*
1097 * If we have not wired the user supplied buffer and we are currently
1098 * holding locks, drop a witness warning, as it's possible that
1099 * write operations to the user page can sleep.
1100 */
1101 if (req->lock != REQ_WIRED)
1102 WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
1103 "sysctl_old_user()");
1104 i = l;
1105 len = req->validlen;
1106 if (len <= origidx)
1107 i = 0;
1108 else {
1109 if (i > len - origidx)
1110 i = len - origidx;
1111 error = copyout(p, (char *)req->oldptr + origidx, i);
1112 }
1113 if (error)
1114 return (error);
1115 if (i < l)
1116 return (ENOMEM);
1117 return (0);
1118 }
1119
1120 static int
1121 sysctl_new_user(struct sysctl_req *req, void *p, size_t l)
1122 {
1123 int error;
1124
1125 if (!req->newptr)
1126 return (0);
1127 if (req->newlen - req->newidx < l)
1128 return (EINVAL);
1129 WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
1130 "sysctl_new_user()");
1131 error = copyin((char *)req->newptr + req->newidx, p, l);
1132 req->newidx += l;
1133 return (error);
1134 }
1135
1136 /*
1137 * Wire the user space destination buffer. If set to a value greater than
1138 * zero, the len parameter limits the maximum amount of wired memory.
1139 */
1140 int
1141 sysctl_wire_old_buffer(struct sysctl_req *req, size_t len)
1142 {
1143 int ret;
1144 size_t i, wiredlen;
1145 char *cp, dummy;
1146
1147 wiredlen = (len > 0 && len < req->oldlen) ? len : req->oldlen;
1148 ret = 0;
1149 if (req->lock == REQ_LOCKED && req->oldptr &&
1150 req->oldfunc == sysctl_old_user) {
1151 if (wiredlen != 0) {
1152 ret = vslock(req->oldptr, wiredlen);
1153 if (ret != 0) {
1154 if (ret != ENOMEM)
1155 return (ret);
1156 wiredlen = 0;
1157 }
1158 /*
1159 * Touch all the wired pages to avoid PTE modified
1160 * bit emulation traps on Alpha while holding locks
1161 * in the sysctl handler.
1162 */
1163 for (i = (wiredlen + PAGE_SIZE - 1) / PAGE_SIZE,
1164 cp = req->oldptr; i > 0; i--, cp += PAGE_SIZE) {
1165 copyin(cp, &dummy, 1);
1166 copyout(&dummy, cp, 1);
1167 }
1168 }
1169 req->lock = REQ_WIRED;
1170 req->validlen = wiredlen;
1171 }
1172 return (0);
1173 }
1174
1175 int
1176 sysctl_find_oid(int *name, u_int namelen, struct sysctl_oid **noid,
1177 int *nindx, struct sysctl_req *req)
1178 {
1179 struct sysctl_oid *oid;
1180 int indx;
1181
1182 oid = SLIST_FIRST(&sysctl__children);
1183 indx = 0;
1184 while (oid && indx < CTL_MAXNAME) {
1185 if (oid->oid_number == name[indx]) {
1186 indx++;
1187 if (oid->oid_kind & CTLFLAG_NOLOCK)
1188 req->lock = REQ_UNLOCKED;
1189 if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
1190 if (oid->oid_handler != NULL ||
1191 indx == namelen) {
1192 *noid = oid;
1193 if (nindx != NULL)
1194 *nindx = indx;
1195 return (0);
1196 }
1197 oid = SLIST_FIRST(
1198 (struct sysctl_oid_list *)oid->oid_arg1);
1199 } else if (indx == namelen) {
1200 *noid = oid;
1201 if (nindx != NULL)
1202 *nindx = indx;
1203 return (0);
1204 } else {
1205 return (ENOTDIR);
1206 }
1207 } else {
1208 oid = SLIST_NEXT(oid, oid_link);
1209 }
1210 }
1211 return (ENOENT);
1212 }
1213
1214 /*
1215 * Traverse our tree, and find the right node, execute whatever it points
1216 * to, and return the resulting error code.
1217 */
1218
1219 static int
1220 sysctl_root(SYSCTL_HANDLER_ARGS)
1221 {
1222 struct sysctl_oid *oid;
1223 int error, indx, lvl;
1224
1225 error = sysctl_find_oid(arg1, arg2, &oid, &indx, req);
1226 if (error)
1227 return (error);
1228
1229 if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
1230 /*
1231 * You can't call a sysctl when it's a node, but has
1232 * no handler. Inform the user that it's a node.
1233 * The indx may or may not be the same as namelen.
1234 */
1235 if (oid->oid_handler == NULL)
1236 return (EISDIR);
1237 }
1238
1239 /* Is this sysctl writable? */
1240 if (req->newptr && !(oid->oid_kind & CTLFLAG_WR))
1241 return (EPERM);
1242
1243 KASSERT(req->td != NULL, ("sysctl_root(): req->td == NULL"));
1244
1245 /* Is this sysctl sensitive to securelevels? */
1246 if (req->newptr && (oid->oid_kind & CTLFLAG_SECURE)) {
1247 lvl = (oid->oid_kind & CTLMASK_SECURE) >> CTLSHIFT_SECURE;
1248 error = securelevel_gt(req->td->td_ucred, lvl);
1249 if (error)
1250 return (error);
1251 }
1252
1253 /* Is this sysctl writable by only privileged users? */
1254 if (req->newptr && !(oid->oid_kind & CTLFLAG_ANYBODY)) {
1255 int flags;
1256
1257 if (oid->oid_kind & CTLFLAG_PRISON)
1258 flags = SUSER_ALLOWJAIL;
1259 else
1260 flags = 0;
1261 error = suser_cred(req->td->td_ucred, flags);
1262 if (error)
1263 return (error);
1264 }
1265
1266 if (!oid->oid_handler)
1267 return (EINVAL);
1268
1269 if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
1270 arg1 = (int *)arg1 + indx;
1271 arg2 -= indx;
1272 } else {
1273 arg1 = oid->oid_arg1;
1274 arg2 = oid->oid_arg2;
1275 }
1276 #ifdef MAC
1277 error = mac_check_system_sysctl(req->td->td_ucred, oid, arg1, arg2,
1278 req);
1279 if (error != 0)
1280 return (error);
1281 #endif
1282 error = oid->oid_handler(oid, arg1, arg2, req);
1283
1284 return (error);
1285 }
1286
1287 #ifndef _SYS_SYSPROTO_H_
1288 struct sysctl_args {
1289 int *name;
1290 u_int namelen;
1291 void *old;
1292 size_t *oldlenp;
1293 void *new;
1294 size_t newlen;
1295 };
1296 #endif
1297
1298 /*
1299 * MPSAFE
1300 */
1301 int
1302 __sysctl(struct thread *td, struct sysctl_args *uap)
1303 {
1304 int error, name[CTL_MAXNAME];
1305 size_t j;
1306
1307 if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
1308 return (EINVAL);
1309
1310 error = copyin(uap->name, &name, uap->namelen * sizeof(int));
1311 if (error)
1312 return (error);
1313
1314 mtx_lock(&Giant);
1315
1316 error = userland_sysctl(td, name, uap->namelen,
1317 uap->old, uap->oldlenp, 0,
1318 uap->new, uap->newlen, &j, 0);
1319 if (error && error != ENOMEM)
1320 goto done2;
1321 if (uap->oldlenp) {
1322 int i = copyout(&j, uap->oldlenp, sizeof(j));
1323 if (i)
1324 error = i;
1325 }
1326 done2:
1327 mtx_unlock(&Giant);
1328 return (error);
1329 }
1330
1331 /*
1332 * This is used from various compatibility syscalls too. That's why name
1333 * must be in kernel space.
1334 */
1335 int
1336 userland_sysctl(struct thread *td, int *name, u_int namelen, void *old,
1337 size_t *oldlenp, int inkernel, void *new, size_t newlen, size_t *retval,
1338 int flags)
1339 {
1340 int error = 0;
1341 struct sysctl_req req;
1342
1343 bzero(&req, sizeof req);
1344
1345 req.td = td;
1346 req.flags = flags;
1347
1348 if (oldlenp) {
1349 if (inkernel) {
1350 req.oldlen = *oldlenp;
1351 } else {
1352 error = copyin(oldlenp, &req.oldlen, sizeof(*oldlenp));
1353 if (error)
1354 return (error);
1355 }
1356 }
1357 req.validlen = req.oldlen;
1358
1359 if (old) {
1360 if (!useracc(old, req.oldlen, VM_PROT_WRITE))
1361 return (EFAULT);
1362 req.oldptr= old;
1363 }
1364
1365 if (new != NULL) {
1366 if (!useracc(new, req.newlen, VM_PROT_READ))
1367 return (EFAULT);
1368 req.newlen = newlen;
1369 req.newptr = new;
1370 }
1371
1372 req.oldfunc = sysctl_old_user;
1373 req.newfunc = sysctl_new_user;
1374 req.lock = REQ_LOCKED;
1375
1376 SYSCTL_LOCK();
1377
1378 for (;;) {
1379 req.oldidx = 0;
1380 req.newidx = 0;
1381 error = sysctl_root(0, name, namelen, &req);
1382 if (error != EAGAIN)
1383 break;
1384 uio_yield();
1385 }
1386
1387 if (req.lock == REQ_WIRED && req.validlen > 0)
1388 vsunlock(req.oldptr, req.validlen);
1389
1390 SYSCTL_UNLOCK();
1391
1392 if (error && error != ENOMEM)
1393 return (error);
1394
1395 if (retval) {
1396 if (req.oldptr && req.oldidx > req.validlen)
1397 *retval = req.validlen;
1398 else
1399 *retval = req.oldidx;
1400 }
1401 return (error);
1402 }
1403
1404 #ifdef COMPAT_43
1405 #include <sys/socket.h>
1406 #include <vm/vm_param.h>
1407
1408 #define KINFO_PROC (0<<8)
1409 #define KINFO_RT (1<<8)
1410 #define KINFO_VNODE (2<<8)
1411 #define KINFO_FILE (3<<8)
1412 #define KINFO_METER (4<<8)
1413 #define KINFO_LOADAVG (5<<8)
1414 #define KINFO_CLOCKRATE (6<<8)
1415
1416 /* Non-standard BSDI extension - only present on their 4.3 net-2 releases */
1417 #define KINFO_BSDI_SYSINFO (101<<8)
1418
1419 /*
1420 * XXX this is bloat, but I hope it's better here than on the potentially
1421 * limited kernel stack... -Peter
1422 */
1423
1424 static struct {
1425 int bsdi_machine; /* "i386" on BSD/386 */
1426 /* ^^^ this is an offset to the string, relative to the struct start */
1427 char *pad0;
1428 long pad1;
1429 long pad2;
1430 long pad3;
1431 u_long pad4;
1432 u_long pad5;
1433 u_long pad6;
1434
1435 int bsdi_ostype; /* "BSD/386" on BSD/386 */
1436 int bsdi_osrelease; /* "1.1" on BSD/386 */
1437 long pad7;
1438 long pad8;
1439 char *pad9;
1440
1441 long pad10;
1442 long pad11;
1443 int pad12;
1444 long pad13;
1445 quad_t pad14;
1446 long pad15;
1447
1448 struct timeval pad16;
1449 /* we dont set this, because BSDI's uname used gethostname() instead */
1450 int bsdi_hostname; /* hostname on BSD/386 */
1451
1452 /* the actual string data is appended here */
1453
1454 } bsdi_si;
1455 /*
1456 * this data is appended to the end of the bsdi_si structure during copyout.
1457 * The "char *" offsets are relative to the base of the bsdi_si struct.
1458 * This contains "FreeBSD\02.0-BUILT-nnnnnn\0i386\0", and these strings
1459 * should not exceed the length of the buffer here... (or else!! :-)
1460 */
1461 static char bsdi_strings[80]; /* It had better be less than this! */
1462
1463 #ifndef _SYS_SYSPROTO_H_
1464 struct getkerninfo_args {
1465 int op;
1466 char *where;
1467 size_t *size;
1468 int arg;
1469 };
1470 #endif
1471
1472 /*
1473 * MPSAFE
1474 */
1475 int
1476 ogetkerninfo(struct thread *td, struct getkerninfo_args *uap)
1477 {
1478 int error, name[6];
1479 size_t size;
1480 u_int needed = 0;
1481
1482 mtx_lock(&Giant);
1483
1484 switch (uap->op & 0xff00) {
1485
1486 case KINFO_RT:
1487 name[0] = CTL_NET;
1488 name[1] = PF_ROUTE;
1489 name[2] = 0;
1490 name[3] = (uap->op & 0xff0000) >> 16;
1491 name[4] = uap->op & 0xff;
1492 name[5] = uap->arg;
1493 error = userland_sysctl(td, name, 6, uap->where, uap->size,
1494 0, 0, 0, &size, 0);
1495 break;
1496
1497 case KINFO_VNODE:
1498 name[0] = CTL_KERN;
1499 name[1] = KERN_VNODE;
1500 error = userland_sysctl(td, name, 2, uap->where, uap->size,
1501 0, 0, 0, &size, 0);
1502 break;
1503
1504 case KINFO_PROC:
1505 name[0] = CTL_KERN;
1506 name[1] = KERN_PROC;
1507 name[2] = uap->op & 0xff;
1508 name[3] = uap->arg;
1509 error = userland_sysctl(td, name, 4, uap->where, uap->size,
1510 0, 0, 0, &size, 0);
1511 break;
1512
1513 case KINFO_FILE:
1514 name[0] = CTL_KERN;
1515 name[1] = KERN_FILE;
1516 error = userland_sysctl(td, name, 2, uap->where, uap->size,
1517 0, 0, 0, &size, 0);
1518 break;
1519
1520 case KINFO_METER:
1521 name[0] = CTL_VM;
1522 name[1] = VM_TOTAL;
1523 error = userland_sysctl(td, name, 2, uap->where, uap->size,
1524 0, 0, 0, &size, 0);
1525 break;
1526
1527 case KINFO_LOADAVG:
1528 name[0] = CTL_VM;
1529 name[1] = VM_LOADAVG;
1530 error = userland_sysctl(td, name, 2, uap->where, uap->size,
1531 0, 0, 0, &size, 0);
1532 break;
1533
1534 case KINFO_CLOCKRATE:
1535 name[0] = CTL_KERN;
1536 name[1] = KERN_CLOCKRATE;
1537 error = userland_sysctl(td, name, 2, uap->where, uap->size,
1538 0, 0, 0, &size, 0);
1539 break;
1540
1541 case KINFO_BSDI_SYSINFO: {
1542 /*
1543 * this is pretty crude, but it's just enough for uname()
1544 * from BSDI's 1.x libc to work.
1545 *
1546 * *size gives the size of the buffer before the call, and
1547 * the amount of data copied after a successful call.
1548 * If successful, the return value is the amount of data
1549 * available, which can be larger than *size.
1550 *
1551 * BSDI's 2.x product apparently fails with ENOMEM if *size
1552 * is too small.
1553 */
1554
1555 u_int left;
1556 char *s;
1557
1558 bzero((char *)&bsdi_si, sizeof(bsdi_si));
1559 bzero(bsdi_strings, sizeof(bsdi_strings));
1560
1561 s = bsdi_strings;
1562
1563 bsdi_si.bsdi_ostype = (s - bsdi_strings) + sizeof(bsdi_si);
1564 strcpy(s, ostype);
1565 s += strlen(s) + 1;
1566
1567 bsdi_si.bsdi_osrelease = (s - bsdi_strings) + sizeof(bsdi_si);
1568 strcpy(s, osrelease);
1569 s += strlen(s) + 1;
1570
1571 bsdi_si.bsdi_machine = (s - bsdi_strings) + sizeof(bsdi_si);
1572 strcpy(s, machine);
1573 s += strlen(s) + 1;
1574
1575 needed = sizeof(bsdi_si) + (s - bsdi_strings);
1576
1577 if ((uap->where == NULL) || (uap->size == NULL)) {
1578 /* process is asking how much buffer to supply.. */
1579 size = needed;
1580 error = 0;
1581 break;
1582 }
1583
1584 if ((error = copyin(uap->size, &size, sizeof(size))) != 0)
1585 break;
1586
1587 /* if too much buffer supplied, trim it down */
1588 if (size > needed)
1589 size = needed;
1590
1591 /* how much of the buffer is remaining */
1592 left = size;
1593
1594 if ((error = copyout((char *)&bsdi_si, uap->where, left)) != 0)
1595 break;
1596
1597 /* is there any point in continuing? */
1598 if (left > sizeof(bsdi_si)) {
1599 left -= sizeof(bsdi_si);
1600 error = copyout(&bsdi_strings,
1601 uap->where + sizeof(bsdi_si), left);
1602 }
1603 break;
1604 }
1605
1606 default:
1607 error = EOPNOTSUPP;
1608 break;
1609 }
1610 if (error == 0) {
1611 td->td_retval[0] = needed ? needed : size;
1612 if (uap->size) {
1613 error = copyout(&size, uap->size, sizeof(size));
1614 }
1615 }
1616 mtx_unlock(&Giant);
1617 return (error);
1618 }
1619 #endif /* COMPAT_43 */
Cache object: 8309957d34e19a18e2879ebb7241b83f
|