1221807Sstas/*- 2221807Sstas * Copyright (c) 2009 Stanislav Sedov <stas@FreeBSD.org> 3221807Sstas * Copyright (c) 1988, 1993 4221807Sstas * The Regents of the University of California. All rights reserved. 5221807Sstas * 6221807Sstas * Redistribution and use in source and binary forms, with or without 7221807Sstas * modification, are permitted provided that the following conditions 8221807Sstas * are met: 9221807Sstas * 1. Redistributions of source code must retain the above copyright 10221807Sstas * notice, this list of conditions and the following disclaimer. 11221807Sstas * 2. Redistributions in binary form must reproduce the above copyright 12221807Sstas * notice, this list of conditions and the following disclaimer in the 13221807Sstas * documentation and/or other materials provided with the distribution. 14221807Sstas * 3. All advertising materials mentioning features or use of this software 15221807Sstas * must display the following acknowledgement: 16221807Sstas * This product includes software developed by the University of 17221807Sstas * California, Berkeley and its contributors. 18221807Sstas * 4. Neither the name of the University nor the names of its contributors 19221807Sstas * may be used to endorse or promote products derived from this software 20221807Sstas * without specific prior written permission. 21221807Sstas * 22221807Sstas * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23221807Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24221807Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25221807Sstas * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26221807Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27221807Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28221807Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29221807Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30221807Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31221807Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32221807Sstas * SUCH DAMAGE. 33221807Sstas */ 34221807Sstas 35221807Sstas#include <sys/cdefs.h> 36221807Sstas__FBSDID("$FreeBSD: stable/10/lib/libprocstat/libprocstat.c 312036 2017-01-13 08:42:11Z ngie $"); 37221807Sstas 38221807Sstas#include <sys/param.h> 39249681Strociny#include <sys/elf.h> 40221807Sstas#include <sys/time.h> 41249674Strociny#include <sys/resourcevar.h> 42250146Strociny#define _WANT_UCRED 43250146Strociny#include <sys/ucred.h> 44250146Strociny#undef _WANT_UCRED 45221807Sstas#include <sys/proc.h> 46221807Sstas#include <sys/user.h> 47221807Sstas#include <sys/stat.h> 48221807Sstas#include <sys/vnode.h> 49221807Sstas#include <sys/socket.h> 50221807Sstas#include <sys/socketvar.h> 51221807Sstas#include <sys/domain.h> 52221807Sstas#include <sys/protosw.h> 53221807Sstas#include <sys/un.h> 54221807Sstas#include <sys/unpcb.h> 55221807Sstas#include <sys/sysctl.h> 56221807Sstas#include <sys/tty.h> 57221807Sstas#include <sys/filedesc.h> 58221807Sstas#include <sys/queue.h> 59221807Sstas#define _WANT_FILE 60221807Sstas#include <sys/file.h> 61221807Sstas#include <sys/conf.h> 62250223Sjhb#include <sys/ksem.h> 63233760Sjhb#include <sys/mman.h> 64280250Srwatson#include <sys/capsicum.h> 65221807Sstas#define _KERNEL 66221807Sstas#include <sys/mount.h> 67221807Sstas#include <sys/pipe.h> 68221807Sstas#include <ufs/ufs/quota.h> 69221807Sstas#include <ufs/ufs/inode.h> 70221807Sstas#include <fs/devfs/devfs.h> 71221807Sstas#include <fs/devfs/devfs_int.h> 72221807Sstas#undef _KERNEL 73221807Sstas#include <nfs/nfsproto.h> 74221807Sstas#include <nfsclient/nfs.h> 75221807Sstas#include <nfsclient/nfsnode.h> 76221807Sstas 77221807Sstas#include <vm/vm.h> 78221807Sstas#include <vm/vm_map.h> 79221807Sstas#include <vm/vm_object.h> 80221807Sstas 81221807Sstas#include <net/route.h> 82221807Sstas#include <netinet/in.h> 83221807Sstas#include <netinet/in_systm.h> 84221807Sstas#include <netinet/ip.h> 85221807Sstas#include <netinet/in_pcb.h> 86221807Sstas 87221807Sstas#include <assert.h> 88221807Sstas#include <ctype.h> 89221807Sstas#include <err.h> 90221807Sstas#include <fcntl.h> 91221807Sstas#include <kvm.h> 92221807Sstas#include <libutil.h> 93221807Sstas#include <limits.h> 94221807Sstas#include <paths.h> 95221807Sstas#include <pwd.h> 96221807Sstas#include <stdio.h> 97221807Sstas#include <stdlib.h> 98221807Sstas#include <stddef.h> 99221807Sstas#include <string.h> 100221807Sstas#include <unistd.h> 101221807Sstas#include <netdb.h> 102221807Sstas 103221807Sstas#include <libprocstat.h> 104221807Sstas#include "libprocstat_internal.h" 105221807Sstas#include "common_kvm.h" 106249666Strociny#include "core.h" 107221807Sstas 108221807Sstasint statfs(const char *, struct statfs *); /* XXX */ 109221807Sstas 110221807Sstas#define PROCSTAT_KVM 1 111221807Sstas#define PROCSTAT_SYSCTL 2 112249666Strociny#define PROCSTAT_CORE 3 113221807Sstas 114249679Strocinystatic char **getargv(struct procstat *procstat, struct kinfo_proc *kp, 115249679Strociny size_t nchr, int env); 116221807Sstasstatic char *getmnton(kvm_t *kd, struct mount *m); 117249667Strocinystatic struct kinfo_vmentry * kinfo_getvmmap_core(struct procstat_core *core, 118249667Strociny int *cntp); 119249681Strocinystatic Elf_Auxinfo *procstat_getauxv_core(struct procstat_core *core, 120249681Strociny unsigned int *cntp); 121249681Strocinystatic Elf_Auxinfo *procstat_getauxv_sysctl(pid_t pid, unsigned int *cntp); 122221807Sstasstatic struct filestat_list *procstat_getfiles_kvm( 123221807Sstas struct procstat *procstat, struct kinfo_proc *kp, int mmapped); 124221807Sstasstatic struct filestat_list *procstat_getfiles_sysctl( 125221807Sstas struct procstat *procstat, struct kinfo_proc *kp, int mmapped); 126221807Sstasstatic int procstat_get_pipe_info_sysctl(struct filestat *fst, 127221807Sstas struct pipestat *pipe, char *errbuf); 128221807Sstasstatic int procstat_get_pipe_info_kvm(kvm_t *kd, struct filestat *fst, 129221807Sstas struct pipestat *pipe, char *errbuf); 130221807Sstasstatic int procstat_get_pts_info_sysctl(struct filestat *fst, 131221807Sstas struct ptsstat *pts, char *errbuf); 132221807Sstasstatic int procstat_get_pts_info_kvm(kvm_t *kd, struct filestat *fst, 133221807Sstas struct ptsstat *pts, char *errbuf); 134250223Sjhbstatic int procstat_get_sem_info_sysctl(struct filestat *fst, 135250223Sjhb struct semstat *sem, char *errbuf); 136250223Sjhbstatic int procstat_get_sem_info_kvm(kvm_t *kd, struct filestat *fst, 137250223Sjhb struct semstat *sem, char *errbuf); 138233760Sjhbstatic int procstat_get_shm_info_sysctl(struct filestat *fst, 139233760Sjhb struct shmstat *shm, char *errbuf); 140233760Sjhbstatic int procstat_get_shm_info_kvm(kvm_t *kd, struct filestat *fst, 141233760Sjhb struct shmstat *shm, char *errbuf); 142221807Sstasstatic int procstat_get_socket_info_sysctl(struct filestat *fst, 143221807Sstas struct sockstat *sock, char *errbuf); 144221807Sstasstatic int procstat_get_socket_info_kvm(kvm_t *kd, struct filestat *fst, 145221807Sstas struct sockstat *sock, char *errbuf); 146221807Sstasstatic int to_filestat_flags(int flags); 147221807Sstasstatic int procstat_get_vnode_info_kvm(kvm_t *kd, struct filestat *fst, 148221807Sstas struct vnstat *vn, char *errbuf); 149221807Sstasstatic int procstat_get_vnode_info_sysctl(struct filestat *fst, 150221807Sstas struct vnstat *vn, char *errbuf); 151249670Strocinystatic gid_t *procstat_getgroups_core(struct procstat_core *core, 152249670Strociny unsigned int *count); 153250146Strocinystatic gid_t * procstat_getgroups_kvm(kvm_t *kd, struct kinfo_proc *kp, 154250146Strociny unsigned int *count); 155249670Strocinystatic gid_t *procstat_getgroups_sysctl(pid_t pid, unsigned int *count); 156249684Strocinystatic struct kinfo_kstack *procstat_getkstack_sysctl(pid_t pid, 157249684Strociny int *cntp); 158250146Strocinystatic int procstat_getosrel_core(struct procstat_core *core, 159250146Strociny int *osrelp); 160250146Strocinystatic int procstat_getosrel_kvm(kvm_t *kd, struct kinfo_proc *kp, 161250146Strociny int *osrelp); 162250146Strocinystatic int procstat_getosrel_sysctl(pid_t pid, int *osrelp); 163249676Strocinystatic int procstat_getpathname_core(struct procstat_core *core, 164249676Strociny char *pathname, size_t maxlen); 165249676Strocinystatic int procstat_getpathname_sysctl(pid_t pid, char *pathname, 166249676Strociny size_t maxlen); 167249674Strocinystatic int procstat_getrlimit_core(struct procstat_core *core, int which, 168249674Strociny struct rlimit* rlimit); 169250146Strocinystatic int procstat_getrlimit_kvm(kvm_t *kd, struct kinfo_proc *kp, 170250146Strociny int which, struct rlimit* rlimit); 171249674Strocinystatic int procstat_getrlimit_sysctl(pid_t pid, int which, 172249674Strociny struct rlimit* rlimit); 173249672Strocinystatic int procstat_getumask_core(struct procstat_core *core, 174249672Strociny unsigned short *maskp); 175250146Strocinystatic int procstat_getumask_kvm(kvm_t *kd, struct kinfo_proc *kp, 176250146Strociny unsigned short *maskp); 177249672Strocinystatic int procstat_getumask_sysctl(pid_t pid, unsigned short *maskp); 178221807Sstasstatic int vntype2psfsttype(int type); 179221807Sstas 180221807Sstasvoid 181221807Sstasprocstat_close(struct procstat *procstat) 182221807Sstas{ 183221807Sstas 184221807Sstas assert(procstat); 185221807Sstas if (procstat->type == PROCSTAT_KVM) 186221807Sstas kvm_close(procstat->kd); 187249666Strociny else if (procstat->type == PROCSTAT_CORE) 188249666Strociny procstat_core_close(procstat->core); 189249679Strociny procstat_freeargv(procstat); 190249679Strociny procstat_freeenvv(procstat); 191222053Spluknet free(procstat); 192221807Sstas} 193221807Sstas 194221807Sstasstruct procstat * 195221807Sstasprocstat_open_sysctl(void) 196221807Sstas{ 197221807Sstas struct procstat *procstat; 198221807Sstas 199221807Sstas procstat = calloc(1, sizeof(*procstat)); 200221807Sstas if (procstat == NULL) { 201221807Sstas warn("malloc()"); 202221807Sstas return (NULL); 203221807Sstas } 204221807Sstas procstat->type = PROCSTAT_SYSCTL; 205221807Sstas return (procstat); 206221807Sstas} 207221807Sstas 208221807Sstasstruct procstat * 209221807Sstasprocstat_open_kvm(const char *nlistf, const char *memf) 210221807Sstas{ 211221807Sstas struct procstat *procstat; 212221807Sstas kvm_t *kd; 213221807Sstas char buf[_POSIX2_LINE_MAX]; 214221807Sstas 215221807Sstas procstat = calloc(1, sizeof(*procstat)); 216221807Sstas if (procstat == NULL) { 217221807Sstas warn("malloc()"); 218221807Sstas return (NULL); 219221807Sstas } 220221807Sstas kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf); 221221807Sstas if (kd == NULL) { 222221807Sstas warnx("kvm_openfiles(): %s", buf); 223221807Sstas free(procstat); 224221807Sstas return (NULL); 225221807Sstas } 226221807Sstas procstat->type = PROCSTAT_KVM; 227221807Sstas procstat->kd = kd; 228221807Sstas return (procstat); 229221807Sstas} 230221807Sstas 231249666Strocinystruct procstat * 232249666Strocinyprocstat_open_core(const char *filename) 233249666Strociny{ 234249666Strociny struct procstat *procstat; 235249666Strociny struct procstat_core *core; 236249666Strociny 237249666Strociny procstat = calloc(1, sizeof(*procstat)); 238249666Strociny if (procstat == NULL) { 239249666Strociny warn("malloc()"); 240249666Strociny return (NULL); 241249666Strociny } 242249666Strociny core = procstat_core_open(filename); 243249666Strociny if (core == NULL) { 244249666Strociny free(procstat); 245249666Strociny return (NULL); 246249666Strociny } 247249666Strociny procstat->type = PROCSTAT_CORE; 248249666Strociny procstat->core = core; 249249666Strociny return (procstat); 250249666Strociny} 251249666Strociny 252221807Sstasstruct kinfo_proc * 253221807Sstasprocstat_getprocs(struct procstat *procstat, int what, int arg, 254221807Sstas unsigned int *count) 255221807Sstas{ 256221807Sstas struct kinfo_proc *p0, *p; 257251637Sjhb size_t len, olen; 258221807Sstas int name[4]; 259241304Savg int cnt; 260221807Sstas int error; 261221807Sstas 262221807Sstas assert(procstat); 263221807Sstas assert(count); 264221807Sstas p = NULL; 265221807Sstas if (procstat->type == PROCSTAT_KVM) { 266241304Savg *count = 0; 267241304Savg p0 = kvm_getprocs(procstat->kd, what, arg, &cnt); 268241304Savg if (p0 == NULL || cnt <= 0) 269221807Sstas return (NULL); 270241304Savg *count = cnt; 271221807Sstas len = *count * sizeof(*p); 272221807Sstas p = malloc(len); 273221807Sstas if (p == NULL) { 274223269Sjilles warnx("malloc(%zu)", len); 275221807Sstas goto fail; 276221807Sstas } 277221807Sstas bcopy(p0, p, len); 278221807Sstas return (p); 279221807Sstas } else if (procstat->type == PROCSTAT_SYSCTL) { 280221807Sstas len = 0; 281221807Sstas name[0] = CTL_KERN; 282221807Sstas name[1] = KERN_PROC; 283221807Sstas name[2] = what; 284221807Sstas name[3] = arg; 285312036Sngie error = sysctl(name, nitems(name), NULL, &len, NULL, 0); 286221807Sstas if (error < 0 && errno != EPERM) { 287221807Sstas warn("sysctl(kern.proc)"); 288221807Sstas goto fail; 289221807Sstas } 290221807Sstas if (len == 0) { 291221807Sstas warnx("no processes?"); 292221807Sstas goto fail; 293221807Sstas } 294251637Sjhb do { 295251637Sjhb len += len / 10; 296251637Sjhb p = reallocf(p, len); 297251637Sjhb if (p == NULL) { 298251637Sjhb warnx("reallocf(%zu)", len); 299251637Sjhb goto fail; 300251637Sjhb } 301251637Sjhb olen = len; 302312036Sngie error = sysctl(name, nitems(name), p, &len, NULL, 0); 303251637Sjhb } while (error < 0 && errno == ENOMEM && olen == len); 304221807Sstas if (error < 0 && errno != EPERM) { 305221807Sstas warn("sysctl(kern.proc)"); 306221807Sstas goto fail; 307221807Sstas } 308221807Sstas /* Perform simple consistency checks. */ 309221807Sstas if ((len % sizeof(*p)) != 0 || p->ki_structsize != sizeof(*p)) { 310249666Strociny warnx("kinfo_proc structure size mismatch (len = %zu)", len); 311249666Strociny goto fail; 312249666Strociny } 313249666Strociny *count = len / sizeof(*p); 314249666Strociny return (p); 315249666Strociny } else if (procstat->type == PROCSTAT_CORE) { 316249666Strociny p = procstat_core_get(procstat->core, PSC_TYPE_PROC, NULL, 317249666Strociny &len); 318249666Strociny if ((len % sizeof(*p)) != 0 || p->ki_structsize != sizeof(*p)) { 319221807Sstas warnx("kinfo_proc structure size mismatch"); 320221807Sstas goto fail; 321221807Sstas } 322221807Sstas *count = len / sizeof(*p); 323221807Sstas return (p); 324221807Sstas } else { 325223276Sjilles warnx("unknown access method: %d", procstat->type); 326221807Sstas return (NULL); 327221807Sstas } 328221807Sstasfail: 329221807Sstas if (p) 330221807Sstas free(p); 331221807Sstas return (NULL); 332221807Sstas} 333221807Sstas 334221807Sstasvoid 335221807Sstasprocstat_freeprocs(struct procstat *procstat __unused, struct kinfo_proc *p) 336221807Sstas{ 337221807Sstas 338221807Sstas if (p != NULL) 339221807Sstas free(p); 340221807Sstas p = NULL; 341221807Sstas} 342221807Sstas 343221807Sstasstruct filestat_list * 344221807Sstasprocstat_getfiles(struct procstat *procstat, struct kinfo_proc *kp, int mmapped) 345221807Sstas{ 346249666Strociny 347249666Strociny switch(procstat->type) { 348249666Strociny case PROCSTAT_KVM: 349249666Strociny return (procstat_getfiles_kvm(procstat, kp, mmapped)); 350249666Strociny case PROCSTAT_SYSCTL: 351249666Strociny case PROCSTAT_CORE: 352221807Sstas return (procstat_getfiles_sysctl(procstat, kp, mmapped)); 353249666Strociny default: 354249666Strociny warnx("unknown access method: %d", procstat->type); 355221807Sstas return (NULL); 356249666Strociny } 357221807Sstas} 358221807Sstas 359221807Sstasvoid 360221807Sstasprocstat_freefiles(struct procstat *procstat, struct filestat_list *head) 361221807Sstas{ 362221807Sstas struct filestat *fst, *tmp; 363221807Sstas 364221807Sstas STAILQ_FOREACH_SAFE(fst, head, next, tmp) { 365221807Sstas if (fst->fs_path != NULL) 366221807Sstas free(fst->fs_path); 367221807Sstas free(fst); 368221807Sstas } 369221807Sstas free(head); 370221807Sstas if (procstat->vmentries != NULL) { 371223270Sjilles free(procstat->vmentries); 372221807Sstas procstat->vmentries = NULL; 373221807Sstas } 374221807Sstas if (procstat->files != NULL) { 375223270Sjilles free(procstat->files); 376221807Sstas procstat->files = NULL; 377221807Sstas } 378221807Sstas} 379221807Sstas 380221807Sstasstatic struct filestat * 381221807Sstasfilestat_new_entry(void *typedep, int type, int fd, int fflags, int uflags, 382255219Spjd int refcount, off_t offset, char *path, cap_rights_t *cap_rightsp) 383221807Sstas{ 384221807Sstas struct filestat *entry; 385221807Sstas 386221807Sstas entry = calloc(1, sizeof(*entry)); 387221807Sstas if (entry == NULL) { 388221807Sstas warn("malloc()"); 389221807Sstas return (NULL); 390221807Sstas } 391221807Sstas entry->fs_typedep = typedep; 392221807Sstas entry->fs_fflags = fflags; 393221807Sstas entry->fs_uflags = uflags; 394221807Sstas entry->fs_fd = fd; 395221807Sstas entry->fs_type = type; 396221807Sstas entry->fs_ref_count = refcount; 397221807Sstas entry->fs_offset = offset; 398221807Sstas entry->fs_path = path; 399256242Spjd if (cap_rightsp != NULL) 400256242Spjd entry->fs_cap_rights = *cap_rightsp; 401256242Spjd else 402256242Spjd cap_rights_init(&entry->fs_cap_rights); 403221807Sstas return (entry); 404221807Sstas} 405221807Sstas 406221807Sstasstatic struct vnode * 407221807Sstasgetctty(kvm_t *kd, struct kinfo_proc *kp) 408221807Sstas{ 409221807Sstas struct pgrp pgrp; 410221807Sstas struct proc proc; 411221807Sstas struct session sess; 412221807Sstas int error; 413221807Sstas 414221807Sstas assert(kp); 415221807Sstas error = kvm_read_all(kd, (unsigned long)kp->ki_paddr, &proc, 416221807Sstas sizeof(proc)); 417221807Sstas if (error == 0) { 418221807Sstas warnx("can't read proc struct at %p for pid %d", 419221807Sstas kp->ki_paddr, kp->ki_pid); 420221807Sstas return (NULL); 421221807Sstas } 422221807Sstas if (proc.p_pgrp == NULL) 423221807Sstas return (NULL); 424221807Sstas error = kvm_read_all(kd, (unsigned long)proc.p_pgrp, &pgrp, 425221807Sstas sizeof(pgrp)); 426221807Sstas if (error == 0) { 427221807Sstas warnx("can't read pgrp struct at %p for pid %d", 428221807Sstas proc.p_pgrp, kp->ki_pid); 429221807Sstas return (NULL); 430221807Sstas } 431221807Sstas error = kvm_read_all(kd, (unsigned long)pgrp.pg_session, &sess, 432221807Sstas sizeof(sess)); 433221807Sstas if (error == 0) { 434221807Sstas warnx("can't read session struct at %p for pid %d", 435221807Sstas pgrp.pg_session, kp->ki_pid); 436221807Sstas return (NULL); 437221807Sstas } 438221807Sstas return (sess.s_ttyvp); 439221807Sstas} 440221807Sstas 441221807Sstasstatic struct filestat_list * 442221807Sstasprocstat_getfiles_kvm(struct procstat *procstat, struct kinfo_proc *kp, int mmapped) 443221807Sstas{ 444221807Sstas struct file file; 445221807Sstas struct filedesc filed; 446221807Sstas struct vm_map_entry vmentry; 447221807Sstas struct vm_object object; 448221807Sstas struct vmspace vmspace; 449221807Sstas vm_map_entry_t entryp; 450221807Sstas vm_map_t map; 451221807Sstas vm_object_t objp; 452221807Sstas struct vnode *vp; 453221807Sstas struct file **ofiles; 454221807Sstas struct filestat *entry; 455221807Sstas struct filestat_list *head; 456221807Sstas kvm_t *kd; 457221807Sstas void *data; 458221807Sstas int i, fflags; 459221807Sstas int prot, type; 460221807Sstas unsigned int nfiles; 461221807Sstas 462221807Sstas assert(procstat); 463221807Sstas kd = procstat->kd; 464221807Sstas if (kd == NULL) 465221807Sstas return (NULL); 466221807Sstas if (kp->ki_fd == NULL) 467221807Sstas return (NULL); 468221807Sstas if (!kvm_read_all(kd, (unsigned long)kp->ki_fd, &filed, 469221807Sstas sizeof(filed))) { 470221807Sstas warnx("can't read filedesc at %p", (void *)kp->ki_fd); 471221807Sstas return (NULL); 472221807Sstas } 473221807Sstas 474221807Sstas /* 475221807Sstas * Allocate list head. 476221807Sstas */ 477221807Sstas head = malloc(sizeof(*head)); 478221807Sstas if (head == NULL) 479221807Sstas return (NULL); 480221807Sstas STAILQ_INIT(head); 481221807Sstas 482221807Sstas /* root directory vnode, if one. */ 483221807Sstas if (filed.fd_rdir) { 484221807Sstas entry = filestat_new_entry(filed.fd_rdir, PS_FST_TYPE_VNODE, -1, 485256242Spjd PS_FST_FFLAG_READ, PS_FST_UFLAG_RDIR, 0, 0, NULL, NULL); 486221807Sstas if (entry != NULL) 487221807Sstas STAILQ_INSERT_TAIL(head, entry, next); 488221807Sstas } 489221807Sstas /* current working directory vnode. */ 490221807Sstas if (filed.fd_cdir) { 491221807Sstas entry = filestat_new_entry(filed.fd_cdir, PS_FST_TYPE_VNODE, -1, 492256242Spjd PS_FST_FFLAG_READ, PS_FST_UFLAG_CDIR, 0, 0, NULL, NULL); 493221807Sstas if (entry != NULL) 494221807Sstas STAILQ_INSERT_TAIL(head, entry, next); 495221807Sstas } 496221807Sstas /* jail root, if any. */ 497221807Sstas if (filed.fd_jdir) { 498221807Sstas entry = filestat_new_entry(filed.fd_jdir, PS_FST_TYPE_VNODE, -1, 499256242Spjd PS_FST_FFLAG_READ, PS_FST_UFLAG_JAIL, 0, 0, NULL, NULL); 500221807Sstas if (entry != NULL) 501221807Sstas STAILQ_INSERT_TAIL(head, entry, next); 502221807Sstas } 503221807Sstas /* ktrace vnode, if one */ 504221807Sstas if (kp->ki_tracep) { 505221807Sstas entry = filestat_new_entry(kp->ki_tracep, PS_FST_TYPE_VNODE, -1, 506221807Sstas PS_FST_FFLAG_READ | PS_FST_FFLAG_WRITE, 507256242Spjd PS_FST_UFLAG_TRACE, 0, 0, NULL, NULL); 508221807Sstas if (entry != NULL) 509221807Sstas STAILQ_INSERT_TAIL(head, entry, next); 510221807Sstas } 511221807Sstas /* text vnode, if one */ 512221807Sstas if (kp->ki_textvp) { 513221807Sstas entry = filestat_new_entry(kp->ki_textvp, PS_FST_TYPE_VNODE, -1, 514256242Spjd PS_FST_FFLAG_READ, PS_FST_UFLAG_TEXT, 0, 0, NULL, NULL); 515221807Sstas if (entry != NULL) 516221807Sstas STAILQ_INSERT_TAIL(head, entry, next); 517221807Sstas } 518221807Sstas /* Controlling terminal. */ 519221807Sstas if ((vp = getctty(kd, kp)) != NULL) { 520221807Sstas entry = filestat_new_entry(vp, PS_FST_TYPE_VNODE, -1, 521221807Sstas PS_FST_FFLAG_READ | PS_FST_FFLAG_WRITE, 522256242Spjd PS_FST_UFLAG_CTTY, 0, 0, NULL, NULL); 523221807Sstas if (entry != NULL) 524221807Sstas STAILQ_INSERT_TAIL(head, entry, next); 525221807Sstas } 526221807Sstas 527221807Sstas nfiles = filed.fd_lastfile + 1; 528221807Sstas ofiles = malloc(nfiles * sizeof(struct file *)); 529221807Sstas if (ofiles == NULL) { 530223269Sjilles warn("malloc(%zu)", nfiles * sizeof(struct file *)); 531221807Sstas goto do_mmapped; 532221807Sstas } 533221807Sstas if (!kvm_read_all(kd, (unsigned long)filed.fd_ofiles, ofiles, 534221807Sstas nfiles * sizeof(struct file *))) { 535221807Sstas warnx("cannot read file structures at %p", 536221807Sstas (void *)filed.fd_ofiles); 537221807Sstas free(ofiles); 538221807Sstas goto do_mmapped; 539221807Sstas } 540221807Sstas for (i = 0; i <= filed.fd_lastfile; i++) { 541221807Sstas if (ofiles[i] == NULL) 542221807Sstas continue; 543221807Sstas if (!kvm_read_all(kd, (unsigned long)ofiles[i], &file, 544221807Sstas sizeof(struct file))) { 545221807Sstas warnx("can't read file %d at %p", i, 546221807Sstas (void *)ofiles[i]); 547221807Sstas continue; 548221807Sstas } 549221807Sstas switch (file.f_type) { 550221807Sstas case DTYPE_VNODE: 551221807Sstas type = PS_FST_TYPE_VNODE; 552221807Sstas data = file.f_vnode; 553221807Sstas break; 554221807Sstas case DTYPE_SOCKET: 555221807Sstas type = PS_FST_TYPE_SOCKET; 556221807Sstas data = file.f_data; 557221807Sstas break; 558221807Sstas case DTYPE_PIPE: 559221807Sstas type = PS_FST_TYPE_PIPE; 560221807Sstas data = file.f_data; 561221807Sstas break; 562221807Sstas case DTYPE_FIFO: 563221807Sstas type = PS_FST_TYPE_FIFO; 564221807Sstas data = file.f_vnode; 565221807Sstas break; 566221807Sstas#ifdef DTYPE_PTS 567221807Sstas case DTYPE_PTS: 568221807Sstas type = PS_FST_TYPE_PTS; 569221807Sstas data = file.f_data; 570221807Sstas break; 571221807Sstas#endif 572250223Sjhb case DTYPE_SEM: 573250223Sjhb type = PS_FST_TYPE_SEM; 574250223Sjhb data = file.f_data; 575250223Sjhb break; 576233760Sjhb case DTYPE_SHM: 577233760Sjhb type = PS_FST_TYPE_SHM; 578233760Sjhb data = file.f_data; 579233760Sjhb break; 580221807Sstas default: 581221807Sstas continue; 582221807Sstas } 583224859Srwatson /* XXXRW: No capability rights support for kvm yet. */ 584221807Sstas entry = filestat_new_entry(data, type, i, 585256242Spjd to_filestat_flags(file.f_flag), 0, 0, 0, NULL, NULL); 586221807Sstas if (entry != NULL) 587221807Sstas STAILQ_INSERT_TAIL(head, entry, next); 588221807Sstas } 589221807Sstas free(ofiles); 590221807Sstas 591221807Sstasdo_mmapped: 592221807Sstas 593221807Sstas /* 594221807Sstas * Process mmapped files if requested. 595221807Sstas */ 596221807Sstas if (mmapped) { 597221807Sstas if (!kvm_read_all(kd, (unsigned long)kp->ki_vmspace, &vmspace, 598221807Sstas sizeof(vmspace))) { 599221807Sstas warnx("can't read vmspace at %p", 600221807Sstas (void *)kp->ki_vmspace); 601221807Sstas goto exit; 602221807Sstas } 603221807Sstas map = &vmspace.vm_map; 604221807Sstas 605221807Sstas for (entryp = map->header.next; 606221807Sstas entryp != &kp->ki_vmspace->vm_map.header; 607221807Sstas entryp = vmentry.next) { 608221807Sstas if (!kvm_read_all(kd, (unsigned long)entryp, &vmentry, 609221807Sstas sizeof(vmentry))) { 610221807Sstas warnx("can't read vm_map_entry at %p", 611221807Sstas (void *)entryp); 612221807Sstas continue; 613221807Sstas } 614221807Sstas if (vmentry.eflags & MAP_ENTRY_IS_SUB_MAP) 615221807Sstas continue; 616221807Sstas if ((objp = vmentry.object.vm_object) == NULL) 617221807Sstas continue; 618221807Sstas for (; objp; objp = object.backing_object) { 619221807Sstas if (!kvm_read_all(kd, (unsigned long)objp, 620221807Sstas &object, sizeof(object))) { 621221807Sstas warnx("can't read vm_object at %p", 622221807Sstas (void *)objp); 623221807Sstas break; 624221807Sstas } 625221807Sstas } 626221807Sstas 627221807Sstas /* We want only vnode objects. */ 628221807Sstas if (object.type != OBJT_VNODE) 629221807Sstas continue; 630221807Sstas 631221807Sstas prot = vmentry.protection; 632221807Sstas fflags = 0; 633221807Sstas if (prot & VM_PROT_READ) 634221807Sstas fflags = PS_FST_FFLAG_READ; 635223279Sjilles if ((vmentry.eflags & MAP_ENTRY_COW) == 0 && 636223279Sjilles prot & VM_PROT_WRITE) 637221807Sstas fflags |= PS_FST_FFLAG_WRITE; 638221807Sstas 639221807Sstas /* 640221807Sstas * Create filestat entry. 641221807Sstas */ 642221807Sstas entry = filestat_new_entry(object.handle, 643221807Sstas PS_FST_TYPE_VNODE, -1, fflags, 644256242Spjd PS_FST_UFLAG_MMAP, 0, 0, NULL, NULL); 645221807Sstas if (entry != NULL) 646221807Sstas STAILQ_INSERT_TAIL(head, entry, next); 647221807Sstas } 648221807Sstas } 649221807Sstasexit: 650221807Sstas return (head); 651221807Sstas} 652221807Sstas 653221807Sstas/* 654221807Sstas * kinfo types to filestat translation. 655221807Sstas */ 656221807Sstasstatic int 657221807Sstaskinfo_type2fst(int kftype) 658221807Sstas{ 659221807Sstas static struct { 660221807Sstas int kf_type; 661221807Sstas int fst_type; 662221807Sstas } kftypes2fst[] = { 663221807Sstas { KF_TYPE_CRYPTO, PS_FST_TYPE_CRYPTO }, 664221807Sstas { KF_TYPE_FIFO, PS_FST_TYPE_FIFO }, 665221807Sstas { KF_TYPE_KQUEUE, PS_FST_TYPE_KQUEUE }, 666221807Sstas { KF_TYPE_MQUEUE, PS_FST_TYPE_MQUEUE }, 667221807Sstas { KF_TYPE_NONE, PS_FST_TYPE_NONE }, 668221807Sstas { KF_TYPE_PIPE, PS_FST_TYPE_PIPE }, 669221807Sstas { KF_TYPE_PTS, PS_FST_TYPE_PTS }, 670221807Sstas { KF_TYPE_SEM, PS_FST_TYPE_SEM }, 671221807Sstas { KF_TYPE_SHM, PS_FST_TYPE_SHM }, 672221807Sstas { KF_TYPE_SOCKET, PS_FST_TYPE_SOCKET }, 673221807Sstas { KF_TYPE_VNODE, PS_FST_TYPE_VNODE }, 674221807Sstas { KF_TYPE_UNKNOWN, PS_FST_TYPE_UNKNOWN } 675221807Sstas }; 676221807Sstas#define NKFTYPES (sizeof(kftypes2fst) / sizeof(*kftypes2fst)) 677221807Sstas unsigned int i; 678221807Sstas 679221807Sstas for (i = 0; i < NKFTYPES; i++) 680221807Sstas if (kftypes2fst[i].kf_type == kftype) 681221807Sstas break; 682221807Sstas if (i == NKFTYPES) 683221807Sstas return (PS_FST_TYPE_UNKNOWN); 684221807Sstas return (kftypes2fst[i].fst_type); 685221807Sstas} 686221807Sstas 687221807Sstas/* 688221807Sstas * kinfo flags to filestat translation. 689221807Sstas */ 690221807Sstasstatic int 691221807Sstaskinfo_fflags2fst(int kfflags) 692221807Sstas{ 693221807Sstas static struct { 694221807Sstas int kf_flag; 695221807Sstas int fst_flag; 696221807Sstas } kfflags2fst[] = { 697221807Sstas { KF_FLAG_APPEND, PS_FST_FFLAG_APPEND }, 698221807Sstas { KF_FLAG_ASYNC, PS_FST_FFLAG_ASYNC }, 699221807Sstas { KF_FLAG_CREAT, PS_FST_FFLAG_CREAT }, 700221807Sstas { KF_FLAG_DIRECT, PS_FST_FFLAG_DIRECT }, 701221807Sstas { KF_FLAG_EXCL, PS_FST_FFLAG_EXCL }, 702221807Sstas { KF_FLAG_EXEC, PS_FST_FFLAG_EXEC }, 703221807Sstas { KF_FLAG_EXLOCK, PS_FST_FFLAG_EXLOCK }, 704221807Sstas { KF_FLAG_FSYNC, PS_FST_FFLAG_SYNC }, 705221807Sstas { KF_FLAG_HASLOCK, PS_FST_FFLAG_HASLOCK }, 706221807Sstas { KF_FLAG_NOFOLLOW, PS_FST_FFLAG_NOFOLLOW }, 707221807Sstas { KF_FLAG_NONBLOCK, PS_FST_FFLAG_NONBLOCK }, 708221807Sstas { KF_FLAG_READ, PS_FST_FFLAG_READ }, 709221807Sstas { KF_FLAG_SHLOCK, PS_FST_FFLAG_SHLOCK }, 710221807Sstas { KF_FLAG_TRUNC, PS_FST_FFLAG_TRUNC }, 711221807Sstas { KF_FLAG_WRITE, PS_FST_FFLAG_WRITE } 712221807Sstas }; 713221807Sstas#define NKFFLAGS (sizeof(kfflags2fst) / sizeof(*kfflags2fst)) 714221807Sstas unsigned int i; 715221807Sstas int flags; 716221807Sstas 717221807Sstas flags = 0; 718221807Sstas for (i = 0; i < NKFFLAGS; i++) 719221807Sstas if ((kfflags & kfflags2fst[i].kf_flag) != 0) 720221807Sstas flags |= kfflags2fst[i].fst_flag; 721221807Sstas return (flags); 722221807Sstas} 723221807Sstas 724221807Sstasstatic int 725221807Sstaskinfo_uflags2fst(int fd) 726221807Sstas{ 727221807Sstas 728221807Sstas switch (fd) { 729221807Sstas case KF_FD_TYPE_CTTY: 730221807Sstas return (PS_FST_UFLAG_CTTY); 731221807Sstas case KF_FD_TYPE_CWD: 732221807Sstas return (PS_FST_UFLAG_CDIR); 733221807Sstas case KF_FD_TYPE_JAIL: 734221807Sstas return (PS_FST_UFLAG_JAIL); 735221807Sstas case KF_FD_TYPE_TEXT: 736221807Sstas return (PS_FST_UFLAG_TEXT); 737221807Sstas case KF_FD_TYPE_TRACE: 738221807Sstas return (PS_FST_UFLAG_TRACE); 739221807Sstas case KF_FD_TYPE_ROOT: 740221807Sstas return (PS_FST_UFLAG_RDIR); 741221807Sstas } 742221807Sstas return (0); 743221807Sstas} 744221807Sstas 745249666Strocinystatic struct kinfo_file * 746249666Strocinykinfo_getfile_core(struct procstat_core *core, int *cntp) 747249666Strociny{ 748249666Strociny int cnt; 749249666Strociny size_t len; 750249666Strociny char *buf, *bp, *eb; 751249666Strociny struct kinfo_file *kif, *kp, *kf; 752249666Strociny 753249666Strociny buf = procstat_core_get(core, PSC_TYPE_FILES, NULL, &len); 754249666Strociny if (buf == NULL) 755249666Strociny return (NULL); 756249666Strociny /* 757249666Strociny * XXXMG: The code below is just copy&past from libutil. 758249666Strociny * The code duplication can be avoided if libutil 759249666Strociny * is extended to provide something like: 760249666Strociny * struct kinfo_file *kinfo_getfile_from_buf(const char *buf, 761249666Strociny * size_t len, int *cntp); 762249666Strociny */ 763249666Strociny 764249666Strociny /* Pass 1: count items */ 765249666Strociny cnt = 0; 766249666Strociny bp = buf; 767249666Strociny eb = buf + len; 768249666Strociny while (bp < eb) { 769249666Strociny kf = (struct kinfo_file *)(uintptr_t)bp; 770295454Sjhb if (kf->kf_structsize == 0) 771295454Sjhb break; 772249666Strociny bp += kf->kf_structsize; 773249666Strociny cnt++; 774249666Strociny } 775249666Strociny 776249666Strociny kif = calloc(cnt, sizeof(*kif)); 777249666Strociny if (kif == NULL) { 778249666Strociny free(buf); 779249666Strociny return (NULL); 780249666Strociny } 781249666Strociny bp = buf; 782249666Strociny eb = buf + len; 783249666Strociny kp = kif; 784249666Strociny /* Pass 2: unpack */ 785249666Strociny while (bp < eb) { 786249666Strociny kf = (struct kinfo_file *)(uintptr_t)bp; 787295454Sjhb if (kf->kf_structsize == 0) 788295454Sjhb break; 789249666Strociny /* Copy/expand into pre-zeroed buffer */ 790249666Strociny memcpy(kp, kf, kf->kf_structsize); 791249666Strociny /* Advance to next packed record */ 792249666Strociny bp += kf->kf_structsize; 793249666Strociny /* Set field size to fixed length, advance */ 794249666Strociny kp->kf_structsize = sizeof(*kp); 795249666Strociny kp++; 796249666Strociny } 797249666Strociny free(buf); 798249666Strociny *cntp = cnt; 799249666Strociny return (kif); /* Caller must free() return value */ 800249666Strociny} 801249666Strociny 802221807Sstasstatic struct filestat_list * 803249666Strocinyprocstat_getfiles_sysctl(struct procstat *procstat, struct kinfo_proc *kp, 804249666Strociny int mmapped) 805221807Sstas{ 806221807Sstas struct kinfo_file *kif, *files; 807221807Sstas struct kinfo_vmentry *kve, *vmentries; 808221807Sstas struct filestat_list *head; 809221807Sstas struct filestat *entry; 810221807Sstas char *path; 811221807Sstas off_t offset; 812221807Sstas int cnt, fd, fflags; 813221807Sstas int i, type, uflags; 814221807Sstas int refcount; 815224859Srwatson cap_rights_t cap_rights; 816221807Sstas 817221807Sstas assert(kp); 818221807Sstas if (kp->ki_fd == NULL) 819221807Sstas return (NULL); 820249666Strociny switch(procstat->type) { 821249666Strociny case PROCSTAT_SYSCTL: 822249666Strociny files = kinfo_getfile(kp->ki_pid, &cnt); 823249666Strociny break; 824249666Strociny case PROCSTAT_CORE: 825249666Strociny files = kinfo_getfile_core(procstat->core, &cnt); 826249666Strociny break; 827249666Strociny default: 828249666Strociny assert(!"invalid type"); 829249666Strociny } 830221807Sstas if (files == NULL && errno != EPERM) { 831221807Sstas warn("kinfo_getfile()"); 832221807Sstas return (NULL); 833221807Sstas } 834221807Sstas procstat->files = files; 835221807Sstas 836221807Sstas /* 837221807Sstas * Allocate list head. 838221807Sstas */ 839221807Sstas head = malloc(sizeof(*head)); 840221807Sstas if (head == NULL) 841221807Sstas return (NULL); 842221807Sstas STAILQ_INIT(head); 843221807Sstas for (i = 0; i < cnt; i++) { 844221807Sstas kif = &files[i]; 845221807Sstas 846221807Sstas type = kinfo_type2fst(kif->kf_type); 847221807Sstas fd = kif->kf_fd >= 0 ? kif->kf_fd : -1; 848221807Sstas fflags = kinfo_fflags2fst(kif->kf_flags); 849221807Sstas uflags = kinfo_uflags2fst(kif->kf_fd); 850221807Sstas refcount = kif->kf_ref_count; 851221807Sstas offset = kif->kf_offset; 852221807Sstas if (*kif->kf_path != '\0') 853221807Sstas path = strdup(kif->kf_path); 854221807Sstas else 855221807Sstas path = NULL; 856224859Srwatson cap_rights = kif->kf_cap_rights; 857221807Sstas 858221807Sstas /* 859221807Sstas * Create filestat entry. 860221807Sstas */ 861221807Sstas entry = filestat_new_entry(kif, type, fd, fflags, uflags, 862255219Spjd refcount, offset, path, &cap_rights); 863221807Sstas if (entry != NULL) 864221807Sstas STAILQ_INSERT_TAIL(head, entry, next); 865221807Sstas } 866221807Sstas if (mmapped != 0) { 867249667Strociny vmentries = procstat_getvmmap(procstat, kp, &cnt); 868221807Sstas procstat->vmentries = vmentries; 869221807Sstas if (vmentries == NULL || cnt == 0) 870221807Sstas goto fail; 871221807Sstas for (i = 0; i < cnt; i++) { 872221807Sstas kve = &vmentries[i]; 873221807Sstas if (kve->kve_type != KVME_TYPE_VNODE) 874221807Sstas continue; 875221807Sstas fflags = 0; 876221807Sstas if (kve->kve_protection & KVME_PROT_READ) 877221807Sstas fflags = PS_FST_FFLAG_READ; 878223279Sjilles if ((kve->kve_flags & KVME_FLAG_COW) == 0 && 879223279Sjilles kve->kve_protection & KVME_PROT_WRITE) 880221807Sstas fflags |= PS_FST_FFLAG_WRITE; 881221807Sstas offset = kve->kve_offset; 882221807Sstas refcount = kve->kve_ref_count; 883221807Sstas if (*kve->kve_path != '\0') 884221807Sstas path = strdup(kve->kve_path); 885221807Sstas else 886221807Sstas path = NULL; 887221807Sstas entry = filestat_new_entry(kve, PS_FST_TYPE_VNODE, -1, 888224859Srwatson fflags, PS_FST_UFLAG_MMAP, refcount, offset, path, 889256242Spjd NULL); 890221807Sstas if (entry != NULL) 891221807Sstas STAILQ_INSERT_TAIL(head, entry, next); 892221807Sstas } 893221807Sstas } 894221807Sstasfail: 895221807Sstas return (head); 896221807Sstas} 897221807Sstas 898221807Sstasint 899221807Sstasprocstat_get_pipe_info(struct procstat *procstat, struct filestat *fst, 900221807Sstas struct pipestat *ps, char *errbuf) 901221807Sstas{ 902221807Sstas 903221807Sstas assert(ps); 904221807Sstas if (procstat->type == PROCSTAT_KVM) { 905221807Sstas return (procstat_get_pipe_info_kvm(procstat->kd, fst, ps, 906221807Sstas errbuf)); 907249666Strociny } else if (procstat->type == PROCSTAT_SYSCTL || 908249666Strociny procstat->type == PROCSTAT_CORE) { 909221807Sstas return (procstat_get_pipe_info_sysctl(fst, ps, errbuf)); 910221807Sstas } else { 911223276Sjilles warnx("unknown access method: %d", procstat->type); 912250378Strociny if (errbuf != NULL) 913250378Strociny snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 914221807Sstas return (1); 915221807Sstas } 916221807Sstas} 917221807Sstas 918221807Sstasstatic int 919221807Sstasprocstat_get_pipe_info_kvm(kvm_t *kd, struct filestat *fst, 920221807Sstas struct pipestat *ps, char *errbuf) 921221807Sstas{ 922221807Sstas struct pipe pi; 923221807Sstas void *pipep; 924221807Sstas 925221807Sstas assert(kd); 926221807Sstas assert(ps); 927221807Sstas assert(fst); 928221807Sstas bzero(ps, sizeof(*ps)); 929221807Sstas pipep = fst->fs_typedep; 930221807Sstas if (pipep == NULL) 931221807Sstas goto fail; 932221807Sstas if (!kvm_read_all(kd, (unsigned long)pipep, &pi, sizeof(struct pipe))) { 933221807Sstas warnx("can't read pipe at %p", (void *)pipep); 934221807Sstas goto fail; 935221807Sstas } 936221807Sstas ps->addr = (uintptr_t)pipep; 937221807Sstas ps->peer = (uintptr_t)pi.pipe_peer; 938221807Sstas ps->buffer_cnt = pi.pipe_buffer.cnt; 939221807Sstas return (0); 940221807Sstas 941221807Sstasfail: 942250378Strociny if (errbuf != NULL) 943250378Strociny snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 944221807Sstas return (1); 945221807Sstas} 946221807Sstas 947221807Sstasstatic int 948221807Sstasprocstat_get_pipe_info_sysctl(struct filestat *fst, struct pipestat *ps, 949221807Sstas char *errbuf __unused) 950221807Sstas{ 951221807Sstas struct kinfo_file *kif; 952221807Sstas 953221807Sstas assert(ps); 954221807Sstas assert(fst); 955221807Sstas bzero(ps, sizeof(*ps)); 956221807Sstas kif = fst->fs_typedep; 957221807Sstas if (kif == NULL) 958221807Sstas return (1); 959221807Sstas ps->addr = kif->kf_un.kf_pipe.kf_pipe_addr; 960221807Sstas ps->peer = kif->kf_un.kf_pipe.kf_pipe_peer; 961221807Sstas ps->buffer_cnt = kif->kf_un.kf_pipe.kf_pipe_buffer_cnt; 962221807Sstas return (0); 963221807Sstas} 964221807Sstas 965221807Sstasint 966221807Sstasprocstat_get_pts_info(struct procstat *procstat, struct filestat *fst, 967221807Sstas struct ptsstat *pts, char *errbuf) 968221807Sstas{ 969221807Sstas 970221807Sstas assert(pts); 971221807Sstas if (procstat->type == PROCSTAT_KVM) { 972221807Sstas return (procstat_get_pts_info_kvm(procstat->kd, fst, pts, 973221807Sstas errbuf)); 974249666Strociny } else if (procstat->type == PROCSTAT_SYSCTL || 975249666Strociny procstat->type == PROCSTAT_CORE) { 976221807Sstas return (procstat_get_pts_info_sysctl(fst, pts, errbuf)); 977221807Sstas } else { 978223276Sjilles warnx("unknown access method: %d", procstat->type); 979250378Strociny if (errbuf != NULL) 980250378Strociny snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 981221807Sstas return (1); 982221807Sstas } 983221807Sstas} 984221807Sstas 985221807Sstasstatic int 986221807Sstasprocstat_get_pts_info_kvm(kvm_t *kd, struct filestat *fst, 987221807Sstas struct ptsstat *pts, char *errbuf) 988221807Sstas{ 989221807Sstas struct tty tty; 990221807Sstas void *ttyp; 991221807Sstas 992221807Sstas assert(kd); 993221807Sstas assert(pts); 994221807Sstas assert(fst); 995221807Sstas bzero(pts, sizeof(*pts)); 996221807Sstas ttyp = fst->fs_typedep; 997221807Sstas if (ttyp == NULL) 998221807Sstas goto fail; 999221807Sstas if (!kvm_read_all(kd, (unsigned long)ttyp, &tty, sizeof(struct tty))) { 1000221807Sstas warnx("can't read tty at %p", (void *)ttyp); 1001221807Sstas goto fail; 1002221807Sstas } 1003221807Sstas pts->dev = dev2udev(kd, tty.t_dev); 1004221807Sstas (void)kdevtoname(kd, tty.t_dev, pts->devname); 1005221807Sstas return (0); 1006221807Sstas 1007221807Sstasfail: 1008250378Strociny if (errbuf != NULL) 1009250378Strociny snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 1010221807Sstas return (1); 1011221807Sstas} 1012221807Sstas 1013221807Sstasstatic int 1014221807Sstasprocstat_get_pts_info_sysctl(struct filestat *fst, struct ptsstat *pts, 1015221807Sstas char *errbuf __unused) 1016221807Sstas{ 1017221807Sstas struct kinfo_file *kif; 1018221807Sstas 1019221807Sstas assert(pts); 1020221807Sstas assert(fst); 1021221807Sstas bzero(pts, sizeof(*pts)); 1022221807Sstas kif = fst->fs_typedep; 1023221807Sstas if (kif == NULL) 1024221807Sstas return (0); 1025221807Sstas pts->dev = kif->kf_un.kf_pts.kf_pts_dev; 1026221807Sstas strlcpy(pts->devname, kif->kf_path, sizeof(pts->devname)); 1027221807Sstas return (0); 1028221807Sstas} 1029221807Sstas 1030221807Sstasint 1031250223Sjhbprocstat_get_sem_info(struct procstat *procstat, struct filestat *fst, 1032250223Sjhb struct semstat *sem, char *errbuf) 1033250223Sjhb{ 1034250223Sjhb 1035250223Sjhb assert(sem); 1036250223Sjhb if (procstat->type == PROCSTAT_KVM) { 1037250223Sjhb return (procstat_get_sem_info_kvm(procstat->kd, fst, sem, 1038250223Sjhb errbuf)); 1039250223Sjhb } else if (procstat->type == PROCSTAT_SYSCTL || 1040250223Sjhb procstat->type == PROCSTAT_CORE) { 1041250223Sjhb return (procstat_get_sem_info_sysctl(fst, sem, errbuf)); 1042250223Sjhb } else { 1043250223Sjhb warnx("unknown access method: %d", procstat->type); 1044250378Strociny if (errbuf != NULL) 1045250378Strociny snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 1046250223Sjhb return (1); 1047250223Sjhb } 1048250223Sjhb} 1049250223Sjhb 1050250223Sjhbstatic int 1051250223Sjhbprocstat_get_sem_info_kvm(kvm_t *kd, struct filestat *fst, 1052250223Sjhb struct semstat *sem, char *errbuf) 1053250223Sjhb{ 1054250223Sjhb struct ksem ksem; 1055250223Sjhb void *ksemp; 1056250223Sjhb char *path; 1057250223Sjhb int i; 1058250223Sjhb 1059250223Sjhb assert(kd); 1060250223Sjhb assert(sem); 1061250223Sjhb assert(fst); 1062250223Sjhb bzero(sem, sizeof(*sem)); 1063250223Sjhb ksemp = fst->fs_typedep; 1064250223Sjhb if (ksemp == NULL) 1065250223Sjhb goto fail; 1066250223Sjhb if (!kvm_read_all(kd, (unsigned long)ksemp, &ksem, 1067250223Sjhb sizeof(struct ksem))) { 1068250223Sjhb warnx("can't read ksem at %p", (void *)ksemp); 1069250223Sjhb goto fail; 1070250223Sjhb } 1071250223Sjhb sem->mode = S_IFREG | ksem.ks_mode; 1072250223Sjhb sem->value = ksem.ks_value; 1073250223Sjhb if (fst->fs_path == NULL && ksem.ks_path != NULL) { 1074250223Sjhb path = malloc(MAXPATHLEN); 1075250223Sjhb for (i = 0; i < MAXPATHLEN - 1; i++) { 1076250223Sjhb if (!kvm_read_all(kd, (unsigned long)ksem.ks_path + i, 1077250223Sjhb path + i, 1)) 1078250223Sjhb break; 1079250223Sjhb if (path[i] == '\0') 1080250223Sjhb break; 1081250223Sjhb } 1082250223Sjhb path[i] = '\0'; 1083250223Sjhb if (i == 0) 1084250223Sjhb free(path); 1085250223Sjhb else 1086250223Sjhb fst->fs_path = path; 1087250223Sjhb } 1088250223Sjhb return (0); 1089250223Sjhb 1090250223Sjhbfail: 1091250378Strociny if (errbuf != NULL) 1092250378Strociny snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 1093250223Sjhb return (1); 1094250223Sjhb} 1095250223Sjhb 1096250223Sjhbstatic int 1097250223Sjhbprocstat_get_sem_info_sysctl(struct filestat *fst, struct semstat *sem, 1098250223Sjhb char *errbuf __unused) 1099250223Sjhb{ 1100250223Sjhb struct kinfo_file *kif; 1101250223Sjhb 1102250223Sjhb assert(sem); 1103250223Sjhb assert(fst); 1104250223Sjhb bzero(sem, sizeof(*sem)); 1105250223Sjhb kif = fst->fs_typedep; 1106250223Sjhb if (kif == NULL) 1107250223Sjhb return (0); 1108250223Sjhb sem->value = kif->kf_un.kf_sem.kf_sem_value; 1109250223Sjhb sem->mode = kif->kf_un.kf_sem.kf_sem_mode; 1110250223Sjhb return (0); 1111250223Sjhb} 1112250223Sjhb 1113250223Sjhbint 1114233760Sjhbprocstat_get_shm_info(struct procstat *procstat, struct filestat *fst, 1115233760Sjhb struct shmstat *shm, char *errbuf) 1116233760Sjhb{ 1117233760Sjhb 1118233760Sjhb assert(shm); 1119233760Sjhb if (procstat->type == PROCSTAT_KVM) { 1120233760Sjhb return (procstat_get_shm_info_kvm(procstat->kd, fst, shm, 1121233760Sjhb errbuf)); 1122249666Strociny } else if (procstat->type == PROCSTAT_SYSCTL || 1123249666Strociny procstat->type == PROCSTAT_CORE) { 1124233760Sjhb return (procstat_get_shm_info_sysctl(fst, shm, errbuf)); 1125233760Sjhb } else { 1126233760Sjhb warnx("unknown access method: %d", procstat->type); 1127250378Strociny if (errbuf != NULL) 1128250378Strociny snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 1129233760Sjhb return (1); 1130233760Sjhb } 1131233760Sjhb} 1132233760Sjhb 1133233760Sjhbstatic int 1134233760Sjhbprocstat_get_shm_info_kvm(kvm_t *kd, struct filestat *fst, 1135233760Sjhb struct shmstat *shm, char *errbuf) 1136233760Sjhb{ 1137233760Sjhb struct shmfd shmfd; 1138233760Sjhb void *shmfdp; 1139236717Sjhb char *path; 1140236717Sjhb int i; 1141233760Sjhb 1142233760Sjhb assert(kd); 1143233760Sjhb assert(shm); 1144233760Sjhb assert(fst); 1145233760Sjhb bzero(shm, sizeof(*shm)); 1146233760Sjhb shmfdp = fst->fs_typedep; 1147233760Sjhb if (shmfdp == NULL) 1148233760Sjhb goto fail; 1149233760Sjhb if (!kvm_read_all(kd, (unsigned long)shmfdp, &shmfd, 1150233760Sjhb sizeof(struct shmfd))) { 1151233760Sjhb warnx("can't read shmfd at %p", (void *)shmfdp); 1152233760Sjhb goto fail; 1153233760Sjhb } 1154233760Sjhb shm->mode = S_IFREG | shmfd.shm_mode; 1155233760Sjhb shm->size = shmfd.shm_size; 1156236717Sjhb if (fst->fs_path == NULL && shmfd.shm_path != NULL) { 1157236717Sjhb path = malloc(MAXPATHLEN); 1158236717Sjhb for (i = 0; i < MAXPATHLEN - 1; i++) { 1159236717Sjhb if (!kvm_read_all(kd, (unsigned long)shmfd.shm_path + i, 1160236717Sjhb path + i, 1)) 1161236717Sjhb break; 1162236717Sjhb if (path[i] == '\0') 1163236717Sjhb break; 1164236717Sjhb } 1165236717Sjhb path[i] = '\0'; 1166236717Sjhb if (i == 0) 1167236717Sjhb free(path); 1168236717Sjhb else 1169236717Sjhb fst->fs_path = path; 1170236717Sjhb } 1171233760Sjhb return (0); 1172233760Sjhb 1173233760Sjhbfail: 1174250378Strociny if (errbuf != NULL) 1175250378Strociny snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 1176233760Sjhb return (1); 1177233760Sjhb} 1178233760Sjhb 1179233760Sjhbstatic int 1180233760Sjhbprocstat_get_shm_info_sysctl(struct filestat *fst, struct shmstat *shm, 1181233760Sjhb char *errbuf __unused) 1182233760Sjhb{ 1183233760Sjhb struct kinfo_file *kif; 1184233760Sjhb 1185233760Sjhb assert(shm); 1186233760Sjhb assert(fst); 1187233760Sjhb bzero(shm, sizeof(*shm)); 1188233760Sjhb kif = fst->fs_typedep; 1189233760Sjhb if (kif == NULL) 1190233760Sjhb return (0); 1191233760Sjhb shm->size = kif->kf_un.kf_file.kf_file_size; 1192233760Sjhb shm->mode = kif->kf_un.kf_file.kf_file_mode; 1193233760Sjhb return (0); 1194233760Sjhb} 1195233760Sjhb 1196233760Sjhbint 1197221807Sstasprocstat_get_vnode_info(struct procstat *procstat, struct filestat *fst, 1198221807Sstas struct vnstat *vn, char *errbuf) 1199221807Sstas{ 1200221807Sstas 1201221807Sstas assert(vn); 1202221807Sstas if (procstat->type == PROCSTAT_KVM) { 1203221807Sstas return (procstat_get_vnode_info_kvm(procstat->kd, fst, vn, 1204221807Sstas errbuf)); 1205249666Strociny } else if (procstat->type == PROCSTAT_SYSCTL || 1206249666Strociny procstat->type == PROCSTAT_CORE) { 1207221807Sstas return (procstat_get_vnode_info_sysctl(fst, vn, errbuf)); 1208221807Sstas } else { 1209223276Sjilles warnx("unknown access method: %d", procstat->type); 1210250378Strociny if (errbuf != NULL) 1211250378Strociny snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 1212221807Sstas return (1); 1213221807Sstas } 1214221807Sstas} 1215221807Sstas 1216221807Sstasstatic int 1217221807Sstasprocstat_get_vnode_info_kvm(kvm_t *kd, struct filestat *fst, 1218221807Sstas struct vnstat *vn, char *errbuf) 1219221807Sstas{ 1220221807Sstas /* Filesystem specific handlers. */ 1221221807Sstas #define FSTYPE(fst) {#fst, fst##_filestat} 1222221807Sstas struct { 1223221807Sstas const char *tag; 1224221807Sstas int (*handler)(kvm_t *kd, struct vnode *vp, 1225221807Sstas struct vnstat *vn); 1226221807Sstas } fstypes[] = { 1227221807Sstas FSTYPE(devfs), 1228221807Sstas FSTYPE(isofs), 1229221807Sstas FSTYPE(msdosfs), 1230221807Sstas FSTYPE(nfs), 1231252356Sdavide FSTYPE(smbfs), 1232221807Sstas FSTYPE(udf), 1233221807Sstas FSTYPE(ufs), 1234221824Sstas#ifdef LIBPROCSTAT_ZFS 1235221807Sstas FSTYPE(zfs), 1236221807Sstas#endif 1237221807Sstas }; 1238221807Sstas#define NTYPES (sizeof(fstypes) / sizeof(*fstypes)) 1239221807Sstas struct vnode vnode; 1240221807Sstas char tagstr[12]; 1241221807Sstas void *vp; 1242221807Sstas int error, found; 1243221807Sstas unsigned int i; 1244221807Sstas 1245221807Sstas assert(kd); 1246221807Sstas assert(vn); 1247221807Sstas assert(fst); 1248221807Sstas vp = fst->fs_typedep; 1249221807Sstas if (vp == NULL) 1250221807Sstas goto fail; 1251221807Sstas error = kvm_read_all(kd, (unsigned long)vp, &vnode, sizeof(vnode)); 1252221807Sstas if (error == 0) { 1253221807Sstas warnx("can't read vnode at %p", (void *)vp); 1254221807Sstas goto fail; 1255221807Sstas } 1256221807Sstas bzero(vn, sizeof(*vn)); 1257221807Sstas vn->vn_type = vntype2psfsttype(vnode.v_type); 1258221807Sstas if (vnode.v_type == VNON || vnode.v_type == VBAD) 1259221807Sstas return (0); 1260221807Sstas error = kvm_read_all(kd, (unsigned long)vnode.v_tag, tagstr, 1261221807Sstas sizeof(tagstr)); 1262221807Sstas if (error == 0) { 1263221807Sstas warnx("can't read v_tag at %p", (void *)vp); 1264221807Sstas goto fail; 1265221807Sstas } 1266221807Sstas tagstr[sizeof(tagstr) - 1] = '\0'; 1267221807Sstas 1268221807Sstas /* 1269221807Sstas * Find appropriate handler. 1270221807Sstas */ 1271221807Sstas for (i = 0, found = 0; i < NTYPES; i++) 1272221807Sstas if (!strcmp(fstypes[i].tag, tagstr)) { 1273221807Sstas if (fstypes[i].handler(kd, &vnode, vn) != 0) { 1274221807Sstas goto fail; 1275221807Sstas } 1276221807Sstas break; 1277221807Sstas } 1278221807Sstas if (i == NTYPES) { 1279250378Strociny if (errbuf != NULL) 1280250378Strociny snprintf(errbuf, _POSIX2_LINE_MAX, "?(%s)", tagstr); 1281221807Sstas return (1); 1282221807Sstas } 1283221807Sstas vn->vn_mntdir = getmnton(kd, vnode.v_mount); 1284221807Sstas if ((vnode.v_type == VBLK || vnode.v_type == VCHR) && 1285221807Sstas vnode.v_rdev != NULL){ 1286221807Sstas vn->vn_dev = dev2udev(kd, vnode.v_rdev); 1287221807Sstas (void)kdevtoname(kd, vnode.v_rdev, vn->vn_devname); 1288221807Sstas } else { 1289221807Sstas vn->vn_dev = -1; 1290221807Sstas } 1291221807Sstas return (0); 1292221807Sstas 1293221807Sstasfail: 1294250378Strociny if (errbuf != NULL) 1295250378Strociny snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 1296221807Sstas return (1); 1297221807Sstas} 1298221807Sstas 1299221807Sstas/* 1300221807Sstas * kinfo vnode type to filestat translation. 1301221807Sstas */ 1302221807Sstasstatic int 1303221807Sstaskinfo_vtype2fst(int kfvtype) 1304221807Sstas{ 1305221807Sstas static struct { 1306221807Sstas int kf_vtype; 1307221807Sstas int fst_vtype; 1308221807Sstas } kfvtypes2fst[] = { 1309221807Sstas { KF_VTYPE_VBAD, PS_FST_VTYPE_VBAD }, 1310221807Sstas { KF_VTYPE_VBLK, PS_FST_VTYPE_VBLK }, 1311221807Sstas { KF_VTYPE_VCHR, PS_FST_VTYPE_VCHR }, 1312221807Sstas { KF_VTYPE_VDIR, PS_FST_VTYPE_VDIR }, 1313221807Sstas { KF_VTYPE_VFIFO, PS_FST_VTYPE_VFIFO }, 1314221807Sstas { KF_VTYPE_VLNK, PS_FST_VTYPE_VLNK }, 1315221807Sstas { KF_VTYPE_VNON, PS_FST_VTYPE_VNON }, 1316221807Sstas { KF_VTYPE_VREG, PS_FST_VTYPE_VREG }, 1317221807Sstas { KF_VTYPE_VSOCK, PS_FST_VTYPE_VSOCK } 1318221807Sstas }; 1319221807Sstas#define NKFVTYPES (sizeof(kfvtypes2fst) / sizeof(*kfvtypes2fst)) 1320221807Sstas unsigned int i; 1321221807Sstas 1322221807Sstas for (i = 0; i < NKFVTYPES; i++) 1323221807Sstas if (kfvtypes2fst[i].kf_vtype == kfvtype) 1324221807Sstas break; 1325221807Sstas if (i == NKFVTYPES) 1326221807Sstas return (PS_FST_VTYPE_UNKNOWN); 1327221807Sstas return (kfvtypes2fst[i].fst_vtype); 1328221807Sstas} 1329221807Sstas 1330221807Sstasstatic int 1331221807Sstasprocstat_get_vnode_info_sysctl(struct filestat *fst, struct vnstat *vn, 1332221807Sstas char *errbuf) 1333221807Sstas{ 1334221807Sstas struct statfs stbuf; 1335221807Sstas struct kinfo_file *kif; 1336221807Sstas struct kinfo_vmentry *kve; 1337221807Sstas uint64_t fileid; 1338221807Sstas uint64_t size; 1339221807Sstas char *name, *path; 1340221807Sstas uint32_t fsid; 1341221807Sstas uint16_t mode; 1342221807Sstas uint32_t rdev; 1343221807Sstas int vntype; 1344221807Sstas int status; 1345221807Sstas 1346221807Sstas assert(fst); 1347221807Sstas assert(vn); 1348221807Sstas bzero(vn, sizeof(*vn)); 1349221807Sstas if (fst->fs_typedep == NULL) 1350221807Sstas return (1); 1351221807Sstas if (fst->fs_uflags & PS_FST_UFLAG_MMAP) { 1352221807Sstas kve = fst->fs_typedep; 1353221807Sstas fileid = kve->kve_vn_fileid; 1354221807Sstas fsid = kve->kve_vn_fsid; 1355221807Sstas mode = kve->kve_vn_mode; 1356221807Sstas path = kve->kve_path; 1357221807Sstas rdev = kve->kve_vn_rdev; 1358221807Sstas size = kve->kve_vn_size; 1359221807Sstas vntype = kinfo_vtype2fst(kve->kve_vn_type); 1360221807Sstas status = kve->kve_status; 1361221807Sstas } else { 1362221807Sstas kif = fst->fs_typedep; 1363221807Sstas fileid = kif->kf_un.kf_file.kf_file_fileid; 1364221807Sstas fsid = kif->kf_un.kf_file.kf_file_fsid; 1365221807Sstas mode = kif->kf_un.kf_file.kf_file_mode; 1366221807Sstas path = kif->kf_path; 1367221807Sstas rdev = kif->kf_un.kf_file.kf_file_rdev; 1368221807Sstas size = kif->kf_un.kf_file.kf_file_size; 1369221807Sstas vntype = kinfo_vtype2fst(kif->kf_vnode_type); 1370221807Sstas status = kif->kf_status; 1371221807Sstas } 1372221807Sstas vn->vn_type = vntype; 1373221807Sstas if (vntype == PS_FST_VTYPE_VNON || vntype == PS_FST_VTYPE_VBAD) 1374221807Sstas return (0); 1375221807Sstas if ((status & KF_ATTR_VALID) == 0) { 1376250378Strociny if (errbuf != NULL) { 1377250378Strociny snprintf(errbuf, _POSIX2_LINE_MAX, 1378250378Strociny "? (no info available)"); 1379250378Strociny } 1380221807Sstas return (1); 1381221807Sstas } 1382221807Sstas if (path && *path) { 1383221807Sstas statfs(path, &stbuf); 1384221807Sstas vn->vn_mntdir = strdup(stbuf.f_mntonname); 1385221807Sstas } else 1386221807Sstas vn->vn_mntdir = strdup("-"); 1387221807Sstas vn->vn_dev = rdev; 1388221807Sstas if (vntype == PS_FST_VTYPE_VBLK) { 1389221807Sstas name = devname(rdev, S_IFBLK); 1390221807Sstas if (name != NULL) 1391221807Sstas strlcpy(vn->vn_devname, name, 1392221807Sstas sizeof(vn->vn_devname)); 1393221807Sstas } else if (vntype == PS_FST_VTYPE_VCHR) { 1394221807Sstas name = devname(vn->vn_dev, S_IFCHR); 1395221807Sstas if (name != NULL) 1396221807Sstas strlcpy(vn->vn_devname, name, 1397221807Sstas sizeof(vn->vn_devname)); 1398221807Sstas } 1399221807Sstas vn->vn_fsid = fsid; 1400221807Sstas vn->vn_fileid = fileid; 1401221807Sstas vn->vn_size = size; 1402221807Sstas vn->vn_mode = mode; 1403221807Sstas return (0); 1404221807Sstas} 1405221807Sstas 1406221807Sstasint 1407221807Sstasprocstat_get_socket_info(struct procstat *procstat, struct filestat *fst, 1408221807Sstas struct sockstat *sock, char *errbuf) 1409221807Sstas{ 1410221807Sstas 1411221807Sstas assert(sock); 1412221807Sstas if (procstat->type == PROCSTAT_KVM) { 1413221807Sstas return (procstat_get_socket_info_kvm(procstat->kd, fst, sock, 1414221807Sstas errbuf)); 1415249666Strociny } else if (procstat->type == PROCSTAT_SYSCTL || 1416249666Strociny procstat->type == PROCSTAT_CORE) { 1417221807Sstas return (procstat_get_socket_info_sysctl(fst, sock, errbuf)); 1418221807Sstas } else { 1419223276Sjilles warnx("unknown access method: %d", procstat->type); 1420250378Strociny if (errbuf != NULL) 1421250378Strociny snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 1422221807Sstas return (1); 1423221807Sstas } 1424221807Sstas} 1425221807Sstas 1426221807Sstasstatic int 1427221807Sstasprocstat_get_socket_info_kvm(kvm_t *kd, struct filestat *fst, 1428221807Sstas struct sockstat *sock, char *errbuf) 1429221807Sstas{ 1430221807Sstas struct domain dom; 1431221807Sstas struct inpcb inpcb; 1432221807Sstas struct protosw proto; 1433221807Sstas struct socket s; 1434221807Sstas struct unpcb unpcb; 1435221807Sstas ssize_t len; 1436221807Sstas void *so; 1437221807Sstas 1438221807Sstas assert(kd); 1439221807Sstas assert(sock); 1440221807Sstas assert(fst); 1441221807Sstas bzero(sock, sizeof(*sock)); 1442221807Sstas so = fst->fs_typedep; 1443221807Sstas if (so == NULL) 1444221807Sstas goto fail; 1445221807Sstas sock->so_addr = (uintptr_t)so; 1446221807Sstas /* fill in socket */ 1447221807Sstas if (!kvm_read_all(kd, (unsigned long)so, &s, 1448221807Sstas sizeof(struct socket))) { 1449221807Sstas warnx("can't read sock at %p", (void *)so); 1450221807Sstas goto fail; 1451221807Sstas } 1452221807Sstas /* fill in protosw entry */ 1453221807Sstas if (!kvm_read_all(kd, (unsigned long)s.so_proto, &proto, 1454221807Sstas sizeof(struct protosw))) { 1455221807Sstas warnx("can't read protosw at %p", (void *)s.so_proto); 1456221807Sstas goto fail; 1457221807Sstas } 1458221807Sstas /* fill in domain */ 1459221807Sstas if (!kvm_read_all(kd, (unsigned long)proto.pr_domain, &dom, 1460221807Sstas sizeof(struct domain))) { 1461221807Sstas warnx("can't read domain at %p", 1462221807Sstas (void *)proto.pr_domain); 1463221807Sstas goto fail; 1464221807Sstas } 1465221807Sstas if ((len = kvm_read(kd, (unsigned long)dom.dom_name, sock->dname, 1466221807Sstas sizeof(sock->dname) - 1)) < 0) { 1467221807Sstas warnx("can't read domain name at %p", (void *)dom.dom_name); 1468221807Sstas sock->dname[0] = '\0'; 1469221807Sstas } 1470221807Sstas else 1471221807Sstas sock->dname[len] = '\0'; 1472221807Sstas 1473221807Sstas /* 1474221807Sstas * Fill in known data. 1475221807Sstas */ 1476221807Sstas sock->type = s.so_type; 1477221807Sstas sock->proto = proto.pr_protocol; 1478221807Sstas sock->dom_family = dom.dom_family; 1479221807Sstas sock->so_pcb = (uintptr_t)s.so_pcb; 1480221807Sstas 1481221807Sstas /* 1482221807Sstas * Protocol specific data. 1483221807Sstas */ 1484221807Sstas switch(dom.dom_family) { 1485221807Sstas case AF_INET: 1486221807Sstas case AF_INET6: 1487221807Sstas if (proto.pr_protocol == IPPROTO_TCP) { 1488221807Sstas if (s.so_pcb) { 1489221807Sstas if (kvm_read(kd, (u_long)s.so_pcb, 1490221807Sstas (char *)&inpcb, sizeof(struct inpcb)) 1491221807Sstas != sizeof(struct inpcb)) { 1492221807Sstas warnx("can't read inpcb at %p", 1493221807Sstas (void *)s.so_pcb); 1494221807Sstas } else 1495221807Sstas sock->inp_ppcb = 1496221807Sstas (uintptr_t)inpcb.inp_ppcb; 1497221807Sstas } 1498221807Sstas } 1499221807Sstas break; 1500221807Sstas case AF_UNIX: 1501221807Sstas if (s.so_pcb) { 1502221807Sstas if (kvm_read(kd, (u_long)s.so_pcb, (char *)&unpcb, 1503221807Sstas sizeof(struct unpcb)) != sizeof(struct unpcb)){ 1504221807Sstas warnx("can't read unpcb at %p", 1505221807Sstas (void *)s.so_pcb); 1506221807Sstas } else if (unpcb.unp_conn) { 1507221807Sstas sock->so_rcv_sb_state = s.so_rcv.sb_state; 1508221807Sstas sock->so_snd_sb_state = s.so_snd.sb_state; 1509221807Sstas sock->unp_conn = (uintptr_t)unpcb.unp_conn; 1510221807Sstas } 1511221807Sstas } 1512221807Sstas break; 1513221807Sstas default: 1514221807Sstas break; 1515221807Sstas } 1516221807Sstas return (0); 1517221807Sstas 1518221807Sstasfail: 1519250378Strociny if (errbuf != NULL) 1520250378Strociny snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 1521221807Sstas return (1); 1522221807Sstas} 1523221807Sstas 1524221807Sstasstatic int 1525221807Sstasprocstat_get_socket_info_sysctl(struct filestat *fst, struct sockstat *sock, 1526221807Sstas char *errbuf __unused) 1527221807Sstas{ 1528221807Sstas struct kinfo_file *kif; 1529221807Sstas 1530221807Sstas assert(sock); 1531221807Sstas assert(fst); 1532221807Sstas bzero(sock, sizeof(*sock)); 1533221807Sstas kif = fst->fs_typedep; 1534221807Sstas if (kif == NULL) 1535221807Sstas return (0); 1536221807Sstas 1537221807Sstas /* 1538221807Sstas * Fill in known data. 1539221807Sstas */ 1540221807Sstas sock->type = kif->kf_sock_type; 1541221807Sstas sock->proto = kif->kf_sock_protocol; 1542221807Sstas sock->dom_family = kif->kf_sock_domain; 1543221807Sstas sock->so_pcb = kif->kf_un.kf_sock.kf_sock_pcb; 1544221807Sstas strlcpy(sock->dname, kif->kf_path, sizeof(sock->dname)); 1545221807Sstas bcopy(&kif->kf_sa_local, &sock->sa_local, kif->kf_sa_local.ss_len); 1546221807Sstas bcopy(&kif->kf_sa_peer, &sock->sa_peer, kif->kf_sa_peer.ss_len); 1547221807Sstas 1548221807Sstas /* 1549221807Sstas * Protocol specific data. 1550221807Sstas */ 1551221807Sstas switch(sock->dom_family) { 1552221807Sstas case AF_INET: 1553221807Sstas case AF_INET6: 1554221807Sstas if (sock->proto == IPPROTO_TCP) 1555221807Sstas sock->inp_ppcb = kif->kf_un.kf_sock.kf_sock_inpcb; 1556221807Sstas break; 1557221807Sstas case AF_UNIX: 1558221807Sstas if (kif->kf_un.kf_sock.kf_sock_unpconn != 0) { 1559221807Sstas sock->so_rcv_sb_state = 1560221807Sstas kif->kf_un.kf_sock.kf_sock_rcv_sb_state; 1561221807Sstas sock->so_snd_sb_state = 1562221807Sstas kif->kf_un.kf_sock.kf_sock_snd_sb_state; 1563221807Sstas sock->unp_conn = 1564221807Sstas kif->kf_un.kf_sock.kf_sock_unpconn; 1565221807Sstas } 1566221807Sstas break; 1567221807Sstas default: 1568221807Sstas break; 1569221807Sstas } 1570221807Sstas return (0); 1571221807Sstas} 1572221807Sstas 1573221807Sstas/* 1574221807Sstas * Descriptor flags to filestat translation. 1575221807Sstas */ 1576221807Sstasstatic int 1577221807Sstasto_filestat_flags(int flags) 1578221807Sstas{ 1579221807Sstas static struct { 1580221807Sstas int flag; 1581221807Sstas int fst_flag; 1582221807Sstas } fstflags[] = { 1583221807Sstas { FREAD, PS_FST_FFLAG_READ }, 1584221807Sstas { FWRITE, PS_FST_FFLAG_WRITE }, 1585221807Sstas { O_APPEND, PS_FST_FFLAG_APPEND }, 1586221807Sstas { O_ASYNC, PS_FST_FFLAG_ASYNC }, 1587221807Sstas { O_CREAT, PS_FST_FFLAG_CREAT }, 1588221807Sstas { O_DIRECT, PS_FST_FFLAG_DIRECT }, 1589221807Sstas { O_EXCL, PS_FST_FFLAG_EXCL }, 1590221807Sstas { O_EXEC, PS_FST_FFLAG_EXEC }, 1591221807Sstas { O_EXLOCK, PS_FST_FFLAG_EXLOCK }, 1592221807Sstas { O_NOFOLLOW, PS_FST_FFLAG_NOFOLLOW }, 1593221807Sstas { O_NONBLOCK, PS_FST_FFLAG_NONBLOCK }, 1594221807Sstas { O_SHLOCK, PS_FST_FFLAG_SHLOCK }, 1595221807Sstas { O_SYNC, PS_FST_FFLAG_SYNC }, 1596221807Sstas { O_TRUNC, PS_FST_FFLAG_TRUNC } 1597221807Sstas }; 1598221807Sstas#define NFSTFLAGS (sizeof(fstflags) / sizeof(*fstflags)) 1599221807Sstas int fst_flags; 1600221807Sstas unsigned int i; 1601221807Sstas 1602221807Sstas fst_flags = 0; 1603221807Sstas for (i = 0; i < NFSTFLAGS; i++) 1604221807Sstas if (flags & fstflags[i].flag) 1605221807Sstas fst_flags |= fstflags[i].fst_flag; 1606221807Sstas return (fst_flags); 1607221807Sstas} 1608221807Sstas 1609221807Sstas/* 1610221807Sstas * Vnode type to filestate translation. 1611221807Sstas */ 1612221807Sstasstatic int 1613221807Sstasvntype2psfsttype(int type) 1614221807Sstas{ 1615221807Sstas static struct { 1616221807Sstas int vtype; 1617221807Sstas int fst_vtype; 1618221807Sstas } vt2fst[] = { 1619221807Sstas { VBAD, PS_FST_VTYPE_VBAD }, 1620221807Sstas { VBLK, PS_FST_VTYPE_VBLK }, 1621221807Sstas { VCHR, PS_FST_VTYPE_VCHR }, 1622221807Sstas { VDIR, PS_FST_VTYPE_VDIR }, 1623221807Sstas { VFIFO, PS_FST_VTYPE_VFIFO }, 1624221807Sstas { VLNK, PS_FST_VTYPE_VLNK }, 1625221807Sstas { VNON, PS_FST_VTYPE_VNON }, 1626221807Sstas { VREG, PS_FST_VTYPE_VREG }, 1627221807Sstas { VSOCK, PS_FST_VTYPE_VSOCK } 1628221807Sstas }; 1629221807Sstas#define NVFTYPES (sizeof(vt2fst) / sizeof(*vt2fst)) 1630221807Sstas unsigned int i, fst_type; 1631221807Sstas 1632221807Sstas fst_type = PS_FST_VTYPE_UNKNOWN; 1633221807Sstas for (i = 0; i < NVFTYPES; i++) { 1634221807Sstas if (type == vt2fst[i].vtype) { 1635221807Sstas fst_type = vt2fst[i].fst_vtype; 1636221807Sstas break; 1637221807Sstas } 1638221807Sstas } 1639221807Sstas return (fst_type); 1640221807Sstas} 1641221807Sstas 1642221807Sstasstatic char * 1643221807Sstasgetmnton(kvm_t *kd, struct mount *m) 1644221807Sstas{ 1645223262Sbenl struct mount mnt; 1646221807Sstas static struct mtab { 1647221807Sstas struct mtab *next; 1648221807Sstas struct mount *m; 1649221807Sstas char mntonname[MNAMELEN + 1]; 1650221807Sstas } *mhead = NULL; 1651221807Sstas struct mtab *mt; 1652221807Sstas 1653221807Sstas for (mt = mhead; mt != NULL; mt = mt->next) 1654221807Sstas if (m == mt->m) 1655221807Sstas return (mt->mntonname); 1656221807Sstas if (!kvm_read_all(kd, (unsigned long)m, &mnt, sizeof(struct mount))) { 1657221807Sstas warnx("can't read mount table at %p", (void *)m); 1658221807Sstas return (NULL); 1659221807Sstas } 1660221807Sstas if ((mt = malloc(sizeof (struct mtab))) == NULL) 1661221807Sstas err(1, NULL); 1662221807Sstas mt->m = m; 1663221807Sstas bcopy(&mnt.mnt_stat.f_mntonname[0], &mt->mntonname[0], MNAMELEN); 1664223262Sbenl mt->mntonname[MNAMELEN] = '\0'; 1665221807Sstas mt->next = mhead; 1666221807Sstas mhead = mt; 1667221807Sstas return (mt->mntonname); 1668221807Sstas} 1669249666Strociny 1670249679Strociny/* 1671249679Strociny * Auxiliary structures and functions to get process environment or 1672249679Strociny * command line arguments. 1673249679Strociny */ 1674249679Strocinystruct argvec { 1675249679Strociny char *buf; 1676249679Strociny size_t bufsize; 1677249679Strociny char **argv; 1678249679Strociny size_t argc; 1679249679Strociny}; 1680249679Strociny 1681249679Strocinystatic struct argvec * 1682249679Strocinyargvec_alloc(size_t bufsize) 1683249679Strociny{ 1684249679Strociny struct argvec *av; 1685249679Strociny 1686249679Strociny av = malloc(sizeof(*av)); 1687249679Strociny if (av == NULL) 1688249679Strociny return (NULL); 1689249679Strociny av->bufsize = bufsize; 1690249679Strociny av->buf = malloc(av->bufsize); 1691249679Strociny if (av->buf == NULL) { 1692249679Strociny free(av); 1693249679Strociny return (NULL); 1694249679Strociny } 1695249679Strociny av->argc = 32; 1696249679Strociny av->argv = malloc(sizeof(char *) * av->argc); 1697249679Strociny if (av->argv == NULL) { 1698249679Strociny free(av->buf); 1699249679Strociny free(av); 1700249679Strociny return (NULL); 1701249679Strociny } 1702249679Strociny return av; 1703249679Strociny} 1704249679Strociny 1705249679Strocinystatic void 1706249679Strocinyargvec_free(struct argvec * av) 1707249679Strociny{ 1708249679Strociny 1709249679Strociny free(av->argv); 1710249679Strociny free(av->buf); 1711249679Strociny free(av); 1712249679Strociny} 1713249679Strociny 1714249679Strocinystatic char ** 1715249679Strocinygetargv(struct procstat *procstat, struct kinfo_proc *kp, size_t nchr, int env) 1716249679Strociny{ 1717249679Strociny int error, name[4], argc, i; 1718249679Strociny struct argvec *av, **avp; 1719249679Strociny enum psc_type type; 1720249679Strociny size_t len; 1721249679Strociny char *p, **argv; 1722249679Strociny 1723249679Strociny assert(procstat); 1724249679Strociny assert(kp); 1725249679Strociny if (procstat->type == PROCSTAT_KVM) { 1726249679Strociny warnx("can't use kvm access method"); 1727249679Strociny return (NULL); 1728249679Strociny } 1729249679Strociny if (procstat->type != PROCSTAT_SYSCTL && 1730249679Strociny procstat->type != PROCSTAT_CORE) { 1731249679Strociny warnx("unknown access method: %d", procstat->type); 1732249679Strociny return (NULL); 1733249679Strociny } 1734249679Strociny 1735249679Strociny if (nchr == 0 || nchr > ARG_MAX) 1736249679Strociny nchr = ARG_MAX; 1737249679Strociny 1738249679Strociny avp = (struct argvec **)(env ? &procstat->argv : &procstat->envv); 1739249679Strociny av = *avp; 1740249679Strociny 1741249679Strociny if (av == NULL) 1742249679Strociny { 1743249679Strociny av = argvec_alloc(nchr); 1744249679Strociny if (av == NULL) 1745249679Strociny { 1746249679Strociny warn("malloc(%zu)", nchr); 1747249679Strociny return (NULL); 1748249679Strociny } 1749249679Strociny *avp = av; 1750249679Strociny } else if (av->bufsize < nchr) { 1751249679Strociny av->buf = reallocf(av->buf, nchr); 1752249679Strociny if (av->buf == NULL) { 1753249679Strociny warn("malloc(%zu)", nchr); 1754249679Strociny return (NULL); 1755249679Strociny } 1756249679Strociny } 1757249679Strociny if (procstat->type == PROCSTAT_SYSCTL) { 1758249679Strociny name[0] = CTL_KERN; 1759249679Strociny name[1] = KERN_PROC; 1760249679Strociny name[2] = env ? KERN_PROC_ENV : KERN_PROC_ARGS; 1761249679Strociny name[3] = kp->ki_pid; 1762249679Strociny len = nchr; 1763312036Sngie error = sysctl(name, nitems(name), av->buf, &len, NULL, 0); 1764249679Strociny if (error != 0 && errno != ESRCH && errno != EPERM) 1765249679Strociny warn("sysctl(kern.proc.%s)", env ? "env" : "args"); 1766249679Strociny if (error != 0 || len == 0) 1767249679Strociny return (NULL); 1768249679Strociny } else /* procstat->type == PROCSTAT_CORE */ { 1769249679Strociny type = env ? PSC_TYPE_ENVV : PSC_TYPE_ARGV; 1770249679Strociny len = nchr; 1771249679Strociny if (procstat_core_get(procstat->core, type, av->buf, &len) 1772249679Strociny == NULL) { 1773249679Strociny return (NULL); 1774249679Strociny } 1775249679Strociny } 1776249679Strociny 1777249679Strociny argv = av->argv; 1778249679Strociny argc = av->argc; 1779249679Strociny i = 0; 1780249679Strociny for (p = av->buf; p < av->buf + len; p += strlen(p) + 1) { 1781249679Strociny argv[i++] = p; 1782249679Strociny if (i < argc) 1783249679Strociny continue; 1784249679Strociny /* Grow argv. */ 1785249679Strociny argc += argc; 1786249679Strociny argv = realloc(argv, sizeof(char *) * argc); 1787249679Strociny if (argv == NULL) { 1788249679Strociny warn("malloc(%zu)", sizeof(char *) * argc); 1789249679Strociny return (NULL); 1790249679Strociny } 1791249679Strociny av->argv = argv; 1792249679Strociny av->argc = argc; 1793249679Strociny } 1794249679Strociny argv[i] = NULL; 1795249679Strociny 1796249679Strociny return (argv); 1797249679Strociny} 1798249679Strociny 1799249679Strociny/* 1800249679Strociny * Return process command line arguments. 1801249679Strociny */ 1802249679Strocinychar ** 1803249679Strocinyprocstat_getargv(struct procstat *procstat, struct kinfo_proc *p, size_t nchr) 1804249679Strociny{ 1805249679Strociny 1806249679Strociny return (getargv(procstat, p, nchr, 0)); 1807249679Strociny} 1808249679Strociny 1809249679Strociny/* 1810249679Strociny * Free the buffer allocated by procstat_getargv(). 1811249679Strociny */ 1812249679Strocinyvoid 1813249679Strocinyprocstat_freeargv(struct procstat *procstat) 1814249679Strociny{ 1815249679Strociny 1816249679Strociny if (procstat->argv != NULL) { 1817249679Strociny argvec_free(procstat->argv); 1818249679Strociny procstat->argv = NULL; 1819249679Strociny } 1820249679Strociny} 1821249679Strociny 1822249679Strociny/* 1823249679Strociny * Return process environment. 1824249679Strociny */ 1825249679Strocinychar ** 1826249679Strocinyprocstat_getenvv(struct procstat *procstat, struct kinfo_proc *p, size_t nchr) 1827249679Strociny{ 1828249679Strociny 1829249679Strociny return (getargv(procstat, p, nchr, 1)); 1830249679Strociny} 1831249679Strociny 1832249679Strociny/* 1833249679Strociny * Free the buffer allocated by procstat_getenvv(). 1834249679Strociny */ 1835249679Strocinyvoid 1836249679Strocinyprocstat_freeenvv(struct procstat *procstat) 1837249679Strociny{ 1838249679Strociny if (procstat->envv != NULL) { 1839249679Strociny argvec_free(procstat->envv); 1840249679Strociny procstat->envv = NULL; 1841249679Strociny } 1842249679Strociny} 1843249679Strociny 1844249667Strocinystatic struct kinfo_vmentry * 1845249667Strocinykinfo_getvmmap_core(struct procstat_core *core, int *cntp) 1846249667Strociny{ 1847249667Strociny int cnt; 1848249667Strociny size_t len; 1849249667Strociny char *buf, *bp, *eb; 1850249667Strociny struct kinfo_vmentry *kiv, *kp, *kv; 1851249667Strociny 1852249667Strociny buf = procstat_core_get(core, PSC_TYPE_VMMAP, NULL, &len); 1853249667Strociny if (buf == NULL) 1854249667Strociny return (NULL); 1855249667Strociny 1856249667Strociny /* 1857249667Strociny * XXXMG: The code below is just copy&past from libutil. 1858249667Strociny * The code duplication can be avoided if libutil 1859249667Strociny * is extended to provide something like: 1860249667Strociny * struct kinfo_vmentry *kinfo_getvmmap_from_buf(const char *buf, 1861249667Strociny * size_t len, int *cntp); 1862249667Strociny */ 1863249667Strociny 1864249667Strociny /* Pass 1: count items */ 1865249667Strociny cnt = 0; 1866249667Strociny bp = buf; 1867249667Strociny eb = buf + len; 1868249667Strociny while (bp < eb) { 1869249667Strociny kv = (struct kinfo_vmentry *)(uintptr_t)bp; 1870295454Sjhb if (kv->kve_structsize == 0) 1871295454Sjhb break; 1872249667Strociny bp += kv->kve_structsize; 1873249667Strociny cnt++; 1874249667Strociny } 1875249667Strociny 1876249667Strociny kiv = calloc(cnt, sizeof(*kiv)); 1877249667Strociny if (kiv == NULL) { 1878249667Strociny free(buf); 1879249667Strociny return (NULL); 1880249667Strociny } 1881249667Strociny bp = buf; 1882249667Strociny eb = buf + len; 1883249667Strociny kp = kiv; 1884249667Strociny /* Pass 2: unpack */ 1885249667Strociny while (bp < eb) { 1886249667Strociny kv = (struct kinfo_vmentry *)(uintptr_t)bp; 1887295454Sjhb if (kv->kve_structsize == 0) 1888295454Sjhb break; 1889249667Strociny /* Copy/expand into pre-zeroed buffer */ 1890249667Strociny memcpy(kp, kv, kv->kve_structsize); 1891249667Strociny /* Advance to next packed record */ 1892249667Strociny bp += kv->kve_structsize; 1893249667Strociny /* Set field size to fixed length, advance */ 1894249667Strociny kp->kve_structsize = sizeof(*kp); 1895249667Strociny kp++; 1896249667Strociny } 1897249667Strociny free(buf); 1898249667Strociny *cntp = cnt; 1899249667Strociny return (kiv); /* Caller must free() return value */ 1900249667Strociny} 1901249667Strociny 1902249667Strocinystruct kinfo_vmentry * 1903249667Strocinyprocstat_getvmmap(struct procstat *procstat, struct kinfo_proc *kp, 1904249667Strociny unsigned int *cntp) 1905249667Strociny{ 1906249684Strociny 1907249667Strociny switch(procstat->type) { 1908249667Strociny case PROCSTAT_KVM: 1909249667Strociny warnx("kvm method is not supported"); 1910249667Strociny return (NULL); 1911249667Strociny case PROCSTAT_SYSCTL: 1912249667Strociny return (kinfo_getvmmap(kp->ki_pid, cntp)); 1913249667Strociny case PROCSTAT_CORE: 1914249667Strociny return (kinfo_getvmmap_core(procstat->core, cntp)); 1915249667Strociny default: 1916249667Strociny warnx("unknown access method: %d", procstat->type); 1917249667Strociny return (NULL); 1918249667Strociny } 1919249667Strociny} 1920249667Strociny 1921249667Strocinyvoid 1922249667Strocinyprocstat_freevmmap(struct procstat *procstat __unused, 1923249667Strociny struct kinfo_vmentry *vmmap) 1924249667Strociny{ 1925249667Strociny 1926249667Strociny free(vmmap); 1927249667Strociny} 1928249670Strociny 1929249670Strocinystatic gid_t * 1930250146Strocinyprocstat_getgroups_kvm(kvm_t *kd, struct kinfo_proc *kp, unsigned int *cntp) 1931250146Strociny{ 1932250146Strociny struct proc proc; 1933250146Strociny struct ucred ucred; 1934250146Strociny gid_t *groups; 1935250146Strociny size_t len; 1936250146Strociny 1937250146Strociny assert(kd != NULL); 1938250146Strociny assert(kp != NULL); 1939250146Strociny if (!kvm_read_all(kd, (unsigned long)kp->ki_paddr, &proc, 1940250146Strociny sizeof(proc))) { 1941250146Strociny warnx("can't read proc struct at %p for pid %d", 1942250146Strociny kp->ki_paddr, kp->ki_pid); 1943250146Strociny return (NULL); 1944250146Strociny } 1945250146Strociny if (proc.p_ucred == NOCRED) 1946250146Strociny return (NULL); 1947250146Strociny if (!kvm_read_all(kd, (unsigned long)proc.p_ucred, &ucred, 1948250146Strociny sizeof(ucred))) { 1949250146Strociny warnx("can't read ucred struct at %p for pid %d", 1950250146Strociny proc.p_ucred, kp->ki_pid); 1951250146Strociny return (NULL); 1952250146Strociny } 1953250146Strociny len = ucred.cr_ngroups * sizeof(gid_t); 1954250146Strociny groups = malloc(len); 1955250146Strociny if (groups == NULL) { 1956250146Strociny warn("malloc(%zu)", len); 1957250146Strociny return (NULL); 1958250146Strociny } 1959250146Strociny if (!kvm_read_all(kd, (unsigned long)ucred.cr_groups, groups, len)) { 1960250146Strociny warnx("can't read groups at %p for pid %d", 1961250146Strociny ucred.cr_groups, kp->ki_pid); 1962250146Strociny free(groups); 1963250146Strociny return (NULL); 1964250146Strociny } 1965250146Strociny *cntp = ucred.cr_ngroups; 1966250146Strociny return (groups); 1967250146Strociny} 1968250146Strociny 1969250146Strocinystatic gid_t * 1970249670Strocinyprocstat_getgroups_sysctl(pid_t pid, unsigned int *cntp) 1971249670Strociny{ 1972249670Strociny int mib[4]; 1973249670Strociny size_t len; 1974249670Strociny gid_t *groups; 1975249670Strociny 1976249670Strociny mib[0] = CTL_KERN; 1977249670Strociny mib[1] = KERN_PROC; 1978249670Strociny mib[2] = KERN_PROC_GROUPS; 1979249670Strociny mib[3] = pid; 1980249670Strociny len = (sysconf(_SC_NGROUPS_MAX) + 1) * sizeof(gid_t); 1981249670Strociny groups = malloc(len); 1982249670Strociny if (groups == NULL) { 1983249670Strociny warn("malloc(%zu)", len); 1984249670Strociny return (NULL); 1985249670Strociny } 1986312036Sngie if (sysctl(mib, nitems(mib), groups, &len, NULL, 0) == -1) { 1987249670Strociny warn("sysctl: kern.proc.groups: %d", pid); 1988249670Strociny free(groups); 1989249670Strociny return (NULL); 1990249670Strociny } 1991249670Strociny *cntp = len / sizeof(gid_t); 1992249670Strociny return (groups); 1993249670Strociny} 1994249670Strociny 1995249670Strocinystatic gid_t * 1996249670Strocinyprocstat_getgroups_core(struct procstat_core *core, unsigned int *cntp) 1997249670Strociny{ 1998249670Strociny size_t len; 1999249670Strociny gid_t *groups; 2000249670Strociny 2001249670Strociny groups = procstat_core_get(core, PSC_TYPE_GROUPS, NULL, &len); 2002249670Strociny if (groups == NULL) 2003249670Strociny return (NULL); 2004249670Strociny *cntp = len / sizeof(gid_t); 2005249670Strociny return (groups); 2006249670Strociny} 2007249670Strociny 2008249670Strocinygid_t * 2009249670Strocinyprocstat_getgroups(struct procstat *procstat, struct kinfo_proc *kp, 2010249670Strociny unsigned int *cntp) 2011249670Strociny{ 2012249670Strociny switch(procstat->type) { 2013249670Strociny case PROCSTAT_KVM: 2014250146Strociny return (procstat_getgroups_kvm(procstat->kd, kp, cntp)); 2015249670Strociny case PROCSTAT_SYSCTL: 2016249670Strociny return (procstat_getgroups_sysctl(kp->ki_pid, cntp)); 2017249670Strociny case PROCSTAT_CORE: 2018249670Strociny return (procstat_getgroups_core(procstat->core, cntp)); 2019249670Strociny default: 2020249670Strociny warnx("unknown access method: %d", procstat->type); 2021249670Strociny return (NULL); 2022249670Strociny } 2023249670Strociny} 2024249670Strociny 2025249670Strocinyvoid 2026249670Strocinyprocstat_freegroups(struct procstat *procstat __unused, gid_t *groups) 2027249670Strociny{ 2028249670Strociny 2029249670Strociny free(groups); 2030249670Strociny} 2031249672Strociny 2032249672Strocinystatic int 2033250146Strocinyprocstat_getumask_kvm(kvm_t *kd, struct kinfo_proc *kp, unsigned short *maskp) 2034250146Strociny{ 2035250146Strociny struct filedesc fd; 2036250146Strociny 2037250146Strociny assert(kd != NULL); 2038250146Strociny assert(kp != NULL); 2039250146Strociny if (kp->ki_fd == NULL) 2040250146Strociny return (-1); 2041250146Strociny if (!kvm_read_all(kd, (unsigned long)kp->ki_fd, &fd, sizeof(fd))) { 2042250146Strociny warnx("can't read filedesc at %p for pid %d", kp->ki_fd, 2043250146Strociny kp->ki_pid); 2044250146Strociny return (-1); 2045250146Strociny } 2046250146Strociny *maskp = fd.fd_cmask; 2047250146Strociny return (0); 2048250146Strociny} 2049250146Strociny 2050250146Strocinystatic int 2051249672Strocinyprocstat_getumask_sysctl(pid_t pid, unsigned short *maskp) 2052249672Strociny{ 2053249672Strociny int error; 2054249672Strociny int mib[4]; 2055249672Strociny size_t len; 2056249672Strociny 2057249672Strociny mib[0] = CTL_KERN; 2058249672Strociny mib[1] = KERN_PROC; 2059249672Strociny mib[2] = KERN_PROC_UMASK; 2060249672Strociny mib[3] = pid; 2061249672Strociny len = sizeof(*maskp); 2062312036Sngie error = sysctl(mib, nitems(mib), maskp, &len, NULL, 0); 2063262947Srwatson if (error != 0 && errno != ESRCH && errno != EPERM) 2064249672Strociny warn("sysctl: kern.proc.umask: %d", pid); 2065249672Strociny return (error); 2066249672Strociny} 2067249672Strociny 2068249672Strocinystatic int 2069249672Strocinyprocstat_getumask_core(struct procstat_core *core, unsigned short *maskp) 2070249672Strociny{ 2071249672Strociny size_t len; 2072249672Strociny unsigned short *buf; 2073249672Strociny 2074249672Strociny buf = procstat_core_get(core, PSC_TYPE_UMASK, NULL, &len); 2075249672Strociny if (buf == NULL) 2076249672Strociny return (-1); 2077249672Strociny if (len < sizeof(*maskp)) { 2078249672Strociny free(buf); 2079249672Strociny return (-1); 2080249672Strociny } 2081249672Strociny *maskp = *buf; 2082249672Strociny free(buf); 2083249672Strociny return (0); 2084249672Strociny} 2085249672Strociny 2086249672Strocinyint 2087249672Strocinyprocstat_getumask(struct procstat *procstat, struct kinfo_proc *kp, 2088249672Strociny unsigned short *maskp) 2089249672Strociny{ 2090249672Strociny switch(procstat->type) { 2091249672Strociny case PROCSTAT_KVM: 2092250146Strociny return (procstat_getumask_kvm(procstat->kd, kp, maskp)); 2093249672Strociny case PROCSTAT_SYSCTL: 2094249672Strociny return (procstat_getumask_sysctl(kp->ki_pid, maskp)); 2095249672Strociny case PROCSTAT_CORE: 2096249672Strociny return (procstat_getumask_core(procstat->core, maskp)); 2097249672Strociny default: 2098249672Strociny warnx("unknown access method: %d", procstat->type); 2099249672Strociny return (-1); 2100249672Strociny } 2101249672Strociny} 2102249674Strociny 2103249674Strocinystatic int 2104250146Strocinyprocstat_getrlimit_kvm(kvm_t *kd, struct kinfo_proc *kp, int which, 2105250146Strociny struct rlimit* rlimit) 2106250146Strociny{ 2107250146Strociny struct proc proc; 2108250146Strociny unsigned long offset; 2109250146Strociny 2110250146Strociny assert(kd != NULL); 2111250146Strociny assert(kp != NULL); 2112250146Strociny assert(which >= 0 && which < RLIM_NLIMITS); 2113250146Strociny if (!kvm_read_all(kd, (unsigned long)kp->ki_paddr, &proc, 2114250146Strociny sizeof(proc))) { 2115250146Strociny warnx("can't read proc struct at %p for pid %d", 2116250146Strociny kp->ki_paddr, kp->ki_pid); 2117250146Strociny return (-1); 2118250146Strociny } 2119250146Strociny if (proc.p_limit == NULL) 2120250146Strociny return (-1); 2121250146Strociny offset = (unsigned long)proc.p_limit + sizeof(struct rlimit) * which; 2122250146Strociny if (!kvm_read_all(kd, offset, rlimit, sizeof(*rlimit))) { 2123250146Strociny warnx("can't read rlimit struct at %p for pid %d", 2124250146Strociny (void *)offset, kp->ki_pid); 2125250146Strociny return (-1); 2126250146Strociny } 2127250146Strociny return (0); 2128250146Strociny} 2129250146Strociny 2130250146Strocinystatic int 2131249674Strocinyprocstat_getrlimit_sysctl(pid_t pid, int which, struct rlimit* rlimit) 2132249674Strociny{ 2133249674Strociny int error, name[5]; 2134249674Strociny size_t len; 2135249674Strociny 2136249674Strociny name[0] = CTL_KERN; 2137249674Strociny name[1] = KERN_PROC; 2138249674Strociny name[2] = KERN_PROC_RLIMIT; 2139249674Strociny name[3] = pid; 2140249674Strociny name[4] = which; 2141249674Strociny len = sizeof(struct rlimit); 2142312036Sngie error = sysctl(name, nitems(name), rlimit, &len, NULL, 0); 2143249674Strociny if (error < 0 && errno != ESRCH) { 2144249674Strociny warn("sysctl: kern.proc.rlimit: %d", pid); 2145249674Strociny return (-1); 2146249674Strociny } 2147249674Strociny if (error < 0 || len != sizeof(struct rlimit)) 2148249674Strociny return (-1); 2149249674Strociny return (0); 2150249674Strociny} 2151249674Strociny 2152249674Strocinystatic int 2153249674Strocinyprocstat_getrlimit_core(struct procstat_core *core, int which, 2154249674Strociny struct rlimit* rlimit) 2155249674Strociny{ 2156249674Strociny size_t len; 2157249674Strociny struct rlimit* rlimits; 2158249674Strociny 2159249674Strociny if (which < 0 || which >= RLIM_NLIMITS) { 2160249674Strociny errno = EINVAL; 2161249674Strociny warn("getrlimit: which"); 2162249674Strociny return (-1); 2163249674Strociny } 2164249674Strociny rlimits = procstat_core_get(core, PSC_TYPE_RLIMIT, NULL, &len); 2165249674Strociny if (rlimits == NULL) 2166249674Strociny return (-1); 2167249674Strociny if (len < sizeof(struct rlimit) * RLIM_NLIMITS) { 2168249674Strociny free(rlimits); 2169249674Strociny return (-1); 2170249674Strociny } 2171249674Strociny *rlimit = rlimits[which]; 2172249674Strociny return (0); 2173249674Strociny} 2174249674Strociny 2175249674Strocinyint 2176249674Strocinyprocstat_getrlimit(struct procstat *procstat, struct kinfo_proc *kp, int which, 2177249674Strociny struct rlimit* rlimit) 2178249674Strociny{ 2179249674Strociny switch(procstat->type) { 2180249674Strociny case PROCSTAT_KVM: 2181250146Strociny return (procstat_getrlimit_kvm(procstat->kd, kp, which, 2182250146Strociny rlimit)); 2183249674Strociny case PROCSTAT_SYSCTL: 2184249674Strociny return (procstat_getrlimit_sysctl(kp->ki_pid, which, rlimit)); 2185249674Strociny case PROCSTAT_CORE: 2186249674Strociny return (procstat_getrlimit_core(procstat->core, which, rlimit)); 2187249674Strociny default: 2188249674Strociny warnx("unknown access method: %d", procstat->type); 2189249674Strociny return (-1); 2190249674Strociny } 2191249674Strociny} 2192249676Strociny 2193249676Strocinystatic int 2194249676Strocinyprocstat_getpathname_sysctl(pid_t pid, char *pathname, size_t maxlen) 2195249676Strociny{ 2196249676Strociny int error, name[4]; 2197249676Strociny size_t len; 2198249676Strociny 2199249676Strociny name[0] = CTL_KERN; 2200249676Strociny name[1] = KERN_PROC; 2201249676Strociny name[2] = KERN_PROC_PATHNAME; 2202249676Strociny name[3] = pid; 2203249676Strociny len = maxlen; 2204312036Sngie error = sysctl(name, nitems(name), pathname, &len, NULL, 0); 2205249676Strociny if (error != 0 && errno != ESRCH) 2206249676Strociny warn("sysctl: kern.proc.pathname: %d", pid); 2207249676Strociny if (len == 0) 2208249676Strociny pathname[0] = '\0'; 2209249676Strociny return (error); 2210249676Strociny} 2211249676Strociny 2212249676Strocinystatic int 2213249676Strocinyprocstat_getpathname_core(struct procstat_core *core, char *pathname, 2214249676Strociny size_t maxlen) 2215249676Strociny{ 2216249676Strociny struct kinfo_file *files; 2217249676Strociny int cnt, i, result; 2218249676Strociny 2219249676Strociny files = kinfo_getfile_core(core, &cnt); 2220249676Strociny if (files == NULL) 2221249676Strociny return (-1); 2222249676Strociny result = -1; 2223249676Strociny for (i = 0; i < cnt; i++) { 2224249676Strociny if (files[i].kf_fd != KF_FD_TYPE_TEXT) 2225249676Strociny continue; 2226249676Strociny strncpy(pathname, files[i].kf_path, maxlen); 2227249676Strociny result = 0; 2228249676Strociny break; 2229249676Strociny } 2230249676Strociny free(files); 2231249676Strociny return (result); 2232249676Strociny} 2233249676Strociny 2234249676Strocinyint 2235249676Strocinyprocstat_getpathname(struct procstat *procstat, struct kinfo_proc *kp, 2236249676Strociny char *pathname, size_t maxlen) 2237249676Strociny{ 2238249676Strociny switch(procstat->type) { 2239249676Strociny case PROCSTAT_KVM: 2240250147Strociny /* XXX: Return empty string. */ 2241250147Strociny if (maxlen > 0) 2242250147Strociny pathname[0] = '\0'; 2243250147Strociny return (0); 2244249676Strociny case PROCSTAT_SYSCTL: 2245249676Strociny return (procstat_getpathname_sysctl(kp->ki_pid, pathname, 2246249676Strociny maxlen)); 2247249676Strociny case PROCSTAT_CORE: 2248249676Strociny return (procstat_getpathname_core(procstat->core, pathname, 2249249676Strociny maxlen)); 2250249676Strociny default: 2251249676Strociny warnx("unknown access method: %d", procstat->type); 2252249676Strociny return (-1); 2253249676Strociny } 2254249676Strociny} 2255249677Strociny 2256249677Strocinystatic int 2257250146Strocinyprocstat_getosrel_kvm(kvm_t *kd, struct kinfo_proc *kp, int *osrelp) 2258250146Strociny{ 2259250146Strociny struct proc proc; 2260250146Strociny 2261250146Strociny assert(kd != NULL); 2262250146Strociny assert(kp != NULL); 2263250146Strociny if (!kvm_read_all(kd, (unsigned long)kp->ki_paddr, &proc, 2264250146Strociny sizeof(proc))) { 2265250146Strociny warnx("can't read proc struct at %p for pid %d", 2266250146Strociny kp->ki_paddr, kp->ki_pid); 2267250146Strociny return (-1); 2268250146Strociny } 2269250146Strociny *osrelp = proc.p_osrel; 2270250146Strociny return (0); 2271250146Strociny} 2272250146Strociny 2273250146Strocinystatic int 2274249677Strocinyprocstat_getosrel_sysctl(pid_t pid, int *osrelp) 2275249677Strociny{ 2276249677Strociny int error, name[4]; 2277249677Strociny size_t len; 2278249677Strociny 2279249677Strociny name[0] = CTL_KERN; 2280249677Strociny name[1] = KERN_PROC; 2281249677Strociny name[2] = KERN_PROC_OSREL; 2282249677Strociny name[3] = pid; 2283249677Strociny len = sizeof(*osrelp); 2284312036Sngie error = sysctl(name, nitems(name), osrelp, &len, NULL, 0); 2285249677Strociny if (error != 0 && errno != ESRCH) 2286249677Strociny warn("sysctl: kern.proc.osrel: %d", pid); 2287249677Strociny return (error); 2288249677Strociny} 2289249677Strociny 2290249677Strocinystatic int 2291249677Strocinyprocstat_getosrel_core(struct procstat_core *core, int *osrelp) 2292249677Strociny{ 2293249677Strociny size_t len; 2294249677Strociny int *buf; 2295249677Strociny 2296249677Strociny buf = procstat_core_get(core, PSC_TYPE_OSREL, NULL, &len); 2297249677Strociny if (buf == NULL) 2298249677Strociny return (-1); 2299249677Strociny if (len < sizeof(*osrelp)) { 2300249677Strociny free(buf); 2301249677Strociny return (-1); 2302249677Strociny } 2303249677Strociny *osrelp = *buf; 2304249677Strociny free(buf); 2305249677Strociny return (0); 2306249677Strociny} 2307249677Strociny 2308249677Strocinyint 2309249677Strocinyprocstat_getosrel(struct procstat *procstat, struct kinfo_proc *kp, int *osrelp) 2310249677Strociny{ 2311249677Strociny switch(procstat->type) { 2312249677Strociny case PROCSTAT_KVM: 2313250146Strociny return (procstat_getosrel_kvm(procstat->kd, kp, osrelp)); 2314249677Strociny case PROCSTAT_SYSCTL: 2315249677Strociny return (procstat_getosrel_sysctl(kp->ki_pid, osrelp)); 2316249677Strociny case PROCSTAT_CORE: 2317249677Strociny return (procstat_getosrel_core(procstat->core, osrelp)); 2318249677Strociny default: 2319249677Strociny warnx("unknown access method: %d", procstat->type); 2320249677Strociny return (-1); 2321249677Strociny } 2322249677Strociny} 2323249681Strociny 2324249681Strociny#define PROC_AUXV_MAX 256 2325249681Strociny 2326249681Strociny#if __ELF_WORD_SIZE == 64 2327249681Strocinystatic const char *elf32_sv_names[] = { 2328249681Strociny "Linux ELF32", 2329249681Strociny "FreeBSD ELF32", 2330249681Strociny}; 2331249681Strociny 2332249681Strocinystatic int 2333249681Strocinyis_elf32_sysctl(pid_t pid) 2334249681Strociny{ 2335249681Strociny int error, name[4]; 2336249681Strociny size_t len, i; 2337249681Strociny static char sv_name[256]; 2338249681Strociny 2339249681Strociny name[0] = CTL_KERN; 2340249681Strociny name[1] = KERN_PROC; 2341249681Strociny name[2] = KERN_PROC_SV_NAME; 2342249681Strociny name[3] = pid; 2343249681Strociny len = sizeof(sv_name); 2344312036Sngie error = sysctl(name, nitems(name), sv_name, &len, NULL, 0); 2345249681Strociny if (error != 0 || len == 0) 2346249681Strociny return (0); 2347249681Strociny for (i = 0; i < sizeof(elf32_sv_names) / sizeof(*elf32_sv_names); i++) { 2348249681Strociny if (strncmp(sv_name, elf32_sv_names[i], sizeof(sv_name)) == 0) 2349249681Strociny return (1); 2350249681Strociny } 2351249681Strociny return (0); 2352249681Strociny} 2353249681Strociny 2354249681Strocinystatic Elf_Auxinfo * 2355249681Strocinyprocstat_getauxv32_sysctl(pid_t pid, unsigned int *cntp) 2356249681Strociny{ 2357249681Strociny Elf_Auxinfo *auxv; 2358249681Strociny Elf32_Auxinfo *auxv32; 2359249681Strociny void *ptr; 2360249681Strociny size_t len; 2361249681Strociny unsigned int i, count; 2362249681Strociny int name[4]; 2363249681Strociny 2364249681Strociny name[0] = CTL_KERN; 2365249681Strociny name[1] = KERN_PROC; 2366249681Strociny name[2] = KERN_PROC_AUXV; 2367249681Strociny name[3] = pid; 2368249681Strociny len = PROC_AUXV_MAX * sizeof(Elf32_Auxinfo); 2369249681Strociny auxv = NULL; 2370249681Strociny auxv32 = malloc(len); 2371249681Strociny if (auxv32 == NULL) { 2372249681Strociny warn("malloc(%zu)", len); 2373249681Strociny goto out; 2374249681Strociny } 2375312036Sngie if (sysctl(name, nitems(name), auxv32, &len, NULL, 0) == -1) { 2376249681Strociny if (errno != ESRCH && errno != EPERM) 2377249681Strociny warn("sysctl: kern.proc.auxv: %d: %d", pid, errno); 2378249681Strociny goto out; 2379249681Strociny } 2380249681Strociny count = len / sizeof(Elf_Auxinfo); 2381249681Strociny auxv = malloc(count * sizeof(Elf_Auxinfo)); 2382249681Strociny if (auxv == NULL) { 2383249681Strociny warn("malloc(%zu)", count * sizeof(Elf_Auxinfo)); 2384249681Strociny goto out; 2385249681Strociny } 2386249681Strociny for (i = 0; i < count; i++) { 2387249681Strociny /* 2388249681Strociny * XXX: We expect that values for a_type on a 32-bit platform 2389249681Strociny * are directly mapped to values on 64-bit one, which is not 2390249681Strociny * necessarily true. 2391249681Strociny */ 2392249681Strociny auxv[i].a_type = auxv32[i].a_type; 2393249681Strociny ptr = &auxv32[i].a_un; 2394249681Strociny auxv[i].a_un.a_val = *((uint32_t *)ptr); 2395249681Strociny } 2396249681Strociny *cntp = count; 2397249681Strocinyout: 2398249681Strociny free(auxv32); 2399249681Strociny return (auxv); 2400249681Strociny} 2401249681Strociny#endif /* __ELF_WORD_SIZE == 64 */ 2402249681Strociny 2403249681Strocinystatic Elf_Auxinfo * 2404249681Strocinyprocstat_getauxv_sysctl(pid_t pid, unsigned int *cntp) 2405249681Strociny{ 2406249681Strociny Elf_Auxinfo *auxv; 2407249681Strociny int name[4]; 2408249681Strociny size_t len; 2409249681Strociny 2410249681Strociny#if __ELF_WORD_SIZE == 64 2411249681Strociny if (is_elf32_sysctl(pid)) 2412249681Strociny return (procstat_getauxv32_sysctl(pid, cntp)); 2413249681Strociny#endif 2414249681Strociny name[0] = CTL_KERN; 2415249681Strociny name[1] = KERN_PROC; 2416249681Strociny name[2] = KERN_PROC_AUXV; 2417249681Strociny name[3] = pid; 2418249681Strociny len = PROC_AUXV_MAX * sizeof(Elf_Auxinfo); 2419249681Strociny auxv = malloc(len); 2420249681Strociny if (auxv == NULL) { 2421249681Strociny warn("malloc(%zu)", len); 2422249681Strociny return (NULL); 2423249681Strociny } 2424312036Sngie if (sysctl(name, nitems(name), auxv, &len, NULL, 0) == -1) { 2425249681Strociny if (errno != ESRCH && errno != EPERM) 2426249681Strociny warn("sysctl: kern.proc.auxv: %d: %d", pid, errno); 2427249681Strociny free(auxv); 2428249681Strociny return (NULL); 2429249681Strociny } 2430249681Strociny *cntp = len / sizeof(Elf_Auxinfo); 2431249681Strociny return (auxv); 2432249681Strociny} 2433249681Strociny 2434249681Strocinystatic Elf_Auxinfo * 2435249681Strocinyprocstat_getauxv_core(struct procstat_core *core, unsigned int *cntp) 2436249681Strociny{ 2437249681Strociny Elf_Auxinfo *auxv; 2438249681Strociny size_t len; 2439249681Strociny 2440249681Strociny auxv = procstat_core_get(core, PSC_TYPE_AUXV, NULL, &len); 2441249681Strociny if (auxv == NULL) 2442249681Strociny return (NULL); 2443249681Strociny *cntp = len / sizeof(Elf_Auxinfo); 2444249681Strociny return (auxv); 2445249681Strociny} 2446249681Strociny 2447249681StrocinyElf_Auxinfo * 2448249681Strocinyprocstat_getauxv(struct procstat *procstat, struct kinfo_proc *kp, 2449249681Strociny unsigned int *cntp) 2450249681Strociny{ 2451249681Strociny switch(procstat->type) { 2452249681Strociny case PROCSTAT_KVM: 2453249681Strociny warnx("kvm method is not supported"); 2454249681Strociny return (NULL); 2455249681Strociny case PROCSTAT_SYSCTL: 2456249681Strociny return (procstat_getauxv_sysctl(kp->ki_pid, cntp)); 2457249681Strociny case PROCSTAT_CORE: 2458249681Strociny return (procstat_getauxv_core(procstat->core, cntp)); 2459249681Strociny default: 2460249681Strociny warnx("unknown access method: %d", procstat->type); 2461249681Strociny return (NULL); 2462249681Strociny } 2463249681Strociny} 2464249681Strociny 2465249681Strocinyvoid 2466249681Strocinyprocstat_freeauxv(struct procstat *procstat __unused, Elf_Auxinfo *auxv) 2467249681Strociny{ 2468249681Strociny 2469249681Strociny free(auxv); 2470249681Strociny} 2471249684Strociny 2472249684Strocinystatic struct kinfo_kstack * 2473249684Strocinyprocstat_getkstack_sysctl(pid_t pid, int *cntp) 2474249684Strociny{ 2475249684Strociny struct kinfo_kstack *kkstp; 2476249684Strociny int error, name[4]; 2477249684Strociny size_t len; 2478249684Strociny 2479249684Strociny name[0] = CTL_KERN; 2480249684Strociny name[1] = KERN_PROC; 2481249684Strociny name[2] = KERN_PROC_KSTACK; 2482249684Strociny name[3] = pid; 2483249684Strociny 2484249684Strociny len = 0; 2485312036Sngie error = sysctl(name, nitems(name), NULL, &len, NULL, 0); 2486249684Strociny if (error < 0 && errno != ESRCH && errno != EPERM && errno != ENOENT) { 2487249684Strociny warn("sysctl: kern.proc.kstack: %d", pid); 2488249684Strociny return (NULL); 2489249684Strociny } 2490249684Strociny if (error == -1 && errno == ENOENT) { 2491249684Strociny warnx("sysctl: kern.proc.kstack unavailable" 2492249684Strociny " (options DDB or options STACK required in kernel)"); 2493249684Strociny return (NULL); 2494249684Strociny } 2495249684Strociny if (error == -1) 2496249684Strociny return (NULL); 2497249684Strociny kkstp = malloc(len); 2498249684Strociny if (kkstp == NULL) { 2499249684Strociny warn("malloc(%zu)", len); 2500249684Strociny return (NULL); 2501249684Strociny } 2502312036Sngie if (sysctl(name, nitems(name), kkstp, &len, NULL, 0) == -1) { 2503249684Strociny warn("sysctl: kern.proc.pid: %d", pid); 2504249684Strociny free(kkstp); 2505249684Strociny return (NULL); 2506249684Strociny } 2507249684Strociny *cntp = len / sizeof(*kkstp); 2508249684Strociny 2509249684Strociny return (kkstp); 2510249684Strociny} 2511249684Strociny 2512249684Strocinystruct kinfo_kstack * 2513249684Strocinyprocstat_getkstack(struct procstat *procstat, struct kinfo_proc *kp, 2514249684Strociny unsigned int *cntp) 2515249684Strociny{ 2516249684Strociny switch(procstat->type) { 2517249684Strociny case PROCSTAT_KVM: 2518249684Strociny warnx("kvm method is not supported"); 2519249684Strociny return (NULL); 2520249684Strociny case PROCSTAT_SYSCTL: 2521249684Strociny return (procstat_getkstack_sysctl(kp->ki_pid, cntp)); 2522249684Strociny case PROCSTAT_CORE: 2523249684Strociny warnx("core method is not supported"); 2524249684Strociny return (NULL); 2525249684Strociny default: 2526249684Strociny warnx("unknown access method: %d", procstat->type); 2527249684Strociny return (NULL); 2528249684Strociny } 2529249684Strociny} 2530249684Strociny 2531249684Strocinyvoid 2532249684Strocinyprocstat_freekstack(struct procstat *procstat __unused, 2533249684Strociny struct kinfo_kstack *kkstp) 2534249684Strociny{ 2535249684Strociny 2536249684Strociny free(kkstp); 2537249684Strociny} 2538