use mkdir -p, so it will construct the path
[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 *
0f1d36b0 10 * @(#)kern_sysctl.c 7.29 (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;
52 u_int *oldlenp;
53 void *new;
54 u_int 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;
157 u_int *oldlenp;
158 void *newp;
159 u_int 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;
224 u_int *oldlenp;
225 void *newp;
226 u_int 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;
263 u_int *oldlenp;
264 void *newp;
265 u_int newlen;
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;
287 u_int *oldlenp;
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;
309 u_int *oldlenp;
310 void *newp;
311 u_int newlen;
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;
338 u_int *oldlenp;
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;
361 u_int *oldlenp;
362 void *newp;
363 void *sp;
364 int len;
365{
366 int error = 0;
367
368 if (oldp && *oldlenp < len)
369 return (ENOMEM);
370 if (newp)
371 return (EPERM);
372 *oldlenp = len;
373 if (oldp)
374 error = copyout(sp, oldp, len);
375 return (error);
376}
377
378/*
379 * Get file structures.
380 */
381sysctl_file(where, sizep)
382 char *where;
383 int *sizep;
384{
385 int buflen, error;
386 struct file *fp;
387 char *start = where;
388
389 buflen = *sizep;
390 if (where == NULL) {
391 /*
392 * overestimate by 10 files
393 */
394 *sizep = sizeof(filehead) + (nfiles + 10) * sizeof(struct file);
395 return (0);
396 }
397
398 /*
399 * first copyout filehead
400 */
401 if (buflen < sizeof(filehead)) {
402 *sizep = 0;
403 return (0);
404 }
405 if (error = copyout((caddr_t)&filehead, where, sizeof(filehead)))
406 return (error);
407 buflen += sizeof(filehead);
408 where += sizeof(filehead);
409
410 /*
411 * followed by an array of file structures
412 */
413 for (fp = filehead; fp != NULL; fp = fp->f_filef) {
414 if (buflen < sizeof(struct file)) {
415 *sizep = where - start;
416 return (ENOMEM);
417 }
418 if (error = copyout((caddr_t)fp, where, sizeof (struct file)))
419 return (error);
420 buflen -= sizeof(struct file);
421 where += sizeof(struct file);
422 }
423 *sizep = where - start;
424 return (0);
425}
426
4a24f1b0
MT
427/*
428 * try over estimating by 5 procs
429 */
780d91b3 430#define KERN_PROCSLOP (5 * sizeof (struct kinfo_proc))
4a24f1b0 431
780d91b3
KM
432sysctl_doproc(name, namelen, where, sizep)
433 int *name;
434 int namelen;
4a24f1b0 435 char *where;
780d91b3 436 int *sizep;
4a24f1b0
MT
437{
438 register struct proc *p;
a65b44f0 439 register struct kinfo_proc *dp = (struct kinfo_proc *)where;
780d91b3
KM
440 register int needed = 0;
441 int buflen = where != NULL ? *sizep : 0;
4a24f1b0 442 int doingzomb;
7747bd3b 443 struct eproc eproc;
4a24f1b0
MT
444 int error = 0;
445
780d91b3
KM
446 if (namelen != 2)
447 return (EINVAL);
80a8e5e6 448 p = (struct proc *)allproc;
4a24f1b0
MT
449 doingzomb = 0;
450again:
451 for (; p != NULL; p = p->p_nxt) {
02ea4076
KM
452 /*
453 * Skip embryonic processes.
454 */
455 if (p->p_stat == SIDL)
456 continue;
4a24f1b0
MT
457 /*
458 * TODO - make more efficient (see notes below).
459 * do by session.
460 */
780d91b3 461 switch (name[0]) {
4a24f1b0 462
780d91b3 463 case KERN_PROC_PID:
4a24f1b0 464 /* could do this with just a lookup */
780d91b3 465 if (p->p_pid != (pid_t)name[1])
4a24f1b0
MT
466 continue;
467 break;
468
780d91b3 469 case KERN_PROC_PGRP:
4a24f1b0 470 /* could do this by traversing pgrp */
780d91b3 471 if (p->p_pgrp->pg_id != (pid_t)name[1])
4a24f1b0
MT
472 continue;
473 break;
474
780d91b3 475 case KERN_PROC_TTY:
4a24f1b0
MT
476 if ((p->p_flag&SCTTY) == 0 ||
477 p->p_session->s_ttyp == NULL ||
780d91b3 478 p->p_session->s_ttyp->t_dev != (dev_t)name[1])
4a24f1b0
MT
479 continue;
480 break;
481
780d91b3
KM
482 case KERN_PROC_UID:
483 if (p->p_ucred->cr_uid != (uid_t)name[1])
4a24f1b0
MT
484 continue;
485 break;
486
780d91b3
KM
487 case KERN_PROC_RUID:
488 if (p->p_cred->p_ruid != (uid_t)name[1])
4a24f1b0
MT
489 continue;
490 break;
491 }
780d91b3 492 if (buflen >= sizeof(struct kinfo_proc)) {
32041eb1 493 fill_eproc(p, &eproc);
a65b44f0 494 if (error = copyout((caddr_t)p, &dp->kp_proc,
780d91b3 495 sizeof(struct proc)))
4a24f1b0 496 return (error);
a65b44f0 497 if (error = copyout((caddr_t)&eproc, &dp->kp_eproc,
780d91b3 498 sizeof(eproc)))
4a24f1b0 499 return (error);
a65b44f0 500 dp++;
780d91b3 501 buflen -= sizeof(struct kinfo_proc);
4a24f1b0 502 }
780d91b3 503 needed += sizeof(struct kinfo_proc);
4a24f1b0
MT
504 }
505 if (doingzomb == 0) {
506 p = zombproc;
507 doingzomb++;
508 goto again;
509 }
780d91b3
KM
510 if (where != NULL) {
511 *sizep = (caddr_t)dp - where;
512 if (needed > *sizep)
513 return (ENOMEM);
514 } else {
515 needed += KERN_PROCSLOP;
516 *sizep = needed;
517 }
4a24f1b0
MT
518 return (0);
519}
32041eb1
MK
520
521/*
522 * Fill in an eproc structure for the specified process.
523 */
524void
525fill_eproc(p, ep)
526 register struct proc *p;
527 register struct eproc *ep;
528{
529 register struct tty *tp;
530
531 ep->e_paddr = p;
532 ep->e_sess = p->p_pgrp->pg_session;
533 ep->e_pcred = *p->p_cred;
534 ep->e_ucred = *p->p_ucred;
13bbbe63
CT
535 if (p->p_stat == SIDL || p->p_stat == SZOMB) {
536 ep->e_vm.vm_rssize = 0;
537 ep->e_vm.vm_tsize = 0;
538 ep->e_vm.vm_dsize = 0;
539 ep->e_vm.vm_ssize = 0;
540#ifndef sparc
541 /* ep->e_vm.vm_pmap = XXX; */
542#endif
543 } else {
544 register struct vmspace *vm = p->p_vmspace;
545
546 ep->e_vm.vm_rssize = vm->vm_rssize;
547 ep->e_vm.vm_tsize = vm->vm_tsize;
548 ep->e_vm.vm_dsize = vm->vm_dsize;
549 ep->e_vm.vm_ssize = vm->vm_ssize;
550#ifndef sparc
551 ep->e_vm.vm_pmap = vm->vm_pmap;
552#endif
553 }
31c481fa
MK
554 if (p->p_pptr)
555 ep->e_ppid = p->p_pptr->p_pid;
556 else
557 ep->e_ppid = 0;
32041eb1
MK
558 ep->e_pgid = p->p_pgrp->pg_id;
559 ep->e_jobc = p->p_pgrp->pg_jobc;
560 if ((p->p_flag&SCTTY) &&
561 (tp = ep->e_sess->s_ttyp)) {
562 ep->e_tdev = tp->t_dev;
51d82109 563 ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
32041eb1
MK
564 ep->e_tsess = tp->t_session;
565 } else
566 ep->e_tdev = NODEV;
567 ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0;
568 if (SESS_LEADER(p))
569 ep->e_flag |= EPROC_SLEADER;
570 if (p->p_wmesg)
571 strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN);
572 ep->e_xsize = ep->e_xrssize = 0;
573 ep->e_xccount = ep->e_xswrss = 0;
574}
318784c4 575
780d91b3 576#ifdef COMPAT_43
780d91b3 577#include <sys/socket.h>
1fa29dab
KM
578#define KINFO_PROC (0<<8)
579#define KINFO_RT (1<<8)
580#define KINFO_VNODE (2<<8)
581#define KINFO_FILE (3<<8)
582#define KINFO_METER (4<<8)
583#define KINFO_LOADAVG (5<<8)
584#define KINFO_CLOCKRATE (6<<8)
780d91b3
KM
585
586struct getkerninfo_args {
587 int op;
588 char *where;
589 int *size;
590 int arg;
591};
592
593getkerninfo(p, uap, retval)
594 struct proc *p;
595 register struct getkerninfo_args *uap;
596 int *retval;
318784c4 597{
780d91b3
KM
598 int error, name[5];
599 u_int size;
318784c4 600
780d91b3
KM
601 if (error = copyin((caddr_t)uap->size, (caddr_t)&size, sizeof(size)))
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;
653 return (copyout((caddr_t)&size, (caddr_t)uap->size, sizeof(size)));
318784c4 654}
780d91b3 655#endif /* COMPAT_43 */