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