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