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