int osf1_sys_getrusage(struct lwp *l, const struct osf1_sys_getrusage_args *uap, register_t *retval) { struct osf1_rusage osf1_rusage; struct rusage ru; struct proc *p = l->l_proc; switch (SCARG(uap, who)) { case OSF1_RUSAGE_SELF: mutex_enter(p->p_lock); ru = p->p_stats->p_ru; calcru(p, &ru.ru_utime, &ru.ru_stime, NULL, NULL); rulwps(p, &ru); mutex_exit(p->p_lock); break; case OSF1_RUSAGE_CHILDREN: ru = p->p_stats->p_cru; break; case OSF1_RUSAGE_THREAD: /* XXX not supported */ default: return (EINVAL); } osf1_cvt_rusage_from_native(&ru, &osf1_rusage); return copyout(&osf1_rusage, SCARG(uap, rusage), sizeof osf1_rusage); }
int get_process_info_sysdep(ProcInfo_T p) { struct kinfo_proc *pinfo; /* Only needed for older versions of BSD that use kvm_uread */ /* struct user *u_addr = (struct user *)USRSTACK; */ struct pstats pstats; struct plimit plimit; struct vmspace *vms; register struct rusage *rup; long stat_utime; long stat_stime; long stat_cutime; long stat_cstime; u_int64_t rss_lim; int count; /* Got it from libgtop */ pinfo = kvm_getprocs(kvm_handle, KERN_PROC_PID, p->pid, &count); if ((pinfo == NULL) || (count < 1)) { return FALSE; } /* ----------------------------- CPU TIMING ----------------------------*/ /* Got it from libgtop/sysdep/freebsd/proctime.c */ if (kvm_read (kvm_handle, #if (__FreeBSD_version > 500000) (unsigned long) &pinfo->ki_addr->u_stats, #else (unsigned long) pinfo [0].kp_proc.p_stats, #endif &pstats, sizeof (pstats)) == sizeof (pstats)) { /* Need to fix for different versions of BSD - I think older ones use kvm_uread, and newer use kvm_read */ /* if ((pinfo [0].kp_proc.p_flag & P_INMEM) && kvm_uread (kvm_handle, &(pinfo [0]).kp_proc, (unsigned long) &u_addr->u_stats, (char *) &pstats, sizeof (pstats)) == sizeof (pstats)) { */ rup = &pstats.p_ru; #if (__FreeBSD_version > 500000) calcru(&pinfo->ki_addr, #else calcru(&(pinfo [0]).kp_proc, #endif &rup->ru_utime, &rup->ru_stime, NULL); stat_utime = tv2sec (pstats.p_ru.ru_utime); stat_stime = tv2sec (pstats.p_ru.ru_stime); stat_cutime = tv2sec (pstats.p_cru.ru_utime); stat_cstime = tv2sec (pstats.p_cru.ru_stime); } else {
int procfs_doprocstatus(PFS_FILL_ARGS) { struct session *sess; struct thread *tdfirst; struct tty *tp; struct ucred *cr; const char *wmesg; char *pc; char *sep; int pid, ppid, pgid, sid; int i; pid = p->p_pid; PROC_LOCK(p); ppid = p->p_pptr ? p->p_pptr->p_pid : 0; pgid = p->p_pgrp->pg_id; sess = p->p_pgrp->pg_session; SESS_LOCK(sess); sid = sess->s_leader ? sess->s_leader->p_pid : 0; /* comm pid ppid pgid sid tty ctty,sldr start ut st wmsg euid ruid rgid,egid,groups[1 .. ngroups] */ pc = p->p_comm; do { if (*pc < 33 || *pc > 126 || *pc == '\\') sbuf_printf(sb, "\\%03o", *pc); else sbuf_putc(sb, *pc); } while (*++pc); sbuf_printf(sb, " %d %d %d %d ", pid, ppid, pgid, sid); if ((p->p_flag & P_CONTROLT) && (tp = sess->s_ttyp)) sbuf_printf(sb, "%s ", devtoname(tp->t_dev)); else sbuf_printf(sb, "- "); sep = ""; if (sess->s_ttyvp) { sbuf_printf(sb, "%sctty", sep); sep = ","; } if (SESS_LEADER(p)) { sbuf_printf(sb, "%ssldr", sep); sep = ","; } SESS_UNLOCK(sess); if (*sep != ',') { sbuf_printf(sb, "noflags"); } tdfirst = FIRST_THREAD_IN_PROC(p); thread_lock(tdfirst); if (tdfirst->td_wchan != NULL) { KASSERT(tdfirst->td_wmesg != NULL, ("wchan %p has no wmesg", tdfirst->td_wchan)); wmesg = tdfirst->td_wmesg; } else wmesg = "nochan"; thread_unlock(tdfirst); if (p->p_flag & P_INMEM) { struct timeval start, ut, st; PROC_SLOCK(p); calcru(p, &ut, &st); PROC_SUNLOCK(p); start = p->p_stats->p_start; timevaladd(&start, &boottime); sbuf_printf(sb, " %jd,%ld %jd,%ld %jd,%ld", (intmax_t)start.tv_sec, start.tv_usec, (intmax_t)ut.tv_sec, ut.tv_usec, (intmax_t)st.tv_sec, st.tv_usec); } else sbuf_printf(sb, " -1,-1 -1,-1 -1,-1"); sbuf_printf(sb, " %s", wmesg); cr = p->p_ucred; sbuf_printf(sb, " %lu %lu %lu", (u_long)cr->cr_uid, (u_long)cr->cr_ruid, (u_long)cr->cr_rgid); /* egid (cr->cr_svgid) is equal to cr_ngroups[0] see also getegid(2) in /sys/kern/kern_prot.c */ for (i = 0; i < cr->cr_ngroups; i++) { sbuf_printf(sb, ",%lu", (u_long)cr->cr_groups[i]); } if (jailed(cr)) { mtx_lock(&cr->cr_prison->pr_mtx); sbuf_printf(sb, " %s", prison_name(td->td_ucred->cr_prison, cr->cr_prison)); mtx_unlock(&cr->cr_prison->pr_mtx); } else { sbuf_printf(sb, " -"); } PROC_UNLOCK(p); sbuf_printf(sb, "\n"); return (0); }
/* * Write out process accounting information, on process exit. * Data to be written out is specified in Leffler, et al. * and are enumerated below. (They're also noted in the system * "acct.h" header file.) */ int acct_process(struct proc *p) { struct acct acct; struct process *pr = p->p_p; struct rusage *r; struct timeval ut, st, tmp; int t; struct vnode *vp; struct plimit *oplim = NULL; int error; /* If accounting isn't enabled, don't bother */ vp = acctp; if (vp == NULL) return (0); /* * Raise the file limit so that accounting can't be stopped by the * user. (XXX - we should think about the cpu limit too). */ if (pr->ps_limit->p_refcnt > 1) { oplim = pr->ps_limit; pr->ps_limit = limcopy(pr->ps_limit); } p->p_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY; /* * Get process accounting information. */ /* (1) The name of the command that ran */ bcopy(p->p_comm, acct.ac_comm, sizeof acct.ac_comm); /* (2) The amount of user and system time that was used */ calcru(&pr->ps_tu, &ut, &st, NULL); acct.ac_utime = encode_comp_t(ut.tv_sec, ut.tv_usec); acct.ac_stime = encode_comp_t(st.tv_sec, st.tv_usec); /* (3) The elapsed time the command ran (and its starting time) */ acct.ac_btime = pr->ps_start.tv_sec; getmicrotime(&tmp); timersub(&tmp, &pr->ps_start, &tmp); acct.ac_etime = encode_comp_t(tmp.tv_sec, tmp.tv_usec); /* (4) The average amount of memory used */ r = &p->p_ru; timeradd(&ut, &st, &tmp); t = tmp.tv_sec * hz + tmp.tv_usec / tick; if (t) acct.ac_mem = (r->ru_ixrss + r->ru_idrss + r->ru_isrss) / t; else acct.ac_mem = 0; /* (5) The number of disk I/O operations done */ acct.ac_io = encode_comp_t(r->ru_inblock + r->ru_oublock, 0); /* (6) The UID and GID of the process */ acct.ac_uid = p->p_cred->p_ruid; acct.ac_gid = p->p_cred->p_rgid; /* (7) The terminal from which the process was started */ if ((pr->ps_flags & PS_CONTROLT) && pr->ps_pgrp->pg_session->s_ttyp) acct.ac_tty = pr->ps_pgrp->pg_session->s_ttyp->t_dev; else acct.ac_tty = NODEV; /* (8) The boolean flags that tell how the process terminated, etc. */ acct.ac_flag = pr->ps_acflag; /* * Now, just write the accounting information to the file. */ error = vn_rdwr(UIO_WRITE, vp, (caddr_t)&acct, sizeof (acct), (off_t)0, UIO_SYSSPACE, IO_APPEND|IO_UNIT, p->p_ucred, NULL, p); if (oplim) { limfree(pr->ps_limit); pr->ps_limit = oplim; } return error; }
/* * Linux compatible /proc/<pid>/stat. Only active when the -o linux * mountflag is used. */ int procfs_do_pid_stat(struct lwp *curl, struct lwp *l, struct pfsnode *pfs, struct uio *uio) { char *bf; struct proc *p = l->l_proc; int len; struct tty *tty = p->p_session->s_ttyp; struct rusage *ru = &p->p_stats->p_ru; struct rusage *cru = &p->p_stats->p_cru; unsigned long stext = 0, etext = 0, sstack = 0; struct timeval rt; struct vmspace *vm; int error = 0; bf = malloc(LBFSZ, M_TEMP, M_WAITOK); if ((error = proc_vmspace_getref(p, &vm)) != 0) { goto out; } get_proc_size_info(l, &stext, &etext, &sstack); mutex_enter(proc_lock); mutex_enter(p->p_lock); calcru(p, NULL, NULL, NULL, &rt); len = snprintf(bf, LBFSZ, "%d (%s) %c %d %d %d %lld %d " "%u " "%lu %lu %lu %lu %lu %lu %lu %lu " "%d %d %d " "%lld %lld %lu %lu %" PRIu64 " " "%lu %lu %lu " "%u %u " "%u %u %u %u " "%lu %lu %lu %d %d\n", p->p_pid, p->p_comm, "0IR3SZD"[(p->p_stat > 6) ? 0 : (int)p->p_stat], (p->p_pptr != NULL) ? p->p_pptr->p_pid : 0, p->p_pgid, p->p_session->s_sid, (unsigned long long)(tty ? tty->t_dev : 0), (tty && tty->t_pgrp) ? tty->t_pgrp->pg_id : 0, p->p_flag, ru->ru_minflt, cru->ru_minflt, ru->ru_majflt, cru->ru_majflt, (long)USEC_2_TICKS(ru->ru_utime.tv_usec), (long)USEC_2_TICKS(ru->ru_stime.tv_usec), (long)USEC_2_TICKS(cru->ru_utime.tv_usec), (long)USEC_2_TICKS(cru->ru_stime.tv_usec), l->l_priority, /* XXX: priority */ p->p_nice - 20, 0, (long long)rt.tv_sec, (long long)p->p_stats->p_start.tv_sec, (unsigned long)(vm->vm_tsize + vm->vm_dsize + vm->vm_ssize), /* size */ (unsigned long)(vm->vm_rssize), /* resident */ p->p_rlimit[RLIMIT_RSS].rlim_cur, stext, /* start code */ etext, /* end code */ sstack, /* mm start stack */ 0, /* XXX: pc */ 0, /* XXX: sp */ p->p_sigpend.sp_set.__bits[0], /* XXX: pending */ 0, /* XXX: held */ p->p_sigctx.ps_sigignore.__bits[0], /* ignored */ p->p_sigctx.ps_sigcatch.__bits[0], /* caught */ (unsigned long)(intptr_t)l->l_wchan, ru->ru_nvcsw, ru->ru_nivcsw, p->p_exitsig, 0); /* XXX: processor */ mutex_exit(p->p_lock); mutex_exit(proc_lock); uvmspace_free(vm); if (len == 0) goto out; error = uiomove_frombuf(bf, len, uio); out: free(bf, M_TEMP); return error; }
/* * Linux compatible /proc/<pid>/stat. Only active when the -o linux * mountflag is used. */ int procfs_do_pid_stat(struct lwp *curl, struct lwp *l, struct pfsnode *pfs, struct uio *uio) { char *bf; struct proc *p = l->l_proc; int len; struct rusage *cru = &p->p_stats->p_cru; unsigned long stext = 0, etext = 0, sstack = 0; struct timeval rt; struct vmspace *vm; struct kinfo_proc2 ki; int error = 0; bf = malloc(LBFSZ, M_TEMP, M_WAITOK); if ((error = proc_vmspace_getref(p, &vm)) != 0) { goto out; } get_proc_size_info(l, &stext, &etext, &sstack); mutex_enter(proc_lock); mutex_enter(p->p_lock); fill_kproc2(p, &ki, false); calcru(p, NULL, NULL, NULL, &rt); len = snprintf(bf, LBFSZ, "%d (%s) %c %d %d %d %u %d " "%u " "%"PRIu64" %lu %"PRIu64" %lu %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64" " "%d %d %"PRIu64" " "%lld %"PRIu64" %"PRId64" %lu %"PRIu64" " "%lu %lu %lu " "%u %u " "%u %u %u %u " "%"PRIu64" %"PRIu64" %"PRIu64" %d %"PRIu64"\n", ki.p_pid, /* 1 pid */ ki.p_comm, /* 2 tcomm */ "0RRSTZXR8"[(ki.p_stat > 8) ? 0 : (int)ki.p_stat], /* 3 state */ ki.p_ppid, /* 4 ppid */ ki.p__pgid, /* 5 pgrp */ ki.p_sid, /* 6 sid */ (ki.p_tdev != (uint32_t)NODEV) ? ki.p_tdev : 0, /* 7 tty_nr */ ki.p_tpgid, /* 8 tty_pgrp */ ki.p_flag, /* 9 flags */ ki.p_uru_minflt, /* 10 min_flt */ cru->ru_minflt, ki.p_uru_majflt, /* 12 maj_flt */ cru->ru_majflt, UTIME2TICKS(ki.p_uutime_sec, ki.p_uutime_usec), /* 14 utime */ UTIME2TICKS(ki.p_ustime_sec, ki.p_ustime_usec), /* 15 stime */ UTIME2TICKS(cru->ru_utime.tv_sec, cru->ru_utime.tv_usec), /* 16 cutime */ UTIME2TICKS(cru->ru_stime.tv_sec, cru->ru_stime.tv_usec), /* 17 cstime */ ki.p_priority, /* XXX: 18 priority */ ki.p_nice - NZERO, /* 19 nice */ ki.p_nlwps, /* 20 num_threads */ (long long)rt.tv_sec, UTIME2TICKS(ki.p_ustart_sec, ki.p_ustart_usec), /* 22 start_time */ ki.p_vm_msize, /* 23 vsize */ PGTOKB(ki.p_vm_rssize), /* 24 rss */ p->p_rlimit[RLIMIT_RSS].rlim_cur, /* 25 rsslim */ stext, /* 26 start_code */ etext, /* 27 end_code */ sstack, /* 28 start_stack */ 0, /* XXX: 29 esp */ 0, /* XXX: 30 eip */ ki.p_siglist.__bits[0], /* XXX: 31 pending */ 0, /* XXX: 32 blocked */ ki.p_sigignore.__bits[0], /* 33 sigign */ ki.p_sigcatch.__bits[0], /* 34 sigcatch */ ki.p_wchan, /* 35 wchan */ ki.p_uru_nvcsw, ki.p_uru_nivcsw, ki.p_exitsig, /* 38 exit_signal */ ki.p_cpuid); /* 39 task_cpu */ mutex_exit(p->p_lock); mutex_exit(proc_lock); uvmspace_free(vm); if (len == 0) goto out; error = uiomove_frombuf(bf, len, uio); out: free(bf, M_TEMP); return error; }
/* * Write out process accounting information, on process exit. * Data to be written out is specified in Leffler, et al. * and are enumerated below. (They're also noted in the system * "acct.h" header file.) */ int acct_process(proc_t p) { struct acct an_acct; struct rusage rup, *r; struct timeval ut, st, tmp; int t; int error; struct vnode *vp; kauth_cred_t safecred; struct session * sessp; boolean_t fstate; /* If accounting isn't enabled, don't bother */ vp = acctp; if (vp == NULLVP) return (0); /* * Get process accounting information. */ /* (1) The name of the command that ran */ bcopy(p->p_comm, an_acct.ac_comm, sizeof an_acct.ac_comm); /* (2) The amount of user and system time that was used */ calcru(p, &ut, &st, NULL); an_acct.ac_utime = encode_comp_t(ut.tv_sec, ut.tv_usec); an_acct.ac_stime = encode_comp_t(st.tv_sec, st.tv_usec); /* (3) The elapsed time the commmand ran (and its starting time) */ an_acct.ac_btime = p->p_start.tv_sec; microtime(&tmp); timevalsub(&tmp, &p->p_start); an_acct.ac_etime = encode_comp_t(tmp.tv_sec, tmp.tv_usec); /* (4) The average amount of memory used */ proc_lock(p); rup = p->p_stats->p_ru; proc_unlock(p); r = &rup; tmp = ut; timevaladd(&tmp, &st); t = tmp.tv_sec * hz + tmp.tv_usec / tick; if (t) an_acct.ac_mem = (r->ru_ixrss + r->ru_idrss + r->ru_isrss) / t; else an_acct.ac_mem = 0; /* (5) The number of disk I/O operations done */ an_acct.ac_io = encode_comp_t(r->ru_inblock + r->ru_oublock, 0); /* (6) The UID and GID of the process */ safecred = kauth_cred_proc_ref(p); an_acct.ac_uid = safecred->cr_ruid; an_acct.ac_gid = safecred->cr_rgid; /* (7) The terminal from which the process was started */ sessp = proc_session(p); if ((p->p_flag & P_CONTROLT) && (sessp != SESSION_NULL) && (sessp->s_ttyp != TTY_NULL)) { fstate = thread_funnel_set(kernel_flock, TRUE); an_acct.ac_tty = sessp->s_ttyp->t_dev; (void) thread_funnel_set(kernel_flock, fstate); }else an_acct.ac_tty = NODEV; if (sessp != SESSION_NULL) session_rele(sessp); /* (8) The boolean flags that tell how the process terminated, etc. */ an_acct.ac_flag = p->p_acflag; /* * Now, just write the accounting information to the file. */ if ((error = vnode_getwithref(vp)) == 0) { error = vn_rdwr(UIO_WRITE, vp, (caddr_t)&an_acct, sizeof (an_acct), (off_t)0, UIO_SYSSPACE32, IO_APPEND|IO_UNIT, safecred, (int *)0, p); vnode_put(vp); } kauth_cred_unref(&safecred); return (error); }