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