libprocstat.c revision 249670
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: head/lib/libprocstat/libprocstat.c 249670 2013-04-20 07:54:07Z trociny $"); 37221807Sstas 38221807Sstas#include <sys/param.h> 39221807Sstas#include <sys/time.h> 40221807Sstas#include <sys/proc.h> 41221807Sstas#include <sys/user.h> 42221807Sstas#include <sys/stat.h> 43221807Sstas#include <sys/vnode.h> 44221807Sstas#include <sys/socket.h> 45221807Sstas#include <sys/socketvar.h> 46221807Sstas#include <sys/domain.h> 47221807Sstas#include <sys/protosw.h> 48221807Sstas#include <sys/un.h> 49221807Sstas#include <sys/unpcb.h> 50221807Sstas#include <sys/sysctl.h> 51221807Sstas#include <sys/tty.h> 52221807Sstas#include <sys/filedesc.h> 53221807Sstas#include <sys/queue.h> 54221807Sstas#define _WANT_FILE 55221807Sstas#include <sys/file.h> 56221807Sstas#include <sys/conf.h> 57233760Sjhb#include <sys/mman.h> 58221807Sstas#define _KERNEL 59221807Sstas#include <sys/mount.h> 60221807Sstas#include <sys/pipe.h> 61221807Sstas#include <ufs/ufs/quota.h> 62221807Sstas#include <ufs/ufs/inode.h> 63221807Sstas#include <fs/devfs/devfs.h> 64221807Sstas#include <fs/devfs/devfs_int.h> 65221807Sstas#undef _KERNEL 66221807Sstas#include <nfs/nfsproto.h> 67221807Sstas#include <nfsclient/nfs.h> 68221807Sstas#include <nfsclient/nfsnode.h> 69221807Sstas 70221807Sstas#include <vm/vm.h> 71221807Sstas#include <vm/vm_map.h> 72221807Sstas#include <vm/vm_object.h> 73221807Sstas 74221807Sstas#include <net/route.h> 75221807Sstas#include <netinet/in.h> 76221807Sstas#include <netinet/in_systm.h> 77221807Sstas#include <netinet/ip.h> 78221807Sstas#include <netinet/in_pcb.h> 79221807Sstas 80221807Sstas#include <assert.h> 81221807Sstas#include <ctype.h> 82221807Sstas#include <err.h> 83221807Sstas#include <fcntl.h> 84221807Sstas#include <kvm.h> 85221807Sstas#include <libutil.h> 86221807Sstas#include <limits.h> 87221807Sstas#include <paths.h> 88221807Sstas#include <pwd.h> 89221807Sstas#include <stdio.h> 90221807Sstas#include <stdlib.h> 91221807Sstas#include <stddef.h> 92221807Sstas#include <string.h> 93221807Sstas#include <unistd.h> 94221807Sstas#include <netdb.h> 95221807Sstas 96221807Sstas#include <libprocstat.h> 97221807Sstas#include "libprocstat_internal.h" 98221807Sstas#include "common_kvm.h" 99249666Strociny#include "core.h" 100221807Sstas 101221807Sstasint statfs(const char *, struct statfs *); /* XXX */ 102221807Sstas 103221807Sstas#define PROCSTAT_KVM 1 104221807Sstas#define PROCSTAT_SYSCTL 2 105249666Strociny#define PROCSTAT_CORE 3 106221807Sstas 107221807Sstasstatic char *getmnton(kvm_t *kd, struct mount *m); 108249667Strocinystatic struct kinfo_vmentry * kinfo_getvmmap_core(struct procstat_core *core, 109249667Strociny int *cntp); 110221807Sstasstatic struct filestat_list *procstat_getfiles_kvm( 111221807Sstas struct procstat *procstat, struct kinfo_proc *kp, int mmapped); 112221807Sstasstatic struct filestat_list *procstat_getfiles_sysctl( 113221807Sstas struct procstat *procstat, struct kinfo_proc *kp, int mmapped); 114221807Sstasstatic int procstat_get_pipe_info_sysctl(struct filestat *fst, 115221807Sstas struct pipestat *pipe, char *errbuf); 116221807Sstasstatic int procstat_get_pipe_info_kvm(kvm_t *kd, struct filestat *fst, 117221807Sstas struct pipestat *pipe, char *errbuf); 118221807Sstasstatic int procstat_get_pts_info_sysctl(struct filestat *fst, 119221807Sstas struct ptsstat *pts, char *errbuf); 120221807Sstasstatic int procstat_get_pts_info_kvm(kvm_t *kd, struct filestat *fst, 121221807Sstas struct ptsstat *pts, char *errbuf); 122233760Sjhbstatic int procstat_get_shm_info_sysctl(struct filestat *fst, 123233760Sjhb struct shmstat *shm, char *errbuf); 124233760Sjhbstatic int procstat_get_shm_info_kvm(kvm_t *kd, struct filestat *fst, 125233760Sjhb struct shmstat *shm, char *errbuf); 126221807Sstasstatic int procstat_get_socket_info_sysctl(struct filestat *fst, 127221807Sstas struct sockstat *sock, char *errbuf); 128221807Sstasstatic int procstat_get_socket_info_kvm(kvm_t *kd, struct filestat *fst, 129221807Sstas struct sockstat *sock, char *errbuf); 130221807Sstasstatic int to_filestat_flags(int flags); 131221807Sstasstatic int procstat_get_vnode_info_kvm(kvm_t *kd, struct filestat *fst, 132221807Sstas struct vnstat *vn, char *errbuf); 133221807Sstasstatic int procstat_get_vnode_info_sysctl(struct filestat *fst, 134221807Sstas struct vnstat *vn, char *errbuf); 135249670Strocinystatic gid_t *procstat_getgroups_core(struct procstat_core *core, 136249670Strociny unsigned int *count); 137249670Strocinystatic gid_t *procstat_getgroups_sysctl(pid_t pid, unsigned int *count); 138221807Sstasstatic int vntype2psfsttype(int type); 139221807Sstas 140221807Sstasvoid 141221807Sstasprocstat_close(struct procstat *procstat) 142221807Sstas{ 143221807Sstas 144221807Sstas assert(procstat); 145221807Sstas if (procstat->type == PROCSTAT_KVM) 146221807Sstas kvm_close(procstat->kd); 147249666Strociny else if (procstat->type == PROCSTAT_CORE) 148249666Strociny procstat_core_close(procstat->core); 149222053Spluknet free(procstat); 150221807Sstas} 151221807Sstas 152221807Sstasstruct procstat * 153221807Sstasprocstat_open_sysctl(void) 154221807Sstas{ 155221807Sstas struct procstat *procstat; 156221807Sstas 157221807Sstas procstat = calloc(1, sizeof(*procstat)); 158221807Sstas if (procstat == NULL) { 159221807Sstas warn("malloc()"); 160221807Sstas return (NULL); 161221807Sstas } 162221807Sstas procstat->type = PROCSTAT_SYSCTL; 163221807Sstas return (procstat); 164221807Sstas} 165221807Sstas 166221807Sstasstruct procstat * 167221807Sstasprocstat_open_kvm(const char *nlistf, const char *memf) 168221807Sstas{ 169221807Sstas struct procstat *procstat; 170221807Sstas kvm_t *kd; 171221807Sstas char buf[_POSIX2_LINE_MAX]; 172221807Sstas 173221807Sstas procstat = calloc(1, sizeof(*procstat)); 174221807Sstas if (procstat == NULL) { 175221807Sstas warn("malloc()"); 176221807Sstas return (NULL); 177221807Sstas } 178221807Sstas kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf); 179221807Sstas if (kd == NULL) { 180221807Sstas warnx("kvm_openfiles(): %s", buf); 181221807Sstas free(procstat); 182221807Sstas return (NULL); 183221807Sstas } 184221807Sstas procstat->type = PROCSTAT_KVM; 185221807Sstas procstat->kd = kd; 186221807Sstas return (procstat); 187221807Sstas} 188221807Sstas 189249666Strocinystruct procstat * 190249666Strocinyprocstat_open_core(const char *filename) 191249666Strociny{ 192249666Strociny struct procstat *procstat; 193249666Strociny struct procstat_core *core; 194249666Strociny 195249666Strociny procstat = calloc(1, sizeof(*procstat)); 196249666Strociny if (procstat == NULL) { 197249666Strociny warn("malloc()"); 198249666Strociny return (NULL); 199249666Strociny } 200249666Strociny core = procstat_core_open(filename); 201249666Strociny if (core == NULL) { 202249666Strociny free(procstat); 203249666Strociny return (NULL); 204249666Strociny } 205249666Strociny procstat->type = PROCSTAT_CORE; 206249666Strociny procstat->core = core; 207249666Strociny return (procstat); 208249666Strociny} 209249666Strociny 210221807Sstasstruct kinfo_proc * 211221807Sstasprocstat_getprocs(struct procstat *procstat, int what, int arg, 212221807Sstas unsigned int *count) 213221807Sstas{ 214221807Sstas struct kinfo_proc *p0, *p; 215221807Sstas size_t len; 216221807Sstas int name[4]; 217241304Savg int cnt; 218221807Sstas int error; 219221807Sstas 220221807Sstas assert(procstat); 221221807Sstas assert(count); 222221807Sstas p = NULL; 223221807Sstas if (procstat->type == PROCSTAT_KVM) { 224241304Savg *count = 0; 225241304Savg p0 = kvm_getprocs(procstat->kd, what, arg, &cnt); 226241304Savg if (p0 == NULL || cnt <= 0) 227221807Sstas return (NULL); 228241304Savg *count = cnt; 229221807Sstas len = *count * sizeof(*p); 230221807Sstas p = malloc(len); 231221807Sstas if (p == NULL) { 232223269Sjilles warnx("malloc(%zu)", len); 233221807Sstas goto fail; 234221807Sstas } 235221807Sstas bcopy(p0, p, len); 236221807Sstas return (p); 237221807Sstas } else if (procstat->type == PROCSTAT_SYSCTL) { 238221807Sstas len = 0; 239221807Sstas name[0] = CTL_KERN; 240221807Sstas name[1] = KERN_PROC; 241221807Sstas name[2] = what; 242221807Sstas name[3] = arg; 243221807Sstas error = sysctl(name, 4, NULL, &len, NULL, 0); 244221807Sstas if (error < 0 && errno != EPERM) { 245221807Sstas warn("sysctl(kern.proc)"); 246221807Sstas goto fail; 247221807Sstas } 248221807Sstas if (len == 0) { 249221807Sstas warnx("no processes?"); 250221807Sstas goto fail; 251221807Sstas } 252221807Sstas p = malloc(len); 253221807Sstas if (p == NULL) { 254223269Sjilles warnx("malloc(%zu)", len); 255221807Sstas goto fail; 256221807Sstas } 257221807Sstas error = sysctl(name, 4, p, &len, NULL, 0); 258221807Sstas if (error < 0 && errno != EPERM) { 259221807Sstas warn("sysctl(kern.proc)"); 260221807Sstas goto fail; 261221807Sstas } 262221807Sstas /* Perform simple consistency checks. */ 263221807Sstas if ((len % sizeof(*p)) != 0 || p->ki_structsize != sizeof(*p)) { 264249666Strociny warnx("kinfo_proc structure size mismatch (len = %zu)", len); 265249666Strociny goto fail; 266249666Strociny } 267249666Strociny *count = len / sizeof(*p); 268249666Strociny return (p); 269249666Strociny } else if (procstat->type == PROCSTAT_CORE) { 270249666Strociny p = procstat_core_get(procstat->core, PSC_TYPE_PROC, NULL, 271249666Strociny &len); 272249666Strociny if ((len % sizeof(*p)) != 0 || p->ki_structsize != sizeof(*p)) { 273221807Sstas warnx("kinfo_proc structure size mismatch"); 274221807Sstas goto fail; 275221807Sstas } 276221807Sstas *count = len / sizeof(*p); 277221807Sstas return (p); 278221807Sstas } else { 279223276Sjilles warnx("unknown access method: %d", procstat->type); 280221807Sstas return (NULL); 281221807Sstas } 282221807Sstasfail: 283221807Sstas if (p) 284221807Sstas free(p); 285221807Sstas return (NULL); 286221807Sstas} 287221807Sstas 288221807Sstasvoid 289221807Sstasprocstat_freeprocs(struct procstat *procstat __unused, struct kinfo_proc *p) 290221807Sstas{ 291221807Sstas 292221807Sstas if (p != NULL) 293221807Sstas free(p); 294221807Sstas p = NULL; 295221807Sstas} 296221807Sstas 297221807Sstasstruct filestat_list * 298221807Sstasprocstat_getfiles(struct procstat *procstat, struct kinfo_proc *kp, int mmapped) 299221807Sstas{ 300249666Strociny 301249666Strociny switch(procstat->type) { 302249666Strociny case PROCSTAT_KVM: 303249666Strociny return (procstat_getfiles_kvm(procstat, kp, mmapped)); 304249666Strociny case PROCSTAT_SYSCTL: 305249666Strociny case PROCSTAT_CORE: 306221807Sstas return (procstat_getfiles_sysctl(procstat, kp, mmapped)); 307249666Strociny default: 308249666Strociny warnx("unknown access method: %d", procstat->type); 309221807Sstas return (NULL); 310249666Strociny } 311221807Sstas} 312221807Sstas 313221807Sstasvoid 314221807Sstasprocstat_freefiles(struct procstat *procstat, struct filestat_list *head) 315221807Sstas{ 316221807Sstas struct filestat *fst, *tmp; 317221807Sstas 318221807Sstas STAILQ_FOREACH_SAFE(fst, head, next, tmp) { 319221807Sstas if (fst->fs_path != NULL) 320221807Sstas free(fst->fs_path); 321221807Sstas free(fst); 322221807Sstas } 323221807Sstas free(head); 324221807Sstas if (procstat->vmentries != NULL) { 325223270Sjilles free(procstat->vmentries); 326221807Sstas procstat->vmentries = NULL; 327221807Sstas } 328221807Sstas if (procstat->files != NULL) { 329223270Sjilles free(procstat->files); 330221807Sstas procstat->files = NULL; 331221807Sstas } 332221807Sstas} 333221807Sstas 334221807Sstasstatic struct filestat * 335221807Sstasfilestat_new_entry(void *typedep, int type, int fd, int fflags, int uflags, 336224859Srwatson int refcount, off_t offset, char *path, cap_rights_t cap_rights) 337221807Sstas{ 338221807Sstas struct filestat *entry; 339221807Sstas 340221807Sstas entry = calloc(1, sizeof(*entry)); 341221807Sstas if (entry == NULL) { 342221807Sstas warn("malloc()"); 343221807Sstas return (NULL); 344221807Sstas } 345221807Sstas entry->fs_typedep = typedep; 346221807Sstas entry->fs_fflags = fflags; 347221807Sstas entry->fs_uflags = uflags; 348221807Sstas entry->fs_fd = fd; 349221807Sstas entry->fs_type = type; 350221807Sstas entry->fs_ref_count = refcount; 351221807Sstas entry->fs_offset = offset; 352221807Sstas entry->fs_path = path; 353224859Srwatson entry->fs_cap_rights = cap_rights; 354221807Sstas return (entry); 355221807Sstas} 356221807Sstas 357221807Sstasstatic struct vnode * 358221807Sstasgetctty(kvm_t *kd, struct kinfo_proc *kp) 359221807Sstas{ 360221807Sstas struct pgrp pgrp; 361221807Sstas struct proc proc; 362221807Sstas struct session sess; 363221807Sstas int error; 364221807Sstas 365221807Sstas assert(kp); 366221807Sstas error = kvm_read_all(kd, (unsigned long)kp->ki_paddr, &proc, 367221807Sstas sizeof(proc)); 368221807Sstas if (error == 0) { 369221807Sstas warnx("can't read proc struct at %p for pid %d", 370221807Sstas kp->ki_paddr, kp->ki_pid); 371221807Sstas return (NULL); 372221807Sstas } 373221807Sstas if (proc.p_pgrp == NULL) 374221807Sstas return (NULL); 375221807Sstas error = kvm_read_all(kd, (unsigned long)proc.p_pgrp, &pgrp, 376221807Sstas sizeof(pgrp)); 377221807Sstas if (error == 0) { 378221807Sstas warnx("can't read pgrp struct at %p for pid %d", 379221807Sstas proc.p_pgrp, kp->ki_pid); 380221807Sstas return (NULL); 381221807Sstas } 382221807Sstas error = kvm_read_all(kd, (unsigned long)pgrp.pg_session, &sess, 383221807Sstas sizeof(sess)); 384221807Sstas if (error == 0) { 385221807Sstas warnx("can't read session struct at %p for pid %d", 386221807Sstas pgrp.pg_session, kp->ki_pid); 387221807Sstas return (NULL); 388221807Sstas } 389221807Sstas return (sess.s_ttyvp); 390221807Sstas} 391221807Sstas 392221807Sstasstatic struct filestat_list * 393221807Sstasprocstat_getfiles_kvm(struct procstat *procstat, struct kinfo_proc *kp, int mmapped) 394221807Sstas{ 395221807Sstas struct file file; 396221807Sstas struct filedesc filed; 397221807Sstas struct vm_map_entry vmentry; 398221807Sstas struct vm_object object; 399221807Sstas struct vmspace vmspace; 400221807Sstas vm_map_entry_t entryp; 401221807Sstas vm_map_t map; 402221807Sstas vm_object_t objp; 403221807Sstas struct vnode *vp; 404221807Sstas struct file **ofiles; 405221807Sstas struct filestat *entry; 406221807Sstas struct filestat_list *head; 407221807Sstas kvm_t *kd; 408221807Sstas void *data; 409221807Sstas int i, fflags; 410221807Sstas int prot, type; 411221807Sstas unsigned int nfiles; 412221807Sstas 413221807Sstas assert(procstat); 414221807Sstas kd = procstat->kd; 415221807Sstas if (kd == NULL) 416221807Sstas return (NULL); 417221807Sstas if (kp->ki_fd == NULL) 418221807Sstas return (NULL); 419221807Sstas if (!kvm_read_all(kd, (unsigned long)kp->ki_fd, &filed, 420221807Sstas sizeof(filed))) { 421221807Sstas warnx("can't read filedesc at %p", (void *)kp->ki_fd); 422221807Sstas return (NULL); 423221807Sstas } 424221807Sstas 425221807Sstas /* 426221807Sstas * Allocate list head. 427221807Sstas */ 428221807Sstas head = malloc(sizeof(*head)); 429221807Sstas if (head == NULL) 430221807Sstas return (NULL); 431221807Sstas STAILQ_INIT(head); 432221807Sstas 433221807Sstas /* root directory vnode, if one. */ 434221807Sstas if (filed.fd_rdir) { 435221807Sstas entry = filestat_new_entry(filed.fd_rdir, PS_FST_TYPE_VNODE, -1, 436224859Srwatson PS_FST_FFLAG_READ, PS_FST_UFLAG_RDIR, 0, 0, NULL, 0); 437221807Sstas if (entry != NULL) 438221807Sstas STAILQ_INSERT_TAIL(head, entry, next); 439221807Sstas } 440221807Sstas /* current working directory vnode. */ 441221807Sstas if (filed.fd_cdir) { 442221807Sstas entry = filestat_new_entry(filed.fd_cdir, PS_FST_TYPE_VNODE, -1, 443224859Srwatson PS_FST_FFLAG_READ, PS_FST_UFLAG_CDIR, 0, 0, NULL, 0); 444221807Sstas if (entry != NULL) 445221807Sstas STAILQ_INSERT_TAIL(head, entry, next); 446221807Sstas } 447221807Sstas /* jail root, if any. */ 448221807Sstas if (filed.fd_jdir) { 449221807Sstas entry = filestat_new_entry(filed.fd_jdir, PS_FST_TYPE_VNODE, -1, 450224859Srwatson PS_FST_FFLAG_READ, PS_FST_UFLAG_JAIL, 0, 0, NULL, 0); 451221807Sstas if (entry != NULL) 452221807Sstas STAILQ_INSERT_TAIL(head, entry, next); 453221807Sstas } 454221807Sstas /* ktrace vnode, if one */ 455221807Sstas if (kp->ki_tracep) { 456221807Sstas entry = filestat_new_entry(kp->ki_tracep, PS_FST_TYPE_VNODE, -1, 457221807Sstas PS_FST_FFLAG_READ | PS_FST_FFLAG_WRITE, 458224859Srwatson PS_FST_UFLAG_TRACE, 0, 0, NULL, 0); 459221807Sstas if (entry != NULL) 460221807Sstas STAILQ_INSERT_TAIL(head, entry, next); 461221807Sstas } 462221807Sstas /* text vnode, if one */ 463221807Sstas if (kp->ki_textvp) { 464221807Sstas entry = filestat_new_entry(kp->ki_textvp, PS_FST_TYPE_VNODE, -1, 465224859Srwatson PS_FST_FFLAG_READ, PS_FST_UFLAG_TEXT, 0, 0, NULL, 0); 466221807Sstas if (entry != NULL) 467221807Sstas STAILQ_INSERT_TAIL(head, entry, next); 468221807Sstas } 469221807Sstas /* Controlling terminal. */ 470221807Sstas if ((vp = getctty(kd, kp)) != NULL) { 471221807Sstas entry = filestat_new_entry(vp, PS_FST_TYPE_VNODE, -1, 472221807Sstas PS_FST_FFLAG_READ | PS_FST_FFLAG_WRITE, 473224859Srwatson PS_FST_UFLAG_CTTY, 0, 0, NULL, 0); 474221807Sstas if (entry != NULL) 475221807Sstas STAILQ_INSERT_TAIL(head, entry, next); 476221807Sstas } 477221807Sstas 478221807Sstas nfiles = filed.fd_lastfile + 1; 479221807Sstas ofiles = malloc(nfiles * sizeof(struct file *)); 480221807Sstas if (ofiles == NULL) { 481223269Sjilles warn("malloc(%zu)", nfiles * sizeof(struct file *)); 482221807Sstas goto do_mmapped; 483221807Sstas } 484221807Sstas if (!kvm_read_all(kd, (unsigned long)filed.fd_ofiles, ofiles, 485221807Sstas nfiles * sizeof(struct file *))) { 486221807Sstas warnx("cannot read file structures at %p", 487221807Sstas (void *)filed.fd_ofiles); 488221807Sstas free(ofiles); 489221807Sstas goto do_mmapped; 490221807Sstas } 491221807Sstas for (i = 0; i <= filed.fd_lastfile; i++) { 492221807Sstas if (ofiles[i] == NULL) 493221807Sstas continue; 494221807Sstas if (!kvm_read_all(kd, (unsigned long)ofiles[i], &file, 495221807Sstas sizeof(struct file))) { 496221807Sstas warnx("can't read file %d at %p", i, 497221807Sstas (void *)ofiles[i]); 498221807Sstas continue; 499221807Sstas } 500221807Sstas switch (file.f_type) { 501221807Sstas case DTYPE_VNODE: 502221807Sstas type = PS_FST_TYPE_VNODE; 503221807Sstas data = file.f_vnode; 504221807Sstas break; 505221807Sstas case DTYPE_SOCKET: 506221807Sstas type = PS_FST_TYPE_SOCKET; 507221807Sstas data = file.f_data; 508221807Sstas break; 509221807Sstas case DTYPE_PIPE: 510221807Sstas type = PS_FST_TYPE_PIPE; 511221807Sstas data = file.f_data; 512221807Sstas break; 513221807Sstas case DTYPE_FIFO: 514221807Sstas type = PS_FST_TYPE_FIFO; 515221807Sstas data = file.f_vnode; 516221807Sstas break; 517221807Sstas#ifdef DTYPE_PTS 518221807Sstas case DTYPE_PTS: 519221807Sstas type = PS_FST_TYPE_PTS; 520221807Sstas data = file.f_data; 521221807Sstas break; 522221807Sstas#endif 523233760Sjhb case DTYPE_SHM: 524233760Sjhb type = PS_FST_TYPE_SHM; 525233760Sjhb data = file.f_data; 526233760Sjhb break; 527221807Sstas default: 528221807Sstas continue; 529221807Sstas } 530224859Srwatson /* XXXRW: No capability rights support for kvm yet. */ 531221807Sstas entry = filestat_new_entry(data, type, i, 532224859Srwatson to_filestat_flags(file.f_flag), 0, 0, 0, NULL, 0); 533221807Sstas if (entry != NULL) 534221807Sstas STAILQ_INSERT_TAIL(head, entry, next); 535221807Sstas } 536221807Sstas free(ofiles); 537221807Sstas 538221807Sstasdo_mmapped: 539221807Sstas 540221807Sstas /* 541221807Sstas * Process mmapped files if requested. 542221807Sstas */ 543221807Sstas if (mmapped) { 544221807Sstas if (!kvm_read_all(kd, (unsigned long)kp->ki_vmspace, &vmspace, 545221807Sstas sizeof(vmspace))) { 546221807Sstas warnx("can't read vmspace at %p", 547221807Sstas (void *)kp->ki_vmspace); 548221807Sstas goto exit; 549221807Sstas } 550221807Sstas map = &vmspace.vm_map; 551221807Sstas 552221807Sstas for (entryp = map->header.next; 553221807Sstas entryp != &kp->ki_vmspace->vm_map.header; 554221807Sstas entryp = vmentry.next) { 555221807Sstas if (!kvm_read_all(kd, (unsigned long)entryp, &vmentry, 556221807Sstas sizeof(vmentry))) { 557221807Sstas warnx("can't read vm_map_entry at %p", 558221807Sstas (void *)entryp); 559221807Sstas continue; 560221807Sstas } 561221807Sstas if (vmentry.eflags & MAP_ENTRY_IS_SUB_MAP) 562221807Sstas continue; 563221807Sstas if ((objp = vmentry.object.vm_object) == NULL) 564221807Sstas continue; 565221807Sstas for (; objp; objp = object.backing_object) { 566221807Sstas if (!kvm_read_all(kd, (unsigned long)objp, 567221807Sstas &object, sizeof(object))) { 568221807Sstas warnx("can't read vm_object at %p", 569221807Sstas (void *)objp); 570221807Sstas break; 571221807Sstas } 572221807Sstas } 573221807Sstas 574221807Sstas /* We want only vnode objects. */ 575221807Sstas if (object.type != OBJT_VNODE) 576221807Sstas continue; 577221807Sstas 578221807Sstas prot = vmentry.protection; 579221807Sstas fflags = 0; 580221807Sstas if (prot & VM_PROT_READ) 581221807Sstas fflags = PS_FST_FFLAG_READ; 582223279Sjilles if ((vmentry.eflags & MAP_ENTRY_COW) == 0 && 583223279Sjilles prot & VM_PROT_WRITE) 584221807Sstas fflags |= PS_FST_FFLAG_WRITE; 585221807Sstas 586221807Sstas /* 587221807Sstas * Create filestat entry. 588221807Sstas */ 589221807Sstas entry = filestat_new_entry(object.handle, 590221807Sstas PS_FST_TYPE_VNODE, -1, fflags, 591224859Srwatson PS_FST_UFLAG_MMAP, 0, 0, NULL, 0); 592221807Sstas if (entry != NULL) 593221807Sstas STAILQ_INSERT_TAIL(head, entry, next); 594221807Sstas } 595221807Sstas } 596221807Sstasexit: 597221807Sstas return (head); 598221807Sstas} 599221807Sstas 600221807Sstas/* 601221807Sstas * kinfo types to filestat translation. 602221807Sstas */ 603221807Sstasstatic int 604221807Sstaskinfo_type2fst(int kftype) 605221807Sstas{ 606221807Sstas static struct { 607221807Sstas int kf_type; 608221807Sstas int fst_type; 609221807Sstas } kftypes2fst[] = { 610221807Sstas { KF_TYPE_CRYPTO, PS_FST_TYPE_CRYPTO }, 611221807Sstas { KF_TYPE_FIFO, PS_FST_TYPE_FIFO }, 612221807Sstas { KF_TYPE_KQUEUE, PS_FST_TYPE_KQUEUE }, 613221807Sstas { KF_TYPE_MQUEUE, PS_FST_TYPE_MQUEUE }, 614221807Sstas { KF_TYPE_NONE, PS_FST_TYPE_NONE }, 615221807Sstas { KF_TYPE_PIPE, PS_FST_TYPE_PIPE }, 616221807Sstas { KF_TYPE_PTS, PS_FST_TYPE_PTS }, 617221807Sstas { KF_TYPE_SEM, PS_FST_TYPE_SEM }, 618221807Sstas { KF_TYPE_SHM, PS_FST_TYPE_SHM }, 619221807Sstas { KF_TYPE_SOCKET, PS_FST_TYPE_SOCKET }, 620221807Sstas { KF_TYPE_VNODE, PS_FST_TYPE_VNODE }, 621221807Sstas { KF_TYPE_UNKNOWN, PS_FST_TYPE_UNKNOWN } 622221807Sstas }; 623221807Sstas#define NKFTYPES (sizeof(kftypes2fst) / sizeof(*kftypes2fst)) 624221807Sstas unsigned int i; 625221807Sstas 626221807Sstas for (i = 0; i < NKFTYPES; i++) 627221807Sstas if (kftypes2fst[i].kf_type == kftype) 628221807Sstas break; 629221807Sstas if (i == NKFTYPES) 630221807Sstas return (PS_FST_TYPE_UNKNOWN); 631221807Sstas return (kftypes2fst[i].fst_type); 632221807Sstas} 633221807Sstas 634221807Sstas/* 635221807Sstas * kinfo flags to filestat translation. 636221807Sstas */ 637221807Sstasstatic int 638221807Sstaskinfo_fflags2fst(int kfflags) 639221807Sstas{ 640221807Sstas static struct { 641221807Sstas int kf_flag; 642221807Sstas int fst_flag; 643221807Sstas } kfflags2fst[] = { 644221807Sstas { KF_FLAG_APPEND, PS_FST_FFLAG_APPEND }, 645221807Sstas { KF_FLAG_ASYNC, PS_FST_FFLAG_ASYNC }, 646221807Sstas { KF_FLAG_CREAT, PS_FST_FFLAG_CREAT }, 647221807Sstas { KF_FLAG_DIRECT, PS_FST_FFLAG_DIRECT }, 648221807Sstas { KF_FLAG_EXCL, PS_FST_FFLAG_EXCL }, 649221807Sstas { KF_FLAG_EXEC, PS_FST_FFLAG_EXEC }, 650221807Sstas { KF_FLAG_EXLOCK, PS_FST_FFLAG_EXLOCK }, 651221807Sstas { KF_FLAG_FSYNC, PS_FST_FFLAG_SYNC }, 652221807Sstas { KF_FLAG_HASLOCK, PS_FST_FFLAG_HASLOCK }, 653221807Sstas { KF_FLAG_NOFOLLOW, PS_FST_FFLAG_NOFOLLOW }, 654221807Sstas { KF_FLAG_NONBLOCK, PS_FST_FFLAG_NONBLOCK }, 655221807Sstas { KF_FLAG_READ, PS_FST_FFLAG_READ }, 656221807Sstas { KF_FLAG_SHLOCK, PS_FST_FFLAG_SHLOCK }, 657221807Sstas { KF_FLAG_TRUNC, PS_FST_FFLAG_TRUNC }, 658221807Sstas { KF_FLAG_WRITE, PS_FST_FFLAG_WRITE } 659221807Sstas }; 660221807Sstas#define NKFFLAGS (sizeof(kfflags2fst) / sizeof(*kfflags2fst)) 661221807Sstas unsigned int i; 662221807Sstas int flags; 663221807Sstas 664221807Sstas flags = 0; 665221807Sstas for (i = 0; i < NKFFLAGS; i++) 666221807Sstas if ((kfflags & kfflags2fst[i].kf_flag) != 0) 667221807Sstas flags |= kfflags2fst[i].fst_flag; 668221807Sstas return (flags); 669221807Sstas} 670221807Sstas 671221807Sstasstatic int 672221807Sstaskinfo_uflags2fst(int fd) 673221807Sstas{ 674221807Sstas 675221807Sstas switch (fd) { 676221807Sstas case KF_FD_TYPE_CTTY: 677221807Sstas return (PS_FST_UFLAG_CTTY); 678221807Sstas case KF_FD_TYPE_CWD: 679221807Sstas return (PS_FST_UFLAG_CDIR); 680221807Sstas case KF_FD_TYPE_JAIL: 681221807Sstas return (PS_FST_UFLAG_JAIL); 682221807Sstas case KF_FD_TYPE_TEXT: 683221807Sstas return (PS_FST_UFLAG_TEXT); 684221807Sstas case KF_FD_TYPE_TRACE: 685221807Sstas return (PS_FST_UFLAG_TRACE); 686221807Sstas case KF_FD_TYPE_ROOT: 687221807Sstas return (PS_FST_UFLAG_RDIR); 688221807Sstas } 689221807Sstas return (0); 690221807Sstas} 691221807Sstas 692249666Strocinystatic struct kinfo_file * 693249666Strocinykinfo_getfile_core(struct procstat_core *core, int *cntp) 694249666Strociny{ 695249666Strociny int cnt; 696249666Strociny size_t len; 697249666Strociny char *buf, *bp, *eb; 698249666Strociny struct kinfo_file *kif, *kp, *kf; 699249666Strociny 700249666Strociny buf = procstat_core_get(core, PSC_TYPE_FILES, NULL, &len); 701249666Strociny if (buf == NULL) 702249666Strociny return (NULL); 703249666Strociny /* 704249666Strociny * XXXMG: The code below is just copy&past from libutil. 705249666Strociny * The code duplication can be avoided if libutil 706249666Strociny * is extended to provide something like: 707249666Strociny * struct kinfo_file *kinfo_getfile_from_buf(const char *buf, 708249666Strociny * size_t len, int *cntp); 709249666Strociny */ 710249666Strociny 711249666Strociny /* Pass 1: count items */ 712249666Strociny cnt = 0; 713249666Strociny bp = buf; 714249666Strociny eb = buf + len; 715249666Strociny while (bp < eb) { 716249666Strociny kf = (struct kinfo_file *)(uintptr_t)bp; 717249666Strociny bp += kf->kf_structsize; 718249666Strociny cnt++; 719249666Strociny } 720249666Strociny 721249666Strociny kif = calloc(cnt, sizeof(*kif)); 722249666Strociny if (kif == NULL) { 723249666Strociny free(buf); 724249666Strociny return (NULL); 725249666Strociny } 726249666Strociny bp = buf; 727249666Strociny eb = buf + len; 728249666Strociny kp = kif; 729249666Strociny /* Pass 2: unpack */ 730249666Strociny while (bp < eb) { 731249666Strociny kf = (struct kinfo_file *)(uintptr_t)bp; 732249666Strociny /* Copy/expand into pre-zeroed buffer */ 733249666Strociny memcpy(kp, kf, kf->kf_structsize); 734249666Strociny /* Advance to next packed record */ 735249666Strociny bp += kf->kf_structsize; 736249666Strociny /* Set field size to fixed length, advance */ 737249666Strociny kp->kf_structsize = sizeof(*kp); 738249666Strociny kp++; 739249666Strociny } 740249666Strociny free(buf); 741249666Strociny *cntp = cnt; 742249666Strociny return (kif); /* Caller must free() return value */ 743249666Strociny} 744249666Strociny 745221807Sstasstatic struct filestat_list * 746249666Strocinyprocstat_getfiles_sysctl(struct procstat *procstat, struct kinfo_proc *kp, 747249666Strociny int mmapped) 748221807Sstas{ 749221807Sstas struct kinfo_file *kif, *files; 750221807Sstas struct kinfo_vmentry *kve, *vmentries; 751221807Sstas struct filestat_list *head; 752221807Sstas struct filestat *entry; 753221807Sstas char *path; 754221807Sstas off_t offset; 755221807Sstas int cnt, fd, fflags; 756221807Sstas int i, type, uflags; 757221807Sstas int refcount; 758224859Srwatson cap_rights_t cap_rights; 759221807Sstas 760221807Sstas assert(kp); 761221807Sstas if (kp->ki_fd == NULL) 762221807Sstas return (NULL); 763249666Strociny switch(procstat->type) { 764249666Strociny case PROCSTAT_SYSCTL: 765249666Strociny files = kinfo_getfile(kp->ki_pid, &cnt); 766249666Strociny break; 767249666Strociny case PROCSTAT_CORE: 768249666Strociny files = kinfo_getfile_core(procstat->core, &cnt); 769249666Strociny break; 770249666Strociny default: 771249666Strociny assert(!"invalid type"); 772249666Strociny } 773221807Sstas if (files == NULL && errno != EPERM) { 774221807Sstas warn("kinfo_getfile()"); 775221807Sstas return (NULL); 776221807Sstas } 777221807Sstas procstat->files = files; 778221807Sstas 779221807Sstas /* 780221807Sstas * Allocate list head. 781221807Sstas */ 782221807Sstas head = malloc(sizeof(*head)); 783221807Sstas if (head == NULL) 784221807Sstas return (NULL); 785221807Sstas STAILQ_INIT(head); 786221807Sstas for (i = 0; i < cnt; i++) { 787221807Sstas kif = &files[i]; 788221807Sstas 789221807Sstas type = kinfo_type2fst(kif->kf_type); 790221807Sstas fd = kif->kf_fd >= 0 ? kif->kf_fd : -1; 791221807Sstas fflags = kinfo_fflags2fst(kif->kf_flags); 792221807Sstas uflags = kinfo_uflags2fst(kif->kf_fd); 793221807Sstas refcount = kif->kf_ref_count; 794221807Sstas offset = kif->kf_offset; 795221807Sstas if (*kif->kf_path != '\0') 796221807Sstas path = strdup(kif->kf_path); 797221807Sstas else 798221807Sstas path = NULL; 799224859Srwatson cap_rights = kif->kf_cap_rights; 800221807Sstas 801221807Sstas /* 802221807Sstas * Create filestat entry. 803221807Sstas */ 804221807Sstas entry = filestat_new_entry(kif, type, fd, fflags, uflags, 805224859Srwatson refcount, offset, path, cap_rights); 806221807Sstas if (entry != NULL) 807221807Sstas STAILQ_INSERT_TAIL(head, entry, next); 808221807Sstas } 809221807Sstas if (mmapped != 0) { 810249667Strociny vmentries = procstat_getvmmap(procstat, kp, &cnt); 811221807Sstas procstat->vmentries = vmentries; 812221807Sstas if (vmentries == NULL || cnt == 0) 813221807Sstas goto fail; 814221807Sstas for (i = 0; i < cnt; i++) { 815221807Sstas kve = &vmentries[i]; 816221807Sstas if (kve->kve_type != KVME_TYPE_VNODE) 817221807Sstas continue; 818221807Sstas fflags = 0; 819221807Sstas if (kve->kve_protection & KVME_PROT_READ) 820221807Sstas fflags = PS_FST_FFLAG_READ; 821223279Sjilles if ((kve->kve_flags & KVME_FLAG_COW) == 0 && 822223279Sjilles kve->kve_protection & KVME_PROT_WRITE) 823221807Sstas fflags |= PS_FST_FFLAG_WRITE; 824221807Sstas offset = kve->kve_offset; 825221807Sstas refcount = kve->kve_ref_count; 826221807Sstas if (*kve->kve_path != '\0') 827221807Sstas path = strdup(kve->kve_path); 828221807Sstas else 829221807Sstas path = NULL; 830221807Sstas entry = filestat_new_entry(kve, PS_FST_TYPE_VNODE, -1, 831224859Srwatson fflags, PS_FST_UFLAG_MMAP, refcount, offset, path, 832224859Srwatson 0); 833221807Sstas if (entry != NULL) 834221807Sstas STAILQ_INSERT_TAIL(head, entry, next); 835221807Sstas } 836221807Sstas } 837221807Sstasfail: 838221807Sstas return (head); 839221807Sstas} 840221807Sstas 841221807Sstasint 842221807Sstasprocstat_get_pipe_info(struct procstat *procstat, struct filestat *fst, 843221807Sstas struct pipestat *ps, char *errbuf) 844221807Sstas{ 845221807Sstas 846221807Sstas assert(ps); 847221807Sstas if (procstat->type == PROCSTAT_KVM) { 848221807Sstas return (procstat_get_pipe_info_kvm(procstat->kd, fst, ps, 849221807Sstas errbuf)); 850249666Strociny } else if (procstat->type == PROCSTAT_SYSCTL || 851249666Strociny procstat->type == PROCSTAT_CORE) { 852221807Sstas return (procstat_get_pipe_info_sysctl(fst, ps, errbuf)); 853221807Sstas } else { 854223276Sjilles warnx("unknown access method: %d", procstat->type); 855221807Sstas snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 856221807Sstas return (1); 857221807Sstas } 858221807Sstas} 859221807Sstas 860221807Sstasstatic int 861221807Sstasprocstat_get_pipe_info_kvm(kvm_t *kd, struct filestat *fst, 862221807Sstas struct pipestat *ps, char *errbuf) 863221807Sstas{ 864221807Sstas struct pipe pi; 865221807Sstas void *pipep; 866221807Sstas 867221807Sstas assert(kd); 868221807Sstas assert(ps); 869221807Sstas assert(fst); 870221807Sstas bzero(ps, sizeof(*ps)); 871221807Sstas pipep = fst->fs_typedep; 872221807Sstas if (pipep == NULL) 873221807Sstas goto fail; 874221807Sstas if (!kvm_read_all(kd, (unsigned long)pipep, &pi, sizeof(struct pipe))) { 875221807Sstas warnx("can't read pipe at %p", (void *)pipep); 876221807Sstas goto fail; 877221807Sstas } 878221807Sstas ps->addr = (uintptr_t)pipep; 879221807Sstas ps->peer = (uintptr_t)pi.pipe_peer; 880221807Sstas ps->buffer_cnt = pi.pipe_buffer.cnt; 881221807Sstas return (0); 882221807Sstas 883221807Sstasfail: 884221807Sstas snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 885221807Sstas return (1); 886221807Sstas} 887221807Sstas 888221807Sstasstatic int 889221807Sstasprocstat_get_pipe_info_sysctl(struct filestat *fst, struct pipestat *ps, 890221807Sstas char *errbuf __unused) 891221807Sstas{ 892221807Sstas struct kinfo_file *kif; 893221807Sstas 894221807Sstas assert(ps); 895221807Sstas assert(fst); 896221807Sstas bzero(ps, sizeof(*ps)); 897221807Sstas kif = fst->fs_typedep; 898221807Sstas if (kif == NULL) 899221807Sstas return (1); 900221807Sstas ps->addr = kif->kf_un.kf_pipe.kf_pipe_addr; 901221807Sstas ps->peer = kif->kf_un.kf_pipe.kf_pipe_peer; 902221807Sstas ps->buffer_cnt = kif->kf_un.kf_pipe.kf_pipe_buffer_cnt; 903221807Sstas return (0); 904221807Sstas} 905221807Sstas 906221807Sstasint 907221807Sstasprocstat_get_pts_info(struct procstat *procstat, struct filestat *fst, 908221807Sstas struct ptsstat *pts, char *errbuf) 909221807Sstas{ 910221807Sstas 911221807Sstas assert(pts); 912221807Sstas if (procstat->type == PROCSTAT_KVM) { 913221807Sstas return (procstat_get_pts_info_kvm(procstat->kd, fst, pts, 914221807Sstas errbuf)); 915249666Strociny } else if (procstat->type == PROCSTAT_SYSCTL || 916249666Strociny procstat->type == PROCSTAT_CORE) { 917221807Sstas return (procstat_get_pts_info_sysctl(fst, pts, errbuf)); 918221807Sstas } else { 919223276Sjilles warnx("unknown access method: %d", procstat->type); 920221807Sstas snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 921221807Sstas return (1); 922221807Sstas } 923221807Sstas} 924221807Sstas 925221807Sstasstatic int 926221807Sstasprocstat_get_pts_info_kvm(kvm_t *kd, struct filestat *fst, 927221807Sstas struct ptsstat *pts, char *errbuf) 928221807Sstas{ 929221807Sstas struct tty tty; 930221807Sstas void *ttyp; 931221807Sstas 932221807Sstas assert(kd); 933221807Sstas assert(pts); 934221807Sstas assert(fst); 935221807Sstas bzero(pts, sizeof(*pts)); 936221807Sstas ttyp = fst->fs_typedep; 937221807Sstas if (ttyp == NULL) 938221807Sstas goto fail; 939221807Sstas if (!kvm_read_all(kd, (unsigned long)ttyp, &tty, sizeof(struct tty))) { 940221807Sstas warnx("can't read tty at %p", (void *)ttyp); 941221807Sstas goto fail; 942221807Sstas } 943221807Sstas pts->dev = dev2udev(kd, tty.t_dev); 944221807Sstas (void)kdevtoname(kd, tty.t_dev, pts->devname); 945221807Sstas return (0); 946221807Sstas 947221807Sstasfail: 948221807Sstas snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 949221807Sstas return (1); 950221807Sstas} 951221807Sstas 952221807Sstasstatic int 953221807Sstasprocstat_get_pts_info_sysctl(struct filestat *fst, struct ptsstat *pts, 954221807Sstas char *errbuf __unused) 955221807Sstas{ 956221807Sstas struct kinfo_file *kif; 957221807Sstas 958221807Sstas assert(pts); 959221807Sstas assert(fst); 960221807Sstas bzero(pts, sizeof(*pts)); 961221807Sstas kif = fst->fs_typedep; 962221807Sstas if (kif == NULL) 963221807Sstas return (0); 964221807Sstas pts->dev = kif->kf_un.kf_pts.kf_pts_dev; 965221807Sstas strlcpy(pts->devname, kif->kf_path, sizeof(pts->devname)); 966221807Sstas return (0); 967221807Sstas} 968221807Sstas 969221807Sstasint 970233760Sjhbprocstat_get_shm_info(struct procstat *procstat, struct filestat *fst, 971233760Sjhb struct shmstat *shm, char *errbuf) 972233760Sjhb{ 973233760Sjhb 974233760Sjhb assert(shm); 975233760Sjhb if (procstat->type == PROCSTAT_KVM) { 976233760Sjhb return (procstat_get_shm_info_kvm(procstat->kd, fst, shm, 977233760Sjhb errbuf)); 978249666Strociny } else if (procstat->type == PROCSTAT_SYSCTL || 979249666Strociny procstat->type == PROCSTAT_CORE) { 980233760Sjhb return (procstat_get_shm_info_sysctl(fst, shm, errbuf)); 981233760Sjhb } else { 982233760Sjhb warnx("unknown access method: %d", procstat->type); 983233760Sjhb snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 984233760Sjhb return (1); 985233760Sjhb } 986233760Sjhb} 987233760Sjhb 988233760Sjhbstatic int 989233760Sjhbprocstat_get_shm_info_kvm(kvm_t *kd, struct filestat *fst, 990233760Sjhb struct shmstat *shm, char *errbuf) 991233760Sjhb{ 992233760Sjhb struct shmfd shmfd; 993233760Sjhb void *shmfdp; 994236717Sjhb char *path; 995236717Sjhb int i; 996233760Sjhb 997233760Sjhb assert(kd); 998233760Sjhb assert(shm); 999233760Sjhb assert(fst); 1000233760Sjhb bzero(shm, sizeof(*shm)); 1001233760Sjhb shmfdp = fst->fs_typedep; 1002233760Sjhb if (shmfdp == NULL) 1003233760Sjhb goto fail; 1004233760Sjhb if (!kvm_read_all(kd, (unsigned long)shmfdp, &shmfd, 1005233760Sjhb sizeof(struct shmfd))) { 1006233760Sjhb warnx("can't read shmfd at %p", (void *)shmfdp); 1007233760Sjhb goto fail; 1008233760Sjhb } 1009233760Sjhb shm->mode = S_IFREG | shmfd.shm_mode; 1010233760Sjhb shm->size = shmfd.shm_size; 1011236717Sjhb if (fst->fs_path == NULL && shmfd.shm_path != NULL) { 1012236717Sjhb path = malloc(MAXPATHLEN); 1013236717Sjhb for (i = 0; i < MAXPATHLEN - 1; i++) { 1014236717Sjhb if (!kvm_read_all(kd, (unsigned long)shmfd.shm_path + i, 1015236717Sjhb path + i, 1)) 1016236717Sjhb break; 1017236717Sjhb if (path[i] == '\0') 1018236717Sjhb break; 1019236717Sjhb } 1020236717Sjhb path[i] = '\0'; 1021236717Sjhb if (i == 0) 1022236717Sjhb free(path); 1023236717Sjhb else 1024236717Sjhb fst->fs_path = path; 1025236717Sjhb } 1026233760Sjhb return (0); 1027233760Sjhb 1028233760Sjhbfail: 1029233760Sjhb snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 1030233760Sjhb return (1); 1031233760Sjhb} 1032233760Sjhb 1033233760Sjhbstatic int 1034233760Sjhbprocstat_get_shm_info_sysctl(struct filestat *fst, struct shmstat *shm, 1035233760Sjhb char *errbuf __unused) 1036233760Sjhb{ 1037233760Sjhb struct kinfo_file *kif; 1038233760Sjhb 1039233760Sjhb assert(shm); 1040233760Sjhb assert(fst); 1041233760Sjhb bzero(shm, sizeof(*shm)); 1042233760Sjhb kif = fst->fs_typedep; 1043233760Sjhb if (kif == NULL) 1044233760Sjhb return (0); 1045233760Sjhb shm->size = kif->kf_un.kf_file.kf_file_size; 1046233760Sjhb shm->mode = kif->kf_un.kf_file.kf_file_mode; 1047233760Sjhb return (0); 1048233760Sjhb} 1049233760Sjhb 1050233760Sjhbint 1051221807Sstasprocstat_get_vnode_info(struct procstat *procstat, struct filestat *fst, 1052221807Sstas struct vnstat *vn, char *errbuf) 1053221807Sstas{ 1054221807Sstas 1055221807Sstas assert(vn); 1056221807Sstas if (procstat->type == PROCSTAT_KVM) { 1057221807Sstas return (procstat_get_vnode_info_kvm(procstat->kd, fst, vn, 1058221807Sstas errbuf)); 1059249666Strociny } else if (procstat->type == PROCSTAT_SYSCTL || 1060249666Strociny procstat->type == PROCSTAT_CORE) { 1061221807Sstas return (procstat_get_vnode_info_sysctl(fst, vn, errbuf)); 1062221807Sstas } else { 1063223276Sjilles warnx("unknown access method: %d", procstat->type); 1064221807Sstas snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 1065221807Sstas return (1); 1066221807Sstas } 1067221807Sstas} 1068221807Sstas 1069221807Sstasstatic int 1070221807Sstasprocstat_get_vnode_info_kvm(kvm_t *kd, struct filestat *fst, 1071221807Sstas struct vnstat *vn, char *errbuf) 1072221807Sstas{ 1073221807Sstas /* Filesystem specific handlers. */ 1074221807Sstas #define FSTYPE(fst) {#fst, fst##_filestat} 1075221807Sstas struct { 1076221807Sstas const char *tag; 1077221807Sstas int (*handler)(kvm_t *kd, struct vnode *vp, 1078221807Sstas struct vnstat *vn); 1079221807Sstas } fstypes[] = { 1080221807Sstas FSTYPE(devfs), 1081221807Sstas FSTYPE(isofs), 1082221807Sstas FSTYPE(msdosfs), 1083221807Sstas FSTYPE(nfs), 1084221807Sstas FSTYPE(udf), 1085221807Sstas FSTYPE(ufs), 1086221824Sstas#ifdef LIBPROCSTAT_ZFS 1087221807Sstas FSTYPE(zfs), 1088221807Sstas#endif 1089221807Sstas }; 1090221807Sstas#define NTYPES (sizeof(fstypes) / sizeof(*fstypes)) 1091221807Sstas struct vnode vnode; 1092221807Sstas char tagstr[12]; 1093221807Sstas void *vp; 1094221807Sstas int error, found; 1095221807Sstas unsigned int i; 1096221807Sstas 1097221807Sstas assert(kd); 1098221807Sstas assert(vn); 1099221807Sstas assert(fst); 1100221807Sstas vp = fst->fs_typedep; 1101221807Sstas if (vp == NULL) 1102221807Sstas goto fail; 1103221807Sstas error = kvm_read_all(kd, (unsigned long)vp, &vnode, sizeof(vnode)); 1104221807Sstas if (error == 0) { 1105221807Sstas warnx("can't read vnode at %p", (void *)vp); 1106221807Sstas goto fail; 1107221807Sstas } 1108221807Sstas bzero(vn, sizeof(*vn)); 1109221807Sstas vn->vn_type = vntype2psfsttype(vnode.v_type); 1110221807Sstas if (vnode.v_type == VNON || vnode.v_type == VBAD) 1111221807Sstas return (0); 1112221807Sstas error = kvm_read_all(kd, (unsigned long)vnode.v_tag, tagstr, 1113221807Sstas sizeof(tagstr)); 1114221807Sstas if (error == 0) { 1115221807Sstas warnx("can't read v_tag at %p", (void *)vp); 1116221807Sstas goto fail; 1117221807Sstas } 1118221807Sstas tagstr[sizeof(tagstr) - 1] = '\0'; 1119221807Sstas 1120221807Sstas /* 1121221807Sstas * Find appropriate handler. 1122221807Sstas */ 1123221807Sstas for (i = 0, found = 0; i < NTYPES; i++) 1124221807Sstas if (!strcmp(fstypes[i].tag, tagstr)) { 1125221807Sstas if (fstypes[i].handler(kd, &vnode, vn) != 0) { 1126221807Sstas goto fail; 1127221807Sstas } 1128221807Sstas break; 1129221807Sstas } 1130221807Sstas if (i == NTYPES) { 1131221807Sstas snprintf(errbuf, _POSIX2_LINE_MAX, "?(%s)", tagstr); 1132221807Sstas return (1); 1133221807Sstas } 1134221807Sstas vn->vn_mntdir = getmnton(kd, vnode.v_mount); 1135221807Sstas if ((vnode.v_type == VBLK || vnode.v_type == VCHR) && 1136221807Sstas vnode.v_rdev != NULL){ 1137221807Sstas vn->vn_dev = dev2udev(kd, vnode.v_rdev); 1138221807Sstas (void)kdevtoname(kd, vnode.v_rdev, vn->vn_devname); 1139221807Sstas } else { 1140221807Sstas vn->vn_dev = -1; 1141221807Sstas } 1142221807Sstas return (0); 1143221807Sstas 1144221807Sstasfail: 1145221807Sstas snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 1146221807Sstas return (1); 1147221807Sstas} 1148221807Sstas 1149221807Sstas/* 1150221807Sstas * kinfo vnode type to filestat translation. 1151221807Sstas */ 1152221807Sstasstatic int 1153221807Sstaskinfo_vtype2fst(int kfvtype) 1154221807Sstas{ 1155221807Sstas static struct { 1156221807Sstas int kf_vtype; 1157221807Sstas int fst_vtype; 1158221807Sstas } kfvtypes2fst[] = { 1159221807Sstas { KF_VTYPE_VBAD, PS_FST_VTYPE_VBAD }, 1160221807Sstas { KF_VTYPE_VBLK, PS_FST_VTYPE_VBLK }, 1161221807Sstas { KF_VTYPE_VCHR, PS_FST_VTYPE_VCHR }, 1162221807Sstas { KF_VTYPE_VDIR, PS_FST_VTYPE_VDIR }, 1163221807Sstas { KF_VTYPE_VFIFO, PS_FST_VTYPE_VFIFO }, 1164221807Sstas { KF_VTYPE_VLNK, PS_FST_VTYPE_VLNK }, 1165221807Sstas { KF_VTYPE_VNON, PS_FST_VTYPE_VNON }, 1166221807Sstas { KF_VTYPE_VREG, PS_FST_VTYPE_VREG }, 1167221807Sstas { KF_VTYPE_VSOCK, PS_FST_VTYPE_VSOCK } 1168221807Sstas }; 1169221807Sstas#define NKFVTYPES (sizeof(kfvtypes2fst) / sizeof(*kfvtypes2fst)) 1170221807Sstas unsigned int i; 1171221807Sstas 1172221807Sstas for (i = 0; i < NKFVTYPES; i++) 1173221807Sstas if (kfvtypes2fst[i].kf_vtype == kfvtype) 1174221807Sstas break; 1175221807Sstas if (i == NKFVTYPES) 1176221807Sstas return (PS_FST_VTYPE_UNKNOWN); 1177221807Sstas return (kfvtypes2fst[i].fst_vtype); 1178221807Sstas} 1179221807Sstas 1180221807Sstasstatic int 1181221807Sstasprocstat_get_vnode_info_sysctl(struct filestat *fst, struct vnstat *vn, 1182221807Sstas char *errbuf) 1183221807Sstas{ 1184221807Sstas struct statfs stbuf; 1185221807Sstas struct kinfo_file *kif; 1186221807Sstas struct kinfo_vmentry *kve; 1187221807Sstas uint64_t fileid; 1188221807Sstas uint64_t size; 1189221807Sstas char *name, *path; 1190221807Sstas uint32_t fsid; 1191221807Sstas uint16_t mode; 1192221807Sstas uint32_t rdev; 1193221807Sstas int vntype; 1194221807Sstas int status; 1195221807Sstas 1196221807Sstas assert(fst); 1197221807Sstas assert(vn); 1198221807Sstas bzero(vn, sizeof(*vn)); 1199221807Sstas if (fst->fs_typedep == NULL) 1200221807Sstas return (1); 1201221807Sstas if (fst->fs_uflags & PS_FST_UFLAG_MMAP) { 1202221807Sstas kve = fst->fs_typedep; 1203221807Sstas fileid = kve->kve_vn_fileid; 1204221807Sstas fsid = kve->kve_vn_fsid; 1205221807Sstas mode = kve->kve_vn_mode; 1206221807Sstas path = kve->kve_path; 1207221807Sstas rdev = kve->kve_vn_rdev; 1208221807Sstas size = kve->kve_vn_size; 1209221807Sstas vntype = kinfo_vtype2fst(kve->kve_vn_type); 1210221807Sstas status = kve->kve_status; 1211221807Sstas } else { 1212221807Sstas kif = fst->fs_typedep; 1213221807Sstas fileid = kif->kf_un.kf_file.kf_file_fileid; 1214221807Sstas fsid = kif->kf_un.kf_file.kf_file_fsid; 1215221807Sstas mode = kif->kf_un.kf_file.kf_file_mode; 1216221807Sstas path = kif->kf_path; 1217221807Sstas rdev = kif->kf_un.kf_file.kf_file_rdev; 1218221807Sstas size = kif->kf_un.kf_file.kf_file_size; 1219221807Sstas vntype = kinfo_vtype2fst(kif->kf_vnode_type); 1220221807Sstas status = kif->kf_status; 1221221807Sstas } 1222221807Sstas vn->vn_type = vntype; 1223221807Sstas if (vntype == PS_FST_VTYPE_VNON || vntype == PS_FST_VTYPE_VBAD) 1224221807Sstas return (0); 1225221807Sstas if ((status & KF_ATTR_VALID) == 0) { 1226221807Sstas snprintf(errbuf, _POSIX2_LINE_MAX, "? (no info available)"); 1227221807Sstas return (1); 1228221807Sstas } 1229221807Sstas if (path && *path) { 1230221807Sstas statfs(path, &stbuf); 1231221807Sstas vn->vn_mntdir = strdup(stbuf.f_mntonname); 1232221807Sstas } else 1233221807Sstas vn->vn_mntdir = strdup("-"); 1234221807Sstas vn->vn_dev = rdev; 1235221807Sstas if (vntype == PS_FST_VTYPE_VBLK) { 1236221807Sstas name = devname(rdev, S_IFBLK); 1237221807Sstas if (name != NULL) 1238221807Sstas strlcpy(vn->vn_devname, name, 1239221807Sstas sizeof(vn->vn_devname)); 1240221807Sstas } else if (vntype == PS_FST_VTYPE_VCHR) { 1241221807Sstas name = devname(vn->vn_dev, S_IFCHR); 1242221807Sstas if (name != NULL) 1243221807Sstas strlcpy(vn->vn_devname, name, 1244221807Sstas sizeof(vn->vn_devname)); 1245221807Sstas } 1246221807Sstas vn->vn_fsid = fsid; 1247221807Sstas vn->vn_fileid = fileid; 1248221807Sstas vn->vn_size = size; 1249221807Sstas vn->vn_mode = mode; 1250221807Sstas return (0); 1251221807Sstas} 1252221807Sstas 1253221807Sstasint 1254221807Sstasprocstat_get_socket_info(struct procstat *procstat, struct filestat *fst, 1255221807Sstas struct sockstat *sock, char *errbuf) 1256221807Sstas{ 1257221807Sstas 1258221807Sstas assert(sock); 1259221807Sstas if (procstat->type == PROCSTAT_KVM) { 1260221807Sstas return (procstat_get_socket_info_kvm(procstat->kd, fst, sock, 1261221807Sstas errbuf)); 1262249666Strociny } else if (procstat->type == PROCSTAT_SYSCTL || 1263249666Strociny procstat->type == PROCSTAT_CORE) { 1264221807Sstas return (procstat_get_socket_info_sysctl(fst, sock, errbuf)); 1265221807Sstas } else { 1266223276Sjilles warnx("unknown access method: %d", procstat->type); 1267221807Sstas snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 1268221807Sstas return (1); 1269221807Sstas } 1270221807Sstas} 1271221807Sstas 1272221807Sstasstatic int 1273221807Sstasprocstat_get_socket_info_kvm(kvm_t *kd, struct filestat *fst, 1274221807Sstas struct sockstat *sock, char *errbuf) 1275221807Sstas{ 1276221807Sstas struct domain dom; 1277221807Sstas struct inpcb inpcb; 1278221807Sstas struct protosw proto; 1279221807Sstas struct socket s; 1280221807Sstas struct unpcb unpcb; 1281221807Sstas ssize_t len; 1282221807Sstas void *so; 1283221807Sstas 1284221807Sstas assert(kd); 1285221807Sstas assert(sock); 1286221807Sstas assert(fst); 1287221807Sstas bzero(sock, sizeof(*sock)); 1288221807Sstas so = fst->fs_typedep; 1289221807Sstas if (so == NULL) 1290221807Sstas goto fail; 1291221807Sstas sock->so_addr = (uintptr_t)so; 1292221807Sstas /* fill in socket */ 1293221807Sstas if (!kvm_read_all(kd, (unsigned long)so, &s, 1294221807Sstas sizeof(struct socket))) { 1295221807Sstas warnx("can't read sock at %p", (void *)so); 1296221807Sstas goto fail; 1297221807Sstas } 1298221807Sstas /* fill in protosw entry */ 1299221807Sstas if (!kvm_read_all(kd, (unsigned long)s.so_proto, &proto, 1300221807Sstas sizeof(struct protosw))) { 1301221807Sstas warnx("can't read protosw at %p", (void *)s.so_proto); 1302221807Sstas goto fail; 1303221807Sstas } 1304221807Sstas /* fill in domain */ 1305221807Sstas if (!kvm_read_all(kd, (unsigned long)proto.pr_domain, &dom, 1306221807Sstas sizeof(struct domain))) { 1307221807Sstas warnx("can't read domain at %p", 1308221807Sstas (void *)proto.pr_domain); 1309221807Sstas goto fail; 1310221807Sstas } 1311221807Sstas if ((len = kvm_read(kd, (unsigned long)dom.dom_name, sock->dname, 1312221807Sstas sizeof(sock->dname) - 1)) < 0) { 1313221807Sstas warnx("can't read domain name at %p", (void *)dom.dom_name); 1314221807Sstas sock->dname[0] = '\0'; 1315221807Sstas } 1316221807Sstas else 1317221807Sstas sock->dname[len] = '\0'; 1318221807Sstas 1319221807Sstas /* 1320221807Sstas * Fill in known data. 1321221807Sstas */ 1322221807Sstas sock->type = s.so_type; 1323221807Sstas sock->proto = proto.pr_protocol; 1324221807Sstas sock->dom_family = dom.dom_family; 1325221807Sstas sock->so_pcb = (uintptr_t)s.so_pcb; 1326221807Sstas 1327221807Sstas /* 1328221807Sstas * Protocol specific data. 1329221807Sstas */ 1330221807Sstas switch(dom.dom_family) { 1331221807Sstas case AF_INET: 1332221807Sstas case AF_INET6: 1333221807Sstas if (proto.pr_protocol == IPPROTO_TCP) { 1334221807Sstas if (s.so_pcb) { 1335221807Sstas if (kvm_read(kd, (u_long)s.so_pcb, 1336221807Sstas (char *)&inpcb, sizeof(struct inpcb)) 1337221807Sstas != sizeof(struct inpcb)) { 1338221807Sstas warnx("can't read inpcb at %p", 1339221807Sstas (void *)s.so_pcb); 1340221807Sstas } else 1341221807Sstas sock->inp_ppcb = 1342221807Sstas (uintptr_t)inpcb.inp_ppcb; 1343221807Sstas } 1344221807Sstas } 1345221807Sstas break; 1346221807Sstas case AF_UNIX: 1347221807Sstas if (s.so_pcb) { 1348221807Sstas if (kvm_read(kd, (u_long)s.so_pcb, (char *)&unpcb, 1349221807Sstas sizeof(struct unpcb)) != sizeof(struct unpcb)){ 1350221807Sstas warnx("can't read unpcb at %p", 1351221807Sstas (void *)s.so_pcb); 1352221807Sstas } else if (unpcb.unp_conn) { 1353221807Sstas sock->so_rcv_sb_state = s.so_rcv.sb_state; 1354221807Sstas sock->so_snd_sb_state = s.so_snd.sb_state; 1355221807Sstas sock->unp_conn = (uintptr_t)unpcb.unp_conn; 1356221807Sstas } 1357221807Sstas } 1358221807Sstas break; 1359221807Sstas default: 1360221807Sstas break; 1361221807Sstas } 1362221807Sstas return (0); 1363221807Sstas 1364221807Sstasfail: 1365221807Sstas snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 1366221807Sstas return (1); 1367221807Sstas} 1368221807Sstas 1369221807Sstasstatic int 1370221807Sstasprocstat_get_socket_info_sysctl(struct filestat *fst, struct sockstat *sock, 1371221807Sstas char *errbuf __unused) 1372221807Sstas{ 1373221807Sstas struct kinfo_file *kif; 1374221807Sstas 1375221807Sstas assert(sock); 1376221807Sstas assert(fst); 1377221807Sstas bzero(sock, sizeof(*sock)); 1378221807Sstas kif = fst->fs_typedep; 1379221807Sstas if (kif == NULL) 1380221807Sstas return (0); 1381221807Sstas 1382221807Sstas /* 1383221807Sstas * Fill in known data. 1384221807Sstas */ 1385221807Sstas sock->type = kif->kf_sock_type; 1386221807Sstas sock->proto = kif->kf_sock_protocol; 1387221807Sstas sock->dom_family = kif->kf_sock_domain; 1388221807Sstas sock->so_pcb = kif->kf_un.kf_sock.kf_sock_pcb; 1389221807Sstas strlcpy(sock->dname, kif->kf_path, sizeof(sock->dname)); 1390221807Sstas bcopy(&kif->kf_sa_local, &sock->sa_local, kif->kf_sa_local.ss_len); 1391221807Sstas bcopy(&kif->kf_sa_peer, &sock->sa_peer, kif->kf_sa_peer.ss_len); 1392221807Sstas 1393221807Sstas /* 1394221807Sstas * Protocol specific data. 1395221807Sstas */ 1396221807Sstas switch(sock->dom_family) { 1397221807Sstas case AF_INET: 1398221807Sstas case AF_INET6: 1399221807Sstas if (sock->proto == IPPROTO_TCP) 1400221807Sstas sock->inp_ppcb = kif->kf_un.kf_sock.kf_sock_inpcb; 1401221807Sstas break; 1402221807Sstas case AF_UNIX: 1403221807Sstas if (kif->kf_un.kf_sock.kf_sock_unpconn != 0) { 1404221807Sstas sock->so_rcv_sb_state = 1405221807Sstas kif->kf_un.kf_sock.kf_sock_rcv_sb_state; 1406221807Sstas sock->so_snd_sb_state = 1407221807Sstas kif->kf_un.kf_sock.kf_sock_snd_sb_state; 1408221807Sstas sock->unp_conn = 1409221807Sstas kif->kf_un.kf_sock.kf_sock_unpconn; 1410221807Sstas } 1411221807Sstas break; 1412221807Sstas default: 1413221807Sstas break; 1414221807Sstas } 1415221807Sstas return (0); 1416221807Sstas} 1417221807Sstas 1418221807Sstas/* 1419221807Sstas * Descriptor flags to filestat translation. 1420221807Sstas */ 1421221807Sstasstatic int 1422221807Sstasto_filestat_flags(int flags) 1423221807Sstas{ 1424221807Sstas static struct { 1425221807Sstas int flag; 1426221807Sstas int fst_flag; 1427221807Sstas } fstflags[] = { 1428221807Sstas { FREAD, PS_FST_FFLAG_READ }, 1429221807Sstas { FWRITE, PS_FST_FFLAG_WRITE }, 1430221807Sstas { O_APPEND, PS_FST_FFLAG_APPEND }, 1431221807Sstas { O_ASYNC, PS_FST_FFLAG_ASYNC }, 1432221807Sstas { O_CREAT, PS_FST_FFLAG_CREAT }, 1433221807Sstas { O_DIRECT, PS_FST_FFLAG_DIRECT }, 1434221807Sstas { O_EXCL, PS_FST_FFLAG_EXCL }, 1435221807Sstas { O_EXEC, PS_FST_FFLAG_EXEC }, 1436221807Sstas { O_EXLOCK, PS_FST_FFLAG_EXLOCK }, 1437221807Sstas { O_NOFOLLOW, PS_FST_FFLAG_NOFOLLOW }, 1438221807Sstas { O_NONBLOCK, PS_FST_FFLAG_NONBLOCK }, 1439221807Sstas { O_SHLOCK, PS_FST_FFLAG_SHLOCK }, 1440221807Sstas { O_SYNC, PS_FST_FFLAG_SYNC }, 1441221807Sstas { O_TRUNC, PS_FST_FFLAG_TRUNC } 1442221807Sstas }; 1443221807Sstas#define NFSTFLAGS (sizeof(fstflags) / sizeof(*fstflags)) 1444221807Sstas int fst_flags; 1445221807Sstas unsigned int i; 1446221807Sstas 1447221807Sstas fst_flags = 0; 1448221807Sstas for (i = 0; i < NFSTFLAGS; i++) 1449221807Sstas if (flags & fstflags[i].flag) 1450221807Sstas fst_flags |= fstflags[i].fst_flag; 1451221807Sstas return (fst_flags); 1452221807Sstas} 1453221807Sstas 1454221807Sstas/* 1455221807Sstas * Vnode type to filestate translation. 1456221807Sstas */ 1457221807Sstasstatic int 1458221807Sstasvntype2psfsttype(int type) 1459221807Sstas{ 1460221807Sstas static struct { 1461221807Sstas int vtype; 1462221807Sstas int fst_vtype; 1463221807Sstas } vt2fst[] = { 1464221807Sstas { VBAD, PS_FST_VTYPE_VBAD }, 1465221807Sstas { VBLK, PS_FST_VTYPE_VBLK }, 1466221807Sstas { VCHR, PS_FST_VTYPE_VCHR }, 1467221807Sstas { VDIR, PS_FST_VTYPE_VDIR }, 1468221807Sstas { VFIFO, PS_FST_VTYPE_VFIFO }, 1469221807Sstas { VLNK, PS_FST_VTYPE_VLNK }, 1470221807Sstas { VNON, PS_FST_VTYPE_VNON }, 1471221807Sstas { VREG, PS_FST_VTYPE_VREG }, 1472221807Sstas { VSOCK, PS_FST_VTYPE_VSOCK } 1473221807Sstas }; 1474221807Sstas#define NVFTYPES (sizeof(vt2fst) / sizeof(*vt2fst)) 1475221807Sstas unsigned int i, fst_type; 1476221807Sstas 1477221807Sstas fst_type = PS_FST_VTYPE_UNKNOWN; 1478221807Sstas for (i = 0; i < NVFTYPES; i++) { 1479221807Sstas if (type == vt2fst[i].vtype) { 1480221807Sstas fst_type = vt2fst[i].fst_vtype; 1481221807Sstas break; 1482221807Sstas } 1483221807Sstas } 1484221807Sstas return (fst_type); 1485221807Sstas} 1486221807Sstas 1487221807Sstasstatic char * 1488221807Sstasgetmnton(kvm_t *kd, struct mount *m) 1489221807Sstas{ 1490223262Sbenl struct mount mnt; 1491221807Sstas static struct mtab { 1492221807Sstas struct mtab *next; 1493221807Sstas struct mount *m; 1494221807Sstas char mntonname[MNAMELEN + 1]; 1495221807Sstas } *mhead = NULL; 1496221807Sstas struct mtab *mt; 1497221807Sstas 1498221807Sstas for (mt = mhead; mt != NULL; mt = mt->next) 1499221807Sstas if (m == mt->m) 1500221807Sstas return (mt->mntonname); 1501221807Sstas if (!kvm_read_all(kd, (unsigned long)m, &mnt, sizeof(struct mount))) { 1502221807Sstas warnx("can't read mount table at %p", (void *)m); 1503221807Sstas return (NULL); 1504221807Sstas } 1505221807Sstas if ((mt = malloc(sizeof (struct mtab))) == NULL) 1506221807Sstas err(1, NULL); 1507221807Sstas mt->m = m; 1508221807Sstas bcopy(&mnt.mnt_stat.f_mntonname[0], &mt->mntonname[0], MNAMELEN); 1509223262Sbenl mt->mntonname[MNAMELEN] = '\0'; 1510221807Sstas mt->next = mhead; 1511221807Sstas mhead = mt; 1512221807Sstas return (mt->mntonname); 1513221807Sstas} 1514249666Strociny 1515249667Strocinystatic struct kinfo_vmentry * 1516249667Strocinykinfo_getvmmap_core(struct procstat_core *core, int *cntp) 1517249667Strociny{ 1518249667Strociny int cnt; 1519249667Strociny size_t len; 1520249667Strociny char *buf, *bp, *eb; 1521249667Strociny struct kinfo_vmentry *kiv, *kp, *kv; 1522249667Strociny 1523249667Strociny buf = procstat_core_get(core, PSC_TYPE_VMMAP, NULL, &len); 1524249667Strociny if (buf == NULL) 1525249667Strociny return (NULL); 1526249667Strociny 1527249667Strociny /* 1528249667Strociny * XXXMG: The code below is just copy&past from libutil. 1529249667Strociny * The code duplication can be avoided if libutil 1530249667Strociny * is extended to provide something like: 1531249667Strociny * struct kinfo_vmentry *kinfo_getvmmap_from_buf(const char *buf, 1532249667Strociny * size_t len, int *cntp); 1533249667Strociny */ 1534249667Strociny 1535249667Strociny /* Pass 1: count items */ 1536249667Strociny cnt = 0; 1537249667Strociny bp = buf; 1538249667Strociny eb = buf + len; 1539249667Strociny while (bp < eb) { 1540249667Strociny kv = (struct kinfo_vmentry *)(uintptr_t)bp; 1541249667Strociny bp += kv->kve_structsize; 1542249667Strociny cnt++; 1543249667Strociny } 1544249667Strociny 1545249667Strociny kiv = calloc(cnt, sizeof(*kiv)); 1546249667Strociny if (kiv == NULL) { 1547249667Strociny free(buf); 1548249667Strociny return (NULL); 1549249667Strociny } 1550249667Strociny bp = buf; 1551249667Strociny eb = buf + len; 1552249667Strociny kp = kiv; 1553249667Strociny /* Pass 2: unpack */ 1554249667Strociny while (bp < eb) { 1555249667Strociny kv = (struct kinfo_vmentry *)(uintptr_t)bp; 1556249667Strociny /* Copy/expand into pre-zeroed buffer */ 1557249667Strociny memcpy(kp, kv, kv->kve_structsize); 1558249667Strociny /* Advance to next packed record */ 1559249667Strociny bp += kv->kve_structsize; 1560249667Strociny /* Set field size to fixed length, advance */ 1561249667Strociny kp->kve_structsize = sizeof(*kp); 1562249667Strociny kp++; 1563249667Strociny } 1564249667Strociny free(buf); 1565249667Strociny *cntp = cnt; 1566249667Strociny return (kiv); /* Caller must free() return value */ 1567249667Strociny} 1568249667Strociny 1569249667Strocinystruct kinfo_vmentry * 1570249667Strocinyprocstat_getvmmap(struct procstat *procstat, struct kinfo_proc *kp, 1571249667Strociny unsigned int *cntp) 1572249667Strociny{ 1573249667Strociny switch(procstat->type) { 1574249667Strociny case PROCSTAT_KVM: 1575249667Strociny warnx("kvm method is not supported"); 1576249667Strociny return (NULL); 1577249667Strociny case PROCSTAT_SYSCTL: 1578249667Strociny return (kinfo_getvmmap(kp->ki_pid, cntp)); 1579249667Strociny case PROCSTAT_CORE: 1580249667Strociny return (kinfo_getvmmap_core(procstat->core, cntp)); 1581249667Strociny default: 1582249667Strociny warnx("unknown access method: %d", procstat->type); 1583249667Strociny return (NULL); 1584249667Strociny } 1585249667Strociny} 1586249667Strociny 1587249667Strocinyvoid 1588249667Strocinyprocstat_freevmmap(struct procstat *procstat __unused, 1589249667Strociny struct kinfo_vmentry *vmmap) 1590249667Strociny{ 1591249667Strociny 1592249667Strociny free(vmmap); 1593249667Strociny} 1594249670Strociny 1595249670Strocinystatic gid_t * 1596249670Strocinyprocstat_getgroups_sysctl(pid_t pid, unsigned int *cntp) 1597249670Strociny{ 1598249670Strociny int mib[4]; 1599249670Strociny size_t len; 1600249670Strociny gid_t *groups; 1601249670Strociny 1602249670Strociny mib[0] = CTL_KERN; 1603249670Strociny mib[1] = KERN_PROC; 1604249670Strociny mib[2] = KERN_PROC_GROUPS; 1605249670Strociny mib[3] = pid; 1606249670Strociny len = (sysconf(_SC_NGROUPS_MAX) + 1) * sizeof(gid_t); 1607249670Strociny groups = malloc(len); 1608249670Strociny if (groups == NULL) { 1609249670Strociny warn("malloc(%zu)", len); 1610249670Strociny return (NULL); 1611249670Strociny } 1612249670Strociny if (sysctl(mib, 4, groups, &len, NULL, 0) == -1) { 1613249670Strociny warn("sysctl: kern.proc.groups: %d", pid); 1614249670Strociny free(groups); 1615249670Strociny return (NULL); 1616249670Strociny } 1617249670Strociny *cntp = len / sizeof(gid_t); 1618249670Strociny return (groups); 1619249670Strociny} 1620249670Strociny 1621249670Strocinystatic gid_t * 1622249670Strocinyprocstat_getgroups_core(struct procstat_core *core, unsigned int *cntp) 1623249670Strociny{ 1624249670Strociny size_t len; 1625249670Strociny gid_t *groups; 1626249670Strociny 1627249670Strociny groups = procstat_core_get(core, PSC_TYPE_GROUPS, NULL, &len); 1628249670Strociny if (groups == NULL) 1629249670Strociny return (NULL); 1630249670Strociny *cntp = len / sizeof(gid_t); 1631249670Strociny return (groups); 1632249670Strociny} 1633249670Strociny 1634249670Strocinygid_t * 1635249670Strocinyprocstat_getgroups(struct procstat *procstat, struct kinfo_proc *kp, 1636249670Strociny unsigned int *cntp) 1637249670Strociny{ 1638249670Strociny switch(procstat->type) { 1639249670Strociny case PROCSTAT_KVM: 1640249670Strociny warnx("kvm method is not supported"); 1641249670Strociny return (NULL); 1642249670Strociny case PROCSTAT_SYSCTL: 1643249670Strociny return (procstat_getgroups_sysctl(kp->ki_pid, cntp)); 1644249670Strociny case PROCSTAT_CORE: 1645249670Strociny return (procstat_getgroups_core(procstat->core, cntp)); 1646249670Strociny default: 1647249670Strociny warnx("unknown access method: %d", procstat->type); 1648249670Strociny return (NULL); 1649249670Strociny } 1650249670Strociny} 1651249670Strociny 1652249670Strocinyvoid 1653249670Strocinyprocstat_freegroups(struct procstat *procstat __unused, gid_t *groups) 1654249670Strociny{ 1655249670Strociny 1656249670Strociny free(groups); 1657249670Strociny} 1658