Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 24 Jun 2009 19:09:36 +0000 (UTC)
From:      Ulf Lilleengen <lulf@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r194888 - projects/libprocstat/usr.bin/fstat
Message-ID:  <200906241909.n5OJ9aJc025585@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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);
 }



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200906241909.n5OJ9aJc025585>