Index: projects/libprocstat/usr.bin/fstat/fstat.c =================================================================== --- projects/libprocstat/usr.bin/fstat/fstat.c (revision 195721) +++ projects/libprocstat/usr.bin/fstat/fstat.c (revision 195722) @@ -1,575 +1,531 @@ /*- * Copyright (c) 2009 Stanislav Sedov * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include -#include -#include #include #include -#include #include #include -#include -#include -#include -#include #include -#include -#include #include -#define _WANT_FILE -#include -#include -#define _KERNEL -#include -#include -#include -#include -#include -#include -#undef _KERNEL -#include -#include -#include - #include #include #include -#include #include -#include -#include -#include #include #include #include -#include #include -#include #include -#include #include #include #include #include #include #include #include #include "functions.h" #include "libprocstat.h" int fsflg, /* show files on same filesystem as file(s) argument */ pflg, /* show files open by a particular pid */ uflg; /* show files open by a particular (effective) user */ int checkfile; /* true if restricting to particular files or filesystems */ int nflg; /* (numerical) display f.s. and rdev as dev_t */ int mflg; /* include memory-mapped files */ int vflg; /* be verbose */ typedef struct devs { struct devs *next; long fsid; long ino; const char *name; } DEVS; DEVS *devs; char *memf, *nlistf; -static void fstat1(int what, int arg); -static void dofiles(struct procstat *procstat, struct kinfo_proc *p); -void dofiles_kinfo(struct kinfo_proc *kp); -void dommap(struct kinfo_proc *kp); -void vtrans(struct vnode *vp, int i, int flag, const char *uname, const char *cmd, int pid); -char *getmnton(struct mount *m); -void pipetrans(struct pipe *pi, int i, int flag, const char *uname, const char *cmd, int pid); -void socktrans(struct socket *sock, int i, const char *uname, const char *cmd, int pid); -void ptstrans(struct tty *tp, int i, int flag, const char *uname, const char *cmd, int pid); -void getinetproto(int number); -int getfname(const char *filename); -void usage(void); -void vtrans_kinfo(struct kinfo_file *, int i, int flag, const char *uname, const char *cmd, int pid); -static void print_file_info(struct procstat *procstat, struct filestat *fst, const char *uname, const char *cmd, int pid); +static int getfname(const char *filename); +static void dofiles(struct procstat *procstat, struct kinfo_proc *p); +static void dommap(struct procstat *procstat, struct kinfo_proc *p); +static void print_access_flags(int flags); +static void print_file_info(struct procstat *procstat, + struct filestat *fst, const char *uname, const char *cmd, int pid); +static void print_pipe_info(struct procstat *procstat, + struct filestat *fst); +static void print_pts_info(struct procstat *procstat, + struct filestat *fst); +static void print_socket_info(struct procstat *procstat, + struct filestat *fst); +static void print_vnode_info(struct procstat *procstat, + struct filestat *fst); +static void usage(void) __dead2; -static void -print_socket_info(struct procstat *procstat, struct filestat *fst); -static void -print_pipe_info(struct procstat *procstat, struct filestat *fst); -static void -print_pts_info(struct procstat *procstat, struct filestat *fst); -static void -print_vnode_info(struct procstat *procstat, struct filestat *fst); -static void -print_access_flags(int flags); - int do_fstat(int argc, char **argv) { + struct kinfo_proc *p; struct passwd *passwd; + struct procstat *procstat; int arg, ch, what; + int cnt, i; arg = 0; what = KERN_PROC_PROC; nlistf = memf = NULL; while ((ch = getopt(argc, argv, "fmnp:u:vN:M:")) != -1) switch((char)ch) { case 'f': fsflg = 1; break; case 'M': memf = optarg; break; case 'N': nlistf = optarg; break; case 'm': mflg = 1; break; case 'n': nflg = 1; break; case 'p': if (pflg++) usage(); if (!isdigit(*optarg)) { warnx("-p requires a process id"); usage(); } what = KERN_PROC_PID; arg = atoi(optarg); break; case 'u': if (uflg++) usage(); if (!(passwd = getpwnam(optarg))) errx(1, "%s: unknown uid", optarg); what = KERN_PROC_UID; arg = passwd->pw_uid; break; case 'v': vflg = 1; break; case '?': default: usage(); } if (*(argv += optind)) { for (; *argv; ++argv) { if (getfname(*argv)) checkfile = 1; } if (!checkfile) /* file(s) specified, but none accessable */ exit(1); } if (fsflg && !checkfile) { /* -f with no files means use wd */ if (getfname(".") == 0) exit(1); checkfile = 1; } - fstat1(what, arg); - exit(0); -} - -static void -fstat1(int what, int arg) -{ - struct kinfo_proc *p; - struct procstat *procstat; - int cnt; - int i; - procstat = procstat_open(nlistf, memf); if (procstat == NULL) errx(1, "procstat_open()"); p = procstat_getprocs(procstat, what, arg, &cnt); if (p == NULL) errx(1, "procstat_getprocs()"); /* * Print header. */ if (nflg) printf("%s", "USER CMD PID FD DEV INUM MODE SZ|DV R/W"); else printf("%s", "USER CMD PID FD MOUNT INUM MODE SZ|DV R/W"); if (checkfile && fsflg == 0) printf(" NAME\n"); else putchar('\n'); /* * Go through the process list. */ for (i = 0; i < cnt; i++) { if (p[i].ki_stat == SZOMB) continue; dofiles(procstat, &p[i]); -/* if (mflg) dommap(procstat, &p[i]); -*/ } free(p); procstat_close(procstat); + return (0); } static void +dommap(struct procstat *procstat __unused, struct kinfo_proc *kp __unused) +{ + + fprintf(stderr, "Not implemented\n"); +} + +static void dofiles(struct procstat *procstat, struct kinfo_proc *kp) { struct filestat_list *head; const char *cmd; const char *uname; int pid; struct filestat *fst; uname = user_from_uid(kp->ki_uid, 0); pid = kp->ki_pid; cmd = kp->ki_comm; head = procstat_getfiles(procstat, kp); if (head == NULL) return; STAILQ_FOREACH(fst, head, next) print_file_info(procstat, fst, uname, cmd, pid); } static void print_file_info(struct procstat *procstat, struct filestat *fst, const char *uname, const char *cmd, int pid) { const char *filename; struct vnstat vn; int error; int fsmatch = 0; DEVS *d; filename = NULL; if (checkfile != 0) { if (fst->fs_type != PS_FST_TYPE_VNODE && fst->fs_type == PS_FST_TYPE_FIFO) return; error = procstat_get_vnode_info(procstat, fst, &vn, NULL); if (error != 0) return; for (d = devs; d != NULL; d = d->next) if (d->fsid == vn.vn_fsid) { fsmatch = 1; if (d->ino == vn.vn_fileid) { filename = d->name; break; } } if (fsmatch == 0 || (filename == NULL && fsflg == 0)) return; } /* * Print entry prefix. */ printf("%-8.8s %-10s %5d", uname, cmd, pid); switch(fst->fs_fd) { case PS_FST_FD_TEXT: printf(" text"); break; case PS_FST_FD_CDIR: printf(" wd"); break; case PS_FST_FD_RDIR: printf(" root"); break; case PS_FST_FD_TRACE: printf(" tr"); break; case PS_FST_FD_MMAP: printf(" mmap"); break; case PS_FST_FD_JAIL: printf(" jail"); break; default: printf(" %4d", fst->fs_fd); break; } /* * Print type-specific data. */ switch (fst->fs_type) { case PS_FST_TYPE_FIFO: case PS_FST_TYPE_VNODE: print_vnode_info(procstat, fst); break; case PS_FST_TYPE_SOCKET: print_socket_info(procstat, fst); break; case PS_FST_TYPE_PIPE: print_pipe_info(procstat, fst); break; case PS_FST_TYPE_PTS: print_pts_info(procstat, fst); break; default: if (vflg) fprintf(stderr, "unknown file type %d for file %d of pid %d\n", fst->fs_type, fst->fs_fd, pid); } if (filename && !fsflg) printf(" %s", filename); putchar('\n'); } static void print_socket_info(struct procstat *procstat, struct filestat *fst) { static const char *stypename[] = { "unused", /* 0 */ "stream", /* 1 */ "dgram", /* 2 */ "raw", /* 3 */ "rdm", /* 4 */ "seqpak" /* 5 */ }; #define STYPEMAX 5 struct sockstat sock; char errbuf[_POSIX2_LINE_MAX]; static int isopen; struct protoent *pe; int error; error = procstat_get_socket_info(procstat, fst, &sock, errbuf); if (error != 0) { printf("* error"); return; } if (sock.type > STYPEMAX) printf("* %s ?%d", sock.dname, sock.type); else printf("* %s %s", sock.dname, stypename[sock.type]); /* * protocol specific formatting * * Try to find interesting things to print. For tcp, the interesting * thing is the address of the tcpcb, for udp and others, just the * inpcb (socket pcb). For unix domain, its the address of the socket * pcb and the address of the connected pcb (if connected). Otherwise * just print the protocol number and address of the socket itself. * The idea is not to duplicate netstat, but to make available enough * information for further analysis. */ switch (sock.dom_family) { case AF_INET: case AF_INET6: if (!isopen) setprotoent(++isopen); if ((pe = getprotobynumber(sock.proto)) != NULL) printf(" %s", pe->p_name); else printf(" %d", sock.proto); if (sock.proto == IPPROTO_TCP ) { if (sock.inp_ppcb != 0) printf(" %lx", (u_long)sock.inp_ppcb); } else if (sock.so_pcb != 0) printf(" %lx", (u_long)sock.so_pcb); break; case AF_UNIX: /* print address of pcb and connected pcb */ if (sock.so_pcb != 0) { printf(" %lx", (u_long)sock.so_pcb); if (sock.unp_conn) { char shoconn[4], *cp; cp = shoconn; if (!(sock.so_rcv_sb_state & SBS_CANTRCVMORE)) *cp++ = '<'; *cp++ = '-'; if (!(sock.so_snd_sb_state & SBS_CANTSENDMORE)) *cp++ = '>'; *cp = '\0'; printf(" %s %lx", shoconn, (u_long)sock.unp_conn); } } break; default: /* print protocol number and socket address */ printf(" %d %lx", sock.proto, (u_long)sock.so_addr); } } static void print_pipe_info(struct procstat *procstat, struct filestat *fst) { - struct pipestat pipe; + struct pipestat ps; char errbuf[_POSIX2_LINE_MAX]; int error; - error = procstat_get_pipe_info(procstat, fst, &pipe, errbuf); + error = procstat_get_pipe_info(procstat, fst, &ps, errbuf); if (error != 0) { printf("* error"); return; } - printf("* pipe %8lx <-> %8lx", (u_long)pipe.addr, (u_long)pipe.peer); - printf(" %6zd", pipe.buffer_cnt); + printf("* pipe %8lx <-> %8lx", (u_long)ps.addr, (u_long)ps.peer); + printf(" %6zd", ps.buffer_cnt); print_access_flags(fst->fs_fflags); } static void print_pts_info(struct procstat *procstat, struct filestat *fst) { struct ptsstat pts; char errbuf[_POSIX2_LINE_MAX]; int error; error = procstat_get_pts_info(procstat, fst, &pts, errbuf); if (error != 0) { printf("* error"); return; } printf("* pseudo-terminal master "); if (nflg || !*pts.devname) { printf("%10d,%-2d", major(pts.dev), minor(pts.dev)); } else { printf("%10s", pts.devname); } print_access_flags(fst->fs_fflags); } static void print_vnode_info(struct procstat *procstat, struct filestat *fst) { struct vnstat vn; const char *badtype; char errbuf[_POSIX2_LINE_MAX]; char mode[15]; int error; badtype = NULL; error = procstat_get_vnode_info(procstat, fst, &vn, errbuf); if (error != 0) badtype = errbuf; else if (vn.vn_type == PS_FST_VTYPE_VBAD) badtype = "bad"; else if (vn.vn_type == PS_FST_VTYPE_VNON) badtype = "none"; if (badtype != NULL) { printf(" - - %10s -", badtype); return; } if (nflg) printf(" %2d,%-2d", major(vn.vn_fsid), minor(vn.vn_fsid)); else if (vn.mntdir != NULL) (void)printf(" %-8s", vn.mntdir); /* * Print access mode. */ if (nflg) (void)snprintf(mode, sizeof(mode), "%o", vn.vn_mode); else { strmode(vn.vn_mode, mode); } (void)printf(" %6ld %10s", vn.vn_fileid, mode); if (vn.vn_type == PS_FST_VTYPE_VBLK || vn.vn_type == PS_FST_VTYPE_VCHR) { if (nflg || !*vn.vn_devname) printf(" %2d,%-2d", major(vn.vn_dev), minor(vn.vn_dev)); else { printf(" %6s", vn.vn_devname); } } else printf(" %6lu", vn.vn_size); print_access_flags(fst->fs_fflags); } static void print_access_flags(int flags) { char rw[3]; rw[0] = '\0'; if (flags & PS_FST_FFLAG_READ) strcat(rw, "r"); if (flags & PS_FST_FFLAG_WRITE) strcat(rw, "w"); printf(" %2s", rw); } int getfname(const char *filename) { struct stat statbuf; DEVS *cur; if (stat(filename, &statbuf)) { warn("%s", filename); return (0); } if ((cur = malloc(sizeof(DEVS))) == NULL) err(1, NULL); cur->next = devs; devs = cur; cur->ino = statbuf.st_ino; cur->fsid = statbuf.st_dev; cur->name = filename; return (1); } -void +static void usage(void) { (void)fprintf(stderr, "usage: fstat [-fmnv] [-M core] [-N system] [-p pid] [-u user] [file ...]\n"); exit(1); } Index: projects/libprocstat/usr.bin/fstat/libprocstat.c =================================================================== --- projects/libprocstat/usr.bin/fstat/libprocstat.c (revision 195721) +++ projects/libprocstat/usr.bin/fstat/libprocstat.c (revision 195722) @@ -1,836 +1,836 @@ /*- * Copyright (c) 2009 Stanislav Sedov * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define _WANT_FILE #include #include #define _KERNEL #include #include #include #include #include #include #undef _KERNEL #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "libprocstat.h" #include "common_kvm.h" /* * Vnode-to-filestat types translation table. */ static struct { int vtype; int fst_vtype; } vt2fst[] = { { VNON, PS_FST_VTYPE_VNON }, { VREG, PS_FST_VTYPE_VREG }, { VDIR, PS_FST_VTYPE_VDIR }, { VBLK, PS_FST_VTYPE_VBLK }, { VCHR, PS_FST_VTYPE_VCHR }, { VLNK, PS_FST_VTYPE_VLNK }, { VSOCK, PS_FST_VTYPE_VSOCK }, { VFIFO, PS_FST_VTYPE_VFIFO }, { VBAD, PS_FST_VTYPE_VBAD } }; #define NVFTYPES (sizeof(vt2fst) / sizeof(*vt2fst)) /* * Descriptor-to-filestat flags translation table. */ static struct { int flag; int fst_flag; } fstflags[] = { { FREAD, PS_FST_FFLAG_READ }, { FWRITE, PS_FST_FFLAG_WRITE }, { O_NONBLOCK, PS_FST_FFLAG_NONBLOCK }, { O_APPEND, PS_FST_FFLAG_APPEND }, { O_SHLOCK, PS_FST_FFLAG_SHLOCK }, { O_EXLOCK, PS_FST_FFLAG_EXLOCK }, { O_ASYNC, PS_FST_FFLAG_ASYNC }, { O_SYNC, PS_FST_FFLAG_SYNC }, { O_NOFOLLOW, PS_FST_FFLAG_NOFOLLOW }, { O_CREAT, PS_FST_FFLAG_CREAT }, { O_TRUNC, PS_FST_FFLAG_TRUNC }, { O_EXCL, PS_FST_FFLAG_EXCL } }; #define NFSTFLAGS (sizeof(fstflags) / sizeof(*fstflags)) /* * Filesystem specific handlers. */ #define FSTYPE(fst) {#fst, fst##_filestat} struct { const char *tag; int (*handler)(kvm_t *kd, struct vnode *vp, struct vnstat *vn); } fstypes[] = { FSTYPE(ufs), FSTYPE(devfs), FSTYPE(nfs), FSTYPE(msdosfs), FSTYPE(isofs), #ifdef ZFS FSTYPE(zfs), #endif /* FSTYPE(ntfs), FSTYPE(nwfs), FSTYPE(smbfs), FSTYPE(udf), */ }; #define NTYPES (sizeof(fstypes) / sizeof(*fstypes)) #define PROCSTAT_KVM 1 #define PROCSTAT_SYSCTL 2 static char *getmnton(kvm_t *kd, struct mount *m); static struct filestat_list *procstat_getfiles_kvm(kvm_t *kd, struct kinfo_proc *kp); static struct filestat_list *procstat_getfiles_sysctl( struct kinfo_proc *kp); static int procstat_get_pipe_info_sysctl(struct filestat *fst, struct pipestat *pipe, char *errbuf); static int procstat_get_pipe_info_kvm(kvm_t *kd, struct filestat *fst, struct pipestat *pipe, char *errbuf); static int procstat_get_pts_info_sysctl(struct filestat *fst, struct ptsstat *pts, char *errbuf); static int procstat_get_pts_info_kvm(kvm_t *kd, struct filestat *fst, struct ptsstat *pts, char *errbuf); static int procstat_get_socket_info_sysctl(struct filestat *fst, struct sockstat *sock, char *errbuf); static int procstat_get_socket_info_kvm(kvm_t *kd, struct filestat *fst, struct sockstat *sock, char *errbuf); static int to_filestat_flags(int flags); static int procstat_get_vnode_info_kvm(kvm_t *kd, struct filestat *fst, struct vnstat *vn, char *errbuf); static int procstat_get_vnode_info_sysctl(struct filestat *fst, struct vnstat *vn, char *errbuf); static int vntype2psfsttype(int type); void procstat_close(struct procstat *procstat) { assert(procstat); if (procstat->type == PROCSTAT_KVM) kvm_close(procstat->kd); } struct procstat * procstat_open(const char *nlistf, const char *memf) { kvm_t *kd; char buf[_POSIX2_LINE_MAX]; struct procstat *procstat; procstat = calloc(1, sizeof(*procstat)); if (procstat == NULL) { warn("malloc()"); return (NULL); } if (memf != NULL) { kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf); if (kd == NULL) { warnx("kvm_openfiles(): %s", buf); free(procstat); return (NULL); } procstat->type = PROCSTAT_KVM; procstat->kd = kd; } else { procstat->type = PROCSTAT_SYSCTL; } return (procstat); } struct kinfo_proc * procstat_getprocs(struct procstat *procstat, int what, int arg, unsigned int *count) { struct kinfo_proc *p0, *p; size_t len; int name[4]; int error; assert(procstat); assert(count); p = NULL; if (procstat->type == PROCSTAT_KVM) { p0 = kvm_getprocs(procstat->kd, what, arg, count); if (p0 == NULL || count == 0) return (NULL); len = *count * sizeof(*p); p = malloc(len); if (p == NULL) { warnx("malloc(%zd)", len); goto fail; } bcopy(p0, p, len); return (p); } else if (procstat->type == PROCSTAT_SYSCTL) { len = 0; name[0] = CTL_KERN; name[1] = KERN_PROC; name[2] = what; name[3] = arg; error = sysctl(name, 4, NULL, &len, NULL, 0); if (error < 0) { warn("sysctl(kern.proc)"); goto fail; } if (len == 0) { warnx("no processes?"); goto fail; } p = malloc(len); if (p == NULL) { warnx("malloc(%zd)", len); goto fail; } error = sysctl(name, 4, p, &len, NULL, 0); if (error < 0) { warn("sysctl(kern.proc)"); goto fail; } /* Perform simple consistency checks. */ if ((len % sizeof(*p)) != 0 || p->ki_structsize != sizeof(*p)) { warnx("kinfo_proc structure size mismatch"); goto fail; } *count = len / sizeof(*p); return (p); } else { warnx("unknown access method"); return (NULL); } fail: if (p) free(p); return (NULL); } struct filestat_list * procstat_getfiles(struct procstat *procstat, struct kinfo_proc *kp) { if (procstat->type == PROCSTAT_SYSCTL) return (procstat_getfiles_sysctl(kp)); else if (procstat->type == PROCSTAT_KVM) return (procstat_getfiles_kvm(procstat->kd, kp)); else return (NULL); } static struct filestat * filestat_new_entry(struct vnode *vp, int type, int fd, int fflags) { struct filestat *entry; entry = calloc(1, sizeof(*entry)); if (entry == NULL) { warn("malloc()"); return (NULL); } entry->fs_typedep = vp; entry->fs_fflags = fflags; entry->fs_fd = fd; entry->fs_type = type; return (entry); } static struct filestat_list * procstat_getfiles_kvm(kvm_t *kd, struct kinfo_proc *kp) { int i; struct file file; struct filedesc filed; unsigned int nfiles; struct file **ofiles; struct filestat *entry; struct filestat_list *head; int type; void *data; assert(kd); if (kp->ki_fd == NULL) return (NULL); if (!kvm_read_all(kd, (unsigned long)kp->ki_fd, &filed, sizeof(filed))) { warnx("can't read filedesc at %p\n", (void *)kp->ki_fd); return (NULL); } /* * Allocate list head. */ head = malloc(sizeof(*head)); if (head == NULL) return (NULL); STAILQ_INIT(head); /* root directory vnode, if one. */ if (filed.fd_rdir) { entry = filestat_new_entry(filed.fd_rdir, PS_FST_TYPE_VNODE, PS_FST_FD_RDIR, PS_FST_FFLAG_READ); if (entry != NULL) STAILQ_INSERT_TAIL(head, entry, next); } /* current working directory vnode. */ if (filed.fd_cdir) { entry = filestat_new_entry(filed.fd_cdir, PS_FST_TYPE_VNODE, PS_FST_FD_CDIR, PS_FST_FFLAG_READ); if (entry != NULL) STAILQ_INSERT_TAIL(head, entry, next); } /* jail root, if any. */ if (filed.fd_jdir) { entry = filestat_new_entry(filed.fd_jdir, PS_FST_TYPE_VNODE, PS_FST_FD_JAIL, PS_FST_FFLAG_READ); if (entry != NULL) STAILQ_INSERT_TAIL(head, entry, next); } /* ktrace vnode, if one */ if (kp->ki_tracep) { entry = filestat_new_entry(kp->ki_tracep, PS_FST_TYPE_VNODE, PS_FST_FD_TRACE, PS_FST_FFLAG_READ | PS_FST_FFLAG_WRITE); if (entry != NULL) STAILQ_INSERT_TAIL(head, entry, next); } /* text vnode, if one */ if (kp->ki_textvp) { entry = filestat_new_entry(kp->ki_textvp, PS_FST_TYPE_VNODE, PS_FST_FD_TEXT, PS_FST_FFLAG_READ); if (entry != NULL) STAILQ_INSERT_TAIL(head, entry, next); } nfiles = filed.fd_lastfile + 1; ofiles = malloc(nfiles * sizeof(struct file *)); if (ofiles == NULL) { warn("malloc(%zd)", nfiles * sizeof(struct file *)); goto exit; } if (!kvm_read_all(kd, (unsigned long)filed.fd_ofiles, ofiles, nfiles * sizeof(struct file *))) { warn("cannot read file structures at %p\n", (void *)filed.fd_ofiles); free(ofiles); goto exit; } for (i = 0; i <= filed.fd_lastfile; i++) { if (ofiles[i] == NULL) continue; if (!kvm_read_all(kd, (unsigned long)ofiles[i], &file, sizeof(struct file))) { warn("can't read file %d at %p\n", i, (void *)ofiles[i]); continue; } switch (file.f_type) { case DTYPE_VNODE: type = PS_FST_TYPE_VNODE; data = file.f_vnode; break; case DTYPE_SOCKET: type = PS_FST_TYPE_SOCKET; data = file.f_data; break; case DTYPE_PIPE: type = PS_FST_TYPE_PIPE; data = file.f_data; break; case DTYPE_FIFO: type = PS_FST_TYPE_FIFO; data = file.f_vnode; break; #ifdef DTYPE_PTS case DTYPE_PTS: type = PS_FST_TYPE_PTS; data = file.f_data; break; #endif default: warnx("unknown file type %d for file %d\n", file.f_type, i); continue; } entry = filestat_new_entry(data, type, i, to_filestat_flags(file.f_flag)); if (entry != NULL) STAILQ_INSERT_TAIL(head, entry, next); } free(ofiles); exit: return (head); } static struct filestat_list * procstat_getfiles_sysctl(struct kinfo_proc *kp __unused) { return (NULL); } int procstat_get_pipe_info(struct procstat *procstat, struct filestat *fst, - struct pipestat *pipe, char *errbuf) + struct pipestat *ps, char *errbuf) { - assert(pipe); + assert(ps); if (procstat->type == PROCSTAT_KVM) { - return (procstat_get_pipe_info_kvm(procstat->kd, fst, pipe, + return (procstat_get_pipe_info_kvm(procstat->kd, fst, ps, errbuf)); } else if (procstat->type == PROCSTAT_SYSCTL) { - return (procstat_get_pipe_info_sysctl(fst, pipe, errbuf)); + return (procstat_get_pipe_info_sysctl(fst, ps, errbuf)); } else { warnx("unknow access method: %d", procstat->type); snprintf(errbuf, _POSIX2_LINE_MAX, "error"); return (1); } } static int procstat_get_pipe_info_kvm(kvm_t *kd, struct filestat *fst, - struct pipestat *pipe, char *errbuf) + struct pipestat *ps, char *errbuf) { struct pipe pi; void *pipep; assert(kd); - assert(pipe); + assert(ps); assert(fst); - bzero(pipe, sizeof(*pipe)); + bzero(ps, sizeof(*ps)); pipep = fst->fs_typedep; if (pipep == NULL) goto fail; if (!kvm_read_all(kd, (unsigned long)pipep, &pi, sizeof(struct pipe))) { warnx("can't read pipe at %p", (void *)pipep); goto fail; } - pipe->addr = (caddr_t)pipep; - pipe->peer = (caddr_t)pi.pipe_peer; - pipe->buffer_cnt = pi.pipe_buffer.cnt; + ps->addr = (caddr_t)pipep; + ps->peer = (caddr_t)pi.pipe_peer; + ps->buffer_cnt = pi.pipe_buffer.cnt; return (0); fail: snprintf(errbuf, _POSIX2_LINE_MAX, "error"); return (1); } static int -procstat_get_pipe_info_sysctl(struct filestat *fst, struct pipestat *pipe, +procstat_get_pipe_info_sysctl(struct filestat *fst, struct pipestat *ps, char *errbuf) { warnx("not implemented: %s:%d", __FUNCTION__, __LINE__); snprintf(errbuf, _POSIX2_LINE_MAX, "error"); return (1); } int procstat_get_pts_info(struct procstat *procstat, struct filestat *fst, struct ptsstat *pts, char *errbuf) { assert(pts); if (procstat->type == PROCSTAT_KVM) { return (procstat_get_pts_info_kvm(procstat->kd, fst, pts, errbuf)); } else if (procstat->type == PROCSTAT_SYSCTL) { return (procstat_get_pts_info_sysctl(fst, pts, errbuf)); } else { warnx("unknow access method: %d", procstat->type); snprintf(errbuf, _POSIX2_LINE_MAX, "error"); return (1); } } static int procstat_get_pts_info_kvm(kvm_t *kd, struct filestat *fst, struct ptsstat *pts, char *errbuf) { struct tty tty; void *ttyp; assert(kd); assert(pts); assert(fst); bzero(pts, sizeof(*pts)); ttyp = fst->fs_typedep; if (ttyp == NULL) goto fail; if (!kvm_read_all(kd, (unsigned long)ttyp, &tty, sizeof(struct tty))) { warnx("can't read tty at %p", (void *)ttyp); goto fail; } pts->dev = dev2udev(kd, tty.t_dev); (void)kdevtoname(kd, tty.t_dev, pts->devname); return (0); fail: snprintf(errbuf, _POSIX2_LINE_MAX, "error"); return (1); } static int procstat_get_pts_info_sysctl(struct filestat *fst, struct ptsstat *pts, char *errbuf) { warnx("not implemented: %s:%d", __FUNCTION__, __LINE__); snprintf(errbuf, _POSIX2_LINE_MAX, "error"); return (1); } int procstat_get_vnode_info(struct procstat *procstat, struct filestat *fst, struct vnstat *vn, char *errbuf) { assert(vn); if (procstat->type == PROCSTAT_KVM) { return (procstat_get_vnode_info_kvm(procstat->kd, fst, vn, errbuf)); } else if (procstat->type == PROCSTAT_SYSCTL) { return (procstat_get_vnode_info_sysctl(fst, vn, errbuf)); } else { warnx("unknow access method: %d", procstat->type); snprintf(errbuf, _POSIX2_LINE_MAX, "error"); return (1); } } static int procstat_get_vnode_info_kvm(kvm_t *kd, struct filestat *fst, struct vnstat *vn, char *errbuf) { char tagstr[12]; int error; int found; struct vnode vnode; void *vp; unsigned int i; assert(kd); assert(vn); assert(fst); vp = fst->fs_typedep; if (vp == NULL) goto fail; error = kvm_read_all(kd, (unsigned long)vp, &vnode, sizeof(vnode)); if (error == 0) { warnx("can't read vnode at %p\n", (void *)vp); goto fail; } bzero(vn, sizeof(*vn)); vn->vn_type = vntype2psfsttype(vnode.v_type); if (vnode.v_type == VNON || vnode.v_type == VBAD) return (0); error = kvm_read_all(kd, (unsigned long)vnode.v_tag, tagstr, sizeof(tagstr)); if (error == 0) { warnx("can't read v_tag at %p\n", (void *)vp); goto fail; } tagstr[sizeof(tagstr) - 1] = '\0'; /* * Find appropriate handler. */ for (i = 0, found = 0; i < NTYPES; i++) if (!strcmp(fstypes[i].tag, tagstr)) { if (fstypes[i].handler(kd, &vnode, vn) != 0) { goto fail; } break; } if (i == NTYPES) { snprintf(errbuf, _POSIX2_LINE_MAX, "?(%s)", tagstr); return (1); } vn->mntdir = getmnton(kd, vnode.v_mount); if ((vnode.v_type == VBLK || vnode.v_type == VCHR) && vnode.v_rdev != NULL){ vn->vn_dev = dev2udev(kd, vnode.v_rdev); (void)kdevtoname(kd, vnode.v_rdev, vn->vn_devname); } else { vn->vn_dev = -1; } return (0); fail: snprintf(errbuf, _POSIX2_LINE_MAX, "error"); return (1); } static int procstat_get_vnode_info_sysctl(struct filestat *fst, struct vnstat *vn, char *errbuf) { warnx("not implemented: %s:%d", __FUNCTION__, __LINE__); snprintf(errbuf, _POSIX2_LINE_MAX, "error"); return (1); } int procstat_get_socket_info(struct procstat *procstat, struct filestat *fst, struct sockstat *sock, char *errbuf) { assert(sock); if (procstat->type == PROCSTAT_KVM) { return (procstat_get_socket_info_kvm(procstat->kd, fst, sock, errbuf)); } else if (procstat->type == PROCSTAT_SYSCTL) { return (procstat_get_socket_info_sysctl(fst, sock, errbuf)); } else { warnx("unknow access method: %d", procstat->type); snprintf(errbuf, _POSIX2_LINE_MAX, "error"); return (1); } } static int procstat_get_socket_info_kvm(kvm_t *kd, struct filestat *fst, struct sockstat *sock, char *errbuf) { struct socket s; struct protosw proto; struct domain dom; struct inpcb inpcb; struct unpcb unpcb; ssize_t len; void *so; assert(kd); assert(sock); assert(fst); bzero(sock, sizeof(*sock)); so = fst->fs_typedep; if (so == NULL) goto fail; sock->so_addr = (caddr_t)so; /* fill in socket */ if (!kvm_read_all(kd, (unsigned long)so, &s, sizeof(struct socket))) { warnx("can't read sock at %p", (void *)so); goto fail; } /* fill in protosw entry */ if (!kvm_read_all(kd, (unsigned long)s.so_proto, &proto, sizeof(struct protosw))) { warnx("can't read protosw at %p", (void *)s.so_proto); goto fail; } /* fill in domain */ if (!kvm_read_all(kd, (unsigned long)proto.pr_domain, &dom, sizeof(struct domain))) { warnx("can't read domain at %p", (void *)proto.pr_domain); goto fail; } if ((len = kvm_read(kd, (unsigned long)dom.dom_name, sock->dname, sizeof(sock->dname) - 1)) < 0) { warnx("can't read domain name at %p", (void *)dom.dom_name); sock->dname[0] = '\0'; } else sock->dname[len] = '\0'; /* * Fill in known data. */ sock->type = s.so_type; sock->proto = proto.pr_protocol; sock->dom_family = dom.dom_family; sock->so_pcb = s.so_pcb; /* * Protocol specific data. */ switch(dom.dom_family) { case AF_INET: case AF_INET6: if (proto.pr_protocol == IPPROTO_TCP ) { if (s.so_pcb) { if (kvm_read(kd, (u_long)s.so_pcb, (char *)&inpcb, sizeof(struct inpcb)) != sizeof(struct inpcb)) { warnx("can't read inpcb at %p\n", (void *)s.so_pcb); } else sock->inp_ppcb = (caddr_t)inpcb.inp_ppcb; } } break; case AF_UNIX: if (s.so_pcb) { if (kvm_read(kd, (u_long)s.so_pcb, (char *)&unpcb, sizeof(struct unpcb)) != sizeof(struct unpcb)){ warnx("can't read unpcb at %p\n", (void *)s.so_pcb); } else if (unpcb.unp_conn) { sock->so_rcv_sb_state = s.so_rcv.sb_state; sock->so_snd_sb_state = s.so_snd.sb_state; sock->unp_conn = (caddr_t)unpcb.unp_conn; } } break; default: break; } return (0); fail: snprintf(errbuf, _POSIX2_LINE_MAX, "error"); return (1); } static int procstat_get_socket_info_sysctl(struct filestat *fst, struct sockstat *sock, char *errbuf) { warnx("not implemented: %s:%d", __FUNCTION__, __LINE__); snprintf(errbuf, _POSIX2_LINE_MAX, "error"); return (1); } static int to_filestat_flags(int flags) { int fst_flags; unsigned int i; fst_flags = 0; for (i = 0; i < NFSTFLAGS; i++) if (flags & fstflags[i].flag) fst_flags |= fstflags[i].fst_flag; return (fst_flags); } static int vntype2psfsttype(int type) { unsigned int i, fst_type; fst_type = PS_FST_VTYPE_UNKNOWN; for (i = 0; i < NVFTYPES; i++) { if (type == vt2fst[i].vtype) { fst_type = vt2fst[i].fst_vtype; break; } } return (fst_type); } static char * getmnton(kvm_t *kd, struct mount *m) { static struct mount mnt; static struct mtab { struct mtab *next; struct mount *m; char mntonname[MNAMELEN + 1]; } *mhead = NULL; struct mtab *mt; for (mt = mhead; mt != NULL; mt = mt->next) if (m == mt->m) return (mt->mntonname); if (!kvm_read_all(kd, (unsigned long)m, &mnt, sizeof(struct mount))) { warnx("can't read mount table at %p", (void *)m); return (NULL); } if ((mt = malloc(sizeof (struct mtab))) == NULL) err(1, NULL); mt->m = m; bcopy(&mnt.mnt_stat.f_mntonname[0], &mt->mntonname[0], MNAMELEN); mnt.mnt_stat.f_mntonname[MNAMELEN] = '\0'; mt->next = mhead; mhead = mt; return (mt->mntonname); }