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