summaryrefslogtreecommitdiff
path: root/dialects/darwin
diff options
context:
space:
mode:
Diffstat (limited to 'dialects/darwin')
-rwxr-xr-xdialects/darwin/get-hdr-loc.sh119
-rw-r--r--dialects/darwin/kmem/Makefile171
-rwxr-xr-xdialects/darwin/kmem/Mksrc24
-rw-r--r--dialects/darwin/kmem/ddev.c479
-rw-r--r--dialects/darwin/kmem/dfile.c390
-rw-r--r--dialects/darwin/kmem/dlsof.h337
-rw-r--r--dialects/darwin/kmem/dmnt.c229
-rw-r--r--dialects/darwin/kmem/dnode.c1038
-rw-r--r--dialects/darwin/kmem/dnode1.c107
-rw-r--r--dialects/darwin/kmem/dproc.c763
-rw-r--r--dialects/darwin/kmem/dproto.h62
-rw-r--r--dialects/darwin/kmem/dsock.c478
-rw-r--r--dialects/darwin/kmem/dstore.c105
-rw-r--r--dialects/darwin/kmem/machine.h647
-rw-r--r--dialects/darwin/libproc/Makefile171
-rwxr-xr-xdialects/darwin/libproc/Mksrc24
-rw-r--r--dialects/darwin/libproc/ddev.c549
-rw-r--r--dialects/darwin/libproc/dfile.c682
-rw-r--r--dialects/darwin/libproc/dlsof.h136
-rw-r--r--dialects/darwin/libproc/dmnt.c201
-rw-r--r--dialects/darwin/libproc/dproc.c839
-rw-r--r--dialects/darwin/libproc/dproto.h61
-rw-r--r--dialects/darwin/libproc/dsock.c449
-rw-r--r--dialects/darwin/libproc/dstore.c91
-rw-r--r--dialects/darwin/libproc/machine.h629
25 files changed, 8781 insertions, 0 deletions
diff --git a/dialects/darwin/get-hdr-loc.sh b/dialects/darwin/get-hdr-loc.sh
new file mode 100755
index 0000000..c0d9880
--- /dev/null
+++ b/dialects/darwin/get-hdr-loc.sh
@@ -0,0 +1,119 @@
+#!/bin/sh
+#
+# get-hdr-loc.sh -- get Darwin XNU kernel header file location
+#
+# Interactively requests the specification of the path to the host's Darwin
+# XNU kernel header files. Checks that path and returns it to the caller.
+#
+# Usage: file1 file2 ... fileN
+#
+# Where: file1 first header file needed
+# file2 second header file needed
+# ...
+# fileN last header file needed
+#
+# Exit:
+#
+# Exit code: 0 if path found; path returned on STDOUT
+#
+# 1 if path not found: error message returned
+# on STDOUT
+#
+#set -x # for DEBUGging
+
+# Check argument count. There must be at least one argument.
+
+if test $# -lt 1 # {
+then
+ echo "insufficient arguments: $#"
+ exit 1
+fi # }
+lst=$*
+
+# Request the path to the Darwin XNU kernel header files.
+
+trap 'stty echo; echo interrupted; exit 1' 1 2 3 15
+FOREVER=1
+while test $FOREVER -ge 1 # {
+do
+ if test $FOREVER -eq 1 # {
+ then
+ echo "---------------------------------------------------------------" 1>&2
+ echo "" 1>&2
+ echo "Lsof cannot find some Darwin XNU kernel header files it needs." 1>&2
+ echo "They should have already been downloaded from:" 1>&2
+ echo "" 1>&2
+ echo " http://www.opensource.apple.com/darwinsource/index.html" 1>&2
+ echo "" 1>&2
+ echo "and then installed. (See 00FAQ for download and installation" 1>&2
+ echo "instructions.)" 1>&2
+ echo "" 1>&2
+ echo "Please specify the path to the place where they were installed." 1>&2
+ echo "" 1>&2
+ echo "---------------------------------------------------------------" 1>&2
+ fi # }
+
+ END=0
+ while test $END = 0 # {
+ do
+ echo "" 1>&2
+ echo -n "What is the path? " 1>&2
+ read HP EXCESS
+ HP=`echo echo $HP | /bin/csh -fs`
+ if test $? -eq 0 # {
+ then
+ if test "X$HP" = "X" # {
+ then
+ echo "" 1>&2
+ echo "+================================+" 1>&2
+ echo "| Please enter a non-empty path. |" 1>&2
+ echo "+================================+" 1>&2
+ echo "" 1>&2
+ else
+ END=1
+ fi # }
+ else
+ echo "" 1>&2
+ echo "+============================+" 1>&2
+ echo "| Please enter a legal path. |" 1>&2
+ echo "+============================+" 1>&2
+ echo "" 1>&2
+ fi # }
+ done # }
+
+ # See if the header files are available in the specified path.
+
+ MH=""
+ for i in $lst # {
+ do
+ if test ! -f ${HP}/bsd/$i -a ! -f ${HP}/osfmk/$i # {
+ then
+ if test "X$MH" = "X" # {
+ then
+ MH=$i
+ else
+ MH="$MH $i"
+ fi # }
+ fi # }
+ done # }
+ if test "X$MH" = "X" # {
+ then
+
+ # All header files are available, so return the path and exit cleanly.
+
+ echo $HP
+ exit 0
+ else
+ echo "" 1>&2
+ echo "ERROR: not all header files are in:" 1>&2
+ echo "" 1>&2
+ echo " ${HP}" 1>&2
+ echo "" 1>&2
+ echo " These are missing:" 1>&2
+ echo "" 1>&2
+ echo " $MH" 1>&2
+ FOREVER=2
+ fi # }
+done # }
+echo "unknown error"
+exit 1
diff --git a/dialects/darwin/kmem/Makefile b/dialects/darwin/kmem/Makefile
new file mode 100644
index 0000000..47ebfee
--- /dev/null
+++ b/dialects/darwin/kmem/Makefile
@@ -0,0 +1,171 @@
+
+# Darwin /dev/kmem-based lsof Makefile
+#
+# $Id: Makefile,v 1.8 2008/10/21 16:15:34 abe Exp $
+
+PROG= lsof
+
+BIN= ${DSTROOT}/usr/sbin
+
+DOC= ${DSTROOT}/usr/share/man/man8
+
+I=/usr/include
+S=/usr/include/sys
+L=/usr/include/local
+P=
+
+CDEF= ${RC_CFLAGS}
+CDEFS= ${CDEF} ${CFGF}
+INCL= ${DINC}
+override CFLAGS= ${CDEFS} ${INCL} ${DEBUG}
+
+GRP=
+
+HDR= lsof.h lsof_fields.h dlsof.h machine.h proto.h dproto.h
+
+SRC= ddev.c dfile.c dmnt.c dnode.c dnode1.c dproc.c dsock.c dstore.c \
+ arg.c main.c misc.c node.c print.c proc.c store.c usage.c util.c
+
+OBJ= ddev.o dfile.o dmnt.o dnode.o dnode1.o dproc.o dsock.o dstore.o \
+ arg.o main.o misc.o node.o print.o proc.o store.o usage.o util.o
+
+MAN= lsof.8
+
+OTHER=
+
+SHELL= /bin/sh
+
+SOURCE= Makefile ${OTHER} ${MAN} ${HDR} ${SRC}
+
+all: ${PROG}
+
+${PROG}: ${LIB} ${P} ${OBJ}
+ ${CC} -o $@ ${CFLAGS} ${OBJ} ${CFGL}
+
+clean: FRC
+ rm -f Makefile.bak ${PROG} a.out core errs lint.out tags *.o version.h
+ rm -f machine.h.old new_machine.h
+ (cd lib; ${MAKE} -f Makefile.skel clean)
+
+install-strip: all FRC
+ mkdir -p ${BIN}
+ install -c -s -m 2755 -g kmem ${PROG} ${BIN}
+ mkdir -p ${DOC}
+ install -c -m 444 ${MAN} ${DOC}
+
+install: all FRC
+ @echo ''
+ @echo 'Please write your own install rule. Lsof for Darwin below 8'
+ @echo 'should be installed setgid to the group that has permission'
+ @echo 'to read /dev/kmem, often kmem or sys. Lsof for Darwin 8 and'
+ @echo 'above should be installed setuid-root. Your install rule'
+ @echo 'actions for Darwin below 8 might look something like this:'
+ @echo ''
+ @echo ' install -m 2xxx -g $${GRP} $${PROG} $${BIN}'
+ @echo ' install -m 444 $${MAN} $${DOC}'
+ @echo ''
+ @echo 'Your install rule actions for Darwin 8 and above might look'
+ @echo 'something like this:'
+ @echo ''
+ @echo ' install -m 4xxx -o root $${PROG} $${BIN}'
+ @echo ' install -m 444 $${MAN} $${DOC}'
+ @echo ''
+ @echo 'You will have to complete the xxx modes, the GRP value, and'
+ @echo 'the skeletons for the BIN and DOC strings, given at the'
+ @echo 'beginning of this Makefile, e.g.,'
+ @echo ''
+ @echo ' BIN= $${DESTDIR}/usr/local/etc'
+ @echo ' DOC= $${DESTDIR}/usr/man/man8'
+ @echo ' GRP= kmem'
+ @echo ''
+
+${LIB}: FRC
+ (cd lib; ${MAKE} DEBUG="${DEBUG}" CFGF="${CFGF}")
+
+version.h: FRC
+ @echo Constructing version.h
+ @rm -f version.h
+ @echo '#define LSOF_BLDCMT "${LSOF_BLDCMT}"' > version.h;
+ @echo '#define LSOF_CC "${CC}"' >> version.h
+ @echo '#define LSOF_CCV "${CCV}"' >> version.h
+ @echo '#define LSOF_CCDATE "'`date`'"' >> version.h
+ @echo '#define LSOF_CCFLAGS "'`echo ${CFLAGS} | sed 's/\\\\(/\\(/g' | sed 's/\\\\)/\\)/g' | sed 's/"/\\\\"/g'`'"' >> version.h
+ @echo '#define LSOF_CINFO "${CINFO}"' >> version.h
+ @if [ "X${LSOF_HOST}" = "X" ]; then \
+ echo '#define LSOF_HOST "'`uname -n`'"' >> version.h; \
+ else \
+ if [ "${LSOF_HOST}" = "none" ]; then \
+ echo '#define LSOF_HOST ""' >> version.h; \
+ else \
+ echo '#define LSOF_HOST "${LSOF_HOST}"' >> version.h; \
+ fi \
+ fi
+ @echo '#define LSOF_LDFLAGS "${CFGL}"' >> version.h
+ @if [ "X${LSOF_LOGNAME}" = "X" ]; then \
+ echo '#define LSOF_LOGNAME "${LOGNAME}"' >> version.h; \
+ else \
+ if [ "${LSOF_LOGNAME}" = "none" ]; then \
+ echo '#define LSOF_LOGNAME ""' >> version.h; \
+ else \
+ echo '#define LSOF_LOGNAME "${LSOF_LOGNAME}"' >> version.h; \
+ fi; \
+ fi
+ @if [ "X${LSOF_SYSINFO}" = "X" ]; then \
+ echo '#define LSOF_SYSINFO "'`uname -a`'"' >> version.h; \
+ else \
+ if [ "${LSOF_SYSINFO}" = "none" ]; then \
+ echo '#define LSOF_SYSINFO ""' >> version.h; \
+ else \
+ echo '#define LSOF_SYSINFO "${LSOF_SYSINFO}"' >> version.h; \
+ fi \
+ fi
+ @if [ "X${LSOF_USER}" = "X" ]; then \
+ echo '#define LSOF_USER "${USER}"' >> version.h; \
+ else \
+ if [ "${LSOF_USER}" = "none" ]; then \
+ echo '#define LSOF_USER ""' >> version.h; \
+ else \
+ echo '#define LSOF_USER "${LSOF_USER}"' >> version.h; \
+ fi \
+ fi
+ @sed '/VN/s/.ds VN \(.*\)/#define LSOF_VERSION "\1"/' < version >> version.h
+
+FRC:
+
+# DO NOT DELETE THIS LINE - make depend DEPENDS ON IT
+
+ddev.o: ${HDR} ddev.c
+
+dfile.o: ${HDR} dfile.c
+
+dmnt.o: ${HDR} dmnt.c
+
+dnode.o: ${HDR} dnode.c
+
+dnode1.o: ${HDR} dnode1.c
+
+dproc.o: ${HDR} dproc.c
+
+dsock.o: ${HDR} dsock.c
+
+dstore.o: ${HDR} dstore.c
+
+arg.o: ${HDR} arg.c
+
+main.o: ${HDR} main.c
+
+misc.o: ${HDR} misc.c
+
+node.o: ${HDR} node.c
+
+print.o: ${HDR} print.c
+
+proc.o: ${HDR} proc.c
+
+store.o: ${HDR} store.c
+
+usage.o: ${HDR} version.h usage.c
+
+util.o: ${HDR} util.c
+
+# *** Do not add anything here - It will go away. ***
diff --git a/dialects/darwin/kmem/Mksrc b/dialects/darwin/kmem/Mksrc
new file mode 100755
index 0000000..e576427
--- /dev/null
+++ b/dialects/darwin/kmem/Mksrc
@@ -0,0 +1,24 @@
+#!/bin/sh
+#
+# Mksrc - make Darwin /dev/kmem-based lsof source files
+#
+# WARNING: This script assumes it is running from the main directory
+# of the lsof, version 4 distribution.
+#
+# One environment variable applies:
+#
+# LSOF_MKC is the method for creating the source files.
+# It defaults to "ln -s". A common alternative is "cp".
+#
+# $Id: Mksrc,v 1.5 2006/03/27 23:24:50 abe Exp $
+
+
+D=dialects/darwin/kmem
+L="dlsof.h ddev.c dfile.c dmnt.c dnode.c dnode1.c dproc.c dproto.h dsock.c dstore.c machine.h"
+
+for i in $L
+do
+ rm -f $i
+ $LSOF_MKC $D/$i $i
+ echo "$LSOF_MKC $D/$i $i"
+done
diff --git a/dialects/darwin/kmem/ddev.c b/dialects/darwin/kmem/ddev.c
new file mode 100644
index 0000000..fc6ce28
--- /dev/null
+++ b/dialects/darwin/kmem/ddev.c
@@ -0,0 +1,479 @@
+/*
+ * ddev.c - Darwin device support functions for /dev/kmem-based lsof
+ */
+
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907. All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ * consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Credit to the authors and Purdue
+ * University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
+static char *rcsid = "$Id: ddev.c,v 1.5 2006/03/27 23:24:50 abe Exp $";
+#endif
+
+
+#include "lsof.h"
+
+
+/*
+ * Local definitions
+ */
+
+#if defined(DVCH_DEVPATH)
+#define DDEV_DEVPATH DVCH_DEVPATH
+#else /* !defined(DVCH_DEVPATH) */
+#define DDEV_DEVPATH "/dev"
+#endif /* defined(DVCH_DEVPATH) */
+
+#if defined(USE_STAT)
+#define STATFN stat
+#else /* !defined(USE_STAT) */
+#define STATFN lstat
+#endif /* defined(USE_STAT) */
+
+
+/*
+ * Local static variables.
+ */
+
+static dev_t *ADev = (dev_t *) NULL; /* device numbers besides DevDev found
+ * inside DDEV_DEVPATH */
+static int ADevA = 0; /* entries allocated to ADev[] */
+static int ADevU = 0; /* entries used in ADev[] */
+
+
+/*
+ * Local function prototypes
+ */
+
+_PROTOTYPE(static int rmdupdev,(struct l_dev ***dp, int n, char *nm));
+_PROTOTYPE(static void saveADev,(struct stat *s));
+
+
+#if defined(HASSPECDEVD)
+/*
+ * HASSPECDEVD() -- process stat(2) result to see if the device number is
+ * inside DDEV_DEVPATH "/"
+ *
+ * exit: s->st_dev changed to DevDev, as required
+ */
+
+void
+HASSPECDEVD(p, s)
+ char *p; /* file path */
+ struct stat *s; /* stat(2) result for file */
+{
+ int i;
+
+ switch (s->st_mode & S_IFMT) {
+ case S_IFCHR:
+ case S_IFBLK:
+ if (s->st_dev == DevDev)
+ return;
+ (void) readdev(0);
+ if (!ADev)
+ return;
+ for (i = 0; i < ADevU; i++) {
+ if (s->st_dev == ADev[i]) {
+ s->st_dev = DevDev;
+ return;
+ }
+ }
+ }
+}
+#endif /* defined(HASSPECDEVD) */
+
+
+/*
+ * readdev() - read device names, modes and types
+ */
+
+void
+readdev(skip)
+ int skip; /* skip device cache read if 1 --
+ * ignored since device cache not
+ * used */
+{
+ DIR *dfp;
+ int dnamlen;
+ struct dirent *dp;
+ char *fp = (char *)NULL;
+ char *path = (char *)NULL;
+ int i = 0;
+ int j = 0;
+ MALLOC_S pl, sz;
+ struct stat sb;
+/*
+ * Read device names but once.
+ */
+ if (Sdev)
+ return;
+/*
+ * Prepare to scan DDEV_DEVPATH.
+ */
+ Dstkn = Dstkx = 0;
+ Dstk = (char **)NULL;
+ (void) stkdir(DDEV_DEVPATH);
+/*
+ * Unstack the next directory.
+ */
+ while (--Dstkx >= 0) {
+ if (!(dfp = OpenDir(Dstk[Dstkx]))) {
+
+# if defined(WARNDEVACCESS)
+ if (!Fwarn) {
+ (void) fprintf(stderr, "%s: WARNING: can't open: ", Pn);
+ safestrprt(Dstk[Dstkx], stderr, 1);
+ }
+# endif /* defined(WARNDEVACCESS) */
+
+ (void) free((FREE_P *)Dstk[Dstkx]);
+ Dstk[Dstkx] = (char *)NULL;
+ continue;
+ }
+ if (path) {
+ (void) free((FREE_P *)path);
+ path = (char *)NULL;
+ }
+ if (!(path = mkstrcat(Dstk[Dstkx], -1, "/", 1, (char *)NULL, -1,
+ &pl)))
+ {
+ (void) fprintf(stderr, "%s: no space for: ", Pn);
+ safestrprt(Dstk[Dstkx], stderr, 1);
+ Exit(1);
+ }
+ (void) free((FREE_P *)Dstk[Dstkx]);
+ Dstk[Dstkx] = (char *)NULL;
+ /*
+ * Scan the directory.
+ */
+ for (dp = ReadDir(dfp); dp; dp = ReadDir(dfp)) {
+ if (dp->d_ino == 0 || dp->d_name[0] == '.')
+ continue;
+ /*
+ * Form the full path name and get its status.
+ */
+ dnamlen = (int)dp->d_namlen;
+ if (fp) {
+ (void) free((FREE_P *)fp);
+ fp = (char *)NULL;
+ }
+ if (!(fp = mkstrcat(path, pl, dp->d_name, dnamlen,
+ (char *)NULL, -1, (MALLOC_S *)NULL)))
+ {
+ (void) fprintf(stderr, "%s: no space for: ", Pn);
+ safestrprt(path, stderr, 0);
+ safestrprtn(dp->d_name, dnamlen, stderr, 1);
+ Exit(1);
+ }
+ if (STATFN(fp, &sb) != 0) {
+ if (errno == ENOENT) /* a sym link to nowhere? */
+ continue;
+
+# if defined(WARNDEVACCESS)
+ if (!Fwarn) {
+ int errno_save = errno;
+
+ (void) fprintf(stderr, "%s: can't stat ", Pn);
+ safestrprt(fp, stderr, 0);
+ (void) fprintf(stderr, ": %s\n", strerror(errno_save));
+ }
+# endif /* defined(WARNDEVACCESS) */
+
+ continue;
+ }
+ /*
+ * If it's a subdirectory, stack its name for later
+ * processing.
+ */
+ if ((sb.st_mode & S_IFMT) == S_IFDIR) {
+
+ /*
+ * Skip /dev/fd.
+ */
+ if (strcmp(fp, "/dev/fd"))
+ (void) stkdir(fp);
+ continue;
+ }
+ if ((sb.st_mode & S_IFMT) == S_IFLNK) {
+
+ /*
+ * Ignore symbolic links.
+ */
+ continue;
+ }
+ if ((sb.st_mode & S_IFMT) == S_IFCHR) {
+
+ /*
+ * Save character device information in Devtp[].
+ */
+ if (i >= Ndev) {
+ Ndev += DEVINCR;
+ if (!Devtp)
+ Devtp = (struct l_dev *)malloc(
+ (MALLOC_S)(sizeof(struct l_dev)*Ndev));
+ else
+ Devtp = (struct l_dev *)realloc((MALLOC_P *)Devtp,
+ (MALLOC_S)(sizeof(struct l_dev)*Ndev));
+ if (!Devtp) {
+ (void) fprintf(stderr,
+ "%s: no space for character device\n", Pn);
+ Exit(1);
+ }
+ }
+ Devtp[i].rdev = sb.st_rdev;
+ Devtp[i].inode = (INODETYPE)sb.st_ino;
+ if (!(Devtp[i].name = mkstrcpy(fp, (MALLOC_S *)NULL))) {
+ (void) fprintf(stderr,
+ "%s: no space for device name: ", Pn);
+ safestrprt(fp, stderr, 1);
+ Exit(1);
+ }
+ Devtp[i].v = 0;
+ i++;
+ }
+
+# if defined(HASBLKDEV)
+ if ((sb.st_mode & S_IFMT) == S_IFBLK) {
+
+ /*
+ * Save block device information in BDevtp[].
+ */
+ if (j >= BNdev) {
+ BNdev += DEVINCR;
+ if (!BDevtp)
+ BDevtp = (struct l_dev *)malloc(
+ (MALLOC_S)(sizeof(struct l_dev)*BNdev));
+ else
+ BDevtp = (struct l_dev *)realloc((MALLOC_P *)BDevtp,
+ (MALLOC_S)(sizeof(struct l_dev)*BNdev));
+ if (!BDevtp) {
+ (void) fprintf(stderr,
+ "%s: no space for block device\n", Pn);
+ Exit(1);
+ }
+ }
+ BDevtp[j].name = fp;
+ fp = (char *)NULL;
+ BDevtp[j].inode = (INODETYPE)sb.st_ino;
+ BDevtp[j].rdev = sb.st_rdev;
+ BDevtp[j].v = 0;
+ j++;
+ }
+# endif /* defined(HASBLKDEV) */
+
+ /*
+ * Save a possible new st_dev number within DDEV_DEVPATH.
+ */
+ if (sb.st_dev != DevDev)
+ (void) saveADev(&sb);
+ }
+ (void) CloseDir(dfp);
+ }
+/*
+ * Free any unneeded space that was allocated.
+ */
+ if (ADev && (ADevU < ADevA)) {
+
+ /*
+ * Reduce space allocated to additional DDEV_DEVPATH device numbers.
+ */
+ if (!ADevU) {
+
+ /*
+ * If no space was used, free the entire allocation.
+ */
+ (void) free((FREE_P *)ADev);
+ ADev = (dev_t *)NULL;
+ ADevA = 0;
+ } else {
+
+ /*
+ * Reduce the allocation to what was used.
+ */
+ sz = (MALLOC_S)(ADevU * sizeof(dev_t));
+ if (!(ADev = (dev_t *)realloc((MALLOC_P *)ADev, sz))) {
+ (void) fprintf(stderr, "%s: can't reduce ADev[]\n", Pn);
+ Exit(1);
+ }
+ }
+ }
+ if (!Dstk) {
+ (void) free((FREE_P *)Dstk);
+ Dstk = (char **)NULL;
+ }
+ if (fp)
+ (void) free((FREE_P *)fp);
+ if (path)
+ (void) free((FREE_P *)path);
+
+# if defined(HASBLKDEV)
+/*
+ * Reduce the BDevtp[] (optional) and Devtp[] tables to their minimum
+ * sizes; allocate and build sort pointer lists; and sort the tables by
+ * device number.
+ */
+ if (BNdev) {
+ if (BNdev > j) {
+ BNdev = j;
+ BDevtp = (struct l_dev *)realloc((MALLOC_P *)BDevtp,
+ (MALLOC_S)(sizeof(struct l_dev) * BNdev));
+ }
+ if (!(BSdev = (struct l_dev **)malloc(
+ (MALLOC_S)(sizeof(struct l_dev *) * BNdev))))
+ {
+ (void) fprintf(stderr,
+ "%s: no space for block device sort pointers\n", Pn);
+ Exit(1);
+ }
+ for (j = 0; j < BNdev; j++) {
+ BSdev[j] = &BDevtp[j];
+ }
+ (void) qsort((QSORT_P *)BSdev, (size_t)BNdev,
+ (size_t)sizeof(struct l_dev *), compdev);
+ BNdev = rmdupdev(&BSdev, BNdev, "block");
+ }
+
+# if !defined(NOWARNBLKDEV)
+ else {
+ if (!Fwarn)
+ (void) fprintf(stderr,
+ "%s: WARNING: no block devices found\n", Pn);
+ }
+# endif /* !defined(NOWARNBLKDEV) */
+# endif /* defined(HASBLKDEV) */
+
+ if (Ndev) {
+ if (Ndev > i) {
+ Ndev = i;
+ Devtp = (struct l_dev *)realloc((MALLOC_P *)Devtp,
+ (MALLOC_S)(sizeof(struct l_dev) * Ndev));
+ }
+ if (!(Sdev = (struct l_dev **)malloc(
+ (MALLOC_S)(sizeof(struct l_dev *) * Ndev))))
+ {
+ (void) fprintf(stderr,
+ "%s: no space for character device sort pointers\n", Pn);
+ Exit(1);
+ }
+ for (i = 0; i < Ndev; i++) {
+ Sdev[i] = &Devtp[i];
+ }
+ (void) qsort((QSORT_P *)Sdev, (size_t)Ndev,
+ (size_t)sizeof(struct l_dev *), compdev);
+ Ndev = rmdupdev(&Sdev, Ndev, "char");
+ } else {
+ (void) fprintf(stderr, "%s: no character devices found\n", Pn);
+ Exit(1);
+ }
+}
+
+
+/*
+ * rmdupdev() - remove duplicate (major/minor/inode) devices
+ */
+
+static int
+rmdupdev(dp, n, nm)
+ struct l_dev ***dp; /* device table pointers address */
+ int n; /* number of pointers */
+ char *nm; /* device table name for error message */
+{
+ int i, j, k;
+ struct l_dev **p;
+
+ for (i = j = 0, p = *dp; i < n ;) {
+ for (k = i + 1; k < n; k++) {
+ if (p[i]->rdev != p[k]->rdev || p[i]->inode != p[k]->inode)
+ break;
+ }
+ if (i != j)
+ p[j] = p[i];
+ j++;
+ i = k;
+ }
+ if (n == j)
+ return(n);
+ if (!(*dp = (struct l_dev **)realloc((MALLOC_P *)*dp,
+ (MALLOC_S)(j * sizeof(struct l_dev *)))))
+ {
+ (void) fprintf(stderr, "%s: can't realloc %s device pointers\n",
+ Pn, nm);
+ Exit(1);
+ }
+ return(j);
+}
+
+
+/*
+ * saveADev() - save additional device number appearing inside DDEV_DEVPATH
+ */
+
+static void
+saveADev(s)
+ struct stat *s; /* stat(2) buffer for file */
+{
+ int i;
+ MALLOC_S sz;
+/*
+ * Process VCHR files.
+ *
+ * Optionally process VBLK files.
+ */
+
+#if defined(HASBLKDEV)
+ if (((s->st_mode & S_IFMT) != S_IFBLK)
+ && ((s->st_mode & S_IFMT) != S_IFCHR))
+#else /* !defined(HASBLKDEV) */
+ if ((s->st_mode & S_IFCHR) != S_IFCHR)
+#endif /* defined(HASBLKDEV) */
+
+ return;
+/*
+ * See if this is a new VBLK or VCHR st_dev value for ADev[].
+ */
+ for (i = 0; i < ADevU; i++) {
+ if (s->st_dev == ADev[i])
+ return;
+ }
+/*
+ * This is a new device number to add to ADev[].
+ */
+ if (ADevU >= ADevA) {
+ ADevA += 16;
+ sz = (MALLOC_S)(ADevA * sizeof(dev_t));
+ if (ADev)
+ ADev = (dev_t *)realloc((MALLOC_P *)ADev, sz);
+ else
+ ADev = (dev_t *)malloc(sz);
+ if (!ADev) {
+ (void) fprintf(stderr, "%s: no space for ADev[]\n", Pn);
+ Exit(1);
+ }
+ }
+ ADev[ADevU++] = s->st_dev;
+}
diff --git a/dialects/darwin/kmem/dfile.c b/dialects/darwin/kmem/dfile.c
new file mode 100644
index 0000000..e1b23a7
--- /dev/null
+++ b/dialects/darwin/kmem/dfile.c
@@ -0,0 +1,390 @@
+/*
+ * dfile.c - Darwin file processing functions for /dev/kmem-based lsof
+ */
+
+
+/*
+ * Copyright 2005 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907. All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ * consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Credit to the authors and Purdue
+ * University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright 2005 Purdue Research Foundation.\nAll rights reserved.\n";
+static char *rcsid = "$Id$";
+#endif
+
+
+#include "lsof.h"
+
+
+/*
+ * Local definitions
+ */
+
+#if DARWINV>=800
+#define file fileglob
+#define f_flag fg_flag
+#define f_type fg_type
+#define f_count fg_count
+#define f_ops fg_ops
+#define f_offset fg_offset
+#define f_data fg_data
+#endif /* DARWINV>=800 */
+
+#if defined(HASPSXSEM)
+#define PSEMNAMLEN 31 /* from kern/posix_sem.c */
+#endif /* defined(HASPSXSEM) */
+
+#if defined(HASPSXSHM)
+#define PSHMNAMLEN 31 /* from kern/posix_shm.c */
+#endif /* defined(HASPSXSHM) */
+
+
+/*
+ * Local structure definitions
+ */
+
+#if defined(HASPSXSEM)
+struct pseminfo { /* from kern/posix_sem.c */
+ unsigned int psem_flags;
+ unsigned int psem_usecount;
+ mode_t psem_mode;
+ uid_t psem_uid;
+ gid_t psem_gid;
+ char psem_name[PSEMNAMLEN + 1];
+ void *psem_semobject;
+ struct proc *sem_proc;
+};
+
+struct psemnode {
+ struct pseminfo *pinfo;
+};
+#endif /* defined(HASPSXSEM) */
+
+#if defined(HASPSXSHM) /* from kern/posix_shm.c */
+struct pshminfo {
+ unsigned int pshm_flags;
+ unsigned int pshm_usecount;
+ off_t pshm_length;
+ mode_t pshm_mode;
+ uid_t pshm_uid;
+ gid_t pshm_gid;
+ char pshm_name[PSHMNAMLEN + 1];
+ void *pshm_memobject;
+};
+
+struct pshmnode {
+ off_t mapp_addr;
+
+# if DARWINV<800
+ size_t map_size;
+# else /* DARWINV>=800 */
+ user_size_t map_size;
+# endif /* DARWINV>=800 */
+
+ struct pshminfo *pinfo;
+};
+#endif /* defined(HASPSXSHM) */
+
+
+#if DARWINV>=800
+/*
+ * print_v_path() - print vnode's path
+ */
+
+int
+print_v_path(lf)
+ struct lfile *lf;
+{
+ if (lf->V_path) {
+ safestrprt(lf->V_path, stdout, 0);
+ return(1);
+ }
+ return(0);
+}
+#endif /* DARWINV>=800 */
+
+
+#if defined(HASKQUEUE)
+/*
+ * process_kqueue() -- process kqueue file
+ */
+
+void
+process_kqueue(ka)
+ KA_T ka; /* kqueue file structure address */
+{
+ struct kqueue kq; /* kqueue structure */
+
+ (void) snpf(Lf->type, sizeof(Lf->type), "KQUEUE");
+ enter_dev_ch(print_kptr(ka, (char *)NULL, 0));
+ if (!ka || kread(ka, (char *)&kq, sizeof(kq)))
+ return;
+ (void) snpf(Namech, Namechl, "count=%d, state=%#x", kq.kq_count,
+ kq.kq_state);
+ enter_nm(Namech);
+}
+#endif /* defined(HASKQUEUE) */
+
+
+#if DARWINV>=800
+/*
+ * process_pipe() - process a file structure whose type is DTYPE_PIPE
+ */
+
+void
+process_pipe(pa)
+ KA_T pa; /* pipe structure address */
+{
+ (void) snpf(Lf->type, sizeof(Lf->type), "PIPE");
+ enter_dev_ch(print_kptr(pa, (char *)NULL, 0));
+ Namech[0] = '\0';
+}
+#endif /* DARWINV>=800 */
+
+
+#if defined(HASPSXSEM)
+/*
+ * process_psxsem() -- process POSIX semaphore file
+ */
+
+void
+process_psxsem(pa)
+ KA_T pa; /* psxsem file structure address */
+{
+ struct pseminfo pi;
+ struct psemnode pn;
+
+ (void) snpf(Lf->type, sizeof(Lf->type), "PSXSEM");
+ enter_dev_ch(print_kptr(pa, (char *)NULL, 0));
+ if (!Fsize)
+ Lf->off_def = 1;
+ if (pa && !kread(pa, (char *)&pn, sizeof(pn))) {
+ if (pn.pinfo && !kread((KA_T)pn.pinfo, (char *)&pi, sizeof(pi))) {
+ if (pi.psem_name[0]) {
+ pi.psem_name[PSEMNAMLEN] = '\0';
+ (void) snpf(Namech, Namechl, "%s", pi.psem_name);
+ enter_nm(Namech);
+ }
+ }
+ }
+}
+#endif /* defined(HASPSXSEM) */
+
+
+#if defined(HASPSXSHM)
+/*
+ * process_psxshm() -- process POSIX shared memory file
+ */
+
+void
+process_psxshm(pa)
+ KA_T pa; /* psxshm file structure address */
+{
+ struct pshminfo pi;
+ struct pshmnode pn;
+ int pns = 0;
+
+ (void) snpf(Lf->type, sizeof(Lf->type), "PSXSHM");
+ enter_dev_ch(print_kptr(pa, (char *)NULL, 0));
+ if (pa && !kread(pa, (char *)&pn, sizeof(pn))) {
+ pns = 1;
+ if (pn.pinfo && !kread((KA_T)pn.pinfo, (char *)&pi, sizeof(pi))) {
+ if (pi.pshm_name[0]) {
+ pi.pshm_name[PSEMNAMLEN] = '\0';
+ (void) snpf(Namech, Namechl, "%s", pi.pshm_name);
+ enter_nm(Namech);
+ } else if (pi.pshm_memobject) {
+ (void) snpf(Namech, Namechl, "obj=%s",
+ print_kptr((KA_T)pi.pshm_memobject, (char *)NULL, 0));
+ enter_nm(Namech);
+ }
+ }
+ }
+ if (Foffset)
+ Lf->off_def = 1;
+ else if (pns) {
+ Lf->sz = (SZOFFTYPE)pn.map_size;
+ Lf->sz_def = 1;
+ }
+}
+#endif /* defined(HASPSXSHM) */
+
+
+/*
+ * process_file() - process file
+ */
+
+/*
+ * The caller may define:
+ *
+ * FILEPTR as the name of the location to store a pointer
+ * to the current file struct -- e.g.,
+ *
+ * struct file *foobar;
+ * #define FILEPTR foobar
+ */
+
+void
+process_file(fp)
+ KA_T fp; /* kernel file structure address */
+{
+
+#if DARWINV<800
+ struct file f;
+#else /* DARWINV>=800 */
+ struct fileglob f;
+ struct fileproc fileproc;
+#endif /* DARWINV>=800 */
+
+ int flag;
+
+#if defined(FILEPTR)
+/*
+ * Save file structure address for process_node().
+ */
+ FILEPTR = &f;
+#endif /* defined(FILEPTR) */
+
+/*
+ * Read file structure.
+ */
+
+#if DARWINV<800
+ if (kread((KA_T)fp, (char *)&f, sizeof(f))) {
+ (void) snpf(Namech, Namechl, "can't read file struct from %s",
+ print_kptr(fp, (char *)NULL, 0));
+ enter_nm(Namech);
+ return;
+ }
+#else /* DARWINV>=800 */
+ if (kread((KA_T)fp, (char *)&fileproc, sizeof(fileproc))) {
+ (void) snpf(Namech, Namechl, "can't read fileproc struct from %s",
+ print_kptr(fp, (char *)NULL, 0));
+ enter_nm(Namech);
+ return;
+ }
+ if (kread((KA_T)fileproc.f_fglob, (char *)&f, sizeof(f))) {
+ (void) snpf(Namech, Namechl, "can't read fileglob struct from %s",
+ print_kptr((KA_T)fileproc.f_fglob, (char *)NULL, 0));
+ enter_nm(Namech);
+ return;
+ }
+#endif /* DARWINV>=800 */
+
+ Lf->off = (SZOFFTYPE)f.f_offset;
+ if (f.f_count) {
+
+ /*
+ * Construct access code.
+ */
+ if ((flag = (f.f_flag & (FREAD | FWRITE))) == FREAD)
+ Lf->access = 'r';
+ else if (flag == FWRITE)
+ Lf->access = 'w';
+ else if (flag == (FREAD | FWRITE))
+ Lf->access = 'u';
+
+#if defined(HASFSTRUCT)
+ /*
+ * Save file structure values.
+ */
+ if (Fsv & FSV_CT) {
+ Lf->fct = (long)f.f_count;
+ Lf->fsv |= FSV_CT;
+ }
+ if (Fsv & FSV_FA) {
+ Lf->fsa = fp;
+ Lf->fsv |= FSV_FA;
+ }
+ if (Fsv & FSV_FG) {
+ Lf->ffg = (long)f.f_flag;
+ Lf->fsv |= FSV_FG;
+ }
+ if (Fsv & FSV_NI) {
+ Lf->fna = (KA_T)f.f_data;
+ Lf->fsv |= FSV_NI;
+ }
+#endif /* defined(HASFSTRUCT) */
+
+ /*
+ * Process structure by its type.
+ */
+ switch (f.f_type) {
+
+
+#if defined(DTYPE_PIPE)
+ case DTYPE_PIPE:
+# if defined(HASPIPEFN)
+ if (!Selinet)
+ HASPIPEFN((KA_T)f.f_data);
+# endif /* defined(HASPIPEFN) */
+ return;
+#endif /* defined(DTYPE_PIPE) */
+
+ case DTYPE_VNODE:
+ if (!Selinet)
+ process_node((KA_T)f.f_data);
+ return;
+ case DTYPE_SOCKET:
+ process_socket((KA_T)f.f_data);
+ return;
+
+#if defined(HASKQUEUE)
+ case DTYPE_KQUEUE:
+ process_kqueue((KA_T)f.f_data);
+ return;
+#endif /* defined(HASKQUEUE) */
+
+#if defined(HASPSXSEM)
+ case DTYPE_PSXSEM:
+ process_psxsem((KA_T)f.f_data);
+ return;
+#endif /* defined(HASPSXSEM) */
+
+#if defined(HASPSXSHM)
+ case DTYPE_PSXSHM:
+ process_psxshm((KA_T)f.f_data);
+ return;
+#endif /* defined(HASPSXSHM) */
+
+#if defined(HASPRIVFILETYPE)
+ case PRIVFILETYPE:
+ HASPRIVFILETYPE((KA_T)f.f_data);
+ return;
+#endif /* defined(HASPRIVFILETYPE) */
+
+ default:
+ if (f.f_type || f.f_ops) {
+ (void) snpf(Namech, Namechl,
+ "%s file struct, ty=%#x, op=%p",
+ print_kptr(fp, (char *)NULL, 0), f.f_type, f.f_ops);
+ enter_nm(Namech);
+ return;
+ }
+ }
+ }
+ enter_nm("no more information");
+}
diff --git a/dialects/darwin/kmem/dlsof.h b/dialects/darwin/kmem/dlsof.h
new file mode 100644
index 0000000..f5e50eb
--- /dev/null
+++ b/dialects/darwin/kmem/dlsof.h
@@ -0,0 +1,337 @@
+/*
+ * dlsof.h - Darwin header file for /dev/kmem-based lsof
+ */
+
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907. All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ * consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Credit to the authors and Purdue
+ * University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+
+/*
+ * $Id: dlsof.h,v 1.11 2005/11/01 20:24:51 abe Exp $
+ */
+
+
+#if !defined(DARWIN_LSOF_H)
+#define DARWIN_LSOF_H 1
+
+#include <stdlib.h>
+#include <dirent.h>
+#include <nlist.h>
+#include <setjmp.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/conf.h>
+#include <sys/filedesc.h>
+#include <sys/ucred.h>
+
+#if DARWINV<800
+#include <sys/mount.h>
+#define m_stat mnt_stat
+#else /* DARWINV>=800 */
+#include <sys/mount_internal.h>
+#define m_stat mnt_vfsstat
+#endif /* DARWINV>=800 */
+
+#if DARWINV<800
+#include <sys/uio.h>
+#include <sys/vnode.h>
+#else /* DARWINV>=800 */
+#include <sys/vnode.h>
+#define _SYS_SYSTM_H_
+struct nameidata { int dummy; }; /* to satisfy function prototypes */
+#include <sys/vnode_internal.h>
+#endif /* DARWINV>=800 */
+
+#include <rpc/types.h>
+#define KERNEL_PRIVATE
+#include <sys/socketvar.h>
+#undef KERNEL_PRIVATE
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/unpcb.h>
+
+# if defined(AF_NDRV)
+#include <net/if_var.h>
+#define KERNEL
+#include <sys/kern_event.h>
+#undef KERNEL
+#include <net/ndrv.h>
+# if DARWINV>=530
+#define KERNEL 1
+#include <net/ndrv_var.h>
+#undef KERNEL
+# endif /* DARWINV>=530 */
+# endif /* defined(AF_NDRV) */
+
+# if defined(AF_SYSTEM)
+#include <sys/queue.h>
+#define KERNEL
+#include <sys/kern_event.h>
+#undef KERNEL
+# endif /* defined(AF_SYSTEM) */
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <net/route.h>
+#include <netinet6/ipsec.h>
+#include <netinet/in_pcb.h>
+#include <netinet/ip_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcpip.h>
+#include <netinet/tcp_fsm.h>
+#include <netinet/tcp_timer.h>
+#include <netinet/tcp_var.h>
+#include <arpa/inet.h>
+#include <net/raw_cb.h>
+#include <sys/domain.h>
+#define pmap RPC_pmap
+#include <rpc/rpc.h>
+#include <rpc/pmap_prot.h>
+#undef pmap
+
+#include <sys/quota.h>
+#include <sys/event.h>
+
+# if DARWINV<800
+#include <paths.h>
+#undef MAXNAMLEN
+#include <ufs/ufs/quota.h>
+#include <paths.h>
+#include <ufs/ufs/quota.h>
+#include <ufs/ufs/inode.h>
+#include <nfs/rpcv2.h>
+#include <nfs/nfs.h>
+#include <nfs/nfsproto.h>
+#include <nfs/nfsnode.h>
+
+# if DARWINV<600
+#include <hfs/hfs.h>
+#undef offsetof
+# else /* DARWINV>=600 */
+#define KERNEL
+#include <hfs/hfs_cnode.h>
+#undef KERNEL
+# endif /* DARWINV<600 */
+# endif /* DARWINV<800 */
+
+# if DARWINV<800
+#define time t1 /* hack to make dn_times() happy */
+#include <miscfs/devfs/devfsdefs.h>
+#undef time
+# endif /* DARWINV<800 */
+
+# if DARWINV<800
+#define KERNEL
+#include <miscfs/fdesc/fdesc.h>
+#undef KERNEL
+# endif /* DARWINV<800 */
+
+# if DARWINV<800
+#include <sys/proc.h>
+# else /* DARWINV>=800 */
+#define PROC_DEF_ENABLED
+#define sleep kernel_sleep
+#include <sys/proc_internal.h>
+#undef sleep
+# endif /* DARWINV<800 */
+
+#include <kvm.h>
+#undef TRUE
+#undef FALSE
+
+# if DARWINV<800
+#include <sys/sysctl.h>
+# else /* DARWINV>=800 */
+#include "/usr/include/sys/sysctl.h"
+# endif /* DARWINV<800 */
+
+# if DARWINV<800
+#define KERNEL
+#include <sys/fcntl.h>
+#include <sys/file.h>
+#undef KERNEL
+# else /* DARWINV>=800 */
+#include <sys/fcntl.h>
+#include <sys/file_internal.h>
+# endif /* DARWINV<800 */
+
+# if defined(HASKQUEUE)
+#include <sys/eventvar.h>
+# endif /* defined(HASKQUEUE) */
+
+# if defined(DTYPE_PSXSEM)
+#define HASPSXSEM /* has the POSIX semaphore file
+ * type */
+# endif /* defined(DTYPE_PSXSEM) */
+
+# if defined(DTYPE_PSXSHM)
+#define HASPSXSHM /* has the POSIX shared memory
+ * file type */
+# endif /* defined(DTYPE_PSXSHM) */
+
+struct vop_advlock_args { int dummy; }; /* to satisfy lf_advlock() prototype */
+#include <sys/lockf.h>
+#include <sys/lock.h>
+
+/*
+ * Compensate for removal of MAP_ENTRY_IS_A_MAP from <vm/vm_map.h>,
+ * This work-around was supplied by John Polstra <jdp@polstra.com>.
+ */
+
+# if defined(MAP_ENTRY_IS_SUB_MAP) && !defined(MAP_ENTRY_IS_A_MAP)
+#define MAP_ENTRY_IS_A_MAP 0
+# endif /* defined(MAP_ENTRY_IS_SUB_MAP) && !defined(MAP_ENTRY_IS_A_MAP) */
+
+#undef B_NEEDCOMMIT
+#include <sys/buf.h>
+#include <sys/signal.h>
+#define user_sigaltstack sigaltstack
+#include <sys/user.h>
+
+#define COMP_P const void
+#define DEVINCR 1024 /* device table malloc() increment */
+#define DIRTYPE dirent /* directory entry type */
+
+typedef u_long KA_T;
+
+#define KMEM "/dev/kmem"
+#define LOGINML MAXLOGNAME
+#define MALLOC_P void
+#define FREE_P MALLOC_P
+#define MALLOC_S size_t
+
+#define N_UNIX "/mach_kernel"
+
+#define QSORT_P void
+#define READLEN_T int
+#define STRNCPY_L size_t
+#define SWAP "/dev/drum"
+
+# if DARWINV>=800
+#define SZOFFTYPE unsigned long long
+ /* size and offset internal storage
+ * type */
+#define SZOFFPSPEC "ll" /* SZOFFTYPE printf specification
+ * modifier */
+# endif /* DARWINV>=800 */
+
+
+/*
+ * Global storage definitions (including their structure definitions)
+ */
+
+struct file * Cfp;
+
+extern int Kd; /* KMEM descriptor */
+extern KA_T Kpa;
+
+struct l_vfs {
+ KA_T addr; /* kernel address */
+ fsid_t fsid; /* file system ID */
+
+# if defined(MOUNT_NONE)
+ short type; /* type of file system */
+# else /* !defined(MOUNT_NONE) */
+ char *typnm; /* file system type name */
+# endif /* defined(MOUNT_NONE) */
+
+ char *dir; /* mounted directory */
+ char *fsname; /* file system name */
+ struct l_vfs *next; /* forward link */
+};
+extern struct l_vfs *Lvfs;
+
+struct mounts {
+ char *dir; /* directory (mounted on) */
+ char *fsname; /* file system
+ * (symbolic links unresolved) */
+ char *fsnmres; /* file system
+ * (symbolic links resolved) */
+ dev_t dev; /* directory st_dev */
+ dev_t rdev; /* directory st_rdev */
+ INODETYPE inode; /* directory st_ino */
+ mode_t mode; /* directory st_mode */
+ mode_t fs_mode; /* file system st_mode */
+ struct mounts *next; /* forward link */
+};
+
+#define X_NCACHE "ncache"
+#define X_NCSIZE "ncsize"
+#define NL_NAME n_name
+
+struct sfile {
+ char *aname; /* argument file name */
+ char *name; /* file name (after readlink()) */
+ char *devnm; /* device name (optional) */
+ dev_t dev; /* device */
+ dev_t rdev; /* raw device */
+ u_short mode; /* S_IFMT mode bits from stat() */
+ int type; /* file type: 0 = file system
+ * 1 = regular file */
+ INODETYPE i; /* inode number */
+ int f; /* file found flag */
+ struct sfile *next; /* forward link */
+
+};
+
+#define XDR_VOID (const xdrproc_t)xdr_void
+#define XDR_PMAPLIST (const xdrproc_t)xdr_pmaplist
+
+
+/*
+ * Definitions for rnmh.c
+ */
+
+# if defined(HASNCACHE)
+#include <sys/uio.h>
+#include <sys/namei.h>
+
+# if !defined(offsetof)
+#define offsetof(type, member) ((size_t)(&((type *)0)->member))
+# endif /* !defined(offsetof) */
+
+#define NCACHE namecache /* kernel's structure name */
+
+#define NCACHE_NM nc_name /* name in NCACHE */
+
+# if DARWINV<700
+#define NCACHE_NMLEN nc_nlen /* name length in NCACHE */
+# endif /* DARWINV<700 */
+
+#define NCACHE_NXT nc_hash.le_next /* link in NCACHE */
+#define NCACHE_NODEADDR nc_vp /* node address in NCACHE */
+#define NCACHE_PARADDR nc_dvp /* parent node address in NCACHE */
+
+# if defined(HASNCVPID)
+#define NCACHE_NODEID nc_vpid /* node ID in NCACHE */
+#define NCACHE_PARID nc_dvpid /* parent node ID in NCACHE */
+# endif /* defined(HASNCVPID) */
+# endif /* defined(HASNCACHE) */
+
+#endif /* DARWIN_LSOF_H */
diff --git a/dialects/darwin/kmem/dmnt.c b/dialects/darwin/kmem/dmnt.c
new file mode 100644
index 0000000..7ba9453
--- /dev/null
+++ b/dialects/darwin/kmem/dmnt.c
@@ -0,0 +1,229 @@
+/*
+ * dmnt.c - Darwin mount support functions for /dev/kmem-based lsof
+ */
+
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907. All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ * consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Credit to the authors and Purdue
+ * University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
+static char *rcsid = "$Id: dmnt.c,v 1.4 2005/11/01 20:24:51 abe Exp $";
+#endif
+
+
+#include "lsof.h"
+
+
+/*
+ * Local static information
+ */
+
+static struct mounts *Lmi = (struct mounts *)NULL; /* local mount info */
+static int Lmist = 0; /* Lmi status */
+
+/*
+ * readmnt() - read mount table
+ */
+
+struct mounts *
+readmnt()
+{
+ char *dn = (char *)NULL;
+ char *ln;
+ struct statfs *mb = (struct statfs *)NULL;
+ struct mounts *mtp;
+ int n;
+ struct stat sb;
+
+ if (Lmi || Lmist)
+ return(Lmi);
+/*
+ * Access mount information.
+ */
+ if ((n = getmntinfo(&mb, MNT_NOWAIT)) <= 0) {
+ (void) fprintf(stderr, "%s: no mount information\n", Pn);
+ return(0);
+ }
+/*
+ * Read mount information.
+ */
+ for (; n; n--, mb++) {
+
+ if (!mb->f_type)
+ continue;
+ /*
+ * Interpolate a possible symbolic directory link.
+ */
+ if (dn)
+ (void) free((FREE_P *)dn);
+ if (!(dn = mkstrcpy(mb->f_mntonname, (MALLOC_S *)NULL))) {
+
+no_space_for_mount:
+
+ (void) fprintf(stderr, "%s: no space for mount at ", Pn);
+ safestrprt(mb->f_mntonname, stderr, 0);
+ (void) fprintf(stderr, " (");
+ safestrprt(mb->f_mntfromname, stderr, 0);
+ (void) fprintf(stderr, ")\n");
+ Exit(1);
+ }
+ if (!(ln = Readlink(dn))) {
+ if (!Fwarn) {
+ (void) fprintf(stderr,
+ " Output information may be incomplete.\n");
+ }
+ continue;
+ }
+ if (ln != dn) {
+ (void) free((FREE_P *)dn);
+ dn = ln;
+ }
+ if (*dn != '/')
+ continue;
+ /*
+ * Stat() the directory.
+ */
+ if (statsafely(dn, &sb)) {
+ if (!Fwarn) {
+ (void) fprintf(stderr, "%s: WARNING: can't stat() ", Pn);
+
+ safestrprt(mb->f_fstypename, stderr, 0);
+
+ (void) fprintf(stderr, " file system ");
+ safestrprt(mb->f_mntonname, stderr, 1);
+ (void) fprintf(stderr,
+ " Output information may be incomplete.\n");
+ }
+ (void) bzero((char *)&sb, sizeof(sb));
+ sb.st_dev = (dev_t)mb->f_fsid.val[0];
+ sb.st_mode = S_IFDIR | 0777;
+ if (!Fwarn) {
+ (void) fprintf(stderr,
+ " assuming \"dev=%x\" from mount table\n",
+ sb.st_dev);
+ }
+ }
+ /*
+ * Allocate and fill a local mount structure.
+ */
+ if (!(mtp = (struct mounts *)malloc(sizeof(struct mounts))))
+ goto no_space_for_mount;
+ mtp->dir = dn;
+ dn = (char *)NULL;
+
+ mtp->next = Lmi;
+ mtp->dev = sb.st_dev;
+ mtp->rdev = sb.st_rdev;
+ mtp->inode = (INODETYPE)sb.st_ino;
+ mtp->mode = sb.st_mode;
+ /*
+ * Interpolate a possible file system (mounted-on) device name link.
+ */
+ if (!(dn = mkstrcpy(mb->f_mntfromname, (MALLOC_S *)NULL)))
+ goto no_space_for_mount;
+ mtp->fsname = dn;
+ ln = Readlink(dn);
+ dn = (char *)NULL;
+ /*
+ * Stat() the file system (mounted-on) name and add file system
+ * information to the local mount table entry.
+ */
+ if (!ln || statsafely(ln, &sb))
+ sb.st_mode = 0;
+ mtp->fsnmres = ln;
+ mtp->fs_mode = sb.st_mode;
+ Lmi = mtp;
+ }
+/*
+ * Clean up and return the local mount info table address.
+ */
+ if (dn)
+ (void) free((FREE_P *)dn);
+ Lmist = 1;
+ return(Lmi);
+}
+
+
+/*
+ * readvfs() - read vfs structure
+ */
+
+struct l_vfs *
+readvfs(vm)
+ KA_T vm; /* kernel mount address from vnode */
+{
+ struct mount m;
+ struct l_vfs *vp;
+/*
+ * Search for match on existing entry.
+ */
+ for (vp = Lvfs; vp; vp = vp->next) {
+ if (vm == vp->addr)
+ return(vp);
+ }
+/*
+ * Read the (new) mount structure, allocate a local entry, and fill it.
+ */
+ if (kread((KA_T)vm, (char *)&m, sizeof(m)) != 0)
+ return((struct l_vfs *)NULL);
+ if (!(vp = (struct l_vfs *)malloc(sizeof(struct l_vfs)))) {
+ (void) fprintf(stderr, "%s: PID %d, no space for vfs\n",
+ Pn, Lp->pid);
+ Exit(1);
+ }
+ if (!(vp->dir = mkstrcpy(m.m_stat.f_mntonname, (MALLOC_S *)NULL))
+ || !(vp->fsname = mkstrcpy(m.m_stat.f_mntfromname, (MALLOC_S *)NULL)))
+ {
+ (void) fprintf(stderr, "%s: PID %d, no space for mount names\n",
+ Pn, Lp->pid);
+ Exit(1);
+ }
+ vp->addr = vm;
+ vp->fsid = m.m_stat.f_fsid;
+ {
+ int len;
+
+ if ((len = strlen(m.m_stat.f_fstypename))) {
+ if (len > (MFSNAMELEN - 1))
+ len = MFSNAMELEN - 1;
+ if (!(vp->typnm = mkstrcat(m.m_stat.f_fstypename, len,
+ (char *)NULL, -1, (char *)NULL, -1,
+ (MALLOC_S *)NULL)))
+ {
+ (void) fprintf(stderr,
+ "%s: no space for fs type name: ", Pn);
+ safestrprt(m.m_stat.f_fstypename, stderr, 1);
+ Exit(1);
+ }
+ } else
+ vp->typnm = "";
+ }
+ vp->next = Lvfs;
+ Lvfs = vp;
+ return(vp);
+}
diff --git a/dialects/darwin/kmem/dnode.c b/dialects/darwin/kmem/dnode.c
new file mode 100644
index 0000000..d634c62
--- /dev/null
+++ b/dialects/darwin/kmem/dnode.c
@@ -0,0 +1,1038 @@
+/*
+ * dnode.c - Darwin node functions for /dev/kmem-based lsof
+ */
+
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907. All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ * consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Credit to the authors and Purdue
+ * University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
+static char *rcsid = "$Id: dnode.c,v 1.11 2006/03/27 23:24:50 abe Exp $";
+#endif
+
+
+#include "lsof.h"
+
+
+/*
+ * Local function prototypes
+ */
+
+#if DARWINV<600
+_PROTOTYPE(static int lkup_dev_tty,(dev_t *dr, dev_t *rdr, INODETYPE *ir));
+#endif /* DARWINV<600 */
+
+#if DARWINV>=800
+_PROTOTYPE(static char *getvpath,(KA_T va, struct vnode *rv));
+_PROTOTYPE(static int readvname,(KA_T addr, char *buf, int buflen));
+#endif /* DARWINV>=800 */
+
+
+#if DARWINV>=800
+/*
+ * getvpath() - get vnode path
+ * adapted from build_path() (.../bsd/vfs/vfs_subr.c)
+ */
+
+static char *
+getvpath(va, rv)
+ KA_T va; /* kernel address of the rightmost
+ * vnode in the path */
+ struct vnode *rv; /* pointer to rightmost vnode */
+{
+ char *ap;
+ static char *bp = (char *)NULL;
+ static size_t bl = (size_t)(MAXPATHLEN + MAXPATHLEN + 1);
+ static char *cb = (char *)NULL;
+ static size_t cbl = (size_t)0;
+ static int ce = 0;
+ struct mount mb;
+ int pl, vnl;
+ char *pp, vn[MAXPATHLEN+1];
+ struct vnode vb;
+ KA_T vas = va;
+/*
+ * Initialize the path assembly.
+ */
+ if (!bp) {
+ if (!(bp = (char *)malloc((MALLOC_S)bl))) {
+ (void) fprintf(stderr, "%s: no space (%d) for path assembly\n",
+ Pn, (int)bl);
+ Exit(1);
+ }
+ }
+ pp = bp + bl - 1;
+ *pp = '\0';
+ pl = 0;
+/*
+ * Process the starting vnode.
+ */
+ if (!va)
+ return(0);
+ if ((rv->v_flag & VROOT) && rv->v_mount) {
+
+ /*
+ * This is the root of a file system and it has a mount structure.
+ * Read the mount structure.
+ */
+ if (kread((KA_T)rv->v_mount, (char *)&mb, sizeof(mb)))
+ return(0);
+ if (mb.mnt_flag & MNT_ROOTFS) {
+
+ /*
+ * This is the root file system, so the path is "/".
+ */
+ pp--;
+ *pp = '/';
+ pl = 1;
+ goto getvpath_alloc;
+ } else {
+
+ /*
+ * Get the covered vnode's pointer and read it. Use it to
+ * form the path.
+ */
+ if ((va = (KA_T)mb.mnt_vnodecovered)) {
+ if (readvnode(va, &vb))
+ return(0);
+ }
+ }
+ } else {
+
+ /*
+ * Use the supplied vnode.
+ */
+ vb = *rv;
+ }
+/*
+ * Accumulate the path from the vnode chain.
+ */
+ while (va && ((KA_T)vb.v_parent != va)) {
+ if (!vb.v_name) {
+
+ /*
+ * If there is no name pointer or parent, the assembly is complete.
+ */
+ if (vb.v_parent) {
+
+ /*
+ * It is an error if there is a parent but no name.
+ */
+ return((char *)NULL);
+ }
+ break;
+ }
+ /*
+ * Read the name and add it to the assembly.
+ */
+ if ((vnl = readvname((KA_T)vb.v_name, vn, sizeof(vn))) <= 0)
+ return((char *)NULL);
+ if ((vnl + 1 + pl + 1) > bl)
+ return((char *)NULL);
+ memmove((void *)(pp - vnl), (void *)vn, vnl);
+ pp -= (vnl + 1);
+ *pp = '/';
+ pl += vnl + 1;
+ if ((va == vas) && (vb.v_flag & VROOT)) {
+
+ /*
+ * This is the starting vnode and it is a root vnode. Read its
+ * mount structure.
+ */
+ if (vb.v_mount) {
+ if (kread((KA_T)vb.v_mount, (char *)&mb, sizeof(mb)))
+ return((char *)NULL);
+ if (mb.mnt_vnodecovered) {
+
+ /*
+ * If there's a covered vnode, read it and use it's parent
+ * vnode pointer.
+ */
+ if ((va = (KA_T)mb.mnt_vnodecovered)) {
+ if (readvnode(va, &vb))
+ return((char *)NULL);
+ va = (KA_T)vb.v_parent;
+ }
+ } else
+ va = (KA_T)NULL;
+ } else
+ va = (KA_T)NULL;
+ } else
+ va = (KA_T)vb.v_parent;
+ /*
+ * If there's a parent vnode, read it.
+ */
+ if (va) {
+ if (readvnode(va, &vb))
+ return((char *)NULL);
+ if ((vb.v_flag & VROOT) && vb.v_mount) {
+
+ /*
+ * The mount point has been reached. Read the mount structure
+ * and use its covered vnode pointer.
+ */
+ if (kread((KA_T)vb.v_mount, (char *)&mb, sizeof(mb)))
+ return((char *)NULL);
+ if ((va = (KA_T)mb.mnt_vnodecovered)) {
+ if (readvnode(va, &vb))
+ return((char *)NULL);
+ }
+ }
+ }
+ }
+/*
+ * As a special case the following code attempts to trim a path that is
+ * larger than MAXPATHLEN by seeing if the lsof process CWD can be removed
+ * from the start of the path to make it MAXPATHLEN characters or less.
+ */
+ if (pl > MAXPATHLEN) {
+
+ /*
+ * Get the cwd. If that can't be done, return an error.
+ */
+ if (ce)
+ return((char *)NULL);
+ if (!cb) {
+ if (!(cb = (char *)malloc((MALLOC_S)(MAXPATHLEN + 1)))) {
+ (void) fprintf(stderr, "%s: no space (%d) for CWD\n",
+ Pn, (int)bl);
+ Exit(1);
+ }
+ if (!getcwd(cb, (size_t)(MAXPATHLEN + 1))) {
+ if (!Fwarn) {
+ (void) fprintf(stderr, "%s: WARNING: can't get CWD\n",
+ Pn);
+ }
+ ce = 1;
+ return((char *)NULL);
+ }
+ cb[MAXPATHLEN - 1] = '\0';
+ if (!(cbl = (size_t)strlen(cb))) {
+ if (!Fwarn) {
+ (void) fprintf(stderr, "%s: WARNING: CWD is NULL\n",
+ Pn);
+ }
+ ce = 1;
+ return((char *)NULL);
+ }
+ }
+ /*
+ * See if trimming the CWD shortens the path to MAXPATHLEN or less.
+ */
+ if ((pl <= cbl) || strncmp(cb, pp, cbl))
+ return((char *)NULL);
+ pp += cbl;
+ pl -= cbl;
+ if (cb[cbl - 1] == '/') {
+
+ /*
+ * The CWD ends in a '/', so the path must not begin with one. If
+ * it does, no trimming can be done.
+ */
+ if (*pp == '/')
+ return((char *)NULL);
+ } else {
+
+ /*
+ * The CWD doesn't end in a '/', so the path must begin with one.
+ * If it doesn't, no trimming can be done.
+ */
+ if (*pp != '/')
+ return((char *)NULL);
+ /*
+ * Skip all leading path '/' characters. Some characters must
+ * remain.
+ */
+ while ((pl > 0) && (*pp == '/')) {
+ pp++;
+ pl--;
+ }
+ if (!pl)
+ return((char *)NULL);
+ }
+ }
+/*
+ * Allocate space for the assembled path, including terminator, and return its
+ * pointer.
+ */
+
+getvpath_alloc:
+
+ if (!(ap = (char *)malloc(pl + 1))) {
+ (void) fprintf(stderr, "%s: no getvpath space (%d)\n",
+ Pn, pl + 1);
+ Exit(1);
+ }
+ (void) memmove(ap, pp, pl + 1);
+ return(ap);
+}
+#endif /* DARWINV>=800 */
+
+
+#if DARWINV<600
+/*
+ * lkup_dev_tty() - look up /dev/tty
+ */
+
+static int
+lkup_dev_tty(dr, rdr, ir)
+ dev_t *dr; /* place to return device number */
+ dev_t *rdr; /* place to return raw device number */
+ INODETYPE *ir; /* place to return inode number */
+{
+ int i;
+
+ readdev(0);
+ for (i = 0; i < Ndev; i++) {
+ if (strcmp(Devtp[i].name, "/dev/tty") == 0) {
+ *dr = DevDev;
+ *rdr = Devtp[i].rdev;
+ *ir = (INODETYPE)Devtp[i].inode;
+ return(1);
+ }
+ }
+ return(-1);
+}
+#endif /* DARWINV<600 */
+
+
+/*
+ * process_node() - process vnode
+ */
+
+void
+process_node(va)
+ KA_T va; /* vnode kernel space address */
+{
+ dev_t dev = (dev_t)0;
+ dev_t rdev = (dev_t)0;
+ unsigned char devs = 0;
+ unsigned char rdevs = 0;
+
+#if DARWINV<800
+ struct devnode *d = (struct devnode *)NULL;
+ struct devnode db;
+ unsigned char lt;
+ char dev_ch[32];
+
+# if defined(HASFDESCFS)
+ struct fdescnode *f = (struct fdescnode *)NULL;
+ struct fdescnode fb;
+# endif /* defined(HASFDESCFS) */
+
+ static INODETYPE fi;
+ static dev_t fdev, frdev;
+ static int fs = 0;
+ struct inode *i = (struct inode *)NULL;
+ struct inode ib;
+ struct lockf lf, *lff, *lfp;
+ struct nfsnode *n = (struct nfsnode *)NULL;
+ struct nfsnode nb;
+#else /* DARWINV>=800 */
+ struct stat sb;
+ char *vn;
+#endif /* DARWINV<800 */
+
+ char *ty;
+ enum vtype type;
+ struct vnode *v, vb;
+ struct l_vfs *vfs;
+
+#if DARWINV<600
+ struct hfsnode *h = (struct hfsnode *)NULL;
+ struct hfsnode hb;
+ struct hfsfilemeta *hm = (struct hfsfilemeta *)NULL;
+ struct hfsfilemeta hmb;
+#else /* DARWINV>=600 */
+# if DARWINV<800
+ struct cnode *h = (struct cnode *)NULL;
+ struct cnode hb;
+ struct filefork *hf = (struct filefork *)NULL;
+ struct filefork hfb;
+# endif /* DARWINV<800 */
+#endif /* DARWINV<600 */
+
+#if defined(HAS9660FS)
+ dev_t iso_dev;
+ int iso_dev_def = 0;
+ INODETYPE iso_ino;
+ long iso_links;
+ int iso_stat = 0;
+ SZOFFTYPE iso_sz;
+#endif /* defined(HAS9660FS) */
+
+/*
+ * Read the vnode.
+ */
+ if ( ! va) {
+ enter_nm("no vnode address");
+ return;
+ }
+ v = &vb;
+ if (readvnode(va, v)) {
+ enter_nm(Namech);
+ return;
+ }
+ type = v->v_type;
+
+#if defined(HASNCACHE)
+ Lf->na = va;
+# if defined(HASNCVPID)
+ Lf->id = v->v_id;
+# endif /* defined(HASNCVPID) */
+#endif /* defined(HASNCACHE) */
+
+#if defined(HASFSTRUCT)
+ Lf->fna = va;
+ Lf->fsv |= FSV_NI;
+#endif /* defined(HASFSTRUCT) */
+
+/*
+ * Get the vnode type.
+ */
+ if (!v->v_mount)
+ vfs = (struct l_vfs *)NULL;
+ else {
+ vfs = readvfs((KA_T)v->v_mount);
+ if (vfs) {
+ if (strcasecmp(vfs->typnm, "nfs") == 0)
+ Ntype = N_NFS;
+
+#if DARWINV<130
+ else if (strcasecmp(vfs->typnm, "afpfs") == 0)
+ Ntype = N_AFPFS;
+#endif /* DARWINV<130 */
+
+ }
+ }
+ if (Ntype == N_REGLR) {
+ switch (v->v_type) {
+ case VFIFO:
+ Ntype = N_FIFO;
+ break;
+ default:
+ break;
+ }
+ }
+
+#if DARWINV<800
+/*
+ * Define the specific node pointer.
+ */
+ switch (v->v_tag) {
+
+# if DARWINV>120
+ case VT_AFP:
+ break;
+# endif /* DARWINV>120 */
+
+# if DARWINV>120
+ case VT_CDDA:
+ break;
+# endif /* DARWINV>120 */
+
+# if DARWINV>120
+ case VT_CIFS:
+ break;
+# endif /* DARWINV>120 */
+
+ case VT_DEVFS:
+ if (!v->v_data
+ || kread((KA_T)v->v_data, (char *)&db, sizeof(db))) {
+ (void) snpf(Namech, Namechl, "no devfs node: %#x", v->v_data);
+ enter_nm(Namech);
+ return;
+ }
+ d = &db;
+ break;
+
+# if defined(HASFDESCFS)
+ case VT_FDESC:
+ if (!v->v_data
+ || kread((KA_T)v->v_data, (char *)&fb, sizeof(fb))) {
+ (void) snpf(Namech, Namechl, "no fdesc node: %s",
+ print_kptr((KA_T)v->v_data, (char *)NULL, 0));
+ enter_nm(Namech);
+ return;
+ }
+ f = &fb;
+ break;
+# endif /* defined(HASFDESCFS) */
+
+ case VT_HFS:
+
+# if DARWINV<130
+ if (Ntype != N_AFPFS) {
+# endif /* DARWINV<130 */
+
+ if (!v->v_data
+ || kread((KA_T)v->v_data, (char *)&hb, sizeof(hb))) {
+ (void) snpf(Namech, Namechl, "no hfs node: %s",
+ print_kptr((KA_T)v->v_data, (char *)NULL, 0));
+ enter_nm(Namech);
+ return;
+ }
+ h = &hb;
+
+# if DARWINV<600
+ if (!h->h_meta
+ || kread((KA_T)h->h_meta, (char *)&hmb, sizeof(hmb))) {
+ (void) snpf(Namech, Namechl, "no hfs node metadata: %s",
+ print_kptr((KA_T)v->v_data, (char *)NULL, 0));
+ enter_nm(Namech);
+ return;
+ }
+ hm = &hmb;
+# else /* DARWINV>=600 */
+ if (v->v_type == VDIR)
+ break;
+ if (h->c_rsrc_vp == v)
+ hf = h->c_rsrcfork;
+ else
+ hf = h->c_datafork;
+ if (!hf
+ || kread((KA_T)hf, (char *)&hfb, sizeof(hfb))) {
+ (void) snpf(Namech, Namechl, "no hfs node fork: %s",
+ print_kptr((KA_T)v->v_data, (char *)NULL, 0));
+ enter_nm(Namech);
+ return;
+ }
+ hf = &hfb;
+# endif /* DARWINV<600 */
+
+# if DARWINV<130
+ }
+# endif /* DARWINV<130 */
+
+ break;
+
+# if defined(HAS9660FS)
+ case VT_ISOFS:
+ if (read_iso_node(v, &iso_dev, &iso_dev_def, &iso_ino, &iso_links,
+ &iso_sz))
+ {
+ (void) snpf(Namech, Namechl, "no iso node: %s",
+ print_kptr((KA_T)v->v_data, (char *)NULL, 0));
+ enter_nm(Namech);
+ return;
+ }
+ iso_stat = 1;
+ break;
+# endif /* defined(HAS9660FS) */
+
+ case VT_NFS:
+ if (!v->v_data
+ || kread((KA_T)v->v_data, (char *)&nb, sizeof(nb))) {
+ (void) snpf(Namech, Namechl, "no nfs node: %s",
+ print_kptr((KA_T)v->v_data, (char *)NULL, 0));
+ enter_nm(Namech);
+ return;
+ }
+ n = &nb;
+ break;
+
+# if DARWINV>120
+ case VT_UDF:
+ break;
+# endif /* DARWINV>120 */
+
+ case VT_UFS:
+ if (!v->v_data
+ || kread((KA_T)v->v_data, (char *)&ib, sizeof(ib))) {
+ (void) snpf(Namech, Namechl, "no ufs node: %s",
+ print_kptr((KA_T)v->v_data, (char *)NULL, 0));
+ enter_nm(Namech);
+ return;
+ }
+ i = &ib;
+ if ((lff = i->i_lockf)) {
+
+ /*
+ * Determine the lock state.
+ */
+ lfp = lff;
+ do {
+ if (kread((KA_T)lfp, (char *)&lf, sizeof(lf)))
+ break;
+ lt = 0;
+ switch (lf.lf_flags & (F_FLOCK|F_POSIX)) {
+ case F_FLOCK:
+ if (Cfp && (struct file *)lf.lf_id == Cfp)
+ lt = 1;
+ break;
+ case F_POSIX:
+ if ((KA_T)lf.lf_id == Kpa)
+ lt = 1;
+ break;
+ }
+ if (!lt)
+ continue;
+ if (lf.lf_start == (off_t)0
+ && lf.lf_end == 0xffffffffffffffffLL)
+ lt = 1;
+ else
+ lt = 0;
+ if (lf.lf_type == F_RDLCK)
+ Lf->lock = lt ? 'R' : 'r';
+ else if (lf.lf_type == F_WRLCK)
+ Lf->lock = lt ? 'W' : 'w';
+ else if (lf.lf_type == (F_RDLCK | F_WRLCK))
+ Lf->lock = 'u';
+ break;
+ } while ((lfp = lf.lf_next) && lfp != lff);
+ }
+ break;
+
+# if DARWINV>120
+ case VT_WEBDAV:
+ break;
+# endif /* DARWINV>120 */
+
+ default:
+ if (v->v_type == VBAD || v->v_type == VNON)
+ break;
+ (void) snpf(Namech, Namechl, "unknown file system type: %d",
+ v->v_tag);
+ enter_nm(Namech);
+ return;
+ }
+/*
+ * Get device and type for printing.
+ */
+ if (n) {
+ dev = n->n_vattr.va_fsid;
+ devs = 1;
+ } else if (i) {
+ dev = i->i_dev;
+ devs = 1;
+ if ((type == VCHR) || (type == VBLK)) {
+ rdev = i->i_rdev ;
+ rdevs = 1;
+ }
+ }
+
+# if defined(HASFDESCFS)
+ else if (f) {
+ if (f->fd_link
+ && !kread((KA_T)f->fd_link, Namech, Namechl -1))
+ Namech[Namechl - 1] = '\0';
+
+# if DARWINV<600
+ else if (f->fd_type == Fctty) {
+ if (fs == 0)
+ fs = lkup_dev_tty(&fdev, &frdev, &fi);
+ if (fs == 1) {
+ dev = fdev;
+ rdev = frdev;
+ devs = Lf->inp_ty = rdevs = 1;
+ Lf->inode = fi;
+ }
+ }
+ }
+# endif /* DARWINV<600 */
+# endif /* defined(HASFDESCFS) */
+
+ else if (h) {
+
+# if DARWINV<600
+ dev = hm->h_dev;
+# else /* DARWINV>=600 */
+ dev = h->c_dev;
+# endif /* DARWINV<600 */
+
+ devs = 1;
+ if ((type == VCHR) || (type == VBLK)) {
+
+# if DARWINV<600
+ rdev = hm->h_rdev;
+# else /* DARWINV>=600 */
+ rdev = h->c_rdev;
+# endif /* DARWINV<600 */
+
+ rdevs = 1;
+ }
+ } else if (d) {
+ dev = DevDev;
+ devs = 1;
+ rdev = d->dn_typeinfo.dev;
+ rdevs = 1;
+ }
+
+# if defined(HAS9660FS)
+ else if (iso_stat && iso_dev_def) {
+ dev = iso_dev;
+ devs = Lf->inp_ty = 1;
+ }
+# endif /* defined(HAS9660FS) */
+
+
+/*
+ * Obtain the inode number.
+ */
+ if (i) {
+ Lf->inode = (INODETYPE)i->i_number;
+ Lf->inp_ty = 1;
+ } else if (n) {
+ Lf->inode = (INODETYPE)n->n_vattr.va_fileid;
+ Lf->inp_ty = 1;
+ } else if (h) {
+
+# if DARWINV<600
+ Lf->inode = (INODETYPE)hm->h_nodeID;
+# else /* DARWINV>=600 */
+ Lf->inode = (INODETYPE)h->c_fileid;
+# endif /* DARWINV<600 */
+
+ Lf->inp_ty = 1;
+ }
+
+# if defined(HAS9660FS)
+ else if (iso_stat) {
+ Lf->inode = iso_ino;
+ Lf->inp_ty = 1;
+ }
+# endif /* defined(HAS9660FS) */
+
+/*
+ * Obtain the file size.
+ */
+ if (Foffset)
+ Lf->off_def = 1;
+ else {
+ switch (Ntype) {
+ case N_FIFO:
+ if (!Fsize)
+ Lf->off_def = 1;
+ break;
+ case N_NFS:
+ if (n) {
+ Lf->sz = (SZOFFTYPE)n->n_vattr.va_size;
+ Lf->sz_def = 1;
+ }
+ break;
+
+# if DARWINV<130
+ case N_AFPFS:
+ break;
+# endif /* DARWINV<130 */
+
+ case N_REGLR:
+ if (type == VREG || type == VDIR) {
+ if (i) {
+ Lf->sz = (SZOFFTYPE)i->i_size;
+ Lf->sz_def = 1;
+ } else if (h) {
+
+# if DARWINV<600
+ Lf->sz = (type == VDIR) ? (SZOFFTYPE)hm->h_size
+ : (SZOFFTYPE)h->fcbEOF;
+# else /* DARWINV>=600 */
+ if (type == VDIR)
+ Lf->sz = (SZOFFTYPE)h->c_nlink * 128;
+ else
+ Lf->sz = (SZOFFTYPE)hf->ff_size;
+# endif /* DARWINV<600 */
+
+ Lf->sz_def = 1;
+ }
+
+# if defined(HAS9660FS)
+ else if (iso_stat) {
+ Lf->sz = (SZOFFTYPE)iso_sz;
+ Lf->sz_def = 1;
+ }
+# endif /* defined(HAS9660FS) */
+
+ }
+ else if ((type == VCHR || type == VBLK) && !Fsize)
+ Lf->off_def = 1;
+ break;
+ }
+ }
+/*
+ * Record the link count.
+ */
+ if (Fnlink) {
+ switch(Ntype) {
+ case N_NFS:
+ if (n) {
+ Lf->nlink = (long)n->n_vattr.va_nlink;
+ Lf->nlink_def = 1;
+ }
+ break;
+
+# if DARWINV<130
+ case N_AFPFS:
+ break;
+# endif /* DARWINV<130 */
+
+ case N_REGLR:
+ if (i) {
+ Lf->nlink = (long)i->i_nlink;
+ Lf->nlink_def = 1;
+ } else if (h) {
+
+# if DARWINV<600
+ Lf->nlink = (long)hm->h_nlink;
+# else /* DARWINV>=600 */
+ Lf->nlink = (long)h->c_nlink;
+# endif /* DARWINV<600 */
+
+ Lf->nlink_def = 1;
+ }
+
+# if defined(HAS9660FS)
+ else if (iso_stat) {
+ Lf->nlink = iso_links;
+ Lf->nlink_def = 1;
+ }
+# endif /* defined(HAS9660FS) */
+
+ break;
+ }
+ if (Lf->nlink_def && Nlink && (Lf->nlink < Nlink))
+ Lf->sf |= SELNLINK;
+ }
+#else /* DARWINV>=800 */
+
+/*
+ * Process a vnode for Darwin >= 8.0.
+ */
+ if ((vn = getvpath(va, v))) {
+
+ /*
+ * If the vnode yields a path, get the file's information by doing
+ * a "safe" stat(2) of the path.
+ */
+ if (!statsafely(vn, &sb)) {
+
+ /*
+ * Save file size or offset.
+ */
+ if (Foffset) {
+ Lf->off_def = 1;
+ } else {
+ switch (Ntype) {
+ case N_FIFO:
+ if (!Fsize)
+ Lf->off_def = 1;
+ break;
+ case N_NFS:
+ case N_REGLR:
+ if (type == VREG || type == VDIR) {
+ Lf->sz = sb.st_size;
+ Lf->sz_def = 1;
+ } else if ((type == VCHR || type == VBLK) && !Fsize)
+ Lf->off_def = 1;
+ break;
+ }
+ }
+ /*
+ * Save node number.
+ */
+ Lf->inode = (INODETYPE)sb.st_ino;
+ Lf->inp_ty = 1;
+ /*
+ * Optionally save link count.
+ */
+ if (Fnlink) {
+ Lf->nlink = sb.st_nlink;
+ Lf->nlink_def = 1;
+ }
+ /*
+ * Save device number and path.
+ */
+ switch (v->v_tag) {
+ case VT_DEVFS:
+ if (vn)
+ (void) free((FREE_P *)vn);
+ dev = DevDev;
+ devs = 1;
+ break;
+ default :
+ Lf->V_path = vn;
+ dev = sb.st_dev;
+ devs = 1;
+ break;
+ }
+ /*
+ * Save character and block device number.
+ */
+ if ((type == VCHR) || (type == VBLK)) {
+ rdev = sb.st_rdev;
+ rdevs = 1;
+ }
+ } else {
+
+ /*
+ * Indicate a stat(2) failure in Namech[].
+ */
+ (void) snpf(Namech, Namechl, "stat(%s): %s", vn,
+ strerror(errno));
+ (void) free((FREE_P *)vn);
+ }
+ /*
+ * Record an NFS file.
+ */
+ if (vfs && !strcmp(vfs->typnm, "nfs"))
+ Ntype = N_NFS;
+ }
+#endif /* DARWINV>=800 */
+
+/*
+ * Record an NFS file selection.
+ */
+ if (Ntype == N_NFS && Fnfs)
+ Lf->sf |= SELNFS;
+/*
+ * Save the file system names.
+ */
+ if (vfs) {
+ Lf->fsdir = vfs->dir;
+ Lf->fsdev = vfs->fsname;
+ }
+/*
+ * Save the device numbers and their states.
+ *
+ * Format the vnode type, and possibly the device name.
+ */
+ Lf->dev = dev;
+ Lf->dev_def = devs;
+ Lf->rdev = rdev;
+ Lf->rdev_def = rdevs;
+ switch (type) {
+ case VNON:
+ ty ="VNON";
+ break;
+ case VREG:
+ ty = "VREG";
+ break;
+ case VDIR:
+ ty = "VDIR";
+ break;
+ case VBLK:
+ ty = "VBLK";
+ Ntype = N_BLK;
+ break;
+ case VCHR:
+ ty = "VCHR";
+ Ntype = N_CHR;
+ break;
+ case VLNK:
+ ty = "VLNK";
+ break;
+
+#if defined(VSOCK)
+ case VSOCK:
+ ty = "SOCK";
+ break;
+#endif /* defined(VSOCK) */
+
+ case VBAD:
+ ty = "VBAD";
+ break;
+ case VFIFO:
+ ty = "FIFO";
+ break;
+ default:
+ (void) snpf(Lf->type, sizeof(Lf->type), "%04o", (type & 0xfff));
+ ty = (char *)NULL;
+ }
+ if (ty)
+ (void) snpf(Lf->type, sizeof(Lf->type), "%s", ty);
+ Lf->ntype = Ntype;
+/*
+ * Handle some special cases:
+ *
+ * ioctl(fd, TIOCNOTTY) files;
+ * memory node files;
+ * /proc files.
+ */
+ if (type == VBAD)
+ (void) snpf(Namech, Namechl, "(revoked)");
+
+#if defined(HASBLKDEV)
+/*
+ * If this is a VBLK file and it's missing an inode number, try to
+ * supply one.
+ */
+ if ((Lf->inp_ty == 0) && (type == VBLK))
+ find_bl_ino();
+#endif /* defined(HASBLKDEV) */
+
+/*
+ * If this is a VCHR file and it's missing an inode number, try to
+ * supply one.
+ */
+ if ((Lf->inp_ty == 0) && (type == VCHR))
+ find_ch_ino();
+/*
+ * Test for specified file.
+ */
+ if (Sfile && is_file_named((char *)NULL,
+ ((type == VCHR) || (type == VBLK) ? 1
+ : 0)))
+ Lf->sf |= SELNM;
+/*
+ * Enter name characters.
+ */
+ if (Namech[0])
+ enter_nm(Namech);
+}
+
+
+#if DARWINV>=800
+/*
+ * readvname() - read vnode's path name
+ */
+
+static int
+readvname(addr, buf, buflen)
+ KA_T addr; /* kernel v_path address */
+ char *buf; /* receiving buffer */
+ int buflen; /* sizeof(buf) */
+{
+ int n, rl;
+/*
+ * Read the name 32 characters at a time, until a NUL character
+ * has been read or the buffer has been filled.
+ */
+ for (n = 0; n < buflen; addr += 32, n += 32) {
+ rl = buflen - n;
+ if (rl > 32)
+ rl = 32;
+ if (kread(addr, &buf[n], rl))
+ return(0);
+ buf[n + rl] = '\0';
+ if ((rl = (int)strlen(&buf[n])) < 32) {
+ return(n + rl);
+ }
+ }
+ return(0);
+}
+#endif /* DARWINV>=800 */
diff --git a/dialects/darwin/kmem/dnode1.c b/dialects/darwin/kmem/dnode1.c
new file mode 100644
index 0000000..20a76c1
--- /dev/null
+++ b/dialects/darwin/kmem/dnode1.c
@@ -0,0 +1,107 @@
+/*
+ * dnode1.c - Darwin node functions for /dev/kmem-based lsof
+ *
+ * This module must be separate to keep separate the multiple kernel inode
+ * structure definitions.
+ */
+
+
+/*
+ * Copyright 1995 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907. All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ * consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Credit to the authors and Purdue
+ * University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
+static char *rcsid = "$Id: dnode1.c,v 1.3 2005/11/01 20:24:51 abe Exp $";
+#endif
+
+#include "lsof.h"
+
+#if defined(HAS9660FS)
+
+/*
+ * Do a little preparation for #include'ing cd9660_node.h, then #include it.
+ */
+
+#undef i_size;
+#undef doff_t
+#undef IN_ACCESS
+
+struct vop_abortop_args { int dummy; };
+struct vop_access_args { int dummy; };
+struct vop_blkatoff_args { int dummy; };
+struct vop_bmap_args { int dummy; };
+struct vop_close_args { int dummy; };
+struct vop_getattr_args { int dummy; };
+struct vop_inactive_args { int dummy; };
+struct vop_ioctl_args { int dummy; };
+struct vop_islocked_args { int dummy; };
+struct vop_lock_args { int dummy; };
+struct vop_lookup_args { int dummy; };
+struct vop_mmap_args { int dummy; };
+struct vop_open_args { int dummy; };
+struct vop_pathconf_args { int dummy; };
+struct vop_print_args { int dummy; };
+struct vop_read_args { int dummy; };
+struct vop_readdir_args { int dummy; };
+struct vop_readlink_args { int dummy; };
+struct vop_reclaim_args { int dummy; };
+struct vop_seek_args { int dummy; };
+struct vop_select_args { int dummy; };
+struct vop_strategy_args { int dummy; };
+struct vop_unlock_args { int dummy; };
+
+#include <isofs/cd9660/cd9660_node.h>
+
+/*
+ * read_iso_node() -- read CD 9660 iso_node
+ */
+
+int
+read_iso_node(v, d, dd, ino, nl, sz)
+ struct vnode *v; /* containing vnode */
+ dev_t *d; /* returned device number */
+ int *dd; /* returned device-defined flag */
+ INODETYPE *ino; /* returned inode number */
+ long *nl; /* returned number of links */
+ SZOFFTYPE *sz; /* returned size */
+{
+
+ struct iso_node i;
+
+ if (!v->v_data
+ || kread((KA_T)v->v_data, (char *)&i, sizeof(i)))
+ return(1);
+
+ *d = i.i_dev;
+ *dd = 1;
+ *ino = (INODETYPE)i.i_number;
+ *nl = (long)i.inode.iso_links;
+ *sz = (SZOFFTYPE)i.i_size;
+
+ return(0);
+}
+#endif /* defined(HAS9660FS) */
diff --git a/dialects/darwin/kmem/dproc.c b/dialects/darwin/kmem/dproc.c
new file mode 100644
index 0000000..6fb0dd6
--- /dev/null
+++ b/dialects/darwin/kmem/dproc.c
@@ -0,0 +1,763 @@
+/*
+ * dproc.c - Darwin process access functions for /dev/kmem-based lsof
+ */
+
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907. All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ * consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Credit to the authors and Purdue
+ * University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
+static char *rcsid = "$Id: dproc.c,v 1.8 2005/11/01 20:24:51 abe Exp $";
+#endif
+
+#include "lsof.h"
+
+#include <mach/mach_traps.h>
+#include <mach/mach_init.h>
+#include <mach/message.h>
+#include <mach/vm_map.h>
+
+
+/*
+ * Local definitions
+ */
+
+#define NPHASH 1024 /* Phash bucket count --
+ * MUST BE A POWER OF 2!!! */
+#define PHASH(a) (((int)((a * 31415) >> 3)) & (NPHASH - 1))
+#define PINCRSZ 256 /* Proc[] size inrement */
+
+
+/*
+ * Local structures
+ */
+
+struct phash {
+ KA_T ka; /* kernel proc struct address */
+ struct proc *la; /* local proc struct address */
+ struct phash *next; /* next phash entry */
+};
+
+
+/*
+ * Local function prototypes
+ */
+
+_PROTOTYPE(static pid_t get_parent_pid,(KA_T kpa));
+_PROTOTYPE(static int read_procs,());
+_PROTOTYPE(static void process_map,(pid_t pid));
+_PROTOTYPE(static void enter_vn_text,(KA_T va, int *n));
+
+#if DARWINV>=700
+_PROTOTYPE(static char *getcmdnm,(pid_t pid));
+#endif /* DARWINV>=700 */
+
+_PROTOTYPE(static void get_kernel_access,(void));
+
+
+/*
+ * Local static values
+ */
+
+static KA_T Akp = (KA_T)NULL; /* kernel allproc chain address */
+static int Np = 0; /* PA[] and Proc[] entry count */
+static int Npa = 0; /* Proc[] structure allocation count */
+static MALLOC_S Nv = 0; /* allocated Vp[] entries */
+static KA_T *Pa = (KA_T *)NULL; /* Proc[] addresses */
+struct phash **Phash = (struct phash **)NULL;
+ /* kernel proc address hash pointers */
+static struct proc *Proc = (struct proc *)NULL;
+ /* local copy of prc struct chain */
+static KA_T *Vp = NULL; /* vnode address cache */
+
+
+/*
+ * enter_vn_text() - enter a vnode text reference
+ */
+
+static void
+enter_vn_text(va, n)
+ KA_T va; /* vnode address */
+ int *n; /* Vp[] entries in use */
+{
+ int i;
+/*
+ * Ignore the request if the vnode has already been entered.
+ */
+ for (i = 0; i < *n; i++) {
+ if (va == Vp[i])
+ return;
+ }
+/*
+ * Save the text file information.
+ */
+ alloc_lfile(" txt", -1);
+ Cfp = (struct file *)NULL;
+ process_node(va);
+ if (Lf->sf)
+ link_lfile();
+ if (i >= Nv) {
+
+ /*
+ * Allocate space for remembering the vnode.
+ */
+ Nv += 10;
+ if (!Vp)
+ Vp=(KA_T *)malloc((MALLOC_S)(sizeof(struct vnode *)*10));
+ else
+ Vp=(KA_T *)realloc((MALLOC_P *)Vp,(MALLOC_S)(Nv*sizeof(KA_T)));
+ if (!Vp) {
+ (void) fprintf(stderr, "%s: no txt ptr space, PID %d\n",
+ Pn, Lp->pid);
+ Exit(1);
+ }
+ }
+/*
+ * Remember the vnode.
+ */
+ Vp[*n] = va;
+ (*n)++;
+}
+
+
+/*
+ * gather_proc_info() -- gather process information
+ */
+
+void
+gather_proc_info()
+{
+ char *cmd;
+ struct filedesc fd;
+ int i, nf;
+ MALLOC_S nb;
+ static struct file **ofb = NULL;
+ static int ofbb = 0;
+ struct proc *p;
+ int pgid;
+ int ppid = 0;
+ static char *pof = (char *)NULL;
+ static int pofb = 0;
+ short pss, sf;
+ int px;
+ uid_t uid;
+
+#if DARWINV<800
+ struct pcred pc;
+#else /* DARWINV>=800 */
+ struct ucred uc;
+#endif /* DARWINV<800 */
+
+/*
+ * Read the process table.
+ */
+ if (read_procs()) {
+ (void) fprintf(stderr, "%s: can't read process table\n", Pn);
+ Exit(1);
+ }
+/*
+ * Examine proc structures and their associated information.
+ */
+ for (p = Proc, px = 0; px < Np; p++, px++)
+ {
+
+#if DARWINV<800
+ if (!p->p_cred || kread((KA_T)p->p_cred, (char *)&pc, sizeof(pc)))
+ continue;
+ pgid = pc.p_rgid;
+ uid = pc.p_ruid;
+#else /* DARWINV>=800 */
+ if (!p->p_ucred || kread((KA_T)p->p_ucred, (char *)&uc, sizeof(uc)))
+ continue;
+ pgid = uc.cr_rgid;
+ uid = uc.cr_uid;
+#endif /* DARWINV<800 */
+
+#if defined(HASPPID)
+ ppid = get_parent_pid((KA_T)p->p_pptr);
+#endif /* defined(HASPPID) */
+
+ /*
+ * Get the command name.
+ */
+
+#if DARWINV<700
+ cmd = p->P_COMM;
+#else /* DARWINV>=700 */
+ if (!strcmp(p->p_comm, "LaunchCFMApp")) {
+ if (!(cmd = getcmdnm(p->p_pid)))
+ cmd = p->p_comm;
+ } else
+ cmd = p->p_comm;
+#endif /* DARWINV<700 */
+
+ /*
+ * See if process is excluded.
+ *
+ * Read file structure pointers.
+ */
+ if (is_proc_excl(p->p_pid, pgid, (UID_ARG)uid, &pss, &sf))
+ continue;
+ if (!p->p_fd || kread((KA_T)p->p_fd, (char *)&fd, sizeof(fd)))
+ continue;
+ if (!fd.fd_refcnt || fd.fd_lastfile > fd.fd_nfiles)
+ continue;
+ /*
+ * Allocate a local process structure.
+ *
+ * Set kernel's proc structure address.
+ */
+ if (is_cmd_excl(cmd, &pss, &sf))
+ continue;
+ alloc_lproc(p->p_pid, pgid, ppid, (UID_ARG)uid, cmd, (int)pss,
+ (int)sf);
+ Plf = (struct lfile *)NULL;
+ Kpa = Pa[px];
+ /*
+ * Save current working directory information.
+ */
+ if (fd.fd_cdir) {
+ alloc_lfile(CWD, -1);
+ Cfp = (struct file *)NULL;
+ process_node((KA_T)fd.fd_cdir);
+ if (Lf->sf)
+ link_lfile();
+ }
+ /*
+ * Save root directory information.
+ */
+ if (fd.fd_rdir) {
+ alloc_lfile(RTD, -1);
+ Cfp = (struct file *)NULL;
+ process_node((KA_T)fd.fd_rdir);
+ if (Lf->sf)
+ link_lfile();
+ }
+ /*
+ * Process the VM map.
+ */
+ process_map(p->p_pid);
+ /*
+ * Read open file structure pointers.
+ */
+ if (!fd.fd_ofiles || (nf = fd.fd_nfiles) <= 0)
+ continue;
+ nb = (MALLOC_S)(sizeof(struct file *) * nf);
+ if (nb > ofbb) {
+ if (!ofb)
+ ofb = (struct file **)malloc(nb);
+ else
+ ofb = (struct file **)realloc((MALLOC_P *)ofb, nb);
+ if (!ofb) {
+ (void) fprintf(stderr, "%s: PID %d, no file * space\n",
+ Pn, p->p_pid);
+ Exit(1);
+ }
+ ofbb = nb;
+ }
+ if (kread((KA_T)fd.fd_ofiles, (char *)ofb, nb))
+ continue;
+
+ nb = (MALLOC_S)(sizeof(char) * nf);
+ if (nb > pofb) {
+ if (!pof)
+ pof = (char *)malloc(nb);
+ else
+ pof = (char *)realloc((MALLOC_P *)pof, nb);
+ if (!pof) {
+ (void) fprintf(stderr, "%s: PID %d, no file flag space\n",
+ Pn, p->p_pid);
+ Exit(1);
+ }
+ pofb = nb;
+ }
+ if (!fd.fd_ofileflags || kread((KA_T)fd.fd_ofileflags, pof, nb))
+ zeromem(pof, nb);
+
+ /*
+ * Save information on file descriptors.
+ */
+ for (i = 0; i < nf; i++) {
+ if (ofb[i] && !(pof[i] & UF_RESERVED)) {
+ alloc_lfile(NULL, i);
+ process_file((KA_T)(Cfp = ofb[i]));
+ if (Lf->sf) {
+
+#if defined(HASFSTRUCT)
+ if (Fsv & FSV_FG)
+ Lf->pof = (long)pof[i];
+#endif /* defined(HASFSTRUCT) */
+
+ link_lfile();
+ }
+ }
+ }
+ /*
+ * Examine results.
+ */
+ if (examine_lproc())
+ return;
+ }
+}
+
+
+#if DARWINV>=700
+static char *
+getcmdnm(pid)
+ pid_t pid; /* process ID */
+{
+ static int am;
+ static char *ap = (char *)NULL;
+ char *cp, *ep, *sp;
+ int mib[3];
+ size_t sz;
+
+ if (!ap) {
+
+ /*
+ * Allocate space for the maximum argument size.
+ */
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_ARGMAX;
+ sz = sizeof(am);
+ if (sysctl(mib, 2, &am, &sz, NULL, 0) == -1) {
+ (void) fprintf(stderr, "%s: can't get arg max, PID %d\n",
+ Pn, pid);
+ Exit(1);
+ }
+ if (!(ap = (char *)malloc((MALLOC_S)am))) {
+ (void) fprintf(stderr, "%s: no arg ptr (%d) space, PID %d\n",
+ Pn, am, pid);
+ Exit(1);
+ }
+ }
+/*
+ * Get the arguments for the process.
+ */
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROCARGS;
+ mib[2] = pid;
+ sz = (size_t)am;
+ if (sysctl(mib, 3, ap, &sz, NULL, 0) == -1)
+ return((char *)NULL);
+/*
+ * Skip to the first NUL character, which should end the saved exec path.
+ */
+ for (cp = ap; *cp && (cp < (ap + sz)); cp++) {
+ ;
+ }
+ if (cp >= (ap + sz))
+ return((char *)NULL);
+/*
+ * Skip trailing NULs, which should find the beginning of the command.
+ */
+ while (!*cp && (cp < (ap + sz))) {
+ cp++;
+ }
+ if (cp >= (ap + sz))
+ return((char *)NULL);
+/*
+ * Make sure that the command is NUL-terminated.
+ */
+ for (sp = cp; *cp && (cp < (ap + sz)); cp++) {
+ ;
+ }
+ if (cp >= (ap + sz))
+ return((char *)NULL);
+ ep = cp;
+/*
+ * Locate the start of the command's base name and return it.
+ */
+ for (ep = cp, cp--; cp >= sp; cp--) {
+ if (*cp == '/') {
+ return(cp + 1);
+ }
+ }
+ return(sp);
+}
+#endif /* DARWINV>=700 */
+
+
+/*
+ * get_kernel_access() - get access to kernel memory
+ */
+
+static void
+get_kernel_access()
+{
+
+/*
+ * Check kernel version.
+ */
+ (void) ckkv("Darwin", LSOF_VSTR, (char *)NULL, (char *)NULL);
+/*
+ * Set name list file path.
+ */
+ if (!Nmlst)
+ Nmlst = N_UNIX;
+
+#if defined(WILLDROPGID)
+/*
+ * If kernel memory isn't coming from KMEM, drop setgid permission
+ * before attempting to open the (Memory) file.
+ */
+ if (Memory)
+ (void) dropgid();
+#else /* !defined(WILLDROPGID) */
+/*
+ * See if the non-KMEM memory and the name list files are readable.
+ */
+ if ((Memory && !is_readable(Memory, 1))
+ || (Nmlst && !is_readable(Nmlst, 1)))
+ Exit(1);
+#endif /* defined(WILLDROPGID) */
+
+/*
+ * Open kernel memory access.
+ */
+ if ((Kd = open(Memory ? Memory : KMEM, O_RDONLY, 0)) < 0)
+ {
+ (void) fprintf(stderr, "%s: open(%s): %s\n", Pn,
+ Memory ? Memory : KMEM,
+ strerror(errno));
+ Exit(1);
+ }
+ (void) build_Nl(Drive_Nl);
+ if (nlist(Nmlst, Nl) < 0) {
+ (void) fprintf(stderr, "%s: can't read namelist from %s\n",
+ Pn, Nmlst);
+ Exit(1);
+ }
+
+#if defined(WILLDROPGID)
+/*
+ * Drop setgid permission, if necessary.
+ */
+ if (!Memory)
+ (void) dropgid();
+#endif /* defined(WILLDROPGID) */
+
+}
+
+
+/*
+ * get_parent_pid() - get parent process PID
+ */
+
+static pid_t
+get_parent_pid(kpa)
+ KA_T kpa; /* kernel parent process address */
+{
+ struct phash *ph;
+
+ if (kpa) {
+ for (ph = Phash[PHASH(kpa)]; ph; ph = ph->next) {
+ if (ph->ka == kpa)
+ return((pid_t)ph->la->p_pid);
+ }
+ }
+ return((pid_t)0);
+}
+
+
+/*
+ * initialize() - perform all initialization
+ */
+
+void
+initialize()
+{
+ get_kernel_access();
+}
+
+
+/*
+ * kread() - read from kernel memory
+ */
+
+int
+kread(addr, buf, len)
+ KA_T addr; /* kernel memory address */
+ char *buf; /* buffer to receive data */
+ READLEN_T len; /* length to read */
+{
+ int br;
+
+ if ((off_t)addr & (off_t)0x3) {
+
+ /*
+ * No read is possible if the address is not aligned on a word
+ * boundary.
+ */
+ return(1);
+ }
+ if (lseek(Kd, (off_t)addr, SEEK_SET) == (off_t)-1)
+ return(1);
+ br = read(Kd, buf, len);
+ return((br == len) ? 0 : 1);
+}
+
+
+/*
+ * prcess_map() - process VM map
+ */
+
+static void
+process_map(pid)
+ pid_t pid; /* process id */
+{
+ vm_address_t address = 0;
+ mach_msg_type_number_t count;
+ vm_region_extended_info_data_t e_info;
+ int n = 0;
+ mach_port_t object_name;
+ vm_size_t size = 0;
+ vm_map_t task;
+ vm_region_top_info_data_t t_info;
+
+ struct vm_object { /* should come from <vm/vm_object.h> */
+
+#if DARWINV<800
+ KA_T Dummy1[15];
+#else /* DARWINV>=800 */
+ KA_T Dummy1[14];
+#endif /* DARWINV>=800 */
+
+ memory_object_t pager;
+ } vmo;
+
+ struct vnode_pager { /* from <osfmk/vm/bsd_vm.c> */
+ KA_T Dummy1[4];
+ struct vnode *vnode;
+ } vp;
+
+/*
+ * Get the task port associated with the process
+ */
+ if (task_for_pid((mach_port_name_t)mach_task_self(), pid,
+ (mach_port_name_t *)&task)
+ != KERN_SUCCESS) {
+ return;
+ }
+/*
+ * Go through the task's address space, looking for blocks of memory
+ * backed by an external pager (i.e, a "vnode")
+ */
+ for (address = 0;; address += size) {
+ count = VM_REGION_EXTENDED_INFO_COUNT;
+ if (vm_region(task, &address, &size, VM_REGION_EXTENDED_INFO,
+ (vm_region_info_t)&e_info, &count, &object_name)
+ != KERN_SUCCESS) {
+ break;
+ }
+ if (!e_info.external_pager)
+ continue;
+ count = VM_REGION_TOP_INFO_COUNT;
+ if (vm_region(task, &address, &size, VM_REGION_TOP_INFO,
+ (vm_region_info_t)&t_info, &count, &object_name)
+ != KERN_SUCCESS) {
+ break;
+ }
+ /*
+ * The returned "obj_id" is the "vm_object_t" address.
+ */
+ if (!t_info.obj_id)
+ continue;
+ if (kread(t_info.obj_id, (char *)&vmo, sizeof(vmo)))
+ break;
+ /*
+ * If the "pager" is backed by a vnode then the "vm_object_t"
+ * "memory_object_t" address is actually a "struct vnode_pager *".
+ */
+ if (!vmo.pager)
+ continue;
+ if (kread((KA_T)vmo.pager, (char *)&vp, sizeof(vp)))
+ break;
+ (void) enter_vn_text((KA_T)vp.vnode, &n);
+ }
+ return;
+}
+
+
+/*
+ * read_procs() - read proc structures
+ */
+
+static int
+read_procs()
+{
+ int h, i, np, pe;
+ KA_T kp, kpn;
+ MALLOC_S msz;
+ struct proc *p;
+ struct phash *ph, *phn;
+
+ if (!Akp) {
+
+ /*
+ * Get kernel allproc structure pointer once.
+ */
+ if (get_Nl_value("aproc", Drive_Nl, &Akp) < 0 || !Akp) {
+ (void) fprintf(stderr, "%s: can't get proc table address\n",
+ Pn);
+ Exit(1);
+ }
+ }
+/*
+ * Get the current number of processes and calculate PA and Proc[] allocation
+ * sizes large enough to handle it.
+ */
+ if (get_Nl_value("nproc", Drive_Nl, &kp) < 0 || !kp) {
+ (void) fprintf(stderr, "%s: can't get nproc address\n", Pn);
+ Exit(1);
+ }
+ if (kread(kp, (char *)&np, sizeof(np))) {
+ (void) fprintf(stderr, "%s: can't read process count from %s\n",
+ Pn, print_kptr(kp, (char *)NULL, 0));
+ Exit(1);
+ }
+ for (np += np, pe = PINCRSZ; pe < np; pe += PINCRSZ)
+ ;
+/*
+ * Allocate or reallocate the Pa[] and Proc[] tables.
+ */
+ msz = (MALLOC_S)(pe * sizeof(struct proc));
+ if (!Proc)
+ Proc = (struct proc *)malloc(msz);
+ else if (pe > Npa)
+ Proc = (struct proc *)realloc((MALLOC_P *)Proc, msz);
+ if (!Proc) {
+ (void) fprintf(stderr, "%s: no space for proc table\n", Pn);
+ Exit(1);
+ }
+ msz = (MALLOC_S)(pe * sizeof(KA_T));
+ if (!Pa)
+ Pa = (KA_T *)malloc(msz);
+ else if (pe > Npa)
+ Pa = (KA_T *)realloc((MALLOC_P *)Pa, msz);
+ if (!Pa) {
+ (void) fprintf(stderr, "%s: no space for proc addr table\n", Pn);
+ Exit(1);
+ }
+ Npa = pe;
+/*
+ * Allocate or reset the Phash[] table.
+ */
+ if (!Phash) {
+ Phash = (struct phash **)calloc(NPHASH, sizeof(struct phash *));
+ } else {
+ for (h = 0; h < NPHASH; h++) {
+ for (ph = Phash[h]; ph; ph = phn) {
+ phn = ph->next;
+ (void) free((MALLOC_P *)ph);
+ }
+ Phash[h] = (struct phash *)NULL;
+ }
+ }
+ if (!Phash) {
+ (void) fprintf(stderr, "%s: no space for proc address hash\n", Pn);
+ Exit(1);
+ }
+/*
+ * Read the proc structures on the kernel's chain.
+ */
+ for (i = Np = 0, kp = Akp, p = Proc, pe += pe;
+ kp && i < pe;
+ i++, kp = kpn)
+ {
+ if (kread(kp, (char *)p, sizeof(struct proc)))
+ break;
+ kpn = (KA_T)(((KA_T)p->p_list.le_next == Akp) ? NULL
+ : p->p_list.le_next);
+ if (p->p_stat == 0 || p->p_stat == SZOMB)
+ continue;
+ /*
+ * Cache the proc structure's addresses.
+ */
+ h = PHASH(kp);
+ if (!(ph = (struct phash *)malloc((MALLOC_S)sizeof(struct phash))))
+ {
+ (void) fprintf(stderr, "%s: no space for phash struct\n", Pn);
+ Exit(1);
+ }
+ ph->ka = kp;
+ ph->la = p;
+ ph->next = Phash[h];
+ Phash[h] = ph;
+ p++;
+ Pa[Np++] = kp;
+ if (Np >= Npa) {
+
+ /*
+ * Enlarge Pa[] and Proc[].
+ */
+ msz = (int)((Npa + PINCRSZ) * sizeof(struct proc));
+ if (!(Proc = (struct proc *)realloc((MALLOC_P *)Proc, msz))) {
+ (void) fprintf(stderr, "%s: no additional proc space\n",
+ Pn);
+ Exit(1);
+ }
+ msz = (int)((Npa + PINCRSZ) * sizeof(KA_T));
+ if (!(Pa = (KA_T *)realloc((MALLOC_P *)Pa, msz))) {
+ (void) fprintf(stderr,
+ "%s: no additional proc addr space\n", Pn);
+ Exit(1);
+ }
+ Npa += PINCRSZ;
+ }
+ }
+/*
+ * If too many processes were read, the chain following probably failed;
+ * report that and exit.
+ */
+ if (i >= pe) {
+ (void) fprintf(stderr, "%s: can't follow kernel proc chain\n", Pn);
+ Exit(1);
+ }
+/*
+ * If not in repeat mode, reduce Pa[] and Proc[] to their minimums.
+ */
+ if (Np < Npa && !RptTm) {
+ msz = (MALLOC_S)(Np * sizeof(struct proc));
+ if (!(Proc = (struct proc *)realloc((MALLOC_P *)Proc, msz))) {
+ (void) fprintf(stderr, "%s: can't reduce proc table\n", Pn);
+ Exit(1);
+ }
+ msz = (MALLOC_S)(Np * sizeof(KA_T));
+ if (!(Pa = (KA_T *)realloc((MALLOC_P *)Pa, msz))) {
+ (void) fprintf(stderr, "%s: can't reduce proc addr table\n",
+ Pn);
+ Exit(1);
+ }
+ Npa = Np;
+ }
+/*
+ * Return 0 if any processes were loaded; 1 if none were.
+ */
+ return((Np > 0) ? 0 : 1);
+}
diff --git a/dialects/darwin/kmem/dproto.h b/dialects/darwin/kmem/dproto.h
new file mode 100644
index 0000000..15ddb64
--- /dev/null
+++ b/dialects/darwin/kmem/dproto.h
@@ -0,0 +1,62 @@
+/*
+ * dproto.h - Darwin function prototypes for /dev/kmem-based lsof
+ *
+ * The _PROTOTYPE macro is defined in the common proto.h.
+ */
+
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907. All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ * consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Credit to the authors and Purdue
+ * University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+
+/*
+ * $Id: dproto.h,v 1.4 2005/11/01 20:24:51 abe Exp $
+ */
+
+_PROTOTYPE(extern int is_file_named,(char *p, int cd));
+_PROTOTYPE(extern struct l_vfs *readvfs,(KA_T vm));
+
+#if defined(HASKQUEUE)
+_PROTOTYPE(extern void process_kqueue,(KA_T ka));
+#endif /* defined(HASKQUEUE) */
+
+#if defined(HASPIPEFN)
+_PROTOTYPE(extern void process_pipe,(KA_T pa));
+#endif /* defined(HASPIPEFN) */
+
+#if defined(HASPSXSEM)
+_PROTOTYPE(extern void process_psxsem,(KA_T pa));
+#endif /* defined(HASPSXSEM) */
+
+#if defined(HASPSXSHM)
+_PROTOTYPE(extern void process_psxshm,(KA_T pa));
+#endif /* defined(HASPSXSHM) */
+
+#if defined(HAS9660FS)
+_PROTOTYPE(extern int read_iso_node,(struct vnode *v, dev_t *d, int *dd, INODETYPE *ino, long *nl, SZOFFTYPE *sz));
+#endif /* defined(HAS9660FS) */
+
+_PROTOTYPE(extern void process_socket,(KA_T sa));
diff --git a/dialects/darwin/kmem/dsock.c b/dialects/darwin/kmem/dsock.c
new file mode 100644
index 0000000..a5a993b
--- /dev/null
+++ b/dialects/darwin/kmem/dsock.c
@@ -0,0 +1,478 @@
+/*
+ * dsock.c - Darwin socket processing functions for /dev/kmem-based lsof
+ */
+
+/*
+ * Special Darwin socket info: Justin Walker, 000927
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907. All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ * consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Credit to the authors and Purdue
+ * University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
+static char *rcsid = "$Id: dsock.c,v 1.11 2005/11/01 20:24:51 abe Exp $";
+#endif
+
+
+#include "lsof.h"
+
+
+#if defined(HASIPv6)
+/*
+ * IPv6_2_IPv4() -- macro to define the address of an IPv4 address contained
+ * in an IPv6 address
+ */
+
+#define IPv6_2_IPv4(v6) (((uint8_t *)((struct in6_addr *)v6)->s6_addr)+12)
+#endif /* defined(HASIPv6) */
+
+
+/*
+ * process_socket() - process socket
+ */
+
+void
+process_socket(sa)
+ KA_T sa; /* socket address in kernel */
+{
+ struct domain d;
+ unsigned char *fa = (unsigned char *)NULL;
+ int fam, lp;
+ int fp = 0;
+ struct inpcb inp;
+ unsigned char *la = (unsigned char *)NULL;
+ struct protosw p;
+ struct socket s;
+ struct tcpcb t;
+ KA_T ta = (KA_T)NULL;
+ struct unpcb uc, unp;
+ struct sockaddr_un *ua = NULL;
+ struct sockaddr_un un;
+ int unl;
+
+#if defined(HASIPv6)
+ struct in6pcb in6p;
+#endif /* defined(HASIPv6) */
+
+#if defined(AF_SYSTEM)
+ struct kern_event_pcb kev_cb;
+#endif /* defined(AF_SYSTEM) */
+
+#if defined(AF_NDRV)
+ char buf[IFNAMSIZ];
+ struct ndrv_cb ndrv_cb;
+ struct ifnet ifnet;
+#endif /* defined(AF_NDRV) */
+
+ (void) snpf(Lf->type, sizeof(Lf->type), "sock");
+ Lf->inp_ty = 2;
+/*
+ * Read the socket, protocol, and domain structures.
+ */
+ if (!sa) {
+ enter_nm("no socket address");
+ return;
+ }
+ if (kread(sa, (char *)&s, sizeof(s))) {
+ (void) snpf(Namech, Namechl, "can't read socket struct from %s",
+ print_kptr(sa, (char *)NULL, 0));
+ enter_nm(Namech);
+ return;
+ }
+ if (!s.so_type) {
+ enter_nm("no socket type");
+ return;
+ }
+ if (!s.so_proto
+ || kread((KA_T)s.so_proto, (char *)&p, sizeof(p))) {
+ (void) snpf(Namech, Namechl, "can't read protocol switch from %s",
+ print_kptr((KA_T)s.so_proto, (char *)NULL, 0));
+ enter_nm(Namech);
+ return;
+ }
+ if (!p.pr_domain
+ || kread((KA_T)p.pr_domain, (char *)&d, sizeof(d))) {
+ (void) snpf(Namech, Namechl, "can't read domain struct from %s",
+ print_kptr((KA_T)p.pr_domain, (char *)NULL, 0));
+ enter_nm(Namech);
+ return;
+ }
+/*
+ * Save size information.
+ */
+ if (Fsize) {
+ if (Lf->access == 'r')
+ Lf->sz = (SZOFFTYPE)s.so_rcv.sb_cc;
+ else if (Lf->access == 'w')
+ Lf->sz = (SZOFFTYPE)s.so_snd.sb_cc;
+ else
+ Lf->sz = (SZOFFTYPE)(s.so_rcv.sb_cc + s.so_snd.sb_cc);
+ Lf->sz_def = 1;
+ } else
+ Lf->off_def = 1;
+
+#if defined(HASTCPTPIQ)
+ Lf->lts.rq = s.so_rcv.sb_cc;
+ Lf->lts.sq = s.so_snd.sb_cc;
+ Lf->lts.rqs = Lf->lts.sqs = 1;
+#endif /* defined(HASTCPTPIQ) */
+
+#if defined(HASSOOPT)
+ Lf->lts.ltm = (unsigned int)(s.so_linger & 0xffff);
+ Lf->lts.opt = (unsigned int)(s.so_options & 0xffff);
+ Lf->lts.pqlen = (unsigned int)s.so_incqlen;
+ Lf->lts.qlen = (unsigned int)s.so_qlen;
+ Lf->lts.qlim = (unsigned int)s.so_qlimit;
+ Lf->lts.rbsz = (unsigned long)s.so_rcv.sb_mbmax;
+ Lf->lts.sbsz = (unsigned long)s.so_snd.sb_mbmax;
+ Lf->lts.pqlens = Lf->lts.qlens = Lf->lts.qlims = Lf->lts.rbszs
+ = Lf->lts.sbszs = (unsigned char)1;
+#endif /* defined(HASSOOPT) */
+
+#if defined(HASSOSTATE)
+ Lf->lts.ss = (unsigned int)s.so_state;
+#endif /* defined(HASSOSTATE) */
+
+/*
+ * Process socket by the associated domain family.
+ */
+ switch ((fam = d.dom_family)) {
+/*
+ * Process an Internet domain socket.
+ */
+ case AF_INET:
+
+#if defined(HASIPv6)
+ case AF_INET6:
+#endif /* defined(HASIPv6) */
+
+ if (Fnet) {
+ if (!FnetTy
+ || ((FnetTy == 4) && (fam == AF_INET))
+
+#if defined(HASIPv6)
+ || ((FnetTy == 6) && (fam == AF_INET6))
+#endif /* defined(HASIPv6) */
+
+ )
+ Lf->sf |= SELNET;
+ }
+ printiproto(p.pr_protocol);
+
+#if defined(HASIPv6)
+ (void) snpf(Lf->type, sizeof(Lf->type),
+ (fam == AF_INET) ? "IPv4" : "IPv6");
+#else /* !defined(HASIPv6) */
+ (void) snpf(Lf->type, sizeof(Lf->type), "inet");
+#endif /* defined(HASIPv6) */
+
+#if defined(HASIPv6)
+ if (fam == AF_INET6) {
+
+ /*
+ * Read IPv6 protocol control block.
+ */
+ if (!s.so_pcb
+ || kread((KA_T)s.so_pcb, (char *)&in6p, sizeof(in6p)))
+ {
+ (void) snpf(Namech, Namechl, "can't read in6pcb at %s",
+ print_kptr((KA_T)s.so_pcb, (char *)NULL, 0));
+ enter_nm(Namech);
+ return;
+ }
+ /*
+ * Save IPv6 address information.
+ */
+ enter_dev_ch(print_kptr((KA_T)(in6p.in6p_ppcb ? in6p.in6p_ppcb
+ : s.so_pcb),
+ (char *)NULL, 0));
+ if (p.pr_protocol == IPPROTO_TCP)
+ ta = (KA_T)in6p.in6p_ppcb;
+ la = (unsigned char *)&in6p.in6p_laddr;
+ lp = (int)ntohs(in6p.in6p_lport);
+ if (!IN6_IS_ADDR_UNSPECIFIED(&in6p.in6p_faddr)
+ || in6p.in6p_fport)
+ {
+ fa = (unsigned char *)&in6p.in6p_faddr;
+ fp = (int)ntohs(in6p.in6p_fport);
+ }
+ } else
+#endif /* defined(HASIPv6) */
+
+ {
+
+ /*
+ * Read IPv4 protocol control block.
+ */
+ if (!s.so_pcb
+ || kread((KA_T)s.so_pcb, (char *)&inp, sizeof(inp))) {
+ if (!s.so_pcb) {
+ (void) snpf(Namech, Namechl, "no PCB%s%s",
+ (s.so_state & SS_CANTSENDMORE) ? ", CANTSENDMORE"
+ : "",
+ (s.so_state & SS_CANTRCVMORE) ? ", CANTRCVMORE"
+ : "");
+ } else {
+ (void) snpf(Namech, Namechl, "can't read inpcb at %s",
+ print_kptr((KA_T)s.so_pcb, (char *)NULL, 0));
+ }
+ enter_nm(Namech);
+ return;
+ }
+ /*
+ * Print Internet socket information.
+ */
+ enter_dev_ch(print_kptr((KA_T)(inp.inp_ppcb ? inp.inp_ppcb
+ : s.so_pcb),
+ (char *)NULL, 0));
+ /*
+ * Save IPv4 address information.
+ */
+ if (p.pr_protocol == IPPROTO_TCP)
+ ta = (KA_T)inp.inp_ppcb;
+ la = (unsigned char *)&inp.inp_laddr;
+ lp = (int)ntohs(inp.inp_lport);
+ if (inp.inp_faddr.s_addr != INADDR_ANY || inp.inp_fport) {
+ fa = (unsigned char *)&inp.inp_faddr;
+ fp = (int)ntohs(inp.inp_fport);
+ }
+ }
+
+#if defined(HASIPv6)
+ if ((fam == AF_INET6)
+ && ((la && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)la))
+ || ((fa && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)fa))))) {
+
+ /*
+ * Adjust for IPv4 addresses mapped in IPv6 addresses.
+ */
+ if (la)
+ la = (unsigned char *)IPv6_2_IPv4(la);
+ if (fa)
+ fa = (unsigned char *)IPv6_2_IPv4(fa);
+ fam = AF_INET;
+ }
+#endif /* defined(HASIPv6) */
+
+ /*
+ * Enter local and remote addresses by address family.
+ */
+ if (fa || la)
+ (void) ent_inaddr(la, lp, fa, fp, fam);
+ if (ta && !kread(ta, (char *)&t, sizeof(t))) {
+ Lf->lts.type = 0;
+ Lf->lts.state.i = (int)t.t_state;
+
+#if defined(HASSOOPT)
+ Lf->lts.kai = (unsigned int)t.t_timer[TCPT_KEEP];
+#endif /* defined(HASSOOPT) */
+
+#if defined(HASTCPOPT)
+ Lf->lts.mss = (unsigned long)t.t_maxseg;
+ Lf->lts.msss = (unsigned char)1;
+ Lf->lts.topt = (unsigned int)t.t_flags;
+#endif /* defined(HASTCPOPT) */
+
+ }
+ break;
+
+#if defined(AF_NDRV)
+/*
+ * Process an NDRV domain socket.
+ */
+ case AF_NDRV:
+ {
+ (void) snpf(Lf->type, sizeof(Lf->type), "ndrv");
+ /*
+ * Read protocol control block.
+ */
+ if (!s.so_pcb
+ || kread((KA_T)s.so_pcb, (char *)&ndrv_cb, sizeof(ndrv_cb))) {
+ (void) snpf(Namech, Namechl, "can't read ndrv_cb at %s",
+ print_kptr((KA_T)s.so_pcb, (char *)NULL, 0));
+ enter_nm(Namech);
+ return;
+ }
+ /*
+ * Print NDRV socket information.
+ */
+ enter_dev_ch(print_kptr((KA_T)(s.so_pcb), (char *)NULL, 0));
+ /*
+ * Print device name, if bound
+ */
+ if (!ndrv_cb.nd_if
+ || kread((KA_T)ndrv_cb.nd_if, (char *)&ifnet, sizeof(ifnet))) {
+ (void) snpf(Namech, Namechl, "can't read ifnet at %s",
+ print_kptr((KA_T)ndrv_cb.nd_if, (char *)NULL, 0));
+ enter_nm(Namech);
+ return;
+ }
+ if (!ifnet.if_name
+ || kread((KA_T)ifnet.if_name, buf, sizeof(buf))) {
+ (void) snpf(Namech, Namechl, "can't read ifnet.if_name at %s",
+ print_kptr((KA_T)ifnet.if_name, (char *)NULL, 0));
+ enter_nm(Namech);
+ return;
+ }
+ (void) snpf(Namech, Namechl, "-> %s%d", buf, ifnet.if_unit);
+ }
+ break;
+#endif /* defined(AF_NDRV) */
+
+#if defined(pseudo_AF_KEY)
+/*
+ * Process an [internal] key-management function socket
+ */
+ case pseudo_AF_KEY:
+ (void) snpf(Lf->type, sizeof(Lf->type), "key");
+ break;
+#endif /* defined(pseudo_AF_KEY) */
+
+#if defined(AF_SYSTEM)
+/*
+ * Process a SYSTEM domain socket
+ */
+ case AF_SYSTEM:
+ (void) snpf(Lf->type, sizeof(Lf->type), "systm");
+ /*
+ * Read protocol control block.
+ */
+ if (!s.so_pcb
+ || kread((KA_T)s.so_pcb, (char *)&kev_cb, sizeof(kev_cb))) {
+ (void) snpf(Namech, Namechl, "can't read kev_cb at %s",
+ print_kptr((KA_T)s.so_pcb, (char *)NULL, 0));
+ enter_nm(Namech);
+ return;
+ }
+ /*
+ * Print SYSTEM socket information.
+ */
+ enter_dev_ch(print_kptr((KA_T)(s.so_pcb), (char *)NULL, 0));
+ (void) snpf(Namech, Namechl, "[%lx:%lx:%lx]",
+ kev_cb.vendor_code_filter,
+ kev_cb.class_filter, kev_cb.subclass_filter);
+ break;
+#endif /* defined(AF_SYSTEM) */
+
+#if defined(AF_PPP)
+/*
+ * Process a PPP domain socket
+ */
+ case AF_PPP:
+ (void) snpf(Lf->type, sizeof(Lf->type), "ppp");
+ break;
+#endif /* defined(AF_PPP) */
+
+/*
+ * Process a ROUTE domain socket.
+ */
+ case AF_ROUTE:
+ (void) snpf(Lf->type, sizeof(Lf->type), "rte");
+ if (s.so_pcb)
+ enter_dev_ch(print_kptr((KA_T)(s.so_pcb), (char *)NULL, 0));
+ else
+ (void) snpf(Namech, Namechl, "no protocol control block");
+ if (!Fsize)
+ Lf->off_def = 1;
+ break;
+/*
+ * Process a Unix domain socket.
+ */
+ case AF_UNIX:
+ if (Funix)
+ Lf->sf |= SELUNX;
+ (void) snpf(Lf->type, sizeof(Lf->type), "unix");
+ /*
+ * Read Unix protocol control block and the Unix address structure.
+ */
+
+ enter_dev_ch(print_kptr(sa, (char *)NULL, 0));
+ if (!s.so_pcb
+ || kread((KA_T)s.so_pcb, (char *)&unp, sizeof(unp))) {
+ (void) snpf(Namech, Namechl, "can't read unpcb at %s",
+ print_kptr((KA_T)s.so_pcb, (char *)NULL, 0));
+ break;
+ }
+ if ((struct socket *)sa != unp.unp_socket) {
+ (void) snpf(Namech, Namechl, "unp_socket (%s) mismatch",
+ print_kptr((KA_T)unp.unp_socket, (char *)NULL, 0));
+ break;
+ }
+ if (unp.unp_addr) {
+ if (kread((KA_T)unp.unp_addr, (char *)&un, sizeof(un))) {
+ (void) snpf(Namech, Namechl, "can't read unp_addr at %s",
+ print_kptr((KA_T)unp.unp_addr, (char *)NULL, 0));
+ break;
+ }
+ ua = &un;
+ }
+ if (!ua) {
+ ua = &un;
+ (void) bzero((char *)ua, sizeof(un));
+ ua->sun_family = AF_UNSPEC;
+ }
+ /*
+ * Print information on Unix socket that has no address bound
+ * to it, although it may be connected to another Unix domain
+ * socket as a pipe.
+ */
+ if (ua->sun_family != AF_UNIX) {
+ if (ua->sun_family == AF_UNSPEC) {
+ if (unp.unp_conn) {
+ if (kread((KA_T)unp.unp_conn, (char *)&uc, sizeof(uc)))
+ (void) snpf(Namech, Namechl,
+ "can't read unp_conn at %s",
+ print_kptr((KA_T)unp.unp_conn,(char *)NULL,0));
+ else
+ (void) snpf(Namech, Namechl, "->%s",
+ print_kptr((KA_T)uc.unp_socket,(char *)NULL,0));
+ } else
+ (void) snpf(Namech, Namechl, "->(none)");
+ } else
+ (void) snpf(Namech, Namechl, "unknown sun_family (%d)",
+ ua->sun_family);
+ break;
+ }
+ if (ua->sun_path[0]) {
+ unl = ua->sun_len - offsetof(struct sockaddr_un, sun_path);
+ if ((unl < 0) || (unl >= sizeof(ua->sun_path)))
+ unl = sizeof(ua->sun_path) - 1;
+ ua->sun_path[unl] = '\0';
+ if (ua->sun_path[0] && Sfile && is_file_named(ua->sun_path, 0))
+ Lf->sf |= SELNM;
+ if (ua->sun_path[0] && !Namech[0])
+ (void) snpf(Namech, Namechl, "%s", ua->sun_path);
+ } else
+ (void) snpf(Namech, Namechl, "no address");
+ break;
+ default:
+ printunkaf(fam, 1);
+ }
+ if (Namech[0])
+ enter_nm(Namech);
+}
diff --git a/dialects/darwin/kmem/dstore.c b/dialects/darwin/kmem/dstore.c
new file mode 100644
index 0000000..06a91f7
--- /dev/null
+++ b/dialects/darwin/kmem/dstore.c
@@ -0,0 +1,105 @@
+/*
+ * dstore.c - Darwin global storage for /dev/kmem-based lsof
+ */
+
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907. All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ * consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Credit to the authors and Purdue
+ * University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
+static char *rcsid = "$Id: dstore.c,v 1.5 2005/11/01 20:24:51 abe Exp $";
+#endif
+
+
+#include "lsof.h"
+
+struct file *Cfp; /* curent file's file struct pointer */
+
+
+/*
+ * Drive_Nl -- table to drive the building of Nl[] via build_Nl()
+ * (See lsof.h and misc.c.)
+ */
+
+struct drive_Nl Drive_Nl[] = {
+
+ { "aproc", "_allproc" },
+ { "nproc", "_nprocs" },
+ { X_NCACHE, "_nchashtbl" },
+ { X_NCSIZE, "_nchash" },
+ { "", "" },
+ { NULL, NULL }
+};
+
+int Kd = -1; /* KMEM descriptor */
+KA_T Kpa; /* kernel proc struct address */
+struct l_vfs *Lvfs = NULL; /* local vfs structure table */
+
+int Np = 0; /* number of kernel processes */
+
+struct kinfo_proc *P = NULL; /* local process table copy */
+
+#if defined(HASFSTRUCT)
+/*
+ * Pff_tab[] - table for printing file flags
+ */
+
+struct pff_tab Pff_tab[] = {
+ { (long)FREAD, FF_READ },
+ { (long)FWRITE, FF_WRITE },
+ { (long)FNONBLOCK, FF_NBLOCK },
+ { (long)FNDELAY, FF_NDELAY },
+ { (long)FAPPEND, FF_APPEND },
+ { (long)FASYNC, FF_ASYNC },
+ { (long)FFSYNC, FF_FSYNC },
+ { (long)FMARK, FF_MARK },
+ { (long)FDEFER, FF_DEFER },
+ { (long)FHASLOCK, FF_HASLOCK },
+ { (long)O_NOCTTY, FF_NOCTTY },
+ { (long)O_EVTONLY, FF_EVTONLY },
+ { (long)0, NULL }
+};
+
+
+/*
+ * Pof_tab[] - table for print process open file flags
+ */
+
+struct pff_tab Pof_tab[] = {
+
+# if defined(UF_EXCLOSE)
+ { (long)UF_EXCLOSE, POF_CLOEXEC },
+# endif /* defined(UF_EXCLOSE) */
+
+# if defined(UF_MAPPED)
+ { (long)UF_MAPPED, POF_MAPPED },
+# endif /* defined(UF_MAPPED) */
+
+ { (long)0, NULL }
+};
+#endif /* defined(HASFSTRUCT) */
diff --git a/dialects/darwin/kmem/machine.h b/dialects/darwin/kmem/machine.h
new file mode 100644
index 0000000..ebb2490
--- /dev/null
+++ b/dialects/darwin/kmem/machine.h
@@ -0,0 +1,647 @@
+/*
+ * machine.h - Darwin definitions for /dev/kmem-based lsof
+ */
+
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907. All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ * consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Credit to the authors and Purdue
+ * University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+
+/*
+ * $Id: machine.h,v 1.16 2010/07/29 16:03:04 abe Exp $
+ */
+
+
+#if !defined(LSOF_MACHINE_H)
+#define LSOF_MACHINE_H 1
+
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+# if DARWINV>=800
+#include "/usr/include/string.h"
+# endif /* DARWINV>=800 */
+
+
+/*
+ * CAN_USE_CLNT_CREATE is defined for those dialects where RPC clnt_create()
+ * can be used to obtain a CLIENT handle in lieu of clnttcp_create().
+ */
+
+#define CAN_USE_CLNT_CREATE 1
+
+
+/*
+ * DEVDEV_PATH defines the path to the directory that contains device
+ * nodes.
+ */
+
+#define DEVDEV_PATH "/dev"
+
+
+/*
+ * GET_MAX_FD is defined for those dialects that provide a function other than
+ * getdtablesize() to obtain the maximum file descriptor number plus one.
+ */
+
+/* #define GET_MAX_FD ? */
+
+
+/*
+ * HASAOPT is defined for those dialects that have AFS support; it specifies
+ * that the default path to an alternate AFS kernel name list file may be
+ * supplied with the -A <path> option.
+ */
+
+/* #define HASAOPT 1 */
+
+
+/*
+ * HASBLKDEV is defined for those dialects that want block device information
+ * recorded in BDevtp[].
+ */
+
+#define HASBLKDEV 1
+
+
+/*
+ * HASDCACHE is defined for those dialects that support a device cache
+ * file.
+ *
+ * HASENVDC defined the name of an environment variable that contains the
+ * device cache file path. The HASENVDC environment variable is ignored when
+ * the lsof process is setuid(root) or its real UID is 0.
+ *
+ * HASPERSDC defines the format for the last component of a personal device
+ * cache file path. The first will be the home directory of the real UID that
+ * executes lsof.
+ *
+ * HASPERSDCPATH defines the environment variable whose value is the middle
+ * component of the personal device cache file path. The middle component
+ * follows the home directory and precedes the results of applying HASPERSDC.
+ * The HASPERSDCPATH environment variable is ignored when the lsof process is
+ * setuid(root) or its real UID is 0.
+ *
+ * HASSYSDC defines a public device cache file path. When it's defined, it's
+ * used as the path from which to read the device cache.
+ *
+ * Consult the 00DCACHE and 00FAQ files of the lsof distribution for more
+ * information on device cache file path construction.
+ */
+
+/* #define HASDCACHE 1 */
+/* #define HASENVDC "LSOFDEVCACHE" */
+/* #define HASPERSDC "%h/%p.lsof_%L" */
+/* #define HASPERSDCPATH "LSOFPERSDCPATH" */
+/* #define HASSYSDC "/your/choice/of/path" */
+
+
+/*
+ * HASCDRNODE is defined for those dialects that have CD-ROM nodes.
+ */
+
+/* #define HASCDRNODE 1 */
+
+
+/*
+ * HASFIFONODE is defined for those dialects that have FIFO nodes.
+ */
+
+/* #define HASFIFONODE 1 */
+
+
+/*
+ * HASFSINO is defined for those dialects that have the file system
+ * inode element, fs_ino, in the lfile structure definition in lsof.h.
+ */
+
+/* #define HASFSINO 1 */
+
+
+/*
+ * HASFSTRUCT is defined if the dialect has a file structure.
+ *
+ * FSV_DEFAULT defines the default set of file structure values to list.
+ * It defaults to zero (0), but may be made up of a combination of the
+ * FSV_* symbols from lsof.h.
+ *
+ * HASNOFSADDR -- has no file structure address
+ * HASNOFSFLAGS -- has no file structure flags
+ * HASNOFSCOUNT -- has no file structure count
+ * HASNOFSNADDR -- has no file structure node address
+ */
+
+#define HASFSTRUCT 1
+/* #define FSV_DEFAULT FSV_? | FSV_? | FSV_? */
+/* #define HASNOFSADDR 1 has no file structure address */
+/* #define HASNOFSFLAGS 1 has no file structure flags */
+/* #define HASNOFSCOUNT 1 has no file structure count */
+/* #define HASNOFSNADDR 1 has no file structure node address */
+
+
+/*
+ * HASGNODE is defined for those dialects that have gnodes.
+ */
+
+/* #define HASGNODE 1 */
+
+
+/*
+ * HASHSNODE is defined for those dialects that have High Sierra nodes.
+ */
+
+/* #define HASHSNODE 1 */
+
+
+/*
+ * HASINODE is defined for those dialects that have inodes and wish to
+ * use readinode() from node.c.
+ */
+
+# if DARWINV<800
+#define HASINODE 1
+# endif /* DARWINV<800 */
+
+
+/*
+ * HASINTSIGNAL is defined for those dialects whose signal function returns
+ * an int.
+ */
+
+/* #define HASINTSIGNAL 1 */
+
+
+/*
+ * HASKERNIDCK is defined for those dialects that support the comparison of
+ * the build to running kernel identity.
+ */
+
+#define HASKERNIDCK 1
+
+
+/*
+ * HASKOPT is defined for those dialects that support the -k option of
+ * reading the kernel's name list from an optional file.
+ */
+
+#define HASKOPT 1
+
+
+/*
+ * HASLFILEADD is defined for those dialects that need additional elements
+ * in struct lfile. The HASLFILEADD definition is a macro that defines
+ * them. If any of the additional elements need to be preset in the
+ * alloc_lfile() function of proc.c, the SETLFILEADD macro may be defined
+ * to do that.
+ *
+ * If any additional elements need to be cleared in alloc_lfile() or in the
+ * free_proc() function of proc.c, the CLRLFILEADD macro may be defined to
+ * do that. Note that CLRLFILEADD takes one argument, the pointer to the
+ * lfile struct. The CLRLFILEADD macro is expected to expand to statements
+ * that are complete -- i.e., have terminating semi-colons -- so the macro is
+ * called without a terminating semicolon by proc.c.
+ *
+ * The HASXOPT definition may be used to select the conditions under which
+ * private lfile elements are used.
+ */
+
+# if DARWINV>=800
+#define HASLFILEADD char *V_path;
+#define CLRLFILEADD(lf) if (lf->V_path) { \
+ (void) free((FREE_P *)lf->V_path); \
+ lf->V_path = (char *)NULL; \
+ }
+#define SETLFILEADD Lf->V_path = (char *)NULL;
+# endif /* DARWINV>=800 */
+
+
+/*
+ * HASMNTSTAT indicates the dialect supports the mount stat(2) result option
+ * in its l_vfs and mounts structures.
+ */
+
+/* #define HASMNTSTAT 1 */
+
+
+/*
+ * HASMNTSUP is defined for those dialects that support the mount supplement
+ * option.
+ */
+
+/* #define HASMNTSUP 1 */
+
+
+/*
+ * HASMOPT is defined for those dialects that support the reading of
+ * kernel memory from an alternate file.
+ */
+
+#define HASMOPT 1
+
+
+/*
+ * HASNCACHE is defined for those dialects that have a kernel name cache
+ * that lsof can search. A value of 1 directs printname() to prefix the
+ * cache value with the file system directory name; 2, avoid the prefix.
+ *
+ * NCACHELDPFX is a set of C commands to execute before calling ncache_load().
+ *
+ * NCACHELDSFX is a set of C commands to execute after calling ncache_load().
+ */
+
+# if DARWINV<800
+#define HASNCACHE 1
+/* #define NCACHELDPFX ??? */
+/* #define NCACHELDSFX ??? */
+# else /* DARWINV>=800 */
+/* #define HASNCACHE 1 */
+/* #define NCACHELDPFX ??? */
+/* #define NCACHELDSFX ??? */
+# endif /* DARWINV<800 */
+
+
+/*
+ * HASNLIST is defined for those dialects that use nlist() to acccess
+ * kernel symbols.
+ */
+
+#define HASNLIST 1
+
+
+/*
+ * HASPIPEFN is defined for those dialects that have a special function to
+ * process DTYPE_PIPE file structure entries. Its value is the name of the
+ * function.
+ *
+ * NOTE: don't forget to define a prototype for this function in dproto.h.
+ */
+
+# if DARWINV<800
+/* #define HASPIPEFN process_pipe? */
+# else /* DARWINV>=800 */
+#define HASPIPEFN process_pipe
+# endif /* DARWINV<800 */
+
+
+/*
+ * HASPIPENODE is defined for those dialects that have pipe nodes.
+ */
+
+/* #define HASPIPENODE 1 */
+
+
+/*
+ * HASPMAPENABLED is defined when the reporting of portmapper registration
+ * info is enabled by default.
+ */
+
+/* #define HASPMAPENABLED 1 */
+
+
+/*
+ * HASPPID is defined for those dialects that support identification of
+ * the parent process IDentifier (PPID) of a process.
+ */
+#define HASPPID 1
+
+
+/*
+ * HASPRINTDEV, HASPRINTINO, HASPRINTNM, HASPRINTOFF, and HASPRINTSZ
+ * define private dialect-specific functions for printing DEVice numbers,
+ * INOde numbers, NaMes, file OFFsets, and file SiZes. The functions are
+ * called from print_file().
+ */
+
+/* #define HASPRINTDEV print_dev? */
+/* #define HASPRINTINO print_ino? */
+/* #define HASPRINTNM print_nm? */
+/* #define HASPRINTOFF print_off? */
+/* #define HASPRINTSZ print_sz? */
+
+
+/*
+ * HASPRIVFILETYPE and PRIVFILETYPE are defined for dialects that have a
+ * file structure type that isn't defined by a DTYPE_* symbol. They are
+ * used in lib/prfp.c to select the type's processing.
+ *
+ * PRIVFILETYPE is the definition of the f_type value in the file struct.
+ *
+ * HASPRIVFILETYPE is the name of the processing function.
+ */
+
+/* #define HASPRIVFILETYPE process_shmf? */
+/* #define PRIVFILETYPE ?? */
+
+
+/*
+ * HASPRIVNMCACHE is defined for dialects that have a private method for
+ * printing cached NAME column values for some files. HASPRIVNAMECACHE
+ * is defined to be the name of the function.
+ *
+ * The function takes one argument, a struct lfile pointer to the file, and
+ * returns non-zero if it prints a name to stdout.
+ */
+
+# if DARWINV<800
+/* #define HASPRIVNMCACHE <function name> */
+# else /* DARWINV>=800 */
+#define HASPRIVNMCACHE print_v_path
+# endif /* DARWINV<800 */
+
+
+/*
+ * HASPRIVPRIPP is defined for dialects that have a private function for
+ * printing IP protocol names. When HASPRIVPRIPP isn't defined, the
+ * IP protocol name printing function defaults to printiprto().
+ */
+
+/* #define HASPRIVPRIPP 1 */
+
+
+/*
+ * HASPROCFS is defined for those dialects that have a proc file system --
+ * usually /proc and usually in SYSV4 derivatives.
+ *
+ * HASFSTYPE is defined as 1 for those systems that have a file system type
+ * string, st_fstype, in the stat() buffer; 2, for those systems that have a
+ * file system type integer in the stat() buffer, named MOUNTS_STAT_FSTYPE;
+ * 0, for systems whose stat(2) structure has no file system type member. The
+ * additional symbols MOUNTS_FSTYPE, RMNT_FSTYPE, and RMNT_STAT_FSTYPE may be
+ * defined in dlsof.h to direct how the readmnt() function in lib/rmnt.c
+ * preserves these stat(2) and getmntent(3) buffer values in the local mounts
+ * structure.
+ *
+ * The defined value is the string that names the file system type.
+ *
+ * The HASPROCFS definition usually must be accompanied by the HASFSTYPE
+ * definition and the providing of an fstype element in the local mounts
+ * structure (defined in dlsof.h).
+ *
+ * The HASPROCFS definition may be accompanied by the HASPINODEN definition.
+ * HASPINODEN specifies that searching for files in HASPROCFS is to be done
+ * by inode number.
+ */
+
+# if defined(HASPROCFS)
+#undef HASPROCFS
+#define HASPROCFS "proc"
+# endif /* defined(HASPROCFS) */
+
+/* #define HASPROCFS "proc?" */
+/* #define HASFSTYPE 1 */
+
+#define HASPINODEN 1
+
+
+/*
+ * HASRNODE is defined for those dialects that have rnodes.
+ */
+
+/* #define HASRNODE 1 */
+
+
+/*
+ * Define HASSECURITY to restrict the listing of all open files to the
+ * root user. When HASSECURITY is defined, the non-root user may list
+ * only files whose processes have the same user ID as the real user ID
+ * (the one that its user logged on with) of the lsof process.
+ */
+
+/* #define HASSECURITY 1 */
+
+
+/*
+ * If HASSECURITY is defined, define HASNOSOCKSECURITY to allow users
+ * restricted by HASSECURITY to list any open socket files, provide their
+ * listing is selected by the "-i" option.
+ */
+
+/* #define HASNOSOCKSECURITY 1 */
+
+
+/*
+ * HASSETLOCALE is defined for those dialects that have <locale.h> and
+ * setlocale().
+ *
+ * If the dialect also has wide character support for language locales,
+ * HASWIDECHAR activates lsof's wide character support and WIDECHARINCL
+ * defines the header file (if any) that must be #include'd to use the
+ * mblen() and mbtowc() functions.
+ */
+
+#define HASSETLOCALE 1
+
+# if DARWINV>=700
+#define HASWIDECHAR 1
+# endif /* DARWINV>=700 */
+
+/* #define WIDECHARINCL <wchar.h> */
+
+
+/*
+ * HASSNODE is defined for those dialects that have snodes.
+ */
+
+/* #define HASSNODE 1 */
+
+
+/*
+ * HASTASKS is defined for those dialects that have task reporting support.
+ */
+
+/* #define HASTASKS 1 */
+
+
+/*
+ * HASSOOPT, HASSOSTATE and HASTCPOPT define the availability of information
+ * on socket options (SO_* symbols), socket states (SS_* symbols) and TCP
+ * options.
+ */
+
+#define HASSOOPT 1 /* has socket option information */
+#define HASSOSTATE 1 /* has socket state information */
+#define HASTCPOPT 1 /* has TCP options or flags */
+
+
+/*
+ * Define HASSPECDEVD to be the name of a function that handles the results
+ * of a successful stat(2) of a file name argument.
+ *
+ * For example, HASSPECDEVD() for Darwin makes sure that st_dev is set to
+ * what stat("/dev") returns -- i.e., what's in DevDev.
+ *
+ * The function takes two arguments:
+ *
+ * 1: pointer to the full path name of file
+ * 2: pointer to the stat(2) result
+ *
+ * The function returns void.
+ */
+
+#define HASSPECDEVD process_dev_stat
+
+
+/*
+ * HASSTREAMS is defined for those dialects that support streams.
+ */
+
+/* #define HASSTREAMS 1 */
+
+
+/*
+ * HASTCPTPIQ is defined for dialects where it is possible to report the
+ * TCP/TPI Recv-Q and Send-Q values produced by netstat.
+ */
+
+#define HASTCPTPIQ 1
+
+
+/*
+ * HASTCPTPIW is defined for dialects where it is possible to report the
+ * TCP/TPI send and receive window sizes produced by netstat.
+ */
+
+/* #define HASTCPTPIW 1 */
+
+
+/*
+ * HASTMPNODE is defined for those dialects that have tmpnodes.
+ */
+
+/* #define HASTMPNODE 1 */
+
+
+/*
+ * HASVNODE is defined for those dialects that use the Sun virtual file system
+ * node, the vnode. BSD derivatives usually do; System V derivatives prior
+ * to R4 usually don't.
+ * doesn't.
+ */
+
+#define HASVNODE 1
+
+
+/*
+ * HASXOPT is defined for those dialects that have an X option. It
+ * defines the text for the usage display. HASXOPT_VALUE defines the
+ * option's default binary value -- 0 or 1.
+ */
+
+/* #define HASXOPT "help text for X option" */
+/* #define HASXOPT_VALUE 1 */
+
+
+/*
+ * INODETYPE and INODEPSPEC define the internal node number type and its
+ * printf specification modifier. These need not be defined and lsof.h
+ * can be allowed to define defaults.
+ *
+ * These are defined here, because they must be used in dlsof.h.
+ */
+
+# if DARWINV>=800
+#define INODETYPE unsigned long long
+ /* inode number internal storage type */
+#define INODEPSPEC "ll" /* INODETYPE printf specification
+ * modifier */
+# endif /* DARWINV>=800 */
+
+
+/*
+ * UID_ARG defines the size of a User ID number when it is passed
+ * as a function argument.
+ */
+
+#define UID_ARG int
+
+
+/*
+ * Each USE_LIB_<function_name> is defined for dialects that use the
+ * <function_name> in the lsof library.
+ *
+ * Note: other definitions and operations may be required to condition the
+ * library function source code. They may be found in the dialect dlsof.h
+ * header files.
+ */
+
+#define USE_LIB_CKKV 1 /* ckkv.c */
+/* #define USE_LIB_COMPLETEVFS 1 cvfs.c */
+#define USE_LIB_FIND_CH_INO 1 /* fino.c */
+#define USE_LIB_IS_FILE_NAMED 1 /* isfn.c */
+#define USE_LIB_LKUPDEV 1 /* lkud.c */
+#define USE_LIB_PRINTDEVNAME 1 /* pdvn.c */
+/* #define USE_LIB_PROCESS_FILE 1 prfp.c */
+#define USE_LIB_PRINT_TCPTPI 1 /* ptti.c */
+/* #define USE_LIB_READDEV 1 rdev.c */
+/* #define USE_LIB_READMNT 1 rmnt.c */
+/* #define USE_LIB_REGEX 1 regex.c */
+/* #define USE_LIB_RNAM 1 rnam.c */
+
+#if DARWINV<800
+#define USE_LIB_RNMH 1 /* rnmh.c */
+#else /* DARWINV>800 */
+/* #define USE_LIB_RNMH 1 rnmh.c */
+#endif /* DARWINV<800 */
+
+/* #define USE_LIB_RNCH 1 rnch.c */
+/* #define USE_LIB_SNPF 1 snpf.c */
+#define snpf snprintf /* use the system's snprintf() */
+
+
+/*
+ * WARNDEVACCESS is defined for those dialects that should issue a warning
+ * when lsof can't access /dev (or /device) or one of its sub-directories.
+ * The warning can be inhibited by the lsof caller with the -w option.
+ */
+
+#define WARNDEVACCESS 1
+
+
+/*
+ * WARNINGSTATE is defined for those dialects that want to suppress all lsof
+ * warning messages.
+ */
+
+/* #define WARNINGSTATE 1 warnings are enabled by default */
+
+
+/*
+ * WILLDROPGID is defined for those dialects whose lsof executable runs
+ * setgid(not_real_GID) and whose setgid power can be relinquished after
+ * the dialect's initialize() function has been executed.
+ */
+
+#define WILLDROPGID 1
+
+
+/*
+ * zeromem is a macro that uses bzero or memset.
+ */
+
+#define zeromem(a, l) memset(a, 0, l)
+
+#endif /* !defined(LSOF_MACHINE_H) */
diff --git a/dialects/darwin/libproc/Makefile b/dialects/darwin/libproc/Makefile
new file mode 100644
index 0000000..bda2623
--- /dev/null
+++ b/dialects/darwin/libproc/Makefile
@@ -0,0 +1,171 @@
+
+# Darwin libproc-based lsof Makefile
+#
+# $Id: Makefile,v 1.7 2009/03/25 19:21:37 abe Exp $
+
+PROG= lsof
+
+BIN= ${DSTROOT}/usr/sbin
+
+DOC= ${DSTROOT}/usr/share/man/man8
+
+I=/usr/include
+S=/usr/include/sys
+L=/usr/include/local
+P=
+
+CDEF= ${RC_CFLAGS}
+CDEFS= ${CDEF} ${CFGF}
+INCL= ${DINC}
+override CFLAGS= ${CDEFS} ${INCL} ${DEBUG}
+
+GRP= wheel
+
+HDR= lsof.h lsof_fields.h dlsof.h machine.h proto.h dproto.h
+
+SRC= ddev.c dfile.c dmnt.c dproc.c dsock.c dstore.c \
+ arg.c main.c misc.c node.c print.c proc.c store.c usage.c util.c
+
+OBJ= ddev.o dfile.o dmnt.o dproc.o dsock.o dstore.o \
+ arg.o main.o misc.o node.o print.o proc.o store.o usage.o util.o
+
+MAN= lsof.8
+
+OTHER=
+
+SHELL= /bin/sh
+
+SOURCE= Makefile ${OTHER} ${MAN} ${HDR} ${SRC}
+
+all: ${PROG}
+
+${PROG}: ${LIB} ${P} ${OBJ}
+ ${CC} -o $@ ${CFLAGS} ${OBJ} ${CFGL}
+
+clean: FRC
+ rm -f Makefile.bak ${PROG} a.out core errs lint.out tags *.o version.h
+ rm -f machine.h.old new_machine.h
+ (cd lib; ${MAKE} -f Makefile.skel clean)
+
+install-strip: all FRC
+ @if [ -n "${SYMROOT}" ]; then \
+ mkdir -p ${SYMROOT}; \
+ cp -p ${PROG} ${SYMROOT}/${PROG}; \
+ fi
+ mkdir -p ${BIN}
+ install -c -s -m 755 -g ${GRP} ${PROG} ${BIN}
+ mkdir -p ${DOC}
+ install -c -m 444 ${MAN} ${DOC}
+
+install: all FRC
+ @echo ''
+ @echo 'Please write your own install rule. Lsof for Darwin below 8'
+ @echo 'should be installed setgid to the group that has permission'
+ @echo 'to read /dev/kmem, often kmem or sys. Lsof for Darwin 8 and'
+ @echo 'above should be installed setuid-root. Your install rule'
+ @echo 'actions for Darwin below 8 might look something like this:'
+ @echo ''
+ @echo ' install -m 2xxx -g $${GRP} $${PROG} $${BIN}'
+ @echo ' install -m 444 $${MAN} $${DOC}'
+ @echo ''
+ @echo 'Your install rule actions for Darwin 8 and above might look'
+ @echo 'something like this:'
+ @echo ''
+ @echo ' install -m 4xxx -o root $${PROG} $${BIN}'
+ @echo ' install -m 444 $${MAN} $${DOC}'
+ @echo ''
+ @echo 'You will have to complete the xxx modes, the GRP value, and'
+ @echo 'the skeletons for the BIN and DOC strings, given at the'
+ @echo 'beginning of this Makefile, e.g.,'
+ @echo ''
+ @echo ' BIN= $${DESTDIR}/usr/local/etc'
+ @echo ' DOC= $${DESTDIR}/usr/man/man8'
+ @echo ' GRP= kmem'
+ @echo ''
+
+${LIB}: FRC
+ (cd lib; ${MAKE} DEBUG="${DEBUG}" CFGF="${CFGF}")
+
+version.h: FRC
+ @echo Constructing version.h
+ @rm -f version.h
+ @echo '#define LSOF_BLDCMT "${LSOF_BLDCMT}"' > version.h;
+ @echo '#define LSOF_CC "${CC}"' >> version.h
+ @echo '#define LSOF_CCV "${CCV}"' >> version.h
+ @echo '#define LSOF_CCDATE "'`date`'"' >> version.h
+ @echo '#define LSOF_CCFLAGS "'`echo ${CFLAGS} | sed 's/\\\\(/\\(/g' | sed 's/\\\\)/\\)/g' | sed 's/"/\\\\"/g'`'"' >> version.h
+ @echo '#define LSOF_CINFO "${CINFO}"' >> version.h
+ @if [ "X${LSOF_HOST}" = "X" ]; then \
+ echo '#define LSOF_HOST "'`uname -n`'"' >> version.h; \
+ else \
+ if [ "${LSOF_HOST}" = "none" ]; then \
+ echo '#define LSOF_HOST ""' >> version.h; \
+ else \
+ echo '#define LSOF_HOST "${LSOF_HOST}"' >> version.h; \
+ fi \
+ fi
+ @echo '#define LSOF_LDFLAGS "${CFGL}"' >> version.h
+ @if [ "X${LSOF_LOGNAME}" = "X" ]; then \
+ echo '#define LSOF_LOGNAME "${LOGNAME}"' >> version.h; \
+ else \
+ if [ "${LSOF_LOGNAME}" = "none" ]; then \
+ echo '#define LSOF_LOGNAME ""' >> version.h; \
+ else \
+ echo '#define LSOF_LOGNAME "${LSOF_LOGNAME}"' >> version.h; \
+ fi; \
+ fi
+ @if [ "X${LSOF_SYSINFO}" = "X" ]; then \
+ echo '#define LSOF_SYSINFO "'`uname -a`'"' >> version.h; \
+ else \
+ if [ "${LSOF_SYSINFO}" = "none" ]; then \
+ echo '#define LSOF_SYSINFO ""' >> version.h; \
+ else \
+ echo '#define LSOF_SYSINFO "${LSOF_SYSINFO}"' >> version.h; \
+ fi \
+ fi
+ @if [ "X${LSOF_USER}" = "X" ]; then \
+ echo '#define LSOF_USER "${USER}"' >> version.h; \
+ else \
+ if [ "${LSOF_USER}" = "none" ]; then \
+ echo '#define LSOF_USER ""' >> version.h; \
+ else \
+ echo '#define LSOF_USER "${LSOF_USER}"' >> version.h; \
+ fi \
+ fi
+ @sed '/VN/s/.ds VN \(.*\)/#define LSOF_VERSION "\1"/' < version >> version.h
+
+FRC:
+
+# DO NOT DELETE THIS LINE - make depend DEPENDS ON IT
+
+ddev.o: ${HDR} ddev.c
+
+dfile.o: ${HDR} dfile.c
+
+dmnt.o: ${HDR} dmnt.c
+
+dproc.o: ${HDR} dproc.c
+
+dsock.o: ${HDR} dsock.c
+
+dstore.o: ${HDR} dstore.c
+
+arg.o: ${HDR} arg.c
+
+main.o: ${HDR} main.c
+
+misc.o: ${HDR} misc.c
+
+node.o: ${HDR} node.c
+
+print.o: ${HDR} print.c
+
+proc.o: ${HDR} proc.c
+
+store.o: ${HDR} store.c
+
+usage.o: ${HDR} version.h usage.c
+
+util.o: ${HDR} util.c
+
+# *** Do not add anything here - It will go away. ***
diff --git a/dialects/darwin/libproc/Mksrc b/dialects/darwin/libproc/Mksrc
new file mode 100755
index 0000000..870d6ca
--- /dev/null
+++ b/dialects/darwin/libproc/Mksrc
@@ -0,0 +1,24 @@
+#!/bin/sh
+#
+# Mksrc -- make Darwin libproc-based lsof source files
+#
+# WARNING: This script assumes it is running from the main directory
+# of the lsof, version 4 distribution.
+#
+# One environment variable applies:
+#
+# LSOF_MKC is the method for creating the source files.
+# It defaults to "ln -s". A common alternative is "cp".
+#
+# $Id: Mksrc,v 1.5 2005/11/06 12:50:09 abe Exp $
+
+
+D=dialects/darwin/libproc
+L="dlsof.h ddev.c dfile.c dmnt.c dproc.c dproto.h dsock.c dstore.c machine.h"
+
+for i in $L
+do
+ rm -f $i
+ $LSOF_MKC $D/$i $i
+ echo "$LSOF_MKC $D/$i $i"
+done
diff --git a/dialects/darwin/libproc/ddev.c b/dialects/darwin/libproc/ddev.c
new file mode 100644
index 0000000..2240501
--- /dev/null
+++ b/dialects/darwin/libproc/ddev.c
@@ -0,0 +1,549 @@
+/*
+ * ddev.c -- Darwin device support functions for libproc-based lsof
+ */
+
+
+/*
+ * Portions Copyright 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * Copyright 2005 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907. All rights reserved.
+ *
+ * Written by Allan Nathanson, Apple Computer, Inc., and Victor A.
+ * Abell, Purdue University.
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors, nor Apple Computer, Inc. nor Purdue University
+ * are responsible for any consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either
+ * by explicit claim or by omission. Credit to the authors, Apple
+ * Computer, Inc. and Purdue University must appear in documentation
+ * and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright 2005 Apple Computer, Inc. and Purdue Research Foundation.\nAll rights reserved.\n";
+static char *rcsid = "$Id: ddev.c,v 1.2 2006/03/27 23:23:13 abe Exp $";
+#endif
+
+
+#include "lsof.h"
+
+
+/*
+ * Local definitions
+ */
+
+#if defined(DVCH_DEVPATH)
+#define DDEV_DEVPATH DVCH_DEVPATH
+#else /* !defined(DVCH_DEVPATH) */
+#define DDEV_DEVPATH "/dev"
+#endif /* defined(DVCH_DEVPATH) */
+
+#define LIKE_BLK_SPEC "like block special"
+#define LIKE_CHR_SPEC "like character special"
+
+#if defined(USE_STAT)
+#define STATFN stat
+#else /* !defined(USE_STAT) */
+#define STATFN lstat
+#endif /* defined(USE_STAT) */
+
+
+/*
+ * Local static variables.
+ */
+
+static dev_t *ADev = (dev_t *) NULL; /* device numbers besides DevDev found
+ * inside DDEV_DEVPATH */
+static int ADevA = 0; /* entries allocated to ADev[] */
+static int ADevU = 0; /* entries used in ADev[] */
+
+
+/*
+ * Local function prototypes
+ */
+
+_PROTOTYPE(static int rmdupdev,(struct l_dev ***dp, int n, char *nm));
+_PROTOTYPE(static void saveADev,(struct stat *s));
+
+
+#if defined(HASSPECDEVD)
+/*
+ * HASSPECDEVD() -- process stat(2) result to see if the device number is
+ * inside DDEV_DEVPATH "/"
+ *
+ * exit: s->st_dev changed to DevDev, as required
+ */
+
+void
+HASSPECDEVD(p, s)
+ char *p; /* file path */
+ struct stat *s; /* stat(2) result for file */
+{
+ int i;
+
+ switch (s->st_mode & S_IFMT) {
+ case S_IFCHR:
+ case S_IFBLK:
+ if (s->st_dev == DevDev)
+ return;
+ (void) readdev(0);
+ if (!ADev)
+ return;
+ for (i = 0; i < ADevU; i++) {
+ if (s->st_dev == ADev[i]) {
+ s->st_dev = DevDev;
+ return;
+ }
+ }
+ }
+}
+#endif /* defined(HASSPECDEVD) */
+
+
+/*
+ * printdevname() -- print character device name
+ */
+
+int
+printdevname(dev, rdev, f, nty)
+ dev_t *dev; /* device */
+ dev_t *rdev; /* raw device */
+ int f; /* 1 = follow with '\n' */
+ int nty; /* node type: N_BLK or N_chr */
+{
+ char *cp, *ttl;
+ struct l_dev *dp;
+ int i, len;
+/*
+ * See if the device node resides in DDEV_DEVPATH. If it does, return zero
+ * to indicate the vnode path is to be used for the NAME column.
+ */
+ if (*dev == DevDev)
+ return(0);
+ readdev(0);
+ for (i = 0; i < ADevU; i++) {
+ if (*dev == ADev[i])
+ return(0);
+ }
+/*
+ * This device is not in DDEV_DEVPATH.
+ *
+ * See if it has a DDEV_DEVPATH analogue by searching the device table for a
+ * match without inode number and dev.
+ */
+
+#if defined(HASBLKDEV)
+ if (nty == N_BLK)
+ dp = lkupbdev(&DevDev, rdev, 0, 1);
+ else
+#endif /* defined(HASBLKDEV) */
+
+ dp = lkupdev(&DevDev, rdev, 0, 1);
+ if (dp) {
+
+ /*
+ * A match was found. Record it as a name column addition.
+ */
+ ttl = (nty == N_BLK) ? LIKE_BLK_SPEC : LIKE_CHR_SPEC;
+ len = (int)(1 + strlen(ttl) + 1 + strlen(dp->name) + 1);
+ if (!(cp = (char *)malloc((MALLOC_S)(len + 1)))) {
+ (void) fprintf(stderr, "%s: no nma space for: (%s %s)\n",
+ Pn, ttl, dp->name);
+ Exit(1);
+ }
+ (void) snpf(cp, len + 1, "(%s %s)", ttl, dp->name);
+ (void) add_nma(cp, len);
+ (void) free((MALLOC_P *)cp);
+ }
+/*
+ * Return zero to indicate the vnode path is to be used for the NAME column.
+ */
+ return(0);
+}
+
+
+/*
+ * readdev() -- read device names, modes and types
+ */
+
+void
+readdev(skip)
+ int skip; /* skip device cache read if 1 --
+ * ignored since device cache not
+ * used */
+{
+ DIR *dfp;
+ int dnamlen;
+ struct dirent *dp;
+ char *fp = (char *)NULL;
+ char *path = (char *)NULL;
+ int i = 0;
+ int j = 0;
+ MALLOC_S pl, sz;
+ struct stat sb;
+/*
+ * Read device names but once.
+ */
+ if (Sdev)
+ return;
+/*
+ * Prepare to scan DDEV_DEVPATH.
+ */
+ Dstkn = Dstkx = 0;
+ Dstk = (char **)NULL;
+ (void) stkdir(DDEV_DEVPATH);
+/*
+ * Unstack the next directory.
+ */
+ while (--Dstkx >= 0) {
+ if (!(dfp = OpenDir(Dstk[Dstkx]))) {
+
+# if defined(WARNDEVACCESS)
+ if (!Fwarn) {
+ (void) fprintf(stderr, "%s: WARNING: can't open: ", Pn);
+ safestrprt(Dstk[Dstkx], stderr, 1);
+ }
+# endif /* defined(WARNDEVACCESS) */
+
+ (void) free((FREE_P *)Dstk[Dstkx]);
+ Dstk[Dstkx] = (char *)NULL;
+ continue;
+ }
+ if (path) {
+ (void) free((FREE_P *)path);
+ path = (char *)NULL;
+ }
+ if (!(path = mkstrcat(Dstk[Dstkx], -1, "/", 1, (char *)NULL, -1,
+ &pl)))
+ {
+ (void) fprintf(stderr, "%s: no space for: ", Pn);
+ safestrprt(Dstk[Dstkx], stderr, 1);
+ Exit(1);
+ }
+ (void) free((FREE_P *)Dstk[Dstkx]);
+ Dstk[Dstkx] = (char *)NULL;
+ /*
+ * Scan the directory.
+ */
+ for (dp = ReadDir(dfp); dp; dp = ReadDir(dfp)) {
+ if (dp->d_ino == 0 || dp->d_name[0] == '.')
+ continue;
+ /*
+ * Form the full path name and get its status.
+ */
+ dnamlen = (int)dp->d_namlen;
+ if (fp) {
+ (void) free((FREE_P *)fp);
+ fp = (char *)NULL;
+ }
+ if (!(fp = mkstrcat(path, pl, dp->d_name, dnamlen,
+ (char *)NULL, -1, (MALLOC_S *)NULL)))
+ {
+ (void) fprintf(stderr, "%s: no space for: ", Pn);
+ safestrprt(path, stderr, 0);
+ safestrprtn(dp->d_name, dnamlen, stderr, 1);
+ Exit(1);
+ }
+ if (STATFN(fp, &sb) != 0) {
+ if (errno == ENOENT) /* a sym link to nowhere? */
+ continue;
+
+# if defined(WARNDEVACCESS)
+ if (!Fwarn) {
+ int errno_save = errno;
+
+ (void) fprintf(stderr, "%s: can't stat ", Pn);
+ safestrprt(fp, stderr, 0);
+ (void) fprintf(stderr, ": %s\n", strerror(errno_save));
+ }
+# endif /* defined(WARNDEVACCESS) */
+
+ continue;
+ }
+ /*
+ * If it's a subdirectory, stack its name for later
+ * processing.
+ */
+ if ((sb.st_mode & S_IFMT) == S_IFDIR) {
+
+ /*
+ * Skip /dev/fd.
+ */
+ if (strcmp(fp, "/dev/fd"))
+ (void) stkdir(fp);
+ continue;
+ }
+ if ((sb.st_mode & S_IFMT) == S_IFLNK) {
+
+ /*
+ * Ignore symbolic links.
+ */
+ continue;
+ }
+ if ((sb.st_mode & S_IFMT) == S_IFCHR) {
+
+ /*
+ * Save character device information in Devtp[].
+ */
+ if (i >= Ndev) {
+ Ndev += DEVINCR;
+ if (!Devtp)
+ Devtp = (struct l_dev *)malloc(
+ (MALLOC_S)(sizeof(struct l_dev)*Ndev));
+ else
+ Devtp = (struct l_dev *)realloc((MALLOC_P *)Devtp,
+ (MALLOC_S)(sizeof(struct l_dev)*Ndev));
+ if (!Devtp) {
+ (void) fprintf(stderr,
+ "%s: no space for character device\n", Pn);
+ Exit(1);
+ }
+ }
+ Devtp[i].rdev = sb.st_rdev;
+ Devtp[i].inode = (INODETYPE)sb.st_ino;
+ if (!(Devtp[i].name = mkstrcpy(fp, (MALLOC_S *)NULL))) {
+ (void) fprintf(stderr,
+ "%s: no space for device name: ", Pn);
+ safestrprt(fp, stderr, 1);
+ Exit(1);
+ }
+ Devtp[i].v = 0;
+ i++;
+ }
+
+# if defined(HASBLKDEV)
+ if ((sb.st_mode & S_IFMT) == S_IFBLK) {
+
+ /*
+ * Save block device information in BDevtp[].
+ */
+ if (j >= BNdev) {
+ BNdev += DEVINCR;
+ if (!BDevtp)
+ BDevtp = (struct l_dev *)malloc(
+ (MALLOC_S)(sizeof(struct l_dev)*BNdev));
+ else
+ BDevtp = (struct l_dev *)realloc((MALLOC_P *)BDevtp,
+ (MALLOC_S)(sizeof(struct l_dev)*BNdev));
+ if (!BDevtp) {
+ (void) fprintf(stderr,
+ "%s: no space for block device\n", Pn);
+ Exit(1);
+ }
+ }
+ BDevtp[j].name = fp;
+ fp = (char *)NULL;
+ BDevtp[j].inode = (INODETYPE)sb.st_ino;
+ BDevtp[j].rdev = sb.st_rdev;
+ BDevtp[j].v = 0;
+ j++;
+ }
+# endif /* defined(HASBLKDEV) */
+
+ /*
+ * Save a possible new st_dev number within DDEV_DEVPATH.
+ */
+ if (sb.st_dev != DevDev)
+ (void) saveADev(&sb);
+ }
+ (void) CloseDir(dfp);
+ }
+/*
+ * Free any unneeded space that was allocated.
+ */
+ if (ADev && (ADevU < ADevA)) {
+
+ /*
+ * Reduce space allocated to additional DDEV_DEVPATH device numbers.
+ */
+ if (!ADevU) {
+
+ /*
+ * If no space was used, free the entire allocation.
+ */
+ (void) free((FREE_P *)ADev);
+ ADev = (dev_t *)NULL;
+ ADevA = 0;
+ } else {
+
+ /*
+ * Reduce the allocation to what was used.
+ */
+ sz = (MALLOC_S)(ADevU * sizeof(dev_t));
+ if (!(ADev = (dev_t *)realloc((MALLOC_P *)ADev, sz))) {
+ (void) fprintf(stderr, "%s: can't reduce ADev[]\n", Pn);
+ Exit(1);
+ }
+ }
+ }
+ if (!Dstk) {
+ (void) free((FREE_P *)Dstk);
+ Dstk = (char **)NULL;
+ }
+ if (fp)
+ (void) free((FREE_P *)fp);
+ if (path)
+ (void) free((FREE_P *)path);
+
+# if defined(HASBLKDEV)
+/*
+ * Reduce the BDevtp[] (optional) and Devtp[] tables to their minimum
+ * sizes; allocate and build sort pointer lists; and sort the tables by
+ * device number.
+ */
+ if (BNdev) {
+ if (BNdev > j) {
+ BNdev = j;
+ BDevtp = (struct l_dev *)realloc((MALLOC_P *)BDevtp,
+ (MALLOC_S)(sizeof(struct l_dev) * BNdev));
+ }
+ if (!(BSdev = (struct l_dev **)malloc(
+ (MALLOC_S)(sizeof(struct l_dev *) * BNdev))))
+ {
+ (void) fprintf(stderr,
+ "%s: no space for block device sort pointers\n", Pn);
+ Exit(1);
+ }
+ for (j = 0; j < BNdev; j++) {
+ BSdev[j] = &BDevtp[j];
+ }
+ (void) qsort((QSORT_P *)BSdev, (size_t)BNdev,
+ (size_t)sizeof(struct l_dev *), compdev);
+ BNdev = rmdupdev(&BSdev, BNdev, "block");
+ }
+
+# if !defined(NOWARNBLKDEV)
+ else {
+ if (!Fwarn)
+ (void) fprintf(stderr,
+ "%s: WARNING: no block devices found\n", Pn);
+ }
+# endif /* !defined(NOWARNBLKDEV) */
+# endif /* defined(HASBLKDEV) */
+
+ if (Ndev) {
+ if (Ndev > i) {
+ Ndev = i;
+ Devtp = (struct l_dev *)realloc((MALLOC_P *)Devtp,
+ (MALLOC_S)(sizeof(struct l_dev) * Ndev));
+ }
+ if (!(Sdev = (struct l_dev **)malloc(
+ (MALLOC_S)(sizeof(struct l_dev *) * Ndev))))
+ {
+ (void) fprintf(stderr,
+ "%s: no space for character device sort pointers\n", Pn);
+ Exit(1);
+ }
+ for (i = 0; i < Ndev; i++) {
+ Sdev[i] = &Devtp[i];
+ }
+ (void) qsort((QSORT_P *)Sdev, (size_t)Ndev,
+ (size_t)sizeof(struct l_dev *), compdev);
+ Ndev = rmdupdev(&Sdev, Ndev, "char");
+ } else {
+ (void) fprintf(stderr, "%s: no character devices found\n", Pn);
+ Exit(1);
+ }
+}
+
+
+/*
+ * rmdupdev() - remove duplicate (major/minor/inode) devices
+ */
+
+static int
+rmdupdev(dp, n, nm)
+ struct l_dev ***dp; /* device table pointers address */
+ int n; /* number of pointers */
+ char *nm; /* device table name for error message */
+{
+ int i, j, k;
+ struct l_dev **p;
+
+ for (i = j = 0, p = *dp; i < n ;) {
+ for (k = i + 1; k < n; k++) {
+ if (p[i]->rdev != p[k]->rdev || p[i]->inode != p[k]->inode)
+ break;
+ }
+ if (i != j)
+ p[j] = p[i];
+ j++;
+ i = k;
+ }
+ if (n == j)
+ return(n);
+ if (!(*dp = (struct l_dev **)realloc((MALLOC_P *)*dp,
+ (MALLOC_S)(j * sizeof(struct l_dev *)))))
+ {
+ (void) fprintf(stderr, "%s: can't realloc %s device pointers\n",
+ Pn, nm);
+ Exit(1);
+ }
+ return(j);
+}
+
+
+/*
+ * saveADev() - save additional device number appearing inside DDEV_DEVPATH
+ */
+
+static void
+saveADev(s)
+ struct stat *s; /* stat(2) buffer for file */
+{
+ int i;
+ MALLOC_S sz;
+/*
+ * Process VCHR files.
+ *
+ * Optionally process VBLK files.
+ */
+
+#if defined(HASBLKDEV)
+ if (((s->st_mode & S_IFMT) != S_IFBLK)
+ && ((s->st_mode & S_IFMT) != S_IFCHR))
+#else /* !defined(HASBLKDEV) */
+ if ((s->st_mode & S_IFCHR) != S_IFCHR)
+#endif /* defined(HASBLKDEV) */
+
+ return;
+/*
+ * See if this is a new VBLK or VCHR st_dev value for ADev[].
+ */
+ for (i = 0; i < ADevU; i++) {
+ if (s->st_dev == ADev[i])
+ return;
+ }
+/*
+ * This is a new device number to add to ADev[].
+ */
+ if (ADevU >= ADevA) {
+ ADevA += 16;
+ sz = (MALLOC_S)(ADevA * sizeof(dev_t));
+ if (ADev)
+ ADev = (dev_t *)realloc((MALLOC_P *)ADev, sz);
+ else
+ ADev = (dev_t *)malloc(sz);
+ if (!ADev) {
+ (void) fprintf(stderr, "%s: no space for ADev[]\n", Pn);
+ Exit(1);
+ }
+ }
+ ADev[ADevU++] = s->st_dev;
+}
diff --git a/dialects/darwin/libproc/dfile.c b/dialects/darwin/libproc/dfile.c
new file mode 100644
index 0000000..bd8d81a
--- /dev/null
+++ b/dialects/darwin/libproc/dfile.c
@@ -0,0 +1,682 @@
+/*
+ * dfile.c -- Darwin file processing functions for libproc-based lsof
+ */
+
+
+/*
+ * Portions Copyright 2005-2007 Apple Inc. All rights reserved.
+ *
+ * Copyright 2005 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907. All rights reserved.
+ *
+ * Written by Allan Nathanson, Apple Inc., and Victor A. Abell, Purdue
+ * University.
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors, nor Apple Inc. nor Purdue University are
+ * responsible for any consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either
+ * by explicit claim or by omission. Credit to the authors, Apple
+ * Inc. and Purdue University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright 2005-2007 Apple Inc. and Purdue Research Foundation.\nAll rights reserved.\n";
+static char *rcsid = "$Id: dfile.c,v 1.8 2012/04/10 16:41:04 abe Exp $";
+#endif
+
+
+#include "lsof.h"
+
+
+/*
+ * enter_file_info() -- enter file information
+ */
+
+void
+enter_file_info(pfi)
+ struct proc_fileinfo *pfi; /* pointer to process file info */
+{
+ int f;
+/*
+ * Construct access code
+ */
+ f = pfi->fi_openflags & (FREAD | FWRITE);
+ if (f == FREAD)
+ Lf->access = 'r';
+ else if (f == FWRITE)
+ Lf->access = 'w';
+ else if (f == (FREAD | FWRITE))
+ Lf->access = 'u';
+/*
+ * Save the offset / size
+ */
+ Lf->off = (SZOFFTYPE)pfi->fi_offset;
+ if (Foffset)
+ Lf->off_def = 1;
+/*
+ * Save file structure information as requested.
+ */
+ if (Fsv & FSV_FG) {
+ Lf->ffg = (long)pfi->fi_openflags;
+ Lf->fsv |= FSV_FG;
+ }
+}
+
+
+/*
+ * enter_vnode_info() -- enter vnode information
+ */
+
+void
+enter_vnode_info(vip)
+ struct vnode_info_path *vip; /* pointer to vnode info with path */
+{
+ char buf[32], *cp;
+ dev_t dev = 0;
+ int devs = 0;
+ struct mounts *mp;
+/*
+ * Derive file type.
+ */
+ switch ((int)(vip->vip_vi.vi_stat.vst_mode & S_IFMT)) {
+ case S_IFIFO:
+ cp = "FIFO";
+ Ntype = N_FIFO;
+ break;
+ case S_IFCHR:
+ cp = "CHR";
+ Ntype = N_CHR;
+ break;
+ case S_IFDIR:
+ cp = "DIR";
+ Ntype = N_REGLR;
+ break;
+ case S_IFBLK:
+ cp = "BLK";
+ Ntype = N_BLK;
+ break;
+ case S_IFREG:
+ cp = "REG";
+ Ntype = N_REGLR;
+ break;
+ default:
+ (void) snpf(buf, sizeof(buf), "%04o",
+ (((vip->vip_vi.vi_stat.vst_mode & S_IFMT) >> 12) & 0xfff));
+ cp = buf;
+ Ntype = N_REGLR;
+ }
+ if (!Lf->type[0])
+ (void) snpf(Lf->type, sizeof(Lf->type), "%s", cp);
+ Lf->ntype = Ntype;
+/*
+ * Save device number and path
+ */
+ switch (Ntype) {
+ case N_FIFO:
+ break;
+ case N_CHR:
+ case N_BLK:
+ Lf->rdev = vip->vip_vi.vi_stat.vst_rdev;
+ Lf->rdev_def = 1;
+ /* fall through */
+ default:
+ Lf->dev = dev = vip->vip_vi.vi_stat.vst_dev;
+ Lf->dev_def = devs = 1;
+ }
+/*
+ * Save path name.
+ */
+ vip->vip_path[sizeof(vip->vip_path) - 1] = '\0';
+ if (vip->vip_path[0] != '\0') {
+ Lf->V_path = mkstrcpy(vip->vip_path, (MALLOC_S *)NULL);
+ }
+/*
+ * Save node number.
+ */
+ Lf->inode = (INODETYPE)vip->vip_vi.vi_stat.vst_ino;
+ Lf->inp_ty = 1;
+/*
+ * Save link count, as requested.
+ */
+ if (Fnlink) {
+ Lf->nlink = vip->vip_vi.vi_stat.vst_nlink;
+ Lf->nlink_def = 1;
+ if (Nlink && (Lf->nlink < Nlink))
+ Lf->sf |= SELNLINK;
+ }
+/*
+ * If a device number is defined, locate file system and save its identity.
+ */
+ if (devs) {
+ for (mp = readmnt(); mp; mp = mp->next) {
+ if (dev == mp->dev) {
+ Lf->fsdir = mp->dir;
+ Lf->fsdev = mp->fsname;
+ if (mp->is_nfs && Fnfs)
+ Lf->sf |= SELNFS;
+ break;
+ }
+ }
+ }
+/*
+ * Save the file size.
+ */
+ switch (Ntype) {
+ case N_CHR:
+ case N_FIFO:
+ Lf->off_def = 1;
+ break;
+ default:
+ Lf->sz = (SZOFFTYPE)vip->vip_vi.vi_stat.vst_size;
+ Lf->sz_def = 1;
+ }
+/*
+ * Test for specified file.
+ */
+ if (Sfile && is_file_named(NULL,
+ ((Ntype == N_CHR) || (Ntype == N_BLK) ? 1
+ : 0)))
+ {
+ Lf->sf |= SELNM;
+ }
+/*
+ * Enter name characters.
+ */
+ if (!Lf->nm && Namech[0])
+ enter_nm(Namech);
+}
+
+
+/*
+ * err2nm() -- convert errno to a message in Namech
+ */
+
+void
+err2nm(pfx)
+ char *pfx; /* Namech message prefix */
+{
+ char *sfx;
+
+ switch (errno) {
+ case EBADF:
+
+ /*
+ * The file descriptor is no longer available.
+ */
+ sfx = "FD unavailable";
+ break;
+ case ESRCH:
+
+ /*
+ * The process is no longer available.
+ */
+ sfx = "process unavailable";
+ break;
+ default:
+
+ /*
+ * All other errors are reported with strerror() information.
+ */
+ sfx = strerror(errno);
+ }
+ (void) snpf(Namech, Namechl, "%s: %s", pfx, sfx);
+ enter_nm(Namech);
+}
+
+
+/*
+ * print_nm() -- print Name column
+ */
+void
+print_nm(lf)
+ struct lfile *lf;
+{
+ printname(0);
+#ifdef PROC_PIDLISTFILEPORTS
+ if (lf->fileport) {
+ (void) printf(" (fileport=0x%04x)", lf->fileport);
+ }
+#endif /* PROC_PIDLISTFILEPORTS */
+ putchar('\n');
+}
+
+
+/*
+ * print_v_path() -- print vnode's path
+ */
+
+int
+print_v_path(lf)
+ struct lfile *lf;
+{
+ if (lf->V_path) {
+ safestrprt(lf->V_path, stdout, 0);
+ return(1);
+ }
+ return(0);
+}
+
+
+/*
+ * process_atalk() -- process an Apple Talk file
+ */
+
+void
+process_atalk(pid, fd)
+ int pid; /* PID */
+ int32_t fd; /* FD */
+{
+ (void) snpf(Lf->type, sizeof(Lf->type), "ATALK");
+ return;
+}
+
+
+/*
+ * process_fsevents() -- process a file system events file
+ */
+
+void
+process_fsevents(pid, fd)
+ int pid; /* PID */
+ int32_t fd; /* FD */
+{
+ (void) snpf(Lf->type, sizeof(Lf->type), "FSEVENTS");
+}
+
+
+/*
+ * process_kqueue() -- process a kernel queue file
+ */
+
+void
+process_kqueue(pid, fd)
+ int pid; /* PID */
+ int32_t fd; /* FD */
+{
+ struct kqueue_fdinfo kq;
+ int nb;
+/*
+ * Get the kernel queue file information.
+ */
+ (void) snpf(Lf->type, sizeof(Lf->type), "KQUEUE");
+ nb = proc_pidfdinfo(pid, fd, PROC_PIDFDKQUEUEINFO, &kq, sizeof(kq));
+ if (nb <= 0) {
+ (void) err2nm("kqueue");
+ return;
+ } else if (nb < sizeof(kq)) {
+ (void) fprintf(stderr,
+ "%s: PID %d, FD %d; proc_pidfdinfo(PROC_PIDFDKQUEUEINFO);\n",
+ Pn, pid, fd);
+ (void) fprintf(stderr,
+ " too few bytes; expected %ld, got %d\n",
+ sizeof(kq), nb);
+ Exit(1);
+ }
+/*
+ * Enter the kernel queue file information.
+ */
+ enter_file_info(&kq.pfi);
+/*
+ * Enter queue counts as NAME column information.
+ */
+ (void) snpf(Namech, Namechl,
+ "count=%" SZOFFPSPEC "u, state=%#x",
+ (SZOFFTYPE)kq.kqueueinfo.kq_stat.vst_size,
+ kq.kqueueinfo.kq_state);
+ enter_nm(Namech);
+}
+
+
+/*
+ * process_pipe() -- process pipe file
+ */
+
+static void
+process_pipe_common(pi)
+ struct pipe_fdinfo *pi;
+{
+ char dev_ch[32], *ep;
+ size_t sz;
+
+ (void) snpf(Lf->type, sizeof(Lf->type), "PIPE");
+/*
+ * Enter the pipe handle as the device.
+ */
+ (void) snpf(dev_ch, sizeof(dev_ch), "%s",
+ print_kptr((KA_T)pi->pipeinfo.pipe_handle, (char *)NULL, 0));
+ enter_dev_ch(dev_ch);
+/*
+ * Enable offset or size reporting.
+ */
+ if (Foffset)
+ Lf->off_def = 1;
+ else {
+ Lf->sz = (SZOFFTYPE)pi->pipeinfo.pipe_stat.vst_blksize;
+ Lf->sz_def = 1;
+ }
+/*
+ * If there is a peer handle, enter it in as NAME column information.
+ */
+ if (pi->pipeinfo.pipe_peerhandle) {
+ (void) snpf(Namech, Namechl, "->%s",
+ print_kptr((KA_T)pi->pipeinfo.pipe_peerhandle, (char *)NULL, 0));
+ enter_nm(Namech);
+ } else
+ Namech[0] = '\0';
+/*
+ * If the pipe has a count, add it to the NAME column.
+ */
+ if (pi->pipeinfo.pipe_stat.vst_size) {
+ ep = endnm(&sz);
+ (void) snpf(ep, sz, ", cnt=%" SZOFFPSPEC "u",
+ (SZOFFTYPE)pi->pipeinfo.pipe_stat.vst_size);
+ }
+}
+
+
+void
+process_pipe(pid, fd)
+ int pid; /* PID */
+ int32_t fd; /* FD */
+{
+ int nb;
+ struct pipe_fdinfo pi;
+/*
+ * Get pipe file information.
+ */
+ nb = proc_pidfdinfo(pid, fd, PROC_PIDFDPIPEINFO, &pi, sizeof(pi));
+ if (nb <= 0) {
+ (void) err2nm("pipe");
+ return;
+ } else if (nb < sizeof(pi)) {
+ (void) fprintf(stderr,
+ "%s: PID %d, FD %d; proc_pidfdinfo(PROC_PIDFDPIPEINFO);\n",
+ Pn, pid, fd);
+ (void) fprintf(stderr,
+ " too few bytes; expected %ld, got %d\n",
+ sizeof(pi), nb);
+ Exit(1);
+ }
+
+ process_pipe_common(&pi);
+}
+
+
+#ifdef PROC_PIDLISTFILEPORTS
+void
+process_fileport_pipe(pid, fp)
+ int pid; /* PID */
+ uint32_t fp; /* FILEPORT */
+{
+ int nb;
+ struct pipe_fdinfo pi;
+/*
+ * Get pipe file information.
+ */
+ nb = proc_pidfileportinfo(pid, fp, PROC_PIDFILEPORTPIPEINFO, &pi, sizeof(pi));
+ if (nb <= 0) {
+ (void) err2nm("pipe");
+ return;
+ } else if (nb < sizeof(pi)) {
+ (void) fprintf(stderr,
+ "%s: PID %d, FILEPORT %u; proc_pidfileportinfo(PROC_PIDFILEPORTPIPEINFO);\n",
+ Pn, pid, fp);
+ (void) fprintf(stderr,
+ " too few bytes; expected %ld, got %d\n",
+ sizeof(pi), nb);
+ Exit(1);
+ }
+
+ process_pipe_common(&pi);
+}
+#endif /* PROC_PIDLISTFILEPORTS */
+
+
+/*
+ * process_psem() -- process a POSIX semaphore file
+ */
+
+void
+process_psem(pid, fd)
+ int pid; /* PID */
+ int32_t fd; /* FD */
+{
+ int nb;
+ struct psem_fdinfo ps;
+/*
+ * Get the sempaphore file information.
+ */
+ (void) snpf(Lf->type, sizeof(Lf->type), "PSXSEM");
+ nb = proc_pidfdinfo(pid, fd, PROC_PIDFDPSEMINFO, &ps, sizeof(ps));
+ if (nb <= 0) {
+ (void) err2nm("semaphore");
+ return;
+ } else if (nb < sizeof(ps)) {
+ (void) fprintf(stderr,
+ "%s: PID %d, FD %d; proc_pidfdinfo(PROC_PIDFDPSEMINFO);\n",
+ Pn, pid, fd);
+ (void) fprintf(stderr,
+ " too few bytes; expected %ld, got %d\n",
+ sizeof(ps), nb);
+ Exit(1);
+ }
+/*
+ * Enter the semaphore file information.
+ */
+ enter_file_info(&ps.pfi);
+/*
+ * If there is a semaphore file name, enter it.
+ */
+ if (ps.pseminfo.psem_name[0]) {
+ ps.pseminfo.psem_name[sizeof(ps.pseminfo.psem_name) - 1] = '\0';
+ (void) snpf(Namech, Namechl, "%s", ps.pseminfo.psem_name);
+ enter_nm(Namech);
+ }
+/*
+ * Unless file size has been specifically requested, enable the printing of
+ * file offset.
+ */
+ if (!Fsize)
+ Lf->off_def = 1;
+}
+
+
+/*
+ * process_pshm() -- process POSIX shared memory file
+ */
+
+static void
+process_pshm_common(ps)
+ struct pshm_fdinfo *ps;
+{
+ (void) snpf(Lf->type, sizeof(Lf->type), "PSXSHM");
+/*
+ * Enter the POSIX shared memory file information.
+ */
+ enter_file_info(&ps->pfi);
+/*
+ * If the POSIX shared memory file has a path name, enter it; otherwise, if it
+ * has a mapping address, enter that.
+ */
+ if (ps->pshminfo.pshm_name[0]) {
+ ps->pshminfo.pshm_name[sizeof(ps->pshminfo.pshm_name) - 1] = '\0';
+ (void) snpf(Namech, Namechl, "%s", ps->pshminfo.pshm_name);
+ enter_nm(Namech);
+ } else if (ps->pshminfo.pshm_mappaddr) {
+ (void) snpf(Namech, Namechl, "obj=%s",
+ print_kptr((KA_T)ps->pshminfo.pshm_mappaddr, (char *)NULL, 0));
+ enter_nm(Namech);
+ }
+/*
+ * Enable offset or size reporting.
+ */
+ if (Foffset)
+ Lf->off_def = 1;
+ else {
+ Lf->sz = (SZOFFTYPE)ps->pshminfo.pshm_stat.vst_size;
+ Lf->sz_def = 1;
+ }
+}
+
+
+void
+process_pshm(pid, fd)
+ int pid; /* PID */
+ int32_t fd; /* FD */
+{
+ int nb;
+ struct pshm_fdinfo ps;
+/*
+ * Get the POSIX shared memory file information.
+ */
+ nb = proc_pidfdinfo(pid, fd, PROC_PIDFDPSHMINFO, &ps, sizeof(ps));
+ if (nb <= 0) {
+ (void) err2nm("POSIX shared memory");
+ return;
+ } else if (nb < sizeof(ps)) {
+ (void) fprintf(stderr,
+ "%s: PID %d, FD %d; proc_pidfdinfo(PROC_PIDFDPSHMINFO);\n",
+ Pn, pid, fd);
+ (void) fprintf(stderr,
+ " too few bytes; expected %ld, got %d\n",
+ sizeof(ps), nb);
+ Exit(1);
+ }
+
+ process_pshm_common(&ps);
+}
+
+
+#ifdef PROC_PIDLISTFILEPORTS
+void
+process_fileport_pshm(pid, fp)
+ int pid; /* PID */
+ uint32_t fp; /* FILEPORT */
+{
+ int nb;
+ struct pshm_fdinfo ps;
+/*
+ * Get the POSIX shared memory file information.
+ */
+ nb = proc_pidfileportinfo(pid, fp, PROC_PIDFILEPORTPSHMINFO, &ps, sizeof(ps));
+ if (nb <= 0) {
+ (void) err2nm("POSIX shared memory");
+ return;
+ } else if (nb < sizeof(ps)) {
+ (void) fprintf(stderr,
+ "%s: PID %d, FILEPORT %u; proc_pidfileportinfo(PROC_PIDFILEPORTPSHMINFO);\n",
+ Pn, pid, fp);
+ (void) fprintf(stderr,
+ " too few bytes; expected %ld, got %d\n",
+ sizeof(ps), nb);
+ Exit(1);
+ }
+
+ process_pshm_common(&ps);
+}
+#endif /* PROC_PIDLISTFILEPORTS */
+
+
+/*
+ * process_vnode() -- process a vnode file
+ */
+
+static void
+process_vnode_common(vi)
+ struct vnode_fdinfowithpath *vi;
+{
+/*
+ * Enter the file and vnode information.
+ */
+ enter_file_info(&vi->pfi);
+ enter_vnode_info(&vi->pvip);
+}
+
+
+void
+process_vnode(pid, fd)
+ int pid; /* PID */
+ int32_t fd; /* FD */
+{
+ int nb;
+ struct vnode_fdinfowithpath vi;
+
+ nb = proc_pidfdinfo(pid, fd, PROC_PIDFDVNODEPATHINFO, &vi, sizeof(vi));
+ if (nb <= 0) {
+ if (errno == ENOENT) {
+
+ /*
+ * The file descriptor's vnode may have been revoked. This is a
+ * bit of a hack, since an ENOENT error might not always mean the
+ * descriptor's vnode has been revoked. As the libproc API
+ * matures, this code may need to be revisited.
+ */
+ enter_nm("(revoked)");
+ } else
+ (void) err2nm("vnode");
+ return;
+ } else if (nb < sizeof(vi)) {
+ (void) fprintf(stderr,
+ "%s: PID %d, FD %d: proc_pidfdinfo(PROC_PIDFDVNODEPATHINFO);\n",
+ Pn, pid, fd);
+ (void) fprintf(stderr,
+ " too few bytes; expected %ld, got %d\n",
+ sizeof(vi), nb);
+ Exit(1);
+ }
+
+ process_vnode_common(&vi);
+}
+
+
+#ifdef PROC_PIDLISTFILEPORTS
+void
+process_fileport_vnode(pid, fp)
+ int pid; /* PID */
+ uint32_t fp; /* FILEPORT */
+{
+ int nb;
+ struct vnode_fdinfowithpath vi;
+
+ nb = proc_pidfileportinfo(pid, fp, PROC_PIDFILEPORTVNODEPATHINFO, &vi, sizeof(vi));
+ if (nb <= 0) {
+ if (errno == ENOENT) {
+
+ /*
+ * The file descriptor's vnode may have been revoked. This is a
+ * bit of a hack, since an ENOENT error might not always mean the
+ * descriptor's vnode has been revoked. As the libproc API
+ * matures, this code may need to be revisited.
+ */
+ enter_nm("(revoked)");
+ } else
+ (void) err2nm("vnode");
+ return;
+ } else if (nb < sizeof(vi)) {
+ (void) fprintf(stderr,
+ "%s: PID %d, FILEPORT %u: proc_pidfdinfo(PROC_PIDFDVNODEPATHINFO);\n",
+ Pn, pid, fp);
+ (void) fprintf(stderr,
+ " too few bytes; expected %ld, got %d\n",
+ sizeof(vi), nb);
+ Exit(1);
+ }
+
+ process_vnode_common(&vi);
+}
+#endif /* PROC_PIDLISTFILEPORTS */
diff --git a/dialects/darwin/libproc/dlsof.h b/dialects/darwin/libproc/dlsof.h
new file mode 100644
index 0000000..142a073
--- /dev/null
+++ b/dialects/darwin/libproc/dlsof.h
@@ -0,0 +1,136 @@
+/*
+ * dlsof.h -- Darwin header file for libproc-based lsof
+ */
+
+
+/*
+ * Portions Copyright 2005-2007 Apple Inc. All rights reserved.
+ *
+ * Copyright 2005 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907. All rights reserved.
+ *
+ * Written by Allan Nathanson, Apple Inc., and Victor A. Abell, Purdue
+ * University.
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors, nor Apple Inc. nor Purdue University are
+ * responsible for any consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either
+ * by explicit claim or by omission. Credit to the authors, Apple
+ * Inc. and Purdue University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+
+/*
+ * $Id: dlsof.h,v 1.8 2012/04/10 16:41:04 abe Exp $
+ */
+
+
+#if !defined(DARWIN_LSOF_H)
+#define DARWIN_LSOF_H 1
+
+#include <stdlib.h>
+#include <dirent.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+#include <wctype.h>
+#include <arpa/inet.h>
+#include <sys/attr.h>
+#include <sys/fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp_fsm.h>
+#include <netinet/tcp_timer.h>
+#include <rpc/rpc.h>
+#include <rpc/pmap_prot.h>
+#include <libproc.h>
+
+# if DARWINV<900
+#define vst_blksize st_blksize
+#define vst_dev st_dev
+#define vst_ino st_ino
+#define vst_mode st_mode
+#define vst_nlink st_nlink
+#define vst_rdev st_rdev
+#define vst_size st_size
+# endif /* DARWINV<=900 */
+
+#define COMP_P const void
+#define DEVINCR 1024 /* device table malloc() increment */
+#define DIRTYPE dirent /* directory entry type */
+typedef uintptr_t KA_T;
+#define KA_T_FMT_X "0x%08lx"
+#define LOGINML MAXLOGNAME
+#define MALLOC_P void
+#define FREE_P MALLOC_P
+#define MALLOC_S size_t
+#define MAXSYSCMDL (MAXCOMLEN - 1) /* max system command name length */
+#define MOUNTED MNT_MNTTAB
+#define QSORT_P void
+#define READLEN_T int
+#define STRNCPY_L size_t
+#define SZOFFTYPE unsigned long long
+ /* size and offset internal storage
+ * type */
+#define SZOFFPSPEC "ll" /* SZOFFTYPE printf specification
+ * modifier */
+
+
+/*
+ * Global storage definitions (including their structure definitions)
+ */
+
+struct file *Cfp;
+
+struct mounts {
+ char *dir; /* directory (mounted on) */
+ char *fsname; /* file system
+ * (symbolic links unresolved) */
+ char *fsnmres; /* file system
+ * (symbolic links resolved) */
+ dev_t dev; /* directory st_dev */
+ dev_t rdev; /* directory st_rdev */
+ INODETYPE inode; /* directory st_ino */
+ mode_t mode; /* directory st_mode */
+ mode_t fs_mode; /* file system st_mode */
+ int is_nfs; /* 1 if NFS file system, 0 if not */
+ struct mounts *next; /* forward link */
+};
+
+struct sfile {
+ char *aname; /* argument file name */
+ char *name; /* file name (after readlink()) */
+ char *devnm; /* device name (optional) */
+ dev_t dev; /* device */
+ dev_t rdev; /* raw device */
+ u_short mode; /* S_IFMT mode bits from stat() */
+ int type; /* file type: 0 = file system
+ * 1 = regular file */
+ INODETYPE i; /* inode number */
+ int f; /* file found flag */
+ struct sfile *next; /* forward link */
+
+};
+
+#define XDR_VOID (const xdrproc_t)xdr_void
+#define XDR_PMAPLIST (const xdrproc_t)xdr_pmaplist
+
+# if !defined(offsetof)
+#define offsetof(type, member) ((size_t)(&((type *)0)->member))
+# endif /* !defined(offsetof) */
+
+#endif /* DARWIN_LSOF_H */
diff --git a/dialects/darwin/libproc/dmnt.c b/dialects/darwin/libproc/dmnt.c
new file mode 100644
index 0000000..576f432
--- /dev/null
+++ b/dialects/darwin/libproc/dmnt.c
@@ -0,0 +1,201 @@
+/*
+ * dmnt.c -- Darwin mount support functions for libproc-based lsof
+ */
+
+
+/*
+ * Portions Copyright 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * Copyright 2005 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907. All rights reserved.
+ *
+ * Written by Allan Nathanson, Apple Computer, Inc., and Victor A.
+ * Abell, Purdue University.
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors, nor Apple Computer, Inc. nor Purdue University
+ * are responsible for any consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either
+ * by explicit claim or by omission. Credit to the authors, Apple
+ * Computer, Inc. and Purdue University must appear in documentation
+ * and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright 2005 Apple Computer, Inc. and Purdue Research Foundation.\nAll rights reserved.\n";
+static char *rcsid = "$Id: dmnt.c,v 1.6 2012/04/10 16:41:04 abe Exp $";
+#endif
+
+
+#include "lsof.h"
+
+
+/*
+ * Local static information
+ */
+
+static struct mounts *Lmi = (struct mounts *)NULL; /* local mount info */
+static int Lmist = 0; /* Lmi status */
+
+/*
+ * readmnt() -- read mount table
+ */
+
+struct mounts *
+readmnt()
+{
+#if defined(DIR_MNTSTATUS_TRIGGER)
+ struct {
+ uint32_t length;
+ uint32_t mount_flags;
+ } ab;
+ struct attrlist al;
+#endif /* defined(DIR_MNTSTATUS_TRIGGER) */
+ char *dn = (char *)NULL;
+ char *ln;
+ struct statfs *mb = (struct statfs *)NULL;
+ struct mounts *mtp;
+ int n;
+ struct stat sb;
+
+ if (Lmi || Lmist)
+ return(Lmi);
+/*
+ * Access mount information.
+ */
+ if ((n = getmntinfo(&mb, MNT_NOWAIT)) <= 0) {
+ (void) fprintf(stderr, "%s: no mount information\n", Pn);
+ return(0);
+ }
+/*
+ * Read mount information.
+ */
+ for (; n; n--, mb++) {
+
+ if (!mb->f_type)
+ continue;
+ /*
+ * Avoid file systems that are not appropriate paths to
+ * user data (e.g. automount maps, triggers).
+ */
+#if defined(DIR_MNTSTATUS_TRIGGER)
+ (void) bzero((char *)&al, sizeof(al));
+ al.bitmapcount = ATTR_BIT_MAP_COUNT;
+ al.dirattr = ATTR_DIR_MOUNTSTATUS;
+ if (getattrlist(mb->f_mntonname, &al, &ab, sizeof(ab), 0) == 0) {
+ if (ab.mount_flags & DIR_MNTSTATUS_TRIGGER)
+ continue; // if mount trigger
+ }
+#else /* !defined(DIR_MNTSTATUS_TRIGGER) */
+ if (mb->f_flags & MNT_AUTOMOUNTED) {
+ if (!strncmp(mb->f_mntfromname, "map ", 4)
+ || !strcmp(mb->f_mntfromname, "trigger"))
+ continue;
+ }
+#endif /* defined(DIR_MNTSTATUS_TRIGGER) */
+
+ /*
+ * Interpolate a possible symbolic directory link.
+ */
+ if (dn)
+ (void) free((FREE_P *)dn);
+ if (!(dn = mkstrcpy(mb->f_mntonname, (MALLOC_S *)NULL))) {
+
+no_space_for_mount:
+
+ (void) fprintf(stderr, "%s: no space for mount at ", Pn);
+ safestrprt(mb->f_mntonname, stderr, 0);
+ (void) fprintf(stderr, " (");
+ safestrprt(mb->f_mntfromname, stderr, 0);
+ (void) fprintf(stderr, ")\n");
+ Exit(1);
+ }
+ if (!(ln = Readlink(dn))) {
+ if (!Fwarn) {
+ (void) fprintf(stderr,
+ " Output information may be incomplete.\n");
+ }
+ continue;
+ }
+ if (ln != dn) {
+ (void) free((FREE_P *)dn);
+ dn = ln;
+ }
+ if (*dn != '/')
+ continue;
+ /*
+ * Stat() the directory.
+ */
+ if (statsafely(dn, &sb)) {
+ if (!Fwarn) {
+ (void) fprintf(stderr, "%s: WARNING: can't stat() ", Pn);
+
+ safestrprt(mb->f_fstypename, stderr, 0);
+
+ (void) fprintf(stderr, " file system ");
+ safestrprt(mb->f_mntonname, stderr, 1);
+ (void) fprintf(stderr,
+ " Output information may be incomplete.\n");
+ }
+ (void) bzero((char *)&sb, sizeof(sb));
+ sb.st_dev = (dev_t)mb->f_fsid.val[0];
+ sb.st_mode = S_IFDIR | 0777;
+ if (!Fwarn) {
+ (void) fprintf(stderr,
+ " assuming \"dev=%x\" from mount table\n",
+ sb.st_dev);
+ }
+ }
+ /*
+ * Allocate and fill a local mount structure.
+ */
+ if (!(mtp = (struct mounts *)malloc(sizeof(struct mounts))))
+ goto no_space_for_mount;
+ mtp->dir = dn;
+ dn = (char *)NULL;
+ mtp->next = Lmi;
+ mtp->dev = sb.st_dev;
+ mtp->rdev = sb.st_rdev;
+ mtp->inode = (INODETYPE)sb.st_ino;
+ mtp->mode = sb.st_mode;
+ mtp->is_nfs = strcasecmp(mb->f_fstypename, "nfs") ? 0 : 1;
+ /*
+ * Interpolate a possible file system (mounted-on) device name link.
+ */
+ if (!(dn = mkstrcpy(mb->f_mntfromname, (MALLOC_S *)NULL)))
+ goto no_space_for_mount;
+ mtp->fsname = dn;
+ ln = Readlink(dn);
+ dn = (char *)NULL;
+ /*
+ * Stat() the file system (mounted-on) name and add file system
+ * information to the local mount table entry.
+ */
+ if (!ln || statsafely(ln, &sb))
+ sb.st_mode = 0;
+ mtp->fsnmres = ln;
+ mtp->fs_mode = sb.st_mode;
+ Lmi = mtp;
+ }
+/*
+ * Clean up and return the local mount info table address.
+ */
+ if (dn)
+ (void) free((FREE_P *)dn);
+ Lmist = 1;
+ return(Lmi);
+}
diff --git a/dialects/darwin/libproc/dproc.c b/dialects/darwin/libproc/dproc.c
new file mode 100644
index 0000000..e4a2f00
--- /dev/null
+++ b/dialects/darwin/libproc/dproc.c
@@ -0,0 +1,839 @@
+/*
+ * dproc.c -- Darwin process access functions for libproc-based lsof
+ */
+
+
+/*
+ * Portions Copyright 2005-2007 Apple Inc. All rights reserved.
+ *
+ * Copyright 2005 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907. All rights reserved.
+ *
+ * Written by Allan Nathanson, Apple Inc., and Victor A. Abell, Purdue
+ * University.
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors, nor Apple Inc. nor Purdue University are
+ * responsible for any consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either
+ * by explicit claim or by omission. Credit to the authors, Apple
+ * Inc. and Purdue University must appear in documentation and sources.
+ * and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright 2005-2007 Apple Inc. and Purdue Research Foundation.\nAll rights reserved.\n";
+static char *rcsid = "$Id: dproc.c,v 1.9 2013/01/02 17:03:05 abe Exp $";
+#endif
+
+#include "lsof.h"
+
+
+/*
+ * Local definitions
+ */
+
+#define PIDS_INCR (sizeof(int) * 32) /* PID space increment */
+#define VIPS_INCR 16 /* Vips space increment */
+
+#if DARWINV>=900
+#define THREADS_INCR (sizeof(uint64_t) * 32) /* Threads space increment */
+#endif /* DARWINV>=900 */
+
+#ifdef PROC_PIDLISTFILEPORTS
+#define FILEPORTS_INCR (sizeof(struct proc_fileportinfo) * 32) /* Fileports space increment */
+#endif /* PROC_PIDLISTFILEPORTS */
+
+/*
+ * Local static variables
+ */
+
+static struct proc_fdinfo *Fds = (struct proc_fdinfo *)NULL;
+ /* FD buffer */
+static int NbPids = 0; /* bytes allocated to Pids */
+static int NbFds = 0; /* bytes allocated to FDs */
+static int *Pids = (int *)NULL; /* PID buffer */
+
+#if DARWINV>=900
+static int NbThreads = 0; /* Threads bytes allocated */
+static uint64_t *Threads = (uint64_t *)NULL; /* Thread buffer */
+#endif /* DARWINV>=900 */
+
+#ifdef PROC_PIDLISTFILEPORTS
+static struct proc_fileportinfo *Fps = (struct proc_fileportinfo *)NULL;
+ /* fileport buffer */
+static int NbFps = 0; /* bytes allocated to fileports */
+#endif /* PROC_PIDLISTFILEPORTS */
+
+/*
+ * Local structure definitions
+ */
+
+static struct vips_info {
+ dev_t dev;
+ ino_t ino;
+} *Vips = (struct vips_info *)NULL; /* recorded vnodes */
+static int NbVips = 0; /* bytes allocated to Vips */
+static int NVips = 0; /* entries allocated to Vips */
+
+
+/*
+ * Local function prototypes
+ */
+_PROTOTYPE(static void enter_vn_text,(struct vnode_info_path *vip, int *n));
+_PROTOTYPE(static void process_fds,(int pid, uint32_t n, int ckscko));
+_PROTOTYPE(static void process_text,(int pid));
+
+#if DARWINV>=900
+_PROTOTYPE(static void process_threads,(int pid, uint32_t n));
+#endif /* DARWINV>=900 */
+
+#ifdef PROC_PIDLISTFILEPORTS
+_PROTOTYPE(static void process_fileports,(int pid, int ckscko));
+#endif /* PROC_PIDLISTFILEPORTS */
+
+/*
+ * enter_vn_text() -- enter vnode information text reference
+ */
+
+static void
+enter_vn_text(vip, n)
+ struct vnode_info_path *vip; /* vnode info */
+ int *n; /* number of vips[] entries in use */
+{
+ int i;
+/*
+ * Ignore the request if the vnode information has already been entered.
+ */
+ for (i = 0; i < *n; i++) {
+ if ((vip->vip_vi.vi_stat.vst_dev == Vips[i].dev)
+ && (vip->vip_vi.vi_stat.vst_ino == Vips[i].ino))
+ {
+ return;
+ }
+ }
+/*
+ * Save the text file information.
+ */
+ alloc_lfile(" txt", -1);
+ Cfp = (struct file *)NULL;
+ (void) enter_vnode_info(vip);
+ if (Lf->sf)
+ link_lfile();
+/*
+ * Record the entry of the vnode information.
+ */
+ if (i >= NVips) {
+
+ /*
+ * Allocate space for recording the vnode information.
+ */
+ NVips += VIPS_INCR;
+ NbVips += (int)(VIPS_INCR * sizeof(struct vips_info));
+ if (!Vips)
+ Vips = (struct vips_info *)malloc((MALLOC_S)NbVips);
+ else
+ Vips = (struct vips_info *)realloc((MALLOC_P *)Vips,
+ (MALLOC_S)NbVips);
+ if (!Vips) {
+ (void) fprintf(stderr, "%s: PID %d: no text recording space\n",
+ Pn, Lp->pid);
+ Exit(1);
+ }
+ }
+/*
+ * Record the vnode information.
+ */
+ Vips[*n].dev = vip->vip_vi.vi_stat.vst_dev;
+ Vips[*n].ino = vip->vip_vi.vi_stat.vst_ino;
+ (*n)++;
+}
+
+
+/*
+ * gather_proc_info() -- gather process information
+ */
+
+void
+gather_proc_info()
+{
+ short cckreg; /* conditional status of regular file
+ * checking:
+ * 0 = unconditionally check
+ * 1 = conditionally check */
+ short ckscko; /* socket file only checking status:
+ * 0 = none
+ * 1 = check only socket files,
+ * including TCP and UDP
+ * streams with eXPORT data,
+ * where supported */
+ int cre, cres, ef, i, nb, np, pid;
+ short pss, sf;
+ struct proc_taskallinfo tai;
+ struct proc_vnodepathinfo vpi;
+/*
+ * Define socket and regular file conditional processing flags.
+ *
+ * If only socket files have been selected, or socket files have been
+ * selected, ANDed with other selection options, enable the skipping of
+ * regular files.
+ *
+ * If socket files and some process options have been selected, enable
+ * conditional skipping of regular file; i.e., regular files will be skipped
+ * unless they belong to a process selected by one of the specified options.
+ */
+ if (Selflags & SELNW) {
+
+ /*
+ * Some network files selection options have been specified.
+ */
+ if (Fand || !(Selflags & ~SELNW)) {
+
+ /*
+ * Selection ANDing or only network file options have been
+ * specified, so set unconditional skipping of regular files
+ * and socket file only checking.
+ */
+ cckreg = 0;
+ ckscko = 1;
+ } else {
+
+ /*
+ * If ORed file selection options have been specified, or no
+ * ORed process selection options have been specified, enable
+ * unconditional file checking and clear socket file only
+ * checking.
+ *
+ * If only ORed process selection options have been specified,
+ * enable conditional file skipping and socket file only checking.
+ */
+ if ((Selflags & SELFILE) || !(Selflags & SELPROC))
+ cckreg = ckscko = 0;
+ else
+ cckreg = ckscko = 1;
+ }
+ } else {
+
+ /*
+ * No network file selection options were specified. Enable
+ * unconditional file checking and clear socket file only checking.
+ */
+ cckreg = ckscko = 0;
+ }
+/*
+ * Determine how many bytes are needed to contain the PIDs on the system;
+ * make sure sufficient buffer space is allocated to hold them (and a few
+ * extra); then read the list of PIDs.
+ */
+ if ((nb = proc_listpids(PROC_ALL_PIDS, 0, NULL, 0)) <= 0) {
+ (void) fprintf(stderr, "%s: can't get PID byte count: %s\n",
+ Pn, strerror(errno));
+ Exit(1);
+ }
+ if (nb > NbPids) {
+ while (nb > NbPids) {
+ NbPids += PIDS_INCR;
+ }
+ if (!Pids)
+ Pids = (int *)malloc((MALLOC_S)NbPids);
+ else
+ Pids = (int *)realloc((MALLOC_P *)Pids, (MALLOC_S)NbPids);
+ if (!Pids) {
+ (void) fprintf(stderr,
+ "%s: can't allocate space for %d PIDs\n", Pn,
+ (int)(NbPids / sizeof(int *)));
+ Exit(1);
+ }
+ }
+/*
+ * Get the list of PIDs.
+ */
+ for (ef = 0; !ef;) {
+ if ((nb = proc_listpids(PROC_ALL_PIDS, 0, Pids, NbPids)) <= 0) {
+ (void) fprintf(stderr, "%s: can't get list of PIDs: %s\n",
+ Pn, strerror(errno));
+ Exit(1);
+ }
+
+ if ((nb + sizeof(int)) < NbPids) {
+
+ /*
+ * There is room in the buffer for at least one more PID.
+ */
+ np = nb / sizeof(int);
+ ef = 1;
+ } else {
+
+ /*
+ * The PID buffer must be enlarged.
+ */
+ NbPids += PIDS_INCR;
+ Pids = (int *)realloc((MALLOC_P *)Pids, (MALLOC_S)NbPids);
+ if (!Pids) {
+ (void) fprintf(stderr,
+ "%s: can't allocate space for %d PIDs\n", Pn,
+ (int)(NbPids / sizeof(int *)));
+ Exit(1);
+ }
+ }
+ }
+/*
+ * Loop through the identified processes.
+ */
+ for (i = 0; i < np; i++) {
+ if (!(pid = Pids[i]))
+ continue;
+ nb = proc_pidinfo(pid, PROC_PIDTASKALLINFO, 0, &tai, sizeof(tai));
+ if (nb <= 0) {
+ if ((errno == EPERM) || (errno == ESRCH))
+ continue;
+ if (!Fwarn) {
+ (void) fprintf(stderr, "%s: PID %d information error: %s\n",
+ Pn, pid, strerror(errno));
+ }
+ continue;
+ } else if (nb < sizeof(tai)) {
+ (void) fprintf(stderr,
+ "%s: PID %d: proc_pidinfo(PROC_PIDTASKALLINFO);\n",
+ Pn, pid);
+ (void) fprintf(stderr,
+ " too few bytes; expected %ld, got %d\n",
+ sizeof(tai), nb);
+ Exit(1);
+ }
+ /*
+ * Check for process or command exclusion.
+ */
+ if (is_proc_excl((int)pid, (int)tai.pbsd.pbi_pgid,
+ (UID_ARG)tai.pbsd.pbi_uid, &pss, &sf))
+ {
+ continue;
+ }
+ tai.pbsd.pbi_comm[sizeof(tai.pbsd.pbi_comm) - 1] = '\0';
+ if (is_cmd_excl(tai.pbsd.pbi_comm, &pss, &sf))
+ continue;
+ if (tai.pbsd.pbi_name[0]) {
+ tai.pbsd.pbi_name[sizeof(tai.pbsd.pbi_name) - 1] = '\0';
+ if (is_cmd_excl(tai.pbsd.pbi_name, &pss, &sf))
+ continue;
+ }
+ if (cckreg) {
+
+ /*
+ * If conditional checking of regular files is enabled, enable
+ * socket file only checking, based on the process' selection
+ * status.
+ */
+ ckscko = (sf & SELPROC) ? 0 : 1;
+ }
+ /*
+ * Get root and current directory information.
+ */
+ if (!ckscko) {
+ nb = proc_pidinfo(pid, PROC_PIDVNODEPATHINFO, 0, &vpi,
+ sizeof(vpi));
+ if (nb <= 0) {
+ cre = errno;
+ cres = 1;
+ } else if (nb < sizeof(vpi)) {
+ (void) fprintf(stderr,
+ "%s: PID %d: proc_pidinfo(PROC_PIDVNODEPATHINFO);\n",
+ Pn, pid);
+ (void) fprintf(stderr,
+ " too few bytes; expected %ld, got %d\n",
+ sizeof(vpi), nb);
+ Exit(1);
+ } else
+ cres = 0;
+ }
+ /*
+ * Allocate local process space.
+ */
+ alloc_lproc((int)pid, (int)tai.pbsd.pbi_pgid,
+ (int)tai.pbsd.pbi_ppid, (UID_ARG)tai.pbsd.pbi_uid,
+ (tai.pbsd.pbi_name[0] != '\0') ? tai.pbsd.pbi_name
+ : tai.pbsd.pbi_comm,
+ (int)pss, (int)sf);
+ Plf = (struct lfile *)NULL;
+ /*
+ * Save current working directory information.
+ */
+ if (!ckscko) {
+ if (cres || vpi.pvi_cdir.vip_path[0]) {
+ alloc_lfile(CWD, -1);
+ Cfp = (struct file *)NULL;
+ if (cres) {
+
+ /*
+ * If the CWD|RTD information access error is ESRCH,
+ * ignore it; otherwise report the error's message in the
+ * CWD's NAME column.
+ */
+ if (cre != ESRCH) {
+ (void) snpf(Namech, Namechl, "%s|%s info error: %s",
+ CWD + 1, RTD + 1, strerror(cre));
+ Namech[Namechl - 1] = '\0';
+ enter_nm(Namech);
+ if (Lf->sf)
+ link_lfile();
+ }
+ } else {
+ (void) enter_vnode_info(&vpi.pvi_cdir);
+ if (Lf->sf)
+ link_lfile();
+ }
+ }
+ }
+ /*
+ * Save root directory information.
+ */
+ if (!ckscko) {
+ if (!cres && vpi.pvi_rdir.vip_path[0]) {
+ alloc_lfile(RTD, -1);
+ Cfp = (struct file *)NULL;
+ (void) enter_vnode_info(&vpi.pvi_rdir);
+ if (Lf->sf)
+ link_lfile();
+ }
+ }
+
+#if DARWINV>=900
+ /*
+ * Check for per-thread current working directories
+ */
+ if (!ckscko) {
+ if (tai.pbsd.pbi_flags & PROC_FLAG_THCWD) {
+ (void) process_threads(pid, tai.ptinfo.pti_threadnum);
+ }
+ }
+#endif /* DARWINV>=900 */
+
+ /*
+ * Print text file information.
+ */
+ if (!ckscko)
+ (void) process_text(pid);
+
+#ifdef PROC_PIDLISTFILEPORTS
+ /*
+ * Loop through the fileports
+ */
+ (void) process_fileports(pid, ckscko);
+#endif /* PROC_PIDLISTFILEPORTS */
+
+ /*
+ * Loop through the file descriptors.
+ */
+ (void) process_fds(pid, tai.pbsd.pbi_nfiles, ckscko);
+ /*
+ * Examine results.
+ */
+ if (examine_lproc())
+ return;
+ }
+}
+
+
+/*
+ * initialize() -- perform all initialization
+ */
+
+void
+initialize()
+{
+}
+
+
+/*
+ * process_fds() -- process file descriptors
+ */
+
+static void
+process_fds(pid, n, ckscko)
+ int pid; /* PID of interest */
+ uint32_t n; /* max FDs */
+ int ckscko; /* check socket files only */
+{
+ int i, isock, nb, nf;
+ struct proc_fdinfo *fdp;
+/*
+ * Make sure an FD buffer has been allocated.
+ */
+ if (!Fds) {
+ NbFds = sizeof(struct proc_fdinfo) * n;
+ Fds = (struct proc_fdinfo *)malloc((MALLOC_S)NbFds);
+ } else if (NbFds < sizeof(struct proc_fdinfo) * n) {
+
+ /*
+ * More proc_fdinfo space is required. Allocate it.
+ */
+ NbFds = sizeof(struct proc_fdinfo) * n;
+ Fds = (struct proc_fdinfo *)realloc((MALLOC_P *)Fds,
+ (MALLOC_S)NbFds);
+ }
+ if (!Fds) {
+ (void) fprintf(stderr,
+ "%s: PID %d: can't allocate space for %d FDs\n",
+ Pn, pid, (int)(NbFds / sizeof(struct proc_fdinfo)));
+ Exit(1);
+ }
+/*
+ * Get FD information for the process.
+ */
+ nb = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, Fds, NbFds);
+ if (nb <= 0) {
+ if (errno == ESRCH) {
+
+ /*
+ * Quit if no FD information is available for the process.
+ */
+ return;
+ }
+ /*
+ * Make a dummy file entry with an error message in its NAME column.
+ */
+ alloc_lfile(" err", -1);
+ (void) snpf(Namech, Namechl, "FD info error: %s", strerror(errno));
+ Namech[Namechl - 1] = '\0';
+ enter_nm(Namech);
+ if (Lf->sf)
+ link_lfile();
+ return;
+ }
+ nf = (int)(nb / sizeof(struct proc_fdinfo));
+/*
+ * Loop through the file descriptors.
+ */
+ for (i = 0; i < nf; i++) {
+ fdp = &Fds[i];
+ alloc_lfile(NULL, (int)fdp->proc_fd);
+ /*
+ * Process the file by its type.
+ */
+ isock = 0;
+ switch (fdp->proc_fdtype) {
+ case PROX_FDTYPE_ATALK:
+ if (!ckscko)
+ (void) process_atalk(pid, fdp->proc_fd);
+ break;
+ case PROX_FDTYPE_FSEVENTS:
+ if (!ckscko)
+ (void) process_fsevents(pid, fdp->proc_fd);
+ break;
+ case PROX_FDTYPE_KQUEUE:
+ if (!ckscko)
+ (void) process_kqueue(pid, fdp->proc_fd);
+ break;
+ case PROX_FDTYPE_PIPE:
+ if (!ckscko)
+ (void) process_pipe(pid, fdp->proc_fd);
+ break;
+ case PROX_FDTYPE_PSEM:
+ if (!ckscko)
+ (void) process_psem(pid, fdp->proc_fd);
+ break;
+ case PROX_FDTYPE_SOCKET:
+ (void) process_socket(pid, fdp->proc_fd);
+ isock = 1;
+ break;
+ case PROX_FDTYPE_PSHM:
+ (void) process_pshm(pid, fdp->proc_fd);
+ break;
+ case PROX_FDTYPE_VNODE:
+ (void) process_vnode(pid, fdp->proc_fd);
+ break;
+ default:
+ (void) snpf(Namech, Namechl - 1, "unknown file type: %d",
+ fdp->proc_fdtype);
+ Namech[Namechl - 1] = '\0';
+ (void) enter_nm(Namech);
+ break;
+ }
+ if (Lf->sf) {
+ if (!ckscko || isock)
+ link_lfile();
+ }
+ }
+}
+
+
+#ifdef PROC_PIDLISTFILEPORTS
+/*
+ * process_fileports() -- process fileports
+ */
+
+static void
+process_fileports(pid, ckscko)
+ int pid; /* PID of interest */
+ int ckscko; /* check socket files only */
+{
+ int ef, i, isock, nb = 0, nf;
+ struct proc_fileportinfo *fpi;
+
+/*
+ * Get fileport information for the process.
+ */
+ for (ef = 0; !ef;) {
+ nb = proc_pidinfo(pid, PROC_PIDLISTFILEPORTS, 0, Fps, NbFps);
+ if (nb == 0) {
+
+ /*
+ * Quit if no fileport information
+ */
+ return;
+ } else if (nb < 0) {
+ if (errno == ESRCH) {
+
+ /*
+ * Quit if no fileport information is available for the process.
+ */
+ return;
+ }
+ /*
+ * Make a dummy file entry with an error message in its NAME column.
+ */
+ alloc_lfile(" err", -1);
+ (void) snpf(Namech, Namechl, "FILEPORT info error: %s", strerror(errno));
+ Namech[Namechl - 1] = '\0';
+ enter_nm(Namech);
+ if (Lf->sf)
+ link_lfile();
+ }
+
+ if ((nb + sizeof(struct proc_fileportinfo)) < NbFps) {
+
+ /*
+ * There is room in the buffer for at least one more fileport.
+ */
+ ef = 1;
+ } else {
+ if (Fps && ((nb = proc_pidinfo(pid, PROC_PIDLISTFILEPORTS, 0, NULL, 0)) <= 0)) {
+ (void) fprintf(stderr, "%s: can't get fileport byte count: %s\n",
+ Pn, strerror(errno));
+ Exit(1);
+ }
+
+ /*
+ * The fileport buffer must be enlarged.
+ */
+ while (nb > NbFps) {
+ NbFps += FILEPORTS_INCR;
+ }
+ if (!Fps)
+ Fps = (struct proc_fileportinfo *)malloc((MALLOC_S)NbFps);
+ else
+ Fps = (struct proc_fileportinfo *)realloc((MALLOC_P *)Fps, (MALLOC_S)NbFps);
+ }
+ }
+
+/*
+ * Loop through the fileports.
+ */
+ nf = (int)(nb / sizeof(struct proc_fileportinfo));
+ for (i = 0; i < nf; i++) {
+ fpi = &Fps[i];
+ /*
+ * fileport reported as "fp." with "(fileport=0xXXXX)" in the Name column
+ */
+ alloc_lfile(" fp.", -1);
+ Lf->fileport = fpi->proc_fileport;
+ /*
+ * Process the file by its type.
+ */
+ isock = 0;
+ switch (fpi->proc_fdtype) {
+ case PROX_FDTYPE_PIPE:
+ if (!ckscko)
+ (void) process_fileport_pipe(pid, fpi->proc_fileport);
+ break;
+ case PROX_FDTYPE_SOCKET:
+ (void) process_fileport_socket(pid, fpi->proc_fileport);
+ isock = 1;
+ break;
+ case PROX_FDTYPE_PSHM:
+ (void) process_fileport_pshm(pid, fpi->proc_fileport);
+ break;
+ case PROX_FDTYPE_VNODE:
+ (void) process_fileport_vnode(pid, fpi->proc_fileport);
+ break;
+ default:
+ (void) snpf(Namech, Namechl - 1, "unknown file type: %d",
+ fpi->proc_fileport);
+ Namech[Namechl - 1] = '\0';
+ (void) enter_nm(Namech);
+ break;
+ }
+ if (Lf->sf) {
+ if (!ckscko || isock)
+ link_lfile();
+ }
+ }
+}
+#endif /* PROC_PIDLISTFILEPORTS */
+
+
+/*
+ * process_text() -- process text information
+ */
+
+static void
+process_text(pid)
+ int pid; /* PID */
+{
+ uint64_t a;
+ int i, n, nb;
+ struct proc_regionwithpathinfo rwpi;
+
+ for (a = (uint64_t)0, i = n = 0; i < 10000; i++) {
+ nb = proc_pidinfo(pid, PROC_PIDREGIONPATHINFO, a, &rwpi,
+ sizeof(rwpi));
+ if (nb <= 0) {
+ if ((errno == ESRCH) || (errno == EINVAL)) {
+
+ /*
+ * Quit if no more text information is available for the
+ * process.
+ */
+ return;
+ }
+ /*
+ * Warn about all other errors via a NAME column message.
+ */
+ alloc_lfile(" txt", -1);
+ Cfp = (struct file *)NULL;
+ (void) snpf(Namech, Namechl,
+ "region info error: %s", strerror(errno));
+ Namech[Namechl - 1] = '\0';
+ enter_nm(Namech);
+ if (Lf->sf)
+ link_lfile();
+ return;
+ } else if (nb < sizeof(rwpi)) {
+ (void) fprintf(stderr,
+ "%s: PID %d: proc_pidinfo(PROC_PIDREGIONPATHINFO);\n",
+ Pn, pid);
+ (void) fprintf(stderr,
+ " too few bytes; expected %ld, got %d\n",
+ sizeof(rwpi), nb);
+ Exit(1);
+ }
+ if (rwpi.prp_vip.vip_path[0])
+ enter_vn_text(&rwpi.prp_vip, &n);
+ a = rwpi.prp_prinfo.pri_address + rwpi.prp_prinfo.pri_size;
+ }
+}
+
+
+#if DARWINV>=900
+/*
+ * process_threads() -- process thread information
+ */
+
+#define TWD " twd" /* per-thread current working directory
+ * fd name */
+
+static void
+process_threads(pid, n)
+ int pid; /* PID */
+ uint32_t n; /* number of threads */
+{
+ int i, nb, nt;
+/*
+ * Make sure a thread buffer has been allocated.
+ */
+ n += 10;
+ if (n > NbThreads) {
+ while (n > NbThreads) {
+ NbThreads += THREADS_INCR;
+ }
+ if (!Threads)
+ Threads = (uint64_t *)malloc((MALLOC_S)NbThreads);
+ else
+ Threads = (uint64_t *)realloc((MALLOC_P *)Threads,
+ (MALLOC_S)NbThreads);
+ if (!Threads) {
+ (void) fprintf(stderr,
+ "%s: can't allocate space for %d Threads\n", Pn,
+ (int)(NbThreads / sizeof(int *)));
+ Exit(1);
+ }
+ }
+/*
+ * Get thread information for the process.
+ */
+ nb = proc_pidinfo(pid, PROC_PIDLISTTHREADS, 0, Threads, NbThreads);
+ if (nb <= 0) {
+ if (errno == ESRCH) {
+
+ /*
+ * Quit if no thread information is available for the
+ * process.
+ */
+ return;
+ }
+ }
+ nt = (int)(nb / sizeof(uint64_t));
+/*
+ * Loop through the threads.
+ */
+ for (i = 0; i < nt; i++) {
+ uint64_t t;
+ struct proc_threadwithpathinfo tpi;
+
+ t = Threads[i];
+ nb = proc_pidinfo(pid, PROC_PIDTHREADPATHINFO, t, &tpi,
+ sizeof(tpi));
+ if (nb <= 0) {
+ if ((errno == ESRCH) || (errno == EINVAL)) {
+
+ /*
+ * Quit if no more thread information is available for the
+ * process.
+ */
+ return;
+ }
+ /*
+ * Warn about all other errors via a NAME column message.
+ */
+ alloc_lfile(TWD, -1);
+ Cfp = (struct file *)NULL;
+ (void) snpf(Namech, Namechl,
+ "thread info error: %s", strerror(errno));
+ Namech[Namechl - 1] = '\0';
+ enter_nm(Namech);
+ if (Lf->sf)
+ link_lfile();
+ return;
+ } else if (nb < sizeof(tpi)) {
+ (void) fprintf(stderr,
+ "%s: PID %d: proc_pidinfo(PROC_PIDTHREADPATHINFO);\n",
+ Pn, pid);
+ (void) fprintf(stderr,
+ " too few bytes; expected %ld, got %d\n",
+ sizeof(tpi), nb);
+ Exit(1);
+ }
+ if (tpi.pvip.vip_path[0]) {
+ alloc_lfile(TWD, -1);
+ Cfp = (struct file *)NULL;
+ (void) enter_vnode_info(&tpi.pvip);
+ if (Lf->sf)
+ link_lfile();
+ }
+ }
+}
+#endif /* DARWINV>=900 */
diff --git a/dialects/darwin/libproc/dproto.h b/dialects/darwin/libproc/dproto.h
new file mode 100644
index 0000000..7f20f7d
--- /dev/null
+++ b/dialects/darwin/libproc/dproto.h
@@ -0,0 +1,61 @@
+/*
+ * dproto.h -- Darwin function prototypes for libproc-based lsof
+ *
+ * The _PROTOTYPE macro is defined in the common proto.h.
+ */
+
+
+/*
+ * Portions Copyright 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * Copyright 2005 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907. All rights reserved.
+ *
+ * Written by Allan Nathanson, Apple Computer, Inc., and Victor A.
+ * Abell, Purdue University.
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors, nor Apple Computer, Inc. nor Purdue University
+ * are responsible for any consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either
+ * by explicit claim or by omission. Credit to the authors, Apple
+ * Computer, Inc. and Purdue University must appear in documentation
+ * and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+
+/*
+ * $Id: dproto.h,v 1.6 2012/04/10 16:41:04 abe Exp $
+ */
+
+_PROTOTYPE(extern void enter_file_info,(struct proc_fileinfo *pfi));
+_PROTOTYPE(extern void enter_vnode_info,(struct vnode_info_path *vip));
+_PROTOTYPE(extern void err2nm,(char *pfx));
+_PROTOTYPE(extern int is_file_named,(char *p, int cd));
+_PROTOTYPE(extern void process_atalk,(int pid, int32_t fd));
+_PROTOTYPE(extern void process_fsevents,(int pid, int32_t fd));
+_PROTOTYPE(extern void process_kqueue,(int pid, int32_t fd));
+_PROTOTYPE(extern void process_pipe,(int pid, int32_t fd));
+_PROTOTYPE(extern void process_psem,(int pid, int32_t fd));
+_PROTOTYPE(extern void process_pshm,(int pid, int32_t fd));
+_PROTOTYPE(extern void process_socket,(int pid, int32_t fd));
+_PROTOTYPE(extern void process_vnode,(int pid, int32_t fd));
+#ifdef PROC_PIDLISTFILEPORTS
+_PROTOTYPE(extern void process_fileport_pipe,(int pid, uint32_t fileport));
+_PROTOTYPE(extern void process_fileport_pshm,(int pid, uint32_t fileport));
+_PROTOTYPE(extern void process_fileport_socket,(int pid, uint32_t fileport));
+_PROTOTYPE(extern void process_fileport_vnode,(int pid, uint32_t fileport));
+#endif /* PROC_PIDLISTFILEPORTS */
+
diff --git a/dialects/darwin/libproc/dsock.c b/dialects/darwin/libproc/dsock.c
new file mode 100644
index 0000000..175ca21
--- /dev/null
+++ b/dialects/darwin/libproc/dsock.c
@@ -0,0 +1,449 @@
+/*
+ * dsock.c -- Darwin socket processing functions for libproc-based lsof
+ */
+
+
+/*
+ * Portions Copyright 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * Copyright 2005 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907. All rights reserved.
+ *
+ * Written by Allan Nathanson, Apple Computer, Inc., and Victor A.
+ * Abell, Purdue University.
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors, nor Apple Computer, Inc. nor Purdue University
+ * are responsible for any consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either
+ * by explicit claim or by omission. Credit to the authors, Apple
+ * Computer, Inc. and Purdue University must appear in documentation
+ * and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright 2005 Apple Computer, Inc. and Purdue Research Foundation.\nAll rights reserved.\n";
+static char *rcsid = "$Id: dsock.c,v 1.7 2012/04/10 16:41:04 abe Exp $";
+#endif
+
+
+#include "lsof.h"
+
+
+/*
+ * IPv6_2_IPv4() -- macro to define the address of an IPv4 address contained
+ * in an IPv6 address
+ */
+
+#define IPv6_2_IPv4(v6) (((uint8_t *)((struct in6_addr *)v6)->s6_addr)+12)
+
+
+/*
+ * process_socket() -- process socket file
+ */
+
+static void
+process_socket_common(si)
+ struct socket_fdinfo *si;
+{
+ unsigned char *fa = (unsigned char *)NULL;
+ int fam, fp, lp, unl;
+ unsigned char *la = (unsigned char *)NULL;
+
+/*
+ * Enter basic socket values.
+ */
+ (void) snpf(Lf->type, sizeof(Lf->type), "sock");
+ Lf->inp_ty = 2;
+/*
+ * Enter basic file information.
+ */
+ enter_file_info(&si->pfi);
+/*
+ * Enable size or offset display.
+ */
+ if (Fsize) {
+ if (Lf->access == 'r')
+ Lf->sz = (SZOFFTYPE)si->psi.soi_rcv.sbi_cc;
+ else if (Lf->access == 'w')
+ Lf->sz = (SZOFFTYPE)si->psi.soi_snd.sbi_cc;
+ else
+ Lf->sz = (SZOFFTYPE)(si->psi.soi_rcv.sbi_cc
+ + si->psi.soi_snd.sbi_cc);
+ Lf->sz_def = 1;
+ } else
+ Lf->off_def = 1;
+
+#if defined(HASTCPTPIQ)
+/*
+ * Enter send and receive queue sizes.
+ */
+ Lf->lts.rq = si->psi.soi_rcv.sbi_cc;
+ Lf->lts.sq = si->psi.soi_snd.sbi_cc;
+ Lf->lts.rqs = Lf->lts.sqs = (unsigned char)1;
+#endif /* defined(HASTCPTPIQ) */
+
+#if defined(HASSOOPT)
+/*
+ * Enter socket options.
+ */
+ Lf->lts.ltm = (unsigned int)(si->psi.soi_linger & 0xffff);
+ Lf->lts.opt = (unsigned int)(si->psi.soi_options & 0xffff);
+ Lf->lts.pqlen = (unsigned int)si->psi.soi_incqlen;
+ Lf->lts.qlen = (unsigned int)si->psi.soi_qlen;
+ Lf->lts.qlim = (unsigned int)si->psi.soi_qlimit;
+ Lf->lts.rbsz = (unsigned long)si->psi.soi_rcv.sbi_mbmax;
+ Lf->lts.sbsz = (unsigned long)si->psi.soi_snd.sbi_mbmax;
+ Lf->lts.pqlens = Lf->lts.qlens = Lf->lts.qlims = Lf->lts.rbszs
+ = Lf->lts.sbszs = (unsigned char)1;
+#endif /* defined(HASSOOPT) */
+
+#if defined(HASSOSTATE)
+/*
+ * Enter socket state.
+ */
+ Lf->lts.ss = (unsigned int)si->psi.soi_state;
+#endif /* defined(HASSOSTATE) */
+
+/*
+ * Process socket by its associated domain family.
+ */
+ switch ((fam = si->psi.soi_family)) {
+ case AF_INET:
+ case AF_INET6:
+
+ /*
+ * Process IPv[46] sockets.
+ */
+ (void) snpf(Lf->type, sizeof(Lf->type),
+ (fam == AF_INET) ? "IPv4" : "IPv6");
+ if ((si->psi.soi_kind != SOCKINFO_IN) &&
+ (si->psi.soi_kind != SOCKINFO_TCP))
+ {
+ break;
+ }
+ /*
+ * Process TCP state inclusions and exclusions, as required.
+ */
+ if ((si->psi.soi_kind == SOCKINFO_TCP) && (TcpStXn || TcpStIn)) {
+ int tsnx = (int)si->psi.soi_proto.pri_tcp.tcpsi_state
+ + TcpStOff;
+
+ if ((tsnx >= 0) && (tsnx < TcpNstates)) {
+ if (TcpStXn) {
+ if (TcpStX[tsnx]) {
+ Lf->sf |= SELEXCLF;
+ return;
+ }
+ }
+ if (TcpStIn) {
+ if (TcpStI[tsnx])
+ TcpStI[tsnx] = 2;
+ else {
+ Lf->sf |= SELEXCLF;
+ return;
+ }
+ }
+ }
+ }
+ /*
+ * Process an Internet domain socket.
+ */
+ if (Fnet) {
+ if (!FnetTy
+ || ((FnetTy == 4) && (fam == AF_INET))
+ || ((FnetTy == 6) && (fam == AF_INET6))
+ )
+ Lf->sf |= SELNET;
+ }
+ printiproto(si->psi.soi_protocol);
+ if ((si->psi.soi_kind == SOCKINFO_TCP)
+ && si->psi.soi_proto.pri_tcp.tcpsi_tp)
+ {
+ enter_dev_ch(print_kptr((KA_T)si->psi.soi_proto.pri_tcp.tcpsi_tp,
+ (char *)NULL, 0));
+ } else
+ enter_dev_ch(print_kptr((KA_T)si->psi.soi_pcb, (char *)NULL, 0));
+ if (fam == AF_INET) {
+
+ /*
+ * Enter IPv4 address information.
+ */
+ if (si->psi.soi_kind == SOCKINFO_TCP) {
+
+ /*
+ * Enter information for a TCP socket.
+ */
+ la = (unsigned char *)&si->psi.soi_proto.pri_tcp.tcpsi_ini.insi_laddr.ina_46.i46a_addr4;
+ lp = (int)ntohs(si->psi.soi_proto.pri_tcp.tcpsi_ini.insi_lport);
+ fa = (unsigned char *)&si->psi.soi_proto.pri_tcp.tcpsi_ini.insi_faddr.ina_46.i46a_addr4;
+ fp = (int)ntohs(si->psi.soi_proto.pri_tcp.tcpsi_ini.insi_fport);
+ } else {
+
+ /*
+ * Enter information for a non-TCP socket.
+ */
+ la = (unsigned char *)&si->psi.soi_proto.pri_in.insi_laddr.ina_46.i46a_addr4;
+ lp = (int)ntohs(si->psi.soi_proto.pri_in.insi_lport);
+ fa = (unsigned char *)&si->psi.soi_proto.pri_in.insi_faddr.ina_46.i46a_addr4;
+ fp = (int)ntohs(si->psi.soi_proto.pri_in.insi_fport);
+ }
+ if ((fa && (*fa == INADDR_ANY)) && !fp) {
+ fa = (unsigned char *)NULL;
+ fp = 0;
+ }
+ } else {
+
+ /*
+ * Enter IPv6 address information
+ */
+ int v4mapped = 0;
+
+ if (si->psi.soi_kind == SOCKINFO_TCP)
+ {
+
+ /*
+ * Enter TCP socket information.
+ */
+ la = (unsigned char *)&si->psi.soi_proto.pri_tcp.tcpsi_ini.insi_laddr.ina_6;
+ lp = (int)ntohs(si->psi.soi_proto.pri_tcp.tcpsi_ini.insi_lport);
+ fa = (unsigned char *)&si->psi.soi_proto.pri_tcp.tcpsi_ini.insi_faddr.ina_6;
+ fp = (int)ntohs(si->psi.soi_proto.pri_tcp.tcpsi_ini.insi_fport);
+ if ((si->psi.soi_proto.pri_tcp.tcpsi_ini.insi_vflag & INI_IPV4) != 0)
+ v4mapped = 1;
+ } else {
+
+ /*
+ * Enter non-TCP socket information.
+ */
+ la = (unsigned char *)&si->psi.soi_proto.pri_in.insi_laddr.ina_6;
+ lp = (int)ntohs(si->psi.soi_proto.pri_in.insi_lport);
+ fa = (unsigned char *)&si->psi.soi_proto.pri_in.insi_faddr.ina_6;
+ fp = (int)ntohs(si->psi.soi_proto.pri_in.insi_fport);
+ if ((si->psi.soi_proto.pri_in.insi_vflag & INI_IPV4) != 0)
+ v4mapped = 1;
+ }
+ if (IN6_IS_ADDR_UNSPECIFIED((struct in6_addr *)fa) && !fp) {
+ fa = (unsigned char *)NULL;
+ fp = 0;
+ }
+ if (v4mapped) {
+
+ /*
+ * Adjust IPv4 addresses mapped in IPv6 addresses.
+ */
+ fam = AF_INET;
+ if (la)
+ la = (unsigned char *)IPv6_2_IPv4(la);
+ if (fa)
+ fa = (unsigned char *)IPv6_2_IPv4(fa);
+ }
+ }
+ /*
+ * Enter local and remote addresses by address family.
+ */
+ if (fa || la)
+ (void) ent_inaddr(la, lp, fa, fp, fam);
+ if (si->psi.soi_kind == SOCKINFO_TCP) {
+
+ /*
+ * Enter a TCP socket definition and its state.
+ */
+ Lf->lts.type = 0;
+ Lf->lts.state.i = (int)si->psi.soi_proto.pri_tcp.tcpsi_state;
+ /*
+ * Enter TCP options.
+ */
+
+#if defined(HASSOOPT)
+ Lf->lts.kai = (unsigned int)si->psi.soi_proto.pri_tcp.tcpsi_timer[TCPT_KEEP];
+#endif /* defined(HASSOOPT) */
+
+#if defined(HASTCPOPT)
+ Lf->lts.mss = (unsigned long)si->psi.soi_proto.pri_tcp.tcpsi_mss;
+ Lf->lts.msss = (unsigned char)1;
+ Lf->lts.topt = (unsigned int)si->psi.soi_proto.pri_tcp.tcpsi_flags;
+#endif /* defined(HASTCPOPT) */
+
+ }
+ break;
+ case AF_UNIX:
+
+ /*
+ * Process a UNIX domain socket.
+ */
+ (void) snpf(Lf->type, sizeof(Lf->type), "unix");
+ if (si->psi.soi_kind != SOCKINFO_UN)
+ break;
+ if (Funix)
+ Lf->sf |= SELUNX;
+ enter_dev_ch(print_kptr((KA_T)si->psi.soi_pcb, (char *)NULL, 0));
+ /*
+ * Enter information on a UNIX domain socket that has no address bound
+ * to it, although it may be connected to another UNIX domain socket
+ * as a pipe.
+ */
+ if (si->psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_family != AF_UNIX)
+ {
+ if (si->psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_family
+ == AF_UNSPEC)
+ {
+ if (si->psi.soi_proto.pri_un.unsi_conn_pcb) {
+ (void) snpf(Namech, Namechl, "->%s",
+ print_kptr((KA_T)si->psi.soi_proto.pri_un.unsi_conn_pcb, (char *)NULL, 0));
+ } else
+ (void) snpf(Namech, Namechl, "->(none)");
+ } else
+ (void) snpf(Namech, Namechl, "unknown sun_family (%d)",
+ si->psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_family);
+ break;
+ }
+ if (si->psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_path[0]) {
+ unl = si->psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_len - offsetof(struct sockaddr_un, sun_path);
+ if ((unl < 0) || (unl >= sizeof(si->psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_path)))
+ unl = sizeof(si->psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_path) - 1;
+ si->psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_path[unl] = '\0';
+ if (si->psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_path[0]
+ && Sfile
+ && is_file_named(si->psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_path, 0))
+ Lf->sf |= SELNM;
+ if (si->psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_path[0]
+ && !Namech[0])
+ (void) snpf(Namech, Namechl, "%s", si->psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_path);
+ } else
+ (void) snpf(Namech, Namechl, "no address");
+ break;
+ case AF_ROUTE:
+
+ /*
+ * Process a ROUTE domain socket.
+ */
+ (void) snpf(Lf->type, sizeof(Lf->type), "rte");
+ if (!Fsize)
+ Lf->off_def = 1;
+ break;
+ case AF_NDRV:
+
+ /*
+ * Process an NDRV domain socket.
+ */
+ (void) snpf(Lf->type, sizeof(Lf->type), "ndrv");
+ if (si->psi.soi_kind != SOCKINFO_NDRV)
+ break;
+ enter_dev_ch(print_kptr((KA_T)si->psi.soi_pcb, (char *)NULL, 0));
+ si->psi.soi_proto.pri_ndrv.ndrvsi_if_name[sizeof(si->psi.soi_proto.pri_ndrv.ndrvsi_if_name) - 1] = '\0';
+ (void) snpf(Namech, Namechl, "-> %s%d",
+ si->psi.soi_proto.pri_ndrv.ndrvsi_if_name,
+ si->psi.soi_proto.pri_ndrv.ndrvsi_if_unit);
+ break;
+ case pseudo_AF_KEY:
+
+ /*
+ * Process an [internal] key-management function socket.
+ */
+ (void) snpf(Lf->type, sizeof(Lf->type), "key");
+ enter_dev_ch(print_kptr((KA_T)si->psi.soi_pcb, (char *)NULL, 0));
+ break;
+ case AF_SYSTEM:
+
+ /*
+ * Process a SYSTEM domain socket.
+ */
+ (void) snpf(Lf->type, sizeof(Lf->type), "systm");
+ if (si->psi.soi_kind != SOCKINFO_KERN_EVENT)
+ break;
+ enter_dev_ch(print_kptr((KA_T)si->psi.soi_pcb, (char *)NULL, 0));
+ (void) snpf(Namech, Namechl, "[%x:%x:%x]",
+ si->psi.soi_proto.pri_kern_event.kesi_vendor_code_filter,
+ si->psi.soi_proto.pri_kern_event.kesi_class_filter,
+ si->psi.soi_proto.pri_kern_event.kesi_subclass_filter);
+ break;
+ case AF_PPP:
+
+ /*
+ * Process a PPP domain socket.
+ */
+ (void) snpf(Lf->type, sizeof(Lf->type), "ppp");
+ enter_dev_ch(print_kptr((KA_T)si->psi.soi_pcb, (char *)NULL, 0));
+ break;
+ default:
+ printunkaf(fam, 1);
+ }
+/*
+ * If there are NAME column characters, enter them.
+ */
+ if (Namech[0])
+ enter_nm(Namech);
+}
+
+
+void
+process_socket(pid, fd)
+ int pid; /* PID */
+ int32_t fd; /* FD */
+{
+ int nb;
+ struct socket_fdinfo si;
+/*
+ * Get socket information.
+ */
+ nb = proc_pidfdinfo(pid, fd, PROC_PIDFDSOCKETINFO, &si, sizeof(si));
+ if (nb <= 0) {
+ (void) err2nm("socket");
+ return;
+ } else if (nb < sizeof(si)) {
+ (void) fprintf(stderr,
+ "%s: PID %d, FD %d: proc_pidfdinfo(PROC_PIDFDSOCKETINFO);\n",
+ Pn, pid, fd);
+ (void) fprintf(stderr,
+ " too few bytes; expected %ld, got %d\n",
+ sizeof(si), nb);
+ Exit(1);
+ }
+
+ process_socket_common(&si);
+}
+
+
+#ifdef PROC_PIDLISTFILEPORTS
+void
+process_fileport_socket(pid, fp)
+ int pid; /* PID */
+ uint32_t fp; /* FILEPORT */
+{
+ int nb;
+ struct socket_fdinfo si;
+/*
+ * Get socket information.
+ */
+ nb = proc_pidfileportinfo(pid, fp, PROC_PIDFILEPORTSOCKETINFO, &si, sizeof(si));
+ if (nb <= 0) {
+ (void) err2nm("socket");
+ return;
+ } else if (nb < sizeof(si)) {
+ (void) fprintf(stderr,
+ "%s: PID %d, FILEPORT %u: proc_pidfileportinfo(PROC_PIDFILEPORTSOCKETINFO);\n",
+ Pn, pid, fp);
+ (void) fprintf(stderr,
+ " too few bytes; expected %ld, got %d\n",
+ sizeof(si), nb);
+ Exit(1);
+ }
+
+ process_socket_common(&si);
+}
+#endif /* PROC_PIDLISTFILEPORTS */
diff --git a/dialects/darwin/libproc/dstore.c b/dialects/darwin/libproc/dstore.c
new file mode 100644
index 0000000..b538881
--- /dev/null
+++ b/dialects/darwin/libproc/dstore.c
@@ -0,0 +1,91 @@
+/*
+ * dstore.c -- Darwin global storage for libproc-based lsof
+ */
+
+
+/*
+ * Portions Copyright 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * Copyright 2005 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907. All rights reserved.
+ *
+ * Written by Allan Nathanson, Apple Computer, Inc., and Victor A.
+ * Abell, Purdue University.
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors, nor Apple Computer, Inc. nor Purdue University
+ * are responsible for any consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either
+ * by explicit claim or by omission. Credit to the authors, Apple
+ * Computer, Inc. and Purdue University must appear in documentation
+ * and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright 2005 Apple Computer, Inc. and Purdue Research Foundation.\nAll rights reserved.\n";
+static char *rcsid = "$Id: dstore.c,v 1.4 2008/10/21 16:15:16 abe Exp $";
+#endif
+
+
+#include "lsof.h"
+
+
+#if defined(HASFSTRUCT)
+/*
+ * Pff_tab[] - table for printing file flags
+ */
+
+struct pff_tab Pff_tab[] = {
+ { (long)FREAD, FF_READ },
+ { (long)FWRITE, FF_WRITE },
+ { (long)FNONBLOCK, FF_NBLOCK },
+ { (long)FNDELAY, FF_NDELAY },
+ { (long)FAPPEND, FF_APPEND },
+ { (long)FASYNC, FF_ASYNC },
+ { (long)FFSYNC, FF_FSYNC },
+
+# if defined(FHASLOCK)
+ { (long)FHASLOCK, FF_HASLOCK },
+# endif /* defined(FHASLOCK) */
+
+ { (long)O_NOCTTY, FF_NOCTTY },
+ { (long)O_EVTONLY, FF_EVTONLY },
+ { (long)0, NULL }
+};
+
+
+/*
+ * Pof_tab[] - table for print process open file flags
+ */
+
+struct pff_tab Pof_tab[] = {
+
+# if defined(UF_CLOSING)
+ { (long)UF_CLOSING, POF_CLOSING },
+# endif /* defined(UF_CLOSING) */
+
+# if defined(UF_EXCLOSE)
+ { (long)UF_EXCLOSE, POF_CLOEXEC },
+# endif /* defined(UF_EXCLOSE) */
+
+# if defined(UF_RESERVED)
+ { (long)UF_RESERVED, POF_RESERVED },
+# endif /* defined(UF_RESERVED) */
+
+ { (long)0, NULL }
+};
+#endif /* defined(HASFSTRUCT) */
diff --git a/dialects/darwin/libproc/machine.h b/dialects/darwin/libproc/machine.h
new file mode 100644
index 0000000..2bfa213
--- /dev/null
+++ b/dialects/darwin/libproc/machine.h
@@ -0,0 +1,629 @@
+/*
+ * machine.h -- Darwin definitions for libproc-based lsof
+ */
+
+
+/*
+ * Portions Copyright 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * Copyright 2005 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907. All rights reserved.
+ *
+ * Written by Allan Nathanson, Apple Computer, Inc., and Victor A.
+ * Abell, Purdue University.
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors, nor Apple Computer, Inc. nor Purdue University
+ * are responsible for any consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either
+ * by explicit claim or by omission. Credit to the authors, Apple
+ * Computer, Inc. and Purdue University must appear in documentation
+ * and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+
+/*
+ * $Id: machine.h,v 1.10 2013/01/02 17:03:05 abe Exp $
+ */
+
+
+#if !defined(LSOF_MACHINE_H)
+#define LSOF_MACHINE_H 1
+
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+# if defined(NEEDS_MACH_PORT_T)
+# include <device/device_types.h>
+# endif /* NEED_MACH_PORT_T */
+
+#include "/usr/include/string.h"
+
+
+/*
+ * CAN_USE_CLNT_CREATE is defined for those dialects where RPC clnt_create()
+ * can be used to obtain a CLIENT handle in lieu of clnttcp_create().
+ */
+
+#define CAN_USE_CLNT_CREATE 1
+
+
+/*
+ * DEVDEV_PATH defines the path to the directory that contains device
+ * nodes.
+ */
+
+#define DEVDEV_PATH "/dev"
+
+
+/*
+ * GET_MAX_FD is defined for those dialects that provide a function other than
+ * getdtablesize() to obtain the maximum file descriptor number plus one.
+ */
+
+/* #define GET_MAX_FD ? */
+
+
+/*
+ * HASAOPT is defined for those dialects that have AFS support; it specifies
+ * that the default path to an alternate AFS kernel name list file may be
+ * supplied with the -A <path> option.
+ */
+
+/* #define HASAOPT 1 */
+
+
+/*
+ * HASBLKDEV is defined for those dialects that want block device information
+ * recorded in BDevtp[].
+ */
+
+#define HASBLKDEV 1
+
+
+/*
+ * HASDCACHE is defined for those dialects that support a device cache
+ * file.
+ *
+ * HASENVDC defined the name of an environment variable that contains the
+ * device cache file path. The HASENVDC environment variable is ignored when
+ * the lsof process is setuid(root) or its real UID is 0.
+ *
+ * HASPERSDC defines the format for the last component of a personal device
+ * cache file path. The first will be the home directory of the real UID that
+ * executes lsof.
+ *
+ * HASPERSDCPATH defines the environment variable whose value is the middle
+ * component of the personal device cache file path. The middle component
+ * follows the home directory and precedes the results of applying HASPERSDC.
+ * The HASPERSDCPATH environment variable is ignored when the lsof process is
+ * setuid(root) or its real UID is 0.
+ *
+ * HASSYSDC defines a public device cache file path. When it's defined, it's
+ * used as the path from which to read the device cache.
+ *
+ * Consult the 00DCACHE and 00FAQ files of the lsof distribution for more
+ * information on device cache file path construction.
+ */
+
+/* #define HASDCACHE 1 */
+/* #define HASENVDC "LSOFDEVCACHE" */
+/* #define HASPERSDC "%h/%p.lsof_%L" */
+/* #define HASPERSDCPATH "LSOFPERSDCPATH" */
+/* #define HASSYSDC "/your/choice/of/path" */
+
+
+/*
+ * HASCDRNODE is defined for those dialects that have CD-ROM nodes.
+ */
+
+/* #define HASCDRNODE 1 */
+
+
+/*
+ * HASFIFONODE is defined for those dialects that have FIFO nodes.
+ */
+
+/* #define HASFIFONODE 1 */
+
+
+/*
+ * HASFSINO is defined for those dialects that have the file system
+ * inode element, fs_ino, in the lfile structure definition in lsof.h.
+ */
+
+#define HASFSINO 1
+
+
+/*
+ * HASFSTRUCT is defined if the dialect has a file structure.
+ *
+ * FSV_DEFAULT defines the default set of file structure values to list.
+ * It defaults to zero (0), but may be made up of a combination of the
+ * FSV_* symbols from lsof.h.
+ *
+ * HASNOFSADDR -- has no file structure address
+ * HASNOFSFLAGS -- has no file structure flags
+ * HASNOFSCOUNT -- has no file structure count
+ * HASNOFSNADDR -- has no file structure node address
+ */
+
+#define HASFSTRUCT 1
+/* #define FSV_DEFAULT FSV_? | FSV_? | FSV_? */
+#define HASNOFSADDR 1 /* has no file structure address */
+/* #define HASNOFSFLAGS 1 has no file structure flags */
+/* #define HASNOFSCOUNT 1 has no file structure count */
+#define HASNOFSNADDR 1 /* has no file structure node address */
+
+
+/*
+ * HASGNODE is defined for those dialects that have gnodes.
+ */
+
+/* #define HASGNODE 1 */
+
+
+/*
+ * HASHSNODE is defined for those dialects that have High Sierra nodes.
+ */
+
+/* #define HASHSNODE 1 */
+
+
+/*
+ * HASINODE is defined for those dialects that have inodes and wish to
+ * use readinode() from node.c.
+ */
+
+/* #define HASINODE 1 */
+
+
+/*
+ * HASINTSIGNAL is defined for those dialects whose signal function returns
+ * an int.
+ */
+
+/* #define HASINTSIGNAL 1 */
+
+
+/*
+ * HASKERNIDCK is defined for those dialects that support the comparison of
+ * the build to running kernel identity.
+ */
+
+#define HASKERNIDCK 1
+
+
+/*
+ * HASKOPT is defined for those dialects that support the -k option of
+ * reading the kernel's name list from an optional file.
+ */
+
+/* #define HASKOPT 1 */
+
+
+/*
+ * HASLFILEADD is defined for those dialects that need additional elements
+ * in struct lfile. The HASLFILEADD definition is a macro that defines
+ * them. If any of the additional elements need to be preset in the
+ * alloc_lfile() function of proc.c, the SETLFILEADD macro may be defined
+ * to do that.
+ *
+ * If any additional elements need to be cleared in alloc_lfile() or in the
+ * free_proc() function of proc.c, the CLRLFILEADD macro may be defined to
+ * do that. Note that CLRLFILEADD takes one argument, the pointer to the
+ * lfile struct. The CLRLFILEADD macro is expected to expand to statements
+ * that are complete -- i.e., have terminating semi-colons -- so the macro is
+ * called without a terminating semicolon by proc.c.
+ *
+ * The HASXOPT definition may be used to select the conditions under which
+ * private lfile elements are used.
+ */
+
+#define HASLFILEADD char *V_path; \
+ mach_port_t fileport;
+#define CLRLFILEADD(lf) if (lf->V_path) { \
+ (void) free((FREE_P *)lf->V_path); \
+ lf->V_path = (char *)NULL; \
+ } \
+ lf->fileport = MACH_PORT_NULL;
+#define SETLFILEADD Lf->V_path = (char *)NULL; \
+ Lf->fileport = MACH_PORT_NULL;
+
+
+/*
+ * HASMNTSTAT indicates the dialect supports the mount stat(2) result option
+ * in its l_vfs and mounts structures.
+ */
+
+/* #define HASMNTSTAT 1 */
+
+
+/*
+ * HASMNTSUP is defined for those dialects that support the mount supplement
+ * option.
+ */
+
+/* #define HASMNTSUP 1 */
+
+
+/*
+ * HASMOPT is defined for those dialects that support the reading of
+ * kernel memory from an alternate file.
+ */
+
+/* #define HASMOPT 1 */
+
+
+/*
+ * HASNCACHE is defined for those dialects that have a kernel name cache
+ * that lsof can search. A value of 1 directs printname() to prefix the
+ * cache value with the file system directory name; 2, avoid the prefix.
+ *
+ * NCACHELDPFX is a set of C commands to execute before calling ncache_load().
+ *
+ * NCACHELDSFX is a set of C commands to execute after calling ncache_load().
+ */
+
+/* #define HASNCACHE 1 */
+/* #define NCACHELDPFX ??? */
+/* #define NCACHELDSFX ??? */
+
+
+/*
+ * HASNLIST is defined for those dialects that use nlist() to acccess
+ * kernel symbols.
+ */
+
+/* #define HASNLIST 1 */
+
+
+/*
+ * HASPIPEFN is defined for those dialects that have a special function to
+ * process DTYPE_PIPE file structure entries. Its value is the name of the
+ * function.
+ *
+ * NOTE: don't forget to define a prototype for this function in dproto.h.
+ */
+
+/* #define HASPIPEFN process_pipe? */
+
+
+/*
+ * HASPIPENODE is defined for those dialects that have pipe nodes.
+ */
+
+/* #define HASPIPENODE 1 */
+
+
+/*
+ * HASPMAPENABLED is defined when the reporting of portmapper registration
+ * info is enabled by default.
+ */
+
+/* #define HASPMAPENABLED 1 */
+
+
+/*
+ * HASPPID is defined for those dialects that support identification of
+ * the parent process IDentifier (PPID) of a process.
+ */
+
+#define HASPPID 1
+
+
+/*
+ * HASPRINTDEV, HASPRINTINO, HASPRINTNM, HASPRINTOFF, and HASPRINTSZ
+ * define private dialect-specific functions for printing DEVice numbers,
+ * INOde numbers, NaMes, file OFFsets, and file SiZes. The functions are
+ * called from print_file().
+ */
+
+/* #define HASPRINTDEV print_dev */
+/* #define HASPRINTINO print_ino? */
+#define HASPRINTNM print_nm
+/* #define HASPRINTOFF print_off? */
+/* #define HASPRINTSZ print_sz? */
+
+
+/*
+ * HASPRIVFILETYPE and PRIVFILETYPE are defined for dialects that have a
+ * file structure type that isn't defined by a DTYPE_* symbol. They are
+ * used in lib/prfp.c to select the type's processing.
+ *
+ * PRIVFILETYPE is the definition of the f_type value in the file struct.
+ *
+ * HASPRIVFILETYPE is the name of the processing function.
+ */
+
+/* #define HASPRIVFILETYPE process_shmf? */
+/* #define PRIVFILETYPE ?? */
+
+
+/*
+ * HASPRIVNMCACHE is defined for dialects that have a private method for
+ * printing cached NAME column values for some files. HASPRIVNAMECACHE
+ * is defined to be the name of the function.
+ *
+ * The function takes one argument, a struct lfile pointer to the file, and
+ * returns non-zero if it prints a name to stdout.
+ */
+
+#define HASPRIVNMCACHE print_v_path
+
+
+/*
+ * HASPRIVPRIPP is defined for dialects that have a private function for
+ * printing IP protocol names. When HASPRIVPRIPP isn't defined, the
+ * IP protocol name printing function defaults to printiprto().
+ */
+
+/* #define HASPRIVPRIPP 1 */
+
+
+/*
+ * HASPROCFS is defined for those dialects that have a proc file system --
+ * usually /proc and usually in SYSV4 derivatives.
+ *
+ * HASFSTYPE is defined as 1 for those systems that have a file system type
+ * string, st_fstype, in the stat() buffer; 2, for those systems that have a
+ * file system type integer in the stat() buffer, named MOUNTS_STAT_FSTYPE;
+ * 0, for systems whose stat(2) structure has no file system type member. The
+ * additional symbols MOUNTS_FSTYPE, RMNT_FSTYPE, and RMNT_STAT_FSTYPE may be
+ * defined in dlsof.h to direct how the readmnt() function in lib/rmnt.c
+ * preserves these stat(2) and getmntent(3) buffer values in the local mounts
+ * structure.
+ *
+ * The defined value is the string that names the file system type.
+ *
+ * The HASPROCFS definition usually must be accompanied by the HASFSTYPE
+ * definition and the providing of an fstype element in the local mounts
+ * structure (defined in dlsof.h).
+ *
+ * The HASPROCFS definition may be accompanied by the HASPINODEN definition.
+ * HASPINODEN specifies that searching for files in HASPROCFS is to be done
+ * by inode number.
+ */
+
+/* #define HASPROCFS "proc?" */
+/* #define HASFSTYPE 1 */
+/* #define HASPINODEN 1 */
+
+
+/*
+ * HASRNODE is defined for those dialects that have rnodes.
+ */
+
+/* #define HASRNODE 1 */
+
+
+/*
+ * Define HASSECURITY to restrict the listing of all open files to the
+ * root user. When HASSECURITY is defined, the non-root user may list
+ * only files whose processes have the same user ID as the real user ID
+ * (the one that its user logged on with) of the lsof process.
+ */
+
+/* #define HASSECURITY 1 */
+
+
+/*
+ * If HASSECURITY is defined, define HASNOSOCKSECURITY to allow users
+ * restricted by HASSECURITY to list any open socket files, provide their
+ * listing is selected by the "-i" option.
+ */
+
+/* #define HASNOSOCKSECURITY 1 */
+
+
+/*
+ * HASSETLOCALE is defined for those dialects that have <locale.h> and
+ * setlocale().
+ *
+ * If the dialect also has wide character support for language locales,
+ * HASWIDECHAR activates lsof's wide character support and WIDECHARINCL
+ * defines the header file (if any) that must be #include'd to use the
+ * mblen() and mbtowc() functions.
+ */
+
+#define HASSETLOCALE 1
+#define HASWIDECHAR 1
+/* #define WIDECHARINCL <wchar.h> */
+
+
+/*
+ * HASSNODE is defined for those dialects that have snodes.
+ */
+
+/* #define HASSNODE 1 */
+
+
+/*
+ * HASTASKS is defined for those dialects that have task reporting support.
+ */
+
+/* #define HASTASKS 1 */
+
+
+/*
+ * HASSOOPT, HASSOSTATE and HASTCPOPT define the availability of information
+ * on socket options (SO_* symbols), socket states (SS_* symbols) and TCP
+ * options.
+ */
+
+#define HASSOOPT 1 /* has socket option information */
+#define HASSOSTATE 1 /* has socket state information */
+#define HASTCPOPT 1 /* has TCP options or flags */
+
+
+/*
+ * Define HASSPECDEVD to be the name of a function that handles the results
+ * of a successful stat(2) of a file name argument.
+ *
+ * For example, HASSPECDEVD() for Darwin makes sure that st_dev is set to
+ * what stat("/dev") returns -- i.e., what's in DevDev.
+ *
+ * The function takes two arguments:
+ *
+ * 1: pointer to the full path name of file
+ * 2: pointer to the stat(2) result
+ *
+ * The function returns void.
+ */
+
+#define HASSPECDEVD process_dev_stat
+
+
+/*
+ * HASSTREAMS is defined for those dialects that support streams.
+ */
+
+/* #define HASSTREAMS 1 */
+
+
+/*
+ * HASTCPTPIQ is defined for dialects where it is possible to report the
+ * TCP/TPI Recv-Q and Send-Q values produced by netstat.
+ */
+
+#define HASTCPTPIQ 1
+
+
+/*
+ * HASTCPTPIW is defined for dialects where it is possible to report the
+ * TCP/TPI send and receive window sizes produced by netstat.
+ */
+
+/* #define HASTCPTPIW 1 */
+
+
+/*
+ * HASTCPUDPSTATE is defined for dialects that have TCP and UDP state
+ * support -- i.e., for the "-stcp|udp:state" option and its associated
+ * speed improvements.
+ */
+
+#define HASTCPUDPSTATE 1
+
+
+/*
+ * HASTMPNODE is defined for those dialects that have tmpnodes.
+ */
+
+/* #define HASTMPNODE 1 */
+
+
+/*
+ * HASVNODE is defined for those dialects that use the Sun virtual file system
+ * node, the vnode. BSD derivatives usually do; System V derivatives prior to
+ * R4 usually don't.
+ */
+
+/* #define HASVNODE 1 */
+
+
+/*
+ * HASXOPT is defined for those dialects that have an X option. It
+ * defines the text for the usage display. HASXOPT_VALUE defines the
+ * option's default binary value -- 0 or 1.
+ */
+
+/* #define HASXOPT "help text for X option" */
+/* #define HASXOPT_VALUE 1 */
+
+
+/*
+ * INODETYPE and INODEPSPEC define the internal node number type and its
+ * printf specification modifier. These need not be defined and lsof.h
+ * can be allowed to define defaults.
+ *
+ * These are defined here, because they must be used in dlsof.h.
+ */
+
+#define INODETYPE unsigned long long
+ /* inode number internal storage type */
+#define INODEPSPEC "ll" /* INODETYPE printf specification
+ * modifier */
+
+
+/*
+ * UID_ARG defines the size of a User ID number when it is passed
+ * as a function argument.
+ */
+
+#define UID_ARG int
+
+
+/*
+ * Each USE_LIB_<function_name> is defined for dialects that use the
+ * <function_name> in the lsof library.
+ *
+ * Note: other definitions and operations may be required to condition the
+ * library function source code. They may be found in the dialect dlsof.h
+ * header files.
+ */
+
+#define USE_LIB_CKKV 1 /* ckkv.c */
+/* #define USE_LIB_COMPLETEVFS 1 cvfs.c */
+#define USE_LIB_FIND_CH_INO 1 /* fino.c */
+#define USE_LIB_IS_FILE_NAMED 1 /* isfn.c */
+#define USE_LIB_LKUPDEV 1 /* lkud.c */
+/* #define USE_LIB_PRINTDEVNAME 1 pdvn.c */
+/* #define USE_LIB_PROCESS_FILE 1 prfp.c */
+#define USE_LIB_PRINT_TCPTPI 1 /* ptti.c */
+/* #define USE_LIB_READDEV 1 rdev.c */
+/* #define USE_LIB_READMNT 1 rmnt.c */
+/* #define USE_LIB_REGEX 1 regex.c */
+/* #define USE_LIB_RNAM 1 rnam.c */
+/* #define USE_LIB_RNCH 1 rnch.c */
+/* #define USE_LIB_RNMH 1 rnmh.c */
+/* #define USE_LIB_SNPF 1 snpf.c */
+#define snpf snprintf /* use the system's snprintf() */
+
+
+/*
+ * WARNDEVACCESS is defined for those dialects that should issue a warning
+ * when lsof can't access /dev (or /device) or one of its sub-directories.
+ * The warning can be inhibited by the lsof caller with the -w option.
+ */
+
+/* #define WARNDEVACCESS 1 */
+
+
+/*
+ * WARNINGSTATE is defined for those dialects that want to suppress all lsof
+ * warning messages.
+ */
+
+/* #define WARNINGSTATE 1 warnings are enabled by default */
+
+
+/*
+ * WILLDROPGID is defined for those dialects whose lsof executable runs
+ * setgid(not_real_GID) and whose setgid power can be relinquished after
+ * the dialect's initialize() function has been executed.
+ */
+
+#define WILLDROPGID 1
+
+
+/*
+ * zeromem is a macro that uses bzero or memset.
+ */
+
+#define zeromem(a, l) memset(a, 0, l)
+
+#endif /* !defined(LSOF_MACHINE_H) */