diff options
author | Todd C. Miller <millert@cvs.openbsd.org> | 2004-01-07 02:13:52 +0000 |
---|---|---|
committer | Todd C. Miller <millert@cvs.openbsd.org> | 2004-01-07 02:13:52 +0000 |
commit | fb432cea5dcf9e2d9074c37ea608738ca2713084 (patch) | |
tree | 91bf64f2945789a95b5d98ee5772d777353659da /sys | |
parent | 4f39cdd2c6dddeafd129d4ad78b68964b220c3e2 (diff) |
Implement KERN_PROC2 sysctl from NetBSD. This will allow us to
have ps and friends be independent of changes in struct proc et al
in the kernel. OK deraadt@
Diffstat (limited to 'sys')
-rw-r--r-- | sys/kern/kern_sysctl.c | 272 | ||||
-rw-r--r-- | sys/sys/sysctl.h | 130 |
2 files changed, 367 insertions, 35 deletions
diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c index bc60e59c35f..fc6f1cb487b 100644 --- a/sys/kern/kern_sysctl.c +++ b/sys/kern/kern_sysctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_sysctl.c,v 1.93 2003/12/18 23:46:20 tedu Exp $ */ +/* $OpenBSD: kern_sysctl.c,v 1.94 2004/01/07 02:13:51 millert Exp $ */ /* $NetBSD: kern_sysctl.c,v 1.17 1996/05/20 17:49:05 mrg Exp $ */ /*- @@ -81,6 +81,8 @@ #include <sys/shm.h> #endif +#define PTRTOINT64(_x) ((u_int64_t)(u_long)(_x)) + extern struct forkstat forkstat; extern struct nchstats nchstats; extern int nselcoll, fscale; @@ -262,6 +264,7 @@ kern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) if (namelen != 1) { switch (name[0]) { case KERN_PROC: + case KERN_PROC2: case KERN_PROF: case KERN_MALLOCSTATS: case KERN_TTY: @@ -341,7 +344,8 @@ kern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) case KERN_VNODE: return (sysctl_vnode(oldp, oldlenp, p)); case KERN_PROC: - return (sysctl_doproc(name + 1, namelen - 1, oldp, oldlenp)); + case KERN_PROC2: + return (sysctl_doproc(name, namelen, oldp, oldlenp)); case KERN_PROC_ARGS: return (sysctl_proc_args(name + 1, namelen - 1, oldp, oldlenp, p)); @@ -912,17 +916,33 @@ sysctl_doproc(name, namelen, where, sizep) char *where; size_t *sizep; { - register struct proc *p; - register struct kinfo_proc *dp = (struct kinfo_proc *)where; - register int needed = 0; - int buflen = where != NULL ? *sizep : 0; - int doingzomb; + struct kinfo_proc2 kproc2; struct eproc eproc; - int error = 0; - - if (namelen != 2 && !(namelen == 1 && - (name[0] == KERN_PROC_ALL || name[0] == KERN_PROC_KTHREAD))) - return (EINVAL); + struct proc *p; + char *dp; + int arg, buflen, doingzomb, elem_size, elem_count; + int error, needed, type, op; + + dp = where; + buflen = where != NULL ? *sizep : 0; + needed = error = 0; + type = name[0]; + + if (type == KERN_PROC) { + if (namelen != 3 && !(namelen == 2 && + (name[1] == KERN_PROC_ALL || name[1] == KERN_PROC_KTHREAD))) + return (EINVAL); + op = name[1]; + arg = op == KERN_PROC_ALL ? 0 : name[2]; + elem_size = elem_count = 0; + } else /* if (type == KERN_PROC2) */ { + if (namelen != 5 || name[3] < 0 || name[4] < 0) + return (EINVAL); + op = name[1]; + arg = name[2]; + elem_size = name[3]; + elem_count = name[4]; + } p = LIST_FIRST(&allproc); doingzomb = 0; again: @@ -934,36 +954,41 @@ again: continue; /* * TODO - make more efficient (see notes below). - * do by session. */ - switch (name[0]) { + switch (op) { case KERN_PROC_PID: /* could do this with just a lookup */ - if (p->p_pid != (pid_t)name[1]) + if (p->p_pid != (pid_t)arg) continue; break; case KERN_PROC_PGRP: /* could do this by traversing pgrp */ - if (p->p_pgrp->pg_id != (pid_t)name[1]) + if (p->p_pgrp->pg_id != (pid_t)arg) + continue; + break; + + case KERN_PROC_SESSION: + if (p->p_session->s_leader == NULL || + p->p_session->s_leader->p_pid != (pid_t)arg) continue; break; case KERN_PROC_TTY: if ((p->p_flag & P_CONTROLT) == 0 || p->p_session->s_ttyp == NULL || - p->p_session->s_ttyp->t_dev != (dev_t)name[1]) + p->p_session->s_ttyp->t_dev != (dev_t)arg) continue; break; case KERN_PROC_UID: - if (p->p_ucred->cr_uid != (uid_t)name[1]) + if (p->p_ucred->cr_uid != (uid_t)arg) continue; break; case KERN_PROC_RUID: - if (p->p_cred->p_ruid != (uid_t)name[1]) + if (p->p_cred->p_ruid != (uid_t)arg) continue; break; @@ -971,21 +996,43 @@ again: if (p->p_flag & P_SYSTEM) continue; break; + default: + return (EINVAL); } - if (buflen >= sizeof(struct kinfo_proc)) { - fill_eproc(p, &eproc); - error = copyout((caddr_t)p, &dp->kp_proc, - sizeof(struct proc)); - if (error) - return (error); - error = copyout((caddr_t)&eproc, &dp->kp_eproc, - sizeof(eproc)); - if (error) - return (error); - dp++; - buflen -= sizeof(struct kinfo_proc); + if (type == KERN_PROC) { + if (buflen >= sizeof(struct kinfo_proc)) { + fill_eproc(p, &eproc); + error = copyout((caddr_t)p, + &((struct kinfo_proc *)dp)->kp_proc, + sizeof(struct proc)); + if (error) + return (error); + error = copyout((caddr_t)&eproc, + &((struct kinfo_proc *)dp)->kp_eproc, + sizeof(eproc)); + if (error) + return (error); + dp += sizeof(struct kinfo_proc); + buflen -= sizeof(struct kinfo_proc); + } + needed += sizeof(struct kinfo_proc); + } else /* if (type == KERN_PROC2) */ { + if (buflen >= elem_size && elem_count > 0) { + fill_kproc2(p, &kproc2); + /* + * Copy out elem_size, but not larger than + * the size of a struct kinfo_proc2. + */ + error = copyout(&kproc2, dp, + min(sizeof(kproc2), elem_size)); + if (error) + return (error); + dp += elem_size; + buflen -= elem_size; + elem_count--; + } + needed += elem_size; } - needed += sizeof(struct kinfo_proc); } if (doingzomb == 0) { p = LIST_FIRST(&zombproc); @@ -993,7 +1040,7 @@ again: goto again; } if (where != NULL) { - *sizep = (caddr_t)dp - where; + *sizep = dp - where; if (needed > *sizep) return (ENOMEM); } else { @@ -1061,6 +1108,165 @@ fill_eproc(struct proc *p, struct eproc *ep) ep->e_maxrss = p->p_rlimit ? p->p_rlimit[RLIMIT_RSS].rlim_cur : 0; } +/* + * Fill in a kproc2 structure for the specified process. + */ +void +fill_kproc2(struct proc *p, struct kinfo_proc2 *ki) +{ + struct tty *tp; + struct timeval ut, st; + + bzero(ki, sizeof(*ki)); + + ki->p_paddr = PTRTOINT64(p); + ki->p_fd = PTRTOINT64(p->p_fd); + ki->p_stats = PTRTOINT64(p->p_stats); + ki->p_limit = PTRTOINT64(p->p_limit); + ki->p_vmspace = PTRTOINT64(p->p_vmspace); + ki->p_sigacts = PTRTOINT64(p->p_sigacts); + ki->p_sess = PTRTOINT64(p->p_session); + ki->p_tsess = 0; /* may be changed if controlling tty below */ + ki->p_ru = PTRTOINT64(p->p_ru); + + ki->p_eflag = 0; + ki->p_exitsig = p->p_exitsig; + ki->p_flag = p->p_flag; + + ki->p_pid = p->p_pid; + if (p->p_pptr) + ki->p_ppid = p->p_pptr->p_pid; + else + ki->p_ppid = 0; + if (p->p_session->s_leader) + ki->p_sid = p->p_session->s_leader->p_pid; + else + ki->p_sid = 0; + ki->p__pgid = p->p_pgrp->pg_id; + + ki->p_tpgid = -1; /* may be changed if controlling tty below */ + + ki->p_uid = p->p_ucred->cr_uid; + ki->p_ruid = p->p_cred->p_ruid; + ki->p_gid = p->p_ucred->cr_gid; + ki->p_rgid = p->p_cred->p_rgid; + ki->p_svuid = p->p_cred->p_svuid; + ki->p_svgid = p->p_cred->p_svgid; + + memcpy(ki->p_groups, p->p_cred->pc_ucred->cr_groups, + min(sizeof(ki->p_groups), sizeof(p->p_cred->pc_ucred->cr_groups))); + ki->p_ngroups = p->p_cred->pc_ucred->cr_ngroups; + + ki->p_jobc = p->p_pgrp->pg_jobc; + if ((p->p_flag & P_CONTROLT) && (tp = p->p_session->s_ttyp)) { + ki->p_tdev = tp->t_dev; + ki->p_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : -1; + ki->p_tsess = PTRTOINT64(tp->t_session); + } else { + ki->p_tdev = NODEV; + } + + ki->p_estcpu = p->p_estcpu; + ki->p_rtime_sec = p->p_rtime.tv_sec; + ki->p_rtime_usec = p->p_rtime.tv_usec; + ki->p_cpticks = p->p_cpticks; + ki->p_pctcpu = p->p_pctcpu; + + ki->p_uticks = p->p_uticks; + ki->p_sticks = p->p_sticks; + ki->p_iticks = p->p_iticks; + + ki->p_tracep = PTRTOINT64(p->p_tracep); + ki->p_traceflag = p->p_traceflag; + + ki->p_siglist = p->p_siglist; + ki->p_sigmask = p->p_sigmask; + ki->p_sigignore = p->p_sigignore; + ki->p_sigcatch = p->p_sigcatch; + + ki->p_stat = p->p_stat; + ki->p_nice = p->p_nice; + + ki->p_xstat = p->p_xstat; + ki->p_acflag = p->p_acflag; + + strlcpy(ki->p_comm, p->p_comm, sizeof(ki->p_comm)); + strncpy(ki->p_login, p->p_session->s_login, + min(sizeof(ki->p_login) - 1, sizeof(p->p_session->s_login))); + + if (p->p_stat == SIDL || P_ZOMBIE(p)) { + ki->p_vm_rssize = 0; + ki->p_vm_tsize = 0; + ki->p_vm_dsize = 0; + ki->p_vm_ssize = 0; + } else { + struct vmspace *vm = p->p_vmspace; + + ki->p_vm_rssize = vm_resident_count(vm); + ki->p_vm_tsize = vm->vm_tsize; + ki->p_vm_dsize = vm->vm_dsize; + ki->p_vm_ssize = vm->vm_ssize; + + ki->p_forw = PTRTOINT64(p->p_forw); + ki->p_back = PTRTOINT64(p->p_back); + ki->p_addr = PTRTOINT64(p->p_addr); + ki->p_stat = p->p_stat; + ki->p_swtime = p->p_swtime; + ki->p_slptime = p->p_slptime; + ki->p_schedflags = p->p_schedflags; + ki->p_holdcnt = p->p_holdcnt; + ki->p_priority = p->p_priority; + ki->p_usrpri = p->p_usrpri; + if (p->p_wmesg) + strlcpy(ki->p_wmesg, p->p_wmesg, sizeof(ki->p_wmesg)); + ki->p_wchan = PTRTOINT64(p->p_wchan); + + } + + if (p->p_session->s_ttyvp) + ki->p_eflag |= EPROC_CTTY; + if (SESS_LEADER(p)) + ki->p_eflag |= EPROC_SLEADER; + + /* XXX Is this double check necessary? */ + if (P_ZOMBIE(p)) { + ki->p_uvalid = 0; + } else { + ki->p_uvalid = 1; + + PHOLD(p); /* need for pstats */ + ki->p_ustart_sec = p->p_stats->p_start.tv_sec; + ki->p_ustart_usec = p->p_stats->p_start.tv_usec; + + calcru(p, &ut, &st, 0); + ki->p_uutime_sec = ut.tv_sec; + ki->p_uutime_usec = ut.tv_usec; + ki->p_ustime_sec = st.tv_sec; + ki->p_ustime_usec = st.tv_usec; + + ki->p_uru_maxrss = p->p_stats->p_ru.ru_maxrss; + ki->p_uru_ixrss = p->p_stats->p_ru.ru_ixrss; + ki->p_uru_idrss = p->p_stats->p_ru.ru_idrss; + ki->p_uru_isrss = p->p_stats->p_ru.ru_isrss; + ki->p_uru_minflt = p->p_stats->p_ru.ru_minflt; + ki->p_uru_majflt = p->p_stats->p_ru.ru_majflt; + ki->p_uru_nswap = p->p_stats->p_ru.ru_nswap; + ki->p_uru_inblock = p->p_stats->p_ru.ru_inblock; + ki->p_uru_oublock = p->p_stats->p_ru.ru_oublock; + ki->p_uru_msgsnd = p->p_stats->p_ru.ru_msgsnd; + ki->p_uru_msgrcv = p->p_stats->p_ru.ru_msgrcv; + ki->p_uru_nsignals = p->p_stats->p_ru.ru_nsignals; + ki->p_uru_nvcsw = p->p_stats->p_ru.ru_nvcsw; + ki->p_uru_nivcsw = p->p_stats->p_ru.ru_nivcsw; + + timeradd(&p->p_stats->p_cru.ru_utime, + &p->p_stats->p_cru.ru_stime, &ut); + ki->p_uctime_sec = ut.tv_sec; + ki->p_uctime_usec = ut.tv_usec; + PRELE(p); + } +} + int sysctl_proc_args(int *name, u_int namelen, void *oldp, size_t *oldlenp, struct proc *cp) diff --git a/sys/sys/sysctl.h b/sys/sys/sysctl.h index 728d3b26405..cdacb92cc53 100644 --- a/sys/sys/sysctl.h +++ b/sys/sys/sysctl.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sysctl.h,v 1.67 2003/12/23 20:02:27 tedu Exp $ */ +/* $OpenBSD: sysctl.h,v 1.68 2004/01/07 02:13:51 millert Exp $ */ /* $NetBSD: sysctl.h,v 1.16 1996/04/09 20:55:36 cgd Exp $ */ /* @@ -178,7 +178,8 @@ struct ctlname { #define KERN_INTRCNT 63 /* node: interrupt counters */ #define KERN_WATCHDOG 64 /* node: watchdog */ #define KERN_EMUL 65 /* node: emuls */ -#define KERN_MAXID 66 /* number of valid kern ids */ +#define KERN_PROC2 66 /* struct: process entries */ +#define KERN_MAXID 67 /* number of valid kern ids */ #define CTL_KERN_NAMES { \ { 0, 0 }, \ @@ -247,6 +248,7 @@ struct ctlname { { "intrcnt", CTLTYPE_NODE }, \ { "watchdog", CTLTYPE_NODE }, \ { "emul", CTLTYPE_NODE }, \ + { "proc2", CTLTYPE_STRUCT }, \ } /* @@ -321,6 +323,129 @@ struct kinfo_proc { }; /* + * KERN_PROC2 subtype ops return arrays of relatively fixed size + * structures of process info. Use 8 byte alignment, and new + * elements should only be added to the end of this structure so + * binary compatibility can be preserved. + */ +#define KI_NGROUPS 16 +#define KI_MAXCOMLEN 24 /* extra for 8 byte alignment */ +#define KI_WMESGLEN 8 +#define KI_MAXLOGNAME 32 + +struct kinfo_proc2 { + u_int64_t p_forw; /* PTR: linked run/sleep queue. */ + u_int64_t p_back; + u_int64_t p_paddr; /* PTR: address of proc */ + + u_int64_t p_addr; /* PTR: Kernel virtual addr of u-area */ + u_int64_t p_fd; /* PTR: Ptr to open files structure. */ + u_int64_t p_stats; /* PTR: Accounting/statistics */ + u_int64_t p_limit; /* PTR: Process limits. */ + u_int64_t p_vmspace; /* PTR: Address space. */ + u_int64_t p_sigacts; /* PTR: Signal actions, state */ + u_int64_t p_sess; /* PTR: session pointer */ + u_int64_t p_tsess; /* PTR: tty session pointer */ + u_int64_t p_ru; /* PTR: Exit information. XXX */ + + int32_t p_eflag; /* LONG: extra kinfo_proc2 flags */ + int32_t p_exitsig; /* INT: signal to sent to parent on exit */ + int32_t p_flag; /* INT: P_* flags. */ + + int32_t p_pid; /* PID_T: Process identifier. */ + int32_t p_ppid; /* PID_T: Parent process id */ + int32_t p_sid; /* PID_T: session id */ + int32_t p__pgid; /* PID_T: process group id */ + /* XXX: <sys/proc.h> hijacks p_pgid */ + int32_t p_tpgid; /* PID_T: tty process group id */ + + u_int32_t p_uid; /* UID_T: effective user id */ + u_int32_t p_ruid; /* UID_T: real user id */ + u_int32_t p_gid; /* GID_T: effective group id */ + u_int32_t p_rgid; /* GID_T: real group id */ + + u_int32_t p_groups[KI_NGROUPS]; /* GID_T: groups */ + int16_t p_ngroups; /* SHORT: number of groups */ + + int16_t p_jobc; /* SHORT: job control counter */ + u_int32_t p_tdev; /* DEV_T: controlling tty dev */ + + u_int32_t p_estcpu; /* U_INT: Time averaged value of p_cpticks. */ + u_int32_t p_rtime_sec; /* STRUCT TIMEVAL: Real time. */ + u_int32_t p_rtime_usec; /* STRUCT TIMEVAL: Real time. */ + int32_t p_cpticks; /* INT: Ticks of cpu time. */ + u_int32_t p_pctcpu; /* FIXPT_T: %cpu for this process during p_swtime */ + u_int32_t p_swtime; /* U_INT: Time swapped in or out. */ + u_int32_t p_slptime; /* U_INT: Time since last blocked. */ + int32_t p_schedflags; /* INT: PSCHED_* flags */ + + u_int64_t p_uticks; /* U_QUAD_T: Statclock hits in user mode. */ + u_int64_t p_sticks; /* U_QUAD_T: Statclock hits in system mode. */ + u_int64_t p_iticks; /* U_QUAD_T: Statclock hits processing intr. */ + + u_int64_t p_tracep; /* PTR: Trace to vnode or file */ + int32_t p_traceflag; /* INT: Kernel trace points. */ + + int32_t p_holdcnt; /* INT: If non-zero, don't swap. */ + + int32_t p_siglist; /* INT: Signals arrived but not delivered. */ + int32_t p_sigmask; /* INT: Current signal mask. */ + int32_t p_sigignore; /* INT: Signals being ignored. */ + int32_t p_sigcatch; /* INT: Signals being caught by user. */ + + int8_t p_stat; /* CHAR: S* process status (from LWP). */ + u_int8_t p_priority; /* U_CHAR: Process priority. */ + u_int8_t p_usrpri; /* U_CHAR: User-priority based on p_cpu and p_nice. */ + u_int8_t p_nice; /* U_CHAR: Process "nice" value. */ + + u_int16_t p_xstat; /* U_SHORT: Exit status for wait; also stop signal. */ + u_int16_t p_acflag; /* U_SHORT: Accounting flags. */ + + char p_comm[KI_MAXCOMLEN]; + + char p_wmesg[KI_WMESGLEN]; /* wchan message */ + u_int64_t p_wchan; /* PTR: sleep address. */ + + char p_login[KI_MAXLOGNAME]; /* setlogin() name */ + + int32_t p_vm_rssize; /* SEGSZ_T: current resident set size in pages */ + int32_t p_vm_tsize; /* SEGSZ_T: text size (pages) */ + int32_t p_vm_dsize; /* SEGSZ_T: data size (pages) */ + int32_t p_vm_ssize; /* SEGSZ_T: stack size (pages) */ + + int64_t p_uvalid; /* CHAR: following p_u* members from struct user are valid */ + /* XXX 64 bits for alignment */ + u_int32_t p_ustart_sec; /* STRUCT TIMEVAL: starting time. */ + u_int32_t p_ustart_usec; /* STRUCT TIMEVAL: starting time. */ + + u_int32_t p_uutime_sec; /* STRUCT TIMEVAL: user time. */ + u_int32_t p_uutime_usec; /* STRUCT TIMEVAL: user time. */ + u_int32_t p_ustime_sec; /* STRUCT TIMEVAL: system time. */ + u_int32_t p_ustime_usec; /* STRUCT TIMEVAL: system time. */ + + u_int64_t p_uru_maxrss; /* LONG: max resident set size. */ + u_int64_t p_uru_ixrss; /* LONG: integral shared memory size. */ + u_int64_t p_uru_idrss; /* LONG: integral unshared data ". */ + u_int64_t p_uru_isrss; /* LONG: integral unshared stack ". */ + u_int64_t p_uru_minflt; /* LONG: page reclaims. */ + u_int64_t p_uru_majflt; /* LONG: page faults. */ + u_int64_t p_uru_nswap; /* LONG: swaps. */ + u_int64_t p_uru_inblock; /* LONG: block input operations. */ + u_int64_t p_uru_oublock; /* LONG: block output operations. */ + u_int64_t p_uru_msgsnd; /* LONG: messages sent. */ + u_int64_t p_uru_msgrcv; /* LONG: messages received. */ + u_int64_t p_uru_nsignals; /* LONG: signals received. */ + u_int64_t p_uru_nvcsw; /* LONG: voluntary context switches. */ + u_int64_t p_uru_nivcsw; /* LONG: involuntary ". */ + + u_int32_t p_uctime_sec; /* STRUCT TIMEVAL: child u+s time. */ + u_int32_t p_uctime_usec; /* STRUCT TIMEVAL: child u+s time. */ + u_int64_t p_realflag; /* INT: P_* flags (not including LWPs). */ + u_int32_t p_svuid; /* UID_T: saved user id */ + u_int32_t p_svgid; /* GID_T: saved group id */ +}; + +/* * KERN_INTR_CNT */ #define KERN_INTRCNT_NUM 1 /* int: # intrcnt */ @@ -524,6 +649,7 @@ int sysctl_doprof(int *, u_int, void *, size_t *, void *, size_t); int sysctl_dopool(int *, u_int, char *, size_t *); void fill_eproc(struct proc *, struct eproc *); +void fill_kproc2(struct proc *, struct kinfo_proc2 *); int kern_sysctl(int *, u_int, void *, size_t *, void *, size_t, struct proc *); |