diff options
Diffstat (limited to 'dialects/darwin')
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) */ |