Annotation of sys/kern/kern_sysctl.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: kern_sysctl.c,v 1.155 2007/08/09 04:12:12 cnst Exp $ */
2: /* $NetBSD: kern_sysctl.c,v 1.17 1996/05/20 17:49:05 mrg Exp $ */
3:
4: /*-
5: * Copyright (c) 1982, 1986, 1989, 1993
6: * The Regents of the University of California. All rights reserved.
7: *
8: * This code is derived from software contributed to Berkeley by
9: * Mike Karels at Berkeley Software Design, Inc.
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. 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: /*
39: * sysctl system call.
40: */
41:
42: #include <sys/param.h>
43: #include <sys/systm.h>
44: #include <sys/kernel.h>
45: #include <sys/malloc.h>
46: #include <sys/proc.h>
47: #include <sys/resourcevar.h>
48: #include <sys/file.h>
49: #include <sys/vnode.h>
50: #include <sys/unistd.h>
51: #include <sys/buf.h>
52: #include <sys/ioctl.h>
53: #include <sys/tty.h>
54: #include <sys/disklabel.h>
55: #include <sys/disk.h>
56: #include <uvm/uvm_extern.h>
57: #include <sys/sysctl.h>
58: #include <sys/msgbuf.h>
59: #include <sys/dkstat.h>
60: #include <sys/vmmeter.h>
61: #include <sys/namei.h>
62: #include <sys/exec.h>
63: #include <sys/mbuf.h>
64: #include <sys/sensors.h>
65: #ifdef __HAVE_TIMECOUNTER
66: #include <sys/timetc.h>
67: #endif
68: #include <sys/evcount.h>
69:
70: #include <sys/mount.h>
71: #include <sys/syscallargs.h>
72: #include <dev/rndvar.h>
73:
74: #ifdef DDB
75: #include <ddb/db_var.h>
76: #endif
77:
78: #ifdef SYSVMSG
79: #include <sys/msg.h>
80: #endif
81: #ifdef SYSVSEM
82: #include <sys/sem.h>
83: #endif
84: #ifdef SYSVSHM
85: #include <sys/shm.h>
86: #endif
87:
88: #define PTRTOINT64(_x) ((u_int64_t)(u_long)(_x))
89:
90: extern struct forkstat forkstat;
91: extern struct nchstats nchstats;
92: extern int nselcoll, fscale;
93: extern struct disklist_head disklist;
94: extern fixpt_t ccpu;
95: extern long numvnodes;
96:
97: extern void nmbclust_update(void);
98:
99: int sysctl_diskinit(int, struct proc *);
100: int sysctl_proc_args(int *, u_int, void *, size_t *, struct proc *);
101: int sysctl_intrcnt(int *, u_int, void *, size_t *);
102: int sysctl_sensors(int *, u_int, void *, size_t *, void *, size_t);
103: int sysctl_emul(int *, u_int, void *, size_t *, void *, size_t);
104: int sysctl_cptime2(int *, u_int, void *, size_t *, void *, size_t);
105:
106: int (*cpu_cpuspeed)(int *);
107: void (*cpu_setperf)(int);
108: int perflevel = 100;
109:
110: /*
111: * Lock to avoid too many processes vslocking a large amount of memory
112: * at the same time.
113: */
114: struct rwlock sysctl_lock = RWLOCK_INITIALIZER("sysctllk");
115: struct rwlock sysctl_disklock = RWLOCK_INITIALIZER("sysctldlk");
116:
117: int
118: sys___sysctl(struct proc *p, void *v, register_t *retval)
119: {
120: struct sys___sysctl_args /* {
121: syscallarg(int *) name;
122: syscallarg(u_int) namelen;
123: syscallarg(void *) old;
124: syscallarg(size_t *) oldlenp;
125: syscallarg(void *) new;
126: syscallarg(size_t) newlen;
127: } */ *uap = v;
128: int error, dolock = 1;
129: size_t savelen = 0, oldlen = 0;
130: sysctlfn *fn;
131: int name[CTL_MAXNAME];
132:
133: if (SCARG(uap, new) != NULL &&
134: (error = suser(p, 0)))
135: return (error);
136: /*
137: * all top-level sysctl names are non-terminal
138: */
139: if (SCARG(uap, namelen) > CTL_MAXNAME || SCARG(uap, namelen) < 2)
140: return (EINVAL);
141: error = copyin(SCARG(uap, name), name,
142: SCARG(uap, namelen) * sizeof(int));
143: if (error)
144: return (error);
145:
146: switch (name[0]) {
147: case CTL_KERN:
148: fn = kern_sysctl;
149: if (name[1] == KERN_VNODE) /* XXX */
150: dolock = 0;
151: break;
152: case CTL_HW:
153: fn = hw_sysctl;
154: break;
155: case CTL_VM:
156: fn = uvm_sysctl;
157: break;
158: case CTL_NET:
159: fn = net_sysctl;
160: break;
161: case CTL_FS:
162: fn = fs_sysctl;
163: break;
164: case CTL_VFS:
165: fn = vfs_sysctl;
166: break;
167: case CTL_MACHDEP:
168: fn = cpu_sysctl;
169: break;
170: #ifdef DEBUG
171: case CTL_DEBUG:
172: fn = debug_sysctl;
173: break;
174: #endif
175: #ifdef DDB
176: case CTL_DDB:
177: fn = ddb_sysctl;
178: break;
179: #endif
180: default:
181: return (EOPNOTSUPP);
182: }
183:
184: if (SCARG(uap, oldlenp) &&
185: (error = copyin(SCARG(uap, oldlenp), &oldlen, sizeof(oldlen))))
186: return (error);
187: if (SCARG(uap, old) != NULL) {
188: if ((error = rw_enter(&sysctl_lock, RW_WRITE|RW_INTR)) != 0)
189: return (error);
190: if (dolock) {
191: if (atop(oldlen) > uvmexp.wiredmax - uvmexp.wired) {
192: rw_exit_write(&sysctl_lock);
193: return (ENOMEM);
194: }
195: error = uvm_vslock(p, SCARG(uap, old), oldlen,
196: VM_PROT_READ|VM_PROT_WRITE);
197: if (error) {
198: rw_exit_write(&sysctl_lock);
199: return (error);
200: }
201: }
202: savelen = oldlen;
203: }
204: error = (*fn)(&name[1], SCARG(uap, namelen) - 1, SCARG(uap, old),
205: &oldlen, SCARG(uap, new), SCARG(uap, newlen), p);
206: if (SCARG(uap, old) != NULL) {
207: if (dolock)
208: uvm_vsunlock(p, SCARG(uap, old), savelen);
209: rw_exit_write(&sysctl_lock);
210: }
211: if (error)
212: return (error);
213: if (SCARG(uap, oldlenp))
214: error = copyout(&oldlen, SCARG(uap, oldlenp), sizeof(oldlen));
215: return (error);
216: }
217:
218: /*
219: * Attributes stored in the kernel.
220: */
221: char hostname[MAXHOSTNAMELEN];
222: int hostnamelen;
223: char domainname[MAXHOSTNAMELEN];
224: int domainnamelen;
225: long hostid;
226: char *disknames = NULL;
227: struct diskstats *diskstats = NULL;
228: #ifdef INSECURE
229: int securelevel = -1;
230: #else
231: int securelevel;
232: #endif
233:
234: /*
235: * kernel related system variables.
236: */
237: int
238: kern_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
239: size_t newlen, struct proc *p)
240: {
241: int error, level, inthostid, stackgap;
242: extern int somaxconn, sominconn;
243: extern int usermount, nosuidcoredump;
244: extern long cp_time[CPUSTATES];
245: extern int stackgap_random;
246: #ifdef CRYPTO
247: extern int usercrypto;
248: extern int userasymcrypto;
249: extern int cryptodevallowsoft;
250: #endif
251: extern int maxlocksperuid;
252:
253: /* all sysctl names at this level are terminal except a ton of them */
254: if (namelen != 1) {
255: switch (name[0]) {
256: case KERN_PROC:
257: case KERN_PROC2:
258: case KERN_PROF:
259: case KERN_MALLOCSTATS:
260: case KERN_TTY:
261: case KERN_POOL:
262: case KERN_PROC_ARGS:
263: case KERN_SYSVIPC_INFO:
264: case KERN_SEMINFO:
265: case KERN_SHMINFO:
266: case KERN_INTRCNT:
267: case KERN_WATCHDOG:
268: case KERN_EMUL:
269: case KERN_EVCOUNT:
270: #ifdef __HAVE_TIMECOUNTER
271: case KERN_TIMECOUNTER:
272: #endif
273: case KERN_CPTIME2:
274: break;
275: default:
276: return (ENOTDIR); /* overloaded */
277: }
278: }
279:
280: switch (name[0]) {
281: case KERN_OSTYPE:
282: return (sysctl_rdstring(oldp, oldlenp, newp, ostype));
283: case KERN_OSRELEASE:
284: return (sysctl_rdstring(oldp, oldlenp, newp, osrelease));
285: case KERN_OSREV:
286: return (sysctl_rdint(oldp, oldlenp, newp, OpenBSD));
287: case KERN_OSVERSION:
288: return (sysctl_rdstring(oldp, oldlenp, newp, osversion));
289: case KERN_VERSION:
290: return (sysctl_rdstring(oldp, oldlenp, newp, version));
291: case KERN_MAXVNODES:
292: return(sysctl_int(oldp, oldlenp, newp, newlen, &maxvnodes));
293: case KERN_MAXPROC:
294: return (sysctl_int(oldp, oldlenp, newp, newlen, &maxproc));
295: case KERN_MAXFILES:
296: return (sysctl_int(oldp, oldlenp, newp, newlen, &maxfiles));
297: case KERN_NFILES:
298: return (sysctl_rdint(oldp, oldlenp, newp, nfiles));
299: case KERN_TTYCOUNT:
300: return (sysctl_rdint(oldp, oldlenp, newp, tty_count));
301: case KERN_NUMVNODES:
302: return (sysctl_rdint(oldp, oldlenp, newp, numvnodes));
303: case KERN_ARGMAX:
304: return (sysctl_rdint(oldp, oldlenp, newp, ARG_MAX));
305: case KERN_NSELCOLL:
306: return (sysctl_rdint(oldp, oldlenp, newp, nselcoll));
307: case KERN_SECURELVL:
308: level = securelevel;
309: if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &level)) ||
310: newp == NULL)
311: return (error);
312: if ((securelevel > 0 || level < -1) &&
313: level < securelevel && p->p_pid != 1)
314: return (EPERM);
315: securelevel = level;
316: return (0);
317: case KERN_HOSTNAME:
318: error = sysctl_tstring(oldp, oldlenp, newp, newlen,
319: hostname, sizeof(hostname));
320: if (newp && !error)
321: hostnamelen = newlen;
322: return (error);
323: case KERN_DOMAINNAME:
324: error = sysctl_tstring(oldp, oldlenp, newp, newlen,
325: domainname, sizeof(domainname));
326: if (newp && !error)
327: domainnamelen = newlen;
328: return (error);
329: case KERN_HOSTID:
330: inthostid = hostid; /* XXX assumes sizeof long <= sizeof int */
331: error = sysctl_int(oldp, oldlenp, newp, newlen, &inthostid);
332: hostid = inthostid;
333: return (error);
334: case KERN_CLOCKRATE:
335: return (sysctl_clockrate(oldp, oldlenp));
336: case KERN_BOOTTIME:
337: return (sysctl_rdstruct(oldp, oldlenp, newp, &boottime,
338: sizeof(struct timeval)));
339: case KERN_VNODE:
340: return (sysctl_vnode(oldp, oldlenp, p));
341: #ifndef SMALL_KERNEL
342: case KERN_PROC:
343: case KERN_PROC2:
344: return (sysctl_doproc(name, namelen, oldp, oldlenp));
345: case KERN_PROC_ARGS:
346: return (sysctl_proc_args(name + 1, namelen - 1, oldp, oldlenp,
347: p));
348: #endif
349: case KERN_FILE:
350: return (sysctl_file(oldp, oldlenp));
351: case KERN_MBSTAT:
352: return (sysctl_rdstruct(oldp, oldlenp, newp, &mbstat,
353: sizeof(mbstat)));
354: #ifdef GPROF
355: case KERN_PROF:
356: return (sysctl_doprof(name + 1, namelen - 1, oldp, oldlenp,
357: newp, newlen));
358: #endif
359: case KERN_POSIX1:
360: return (sysctl_rdint(oldp, oldlenp, newp, _POSIX_VERSION));
361: case KERN_NGROUPS:
362: return (sysctl_rdint(oldp, oldlenp, newp, NGROUPS_MAX));
363: case KERN_JOB_CONTROL:
364: return (sysctl_rdint(oldp, oldlenp, newp, 1));
365: case KERN_SAVED_IDS:
366: #ifdef _POSIX_SAVED_IDS
367: return (sysctl_rdint(oldp, oldlenp, newp, 1));
368: #else
369: return (sysctl_rdint(oldp, oldlenp, newp, 0));
370: #endif
371: case KERN_MAXPARTITIONS:
372: return (sysctl_rdint(oldp, oldlenp, newp, MAXPARTITIONS));
373: case KERN_RAWPARTITION:
374: return (sysctl_rdint(oldp, oldlenp, newp, RAW_PART));
375: case KERN_SOMAXCONN:
376: return (sysctl_int(oldp, oldlenp, newp, newlen, &somaxconn));
377: case KERN_SOMINCONN:
378: return (sysctl_int(oldp, oldlenp, newp, newlen, &sominconn));
379: case KERN_USERMOUNT:
380: return (sysctl_int(oldp, oldlenp, newp, newlen, &usermount));
381: case KERN_RND:
382: return (sysctl_rdstruct(oldp, oldlenp, newp, &rndstats,
383: sizeof(rndstats)));
384: case KERN_ARND: {
385: char buf[256];
386:
387: if (*oldlenp > sizeof(buf))
388: *oldlenp = sizeof(buf);
389: if (oldp) {
390: arc4random_bytes(buf, *oldlenp);
391: if ((error = copyout(buf, oldp, *oldlenp)))
392: return (error);
393: }
394: return (0);
395: }
396: case KERN_NOSUIDCOREDUMP:
397: return (sysctl_int(oldp, oldlenp, newp, newlen, &nosuidcoredump));
398: case KERN_FSYNC:
399: return (sysctl_rdint(oldp, oldlenp, newp, 1));
400: case KERN_SYSVMSG:
401: #ifdef SYSVMSG
402: return (sysctl_rdint(oldp, oldlenp, newp, 1));
403: #else
404: return (sysctl_rdint(oldp, oldlenp, newp, 0));
405: #endif
406: case KERN_SYSVSEM:
407: #ifdef SYSVSEM
408: return (sysctl_rdint(oldp, oldlenp, newp, 1));
409: #else
410: return (sysctl_rdint(oldp, oldlenp, newp, 0));
411: #endif
412: case KERN_SYSVSHM:
413: #ifdef SYSVSHM
414: return (sysctl_rdint(oldp, oldlenp, newp, 1));
415: #else
416: return (sysctl_rdint(oldp, oldlenp, newp, 0));
417: #endif
418: case KERN_MSGBUFSIZE:
419: /*
420: * deal with cases where the message buffer has
421: * become corrupted.
422: */
423: if (!msgbufp || msgbufp->msg_magic != MSG_MAGIC)
424: return (ENXIO);
425: return (sysctl_rdint(oldp, oldlenp, newp, msgbufp->msg_bufs));
426: case KERN_MSGBUF:
427: /* see note above */
428: if (!msgbufp || msgbufp->msg_magic != MSG_MAGIC)
429: return (ENXIO);
430: return (sysctl_rdstruct(oldp, oldlenp, newp, msgbufp,
431: msgbufp->msg_bufs + offsetof(struct msgbuf, msg_bufc)));
432: case KERN_MALLOCSTATS:
433: return (sysctl_malloc(name + 1, namelen - 1, oldp, oldlenp,
434: newp, newlen, p));
435: case KERN_CPTIME:
436: {
437: CPU_INFO_ITERATOR cii;
438: struct cpu_info *ci;
439: int i;
440:
441: bzero(cp_time, sizeof(cp_time));
442:
443: CPU_INFO_FOREACH(cii, ci) {
444: for (i = 0; i < CPUSTATES; i++)
445: cp_time[i] += ci->ci_schedstate.spc_cp_time[i];
446: }
447:
448: return (sysctl_rdstruct(oldp, oldlenp, newp, &cp_time,
449: sizeof(cp_time)));
450: }
451: case KERN_NCHSTATS:
452: return (sysctl_rdstruct(oldp, oldlenp, newp, &nchstats,
453: sizeof(struct nchstats)));
454: case KERN_FORKSTAT:
455: return (sysctl_rdstruct(oldp, oldlenp, newp, &forkstat,
456: sizeof(struct forkstat)));
457: case KERN_TTY:
458: return (sysctl_tty(name + 1, namelen - 1, oldp, oldlenp,
459: newp, newlen));
460: case KERN_FSCALE:
461: return (sysctl_rdint(oldp, oldlenp, newp, fscale));
462: case KERN_CCPU:
463: return (sysctl_rdint(oldp, oldlenp, newp, ccpu));
464: case KERN_NPROCS:
465: return (sysctl_rdint(oldp, oldlenp, newp, nprocs));
466: case KERN_POOL:
467: return (sysctl_dopool(name + 1, namelen - 1, oldp, oldlenp));
468: case KERN_STACKGAPRANDOM:
469: stackgap = stackgap_random;
470: error = sysctl_int(oldp, oldlenp, newp, newlen, &stackgap);
471: if (error)
472: return (error);
473: /*
474: * Safety harness.
475: */
476: if ((stackgap < ALIGNBYTES && stackgap != 0) ||
477: !powerof2(stackgap) || stackgap >= MAXSSIZ)
478: return (EINVAL);
479: stackgap_random = stackgap;
480: return (0);
481: #if defined(SYSVMSG) || defined(SYSVSEM) || defined(SYSVSHM)
482: case KERN_SYSVIPC_INFO:
483: return (sysctl_sysvipc(name + 1, namelen - 1, oldp, oldlenp));
484: #endif
485: #ifdef CRYPTO
486: case KERN_USERCRYPTO:
487: return (sysctl_int(oldp, oldlenp, newp, newlen, &usercrypto));
488: case KERN_USERASYMCRYPTO:
489: return (sysctl_int(oldp, oldlenp, newp, newlen,
490: &userasymcrypto));
491: case KERN_CRYPTODEVALLOWSOFT:
492: return (sysctl_int(oldp, oldlenp, newp, newlen,
493: &cryptodevallowsoft));
494: #endif
495: case KERN_SPLASSERT:
496: return (sysctl_int(oldp, oldlenp, newp, newlen,
497: &splassert_ctl));
498: #ifdef SYSVSEM
499: case KERN_SEMINFO:
500: return (sysctl_sysvsem(name + 1, namelen - 1, oldp, oldlenp,
501: newp, newlen));
502: #endif
503: #ifdef SYSVSHM
504: case KERN_SHMINFO:
505: return (sysctl_sysvshm(name + 1, namelen - 1, oldp, oldlenp,
506: newp, newlen));
507: #endif
508: #ifndef SMALL_KERNEL
509: case KERN_INTRCNT:
510: return (sysctl_intrcnt(name + 1, namelen - 1, oldp, oldlenp));
511: case KERN_WATCHDOG:
512: return (sysctl_wdog(name + 1, namelen - 1, oldp, oldlenp,
513: newp, newlen));
514: case KERN_EMUL:
515: return (sysctl_emul(name + 1, namelen - 1, oldp, oldlenp,
516: newp, newlen));
517: #endif
518: case KERN_MAXCLUSTERS:
519: error = sysctl_int(oldp, oldlenp, newp, newlen, &nmbclust);
520: if (!error)
521: nmbclust_update();
522: return (error);
523: #ifndef SMALL_KERNEL
524: case KERN_EVCOUNT:
525: return (evcount_sysctl(name + 1, namelen - 1, oldp, oldlenp,
526: newp, newlen));
527: #endif
528: #ifdef __HAVE_TIMECOUNTER
529: case KERN_TIMECOUNTER:
530: return (sysctl_tc(name + 1, namelen - 1, oldp, oldlenp,
531: newp, newlen));
532: #endif
533: case KERN_MAXLOCKSPERUID:
534: return (sysctl_int(oldp, oldlenp, newp, newlen, &maxlocksperuid));
535: case KERN_CPTIME2:
536: return (sysctl_cptime2(name + 1, namelen -1, oldp, oldlenp,
537: newp, newlen));
538: default:
539: return (EOPNOTSUPP);
540: }
541: /* NOTREACHED */
542: }
543:
544: /*
545: * hardware related system variables.
546: */
547: char *hw_vendor, *hw_prod, *hw_uuid, *hw_serial, *hw_ver;
548:
549: int
550: hw_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
551: size_t newlen, struct proc *p)
552: {
553: extern char machine[], cpu_model[];
554: int err, cpuspeed;
555:
556: /* all sysctl names at this level except sensors are terminal */
557: if (name[0] != HW_SENSORS && namelen != 1)
558: return (ENOTDIR); /* overloaded */
559:
560: switch (name[0]) {
561: case HW_MACHINE:
562: return (sysctl_rdstring(oldp, oldlenp, newp, machine));
563: case HW_MODEL:
564: return (sysctl_rdstring(oldp, oldlenp, newp, cpu_model));
565: case HW_NCPU:
566: return (sysctl_rdint(oldp, oldlenp, newp, ncpus));
567: case HW_BYTEORDER:
568: return (sysctl_rdint(oldp, oldlenp, newp, BYTE_ORDER));
569: case HW_PHYSMEM:
570: return (sysctl_rdint(oldp, oldlenp, newp, ctob(physmem)));
571: case HW_USERMEM:
572: return (sysctl_rdint(oldp, oldlenp, newp,
573: ctob(physmem - uvmexp.wired)));
574: case HW_PAGESIZE:
575: return (sysctl_rdint(oldp, oldlenp, newp, PAGE_SIZE));
576: case HW_DISKNAMES:
577: err = sysctl_diskinit(0, p);
578: if (err)
579: return err;
580: if (disknames)
581: return (sysctl_rdstring(oldp, oldlenp, newp,
582: disknames));
583: else
584: return (sysctl_rdstring(oldp, oldlenp, newp, ""));
585: case HW_DISKSTATS:
586: err = sysctl_diskinit(1, p);
587: if (err)
588: return err;
589: return (sysctl_rdstruct(oldp, oldlenp, newp, diskstats,
590: disk_count * sizeof(struct diskstats)));
591: case HW_DISKCOUNT:
592: return (sysctl_rdint(oldp, oldlenp, newp, disk_count));
593: #ifndef SMALL_KERNEL
594: case HW_SENSORS:
595: return (sysctl_sensors(name + 1, namelen - 1, oldp, oldlenp,
596: newp, newlen));
597: #endif
598: case HW_CPUSPEED:
599: if (!cpu_cpuspeed)
600: return (EOPNOTSUPP);
601: err = cpu_cpuspeed(&cpuspeed);
602: if (err)
603: return err;
604: return (sysctl_rdint(oldp, oldlenp, newp, cpuspeed));
605: case HW_SETPERF:
606: if (!cpu_setperf)
607: return (EOPNOTSUPP);
608: err = sysctl_int(oldp, oldlenp, newp, newlen, &perflevel);
609: if (err)
610: return err;
611: if (perflevel > 100)
612: perflevel = 100;
613: if (perflevel < 0)
614: perflevel = 0;
615: if (newp)
616: cpu_setperf(perflevel);
617: return (0);
618: case HW_VENDOR:
619: if (hw_vendor)
620: return (sysctl_rdstring(oldp, oldlenp, newp,
621: hw_vendor));
622: else
623: return (EOPNOTSUPP);
624: case HW_PRODUCT:
625: if (hw_prod)
626: return (sysctl_rdstring(oldp, oldlenp, newp, hw_prod));
627: else
628: return (EOPNOTSUPP);
629: case HW_VERSION:
630: if (hw_ver)
631: return (sysctl_rdstring(oldp, oldlenp, newp, hw_ver));
632: else
633: return (EOPNOTSUPP);
634: case HW_SERIALNO:
635: if (hw_serial)
636: return (sysctl_rdstring(oldp, oldlenp, newp,
637: hw_serial));
638: else
639: return (EOPNOTSUPP);
640: case HW_UUID:
641: if (hw_uuid)
642: return (sysctl_rdstring(oldp, oldlenp, newp, hw_uuid));
643: else
644: return (EOPNOTSUPP);
645: default:
646: return (EOPNOTSUPP);
647: }
648: /* NOTREACHED */
649: }
650:
651: #ifdef DEBUG
652: /*
653: * Debugging related system variables.
654: */
655: extern struct ctldebug debug0, debug1;
656: struct ctldebug debug2, debug3, debug4;
657: struct ctldebug debug5, debug6, debug7, debug8, debug9;
658: struct ctldebug debug10, debug11, debug12, debug13, debug14;
659: struct ctldebug debug15, debug16, debug17, debug18, debug19;
660: static struct ctldebug *debugvars[CTL_DEBUG_MAXID] = {
661: &debug0, &debug1, &debug2, &debug3, &debug4,
662: &debug5, &debug6, &debug7, &debug8, &debug9,
663: &debug10, &debug11, &debug12, &debug13, &debug14,
664: &debug15, &debug16, &debug17, &debug18, &debug19,
665: };
666: int
667: debug_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
668: size_t newlen, struct proc *p)
669: {
670: struct ctldebug *cdp;
671:
672: /* all sysctl names at this level are name and field */
673: if (namelen != 2)
674: return (ENOTDIR); /* overloaded */
675: cdp = debugvars[name[0]];
676: if (cdp->debugname == 0)
677: return (EOPNOTSUPP);
678: switch (name[1]) {
679: case CTL_DEBUG_NAME:
680: return (sysctl_rdstring(oldp, oldlenp, newp, cdp->debugname));
681: case CTL_DEBUG_VALUE:
682: return (sysctl_int(oldp, oldlenp, newp, newlen, cdp->debugvar));
683: default:
684: return (EOPNOTSUPP);
685: }
686: /* NOTREACHED */
687: }
688: #endif /* DEBUG */
689:
690: /*
691: * Reads, or writes that lower the value
692: */
693: int
694: sysctl_int_lower(void *oldp, size_t *oldlenp, void *newp, size_t newlen, int *valp)
695: {
696: unsigned int oval = *valp, val = *valp;
697: int error;
698:
699: if (newp == NULL)
700: return (sysctl_rdint(oldp, oldlenp, newp, *valp));
701:
702: if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &val)))
703: return (error);
704: if (val > oval)
705: return (EPERM); /* do not allow raising */
706: *(unsigned int *)valp = val;
707: return (0);
708: }
709:
710: /*
711: * Validate parameters and get old / set new parameters
712: * for an integer-valued sysctl function.
713: */
714: int
715: sysctl_int(void *oldp, size_t *oldlenp, void *newp, size_t newlen, int *valp)
716: {
717: int error = 0;
718:
719: if (oldp && *oldlenp < sizeof(int))
720: return (ENOMEM);
721: if (newp && newlen != sizeof(int))
722: return (EINVAL);
723: *oldlenp = sizeof(int);
724: if (oldp)
725: error = copyout(valp, oldp, sizeof(int));
726: if (error == 0 && newp)
727: error = copyin(newp, valp, sizeof(int));
728: return (error);
729: }
730:
731: /*
732: * As above, but read-only.
733: */
734: int
735: sysctl_rdint(void *oldp, size_t *oldlenp, void *newp, int val)
736: {
737: int error = 0;
738:
739: if (oldp && *oldlenp < sizeof(int))
740: return (ENOMEM);
741: if (newp)
742: return (EPERM);
743: *oldlenp = sizeof(int);
744: if (oldp)
745: error = copyout((caddr_t)&val, oldp, sizeof(int));
746: return (error);
747: }
748:
749: /*
750: * Array of integer values.
751: */
752: int
753: sysctl_int_arr(int **valpp, int *name, u_int namelen, void *oldp,
754: size_t *oldlenp, void *newp, size_t newlen)
755: {
756: if (namelen > 1)
757: return (ENOTDIR);
758: if (name[0] < 0 || valpp[name[0]] == NULL)
759: return (EOPNOTSUPP);
760: return (sysctl_int(oldp, oldlenp, newp, newlen, valpp[name[0]]));
761: }
762:
763: /*
764: * Validate parameters and get old / set new parameters
765: * for an integer-valued sysctl function.
766: */
767: int
768: sysctl_quad(void *oldp, size_t *oldlenp, void *newp, size_t newlen,
769: int64_t *valp)
770: {
771: int error = 0;
772:
773: if (oldp && *oldlenp < sizeof(int64_t))
774: return (ENOMEM);
775: if (newp && newlen != sizeof(int64_t))
776: return (EINVAL);
777: *oldlenp = sizeof(int64_t);
778: if (oldp)
779: error = copyout(valp, oldp, sizeof(int64_t));
780: if (error == 0 && newp)
781: error = copyin(newp, valp, sizeof(int64_t));
782: return (error);
783: }
784:
785: /*
786: * As above, but read-only.
787: */
788: int
789: sysctl_rdquad(void *oldp, size_t *oldlenp, void *newp, int64_t val)
790: {
791: int error = 0;
792:
793: if (oldp && *oldlenp < sizeof(int64_t))
794: return (ENOMEM);
795: if (newp)
796: return (EPERM);
797: *oldlenp = sizeof(int64_t);
798: if (oldp)
799: error = copyout((caddr_t)&val, oldp, sizeof(int64_t));
800: return (error);
801: }
802:
803: /*
804: * Validate parameters and get old / set new parameters
805: * for a string-valued sysctl function.
806: */
807: int
808: sysctl_string(void *oldp, size_t *oldlenp, void *newp, size_t newlen, char *str,
809: int maxlen)
810: {
811: return sysctl__string(oldp, oldlenp, newp, newlen, str, maxlen, 0);
812: }
813:
814: int
815: sysctl_tstring(void *oldp, size_t *oldlenp, void *newp, size_t newlen,
816: char *str, int maxlen)
817: {
818: return sysctl__string(oldp, oldlenp, newp, newlen, str, maxlen, 1);
819: }
820:
821: int
822: sysctl__string(void *oldp, size_t *oldlenp, void *newp, size_t newlen,
823: char *str, int maxlen, int trunc)
824: {
825: int len, error = 0;
826: char c;
827:
828: len = strlen(str) + 1;
829: if (oldp && *oldlenp < len) {
830: if (trunc == 0 || *oldlenp == 0)
831: return (ENOMEM);
832: }
833: if (newp && newlen >= maxlen)
834: return (EINVAL);
835: if (oldp) {
836: if (trunc && *oldlenp < len) {
837: /* save & zap NUL terminator while copying */
838: c = str[*oldlenp-1];
839: str[*oldlenp-1] = '\0';
840: error = copyout(str, oldp, *oldlenp);
841: str[*oldlenp-1] = c;
842: } else {
843: *oldlenp = len;
844: error = copyout(str, oldp, len);
845: }
846: }
847: if (error == 0 && newp) {
848: error = copyin(newp, str, newlen);
849: str[newlen] = 0;
850: }
851: return (error);
852: }
853:
854: /*
855: * As above, but read-only.
856: */
857: int
858: sysctl_rdstring(void *oldp, size_t *oldlenp, void *newp, const char *str)
859: {
860: int len, error = 0;
861:
862: len = strlen(str) + 1;
863: if (oldp && *oldlenp < len)
864: return (ENOMEM);
865: if (newp)
866: return (EPERM);
867: *oldlenp = len;
868: if (oldp)
869: error = copyout(str, oldp, len);
870: return (error);
871: }
872:
873: /*
874: * Validate parameters and get old / set new parameters
875: * for a structure oriented sysctl function.
876: */
877: int
878: sysctl_struct(void *oldp, size_t *oldlenp, void *newp, size_t newlen, void *sp,
879: int len)
880: {
881: int error = 0;
882:
883: if (oldp && *oldlenp < len)
884: return (ENOMEM);
885: if (newp && newlen > len)
886: return (EINVAL);
887: if (oldp) {
888: *oldlenp = len;
889: error = copyout(sp, oldp, len);
890: }
891: if (error == 0 && newp)
892: error = copyin(newp, sp, len);
893: return (error);
894: }
895:
896: /*
897: * Validate parameters and get old parameters
898: * for a structure oriented sysctl function.
899: */
900: int
901: sysctl_rdstruct(void *oldp, size_t *oldlenp, void *newp, const void *sp,
902: int len)
903: {
904: int error = 0;
905:
906: if (oldp && *oldlenp < len)
907: return (ENOMEM);
908: if (newp)
909: return (EPERM);
910: *oldlenp = len;
911: if (oldp)
912: error = copyout(sp, oldp, len);
913: return (error);
914: }
915:
916: /*
917: * Get file structures.
918: */
919: int
920: sysctl_file(char *where, size_t *sizep)
921: {
922: int buflen, error;
923: struct file *fp;
924: char *start = where;
925:
926: buflen = *sizep;
927: if (where == NULL) {
928: /*
929: * overestimate by 10 files
930: */
931: *sizep = sizeof(filehead) + (nfiles + 10) * sizeof(struct file);
932: return (0);
933: }
934:
935: /*
936: * first copyout filehead
937: */
938: if (buflen < sizeof(filehead)) {
939: *sizep = 0;
940: return (0);
941: }
942: error = copyout((caddr_t)&filehead, where, sizeof(filehead));
943: if (error)
944: return (error);
945: buflen -= sizeof(filehead);
946: where += sizeof(filehead);
947:
948: /*
949: * followed by an array of file structures
950: */
951: LIST_FOREACH(fp, &filehead, f_list) {
952: if (buflen < sizeof(struct file)) {
953: *sizep = where - start;
954: return (ENOMEM);
955: }
956: error = copyout((caddr_t)fp, where, sizeof (struct file));
957: if (error)
958: return (error);
959: buflen -= sizeof(struct file);
960: where += sizeof(struct file);
961: }
962: *sizep = where - start;
963: return (0);
964: }
965:
966: #ifndef SMALL_KERNEL
967:
968: /*
969: * try over estimating by 5 procs
970: */
971: #define KERN_PROCSLOP (5 * sizeof (struct kinfo_proc))
972:
973: int
974: sysctl_doproc(int *name, u_int namelen, char *where, size_t *sizep)
975: {
976: struct kinfo_proc2 *kproc2 = NULL;
977: struct eproc *eproc = NULL;
978: struct proc *p;
979: char *dp;
980: int arg, buflen, doingzomb, elem_size, elem_count;
981: int error, needed, type, op;
982:
983: dp = where;
984: buflen = where != NULL ? *sizep : 0;
985: needed = error = 0;
986: type = name[0];
987:
988: if (type == KERN_PROC) {
989: if (namelen != 3 && !(namelen == 2 &&
990: (name[1] == KERN_PROC_ALL || name[1] == KERN_PROC_KTHREAD)))
991: return (EINVAL);
992: op = name[1];
993: arg = op == KERN_PROC_ALL ? 0 : name[2];
994: elem_size = elem_count = 0;
995: eproc = malloc(sizeof(struct eproc), M_TEMP, M_WAITOK);
996: } else /* if (type == KERN_PROC2) */ {
997: if (namelen != 5 || name[3] < 0 || name[4] < 0)
998: return (EINVAL);
999: op = name[1];
1000: arg = name[2];
1001: elem_size = name[3];
1002: elem_count = name[4];
1003: kproc2 = malloc(sizeof(struct kinfo_proc2), M_TEMP, M_WAITOK);
1004: }
1005: p = LIST_FIRST(&allproc);
1006: doingzomb = 0;
1007: again:
1008: for (; p != 0; p = LIST_NEXT(p, p_list)) {
1009: /*
1010: * Skip embryonic processes.
1011: */
1012: if (p->p_stat == SIDL)
1013: continue;
1014: /*
1015: * TODO - make more efficient (see notes below).
1016: */
1017: switch (op) {
1018:
1019: case KERN_PROC_PID:
1020: /* could do this with just a lookup */
1021: if (p->p_pid != (pid_t)arg)
1022: continue;
1023: break;
1024:
1025: case KERN_PROC_PGRP:
1026: /* could do this by traversing pgrp */
1027: if (p->p_pgrp->pg_id != (pid_t)arg)
1028: continue;
1029: break;
1030:
1031: case KERN_PROC_SESSION:
1032: if (p->p_session->s_leader == NULL ||
1033: p->p_session->s_leader->p_pid != (pid_t)arg)
1034: continue;
1035: break;
1036:
1037: case KERN_PROC_TTY:
1038: if ((p->p_flag & P_CONTROLT) == 0 ||
1039: p->p_session->s_ttyp == NULL ||
1040: p->p_session->s_ttyp->t_dev != (dev_t)arg)
1041: continue;
1042: break;
1043:
1044: case KERN_PROC_UID:
1045: if (p->p_ucred->cr_uid != (uid_t)arg)
1046: continue;
1047: break;
1048:
1049: case KERN_PROC_RUID:
1050: if (p->p_cred->p_ruid != (uid_t)arg)
1051: continue;
1052: break;
1053:
1054: case KERN_PROC_ALL:
1055: if (p->p_flag & P_SYSTEM)
1056: continue;
1057: break;
1058: case KERN_PROC_KTHREAD:
1059: /* no filtering */
1060: break;
1061: default:
1062: error = EINVAL;
1063: goto err;
1064: }
1065: if (type == KERN_PROC) {
1066: if (buflen >= sizeof(struct kinfo_proc)) {
1067: fill_eproc(p, eproc);
1068: error = copyout((caddr_t)p,
1069: &((struct kinfo_proc *)dp)->kp_proc,
1070: sizeof(struct proc));
1071: if (error)
1072: goto err;
1073: error = copyout((caddr_t)eproc,
1074: &((struct kinfo_proc *)dp)->kp_eproc,
1075: sizeof(*eproc));
1076: if (error)
1077: goto err;
1078: dp += sizeof(struct kinfo_proc);
1079: buflen -= sizeof(struct kinfo_proc);
1080: }
1081: needed += sizeof(struct kinfo_proc);
1082: } else /* if (type == KERN_PROC2) */ {
1083: if (buflen >= elem_size && elem_count > 0) {
1084: fill_kproc2(p, kproc2);
1085: /*
1086: * Copy out elem_size, but not larger than
1087: * the size of a struct kinfo_proc2.
1088: */
1089: error = copyout(kproc2, dp,
1090: min(sizeof(*kproc2), elem_size));
1091: if (error)
1092: goto err;
1093: dp += elem_size;
1094: buflen -= elem_size;
1095: elem_count--;
1096: }
1097: needed += elem_size;
1098: }
1099: }
1100: if (doingzomb == 0) {
1101: p = LIST_FIRST(&zombproc);
1102: doingzomb++;
1103: goto again;
1104: }
1105: if (where != NULL) {
1106: *sizep = dp - where;
1107: if (needed > *sizep) {
1108: error = ENOMEM;
1109: goto err;
1110: }
1111: } else {
1112: needed += KERN_PROCSLOP;
1113: *sizep = needed;
1114: }
1115: err:
1116: if (eproc)
1117: free(eproc, M_TEMP);
1118: if (kproc2)
1119: free(kproc2, M_TEMP);
1120: return (error);
1121: }
1122:
1123: #endif /* SMALL_KERNEL */
1124:
1125: /*
1126: * Fill in an eproc structure for the specified process.
1127: */
1128: void
1129: fill_eproc(struct proc *p, struct eproc *ep)
1130: {
1131: struct tty *tp;
1132:
1133: ep->e_paddr = p;
1134: ep->e_sess = p->p_pgrp->pg_session;
1135: ep->e_pcred = *p->p_cred;
1136: ep->e_ucred = *p->p_ucred;
1137: if (p->p_stat == SIDL || P_ZOMBIE(p)) {
1138: ep->e_vm.vm_rssize = 0;
1139: ep->e_vm.vm_tsize = 0;
1140: ep->e_vm.vm_dsize = 0;
1141: ep->e_vm.vm_ssize = 0;
1142: bzero(&ep->e_pstats, sizeof(ep->e_pstats));
1143: ep->e_pstats_valid = 0;
1144: } else {
1145: struct vmspace *vm = p->p_vmspace;
1146:
1147: ep->e_vm.vm_rssize = vm_resident_count(vm);
1148: ep->e_vm.vm_tsize = vm->vm_tsize;
1149: ep->e_vm.vm_dsize = vm->vm_dused;
1150: ep->e_vm.vm_ssize = vm->vm_ssize;
1151: ep->e_pstats = *p->p_stats;
1152: ep->e_pstats_valid = 1;
1153: }
1154: if (p->p_pptr)
1155: ep->e_ppid = p->p_pptr->p_pid;
1156: else
1157: ep->e_ppid = 0;
1158: ep->e_pgid = p->p_pgrp->pg_id;
1159: ep->e_jobc = p->p_pgrp->pg_jobc;
1160: if ((p->p_flag & P_CONTROLT) &&
1161: (tp = ep->e_sess->s_ttyp)) {
1162: ep->e_tdev = tp->t_dev;
1163: ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
1164: ep->e_tsess = tp->t_session;
1165: } else
1166: ep->e_tdev = NODEV;
1167: ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0;
1168: if (SESS_LEADER(p))
1169: ep->e_flag |= EPROC_SLEADER;
1170: strncpy(ep->e_wmesg, p->p_wmesg ? p->p_wmesg : "", WMESGLEN);
1171: ep->e_wmesg[WMESGLEN] = '\0';
1172: ep->e_xsize = ep->e_xrssize = 0;
1173: ep->e_xccount = ep->e_xswrss = 0;
1174: strncpy(ep->e_login, ep->e_sess->s_login, MAXLOGNAME-1);
1175: ep->e_login[MAXLOGNAME-1] = '\0';
1176: strncpy(ep->e_emul, p->p_emul->e_name, EMULNAMELEN);
1177: ep->e_emul[EMULNAMELEN] = '\0';
1178: ep->e_maxrss = p->p_rlimit ? p->p_rlimit[RLIMIT_RSS].rlim_cur : 0;
1179: ep->e_limit = p->p_p->ps_limit;
1180: }
1181:
1182: #ifndef SMALL_KERNEL
1183:
1184: /*
1185: * Fill in a kproc2 structure for the specified process.
1186: */
1187: void
1188: fill_kproc2(struct proc *p, struct kinfo_proc2 *ki)
1189: {
1190: struct tty *tp;
1191: struct timeval ut, st;
1192:
1193: bzero(ki, sizeof(*ki));
1194:
1195: ki->p_paddr = PTRTOINT64(p);
1196: ki->p_fd = PTRTOINT64(p->p_fd);
1197: ki->p_stats = PTRTOINT64(p->p_stats);
1198: ki->p_limit = PTRTOINT64(p->p_p->ps_limit);
1199: ki->p_vmspace = PTRTOINT64(p->p_vmspace);
1200: ki->p_sigacts = PTRTOINT64(p->p_sigacts);
1201: ki->p_sess = PTRTOINT64(p->p_session);
1202: ki->p_tsess = 0; /* may be changed if controlling tty below */
1203: ki->p_ru = PTRTOINT64(p->p_ru);
1204:
1205: ki->p_eflag = 0;
1206: ki->p_exitsig = p->p_exitsig;
1207: ki->p_flag = p->p_flag | P_INMEM;
1208:
1209: ki->p_pid = p->p_pid;
1210: if (p->p_pptr)
1211: ki->p_ppid = p->p_pptr->p_pid;
1212: else
1213: ki->p_ppid = 0;
1214: if (p->p_session->s_leader)
1215: ki->p_sid = p->p_session->s_leader->p_pid;
1216: else
1217: ki->p_sid = 0;
1218: ki->p__pgid = p->p_pgrp->pg_id;
1219:
1220: ki->p_tpgid = -1; /* may be changed if controlling tty below */
1221:
1222: ki->p_uid = p->p_ucred->cr_uid;
1223: ki->p_ruid = p->p_cred->p_ruid;
1224: ki->p_gid = p->p_ucred->cr_gid;
1225: ki->p_rgid = p->p_cred->p_rgid;
1226: ki->p_svuid = p->p_cred->p_svuid;
1227: ki->p_svgid = p->p_cred->p_svgid;
1228:
1229: memcpy(ki->p_groups, p->p_cred->pc_ucred->cr_groups,
1230: min(sizeof(ki->p_groups), sizeof(p->p_cred->pc_ucred->cr_groups)));
1231: ki->p_ngroups = p->p_cred->pc_ucred->cr_ngroups;
1232:
1233: ki->p_jobc = p->p_pgrp->pg_jobc;
1234: if ((p->p_flag & P_CONTROLT) && (tp = p->p_session->s_ttyp)) {
1235: ki->p_tdev = tp->t_dev;
1236: ki->p_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : -1;
1237: ki->p_tsess = PTRTOINT64(tp->t_session);
1238: } else {
1239: ki->p_tdev = NODEV;
1240: }
1241:
1242: ki->p_estcpu = p->p_estcpu;
1243: ki->p_rtime_sec = p->p_rtime.tv_sec;
1244: ki->p_rtime_usec = p->p_rtime.tv_usec;
1245: ki->p_cpticks = p->p_cpticks;
1246: ki->p_pctcpu = p->p_pctcpu;
1247:
1248: ki->p_uticks = p->p_uticks;
1249: ki->p_sticks = p->p_sticks;
1250: ki->p_iticks = p->p_iticks;
1251:
1252: ki->p_tracep = PTRTOINT64(p->p_tracep);
1253: ki->p_traceflag = p->p_traceflag;
1254:
1255: ki->p_siglist = p->p_siglist;
1256: ki->p_sigmask = p->p_sigmask;
1257: ki->p_sigignore = p->p_sigignore;
1258: ki->p_sigcatch = p->p_sigcatch;
1259:
1260: ki->p_stat = p->p_stat;
1261: ki->p_nice = p->p_nice;
1262:
1263: ki->p_xstat = p->p_xstat;
1264: ki->p_acflag = p->p_acflag;
1265:
1266: strlcpy(ki->p_emul, p->p_emul->e_name, sizeof(ki->p_emul));
1267: strlcpy(ki->p_comm, p->p_comm, sizeof(ki->p_comm));
1268: strncpy(ki->p_login, p->p_session->s_login,
1269: min(sizeof(ki->p_login) - 1, sizeof(p->p_session->s_login)));
1270:
1271: if (p->p_stat == SIDL || P_ZOMBIE(p)) {
1272: ki->p_vm_rssize = 0;
1273: ki->p_vm_tsize = 0;
1274: ki->p_vm_dsize = 0;
1275: ki->p_vm_ssize = 0;
1276: } else {
1277: struct vmspace *vm = p->p_vmspace;
1278:
1279: ki->p_vm_rssize = vm_resident_count(vm);
1280: ki->p_vm_tsize = vm->vm_tsize;
1281: ki->p_vm_dsize = vm->vm_dused;
1282: ki->p_vm_ssize = vm->vm_ssize;
1283:
1284: ki->p_forw = PTRTOINT64(p->p_forw);
1285: ki->p_back = PTRTOINT64(p->p_back);
1286: ki->p_addr = PTRTOINT64(p->p_addr);
1287: ki->p_stat = p->p_stat;
1288: ki->p_swtime = p->p_swtime;
1289: ki->p_slptime = p->p_slptime;
1290: ki->p_schedflags = 0;
1291: ki->p_holdcnt = 1;
1292: ki->p_priority = p->p_priority;
1293: ki->p_usrpri = p->p_usrpri;
1294: if (p->p_wmesg)
1295: strlcpy(ki->p_wmesg, p->p_wmesg, sizeof(ki->p_wmesg));
1296: ki->p_wchan = PTRTOINT64(p->p_wchan);
1297:
1298: }
1299:
1300: if (p->p_session->s_ttyvp)
1301: ki->p_eflag |= EPROC_CTTY;
1302: if (SESS_LEADER(p))
1303: ki->p_eflag |= EPROC_SLEADER;
1304: if (p->p_rlimit)
1305: ki->p_rlim_rss_cur = p->p_rlimit[RLIMIT_RSS].rlim_cur;
1306:
1307: /* XXX Is this double check necessary? */
1308: if (P_ZOMBIE(p)) {
1309: ki->p_uvalid = 0;
1310: } else {
1311: ki->p_uvalid = 1;
1312:
1313: ki->p_ustart_sec = p->p_stats->p_start.tv_sec;
1314: ki->p_ustart_usec = p->p_stats->p_start.tv_usec;
1315:
1316: calcru(p, &ut, &st, 0);
1317: ki->p_uutime_sec = ut.tv_sec;
1318: ki->p_uutime_usec = ut.tv_usec;
1319: ki->p_ustime_sec = st.tv_sec;
1320: ki->p_ustime_usec = st.tv_usec;
1321:
1322: ki->p_uru_maxrss = p->p_stats->p_ru.ru_maxrss;
1323: ki->p_uru_ixrss = p->p_stats->p_ru.ru_ixrss;
1324: ki->p_uru_idrss = p->p_stats->p_ru.ru_idrss;
1325: ki->p_uru_isrss = p->p_stats->p_ru.ru_isrss;
1326: ki->p_uru_minflt = p->p_stats->p_ru.ru_minflt;
1327: ki->p_uru_majflt = p->p_stats->p_ru.ru_majflt;
1328: ki->p_uru_nswap = p->p_stats->p_ru.ru_nswap;
1329: ki->p_uru_inblock = p->p_stats->p_ru.ru_inblock;
1330: ki->p_uru_oublock = p->p_stats->p_ru.ru_oublock;
1331: ki->p_uru_msgsnd = p->p_stats->p_ru.ru_msgsnd;
1332: ki->p_uru_msgrcv = p->p_stats->p_ru.ru_msgrcv;
1333: ki->p_uru_nsignals = p->p_stats->p_ru.ru_nsignals;
1334: ki->p_uru_nvcsw = p->p_stats->p_ru.ru_nvcsw;
1335: ki->p_uru_nivcsw = p->p_stats->p_ru.ru_nivcsw;
1336:
1337: timeradd(&p->p_stats->p_cru.ru_utime,
1338: &p->p_stats->p_cru.ru_stime, &ut);
1339: ki->p_uctime_sec = ut.tv_sec;
1340: ki->p_uctime_usec = ut.tv_usec;
1341: ki->p_cpuid = KI_NOCPU;
1342: #ifdef MULTIPROCESSOR
1343: if (p->p_cpu != NULL)
1344: ki->p_cpuid = CPU_INFO_UNIT(p->p_cpu);
1345: #endif
1346: }
1347: }
1348:
1349: int
1350: sysctl_proc_args(int *name, u_int namelen, void *oldp, size_t *oldlenp,
1351: struct proc *cp)
1352: {
1353: struct proc *vp;
1354: pid_t pid;
1355: int op;
1356: struct ps_strings pss;
1357: struct iovec iov;
1358: struct uio uio;
1359: int error;
1360: size_t limit;
1361: int cnt;
1362: char **rargv, **vargv; /* reader vs. victim */
1363: char *rarg, *varg;
1364: char *buf;
1365:
1366: if (namelen > 2)
1367: return (ENOTDIR);
1368: if (namelen < 2)
1369: return (EINVAL);
1370:
1371: pid = name[0];
1372: op = name[1];
1373:
1374: switch (op) {
1375: case KERN_PROC_ARGV:
1376: case KERN_PROC_NARGV:
1377: case KERN_PROC_ENV:
1378: case KERN_PROC_NENV:
1379: break;
1380: default:
1381: return (EOPNOTSUPP);
1382: }
1383:
1384: if ((vp = pfind(pid)) == NULL)
1385: return (ESRCH);
1386:
1387: if (oldp == NULL) {
1388: if (op == KERN_PROC_NARGV || op == KERN_PROC_NENV)
1389: *oldlenp = sizeof(int);
1390: else
1391: *oldlenp = ARG_MAX; /* XXX XXX XXX */
1392: return (0);
1393: }
1394:
1395: if (P_ZOMBIE(vp) || (vp->p_flag & P_SYSTEM))
1396: return (EINVAL);
1397:
1398: /* Exiting - don't bother, it will be gone soon anyway */
1399: if ((vp->p_flag & P_WEXIT))
1400: return (ESRCH);
1401:
1402: /* Execing - danger. */
1403: if ((vp->p_flag & P_INEXEC))
1404: return (EBUSY);
1405:
1406: vp->p_vmspace->vm_refcnt++; /* XXX */
1407: buf = malloc(PAGE_SIZE, M_TEMP, M_WAITOK);
1408:
1409: iov.iov_base = &pss;
1410: iov.iov_len = sizeof(pss);
1411: uio.uio_iov = &iov;
1412: uio.uio_iovcnt = 1;
1413: uio.uio_offset = (off_t)PS_STRINGS;
1414: uio.uio_resid = sizeof(pss);
1415: uio.uio_segflg = UIO_SYSSPACE;
1416: uio.uio_rw = UIO_READ;
1417: uio.uio_procp = cp;
1418:
1419: if ((error = uvm_io(&vp->p_vmspace->vm_map, &uio, 0)) != 0)
1420: goto out;
1421:
1422: if (op == KERN_PROC_NARGV) {
1423: error = sysctl_rdint(oldp, oldlenp, NULL, pss.ps_nargvstr);
1424: goto out;
1425: }
1426: if (op == KERN_PROC_NENV) {
1427: error = sysctl_rdint(oldp, oldlenp, NULL, pss.ps_nenvstr);
1428: goto out;
1429: }
1430:
1431: if (op == KERN_PROC_ARGV) {
1432: cnt = pss.ps_nargvstr;
1433: vargv = pss.ps_argvstr;
1434: } else {
1435: cnt = pss.ps_nenvstr;
1436: vargv = pss.ps_envstr;
1437: }
1438:
1439: /* -1 to have space for a terminating NUL */
1440: limit = *oldlenp - 1;
1441: *oldlenp = 0;
1442:
1443: rargv = oldp;
1444:
1445: /*
1446: * *oldlenp - number of bytes copied out into readers buffer.
1447: * limit - maximal number of bytes allowed into readers buffer.
1448: * rarg - pointer into readers buffer where next arg will be stored.
1449: * rargv - pointer into readers buffer where the next rarg pointer
1450: * will be stored.
1451: * vargv - pointer into victim address space where the next argument
1452: * will be read.
1453: */
1454:
1455: /* space for cnt pointers and a NULL */
1456: rarg = (char *)(rargv + cnt + 1);
1457: *oldlenp += (cnt + 1) * sizeof(char **);
1458:
1459: while (cnt > 0 && *oldlenp < limit) {
1460: size_t len, vstrlen;
1461:
1462: /* Write to readers argv */
1463: if ((error = copyout(&rarg, rargv, sizeof(rarg))) != 0)
1464: goto out;
1465:
1466: /* read the victim argv */
1467: iov.iov_base = &varg;
1468: iov.iov_len = sizeof(varg);
1469: uio.uio_iov = &iov;
1470: uio.uio_iovcnt = 1;
1471: uio.uio_offset = (off_t)(vaddr_t)vargv;
1472: uio.uio_resid = sizeof(varg);
1473: uio.uio_segflg = UIO_SYSSPACE;
1474: uio.uio_rw = UIO_READ;
1475: uio.uio_procp = cp;
1476: if ((error = uvm_io(&vp->p_vmspace->vm_map, &uio, 0)) != 0)
1477: goto out;
1478:
1479: if (varg == NULL)
1480: break;
1481:
1482: /*
1483: * read the victim arg. We must jump through hoops to avoid
1484: * crossing a page boundary too much and returning an error.
1485: */
1486: more:
1487: len = PAGE_SIZE - (((vaddr_t)varg) & PAGE_MASK);
1488: /* leave space for the terminating NUL */
1489: iov.iov_base = buf;
1490: iov.iov_len = len;
1491: uio.uio_iov = &iov;
1492: uio.uio_iovcnt = 1;
1493: uio.uio_offset = (off_t)(vaddr_t)varg;
1494: uio.uio_resid = len;
1495: uio.uio_segflg = UIO_SYSSPACE;
1496: uio.uio_rw = UIO_READ;
1497: uio.uio_procp = cp;
1498: if ((error = uvm_io(&vp->p_vmspace->vm_map, &uio, 0)) != 0)
1499: goto out;
1500:
1501: for (vstrlen = 0; vstrlen < len; vstrlen++) {
1502: if (buf[vstrlen] == '\0')
1503: break;
1504: }
1505:
1506: /* Don't overflow readers buffer. */
1507: if (*oldlenp + vstrlen + 1 >= limit) {
1508: error = ENOMEM;
1509: goto out;
1510: }
1511:
1512: if ((error = copyout(buf, rarg, vstrlen)) != 0)
1513: goto out;
1514:
1515: *oldlenp += vstrlen;
1516: rarg += vstrlen;
1517:
1518: /* The string didn't end in this page? */
1519: if (vstrlen == len) {
1520: varg += vstrlen;
1521: goto more;
1522: }
1523:
1524: /* End of string. Terminate it with a NUL */
1525: buf[0] = '\0';
1526: if ((error = copyout(buf, rarg, 1)) != 0)
1527: goto out;
1528: *oldlenp += 1;
1529: rarg += 1;
1530:
1531: vargv++;
1532: rargv++;
1533: cnt--;
1534: }
1535:
1536: if (*oldlenp >= limit) {
1537: error = ENOMEM;
1538: goto out;
1539: }
1540:
1541: /* Write the terminating null */
1542: rarg = NULL;
1543: error = copyout(&rarg, rargv, sizeof(rarg));
1544:
1545: out:
1546: uvmspace_free(vp->p_vmspace);
1547: free(buf, M_TEMP);
1548: return (error);
1549: }
1550:
1551: #endif
1552:
1553: /*
1554: * Initialize disknames/diskstats for export by sysctl. If update is set,
1555: * then we simply update the disk statistics information.
1556: */
1557: int
1558: sysctl_diskinit(int update, struct proc *p)
1559: {
1560: struct diskstats *sdk;
1561: struct disk *dk;
1562: int i, tlen, l;
1563:
1564: if ((i = rw_enter(&sysctl_disklock, RW_WRITE|RW_INTR)) != 0)
1565: return i;
1566:
1567: if (disk_change) {
1568: for (dk = TAILQ_FIRST(&disklist), tlen = 0; dk;
1569: dk = TAILQ_NEXT(dk, dk_link))
1570: tlen += strlen(dk->dk_name) + 1;
1571: tlen++;
1572:
1573: if (disknames)
1574: free(disknames, M_SYSCTL);
1575: if (diskstats)
1576: free(diskstats, M_SYSCTL);
1577: diskstats = NULL;
1578: disknames = NULL;
1579: diskstats = malloc(disk_count * sizeof(struct diskstats),
1580: M_SYSCTL, M_WAITOK);
1581: disknames = malloc(tlen, M_SYSCTL, M_WAITOK);
1582: disknames[0] = '\0';
1583:
1584: for (dk = TAILQ_FIRST(&disklist), i = 0, l = 0; dk;
1585: dk = TAILQ_NEXT(dk, dk_link), i++) {
1586: snprintf(disknames + l, tlen - l, "%s,",
1587: dk->dk_name ? dk->dk_name : "");
1588: l += strlen(disknames + l);
1589: sdk = diskstats + i;
1590: strlcpy(sdk->ds_name, dk->dk_name,
1591: sizeof(sdk->ds_name));
1592: sdk->ds_busy = dk->dk_busy;
1593: sdk->ds_rxfer = dk->dk_rxfer;
1594: sdk->ds_wxfer = dk->dk_wxfer;
1595: sdk->ds_seek = dk->dk_seek;
1596: sdk->ds_rbytes = dk->dk_rbytes;
1597: sdk->ds_wbytes = dk->dk_wbytes;
1598: sdk->ds_attachtime = dk->dk_attachtime;
1599: sdk->ds_timestamp = dk->dk_timestamp;
1600: sdk->ds_time = dk->dk_time;
1601: }
1602:
1603: /* Eliminate trailing comma */
1604: if (l != 0)
1605: disknames[l - 1] = '\0';
1606: disk_change = 0;
1607: } else if (update) {
1608: /* Just update, number of drives hasn't changed */
1609: for (dk = TAILQ_FIRST(&disklist), i = 0; dk;
1610: dk = TAILQ_NEXT(dk, dk_link), i++) {
1611: sdk = diskstats + i;
1612: strlcpy(sdk->ds_name, dk->dk_name,
1613: sizeof(sdk->ds_name));
1614: sdk->ds_busy = dk->dk_busy;
1615: sdk->ds_rxfer = dk->dk_rxfer;
1616: sdk->ds_wxfer = dk->dk_wxfer;
1617: sdk->ds_seek = dk->dk_seek;
1618: sdk->ds_rbytes = dk->dk_rbytes;
1619: sdk->ds_wbytes = dk->dk_wbytes;
1620: sdk->ds_attachtime = dk->dk_attachtime;
1621: sdk->ds_timestamp = dk->dk_timestamp;
1622: sdk->ds_time = dk->dk_time;
1623: }
1624: }
1625: rw_exit_write(&sysctl_disklock);
1626: return 0;
1627: }
1628:
1629: #if defined(SYSVMSG) || defined(SYSVSEM) || defined(SYSVSHM)
1630: int
1631: sysctl_sysvipc(int *name, u_int namelen, void *where, size_t *sizep)
1632: {
1633: #ifdef SYSVMSG
1634: struct msg_sysctl_info *msgsi;
1635: #endif
1636: #ifdef SYSVSEM
1637: struct sem_sysctl_info *semsi;
1638: #endif
1639: #ifdef SYSVSHM
1640: struct shm_sysctl_info *shmsi;
1641: #endif
1642: size_t infosize, dssize, tsize, buflen;
1643: int i, nds, error, ret;
1644: void *buf;
1645:
1646: if (namelen != 1)
1647: return (EINVAL);
1648:
1649: buflen = *sizep;
1650:
1651: switch (*name) {
1652: case KERN_SYSVIPC_MSG_INFO:
1653: #ifdef SYSVMSG
1654: infosize = sizeof(msgsi->msginfo);
1655: nds = msginfo.msgmni;
1656: dssize = sizeof(msgsi->msgids[0]);
1657: break;
1658: #else
1659: return (EOPNOTSUPP);
1660: #endif
1661: case KERN_SYSVIPC_SEM_INFO:
1662: #ifdef SYSVSEM
1663: infosize = sizeof(semsi->seminfo);
1664: nds = seminfo.semmni;
1665: dssize = sizeof(semsi->semids[0]);
1666: break;
1667: #else
1668: return (EOPNOTSUPP);
1669: #endif
1670: case KERN_SYSVIPC_SHM_INFO:
1671: #ifdef SYSVSHM
1672: infosize = sizeof(shmsi->shminfo);
1673: nds = shminfo.shmmni;
1674: dssize = sizeof(shmsi->shmids[0]);
1675: break;
1676: #else
1677: return (EOPNOTSUPP);
1678: #endif
1679: default:
1680: return (EINVAL);
1681: }
1682: tsize = infosize + (nds * dssize);
1683:
1684: /* Return just the total size required. */
1685: if (where == NULL) {
1686: *sizep = tsize;
1687: return (0);
1688: }
1689:
1690: /* Not enough room for even the info struct. */
1691: if (buflen < infosize) {
1692: *sizep = 0;
1693: return (ENOMEM);
1694: }
1695: buf = malloc(min(tsize, buflen), M_TEMP, M_WAITOK);
1696: bzero(buf, min(tsize, buflen));
1697:
1698: switch (*name) {
1699: #ifdef SYSVMSG
1700: case KERN_SYSVIPC_MSG_INFO:
1701: msgsi = (struct msg_sysctl_info *)buf;
1702: msgsi->msginfo = msginfo;
1703: break;
1704: #endif
1705: #ifdef SYSVSEM
1706: case KERN_SYSVIPC_SEM_INFO:
1707: semsi = (struct sem_sysctl_info *)buf;
1708: semsi->seminfo = seminfo;
1709: break;
1710: #endif
1711: #ifdef SYSVSHM
1712: case KERN_SYSVIPC_SHM_INFO:
1713: shmsi = (struct shm_sysctl_info *)buf;
1714: shmsi->shminfo = shminfo;
1715: break;
1716: #endif
1717: }
1718: buflen -= infosize;
1719:
1720: ret = 0;
1721: if (buflen > 0) {
1722: /* Fill in the IPC data structures. */
1723: for (i = 0; i < nds; i++) {
1724: if (buflen < dssize) {
1725: ret = ENOMEM;
1726: break;
1727: }
1728: switch (*name) {
1729: #ifdef SYSVMSG
1730: case KERN_SYSVIPC_MSG_INFO:
1731: bcopy(&msqids[i], &msgsi->msgids[i], dssize);
1732: break;
1733: #endif
1734: #ifdef SYSVSEM
1735: case KERN_SYSVIPC_SEM_INFO:
1736: if (sema[i] != NULL)
1737: bcopy(sema[i], &semsi->semids[i],
1738: dssize);
1739: else
1740: bzero(&semsi->semids[i], dssize);
1741: break;
1742: #endif
1743: #ifdef SYSVSHM
1744: case KERN_SYSVIPC_SHM_INFO:
1745: if (shmsegs[i] != NULL)
1746: bcopy(shmsegs[i], &shmsi->shmids[i],
1747: dssize);
1748: else
1749: bzero(&shmsi->shmids[i], dssize);
1750: break;
1751: #endif
1752: }
1753: buflen -= dssize;
1754: }
1755: }
1756: *sizep -= buflen;
1757: error = copyout(buf, where, *sizep);
1758: free(buf, M_TEMP);
1759: /* If copyout succeeded, use return code set earlier. */
1760: return (error ? error : ret);
1761: }
1762: #endif /* SYSVMSG || SYSVSEM || SYSVSHM */
1763:
1764: #ifndef SMALL_KERNEL
1765:
1766: int
1767: sysctl_intrcnt(int *name, u_int namelen, void *oldp, size_t *oldlenp)
1768: {
1769: return (evcount_sysctl(name, namelen, oldp, oldlenp, NULL, 0));
1770: }
1771:
1772:
1773: int
1774: sysctl_sensors(int *name, u_int namelen, void *oldp, size_t *oldlenp,
1775: void *newp, size_t newlen)
1776: {
1777: struct ksensor *ks;
1778: struct sensor *us;
1779: struct ksensordev *ksd;
1780: struct sensordev *usd;
1781: int dev, numt, ret;
1782: enum sensor_type type;
1783:
1784: if (namelen != 1 && namelen != 3)
1785: return (ENOTDIR);
1786:
1787: dev = name[0];
1788: if (namelen == 1) {
1789: ksd = sensordev_get(dev);
1790: if (ksd == NULL)
1791: return (ENOENT);
1792:
1793: /* Grab a copy, to clear the kernel pointers */
1794: usd = malloc(sizeof(*usd), M_TEMP, M_WAITOK);
1795: bzero(usd, sizeof(*usd));
1796: usd->num = ksd->num;
1797: strlcpy(usd->xname, ksd->xname, sizeof(usd->xname));
1798: memcpy(usd->maxnumt, ksd->maxnumt, sizeof(usd->maxnumt));
1799: usd->sensors_count = ksd->sensors_count;
1800:
1801: ret = sysctl_rdstruct(oldp, oldlenp, newp, usd,
1802: sizeof(struct sensordev));
1803:
1804: free(usd, M_TEMP);
1805: return (ret);
1806: }
1807:
1808: type = name[1];
1809: numt = name[2];
1810:
1811: ks = sensor_find(dev, type, numt);
1812: if (ks == NULL)
1813: return (ENOENT);
1814:
1815: /* Grab a copy, to clear the kernel pointers */
1816: us = malloc(sizeof(*us), M_TEMP, M_WAITOK);
1817: bzero(us, sizeof(*us));
1818: memcpy(us->desc, ks->desc, sizeof(us->desc));
1819: us->tv = ks->tv;
1820: us->value = ks->value;
1821: us->type = ks->type;
1822: us->status = ks->status;
1823: us->numt = ks->numt;
1824: us->flags = ks->flags;
1825:
1826: ret = sysctl_rdstruct(oldp, oldlenp, newp, us,
1827: sizeof(struct sensor));
1828: free(us, M_TEMP);
1829: return (ret);
1830: }
1831:
1832: int
1833: sysctl_emul(int *name, u_int namelen, void *oldp, size_t *oldlenp,
1834: void *newp, size_t newlen)
1835: {
1836: int enabled, error;
1837: struct emul *e;
1838:
1839: if (name[0] == KERN_EMUL_NUM) {
1840: if (namelen != 1)
1841: return (ENOTDIR);
1842: return (sysctl_rdint(oldp, oldlenp, newp, nexecs));
1843: }
1844:
1845: if (namelen != 2)
1846: return (ENOTDIR);
1847: if (name[0] > nexecs || name[0] < 0)
1848: return (EINVAL);
1849: e = execsw[name[0] - 1].es_emul;
1850: if (e == NULL)
1851: return (EINVAL);
1852:
1853: switch (name[1]) {
1854: case KERN_EMUL_NAME:
1855: return (sysctl_rdstring(oldp, oldlenp, newp, e->e_name));
1856: case KERN_EMUL_ENABLED:
1857: enabled = (e->e_flags & EMUL_ENABLED);
1858: error = sysctl_int(oldp, oldlenp, newp, newlen,
1859: &enabled);
1860: e->e_flags = (enabled & EMUL_ENABLED);
1861: return (error);
1862: default:
1863: return (EINVAL);
1864: }
1865: }
1866:
1867: #endif /* SMALL_KERNEL */
1868:
1869: int
1870: sysctl_cptime2(int *name, u_int namelen, void *oldp, size_t *oldlenp,
1871: void *newp, size_t newlen)
1872: {
1873: CPU_INFO_ITERATOR cii;
1874: struct cpu_info *ci;
1875: int i;
1876:
1877: if (namelen != 1)
1878: return (ENOTDIR);
1879:
1880: i = name[0];
1881:
1882: CPU_INFO_FOREACH(cii, ci) {
1883: if (i-- == 0)
1884: break;
1885: }
1886: if (i > 0)
1887: return (ENOENT);
1888:
1889: return (sysctl_rdstruct(oldp, oldlenp, newp,
1890: &ci->ci_schedstate.spc_cp_time,
1891: sizeof(ci->ci_schedstate.spc_cp_time)));
1892: }
CVSweb