svn commit: r194888 - projects/libprocstat/usr.bin/fstat
Ulf Lilleengen
lulf at FreeBSD.org
Wed Jun 24 19:09:36 UTC 2009
Author: lulf
Date: Wed Jun 24 19:09:36 2009
New Revision: 194888
URL: http://svn.freebsd.org/changeset/base/194888
Log:
- Update to the correct version of the sysctl version of fstat.
Modified:
projects/libprocstat/usr.bin/fstat/fstat_vnode.c
Modified: projects/libprocstat/usr.bin/fstat/fstat_vnode.c
==============================================================================
--- projects/libprocstat/usr.bin/fstat/fstat_vnode.c Wed Jun 24 19:05:39 2009 (r194887)
+++ projects/libprocstat/usr.bin/fstat/fstat_vnode.c Wed Jun 24 19:09:36 2009 (r194888)
@@ -1,6 +1,6 @@
/*-
- * Copyright (c) 2009 Ulf Lilleengen
- * All rights reserved.
+ * 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
@@ -10,11 +10,18 @@
* 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * 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)
@@ -22,52 +29,886 @@
* 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.
- *
- * $FreeBSD$
*/
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1988, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)fstat.c 8.3 (Berkeley) 5/2/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/stat.h>
+#include <sys/vnode.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/domain.h>
+#include <sys/protosw.h>
+#include <sys/un.h>
+#include <sys/unpcb.h>
#include <sys/sysctl.h>
+#include <sys/tty.h>
+#include <sys/filedesc.h>
+#include <sys/queue.h>
+#define _WANT_FILE
+#include <sys/file.h>
+#include <sys/conf.h>
+#define _KERNEL
+#include <sys/pipe.h>
+#include <fs/devfs/devfs.h>
+#include <fs/devfs/devfs_int.h>
+#undef _KERNEL
+#include <sys/mount.h>
+#include <nfs/nfsproto.h>
+#include <nfs/rpcv2.h>
+#include <nfsclient/nfs.h>
+#include <nfsclient/nfsnode.h>
+
+
+#include <vm/vm.h>
+#include <vm/vm_map.h>
+#include <vm/vm_object.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/in_pcb.h>
+
+#include <ctype.h>
#include <err.h>
+#include <fcntl.h>
+#include <kvm.h>
+#include <limits.h>
+#include <nlist.h>
+#include <paths.h>
+#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <libutil.h>
+
+#include "fstat.h"
+
+#define TEXT -1
+#define CDIR -2
+#define RDIR -3
+#define TRACE -4
+#define MMAP -5
+#define JDIR -6
-struct filestat {
- long fsid;
- long fileid;
- mode_t mode;
- u_long size;
- dev_t rdev;
+DEVS *devs;
+
+#ifdef notdef
+struct nlist nl[] = {
+ { "" },
};
+#endif
+
+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 vflg; /* display errors in locating kernel data objects etc... */
+int mflg; /* include memory-mapped files */
+
+
+struct file **ofiles; /* buffer of pointers to file structures */
+int maxfiles;
+#define ALLOC_OFILES(d) \
+ if ((d) > maxfiles) { \
+ free(ofiles); \
+ ofiles = malloc((d) * sizeof(struct file *)); \
+ if (ofiles == NULL) { \
+ err(1, NULL); \
+ } \
+ maxfiles = (d); \
+ }
+
+char *memf, *nlistf;
+kvm_t *kd;
+
+static void fstat_kvm(int, int);
+static void fstat_sysctl(int, int);
+void dofiles_kinfo(struct kinfo_proc *kp);
+static int kinfo_proc_compare(const void *, const void *);
+static void kinfo_proc_sort(struct kinfo_proc *, int);
+void dommap(struct kinfo_proc *kp);
+void vtrans_kinfo(struct kinfo_file *, int i, int flag);
+char *getmnton(struct mount *m);
+void pipetrans(struct pipe *pi, int i, int flag);
+void socktrans(struct socket *sock, int i);
+void ptstrans(struct tty *tp, int i, int flag);
+void getinetproto(int number);
+int getfname(const char *filename);
+void usage(void);
+char *kdevtoname(struct cdev *dev);
+int gettextvp(struct kinfo_proc *, struct kinfo_file *);
int
main(int argc, char **argv)
{
- struct filestat *fs_buf;
- struct filestat *fsp;
- size_t size, numentries, i;
-
- if (sysctlbyname("kern.fileinfo", NULL, &size, NULL, 0) == -1) {
- fprintf(stderr, "error getting sysctl\n");
- return (0);
- }
- fs_buf = malloc(size);
- if (fs_buf == NULL) {
- printf("OOPS\n");
- return (-1);
- }
- printf("Data size: %d\n", size);
- numentries = size / sizeof(struct filestat);
- printf("Data entries: %d\n", numentries);
- if (sysctlbyname("kern.fileinfo", fs_buf, &size, NULL, 0) == -1) {
- fprintf(stderr, "error getting sysctl\n");
- return (0);
- }
- fsp = fs_buf;
- for (i = 0; i < numentries; i++) {
- printf("FSID: %ld fileid %ld Size: %lu\n", fsp->fsid, fsp->fileid, fsp->size);
+ struct passwd *passwd;
+ int arg, ch, what;
+
+ 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;
+ }
+
+ if (memf != NULL)
+ fstat_kvm(what, arg);
+ else
+ fstat_sysctl(what, arg);
+ exit(0);
+}
+
+static void
+print_header(void)
+{
+
+ 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');
+}
+
+static void
+fstat_kvm(int what, int arg)
+{
+ struct kinfo_proc *p, *plast;
+ char buf[_POSIX2_LINE_MAX];
+ int cnt;
+
+ ALLOC_OFILES(256); /* reserve space for file pointers */
+
+ /*
+ * Discard setgid privileges if not the running kernel so that bad
+ * guys can't print interesting stuff from kernel memory.
+ */
+ if (nlistf != NULL || memf != NULL)
+ setgid(getgid());
+
+ if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf)) == NULL)
+ errx(1, "%s", buf);
+ setgid(getgid());
+#ifdef notdef
+ if (kvm_nlist(kd, nl) != 0)
+ errx(1, "no namelist: %s", kvm_geterr(kd));
+#endif
+ if ((p = kvm_getprocs(kd, what, arg, &cnt)) == NULL)
+ errx(1, "%s", kvm_geterr(kd));
+ print_header();
+ for (plast = &p[cnt]; p < plast; ++p) {
+ if (p->ki_stat == SZOMB)
+ continue;
+ //dofiles(p);
+ if (mflg)
+ dommap(p);
+ }
+}
+
+/*
+ * Sort processes first by pid and then tid.
+ */
+static int
+kinfo_proc_compare(const void *a, const void *b)
+{
+ int i;
+
+ i = ((const struct kinfo_proc *)b)->ki_pid -
+ ((const struct kinfo_proc *)a)->ki_pid;
+ if (i != 0)
+ return (i);
+ i = ((const struct kinfo_proc *)b)->ki_tid -
+ ((const struct kinfo_proc *)a)->ki_tid;
+ return (i);
+}
+
+static void
+kinfo_proc_sort(struct kinfo_proc *kipp, int count)
+{
+
+ qsort(kipp, count, sizeof(*kipp), kinfo_proc_compare);
+}
+
+static void
+fstat_sysctl(int what, int arg)
+{
+ struct kinfo_proc *kipp;
+ int name[4];
+ size_t len;
+ unsigned int i;
+
+ name[0] = CTL_KERN;
+ name[1] = KERN_PROC;
+ name[2] = what;
+ name[3] = arg;
+
+ len = 0;
+ if (sysctl(name, 4, NULL, &len, NULL, 0) < 0)
+ err(-1, "sysctl: kern.proc");
+ kipp = malloc(len);
+ if (kipp == NULL)
+ err(-1, "malloc");
+
+ if (sysctl(name, 4, kipp, &len, NULL, 0) < 0) {
+ free(kipp);
+ err(-1, "sysctl: kern.proc");
+ }
+ if (len % sizeof(*kipp) != 0)
+ err(-1, "kinfo_proc mismatch");
+ if (kipp->ki_structsize != sizeof(*kipp))
+ err(-1, "kinfo_proc structure mismatch");
+ kinfo_proc_sort(kipp, len / sizeof(*kipp));
+ print_header();
+ for (i = 0; i < len / sizeof(*kipp); i++) {
+ dofiles_kinfo(&kipp[i]);
+ if (mflg)
+ dommap(&kipp[i]);
+ }
+ free(kipp);
+}
+
+const char *Uname, *Comm;
+int Pid;
+
+#define PREFIX(i) printf("%-8.8s %-10s %5d", Uname, Comm, Pid); \
+ switch(i) { \
+ case TEXT: \
+ printf(" text"); \
+ break; \
+ case CDIR: \
+ printf(" wd"); \
+ break; \
+ case RDIR: \
+ printf(" root"); \
+ break; \
+ case TRACE: \
+ printf(" tr"); \
+ break; \
+ case MMAP: \
+ printf(" mmap"); \
+ break; \
+ case JDIR: \
+ printf(" jail"); \
+ break; \
+ default: \
+ printf(" %4d", i); \
+ break; \
+ }
+
+void
+dommap(struct kinfo_proc *kp)
+{
+ vm_map_t map;
+ struct vmspace vmspace;
+ struct vm_map_entry entry;
+ vm_map_entry_t entryp;
+ struct vm_object object;
+ vm_object_t objp;
+ int prot, fflags;
+
+ if (!KVM_READ(kp->ki_vmspace, &vmspace, sizeof(vmspace))) {
+ dprintf(stderr,
+ "can't read vmspace at %p for pid %d\n",
+ (void *)kp->ki_vmspace, Pid);
+ return;
+ }
+ map = &vmspace.vm_map;
+
+ for (entryp = map->header.next;
+ entryp != &kp->ki_vmspace->vm_map.header; entryp = entry.next) {
+ if (!KVM_READ(entryp, &entry, sizeof(entry))) {
+ dprintf(stderr,
+ "can't read vm_map_entry at %p for pid %d\n",
+ (void *)entryp, Pid);
+ return;
+ }
+
+ if (entry.eflags & MAP_ENTRY_IS_SUB_MAP)
+ continue;
+
+ if ((objp = entry.object.vm_object) == NULL)
+ continue;
+
+ for (; objp; objp = object.backing_object) {
+ if (!KVM_READ(objp, &object, sizeof(object))) {
+ dprintf(stderr,
+ "can't read vm_object at %p for pid %d\n",
+ (void *)objp, Pid);
+ return;
+ }
+ }
+
+ prot = entry.protection;
+ fflags = (prot & VM_PROT_READ ? FREAD : 0) |
+ (prot & VM_PROT_WRITE ? FWRITE : 0);
+
+ switch (object.type) {
+ case OBJT_VNODE:
+ //vtrans((struct vnode *)object.handle, MMAP, fflags);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+/*
+ * print open files attributed to this process using kinfo
+ */
+void
+dofiles_kinfo(struct kinfo_proc *kp)
+{
+ struct kinfo_file *kif, *freep;
+ struct kinfo_file kifb;
+ int i, cnt, fd_type, flags;
+
+ Uname = user_from_uid(kp->ki_uid, 0);
+ Pid = kp->ki_pid;
+ Comm = kp->ki_comm;
+
+ if (kp->ki_fd == NULL)
+ return;
+
+#if 0
+ /*
+ * ktrace vnode, if one
+ */
+ if (kp->ki_tracep)
+ vtrans_kin(kp->ki_tracep, TRACE, FREAD|FWRITE);
+ /*
+ * text vnode, if one
+ */
+ vtrans(kp->ki_textvp, TEXT, FREAD);
+ /* Text vnode. */
+ if (kp->ki_textvp) {
+ if (gettextvp(kp, &kifb) == 0)
+ vtrans_kinfo(&kifb, TEXT, FREAD);
+ }
+#endif
+
+ /*
+ * open files
+ */
+ freep = kinfo_getfile(kp->ki_pid, &cnt);
+ if (freep == NULL)
+ err(1, "kinfo_getfile");
+
+ for (i = 0; i < cnt; i++) {
+ kif = &freep[i];
+ switch (kif->kf_type) {
+ case KF_TYPE_VNODE:
+ if (kif->kf_fd == KF_FD_TYPE_CWD) {
+ fd_type = CDIR;
+ flags = FREAD;
+ } else if (kif->kf_fd == KF_FD_TYPE_ROOT) {
+ fd_type = RDIR;
+ flags = FREAD;
+ } else if (kif->kf_fd == KF_FD_TYPE_JAIL) {
+ fd_type = JDIR;
+ flags = FREAD;
+ } else {
+ fd_type = i;
+ flags = kif->kf_flags;
+ }
+ /* Only do this if the attributes are valid. */
+ if (kif->kf_status & KF_ATTR_VALID)
+ vtrans_kinfo(kif, fd_type, flags);
+ break;
+#if 0
+ case KF_TYPE_PIPE:
+ if (checkfile == 0)
+ pipetrans_kinfo(kif, i, kif->kf_flags);
+ break;
+ else if (file.f_type == DTYPE_SOCKET) {
+ if (checkfile == 0)
+ socktrans(file.f_data, i);
+ }
+#ifdef DTYPE_PIPE
+ else if (file.f_type == DTYPE_PIPE) {
+ if (checkfile == 0)
+ pipetrans(file.f_data, i, file.f_flag);
+ }
+#endif
+#ifdef DTYPE_FIFO
+ else if (file.f_type == DTYPE_FIFO) {
+ if (checkfile == 0)
+ vtrans(file.f_vnode, i, file.f_flag);
+ }
+#endif
+#ifdef DTYPE_PTS
+ else if (file.f_type == DTYPE_PTS) {
+ if (checkfile == 0)
+ ptstrans(file.f_data, i, file.f_flag);
+ }
+#endif
+ else {
+ dprintf(stderr,
+ "unknown file type %d for file %d of pid %d\n",
+ file.f_type, i, Pid);
+ }
+#endif
+ }
+ }
+ free(freep);
+}
+
+char *
+kdevtoname(struct cdev *dev)
+{
+ struct cdev si;
+
+ if (!KVM_READ(dev, &si, sizeof si))
+ return (NULL);
+ return (strdup(si.__si_namebuf));
+}
+
+void
+vtrans_kinfo(struct kinfo_file *kif, int i, int flag)
+{
+ struct filestat fst;
+ char rw[3], mode[15];
+ const char *badtype, *filename;
+ struct statfs stbuf;
+
+ filename = badtype = NULL;
+ fst.fsid = fst.fileid = fst.mode = fst.size = fst.rdev = 0;
+ bzero(&stbuf, sizeof(struct statfs));
+ switch (kif->kf_vnode_type) {
+ case VNON:
+ badtype = "none";
+ break;
+ case VBAD:
+ badtype = "bad";
+ break;
+ default:
+ fst.fsid = kif->kf_file_fsid;
+ fst.fileid = kif->kf_file_fileid;
+ fst.mode = kif->kf_file_mode;
+ fst.size = kif->kf_file_size;
+ fst.rdev = kif->kf_file_rdev;
+ break;
+ }
+ if (checkfile) {
+ int fsmatch = 0;
+ DEVS *d;
+
+ if (badtype)
+ return;
+ for (d = devs; d != NULL; d = d->next)
+ if (d->fsid == fst.fsid) {
+ fsmatch = 1;
+ if (d->ino == fst.fileid) {
+ filename = d->name;
+ break;
+ }
+ }
+ if (fsmatch == 0 || (filename == NULL && fsflg == 0))
+ return;
+ }
+ PREFIX(i);
+ if (badtype) {
+ (void)printf(" - - %10s -\n", badtype);
+ return;
+ }
+ if (nflg)
+ (void)printf(" %2d,%-2d", major(fst.fsid), minor(fst.fsid));
+ else {
+ if (strlen(kif->kf_path) > 0)
+ statfs(kif->kf_path, &stbuf);
+ (void)printf(" %-8s", stbuf.f_mntonname);
+ }
+ if (nflg)
+ (void)sprintf(mode, "%o", fst.mode);
+ else {
+ strmode(fst.mode, mode);
+ }
+ (void)printf(" %6ld %10s", fst.fileid, mode);
+ switch (kif->kf_vnode_type) {
+ case KF_VTYPE_VBLK: {
+ char *name;
+ name = devname(fst.rdev, S_IFBLK);
+ if (nflg || !name)
+ printf(" %2d,%-2d", major(fst.rdev), minor(fst.rdev));
+ else {
+ printf(" %6s", name);
+ }
+ break;
+ }
+ case KF_VTYPE_VCHR: {
+ char *name;
+ name = devname(fst.rdev, S_IFCHR);
+ if (nflg || !name)
+ printf(" %2d,%-2d", major(fst.rdev), minor(fst.rdev));
+ else {
+ printf(" %6s", name);
+ }
+ break;
+ }
+ default:
+ printf(" %6lu", fst.size);
+ }
+ rw[0] = '\0';
+ if (flag & FREAD)
+ strcat(rw, "r");
+ if (flag & FWRITE)
+ strcat(rw, "w");
+ printf(" %2s", rw);
+ if (filename && !fsflg)
+ printf(" %s", filename);
+ putchar('\n');
+}
+
+void
+pipetrans(struct pipe *pi, int i, int flag)
+{
+ struct pipe pip;
+ char rw[3];
- fsp++;
+ PREFIX(i);
+
+ /* fill in socket */
+ if (!KVM_READ(pi, &pip, sizeof(struct pipe))) {
+ dprintf(stderr, "can't read pipe at %p\n", (void *)pi);
+ goto bad;
}
+
+ printf("* pipe %8lx <-> %8lx", (u_long)pi, (u_long)pip.pipe_peer);
+ printf(" %6d", (int)pip.pipe_buffer.cnt);
+ rw[0] = '\0';
+ if (flag & FREAD)
+ strcat(rw, "r");
+ if (flag & FWRITE)
+ strcat(rw, "w");
+ printf(" %2s", rw);
+ putchar('\n');
+ return;
+
+bad:
+ printf("* error\n");
+}
+
+void
+socktrans(struct socket *sock, int i)
+{
+ static const char *stypename[] = {
+ "unused", /* 0 */
+ "stream", /* 1 */
+ "dgram", /* 2 */
+ "raw", /* 3 */
+ "rdm", /* 4 */
+ "seqpak" /* 5 */
+ };
+#define STYPEMAX 5
+ struct socket so;
+ struct protosw proto;
+ struct domain dom;
+ struct inpcb inpcb;
+ struct unpcb unpcb;
+ int len;
+ char dname[32];
+
+ PREFIX(i);
+
+ /* fill in socket */
+ if (!KVM_READ(sock, &so, sizeof(struct socket))) {
+ dprintf(stderr, "can't read sock at %p\n", (void *)sock);
+ goto bad;
+ }
+
+ /* fill in protosw entry */
+ if (!KVM_READ(so.so_proto, &proto, sizeof(struct protosw))) {
+ dprintf(stderr, "can't read protosw at %p",
+ (void *)so.so_proto);
+ goto bad;
+ }
+
+ /* fill in domain */
+ if (!KVM_READ(proto.pr_domain, &dom, sizeof(struct domain))) {
+ dprintf(stderr, "can't read domain at %p\n",
+ (void *)proto.pr_domain);
+ goto bad;
+ }
+
+ if ((len = kvm_read(kd, (u_long)dom.dom_name, dname,
+ sizeof(dname) - 1)) < 0) {
+ dprintf(stderr, "can't read domain name at %p\n",
+ (void *)dom.dom_name);
+ dname[0] = '\0';
+ }
+ else
+ dname[len] = '\0';
+
+ if ((u_short)so.so_type > STYPEMAX)
+ printf("* %s ?%d", dname, so.so_type);
+ else
+ printf("* %s %s", dname, stypename[so.so_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(dom.dom_family) {
+ case AF_INET:
+ case AF_INET6:
+ getinetproto(proto.pr_protocol);
+ if (proto.pr_protocol == IPPROTO_TCP ) {
+ if (so.so_pcb) {
+ if (kvm_read(kd, (u_long)so.so_pcb,
+ (char *)&inpcb, sizeof(struct inpcb))
+ != sizeof(struct inpcb)) {
+ dprintf(stderr,
+ "can't read inpcb at %p\n",
+ (void *)so.so_pcb);
+ goto bad;
+ }
+ printf(" %lx", (u_long)inpcb.inp_ppcb);
+ }
+ }
+ else if (so.so_pcb)
+ printf(" %lx", (u_long)so.so_pcb);
+ break;
+ case AF_UNIX:
+ /* print address of pcb and connected pcb */
+ if (so.so_pcb) {
+ printf(" %lx", (u_long)so.so_pcb);
+ if (kvm_read(kd, (u_long)so.so_pcb, (char *)&unpcb,
+ sizeof(struct unpcb)) != sizeof(struct unpcb)){
+ dprintf(stderr, "can't read unpcb at %p\n",
+ (void *)so.so_pcb);
+ goto bad;
+ }
+ if (unpcb.unp_conn) {
+ char shoconn[4], *cp;
+
+ cp = shoconn;
+ if (!(so.so_rcv.sb_state & SBS_CANTRCVMORE))
+ *cp++ = '<';
+ *cp++ = '-';
+ if (!(so.so_snd.sb_state & SBS_CANTSENDMORE))
+ *cp++ = '>';
+ *cp = '\0';
+ printf(" %s %lx", shoconn,
+ (u_long)unpcb.unp_conn);
+ }
+ }
+ break;
+ default:
+ /* print protocol number and socket address */
+ printf(" %d %lx", proto.pr_protocol, (u_long)sock);
+ }
+ printf("\n");
+ return;
+bad:
+ printf("* error\n");
+}
+
+void
+ptstrans(struct tty *tp, int i, int flag)
+{
+ struct tty tty;
+ char *name;
+ char rw[3];
+ dev_t rdev;
+
+ PREFIX(i);
+
+ /* Obtain struct tty. */
+ if (!KVM_READ(tp, &tty, sizeof(struct tty))) {
+ dprintf(stderr, "can't read tty at %p\n", (void *)tp);
+ goto bad;
+ }
+
+ /* Figure out the device name. */
+ name = kdevtoname(tty.t_dev);
+ if (name == NULL) {
+ dprintf(stderr, "can't determine tty name at %p\n", (void *)tp);
+ goto bad;
+ }
+
+ rw[0] = '\0';
+ if (flag & FREAD)
+ strcat(rw, "r");
+ if (flag & FWRITE)
+ strcat(rw, "w");
+
+ printf("* pseudo-terminal master ");
+ if (nflg || !name) {
+ rdev = dev2udev(tty.t_dev);
+ printf("%10d,%-2d", major(rdev), minor(rdev));
+ } else {
+ printf("%10s", name);
+ }
+ printf(" %2s\n", rw);
+
+ free(name);
+
+ return;
+bad:
+ printf("* error\n");
+}
+
+/*
+ * Read the cdev structure in the kernel in order to work out the
+ * associated dev_t
+ */
+dev_t
+dev2udev(struct cdev *dev)
+{
+ struct cdev_priv priv;
+
+ if (KVM_READ(cdev2priv(dev), &priv, sizeof priv)) {
+ return ((dev_t)priv.cdp_inode);
+ } else {
+ dprintf(stderr, "can't convert cdev *%p to a dev_t\n", dev);
+ return -1;
+ }
+}
+
+/*
+ * getinetproto --
+ * print name of protocol number
+ */
+void
+getinetproto(int number)
+{
+ static int isopen;
+ struct protoent *pe;
+
+ if (!isopen)
+ setprotoent(++isopen);
+ if ((pe = getprotobynumber(number)) != NULL)
+ printf(" %s", pe->p_name);
+ else
+ printf(" %d", number);
+}
+
+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);
+}
+
+#ifdef ZFS
+void *
+getvnodedata(struct vnode *vp)
+{
+ return (vp->v_data);
+}
+
+struct mount *
+getvnodemount(struct vnode *vp)
+{
+ return (vp->v_mount);
+}
+#endif
+
+void
+usage(void)
+{
+ (void)fprintf(stderr,
+ "usage: fstat [-fmnv] [-M core] [-N system] [-p pid] [-u user] [file ...]\n");
+ exit(1);
}
More information about the svn-src-projects
mailing list