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