libprocstat.c revision 249677
1/*- 2 * Copyright (c) 2009 Stanislav Sedov <stas@FreeBSD.org> 3 * Copyright (c) 1988, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by the University of 17 * California, Berkeley and its contributors. 18 * 4. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35#include <sys/cdefs.h> 36__FBSDID("$FreeBSD: head/lib/libprocstat/libprocstat.c 249677 2013-04-20 08:03:56Z trociny $"); 37 38#include <sys/param.h> 39#include <sys/time.h> 40#include <sys/resourcevar.h> 41#include <sys/proc.h> 42#include <sys/user.h> 43#include <sys/stat.h> 44#include <sys/vnode.h> 45#include <sys/socket.h> 46#include <sys/socketvar.h> 47#include <sys/domain.h> 48#include <sys/protosw.h> 49#include <sys/un.h> 50#include <sys/unpcb.h> 51#include <sys/sysctl.h> 52#include <sys/tty.h> 53#include <sys/filedesc.h> 54#include <sys/queue.h> 55#define _WANT_FILE 56#include <sys/file.h> 57#include <sys/conf.h> 58#include <sys/mman.h> 59#define _KERNEL 60#include <sys/mount.h> 61#include <sys/pipe.h> 62#include <ufs/ufs/quota.h> 63#include <ufs/ufs/inode.h> 64#include <fs/devfs/devfs.h> 65#include <fs/devfs/devfs_int.h> 66#undef _KERNEL 67#include <nfs/nfsproto.h> 68#include <nfsclient/nfs.h> 69#include <nfsclient/nfsnode.h> 70 71#include <vm/vm.h> 72#include <vm/vm_map.h> 73#include <vm/vm_object.h> 74 75#include <net/route.h> 76#include <netinet/in.h> 77#include <netinet/in_systm.h> 78#include <netinet/ip.h> 79#include <netinet/in_pcb.h> 80 81#include <assert.h> 82#include <ctype.h> 83#include <err.h> 84#include <fcntl.h> 85#include <kvm.h> 86#include <libutil.h> 87#include <limits.h> 88#include <paths.h> 89#include <pwd.h> 90#include <stdio.h> 91#include <stdlib.h> 92#include <stddef.h> 93#include <string.h> 94#include <unistd.h> 95#include <netdb.h> 96 97#include <libprocstat.h> 98#include "libprocstat_internal.h" 99#include "common_kvm.h" 100#include "core.h" 101 102int statfs(const char *, struct statfs *); /* XXX */ 103 104#define PROCSTAT_KVM 1 105#define PROCSTAT_SYSCTL 2 106#define PROCSTAT_CORE 3 107 108static char *getmnton(kvm_t *kd, struct mount *m); 109static struct kinfo_vmentry * kinfo_getvmmap_core(struct procstat_core *core, 110 int *cntp); 111static struct filestat_list *procstat_getfiles_kvm( 112 struct procstat *procstat, struct kinfo_proc *kp, int mmapped); 113static struct filestat_list *procstat_getfiles_sysctl( 114 struct procstat *procstat, struct kinfo_proc *kp, int mmapped); 115static int procstat_get_pipe_info_sysctl(struct filestat *fst, 116 struct pipestat *pipe, char *errbuf); 117static int procstat_get_pipe_info_kvm(kvm_t *kd, struct filestat *fst, 118 struct pipestat *pipe, char *errbuf); 119static int procstat_get_pts_info_sysctl(struct filestat *fst, 120 struct ptsstat *pts, char *errbuf); 121static int procstat_get_pts_info_kvm(kvm_t *kd, struct filestat *fst, 122 struct ptsstat *pts, char *errbuf); 123static int procstat_get_shm_info_sysctl(struct filestat *fst, 124 struct shmstat *shm, char *errbuf); 125static int procstat_get_shm_info_kvm(kvm_t *kd, struct filestat *fst, 126 struct shmstat *shm, char *errbuf); 127static int procstat_get_socket_info_sysctl(struct filestat *fst, 128 struct sockstat *sock, char *errbuf); 129static int procstat_get_socket_info_kvm(kvm_t *kd, struct filestat *fst, 130 struct sockstat *sock, char *errbuf); 131static int to_filestat_flags(int flags); 132static int procstat_get_vnode_info_kvm(kvm_t *kd, struct filestat *fst, 133 struct vnstat *vn, char *errbuf); 134static int procstat_get_vnode_info_sysctl(struct filestat *fst, 135 struct vnstat *vn, char *errbuf); 136static gid_t *procstat_getgroups_core(struct procstat_core *core, 137 unsigned int *count); 138static gid_t *procstat_getgroups_sysctl(pid_t pid, unsigned int *count); 139static int procstat_getpathname_core(struct procstat_core *core, 140 char *pathname, size_t maxlen); 141static int procstat_getpathname_sysctl(pid_t pid, char *pathname, 142 size_t maxlen); 143static int procstat_getrlimit_core(struct procstat_core *core, int which, 144 struct rlimit* rlimit); 145static int procstat_getrlimit_sysctl(pid_t pid, int which, 146 struct rlimit* rlimit); 147static int procstat_getumask_core(struct procstat_core *core, 148 unsigned short *maskp); 149static int procstat_getumask_sysctl(pid_t pid, unsigned short *maskp); 150static int vntype2psfsttype(int type); 151 152void 153procstat_close(struct procstat *procstat) 154{ 155 156 assert(procstat); 157 if (procstat->type == PROCSTAT_KVM) 158 kvm_close(procstat->kd); 159 else if (procstat->type == PROCSTAT_CORE) 160 procstat_core_close(procstat->core); 161 free(procstat); 162} 163 164struct procstat * 165procstat_open_sysctl(void) 166{ 167 struct procstat *procstat; 168 169 procstat = calloc(1, sizeof(*procstat)); 170 if (procstat == NULL) { 171 warn("malloc()"); 172 return (NULL); 173 } 174 procstat->type = PROCSTAT_SYSCTL; 175 return (procstat); 176} 177 178struct procstat * 179procstat_open_kvm(const char *nlistf, const char *memf) 180{ 181 struct procstat *procstat; 182 kvm_t *kd; 183 char buf[_POSIX2_LINE_MAX]; 184 185 procstat = calloc(1, sizeof(*procstat)); 186 if (procstat == NULL) { 187 warn("malloc()"); 188 return (NULL); 189 } 190 kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf); 191 if (kd == NULL) { 192 warnx("kvm_openfiles(): %s", buf); 193 free(procstat); 194 return (NULL); 195 } 196 procstat->type = PROCSTAT_KVM; 197 procstat->kd = kd; 198 return (procstat); 199} 200 201struct procstat * 202procstat_open_core(const char *filename) 203{ 204 struct procstat *procstat; 205 struct procstat_core *core; 206 207 procstat = calloc(1, sizeof(*procstat)); 208 if (procstat == NULL) { 209 warn("malloc()"); 210 return (NULL); 211 } 212 core = procstat_core_open(filename); 213 if (core == NULL) { 214 free(procstat); 215 return (NULL); 216 } 217 procstat->type = PROCSTAT_CORE; 218 procstat->core = core; 219 return (procstat); 220} 221 222struct kinfo_proc * 223procstat_getprocs(struct procstat *procstat, int what, int arg, 224 unsigned int *count) 225{ 226 struct kinfo_proc *p0, *p; 227 size_t len; 228 int name[4]; 229 int cnt; 230 int error; 231 232 assert(procstat); 233 assert(count); 234 p = NULL; 235 if (procstat->type == PROCSTAT_KVM) { 236 *count = 0; 237 p0 = kvm_getprocs(procstat->kd, what, arg, &cnt); 238 if (p0 == NULL || cnt <= 0) 239 return (NULL); 240 *count = cnt; 241 len = *count * sizeof(*p); 242 p = malloc(len); 243 if (p == NULL) { 244 warnx("malloc(%zu)", len); 245 goto fail; 246 } 247 bcopy(p0, p, len); 248 return (p); 249 } else if (procstat->type == PROCSTAT_SYSCTL) { 250 len = 0; 251 name[0] = CTL_KERN; 252 name[1] = KERN_PROC; 253 name[2] = what; 254 name[3] = arg; 255 error = sysctl(name, 4, NULL, &len, NULL, 0); 256 if (error < 0 && errno != EPERM) { 257 warn("sysctl(kern.proc)"); 258 goto fail; 259 } 260 if (len == 0) { 261 warnx("no processes?"); 262 goto fail; 263 } 264 p = malloc(len); 265 if (p == NULL) { 266 warnx("malloc(%zu)", len); 267 goto fail; 268 } 269 error = sysctl(name, 4, p, &len, NULL, 0); 270 if (error < 0 && errno != EPERM) { 271 warn("sysctl(kern.proc)"); 272 goto fail; 273 } 274 /* Perform simple consistency checks. */ 275 if ((len % sizeof(*p)) != 0 || p->ki_structsize != sizeof(*p)) { 276 warnx("kinfo_proc structure size mismatch (len = %zu)", len); 277 goto fail; 278 } 279 *count = len / sizeof(*p); 280 return (p); 281 } else if (procstat->type == PROCSTAT_CORE) { 282 p = procstat_core_get(procstat->core, PSC_TYPE_PROC, NULL, 283 &len); 284 if ((len % sizeof(*p)) != 0 || p->ki_structsize != sizeof(*p)) { 285 warnx("kinfo_proc structure size mismatch"); 286 goto fail; 287 } 288 *count = len / sizeof(*p); 289 return (p); 290 } else { 291 warnx("unknown access method: %d", procstat->type); 292 return (NULL); 293 } 294fail: 295 if (p) 296 free(p); 297 return (NULL); 298} 299 300void 301procstat_freeprocs(struct procstat *procstat __unused, struct kinfo_proc *p) 302{ 303 304 if (p != NULL) 305 free(p); 306 p = NULL; 307} 308 309struct filestat_list * 310procstat_getfiles(struct procstat *procstat, struct kinfo_proc *kp, int mmapped) 311{ 312 313 switch(procstat->type) { 314 case PROCSTAT_KVM: 315 return (procstat_getfiles_kvm(procstat, kp, mmapped)); 316 case PROCSTAT_SYSCTL: 317 case PROCSTAT_CORE: 318 return (procstat_getfiles_sysctl(procstat, kp, mmapped)); 319 default: 320 warnx("unknown access method: %d", procstat->type); 321 return (NULL); 322 } 323} 324 325void 326procstat_freefiles(struct procstat *procstat, struct filestat_list *head) 327{ 328 struct filestat *fst, *tmp; 329 330 STAILQ_FOREACH_SAFE(fst, head, next, tmp) { 331 if (fst->fs_path != NULL) 332 free(fst->fs_path); 333 free(fst); 334 } 335 free(head); 336 if (procstat->vmentries != NULL) { 337 free(procstat->vmentries); 338 procstat->vmentries = NULL; 339 } 340 if (procstat->files != NULL) { 341 free(procstat->files); 342 procstat->files = NULL; 343 } 344} 345 346static struct filestat * 347filestat_new_entry(void *typedep, int type, int fd, int fflags, int uflags, 348 int refcount, off_t offset, char *path, cap_rights_t cap_rights) 349{ 350 struct filestat *entry; 351 352 entry = calloc(1, sizeof(*entry)); 353 if (entry == NULL) { 354 warn("malloc()"); 355 return (NULL); 356 } 357 entry->fs_typedep = typedep; 358 entry->fs_fflags = fflags; 359 entry->fs_uflags = uflags; 360 entry->fs_fd = fd; 361 entry->fs_type = type; 362 entry->fs_ref_count = refcount; 363 entry->fs_offset = offset; 364 entry->fs_path = path; 365 entry->fs_cap_rights = cap_rights; 366 return (entry); 367} 368 369static struct vnode * 370getctty(kvm_t *kd, struct kinfo_proc *kp) 371{ 372 struct pgrp pgrp; 373 struct proc proc; 374 struct session sess; 375 int error; 376 377 assert(kp); 378 error = kvm_read_all(kd, (unsigned long)kp->ki_paddr, &proc, 379 sizeof(proc)); 380 if (error == 0) { 381 warnx("can't read proc struct at %p for pid %d", 382 kp->ki_paddr, kp->ki_pid); 383 return (NULL); 384 } 385 if (proc.p_pgrp == NULL) 386 return (NULL); 387 error = kvm_read_all(kd, (unsigned long)proc.p_pgrp, &pgrp, 388 sizeof(pgrp)); 389 if (error == 0) { 390 warnx("can't read pgrp struct at %p for pid %d", 391 proc.p_pgrp, kp->ki_pid); 392 return (NULL); 393 } 394 error = kvm_read_all(kd, (unsigned long)pgrp.pg_session, &sess, 395 sizeof(sess)); 396 if (error == 0) { 397 warnx("can't read session struct at %p for pid %d", 398 pgrp.pg_session, kp->ki_pid); 399 return (NULL); 400 } 401 return (sess.s_ttyvp); 402} 403 404static struct filestat_list * 405procstat_getfiles_kvm(struct procstat *procstat, struct kinfo_proc *kp, int mmapped) 406{ 407 struct file file; 408 struct filedesc filed; 409 struct vm_map_entry vmentry; 410 struct vm_object object; 411 struct vmspace vmspace; 412 vm_map_entry_t entryp; 413 vm_map_t map; 414 vm_object_t objp; 415 struct vnode *vp; 416 struct file **ofiles; 417 struct filestat *entry; 418 struct filestat_list *head; 419 kvm_t *kd; 420 void *data; 421 int i, fflags; 422 int prot, type; 423 unsigned int nfiles; 424 425 assert(procstat); 426 kd = procstat->kd; 427 if (kd == NULL) 428 return (NULL); 429 if (kp->ki_fd == NULL) 430 return (NULL); 431 if (!kvm_read_all(kd, (unsigned long)kp->ki_fd, &filed, 432 sizeof(filed))) { 433 warnx("can't read filedesc at %p", (void *)kp->ki_fd); 434 return (NULL); 435 } 436 437 /* 438 * Allocate list head. 439 */ 440 head = malloc(sizeof(*head)); 441 if (head == NULL) 442 return (NULL); 443 STAILQ_INIT(head); 444 445 /* root directory vnode, if one. */ 446 if (filed.fd_rdir) { 447 entry = filestat_new_entry(filed.fd_rdir, PS_FST_TYPE_VNODE, -1, 448 PS_FST_FFLAG_READ, PS_FST_UFLAG_RDIR, 0, 0, NULL, 0); 449 if (entry != NULL) 450 STAILQ_INSERT_TAIL(head, entry, next); 451 } 452 /* current working directory vnode. */ 453 if (filed.fd_cdir) { 454 entry = filestat_new_entry(filed.fd_cdir, PS_FST_TYPE_VNODE, -1, 455 PS_FST_FFLAG_READ, PS_FST_UFLAG_CDIR, 0, 0, NULL, 0); 456 if (entry != NULL) 457 STAILQ_INSERT_TAIL(head, entry, next); 458 } 459 /* jail root, if any. */ 460 if (filed.fd_jdir) { 461 entry = filestat_new_entry(filed.fd_jdir, PS_FST_TYPE_VNODE, -1, 462 PS_FST_FFLAG_READ, PS_FST_UFLAG_JAIL, 0, 0, NULL, 0); 463 if (entry != NULL) 464 STAILQ_INSERT_TAIL(head, entry, next); 465 } 466 /* ktrace vnode, if one */ 467 if (kp->ki_tracep) { 468 entry = filestat_new_entry(kp->ki_tracep, PS_FST_TYPE_VNODE, -1, 469 PS_FST_FFLAG_READ | PS_FST_FFLAG_WRITE, 470 PS_FST_UFLAG_TRACE, 0, 0, NULL, 0); 471 if (entry != NULL) 472 STAILQ_INSERT_TAIL(head, entry, next); 473 } 474 /* text vnode, if one */ 475 if (kp->ki_textvp) { 476 entry = filestat_new_entry(kp->ki_textvp, PS_FST_TYPE_VNODE, -1, 477 PS_FST_FFLAG_READ, PS_FST_UFLAG_TEXT, 0, 0, NULL, 0); 478 if (entry != NULL) 479 STAILQ_INSERT_TAIL(head, entry, next); 480 } 481 /* Controlling terminal. */ 482 if ((vp = getctty(kd, kp)) != NULL) { 483 entry = filestat_new_entry(vp, PS_FST_TYPE_VNODE, -1, 484 PS_FST_FFLAG_READ | PS_FST_FFLAG_WRITE, 485 PS_FST_UFLAG_CTTY, 0, 0, NULL, 0); 486 if (entry != NULL) 487 STAILQ_INSERT_TAIL(head, entry, next); 488 } 489 490 nfiles = filed.fd_lastfile + 1; 491 ofiles = malloc(nfiles * sizeof(struct file *)); 492 if (ofiles == NULL) { 493 warn("malloc(%zu)", nfiles * sizeof(struct file *)); 494 goto do_mmapped; 495 } 496 if (!kvm_read_all(kd, (unsigned long)filed.fd_ofiles, ofiles, 497 nfiles * sizeof(struct file *))) { 498 warnx("cannot read file structures at %p", 499 (void *)filed.fd_ofiles); 500 free(ofiles); 501 goto do_mmapped; 502 } 503 for (i = 0; i <= filed.fd_lastfile; i++) { 504 if (ofiles[i] == NULL) 505 continue; 506 if (!kvm_read_all(kd, (unsigned long)ofiles[i], &file, 507 sizeof(struct file))) { 508 warnx("can't read file %d at %p", i, 509 (void *)ofiles[i]); 510 continue; 511 } 512 switch (file.f_type) { 513 case DTYPE_VNODE: 514 type = PS_FST_TYPE_VNODE; 515 data = file.f_vnode; 516 break; 517 case DTYPE_SOCKET: 518 type = PS_FST_TYPE_SOCKET; 519 data = file.f_data; 520 break; 521 case DTYPE_PIPE: 522 type = PS_FST_TYPE_PIPE; 523 data = file.f_data; 524 break; 525 case DTYPE_FIFO: 526 type = PS_FST_TYPE_FIFO; 527 data = file.f_vnode; 528 break; 529#ifdef DTYPE_PTS 530 case DTYPE_PTS: 531 type = PS_FST_TYPE_PTS; 532 data = file.f_data; 533 break; 534#endif 535 case DTYPE_SHM: 536 type = PS_FST_TYPE_SHM; 537 data = file.f_data; 538 break; 539 default: 540 continue; 541 } 542 /* XXXRW: No capability rights support for kvm yet. */ 543 entry = filestat_new_entry(data, type, i, 544 to_filestat_flags(file.f_flag), 0, 0, 0, NULL, 0); 545 if (entry != NULL) 546 STAILQ_INSERT_TAIL(head, entry, next); 547 } 548 free(ofiles); 549 550do_mmapped: 551 552 /* 553 * Process mmapped files if requested. 554 */ 555 if (mmapped) { 556 if (!kvm_read_all(kd, (unsigned long)kp->ki_vmspace, &vmspace, 557 sizeof(vmspace))) { 558 warnx("can't read vmspace at %p", 559 (void *)kp->ki_vmspace); 560 goto exit; 561 } 562 map = &vmspace.vm_map; 563 564 for (entryp = map->header.next; 565 entryp != &kp->ki_vmspace->vm_map.header; 566 entryp = vmentry.next) { 567 if (!kvm_read_all(kd, (unsigned long)entryp, &vmentry, 568 sizeof(vmentry))) { 569 warnx("can't read vm_map_entry at %p", 570 (void *)entryp); 571 continue; 572 } 573 if (vmentry.eflags & MAP_ENTRY_IS_SUB_MAP) 574 continue; 575 if ((objp = vmentry.object.vm_object) == NULL) 576 continue; 577 for (; objp; objp = object.backing_object) { 578 if (!kvm_read_all(kd, (unsigned long)objp, 579 &object, sizeof(object))) { 580 warnx("can't read vm_object at %p", 581 (void *)objp); 582 break; 583 } 584 } 585 586 /* We want only vnode objects. */ 587 if (object.type != OBJT_VNODE) 588 continue; 589 590 prot = vmentry.protection; 591 fflags = 0; 592 if (prot & VM_PROT_READ) 593 fflags = PS_FST_FFLAG_READ; 594 if ((vmentry.eflags & MAP_ENTRY_COW) == 0 && 595 prot & VM_PROT_WRITE) 596 fflags |= PS_FST_FFLAG_WRITE; 597 598 /* 599 * Create filestat entry. 600 */ 601 entry = filestat_new_entry(object.handle, 602 PS_FST_TYPE_VNODE, -1, fflags, 603 PS_FST_UFLAG_MMAP, 0, 0, NULL, 0); 604 if (entry != NULL) 605 STAILQ_INSERT_TAIL(head, entry, next); 606 } 607 } 608exit: 609 return (head); 610} 611 612/* 613 * kinfo types to filestat translation. 614 */ 615static int 616kinfo_type2fst(int kftype) 617{ 618 static struct { 619 int kf_type; 620 int fst_type; 621 } kftypes2fst[] = { 622 { KF_TYPE_CRYPTO, PS_FST_TYPE_CRYPTO }, 623 { KF_TYPE_FIFO, PS_FST_TYPE_FIFO }, 624 { KF_TYPE_KQUEUE, PS_FST_TYPE_KQUEUE }, 625 { KF_TYPE_MQUEUE, PS_FST_TYPE_MQUEUE }, 626 { KF_TYPE_NONE, PS_FST_TYPE_NONE }, 627 { KF_TYPE_PIPE, PS_FST_TYPE_PIPE }, 628 { KF_TYPE_PTS, PS_FST_TYPE_PTS }, 629 { KF_TYPE_SEM, PS_FST_TYPE_SEM }, 630 { KF_TYPE_SHM, PS_FST_TYPE_SHM }, 631 { KF_TYPE_SOCKET, PS_FST_TYPE_SOCKET }, 632 { KF_TYPE_VNODE, PS_FST_TYPE_VNODE }, 633 { KF_TYPE_UNKNOWN, PS_FST_TYPE_UNKNOWN } 634 }; 635#define NKFTYPES (sizeof(kftypes2fst) / sizeof(*kftypes2fst)) 636 unsigned int i; 637 638 for (i = 0; i < NKFTYPES; i++) 639 if (kftypes2fst[i].kf_type == kftype) 640 break; 641 if (i == NKFTYPES) 642 return (PS_FST_TYPE_UNKNOWN); 643 return (kftypes2fst[i].fst_type); 644} 645 646/* 647 * kinfo flags to filestat translation. 648 */ 649static int 650kinfo_fflags2fst(int kfflags) 651{ 652 static struct { 653 int kf_flag; 654 int fst_flag; 655 } kfflags2fst[] = { 656 { KF_FLAG_APPEND, PS_FST_FFLAG_APPEND }, 657 { KF_FLAG_ASYNC, PS_FST_FFLAG_ASYNC }, 658 { KF_FLAG_CREAT, PS_FST_FFLAG_CREAT }, 659 { KF_FLAG_DIRECT, PS_FST_FFLAG_DIRECT }, 660 { KF_FLAG_EXCL, PS_FST_FFLAG_EXCL }, 661 { KF_FLAG_EXEC, PS_FST_FFLAG_EXEC }, 662 { KF_FLAG_EXLOCK, PS_FST_FFLAG_EXLOCK }, 663 { KF_FLAG_FSYNC, PS_FST_FFLAG_SYNC }, 664 { KF_FLAG_HASLOCK, PS_FST_FFLAG_HASLOCK }, 665 { KF_FLAG_NOFOLLOW, PS_FST_FFLAG_NOFOLLOW }, 666 { KF_FLAG_NONBLOCK, PS_FST_FFLAG_NONBLOCK }, 667 { KF_FLAG_READ, PS_FST_FFLAG_READ }, 668 { KF_FLAG_SHLOCK, PS_FST_FFLAG_SHLOCK }, 669 { KF_FLAG_TRUNC, PS_FST_FFLAG_TRUNC }, 670 { KF_FLAG_WRITE, PS_FST_FFLAG_WRITE } 671 }; 672#define NKFFLAGS (sizeof(kfflags2fst) / sizeof(*kfflags2fst)) 673 unsigned int i; 674 int flags; 675 676 flags = 0; 677 for (i = 0; i < NKFFLAGS; i++) 678 if ((kfflags & kfflags2fst[i].kf_flag) != 0) 679 flags |= kfflags2fst[i].fst_flag; 680 return (flags); 681} 682 683static int 684kinfo_uflags2fst(int fd) 685{ 686 687 switch (fd) { 688 case KF_FD_TYPE_CTTY: 689 return (PS_FST_UFLAG_CTTY); 690 case KF_FD_TYPE_CWD: 691 return (PS_FST_UFLAG_CDIR); 692 case KF_FD_TYPE_JAIL: 693 return (PS_FST_UFLAG_JAIL); 694 case KF_FD_TYPE_TEXT: 695 return (PS_FST_UFLAG_TEXT); 696 case KF_FD_TYPE_TRACE: 697 return (PS_FST_UFLAG_TRACE); 698 case KF_FD_TYPE_ROOT: 699 return (PS_FST_UFLAG_RDIR); 700 } 701 return (0); 702} 703 704static struct kinfo_file * 705kinfo_getfile_core(struct procstat_core *core, int *cntp) 706{ 707 int cnt; 708 size_t len; 709 char *buf, *bp, *eb; 710 struct kinfo_file *kif, *kp, *kf; 711 712 buf = procstat_core_get(core, PSC_TYPE_FILES, NULL, &len); 713 if (buf == NULL) 714 return (NULL); 715 /* 716 * XXXMG: The code below is just copy&past from libutil. 717 * The code duplication can be avoided if libutil 718 * is extended to provide something like: 719 * struct kinfo_file *kinfo_getfile_from_buf(const char *buf, 720 * size_t len, int *cntp); 721 */ 722 723 /* Pass 1: count items */ 724 cnt = 0; 725 bp = buf; 726 eb = buf + len; 727 while (bp < eb) { 728 kf = (struct kinfo_file *)(uintptr_t)bp; 729 bp += kf->kf_structsize; 730 cnt++; 731 } 732 733 kif = calloc(cnt, sizeof(*kif)); 734 if (kif == NULL) { 735 free(buf); 736 return (NULL); 737 } 738 bp = buf; 739 eb = buf + len; 740 kp = kif; 741 /* Pass 2: unpack */ 742 while (bp < eb) { 743 kf = (struct kinfo_file *)(uintptr_t)bp; 744 /* Copy/expand into pre-zeroed buffer */ 745 memcpy(kp, kf, kf->kf_structsize); 746 /* Advance to next packed record */ 747 bp += kf->kf_structsize; 748 /* Set field size to fixed length, advance */ 749 kp->kf_structsize = sizeof(*kp); 750 kp++; 751 } 752 free(buf); 753 *cntp = cnt; 754 return (kif); /* Caller must free() return value */ 755} 756 757static struct filestat_list * 758procstat_getfiles_sysctl(struct procstat *procstat, struct kinfo_proc *kp, 759 int mmapped) 760{ 761 struct kinfo_file *kif, *files; 762 struct kinfo_vmentry *kve, *vmentries; 763 struct filestat_list *head; 764 struct filestat *entry; 765 char *path; 766 off_t offset; 767 int cnt, fd, fflags; 768 int i, type, uflags; 769 int refcount; 770 cap_rights_t cap_rights; 771 772 assert(kp); 773 if (kp->ki_fd == NULL) 774 return (NULL); 775 switch(procstat->type) { 776 case PROCSTAT_SYSCTL: 777 files = kinfo_getfile(kp->ki_pid, &cnt); 778 break; 779 case PROCSTAT_CORE: 780 files = kinfo_getfile_core(procstat->core, &cnt); 781 break; 782 default: 783 assert(!"invalid type"); 784 } 785 if (files == NULL && errno != EPERM) { 786 warn("kinfo_getfile()"); 787 return (NULL); 788 } 789 procstat->files = files; 790 791 /* 792 * Allocate list head. 793 */ 794 head = malloc(sizeof(*head)); 795 if (head == NULL) 796 return (NULL); 797 STAILQ_INIT(head); 798 for (i = 0; i < cnt; i++) { 799 kif = &files[i]; 800 801 type = kinfo_type2fst(kif->kf_type); 802 fd = kif->kf_fd >= 0 ? kif->kf_fd : -1; 803 fflags = kinfo_fflags2fst(kif->kf_flags); 804 uflags = kinfo_uflags2fst(kif->kf_fd); 805 refcount = kif->kf_ref_count; 806 offset = kif->kf_offset; 807 if (*kif->kf_path != '\0') 808 path = strdup(kif->kf_path); 809 else 810 path = NULL; 811 cap_rights = kif->kf_cap_rights; 812 813 /* 814 * Create filestat entry. 815 */ 816 entry = filestat_new_entry(kif, type, fd, fflags, uflags, 817 refcount, offset, path, cap_rights); 818 if (entry != NULL) 819 STAILQ_INSERT_TAIL(head, entry, next); 820 } 821 if (mmapped != 0) { 822 vmentries = procstat_getvmmap(procstat, kp, &cnt); 823 procstat->vmentries = vmentries; 824 if (vmentries == NULL || cnt == 0) 825 goto fail; 826 for (i = 0; i < cnt; i++) { 827 kve = &vmentries[i]; 828 if (kve->kve_type != KVME_TYPE_VNODE) 829 continue; 830 fflags = 0; 831 if (kve->kve_protection & KVME_PROT_READ) 832 fflags = PS_FST_FFLAG_READ; 833 if ((kve->kve_flags & KVME_FLAG_COW) == 0 && 834 kve->kve_protection & KVME_PROT_WRITE) 835 fflags |= PS_FST_FFLAG_WRITE; 836 offset = kve->kve_offset; 837 refcount = kve->kve_ref_count; 838 if (*kve->kve_path != '\0') 839 path = strdup(kve->kve_path); 840 else 841 path = NULL; 842 entry = filestat_new_entry(kve, PS_FST_TYPE_VNODE, -1, 843 fflags, PS_FST_UFLAG_MMAP, refcount, offset, path, 844 0); 845 if (entry != NULL) 846 STAILQ_INSERT_TAIL(head, entry, next); 847 } 848 } 849fail: 850 return (head); 851} 852 853int 854procstat_get_pipe_info(struct procstat *procstat, struct filestat *fst, 855 struct pipestat *ps, char *errbuf) 856{ 857 858 assert(ps); 859 if (procstat->type == PROCSTAT_KVM) { 860 return (procstat_get_pipe_info_kvm(procstat->kd, fst, ps, 861 errbuf)); 862 } else if (procstat->type == PROCSTAT_SYSCTL || 863 procstat->type == PROCSTAT_CORE) { 864 return (procstat_get_pipe_info_sysctl(fst, ps, errbuf)); 865 } else { 866 warnx("unknown access method: %d", procstat->type); 867 snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 868 return (1); 869 } 870} 871 872static int 873procstat_get_pipe_info_kvm(kvm_t *kd, struct filestat *fst, 874 struct pipestat *ps, char *errbuf) 875{ 876 struct pipe pi; 877 void *pipep; 878 879 assert(kd); 880 assert(ps); 881 assert(fst); 882 bzero(ps, sizeof(*ps)); 883 pipep = fst->fs_typedep; 884 if (pipep == NULL) 885 goto fail; 886 if (!kvm_read_all(kd, (unsigned long)pipep, &pi, sizeof(struct pipe))) { 887 warnx("can't read pipe at %p", (void *)pipep); 888 goto fail; 889 } 890 ps->addr = (uintptr_t)pipep; 891 ps->peer = (uintptr_t)pi.pipe_peer; 892 ps->buffer_cnt = pi.pipe_buffer.cnt; 893 return (0); 894 895fail: 896 snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 897 return (1); 898} 899 900static int 901procstat_get_pipe_info_sysctl(struct filestat *fst, struct pipestat *ps, 902 char *errbuf __unused) 903{ 904 struct kinfo_file *kif; 905 906 assert(ps); 907 assert(fst); 908 bzero(ps, sizeof(*ps)); 909 kif = fst->fs_typedep; 910 if (kif == NULL) 911 return (1); 912 ps->addr = kif->kf_un.kf_pipe.kf_pipe_addr; 913 ps->peer = kif->kf_un.kf_pipe.kf_pipe_peer; 914 ps->buffer_cnt = kif->kf_un.kf_pipe.kf_pipe_buffer_cnt; 915 return (0); 916} 917 918int 919procstat_get_pts_info(struct procstat *procstat, struct filestat *fst, 920 struct ptsstat *pts, char *errbuf) 921{ 922 923 assert(pts); 924 if (procstat->type == PROCSTAT_KVM) { 925 return (procstat_get_pts_info_kvm(procstat->kd, fst, pts, 926 errbuf)); 927 } else if (procstat->type == PROCSTAT_SYSCTL || 928 procstat->type == PROCSTAT_CORE) { 929 return (procstat_get_pts_info_sysctl(fst, pts, errbuf)); 930 } else { 931 warnx("unknown access method: %d", procstat->type); 932 snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 933 return (1); 934 } 935} 936 937static int 938procstat_get_pts_info_kvm(kvm_t *kd, struct filestat *fst, 939 struct ptsstat *pts, char *errbuf) 940{ 941 struct tty tty; 942 void *ttyp; 943 944 assert(kd); 945 assert(pts); 946 assert(fst); 947 bzero(pts, sizeof(*pts)); 948 ttyp = fst->fs_typedep; 949 if (ttyp == NULL) 950 goto fail; 951 if (!kvm_read_all(kd, (unsigned long)ttyp, &tty, sizeof(struct tty))) { 952 warnx("can't read tty at %p", (void *)ttyp); 953 goto fail; 954 } 955 pts->dev = dev2udev(kd, tty.t_dev); 956 (void)kdevtoname(kd, tty.t_dev, pts->devname); 957 return (0); 958 959fail: 960 snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 961 return (1); 962} 963 964static int 965procstat_get_pts_info_sysctl(struct filestat *fst, struct ptsstat *pts, 966 char *errbuf __unused) 967{ 968 struct kinfo_file *kif; 969 970 assert(pts); 971 assert(fst); 972 bzero(pts, sizeof(*pts)); 973 kif = fst->fs_typedep; 974 if (kif == NULL) 975 return (0); 976 pts->dev = kif->kf_un.kf_pts.kf_pts_dev; 977 strlcpy(pts->devname, kif->kf_path, sizeof(pts->devname)); 978 return (0); 979} 980 981int 982procstat_get_shm_info(struct procstat *procstat, struct filestat *fst, 983 struct shmstat *shm, char *errbuf) 984{ 985 986 assert(shm); 987 if (procstat->type == PROCSTAT_KVM) { 988 return (procstat_get_shm_info_kvm(procstat->kd, fst, shm, 989 errbuf)); 990 } else if (procstat->type == PROCSTAT_SYSCTL || 991 procstat->type == PROCSTAT_CORE) { 992 return (procstat_get_shm_info_sysctl(fst, shm, errbuf)); 993 } else { 994 warnx("unknown access method: %d", procstat->type); 995 snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 996 return (1); 997 } 998} 999 1000static int 1001procstat_get_shm_info_kvm(kvm_t *kd, struct filestat *fst, 1002 struct shmstat *shm, char *errbuf) 1003{ 1004 struct shmfd shmfd; 1005 void *shmfdp; 1006 char *path; 1007 int i; 1008 1009 assert(kd); 1010 assert(shm); 1011 assert(fst); 1012 bzero(shm, sizeof(*shm)); 1013 shmfdp = fst->fs_typedep; 1014 if (shmfdp == NULL) 1015 goto fail; 1016 if (!kvm_read_all(kd, (unsigned long)shmfdp, &shmfd, 1017 sizeof(struct shmfd))) { 1018 warnx("can't read shmfd at %p", (void *)shmfdp); 1019 goto fail; 1020 } 1021 shm->mode = S_IFREG | shmfd.shm_mode; 1022 shm->size = shmfd.shm_size; 1023 if (fst->fs_path == NULL && shmfd.shm_path != NULL) { 1024 path = malloc(MAXPATHLEN); 1025 for (i = 0; i < MAXPATHLEN - 1; i++) { 1026 if (!kvm_read_all(kd, (unsigned long)shmfd.shm_path + i, 1027 path + i, 1)) 1028 break; 1029 if (path[i] == '\0') 1030 break; 1031 } 1032 path[i] = '\0'; 1033 if (i == 0) 1034 free(path); 1035 else 1036 fst->fs_path = path; 1037 } 1038 return (0); 1039 1040fail: 1041 snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 1042 return (1); 1043} 1044 1045static int 1046procstat_get_shm_info_sysctl(struct filestat *fst, struct shmstat *shm, 1047 char *errbuf __unused) 1048{ 1049 struct kinfo_file *kif; 1050 1051 assert(shm); 1052 assert(fst); 1053 bzero(shm, sizeof(*shm)); 1054 kif = fst->fs_typedep; 1055 if (kif == NULL) 1056 return (0); 1057 shm->size = kif->kf_un.kf_file.kf_file_size; 1058 shm->mode = kif->kf_un.kf_file.kf_file_mode; 1059 return (0); 1060} 1061 1062int 1063procstat_get_vnode_info(struct procstat *procstat, struct filestat *fst, 1064 struct vnstat *vn, char *errbuf) 1065{ 1066 1067 assert(vn); 1068 if (procstat->type == PROCSTAT_KVM) { 1069 return (procstat_get_vnode_info_kvm(procstat->kd, fst, vn, 1070 errbuf)); 1071 } else if (procstat->type == PROCSTAT_SYSCTL || 1072 procstat->type == PROCSTAT_CORE) { 1073 return (procstat_get_vnode_info_sysctl(fst, vn, errbuf)); 1074 } else { 1075 warnx("unknown access method: %d", procstat->type); 1076 snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 1077 return (1); 1078 } 1079} 1080 1081static int 1082procstat_get_vnode_info_kvm(kvm_t *kd, struct filestat *fst, 1083 struct vnstat *vn, char *errbuf) 1084{ 1085 /* Filesystem specific handlers. */ 1086 #define FSTYPE(fst) {#fst, fst##_filestat} 1087 struct { 1088 const char *tag; 1089 int (*handler)(kvm_t *kd, struct vnode *vp, 1090 struct vnstat *vn); 1091 } fstypes[] = { 1092 FSTYPE(devfs), 1093 FSTYPE(isofs), 1094 FSTYPE(msdosfs), 1095 FSTYPE(nfs), 1096 FSTYPE(udf), 1097 FSTYPE(ufs), 1098#ifdef LIBPROCSTAT_ZFS 1099 FSTYPE(zfs), 1100#endif 1101 }; 1102#define NTYPES (sizeof(fstypes) / sizeof(*fstypes)) 1103 struct vnode vnode; 1104 char tagstr[12]; 1105 void *vp; 1106 int error, found; 1107 unsigned int i; 1108 1109 assert(kd); 1110 assert(vn); 1111 assert(fst); 1112 vp = fst->fs_typedep; 1113 if (vp == NULL) 1114 goto fail; 1115 error = kvm_read_all(kd, (unsigned long)vp, &vnode, sizeof(vnode)); 1116 if (error == 0) { 1117 warnx("can't read vnode at %p", (void *)vp); 1118 goto fail; 1119 } 1120 bzero(vn, sizeof(*vn)); 1121 vn->vn_type = vntype2psfsttype(vnode.v_type); 1122 if (vnode.v_type == VNON || vnode.v_type == VBAD) 1123 return (0); 1124 error = kvm_read_all(kd, (unsigned long)vnode.v_tag, tagstr, 1125 sizeof(tagstr)); 1126 if (error == 0) { 1127 warnx("can't read v_tag at %p", (void *)vp); 1128 goto fail; 1129 } 1130 tagstr[sizeof(tagstr) - 1] = '\0'; 1131 1132 /* 1133 * Find appropriate handler. 1134 */ 1135 for (i = 0, found = 0; i < NTYPES; i++) 1136 if (!strcmp(fstypes[i].tag, tagstr)) { 1137 if (fstypes[i].handler(kd, &vnode, vn) != 0) { 1138 goto fail; 1139 } 1140 break; 1141 } 1142 if (i == NTYPES) { 1143 snprintf(errbuf, _POSIX2_LINE_MAX, "?(%s)", tagstr); 1144 return (1); 1145 } 1146 vn->vn_mntdir = getmnton(kd, vnode.v_mount); 1147 if ((vnode.v_type == VBLK || vnode.v_type == VCHR) && 1148 vnode.v_rdev != NULL){ 1149 vn->vn_dev = dev2udev(kd, vnode.v_rdev); 1150 (void)kdevtoname(kd, vnode.v_rdev, vn->vn_devname); 1151 } else { 1152 vn->vn_dev = -1; 1153 } 1154 return (0); 1155 1156fail: 1157 snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 1158 return (1); 1159} 1160 1161/* 1162 * kinfo vnode type to filestat translation. 1163 */ 1164static int 1165kinfo_vtype2fst(int kfvtype) 1166{ 1167 static struct { 1168 int kf_vtype; 1169 int fst_vtype; 1170 } kfvtypes2fst[] = { 1171 { KF_VTYPE_VBAD, PS_FST_VTYPE_VBAD }, 1172 { KF_VTYPE_VBLK, PS_FST_VTYPE_VBLK }, 1173 { KF_VTYPE_VCHR, PS_FST_VTYPE_VCHR }, 1174 { KF_VTYPE_VDIR, PS_FST_VTYPE_VDIR }, 1175 { KF_VTYPE_VFIFO, PS_FST_VTYPE_VFIFO }, 1176 { KF_VTYPE_VLNK, PS_FST_VTYPE_VLNK }, 1177 { KF_VTYPE_VNON, PS_FST_VTYPE_VNON }, 1178 { KF_VTYPE_VREG, PS_FST_VTYPE_VREG }, 1179 { KF_VTYPE_VSOCK, PS_FST_VTYPE_VSOCK } 1180 }; 1181#define NKFVTYPES (sizeof(kfvtypes2fst) / sizeof(*kfvtypes2fst)) 1182 unsigned int i; 1183 1184 for (i = 0; i < NKFVTYPES; i++) 1185 if (kfvtypes2fst[i].kf_vtype == kfvtype) 1186 break; 1187 if (i == NKFVTYPES) 1188 return (PS_FST_VTYPE_UNKNOWN); 1189 return (kfvtypes2fst[i].fst_vtype); 1190} 1191 1192static int 1193procstat_get_vnode_info_sysctl(struct filestat *fst, struct vnstat *vn, 1194 char *errbuf) 1195{ 1196 struct statfs stbuf; 1197 struct kinfo_file *kif; 1198 struct kinfo_vmentry *kve; 1199 uint64_t fileid; 1200 uint64_t size; 1201 char *name, *path; 1202 uint32_t fsid; 1203 uint16_t mode; 1204 uint32_t rdev; 1205 int vntype; 1206 int status; 1207 1208 assert(fst); 1209 assert(vn); 1210 bzero(vn, sizeof(*vn)); 1211 if (fst->fs_typedep == NULL) 1212 return (1); 1213 if (fst->fs_uflags & PS_FST_UFLAG_MMAP) { 1214 kve = fst->fs_typedep; 1215 fileid = kve->kve_vn_fileid; 1216 fsid = kve->kve_vn_fsid; 1217 mode = kve->kve_vn_mode; 1218 path = kve->kve_path; 1219 rdev = kve->kve_vn_rdev; 1220 size = kve->kve_vn_size; 1221 vntype = kinfo_vtype2fst(kve->kve_vn_type); 1222 status = kve->kve_status; 1223 } else { 1224 kif = fst->fs_typedep; 1225 fileid = kif->kf_un.kf_file.kf_file_fileid; 1226 fsid = kif->kf_un.kf_file.kf_file_fsid; 1227 mode = kif->kf_un.kf_file.kf_file_mode; 1228 path = kif->kf_path; 1229 rdev = kif->kf_un.kf_file.kf_file_rdev; 1230 size = kif->kf_un.kf_file.kf_file_size; 1231 vntype = kinfo_vtype2fst(kif->kf_vnode_type); 1232 status = kif->kf_status; 1233 } 1234 vn->vn_type = vntype; 1235 if (vntype == PS_FST_VTYPE_VNON || vntype == PS_FST_VTYPE_VBAD) 1236 return (0); 1237 if ((status & KF_ATTR_VALID) == 0) { 1238 snprintf(errbuf, _POSIX2_LINE_MAX, "? (no info available)"); 1239 return (1); 1240 } 1241 if (path && *path) { 1242 statfs(path, &stbuf); 1243 vn->vn_mntdir = strdup(stbuf.f_mntonname); 1244 } else 1245 vn->vn_mntdir = strdup("-"); 1246 vn->vn_dev = rdev; 1247 if (vntype == PS_FST_VTYPE_VBLK) { 1248 name = devname(rdev, S_IFBLK); 1249 if (name != NULL) 1250 strlcpy(vn->vn_devname, name, 1251 sizeof(vn->vn_devname)); 1252 } else if (vntype == PS_FST_VTYPE_VCHR) { 1253 name = devname(vn->vn_dev, S_IFCHR); 1254 if (name != NULL) 1255 strlcpy(vn->vn_devname, name, 1256 sizeof(vn->vn_devname)); 1257 } 1258 vn->vn_fsid = fsid; 1259 vn->vn_fileid = fileid; 1260 vn->vn_size = size; 1261 vn->vn_mode = mode; 1262 return (0); 1263} 1264 1265int 1266procstat_get_socket_info(struct procstat *procstat, struct filestat *fst, 1267 struct sockstat *sock, char *errbuf) 1268{ 1269 1270 assert(sock); 1271 if (procstat->type == PROCSTAT_KVM) { 1272 return (procstat_get_socket_info_kvm(procstat->kd, fst, sock, 1273 errbuf)); 1274 } else if (procstat->type == PROCSTAT_SYSCTL || 1275 procstat->type == PROCSTAT_CORE) { 1276 return (procstat_get_socket_info_sysctl(fst, sock, errbuf)); 1277 } else { 1278 warnx("unknown access method: %d", procstat->type); 1279 snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 1280 return (1); 1281 } 1282} 1283 1284static int 1285procstat_get_socket_info_kvm(kvm_t *kd, struct filestat *fst, 1286 struct sockstat *sock, char *errbuf) 1287{ 1288 struct domain dom; 1289 struct inpcb inpcb; 1290 struct protosw proto; 1291 struct socket s; 1292 struct unpcb unpcb; 1293 ssize_t len; 1294 void *so; 1295 1296 assert(kd); 1297 assert(sock); 1298 assert(fst); 1299 bzero(sock, sizeof(*sock)); 1300 so = fst->fs_typedep; 1301 if (so == NULL) 1302 goto fail; 1303 sock->so_addr = (uintptr_t)so; 1304 /* fill in socket */ 1305 if (!kvm_read_all(kd, (unsigned long)so, &s, 1306 sizeof(struct socket))) { 1307 warnx("can't read sock at %p", (void *)so); 1308 goto fail; 1309 } 1310 /* fill in protosw entry */ 1311 if (!kvm_read_all(kd, (unsigned long)s.so_proto, &proto, 1312 sizeof(struct protosw))) { 1313 warnx("can't read protosw at %p", (void *)s.so_proto); 1314 goto fail; 1315 } 1316 /* fill in domain */ 1317 if (!kvm_read_all(kd, (unsigned long)proto.pr_domain, &dom, 1318 sizeof(struct domain))) { 1319 warnx("can't read domain at %p", 1320 (void *)proto.pr_domain); 1321 goto fail; 1322 } 1323 if ((len = kvm_read(kd, (unsigned long)dom.dom_name, sock->dname, 1324 sizeof(sock->dname) - 1)) < 0) { 1325 warnx("can't read domain name at %p", (void *)dom.dom_name); 1326 sock->dname[0] = '\0'; 1327 } 1328 else 1329 sock->dname[len] = '\0'; 1330 1331 /* 1332 * Fill in known data. 1333 */ 1334 sock->type = s.so_type; 1335 sock->proto = proto.pr_protocol; 1336 sock->dom_family = dom.dom_family; 1337 sock->so_pcb = (uintptr_t)s.so_pcb; 1338 1339 /* 1340 * Protocol specific data. 1341 */ 1342 switch(dom.dom_family) { 1343 case AF_INET: 1344 case AF_INET6: 1345 if (proto.pr_protocol == IPPROTO_TCP) { 1346 if (s.so_pcb) { 1347 if (kvm_read(kd, (u_long)s.so_pcb, 1348 (char *)&inpcb, sizeof(struct inpcb)) 1349 != sizeof(struct inpcb)) { 1350 warnx("can't read inpcb at %p", 1351 (void *)s.so_pcb); 1352 } else 1353 sock->inp_ppcb = 1354 (uintptr_t)inpcb.inp_ppcb; 1355 } 1356 } 1357 break; 1358 case AF_UNIX: 1359 if (s.so_pcb) { 1360 if (kvm_read(kd, (u_long)s.so_pcb, (char *)&unpcb, 1361 sizeof(struct unpcb)) != sizeof(struct unpcb)){ 1362 warnx("can't read unpcb at %p", 1363 (void *)s.so_pcb); 1364 } else if (unpcb.unp_conn) { 1365 sock->so_rcv_sb_state = s.so_rcv.sb_state; 1366 sock->so_snd_sb_state = s.so_snd.sb_state; 1367 sock->unp_conn = (uintptr_t)unpcb.unp_conn; 1368 } 1369 } 1370 break; 1371 default: 1372 break; 1373 } 1374 return (0); 1375 1376fail: 1377 snprintf(errbuf, _POSIX2_LINE_MAX, "error"); 1378 return (1); 1379} 1380 1381static int 1382procstat_get_socket_info_sysctl(struct filestat *fst, struct sockstat *sock, 1383 char *errbuf __unused) 1384{ 1385 struct kinfo_file *kif; 1386 1387 assert(sock); 1388 assert(fst); 1389 bzero(sock, sizeof(*sock)); 1390 kif = fst->fs_typedep; 1391 if (kif == NULL) 1392 return (0); 1393 1394 /* 1395 * Fill in known data. 1396 */ 1397 sock->type = kif->kf_sock_type; 1398 sock->proto = kif->kf_sock_protocol; 1399 sock->dom_family = kif->kf_sock_domain; 1400 sock->so_pcb = kif->kf_un.kf_sock.kf_sock_pcb; 1401 strlcpy(sock->dname, kif->kf_path, sizeof(sock->dname)); 1402 bcopy(&kif->kf_sa_local, &sock->sa_local, kif->kf_sa_local.ss_len); 1403 bcopy(&kif->kf_sa_peer, &sock->sa_peer, kif->kf_sa_peer.ss_len); 1404 1405 /* 1406 * Protocol specific data. 1407 */ 1408 switch(sock->dom_family) { 1409 case AF_INET: 1410 case AF_INET6: 1411 if (sock->proto == IPPROTO_TCP) 1412 sock->inp_ppcb = kif->kf_un.kf_sock.kf_sock_inpcb; 1413 break; 1414 case AF_UNIX: 1415 if (kif->kf_un.kf_sock.kf_sock_unpconn != 0) { 1416 sock->so_rcv_sb_state = 1417 kif->kf_un.kf_sock.kf_sock_rcv_sb_state; 1418 sock->so_snd_sb_state = 1419 kif->kf_un.kf_sock.kf_sock_snd_sb_state; 1420 sock->unp_conn = 1421 kif->kf_un.kf_sock.kf_sock_unpconn; 1422 } 1423 break; 1424 default: 1425 break; 1426 } 1427 return (0); 1428} 1429 1430/* 1431 * Descriptor flags to filestat translation. 1432 */ 1433static int 1434to_filestat_flags(int flags) 1435{ 1436 static struct { 1437 int flag; 1438 int fst_flag; 1439 } fstflags[] = { 1440 { FREAD, PS_FST_FFLAG_READ }, 1441 { FWRITE, PS_FST_FFLAG_WRITE }, 1442 { O_APPEND, PS_FST_FFLAG_APPEND }, 1443 { O_ASYNC, PS_FST_FFLAG_ASYNC }, 1444 { O_CREAT, PS_FST_FFLAG_CREAT }, 1445 { O_DIRECT, PS_FST_FFLAG_DIRECT }, 1446 { O_EXCL, PS_FST_FFLAG_EXCL }, 1447 { O_EXEC, PS_FST_FFLAG_EXEC }, 1448 { O_EXLOCK, PS_FST_FFLAG_EXLOCK }, 1449 { O_NOFOLLOW, PS_FST_FFLAG_NOFOLLOW }, 1450 { O_NONBLOCK, PS_FST_FFLAG_NONBLOCK }, 1451 { O_SHLOCK, PS_FST_FFLAG_SHLOCK }, 1452 { O_SYNC, PS_FST_FFLAG_SYNC }, 1453 { O_TRUNC, PS_FST_FFLAG_TRUNC } 1454 }; 1455#define NFSTFLAGS (sizeof(fstflags) / sizeof(*fstflags)) 1456 int fst_flags; 1457 unsigned int i; 1458 1459 fst_flags = 0; 1460 for (i = 0; i < NFSTFLAGS; i++) 1461 if (flags & fstflags[i].flag) 1462 fst_flags |= fstflags[i].fst_flag; 1463 return (fst_flags); 1464} 1465 1466/* 1467 * Vnode type to filestate translation. 1468 */ 1469static int 1470vntype2psfsttype(int type) 1471{ 1472 static struct { 1473 int vtype; 1474 int fst_vtype; 1475 } vt2fst[] = { 1476 { VBAD, PS_FST_VTYPE_VBAD }, 1477 { VBLK, PS_FST_VTYPE_VBLK }, 1478 { VCHR, PS_FST_VTYPE_VCHR }, 1479 { VDIR, PS_FST_VTYPE_VDIR }, 1480 { VFIFO, PS_FST_VTYPE_VFIFO }, 1481 { VLNK, PS_FST_VTYPE_VLNK }, 1482 { VNON, PS_FST_VTYPE_VNON }, 1483 { VREG, PS_FST_VTYPE_VREG }, 1484 { VSOCK, PS_FST_VTYPE_VSOCK } 1485 }; 1486#define NVFTYPES (sizeof(vt2fst) / sizeof(*vt2fst)) 1487 unsigned int i, fst_type; 1488 1489 fst_type = PS_FST_VTYPE_UNKNOWN; 1490 for (i = 0; i < NVFTYPES; i++) { 1491 if (type == vt2fst[i].vtype) { 1492 fst_type = vt2fst[i].fst_vtype; 1493 break; 1494 } 1495 } 1496 return (fst_type); 1497} 1498 1499static char * 1500getmnton(kvm_t *kd, struct mount *m) 1501{ 1502 struct mount mnt; 1503 static struct mtab { 1504 struct mtab *next; 1505 struct mount *m; 1506 char mntonname[MNAMELEN + 1]; 1507 } *mhead = NULL; 1508 struct mtab *mt; 1509 1510 for (mt = mhead; mt != NULL; mt = mt->next) 1511 if (m == mt->m) 1512 return (mt->mntonname); 1513 if (!kvm_read_all(kd, (unsigned long)m, &mnt, sizeof(struct mount))) { 1514 warnx("can't read mount table at %p", (void *)m); 1515 return (NULL); 1516 } 1517 if ((mt = malloc(sizeof (struct mtab))) == NULL) 1518 err(1, NULL); 1519 mt->m = m; 1520 bcopy(&mnt.mnt_stat.f_mntonname[0], &mt->mntonname[0], MNAMELEN); 1521 mt->mntonname[MNAMELEN] = '\0'; 1522 mt->next = mhead; 1523 mhead = mt; 1524 return (mt->mntonname); 1525} 1526 1527static struct kinfo_vmentry * 1528kinfo_getvmmap_core(struct procstat_core *core, int *cntp) 1529{ 1530 int cnt; 1531 size_t len; 1532 char *buf, *bp, *eb; 1533 struct kinfo_vmentry *kiv, *kp, *kv; 1534 1535 buf = procstat_core_get(core, PSC_TYPE_VMMAP, NULL, &len); 1536 if (buf == NULL) 1537 return (NULL); 1538 1539 /* 1540 * XXXMG: The code below is just copy&past from libutil. 1541 * The code duplication can be avoided if libutil 1542 * is extended to provide something like: 1543 * struct kinfo_vmentry *kinfo_getvmmap_from_buf(const char *buf, 1544 * size_t len, int *cntp); 1545 */ 1546 1547 /* Pass 1: count items */ 1548 cnt = 0; 1549 bp = buf; 1550 eb = buf + len; 1551 while (bp < eb) { 1552 kv = (struct kinfo_vmentry *)(uintptr_t)bp; 1553 bp += kv->kve_structsize; 1554 cnt++; 1555 } 1556 1557 kiv = calloc(cnt, sizeof(*kiv)); 1558 if (kiv == NULL) { 1559 free(buf); 1560 return (NULL); 1561 } 1562 bp = buf; 1563 eb = buf + len; 1564 kp = kiv; 1565 /* Pass 2: unpack */ 1566 while (bp < eb) { 1567 kv = (struct kinfo_vmentry *)(uintptr_t)bp; 1568 /* Copy/expand into pre-zeroed buffer */ 1569 memcpy(kp, kv, kv->kve_structsize); 1570 /* Advance to next packed record */ 1571 bp += kv->kve_structsize; 1572 /* Set field size to fixed length, advance */ 1573 kp->kve_structsize = sizeof(*kp); 1574 kp++; 1575 } 1576 free(buf); 1577 *cntp = cnt; 1578 return (kiv); /* Caller must free() return value */ 1579} 1580 1581struct kinfo_vmentry * 1582procstat_getvmmap(struct procstat *procstat, struct kinfo_proc *kp, 1583 unsigned int *cntp) 1584{ 1585 switch(procstat->type) { 1586 case PROCSTAT_KVM: 1587 warnx("kvm method is not supported"); 1588 return (NULL); 1589 case PROCSTAT_SYSCTL: 1590 return (kinfo_getvmmap(kp->ki_pid, cntp)); 1591 case PROCSTAT_CORE: 1592 return (kinfo_getvmmap_core(procstat->core, cntp)); 1593 default: 1594 warnx("unknown access method: %d", procstat->type); 1595 return (NULL); 1596 } 1597} 1598 1599void 1600procstat_freevmmap(struct procstat *procstat __unused, 1601 struct kinfo_vmentry *vmmap) 1602{ 1603 1604 free(vmmap); 1605} 1606 1607static gid_t * 1608procstat_getgroups_sysctl(pid_t pid, unsigned int *cntp) 1609{ 1610 int mib[4]; 1611 size_t len; 1612 gid_t *groups; 1613 1614 mib[0] = CTL_KERN; 1615 mib[1] = KERN_PROC; 1616 mib[2] = KERN_PROC_GROUPS; 1617 mib[3] = pid; 1618 len = (sysconf(_SC_NGROUPS_MAX) + 1) * sizeof(gid_t); 1619 groups = malloc(len); 1620 if (groups == NULL) { 1621 warn("malloc(%zu)", len); 1622 return (NULL); 1623 } 1624 if (sysctl(mib, 4, groups, &len, NULL, 0) == -1) { 1625 warn("sysctl: kern.proc.groups: %d", pid); 1626 free(groups); 1627 return (NULL); 1628 } 1629 *cntp = len / sizeof(gid_t); 1630 return (groups); 1631} 1632 1633static gid_t * 1634procstat_getgroups_core(struct procstat_core *core, unsigned int *cntp) 1635{ 1636 size_t len; 1637 gid_t *groups; 1638 1639 groups = procstat_core_get(core, PSC_TYPE_GROUPS, NULL, &len); 1640 if (groups == NULL) 1641 return (NULL); 1642 *cntp = len / sizeof(gid_t); 1643 return (groups); 1644} 1645 1646gid_t * 1647procstat_getgroups(struct procstat *procstat, struct kinfo_proc *kp, 1648 unsigned int *cntp) 1649{ 1650 switch(procstat->type) { 1651 case PROCSTAT_KVM: 1652 warnx("kvm method is not supported"); 1653 return (NULL); 1654 case PROCSTAT_SYSCTL: 1655 return (procstat_getgroups_sysctl(kp->ki_pid, cntp)); 1656 case PROCSTAT_CORE: 1657 return (procstat_getgroups_core(procstat->core, cntp)); 1658 default: 1659 warnx("unknown access method: %d", procstat->type); 1660 return (NULL); 1661 } 1662} 1663 1664void 1665procstat_freegroups(struct procstat *procstat __unused, gid_t *groups) 1666{ 1667 1668 free(groups); 1669} 1670 1671static int 1672procstat_getumask_sysctl(pid_t pid, unsigned short *maskp) 1673{ 1674 int error; 1675 int mib[4]; 1676 size_t len; 1677 1678 mib[0] = CTL_KERN; 1679 mib[1] = KERN_PROC; 1680 mib[2] = KERN_PROC_UMASK; 1681 mib[3] = pid; 1682 len = sizeof(*maskp); 1683 error = sysctl(mib, 4, maskp, &len, NULL, 0); 1684 if (error != 0 && errno != ESRCH) 1685 warn("sysctl: kern.proc.umask: %d", pid); 1686 return (error); 1687} 1688 1689static int 1690procstat_getumask_core(struct procstat_core *core, unsigned short *maskp) 1691{ 1692 size_t len; 1693 unsigned short *buf; 1694 1695 buf = procstat_core_get(core, PSC_TYPE_UMASK, NULL, &len); 1696 if (buf == NULL) 1697 return (-1); 1698 if (len < sizeof(*maskp)) { 1699 free(buf); 1700 return (-1); 1701 } 1702 *maskp = *buf; 1703 free(buf); 1704 return (0); 1705} 1706 1707int 1708procstat_getumask(struct procstat *procstat, struct kinfo_proc *kp, 1709 unsigned short *maskp) 1710{ 1711 switch(procstat->type) { 1712 case PROCSTAT_KVM: 1713 warnx("kvm method is not supported"); 1714 return (-1); 1715 case PROCSTAT_SYSCTL: 1716 return (procstat_getumask_sysctl(kp->ki_pid, maskp)); 1717 case PROCSTAT_CORE: 1718 return (procstat_getumask_core(procstat->core, maskp)); 1719 default: 1720 warnx("unknown access method: %d", procstat->type); 1721 return (-1); 1722 } 1723} 1724 1725static int 1726procstat_getrlimit_sysctl(pid_t pid, int which, struct rlimit* rlimit) 1727{ 1728 int error, name[5]; 1729 size_t len; 1730 1731 name[0] = CTL_KERN; 1732 name[1] = KERN_PROC; 1733 name[2] = KERN_PROC_RLIMIT; 1734 name[3] = pid; 1735 name[4] = which; 1736 len = sizeof(struct rlimit); 1737 error = sysctl(name, 5, rlimit, &len, NULL, 0); 1738 if (error < 0 && errno != ESRCH) { 1739 warn("sysctl: kern.proc.rlimit: %d", pid); 1740 return (-1); 1741 } 1742 if (error < 0 || len != sizeof(struct rlimit)) 1743 return (-1); 1744 return (0); 1745} 1746 1747static int 1748procstat_getrlimit_core(struct procstat_core *core, int which, 1749 struct rlimit* rlimit) 1750{ 1751 size_t len; 1752 struct rlimit* rlimits; 1753 1754 if (which < 0 || which >= RLIM_NLIMITS) { 1755 errno = EINVAL; 1756 warn("getrlimit: which"); 1757 return (-1); 1758 } 1759 rlimits = procstat_core_get(core, PSC_TYPE_RLIMIT, NULL, &len); 1760 if (rlimits == NULL) 1761 return (-1); 1762 if (len < sizeof(struct rlimit) * RLIM_NLIMITS) { 1763 free(rlimits); 1764 return (-1); 1765 } 1766 *rlimit = rlimits[which]; 1767 return (0); 1768} 1769 1770int 1771procstat_getrlimit(struct procstat *procstat, struct kinfo_proc *kp, int which, 1772 struct rlimit* rlimit) 1773{ 1774 switch(procstat->type) { 1775 case PROCSTAT_KVM: 1776 warnx("kvm method is not supported"); 1777 return (-1); 1778 case PROCSTAT_SYSCTL: 1779 return (procstat_getrlimit_sysctl(kp->ki_pid, which, rlimit)); 1780 case PROCSTAT_CORE: 1781 return (procstat_getrlimit_core(procstat->core, which, rlimit)); 1782 default: 1783 warnx("unknown access method: %d", procstat->type); 1784 return (-1); 1785 } 1786} 1787 1788static int 1789procstat_getpathname_sysctl(pid_t pid, char *pathname, size_t maxlen) 1790{ 1791 int error, name[4]; 1792 size_t len; 1793 1794 name[0] = CTL_KERN; 1795 name[1] = KERN_PROC; 1796 name[2] = KERN_PROC_PATHNAME; 1797 name[3] = pid; 1798 len = maxlen; 1799 error = sysctl(name, 4, pathname, &len, NULL, 0); 1800 if (error != 0 && errno != ESRCH) 1801 warn("sysctl: kern.proc.pathname: %d", pid); 1802 if (len == 0) 1803 pathname[0] = '\0'; 1804 return (error); 1805} 1806 1807static int 1808procstat_getpathname_core(struct procstat_core *core, char *pathname, 1809 size_t maxlen) 1810{ 1811 struct kinfo_file *files; 1812 int cnt, i, result; 1813 1814 files = kinfo_getfile_core(core, &cnt); 1815 if (files == NULL) 1816 return (-1); 1817 result = -1; 1818 for (i = 0; i < cnt; i++) { 1819 if (files[i].kf_fd != KF_FD_TYPE_TEXT) 1820 continue; 1821 strncpy(pathname, files[i].kf_path, maxlen); 1822 result = 0; 1823 break; 1824 } 1825 free(files); 1826 return (result); 1827} 1828 1829int 1830procstat_getpathname(struct procstat *procstat, struct kinfo_proc *kp, 1831 char *pathname, size_t maxlen) 1832{ 1833 switch(procstat->type) { 1834 case PROCSTAT_KVM: 1835 warnx("kvm method is not supported"); 1836 return (-1); 1837 case PROCSTAT_SYSCTL: 1838 return (procstat_getpathname_sysctl(kp->ki_pid, pathname, 1839 maxlen)); 1840 case PROCSTAT_CORE: 1841 return (procstat_getpathname_core(procstat->core, pathname, 1842 maxlen)); 1843 default: 1844 warnx("unknown access method: %d", procstat->type); 1845 return (-1); 1846 } 1847} 1848 1849static int 1850procstat_getosrel_sysctl(pid_t pid, int *osrelp) 1851{ 1852 int error, name[4]; 1853 size_t len; 1854 1855 name[0] = CTL_KERN; 1856 name[1] = KERN_PROC; 1857 name[2] = KERN_PROC_OSREL; 1858 name[3] = pid; 1859 len = sizeof(*osrelp); 1860 error = sysctl(name, 4, osrelp, &len, NULL, 0); 1861 if (error != 0 && errno != ESRCH) 1862 warn("sysctl: kern.proc.osrel: %d", pid); 1863 return (error); 1864} 1865 1866static int 1867procstat_getosrel_core(struct procstat_core *core, int *osrelp) 1868{ 1869 size_t len; 1870 int *buf; 1871 1872 buf = procstat_core_get(core, PSC_TYPE_OSREL, NULL, &len); 1873 if (buf == NULL) 1874 return (-1); 1875 if (len < sizeof(*osrelp)) { 1876 free(buf); 1877 return (-1); 1878 } 1879 *osrelp = *buf; 1880 free(buf); 1881 return (0); 1882} 1883 1884int 1885procstat_getosrel(struct procstat *procstat, struct kinfo_proc *kp, int *osrelp) 1886{ 1887 switch(procstat->type) { 1888 case PROCSTAT_KVM: 1889 warnx("kvm method is not supported"); 1890 return (-1); 1891 case PROCSTAT_SYSCTL: 1892 return (procstat_getosrel_sysctl(kp->ki_pid, osrelp)); 1893 case PROCSTAT_CORE: 1894 return (procstat_getosrel_core(procstat->core, osrelp)); 1895 default: 1896 warnx("unknown access method: %d", procstat->type); 1897 return (-1); 1898 } 1899} 1900