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$"); 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> 64256242Spjd#include <sys/capability.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; 285221807Sstas error = sysctl(name, 4, 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; 302251637Sjhb error = sysctl(name, 4, 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; 770249666Strociny bp += kf->kf_structsize; 771249666Strociny cnt++; 772249666Strociny } 773249666Strociny 774249666Strociny kif = calloc(cnt, sizeof(*kif)); 775249666Strociny if (kif == NULL) { 776249666Strociny free(buf); 777249666Strociny return (NULL); 778249666Strociny } 779249666Strociny bp = buf; 780249666Strociny eb = buf + len; 781249666Strociny kp = kif; 782249666Strociny /* Pass 2: unpack */ 783249666Strociny while (bp < eb) { 784249666Strociny kf = (struct kinfo_file *)(uintptr_t)bp; 785249666Strociny /* Copy/expand into pre-zeroed buffer */ 786249666Strociny memcpy(kp, kf, kf->kf_structsize); 787249666Strociny /* Advance to next packed record */ 788249666Strociny bp += kf->kf_structsize; 789249666Strociny /* Set field size to fixed length, advance */ 790249666Strociny kp->kf_structsize = sizeof(*kp); 791249666Strociny kp++; 792249666Strociny } 793249666Strociny free(buf); 794249666Strociny *cntp = cnt; 795249666Strociny return (kif); /* Caller must free() return value */ 796249666Strociny} 797249666Strociny 798221807Sstasstatic struct filestat_list * 799249666Strocinyprocstat_getfiles_sysctl(struct procstat *procstat, struct kinfo_proc *kp, 800249666Strociny int mmapped) 801221807Sstas{ 802221807Sstas struct kinfo_file *kif, *files; 803221807Sstas struct kinfo_vmentry *kve, *vmentries; 804221807Sstas struct filestat_list *head; 805221807Sstas struct filestat *entry; 806221807Sstas char *path; 807221807Sstas off_t offset; 808221807Sstas int cnt, fd, fflags; 809221807Sstas int i, type, uflags; 810221807Sstas int refcount; 811224859Srwatson cap_rights_t cap_rights; 812221807Sstas 813221807Sstas assert(kp); 814221807Sstas if (kp->ki_fd == NULL) 815221807Sstas return (NULL); 816249666Strociny switch(procstat->type) { 817249666Strociny case PROCSTAT_SYSCTL: 818249666Strociny files = kinfo_getfile(kp->ki_pid, &cnt); 819249666Strociny break; 820249666Strociny case PROCSTAT_CORE: 821249666Strociny files = kinfo_getfile_core(procstat->core, &cnt); 822249666Strociny break; 823249666Strociny default: 824249666Strociny assert(!"invalid type"); 825249666Strociny } 826221807Sstas if (files == NULL && errno != EPERM) { 827221807Sstas warn("kinfo_getfile()"); 828221807Sstas return (NULL); 829221807Sstas } 830221807Sstas procstat->files = files; 831221807Sstas 832221807Sstas /* 833221807Sstas * Allocate list head. 834221807Sstas */ 835221807Sstas head = malloc(sizeof(*head)); 836221807Sstas if (head == NULL) 837221807Sstas return (NULL); 838221807Sstas STAILQ_INIT(head); 839221807Sstas for (i = 0; i < cnt; i++) { 840221807Sstas kif = &files[i]; 841221807Sstas 842221807Sstas type = kinfo_type2fst(kif->kf_type); 843221807Sstas fd = kif->kf_fd >= 0 ? kif->kf_fd : -1; 844221807Sstas fflags = kinfo_fflags2fst(kif->kf_flags); 845221807Sstas uflags = kinfo_uflags2fst(kif->kf_fd); 846221807Sstas refcount = kif->kf_ref_count; 847221807Sstas offset = kif->kf_offset; 848221807Sstas if (*kif->kf_path != '\0') 849221807Sstas path = strdup(kif->kf_path); 850221807Sstas else 851221807Sstas path = NULL; 852224859Srwatson cap_rights = kif->kf_cap_rights; 853221807Sstas 854221807Sstas /* 855221807Sstas * Create filestat entry. 856221807Sstas */ 857221807Sstas entry = filestat_new_entry(kif, type, fd, fflags, uflags, 858255219Spjd refcount, offset, path, &cap_rights); 859221807Sstas if (entry != NULL) 860221807Sstas STAILQ_INSERT_TAIL(head, entry, next); 861221807Sstas } 862221807Sstas if (mmapped != 0) { 863249667Strociny vmentries = procstat_getvmmap(procstat, kp, &cnt); 864221807Sstas procstat->vmentries = vmentries; 865221807Sstas if (vmentries == NULL || cnt == 0) 866221807Sstas goto fail; 867221807Sstas for (i = 0; i < cnt; i++) { 868221807Sstas kve = &vmentries[i]; 869221807Sstas if (kve->kve_type != KVME_TYPE_VNODE) 870221807Sstas continue; 871221807Sstas fflags = 0; 872221807Sstas if (kve->kve_protection & KVME_PROT_READ) 873221807Sstas fflags = PS_FST_FFLAG_READ; 874223279Sjilles if ((kve->kve_flags & KVME_FLAG_COW) == 0 && 875223279Sjilles kve->kve_protection & KVME_PROT_WRITE) 876221807Sstas fflags |= PS_FST_FFLAG_WRITE; 877221807Sstas offset = kve->kve_offset; 878221807Sstas refcount = kve->kve_ref_count; 879221807Sstas if (*kve->kve_path != '\0') 880221807Sstas path = strdup(kve->kve_path); 881221807Sstas else 882221807Sstas path = NULL; 883221807Sstas entry = filestat_new_entry(kve, PS_FST_TYPE_VNODE, -1, 884224859Srwatson fflags, PS_FST_UFLAG_MMAP, refcount, offset, path, 885256242Spjd NULL); 886221807Sstas if (entry != NULL) 887221807Sstas STAILQ_INSERT_TAIL(head, entry, next); 888221807Sstas } 889221807Sstas } 890221807Sstasfail: 891221807Sstas return (head); 892221807Sstas} 893221807Sstas 894221807Sstasint 895221807Sstasprocstat_get_pipe_info(struct procstat *procstat, struct filestat *fst, 896221807Sstas struct pipestat *ps, char *errbuf) 897221807Sstas{ 898221807Sstas 899221807Sstas assert(ps); 900221807Sstas if (procstat->type == PROCSTAT_KVM) { 901221807Sstas return (procstat_get_pipe_info_kvm(procstat->kd, fst, ps, 902221807Sstas errbuf)); 903249666Strociny } else if (procstat->type == PROCSTAT_SYSCTL || 904249666Strociny procstat->type == PROCSTAT_CORE) { 905221807Sstas return (procstat_get_pipe_info_sysctl(fst, ps, errbuf)); 906221807Sstas } else { 907223276Sjilles warnx("unknown access method: %d", procstat->type); 908250378Strociny if (errbuf != NULL) 909250378Strociny snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 910221807Sstas return (1); 911221807Sstas } 912221807Sstas} 913221807Sstas 914221807Sstasstatic int 915221807Sstasprocstat_get_pipe_info_kvm(kvm_t *kd, struct filestat *fst, 916221807Sstas struct pipestat *ps, char *errbuf) 917221807Sstas{ 918221807Sstas struct pipe pi; 919221807Sstas void *pipep; 920221807Sstas 921221807Sstas assert(kd); 922221807Sstas assert(ps); 923221807Sstas assert(fst); 924221807Sstas bzero(ps, sizeof(*ps)); 925221807Sstas pipep = fst->fs_typedep; 926221807Sstas if (pipep == NULL) 927221807Sstas goto fail; 928221807Sstas if (!kvm_read_all(kd, (unsigned long)pipep, &pi, sizeof(struct pipe))) { 929221807Sstas warnx("can't read pipe at %p", (void *)pipep); 930221807Sstas goto fail; 931221807Sstas } 932221807Sstas ps->addr = (uintptr_t)pipep; 933221807Sstas ps->peer = (uintptr_t)pi.pipe_peer; 934221807Sstas ps->buffer_cnt = pi.pipe_buffer.cnt; 935221807Sstas return (0); 936221807Sstas 937221807Sstasfail: 938250378Strociny if (errbuf != NULL) 939250378Strociny snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 940221807Sstas return (1); 941221807Sstas} 942221807Sstas 943221807Sstasstatic int 944221807Sstasprocstat_get_pipe_info_sysctl(struct filestat *fst, struct pipestat *ps, 945221807Sstas char *errbuf __unused) 946221807Sstas{ 947221807Sstas struct kinfo_file *kif; 948221807Sstas 949221807Sstas assert(ps); 950221807Sstas assert(fst); 951221807Sstas bzero(ps, sizeof(*ps)); 952221807Sstas kif = fst->fs_typedep; 953221807Sstas if (kif == NULL) 954221807Sstas return (1); 955221807Sstas ps->addr = kif->kf_un.kf_pipe.kf_pipe_addr; 956221807Sstas ps->peer = kif->kf_un.kf_pipe.kf_pipe_peer; 957221807Sstas ps->buffer_cnt = kif->kf_un.kf_pipe.kf_pipe_buffer_cnt; 958221807Sstas return (0); 959221807Sstas} 960221807Sstas 961221807Sstasint 962221807Sstasprocstat_get_pts_info(struct procstat *procstat, struct filestat *fst, 963221807Sstas struct ptsstat *pts, char *errbuf) 964221807Sstas{ 965221807Sstas 966221807Sstas assert(pts); 967221807Sstas if (procstat->type == PROCSTAT_KVM) { 968221807Sstas return (procstat_get_pts_info_kvm(procstat->kd, fst, pts, 969221807Sstas errbuf)); 970249666Strociny } else if (procstat->type == PROCSTAT_SYSCTL || 971249666Strociny procstat->type == PROCSTAT_CORE) { 972221807Sstas return (procstat_get_pts_info_sysctl(fst, pts, errbuf)); 973221807Sstas } else { 974223276Sjilles warnx("unknown access method: %d", procstat->type); 975250378Strociny if (errbuf != NULL) 976250378Strociny snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 977221807Sstas return (1); 978221807Sstas } 979221807Sstas} 980221807Sstas 981221807Sstasstatic int 982221807Sstasprocstat_get_pts_info_kvm(kvm_t *kd, struct filestat *fst, 983221807Sstas struct ptsstat *pts, char *errbuf) 984221807Sstas{ 985221807Sstas struct tty tty; 986221807Sstas void *ttyp; 987221807Sstas 988221807Sstas assert(kd); 989221807Sstas assert(pts); 990221807Sstas assert(fst); 991221807Sstas bzero(pts, sizeof(*pts)); 992221807Sstas ttyp = fst->fs_typedep; 993221807Sstas if (ttyp == NULL) 994221807Sstas goto fail; 995221807Sstas if (!kvm_read_all(kd, (unsigned long)ttyp, &tty, sizeof(struct tty))) { 996221807Sstas warnx("can't read tty at %p", (void *)ttyp); 997221807Sstas goto fail; 998221807Sstas } 999221807Sstas pts->dev = dev2udev(kd, tty.t_dev); 1000221807Sstas (void)kdevtoname(kd, tty.t_dev, pts->devname); 1001221807Sstas return (0); 1002221807Sstas 1003221807Sstasfail: 1004250378Strociny if (errbuf != NULL) 1005250378Strociny snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 1006221807Sstas return (1); 1007221807Sstas} 1008221807Sstas 1009221807Sstasstatic int 1010221807Sstasprocstat_get_pts_info_sysctl(struct filestat *fst, struct ptsstat *pts, 1011221807Sstas char *errbuf __unused) 1012221807Sstas{ 1013221807Sstas struct kinfo_file *kif; 1014221807Sstas 1015221807Sstas assert(pts); 1016221807Sstas assert(fst); 1017221807Sstas bzero(pts, sizeof(*pts)); 1018221807Sstas kif = fst->fs_typedep; 1019221807Sstas if (kif == NULL) 1020221807Sstas return (0); 1021221807Sstas pts->dev = kif->kf_un.kf_pts.kf_pts_dev; 1022221807Sstas strlcpy(pts->devname, kif->kf_path, sizeof(pts->devname)); 1023221807Sstas return (0); 1024221807Sstas} 1025221807Sstas 1026221807Sstasint 1027250223Sjhbprocstat_get_sem_info(struct procstat *procstat, struct filestat *fst, 1028250223Sjhb struct semstat *sem, char *errbuf) 1029250223Sjhb{ 1030250223Sjhb 1031250223Sjhb assert(sem); 1032250223Sjhb if (procstat->type == PROCSTAT_KVM) { 1033250223Sjhb return (procstat_get_sem_info_kvm(procstat->kd, fst, sem, 1034250223Sjhb errbuf)); 1035250223Sjhb } else if (procstat->type == PROCSTAT_SYSCTL || 1036250223Sjhb procstat->type == PROCSTAT_CORE) { 1037250223Sjhb return (procstat_get_sem_info_sysctl(fst, sem, errbuf)); 1038250223Sjhb } else { 1039250223Sjhb warnx("unknown access method: %d", procstat->type); 1040250378Strociny if (errbuf != NULL) 1041250378Strociny snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 1042250223Sjhb return (1); 1043250223Sjhb } 1044250223Sjhb} 1045250223Sjhb 1046250223Sjhbstatic int 1047250223Sjhbprocstat_get_sem_info_kvm(kvm_t *kd, struct filestat *fst, 1048250223Sjhb struct semstat *sem, char *errbuf) 1049250223Sjhb{ 1050250223Sjhb struct ksem ksem; 1051250223Sjhb void *ksemp; 1052250223Sjhb char *path; 1053250223Sjhb int i; 1054250223Sjhb 1055250223Sjhb assert(kd); 1056250223Sjhb assert(sem); 1057250223Sjhb assert(fst); 1058250223Sjhb bzero(sem, sizeof(*sem)); 1059250223Sjhb ksemp = fst->fs_typedep; 1060250223Sjhb if (ksemp == NULL) 1061250223Sjhb goto fail; 1062250223Sjhb if (!kvm_read_all(kd, (unsigned long)ksemp, &ksem, 1063250223Sjhb sizeof(struct ksem))) { 1064250223Sjhb warnx("can't read ksem at %p", (void *)ksemp); 1065250223Sjhb goto fail; 1066250223Sjhb } 1067250223Sjhb sem->mode = S_IFREG | ksem.ks_mode; 1068250223Sjhb sem->value = ksem.ks_value; 1069250223Sjhb if (fst->fs_path == NULL && ksem.ks_path != NULL) { 1070250223Sjhb path = malloc(MAXPATHLEN); 1071250223Sjhb for (i = 0; i < MAXPATHLEN - 1; i++) { 1072250223Sjhb if (!kvm_read_all(kd, (unsigned long)ksem.ks_path + i, 1073250223Sjhb path + i, 1)) 1074250223Sjhb break; 1075250223Sjhb if (path[i] == '\0') 1076250223Sjhb break; 1077250223Sjhb } 1078250223Sjhb path[i] = '\0'; 1079250223Sjhb if (i == 0) 1080250223Sjhb free(path); 1081250223Sjhb else 1082250223Sjhb fst->fs_path = path; 1083250223Sjhb } 1084250223Sjhb return (0); 1085250223Sjhb 1086250223Sjhbfail: 1087250378Strociny if (errbuf != NULL) 1088250378Strociny snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 1089250223Sjhb return (1); 1090250223Sjhb} 1091250223Sjhb 1092250223Sjhbstatic int 1093250223Sjhbprocstat_get_sem_info_sysctl(struct filestat *fst, struct semstat *sem, 1094250223Sjhb char *errbuf __unused) 1095250223Sjhb{ 1096250223Sjhb struct kinfo_file *kif; 1097250223Sjhb 1098250223Sjhb assert(sem); 1099250223Sjhb assert(fst); 1100250223Sjhb bzero(sem, sizeof(*sem)); 1101250223Sjhb kif = fst->fs_typedep; 1102250223Sjhb if (kif == NULL) 1103250223Sjhb return (0); 1104250223Sjhb sem->value = kif->kf_un.kf_sem.kf_sem_value; 1105250223Sjhb sem->mode = kif->kf_un.kf_sem.kf_sem_mode; 1106250223Sjhb return (0); 1107250223Sjhb} 1108250223Sjhb 1109250223Sjhbint 1110233760Sjhbprocstat_get_shm_info(struct procstat *procstat, struct filestat *fst, 1111233760Sjhb struct shmstat *shm, char *errbuf) 1112233760Sjhb{ 1113233760Sjhb 1114233760Sjhb assert(shm); 1115233760Sjhb if (procstat->type == PROCSTAT_KVM) { 1116233760Sjhb return (procstat_get_shm_info_kvm(procstat->kd, fst, shm, 1117233760Sjhb errbuf)); 1118249666Strociny } else if (procstat->type == PROCSTAT_SYSCTL || 1119249666Strociny procstat->type == PROCSTAT_CORE) { 1120233760Sjhb return (procstat_get_shm_info_sysctl(fst, shm, errbuf)); 1121233760Sjhb } else { 1122233760Sjhb warnx("unknown access method: %d", procstat->type); 1123250378Strociny if (errbuf != NULL) 1124250378Strociny snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 1125233760Sjhb return (1); 1126233760Sjhb } 1127233760Sjhb} 1128233760Sjhb 1129233760Sjhbstatic int 1130233760Sjhbprocstat_get_shm_info_kvm(kvm_t *kd, struct filestat *fst, 1131233760Sjhb struct shmstat *shm, char *errbuf) 1132233760Sjhb{ 1133233760Sjhb struct shmfd shmfd; 1134233760Sjhb void *shmfdp; 1135236717Sjhb char *path; 1136236717Sjhb int i; 1137233760Sjhb 1138233760Sjhb assert(kd); 1139233760Sjhb assert(shm); 1140233760Sjhb assert(fst); 1141233760Sjhb bzero(shm, sizeof(*shm)); 1142233760Sjhb shmfdp = fst->fs_typedep; 1143233760Sjhb if (shmfdp == NULL) 1144233760Sjhb goto fail; 1145233760Sjhb if (!kvm_read_all(kd, (unsigned long)shmfdp, &shmfd, 1146233760Sjhb sizeof(struct shmfd))) { 1147233760Sjhb warnx("can't read shmfd at %p", (void *)shmfdp); 1148233760Sjhb goto fail; 1149233760Sjhb } 1150233760Sjhb shm->mode = S_IFREG | shmfd.shm_mode; 1151233760Sjhb shm->size = shmfd.shm_size; 1152236717Sjhb if (fst->fs_path == NULL && shmfd.shm_path != NULL) { 1153236717Sjhb path = malloc(MAXPATHLEN); 1154236717Sjhb for (i = 0; i < MAXPATHLEN - 1; i++) { 1155236717Sjhb if (!kvm_read_all(kd, (unsigned long)shmfd.shm_path + i, 1156236717Sjhb path + i, 1)) 1157236717Sjhb break; 1158236717Sjhb if (path[i] == '\0') 1159236717Sjhb break; 1160236717Sjhb } 1161236717Sjhb path[i] = '\0'; 1162236717Sjhb if (i == 0) 1163236717Sjhb free(path); 1164236717Sjhb else 1165236717Sjhb fst->fs_path = path; 1166236717Sjhb } 1167233760Sjhb return (0); 1168233760Sjhb 1169233760Sjhbfail: 1170250378Strociny if (errbuf != NULL) 1171250378Strociny snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 1172233760Sjhb return (1); 1173233760Sjhb} 1174233760Sjhb 1175233760Sjhbstatic int 1176233760Sjhbprocstat_get_shm_info_sysctl(struct filestat *fst, struct shmstat *shm, 1177233760Sjhb char *errbuf __unused) 1178233760Sjhb{ 1179233760Sjhb struct kinfo_file *kif; 1180233760Sjhb 1181233760Sjhb assert(shm); 1182233760Sjhb assert(fst); 1183233760Sjhb bzero(shm, sizeof(*shm)); 1184233760Sjhb kif = fst->fs_typedep; 1185233760Sjhb if (kif == NULL) 1186233760Sjhb return (0); 1187233760Sjhb shm->size = kif->kf_un.kf_file.kf_file_size; 1188233760Sjhb shm->mode = kif->kf_un.kf_file.kf_file_mode; 1189233760Sjhb return (0); 1190233760Sjhb} 1191233760Sjhb 1192233760Sjhbint 1193221807Sstasprocstat_get_vnode_info(struct procstat *procstat, struct filestat *fst, 1194221807Sstas struct vnstat *vn, char *errbuf) 1195221807Sstas{ 1196221807Sstas 1197221807Sstas assert(vn); 1198221807Sstas if (procstat->type == PROCSTAT_KVM) { 1199221807Sstas return (procstat_get_vnode_info_kvm(procstat->kd, fst, vn, 1200221807Sstas errbuf)); 1201249666Strociny } else if (procstat->type == PROCSTAT_SYSCTL || 1202249666Strociny procstat->type == PROCSTAT_CORE) { 1203221807Sstas return (procstat_get_vnode_info_sysctl(fst, vn, errbuf)); 1204221807Sstas } else { 1205223276Sjilles warnx("unknown access method: %d", procstat->type); 1206250378Strociny if (errbuf != NULL) 1207250378Strociny snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 1208221807Sstas return (1); 1209221807Sstas } 1210221807Sstas} 1211221807Sstas 1212221807Sstasstatic int 1213221807Sstasprocstat_get_vnode_info_kvm(kvm_t *kd, struct filestat *fst, 1214221807Sstas struct vnstat *vn, char *errbuf) 1215221807Sstas{ 1216221807Sstas /* Filesystem specific handlers. */ 1217221807Sstas #define FSTYPE(fst) {#fst, fst##_filestat} 1218221807Sstas struct { 1219221807Sstas const char *tag; 1220221807Sstas int (*handler)(kvm_t *kd, struct vnode *vp, 1221221807Sstas struct vnstat *vn); 1222221807Sstas } fstypes[] = { 1223221807Sstas FSTYPE(devfs), 1224221807Sstas FSTYPE(isofs), 1225221807Sstas FSTYPE(msdosfs), 1226221807Sstas FSTYPE(nfs), 1227252356Sdavide FSTYPE(smbfs), 1228221807Sstas FSTYPE(udf), 1229221807Sstas FSTYPE(ufs), 1230221824Sstas#ifdef LIBPROCSTAT_ZFS 1231221807Sstas FSTYPE(zfs), 1232221807Sstas#endif 1233221807Sstas }; 1234221807Sstas#define NTYPES (sizeof(fstypes) / sizeof(*fstypes)) 1235221807Sstas struct vnode vnode; 1236221807Sstas char tagstr[12]; 1237221807Sstas void *vp; 1238221807Sstas int error, found; 1239221807Sstas unsigned int i; 1240221807Sstas 1241221807Sstas assert(kd); 1242221807Sstas assert(vn); 1243221807Sstas assert(fst); 1244221807Sstas vp = fst->fs_typedep; 1245221807Sstas if (vp == NULL) 1246221807Sstas goto fail; 1247221807Sstas error = kvm_read_all(kd, (unsigned long)vp, &vnode, sizeof(vnode)); 1248221807Sstas if (error == 0) { 1249221807Sstas warnx("can't read vnode at %p", (void *)vp); 1250221807Sstas goto fail; 1251221807Sstas } 1252221807Sstas bzero(vn, sizeof(*vn)); 1253221807Sstas vn->vn_type = vntype2psfsttype(vnode.v_type); 1254221807Sstas if (vnode.v_type == VNON || vnode.v_type == VBAD) 1255221807Sstas return (0); 1256221807Sstas error = kvm_read_all(kd, (unsigned long)vnode.v_tag, tagstr, 1257221807Sstas sizeof(tagstr)); 1258221807Sstas if (error == 0) { 1259221807Sstas warnx("can't read v_tag at %p", (void *)vp); 1260221807Sstas goto fail; 1261221807Sstas } 1262221807Sstas tagstr[sizeof(tagstr) - 1] = '\0'; 1263221807Sstas 1264221807Sstas /* 1265221807Sstas * Find appropriate handler. 1266221807Sstas */ 1267221807Sstas for (i = 0, found = 0; i < NTYPES; i++) 1268221807Sstas if (!strcmp(fstypes[i].tag, tagstr)) { 1269221807Sstas if (fstypes[i].handler(kd, &vnode, vn) != 0) { 1270221807Sstas goto fail; 1271221807Sstas } 1272221807Sstas break; 1273221807Sstas } 1274221807Sstas if (i == NTYPES) { 1275250378Strociny if (errbuf != NULL) 1276250378Strociny snprintf(errbuf, _POSIX2_LINE_MAX, "?(%s)", tagstr); 1277221807Sstas return (1); 1278221807Sstas } 1279221807Sstas vn->vn_mntdir = getmnton(kd, vnode.v_mount); 1280221807Sstas if ((vnode.v_type == VBLK || vnode.v_type == VCHR) && 1281221807Sstas vnode.v_rdev != NULL){ 1282221807Sstas vn->vn_dev = dev2udev(kd, vnode.v_rdev); 1283221807Sstas (void)kdevtoname(kd, vnode.v_rdev, vn->vn_devname); 1284221807Sstas } else { 1285221807Sstas vn->vn_dev = -1; 1286221807Sstas } 1287221807Sstas return (0); 1288221807Sstas 1289221807Sstasfail: 1290250378Strociny if (errbuf != NULL) 1291250378Strociny snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 1292221807Sstas return (1); 1293221807Sstas} 1294221807Sstas 1295221807Sstas/* 1296221807Sstas * kinfo vnode type to filestat translation. 1297221807Sstas */ 1298221807Sstasstatic int 1299221807Sstaskinfo_vtype2fst(int kfvtype) 1300221807Sstas{ 1301221807Sstas static struct { 1302221807Sstas int kf_vtype; 1303221807Sstas int fst_vtype; 1304221807Sstas } kfvtypes2fst[] = { 1305221807Sstas { KF_VTYPE_VBAD, PS_FST_VTYPE_VBAD }, 1306221807Sstas { KF_VTYPE_VBLK, PS_FST_VTYPE_VBLK }, 1307221807Sstas { KF_VTYPE_VCHR, PS_FST_VTYPE_VCHR }, 1308221807Sstas { KF_VTYPE_VDIR, PS_FST_VTYPE_VDIR }, 1309221807Sstas { KF_VTYPE_VFIFO, PS_FST_VTYPE_VFIFO }, 1310221807Sstas { KF_VTYPE_VLNK, PS_FST_VTYPE_VLNK }, 1311221807Sstas { KF_VTYPE_VNON, PS_FST_VTYPE_VNON }, 1312221807Sstas { KF_VTYPE_VREG, PS_FST_VTYPE_VREG }, 1313221807Sstas { KF_VTYPE_VSOCK, PS_FST_VTYPE_VSOCK } 1314221807Sstas }; 1315221807Sstas#define NKFVTYPES (sizeof(kfvtypes2fst) / sizeof(*kfvtypes2fst)) 1316221807Sstas unsigned int i; 1317221807Sstas 1318221807Sstas for (i = 0; i < NKFVTYPES; i++) 1319221807Sstas if (kfvtypes2fst[i].kf_vtype == kfvtype) 1320221807Sstas break; 1321221807Sstas if (i == NKFVTYPES) 1322221807Sstas return (PS_FST_VTYPE_UNKNOWN); 1323221807Sstas return (kfvtypes2fst[i].fst_vtype); 1324221807Sstas} 1325221807Sstas 1326221807Sstasstatic int 1327221807Sstasprocstat_get_vnode_info_sysctl(struct filestat *fst, struct vnstat *vn, 1328221807Sstas char *errbuf) 1329221807Sstas{ 1330221807Sstas struct statfs stbuf; 1331221807Sstas struct kinfo_file *kif; 1332221807Sstas struct kinfo_vmentry *kve; 1333221807Sstas uint64_t fileid; 1334221807Sstas uint64_t size; 1335221807Sstas char *name, *path; 1336221807Sstas uint32_t fsid; 1337221807Sstas uint16_t mode; 1338221807Sstas uint32_t rdev; 1339221807Sstas int vntype; 1340221807Sstas int status; 1341221807Sstas 1342221807Sstas assert(fst); 1343221807Sstas assert(vn); 1344221807Sstas bzero(vn, sizeof(*vn)); 1345221807Sstas if (fst->fs_typedep == NULL) 1346221807Sstas return (1); 1347221807Sstas if (fst->fs_uflags & PS_FST_UFLAG_MMAP) { 1348221807Sstas kve = fst->fs_typedep; 1349221807Sstas fileid = kve->kve_vn_fileid; 1350221807Sstas fsid = kve->kve_vn_fsid; 1351221807Sstas mode = kve->kve_vn_mode; 1352221807Sstas path = kve->kve_path; 1353221807Sstas rdev = kve->kve_vn_rdev; 1354221807Sstas size = kve->kve_vn_size; 1355221807Sstas vntype = kinfo_vtype2fst(kve->kve_vn_type); 1356221807Sstas status = kve->kve_status; 1357221807Sstas } else { 1358221807Sstas kif = fst->fs_typedep; 1359221807Sstas fileid = kif->kf_un.kf_file.kf_file_fileid; 1360221807Sstas fsid = kif->kf_un.kf_file.kf_file_fsid; 1361221807Sstas mode = kif->kf_un.kf_file.kf_file_mode; 1362221807Sstas path = kif->kf_path; 1363221807Sstas rdev = kif->kf_un.kf_file.kf_file_rdev; 1364221807Sstas size = kif->kf_un.kf_file.kf_file_size; 1365221807Sstas vntype = kinfo_vtype2fst(kif->kf_vnode_type); 1366221807Sstas status = kif->kf_status; 1367221807Sstas } 1368221807Sstas vn->vn_type = vntype; 1369221807Sstas if (vntype == PS_FST_VTYPE_VNON || vntype == PS_FST_VTYPE_VBAD) 1370221807Sstas return (0); 1371221807Sstas if ((status & KF_ATTR_VALID) == 0) { 1372250378Strociny if (errbuf != NULL) { 1373250378Strociny snprintf(errbuf, _POSIX2_LINE_MAX, 1374250378Strociny "? (no info available)"); 1375250378Strociny } 1376221807Sstas return (1); 1377221807Sstas } 1378221807Sstas if (path && *path) { 1379221807Sstas statfs(path, &stbuf); 1380221807Sstas vn->vn_mntdir = strdup(stbuf.f_mntonname); 1381221807Sstas } else 1382221807Sstas vn->vn_mntdir = strdup("-"); 1383221807Sstas vn->vn_dev = rdev; 1384221807Sstas if (vntype == PS_FST_VTYPE_VBLK) { 1385221807Sstas name = devname(rdev, S_IFBLK); 1386221807Sstas if (name != NULL) 1387221807Sstas strlcpy(vn->vn_devname, name, 1388221807Sstas sizeof(vn->vn_devname)); 1389221807Sstas } else if (vntype == PS_FST_VTYPE_VCHR) { 1390221807Sstas name = devname(vn->vn_dev, S_IFCHR); 1391221807Sstas if (name != NULL) 1392221807Sstas strlcpy(vn->vn_devname, name, 1393221807Sstas sizeof(vn->vn_devname)); 1394221807Sstas } 1395221807Sstas vn->vn_fsid = fsid; 1396221807Sstas vn->vn_fileid = fileid; 1397221807Sstas vn->vn_size = size; 1398221807Sstas vn->vn_mode = mode; 1399221807Sstas return (0); 1400221807Sstas} 1401221807Sstas 1402221807Sstasint 1403221807Sstasprocstat_get_socket_info(struct procstat *procstat, struct filestat *fst, 1404221807Sstas struct sockstat *sock, char *errbuf) 1405221807Sstas{ 1406221807Sstas 1407221807Sstas assert(sock); 1408221807Sstas if (procstat->type == PROCSTAT_KVM) { 1409221807Sstas return (procstat_get_socket_info_kvm(procstat->kd, fst, sock, 1410221807Sstas errbuf)); 1411249666Strociny } else if (procstat->type == PROCSTAT_SYSCTL || 1412249666Strociny procstat->type == PROCSTAT_CORE) { 1413221807Sstas return (procstat_get_socket_info_sysctl(fst, sock, errbuf)); 1414221807Sstas } else { 1415223276Sjilles warnx("unknown access method: %d", procstat->type); 1416250378Strociny if (errbuf != NULL) 1417250378Strociny snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 1418221807Sstas return (1); 1419221807Sstas } 1420221807Sstas} 1421221807Sstas 1422221807Sstasstatic int 1423221807Sstasprocstat_get_socket_info_kvm(kvm_t *kd, struct filestat *fst, 1424221807Sstas struct sockstat *sock, char *errbuf) 1425221807Sstas{ 1426221807Sstas struct domain dom; 1427221807Sstas struct inpcb inpcb; 1428221807Sstas struct protosw proto; 1429221807Sstas struct socket s; 1430221807Sstas struct unpcb unpcb; 1431221807Sstas ssize_t len; 1432221807Sstas void *so; 1433221807Sstas 1434221807Sstas assert(kd); 1435221807Sstas assert(sock); 1436221807Sstas assert(fst); 1437221807Sstas bzero(sock, sizeof(*sock)); 1438221807Sstas so = fst->fs_typedep; 1439221807Sstas if (so == NULL) 1440221807Sstas goto fail; 1441221807Sstas sock->so_addr = (uintptr_t)so; 1442221807Sstas /* fill in socket */ 1443221807Sstas if (!kvm_read_all(kd, (unsigned long)so, &s, 1444221807Sstas sizeof(struct socket))) { 1445221807Sstas warnx("can't read sock at %p", (void *)so); 1446221807Sstas goto fail; 1447221807Sstas } 1448221807Sstas /* fill in protosw entry */ 1449221807Sstas if (!kvm_read_all(kd, (unsigned long)s.so_proto, &proto, 1450221807Sstas sizeof(struct protosw))) { 1451221807Sstas warnx("can't read protosw at %p", (void *)s.so_proto); 1452221807Sstas goto fail; 1453221807Sstas } 1454221807Sstas /* fill in domain */ 1455221807Sstas if (!kvm_read_all(kd, (unsigned long)proto.pr_domain, &dom, 1456221807Sstas sizeof(struct domain))) { 1457221807Sstas warnx("can't read domain at %p", 1458221807Sstas (void *)proto.pr_domain); 1459221807Sstas goto fail; 1460221807Sstas } 1461221807Sstas if ((len = kvm_read(kd, (unsigned long)dom.dom_name, sock->dname, 1462221807Sstas sizeof(sock->dname) - 1)) < 0) { 1463221807Sstas warnx("can't read domain name at %p", (void *)dom.dom_name); 1464221807Sstas sock->dname[0] = '\0'; 1465221807Sstas } 1466221807Sstas else 1467221807Sstas sock->dname[len] = '\0'; 1468221807Sstas 1469221807Sstas /* 1470221807Sstas * Fill in known data. 1471221807Sstas */ 1472221807Sstas sock->type = s.so_type; 1473221807Sstas sock->proto = proto.pr_protocol; 1474221807Sstas sock->dom_family = dom.dom_family; 1475221807Sstas sock->so_pcb = (uintptr_t)s.so_pcb; 1476221807Sstas 1477221807Sstas /* 1478221807Sstas * Protocol specific data. 1479221807Sstas */ 1480221807Sstas switch(dom.dom_family) { 1481221807Sstas case AF_INET: 1482221807Sstas case AF_INET6: 1483221807Sstas if (proto.pr_protocol == IPPROTO_TCP) { 1484221807Sstas if (s.so_pcb) { 1485221807Sstas if (kvm_read(kd, (u_long)s.so_pcb, 1486221807Sstas (char *)&inpcb, sizeof(struct inpcb)) 1487221807Sstas != sizeof(struct inpcb)) { 1488221807Sstas warnx("can't read inpcb at %p", 1489221807Sstas (void *)s.so_pcb); 1490221807Sstas } else 1491221807Sstas sock->inp_ppcb = 1492221807Sstas (uintptr_t)inpcb.inp_ppcb; 1493221807Sstas } 1494221807Sstas } 1495221807Sstas break; 1496221807Sstas case AF_UNIX: 1497221807Sstas if (s.so_pcb) { 1498221807Sstas if (kvm_read(kd, (u_long)s.so_pcb, (char *)&unpcb, 1499221807Sstas sizeof(struct unpcb)) != sizeof(struct unpcb)){ 1500221807Sstas warnx("can't read unpcb at %p", 1501221807Sstas (void *)s.so_pcb); 1502221807Sstas } else if (unpcb.unp_conn) { 1503221807Sstas sock->so_rcv_sb_state = s.so_rcv.sb_state; 1504221807Sstas sock->so_snd_sb_state = s.so_snd.sb_state; 1505221807Sstas sock->unp_conn = (uintptr_t)unpcb.unp_conn; 1506221807Sstas } 1507221807Sstas } 1508221807Sstas break; 1509221807Sstas default: 1510221807Sstas break; 1511221807Sstas } 1512221807Sstas return (0); 1513221807Sstas 1514221807Sstasfail: 1515250378Strociny if (errbuf != NULL) 1516250378Strociny snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 1517221807Sstas return (1); 1518221807Sstas} 1519221807Sstas 1520221807Sstasstatic int 1521221807Sstasprocstat_get_socket_info_sysctl(struct filestat *fst, struct sockstat *sock, 1522221807Sstas char *errbuf __unused) 1523221807Sstas{ 1524221807Sstas struct kinfo_file *kif; 1525221807Sstas 1526221807Sstas assert(sock); 1527221807Sstas assert(fst); 1528221807Sstas bzero(sock, sizeof(*sock)); 1529221807Sstas kif = fst->fs_typedep; 1530221807Sstas if (kif == NULL) 1531221807Sstas return (0); 1532221807Sstas 1533221807Sstas /* 1534221807Sstas * Fill in known data. 1535221807Sstas */ 1536221807Sstas sock->type = kif->kf_sock_type; 1537221807Sstas sock->proto = kif->kf_sock_protocol; 1538221807Sstas sock->dom_family = kif->kf_sock_domain; 1539221807Sstas sock->so_pcb = kif->kf_un.kf_sock.kf_sock_pcb; 1540221807Sstas strlcpy(sock->dname, kif->kf_path, sizeof(sock->dname)); 1541221807Sstas bcopy(&kif->kf_sa_local, &sock->sa_local, kif->kf_sa_local.ss_len); 1542221807Sstas bcopy(&kif->kf_sa_peer, &sock->sa_peer, kif->kf_sa_peer.ss_len); 1543221807Sstas 1544221807Sstas /* 1545221807Sstas * Protocol specific data. 1546221807Sstas */ 1547221807Sstas switch(sock->dom_family) { 1548221807Sstas case AF_INET: 1549221807Sstas case AF_INET6: 1550221807Sstas if (sock->proto == IPPROTO_TCP) 1551221807Sstas sock->inp_ppcb = kif->kf_un.kf_sock.kf_sock_inpcb; 1552221807Sstas break; 1553221807Sstas case AF_UNIX: 1554221807Sstas if (kif->kf_un.kf_sock.kf_sock_unpconn != 0) { 1555221807Sstas sock->so_rcv_sb_state = 1556221807Sstas kif->kf_un.kf_sock.kf_sock_rcv_sb_state; 1557221807Sstas sock->so_snd_sb_state = 1558221807Sstas kif->kf_un.kf_sock.kf_sock_snd_sb_state; 1559221807Sstas sock->unp_conn = 1560221807Sstas kif->kf_un.kf_sock.kf_sock_unpconn; 1561221807Sstas } 1562221807Sstas break; 1563221807Sstas default: 1564221807Sstas break; 1565221807Sstas } 1566221807Sstas return (0); 1567221807Sstas} 1568221807Sstas 1569221807Sstas/* 1570221807Sstas * Descriptor flags to filestat translation. 1571221807Sstas */ 1572221807Sstasstatic int 1573221807Sstasto_filestat_flags(int flags) 1574221807Sstas{ 1575221807Sstas static struct { 1576221807Sstas int flag; 1577221807Sstas int fst_flag; 1578221807Sstas } fstflags[] = { 1579221807Sstas { FREAD, PS_FST_FFLAG_READ }, 1580221807Sstas { FWRITE, PS_FST_FFLAG_WRITE }, 1581221807Sstas { O_APPEND, PS_FST_FFLAG_APPEND }, 1582221807Sstas { O_ASYNC, PS_FST_FFLAG_ASYNC }, 1583221807Sstas { O_CREAT, PS_FST_FFLAG_CREAT }, 1584221807Sstas { O_DIRECT, PS_FST_FFLAG_DIRECT }, 1585221807Sstas { O_EXCL, PS_FST_FFLAG_EXCL }, 1586221807Sstas { O_EXEC, PS_FST_FFLAG_EXEC }, 1587221807Sstas { O_EXLOCK, PS_FST_FFLAG_EXLOCK }, 1588221807Sstas { O_NOFOLLOW, PS_FST_FFLAG_NOFOLLOW }, 1589221807Sstas { O_NONBLOCK, PS_FST_FFLAG_NONBLOCK }, 1590221807Sstas { O_SHLOCK, PS_FST_FFLAG_SHLOCK }, 1591221807Sstas { O_SYNC, PS_FST_FFLAG_SYNC }, 1592221807Sstas { O_TRUNC, PS_FST_FFLAG_TRUNC } 1593221807Sstas }; 1594221807Sstas#define NFSTFLAGS (sizeof(fstflags) / sizeof(*fstflags)) 1595221807Sstas int fst_flags; 1596221807Sstas unsigned int i; 1597221807Sstas 1598221807Sstas fst_flags = 0; 1599221807Sstas for (i = 0; i < NFSTFLAGS; i++) 1600221807Sstas if (flags & fstflags[i].flag) 1601221807Sstas fst_flags |= fstflags[i].fst_flag; 1602221807Sstas return (fst_flags); 1603221807Sstas} 1604221807Sstas 1605221807Sstas/* 1606221807Sstas * Vnode type to filestate translation. 1607221807Sstas */ 1608221807Sstasstatic int 1609221807Sstasvntype2psfsttype(int type) 1610221807Sstas{ 1611221807Sstas static struct { 1612221807Sstas int vtype; 1613221807Sstas int fst_vtype; 1614221807Sstas } vt2fst[] = { 1615221807Sstas { VBAD, PS_FST_VTYPE_VBAD }, 1616221807Sstas { VBLK, PS_FST_VTYPE_VBLK }, 1617221807Sstas { VCHR, PS_FST_VTYPE_VCHR }, 1618221807Sstas { VDIR, PS_FST_VTYPE_VDIR }, 1619221807Sstas { VFIFO, PS_FST_VTYPE_VFIFO }, 1620221807Sstas { VLNK, PS_FST_VTYPE_VLNK }, 1621221807Sstas { VNON, PS_FST_VTYPE_VNON }, 1622221807Sstas { VREG, PS_FST_VTYPE_VREG }, 1623221807Sstas { VSOCK, PS_FST_VTYPE_VSOCK } 1624221807Sstas }; 1625221807Sstas#define NVFTYPES (sizeof(vt2fst) / sizeof(*vt2fst)) 1626221807Sstas unsigned int i, fst_type; 1627221807Sstas 1628221807Sstas fst_type = PS_FST_VTYPE_UNKNOWN; 1629221807Sstas for (i = 0; i < NVFTYPES; i++) { 1630221807Sstas if (type == vt2fst[i].vtype) { 1631221807Sstas fst_type = vt2fst[i].fst_vtype; 1632221807Sstas break; 1633221807Sstas } 1634221807Sstas } 1635221807Sstas return (fst_type); 1636221807Sstas} 1637221807Sstas 1638221807Sstasstatic char * 1639221807Sstasgetmnton(kvm_t *kd, struct mount *m) 1640221807Sstas{ 1641223262Sbenl struct mount mnt; 1642221807Sstas static struct mtab { 1643221807Sstas struct mtab *next; 1644221807Sstas struct mount *m; 1645221807Sstas char mntonname[MNAMELEN + 1]; 1646221807Sstas } *mhead = NULL; 1647221807Sstas struct mtab *mt; 1648221807Sstas 1649221807Sstas for (mt = mhead; mt != NULL; mt = mt->next) 1650221807Sstas if (m == mt->m) 1651221807Sstas return (mt->mntonname); 1652221807Sstas if (!kvm_read_all(kd, (unsigned long)m, &mnt, sizeof(struct mount))) { 1653221807Sstas warnx("can't read mount table at %p", (void *)m); 1654221807Sstas return (NULL); 1655221807Sstas } 1656221807Sstas if ((mt = malloc(sizeof (struct mtab))) == NULL) 1657221807Sstas err(1, NULL); 1658221807Sstas mt->m = m; 1659221807Sstas bcopy(&mnt.mnt_stat.f_mntonname[0], &mt->mntonname[0], MNAMELEN); 1660223262Sbenl mt->mntonname[MNAMELEN] = '\0'; 1661221807Sstas mt->next = mhead; 1662221807Sstas mhead = mt; 1663221807Sstas return (mt->mntonname); 1664221807Sstas} 1665249666Strociny 1666249679Strociny/* 1667249679Strociny * Auxiliary structures and functions to get process environment or 1668249679Strociny * command line arguments. 1669249679Strociny */ 1670249679Strocinystruct argvec { 1671249679Strociny char *buf; 1672249679Strociny size_t bufsize; 1673249679Strociny char **argv; 1674249679Strociny size_t argc; 1675249679Strociny}; 1676249679Strociny 1677249679Strocinystatic struct argvec * 1678249679Strocinyargvec_alloc(size_t bufsize) 1679249679Strociny{ 1680249679Strociny struct argvec *av; 1681249679Strociny 1682249679Strociny av = malloc(sizeof(*av)); 1683249679Strociny if (av == NULL) 1684249679Strociny return (NULL); 1685249679Strociny av->bufsize = bufsize; 1686249679Strociny av->buf = malloc(av->bufsize); 1687249679Strociny if (av->buf == NULL) { 1688249679Strociny free(av); 1689249679Strociny return (NULL); 1690249679Strociny } 1691249679Strociny av->argc = 32; 1692249679Strociny av->argv = malloc(sizeof(char *) * av->argc); 1693249679Strociny if (av->argv == NULL) { 1694249679Strociny free(av->buf); 1695249679Strociny free(av); 1696249679Strociny return (NULL); 1697249679Strociny } 1698249679Strociny return av; 1699249679Strociny} 1700249679Strociny 1701249679Strocinystatic void 1702249679Strocinyargvec_free(struct argvec * av) 1703249679Strociny{ 1704249679Strociny 1705249679Strociny free(av->argv); 1706249679Strociny free(av->buf); 1707249679Strociny free(av); 1708249679Strociny} 1709249679Strociny 1710249679Strocinystatic char ** 1711249679Strocinygetargv(struct procstat *procstat, struct kinfo_proc *kp, size_t nchr, int env) 1712249679Strociny{ 1713249679Strociny int error, name[4], argc, i; 1714249679Strociny struct argvec *av, **avp; 1715249679Strociny enum psc_type type; 1716249679Strociny size_t len; 1717249679Strociny char *p, **argv; 1718249679Strociny 1719249679Strociny assert(procstat); 1720249679Strociny assert(kp); 1721249679Strociny if (procstat->type == PROCSTAT_KVM) { 1722249679Strociny warnx("can't use kvm access method"); 1723249679Strociny return (NULL); 1724249679Strociny } 1725249679Strociny if (procstat->type != PROCSTAT_SYSCTL && 1726249679Strociny procstat->type != PROCSTAT_CORE) { 1727249679Strociny warnx("unknown access method: %d", procstat->type); 1728249679Strociny return (NULL); 1729249679Strociny } 1730249679Strociny 1731249679Strociny if (nchr == 0 || nchr > ARG_MAX) 1732249679Strociny nchr = ARG_MAX; 1733249679Strociny 1734249679Strociny avp = (struct argvec **)(env ? &procstat->argv : &procstat->envv); 1735249679Strociny av = *avp; 1736249679Strociny 1737249679Strociny if (av == NULL) 1738249679Strociny { 1739249679Strociny av = argvec_alloc(nchr); 1740249679Strociny if (av == NULL) 1741249679Strociny { 1742249679Strociny warn("malloc(%zu)", nchr); 1743249679Strociny return (NULL); 1744249679Strociny } 1745249679Strociny *avp = av; 1746249679Strociny } else if (av->bufsize < nchr) { 1747249679Strociny av->buf = reallocf(av->buf, nchr); 1748249679Strociny if (av->buf == NULL) { 1749249679Strociny warn("malloc(%zu)", nchr); 1750249679Strociny return (NULL); 1751249679Strociny } 1752249679Strociny } 1753249679Strociny if (procstat->type == PROCSTAT_SYSCTL) { 1754249679Strociny name[0] = CTL_KERN; 1755249679Strociny name[1] = KERN_PROC; 1756249679Strociny name[2] = env ? KERN_PROC_ENV : KERN_PROC_ARGS; 1757249679Strociny name[3] = kp->ki_pid; 1758249679Strociny len = nchr; 1759249679Strociny error = sysctl(name, 4, av->buf, &len, NULL, 0); 1760249679Strociny if (error != 0 && errno != ESRCH && errno != EPERM) 1761249679Strociny warn("sysctl(kern.proc.%s)", env ? "env" : "args"); 1762249679Strociny if (error != 0 || len == 0) 1763249679Strociny return (NULL); 1764249679Strociny } else /* procstat->type == PROCSTAT_CORE */ { 1765249679Strociny type = env ? PSC_TYPE_ENVV : PSC_TYPE_ARGV; 1766249679Strociny len = nchr; 1767249679Strociny if (procstat_core_get(procstat->core, type, av->buf, &len) 1768249679Strociny == NULL) { 1769249679Strociny return (NULL); 1770249679Strociny } 1771249679Strociny } 1772249679Strociny 1773249679Strociny argv = av->argv; 1774249679Strociny argc = av->argc; 1775249679Strociny i = 0; 1776249679Strociny for (p = av->buf; p < av->buf + len; p += strlen(p) + 1) { 1777249679Strociny argv[i++] = p; 1778249679Strociny if (i < argc) 1779249679Strociny continue; 1780249679Strociny /* Grow argv. */ 1781249679Strociny argc += argc; 1782249679Strociny argv = realloc(argv, sizeof(char *) * argc); 1783249679Strociny if (argv == NULL) { 1784249679Strociny warn("malloc(%zu)", sizeof(char *) * argc); 1785249679Strociny return (NULL); 1786249679Strociny } 1787249679Strociny av->argv = argv; 1788249679Strociny av->argc = argc; 1789249679Strociny } 1790249679Strociny argv[i] = NULL; 1791249679Strociny 1792249679Strociny return (argv); 1793249679Strociny} 1794249679Strociny 1795249679Strociny/* 1796249679Strociny * Return process command line arguments. 1797249679Strociny */ 1798249679Strocinychar ** 1799249679Strocinyprocstat_getargv(struct procstat *procstat, struct kinfo_proc *p, size_t nchr) 1800249679Strociny{ 1801249679Strociny 1802249679Strociny return (getargv(procstat, p, nchr, 0)); 1803249679Strociny} 1804249679Strociny 1805249679Strociny/* 1806249679Strociny * Free the buffer allocated by procstat_getargv(). 1807249679Strociny */ 1808249679Strocinyvoid 1809249679Strocinyprocstat_freeargv(struct procstat *procstat) 1810249679Strociny{ 1811249679Strociny 1812249679Strociny if (procstat->argv != NULL) { 1813249679Strociny argvec_free(procstat->argv); 1814249679Strociny procstat->argv = NULL; 1815249679Strociny } 1816249679Strociny} 1817249679Strociny 1818249679Strociny/* 1819249679Strociny * Return process environment. 1820249679Strociny */ 1821249679Strocinychar ** 1822249679Strocinyprocstat_getenvv(struct procstat *procstat, struct kinfo_proc *p, size_t nchr) 1823249679Strociny{ 1824249679Strociny 1825249679Strociny return (getargv(procstat, p, nchr, 1)); 1826249679Strociny} 1827249679Strociny 1828249679Strociny/* 1829249679Strociny * Free the buffer allocated by procstat_getenvv(). 1830249679Strociny */ 1831249679Strocinyvoid 1832249679Strocinyprocstat_freeenvv(struct procstat *procstat) 1833249679Strociny{ 1834249679Strociny if (procstat->envv != NULL) { 1835249679Strociny argvec_free(procstat->envv); 1836249679Strociny procstat->envv = NULL; 1837249679Strociny } 1838249679Strociny} 1839249679Strociny 1840249667Strocinystatic struct kinfo_vmentry * 1841249667Strocinykinfo_getvmmap_core(struct procstat_core *core, int *cntp) 1842249667Strociny{ 1843249667Strociny int cnt; 1844249667Strociny size_t len; 1845249667Strociny char *buf, *bp, *eb; 1846249667Strociny struct kinfo_vmentry *kiv, *kp, *kv; 1847249667Strociny 1848249667Strociny buf = procstat_core_get(core, PSC_TYPE_VMMAP, NULL, &len); 1849249667Strociny if (buf == NULL) 1850249667Strociny return (NULL); 1851249667Strociny 1852249667Strociny /* 1853249667Strociny * XXXMG: The code below is just copy&past from libutil. 1854249667Strociny * The code duplication can be avoided if libutil 1855249667Strociny * is extended to provide something like: 1856249667Strociny * struct kinfo_vmentry *kinfo_getvmmap_from_buf(const char *buf, 1857249667Strociny * size_t len, int *cntp); 1858249667Strociny */ 1859249667Strociny 1860249667Strociny /* Pass 1: count items */ 1861249667Strociny cnt = 0; 1862249667Strociny bp = buf; 1863249667Strociny eb = buf + len; 1864249667Strociny while (bp < eb) { 1865249667Strociny kv = (struct kinfo_vmentry *)(uintptr_t)bp; 1866249667Strociny bp += kv->kve_structsize; 1867249667Strociny cnt++; 1868249667Strociny } 1869249667Strociny 1870249667Strociny kiv = calloc(cnt, sizeof(*kiv)); 1871249667Strociny if (kiv == NULL) { 1872249667Strociny free(buf); 1873249667Strociny return (NULL); 1874249667Strociny } 1875249667Strociny bp = buf; 1876249667Strociny eb = buf + len; 1877249667Strociny kp = kiv; 1878249667Strociny /* Pass 2: unpack */ 1879249667Strociny while (bp < eb) { 1880249667Strociny kv = (struct kinfo_vmentry *)(uintptr_t)bp; 1881249667Strociny /* Copy/expand into pre-zeroed buffer */ 1882249667Strociny memcpy(kp, kv, kv->kve_structsize); 1883249667Strociny /* Advance to next packed record */ 1884249667Strociny bp += kv->kve_structsize; 1885249667Strociny /* Set field size to fixed length, advance */ 1886249667Strociny kp->kve_structsize = sizeof(*kp); 1887249667Strociny kp++; 1888249667Strociny } 1889249667Strociny free(buf); 1890249667Strociny *cntp = cnt; 1891249667Strociny return (kiv); /* Caller must free() return value */ 1892249667Strociny} 1893249667Strociny 1894249667Strocinystruct kinfo_vmentry * 1895249667Strocinyprocstat_getvmmap(struct procstat *procstat, struct kinfo_proc *kp, 1896249667Strociny unsigned int *cntp) 1897249667Strociny{ 1898249684Strociny 1899249667Strociny switch(procstat->type) { 1900249667Strociny case PROCSTAT_KVM: 1901249667Strociny warnx("kvm method is not supported"); 1902249667Strociny return (NULL); 1903249667Strociny case PROCSTAT_SYSCTL: 1904249667Strociny return (kinfo_getvmmap(kp->ki_pid, cntp)); 1905249667Strociny case PROCSTAT_CORE: 1906249667Strociny return (kinfo_getvmmap_core(procstat->core, cntp)); 1907249667Strociny default: 1908249667Strociny warnx("unknown access method: %d", procstat->type); 1909249667Strociny return (NULL); 1910249667Strociny } 1911249667Strociny} 1912249667Strociny 1913249667Strocinyvoid 1914249667Strocinyprocstat_freevmmap(struct procstat *procstat __unused, 1915249667Strociny struct kinfo_vmentry *vmmap) 1916249667Strociny{ 1917249667Strociny 1918249667Strociny free(vmmap); 1919249667Strociny} 1920249670Strociny 1921249670Strocinystatic gid_t * 1922250146Strocinyprocstat_getgroups_kvm(kvm_t *kd, struct kinfo_proc *kp, unsigned int *cntp) 1923250146Strociny{ 1924250146Strociny struct proc proc; 1925250146Strociny struct ucred ucred; 1926250146Strociny gid_t *groups; 1927250146Strociny size_t len; 1928250146Strociny 1929250146Strociny assert(kd != NULL); 1930250146Strociny assert(kp != NULL); 1931250146Strociny if (!kvm_read_all(kd, (unsigned long)kp->ki_paddr, &proc, 1932250146Strociny sizeof(proc))) { 1933250146Strociny warnx("can't read proc struct at %p for pid %d", 1934250146Strociny kp->ki_paddr, kp->ki_pid); 1935250146Strociny return (NULL); 1936250146Strociny } 1937250146Strociny if (proc.p_ucred == NOCRED) 1938250146Strociny return (NULL); 1939250146Strociny if (!kvm_read_all(kd, (unsigned long)proc.p_ucred, &ucred, 1940250146Strociny sizeof(ucred))) { 1941250146Strociny warnx("can't read ucred struct at %p for pid %d", 1942250146Strociny proc.p_ucred, kp->ki_pid); 1943250146Strociny return (NULL); 1944250146Strociny } 1945250146Strociny len = ucred.cr_ngroups * sizeof(gid_t); 1946250146Strociny groups = malloc(len); 1947250146Strociny if (groups == NULL) { 1948250146Strociny warn("malloc(%zu)", len); 1949250146Strociny return (NULL); 1950250146Strociny } 1951250146Strociny if (!kvm_read_all(kd, (unsigned long)ucred.cr_groups, groups, len)) { 1952250146Strociny warnx("can't read groups at %p for pid %d", 1953250146Strociny ucred.cr_groups, kp->ki_pid); 1954250146Strociny free(groups); 1955250146Strociny return (NULL); 1956250146Strociny } 1957250146Strociny *cntp = ucred.cr_ngroups; 1958250146Strociny return (groups); 1959250146Strociny} 1960250146Strociny 1961250146Strocinystatic gid_t * 1962249670Strocinyprocstat_getgroups_sysctl(pid_t pid, unsigned int *cntp) 1963249670Strociny{ 1964249670Strociny int mib[4]; 1965249670Strociny size_t len; 1966249670Strociny gid_t *groups; 1967249670Strociny 1968249670Strociny mib[0] = CTL_KERN; 1969249670Strociny mib[1] = KERN_PROC; 1970249670Strociny mib[2] = KERN_PROC_GROUPS; 1971249670Strociny mib[3] = pid; 1972249670Strociny len = (sysconf(_SC_NGROUPS_MAX) + 1) * sizeof(gid_t); 1973249670Strociny groups = malloc(len); 1974249670Strociny if (groups == NULL) { 1975249670Strociny warn("malloc(%zu)", len); 1976249670Strociny return (NULL); 1977249670Strociny } 1978249670Strociny if (sysctl(mib, 4, groups, &len, NULL, 0) == -1) { 1979249670Strociny warn("sysctl: kern.proc.groups: %d", pid); 1980249670Strociny free(groups); 1981249670Strociny return (NULL); 1982249670Strociny } 1983249670Strociny *cntp = len / sizeof(gid_t); 1984249670Strociny return (groups); 1985249670Strociny} 1986249670Strociny 1987249670Strocinystatic gid_t * 1988249670Strocinyprocstat_getgroups_core(struct procstat_core *core, unsigned int *cntp) 1989249670Strociny{ 1990249670Strociny size_t len; 1991249670Strociny gid_t *groups; 1992249670Strociny 1993249670Strociny groups = procstat_core_get(core, PSC_TYPE_GROUPS, NULL, &len); 1994249670Strociny if (groups == NULL) 1995249670Strociny return (NULL); 1996249670Strociny *cntp = len / sizeof(gid_t); 1997249670Strociny return (groups); 1998249670Strociny} 1999249670Strociny 2000249670Strocinygid_t * 2001249670Strocinyprocstat_getgroups(struct procstat *procstat, struct kinfo_proc *kp, 2002249670Strociny unsigned int *cntp) 2003249670Strociny{ 2004249670Strociny switch(procstat->type) { 2005249670Strociny case PROCSTAT_KVM: 2006250146Strociny return (procstat_getgroups_kvm(procstat->kd, kp, cntp)); 2007249670Strociny case PROCSTAT_SYSCTL: 2008249670Strociny return (procstat_getgroups_sysctl(kp->ki_pid, cntp)); 2009249670Strociny case PROCSTAT_CORE: 2010249670Strociny return (procstat_getgroups_core(procstat->core, cntp)); 2011249670Strociny default: 2012249670Strociny warnx("unknown access method: %d", procstat->type); 2013249670Strociny return (NULL); 2014249670Strociny } 2015249670Strociny} 2016249670Strociny 2017249670Strocinyvoid 2018249670Strocinyprocstat_freegroups(struct procstat *procstat __unused, gid_t *groups) 2019249670Strociny{ 2020249670Strociny 2021249670Strociny free(groups); 2022249670Strociny} 2023249672Strociny 2024249672Strocinystatic int 2025250146Strocinyprocstat_getumask_kvm(kvm_t *kd, struct kinfo_proc *kp, unsigned short *maskp) 2026250146Strociny{ 2027250146Strociny struct filedesc fd; 2028250146Strociny 2029250146Strociny assert(kd != NULL); 2030250146Strociny assert(kp != NULL); 2031250146Strociny if (kp->ki_fd == NULL) 2032250146Strociny return (-1); 2033250146Strociny if (!kvm_read_all(kd, (unsigned long)kp->ki_fd, &fd, sizeof(fd))) { 2034250146Strociny warnx("can't read filedesc at %p for pid %d", kp->ki_fd, 2035250146Strociny kp->ki_pid); 2036250146Strociny return (-1); 2037250146Strociny } 2038250146Strociny *maskp = fd.fd_cmask; 2039250146Strociny return (0); 2040250146Strociny} 2041250146Strociny 2042250146Strocinystatic int 2043249672Strocinyprocstat_getumask_sysctl(pid_t pid, unsigned short *maskp) 2044249672Strociny{ 2045249672Strociny int error; 2046249672Strociny int mib[4]; 2047249672Strociny size_t len; 2048249672Strociny 2049249672Strociny mib[0] = CTL_KERN; 2050249672Strociny mib[1] = KERN_PROC; 2051249672Strociny mib[2] = KERN_PROC_UMASK; 2052249672Strociny mib[3] = pid; 2053249672Strociny len = sizeof(*maskp); 2054249672Strociny error = sysctl(mib, 4, maskp, &len, NULL, 0); 2055262947Srwatson if (error != 0 && errno != ESRCH && errno != EPERM) 2056249672Strociny warn("sysctl: kern.proc.umask: %d", pid); 2057249672Strociny return (error); 2058249672Strociny} 2059249672Strociny 2060249672Strocinystatic int 2061249672Strocinyprocstat_getumask_core(struct procstat_core *core, unsigned short *maskp) 2062249672Strociny{ 2063249672Strociny size_t len; 2064249672Strociny unsigned short *buf; 2065249672Strociny 2066249672Strociny buf = procstat_core_get(core, PSC_TYPE_UMASK, NULL, &len); 2067249672Strociny if (buf == NULL) 2068249672Strociny return (-1); 2069249672Strociny if (len < sizeof(*maskp)) { 2070249672Strociny free(buf); 2071249672Strociny return (-1); 2072249672Strociny } 2073249672Strociny *maskp = *buf; 2074249672Strociny free(buf); 2075249672Strociny return (0); 2076249672Strociny} 2077249672Strociny 2078249672Strocinyint 2079249672Strocinyprocstat_getumask(struct procstat *procstat, struct kinfo_proc *kp, 2080249672Strociny unsigned short *maskp) 2081249672Strociny{ 2082249672Strociny switch(procstat->type) { 2083249672Strociny case PROCSTAT_KVM: 2084250146Strociny return (procstat_getumask_kvm(procstat->kd, kp, maskp)); 2085249672Strociny case PROCSTAT_SYSCTL: 2086249672Strociny return (procstat_getumask_sysctl(kp->ki_pid, maskp)); 2087249672Strociny case PROCSTAT_CORE: 2088249672Strociny return (procstat_getumask_core(procstat->core, maskp)); 2089249672Strociny default: 2090249672Strociny warnx("unknown access method: %d", procstat->type); 2091249672Strociny return (-1); 2092249672Strociny } 2093249672Strociny} 2094249674Strociny 2095249674Strocinystatic int 2096250146Strocinyprocstat_getrlimit_kvm(kvm_t *kd, struct kinfo_proc *kp, int which, 2097250146Strociny struct rlimit* rlimit) 2098250146Strociny{ 2099250146Strociny struct proc proc; 2100250146Strociny unsigned long offset; 2101250146Strociny 2102250146Strociny assert(kd != NULL); 2103250146Strociny assert(kp != NULL); 2104250146Strociny assert(which >= 0 && which < RLIM_NLIMITS); 2105250146Strociny if (!kvm_read_all(kd, (unsigned long)kp->ki_paddr, &proc, 2106250146Strociny sizeof(proc))) { 2107250146Strociny warnx("can't read proc struct at %p for pid %d", 2108250146Strociny kp->ki_paddr, kp->ki_pid); 2109250146Strociny return (-1); 2110250146Strociny } 2111250146Strociny if (proc.p_limit == NULL) 2112250146Strociny return (-1); 2113250146Strociny offset = (unsigned long)proc.p_limit + sizeof(struct rlimit) * which; 2114250146Strociny if (!kvm_read_all(kd, offset, rlimit, sizeof(*rlimit))) { 2115250146Strociny warnx("can't read rlimit struct at %p for pid %d", 2116250146Strociny (void *)offset, kp->ki_pid); 2117250146Strociny return (-1); 2118250146Strociny } 2119250146Strociny return (0); 2120250146Strociny} 2121250146Strociny 2122250146Strocinystatic int 2123249674Strocinyprocstat_getrlimit_sysctl(pid_t pid, int which, struct rlimit* rlimit) 2124249674Strociny{ 2125249674Strociny int error, name[5]; 2126249674Strociny size_t len; 2127249674Strociny 2128249674Strociny name[0] = CTL_KERN; 2129249674Strociny name[1] = KERN_PROC; 2130249674Strociny name[2] = KERN_PROC_RLIMIT; 2131249674Strociny name[3] = pid; 2132249674Strociny name[4] = which; 2133249674Strociny len = sizeof(struct rlimit); 2134249674Strociny error = sysctl(name, 5, rlimit, &len, NULL, 0); 2135249674Strociny if (error < 0 && errno != ESRCH) { 2136249674Strociny warn("sysctl: kern.proc.rlimit: %d", pid); 2137249674Strociny return (-1); 2138249674Strociny } 2139249674Strociny if (error < 0 || len != sizeof(struct rlimit)) 2140249674Strociny return (-1); 2141249674Strociny return (0); 2142249674Strociny} 2143249674Strociny 2144249674Strocinystatic int 2145249674Strocinyprocstat_getrlimit_core(struct procstat_core *core, int which, 2146249674Strociny struct rlimit* rlimit) 2147249674Strociny{ 2148249674Strociny size_t len; 2149249674Strociny struct rlimit* rlimits; 2150249674Strociny 2151249674Strociny if (which < 0 || which >= RLIM_NLIMITS) { 2152249674Strociny errno = EINVAL; 2153249674Strociny warn("getrlimit: which"); 2154249674Strociny return (-1); 2155249674Strociny } 2156249674Strociny rlimits = procstat_core_get(core, PSC_TYPE_RLIMIT, NULL, &len); 2157249674Strociny if (rlimits == NULL) 2158249674Strociny return (-1); 2159249674Strociny if (len < sizeof(struct rlimit) * RLIM_NLIMITS) { 2160249674Strociny free(rlimits); 2161249674Strociny return (-1); 2162249674Strociny } 2163249674Strociny *rlimit = rlimits[which]; 2164249674Strociny return (0); 2165249674Strociny} 2166249674Strociny 2167249674Strocinyint 2168249674Strocinyprocstat_getrlimit(struct procstat *procstat, struct kinfo_proc *kp, int which, 2169249674Strociny struct rlimit* rlimit) 2170249674Strociny{ 2171249674Strociny switch(procstat->type) { 2172249674Strociny case PROCSTAT_KVM: 2173250146Strociny return (procstat_getrlimit_kvm(procstat->kd, kp, which, 2174250146Strociny rlimit)); 2175249674Strociny case PROCSTAT_SYSCTL: 2176249674Strociny return (procstat_getrlimit_sysctl(kp->ki_pid, which, rlimit)); 2177249674Strociny case PROCSTAT_CORE: 2178249674Strociny return (procstat_getrlimit_core(procstat->core, which, rlimit)); 2179249674Strociny default: 2180249674Strociny warnx("unknown access method: %d", procstat->type); 2181249674Strociny return (-1); 2182249674Strociny } 2183249674Strociny} 2184249676Strociny 2185249676Strocinystatic int 2186249676Strocinyprocstat_getpathname_sysctl(pid_t pid, char *pathname, size_t maxlen) 2187249676Strociny{ 2188249676Strociny int error, name[4]; 2189249676Strociny size_t len; 2190249676Strociny 2191249676Strociny name[0] = CTL_KERN; 2192249676Strociny name[1] = KERN_PROC; 2193249676Strociny name[2] = KERN_PROC_PATHNAME; 2194249676Strociny name[3] = pid; 2195249676Strociny len = maxlen; 2196249676Strociny error = sysctl(name, 4, pathname, &len, NULL, 0); 2197249676Strociny if (error != 0 && errno != ESRCH) 2198249676Strociny warn("sysctl: kern.proc.pathname: %d", pid); 2199249676Strociny if (len == 0) 2200249676Strociny pathname[0] = '\0'; 2201249676Strociny return (error); 2202249676Strociny} 2203249676Strociny 2204249676Strocinystatic int 2205249676Strocinyprocstat_getpathname_core(struct procstat_core *core, char *pathname, 2206249676Strociny size_t maxlen) 2207249676Strociny{ 2208249676Strociny struct kinfo_file *files; 2209249676Strociny int cnt, i, result; 2210249676Strociny 2211249676Strociny files = kinfo_getfile_core(core, &cnt); 2212249676Strociny if (files == NULL) 2213249676Strociny return (-1); 2214249676Strociny result = -1; 2215249676Strociny for (i = 0; i < cnt; i++) { 2216249676Strociny if (files[i].kf_fd != KF_FD_TYPE_TEXT) 2217249676Strociny continue; 2218249676Strociny strncpy(pathname, files[i].kf_path, maxlen); 2219249676Strociny result = 0; 2220249676Strociny break; 2221249676Strociny } 2222249676Strociny free(files); 2223249676Strociny return (result); 2224249676Strociny} 2225249676Strociny 2226249676Strocinyint 2227249676Strocinyprocstat_getpathname(struct procstat *procstat, struct kinfo_proc *kp, 2228249676Strociny char *pathname, size_t maxlen) 2229249676Strociny{ 2230249676Strociny switch(procstat->type) { 2231249676Strociny case PROCSTAT_KVM: 2232250147Strociny /* XXX: Return empty string. */ 2233250147Strociny if (maxlen > 0) 2234250147Strociny pathname[0] = '\0'; 2235250147Strociny return (0); 2236249676Strociny case PROCSTAT_SYSCTL: 2237249676Strociny return (procstat_getpathname_sysctl(kp->ki_pid, pathname, 2238249676Strociny maxlen)); 2239249676Strociny case PROCSTAT_CORE: 2240249676Strociny return (procstat_getpathname_core(procstat->core, pathname, 2241249676Strociny maxlen)); 2242249676Strociny default: 2243249676Strociny warnx("unknown access method: %d", procstat->type); 2244249676Strociny return (-1); 2245249676Strociny } 2246249676Strociny} 2247249677Strociny 2248249677Strocinystatic int 2249250146Strocinyprocstat_getosrel_kvm(kvm_t *kd, struct kinfo_proc *kp, int *osrelp) 2250250146Strociny{ 2251250146Strociny struct proc proc; 2252250146Strociny 2253250146Strociny assert(kd != NULL); 2254250146Strociny assert(kp != NULL); 2255250146Strociny if (!kvm_read_all(kd, (unsigned long)kp->ki_paddr, &proc, 2256250146Strociny sizeof(proc))) { 2257250146Strociny warnx("can't read proc struct at %p for pid %d", 2258250146Strociny kp->ki_paddr, kp->ki_pid); 2259250146Strociny return (-1); 2260250146Strociny } 2261250146Strociny *osrelp = proc.p_osrel; 2262250146Strociny return (0); 2263250146Strociny} 2264250146Strociny 2265250146Strocinystatic int 2266249677Strocinyprocstat_getosrel_sysctl(pid_t pid, int *osrelp) 2267249677Strociny{ 2268249677Strociny int error, name[4]; 2269249677Strociny size_t len; 2270249677Strociny 2271249677Strociny name[0] = CTL_KERN; 2272249677Strociny name[1] = KERN_PROC; 2273249677Strociny name[2] = KERN_PROC_OSREL; 2274249677Strociny name[3] = pid; 2275249677Strociny len = sizeof(*osrelp); 2276249677Strociny error = sysctl(name, 4, osrelp, &len, NULL, 0); 2277249677Strociny if (error != 0 && errno != ESRCH) 2278249677Strociny warn("sysctl: kern.proc.osrel: %d", pid); 2279249677Strociny return (error); 2280249677Strociny} 2281249677Strociny 2282249677Strocinystatic int 2283249677Strocinyprocstat_getosrel_core(struct procstat_core *core, int *osrelp) 2284249677Strociny{ 2285249677Strociny size_t len; 2286249677Strociny int *buf; 2287249677Strociny 2288249677Strociny buf = procstat_core_get(core, PSC_TYPE_OSREL, NULL, &len); 2289249677Strociny if (buf == NULL) 2290249677Strociny return (-1); 2291249677Strociny if (len < sizeof(*osrelp)) { 2292249677Strociny free(buf); 2293249677Strociny return (-1); 2294249677Strociny } 2295249677Strociny *osrelp = *buf; 2296249677Strociny free(buf); 2297249677Strociny return (0); 2298249677Strociny} 2299249677Strociny 2300249677Strocinyint 2301249677Strocinyprocstat_getosrel(struct procstat *procstat, struct kinfo_proc *kp, int *osrelp) 2302249677Strociny{ 2303249677Strociny switch(procstat->type) { 2304249677Strociny case PROCSTAT_KVM: 2305250146Strociny return (procstat_getosrel_kvm(procstat->kd, kp, osrelp)); 2306249677Strociny case PROCSTAT_SYSCTL: 2307249677Strociny return (procstat_getosrel_sysctl(kp->ki_pid, osrelp)); 2308249677Strociny case PROCSTAT_CORE: 2309249677Strociny return (procstat_getosrel_core(procstat->core, osrelp)); 2310249677Strociny default: 2311249677Strociny warnx("unknown access method: %d", procstat->type); 2312249677Strociny return (-1); 2313249677Strociny } 2314249677Strociny} 2315249681Strociny 2316249681Strociny#define PROC_AUXV_MAX 256 2317249681Strociny 2318249681Strociny#if __ELF_WORD_SIZE == 64 2319249681Strocinystatic const char *elf32_sv_names[] = { 2320249681Strociny "Linux ELF32", 2321249681Strociny "FreeBSD ELF32", 2322249681Strociny}; 2323249681Strociny 2324249681Strocinystatic int 2325249681Strocinyis_elf32_sysctl(pid_t pid) 2326249681Strociny{ 2327249681Strociny int error, name[4]; 2328249681Strociny size_t len, i; 2329249681Strociny static char sv_name[256]; 2330249681Strociny 2331249681Strociny name[0] = CTL_KERN; 2332249681Strociny name[1] = KERN_PROC; 2333249681Strociny name[2] = KERN_PROC_SV_NAME; 2334249681Strociny name[3] = pid; 2335249681Strociny len = sizeof(sv_name); 2336249681Strociny error = sysctl(name, 4, sv_name, &len, NULL, 0); 2337249681Strociny if (error != 0 || len == 0) 2338249681Strociny return (0); 2339249681Strociny for (i = 0; i < sizeof(elf32_sv_names) / sizeof(*elf32_sv_names); i++) { 2340249681Strociny if (strncmp(sv_name, elf32_sv_names[i], sizeof(sv_name)) == 0) 2341249681Strociny return (1); 2342249681Strociny } 2343249681Strociny return (0); 2344249681Strociny} 2345249681Strociny 2346249681Strocinystatic Elf_Auxinfo * 2347249681Strocinyprocstat_getauxv32_sysctl(pid_t pid, unsigned int *cntp) 2348249681Strociny{ 2349249681Strociny Elf_Auxinfo *auxv; 2350249681Strociny Elf32_Auxinfo *auxv32; 2351249681Strociny void *ptr; 2352249681Strociny size_t len; 2353249681Strociny unsigned int i, count; 2354249681Strociny int name[4]; 2355249681Strociny 2356249681Strociny name[0] = CTL_KERN; 2357249681Strociny name[1] = KERN_PROC; 2358249681Strociny name[2] = KERN_PROC_AUXV; 2359249681Strociny name[3] = pid; 2360249681Strociny len = PROC_AUXV_MAX * sizeof(Elf32_Auxinfo); 2361249681Strociny auxv = NULL; 2362249681Strociny auxv32 = malloc(len); 2363249681Strociny if (auxv32 == NULL) { 2364249681Strociny warn("malloc(%zu)", len); 2365249681Strociny goto out; 2366249681Strociny } 2367249681Strociny if (sysctl(name, 4, auxv32, &len, NULL, 0) == -1) { 2368249681Strociny if (errno != ESRCH && errno != EPERM) 2369249681Strociny warn("sysctl: kern.proc.auxv: %d: %d", pid, errno); 2370249681Strociny goto out; 2371249681Strociny } 2372249681Strociny count = len / sizeof(Elf_Auxinfo); 2373249681Strociny auxv = malloc(count * sizeof(Elf_Auxinfo)); 2374249681Strociny if (auxv == NULL) { 2375249681Strociny warn("malloc(%zu)", count * sizeof(Elf_Auxinfo)); 2376249681Strociny goto out; 2377249681Strociny } 2378249681Strociny for (i = 0; i < count; i++) { 2379249681Strociny /* 2380249681Strociny * XXX: We expect that values for a_type on a 32-bit platform 2381249681Strociny * are directly mapped to values on 64-bit one, which is not 2382249681Strociny * necessarily true. 2383249681Strociny */ 2384249681Strociny auxv[i].a_type = auxv32[i].a_type; 2385249681Strociny ptr = &auxv32[i].a_un; 2386249681Strociny auxv[i].a_un.a_val = *((uint32_t *)ptr); 2387249681Strociny } 2388249681Strociny *cntp = count; 2389249681Strocinyout: 2390249681Strociny free(auxv32); 2391249681Strociny return (auxv); 2392249681Strociny} 2393249681Strociny#endif /* __ELF_WORD_SIZE == 64 */ 2394249681Strociny 2395249681Strocinystatic Elf_Auxinfo * 2396249681Strocinyprocstat_getauxv_sysctl(pid_t pid, unsigned int *cntp) 2397249681Strociny{ 2398249681Strociny Elf_Auxinfo *auxv; 2399249681Strociny int name[4]; 2400249681Strociny size_t len; 2401249681Strociny 2402249681Strociny#if __ELF_WORD_SIZE == 64 2403249681Strociny if (is_elf32_sysctl(pid)) 2404249681Strociny return (procstat_getauxv32_sysctl(pid, cntp)); 2405249681Strociny#endif 2406249681Strociny name[0] = CTL_KERN; 2407249681Strociny name[1] = KERN_PROC; 2408249681Strociny name[2] = KERN_PROC_AUXV; 2409249681Strociny name[3] = pid; 2410249681Strociny len = PROC_AUXV_MAX * sizeof(Elf_Auxinfo); 2411249681Strociny auxv = malloc(len); 2412249681Strociny if (auxv == NULL) { 2413249681Strociny warn("malloc(%zu)", len); 2414249681Strociny return (NULL); 2415249681Strociny } 2416249681Strociny if (sysctl(name, 4, auxv, &len, NULL, 0) == -1) { 2417249681Strociny if (errno != ESRCH && errno != EPERM) 2418249681Strociny warn("sysctl: kern.proc.auxv: %d: %d", pid, errno); 2419249681Strociny free(auxv); 2420249681Strociny return (NULL); 2421249681Strociny } 2422249681Strociny *cntp = len / sizeof(Elf_Auxinfo); 2423249681Strociny return (auxv); 2424249681Strociny} 2425249681Strociny 2426249681Strocinystatic Elf_Auxinfo * 2427249681Strocinyprocstat_getauxv_core(struct procstat_core *core, unsigned int *cntp) 2428249681Strociny{ 2429249681Strociny Elf_Auxinfo *auxv; 2430249681Strociny size_t len; 2431249681Strociny 2432249681Strociny auxv = procstat_core_get(core, PSC_TYPE_AUXV, NULL, &len); 2433249681Strociny if (auxv == NULL) 2434249681Strociny return (NULL); 2435249681Strociny *cntp = len / sizeof(Elf_Auxinfo); 2436249681Strociny return (auxv); 2437249681Strociny} 2438249681Strociny 2439249681StrocinyElf_Auxinfo * 2440249681Strocinyprocstat_getauxv(struct procstat *procstat, struct kinfo_proc *kp, 2441249681Strociny unsigned int *cntp) 2442249681Strociny{ 2443249681Strociny switch(procstat->type) { 2444249681Strociny case PROCSTAT_KVM: 2445249681Strociny warnx("kvm method is not supported"); 2446249681Strociny return (NULL); 2447249681Strociny case PROCSTAT_SYSCTL: 2448249681Strociny return (procstat_getauxv_sysctl(kp->ki_pid, cntp)); 2449249681Strociny case PROCSTAT_CORE: 2450249681Strociny return (procstat_getauxv_core(procstat->core, cntp)); 2451249681Strociny default: 2452249681Strociny warnx("unknown access method: %d", procstat->type); 2453249681Strociny return (NULL); 2454249681Strociny } 2455249681Strociny} 2456249681Strociny 2457249681Strocinyvoid 2458249681Strocinyprocstat_freeauxv(struct procstat *procstat __unused, Elf_Auxinfo *auxv) 2459249681Strociny{ 2460249681Strociny 2461249681Strociny free(auxv); 2462249681Strociny} 2463249684Strociny 2464249684Strocinystatic struct kinfo_kstack * 2465249684Strocinyprocstat_getkstack_sysctl(pid_t pid, int *cntp) 2466249684Strociny{ 2467249684Strociny struct kinfo_kstack *kkstp; 2468249684Strociny int error, name[4]; 2469249684Strociny size_t len; 2470249684Strociny 2471249684Strociny name[0] = CTL_KERN; 2472249684Strociny name[1] = KERN_PROC; 2473249684Strociny name[2] = KERN_PROC_KSTACK; 2474249684Strociny name[3] = pid; 2475249684Strociny 2476249684Strociny len = 0; 2477249684Strociny error = sysctl(name, 4, NULL, &len, NULL, 0); 2478249684Strociny if (error < 0 && errno != ESRCH && errno != EPERM && errno != ENOENT) { 2479249684Strociny warn("sysctl: kern.proc.kstack: %d", pid); 2480249684Strociny return (NULL); 2481249684Strociny } 2482249684Strociny if (error == -1 && errno == ENOENT) { 2483249684Strociny warnx("sysctl: kern.proc.kstack unavailable" 2484249684Strociny " (options DDB or options STACK required in kernel)"); 2485249684Strociny return (NULL); 2486249684Strociny } 2487249684Strociny if (error == -1) 2488249684Strociny return (NULL); 2489249684Strociny kkstp = malloc(len); 2490249684Strociny if (kkstp == NULL) { 2491249684Strociny warn("malloc(%zu)", len); 2492249684Strociny return (NULL); 2493249684Strociny } 2494249684Strociny if (sysctl(name, 4, kkstp, &len, NULL, 0) == -1) { 2495249684Strociny warn("sysctl: kern.proc.pid: %d", pid); 2496249684Strociny free(kkstp); 2497249684Strociny return (NULL); 2498249684Strociny } 2499249684Strociny *cntp = len / sizeof(*kkstp); 2500249684Strociny 2501249684Strociny return (kkstp); 2502249684Strociny} 2503249684Strociny 2504249684Strocinystruct kinfo_kstack * 2505249684Strocinyprocstat_getkstack(struct procstat *procstat, struct kinfo_proc *kp, 2506249684Strociny unsigned int *cntp) 2507249684Strociny{ 2508249684Strociny switch(procstat->type) { 2509249684Strociny case PROCSTAT_KVM: 2510249684Strociny warnx("kvm method is not supported"); 2511249684Strociny return (NULL); 2512249684Strociny case PROCSTAT_SYSCTL: 2513249684Strociny return (procstat_getkstack_sysctl(kp->ki_pid, cntp)); 2514249684Strociny case PROCSTAT_CORE: 2515249684Strociny warnx("core method is not supported"); 2516249684Strociny return (NULL); 2517249684Strociny default: 2518249684Strociny warnx("unknown access method: %d", procstat->type); 2519249684Strociny return (NULL); 2520249684Strociny } 2521249684Strociny} 2522249684Strociny 2523249684Strocinyvoid 2524249684Strocinyprocstat_freekstack(struct procstat *procstat __unused, 2525249684Strociny struct kinfo_kstack *kkstp) 2526249684Strociny{ 2527249684Strociny 2528249684Strociny free(kkstp); 2529249684Strociny} 2530