libprocstat.c revision 249666
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 249666 2013-04-20 07:47:26Z 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); 108221807Sstasstatic struct filestat_list *procstat_getfiles_kvm( 109221807Sstas struct procstat *procstat, struct kinfo_proc *kp, int mmapped); 110221807Sstasstatic struct filestat_list *procstat_getfiles_sysctl( 111221807Sstas struct procstat *procstat, struct kinfo_proc *kp, int mmapped); 112221807Sstasstatic int procstat_get_pipe_info_sysctl(struct filestat *fst, 113221807Sstas struct pipestat *pipe, char *errbuf); 114221807Sstasstatic int procstat_get_pipe_info_kvm(kvm_t *kd, struct filestat *fst, 115221807Sstas struct pipestat *pipe, char *errbuf); 116221807Sstasstatic int procstat_get_pts_info_sysctl(struct filestat *fst, 117221807Sstas struct ptsstat *pts, char *errbuf); 118221807Sstasstatic int procstat_get_pts_info_kvm(kvm_t *kd, struct filestat *fst, 119221807Sstas struct ptsstat *pts, char *errbuf); 120233760Sjhbstatic int procstat_get_shm_info_sysctl(struct filestat *fst, 121233760Sjhb struct shmstat *shm, char *errbuf); 122233760Sjhbstatic int procstat_get_shm_info_kvm(kvm_t *kd, struct filestat *fst, 123233760Sjhb struct shmstat *shm, char *errbuf); 124221807Sstasstatic int procstat_get_socket_info_sysctl(struct filestat *fst, 125221807Sstas struct sockstat *sock, char *errbuf); 126221807Sstasstatic int procstat_get_socket_info_kvm(kvm_t *kd, struct filestat *fst, 127221807Sstas struct sockstat *sock, char *errbuf); 128221807Sstasstatic int to_filestat_flags(int flags); 129221807Sstasstatic int procstat_get_vnode_info_kvm(kvm_t *kd, struct filestat *fst, 130221807Sstas struct vnstat *vn, char *errbuf); 131221807Sstasstatic int procstat_get_vnode_info_sysctl(struct filestat *fst, 132221807Sstas struct vnstat *vn, char *errbuf); 133221807Sstasstatic int vntype2psfsttype(int type); 134221807Sstas 135221807Sstasvoid 136221807Sstasprocstat_close(struct procstat *procstat) 137221807Sstas{ 138221807Sstas 139221807Sstas assert(procstat); 140221807Sstas if (procstat->type == PROCSTAT_KVM) 141221807Sstas kvm_close(procstat->kd); 142249666Strociny else if (procstat->type == PROCSTAT_CORE) 143249666Strociny procstat_core_close(procstat->core); 144222053Spluknet free(procstat); 145221807Sstas} 146221807Sstas 147221807Sstasstruct procstat * 148221807Sstasprocstat_open_sysctl(void) 149221807Sstas{ 150221807Sstas struct procstat *procstat; 151221807Sstas 152221807Sstas procstat = calloc(1, sizeof(*procstat)); 153221807Sstas if (procstat == NULL) { 154221807Sstas warn("malloc()"); 155221807Sstas return (NULL); 156221807Sstas } 157221807Sstas procstat->type = PROCSTAT_SYSCTL; 158221807Sstas return (procstat); 159221807Sstas} 160221807Sstas 161221807Sstasstruct procstat * 162221807Sstasprocstat_open_kvm(const char *nlistf, const char *memf) 163221807Sstas{ 164221807Sstas struct procstat *procstat; 165221807Sstas kvm_t *kd; 166221807Sstas char buf[_POSIX2_LINE_MAX]; 167221807Sstas 168221807Sstas procstat = calloc(1, sizeof(*procstat)); 169221807Sstas if (procstat == NULL) { 170221807Sstas warn("malloc()"); 171221807Sstas return (NULL); 172221807Sstas } 173221807Sstas kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf); 174221807Sstas if (kd == NULL) { 175221807Sstas warnx("kvm_openfiles(): %s", buf); 176221807Sstas free(procstat); 177221807Sstas return (NULL); 178221807Sstas } 179221807Sstas procstat->type = PROCSTAT_KVM; 180221807Sstas procstat->kd = kd; 181221807Sstas return (procstat); 182221807Sstas} 183221807Sstas 184249666Strocinystruct procstat * 185249666Strocinyprocstat_open_core(const char *filename) 186249666Strociny{ 187249666Strociny struct procstat *procstat; 188249666Strociny struct procstat_core *core; 189249666Strociny 190249666Strociny procstat = calloc(1, sizeof(*procstat)); 191249666Strociny if (procstat == NULL) { 192249666Strociny warn("malloc()"); 193249666Strociny return (NULL); 194249666Strociny } 195249666Strociny core = procstat_core_open(filename); 196249666Strociny if (core == NULL) { 197249666Strociny free(procstat); 198249666Strociny return (NULL); 199249666Strociny } 200249666Strociny procstat->type = PROCSTAT_CORE; 201249666Strociny procstat->core = core; 202249666Strociny return (procstat); 203249666Strociny} 204249666Strociny 205221807Sstasstruct kinfo_proc * 206221807Sstasprocstat_getprocs(struct procstat *procstat, int what, int arg, 207221807Sstas unsigned int *count) 208221807Sstas{ 209221807Sstas struct kinfo_proc *p0, *p; 210221807Sstas size_t len; 211221807Sstas int name[4]; 212241304Savg int cnt; 213221807Sstas int error; 214221807Sstas 215221807Sstas assert(procstat); 216221807Sstas assert(count); 217221807Sstas p = NULL; 218221807Sstas if (procstat->type == PROCSTAT_KVM) { 219241304Savg *count = 0; 220241304Savg p0 = kvm_getprocs(procstat->kd, what, arg, &cnt); 221241304Savg if (p0 == NULL || cnt <= 0) 222221807Sstas return (NULL); 223241304Savg *count = cnt; 224221807Sstas len = *count * sizeof(*p); 225221807Sstas p = malloc(len); 226221807Sstas if (p == NULL) { 227223269Sjilles warnx("malloc(%zu)", len); 228221807Sstas goto fail; 229221807Sstas } 230221807Sstas bcopy(p0, p, len); 231221807Sstas return (p); 232221807Sstas } else if (procstat->type == PROCSTAT_SYSCTL) { 233221807Sstas len = 0; 234221807Sstas name[0] = CTL_KERN; 235221807Sstas name[1] = KERN_PROC; 236221807Sstas name[2] = what; 237221807Sstas name[3] = arg; 238221807Sstas error = sysctl(name, 4, NULL, &len, NULL, 0); 239221807Sstas if (error < 0 && errno != EPERM) { 240221807Sstas warn("sysctl(kern.proc)"); 241221807Sstas goto fail; 242221807Sstas } 243221807Sstas if (len == 0) { 244221807Sstas warnx("no processes?"); 245221807Sstas goto fail; 246221807Sstas } 247221807Sstas p = malloc(len); 248221807Sstas if (p == NULL) { 249223269Sjilles warnx("malloc(%zu)", len); 250221807Sstas goto fail; 251221807Sstas } 252221807Sstas error = sysctl(name, 4, p, &len, NULL, 0); 253221807Sstas if (error < 0 && errno != EPERM) { 254221807Sstas warn("sysctl(kern.proc)"); 255221807Sstas goto fail; 256221807Sstas } 257221807Sstas /* Perform simple consistency checks. */ 258221807Sstas if ((len % sizeof(*p)) != 0 || p->ki_structsize != sizeof(*p)) { 259249666Strociny warnx("kinfo_proc structure size mismatch (len = %zu)", len); 260249666Strociny goto fail; 261249666Strociny } 262249666Strociny *count = len / sizeof(*p); 263249666Strociny return (p); 264249666Strociny } else if (procstat->type == PROCSTAT_CORE) { 265249666Strociny p = procstat_core_get(procstat->core, PSC_TYPE_PROC, NULL, 266249666Strociny &len); 267249666Strociny if ((len % sizeof(*p)) != 0 || p->ki_structsize != sizeof(*p)) { 268221807Sstas warnx("kinfo_proc structure size mismatch"); 269221807Sstas goto fail; 270221807Sstas } 271221807Sstas *count = len / sizeof(*p); 272221807Sstas return (p); 273221807Sstas } else { 274223276Sjilles warnx("unknown access method: %d", procstat->type); 275221807Sstas return (NULL); 276221807Sstas } 277221807Sstasfail: 278221807Sstas if (p) 279221807Sstas free(p); 280221807Sstas return (NULL); 281221807Sstas} 282221807Sstas 283221807Sstasvoid 284221807Sstasprocstat_freeprocs(struct procstat *procstat __unused, struct kinfo_proc *p) 285221807Sstas{ 286221807Sstas 287221807Sstas if (p != NULL) 288221807Sstas free(p); 289221807Sstas p = NULL; 290221807Sstas} 291221807Sstas 292221807Sstasstruct filestat_list * 293221807Sstasprocstat_getfiles(struct procstat *procstat, struct kinfo_proc *kp, int mmapped) 294221807Sstas{ 295249666Strociny 296249666Strociny switch(procstat->type) { 297249666Strociny case PROCSTAT_KVM: 298249666Strociny return (procstat_getfiles_kvm(procstat, kp, mmapped)); 299249666Strociny case PROCSTAT_SYSCTL: 300249666Strociny case PROCSTAT_CORE: 301221807Sstas return (procstat_getfiles_sysctl(procstat, kp, mmapped)); 302249666Strociny default: 303249666Strociny warnx("unknown access method: %d", procstat->type); 304221807Sstas return (NULL); 305249666Strociny } 306221807Sstas} 307221807Sstas 308221807Sstasvoid 309221807Sstasprocstat_freefiles(struct procstat *procstat, struct filestat_list *head) 310221807Sstas{ 311221807Sstas struct filestat *fst, *tmp; 312221807Sstas 313221807Sstas STAILQ_FOREACH_SAFE(fst, head, next, tmp) { 314221807Sstas if (fst->fs_path != NULL) 315221807Sstas free(fst->fs_path); 316221807Sstas free(fst); 317221807Sstas } 318221807Sstas free(head); 319221807Sstas if (procstat->vmentries != NULL) { 320223270Sjilles free(procstat->vmentries); 321221807Sstas procstat->vmentries = NULL; 322221807Sstas } 323221807Sstas if (procstat->files != NULL) { 324223270Sjilles free(procstat->files); 325221807Sstas procstat->files = NULL; 326221807Sstas } 327221807Sstas} 328221807Sstas 329221807Sstasstatic struct filestat * 330221807Sstasfilestat_new_entry(void *typedep, int type, int fd, int fflags, int uflags, 331224859Srwatson int refcount, off_t offset, char *path, cap_rights_t cap_rights) 332221807Sstas{ 333221807Sstas struct filestat *entry; 334221807Sstas 335221807Sstas entry = calloc(1, sizeof(*entry)); 336221807Sstas if (entry == NULL) { 337221807Sstas warn("malloc()"); 338221807Sstas return (NULL); 339221807Sstas } 340221807Sstas entry->fs_typedep = typedep; 341221807Sstas entry->fs_fflags = fflags; 342221807Sstas entry->fs_uflags = uflags; 343221807Sstas entry->fs_fd = fd; 344221807Sstas entry->fs_type = type; 345221807Sstas entry->fs_ref_count = refcount; 346221807Sstas entry->fs_offset = offset; 347221807Sstas entry->fs_path = path; 348224859Srwatson entry->fs_cap_rights = cap_rights; 349221807Sstas return (entry); 350221807Sstas} 351221807Sstas 352221807Sstasstatic struct vnode * 353221807Sstasgetctty(kvm_t *kd, struct kinfo_proc *kp) 354221807Sstas{ 355221807Sstas struct pgrp pgrp; 356221807Sstas struct proc proc; 357221807Sstas struct session sess; 358221807Sstas int error; 359221807Sstas 360221807Sstas assert(kp); 361221807Sstas error = kvm_read_all(kd, (unsigned long)kp->ki_paddr, &proc, 362221807Sstas sizeof(proc)); 363221807Sstas if (error == 0) { 364221807Sstas warnx("can't read proc struct at %p for pid %d", 365221807Sstas kp->ki_paddr, kp->ki_pid); 366221807Sstas return (NULL); 367221807Sstas } 368221807Sstas if (proc.p_pgrp == NULL) 369221807Sstas return (NULL); 370221807Sstas error = kvm_read_all(kd, (unsigned long)proc.p_pgrp, &pgrp, 371221807Sstas sizeof(pgrp)); 372221807Sstas if (error == 0) { 373221807Sstas warnx("can't read pgrp struct at %p for pid %d", 374221807Sstas proc.p_pgrp, kp->ki_pid); 375221807Sstas return (NULL); 376221807Sstas } 377221807Sstas error = kvm_read_all(kd, (unsigned long)pgrp.pg_session, &sess, 378221807Sstas sizeof(sess)); 379221807Sstas if (error == 0) { 380221807Sstas warnx("can't read session struct at %p for pid %d", 381221807Sstas pgrp.pg_session, kp->ki_pid); 382221807Sstas return (NULL); 383221807Sstas } 384221807Sstas return (sess.s_ttyvp); 385221807Sstas} 386221807Sstas 387221807Sstasstatic struct filestat_list * 388221807Sstasprocstat_getfiles_kvm(struct procstat *procstat, struct kinfo_proc *kp, int mmapped) 389221807Sstas{ 390221807Sstas struct file file; 391221807Sstas struct filedesc filed; 392221807Sstas struct vm_map_entry vmentry; 393221807Sstas struct vm_object object; 394221807Sstas struct vmspace vmspace; 395221807Sstas vm_map_entry_t entryp; 396221807Sstas vm_map_t map; 397221807Sstas vm_object_t objp; 398221807Sstas struct vnode *vp; 399221807Sstas struct file **ofiles; 400221807Sstas struct filestat *entry; 401221807Sstas struct filestat_list *head; 402221807Sstas kvm_t *kd; 403221807Sstas void *data; 404221807Sstas int i, fflags; 405221807Sstas int prot, type; 406221807Sstas unsigned int nfiles; 407221807Sstas 408221807Sstas assert(procstat); 409221807Sstas kd = procstat->kd; 410221807Sstas if (kd == NULL) 411221807Sstas return (NULL); 412221807Sstas if (kp->ki_fd == NULL) 413221807Sstas return (NULL); 414221807Sstas if (!kvm_read_all(kd, (unsigned long)kp->ki_fd, &filed, 415221807Sstas sizeof(filed))) { 416221807Sstas warnx("can't read filedesc at %p", (void *)kp->ki_fd); 417221807Sstas return (NULL); 418221807Sstas } 419221807Sstas 420221807Sstas /* 421221807Sstas * Allocate list head. 422221807Sstas */ 423221807Sstas head = malloc(sizeof(*head)); 424221807Sstas if (head == NULL) 425221807Sstas return (NULL); 426221807Sstas STAILQ_INIT(head); 427221807Sstas 428221807Sstas /* root directory vnode, if one. */ 429221807Sstas if (filed.fd_rdir) { 430221807Sstas entry = filestat_new_entry(filed.fd_rdir, PS_FST_TYPE_VNODE, -1, 431224859Srwatson PS_FST_FFLAG_READ, PS_FST_UFLAG_RDIR, 0, 0, NULL, 0); 432221807Sstas if (entry != NULL) 433221807Sstas STAILQ_INSERT_TAIL(head, entry, next); 434221807Sstas } 435221807Sstas /* current working directory vnode. */ 436221807Sstas if (filed.fd_cdir) { 437221807Sstas entry = filestat_new_entry(filed.fd_cdir, PS_FST_TYPE_VNODE, -1, 438224859Srwatson PS_FST_FFLAG_READ, PS_FST_UFLAG_CDIR, 0, 0, NULL, 0); 439221807Sstas if (entry != NULL) 440221807Sstas STAILQ_INSERT_TAIL(head, entry, next); 441221807Sstas } 442221807Sstas /* jail root, if any. */ 443221807Sstas if (filed.fd_jdir) { 444221807Sstas entry = filestat_new_entry(filed.fd_jdir, PS_FST_TYPE_VNODE, -1, 445224859Srwatson PS_FST_FFLAG_READ, PS_FST_UFLAG_JAIL, 0, 0, NULL, 0); 446221807Sstas if (entry != NULL) 447221807Sstas STAILQ_INSERT_TAIL(head, entry, next); 448221807Sstas } 449221807Sstas /* ktrace vnode, if one */ 450221807Sstas if (kp->ki_tracep) { 451221807Sstas entry = filestat_new_entry(kp->ki_tracep, PS_FST_TYPE_VNODE, -1, 452221807Sstas PS_FST_FFLAG_READ | PS_FST_FFLAG_WRITE, 453224859Srwatson PS_FST_UFLAG_TRACE, 0, 0, NULL, 0); 454221807Sstas if (entry != NULL) 455221807Sstas STAILQ_INSERT_TAIL(head, entry, next); 456221807Sstas } 457221807Sstas /* text vnode, if one */ 458221807Sstas if (kp->ki_textvp) { 459221807Sstas entry = filestat_new_entry(kp->ki_textvp, PS_FST_TYPE_VNODE, -1, 460224859Srwatson PS_FST_FFLAG_READ, PS_FST_UFLAG_TEXT, 0, 0, NULL, 0); 461221807Sstas if (entry != NULL) 462221807Sstas STAILQ_INSERT_TAIL(head, entry, next); 463221807Sstas } 464221807Sstas /* Controlling terminal. */ 465221807Sstas if ((vp = getctty(kd, kp)) != NULL) { 466221807Sstas entry = filestat_new_entry(vp, PS_FST_TYPE_VNODE, -1, 467221807Sstas PS_FST_FFLAG_READ | PS_FST_FFLAG_WRITE, 468224859Srwatson PS_FST_UFLAG_CTTY, 0, 0, NULL, 0); 469221807Sstas if (entry != NULL) 470221807Sstas STAILQ_INSERT_TAIL(head, entry, next); 471221807Sstas } 472221807Sstas 473221807Sstas nfiles = filed.fd_lastfile + 1; 474221807Sstas ofiles = malloc(nfiles * sizeof(struct file *)); 475221807Sstas if (ofiles == NULL) { 476223269Sjilles warn("malloc(%zu)", nfiles * sizeof(struct file *)); 477221807Sstas goto do_mmapped; 478221807Sstas } 479221807Sstas if (!kvm_read_all(kd, (unsigned long)filed.fd_ofiles, ofiles, 480221807Sstas nfiles * sizeof(struct file *))) { 481221807Sstas warnx("cannot read file structures at %p", 482221807Sstas (void *)filed.fd_ofiles); 483221807Sstas free(ofiles); 484221807Sstas goto do_mmapped; 485221807Sstas } 486221807Sstas for (i = 0; i <= filed.fd_lastfile; i++) { 487221807Sstas if (ofiles[i] == NULL) 488221807Sstas continue; 489221807Sstas if (!kvm_read_all(kd, (unsigned long)ofiles[i], &file, 490221807Sstas sizeof(struct file))) { 491221807Sstas warnx("can't read file %d at %p", i, 492221807Sstas (void *)ofiles[i]); 493221807Sstas continue; 494221807Sstas } 495221807Sstas switch (file.f_type) { 496221807Sstas case DTYPE_VNODE: 497221807Sstas type = PS_FST_TYPE_VNODE; 498221807Sstas data = file.f_vnode; 499221807Sstas break; 500221807Sstas case DTYPE_SOCKET: 501221807Sstas type = PS_FST_TYPE_SOCKET; 502221807Sstas data = file.f_data; 503221807Sstas break; 504221807Sstas case DTYPE_PIPE: 505221807Sstas type = PS_FST_TYPE_PIPE; 506221807Sstas data = file.f_data; 507221807Sstas break; 508221807Sstas case DTYPE_FIFO: 509221807Sstas type = PS_FST_TYPE_FIFO; 510221807Sstas data = file.f_vnode; 511221807Sstas break; 512221807Sstas#ifdef DTYPE_PTS 513221807Sstas case DTYPE_PTS: 514221807Sstas type = PS_FST_TYPE_PTS; 515221807Sstas data = file.f_data; 516221807Sstas break; 517221807Sstas#endif 518233760Sjhb case DTYPE_SHM: 519233760Sjhb type = PS_FST_TYPE_SHM; 520233760Sjhb data = file.f_data; 521233760Sjhb break; 522221807Sstas default: 523221807Sstas continue; 524221807Sstas } 525224859Srwatson /* XXXRW: No capability rights support for kvm yet. */ 526221807Sstas entry = filestat_new_entry(data, type, i, 527224859Srwatson to_filestat_flags(file.f_flag), 0, 0, 0, NULL, 0); 528221807Sstas if (entry != NULL) 529221807Sstas STAILQ_INSERT_TAIL(head, entry, next); 530221807Sstas } 531221807Sstas free(ofiles); 532221807Sstas 533221807Sstasdo_mmapped: 534221807Sstas 535221807Sstas /* 536221807Sstas * Process mmapped files if requested. 537221807Sstas */ 538221807Sstas if (mmapped) { 539221807Sstas if (!kvm_read_all(kd, (unsigned long)kp->ki_vmspace, &vmspace, 540221807Sstas sizeof(vmspace))) { 541221807Sstas warnx("can't read vmspace at %p", 542221807Sstas (void *)kp->ki_vmspace); 543221807Sstas goto exit; 544221807Sstas } 545221807Sstas map = &vmspace.vm_map; 546221807Sstas 547221807Sstas for (entryp = map->header.next; 548221807Sstas entryp != &kp->ki_vmspace->vm_map.header; 549221807Sstas entryp = vmentry.next) { 550221807Sstas if (!kvm_read_all(kd, (unsigned long)entryp, &vmentry, 551221807Sstas sizeof(vmentry))) { 552221807Sstas warnx("can't read vm_map_entry at %p", 553221807Sstas (void *)entryp); 554221807Sstas continue; 555221807Sstas } 556221807Sstas if (vmentry.eflags & MAP_ENTRY_IS_SUB_MAP) 557221807Sstas continue; 558221807Sstas if ((objp = vmentry.object.vm_object) == NULL) 559221807Sstas continue; 560221807Sstas for (; objp; objp = object.backing_object) { 561221807Sstas if (!kvm_read_all(kd, (unsigned long)objp, 562221807Sstas &object, sizeof(object))) { 563221807Sstas warnx("can't read vm_object at %p", 564221807Sstas (void *)objp); 565221807Sstas break; 566221807Sstas } 567221807Sstas } 568221807Sstas 569221807Sstas /* We want only vnode objects. */ 570221807Sstas if (object.type != OBJT_VNODE) 571221807Sstas continue; 572221807Sstas 573221807Sstas prot = vmentry.protection; 574221807Sstas fflags = 0; 575221807Sstas if (prot & VM_PROT_READ) 576221807Sstas fflags = PS_FST_FFLAG_READ; 577223279Sjilles if ((vmentry.eflags & MAP_ENTRY_COW) == 0 && 578223279Sjilles prot & VM_PROT_WRITE) 579221807Sstas fflags |= PS_FST_FFLAG_WRITE; 580221807Sstas 581221807Sstas /* 582221807Sstas * Create filestat entry. 583221807Sstas */ 584221807Sstas entry = filestat_new_entry(object.handle, 585221807Sstas PS_FST_TYPE_VNODE, -1, fflags, 586224859Srwatson PS_FST_UFLAG_MMAP, 0, 0, NULL, 0); 587221807Sstas if (entry != NULL) 588221807Sstas STAILQ_INSERT_TAIL(head, entry, next); 589221807Sstas } 590221807Sstas } 591221807Sstasexit: 592221807Sstas return (head); 593221807Sstas} 594221807Sstas 595221807Sstas/* 596221807Sstas * kinfo types to filestat translation. 597221807Sstas */ 598221807Sstasstatic int 599221807Sstaskinfo_type2fst(int kftype) 600221807Sstas{ 601221807Sstas static struct { 602221807Sstas int kf_type; 603221807Sstas int fst_type; 604221807Sstas } kftypes2fst[] = { 605221807Sstas { KF_TYPE_CRYPTO, PS_FST_TYPE_CRYPTO }, 606221807Sstas { KF_TYPE_FIFO, PS_FST_TYPE_FIFO }, 607221807Sstas { KF_TYPE_KQUEUE, PS_FST_TYPE_KQUEUE }, 608221807Sstas { KF_TYPE_MQUEUE, PS_FST_TYPE_MQUEUE }, 609221807Sstas { KF_TYPE_NONE, PS_FST_TYPE_NONE }, 610221807Sstas { KF_TYPE_PIPE, PS_FST_TYPE_PIPE }, 611221807Sstas { KF_TYPE_PTS, PS_FST_TYPE_PTS }, 612221807Sstas { KF_TYPE_SEM, PS_FST_TYPE_SEM }, 613221807Sstas { KF_TYPE_SHM, PS_FST_TYPE_SHM }, 614221807Sstas { KF_TYPE_SOCKET, PS_FST_TYPE_SOCKET }, 615221807Sstas { KF_TYPE_VNODE, PS_FST_TYPE_VNODE }, 616221807Sstas { KF_TYPE_UNKNOWN, PS_FST_TYPE_UNKNOWN } 617221807Sstas }; 618221807Sstas#define NKFTYPES (sizeof(kftypes2fst) / sizeof(*kftypes2fst)) 619221807Sstas unsigned int i; 620221807Sstas 621221807Sstas for (i = 0; i < NKFTYPES; i++) 622221807Sstas if (kftypes2fst[i].kf_type == kftype) 623221807Sstas break; 624221807Sstas if (i == NKFTYPES) 625221807Sstas return (PS_FST_TYPE_UNKNOWN); 626221807Sstas return (kftypes2fst[i].fst_type); 627221807Sstas} 628221807Sstas 629221807Sstas/* 630221807Sstas * kinfo flags to filestat translation. 631221807Sstas */ 632221807Sstasstatic int 633221807Sstaskinfo_fflags2fst(int kfflags) 634221807Sstas{ 635221807Sstas static struct { 636221807Sstas int kf_flag; 637221807Sstas int fst_flag; 638221807Sstas } kfflags2fst[] = { 639221807Sstas { KF_FLAG_APPEND, PS_FST_FFLAG_APPEND }, 640221807Sstas { KF_FLAG_ASYNC, PS_FST_FFLAG_ASYNC }, 641221807Sstas { KF_FLAG_CREAT, PS_FST_FFLAG_CREAT }, 642221807Sstas { KF_FLAG_DIRECT, PS_FST_FFLAG_DIRECT }, 643221807Sstas { KF_FLAG_EXCL, PS_FST_FFLAG_EXCL }, 644221807Sstas { KF_FLAG_EXEC, PS_FST_FFLAG_EXEC }, 645221807Sstas { KF_FLAG_EXLOCK, PS_FST_FFLAG_EXLOCK }, 646221807Sstas { KF_FLAG_FSYNC, PS_FST_FFLAG_SYNC }, 647221807Sstas { KF_FLAG_HASLOCK, PS_FST_FFLAG_HASLOCK }, 648221807Sstas { KF_FLAG_NOFOLLOW, PS_FST_FFLAG_NOFOLLOW }, 649221807Sstas { KF_FLAG_NONBLOCK, PS_FST_FFLAG_NONBLOCK }, 650221807Sstas { KF_FLAG_READ, PS_FST_FFLAG_READ }, 651221807Sstas { KF_FLAG_SHLOCK, PS_FST_FFLAG_SHLOCK }, 652221807Sstas { KF_FLAG_TRUNC, PS_FST_FFLAG_TRUNC }, 653221807Sstas { KF_FLAG_WRITE, PS_FST_FFLAG_WRITE } 654221807Sstas }; 655221807Sstas#define NKFFLAGS (sizeof(kfflags2fst) / sizeof(*kfflags2fst)) 656221807Sstas unsigned int i; 657221807Sstas int flags; 658221807Sstas 659221807Sstas flags = 0; 660221807Sstas for (i = 0; i < NKFFLAGS; i++) 661221807Sstas if ((kfflags & kfflags2fst[i].kf_flag) != 0) 662221807Sstas flags |= kfflags2fst[i].fst_flag; 663221807Sstas return (flags); 664221807Sstas} 665221807Sstas 666221807Sstasstatic int 667221807Sstaskinfo_uflags2fst(int fd) 668221807Sstas{ 669221807Sstas 670221807Sstas switch (fd) { 671221807Sstas case KF_FD_TYPE_CTTY: 672221807Sstas return (PS_FST_UFLAG_CTTY); 673221807Sstas case KF_FD_TYPE_CWD: 674221807Sstas return (PS_FST_UFLAG_CDIR); 675221807Sstas case KF_FD_TYPE_JAIL: 676221807Sstas return (PS_FST_UFLAG_JAIL); 677221807Sstas case KF_FD_TYPE_TEXT: 678221807Sstas return (PS_FST_UFLAG_TEXT); 679221807Sstas case KF_FD_TYPE_TRACE: 680221807Sstas return (PS_FST_UFLAG_TRACE); 681221807Sstas case KF_FD_TYPE_ROOT: 682221807Sstas return (PS_FST_UFLAG_RDIR); 683221807Sstas } 684221807Sstas return (0); 685221807Sstas} 686221807Sstas 687249666Strocinystatic struct kinfo_file * 688249666Strocinykinfo_getfile_core(struct procstat_core *core, int *cntp) 689249666Strociny{ 690249666Strociny int cnt; 691249666Strociny size_t len; 692249666Strociny char *buf, *bp, *eb; 693249666Strociny struct kinfo_file *kif, *kp, *kf; 694249666Strociny 695249666Strociny buf = procstat_core_get(core, PSC_TYPE_FILES, NULL, &len); 696249666Strociny if (buf == NULL) 697249666Strociny return (NULL); 698249666Strociny /* 699249666Strociny * XXXMG: The code below is just copy&past from libutil. 700249666Strociny * The code duplication can be avoided if libutil 701249666Strociny * is extended to provide something like: 702249666Strociny * struct kinfo_file *kinfo_getfile_from_buf(const char *buf, 703249666Strociny * size_t len, int *cntp); 704249666Strociny */ 705249666Strociny 706249666Strociny /* Pass 1: count items */ 707249666Strociny cnt = 0; 708249666Strociny bp = buf; 709249666Strociny eb = buf + len; 710249666Strociny while (bp < eb) { 711249666Strociny kf = (struct kinfo_file *)(uintptr_t)bp; 712249666Strociny bp += kf->kf_structsize; 713249666Strociny cnt++; 714249666Strociny } 715249666Strociny 716249666Strociny kif = calloc(cnt, sizeof(*kif)); 717249666Strociny if (kif == NULL) { 718249666Strociny free(buf); 719249666Strociny return (NULL); 720249666Strociny } 721249666Strociny bp = buf; 722249666Strociny eb = buf + len; 723249666Strociny kp = kif; 724249666Strociny /* Pass 2: unpack */ 725249666Strociny while (bp < eb) { 726249666Strociny kf = (struct kinfo_file *)(uintptr_t)bp; 727249666Strociny /* Copy/expand into pre-zeroed buffer */ 728249666Strociny memcpy(kp, kf, kf->kf_structsize); 729249666Strociny /* Advance to next packed record */ 730249666Strociny bp += kf->kf_structsize; 731249666Strociny /* Set field size to fixed length, advance */ 732249666Strociny kp->kf_structsize = sizeof(*kp); 733249666Strociny kp++; 734249666Strociny } 735249666Strociny free(buf); 736249666Strociny *cntp = cnt; 737249666Strociny return (kif); /* Caller must free() return value */ 738249666Strociny} 739249666Strociny 740221807Sstasstatic struct filestat_list * 741249666Strocinyprocstat_getfiles_sysctl(struct procstat *procstat, struct kinfo_proc *kp, 742249666Strociny int mmapped) 743221807Sstas{ 744221807Sstas struct kinfo_file *kif, *files; 745221807Sstas struct kinfo_vmentry *kve, *vmentries; 746221807Sstas struct filestat_list *head; 747221807Sstas struct filestat *entry; 748221807Sstas char *path; 749221807Sstas off_t offset; 750221807Sstas int cnt, fd, fflags; 751221807Sstas int i, type, uflags; 752221807Sstas int refcount; 753224859Srwatson cap_rights_t cap_rights; 754221807Sstas 755221807Sstas assert(kp); 756221807Sstas if (kp->ki_fd == NULL) 757221807Sstas return (NULL); 758249666Strociny switch(procstat->type) { 759249666Strociny case PROCSTAT_SYSCTL: 760249666Strociny files = kinfo_getfile(kp->ki_pid, &cnt); 761249666Strociny break; 762249666Strociny case PROCSTAT_CORE: 763249666Strociny files = kinfo_getfile_core(procstat->core, &cnt); 764249666Strociny break; 765249666Strociny default: 766249666Strociny assert(!"invalid type"); 767249666Strociny } 768221807Sstas if (files == NULL && errno != EPERM) { 769221807Sstas warn("kinfo_getfile()"); 770221807Sstas return (NULL); 771221807Sstas } 772221807Sstas procstat->files = files; 773221807Sstas 774221807Sstas /* 775221807Sstas * Allocate list head. 776221807Sstas */ 777221807Sstas head = malloc(sizeof(*head)); 778221807Sstas if (head == NULL) 779221807Sstas return (NULL); 780221807Sstas STAILQ_INIT(head); 781221807Sstas for (i = 0; i < cnt; i++) { 782221807Sstas kif = &files[i]; 783221807Sstas 784221807Sstas type = kinfo_type2fst(kif->kf_type); 785221807Sstas fd = kif->kf_fd >= 0 ? kif->kf_fd : -1; 786221807Sstas fflags = kinfo_fflags2fst(kif->kf_flags); 787221807Sstas uflags = kinfo_uflags2fst(kif->kf_fd); 788221807Sstas refcount = kif->kf_ref_count; 789221807Sstas offset = kif->kf_offset; 790221807Sstas if (*kif->kf_path != '\0') 791221807Sstas path = strdup(kif->kf_path); 792221807Sstas else 793221807Sstas path = NULL; 794224859Srwatson cap_rights = kif->kf_cap_rights; 795221807Sstas 796221807Sstas /* 797221807Sstas * Create filestat entry. 798221807Sstas */ 799221807Sstas entry = filestat_new_entry(kif, type, fd, fflags, uflags, 800224859Srwatson refcount, offset, path, cap_rights); 801221807Sstas if (entry != NULL) 802221807Sstas STAILQ_INSERT_TAIL(head, entry, next); 803221807Sstas } 804221807Sstas if (mmapped != 0) { 805221807Sstas vmentries = kinfo_getvmmap(kp->ki_pid, &cnt); 806221807Sstas procstat->vmentries = vmentries; 807221807Sstas if (vmentries == NULL || cnt == 0) 808221807Sstas goto fail; 809221807Sstas for (i = 0; i < cnt; i++) { 810221807Sstas kve = &vmentries[i]; 811221807Sstas if (kve->kve_type != KVME_TYPE_VNODE) 812221807Sstas continue; 813221807Sstas fflags = 0; 814221807Sstas if (kve->kve_protection & KVME_PROT_READ) 815221807Sstas fflags = PS_FST_FFLAG_READ; 816223279Sjilles if ((kve->kve_flags & KVME_FLAG_COW) == 0 && 817223279Sjilles kve->kve_protection & KVME_PROT_WRITE) 818221807Sstas fflags |= PS_FST_FFLAG_WRITE; 819221807Sstas offset = kve->kve_offset; 820221807Sstas refcount = kve->kve_ref_count; 821221807Sstas if (*kve->kve_path != '\0') 822221807Sstas path = strdup(kve->kve_path); 823221807Sstas else 824221807Sstas path = NULL; 825221807Sstas entry = filestat_new_entry(kve, PS_FST_TYPE_VNODE, -1, 826224859Srwatson fflags, PS_FST_UFLAG_MMAP, refcount, offset, path, 827224859Srwatson 0); 828221807Sstas if (entry != NULL) 829221807Sstas STAILQ_INSERT_TAIL(head, entry, next); 830221807Sstas } 831221807Sstas } 832221807Sstasfail: 833221807Sstas return (head); 834221807Sstas} 835221807Sstas 836221807Sstasint 837221807Sstasprocstat_get_pipe_info(struct procstat *procstat, struct filestat *fst, 838221807Sstas struct pipestat *ps, char *errbuf) 839221807Sstas{ 840221807Sstas 841221807Sstas assert(ps); 842221807Sstas if (procstat->type == PROCSTAT_KVM) { 843221807Sstas return (procstat_get_pipe_info_kvm(procstat->kd, fst, ps, 844221807Sstas errbuf)); 845249666Strociny } else if (procstat->type == PROCSTAT_SYSCTL || 846249666Strociny procstat->type == PROCSTAT_CORE) { 847221807Sstas return (procstat_get_pipe_info_sysctl(fst, ps, errbuf)); 848221807Sstas } else { 849223276Sjilles warnx("unknown access method: %d", procstat->type); 850221807Sstas snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 851221807Sstas return (1); 852221807Sstas } 853221807Sstas} 854221807Sstas 855221807Sstasstatic int 856221807Sstasprocstat_get_pipe_info_kvm(kvm_t *kd, struct filestat *fst, 857221807Sstas struct pipestat *ps, char *errbuf) 858221807Sstas{ 859221807Sstas struct pipe pi; 860221807Sstas void *pipep; 861221807Sstas 862221807Sstas assert(kd); 863221807Sstas assert(ps); 864221807Sstas assert(fst); 865221807Sstas bzero(ps, sizeof(*ps)); 866221807Sstas pipep = fst->fs_typedep; 867221807Sstas if (pipep == NULL) 868221807Sstas goto fail; 869221807Sstas if (!kvm_read_all(kd, (unsigned long)pipep, &pi, sizeof(struct pipe))) { 870221807Sstas warnx("can't read pipe at %p", (void *)pipep); 871221807Sstas goto fail; 872221807Sstas } 873221807Sstas ps->addr = (uintptr_t)pipep; 874221807Sstas ps->peer = (uintptr_t)pi.pipe_peer; 875221807Sstas ps->buffer_cnt = pi.pipe_buffer.cnt; 876221807Sstas return (0); 877221807Sstas 878221807Sstasfail: 879221807Sstas snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 880221807Sstas return (1); 881221807Sstas} 882221807Sstas 883221807Sstasstatic int 884221807Sstasprocstat_get_pipe_info_sysctl(struct filestat *fst, struct pipestat *ps, 885221807Sstas char *errbuf __unused) 886221807Sstas{ 887221807Sstas struct kinfo_file *kif; 888221807Sstas 889221807Sstas assert(ps); 890221807Sstas assert(fst); 891221807Sstas bzero(ps, sizeof(*ps)); 892221807Sstas kif = fst->fs_typedep; 893221807Sstas if (kif == NULL) 894221807Sstas return (1); 895221807Sstas ps->addr = kif->kf_un.kf_pipe.kf_pipe_addr; 896221807Sstas ps->peer = kif->kf_un.kf_pipe.kf_pipe_peer; 897221807Sstas ps->buffer_cnt = kif->kf_un.kf_pipe.kf_pipe_buffer_cnt; 898221807Sstas return (0); 899221807Sstas} 900221807Sstas 901221807Sstasint 902221807Sstasprocstat_get_pts_info(struct procstat *procstat, struct filestat *fst, 903221807Sstas struct ptsstat *pts, char *errbuf) 904221807Sstas{ 905221807Sstas 906221807Sstas assert(pts); 907221807Sstas if (procstat->type == PROCSTAT_KVM) { 908221807Sstas return (procstat_get_pts_info_kvm(procstat->kd, fst, pts, 909221807Sstas errbuf)); 910249666Strociny } else if (procstat->type == PROCSTAT_SYSCTL || 911249666Strociny procstat->type == PROCSTAT_CORE) { 912221807Sstas return (procstat_get_pts_info_sysctl(fst, pts, errbuf)); 913221807Sstas } else { 914223276Sjilles warnx("unknown access method: %d", procstat->type); 915221807Sstas snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 916221807Sstas return (1); 917221807Sstas } 918221807Sstas} 919221807Sstas 920221807Sstasstatic int 921221807Sstasprocstat_get_pts_info_kvm(kvm_t *kd, struct filestat *fst, 922221807Sstas struct ptsstat *pts, char *errbuf) 923221807Sstas{ 924221807Sstas struct tty tty; 925221807Sstas void *ttyp; 926221807Sstas 927221807Sstas assert(kd); 928221807Sstas assert(pts); 929221807Sstas assert(fst); 930221807Sstas bzero(pts, sizeof(*pts)); 931221807Sstas ttyp = fst->fs_typedep; 932221807Sstas if (ttyp == NULL) 933221807Sstas goto fail; 934221807Sstas if (!kvm_read_all(kd, (unsigned long)ttyp, &tty, sizeof(struct tty))) { 935221807Sstas warnx("can't read tty at %p", (void *)ttyp); 936221807Sstas goto fail; 937221807Sstas } 938221807Sstas pts->dev = dev2udev(kd, tty.t_dev); 939221807Sstas (void)kdevtoname(kd, tty.t_dev, pts->devname); 940221807Sstas return (0); 941221807Sstas 942221807Sstasfail: 943221807Sstas snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 944221807Sstas return (1); 945221807Sstas} 946221807Sstas 947221807Sstasstatic int 948221807Sstasprocstat_get_pts_info_sysctl(struct filestat *fst, struct ptsstat *pts, 949221807Sstas char *errbuf __unused) 950221807Sstas{ 951221807Sstas struct kinfo_file *kif; 952221807Sstas 953221807Sstas assert(pts); 954221807Sstas assert(fst); 955221807Sstas bzero(pts, sizeof(*pts)); 956221807Sstas kif = fst->fs_typedep; 957221807Sstas if (kif == NULL) 958221807Sstas return (0); 959221807Sstas pts->dev = kif->kf_un.kf_pts.kf_pts_dev; 960221807Sstas strlcpy(pts->devname, kif->kf_path, sizeof(pts->devname)); 961221807Sstas return (0); 962221807Sstas} 963221807Sstas 964221807Sstasint 965233760Sjhbprocstat_get_shm_info(struct procstat *procstat, struct filestat *fst, 966233760Sjhb struct shmstat *shm, char *errbuf) 967233760Sjhb{ 968233760Sjhb 969233760Sjhb assert(shm); 970233760Sjhb if (procstat->type == PROCSTAT_KVM) { 971233760Sjhb return (procstat_get_shm_info_kvm(procstat->kd, fst, shm, 972233760Sjhb errbuf)); 973249666Strociny } else if (procstat->type == PROCSTAT_SYSCTL || 974249666Strociny procstat->type == PROCSTAT_CORE) { 975233760Sjhb return (procstat_get_shm_info_sysctl(fst, shm, errbuf)); 976233760Sjhb } else { 977233760Sjhb warnx("unknown access method: %d", procstat->type); 978233760Sjhb snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 979233760Sjhb return (1); 980233760Sjhb } 981233760Sjhb} 982233760Sjhb 983233760Sjhbstatic int 984233760Sjhbprocstat_get_shm_info_kvm(kvm_t *kd, struct filestat *fst, 985233760Sjhb struct shmstat *shm, char *errbuf) 986233760Sjhb{ 987233760Sjhb struct shmfd shmfd; 988233760Sjhb void *shmfdp; 989236717Sjhb char *path; 990236717Sjhb int i; 991233760Sjhb 992233760Sjhb assert(kd); 993233760Sjhb assert(shm); 994233760Sjhb assert(fst); 995233760Sjhb bzero(shm, sizeof(*shm)); 996233760Sjhb shmfdp = fst->fs_typedep; 997233760Sjhb if (shmfdp == NULL) 998233760Sjhb goto fail; 999233760Sjhb if (!kvm_read_all(kd, (unsigned long)shmfdp, &shmfd, 1000233760Sjhb sizeof(struct shmfd))) { 1001233760Sjhb warnx("can't read shmfd at %p", (void *)shmfdp); 1002233760Sjhb goto fail; 1003233760Sjhb } 1004233760Sjhb shm->mode = S_IFREG | shmfd.shm_mode; 1005233760Sjhb shm->size = shmfd.shm_size; 1006236717Sjhb if (fst->fs_path == NULL && shmfd.shm_path != NULL) { 1007236717Sjhb path = malloc(MAXPATHLEN); 1008236717Sjhb for (i = 0; i < MAXPATHLEN - 1; i++) { 1009236717Sjhb if (!kvm_read_all(kd, (unsigned long)shmfd.shm_path + i, 1010236717Sjhb path + i, 1)) 1011236717Sjhb break; 1012236717Sjhb if (path[i] == '\0') 1013236717Sjhb break; 1014236717Sjhb } 1015236717Sjhb path[i] = '\0'; 1016236717Sjhb if (i == 0) 1017236717Sjhb free(path); 1018236717Sjhb else 1019236717Sjhb fst->fs_path = path; 1020236717Sjhb } 1021233760Sjhb return (0); 1022233760Sjhb 1023233760Sjhbfail: 1024233760Sjhb snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 1025233760Sjhb return (1); 1026233760Sjhb} 1027233760Sjhb 1028233760Sjhbstatic int 1029233760Sjhbprocstat_get_shm_info_sysctl(struct filestat *fst, struct shmstat *shm, 1030233760Sjhb char *errbuf __unused) 1031233760Sjhb{ 1032233760Sjhb struct kinfo_file *kif; 1033233760Sjhb 1034233760Sjhb assert(shm); 1035233760Sjhb assert(fst); 1036233760Sjhb bzero(shm, sizeof(*shm)); 1037233760Sjhb kif = fst->fs_typedep; 1038233760Sjhb if (kif == NULL) 1039233760Sjhb return (0); 1040233760Sjhb shm->size = kif->kf_un.kf_file.kf_file_size; 1041233760Sjhb shm->mode = kif->kf_un.kf_file.kf_file_mode; 1042233760Sjhb return (0); 1043233760Sjhb} 1044233760Sjhb 1045233760Sjhbint 1046221807Sstasprocstat_get_vnode_info(struct procstat *procstat, struct filestat *fst, 1047221807Sstas struct vnstat *vn, char *errbuf) 1048221807Sstas{ 1049221807Sstas 1050221807Sstas assert(vn); 1051221807Sstas if (procstat->type == PROCSTAT_KVM) { 1052221807Sstas return (procstat_get_vnode_info_kvm(procstat->kd, fst, vn, 1053221807Sstas errbuf)); 1054249666Strociny } else if (procstat->type == PROCSTAT_SYSCTL || 1055249666Strociny procstat->type == PROCSTAT_CORE) { 1056221807Sstas return (procstat_get_vnode_info_sysctl(fst, vn, errbuf)); 1057221807Sstas } else { 1058223276Sjilles warnx("unknown access method: %d", procstat->type); 1059221807Sstas snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 1060221807Sstas return (1); 1061221807Sstas } 1062221807Sstas} 1063221807Sstas 1064221807Sstasstatic int 1065221807Sstasprocstat_get_vnode_info_kvm(kvm_t *kd, struct filestat *fst, 1066221807Sstas struct vnstat *vn, char *errbuf) 1067221807Sstas{ 1068221807Sstas /* Filesystem specific handlers. */ 1069221807Sstas #define FSTYPE(fst) {#fst, fst##_filestat} 1070221807Sstas struct { 1071221807Sstas const char *tag; 1072221807Sstas int (*handler)(kvm_t *kd, struct vnode *vp, 1073221807Sstas struct vnstat *vn); 1074221807Sstas } fstypes[] = { 1075221807Sstas FSTYPE(devfs), 1076221807Sstas FSTYPE(isofs), 1077221807Sstas FSTYPE(msdosfs), 1078221807Sstas FSTYPE(nfs), 1079221807Sstas FSTYPE(udf), 1080221807Sstas FSTYPE(ufs), 1081221824Sstas#ifdef LIBPROCSTAT_ZFS 1082221807Sstas FSTYPE(zfs), 1083221807Sstas#endif 1084221807Sstas }; 1085221807Sstas#define NTYPES (sizeof(fstypes) / sizeof(*fstypes)) 1086221807Sstas struct vnode vnode; 1087221807Sstas char tagstr[12]; 1088221807Sstas void *vp; 1089221807Sstas int error, found; 1090221807Sstas unsigned int i; 1091221807Sstas 1092221807Sstas assert(kd); 1093221807Sstas assert(vn); 1094221807Sstas assert(fst); 1095221807Sstas vp = fst->fs_typedep; 1096221807Sstas if (vp == NULL) 1097221807Sstas goto fail; 1098221807Sstas error = kvm_read_all(kd, (unsigned long)vp, &vnode, sizeof(vnode)); 1099221807Sstas if (error == 0) { 1100221807Sstas warnx("can't read vnode at %p", (void *)vp); 1101221807Sstas goto fail; 1102221807Sstas } 1103221807Sstas bzero(vn, sizeof(*vn)); 1104221807Sstas vn->vn_type = vntype2psfsttype(vnode.v_type); 1105221807Sstas if (vnode.v_type == VNON || vnode.v_type == VBAD) 1106221807Sstas return (0); 1107221807Sstas error = kvm_read_all(kd, (unsigned long)vnode.v_tag, tagstr, 1108221807Sstas sizeof(tagstr)); 1109221807Sstas if (error == 0) { 1110221807Sstas warnx("can't read v_tag at %p", (void *)vp); 1111221807Sstas goto fail; 1112221807Sstas } 1113221807Sstas tagstr[sizeof(tagstr) - 1] = '\0'; 1114221807Sstas 1115221807Sstas /* 1116221807Sstas * Find appropriate handler. 1117221807Sstas */ 1118221807Sstas for (i = 0, found = 0; i < NTYPES; i++) 1119221807Sstas if (!strcmp(fstypes[i].tag, tagstr)) { 1120221807Sstas if (fstypes[i].handler(kd, &vnode, vn) != 0) { 1121221807Sstas goto fail; 1122221807Sstas } 1123221807Sstas break; 1124221807Sstas } 1125221807Sstas if (i == NTYPES) { 1126221807Sstas snprintf(errbuf, _POSIX2_LINE_MAX, "?(%s)", tagstr); 1127221807Sstas return (1); 1128221807Sstas } 1129221807Sstas vn->vn_mntdir = getmnton(kd, vnode.v_mount); 1130221807Sstas if ((vnode.v_type == VBLK || vnode.v_type == VCHR) && 1131221807Sstas vnode.v_rdev != NULL){ 1132221807Sstas vn->vn_dev = dev2udev(kd, vnode.v_rdev); 1133221807Sstas (void)kdevtoname(kd, vnode.v_rdev, vn->vn_devname); 1134221807Sstas } else { 1135221807Sstas vn->vn_dev = -1; 1136221807Sstas } 1137221807Sstas return (0); 1138221807Sstas 1139221807Sstasfail: 1140221807Sstas snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 1141221807Sstas return (1); 1142221807Sstas} 1143221807Sstas 1144221807Sstas/* 1145221807Sstas * kinfo vnode type to filestat translation. 1146221807Sstas */ 1147221807Sstasstatic int 1148221807Sstaskinfo_vtype2fst(int kfvtype) 1149221807Sstas{ 1150221807Sstas static struct { 1151221807Sstas int kf_vtype; 1152221807Sstas int fst_vtype; 1153221807Sstas } kfvtypes2fst[] = { 1154221807Sstas { KF_VTYPE_VBAD, PS_FST_VTYPE_VBAD }, 1155221807Sstas { KF_VTYPE_VBLK, PS_FST_VTYPE_VBLK }, 1156221807Sstas { KF_VTYPE_VCHR, PS_FST_VTYPE_VCHR }, 1157221807Sstas { KF_VTYPE_VDIR, PS_FST_VTYPE_VDIR }, 1158221807Sstas { KF_VTYPE_VFIFO, PS_FST_VTYPE_VFIFO }, 1159221807Sstas { KF_VTYPE_VLNK, PS_FST_VTYPE_VLNK }, 1160221807Sstas { KF_VTYPE_VNON, PS_FST_VTYPE_VNON }, 1161221807Sstas { KF_VTYPE_VREG, PS_FST_VTYPE_VREG }, 1162221807Sstas { KF_VTYPE_VSOCK, PS_FST_VTYPE_VSOCK } 1163221807Sstas }; 1164221807Sstas#define NKFVTYPES (sizeof(kfvtypes2fst) / sizeof(*kfvtypes2fst)) 1165221807Sstas unsigned int i; 1166221807Sstas 1167221807Sstas for (i = 0; i < NKFVTYPES; i++) 1168221807Sstas if (kfvtypes2fst[i].kf_vtype == kfvtype) 1169221807Sstas break; 1170221807Sstas if (i == NKFVTYPES) 1171221807Sstas return (PS_FST_VTYPE_UNKNOWN); 1172221807Sstas return (kfvtypes2fst[i].fst_vtype); 1173221807Sstas} 1174221807Sstas 1175221807Sstasstatic int 1176221807Sstasprocstat_get_vnode_info_sysctl(struct filestat *fst, struct vnstat *vn, 1177221807Sstas char *errbuf) 1178221807Sstas{ 1179221807Sstas struct statfs stbuf; 1180221807Sstas struct kinfo_file *kif; 1181221807Sstas struct kinfo_vmentry *kve; 1182221807Sstas uint64_t fileid; 1183221807Sstas uint64_t size; 1184221807Sstas char *name, *path; 1185221807Sstas uint32_t fsid; 1186221807Sstas uint16_t mode; 1187221807Sstas uint32_t rdev; 1188221807Sstas int vntype; 1189221807Sstas int status; 1190221807Sstas 1191221807Sstas assert(fst); 1192221807Sstas assert(vn); 1193221807Sstas bzero(vn, sizeof(*vn)); 1194221807Sstas if (fst->fs_typedep == NULL) 1195221807Sstas return (1); 1196221807Sstas if (fst->fs_uflags & PS_FST_UFLAG_MMAP) { 1197221807Sstas kve = fst->fs_typedep; 1198221807Sstas fileid = kve->kve_vn_fileid; 1199221807Sstas fsid = kve->kve_vn_fsid; 1200221807Sstas mode = kve->kve_vn_mode; 1201221807Sstas path = kve->kve_path; 1202221807Sstas rdev = kve->kve_vn_rdev; 1203221807Sstas size = kve->kve_vn_size; 1204221807Sstas vntype = kinfo_vtype2fst(kve->kve_vn_type); 1205221807Sstas status = kve->kve_status; 1206221807Sstas } else { 1207221807Sstas kif = fst->fs_typedep; 1208221807Sstas fileid = kif->kf_un.kf_file.kf_file_fileid; 1209221807Sstas fsid = kif->kf_un.kf_file.kf_file_fsid; 1210221807Sstas mode = kif->kf_un.kf_file.kf_file_mode; 1211221807Sstas path = kif->kf_path; 1212221807Sstas rdev = kif->kf_un.kf_file.kf_file_rdev; 1213221807Sstas size = kif->kf_un.kf_file.kf_file_size; 1214221807Sstas vntype = kinfo_vtype2fst(kif->kf_vnode_type); 1215221807Sstas status = kif->kf_status; 1216221807Sstas } 1217221807Sstas vn->vn_type = vntype; 1218221807Sstas if (vntype == PS_FST_VTYPE_VNON || vntype == PS_FST_VTYPE_VBAD) 1219221807Sstas return (0); 1220221807Sstas if ((status & KF_ATTR_VALID) == 0) { 1221221807Sstas snprintf(errbuf, _POSIX2_LINE_MAX, "? (no info available)"); 1222221807Sstas return (1); 1223221807Sstas } 1224221807Sstas if (path && *path) { 1225221807Sstas statfs(path, &stbuf); 1226221807Sstas vn->vn_mntdir = strdup(stbuf.f_mntonname); 1227221807Sstas } else 1228221807Sstas vn->vn_mntdir = strdup("-"); 1229221807Sstas vn->vn_dev = rdev; 1230221807Sstas if (vntype == PS_FST_VTYPE_VBLK) { 1231221807Sstas name = devname(rdev, S_IFBLK); 1232221807Sstas if (name != NULL) 1233221807Sstas strlcpy(vn->vn_devname, name, 1234221807Sstas sizeof(vn->vn_devname)); 1235221807Sstas } else if (vntype == PS_FST_VTYPE_VCHR) { 1236221807Sstas name = devname(vn->vn_dev, S_IFCHR); 1237221807Sstas if (name != NULL) 1238221807Sstas strlcpy(vn->vn_devname, name, 1239221807Sstas sizeof(vn->vn_devname)); 1240221807Sstas } 1241221807Sstas vn->vn_fsid = fsid; 1242221807Sstas vn->vn_fileid = fileid; 1243221807Sstas vn->vn_size = size; 1244221807Sstas vn->vn_mode = mode; 1245221807Sstas return (0); 1246221807Sstas} 1247221807Sstas 1248221807Sstasint 1249221807Sstasprocstat_get_socket_info(struct procstat *procstat, struct filestat *fst, 1250221807Sstas struct sockstat *sock, char *errbuf) 1251221807Sstas{ 1252221807Sstas 1253221807Sstas assert(sock); 1254221807Sstas if (procstat->type == PROCSTAT_KVM) { 1255221807Sstas return (procstat_get_socket_info_kvm(procstat->kd, fst, sock, 1256221807Sstas errbuf)); 1257249666Strociny } else if (procstat->type == PROCSTAT_SYSCTL || 1258249666Strociny procstat->type == PROCSTAT_CORE) { 1259221807Sstas return (procstat_get_socket_info_sysctl(fst, sock, errbuf)); 1260221807Sstas } else { 1261223276Sjilles warnx("unknown access method: %d", procstat->type); 1262221807Sstas snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 1263221807Sstas return (1); 1264221807Sstas } 1265221807Sstas} 1266221807Sstas 1267221807Sstasstatic int 1268221807Sstasprocstat_get_socket_info_kvm(kvm_t *kd, struct filestat *fst, 1269221807Sstas struct sockstat *sock, char *errbuf) 1270221807Sstas{ 1271221807Sstas struct domain dom; 1272221807Sstas struct inpcb inpcb; 1273221807Sstas struct protosw proto; 1274221807Sstas struct socket s; 1275221807Sstas struct unpcb unpcb; 1276221807Sstas ssize_t len; 1277221807Sstas void *so; 1278221807Sstas 1279221807Sstas assert(kd); 1280221807Sstas assert(sock); 1281221807Sstas assert(fst); 1282221807Sstas bzero(sock, sizeof(*sock)); 1283221807Sstas so = fst->fs_typedep; 1284221807Sstas if (so == NULL) 1285221807Sstas goto fail; 1286221807Sstas sock->so_addr = (uintptr_t)so; 1287221807Sstas /* fill in socket */ 1288221807Sstas if (!kvm_read_all(kd, (unsigned long)so, &s, 1289221807Sstas sizeof(struct socket))) { 1290221807Sstas warnx("can't read sock at %p", (void *)so); 1291221807Sstas goto fail; 1292221807Sstas } 1293221807Sstas /* fill in protosw entry */ 1294221807Sstas if (!kvm_read_all(kd, (unsigned long)s.so_proto, &proto, 1295221807Sstas sizeof(struct protosw))) { 1296221807Sstas warnx("can't read protosw at %p", (void *)s.so_proto); 1297221807Sstas goto fail; 1298221807Sstas } 1299221807Sstas /* fill in domain */ 1300221807Sstas if (!kvm_read_all(kd, (unsigned long)proto.pr_domain, &dom, 1301221807Sstas sizeof(struct domain))) { 1302221807Sstas warnx("can't read domain at %p", 1303221807Sstas (void *)proto.pr_domain); 1304221807Sstas goto fail; 1305221807Sstas } 1306221807Sstas if ((len = kvm_read(kd, (unsigned long)dom.dom_name, sock->dname, 1307221807Sstas sizeof(sock->dname) - 1)) < 0) { 1308221807Sstas warnx("can't read domain name at %p", (void *)dom.dom_name); 1309221807Sstas sock->dname[0] = '\0'; 1310221807Sstas } 1311221807Sstas else 1312221807Sstas sock->dname[len] = '\0'; 1313221807Sstas 1314221807Sstas /* 1315221807Sstas * Fill in known data. 1316221807Sstas */ 1317221807Sstas sock->type = s.so_type; 1318221807Sstas sock->proto = proto.pr_protocol; 1319221807Sstas sock->dom_family = dom.dom_family; 1320221807Sstas sock->so_pcb = (uintptr_t)s.so_pcb; 1321221807Sstas 1322221807Sstas /* 1323221807Sstas * Protocol specific data. 1324221807Sstas */ 1325221807Sstas switch(dom.dom_family) { 1326221807Sstas case AF_INET: 1327221807Sstas case AF_INET6: 1328221807Sstas if (proto.pr_protocol == IPPROTO_TCP) { 1329221807Sstas if (s.so_pcb) { 1330221807Sstas if (kvm_read(kd, (u_long)s.so_pcb, 1331221807Sstas (char *)&inpcb, sizeof(struct inpcb)) 1332221807Sstas != sizeof(struct inpcb)) { 1333221807Sstas warnx("can't read inpcb at %p", 1334221807Sstas (void *)s.so_pcb); 1335221807Sstas } else 1336221807Sstas sock->inp_ppcb = 1337221807Sstas (uintptr_t)inpcb.inp_ppcb; 1338221807Sstas } 1339221807Sstas } 1340221807Sstas break; 1341221807Sstas case AF_UNIX: 1342221807Sstas if (s.so_pcb) { 1343221807Sstas if (kvm_read(kd, (u_long)s.so_pcb, (char *)&unpcb, 1344221807Sstas sizeof(struct unpcb)) != sizeof(struct unpcb)){ 1345221807Sstas warnx("can't read unpcb at %p", 1346221807Sstas (void *)s.so_pcb); 1347221807Sstas } else if (unpcb.unp_conn) { 1348221807Sstas sock->so_rcv_sb_state = s.so_rcv.sb_state; 1349221807Sstas sock->so_snd_sb_state = s.so_snd.sb_state; 1350221807Sstas sock->unp_conn = (uintptr_t)unpcb.unp_conn; 1351221807Sstas } 1352221807Sstas } 1353221807Sstas break; 1354221807Sstas default: 1355221807Sstas break; 1356221807Sstas } 1357221807Sstas return (0); 1358221807Sstas 1359221807Sstasfail: 1360221807Sstas snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 1361221807Sstas return (1); 1362221807Sstas} 1363221807Sstas 1364221807Sstasstatic int 1365221807Sstasprocstat_get_socket_info_sysctl(struct filestat *fst, struct sockstat *sock, 1366221807Sstas char *errbuf __unused) 1367221807Sstas{ 1368221807Sstas struct kinfo_file *kif; 1369221807Sstas 1370221807Sstas assert(sock); 1371221807Sstas assert(fst); 1372221807Sstas bzero(sock, sizeof(*sock)); 1373221807Sstas kif = fst->fs_typedep; 1374221807Sstas if (kif == NULL) 1375221807Sstas return (0); 1376221807Sstas 1377221807Sstas /* 1378221807Sstas * Fill in known data. 1379221807Sstas */ 1380221807Sstas sock->type = kif->kf_sock_type; 1381221807Sstas sock->proto = kif->kf_sock_protocol; 1382221807Sstas sock->dom_family = kif->kf_sock_domain; 1383221807Sstas sock->so_pcb = kif->kf_un.kf_sock.kf_sock_pcb; 1384221807Sstas strlcpy(sock->dname, kif->kf_path, sizeof(sock->dname)); 1385221807Sstas bcopy(&kif->kf_sa_local, &sock->sa_local, kif->kf_sa_local.ss_len); 1386221807Sstas bcopy(&kif->kf_sa_peer, &sock->sa_peer, kif->kf_sa_peer.ss_len); 1387221807Sstas 1388221807Sstas /* 1389221807Sstas * Protocol specific data. 1390221807Sstas */ 1391221807Sstas switch(sock->dom_family) { 1392221807Sstas case AF_INET: 1393221807Sstas case AF_INET6: 1394221807Sstas if (sock->proto == IPPROTO_TCP) 1395221807Sstas sock->inp_ppcb = kif->kf_un.kf_sock.kf_sock_inpcb; 1396221807Sstas break; 1397221807Sstas case AF_UNIX: 1398221807Sstas if (kif->kf_un.kf_sock.kf_sock_unpconn != 0) { 1399221807Sstas sock->so_rcv_sb_state = 1400221807Sstas kif->kf_un.kf_sock.kf_sock_rcv_sb_state; 1401221807Sstas sock->so_snd_sb_state = 1402221807Sstas kif->kf_un.kf_sock.kf_sock_snd_sb_state; 1403221807Sstas sock->unp_conn = 1404221807Sstas kif->kf_un.kf_sock.kf_sock_unpconn; 1405221807Sstas } 1406221807Sstas break; 1407221807Sstas default: 1408221807Sstas break; 1409221807Sstas } 1410221807Sstas return (0); 1411221807Sstas} 1412221807Sstas 1413221807Sstas/* 1414221807Sstas * Descriptor flags to filestat translation. 1415221807Sstas */ 1416221807Sstasstatic int 1417221807Sstasto_filestat_flags(int flags) 1418221807Sstas{ 1419221807Sstas static struct { 1420221807Sstas int flag; 1421221807Sstas int fst_flag; 1422221807Sstas } fstflags[] = { 1423221807Sstas { FREAD, PS_FST_FFLAG_READ }, 1424221807Sstas { FWRITE, PS_FST_FFLAG_WRITE }, 1425221807Sstas { O_APPEND, PS_FST_FFLAG_APPEND }, 1426221807Sstas { O_ASYNC, PS_FST_FFLAG_ASYNC }, 1427221807Sstas { O_CREAT, PS_FST_FFLAG_CREAT }, 1428221807Sstas { O_DIRECT, PS_FST_FFLAG_DIRECT }, 1429221807Sstas { O_EXCL, PS_FST_FFLAG_EXCL }, 1430221807Sstas { O_EXEC, PS_FST_FFLAG_EXEC }, 1431221807Sstas { O_EXLOCK, PS_FST_FFLAG_EXLOCK }, 1432221807Sstas { O_NOFOLLOW, PS_FST_FFLAG_NOFOLLOW }, 1433221807Sstas { O_NONBLOCK, PS_FST_FFLAG_NONBLOCK }, 1434221807Sstas { O_SHLOCK, PS_FST_FFLAG_SHLOCK }, 1435221807Sstas { O_SYNC, PS_FST_FFLAG_SYNC }, 1436221807Sstas { O_TRUNC, PS_FST_FFLAG_TRUNC } 1437221807Sstas }; 1438221807Sstas#define NFSTFLAGS (sizeof(fstflags) / sizeof(*fstflags)) 1439221807Sstas int fst_flags; 1440221807Sstas unsigned int i; 1441221807Sstas 1442221807Sstas fst_flags = 0; 1443221807Sstas for (i = 0; i < NFSTFLAGS; i++) 1444221807Sstas if (flags & fstflags[i].flag) 1445221807Sstas fst_flags |= fstflags[i].fst_flag; 1446221807Sstas return (fst_flags); 1447221807Sstas} 1448221807Sstas 1449221807Sstas/* 1450221807Sstas * Vnode type to filestate translation. 1451221807Sstas */ 1452221807Sstasstatic int 1453221807Sstasvntype2psfsttype(int type) 1454221807Sstas{ 1455221807Sstas static struct { 1456221807Sstas int vtype; 1457221807Sstas int fst_vtype; 1458221807Sstas } vt2fst[] = { 1459221807Sstas { VBAD, PS_FST_VTYPE_VBAD }, 1460221807Sstas { VBLK, PS_FST_VTYPE_VBLK }, 1461221807Sstas { VCHR, PS_FST_VTYPE_VCHR }, 1462221807Sstas { VDIR, PS_FST_VTYPE_VDIR }, 1463221807Sstas { VFIFO, PS_FST_VTYPE_VFIFO }, 1464221807Sstas { VLNK, PS_FST_VTYPE_VLNK }, 1465221807Sstas { VNON, PS_FST_VTYPE_VNON }, 1466221807Sstas { VREG, PS_FST_VTYPE_VREG }, 1467221807Sstas { VSOCK, PS_FST_VTYPE_VSOCK } 1468221807Sstas }; 1469221807Sstas#define NVFTYPES (sizeof(vt2fst) / sizeof(*vt2fst)) 1470221807Sstas unsigned int i, fst_type; 1471221807Sstas 1472221807Sstas fst_type = PS_FST_VTYPE_UNKNOWN; 1473221807Sstas for (i = 0; i < NVFTYPES; i++) { 1474221807Sstas if (type == vt2fst[i].vtype) { 1475221807Sstas fst_type = vt2fst[i].fst_vtype; 1476221807Sstas break; 1477221807Sstas } 1478221807Sstas } 1479221807Sstas return (fst_type); 1480221807Sstas} 1481221807Sstas 1482221807Sstasstatic char * 1483221807Sstasgetmnton(kvm_t *kd, struct mount *m) 1484221807Sstas{ 1485223262Sbenl struct mount mnt; 1486221807Sstas static struct mtab { 1487221807Sstas struct mtab *next; 1488221807Sstas struct mount *m; 1489221807Sstas char mntonname[MNAMELEN + 1]; 1490221807Sstas } *mhead = NULL; 1491221807Sstas struct mtab *mt; 1492221807Sstas 1493221807Sstas for (mt = mhead; mt != NULL; mt = mt->next) 1494221807Sstas if (m == mt->m) 1495221807Sstas return (mt->mntonname); 1496221807Sstas if (!kvm_read_all(kd, (unsigned long)m, &mnt, sizeof(struct mount))) { 1497221807Sstas warnx("can't read mount table at %p", (void *)m); 1498221807Sstas return (NULL); 1499221807Sstas } 1500221807Sstas if ((mt = malloc(sizeof (struct mtab))) == NULL) 1501221807Sstas err(1, NULL); 1502221807Sstas mt->m = m; 1503221807Sstas bcopy(&mnt.mnt_stat.f_mntonname[0], &mt->mntonname[0], MNAMELEN); 1504223262Sbenl mt->mntonname[MNAMELEN] = '\0'; 1505221807Sstas mt->next = mhead; 1506221807Sstas mhead = mt; 1507221807Sstas return (mt->mntonname); 1508221807Sstas} 1509249666Strociny 1510