139963Smarc /* 239963Smarc * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 339963Smarc * All rights reserved. 439963Smarc * 539963Smarc * Redistribution and use in source and binary forms are permitted 639963Smarc * provided that the above copyright notice and this paragraph are 739963Smarc * duplicated in all such forms and that any documentation, 839963Smarc * advertising materials, and other materials related to such 939963Smarc * distribution and use acknowledge that the software was developed 1039963Smarc * by the University of California, Berkeley. The name of the 1139963Smarc * University may not be used to endorse or promote products derived 1239963Smarc * from this software without specific prior written permission. 1339963Smarc * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1439963Smarc * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1539963Smarc * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1639963Smarc * 17*39965Smckusick * @(#)kern_sysctl.c 7.2 (Berkeley) 01/31/90 1839963Smarc */ 1939963Smarc 20*39965Smckusick #include "param.h" 21*39965Smckusick #include "user.h" 22*39965Smckusick #include "proc.h" 2339963Smarc #include "kinfo.h" 2439963Smarc #include "vm.h" 2539963Smarc #include "ioctl.h" 2639963Smarc #include "tty.h" 2739963Smarc #include "buf.h" 2839963Smarc 2939963Smarc /* TODO - gather stats on average and max time spent */ 3039963Smarc getkinfo() 3139963Smarc { 3239963Smarc register struct a { 3339963Smarc int op; 3439963Smarc char *where; 3539963Smarc int *size; 3639963Smarc int arg; 3739963Smarc } *uap = (struct a *)u.u_ap; 3839963Smarc int wanted; 3939963Smarc 4039963Smarc switch (ki_type(uap->op)) { 4139963Smarc 4239963Smarc case KINFO_PROC: 4339963Smarc u.u_error = kinfo_proc(uap->op, (char *)uap->where, 4439963Smarc (int *)uap->size, uap->arg, &wanted); 4539963Smarc if (!u.u_error) 4639963Smarc u.u_r.r_val1 = wanted; 4739963Smarc break; 4839963Smarc 4939963Smarc default: 5039963Smarc u.u_error = EINVAL; 5139963Smarc } 5239963Smarc 5339963Smarc return; 5439963Smarc } 5539963Smarc 5639963Smarc /* 5739963Smarc * try over estimating by 5 procs 5839963Smarc */ 5939963Smarc #define KINFO_PROCSLOP (5 * sizeof (struct kinfo_proc)) 6039963Smarc 6139963Smarc int kinfo_proc_userfailed; 6239963Smarc int kinfo_proc_wefailed; 6339963Smarc 6439963Smarc kinfo_proc(op, where, asize, arg, awanted) 6539963Smarc char *where; 6639963Smarc int *asize, *awanted; 6739963Smarc { 6839963Smarc int bufsize, /* max size of users buffer */ 6939963Smarc copysize, /* size copied */ 7039963Smarc needed; 7139963Smarc int locked; 7239963Smarc int error; 7339963Smarc 7439963Smarc if (error = kinfo_doprocs(op, NULL, NULL, arg, &needed)) 7539963Smarc return (error); 7639963Smarc if (where == NULL || asize == NULL) { 7739963Smarc *awanted = needed; 7839963Smarc return (0); 7939963Smarc } 8039963Smarc if (error = copyin((caddr_t)asize, (caddr_t)&bufsize, sizeof (bufsize))) 8139963Smarc return (error); 8239963Smarc needed += KINFO_PROCSLOP; 8339963Smarc locked = copysize = MIN(needed, bufsize); 8439963Smarc if (!useracc(where, copysize, B_WRITE)) 8539963Smarc return (EFAULT); 8639963Smarc /* 8739963Smarc * lock down target pages - NEED DEADLOCK AVOIDANCE 8839963Smarc */ 8939963Smarc if (copysize > ((int)ptob(freemem) - (20 * 1024))) /* XXX */ 9039963Smarc return (ENOMEM); 9139963Smarc vslock(where, copysize); 9239963Smarc error = kinfo_doprocs(op, where, ©size, arg, &needed); 9339963Smarc vsunlock(where, locked, B_WRITE); 9439963Smarc if (error) 9539963Smarc return (error); 9639963Smarc *awanted = needed; 9739963Smarc if (error = copyout((caddr_t)©size, (caddr_t)asize, 9839963Smarc sizeof (copysize))) 9939963Smarc return (error); 10039963Smarc 10139963Smarc return (0); 10239963Smarc } 10339963Smarc 10439963Smarc kinfo_doprocs(op, where, acopysize, arg, aneeded) 10539963Smarc char *where; 10639963Smarc int *acopysize, *aneeded; 10739963Smarc { 10839963Smarc register struct proc *p; 10939963Smarc register caddr_t dp = (caddr_t)where; 11039963Smarc register needed = 0; 11139963Smarc int buflen; 11239963Smarc int doingzomb; 11339963Smarc struct { 11439963Smarc struct proc *paddr; 11539963Smarc struct session *session; 11639963Smarc pid_t pgid; 11739963Smarc short jobc; 11839963Smarc dev_t ttydev; 11939963Smarc pid_t ttypgid; 12039963Smarc struct session *ttysession; 12139963Smarc } extra; 12239963Smarc struct tty *tp; 12339963Smarc int error = 0; 12439963Smarc 12539963Smarc if (where != NULL) 12639963Smarc buflen = *acopysize; 12739963Smarc 12839963Smarc p = allproc; 12939963Smarc doingzomb = 0; 13039963Smarc again: 13139963Smarc for (; p != NULL; p = p->p_nxt) { 13239963Smarc /* 13339963Smarc * TODO - make more efficient (see notes below). 13439963Smarc * do by session. 13539963Smarc */ 13639963Smarc switch (ki_op(op)) { 13739963Smarc 13839963Smarc case KINFO_PROC_PID: 13939963Smarc /* could do this with just a lookup */ 14039963Smarc if (p->p_pid != (pid_t)arg) 14139963Smarc continue; 14239963Smarc break; 14339963Smarc 14439963Smarc case KINFO_PROC_PGRP: 14539963Smarc /* could do this by traversing pgrp */ 14639963Smarc if (p->p_pgrp->pg_id != (pid_t)arg) 14739963Smarc continue; 14839963Smarc break; 14939963Smarc 15039963Smarc case KINFO_PROC_TTY: 15139963Smarc if ((p->p_flag&SCTTY) == 0 || 15239963Smarc p->p_session->s_ttyp == NULL || 15339963Smarc p->p_session->s_ttyp->t_dev != (dev_t)arg) 15439963Smarc continue; 15539963Smarc break; 15639963Smarc 15739963Smarc case KINFO_PROC_UID: 15839963Smarc if (p->p_uid != (uid_t)arg) 15939963Smarc continue; 16039963Smarc break; 16139963Smarc 16239963Smarc case KINFO_PROC_RUID: 16339963Smarc if (p->p_ruid != (uid_t)arg) 16439963Smarc continue; 16539963Smarc break; 16639963Smarc } 16739963Smarc if (where != NULL && buflen >= sizeof (struct kinfo_proc)) { 16839963Smarc if (error = copyout((caddr_t)p, dp, 16939963Smarc sizeof (struct proc))) 17039963Smarc return (error); 17139963Smarc dp += sizeof (struct proc); 17239963Smarc extra.paddr = p; 17339963Smarc extra.session = p->p_pgrp->pg_session; 17439963Smarc extra.pgid = p->p_pgrp->pg_id; 17539963Smarc extra.jobc = p->p_pgrp->pg_jobc; 17639963Smarc tp = p->p_pgrp->pg_session->s_ttyp; 17739963Smarc if ((p->p_flag&SCTTY) && tp != NULL) { 17839963Smarc extra.ttydev = tp->t_dev; 17939963Smarc extra.ttypgid = tp->t_pgrp ? 18039963Smarc tp->t_pgrp->pg_id : -1; 18139963Smarc extra.ttysession = tp->t_session; 18239963Smarc } else 18339963Smarc extra.ttydev = NODEV; 18439963Smarc if (error = copyout((caddr_t)&extra, dp, 18539963Smarc sizeof (extra))) 18639963Smarc return (error); 18739963Smarc dp += sizeof (extra); 18839963Smarc buflen -= sizeof (struct kinfo_proc); 18939963Smarc } 19039963Smarc needed += sizeof (struct kinfo_proc); 19139963Smarc } 19239963Smarc if (doingzomb == 0) { 19339963Smarc p = zombproc; 19439963Smarc doingzomb++; 19539963Smarc goto again; 19639963Smarc } 19739963Smarc if (where != NULL) 19839963Smarc *acopysize = dp - where; 19939963Smarc *aneeded = needed; 20039963Smarc 20139963Smarc return (0); 20239963Smarc } 203