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