diff --git a/lib/libprocstat/Symbol.map b/lib/libprocstat/Symbol.map --- a/lib/libprocstat/Symbol.map +++ b/lib/libprocstat/Symbol.map @@ -47,4 +47,9 @@ FBSD_1.7 { procstat_getadvlock; procstat_freeadvlock; +}; + +FBSD_1.8 { + procstat_getlimresusage; + procstat_freelimresusage; }; \ No newline at end of file diff --git a/lib/libprocstat/libprocstat.h b/lib/libprocstat/libprocstat.h --- a/lib/libprocstat/libprocstat.h +++ b/lib/libprocstat/libprocstat.h @@ -211,6 +211,7 @@ struct filestat_list *head); void procstat_freeptlwpinfo(struct procstat *procstat, struct ptrace_lwpinfo *pl); +void procstat_freelimresusage(struct procstat *procstat, rlim_t *resusage); void procstat_freevmmap(struct procstat *procstat, struct kinfo_vmentry *vmmap); struct advlock_list *procstat_getadvlock(struct procstat *procstat); @@ -250,6 +251,8 @@ char *pathname, size_t maxlen); int procstat_getrlimit(struct procstat *procstat, struct kinfo_proc *kp, int which, struct rlimit* rlimit); +rlim_t *procstat_getlimresusage(struct procstat *procstat, + struct kinfo_proc *kp, unsigned int *cntp); int procstat_getumask(struct procstat *procstat, struct kinfo_proc *kp, unsigned short* umask); struct kinfo_vmentry *procstat_getvmmap(struct procstat *procstat, diff --git a/lib/libprocstat/libprocstat.c b/lib/libprocstat/libprocstat.c --- a/lib/libprocstat/libprocstat.c +++ b/lib/libprocstat/libprocstat.c @@ -2763,3 +2763,56 @@ free(lst); } +static rlim_t * +procstat_getlimresusage_sysctl(pid_t pid, unsigned *cntp) +{ + int error, name[4]; + rlim_t *val; + size_t len; + + name[0] = CTL_KERN; + name[1] = KERN_PROC; + name[2] = KERN_PROC_RES_USAGE; + name[3] = pid; + + len = 0; + error = sysctl(name, nitems(name), NULL, &len, NULL, 0); + if (error == -1) + return (NULL); + val = malloc(len); + if (val == NULL) + return (NULL); + + error = sysctl(name, nitems(name), val, &len, NULL, 0); + if (error == -1) { + free(val); + return (NULL); + } + *cntp = len / sizeof(rlim_t); + return (val); +} + +rlim_t * +procstat_getlimresusage(struct procstat *procstat, struct kinfo_proc *kp, + unsigned int *cntp) +{ + switch (procstat->type) { + case PROCSTAT_KVM: + warnx("kvm method is not supported"); + return (NULL); + case PROCSTAT_SYSCTL: + return (procstat_getlimresusage_sysctl(kp->ki_pid, cntp)); + case PROCSTAT_CORE: + warnx("core method is not supported"); + return (NULL); + default: + warnx("unknown access method: %d", procstat->type); + return (NULL); + } +} + +void +procstat_freelimresusage(struct procstat *procstat __unused, rlim_t *resusage) +{ + free(resusage); +} diff --git a/lib/libsys/Symbol.sys.map b/lib/libsys/Symbol.sys.map --- a/lib/libsys/Symbol.sys.map +++ b/lib/libsys/Symbol.sys.map @@ -380,6 +380,7 @@ FBSD_1.8 { kcmp; + getrlimusage; }; FBSDprivate_1.0 { diff --git a/lib/libsys/_libsys.h b/lib/libsys/_libsys.h --- a/lib/libsys/_libsys.h +++ b/lib/libsys/_libsys.h @@ -461,6 +461,7 @@ typedef int (__sys_timerfd_gettime_t)(int, struct itimerspec *); typedef int (__sys_timerfd_settime_t)(int, int, const struct itimerspec *, struct itimerspec *); typedef int (__sys_kcmp_t)(pid_t, pid_t, int, uintptr_t, uintptr_t); +typedef int (__sys_getrlimusage_t)(u_int, int, rlim_t *); void __sys_exit(int rval); int __sys_fork(void); @@ -860,6 +861,7 @@ int __sys_timerfd_gettime(int fd, struct itimerspec * curr_value); int __sys_timerfd_settime(int fd, int flags, const struct itimerspec * new_value, struct itimerspec * old_value); int __sys_kcmp(pid_t pid1, pid_t pid2, int type, uintptr_t idx1, uintptr_t idx2); +int __sys_getrlimusage(u_int which, int flags, rlim_t * res); __END_DECLS #endif /* __LIBSYS_H_ */ diff --git a/lib/libsys/syscalls.map b/lib/libsys/syscalls.map --- a/lib/libsys/syscalls.map +++ b/lib/libsys/syscalls.map @@ -801,4 +801,6 @@ __sys_timerfd_settime; _kcmp; __sys_kcmp; + _getrlimusage; + __sys_getrlimusage; }; diff --git a/sys/compat/freebsd32/freebsd32_syscall.h b/sys/compat/freebsd32/freebsd32_syscall.h --- a/sys/compat/freebsd32/freebsd32_syscall.h +++ b/sys/compat/freebsd32/freebsd32_syscall.h @@ -507,4 +507,5 @@ #define FREEBSD32_SYS_freebsd32_timerfd_gettime 586 #define FREEBSD32_SYS_freebsd32_timerfd_settime 587 #define FREEBSD32_SYS_kcmp 588 -#define FREEBSD32_SYS_MAXSYSCALL 589 +#define FREEBSD32_SYS_getrlimusage 589 +#define FREEBSD32_SYS_MAXSYSCALL 590 diff --git a/sys/compat/freebsd32/freebsd32_syscalls.c b/sys/compat/freebsd32/freebsd32_syscalls.c --- a/sys/compat/freebsd32/freebsd32_syscalls.c +++ b/sys/compat/freebsd32/freebsd32_syscalls.c @@ -594,4 +594,5 @@ "freebsd32_timerfd_gettime", /* 586 = freebsd32_timerfd_gettime */ "freebsd32_timerfd_settime", /* 587 = freebsd32_timerfd_settime */ "kcmp", /* 588 = kcmp */ + "getrlimusage", /* 589 = getrlimusage */ }; diff --git a/sys/compat/freebsd32/freebsd32_sysent.c b/sys/compat/freebsd32/freebsd32_sysent.c --- a/sys/compat/freebsd32/freebsd32_sysent.c +++ b/sys/compat/freebsd32/freebsd32_sysent.c @@ -650,4 +650,5 @@ { .sy_narg = AS(freebsd32_timerfd_gettime_args), .sy_call = (sy_call_t *)freebsd32_timerfd_gettime, .sy_auevent = AUE_TIMERFD, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 586 = freebsd32_timerfd_gettime */ { .sy_narg = AS(freebsd32_timerfd_settime_args), .sy_call = (sy_call_t *)freebsd32_timerfd_settime, .sy_auevent = AUE_TIMERFD, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 587 = freebsd32_timerfd_settime */ { .sy_narg = AS(kcmp_args), .sy_call = (sy_call_t *)sys_kcmp, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 588 = kcmp */ + { .sy_narg = AS(getrlimusage_args), .sy_call = (sy_call_t *)sys_getrlimusage, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 589 = getrlimusage */ }; diff --git a/sys/compat/freebsd32/freebsd32_systrace_args.c b/sys/compat/freebsd32/freebsd32_systrace_args.c --- a/sys/compat/freebsd32/freebsd32_systrace_args.c +++ b/sys/compat/freebsd32/freebsd32_systrace_args.c @@ -3368,6 +3368,15 @@ *n_args = 5; break; } + /* getrlimusage */ + case 589: { + struct getrlimusage_args *p = params; + uarg[a++] = p->which; /* u_int */ + iarg[a++] = p->flags; /* int */ + uarg[a++] = (intptr_t)p->res; /* rlim_t * */ + *n_args = 3; + break; + } default: *n_args = 0; break; @@ -9100,6 +9109,22 @@ break; }; break; + /* getrlimusage */ + case 589: + switch (ndx) { + case 0: + p = "u_int"; + break; + case 1: + p = "int"; + break; + case 2: + p = "userland rlim_t *"; + break; + default: + break; + }; + break; default: break; }; @@ -10983,6 +11008,11 @@ if (ndx == 0 || ndx == 1) p = "int"; break; + /* getrlimusage */ + case 589: + if (ndx == 0 || ndx == 1) + p = "int"; + break; default: break; }; diff --git a/sys/kern/init_sysent.c b/sys/kern/init_sysent.c --- a/sys/kern/init_sysent.c +++ b/sys/kern/init_sysent.c @@ -649,4 +649,5 @@ { .sy_narg = AS(timerfd_gettime_args), .sy_call = (sy_call_t *)sys_timerfd_gettime, .sy_auevent = AUE_TIMERFD, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 586 = timerfd_gettime */ { .sy_narg = AS(timerfd_settime_args), .sy_call = (sy_call_t *)sys_timerfd_settime, .sy_auevent = AUE_TIMERFD, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 587 = timerfd_settime */ { .sy_narg = AS(kcmp_args), .sy_call = (sy_call_t *)sys_kcmp, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 588 = kcmp */ + { .sy_narg = AS(getrlimusage_args), .sy_call = (sy_call_t *)sys_getrlimusage, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 589 = getrlimusage */ }; diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -4329,21 +4329,13 @@ } static int -sysctl_kern_proc_nfds(SYSCTL_HANDLER_ARGS) +filedesc_nfiles(struct filedesc *fdp) { NDSLOTTYPE *map; - struct filedesc *fdp; - u_int namelen; int count, off, minoff; - namelen = arg2; - if (namelen != 1) - return (EINVAL); - - if (*(int *)arg1 != 0) - return (EINVAL); - - fdp = curproc->p_fd; + if (fdp == NULL) + return (0); count = 0; FILEDESC_SLOCK(fdp); map = fdp->fd_map; @@ -4351,7 +4343,37 @@ for (minoff = NDSLOT(0); off >= minoff; --off) count += bitcountl(map[off]); FILEDESC_SUNLOCK(fdp); + return (count); +} + +int +proc_nfiles(struct proc *p) +{ + struct filedesc *fdp; + int res; + + PROC_LOCK(p); + fdp = fdhold(p); + PROC_UNLOCK(p); + res = filedesc_nfiles(fdp); + fddrop(fdp); + return (res); +} + +static int +sysctl_kern_proc_nfds(SYSCTL_HANDLER_ARGS) +{ + u_int namelen; + int count; + + namelen = arg2; + if (namelen != 1) + return (EINVAL); + + if (*(int *)arg1 != 0) + return (EINVAL); + count = filedesc_nfiles(curproc->p_fd); return (SYSCTL_OUT(req, &count, sizeof(count))); } diff --git a/sys/kern/kern_resource.c b/sys/kern/kern_resource.c --- a/sys/kern/kern_resource.c +++ b/sys/kern/kern_resource.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -60,6 +61,7 @@ #include #include #include +#include static MALLOC_DEFINE(M_PLIMIT, "plimit", "plimit structures"); static MALLOC_DEFINE(M_UIDINFO, "uidinfo", "uidinfo structures"); @@ -804,6 +806,104 @@ return (error); } +static int +getrlimusage_one(struct thread *td, struct proc *p, u_int which, int flags, + rlim_t *res) +{ + struct uidinfo *ui; + struct vmspace *vm; + uid_t uid; + int error; + + error = 0; + PROC_LOCK(p); + uid = (flags & GETRLIMUSAGE_EUID) == 0 ? p->p_ucred->cr_ruid : + p->p_ucred->cr_uid; + PROC_UNLOCK(p); + + ui = uifind(uid); + vm = vmspace_acquire_ref(p); + + switch (which) { + case RLIMIT_CPU: + PROC_LOCK(p); + PROC_STATLOCK(p); + FOREACH_THREAD_IN_PROC(p, td) + ruxagg(p, td); + PROC_STATUNLOCK(p); + *res = p->p_rux.rux_runtime / cpu_tickrate(); + PROC_UNLOCK(p); + break; + case RLIMIT_FSIZE: + error = ENXIO; + break; + case RLIMIT_DATA: + *res = vm->vm_dsize * PAGE_SIZE; + break; + case RLIMIT_STACK: + *res = vm->vm_ssize * PAGE_SIZE; + break; + case RLIMIT_CORE: + error = ENXIO; + break; + case RLIMIT_RSS: + *res = vmspace_resident_count(vm) * PAGE_SIZE; + break; + case RLIMIT_MEMLOCK: + *res = pmap_wired_count(vmspace_pmap(vm)) * PAGE_SIZE; + break; + case RLIMIT_NPROC: + *res = ui->ui_proccnt; + break; + case RLIMIT_NOFILE: + *res = proc_nfiles(p); + break; + case RLIMIT_SBSIZE: + *res = ui->ui_sbsize; + break; + case RLIMIT_VMEM: + *res = vm->vm_map.size; + break; + case RLIMIT_NPTS: + *res = ui->ui_ptscnt; + break; + case RLIMIT_SWAP: + *res = ui->ui_vmsize; + break; + case RLIMIT_KQUEUES: + *res = ui->ui_kqcnt; + break; + case RLIMIT_UMTXP: + *res = ui->ui_umtxcnt; + break; + case RLIMIT_PIPEBUF: + *res = ui->ui_pipecnt; + break; + default: + error = EINVAL; + break; + } + + vmspace_free(vm); + uifree(ui); + return (error); +} + +int +sys_getrlimusage(struct thread *td, struct getrlimusage_args *uap) +{ + rlim_t res; + int error; + + if ((uap->flags & ~(GETRLIMUSAGE_EUID)) != 0) + return (EINVAL); + error = getrlimusage_one(td, curproc, uap->which, uap->flags, + &res); + if (error == 0) + error = copyout(&res, uap->res, sizeof(res)); + return (error); +} + /* * Transform the running time and tick information for children of proc p * into user and system time usage. @@ -1626,3 +1726,41 @@ return (chglimit(uip, &uip->ui_pipecnt, diff, max, "pipecnt")); } + +static int +sysctl_kern_proc_res_usage(SYSCTL_HANDLER_ARGS) +{ + rlim_t resval[RLIM_NLIMITS]; + struct proc *p; + int error, *name, i; + + name = (int *)arg1; + if ((u_int)arg2 != 1) + return (EINVAL); + if (req->newptr != NULL) + return (EINVAL); + + error = pget((pid_t)name[0], PGET_WANTREAD, &p); + if (error != 0) + return (error); + + memset(resval, 0, sizeof(resval)); + for (i = 0; i < RLIM_NLIMITS; i++) { + error = getrlimusage_one(curthread, p, (unsigned)i, + 0, &resval[i]); + if (error == ENXIO) { + resval[i] = -1; + error = 0; + } else if (error != 0) { + break; + } + } + + if (error == 0) + error = SYSCTL_OUT(req, resval, sizeof(resval)); + PRELE(p); + return (error); +} +static SYSCTL_NODE(_kern_proc, KERN_PROC_RES_USAGE, res_usage, CTLFLAG_RD | + CTLFLAG_ANYBODY | CTLFLAG_MPSAFE, sysctl_kern_proc_res_usage, + "Process limited resources usage info"); diff --git a/sys/kern/syscalls.c b/sys/kern/syscalls.c --- a/sys/kern/syscalls.c +++ b/sys/kern/syscalls.c @@ -594,4 +594,5 @@ "timerfd_gettime", /* 586 = timerfd_gettime */ "timerfd_settime", /* 587 = timerfd_settime */ "kcmp", /* 588 = kcmp */ + "getrlimusage", /* 589 = getrlimusage */ }; diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -3333,5 +3333,12 @@ uintptr_t idx2 ); } +589 AUE_NULL STD|CAPENABLED { + int getrlimusage( + u_int which, + int flags, + _Out_ rlim_t *res + ); + } ; vim: syntax=off diff --git a/sys/kern/systrace_args.c b/sys/kern/systrace_args.c --- a/sys/kern/systrace_args.c +++ b/sys/kern/systrace_args.c @@ -3455,6 +3455,15 @@ *n_args = 5; break; } + /* getrlimusage */ + case 589: { + struct getrlimusage_args *p = params; + uarg[a++] = p->which; /* u_int */ + iarg[a++] = p->flags; /* int */ + uarg[a++] = (intptr_t)p->res; /* rlim_t * */ + *n_args = 3; + break; + } default: *n_args = 0; break; @@ -9245,6 +9254,22 @@ break; }; break; + /* getrlimusage */ + case 589: + switch (ndx) { + case 0: + p = "u_int"; + break; + case 1: + p = "int"; + break; + case 2: + p = "userland rlim_t *"; + break; + default: + break; + }; + break; default: break; }; @@ -11218,6 +11243,11 @@ if (ndx == 0 || ndx == 1) p = "int"; break; + /* getrlimusage */ + case 589: + if (ndx == 0 || ndx == 1) + p = "int"; + break; default: break; }; diff --git a/sys/sys/filedesc.h b/sys/sys/filedesc.h --- a/sys/sys/filedesc.h +++ b/sys/sys/filedesc.h @@ -335,6 +335,8 @@ } #endif +int proc_nfiles(struct proc *p); + /* cdir/rdir/jdir manipulation functions. */ struct pwddesc *pdcopy(struct pwddesc *pdp); void pdescfree(struct thread *td); diff --git a/sys/sys/resource.h b/sys/sys/resource.h --- a/sys/sys/resource.h +++ b/sys/sys/resource.h @@ -171,6 +171,9 @@ #define CP_IDLE 4 #define CPUSTATES 5 +/* getrlimusage flags */ +#define GETRLIMUSAGE_EUID 0x0001 + #endif /* __BSD_VISIBLE */ #ifdef _KERNEL @@ -187,6 +190,9 @@ int getrusage(int, struct rusage *); int setpriority(int, int, int); int setrlimit(int, const struct rlimit *); +#if __BSD_VISIBLE +int getrlimusage(unsigned which, int flags, rlim_t *res); +#endif __END_DECLS #endif /* _KERNEL */ diff --git a/sys/sys/syscall.h b/sys/sys/syscall.h --- a/sys/sys/syscall.h +++ b/sys/sys/syscall.h @@ -525,4 +525,5 @@ #define SYS_timerfd_gettime 586 #define SYS_timerfd_settime 587 #define SYS_kcmp 588 -#define SYS_MAXSYSCALL 589 +#define SYS_getrlimusage 589 +#define SYS_MAXSYSCALL 590 diff --git a/sys/sys/syscall.mk b/sys/sys/syscall.mk --- a/sys/sys/syscall.mk +++ b/sys/sys/syscall.mk @@ -428,4 +428,5 @@ timerfd_create.o \ timerfd_gettime.o \ timerfd_settime.o \ - kcmp.o + kcmp.o \ + getrlimusage.o diff --git a/sys/sys/sysctl.h b/sys/sys/sysctl.h --- a/sys/sys/sysctl.h +++ b/sys/sys/sysctl.h @@ -1040,6 +1040,8 @@ #define KERN_PROC_NFDS 43 /* number of open file descriptors */ #define KERN_PROC_SIGFASTBLK 44 /* address of fastsigblk magic word */ #define KERN_PROC_VM_LAYOUT 45 /* virtual address space layout info */ +#define KERN_PROC_RES_USAGE 46 /* array of rlim_t */ + /* * KERN_IPC identifiers diff --git a/sys/sys/sysproto.h b/sys/sys/sysproto.h --- a/sys/sys/sysproto.h +++ b/sys/sys/sysproto.h @@ -1877,6 +1877,11 @@ char idx1_l_[PADL_(uintptr_t)]; uintptr_t idx1; char idx1_r_[PADR_(uintptr_t)]; char idx2_l_[PADL_(uintptr_t)]; uintptr_t idx2; char idx2_r_[PADR_(uintptr_t)]; }; +struct getrlimusage_args { + char which_l_[PADL_(u_int)]; u_int which; char which_r_[PADR_(u_int)]; + char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)]; + char res_l_[PADL_(rlim_t *)]; rlim_t * res; char res_r_[PADR_(rlim_t *)]; +}; int sys_exit(struct thread *, struct exit_args *); int sys_fork(struct thread *, struct fork_args *); int sys_read(struct thread *, struct read_args *); @@ -2276,6 +2281,7 @@ int sys_timerfd_gettime(struct thread *, struct timerfd_gettime_args *); int sys_timerfd_settime(struct thread *, struct timerfd_settime_args *); int sys_kcmp(struct thread *, struct kcmp_args *); +int sys_getrlimusage(struct thread *, struct getrlimusage_args *); #ifdef COMPAT_43 @@ -3255,6 +3261,7 @@ #define SYS_AUE_timerfd_gettime AUE_TIMERFD #define SYS_AUE_timerfd_settime AUE_TIMERFD #define SYS_AUE_kcmp AUE_NULL +#define SYS_AUE_getrlimusage AUE_NULL #undef PAD_ #undef PADL_ diff --git a/usr.bin/procstat/Makefile b/usr.bin/procstat/Makefile --- a/usr.bin/procstat/Makefile +++ b/usr.bin/procstat/Makefile @@ -12,6 +12,7 @@ procstat_cs.c \ procstat_files.c \ procstat_kstack.c \ + procstat_limresusage.c \ procstat_penv.c \ procstat_ptlwpinfo.c \ procstat_pwdx.c \ diff --git a/usr.bin/procstat/procstat.h b/usr.bin/procstat/procstat.h --- a/usr.bin/procstat/procstat.h +++ b/usr.bin/procstat/procstat.h @@ -65,6 +65,8 @@ void procstat_env(struct procstat *prstat, struct kinfo_proc *kipp); void procstat_files(struct procstat *prstat, struct kinfo_proc *kipp); void procstat_kstack(struct procstat *prstat, struct kinfo_proc *kipp); +void procstat_limresusage(struct procstat *procstat, + struct kinfo_proc *kipp); void procstat_pargs(struct procstat *prstat, struct kinfo_proc *kipp); void procstat_penv(struct procstat *prstat, struct kinfo_proc *kipp); void procstat_ptlwpinfo(struct procstat *prstat, struct kinfo_proc *kipp); diff --git a/usr.bin/procstat/procstat.c b/usr.bin/procstat/procstat.c --- a/usr.bin/procstat/procstat.c +++ b/usr.bin/procstat/procstat.c @@ -105,6 +105,8 @@ PS_CMP_PLURAL }, { "kstack", "kstack", "[-v]", &procstat_kstack, &cmdopt_verbose, PS_CMP_NORMAL }, + { "limresusage", "limresusage", NULL, &procstat_limresusage, + &cmdopt_none, PS_CMP_NORMAL }, { "pargs", "args", NULL, &procstat_pargs, &cmdopt_none, PS_CMP_NORMAL }, { "penv", "env", NULL, &procstat_penv, &cmdopt_none, diff --git a/usr.bin/procstat/procstat_limresusage.c b/usr.bin/procstat/procstat_limresusage.c new file mode 100644 --- /dev/null +++ b/usr.bin/procstat/procstat_limresusage.c @@ -0,0 +1,76 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2024 The FreeBSD Foundation + * + * This software was developed by Konstantin Belousov + * under sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#define _RLIMIT_IDENT +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "procstat.h" + +static const char ru[] = "resource_usage"; + +void +procstat_limresusage(struct procstat *procstat, struct kinfo_proc *kipp) +{ + rlim_t *resuse; + unsigned int cnt, i; + + if ((procstat_opts & PS_OPT_NOHEADER) == 0) + xo_emit("{T:/%7s %12s %4s %18s}\n", + "PID", "RESOURCE", "ID", "USAGE"); + + xo_emit("{ek:process_id/%d}", kipp->ki_pid); + + resuse = procstat_getlimresusage(procstat, kipp, &cnt); + if (resuse == NULL) + return; + xo_open_list(ru); + for (i = 0; i < cnt; i++) { + xo_open_instance("ru"); + xo_emit("{dk:process_id/%7d} ", kipp->ki_pid); + xo_emit("{:resource/%12s}", i < nitems(rlimit_ident) ? + rlimit_ident[i] : "unknown"); + xo_emit("{:resid/%5d} ", i); + xo_emit("{:usage/%jd\n} ", (intmax_t)resuse[i]); + xo_close_instance("ru"); + } + xo_close_list(ru); + procstat_freelimresusage(procstat, resuse); +}