ptyattach (#ifdef notyet); don't need #if NPTY > 0
[unix-history] / usr / src / sys / kern / kern_sysctl.c
CommitLineData
780d91b3
KM
1/*-
2 * Copyright (c) 1982, 1986, 1989, 1993 Regents of the University of California.
4a24f1b0
MT
3 * All rights reserved.
4 *
780d91b3
KM
5 * This code is derived from software contributed to Berkeley by
6 * Mike Karels at Berkeley Software Design, Inc.
7 *
dbf0c423 8 * %sccs.include.redist.c%
4a24f1b0 9 *
7e024c88 10 * @(#)kern_sysctl.c 7.32 (Berkeley) %G%
780d91b3
KM
11 */
12
13/*
14 * sysctl system call.
4a24f1b0
MT
15 */
16
38a01dbe 17#include <sys/param.h>
780d91b3
KM
18#include <sys/systm.h>
19#include <sys/malloc.h>
38a01dbe 20#include <sys/proc.h>
780d91b3
KM
21#include <sys/file.h>
22#include <sys/sysctl.h>
23#include <sys/unistd.h>
24#include <sys/buf.h>
38a01dbe
KB
25#include <sys/ioctl.h>
26#include <sys/tty.h>
4a24f1b0 27
38a01dbe 28#include <vm/vm.h>
32041eb1 29
38a01dbe 30#include <sys/kinfo_proc.h>
32041eb1 31
780d91b3
KM
32sysctlfn kern_sysctl;
33sysctlfn hw_sysctl;
34extern sysctlfn vm_sysctl;
35extern sysctlfn fs_sysctl;
36extern sysctlfn net_sysctl;
37extern sysctlfn cpu_sysctl;
0a4df682 38
780d91b3
KM
39/*
40 * Locking and stats
41 */
42static struct sysctl_lock {
43 int sl_lock;
44 int sl_want;
45 int sl_locked;
46} memlock;
47
48struct sysctl_args {
49 int *name;
50 u_int namelen;
51 void *old;
b48024b7 52 size_t *oldlenp;
780d91b3 53 void *new;
b48024b7 54 size_t newlen;
9e97623a 55};
780d91b3 56
780d91b3 57sysctl(p, uap, retval)
8b24ca5d 58 struct proc *p;
780d91b3 59 register struct sysctl_args *uap;
8b24ca5d
KM
60 int *retval;
61{
780d91b3
KM
62 int error, dolock = 1;
63 u_int savelen, oldlen = 0;
64 sysctlfn *fn;
65 int name[CTL_MAXNAME];
0a4df682 66
780d91b3
KM
67 if (uap->new != NULL && (error = suser(p->p_ucred, &p->p_acflag)))
68 return (error);
69 /*
70 * all top-level sysctl names are non-terminal
71 */
72 if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
73 return (EINVAL);
74 if (error = copyin(uap->name, &name, uap->namelen * sizeof(int)))
75 return (error);
76
77 switch (name[0]) {
78 case CTL_KERN:
79 fn = kern_sysctl;
80 if (name[2] != KERN_VNODE) /* XXX */
81 dolock = 0;
0a4df682 82 break;
780d91b3
KM
83 case CTL_HW:
84 fn = hw_sysctl;
4a24f1b0 85 break;
780d91b3
KM
86 case CTL_VM:
87 fn = vm_sysctl;
452737be 88 break;
780d91b3
KM
89 case CTL_NET:
90 fn = net_sysctl;
318784c4 91 break;
780d91b3
KM
92#ifdef notyet
93 case CTL_FS:
94 fn = fs_sysctl;
15415c71 95 break;
780d91b3
KM
96 case CTL_DEBUG:
97 fn = debug_sysctl;
61ece7fc 98 break;
780d91b3
KM
99 case CTL_MACHDEP:
100 fn = cpu_sysctl;
61ece7fc 101 break;
780d91b3 102#endif
4a24f1b0 103 default:
780d91b3 104 return (EOPNOTSUPP);
7acc8d38 105 }
780d91b3
KM
106
107 if (uap->oldlenp &&
108 (error = copyin(uap->oldlenp, &oldlen, sizeof(oldlen))))
109 return (error);
110 if (uap->old != NULL) {
111 if (!useracc(uap->old, oldlen, B_WRITE))
112 return (EFAULT);
113 while (memlock.sl_lock) {
114 memlock.sl_want = 1;
115 sleep((caddr_t)&memlock, PRIBIO+1);
116 memlock.sl_locked++;
117 }
118 memlock.sl_lock = 1;
119 if (dolock)
120 vslock(uap->old, oldlen);
121 savelen = oldlen;
2ed8b3ea 122 }
780d91b3 123 error = (*fn)(name + 1, uap->namelen - 1, uap->old, &oldlen,
0f1d36b0 124 uap->new, uap->newlen, p);
780d91b3
KM
125 if (uap->old != NULL) {
126 if (dolock)
127 vsunlock(uap->old, savelen, B_WRITE);
128 memlock.sl_lock = 0;
129 if (memlock.sl_want) {
130 memlock.sl_want = 0;
131 wakeup((caddr_t)&memlock);
132 }
4a24f1b0 133 }
780d91b3
KM
134 if (error)
135 return (error);
136 if (uap->oldlenp)
137 error = copyout(&oldlen, uap->oldlenp, sizeof(oldlen));
138 *retval = oldlen;
139 return (0);
140}
141
142/*
143 * Attributes stored in the kernel.
144 */
145char hostname[MAXHOSTNAMELEN];
146int hostnamelen;
147long hostid;
0f1d36b0 148int securelevel;
780d91b3 149
0f1d36b0
KM
150/*
151 * kernel related system variables.
152 */
153kern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
780d91b3
KM
154 int *name;
155 u_int namelen;
156 void *oldp;
b48024b7 157 size_t *oldlenp;
780d91b3 158 void *newp;
b48024b7 159 size_t newlen;
0f1d36b0 160 struct proc *p;
780d91b3 161{
0f1d36b0 162 int error, level;
780d91b3
KM
163 extern char ostype[], osrelease[], version[];
164
165 /* all sysctl names at this level are terminal */
166 if (namelen != 1 && name[0] != KERN_PROC)
167 return (ENOTDIR); /* overloaded */
168
169 switch (name[0]) {
170 case KERN_OSTYPE:
171 return (sysctl_rdstring(oldp, oldlenp, newp, ostype));
172 case KERN_OSRELEASE:
173 return (sysctl_rdstring(oldp, oldlenp, newp, osrelease));
174 case KERN_OSREV:
175 return (sysctl_rdint(oldp, oldlenp, newp, BSD));
176 case KERN_VERSION:
177 return (sysctl_rdstring(oldp, oldlenp, newp, version));
178 case KERN_POSIX1:
179 return (sysctl_rdint(oldp, oldlenp, newp, _POSIX_VERSION));
180 case KERN_MAXPROC:
181 return (sysctl_int(oldp, oldlenp, newp, newlen, &maxproc));
182 case KERN_MAXFILES:
183 return (sysctl_int(oldp, oldlenp, newp, newlen, &maxfiles));
184 case KERN_ARGMAX:
185 return (sysctl_rdint(oldp, oldlenp, newp, ARG_MAX));
186 case KERN_HOSTNAME:
187 error = sysctl_string(oldp, oldlenp, newp, newlen,
188 hostname, sizeof(hostname));
189 if (!error)
190 hostnamelen = newlen;
191 return (error);
192 case KERN_HOSTID:
193 return (sysctl_int(oldp, oldlenp, newp, newlen, &hostid));
0f1d36b0
KM
194 case KERN_SECURELVL:
195 level = securelevel;
196 if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &level)) ||
197 newp == NULL)
198 return (error);
199 if (level < securelevel && p->p_pid != 1)
200 return (EPERM);
201 securelevel = level;
202 return (0);
780d91b3
KM
203 case KERN_CLOCKRATE:
204 return (sysctl_clockrate(oldp, oldlenp));
205 case KERN_FILE:
206 return (sysctl_file(oldp, oldlenp));
207 case KERN_VNODE:
208 return (sysctl_vnode(oldp, oldlenp));
209 case KERN_PROC:
210 return (sysctl_doproc(name + 1, namelen - 1, oldp, oldlenp));
211 default:
212 return (EOPNOTSUPP);
213 }
214 /* NOTREACHED */
215}
216
0f1d36b0
KM
217/*
218 * hardware related system variables.
219 */
220hw_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
780d91b3
KM
221 int *name;
222 u_int namelen;
223 void *oldp;
b48024b7 224 size_t *oldlenp;
780d91b3 225 void *newp;
b48024b7 226 size_t newlen;
0f1d36b0 227 struct proc *p;
780d91b3
KM
228{
229 extern char machine[], cpu_model[];
230
231 /* all sysctl names at this level are terminal */
232 if (namelen != 1)
233 return (ENOTDIR); /* overloaded */
234
235 switch (name[0]) {
236 case HW_MACHINE:
237 return (sysctl_rdstring(oldp, oldlenp, newp, machine));
238 case HW_MODEL:
239 return (sysctl_rdstring(oldp, oldlenp, newp, cpu_model));
240 case HW_NCPU:
241 return (sysctl_rdint(oldp, oldlenp, newp, 1)); /* XXX */
242 case HW_CPUSPEED:
243 return (sysctl_rdint(oldp, oldlenp, newp, cpuspeed));
244 case HW_PHYSMEM:
245 return (sysctl_rdint(oldp, oldlenp, newp, ctob(physmem)));
246 case HW_USERMEM:
247 return (sysctl_rdint(oldp, oldlenp, newp,
248 ctob(physmem - cnt.v_wire_count)));
249 case HW_PAGESIZE:
250 return (sysctl_rdint(oldp, oldlenp, newp, PAGE_SIZE));
251 default:
252 return (EOPNOTSUPP);
253 }
254 /* NOTREACHED */
255}
256
257/*
258 * Validate parameters and get old / set new parameters
259 * for an integer-valued sysctl function.
260 */
261sysctl_int(oldp, oldlenp, newp, newlen, valp)
262 void *oldp;
b48024b7 263 size_t *oldlenp;
780d91b3 264 void *newp;
b48024b7 265 size_t newlen;
780d91b3
KM
266 int *valp;
267{
268 int error = 0;
269
270 if (oldp && *oldlenp < sizeof(int))
271 return (ENOMEM);
272 if (newp && newlen != sizeof(int))
273 return (EINVAL);
274 *oldlenp = sizeof(int);
275 if (oldp)
276 error = copyout(valp, oldp, sizeof(int));
277 if (error == 0 && newp)
278 error = copyin(newp, valp, sizeof(int));
279 return (error);
280}
281
282/*
283 * As above, but read-only.
284 */
285sysctl_rdint(oldp, oldlenp, newp, val)
286 void *oldp;
b48024b7 287 size_t *oldlenp;
780d91b3
KM
288 void *newp;
289 int val;
290{
291 int error = 0;
292
293 if (oldp && *oldlenp < sizeof(int))
294 return (ENOMEM);
295 if (newp)
296 return (EPERM);
297 *oldlenp = sizeof(int);
298 if (oldp)
299 error = copyout((caddr_t)&val, oldp, sizeof(int));
300 return (error);
301}
302
303/*
304 * Validate parameters and get old / set new parameters
305 * for a string-valued sysctl function.
306 */
307sysctl_string(oldp, oldlenp, newp, newlen, str, maxlen)
308 void *oldp;
b48024b7 309 size_t *oldlenp;
780d91b3 310 void *newp;
b48024b7 311 size_t newlen;
780d91b3
KM
312 char *str;
313 int maxlen;
314{
315 int len, error = 0;
316
317 len = strlen(str) + 1;
318 if (oldp && *oldlenp < len)
319 return (ENOMEM);
320 if (newp && newlen >= maxlen)
321 return (EINVAL);
924ae1bd
RC
322 if (oldp) {
323 *oldlenp = len;
780d91b3 324 error = copyout(str, oldp, len);
924ae1bd 325 }
780d91b3
KM
326 if (error == 0 && newp) {
327 error = copyin(newp, str, newlen);
328 str[newlen] = 0;
13bbbe63 329 }
8b24ca5d 330 return (error);
4a24f1b0
MT
331}
332
780d91b3
KM
333/*
334 * As above, but read-only.
335 */
336sysctl_rdstring(oldp, oldlenp, newp, str)
337 void *oldp;
b48024b7 338 size_t *oldlenp;
780d91b3
KM
339 void *newp;
340 char *str;
341{
342 int len, error = 0;
343
344 len = strlen(str) + 1;
345 if (oldp && *oldlenp < len)
346 return (ENOMEM);
347 if (newp)
348 return (EPERM);
349 *oldlenp = len;
350 if (oldp)
351 error = copyout(str, oldp, len);
352 return (error);
353}
354
355/*
356 * Validate parameters and get old parameters
357 * for a structure oriented sysctl function.
358 */
359sysctl_rdstruct(oldp, oldlenp, newp, sp, len)
360 void *oldp;
b48024b7
KB
361 size_t *oldlenp;
362 void *newp, *sp;
780d91b3
KM
363 int len;
364{
365 int error = 0;
366
367 if (oldp && *oldlenp < len)
368 return (ENOMEM);
369 if (newp)
370 return (EPERM);
371 *oldlenp = len;
372 if (oldp)
373 error = copyout(sp, oldp, len);
374 return (error);
375}
376
377/*
378 * Get file structures.
379 */
380sysctl_file(where, sizep)
381 char *where;
b48024b7 382 size_t *sizep;
780d91b3
KM
383{
384 int buflen, error;
385 struct file *fp;
386 char *start = where;
387
388 buflen = *sizep;
389 if (where == NULL) {
390 /*
391 * overestimate by 10 files
392 */
393 *sizep = sizeof(filehead) + (nfiles + 10) * sizeof(struct file);
394 return (0);
395 }
396
397 /*
398 * first copyout filehead
399 */
400 if (buflen < sizeof(filehead)) {
401 *sizep = 0;
402 return (0);
403 }
404 if (error = copyout((caddr_t)&filehead, where, sizeof(filehead)))
405 return (error);
406 buflen += sizeof(filehead);
407 where += sizeof(filehead);
408
409 /*
410 * followed by an array of file structures
411 */
412 for (fp = filehead; fp != NULL; fp = fp->f_filef) {
413 if (buflen < sizeof(struct file)) {
414 *sizep = where - start;
415 return (ENOMEM);
416 }
417 if (error = copyout((caddr_t)fp, where, sizeof (struct file)))
418 return (error);
419 buflen -= sizeof(struct file);
420 where += sizeof(struct file);
421 }
422 *sizep = where - start;
423 return (0);
424}
425
4a24f1b0
MT
426/*
427 * try over estimating by 5 procs
428 */
780d91b3 429#define KERN_PROCSLOP (5 * sizeof (struct kinfo_proc))
4a24f1b0 430
780d91b3
KM
431sysctl_doproc(name, namelen, where, sizep)
432 int *name;
b48024b7 433 u_int namelen;
4a24f1b0 434 char *where;
b48024b7 435 size_t *sizep;
4a24f1b0
MT
436{
437 register struct proc *p;
a65b44f0 438 register struct kinfo_proc *dp = (struct kinfo_proc *)where;
780d91b3
KM
439 register int needed = 0;
440 int buflen = where != NULL ? *sizep : 0;
4a24f1b0 441 int doingzomb;
7747bd3b 442 struct eproc eproc;
4a24f1b0
MT
443 int error = 0;
444
780d91b3
KM
445 if (namelen != 2)
446 return (EINVAL);
80a8e5e6 447 p = (struct proc *)allproc;
4a24f1b0
MT
448 doingzomb = 0;
449again:
450 for (; p != NULL; p = p->p_nxt) {
02ea4076
KM
451 /*
452 * Skip embryonic processes.
453 */
454 if (p->p_stat == SIDL)
455 continue;
4a24f1b0
MT
456 /*
457 * TODO - make more efficient (see notes below).
458 * do by session.
459 */
780d91b3 460 switch (name[0]) {
4a24f1b0 461
780d91b3 462 case KERN_PROC_PID:
4a24f1b0 463 /* could do this with just a lookup */
780d91b3 464 if (p->p_pid != (pid_t)name[1])
4a24f1b0
MT
465 continue;
466 break;
467
780d91b3 468 case KERN_PROC_PGRP:
4a24f1b0 469 /* could do this by traversing pgrp */
780d91b3 470 if (p->p_pgrp->pg_id != (pid_t)name[1])
4a24f1b0
MT
471 continue;
472 break;
473
780d91b3 474 case KERN_PROC_TTY:
4a24f1b0
MT
475 if ((p->p_flag&SCTTY) == 0 ||
476 p->p_session->s_ttyp == NULL ||
780d91b3 477 p->p_session->s_ttyp->t_dev != (dev_t)name[1])
4a24f1b0
MT
478 continue;
479 break;
480
780d91b3
KM
481 case KERN_PROC_UID:
482 if (p->p_ucred->cr_uid != (uid_t)name[1])
4a24f1b0
MT
483 continue;
484 break;
485
780d91b3
KM
486 case KERN_PROC_RUID:
487 if (p->p_cred->p_ruid != (uid_t)name[1])
4a24f1b0
MT
488 continue;
489 break;
490 }
780d91b3 491 if (buflen >= sizeof(struct kinfo_proc)) {
32041eb1 492 fill_eproc(p, &eproc);
a65b44f0 493 if (error = copyout((caddr_t)p, &dp->kp_proc,
780d91b3 494 sizeof(struct proc)))
4a24f1b0 495 return (error);
a65b44f0 496 if (error = copyout((caddr_t)&eproc, &dp->kp_eproc,
780d91b3 497 sizeof(eproc)))
4a24f1b0 498 return (error);
a65b44f0 499 dp++;
780d91b3 500 buflen -= sizeof(struct kinfo_proc);
4a24f1b0 501 }
780d91b3 502 needed += sizeof(struct kinfo_proc);
4a24f1b0
MT
503 }
504 if (doingzomb == 0) {
505 p = zombproc;
506 doingzomb++;
507 goto again;
508 }
780d91b3
KM
509 if (where != NULL) {
510 *sizep = (caddr_t)dp - where;
511 if (needed > *sizep)
512 return (ENOMEM);
513 } else {
514 needed += KERN_PROCSLOP;
515 *sizep = needed;
516 }
4a24f1b0
MT
517 return (0);
518}
32041eb1
MK
519
520/*
521 * Fill in an eproc structure for the specified process.
522 */
523void
524fill_eproc(p, ep)
525 register struct proc *p;
526 register struct eproc *ep;
527{
528 register struct tty *tp;
529
530 ep->e_paddr = p;
531 ep->e_sess = p->p_pgrp->pg_session;
532 ep->e_pcred = *p->p_cred;
533 ep->e_ucred = *p->p_ucred;
13bbbe63
CT
534 if (p->p_stat == SIDL || p->p_stat == SZOMB) {
535 ep->e_vm.vm_rssize = 0;
536 ep->e_vm.vm_tsize = 0;
537 ep->e_vm.vm_dsize = 0;
538 ep->e_vm.vm_ssize = 0;
539#ifndef sparc
540 /* ep->e_vm.vm_pmap = XXX; */
541#endif
542 } else {
543 register struct vmspace *vm = p->p_vmspace;
544
545 ep->e_vm.vm_rssize = vm->vm_rssize;
546 ep->e_vm.vm_tsize = vm->vm_tsize;
547 ep->e_vm.vm_dsize = vm->vm_dsize;
548 ep->e_vm.vm_ssize = vm->vm_ssize;
549#ifndef sparc
550 ep->e_vm.vm_pmap = vm->vm_pmap;
551#endif
552 }
31c481fa
MK
553 if (p->p_pptr)
554 ep->e_ppid = p->p_pptr->p_pid;
555 else
556 ep->e_ppid = 0;
32041eb1
MK
557 ep->e_pgid = p->p_pgrp->pg_id;
558 ep->e_jobc = p->p_pgrp->pg_jobc;
559 if ((p->p_flag&SCTTY) &&
560 (tp = ep->e_sess->s_ttyp)) {
561 ep->e_tdev = tp->t_dev;
51d82109 562 ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
32041eb1
MK
563 ep->e_tsess = tp->t_session;
564 } else
565 ep->e_tdev = NODEV;
566 ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0;
567 if (SESS_LEADER(p))
568 ep->e_flag |= EPROC_SLEADER;
569 if (p->p_wmesg)
570 strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN);
571 ep->e_xsize = ep->e_xrssize = 0;
572 ep->e_xccount = ep->e_xswrss = 0;
573}
318784c4 574
780d91b3 575#ifdef COMPAT_43
780d91b3 576#include <sys/socket.h>
1fa29dab
KM
577#define KINFO_PROC (0<<8)
578#define KINFO_RT (1<<8)
579#define KINFO_VNODE (2<<8)
580#define KINFO_FILE (3<<8)
581#define KINFO_METER (4<<8)
582#define KINFO_LOADAVG (5<<8)
583#define KINFO_CLOCKRATE (6<<8)
780d91b3
KM
584
585struct getkerninfo_args {
586 int op;
587 char *where;
588 int *size;
589 int arg;
590};
591
7e024c88 592ogetkerninfo(p, uap, retval)
780d91b3
KM
593 struct proc *p;
594 register struct getkerninfo_args *uap;
595 int *retval;
318784c4 596{
780d91b3
KM
597 int error, name[5];
598 u_int size;
318784c4 599
358fe79a 600 if (uap->size &&
b48024b7 601 (error = copyin((caddr_t)uap->size, (caddr_t)&size, sizeof(size))))
780d91b3 602 return (error);
318784c4 603
1fa29dab 604 switch (uap->op & 0xff00) {
318784c4 605
780d91b3
KM
606 case KINFO_RT:
607 name[0] = PF_ROUTE;
608 name[1] = 0;
609 name[2] = (uap->op & 0xff0000) >> 16;
610 name[3] = uap->op & 0xff;
611 name[4] = uap->arg;
0f1d36b0 612 error = net_sysctl(name, 5, uap->where, &size, NULL, 0, p);
780d91b3 613 break;
318784c4 614
780d91b3
KM
615 case KINFO_VNODE:
616 name[0] = KERN_VNODE;
0f1d36b0 617 error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p);
780d91b3
KM
618 break;
619
620 case KINFO_PROC:
621 name[0] = KERN_PROC;
622 name[1] = uap->op & 0xff;
623 name[2] = uap->arg;
0f1d36b0 624 error = kern_sysctl(name, 3, uap->where, &size, NULL, 0, p);
780d91b3
KM
625 break;
626
627 case KINFO_FILE:
628 name[0] = KERN_FILE;
0f1d36b0 629 error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p);
780d91b3
KM
630 break;
631
632 case KINFO_METER:
633 name[0] = VM_METER;
0f1d36b0 634 error = vm_sysctl(name, 1, uap->where, &size, NULL, 0, p);
780d91b3
KM
635 break;
636
637 case KINFO_LOADAVG:
638 name[0] = VM_LOADAVG;
0f1d36b0 639 error = vm_sysctl(name, 1, uap->where, &size, NULL, 0, p);
780d91b3
KM
640 break;
641
642 case KINFO_CLOCKRATE:
643 name[0] = KERN_CLOCKRATE;
0f1d36b0 644 error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p);
780d91b3
KM
645 break;
646
647 default:
0f1d36b0 648 return (EOPNOTSUPP);
780d91b3
KM
649 }
650 if (error)
651 return (error);
652 *retval = size;
358fe79a
KM
653 if (uap->size)
654 error = copyout((caddr_t)&size, (caddr_t)uap->size,
655 sizeof(size));
656 return (error);
318784c4 657}
780d91b3 658#endif /* COMPAT_43 */