summaryrefslogtreecommitdiff
path: root/dialects/linux
diff options
context:
space:
mode:
authorPatrick McCarty <patrick.mccarty@linux.intel.com>2013-02-08 13:26:27 -0800
committerPatrick McCarty <patrick.mccarty@linux.intel.com>2013-02-08 13:26:27 -0800
commit9bb81f8a90ecc8b70c955bff72ec59dd3d9e5ae7 (patch)
tree881eebfa461e4f8aa6b6f44b96ac0decd3bc887a /dialects/linux
downloadlsof-9bb81f8a90ecc8b70c955bff72ec59dd3d9e5ae7.tar.gz
lsof-9bb81f8a90ecc8b70c955bff72ec59dd3d9e5ae7.tar.bz2
lsof-9bb81f8a90ecc8b70c955bff72ec59dd3d9e5ae7.zip
Imported Upstream version 4.87upstream/4.87
Diffstat (limited to 'dialects/linux')
-rw-r--r--dialects/linux/Makefile157
-rwxr-xr-xdialects/linux/Mksrc25
-rw-r--r--dialects/linux/dfile.c387
-rw-r--r--dialects/linux/dlsof.h179
-rw-r--r--dialects/linux/dmnt.c698
-rw-r--r--dialects/linux/dnode.c549
-rw-r--r--dialects/linux/dproc.c1563
-rw-r--r--dialects/linux/dproto.h51
-rw-r--r--dialects/linux/dsock.c3946
-rw-r--r--dialects/linux/dstore.c114
-rw-r--r--dialects/linux/machine.h644
11 files changed, 8313 insertions, 0 deletions
diff --git a/dialects/linux/Makefile b/dialects/linux/Makefile
new file mode 100644
index 0000000..2bea108
--- /dev/null
+++ b/dialects/linux/Makefile
@@ -0,0 +1,157 @@
+
+# Linux /proc-based Makefile
+#
+# $Id: Makefile,v 1.11 2008/04/15 13:30:01 abe Exp $
+
+PROG= lsof
+
+BIN= ${DESTDIR}
+
+DOC= ${DESTDIR}
+
+I=/usr/include
+S=/usr/include/sys
+L=/usr/include/local
+P=
+
+CDEF=
+CDEFS= ${CDEF} ${CFGF}
+DEP= ${CFGD} ${CFGDN}
+INCL= ${DINC}
+CFLAGS= ${CDEFS} ${INCL} ${DEP} ${DEBUG}
+
+GRP=
+
+HDR= lsof.h lsof_fields.h dlsof.h machine.h proto.h dproto.h
+
+SRC= dfile.c dmnt.c dnode.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= dfile.o dmnt.o dnode.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}: ${P} ${LIB} ${OBJ}
+ ${CC} -o $@ ${OBJ} ${CFGL}
+
+clean: FRC
+ rm -f Makefile.bak ${PROG} a.out core errs lint.out tags *.o version.h ${CFGDN}
+ rm -f machine.h.old new_machine.h
+ (cd lib; ${MAKE} -f Makefile.skel clean)
+
+install: all FRC
+ @echo ''
+ @echo 'Please write your own install rule. Lsof should be installed'
+ @echo 'setuid to root if you wish any lsof user to be able to examine'
+ @echo 'all open files. Your install rule actions might look something'
+ @echo 'like this:'
+ @echo ''
+ @echo ' install -m 4xxx -o root -g $${GRP} $${PROG} $${BIN}'
+ @echo ' install -m 444 $${MAN} $${DOC}'
+ @echo ''
+ @echo 'You will have to complete the 4xxx 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= sys'
+ @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
+
+dfile.o: ${HDR} dfile.c
+
+dmnt.o: ${HDR} dmnt.c
+
+dnode.o: ${HDR} dnode.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/linux/Mksrc b/dialects/linux/Mksrc
new file mode 100755
index 0000000..8a1ffa1
--- /dev/null
+++ b/dialects/linux/Mksrc
@@ -0,0 +1,25 @@
+#!/bin/sh
+#
+# Mksrc - make Linux source files for /proc-based lsof
+#
+# 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.2 2000/12/04 14:31:02 abe Exp $
+
+
+D=dialects/linux
+L="dfile.c dlsof.h dmnt.c dnode.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/linux/dfile.c b/dialects/linux/dfile.c
new file mode 100644
index 0000000..4a30737
--- /dev/null
+++ b/dialects/linux/dfile.c
@@ -0,0 +1,387 @@
+/*
+ * dfile.c - Linux file processing functions for /proc-based lsof
+ */
+
+
+/*
+ * Copyright 1997 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 1997 Purdue Research Foundation.\nAll rights reserved.\n";
+static char *rcsid = "$Id: dfile.c,v 1.8 2012/04/10 16:39:50 abe Exp $";
+#endif
+
+
+#include "lsof.h"
+
+
+/*
+ * Local structures
+ */
+
+struct hsfile {
+ struct sfile *s; /* the Sfile table address */
+ struct hsfile *next; /* the next hash bucket entry */
+};
+
+/*
+ * Local static variables
+ */
+
+static struct hsfile *HbyFdi = /* hash by file (dev,ino) buckets */
+ (struct hsfile *)NULL;
+static int HbyFdiCt = 0; /* HbyFdi entry count */
+static struct hsfile *HbyFrd = /* hash by file raw device buckets */
+ (struct hsfile *)NULL;
+static int HbyFrdCt = 0; /* HbyFrd entry count */
+static struct hsfile *HbyFsd = /* hash by file system buckets */
+ (struct hsfile *)NULL;
+static int HbyFsdCt = 0; /* HbyFsd entry count */
+static struct hsfile *HbyNm = /* hash by name buckets */
+ (struct hsfile *)NULL;
+static int HbyNmCt = 0; /* HbyNm entry count */
+
+
+/*
+ * Local definitions
+ */
+
+#define SFDIHASH 4094 /* Sfile hash by (device,inode) number
+ * pair bucket count (power of 2!) */
+#define SFFSHASH 1024 /* Sfile hash by file system device
+ * number bucket count (power of 2!) */
+#define SFHASHDEVINO(maj, min, ino, mod) ((int)(((int)((((int)(maj+1))*((int)((min+1))))+ino)*31415)&(mod-1)))
+ /* hash for Sfile by major device,
+ * minor device, and inode, modulo mod
+ * (mod must be a power of 2) */
+#define SFRDHASH 1024 /* Sfile hash by raw device number
+ * bucket count (power of 2!) */
+#define SFHASHRDEVI(maj, min, rmaj, rmin, ino, mod) ((int)(((int)((((int)(maj+1))*((int)((min+1))))+((int)(rmaj+1)*(int)(rmin+1))+ino)*31415)&(mod-1)))
+ /* hash for Sfile by major device,
+ * minor device, major raw device,
+ * minor raw device, and inode, modulo
+ * mod (mod must be a power of 2) */
+#define SFNMHASH 4096 /* Sfile hash by name bucket count
+ * (must be a power of 2!) */
+
+
+/*
+ * hashSfile() - hash Sfile entries for use in is_file_named() searches
+ */
+
+void
+hashSfile()
+{
+ static int hs = 0;
+ int i;
+ struct sfile *s;
+ struct hsfile *sh, *sn;
+/*
+ * Do nothing if there are no file search arguments cached or if the
+ * hashes have already been constructed.
+ */
+ if (!Sfile || hs)
+ return;
+/*
+ * Allocate hash buckets by (device,inode), file system device, and file name.
+ */
+ if (!(HbyFdi = (struct hsfile *)calloc((MALLOC_S)SFDIHASH,
+ sizeof(struct hsfile))))
+ {
+ (void) fprintf(stderr,
+ "%s: can't allocate space for %d (dev,ino) hash buckets\n",
+ Pn, SFDIHASH);
+ Exit(1);
+ }
+ if (!(HbyFrd = (struct hsfile *)calloc((MALLOC_S)SFRDHASH,
+ sizeof(struct hsfile))))
+ {
+ (void) fprintf(stderr,
+ "%s: can't allocate space for %d rdev hash buckets\n",
+ Pn, SFRDHASH);
+ Exit(1);
+ }
+ if (!(HbyFsd = (struct hsfile *)calloc((MALLOC_S)SFFSHASH,
+ sizeof(struct hsfile))))
+ {
+ (void) fprintf(stderr,
+ "%s: can't allocate space for %d file sys hash buckets\n",
+ Pn, SFFSHASH);
+ Exit(1);
+ }
+ if (!(HbyNm = (struct hsfile *)calloc((MALLOC_S)SFNMHASH,
+ sizeof(struct hsfile))))
+ {
+ (void) fprintf(stderr,
+ "%s: can't allocate space for %d name hash buckets\n",
+ Pn, SFNMHASH);
+ Exit(1);
+ }
+ hs++;
+/*
+ * Scan the Sfile chain, building file, file system, raw device, and file
+ * name hash bucket chains.
+ */
+ for (s = Sfile; s; s = s->next) {
+ for (i = 0; i < 3; i++) {
+ switch (i) {
+ case 0: /* hash by name */
+ if (!s->aname)
+ continue;
+ sh = &HbyNm[hashbyname(s->aname, SFNMHASH)];
+ HbyNmCt++;
+ break;
+ case 1: /* hash by device and inode, or file
+ * system device */
+ if (s->type) {
+ sh = &HbyFdi[SFHASHDEVINO(GET_MAJ_DEV(s->dev),
+ GET_MIN_DEV(s->dev), s->i,
+ SFDIHASH)];
+ HbyFdiCt++;
+ } else {
+ sh = &HbyFsd[SFHASHDEVINO(GET_MAJ_DEV(s->dev),
+ GET_MIN_DEV(s->dev),
+ 0,
+ SFFSHASH)];
+ HbyFsdCt++;
+ }
+ break;
+ case 2: /* hash by file's raw device */
+ if ((s->mode == S_IFCHR) || (s->mode == S_IFBLK)) {
+ sh = &HbyFrd[SFHASHRDEVI(GET_MAJ_DEV(s->dev),
+ GET_MIN_DEV(s->dev),
+ GET_MAJ_DEV(s->rdev),
+ GET_MIN_DEV(s->rdev),
+ s->i,
+ SFRDHASH)];
+ HbyFrdCt++;
+ } else
+ continue;
+ }
+ /*
+ * Add hash to the bucket's chain, allocating new entries for
+ * all after the first.
+ */
+ if (!sh->s) {
+ sh->s = s;
+ sh->next = (struct hsfile *)NULL;
+ continue;
+ } else {
+ if (!(sn = (struct hsfile *)malloc(
+ (MALLOC_S)sizeof(struct hsfile))))
+ {
+ (void) fprintf(stderr,
+ "%s: can't allocate hsfile bucket for: %s\n",
+ Pn, s->aname);
+ Exit(1);
+ }
+ sn->s = s;
+ sn->next = sh->next;
+ sh->next = sn;
+ }
+ }
+ }
+}
+
+
+/*
+ * is_file_named() - is this file named?
+ */
+
+int
+is_file_named(ty, p, mp, cd)
+ int ty; /* search type: 0 = only by device
+ * and inode
+ * 1 = by device and
+ * inode, or by file
+ * system device and
+ * path for NFS file
+ * systems
+ * 2 = only by path
+ */
+ char *p; /* path name (device and inode are
+ * identified via *Lf) */
+ struct mounts *mp; /* NFS file system (NULL if not) */
+ int cd; /* character or block type file --
+ * VCHR or VBLK vnode, or S_IFCHR
+ * or S_IFBLK inode */
+{
+ char *ep;
+ int f = 0;
+ struct mounts *smp;
+ struct sfile *s = (struct sfile *)NULL;
+ struct hsfile *sh;
+ size_t sz;
+/*
+ * Check for a path name match, as requested.
+ */
+ if ((ty == 2) && p && HbyNmCt) {
+ for (sh = &HbyNm[hashbyname(p, SFNMHASH)]; sh; sh = sh->next) {
+ if ((s = sh->s) && strcmp(p, s->aname) == 0) {
+ f = 2;
+ break;
+ }
+ }
+ }
+/*
+ * Check for a regular file by device and inode number.
+ */
+ if (!f && (ty < 2) && HbyFdiCt && Lf->dev_def
+ && (Lf->inp_ty == 1 || Lf->inp_ty == 3))
+ {
+ for (sh = &HbyFdi[SFHASHDEVINO(GET_MAJ_DEV(Lf->dev),
+ GET_MIN_DEV(Lf->dev),
+ Lf->inode,
+ SFDIHASH)];
+ sh;
+ sh = sh->next)
+ {
+ if ((s = sh->s) && (Lf->dev == s->dev)
+ && (Lf->inode == s->i)) {
+ f = 1;
+ break;
+ }
+ }
+ }
+/*
+ * Check for a file system match.
+ */
+ if (!f && (ty == 1) && HbyFsdCt && Lf->dev_def) {
+ for (sh = &HbyFsd[SFHASHDEVINO(GET_MAJ_DEV(Lf->dev),
+ GET_MIN_DEV(Lf->dev), 0,
+ SFFSHASH)];
+ sh;
+ sh = sh->next)
+ {
+ if ((s = sh->s) && (s->dev == Lf->dev)) {
+ if (Lf->ntype != N_NFS) {
+
+ /*
+ * A non-NFS file matches to a non-NFS file system by
+ * device.
+ */
+ if (!(smp = s->mp) || (smp->ty != N_NFS)) {
+ f = 1;
+ break;
+ }
+ } else {
+
+ /*
+ * An NFS file must also match to a file system by the
+ * the path name of the file system -- i.e., the first
+ * part of the file's path. This terrible, non-UNIX
+ * hack is forced on lsof by an egregious error in
+ * Linux NFS that can assign the same device number
+ * to two different NFS mounts.
+ */
+ if (p && mp && mp->dirl && mp->dir && s->name
+ && !strncmp(mp->dir, s->name, mp->dirl))
+ {
+ f = 1;
+ break;
+ }
+ }
+ }
+ }
+ }
+/*
+ * Check for a character or block device match.
+ */
+ if (!f && !ty && HbyFrdCt && cd
+ && Lf->dev_def && (Lf->dev == DevDev)
+ && Lf->rdev_def
+ && (Lf->inp_ty == 1 || Lf->inp_ty == 3))
+ {
+ for (sh = &HbyFrd[SFHASHRDEVI(GET_MAJ_DEV(Lf->dev),
+ GET_MIN_DEV(Lf->dev),
+ GET_MAJ_DEV(Lf->rdev),
+ GET_MIN_DEV(Lf->rdev),
+ Lf->inode, SFRDHASH)];
+ sh;
+ sh = sh->next)
+ {
+ if ((s = sh->s) && (s->dev == Lf->dev)
+ && (s->rdev == Lf->rdev) && (s->i == Lf->inode))
+ {
+ f = 1;
+ break;
+ }
+ }
+ }
+/*
+ * Convert the name if a match occurred.
+ */
+ switch (f) {
+ case 0:
+ return(0);
+ case 1:
+ if (s->type) {
+
+ /*
+ * If the search argument isn't a file system, propagate it
+ * to Namech[]; otherwise, let printname() compose the name.
+ */
+ (void) snpf(Namech, Namechl, "%s", s->name);
+ if (s->devnm) {
+ ep = endnm(&sz);
+ (void) snpf(ep, sz, " (%s)", s->devnm);
+ }
+ }
+ break;
+ case 2:
+ (void) strcpy(Namech, p);
+ break;
+ }
+ if (s)
+ s->f = 1;
+ return(1);
+}
+
+
+/*
+ * printdevname() - print character device name
+ *
+ * Note: this function should not be needed in /proc-based lsof, but
+ * since it is called by printname() in print.c, an ersatz one
+ * is provided here.
+ */
+
+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 buf[128];
+
+ (void) snpf(buf, sizeof(buf), "%s device: %d,%d",
+ (nty == N_BLK) ? "BLK" : "CHR",
+ (int)GET_MAJ_DEV(*rdev), (int)GET_MIN_DEV(*rdev));
+ safestrprt(buf, stdout, f);
+ return(1);
+}
diff --git a/dialects/linux/dlsof.h b/dialects/linux/dlsof.h
new file mode 100644
index 0000000..8cca3c5
--- /dev/null
+++ b/dialects/linux/dlsof.h
@@ -0,0 +1,179 @@
+/*
+ * dlsof.h - Linux header file for /proc-based lsof
+ */
+
+
+/*
+ * Copyright 1997 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.22 2012/04/10 16:39:50 abe Exp $
+ */
+
+
+#if !defined(LINUX_LSOF_H)
+#define LINUX_LSOF_H 1
+
+#include <dirent.h>
+#define DIRTYPE dirent /* for arg.c's enter_dir() */
+#define __USE_GNU /* to get all O_* symbols in fcntl.h */
+#include <fcntl.h>
+#include <malloc.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <setjmp.h>
+#include <unistd.h>
+#include <netinet/in.h>
+
+# if defined(GLIBCV) || defined(__UCLIBC__)
+#include <netinet/tcp.h>
+# else /* !defined(GLIBCV) && !defined(__UCLIBC__) */
+#include <linux/tcp.h>
+# endif /* defined(GLIBCV) || defined(__UCLIBC__) */
+
+# if !defined(HASNORPC_H)
+#include <rpc/rpc.h>
+#include <rpc/pmap_prot.h>
+# endif /* !defined(HASNORPC_H) */
+
+#if defined(HASSELINUX)
+#include <selinux/selinux.h>
+#endif /* defined(HASSELINUX) */
+
+#include <sys/sysmacros.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <linux/if_ether.h>
+#include <linux/netlink.h>
+
+
+/*
+ * This definition is needed for the common function prototype definitions
+ * in "proto.h", but isn't used in /proc-based lsof.
+ */
+
+typedef unsigned long KA_T;
+
+
+/*
+ * Local definitions
+ */
+
+#define COMP_P const void
+#define DEVINCR 1024 /* device table malloc() increment */
+#define FSNAMEL 4
+#define MALLOC_P void
+#define FREE_P MALLOC_P
+#define MALLOC_S size_t
+#define MAXSYSCMDL 15 /* max system command name length
+ * This value should be obtained from a
+ * header file #define, but no consistent one
+ * exists. Some versions of the Linux kernel
+ * have a hard-coded "char comm[16]" command
+ * name member of the task structured
+ * definition in <linux/sched.h>, while others
+ * have a "char comm[TASK_COMM_LEN]" member
+ * with TASK_COMM_LEN #define'd to be 16.
+ * Hence, a universal, local definition of
+ * 16 is #define'd here. */
+#define PROCFS "/proc"
+#define QSORT_P void
+#define READLEN_T size_t
+
+/*
+ * Definitions that indicate what values are present in a stat(2) or lstat(2)
+ * buffer.
+ */
+
+#define SB_DEV 0x01 /* st_dev */
+#define SB_INO 0x02 /* st_ino */
+#define SB_MODE 0x04 /* st_mode */
+#define SB_NLINK 0x08 /* st_nlink */
+#define SB_RDEV 0x10 /* st_rdev */
+#define SB_SIZE 0x20 /* st_size */
+#define SB_ALL (SB_DEV | SB_INO | SB_MODE | SB_NLINK | SB_RDEV | \
+ SB_SIZE) /* all values */
+
+#define STRNCPY_L size_t
+#define STRNML 32
+
+# if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS==64
+#define SZOFFTYPE unsigned long long
+ /* size and offset internal storage
+ * type */
+#define SZOFFPSPEC "ll" /* SZOFFTYPE print specification
+ * modifier */
+# endif /* defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS==64 */
+
+#define XDR_PMAPLIST (xdrproc_t)xdr_pmaplist
+#define XDR_VOID (xdrproc_t)xdr_void
+
+
+/*
+ * Global storage definitions (including their structure definitions)
+ */
+
+struct mounts {
+ char *dir; /* directory name (mounted on) */
+ char *fsname; /* file system
+ * (symbolic links unresolved) */
+ char *fsnmres; /* file system
+ * (symbolic links resolved) */
+ size_t dirl; /* length of directory name */
+ dev_t dev; /* directory st_dev */
+ dev_t rdev; /* directory st_rdev */
+ INODETYPE inode; /* directory st_ino */
+ mode_t mode; /* directory st_mode */
+ int ds; /* directory status -- i.e., SB_*
+ * values */
+ mode_t fs_mode; /* file system st_mode */
+ int ty; /* node type -- e.g., N_REGLR, N_NFS */
+ 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 */
+ mode_t 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 mounts *mp; /* mount structure pointer for file
+ * system type entries */
+#define SAVE_MP_IN_SFILE 1 /* for ck_file_arg() im arg.c */
+ struct sfile *next; /* forward link */
+};
+
+extern int HasNFS;
+extern int OffType;
+
+#endif /* LINUX_LSOF_H */
diff --git a/dialects/linux/dmnt.c b/dialects/linux/dmnt.c
new file mode 100644
index 0000000..ab57bbb
--- /dev/null
+++ b/dialects/linux/dmnt.c
@@ -0,0 +1,698 @@
+/*
+ * dmnt.c -- Linux mount support functions for /proc-based lsof
+ */
+
+
+/*
+ * Copyright 1997 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 1997 Purdue Research Foundation.\nAll rights reserved.\n";
+static char *rcsid = "$Id: dmnt.c,v 1.19 2012/04/10 16:39:50 abe Exp $";
+#endif
+
+
+#include "lsof.h"
+
+
+/*
+ * Local definitions
+ */
+
+#if defined(HASMNTSUP)
+#define HASHMNT 128 /* mount supplement hash bucket count
+ * !!!MUST BE A POWER OF 2!!! */
+#endif /* defined(HASMNTSUP) */
+
+
+/*
+ * Local function prototypes
+ */
+
+_PROTOTYPE(static char *cvtoe,(char *os));
+
+#if defined(HASMNTSUP)
+_PROTOTYPE(static int getmntdev,(char *dn, size_t dnl, struct stat *s, int *ss));
+_PROTOTYPE(static int hash_mnt,(char *dn));
+#endif /* defined(HASMNTSUP) */
+
+
+/*
+ * Local structure definitions.
+ */
+
+#if defined(HASMNTSUP)
+typedef struct mntsup {
+ char *dn; /* mounted directory name */
+ size_t dnl; /* strlen(dn) */
+ dev_t dev; /* device number */
+ int ln; /* line on which defined */
+ struct mntsup *next; /* next entry */
+} mntsup_t;
+#endif /* defined(HASMNTSUP) */
+
+
+/*
+ * Local static definitions
+ */
+
+static struct mounts *Lmi = (struct mounts *)NULL; /* local mount info */
+static int Lmist = 0; /* Lmi status */
+static mntsup_t **MSHash = (mntsup_t **)NULL; /* mount supplement
+ * hash buckets */
+
+
+/*
+ * cvtoe() -- convert octal-escaped characters in string
+ */
+
+static char *
+cvtoe(os)
+ char *os; /* original string */
+{
+ int c, cl, cx, ol, ox, tx;
+ char *cs;
+ int tc;
+/*
+ * Allocate space for a copy of the string in which octal-escaped characters
+ * can be replaced by the octal value -- e.g., \040 with ' '. Leave room for
+ * a '\0' terminator.
+ */
+ if (!(ol = (int)strlen(os)))
+ return((char *)NULL);
+ if (!(cs = (char *)malloc(ol + 1))) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d bytes for octal-escaping.\n",
+ Pn, ol + 1);
+ Exit(1);
+ }
+/*
+ * Copy the string, replacing octal-escaped characters as they are found.
+ */
+ for (cx = ox = 0, cl = ol; ox < ol; ox++) {
+ if (((c = (int)os[ox]) == (int)'\\') && ((ox + 3) < ol)) {
+
+ /*
+ * The beginning of an octal-escaped character has been found.
+ *
+ * Convert the octal value to a character value.
+ */
+ for (tc = 0, tx = 1; os[ox + tx] && (tx < 4); tx++) {
+ if (((int)os[ox + tx] < (int)'0')
+ || ((int)os[ox + tx] > (int)'7'))
+ {
+
+ /*
+ * The escape isn't followed by octets, so ignore the
+ * escape and just copy it.
+ */
+ break;
+ }
+ tc <<= 3;
+ tc += (int)(os[ox + tx] - '0');
+ }
+ if (tx == 4) {
+
+ /*
+ * If three octets (plus the escape) were assembled, use their
+ * character-forming result.
+ *
+ * Otherwise copy the escape and what follows it until another
+ * escape is found.
+ */
+ ox += 3;
+ c = (tc & 0xff);
+ }
+ }
+ if (cx >= cl) {
+
+ /*
+ * Expand the copy string, as required. Leave room for a '\0'
+ * terminator.
+ */
+ cl += 64; /* (Make an arbitrary increase.) */
+ if (!(cs = (char *)realloc(cs, cl + 1))) {
+ (void) fprintf(stderr,
+ "%s: can't realloc %d bytes for octal-escaping.\n",
+ Pn, cl + 1);
+ Exit(1);
+ }
+ }
+ /*
+ * Copy the character.
+ */
+ cs[cx++] = (char)c;
+ }
+/*
+ * Terminate the copy and return its pointer.
+ */
+ cs[cx] = '\0';
+ return(cs);
+}
+
+
+#if defined(HASMNTSUP)
+/*
+ * getmntdev() - get mount device from mount supplement
+ */
+
+static int
+getmntdev(dn, dnl, s, ss)
+ char *dn; /* mounted directory name */
+ size_t dnl; /* strlen(dn) */
+ struct stat *s; /* stat(2) buffer receptor */
+ int *ss; /* stat(2) status result -- i.e., SB_*
+ * values */
+{
+ static int err = 0;
+ int h;
+ mntsup_t *mp, *mpn;
+ static char *vbuf = (char *)NULL;
+ static size_t vsz = (size_t)0;
+
+ if (err)
+ return(0);
+ if (!MSHash) {
+
+ /*
+ * No mount supplement hash buckets have been allocated, so read the
+ * mount supplement file and create hash buckets for its entries.
+ */
+ char buf[(MAXPATHLEN*2) + 1], *dp, path[(MAXPATHLEN*2) + 1];
+ dev_t dev;
+ FILE *fs;
+ int ln = 0;
+ size_t sz;
+
+ if ((MntSup != 2) || !MntSupP)
+ return(0);
+ if (!is_readable(MntSupP, 1)) {
+
+ /*
+ * The mount supplement file isn't readable.
+ */
+ err = 1;
+ return(0);
+ }
+ if (!(fs = open_proc_stream(MntSupP, "r", &vbuf, &vsz, 0))) {
+
+ /*
+ * The mount supplement file can't be opened for reading.
+ */
+ if (!Fwarn)
+ (void) fprintf(stderr, "%s: can't open(%s): %s\n",
+ Pn, MntSupP, strerror(errno));
+ err = 1;
+ return(0);
+ }
+ buf[sizeof(buf) - 1] = '\0';
+ /*
+ * Read the mount supplement file.
+ */
+ while (fgets(buf, sizeof(buf) - 1, fs)) {
+ ln++;
+ if ((dp = strchr(buf, '\n')))
+ *dp = '\0';
+ if (buf[0] != '/') {
+
+ /*
+ * The mount supplement line doesn't begin with the absolute
+ * path character '/'.
+ */
+ if (!Fwarn)
+ (void) fprintf(stderr,
+ "%s: %s line %d: no path: \"%s\"\n",
+ Pn, MntSupP, ln, buf);
+ err = 1;
+ continue;
+ }
+ if (!(dp = strchr(buf, ' ')) || strncmp(dp + 1, "0x", 2)) {
+
+ /*
+ * The path on the mount supplement line isn't followed by
+ * " 0x".
+ */
+ if (!Fwarn)
+ (void) fprintf(stderr,
+ "%s: %s line %d: no device: \"%s\"\n",
+ Pn, MntSupP, ln, buf);
+ err = 1;
+ continue;
+ }
+ sz = (size_t)(dp - buf);
+ (void) strncpy(path, buf, sz);
+ path[sz] = '\0';
+ /*
+ * Assemble the hexadecimal device number of the mount supplement
+ * line.
+ */
+ for (dev = 0, dp += 3; *dp; dp++) {
+ if (!isxdigit((int)*dp))
+ break;
+ if (isdigit((int)*dp))
+ dev = (dev << 4) + (int)*dp - (int)'0';
+ else
+ dev = (dev << 4) + (int)tolower(*dp) - (int)'a' + 10;
+ }
+ if (*dp) {
+
+ /*
+ * The device number couldn't be assembled.
+ */
+ if (!Fwarn)
+ (void) fprintf(stderr,
+ "%s: %s line %d: illegal device: \"%s\"\n",
+ Pn, MntSupP, ln, buf);
+ err = 1;
+ continue;
+ }
+ /*
+ * Search the mount supplement hash buckets. (Allocate them as
+ * required.)
+ */
+ if (!MSHash) {
+ if (!(MSHash = (mntsup_t **)calloc(HASHMNT,
+ sizeof(mntsup_t *)))
+ ) {
+ (void) fprintf(stderr,
+ "%s: no space for mount supplement hash buckets\n",
+ Pn);
+ Exit(1);
+ }
+ }
+ h = hash_mnt(path);
+ for (mp = MSHash[h]; mp; mp = mp->next) {
+ if ((mp->dnl == dnl) && !strcmp(mp->dn, path))
+ break;
+ }
+ if (mp) {
+
+ /*
+ * A path match was located. If the device number is the
+ * same, skip this mount supplement line. Otherwise, issue
+ * a warning.
+ */
+ if (mp->dev != dev) {
+ (void) fprintf(stderr,
+ "%s: %s line %d path duplicate of %d: \"%s\"\n",
+ Pn, MntSupP, ln, mp->ln, buf);
+ err = 1;
+ }
+ continue;
+ }
+ /*
+ * Allocate and fill a new mount supplement hash entry.
+ */
+ if (!(mpn = (mntsup_t *)malloc(sizeof(mntsup_t)))) {
+ (void) fprintf(stderr,
+ "%s: no space for mount supplement entry: %d \"%s\"\n",
+ Pn, ln, buf);
+ Exit(1);
+ }
+ if (!(mpn->dn = (char *)malloc(sz + 1))) {
+ (void) fprintf(stderr,
+ "%s: no space for mount supplement path: %d \"%s\"\n",
+ Pn, ln, buf);
+ Exit(1);
+ }
+ (void) strcpy(mpn->dn, path);
+ mpn->dnl = sz;
+ mpn->dev = dev;
+ mpn->ln = ln;
+ mpn->next = MSHash[h];
+ MSHash[h] = mpn;
+ }
+ if (ferror(fs)) {
+ if (!Fwarn)
+ (void) fprintf(stderr, "%s: error reading %s\n",
+ Pn, MntSupP);
+ err = 1;
+ }
+ (void) fclose(fs);
+ if (err) {
+ if (MSHash) {
+ for (h = 0; h < HASHMNT; h++) {
+ for (mp = MSHash[h]; mp; mp = mpn) {
+ mpn = mp->next;
+ if (mp->dn)
+ (void) free((MALLOC_P *)mp->dn);
+ (void) free((MALLOC_P *)mp);
+ }
+ }
+ (void) free((MALLOC_P *)MSHash);
+ MSHash = (mntsup_t **)NULL;
+ }
+ return(0);
+ }
+ }
+/*
+ * If no errors have been detected reading the mount supplement file, search
+ * its hash buckets for the supplied directory path.
+ */
+ if (err)
+ return(0);
+ h = hash_mnt(dn);
+ for (mp = MSHash[h]; mp; mp = mp->next) {
+ if ((dnl == mp->dnl) && !strcmp(dn, mp->dn)) {
+ memset((void *)s, 0, sizeof(struct stat));
+ s->st_dev = mp->dev;
+ *ss |= SB_DEV;
+ return(1);
+ }
+ }
+ return(0);
+}
+
+
+/*
+ * hash_mnt() - hash mount point
+ */
+
+static int
+hash_mnt(dn)
+ char *dn; /* mount point directory name */
+{
+ register int i, h;
+ size_t l;
+
+ if (!(l = strlen(dn)))
+ return(0);
+ if (l == 1)
+ return((int)*dn & (HASHMNT - 1));
+ for (i = h = 0; i < (int)(l - 1); i++) {
+ h ^= ((int)dn[i] * (int)dn[i+1]) << ((i*3)%13);
+ }
+ return(h & (HASHMNT - 1));
+}
+#endif /* defined(HASMNTSUP) */
+
+
+/*
+ * readmnt() - read mount table
+ */
+
+struct mounts *
+readmnt()
+{
+ char buf[MAXPATHLEN], *cp, **fp;
+ char *dn = (char *)NULL;
+ size_t dnl;
+ int ds, ne;
+ char *fp0 = (char *)NULL;
+ char *fp1 = (char *)NULL;
+ int fr, ignrdl, ignstat;
+ char *ln;
+ struct mounts *mp;
+ FILE *ms;
+ int nfs;
+ struct stat sb;
+ static char *vbuf = (char *)NULL;
+ static size_t vsz = (size_t)0;
+
+ if (Lmi || Lmist)
+ return(Lmi);
+/*
+ * Open access to /proc/mounts, assigning a page size buffer to its stream.
+ */
+ (void) snpf(buf, sizeof(buf), "%s/mounts", PROCFS);
+ ms = open_proc_stream(buf, "r", &vbuf, &vsz, 1);
+/*
+ * Read mount table entries.
+ */
+ while (fgets(buf, sizeof(buf), ms)) {
+ if (get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0) < 3
+ || !fp[0] || !fp[1] || !fp[2])
+ continue;
+ /*
+ * Convert octal-escaped characters in the device name and mounted-on
+ * path name.
+ */
+ if (fp0) {
+ (void) free((FREE_P *)fp0);
+ fp0 = (char *)NULL;
+ }
+ if (fp1) {
+ (void) free((FREE_P *)fp1);
+ fp1 = (char *)NULL;
+ }
+ if (!(fp0 = cvtoe(fp[0])) || !(fp1 = cvtoe(fp[1])))
+ continue;
+ /*
+ * Locate any colon (':') in the device name.
+ *
+ * If the colon is followed by * "(pid*" -- it's probably an
+ * automounter entry.
+ *
+ * Ignore autofs, pipefs, and sockfs entries.
+ */
+ cp = strchr(fp0, ':');
+ if (cp && !strncasecmp(++cp, "(pid", 4))
+ continue;
+ if (!strcasecmp(fp[2], "autofs") || !strcasecmp(fp[2], "pipefs")
+ || !strcasecmp(fp[2], "sockfs"))
+ continue;
+ /*
+ * Interpolate a possible symbolic mounted directory link.
+ */
+ if (dn)
+ (void) free((FREE_P *)dn);
+ dn = fp1;
+ fp1 = (char *)NULL;
+
+#if defined(HASEOPT)
+ if (Efsysl) {
+
+ /*
+ * If there is an -e file system list, check it to decide if a stat()
+ * and Readlink() on this one should be performed.
+ */
+ efsys_list_t *ep;
+
+ for (ignrdl = ignstat = 0, ep = Efsysl; ep; ep = ep->next) {
+ if (!strcmp(dn, ep->path)) {
+ ignrdl = ep->rdlnk;
+ ignstat = 1;
+ break;
+ }
+ }
+ } else
+
+#endif /* defined(HASEOPT */
+
+ ignrdl = ignstat = 0;
+
+ /*
+ * Avoid Readlink() when requested.
+ */
+ if (!ignrdl) {
+ 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;
+ dnl = strlen(dn);
+ /*
+ * Test for duplicate and NFS directories.
+ */
+ for (mp = Lmi; mp; mp = mp->next) {
+ if ((dnl == mp->dirl) && !strcmp(dn, mp->dir))
+ break;
+ }
+ if ((nfs = strcasecmp(fp[2], "nfs"))) {
+ if ((nfs = strcasecmp(fp[2], "nfs3")))
+ nfs = strcasecmp(fp[2], "nfs4");
+ }
+ if (mp) {
+
+ /*
+ * If this duplicate directory is not root, ignore it. If the
+ * already remembered entry is NFS-mounted, ignore this one. If
+ * this one is NFS-mounted, ignore the already remembered entry.
+ */
+ if (strcmp(dn, "/"))
+ continue;
+ if (mp->ty == N_NFS)
+ continue;
+ if (nfs)
+ continue;
+ }
+ /*
+ * Stat() the directory.
+ */
+ if (ignstat)
+ fr = 1;
+ else {
+ if ((fr = statsafely(dn, &sb))) {
+ if (!Fwarn) {
+ (void) fprintf(stderr, "%s: WARNING: can't stat() ",
+ Pn);
+ safestrprt(fp[2], stderr, 0);
+ (void) fprintf(stderr, " file system ");
+ safestrprt(dn, stderr, 1);
+ (void) fprintf(stderr,
+ " Output information may be incomplete.\n");
+ }
+ } else
+ ds = SB_ALL;
+ }
+
+#if defined(HASMNTSUP)
+ if (fr) {
+
+ /*
+ * If the stat() failed or wasn't called, check the mount
+ * supplement table, if possible.
+ */
+ if ((MntSup == 2) && MntSupP) {
+ ds = 0;
+ if (getmntdev(dn, dnl, &sb, &ds) || !(ds & SB_DEV)) {
+ (void) fprintf(stderr,
+ "%s: assuming dev=%#lx for %s from %s\n",
+ Pn, (long)sb.st_dev, dn, MntSupP);
+ }
+ } else {
+ if (!ignstat)
+ continue;
+ ds = 0; /* No stat() was allowed. */
+ }
+ }
+#else /* !defined(HASMNTSUP) */
+ if (fr) {
+ if (!ignstat)
+ continue;
+ ds = 0; /* No stat() was allowed. */
+ }
+#endif /* defined(HASMNTSUP) */
+
+ /*
+ * Fill a local mount structure or reuse a previous entry when
+ * indicated.
+ */
+ if (mp) {
+ ne = 0;
+ if (mp->dir) {
+ (void) free((FREE_P *)mp->dir);
+ mp->dir = (char *)NULL;
+ }
+ if (mp->fsname) {
+ (void) free((FREE_P *)mp->fsname);
+ mp->fsname = (char *)NULL;
+ }
+ } else {
+ ne = 1;
+ if (!(mp = (struct mounts *)malloc(sizeof(struct mounts)))) {
+ (void) fprintf(stderr,
+ "%s: can't allocate mounts struct for: ", Pn);
+ safestrprt(dn, stderr, 1);
+ Exit(1);
+ }
+ }
+ mp->dir = dn;
+ dn = (char *)NULL;
+ mp->dirl = dnl;
+ if (ne)
+ mp->next = Lmi;
+ mp->dev = ((mp->ds = ds) & SB_DEV) ? sb.st_dev : 0;
+ mp->rdev = (ds & SB_RDEV) ? sb.st_rdev : 0;
+ mp->inode = (INODETYPE)((ds & SB_INO) ? sb.st_ino : 0);
+ mp->mode = (ds & SB_MODE) ? sb.st_mode : 0;
+ if (!nfs) {
+ mp->ty = N_NFS;
+ if (HasNFS < 2)
+ HasNFS = 2;
+ } else
+ mp->ty = N_REGLR;
+
+#if defined(HASMNTSUP)
+ /*
+ * If support for the mount supplement file is defined and if the
+ * +m option was supplied, print mount supplement information.
+ */
+ if (MntSup == 1) {
+ if (mp->dev)
+ (void) printf("%s %#lx\n", mp->dir, (long)mp->dev);
+ else
+ (void) printf("%s 0x0\n", mp->dir);
+ }
+#endif /* defined(HASMNTSUP) */
+
+ /*
+ * Save mounted-on device or directory name.
+ */
+ dn = fp0;
+ fp0 = (char *)NULL;
+ mp->fsname = dn;
+ /*
+ * Interpolate a possible file system (mounted-on) device name or
+ * directory name link.
+ *
+ * Avoid Readlink() when requested.
+ */
+ if (ignrdl || (*dn != '/')) {
+ if (!(ln = mkstrcpy(dn, (MALLOC_S *)NULL))) {
+ (void) fprintf(stderr,
+ "%s: can't allocate space for: ", Pn);
+ safestrprt(dn, stderr, 1);
+ Exit(1);
+ }
+ ignstat = 1;
+ } else
+ 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 (ignstat || !ln || statsafely(ln, &sb))
+ sb.st_mode = 0;
+ mp->fsnmres = ln;
+ mp->fs_mode = sb.st_mode;
+ if (ne)
+ Lmi = mp;
+ }
+/*
+ * Clean up and return the local mount info table address.
+ */
+ (void) fclose(ms);
+ if (dn)
+ (void) free((FREE_P *)dn);
+ if (fp0)
+ (void) free((FREE_P *)fp0);
+ if (fp1)
+ (void) free((FREE_P *)fp1);
+ Lmist = 1;
+ return(Lmi);
+}
diff --git a/dialects/linux/dnode.c b/dialects/linux/dnode.c
new file mode 100644
index 0000000..8a9bc73
--- /dev/null
+++ b/dialects/linux/dnode.c
@@ -0,0 +1,549 @@
+/*
+ * dnode.c - Linux node functions for /proc-based lsof
+ */
+
+
+/*
+ * Copyright 1997 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 1997 Purdue Research Foundation.\nAll rights reserved.\n";
+static char *rcsid = "$Id: dnode.c,v 1.23 2013/01/02 17:02:36 abe Exp $";
+#endif
+
+
+#include "lsof.h"
+
+
+/*
+ * Local definitions
+ */
+
+#define OFFSET_MAX ((off_t)0x7fffffff) /* this is defined in
+ * .../src/fs/locks.c and not
+ * in a header file */
+#define PIDBUCKS 64 /* PID hash buckets */
+#define HASHPID(pid) (((int)((pid * 31415) >> 3)) & (PIDBUCKS - 1))
+
+
+/*
+ * Local structure definitions
+ */
+
+struct llock {
+ int pid;
+ dev_t dev;
+ INODETYPE inode;
+ char type;
+ struct llock *next;
+};
+
+
+/*
+ * Local definitions
+ */
+
+struct llock **LckH = (struct llock **)NULL; /* PID-hashed locks */
+
+
+/*
+ * Local function prototypes
+ */
+
+_PROTOTYPE(static void check_lock,(void));
+
+
+/*
+ * check_lock() - check lock for file *Lf, process *Lp
+ */
+
+static void
+check_lock()
+{
+ int h;
+ struct llock *lp;
+
+ h = HASHPID(Lp->pid);
+ for (lp = LckH[h]; lp; lp = lp->next) {
+ if (Lp->pid == lp->pid
+ && Lf->dev == lp->dev
+ && Lf->inode == lp->inode)
+ {
+ Lf->lock = lp->type;
+ return;
+ }
+ }
+}
+
+
+/*
+ * get_fields() - separate a line into fields
+ */
+
+int
+get_fields(ln, sep, fr, eb, en)
+ char *ln; /* input line */
+ char *sep; /* separator list */
+ char ***fr; /* field pointer return address */
+ int *eb; /* indexes of fields where blank or an
+ * entry from the separator list may be
+ * embedded and are not separators
+ * (may be NULL) */
+ int en; /* number of entries in eb[] (may be
+ * zero) */
+{
+ char *bp, *cp, *sp;
+ int i, j, n;
+ MALLOC_S len;
+ static char **fp = (char **)NULL;
+ static int nfpa = 0;
+
+ for (cp = ln, n = 0; cp && *cp;) {
+ for (bp = cp; *bp && (*bp == ' ' || *bp == '\t'); bp++);
+ ;
+ if (!*bp || *bp == '\n')
+ break;
+ for (cp = bp; *cp; cp++) {
+ if (*cp == '\n') {
+ *cp = '\0';
+ break;
+ }
+ if (*cp == '\t') /* TAB is always a separator */
+ break;
+ if (*cp == ' ') {
+
+ /*
+ * See if this field may have an embedded space.
+ */
+ if (!eb || !en)
+ break;
+ else {
+ for (i = j = 0; i < en; i++) {
+ if (eb[i] == n) {
+ j = 1;
+ break;
+ }
+ }
+ if (!j)
+ break;
+ }
+ }
+ if (sep) {
+
+ /*
+ * See if the character is in the separator list.
+ */
+ for (sp = sep; *sp; sp++) {
+ if (*sp == *cp)
+ break;
+ }
+ if (*sp) {
+
+ /*
+ * See if this field may have an embedded separator.
+ */
+ if (!eb || !en)
+ break;
+ else {
+ for (i = j = 0; i < en; i++) {
+ if (eb[i] == n) {
+ j = 1;
+ break;
+ }
+ }
+ if (!j)
+ break;
+ }
+ }
+ }
+ }
+ if (*cp)
+ *cp++ = '\0';
+ if (n >= nfpa) {
+ nfpa += 32;
+ len = (MALLOC_S)(nfpa * sizeof(char *));
+ if (fp)
+ fp = (char **)realloc((MALLOC_P *)fp, len);
+ else
+ fp = (char **)malloc(len);
+ if (!fp) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d bytes for field pointers.\n",
+ Pn, (int)len);
+ Exit(1);
+ }
+ }
+ fp[n++] = bp;
+ }
+ *fr = fp;
+ return(n);
+}
+
+
+/*
+ * get_locks() - get lock information from /proc/locks
+ */
+
+void
+get_locks(p)
+ char *p; /* /proc lock path */
+{
+ unsigned long bp, ep;
+ char buf[MAXPATHLEN], *ec, **fp;
+ dev_t dev;
+ int ex, i, h, mode, pid;
+ INODETYPE inode;
+ struct llock *lp, *np;
+ FILE *ls;
+ long maj, min;
+ char type;
+ static char *vbuf = (char *)NULL;
+ static size_t vsz = (size_t)0;
+/*
+ * Destroy previous lock information.
+ */
+ if (LckH) {
+ for (i = 0; i < PIDBUCKS; i++) {
+ for (lp = LckH[i]; lp; lp = np) {
+ np = lp->next;
+ (void) free((FREE_P *)lp);
+ }
+ LckH[i] = (struct llock *)NULL;
+ }
+ } else {
+
+ /*
+ * If first time, allocate the lock PID hash buckets.
+ */
+ LckH = (struct llock **)calloc((MALLOC_S)PIDBUCKS,
+ sizeof(struct llock *));
+ if (!LckH) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d lock hash bytes\n",
+ Pn, (int)(sizeof(struct llock *) * PIDBUCKS));
+ Exit(1);
+ }
+ }
+/*
+ * Open the /proc lock file, assign a page size buffer to its stream,
+ * and read it.
+ */
+ if (!(ls = open_proc_stream(p, "r", &vbuf, &vsz, 0)))
+ return;
+ while (fgets(buf, sizeof(buf), ls)) {
+ if (get_fields(buf, ":", &fp, (int *)NULL, 0) < 10)
+ continue;
+ if (!fp[1] || strcmp(fp[1], "->") == 0)
+ continue;
+ /*
+ * Get lock type.
+ */
+ if (!fp[3])
+ continue;
+ if (*fp[3] == 'R')
+ mode = 0;
+ else if (*fp[3] == 'W')
+ mode = 1;
+ else
+ continue;
+ /*
+ * Get PID.
+ */
+ if (!fp[4] || !*fp[4])
+ continue;
+ pid = atoi(fp[4]);
+ /*
+ * Get device number.
+ */
+ ec = (char *)NULL;
+ if (!fp[5] || !*fp[5]
+ || (maj = strtol(fp[5], &ec, 16)) == LONG_MIN || maj == LONG_MAX
+ || !ec || *ec)
+ continue;
+ ec = (char *)NULL;
+ if (!fp[6] || !*fp[6]
+ || (min = strtol(fp[6], &ec, 16)) == LONG_MIN || min == LONG_MAX
+ || !ec || *ec)
+ continue;
+ dev = (dev_t)makedev((int)maj, (int)min);
+ /*
+ * Get inode number.
+ */
+ ec = (char *)NULL;
+ if (!fp[7] || !*fp[7]
+ || (inode = strtoull(fp[7], &ec, 0)) == ULONG_MAX
+ || !ec || *ec)
+ continue;
+ /*
+ * Get lock extent. Convert it and the lock type to a lock character.
+ */
+ if (!fp[8] || !*fp[8] || !fp[9] || !*fp[9])
+ continue;
+ ec = (char *)NULL;
+ if ((bp = strtoul(fp[8], &ec, 0)) == ULONG_MAX || !ec || *ec)
+ continue;
+ if (!strcmp(fp[9], "EOF")) /* for Linux 2.4.x */
+ ep = OFFSET_MAX;
+ else {
+ ec = (char *)NULL;
+ if ((ep = strtoul(fp[9], &ec, 0)) == ULONG_MAX || !ec || *ec)
+ continue;
+ }
+ ex = ((off_t)bp == (off_t)0 && (off_t)ep == OFFSET_MAX) ? 1 : 0;
+ if (mode)
+ type = ex ? 'W' : 'w';
+ else
+ type = ex ? 'R' : 'r';
+ /*
+ * Look for this lock via the hash buckets.
+ */
+ h = HASHPID(pid);
+ for (lp = LckH[h]; lp; lp = lp->next) {
+ if (lp->pid == pid
+ && lp->dev == dev
+ && lp->inode == inode
+ && lp->type == type)
+ break;
+ }
+ if (lp)
+ continue;
+ /*
+ * Allocate a new llock structure and link it to the PID hash bucket.
+ */
+ if (!(lp = (struct llock *)malloc(sizeof(struct llock)))) {
+ (void) snpf(buf, sizeof(buf), InodeFmt_d, inode);
+ (void) fprintf(stderr,
+ "%s: can't allocate llock: PID %d; dev %x; inode %s\n",
+ Pn, pid, (int)dev, buf);
+ Exit(1);
+ }
+ lp->pid = pid;
+ lp->dev = dev;
+ lp->inode = inode;
+ lp->type = type;
+ lp->next = LckH[h];
+ LckH[h] = lp;
+ }
+ (void) fclose(ls);
+}
+
+
+/*
+ * process_proc_node() - process file node
+ */
+
+void
+process_proc_node(p, pbr, s, ss, l, ls)
+ char *p; /* node's readlink() path */
+ char *pbr; /* node's path before readlink() */
+ struct stat *s; /* stat() result for path */
+ int ss; /* *s status -- i.e., SB_* values */
+ struct stat *l; /* lstat() result for FD (NULL for
+ * others) */
+ int ls; /* *l status -- i.e., SB_* values */
+{
+ mode_t access;
+ mode_t type = 0;
+ char *cp;
+ struct mounts *mp = (struct mounts *)NULL;
+ size_t sz;
+ char *tn;
+/*
+ * Set the access mode, if possible.
+ */
+ if (l && (ls & SB_MODE) && ((l->st_mode & S_IFMT) == S_IFLNK)) {
+ if ((access = l->st_mode & (S_IRUSR | S_IWUSR)) == S_IRUSR)
+ Lf->access = 'r';
+ else if (access == S_IWUSR)
+ Lf->access = 'w';
+ else
+ Lf->access = 'u';
+ }
+/*
+ * Determine node type.
+ */
+ if (ss & SB_MODE) {
+ type = s->st_mode & S_IFMT;
+ switch (type) {
+ case S_IFBLK:
+ Lf->ntype = Ntype = N_BLK;
+ break;
+ case S_IFCHR:
+ Lf->ntype = Ntype = N_CHR;
+ break;
+ case S_IFIFO:
+ Lf->ntype = Ntype = N_FIFO;
+ break;
+ case S_IFSOCK:
+ /* Lf->ntype = Ntype = N_REGLR; by alloc_lfile() */
+ process_proc_sock(p, pbr, s, ss, l, ls);
+ return;
+ case 0:
+ if (!strcmp(p, "anon_inode"))
+ Lf->ntype = Ntype = N_ANON_INODE;
+ break;
+ }
+ }
+ if (Selinet)
+ return;
+/*
+ * Save the device. If it is an NFS device, change the node type to N_NFS.
+ */
+ if (ss & SB_DEV) {
+ Lf->dev = s->st_dev;
+ Lf->dev_def = 1;
+ }
+ if ((Ntype == N_CHR || Ntype == N_BLK)) {
+ if (ss & SB_RDEV) {
+ Lf->rdev = s->st_rdev;
+ Lf->rdev_def = 1;
+ }
+ }
+ if (Ntype == N_REGLR && (HasNFS == 2)) {
+ for (mp = readmnt(); mp; mp = mp->next) {
+ if ((mp->ty == N_NFS)
+ && (mp->ds & SB_DEV) && Lf->dev_def && (Lf->dev == mp->dev)
+ && (mp->dir && mp->dirl
+ && !strncmp(mp->dir, p, mp->dirl))
+ ) {
+ Lf->ntype = Ntype = N_NFS;
+ break;
+ }
+ }
+ }
+/*
+ * Save the inode number.
+ */
+ if (ss & SB_INO) {
+ Lf->inode = (INODETYPE)s->st_ino;
+ Lf->inp_ty = 1;
+ }
+/*
+ * Check for a lock.
+ */
+ if (Lf->dev_def && (Lf->inp_ty == 1))
+ (void) check_lock();
+/*
+ * Save the file size.
+ */
+ switch (Ntype) {
+ case N_BLK:
+ case N_CHR:
+ case N_FIFO:
+ if (!Fsize && l && (ls & SB_SIZE) && OffType) {
+ Lf->off = (SZOFFTYPE)l->st_size;
+ Lf->off_def = 1;
+ }
+ break;
+ default:
+ if (Foffset) {
+ if (l && (ls & SB_SIZE) && OffType) {
+ Lf->off = (SZOFFTYPE)l->st_size;
+ Lf->off_def = 1;
+ }
+ } else if (!Foffset || Fsize) {
+ if (ss & SB_SIZE) {
+ Lf->sz = (SZOFFTYPE)s->st_size;
+ Lf->sz_def = 1;
+ }
+ }
+ }
+/*
+ * Record the link count.
+ */
+ if (Fnlink && (ss & SB_NLINK)) {
+ Lf->nlink = (long)s->st_nlink;
+ Lf->nlink_def = 1;
+ if (Nlink && (Lf->nlink < Nlink))
+ Lf->sf |= SELNLINK;
+ }
+/*
+ * Format the type name.
+ */
+ if (ss & SB_MODE) {
+ switch (type) {
+ case S_IFBLK:
+ tn = "BLK";
+ break;
+ case S_IFCHR:
+ tn = "CHR";
+ break;
+ case S_IFDIR:
+ tn = "DIR";
+ break;
+ case S_IFIFO:
+ tn = "FIFO";
+ break;
+ case S_IFREG:
+ tn = "REG";
+ break;
+ case S_IFLNK:
+ tn = "LINK";
+ break;
+ case S_ISVTX:
+ tn = "VTXT";
+ break;
+ default:
+ if (Ntype == N_ANON_INODE)
+ tn = "a_inode";
+ else {
+ (void) snpf(Lf->type, sizeof(Lf->type), "%04o",
+ ((type >> 12) & 0xf));
+ tn = (char *)NULL;
+ }
+ }
+ } else
+ tn = "unknown";
+ if (tn)
+ (void) snpf(Lf->type, sizeof(Lf->type), "%s", tn);
+/*
+ * Record an NFS file selection.
+ */
+ if (Ntype == N_NFS && Fnfs)
+ Lf->sf |= SELNFS;
+/*
+ * Test for specified file.
+ */
+ if (Sfile
+ && is_file_named(1, p, mp,
+ ((type == S_IFCHR) || (type == S_IFBLK)) ? 1 : 0))
+ Lf->sf |= SELNM;
+/*
+ * If no NAME information has been stored, store the path.
+ *
+ * Store the remote host and mount point for an NFS file.
+ */
+ if (!Namech[0]) {
+ (void) snpf(Namech, Namechl, "%s", p);
+ if ((Ntype == N_NFS) && mp && mp->fsname) {
+ cp = endnm(&sz);
+ (void) snpf(cp, sz, " (%s)", mp->fsname);
+ }
+ }
+ if (Namech[0])
+ enter_nm(Namech);
+}
diff --git a/dialects/linux/dproc.c b/dialects/linux/dproc.c
new file mode 100644
index 0000000..c3045a2
--- /dev/null
+++ b/dialects/linux/dproc.c
@@ -0,0 +1,1563 @@
+/*
+ * dproc.c - Linux process access functions for /proc-based lsof
+ */
+
+
+/*
+ * Copyright 1997 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 1997 Purdue Research Foundation.\nAll rights reserved.\n";
+static char *rcsid = "$Id: dproc.c,v 1.27 2013/01/02 17:02:36 abe Exp $";
+#endif
+
+#include "lsof.h"
+
+
+/*
+ * Local definitions
+ */
+
+#define FDINFO_FLAGS 1 /* fdinfo flags available */
+#define FDINFO_POS 2 /* fdinfo position available */
+#define FDINFO_ALL (FDINFO_FLAGS | FDINFO_POS)
+#define LSTAT_TEST_FILE "/"
+#define LSTAT_TEST_SEEK 1
+
+#if !defined(ULLONG_MAX)
+#define ULLONG_MAX 18446744073709551615ULL
+#endif /* !defined(ULLONG_MAX) */
+
+
+/*
+ * Local structures
+ */
+
+struct l_fdinfo {
+ int flags; /* flags: line value */
+ off_t pos; /* pos: line value */
+};
+
+
+/*
+ * Local variables
+ */
+
+static short Cckreg; /* conditional status of regular file
+ * checking:
+ * 0 = unconditionally check
+ * 1 = conditionally check */
+static short Ckscko; /* socket file only checking status:
+ * 0 = none
+ * 1 = check only socket files */
+
+
+/*
+ * Local function prototypes
+ */
+
+_PROTOTYPE(static int get_fdinfo,(char *p, struct l_fdinfo *fi));
+_PROTOTYPE(static int getlinksrc,(char *ln, char *src, int srcl, char **rest));
+_PROTOTYPE(static int isefsys,(char *path, char *type, int l,
+ efsys_list_t **rep, struct lfile **lfr));
+_PROTOTYPE(static int nm2id,(char *nm, int *id, int *idl));
+_PROTOTYPE(static int read_id_stat,(int ty, char *p, int id, char **cmd,
+ int *ppid, int *pgid));
+_PROTOTYPE(static void process_proc_map,(char *p, struct stat *s, int ss));
+_PROTOTYPE(static int process_id,(char *idp, int idpl, char *cmd, UID_ARG uid,
+ int pid, int ppid, int pgid, int tid));
+_PROTOTYPE(static int statEx,(char *p, struct stat *s, int *ss));
+
+
+#if defined(HASSELINUX)
+_PROTOTYPE(static int cmp_cntx_eq,(char *pcntx, char *ucntx));
+
+
+#include <fnmatch.h>
+
+
+/*
+ * cmp_cntx_eq -- compare program and user security contexts
+ */
+
+static int
+cmp_cntx_eq(pcntx, ucntx)
+ char *pcntx; /* program context */
+ char *ucntx; /* user supplied context */
+{
+ return !fnmatch(ucntx, pcntx, 0);
+}
+
+
+/*
+ * enter_cntx_arg() - enter name ecurity context argument
+ */
+
+int
+enter_cntx_arg(cntx)
+ char *cntx; /* context */
+{
+ cntxlist_t *cntxp;
+/*
+ * Search the argument list for a duplicate.
+ */
+ for (cntxp = CntxArg; cntxp; cntxp = cntxp->next) {
+ if (!strcmp(cntxp->cntx, cntx)) {
+ if (!Fwarn) {
+ (void) fprintf(stderr, "%s: duplicate context: %s\n",
+ Pn, cntx);
+ }
+ return(1);
+ }
+ }
+/*
+ * Create and link a new context argument list entry.
+ */
+ if (!(cntxp = (cntxlist_t *)malloc((MALLOC_S)sizeof(cntxlist_t)))) {
+ (void) fprintf(stderr, "%s: no space for context: %s\n", Pn, cntx);
+ Exit(1);
+ }
+ cntxp->f = 0;
+ cntxp->cntx = cntx;
+ cntxp->next = CntxArg;
+ CntxArg = cntxp;
+ return(0);
+}
+#endif /* defined(HASSELINUX) */
+
+
+/*
+ * gather_proc_info() -- gather process information
+ */
+
+void
+gather_proc_info()
+{
+ char *cmd, *tcmd;
+ struct dirent *dp;
+ unsigned char ht, pidts;
+ int n, nl, pgid, pid, ppid, rv, tid, tpgid, tppid, tx;
+ static char *path = (char *)NULL;
+ static int pathl = 0;
+ static char *pidpath = (char *)NULL;
+ static MALLOC_S pidpathl = 0;
+ static MALLOC_S pidx = 0;
+ static DIR *ps = (DIR *)NULL;
+ struct stat sb;
+ static char *taskpath = (char *)NULL;
+ static int taskpathl = 0;
+ static char *tidpath = (char *)NULL;
+ static int tidpathl = 0;
+ DIR *ts;
+ UID_ARG uid;
+
+/*
+ * Do one-time setup.
+ */
+ if (!pidpath) {
+ pidx = strlen(PROCFS) + 1;
+ pidpathl = pidx + 64 + 1; /* 64 is growth room */
+ if (!(pidpath = (char *)malloc(pidpathl))) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d bytes for \"%s/\"<pid>\n",
+ Pn, (int)pidpathl, PROCFS);
+ Exit(1);
+ }
+ (void) snpf(pidpath, pidpathl, "%s/", PROCFS);
+ }
+/*
+ * Get lock and net information.
+ */
+ (void) make_proc_path(pidpath, pidx, &path, &pathl, "locks");
+ (void) get_locks(path);
+ (void) make_proc_path(pidpath, pidx, &path, &pathl, "net/");
+ (void) set_net_paths(path, strlen(path));
+/*
+ * 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;
+ }
+/*
+ * Read /proc, looking for PID directories. Open each one and
+ * gather its process and file information.
+ */
+ if (!ps) {
+ if (!(ps = opendir(PROCFS))) {
+ (void) fprintf(stderr, "%s: can't open %s\n", Pn, PROCFS);
+ Exit(1);
+ }
+ } else
+ (void) rewinddir(ps);
+ while ((dp = readdir(ps))) {
+ if (nm2id(dp->d_name, &pid, &n))
+ continue;
+ /*
+ * Build path to PID's directory.
+ */
+ if ((pidx + n + 1 + 1) > pidpathl) {
+ pidpathl = pidx + n + 1 + 1 + 64;
+ if (!(pidpath = (char *)realloc((MALLOC_P *)pidpath, pidpathl)))
+ {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d bytes for \"%s/%s/\"\n",
+ Pn, (int)pidpathl, PROCFS, dp->d_name);
+ Exit(1);
+ }
+ }
+ (void) snpf(pidpath + pidx, pidpathl - pidx, "%s/", dp->d_name);
+ n += (pidx + 1);
+ /*
+ * Process the PID's stat info.
+ */
+ if (stat(pidpath, &sb))
+ continue;
+ uid = (UID_ARG)sb.st_uid;
+ ht = pidts = 0;
+
+#if defined(HASTASKS)
+ /*
+ * If task reporting is selected, check the tasks of the process first,
+ * so that the "-p<PID> -aK" options work properly.
+ */
+ if ((Selflags & SELTASK)) {
+ (void) make_proc_path(pidpath, n, &taskpath, &taskpathl,
+ "task");
+ tx = n + 4;
+ if ((ts = opendir(taskpath))) {
+
+ /*
+ * Process the PID's tasks. Record the open files of those
+ * whose TIDs do not match the PID and which are themselves
+ * not zombies.
+ */
+ while ((dp = readdir(ts))) {
+
+ /*
+ * Get the task ID. Skip the task if its ID matches the
+ * process PID.
+ */
+ if (nm2id(dp->d_name, &tid, &nl))
+ continue;
+ if (tid == pid) {
+ pidts = 1;
+ continue;
+ }
+ /*
+ * Form the path for the TID.
+ */
+ if ((tx + 1 + nl + 1 + 4) > tidpathl) {
+ tidpathl = tx + 1 + n + 1 + 4 + 64;
+ if (tidpath)
+ tidpath = (char *)realloc((MALLOC_P *)tidpath,
+ tidpathl);
+ else
+ tidpath = (char *)malloc((MALLOC_S)tidpathl);
+ if (!tidpath) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d task bytes", Pn,
+ tidpathl);
+ (void) fprintf(stderr, " for \"%s/%s/stat\"\n",
+ taskpath, dp->d_name);
+ Exit(1);
+ }
+ }
+ (void) snpf(tidpath, tidpathl, "%s/%s/stat", taskpath,
+ dp->d_name);
+ /*
+ * Check the task state.
+ */
+ rv = read_id_stat(1, tidpath, tid, &tcmd, &tppid,
+ &tpgid);
+ if ((rv < 0) || (rv == 1))
+ continue;
+ /*
+ * Attempt to record the task.
+ */
+ if (!process_id(tidpath, (tx + 1 + nl+ 1), tcmd, uid,
+ pid, tppid, tpgid, tid))
+ {
+ ht = 1;
+ }
+ }
+ (void) closedir(ts);
+ }
+ }
+#endif /* defined(HASTASKS) */
+
+ /*
+ * If the main process is a task and task selection has been specified
+ * along with option ANDing, enter the main process temporarily as a
+ * task, so that the "-aK" option set lists the main process along
+ * with its tasks.
+ */
+ (void) make_proc_path(pidpath, n, &path, &pathl, "stat");
+ if (((rv = read_id_stat(0, path, pid, &cmd, &ppid, &pgid)) >= 0)
+ && (rv != 1))
+ {
+ tid = (Fand && ht && pidts && (Selflags & SELTASK)) ? pid : 0;
+ if ((!process_id(pidpath, n, cmd, uid, pid, ppid, pgid, tid))
+ && tid)
+ {
+ Lp->tid = 0;
+ }
+ }
+ }
+}
+
+
+/*
+ * get_fdinfo() - get values from /proc/<PID>fdinfo/FD
+ */
+
+static int
+get_fdinfo(p, fi)
+ char *p; /* path to fdinfo file */
+ struct l_fdinfo *fi; /* pointer to local fdinfo values
+ * return structure */
+{
+ char buf[MAXPATHLEN + 1], *ep, **fp;
+ FILE *fs;
+ int rv = 0;
+ unsigned long ul;
+ unsigned long long ull;
+/*
+ * Signal no values returned (0) if no fdinfo pointer was provided or if the
+ * fdinfo path can't be opened.
+ */
+ if (!fi)
+ return(0);
+ if (!p || !*p || !(fs = fopen(p, "r")))
+ return(0);
+/*
+ * Read the fdinfo file.
+ */
+ while (fgets(buf, sizeof(buf), fs)) {
+ if (get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0) < 2)
+ continue;
+ if (!fp[0] || !*fp[0] || !fp[1] || !*fp[1])
+ continue;
+ if (!strcmp(fp[0], "flags:")) {
+
+ /*
+ * Process a "flags:" line.
+ */
+ ep = (char *)NULL;
+ if ((ul = strtoul(fp[1], &ep, 0)) == ULONG_MAX
+ || !ep || *ep)
+ continue;
+ fi->flags = (unsigned int)ul;
+ if ((rv |= FDINFO_FLAGS) == FDINFO_ALL)
+ break;
+ } else if (!strcmp(fp[0], "pos:")) {
+
+ /*
+ * Process a "pos:" line.
+ */
+ ep = (char *)NULL;
+ if ((ull = strtoull(fp[1], &ep, 0)) == ULLONG_MAX
+ || !ep || *ep)
+ continue;
+ fi->pos = (off_t)ull;
+ if ((rv |= FDINFO_POS) == FDINFO_ALL)
+ break;
+ }
+ }
+ fclose(fs);
+/*
+ * Signal via the return value what information was obtained. (0 == none)
+ */
+ return(rv);
+}
+
+
+/*
+ * getlinksrc() - get the source path name for the /proc/<PID>/fd/<FD> link
+ */
+
+
+static int
+getlinksrc(ln, src, srcl, rest)
+ char *ln; /* link path */
+ char *src; /* link source path return address */
+ int srcl; /* length of src[] */
+ char **rest; /* pointer to what follows the ':' in
+ * the link source path (NULL if no
+ * return requested) */
+{
+ char *cp;
+ int ll;
+
+ if (rest)
+ *rest = (char *)NULL;
+ if ((ll = readlink(ln, src, srcl - 1)) < 1
+ || ll >= srcl)
+ return(-1);
+ src[ll] = '\0';
+ if (*src == '/')
+ return(ll);
+ if ((cp = strchr(src, ':'))) {
+ *cp = '\0';
+ ll = strlen(src);
+ if (rest)
+ *rest = cp + 1;
+ }
+ return(ll);
+}
+
+
+/*
+ * initialize() - perform all initialization
+ */
+
+void
+initialize()
+{
+ int fd;
+ struct l_fdinfo fi;
+ char path[MAXPATHLEN];
+ struct stat sb;
+/*
+ * Test for -i and -X option conflict.
+ */
+ if (Fxopt && (Fnet || Nwad)) {
+ (void) fprintf(stderr, "%s: -i is useless when -X is specified.\n",
+ Pn);
+ usage(1, 0, 0);
+ }
+/*
+ * Open LSTAT_TEST_FILE and seek to byte LSTAT_TEST_SEEK, then lstat the
+ * /proc/<PID>/fd/<FD> for LSTAT_TEST_FILE to see what position is reported.
+ * If the result is LSTAT_TEST_SEEK, enable offset reporting.
+ *
+ * If the result isn't LSTAT_TEST_SEEK, next check the fdinfo file for the
+ * open LSTAT_TEST_FILE file descriptor. If it exists and contains a "pos:"
+ * value, and if the value is LSTAT_TEST_SEEK, enable offset reporting.
+ */
+ if ((fd = open(LSTAT_TEST_FILE, O_RDONLY)) >= 0) {
+ if (lseek(fd, (off_t)LSTAT_TEST_SEEK, SEEK_SET)
+ == (off_t)LSTAT_TEST_SEEK) {
+ (void) snpf(path, sizeof(path), "%s/%d/fd/%d", PROCFS, Mypid,
+ fd);
+ if (!lstat(path, &sb)) {
+ if (sb.st_size == (off_t)LSTAT_TEST_SEEK)
+ OffType = 1;
+ }
+ }
+ if (!OffType) {
+ (void) snpf(path, sizeof(path), "%s/%d/fdinfo/%d", PROCFS,
+ Mypid, fd);
+ if (get_fdinfo(path, &fi) & FDINFO_POS) {
+ if (fi.pos == (off_t)LSTAT_TEST_SEEK)
+ OffType = 2;
+ }
+ }
+ (void) close(fd);
+ }
+ if (!OffType) {
+ if (Foffset && !Fwarn)
+ (void) fprintf(stderr,
+ "%s: WARNING: can't report offset; disregarding -o.\n",
+ Pn);
+ Foffset = 0;
+ Fsize = 1;
+ }
+ if (Fsv && (OffType != 2)) {
+ if (!Fwarn && FsvByf)
+ (void) fprintf(stderr,
+ "%s: WARNING: can't report file flags; disregarding +f.\n",
+ Pn);
+ Fsv = 0;
+ }
+/*
+ * Make sure the local mount info table is loaded if doing anything other
+ * than just Internet lookups. (HasNFS is defined during the loading of the
+ * local mount table.)
+ */
+ if (Selinet == 0)
+ (void) readmnt();
+}
+
+
+/*
+ * make_proc_path() - make a path in a /proc directory
+ *
+ * entry:
+ * pp = pointer to /proc prefix
+ * lp = length of prefix
+ * np = pointer to malloc'd buffer to receive new file's path
+ * nl = length of new file path buffer
+ * sf = new path's suffix
+ *
+ * return: length of new path
+ * np = updated with new path
+ * nl = updated with new path length
+ */
+
+int
+make_proc_path(pp, pl, np, nl, sf)
+ char *pp; /* path prefix -- e.g., /proc/<pid>/ */
+ int pl; /* strlen(pp) */
+ char **np; /* malloc'd receiving buffer */
+ int *nl; /* strlen(*np) */
+ char *sf; /* suffix of new path */
+{
+ char *cp;
+ MALLOC_S rl, sl;
+
+ sl = strlen(sf);
+ if ((rl = pl + sl + 1) > *nl) {
+ if ((cp = *np))
+ cp = (char *)realloc((MALLOC_P *)cp, rl);
+ else
+ cp = (char *)malloc(rl);
+ if (!cp) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d bytes for %s%s\n",
+ Pn, (int)rl, pp, sf);
+ Exit(1);
+ }
+ *nl = rl;
+ *np = cp;
+ }
+ (void) snpf(*np, *nl, "%s", pp);
+ (void) snpf(*np + pl, *nl - pl, "%s", sf);
+ return(rl - 1);
+}
+
+
+/*
+ * isefsys() -- is path on a file system exempted with -e
+ *
+ * Note: alloc_lfile() must have been called in advance.
+ */
+
+static int
+isefsys(path, type, l, rep, lfr)
+ char *path; /* path to file */
+ char *type; /* unknown file type */
+ int l; /* link request: 0 = report
+ * 1 = link */
+ efsys_list_t **rep; /* returned Efsysl pointer, if not
+ * NULL */
+ struct lfile **lfr; /* allocated struct lfile pointer */
+{
+ efsys_list_t *ep;
+ int ds, len;
+ struct mounts *mp;
+ char nmabuf[MAXPATHLEN + 1];
+
+ len = (int) strlen(path);
+ for (ep = Efsysl; ep; ep = ep->next) {
+
+ /*
+ * Look for a matching exempt file system path at the beginning of
+ * the file path.
+ */
+ if (ep->pathl > len)
+ continue;
+ if (strncmp(ep->path, path, ep->pathl))
+ continue;
+ /*
+ * If only reporting, return information as requested.
+ */
+ if (!l) {
+ if (rep)
+ *rep = ep;
+ return(0);
+ }
+ /*
+ * Process an exempt file.
+ */
+ ds = 0;
+ if ((mp = ep->mp)) {
+ if (mp->ds & SB_DEV) {
+ Lf->dev = mp->dev;
+ ds = Lf->dev_def = 1;
+ }
+ if (mp->ds & SB_RDEV) {
+ Lf->rdev = mp->rdev;
+ ds = Lf->rdev_def = 1;
+ }
+ }
+ if (!ds)
+ (void) enter_dev_ch("UNKNOWN");
+ Lf->ntype = N_UNKN;
+ (void) snpf(Lf->type, sizeof(Lf->type), "%s",
+ (type ? type : "UNKN"));
+ (void) enter_nm(path);
+ (void) snpf(nmabuf, sizeof(nmabuf), "(%ce %s)",
+ ep->rdlnk ? '+' : '-', ep->path);
+ nmabuf[sizeof(nmabuf) - 1] = '\0';
+ (void) add_nma(nmabuf, strlen(nmabuf));
+ if (Lf->sf) {
+ if (lfr)
+ *lfr = Lf;
+ link_lfile();
+ } else if (lfr)
+ *lfr = (struct lfile *)NULL;
+ return(0);
+ }
+ return(1);
+}
+
+
+/*
+ * nm2id() - convert a name to an integer ID
+ */
+
+static int
+nm2id(nm, id, idl)
+ char *nm; /* pointer to name */
+ int *id; /* pointer to ID receiver */
+ int *idl; /* pointer to ID length receiver */
+{
+ register int tid, tidl;
+
+ for (*id = *idl = tid = tidl = 0; *nm; nm++) {
+
+#if defined(__STDC__) /* { */
+ if (!isdigit((unsigned char)*nm))
+#else /* !defined(__STDC__) } { */
+ if (!isascii(*nm) || !isdigit((unsigned char)*cp))
+#endif /* defined(__STDC__) } */
+
+ {
+ return(1);
+ }
+ tid = tid * 10 + (int)(*nm - '0');
+ tidl++;
+ }
+ *id = tid;
+ *idl = tidl;
+ return(0);
+}
+
+
+/*
+ * open_proc_stream() -- open a /proc stream
+ */
+
+FILE *
+open_proc_stream(p, m, buf, sz, act)
+ char *p; /* pointer to path to open */
+ char *m; /* pointer to mode -- e.g., "r" */
+ char **buf; /* pointer tp setvbuf() address
+ * (NULL if none) */
+ size_t *sz; /* setvbuf() size (0 if none or if
+ * getpagesize() desired */
+ int act; /* fopen() failure action:
+ * 0 : return (FILE *)NULL
+ * <>0 : fprintf() an error message
+ * and Exit(1)
+ */
+{
+ FILE *fs; /* opened stream */
+ static size_t psz = (size_t)0; /* page size */
+ size_t tsz; /* temporary size */
+/*
+ * Open the stream.
+ */
+ if (!(fs = fopen(p, m))) {
+ if (!act)
+ return((FILE *)NULL);
+ (void) fprintf(stderr, "%s: can't fopen(%s, \"%s\"): %s\n",
+ Pn, p, m, strerror(errno));
+ Exit(1);
+ }
+/*
+ * Return the stream if no buffer change is required.
+ */
+ if (!buf)
+ return(fs);
+/*
+ * Determine the buffer size required.
+ */
+ if (!(tsz = *sz)) {
+ if (!psz)
+ psz = getpagesize();
+ tsz = psz;
+ }
+/*
+ * Allocate a buffer for the stream, as required.
+ */
+ if (!*buf) {
+ if (!(*buf = (char *)malloc((MALLOC_S)tsz))) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d bytes for %s stream buffer\n",
+ Pn, (int)tsz, p);
+ Exit(1);
+ }
+ *sz = tsz;
+ }
+/*
+ * Assign the buffer to the stream.
+ */
+ if (setvbuf(fs, *buf, _IOFBF, tsz)) {
+ (void) fprintf(stderr, "%s: setvbuf(%s)=%d failure: %s\n",
+ Pn, p, (int)tsz, strerror(errno));
+ Exit(1);
+ }
+ return(fs);
+}
+
+
+/*
+ * process_id - process ID: PID or LWP
+ *
+ * return: 0 == ID processed
+ * 1 == ID not processed
+ */
+
+static int
+process_id(idp, idpl, cmd, uid, pid, ppid, pgid, tid)
+ char *idp; /* pointer to ID's path */
+ int idpl; /* pointer to ID's path length */
+ char *cmd; /* pointer to ID's command */
+ UID_ARG uid; /* ID's UID */
+ int pid; /* ID's PID */
+ int ppid; /* parent PID */
+ int pgid; /* parent GID */
+ int tid; /* task ID, if non-zero */
+{
+ int av;
+ static char *dpath = (char *)NULL;
+ static int dpathl = 0;
+ short efs, enls, enss, lnk, oty, pn, pss, sf;
+ int fd, i, ls, n, ss, sv;
+ struct l_fdinfo fi;
+ DIR *fdp;
+ struct dirent *fp;
+ static char *ipath = (char *)NULL;
+ static int ipathl = 0;
+ int j = 0;
+ struct lfile *lfr;
+ struct stat lsb, sb;
+ char nmabuf[MAXPATHLEN + 1], pbuf[MAXPATHLEN + 1];
+ static char *path = (char *)NULL;
+ static int pathl = 0;
+ static char *pathi = (char *)NULL;
+ static int pathil = 0;
+ char *rest;
+ int txts = 0;
+
+#if defined(HASSELINUX)
+ cntxlist_t *cntxp;
+#endif /* defined(HASSELINUX) */
+
+/*
+ * See if process is excluded.
+ */
+ if (is_proc_excl(pid, pgid, uid, &pss, &sf, tid)
+ || is_cmd_excl(cmd, &pss, &sf))
+ return(1);
+ 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;
+ }
+ alloc_lproc(pid, pgid, ppid, uid, cmd, (int)pss, (int)sf);
+ Lp->tid = tid;
+ Plf = (struct lfile *)NULL;
+/*
+ * Process the ID's current working directory info.
+ */
+ if (!Ckscko) {
+ (void) make_proc_path(idp, idpl, &path, &pathl, "cwd");
+ alloc_lfile(CWD, -1);
+ efs = 0;
+ if (getlinksrc(path, pbuf, sizeof(pbuf), (char **)NULL) < 1) {
+ if (!Fwarn) {
+ (void) memset((void *)&sb, 0, sizeof(sb));
+ lnk = ss = 0;
+ (void) snpf(nmabuf, sizeof(nmabuf), "(readlink: %s)",
+ strerror(errno));
+ nmabuf[sizeof(nmabuf) - 1] = '\0';
+ (void) add_nma(nmabuf, strlen(nmabuf));
+ pn = 1;
+ } else
+ pn = 0;
+ } else {
+ lnk = pn = 1;
+ if (Efsysl && !isefsys(pbuf, "UNKNcwd", 1, NULL, &lfr)) {
+ efs = 1;
+ pn = 0;
+ } else {
+ ss = SB_ALL;
+ if (HasNFS) {
+ if ((sv = statsafely(path, &sb)))
+ sv = statEx(pbuf, &sb, &ss);
+ } else
+ sv = stat(path, &sb);
+ if (sv) {
+ ss = 0;
+ if (!Fwarn) {
+ (void) snpf(nmabuf, sizeof(nmabuf), "(stat: %s)",
+ strerror(errno));
+ nmabuf[sizeof(nmabuf) - 1] = '\0';
+ (void) add_nma(nmabuf, strlen(nmabuf));
+ }
+ }
+ }
+ }
+ if (pn) {
+ (void) process_proc_node(lnk ? pbuf : path,
+ path, &sb, ss,
+ (struct stat *)NULL, 0);
+ if (Lf->sf)
+ link_lfile();
+ }
+ }
+/*
+ * Process the ID's root directory info.
+ */
+ if (!Ckscko) {
+ (void) make_proc_path(idp, idpl, &path, &pathl, "root");
+ alloc_lfile(RTD, -1);
+ if (getlinksrc(path, pbuf, sizeof(pbuf), (char **)NULL) < 1) {
+ if (!Fwarn) {
+ (void) memset((void *)&sb, 0, sizeof(sb));
+ lnk = ss = 0;
+ (void) snpf(nmabuf, sizeof(nmabuf), "(readlink: %s)",
+ strerror(errno));
+ nmabuf[sizeof(nmabuf) - 1] = '\0';
+ (void) add_nma(nmabuf, strlen(nmabuf));
+ pn = 1;
+ } else
+ pn = 0;
+ } else {
+ lnk = pn = 1;
+ if (Efsysl && !isefsys(pbuf, "UNKNrtd", 1, NULL, NULL))
+ pn = 0;
+ else {
+ ss = SB_ALL;
+ if (HasNFS) {
+ if ((sv = statsafely(path, &sb)))
+ sv = statEx(pbuf, &sb, &ss);
+ } else
+ sv = stat(path, &sb);
+ if (sv) {
+ ss = 0;
+ if (!Fwarn) {
+ (void) snpf(nmabuf, sizeof(nmabuf), "(stat: %s)",
+ strerror(errno));
+ nmabuf[sizeof(nmabuf) - 1] = '\0';
+ (void) add_nma(nmabuf, strlen(nmabuf));
+ }
+ }
+ }
+ }
+ if (pn) {
+ (void) process_proc_node(lnk ? pbuf : path,
+ path, &sb, ss,
+ (struct stat *)NULL, 0);
+ if (Lf->sf)
+ link_lfile();
+ }
+ }
+/*
+ * Process the ID's execution info.
+ */
+ if (!Ckscko) {
+ txts = 0;
+ (void) make_proc_path(idp, idpl, &path, &pathl, "exe");
+ alloc_lfile("txt", -1);
+ if (getlinksrc(path, pbuf, sizeof(pbuf), (char **)NULL) < 1) {
+ (void) memset((void *)&sb, 0, sizeof(sb));
+ lnk = ss = 0;
+ if (!Fwarn) {
+ if ((errno != ENOENT) || uid) {
+ (void) snpf(nmabuf, sizeof(nmabuf), "(readlink: %s)",
+ strerror(errno));
+ nmabuf[sizeof(nmabuf) - 1] = '\0';
+ (void) add_nma(nmabuf, strlen(nmabuf));
+ }
+ pn = 1;
+ } else
+ pn = 0;
+ } else {
+ lnk = pn = 1;
+ if (Efsysl && !isefsys(pbuf, "UNKNtxt", 1, NULL, NULL))
+ pn = 0;
+ else {
+ ss = SB_ALL;
+ if (HasNFS) {
+ if ((sv = statsafely(path, &sb))) {
+ sv = statEx(pbuf, &sb, &ss);
+ if (!sv && (ss & SB_DEV) && (ss & SB_INO))
+ txts = 1;
+ }
+ } else
+ sv = stat(path, &sb);
+ if (sv) {
+ ss = 0;
+ if (!Fwarn) {
+ (void) snpf(nmabuf, sizeof(nmabuf), "(stat: %s)",
+ strerror(errno));
+ nmabuf[sizeof(nmabuf) - 1] = '\0';
+ (void) add_nma(nmabuf, strlen(nmabuf));
+ }
+ } else
+ txts = 1;
+ }
+ }
+ if (pn) {
+ (void) process_proc_node(lnk ? pbuf : path,
+ path, &sb, ss,
+ (struct stat *)NULL, 0);
+ if (Lf->sf)
+ link_lfile();
+ }
+ }
+/*
+ * Process the ID's memory map info.
+ */
+ if (!Ckscko) {
+ (void) make_proc_path(idp, idpl, &path, &pathl, "maps");
+ (void) process_proc_map(path, txts ? &sb : (struct stat *)NULL,
+ txts ? ss : 0);
+ }
+
+#if defined(HASSELINUX)
+/*
+ * Process the PID's SELinux context.
+ */
+ if (Fcntx) {
+
+ /*
+ * If the -Z (cntx) option was specified, match the valid contexts.
+ */
+ errno = 0;
+ if (getpidcon(pid, &Lp->cntx) == -1) {
+ Lp->cntx = (char *)NULL;
+ if (!Fwarn) {
+ (void) snpf(nmabuf, sizeof(nmabuf),
+ "(getpidcon: %s)", strerror(errno));
+ if (!(Lp->cntx = strdup(nmabuf))) {
+ (void) fprintf(stderr,
+ "%s: no context error space: PID %ld",
+ Pn, (long)Lp->pid);
+ Exit(1);
+ }
+ }
+ } else if (CntxArg) {
+
+ /*
+ * See if context includes the process.
+ */
+ for (cntxp = CntxArg; cntxp; cntxp = cntxp->next) {
+ if (cmp_cntx_eq(Lp->cntx, cntxp->cntx)) {
+ cntxp->f = 1;
+ Lp->pss |= PS_PRI;
+ Lp->sf |= SELCNTX;
+ break;
+ }
+ }
+ }
+ }
+#endif /* defined(HASSELINUX) */
+
+/*
+ * Process the ID's file descriptor directory.
+ */
+ if ((i = make_proc_path(idp, idpl, &dpath, &dpathl, "fd/")) < 3)
+ return(0);
+ dpath[i - 1] = '\0';
+ if ((OffType == 2)
+ && ((j = make_proc_path(idp, idpl, &ipath, &ipathl, "fdinfo/")) >= 7))
+ oty = 1;
+ else
+ oty = 0;
+ if (!(fdp = opendir(dpath))) {
+ if (!Fwarn) {
+ (void) snpf(nmabuf, sizeof(nmabuf), "%s (opendir: %s)",
+ dpath, strerror(errno));
+ alloc_lfile("NOFD", -1);
+ nmabuf[sizeof(nmabuf) - 1] = '\0';
+ (void) add_nma(nmabuf, strlen(nmabuf));
+ link_lfile();
+ }
+ return(0);
+ }
+ dpath[i - 1] = '/';
+ while ((fp = readdir(fdp))) {
+ if (nm2id(fp->d_name, &fd, &n))
+ continue;
+ (void) make_proc_path(dpath, i, &path, &pathl, fp->d_name);
+ (void) alloc_lfile((char *)NULL, fd);
+ if (getlinksrc(path, pbuf, sizeof(pbuf), &rest) < 1) {
+ (void) memset((void *)&sb, 0, sizeof(sb));
+ lnk = ss = 0;
+ if (!Fwarn) {
+ (void) snpf(nmabuf, sizeof(nmabuf), "(readlink: %s)",
+ strerror(errno));
+ nmabuf[sizeof(nmabuf) - 1] = '\0';
+ (void) add_nma(nmabuf, strlen(nmabuf));
+ pn = 1;
+ } else
+ pn = 0;
+ } else {
+ lnk = 1;
+ if (Efsysl && !isefsys(pbuf, "UNKNfd", 1, NULL, &lfr)) {
+ efs = 1;
+ pn = 0;
+ } else {
+ if (HasNFS) {
+ if (lstatsafely(path, &lsb)) {
+ (void) statEx(pbuf, &lsb, &ls);
+ enls = errno;
+ } else {
+ enls = 0;
+ ls = SB_ALL;
+ }
+ if (statsafely(path, &sb)) {
+ (void) statEx(pbuf, &sb, &ss);
+ enss = errno;
+ } else {
+ enss = 0;
+ ss = SB_ALL;
+ }
+ } else {
+ ls = lstat(path, &lsb) ? 0 : SB_ALL;
+ enls = errno;
+ ss = stat(path, &sb) ? 0 : SB_ALL;
+ enss = errno;
+ }
+ if (!ls && !Fwarn) {
+ (void) snpf(nmabuf, sizeof(nmabuf), "lstat: %s)",
+ strerror(enls));
+ nmabuf[sizeof(nmabuf) - 1] = '\0';
+ (void) add_nma(nmabuf, strlen(nmabuf));
+ }
+ if (!ss && !Fwarn) {
+ (void) snpf(nmabuf, sizeof(nmabuf), "(stat: %s)",
+ strerror(enss));
+ nmabuf[sizeof(nmabuf) - 1] = '\0';
+ (void) add_nma(nmabuf, strlen(nmabuf));
+ }
+ if (Ckscko) {
+ if ((ss & SB_MODE)
+ && ((sb.st_mode & S_IFMT) == S_IFSOCK))
+ {
+ pn = 1;
+ } else
+ pn = 0;
+ } else
+ pn = 1;
+ }
+ }
+ if (pn || (efs && lfr && oty)) {
+ if (oty) {
+ (void) make_proc_path(ipath, j, &pathi, &pathil,
+ fp->d_name);
+ if ((av = get_fdinfo(pathi, &fi)) & FDINFO_POS) {
+ if (efs) {
+ if (Foffset) {
+ lfr->off = (SZOFFTYPE)fi.pos;
+ lfr->off_def = 1;
+ }
+ } else {
+ ls |= SB_SIZE;
+ lsb.st_size = fi.pos;
+ }
+ } else
+ ls &= ~SB_SIZE;
+
+#if !defined(HASNOFSFLAGS)
+ if ((av & FDINFO_FLAGS) && (Fsv & FSV_FG)) {
+ if (efs) {
+ lfr->ffg = (long)fi.flags;
+ lfr->fsv |= FSV_FG;
+ } else {
+ Lf->ffg = (long)fi.flags;
+ Lf->fsv |= FSV_FG;
+ }
+ }
+# endif /* !defined(HASNOFSFLAGS) */
+
+ }
+ if (pn) {
+ process_proc_node(lnk ? pbuf : path, path, &sb, ss, &lsb,
+ ls);
+ if ((Lf->ntype == N_ANON_INODE) && rest && *rest)
+ enter_nm(rest);
+ if (Lf->sf)
+ link_lfile();
+ }
+ }
+ }
+ (void) closedir(fdp);
+ return(0);
+}
+
+
+/*
+ * process_proc_map() - process the memory map of a process
+ */
+
+static void
+process_proc_map(p, s, ss)
+ char *p; /* path to process maps file */
+ struct stat *s; /* executing text file state buffer */
+ int ss; /* *s status -- i.e., SB_* values */
+{
+ char buf[MAXPATHLEN + 1], *ep, fmtbuf[32], **fp, nmabuf[MAXPATHLEN + 1];
+ dev_t dev;
+ int ds, efs, en, i, mss, nf, sv;
+ int eb = 6;
+ INODETYPE inode;
+ MALLOC_S len;
+ long maj, min;
+ FILE *ms;
+ int ns = 0;
+ struct stat sb;
+ struct saved_map {
+ dev_t dev;
+ INODETYPE inode;
+ };
+ static struct saved_map *sm = (struct saved_map *)NULL;
+ efsys_list_t *rep;
+ static int sma = 0;
+ static char *vbuf = (char *)NULL;
+ static size_t vsz = (size_t)0;
+/*
+ * Open the /proc/<pid>/maps file, assign a page size buffer to its stream,
+ * and read it/
+ */
+ if (!(ms = open_proc_stream(p, "r", &vbuf, &vsz, 0)))
+ return;
+ while (fgets(buf, sizeof(buf), ms)) {
+ if ((nf = get_fields(buf, ":", &fp, &eb, 1)) < 7)
+ continue; /* not enough fields */
+ if (!fp[6] || !*fp[6])
+ continue; /* no path name */
+ /*
+ * See if the path ends in " (deleted)". If it does, strip the
+ * " (deleted)" characters and remember that they were there.
+ */
+ if (((ds = (int)strlen(fp[6])) > 10)
+ && !strcmp(fp[6] + ds - 10, " (deleted)"))
+ {
+ *(fp[6] + ds - 10) = '\0';
+ } else
+ ds = 0;
+ /*
+ * Assemble the major and minor device numbers.
+ */
+ ep = (char *)NULL;
+ if (!fp[3] || !*fp[3]
+ || (maj = strtol(fp[3], &ep, 16)) == LONG_MIN || maj == LONG_MAX
+ || !ep || *ep)
+ continue;
+ ep = (char *)NULL;
+ if (!fp[4] || !*fp[4]
+ || (min = strtol(fp[4], &ep, 16)) == LONG_MIN || min == LONG_MAX
+ || !ep || *ep)
+ continue;
+ /*
+ * Assemble the device and inode numbers. If they are both zero, skip
+ * the entry.
+ */
+ dev = (dev_t)makedev((int)maj, (int)min);
+ if (!fp[5] || !*fp[5])
+ continue;
+ ep = (char *)NULL;
+ if ((inode = strtoull(fp[5], &ep, 0)) == ULLONG_MAX
+ || !ep || *ep)
+ continue;
+ if (!dev && !inode)
+ continue;
+ /*
+ * See if the device + inode pair match that of the executable.
+ * If they do, skip this map entry.
+ */
+ if (s && (ss & SB_DEV) && (ss & SB_INO)
+ && (dev == s->st_dev) && (inode == (INODETYPE)s->st_ino))
+ continue;
+ /*
+ * See if this device + inode pair has already been processed as
+ * a map entry.
+ */
+ for (i = 0; i < ns; i++) {
+ if (dev == sm[i].dev && inode == sm[i].inode)
+ break;
+ }
+ if (i < ns)
+ continue;
+ /*
+ * Record the processing of this map entry's device and inode pair.
+ */
+ if (ns >= sma) {
+ sma += 10;
+ len = (MALLOC_S)(sma * sizeof(struct saved_map));
+ if (sm)
+ sm = (struct saved_map *)realloc(sm, len);
+ else
+ sm = (struct saved_map *)malloc(len);
+ if (!sm) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d bytes for saved maps, PID %d\n",
+ Pn, (int)len, Lp->pid);
+ Exit(1);
+ }
+ }
+ sm[ns].dev = dev;
+ sm[ns++].inode = inode;
+ /*
+ * Allocate space for the mapped file, then get stat(2) information
+ * for it. Skip the stat(2) operation if this is on an exempt file
+ * system.
+ */
+ alloc_lfile("mem", -1);
+ if (Efsysl && !isefsys(fp[6], (char *)NULL, 0, &rep, NULL))
+ efs = sv = 1;
+ else
+ efs = 0;
+ if (!efs) {
+ if (HasNFS)
+ sv = statsafely(fp[6], &sb);
+ else
+ sv = stat(fp[6], &sb);
+ }
+ if (sv || efs) {
+ en = errno;
+ /*
+ * Applying stat(2) to the file was not possible (file is on an
+ * exempt file system) or stat(2) failed, so manufacture a partial
+ * stat(2) reply from the process' maps file entry.
+ *
+ * If the file has been deleted, reset its type to "DEL"; otherwise
+ * generate a stat() error name addition.
+ */
+ (void) memset((void *)&sb, 0, sizeof(sb));
+ sb.st_dev = dev;
+ sb.st_ino = (ino_t)inode;
+ sb.st_mode = S_IFREG;
+ mss = SB_DEV | SB_INO | SB_MODE;
+ if (ds)
+ alloc_lfile("DEL", -1);
+ else if (!efs && !Fwarn) {
+ (void) snpf(nmabuf, sizeof(nmabuf), "(stat: %s)",
+ strerror(en));
+ nmabuf[sizeof(nmabuf) - 1] = '\0';
+ (void) add_nma(nmabuf, strlen(nmabuf));
+ }
+ } else if ((sb.st_dev != dev) || ((INODETYPE)sb.st_ino != inode)) {
+
+ /*
+ * The stat(2) device and inode numbers don't match those obtained
+ * from the process' maps file.
+ *
+ * If the file has been deleted, reset its type to "DEL"; otherwise
+ * generate inconsistency name additions.
+ *
+ * Manufacture a partial stat(2) reply from the maps file
+ * information.
+ */
+ if (ds)
+ alloc_lfile("DEL", -1);
+ else if (!Fwarn) {
+ char *sep;
+
+ if (sb.st_dev != dev) {
+ (void) snpf(nmabuf, sizeof(nmabuf),
+ "(path dev=%d,%d%s",
+ GET_MAJ_DEV(sb.st_dev), GET_MIN_DEV(sb.st_dev),
+ ((INODETYPE)sb.st_ino == inode) ? ")" : ",");
+ nmabuf[sizeof(nmabuf) - 1] = '\0';
+ (void) add_nma(nmabuf, strlen(nmabuf));
+ sep = "";
+ } else
+ sep = "(path ";
+ if ((INODETYPE)sb.st_ino != inode) {
+ (void) snpf(fmtbuf, sizeof(fmtbuf), "%%sinode=%s)",
+ InodeFmt_d);
+ (void) snpf(nmabuf, sizeof(nmabuf), fmtbuf,
+ sep, (INODETYPE)sb.st_ino);
+ nmabuf[sizeof(nmabuf) - 1] = '\0';
+ (void) add_nma(nmabuf, strlen(nmabuf));
+ }
+ }
+ (void) memset((void *)&sb, 0, sizeof(sb));
+ sb.st_dev = dev;
+ sb.st_ino = (ino_t)inode;
+ sb.st_mode = S_IFREG;
+ mss = SB_DEV | SB_INO | SB_MODE;
+ } else
+ mss = SB_ALL;
+ /*
+ * Record the file's information.
+ */
+ if (!efs)
+ process_proc_node(fp[6], fp[6], &sb, mss, (struct stat *)NULL,
+ 0);
+ else {
+
+ /*
+ * If this file is on an exempt file system, complete the lfile
+ * structure, but change its type and add the exemption note to
+ * the NAME column.
+ */
+ Lf->dev = sb.st_dev;
+ Lf->inode = (ino_t)sb.st_ino;
+ Lf->dev_def = Lf->inp_ty = 1;
+ (void) enter_nm(fp[6]);
+ (void) snpf(Lf->type, sizeof(Lf->type), "%s",
+ (ds ? "UNKNdel" : "UNKNmem"));
+ (void) snpf(nmabuf, sizeof(nmabuf), "(%ce %s)",
+ rep->rdlnk ? '+' : '-', rep->path);
+ nmabuf[sizeof(nmabuf) - 1] = '\0';
+ (void) add_nma(nmabuf, strlen(nmabuf));
+ }
+ if (Lf->sf)
+ link_lfile();
+ }
+ (void) fclose(ms);
+}
+
+
+/*
+ * read_id_stat() - read ID (PID or LWP ID) status
+ *
+ * return: -1 == ID is unavailable
+ * 0 == ID OK
+ * 1 == ID is a zombie
+ * 2 == ID is a thread
+ */
+
+static int
+read_id_stat(ty, p, id, cmd, ppid, pgid)
+ int ty; /* type: 0 == PID, 1 == LWP */
+ char *p; /* path to status file */
+ int id; /* ID: PID or LWP */
+ char **cmd; /* malloc'd command name */
+ int *ppid; /* returned parent PID for PID type */
+ int *pgid; /* returned process group ID for PID
+ * type */
+{
+ char buf[MAXPATHLEN], *cp, *cp1, **fp;
+ static char *cbf = (char *)NULL;
+ static MALLOC_S cbfa = 0;
+ FILE *fs;
+ MALLOC_S len;
+ int nf;
+ static char *vbuf = (char *)NULL;
+ static size_t vsz = (size_t)0;
+/*
+ * Open the stat file path, assign a page size buffer to its stream,
+ * and read the file's first line.
+ */
+ if (!(fs = open_proc_stream(p, "r", &vbuf, &vsz, 0)))
+ return(-1);
+ cp = fgets(buf, sizeof(buf), fs);
+ (void) fclose(fs);
+ if (!cp)
+ return(-1);
+/*
+ * Separate the line into fields on white space separators. Expect five fields
+ * for a PID type and three for an LWP type.
+ */
+ if ((nf = get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0))
+ < (ty ? 5 : 3))
+ {
+ return(-1);
+ }
+/*
+ * Convert the first field to an integer; its conversion must match the
+ * ID argument.
+ */
+ if (!fp[0] || (atoi(fp[0]) != id))
+ return(-1);
+/*
+ * Get the command name from the second field. Strip a starting '(' and
+ * an ending ')'. Allocate space to hold the result and return the space
+ * pointer.
+ */
+ if (!(cp = fp[1]))
+ return(-1);
+ if (cp && *cp == '(')
+ cp++;
+ if ((cp1 = strrchr(cp, ')')))
+ *cp1 = '\0';
+ if ((len = strlen(cp) + 1) > cbfa) {
+ cbfa = len;
+ if (cbf)
+ cbf = (char *)realloc((MALLOC_P *)cbf, cbfa);
+ else
+ cbf = (char *)malloc(cbfa);
+ if (!cbf) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d bytes for command \"%s\"\n",
+ Pn, (int)cbfa, cp);
+ Exit(1);
+ }
+ }
+ (void) snpf(cbf, len, "%s", cp);
+ *cmd = cbf;
+/*
+ * Convert and return parent process (fourth field) and process group (fifth
+ * field) IDs.
+ */
+ if (fp[3] && *fp[3])
+ *ppid = atoi(fp[3]);
+ else
+ return(-1);
+ if (fp[4] && *fp[4])
+ *pgid = atoi(fp[4]);
+ else
+ return(-1);
+/*
+ * Check the state in the third field. If it is 'Z', return that indication.
+ */
+ if (fp[2] && !strcmp(fp[2], "Z"))
+ return(1);
+ else if (fp[2] && !strcmp(fp[2], "T"))
+ return(2);
+ return(0);
+}
+
+
+/*
+ * statEx() - extended stat() to get device numbers when a "safe" stat has
+ * failed and the system has an NFS mount
+ *
+ * Note: this function was suggested by Paul Szabo as a way to get device
+ * numbers for NFS files when an NFS mount point has the root_squash
+ * option set. In that case, even if lsof is setuid(root), the identity
+ * of its requests to stat() NFS files lose root permission and may fail.
+ *
+ * This function should be used only when links have been successfully
+ * resolved in the /proc path by getlinksrc().
+ */
+
+static int
+statEx(p, s, ss)
+ char *p; /* file path */
+ struct stat *s; /* stat() result -- NULL if none
+ * wanted */
+ int *ss; /* stat() status -- SB_* values */
+{
+ static size_t ca = 0;
+ static char *cb = NULL;
+ char *cp;
+ int ensv = ENOENT;
+ struct stat sb;
+ int st = 0;
+ size_t sz;
+/*
+ * Make a copy of the path.
+ */
+ sz = strlen(p);
+ if ((sz + 1) > ca) {
+ if (cb)
+ cb = (char *)realloc((MALLOC_P *)cb, sz + 1);
+ else
+ cb = (char *)malloc(sz + 1);
+ if (!cb) {
+ (void) fprintf(stderr,
+ "%s: PID %ld: no statEx path space: %s\n",
+ Pn, (long)Lp->pid, p);
+ Exit(1);
+ }
+ ca = sz + 1;
+ }
+ (void) strcpy(cb, p);
+/*
+ * Trim trailing leaves from the end of the path one at a time and do a safe
+ * stat() on each trimmed result. Stop when a safe stat() succeeds or doesn't
+ * fail because of EACCES or EPERM.
+ */
+ for (cp = strrchr(cb, '/'); cp && (cp != cb);) {
+ *cp = '\0';
+ if (!statsafely(cb, &sb)) {
+ st = 1;
+ break;
+ }
+ ensv = errno;
+ if ((ensv != EACCES) && (ensv != EPERM))
+ break;
+ cp = strrchr(cb, '/');
+ }
+/*
+ * If a stat() on a trimmed result succeeded, form partial results containing
+ * only the device and raw device numbers.
+ */
+ memset((void *)s, 0, sizeof(struct stat));
+ if (st) {
+ errno = 0;
+ s->st_dev = sb.st_dev;
+ s->st_rdev = sb.st_rdev;
+ *ss = SB_DEV | SB_RDEV;
+ return(0);
+ }
+ errno = ensv;
+ *ss = 0;
+ return(1);
+}
diff --git a/dialects/linux/dproto.h b/dialects/linux/dproto.h
new file mode 100644
index 0000000..1574bbc
--- /dev/null
+++ b/dialects/linux/dproto.h
@@ -0,0 +1,51 @@
+/*
+ * dproto.h - Linux function prototypes for /proc-based lsof
+ *
+ * The _PROTOTYPE macro is defined in the common proto.h.
+ */
+
+
+/*
+ * Copyright 1997 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.9 2013/01/02 17:02:36 abe Exp $
+ */
+
+
+#if defined(HASSELINUX)
+_PROTOTYPE(extern int enter_cntx_arg,(char *cnxt));
+#endif /* defined(HASSELINUX) */
+
+_PROTOTYPE(extern int get_fields,(char *ln, char *sep, char ***fr, int *eb, int en));
+_PROTOTYPE(extern void get_locks,(char *p));
+_PROTOTYPE(extern int is_file_named,(int ty, char *p, struct mounts *mp, int cd));
+_PROTOTYPE(extern int make_proc_path,(char *pp, int lp, char **np, int *npl, char *sf));
+_PROTOTYPE(extern FILE *open_proc_stream,(char *p, char *mode, char **buf, size_t *sz, int act));
+_PROTOTYPE(extern void process_proc_node,(char *p, char *pbr, struct stat *s, int ss, struct stat *l, int ls));
+_PROTOTYPE(extern void process_proc_sock,(char *p, char *pbr, struct stat *s, int ss, struct stat *l, int ls));
+_PROTOTYPE(extern void set_net_paths,(char *p, int pl));
diff --git a/dialects/linux/dsock.c b/dialects/linux/dsock.c
new file mode 100644
index 0000000..9109b2f
--- /dev/null
+++ b/dialects/linux/dsock.c
@@ -0,0 +1,3946 @@
+/*
+ * dsock.c - Linux socket processing functions for /proc-based lsof
+ */
+
+
+/*
+ * Copyright 1997 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 1997 Purdue Research Foundation.\nAll rights reserved.\n";
+static char *rcsid = "$Id: dsock.c,v 1.39 2013/01/02 17:02:36 abe Exp $";
+#endif
+
+
+#include "lsof.h"
+#include <sys/xattr.h>
+
+
+/*
+ * Local definitions
+ */
+
+#define INOBUCKS 128 /* inode hash bucket count -- must be
+ * a power of two */
+#define INOHASH(ino) ((int)((ino * 31415) >> 3) & (INOBUCKS - 1))
+#define TCPUDPHASH(ino) ((int)((ino * 31415) >> 3) & (TcpUdp_bucks - 1))
+#define TCPUDP6HASH(ino) ((int)((ino * 31415) >> 3) & (TcpUdp6_bucks - 1))
+
+
+/*
+ * Local structures
+ */
+
+struct ax25sin { /* AX25 socket information */
+ char *da; /* destination address */
+ char *dev_ch; /* device characters */
+ char *sa; /* source address */
+ INODETYPE inode;
+ unsigned long sq, rq; /* send and receive queue values */
+ unsigned char sqs, rqs; /* send and receive queue states */
+ int state;
+ struct ax25sin *next;
+};
+
+struct icmpin {
+ INODETYPE inode; /* node number */
+ char *la; /* local address */
+ char *ra; /* remote address */
+ MALLOC_S lal; /* strlen(la) */
+ MALLOC_S ral; /* strlen(ra) */
+ struct icmpin *next;
+};
+
+struct ipxsin { /* IPX socket information */
+ INODETYPE inode;
+ char *la; /* local address */
+ char *ra; /* remote address */
+ int state;
+ unsigned long txq, rxq; /* transmit and receive queue values */
+ struct ipxsin *next;
+};
+
+struct nlksin { /* Netlink socket information */
+ INODETYPE inode; /* node number */
+ unsigned int pr; /* protocol */
+ struct nlksin *next;
+};
+
+struct packin { /* packet information */
+ INODETYPE inode;
+ int ty; /* socket type */
+ int pr; /* protocol */
+ struct packin *next;
+};
+
+struct rawsin { /* raw socket information */
+ INODETYPE inode;
+ char *la; /* local address */
+ char *ra; /* remote address */
+ char *sp; /* state characters */
+ MALLOC_S lal; /* strlen(la) */
+ MALLOC_S ral; /* strlen(ra) */
+ MALLOC_S spl; /* strlen(sp) */
+ struct rawsin *next;
+};
+
+struct sctpsin { /* SCTP socket information */
+ INODETYPE inode;
+ int type; /* type: 0 = assoc
+ * 1 = eps
+ * 2 assoc and eps */
+ char *addr; /* association or endpoint address */
+ char *assocID; /* association ID */
+ char *lport; /* local port */
+ char *rport; /* remote port */
+ char *laddrs; /* local address */
+ char *raddrs; /* remote address */
+ struct sctpsin *next;
+};
+
+struct tcp_udp { /* IPv4 TCP and UDP socket
+ * information */
+ INODETYPE inode;
+ unsigned long faddr, laddr; /* foreign & local IPv6 addresses */
+ int fport, lport; /* foreign & local ports */
+ unsigned long txq, rxq; /* transmit & receive queue values */
+ int proto; /* 0 = TCP, 1 = UDP, 2 = UDPLITE */
+ int state; /* protocol state */
+ struct tcp_udp *next;
+};
+
+#if defined(HASIPv6)
+struct tcp_udp6 { /* IPv6 TCP and UDP socket
+ * information */
+ INODETYPE inode;
+ struct in6_addr faddr, laddr; /* foreign and local IPv6 addresses */
+ int fport, lport; /* foreign & local ports */
+ unsigned long txq, rxq; /* transmit & receive queue values */
+ int proto; /* 0 = TCP, 1 = UDP, 2 = UDPLITE */
+ int state; /* protocol state */
+ struct tcp_udp6 *next;
+};
+#endif /* defined(HASIPv6) */
+
+struct uxsin { /* UNIX socket information */
+ INODETYPE inode; /* node number */
+ char *pcb; /* protocol control block */
+ char *path; /* file path */
+ unsigned char sb_def; /* stat(2) buffer definitions */
+ dev_t sb_dev; /* stat(2) buffer device */
+ INODETYPE sb_ino; /* stat(2) buffer node number */
+ dev_t sb_rdev; /* stat(2) raw device number */
+ struct uxsin *next;
+};
+
+
+/*
+ * Local static values
+ */
+
+static char *AX25path = (char *)NULL; /* path to AX25 /proc information */
+static struct ax25sin **AX25sin = (struct ax25sin **)NULL;
+ /* AX25 socket info, hashed by inode */
+static char *ax25st[] = {
+ "LISTENING", /* 0 */
+ "SABM SENT", /* 1 */
+ "DISC SENT", /* 2 */
+ "ESTABLISHED", /* 3 */
+ "RECOVERY" /* 4 */
+};
+#define NAX25ST (sizeof(ax25st) / sizeof(char *))
+static char *ICMPpath = (char *)NULL; /* path to ICMP /proc information */
+static struct icmpin **Icmpin = (struct icmpin **)NULL;
+ /* ICMP socket info, hashed by inode */
+static char *Ipxpath = (char *)NULL; /* path to IPX /proc information */
+static struct ipxsin **Ipxsin = (struct ipxsin **)NULL;
+ /* IPX socket info, hashed by inode */
+static char *Nlkpath = (char *)NULL; /* path to Netlink /proc information */
+static struct nlksin **Nlksin = (struct nlksin **)NULL;
+ /* Netlink socket info, hashed by
+ * inode */
+static struct packin **Packin = (struct packin **)NULL;
+ /* packet info, hashed by inode */
+static char *Packpath = (char *)NULL; /* path to packet /proc information */
+static char *Rawpath = (char *)NULL; /* path to raw socket /proc
+ * information */
+static struct rawsin **Rawsin = (struct rawsin **)NULL;
+ /* raw socket info, hashed by inode */
+static char *SCTPPath[] = { /* paths to /proc/net STCP info */
+ (char *)NULL, /* 0 = /proc/net/sctp/assocs */
+ (char *)NULL /* 1 = /proc/net/sctp/eps */
+};
+#define NSCTPPATHS sizeof(SCTPPath)/sizeof(char *)
+static char *SCTPSfx[] = { /* /proc/net suffixes */
+ "sctp/assocs", /* 0 = /proc/net/sctp/assocs */
+ "sctp/eps" /* 1 = /proc/net/sctp/eps */
+};
+static struct sctpsin **SCTPsin = (struct sctpsin **)NULL;
+ /* SCTP info, hashed by inode */
+static char *SockStatPath = (char *)NULL;
+ /* path to /proc/net socket status */
+static char *TCPpath = (char *)NULL; /* path to TCP /proc information */
+static struct tcp_udp **TcpUdp = (struct tcp_udp **)NULL;
+ /* IPv4 TCP & UDP info, hashed by
+ * inode */
+static int TcpUdp_bucks = 0; /* dynamically sized hash bucket
+ * count for TCP and UDP -- will
+ * be a power of two */
+
+#if defined(HASIPv6)
+static char *Raw6path = (char *)NULL; /* path to raw IPv6 /proc information */
+static struct rawsin **Rawsin6 = (struct rawsin **)NULL;
+ /* IPv6 raw socket info, hashed by
+ * inode */
+static char *SockStatPath6 = (char *)NULL;
+ /* path to /proc/net IPv6 socket
+ * status */
+static char *TCP6path = (char *)NULL; /* path to IPv6 TCP /proc information */
+static struct tcp_udp6 **TcpUdp6 = (struct tcp_udp6 **)NULL;
+ /* IPv6 TCP & UDP info, hashed by
+ * inode */
+static int TcpUdp6_bucks = 0; /* dynamically sized hash bucket
+ * count for IPv6 TCP and UDP -- will
+ * be a power of two */
+static char *UDP6path = (char *)NULL; /* path to IPv6 UDP /proc information */
+static char *UDPLITE6path = (char *)NULL;
+ /* path to IPv6 UDPLITE /proc
+ * information */
+#endif /* defined(HASIPv6) */
+
+static char *UDPpath = (char *)NULL; /* path to UDP /proc information */
+static char *UDPLITEpath = (char *)NULL;
+ /* path to UDPLITE /proc information */
+static char *UNIXpath = (char *)NULL; /* path to UNIX /proc information */
+static struct uxsin **Uxsin = (struct uxsin **)NULL;
+ /* UNIX socket info, hashed by inode */
+
+
+/*
+ * Local function prototypes
+ */
+
+_PROTOTYPE(static struct ax25sin *check_ax25,(INODETYPE i));
+_PROTOTYPE(static struct icmpin *check_icmp,(INODETYPE i));
+_PROTOTYPE(static struct ipxsin *check_ipx,(INODETYPE i));
+_PROTOTYPE(static struct nlksin *check_netlink,(INODETYPE i));
+_PROTOTYPE(static struct packin *check_pack,(INODETYPE i));
+_PROTOTYPE(static struct rawsin *check_raw,(INODETYPE i));
+_PROTOTYPE(static struct sctpsin *check_sctp,(INODETYPE i));
+_PROTOTYPE(static struct tcp_udp *check_tcpudp,(INODETYPE i, char **p));
+_PROTOTYPE(static struct uxsin *check_unix,(INODETYPE i));
+_PROTOTYPE(static void get_ax25,(char *p));
+_PROTOTYPE(static void get_icmp,(char *p));
+_PROTOTYPE(static void get_ipx,(char *p));
+_PROTOTYPE(static void get_netlink,(char *p));
+_PROTOTYPE(static void get_pack,(char *p));
+_PROTOTYPE(static void get_raw,(char *p));
+_PROTOTYPE(static void get_sctp,(void));
+_PROTOTYPE(static char *get_sctpaddrs,(char **fp, int i, int nf, int *x));
+_PROTOTYPE(static void get_tcpudp,(char *p, int pr, int clr));
+_PROTOTYPE(static void get_unix,(char *p));
+_PROTOTYPE(static int isainb,(char *a, char *b));
+_PROTOTYPE(static void print_ax25info,(struct ax25sin *ap));
+_PROTOTYPE(static void print_ipxinfo,(struct ipxsin *ip));
+
+#if defined(HASIPv6)
+_PROTOTYPE(static struct rawsin *check_raw6,(INODETYPE i));
+_PROTOTYPE(static struct tcp_udp6 *check_tcpudp6,(INODETYPE i, char **p));
+_PROTOTYPE(static void get_raw6,(char *p));
+_PROTOTYPE(static void get_tcpudp6,(char *p, int pr, int clr));
+_PROTOTYPE(static int net6a2in6,(char *as, struct in6_addr *ad));
+#endif /* defined(HASIPv6) */
+
+
+/*
+ * build_IPstates() -- build the TCP and UDP state tables
+ */
+
+void
+build_IPstates()
+{
+ if (!TcpSt) {
+ (void) enter_IPstate("TCP", "ESTABLISHED", TCP_ESTABLISHED);
+ (void) enter_IPstate("TCP", "SYN_SENT", TCP_SYN_SENT);
+ (void) enter_IPstate("TCP", "SYN_RECV", TCP_SYN_RECV);
+ (void) enter_IPstate("TCP", "FIN_WAIT1", TCP_FIN_WAIT1);
+ (void) enter_IPstate("TCP", "FIN_WAIT2", TCP_FIN_WAIT2);
+ (void) enter_IPstate("TCP", "TIME_WAIT", TCP_TIME_WAIT);
+ (void) enter_IPstate("TCP", "CLOSE", TCP_CLOSE);
+ (void) enter_IPstate("TCP", "CLOSE_WAIT", TCP_CLOSE_WAIT);
+ (void) enter_IPstate("TCP", "LAST_ACK", TCP_LAST_ACK);
+ (void) enter_IPstate("TCP", "LISTEN", TCP_LISTEN);
+ (void) enter_IPstate("TCP", "CLOSING", TCP_CLOSING);
+ (void) enter_IPstate("TCP", "CLOSED", 0);
+ (void) enter_IPstate("TCP", (char *)NULL, 0);
+ }
+}
+
+
+/*
+ * check_ax25() - check for AX25 socket file
+ */
+
+static struct ax25sin *
+check_ax25(i)
+ INODETYPE i; /* socket file's inode number */
+{
+ struct ax25sin *ap;
+ int h;
+
+ h = INOHASH(i);
+ for (ap = AX25sin[h]; ap; ap = ap->next) {
+ if (i == ap->inode)
+ return(ap);
+ }
+ return((struct ax25sin *)NULL);
+}
+
+
+
+/*
+ * check_icmp() - check for ICMP socket
+ */
+
+static struct icmpin *
+check_icmp(i)
+ INODETYPE i; /* socket file's inode number */
+{
+ int h;
+ struct icmpin *icmpp;
+
+ h = INOHASH(i);
+ for (icmpp = Icmpin[h]; icmpp; icmpp = icmpp->next) {
+ if (i == icmpp->inode)
+ return(icmpp);
+ }
+ return((struct icmpin *)NULL);
+}
+
+
+/*
+ * check_ipx() - check for IPX socket file
+ */
+
+static struct ipxsin *
+check_ipx(i)
+ INODETYPE i; /* socket file's inode number */
+{
+ int h;
+ struct ipxsin *ip;
+
+ h = INOHASH(i);
+ for (ip = Ipxsin[h]; ip; ip = ip->next) {
+ if (i == ip->inode)
+ return(ip);
+ }
+ return((struct ipxsin *)NULL);
+}
+
+
+/*
+ * check_netlink() - check for Netlink socket file
+ */
+
+static struct nlksin *
+check_netlink(i)
+ INODETYPE i; /* socket file's inode number */
+{
+ int h;
+ struct nlksin *lp;
+
+ h = INOHASH(i);
+ for (lp = Nlksin[h]; lp; lp = lp->next) {
+ if (i == lp->inode)
+ return(lp);
+ }
+ return((struct nlksin *)NULL);
+}
+
+
+/*
+ * check_pack() - check for packet file
+ */
+
+static struct packin *
+check_pack(i)
+ INODETYPE i; /* packet file's inode number */
+{
+ int h;
+ struct packin *pp;
+
+ h = INOHASH(i);
+ for (pp = Packin[h]; pp; pp = pp->next) {
+ if (i == pp->inode)
+ return(pp);
+ }
+ return((struct packin *)NULL);
+}
+
+
+/*
+ * check_raw() - check for raw socket file
+ */
+
+static struct rawsin *
+check_raw(i)
+ INODETYPE i; /* socket file's inode number */
+{
+ int h;
+ struct rawsin *rp;
+
+ h = INOHASH(i);
+ for (rp = Rawsin[h]; rp; rp = rp->next) {
+ if (i == rp->inode)
+ return(rp);
+ }
+ return((struct rawsin *)NULL);
+}
+
+
+/*
+ * check_sctp() - check for SCTP socket file
+ */
+
+static struct sctpsin *
+check_sctp(i)
+ INODETYPE i; /* socket file's inode number */
+{
+ int h;
+ struct sctpsin *sp;
+
+ h = INOHASH(i);
+ for (sp = SCTPsin[h]; sp; sp = sp->next) {
+ if (i == sp->inode)
+ return(sp);
+ }
+ return((struct sctpsin *)NULL);
+}
+
+
+/*
+ * check_tcpudp() - check for IPv4 TCP or UDP socket file
+ */
+
+static struct tcp_udp *
+check_tcpudp(i, p)
+ INODETYPE i; /* socket file's inode number */
+ char **p; /* protocol return */
+{
+ int h;
+ struct tcp_udp *tp;
+
+ h = TCPUDPHASH(i);
+ for (tp = TcpUdp[h]; tp; tp = tp->next) {
+ if (i == tp->inode) {
+ switch (tp->proto) {
+ case 0:
+ *p = "TCP";
+ break;
+ case 1:
+ *p = "UDP";
+ break;
+ case 2:
+ *p = "UDPLITE";
+ break;
+ default:
+ *p = "unknown";
+ }
+ return(tp);
+ }
+ }
+ return((struct tcp_udp *)NULL);
+}
+
+
+#if defined(HASIPv6)
+/*
+ * check_raw6() - check for raw IPv6 socket file
+ */
+
+static struct rawsin *
+check_raw6(i)
+ INODETYPE i; /* socket file's inode number */
+{
+ int h;
+ struct rawsin *rp;
+
+ h = INOHASH(i);
+ for (rp = Rawsin6[h]; rp; rp = rp->next) {
+ if (i == rp->inode)
+ return(rp);
+ }
+ return((struct rawsin *)NULL);
+}
+
+
+/*
+ * check_tcpudp6() - check for IPv6 TCP or UDP socket file
+ */
+
+static struct tcp_udp6 *
+check_tcpudp6(i, p)
+ INODETYPE i; /* socket file's inode number */
+ char **p; /* protocol return */
+{
+ int h;
+ struct tcp_udp6 *tp6;
+
+ h = TCPUDP6HASH(i);
+ for (tp6 = TcpUdp6[h]; tp6; tp6 = tp6->next) {
+ if (i == tp6->inode) {
+ switch (tp6->proto) {
+ case 0:
+ *p = "TCP";
+ break;
+ case 1:
+ *p = "UDP";
+ break;
+ case 2:
+ *p = "UDPLITE";
+ break;
+ default:
+ *p = "unknown";
+ }
+ return(tp6);
+ }
+ }
+ return((struct tcp_udp6 *)NULL);
+}
+#endif /* defined(HASIPv6) */
+
+
+/*
+ * check_unix() - check for UNIX domain socket
+ */
+
+static struct uxsin *
+check_unix(i)
+ INODETYPE i; /* socket file's inode number */
+{
+ int h;
+ struct uxsin *up;
+
+ h = INOHASH(i);
+ for (up = Uxsin[h]; up; up = up->next) {
+ if (i == up->inode)
+ return(up);
+ }
+ return((struct uxsin *)NULL);
+}
+
+
+/*
+ * get_ax25() - get /proc/net/ax25 info
+ */
+
+static void
+get_ax25(p)
+ char *p; /* /proc/net/ipx path */
+{
+ struct ax25sin *ap, *np;
+ FILE *as;
+ char buf[MAXPATHLEN], *da, *dev_ch, *ep, **fp, *sa;
+ int h, nf;
+ INODETYPE inode;
+ unsigned long rq, sq, state;
+ MALLOC_S len;
+ unsigned char rqs, sqs;
+ static char *vbuf = (char *)NULL;
+ static size_t vsz = (size_t)0;
+/*
+ * Do second time cleanup or first time setup.
+ */
+ if (AX25sin) {
+ for (h = 0; h < INOBUCKS; h++) {
+ for (ap = AX25sin[h]; ap; ap = np) {
+ np = ap->next;
+ if (ap->da)
+ (void) free((FREE_P *)ap->da);
+ if (ap->dev_ch)
+ (void) free((FREE_P *)ap->dev_ch);
+ if (ap->sa)
+ (void) free((FREE_P *)ap->sa);
+ (void) free((FREE_P *)ap);
+ }
+ AX25sin[h] = (struct ax25sin *)NULL;
+ }
+ } else {
+ AX25sin = (struct ax25sin **)calloc(INOBUCKS,
+ sizeof(struct ax25sin *));
+ if (!AX25sin) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d AX25 hash pointer bytes\n",
+ Pn, (int)(INOBUCKS * sizeof(struct ax25sin *)));
+ Exit(1);
+ }
+ }
+/*
+ * Open the /proc/net/ax25 file, assign a page size buffer to the stream,
+ * and read it. Store AX25 socket info in the AX25sin[] hash buckets.
+ */
+ if (!(as = open_proc_stream(p, "r", &vbuf, &vsz, 0)))
+ return;
+ while (fgets(buf, sizeof(buf) - 1, as)) {
+ if ((nf = get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0)) < 24)
+ continue;
+ /*
+ * /proc/net/ax25 has no title line, a very poor deficiency in its
+ * implementation.
+ *
+ * The ax25_get_info() function in kern module .../net/ax25/af_ax25.c
+ * says the format of the lines in the file is:
+ *
+ * magic dev src_addr dest_addr,digi1,digi2,.. st vs vr va t1 t1 \
+ * t2 t2 t3 t3 idle idle n2 n2 rtt window paclen Snd-Q Rcv-Q \
+ * inode
+ *
+ * The code in this function is forced to assume that format is in
+ * effect..
+ */
+
+ /*
+ * Assemble the inode number and see if it has already been recorded.
+ * If it has, skip this line.
+ */
+ ep = (char *)NULL;
+ if (!fp[23] || !*fp[23]
+ || (inode = strtoull(fp[23], &ep, 0)) == ULONG_MAX
+ || !ep || *ep)
+ continue;
+ h = INOHASH((INODETYPE)inode);
+ for (ap = AX25sin[h]; ap; ap = ap->next) {
+ if (inode == ap->inode)
+ break;
+ }
+ if (ap)
+ continue;
+ /*
+ * Assemble the send and receive queue values and the state.
+ */
+ rq = sq = (unsigned long)0;
+ rqs = sqs = (unsigned char)0;
+ ep = (char *)NULL;
+ if (!fp[21] || !*fp[21]
+ || (sq = strtoul(fp[21], &ep, 0)) == ULONG_MAX || !ep || *ep)
+ continue;
+ sqs = (unsigned char)1;
+ ep = (char *)NULL;
+ if (!fp[22] || !*fp[22]
+ || (rq = strtoul(fp[22], &ep, 0)) == ULONG_MAX || !ep || *ep)
+ continue;
+ rqs = (unsigned char)1;
+ ep = (char *)NULL;
+ if (!fp[4] || !*fp[4]
+ || (state = strtoul(fp[4], &ep, 0)) == ULONG_MAX || !ep || *ep)
+ continue;
+ /*
+ * Allocate space for the destination address.
+ */
+ if (!fp[3] || !*fp[3])
+ da = (char *)NULL;
+ else if ((len = strlen(fp[3]))) {
+ if (!(da = (char *)malloc(len + 1))) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d destination AX25 addr bytes: %s\n",
+ Pn, (int)(len + 1), fp[3]);
+ Exit(1);
+ }
+ (void) snpf(da, len + 1, "%s", fp[3]);
+ } else
+ da = (char *)NULL;
+ /*
+ * Allocate space for the source address.
+ */
+ if (!fp[2] || !*fp[2])
+ sa = (char *)NULL;
+ else if ((len = strlen(fp[2]))) {
+ if (!(sa = (char *)malloc(len + 1))) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d source AX25 address bytes: %s\n",
+ Pn, (int)(len + 1), fp[2]);
+ Exit(1);
+ }
+ (void) snpf(sa, len + 1, "%s", fp[2]);
+ } else
+ sa = (char *)NULL;
+ /*
+ * Allocate space for the device characters.
+ */
+ if (!fp[1] || !*fp[1])
+ dev_ch = (char *)NULL;
+ else if ((len = strlen(fp[1]))) {
+ if (!(dev_ch = (char *)malloc(len + 1))) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d destination AX25 dev bytes: %s\n",
+ Pn, (int)(len + 1), fp[1]);
+ Exit(1);
+ }
+ (void) snpf(dev_ch, len + 1, "%s", fp[1]);
+ } else
+ dev_ch = (char *)NULL;
+ /*
+ * Allocate space for an ax25sin entry, fill it, and link it to its
+ * hash bucket.
+ */
+ if (!(ap = (struct ax25sin *)malloc(sizeof(struct ax25sin)))) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d byte ax25sin structure\n",
+ Pn, (int)sizeof(struct ax25sin));
+ Exit(1);
+ }
+ ap->da = da;
+ ap->dev_ch = dev_ch;
+ ap->inode = inode;
+ ap->rq = rq;
+ ap->rqs = rqs;
+ ap->sa = sa;
+ ap->sq = sq;
+ ap->sqs = sqs;
+ ap->state = (int)state;
+ ap->next = AX25sin[h];
+ AX25sin[h] = ap;
+ }
+ (void) fclose(as);
+}
+
+
+/*
+ * get_icmp() - get ICMP net info
+ */
+
+static void
+get_icmp(p)
+ char *p; /* /proc/net/icmp path */
+{
+ char buf[MAXPATHLEN], *ep, **fp, *la, *ra;
+ int fl = 1;
+ int h;
+ INODETYPE inode;
+ struct icmpin *np, *icmpp;
+ unsigned long pr;
+ MALLOC_S lal, ral, spl;
+ static char *vbuf = (char *)NULL;
+ static size_t vsz = (size_t)0;
+ FILE *xs;
+/*
+ * Do second time cleanup or first time setup.
+ */
+ if (Icmpin) {
+ for (h = 0; h < INOBUCKS; h++) {
+ for (icmpp = Icmpin[h]; icmpp; icmpp = np) {
+ np = icmpp->next;
+ (void) free((FREE_P *)icmpp);
+ }
+ Icmpin[h] = (struct icmpin *)NULL;
+ }
+ } else {
+ Icmpin = (struct icmpin **)calloc(INOBUCKS,
+ sizeof(struct icmpin *));
+ if (!Icmpin) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d icmp hash pointer bytes\n",
+ Pn, (int)(INOBUCKS * sizeof(struct icmpin *)));
+ Exit(1);
+ }
+ }
+/*
+ * Open the /proc/net/icmp file, assign a page size buffer to its stream,
+ * and read the file. Store icmp info in the Icmpin[] hash buckets.
+ */
+ if (!(xs = open_proc_stream(p, "r", &vbuf, &vsz, 0)))
+ return;
+ while (fgets(buf, sizeof(buf) - 1, xs)) {
+ if (get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0) < 11)
+ continue;
+ if (fl) {
+
+ /*
+ * Check the column labels in the first line.
+ *
+ * NOTE:
+ * In column header, "inode" is at the 11th column.
+ * However, in data rows, inode appears at the 9th column.
+ *
+ * In column header, "tx_queue" and "rx_queue" are separated
+ * by a space. It is the same for "tr" and "tm->when"; in
+ * data rows they are connected with ":".
+ */
+ if (!fp[1] || strcmp(fp[1], "local_address")
+ || !fp[2] || strcmp(fp[2], "rem_address")
+ || !fp[11] || strcmp(fp[11], "inode"))
+ {
+ if (!Fwarn) {
+ (void) fprintf(stderr,
+ "%s: WARNING: unsupported format: %s\n",
+ Pn, p);
+ }
+ break;
+ }
+ fl = 0;
+ continue;
+ }
+ /*
+ * Assemble the inode number and see if the inode is already
+ * recorded.
+ */
+ ep = (char *)NULL;
+ if (!fp[9] || !*fp[9]
+ || (inode = strtoull(fp[9], &ep, 0)) == ULONG_MAX
+ || !ep || *ep)
+ continue;
+ h = INOHASH(inode);
+ for (icmpp = Icmpin[h]; icmpp; icmpp = icmpp->next) {
+ if (inode == icmpp->inode)
+ break;
+ }
+ if (icmpp)
+ continue;
+ /*
+ * Save the local address, and remote address.
+ */
+ if (!fp[1] || !*fp[1] || (lal = strlen(fp[1])) < 1) {
+ la = (char *)NULL;
+ lal = (MALLOC_S)0;
+ } else {
+ if (!(la = (char *)malloc(lal + 1))) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d local icmp address bytes: %s\n",
+ Pn, (int)(lal + 1), fp[1]);
+ Exit(1);
+ }
+ (void) snpf(la, lal + 1, "%s", fp[1]);
+ }
+ if (!fp[2] || !*fp[2] || (ral = strlen(fp[2])) < 1) {
+ ra = (char *)NULL;
+ ral = (MALLOC_S)0;
+ } else {
+ if (!(ra = (char *)malloc(ral + 1))) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d remote icmp address bytes: %s\n",
+ Pn, (int)(ral + 1), fp[2]);
+ Exit(1);
+ }
+ (void) snpf(ra, ral + 1, "%s", fp[2]);
+ }
+ /*
+ * Allocate space for a icmpin entry, fill it, and link it to its
+ * hash bucket.
+ */
+ if (!(icmpp = (struct icmpin *)malloc(sizeof(struct icmpin)))) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d byte icmp structure\n",
+ Pn, (int)sizeof(struct icmpin));
+ Exit(1);
+ }
+ icmpp->inode = inode;
+ icmpp->la = la;
+ icmpp->lal = lal;
+ icmpp->ra = ra;
+ icmpp->ral = ral;
+ icmpp->next = Icmpin[h];
+ Icmpin[h] = icmpp;
+ }
+ (void) fclose(xs);
+}
+
+
+
+/*
+ * get_ipx() - get /proc/net/ipx info
+ */
+
+static void
+get_ipx(p)
+ char *p; /* /proc/net/ipx path */
+{
+ char buf[MAXPATHLEN], *ep, **fp, *la, *ra;
+ int fl = 1;
+ int h;
+ INODETYPE inode;
+ unsigned long rxq, state, txq;
+ struct ipxsin *ip, *np;
+ MALLOC_S len;
+ static char *vbuf = (char *)NULL;
+ static size_t vsz = (size_t)0;
+ FILE *xs;
+/*
+ * Do second time cleanup or first time setup.
+ */
+ if (Ipxsin) {
+ for (h = 0; h < INOBUCKS; h++) {
+ for (ip = Ipxsin[h]; ip; ip = np) {
+ np = ip->next;
+ if (ip->la)
+ (void) free((FREE_P *)ip->la);
+ if (ip->ra)
+ (void) free((FREE_P *)ip->ra);
+ (void) free((FREE_P *)ip);
+ }
+ Ipxsin[h] = (struct ipxsin *)NULL;
+ }
+ } else {
+ Ipxsin = (struct ipxsin **)calloc(INOBUCKS,
+ sizeof(struct ipxsin *));
+ if (!Ipxsin) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d IPX hash pointer bytes\n",
+ Pn, (int)(INOBUCKS * sizeof(struct ipxsin *)));
+ Exit(1);
+ }
+ }
+/*
+ * Open the /proc/net/ipx file, assign a page size buffer to the stream,
+ * and read it. Store IPX socket info in the Ipxsin[] hash buckets.
+ */
+ if (!(xs = open_proc_stream(p, "r", &vbuf, &vsz, 0)))
+ return;
+ while (fgets(buf, sizeof(buf) - 1, xs)) {
+ if (get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0) < 7)
+ continue;
+ if (fl) {
+
+ /*
+ * Check the column labels in the first line.
+ */
+ if (!fp[0] || strcmp(fp[0], "Local_Address")
+ || !fp[1] || strcmp(fp[1], "Remote_Address")
+ || !fp[2] || strcmp(fp[2], "Tx_Queue")
+ || !fp[3] || strcmp(fp[3], "Rx_Queue")
+ || !fp[4] || strcmp(fp[4], "State")
+ || !fp[5] || strcmp(fp[5], "Uid")
+ || !fp[6] || strcmp(fp[6], "Inode"))
+ {
+ if (!Fwarn) {
+ (void) fprintf(stderr,
+ "%s: WARNING: unsupported format: %s\n",
+ Pn, p);
+ }
+ break;
+ }
+ fl = 0;
+ continue;
+ }
+ /*
+ * Assemble the inode number and see if the inode is already
+ * recorded.
+ */
+ ep = (char *)NULL;
+ if (!fp[6] || !*fp[6]
+ || (inode = strtoull(fp[6], &ep, 0)) == ULONG_MAX
+ || !ep || *ep)
+ continue;
+ h = INOHASH(inode);
+ for (ip = Ipxsin[h]; ip; ip = ip->next) {
+ if (inode == ip->inode)
+ break;
+ }
+ if (ip)
+ continue;
+ /*
+ * Assemble the transmit and receive queue values and the state.
+ */
+ ep = (char *)NULL;
+ if (!fp[2] || !*fp[2]
+ || (txq = strtoul(fp[2], &ep, 16)) == ULONG_MAX || !ep || *ep)
+ continue;
+ ep = (char *)NULL;
+ if (!fp[3] || !*fp[3]
+ || (rxq = strtoul(fp[3], &ep, 16)) == ULONG_MAX || !ep || *ep)
+ continue;
+ ep = (char *)NULL;
+ if (!fp[4] || !*fp[4]
+ || (state = strtoul(fp[4], &ep, 16)) == ULONG_MAX || !ep || *ep)
+ continue;
+ /*
+ * Allocate space for the local address, unless it is "Not_Connected".
+ */
+ if (!fp[0] || !*fp[0] || strcmp(fp[0], "Not_Connected") == 0)
+ la = (char *)NULL;
+ else if ((len = strlen(fp[0]))) {
+ if (!(la = (char *)malloc(len + 1))) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d local IPX address bytes: %s\n",
+ Pn, (int)(len + 1), fp[0]);
+ Exit(1);
+ }
+ (void) snpf(la, len + 1, "%s", fp[0]);
+ } else
+ la = (char *)NULL;
+ /*
+ * Allocate space for the remote address, unless it is "Not_Connected".
+ */
+ if (!fp[1] || !*fp[1] || strcmp(fp[1], "Not_Connected") == 0)
+ ra = (char *)NULL;
+ else if ((len = strlen(fp[1]))) {
+ if (!(ra = (char *)malloc(len + 1))) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d remote IPX address bytes: %s\n",
+ Pn, (int)(len + 1), fp[1]);
+ Exit(1);
+ }
+ (void) snpf(ra, len + 1, "%s", fp[1]);
+ } else
+ ra = (char *)NULL;
+ /*
+ * Allocate space for an ipxsin entry, fill it, and link it to its
+ * hash bucket.
+ */
+ if (!(ip = (struct ipxsin *)malloc(sizeof(struct ipxsin)))) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d byte ipxsin structure\n",
+ Pn, (int)sizeof(struct ipxsin));
+ Exit(1);
+ }
+ ip->inode = inode;
+ ip->la = la;
+ ip->ra = ra;
+ ip->txq = txq;
+ ip->rxq = rxq;
+ ip->state = (int)state;
+ ip->next = Ipxsin[h];
+ Ipxsin[h] = ip;
+ }
+ (void) fclose(xs);
+}
+
+
+/*
+ * get_netlink() - get /proc/net/netlink info
+ */
+
+static void
+get_netlink(p)
+ char *p; /* /proc/net/netlink path */
+{
+ char buf[MAXPATHLEN], *ep, **fp;
+ int fr = 1;
+ int h, pr;
+ INODETYPE inode;
+ struct nlksin *np, *lp;
+ static char *vbuf = (char *)NULL;
+ static size_t vsz = (size_t)0;
+ FILE *xs;
+/*
+ * Do second time cleanup or first time setup.
+ */
+ if (Nlksin) {
+ for (h = 0; h < INOBUCKS; h++) {
+ for (lp = Nlksin[h]; lp; lp = np) {
+ np = lp->next;
+ (void) free((FREE_P *)lp);
+ }
+ Nlksin[h] = (struct nlksin *)NULL;
+ }
+ } else {
+ Nlksin = (struct nlksin **)calloc(INOBUCKS,sizeof(struct nlksin *));
+ if (!Nlksin) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d netlink hash pointer bytes\n",
+ Pn, (int)(INOBUCKS * sizeof(struct nlksin *)));
+ Exit(1);
+ }
+ }
+/*
+ * Open the /proc/net/netlink file, assign a page size buffer to its stream,
+ * and read the file. Store Netlink info in the Nlksin[] hash buckets.
+ */
+ if (!(xs = open_proc_stream(p, "r", &vbuf, &vsz, 0)))
+ return;
+ while (fgets(buf, sizeof(buf) - 1, xs)) {
+ if (get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0) < 10)
+ continue;
+ if (fr) {
+
+ /*
+ * Check the column labels in the first line.
+ */
+ if (!fp[1] || strcmp(fp[1], "Eth")
+ || !fp[9] || strcmp(fp[9], "Inode"))
+ {
+ if (!Fwarn) {
+ (void) fprintf(stderr,
+ "%s: WARNING: unsupported format: %s\n",
+ Pn, p);
+ }
+ break;
+ }
+ fr = 0;
+ continue;
+ }
+ /*
+ * Assemble the inode number and see if the inode is already
+ * recorded.
+ */
+ ep = (char *)NULL;
+ if (!fp[9] || !*fp[9]
+ || (inode = strtoull(fp[9], &ep, 0)) == ULONG_MAX
+ || !ep || *ep)
+ continue;
+ h = INOHASH(inode);
+ for (lp = Nlksin[h]; lp; lp = lp->next) {
+ if (inode == lp->inode)
+ break;
+ }
+ if (lp)
+ continue;
+ /*
+ * Save the protocol from the Eth column.
+ */
+ if (!fp[1] || !*fp[1] || (strlen(fp[1])) < 1)
+ continue;
+ pr = atoi(fp[1]);
+ /*
+ * Allocate space for a nlksin entry, fill it, and link it to its
+ * hash bucket.
+ */
+ if (!(lp = (struct nlksin *)malloc(sizeof(struct nlksin)))) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d byte Netlink structure\n",
+ Pn, (int)sizeof(struct nlksin));
+ Exit(1);
+ }
+ lp->inode = inode;
+ lp->pr = pr;
+ lp->next = Nlksin[h];
+ Nlksin[h] = lp;
+ }
+ (void) fclose(xs);
+}
+
+
+/*
+ * get_pack() - get /proc/net/packet info
+ */
+
+static void
+get_pack(p)
+ char *p; /* /proc/net/raw path */
+{
+ char buf[MAXPATHLEN], *ep, **fp;
+ int fl = 1;
+ int h, ty;
+ INODETYPE inode;
+ struct packin *np, *pp;
+ unsigned long pr;
+ static char *vbuf = (char *)NULL;
+ static size_t vsz = (size_t)0;
+ FILE *xs;
+/*
+ * Do second time cleanup or first time setup.
+ */
+ if (Packin) {
+ for (h = 0; h < INOBUCKS; h++) {
+ for (pp = Packin[h]; pp; pp = np) {
+ np = pp->next;
+ (void) free((FREE_P *)pp);
+ }
+ Packin[h] = (struct packin *)NULL;
+ }
+ } else {
+ Packin = (struct packin **)calloc(INOBUCKS,
+ sizeof(struct packin *));
+ if (!Packin) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d packet hash pointer bytes\n",
+ Pn, (int)(INOBUCKS * sizeof(struct packin *)));
+ Exit(1);
+ }
+ }
+/*
+ * Open the /proc/net/packet file, assign a page size buffer to its stream,
+ * and read the file. Store packet info in the Packin[] hash buckets.
+ */
+ if (!(xs = open_proc_stream(p, "r", &vbuf, &vsz, 0)))
+ return;
+ while (fgets(buf, sizeof(buf) - 1, xs)) {
+ if (get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0) < 9)
+ continue;
+ if (fl) {
+
+ /*
+ * Check the column labels in the first line.
+ */
+ if (!fp[2] || strcmp(fp[2], "Type")
+ || !fp[3] || strcmp(fp[3], "Proto")
+ || !fp[8] || strcmp(fp[8], "Inode"))
+ {
+ if (!Fwarn) {
+ (void) fprintf(stderr,
+ "%s: WARNING: unsupported format: %s\n",
+ Pn, p);
+ }
+ break;
+ }
+ fl = 0;
+ continue;
+ }
+ /*
+ * Assemble the inode number and see if the inode is already
+ * recorded.
+ */
+ ep = (char *)NULL;
+ if (!fp[8] || !*fp[8]
+ || (inode = strtoull(fp[8], &ep, 0)) == ULONG_MAX
+ || !ep || *ep)
+ continue;
+ h = INOHASH(inode);
+ for (pp = Packin[h]; pp; pp = pp->next) {
+ if (inode == pp->inode)
+ break;
+ }
+ if (pp)
+ continue;
+ /*
+ * Save the socket type and protocol.
+ */
+ if (!fp[2] || !*fp[2] || (strlen(fp[2])) < 1)
+ continue;
+ ty = atoi(fp[2]);
+ ep = (char *)NULL;
+ if (!fp[3] || !*fp[3] || (strlen(fp[3]) < 1)
+ || ((pr = strtoul(fp[3], &ep, 16)) == ULONG_MAX) || !ep || *ep)
+ continue;
+ /*
+ * Allocate space for a packin entry, fill it, and link it to its
+ * hash bucket.
+ */
+ if (!(pp = (struct packin *)malloc(sizeof(struct packin)))) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d byte packet structure\n",
+ Pn, (int)sizeof(struct packin));
+ Exit(1);
+ }
+ pp->inode = inode;
+ pp->pr = (int)pr;
+ pp->ty = ty;
+ pp->next = Packin[h];
+ Packin[h] = pp;
+ }
+ (void) fclose(xs);
+}
+
+
+/*
+ * get_raw() - get /proc/net/raw info
+ */
+
+static void
+get_raw(p)
+ char *p; /* /proc/net/raw path */
+{
+ char buf[MAXPATHLEN], *ep, **fp, *la, *ra, *sp;
+ int h;
+ INODETYPE inode;
+ int nf = 12;
+ struct rawsin *np, *rp;
+ MALLOC_S lal, ral, spl;
+ static char *vbuf = (char *)NULL;
+ static size_t vsz = (size_t)0;
+ FILE *xs;
+/*
+ * Do second time cleanup or first time setup.
+ */
+ if (Rawsin) {
+ for (h = 0; h < INOBUCKS; h++) {
+ for (rp = Rawsin[h]; rp; rp = np) {
+ np = rp->next;
+ if (rp->la)
+ (void) free((FREE_P *)rp->la);
+ if (rp->ra)
+ (void) free((FREE_P *)rp->ra);
+ (void) free((FREE_P *)rp);
+ }
+ Rawsin[h] = (struct rawsin *)NULL;
+ }
+ } else {
+ Rawsin = (struct rawsin **)calloc(INOBUCKS,
+ sizeof(struct rawsin *));
+ if (!Rawsin) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d raw hash pointer bytes\n",
+ Pn, (int)(INOBUCKS * sizeof(struct rawsin *)));
+ Exit(1);
+ }
+ }
+/*
+ * Open the /proc/net/raw file, assign a page size buffer to its stream,
+ * and read the file. Store raw socket info in the Rawsin[] hash buckets.
+ */
+ if (!(xs = open_proc_stream(p, "r", &vbuf, &vsz, 0)))
+ return;
+ while (fgets(buf, sizeof(buf) - 1, xs)) {
+ if (get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0) < nf)
+ continue;
+ if (nf == 12) {
+
+ /*
+ * Check the column labels in the first line.
+ */
+ if (!fp[1] || strcmp(fp[1], "local_address")
+ || !fp[2] || strcmp(fp[2], "rem_address")
+ || !fp[3] || strcmp(fp[3], "st")
+ || !fp[11] || strcmp(fp[11], "inode"))
+ {
+ if (!Fwarn) {
+ (void) fprintf(stderr,
+ "%s: WARNING: unsupported format: %s\n",
+ Pn, p);
+ }
+ break;
+ }
+ nf = 10;
+ continue;
+ }
+ /*
+ * Assemble the inode number and see if the inode is already
+ * recorded.
+ */
+ ep = (char *)NULL;
+ if (!fp[9] || !*fp[9]
+ || (inode = strtoull(fp[9], &ep, 0)) == ULONG_MAX
+ || !ep || *ep)
+ continue;
+ h = INOHASH(inode);
+ for (rp = Rawsin[h]; rp; rp = rp->next) {
+ if (inode == rp->inode)
+ break;
+ }
+ if (rp)
+ continue;
+ /*
+ * Save the local address, remote address, and state.
+ */
+ if (!fp[1] || !*fp[1] || (lal = strlen(fp[1])) < 1) {
+ la = (char *)NULL;
+ lal = (MALLOC_S)0;
+ } else {
+ if (!(la = (char *)malloc(lal + 1))) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d local raw address bytes: %s\n",
+ Pn, (int)(lal + 1), fp[1]);
+ Exit(1);
+ }
+ (void) snpf(la, lal + 1, "%s", fp[1]);
+ }
+ if (!fp[2] || !*fp[2] || (ral = strlen(fp[2])) < 1) {
+ ra = (char *)NULL;
+ ral = (MALLOC_S)0;
+ } else {
+ if (!(ra = (char *)malloc(ral + 1))) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d remote raw address bytes: %s\n",
+ Pn, (int)(ral + 1), fp[2]);
+ Exit(1);
+ }
+ (void) snpf(ra, ral + 1, "%s", fp[2]);
+ }
+ if (!fp[3] || !*fp[3] || (spl = strlen(fp[3])) < 1) {
+ sp = (char *)NULL;
+ spl = (MALLOC_S)0;
+ } else {
+ if (!(sp = (char *)malloc(spl + 1))) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d remote raw state bytes: %s\n",
+ Pn, (int)(spl + 1), fp[2]);
+ Exit(1);
+ }
+ (void) snpf(sp, spl + 1, "%s", fp[3]);
+ }
+ /*
+ * Allocate space for an rawsin entry, fill it, and link it to its
+ * hash bucket.
+ */
+ if (!(rp = (struct rawsin *)malloc(sizeof(struct rawsin)))) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d byte rawsin structure\n",
+ Pn, (int)sizeof(struct rawsin));
+ Exit(1);
+ }
+ rp->inode = inode;
+ rp->la = la;
+ rp->lal = lal;
+ rp->ra = ra;
+ rp->ral = ral;
+ rp->sp = sp;
+ rp->spl = spl;
+ rp->next = Rawsin[h];
+ Rawsin[h] = rp;
+ }
+ (void) fclose(xs);
+}
+
+
+/*
+ * get_sctp() - get /proc/net/sctp/assocs info
+ */
+
+static void
+get_sctp()
+{
+ char buf[MAXPATHLEN], *a, *ep, **fp, *id, *la, *lp, *ra, *rp, *ta;
+ int d, err, fl, h, i, j, nf, ty, x;
+ INODETYPE inode;
+ MALLOC_S len, plen;
+ struct sctpsin *sp, *np;
+ FILE *ss;
+ static char *vbuf = (char *)NULL;
+ static size_t vsz = (size_t)0;
+/*
+ * Do second time cleanup or first time setup.
+ */
+ if (SCTPsin) {
+ for (h = 0; h < INOBUCKS; h++) {
+ for (sp = SCTPsin[h]; sp; sp = np) {
+ np = sp->next;
+ if (sp->addr)
+ (void) free((FREE_P *)sp->addr);
+ if (sp->assocID)
+ (void) free((FREE_P *)sp->assocID);
+ if (sp->lport)
+ (void) free((FREE_P *)sp->lport);
+ if (sp->rport)
+ (void) free((FREE_P *)sp->rport);
+ if (sp->laddrs)
+ (void) free((FREE_P *)sp->laddrs);
+ if (sp->raddrs)
+ (void) free((FREE_P *)sp->raddrs);
+ (void) free((FREE_P *)sp);
+ }
+ SCTPsin[h] = (struct sctpsin *)NULL;
+ }
+ } else {
+ SCTPsin = (struct sctpsin **)calloc(INOBUCKS,
+ sizeof(struct sctpsin *));
+ if (!SCTPsin) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d SCTP hash pointer bytes\n",
+ Pn, (int)(INOBUCKS * sizeof(struct sctpsin *)));
+ Exit(1);
+ }
+ }
+/*
+ * Open the /proc/net/sctp files, assign a page size buffer to the streams,
+ * and read them. Store SCTP socket info in the SCTPsin[] hash buckets.
+ */
+ for (i = 0; i < NSCTPPATHS; i++ ) {
+ if (!(ss = open_proc_stream(SCTPPath[i], "r", &vbuf, &vsz, 0)))
+ continue;
+ fl = 1;
+ while (fgets(buf, sizeof(buf) - 1, ss)) {
+ if ((nf = get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0))
+ < (i ? 9 : 16)
+ ) {
+ continue;
+ }
+ if (fl) {
+
+ /*
+ * Check the column labels in the first line.
+ */
+ err = 0;
+ switch (i) {
+ case 0:
+ if (!fp[0] || strcmp(fp[0], "ASSOC")
+ || !fp[6] || strcmp(fp[6], "ASSOC-ID")
+ || !fp[10] || strcmp(fp[10], "INODE")
+ || !fp[11] || strcmp(fp[11], "LPORT")
+ || !fp[12] || strcmp(fp[12], "RPORT")
+ || !fp[13] || strcmp(fp[13], "LADDRS")
+ || !fp[14] || strcmp(fp[14], "<->")
+ || !fp[15] || strcmp(fp[15], "RADDRS")
+ ) {
+ err = 1;
+ }
+ break;
+ case 1:
+ if (!fp[0] || strcmp(fp[0], "ENDPT")
+ || !fp[5] || strcmp(fp[5], "LPORT")
+ || !fp[7] || strcmp(fp[7], "INODE")
+ || !fp[8] || strcmp(fp[8], "LADDRS")
+ ) {
+ err = 1;
+ }
+ }
+ if (err) {
+ if (!Fwarn)
+ (void) fprintf(stderr,
+ "%s: WARNING: unsupported format: %s\n",
+ Pn, SCTPPath[i]);
+ break;
+ }
+ fl = 0;
+ continue;
+ }
+ /*
+ * Assemble the inode number and see if it has already been
+ * recorded.
+ */
+ ep = (char *)NULL;
+ j = i ? 7 : 10;
+ if (!fp[j] || !*fp[j]
+ || (inode = strtoull(fp[j], &ep, 0)) == ULONG_MAX
+ || !ep || *ep)
+ continue;
+ h = INOHASH((INODETYPE)inode);
+ for (sp = SCTPsin[h]; sp; sp = sp->next) {
+ if (inode == sp->inode)
+ break;
+ }
+ /*
+ * Set the entry type.
+ */
+ if (sp)
+ ty = (sp->type == i) ? i : 3;
+ else
+ ty = i;
+ /*
+ * Allocate space for this line's sctpsin members.
+ *
+ * The association or endpoint address is in the first field.
+ */
+ a = sp ? sp->addr : (char *)NULL;
+ if (fp[0] && *fp[0] && (len = strlen(fp[0]))) {
+ if (a) {
+ if (isainb(fp[0], a)) {
+ plen = strlen(a);
+ a = (char *)realloc((MALLOC_P *)a, plen + len + 2);
+ d = 0;
+ } else
+ d = 1;
+ } else {
+ plen = (MALLOC_S)0;
+ a = (char *)malloc(len + 1);
+ d = 0;
+ }
+ if (!a) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d SCTP ASSOC bytes: %s\n",
+ Pn, (int)(len + 1), fp[0]);
+ Exit(1);
+ }
+ if (!d) {
+ if (plen)
+ (void) snpf((a + plen), len + 2, ",%s", fp[0]);
+ else
+ (void) snpf(a, len + 1, "%s", fp[0]);
+ }
+ }
+ /*
+ * The association ID is in the seventh field.
+ */
+ id = sp ? sp->assocID : (char *)NULL;
+ if (!i && fp[6] && *fp[6] && (len = strlen(fp[6]))) {
+ if (id) {
+ if (isainb(fp[6], id)) {
+ plen = strlen(id);
+ id = (char *)realloc((MALLOC_P *)id,plen+len+2);
+ d = 0;
+ } else
+ d = 1;
+ } else {
+ plen = (MALLOC_S)0;
+ id = (char *)malloc(len + 1);
+ d = 0;
+ }
+ if (!id) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d SCTP ASSOC-ID bytes: %s\n",
+ Pn, (int)(len + 1), fp[6]);
+ Exit(1);
+ }
+ if (!d) {
+ if (plen)
+ (void) snpf((id + plen), len + 2, ",%s", fp[6]);
+ else
+ (void) snpf(id, len + 1, "%s", fp[6]);
+ }
+ }
+ /*
+ * The field number for the local port depends on the entry type.
+ */
+ j = i ? 5 : 11;
+ lp = sp ? sp->lport : (char *)NULL;
+ if (fp[j] && *fp[j] && (len = strlen(fp[j]))) {
+ if (lp) {
+ if (isainb(fp[j], lp)) {
+ plen = strlen(lp);
+ lp = (char *)realloc((MALLOC_P *)lp,plen+len+2);
+ d = 0;
+ } else
+ d = 1;
+ } else {
+ plen = (MALLOC_S)0;
+ lp = (char *)malloc(len + 1);
+ d = 0;
+ }
+ if (!lp) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d SCTP LPORT bytes: %s\n",
+ Pn, (int)(len + 1), fp[j]);
+ Exit(1);
+ }
+ if (!d) {
+ if (plen)
+ (void) snpf((lp + plen), len + 2, ",%s", fp[j]);
+ else
+ (void) snpf(lp, len + 1, "%s", fp[j]);
+ }
+ }
+ /*
+ * The field number for the remote port depends on the entry type.
+ */
+ rp = sp ? sp->rport : (char *)NULL;
+ if (!i && fp[12] && *fp[12] && (len = strlen(fp[12]))) {
+ if (rp) {
+ if (isainb(fp[12], rp)) {
+ plen = strlen(rp);
+ rp = (char *)realloc((MALLOC_P *)rp,plen+len+2);
+ d = 0;
+ } else
+ d = 1;
+ } else {
+ plen = (MALLOC_S)0;
+ rp = (char *)malloc(len + 1);
+ d = 0;
+ }
+ if (!rp) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d SCTP RPORT bytes: %s\n",
+ Pn, (int)(len + 1), fp[12]);
+ Exit(1);
+ }
+ if (!d) {
+ if (plen)
+ (void) snpf((rp + plen), len + 2, ",%s", fp[12]);
+ else
+ (void) snpf(rp, len + 1, "%s", fp[12]);
+ }
+ }
+ /*
+ * The local addresses begin in a field whose number depends on
+ * the entry type.
+ */
+ j = i ? 8 : 13;
+ la = sp ? sp->laddrs : (char *)NULL;
+ if (fp[j] && *fp[j] && (len = strlen(fp[j]))) {
+ if (!(ta = get_sctpaddrs(fp, j, nf, &x))) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d SCTP LADDRS bytes\n",
+ Pn, (int)len);
+ Exit(1);
+ }
+ if (la) {
+ if (isainb(ta, la)) {
+ len = strlen(ta);
+ plen = strlen(la);
+ if (!(la=(char *)realloc((MALLOC_P *)la,plen+len+2))
+ ) {
+ (void) fprintf(stderr,
+ "%s: can't reallocate %d SCTP LADDRS bytes\n",
+ Pn, (int)len);
+ Exit(1);
+ }
+ (void) snpf(la + plen, len + 2, ",%s", ta);
+ (void) free((FREE_P *)ta);
+ }
+ } else
+ la = ta;
+ }
+ /*
+ * The remote addresses begin after the local addresses, but only
+ * for the ASSOC type.
+ */
+ ra = sp ? sp->raddrs : (char *)NULL;
+ if (!i && x && fp[x+1] && *fp[x+1] && (len = strlen(fp[x+1]))) {
+ if (!(ta = get_sctpaddrs(fp, x + 1, nf, &x))) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d SCTP RADDRS bytes\n",
+ Pn, (int)len);
+ Exit(1);
+ }
+ if (ra) {
+ if (isainb(ta, ra)) {
+ len = strlen(ta);
+ plen = strlen(ra);
+ if (!(ra=(char *)realloc((MALLOC_P *)ra,plen+len+2))
+ ) {
+ (void) fprintf(stderr,
+ "%s: can't reallocate %d SCTP RADDRS bytes\n",
+ Pn, (int)len);
+ Exit(1);
+ }
+ (void) snpf(ra + plen, len + 2, ",%s", ta);
+ (void) free((FREE_P *)ta);
+ }
+ } else
+ ra = ta;
+ }
+ /*
+ * If no matching sctpsin entry was found for this inode, allocate
+ * space for a new sctpsin entry, fill it, and link it to its hash
+ * bucket. Update a matching entry.
+ */
+ if (!sp) {
+ if (!(sp = (struct sctpsin *)malloc(sizeof(struct sctpsin))) ) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d byte sctpsin structure\n",
+ Pn, (int)sizeof(struct sctpsin));
+ Exit(1);
+ }
+ sp->inode = inode;
+ sp->next = SCTPsin[h];
+ SCTPsin[h] = sp;
+ }
+ sp->addr = a;
+ sp->assocID = id;
+ sp->lport = lp;
+ sp->rport = rp;
+ sp->laddrs = la;
+ sp->raddrs = ra;
+ sp->type = ty;
+ }
+ (void) fclose(ss);
+ }
+}
+
+
+static char *
+get_sctpaddrs(fp, i, nf, x)
+ char **fp; /* field pointers */
+ int i; /* first address field index in fp */
+ int nf; /* number of fields */
+ int *x; /* index of first "<->" field entry */
+{
+ MALLOC_S al = (MALLOC_S)0;
+ char *cp = (char *)NULL;
+ MALLOC_S tl;
+
+ *x = 0;
+ do {
+ if ((i >= nf) || !fp[i] || !*fp[i] || !(tl = strlen(fp[i])))
+ break;
+ if (!strcmp(fp[i], "<->")) {
+ *x = i;
+ break;
+ }
+ if (!strchr(fp[i], (int)'.') && !strchr(fp[i], (int)':'))
+ break;
+ if (cp)
+ cp = (char *)realloc((MALLOC_P *)cp, al + tl + 1);
+ else
+ cp = (char *)malloc(al + tl + 1);
+ if (!cp)
+ break;
+ if (al)
+ *(cp + al - 1) = ',';
+ (void) strncpy(al ? (cp + al) : cp, fp[i], tl);
+ al += (tl + 1);
+ *(cp + al - 1) = '\0';
+ } while (++i < nf);
+ return(cp);
+}
+
+
+/*
+ * get_tcpudp() - get IPv4 TCP, UDP or UDPLITE net info
+ */
+
+static void
+get_tcpudp(p, pr, clr)
+ char *p; /* /proc/net/{tcp,udp} path */
+ int pr; /* protocol: 0 = TCP, 1 = UDP,
+ * 2 = UDPLITE */
+ int clr; /* 1 == clear the table */
+{
+ char buf[MAXPATHLEN], *ep, **fp;
+ unsigned long faddr, fport, laddr, lport, rxq, state, txq;
+ FILE *fs;
+ int h, nf;
+ INODETYPE inode;
+ struct tcp_udp *np, *tp;
+ static char *vbuf = (char *)NULL;
+ static size_t vsz = (size_t)0;
+/*
+ * Delete previous table contents.
+ */
+ if (TcpUdp) {
+ if (clr) {
+ for (h = 0; h < TcpUdp_bucks; h++) {
+ for (tp = TcpUdp[h]; tp; tp = np) {
+ np = tp->next;
+ (void) free((FREE_P *)tp);
+ }
+ TcpUdp[h] = (struct tcp_udp *)NULL;
+ }
+ }
+/*
+ * If no hash buckets have been allocated, do so now.
+ */
+ } else {
+
+ /*
+ * Open the /proc/net/sockstat file and establish the hash bucket
+ * count from its "sockets: used" line.
+ */
+ TcpUdp_bucks = INOBUCKS;
+ if ((fs = fopen(SockStatPath, "r"))) {
+ while(fgets(buf, sizeof(buf) - 1, fs)) {
+ if (get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0) != 3)
+ continue;
+ if (!fp[0] || strcmp(fp[0], "sockets:")
+ || !fp[1] || strcmp(fp[1], "used")
+ || !fp[2] || !*fp[2])
+ continue;
+ if ((h = atoi(fp[2])) < 1)
+ h = INOBUCKS;
+ while (TcpUdp_bucks < h)
+ TcpUdp_bucks *= 2;
+ break;
+ }
+ (void) fclose(fs);
+ }
+ if (!(TcpUdp = (struct tcp_udp **)calloc(TcpUdp_bucks,
+ sizeof(struct tcp_udp *))))
+ {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d bytes for TCP&UDP hash buckets\n",
+ Pn, (int)(TcpUdp_bucks * sizeof(struct tcp_udp *)));
+ Exit(1);
+ }
+ }
+/*
+ * Open the /proc/net file, assign a page size buffer to the stream, and
+ * read it.
+ */
+ if (!(fs = open_proc_stream(p, "r", &vbuf, &vsz, 0)))
+ return;
+ nf = 12;
+ while(fgets(buf, sizeof(buf) - 1, fs)) {
+ if (get_fields(buf,
+ (nf == 12) ? (char *)NULL : ":",
+ &fp, (int *)NULL, 0)
+ < nf)
+ continue;
+ if (nf == 12) {
+ if (!fp[1] || strcmp(fp[1], "local_address")
+ || !fp[2] || strcmp(fp[2], "rem_address")
+ || !fp[3] || strcmp(fp[3], "st")
+ || !fp[4] || strcmp(fp[4], "tx_queue")
+ || !fp[5] || strcmp(fp[5], "rx_queue")
+ || !fp[11] || strcmp(fp[11], "inode"))
+ {
+ if (!Fwarn) {
+ (void) fprintf(stderr,
+ "%s: WARNING: unsupported format: %s\n",
+ Pn, p);
+ }
+ break;
+ }
+ nf = 14;
+ continue;
+ }
+ /*
+ * Get the local and remote addresses.
+ */
+ ep = (char *)NULL;
+ if (!fp[1] || !*fp[1]
+ || (laddr = strtoul(fp[1], &ep, 16)) == ULONG_MAX || !ep || *ep)
+ continue;
+ ep = (char *)NULL;
+ if (!fp[2] || !*fp[2]
+ || (lport = strtoul(fp[2], &ep, 16)) == ULONG_MAX || !ep || *ep)
+ continue;
+ ep = (char *)NULL;
+ if (!fp[3] || !*fp[3]
+ || (faddr = strtoul(fp[3], &ep, 16)) == ULONG_MAX || !ep || *ep)
+ continue;
+ ep = (char *)NULL;
+ if (!fp[4] || !*fp[4]
+ || (fport = strtoul(fp[4], &ep, 16)) == ULONG_MAX || !ep || *ep)
+ continue;
+ /*
+ * Get the state and queue sizes.
+ */
+ ep = (char *)NULL;
+ if (!fp[5] || !*fp[5]
+ || (state = strtoul(fp[5], &ep, 16)) == ULONG_MAX || !ep || *ep)
+ continue;
+ ep = (char *)NULL;
+ if (!fp[6] || !*fp[6]
+ || (txq = strtoul(fp[6], &ep, 16)) == ULONG_MAX || !ep || *ep)
+ continue;
+ ep = (char *)NULL;
+ if (!fp[7] || !*fp[7]
+ || (rxq = strtoul(fp[7], &ep, 16)) == ULONG_MAX || !ep || *ep)
+ continue;
+ /*
+ * Get the inode and use it for hashing and searching.
+ */
+ ep = (char *)NULL;
+ if (!fp[13] || !*fp[13]
+ || (inode = strtoull(fp[13], &ep, 0)) == ULONG_MAX || !ep || *ep)
+ continue;
+ h = TCPUDPHASH(inode);
+ for (tp = TcpUdp[h]; tp; tp = tp->next) {
+ if (tp->inode == inode)
+ break;
+ }
+ if (tp)
+ continue;
+ /*
+ * Create a new entry and link it to its hash bucket.
+ */
+ if (!(tp = (struct tcp_udp *)malloc(sizeof(struct tcp_udp)))) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d bytes for tcp_udp struct\n",
+ Pn, (int)sizeof(struct tcp_udp));
+ Exit(1);
+ }
+ tp->inode = inode;
+ tp->faddr = faddr;
+ tp->fport = (int)(fport & 0xffff);
+ tp->laddr = laddr;
+ tp->lport = (int)(lport & 0xffff);
+ tp->txq = txq;
+ tp->rxq = rxq;
+ tp->proto = pr;
+ tp->state = (int)state;
+ tp->next = TcpUdp[h];
+ TcpUdp[h] = tp;
+ }
+ (void) fclose(fs);
+}
+
+
+#if defined(HASIPv6)
+/*
+ * get_raw6() - get /proc/net/raw6 info
+ */
+
+static void
+get_raw6(p)
+ char *p; /* /proc/net/raw path */
+{
+ char buf[MAXPATHLEN], *ep, **fp, *la, *ra, *sp;
+ int h;
+ INODETYPE inode;
+ int nf = 12;
+ struct rawsin *np, *rp;
+ MALLOC_S lal, ral, spl;
+ static char *vbuf = (char *)NULL;
+ static size_t vsz = (size_t)0;
+ FILE *xs;
+/*
+ * Do second time cleanup or first time setup.
+ */
+ if (Rawsin6) {
+ for (h = 0; h < INOBUCKS; h++) {
+ for (rp = Rawsin6[h]; rp; rp = np) {
+ np = rp->next;
+ if (rp->la)
+ (void) free((FREE_P *)rp->la);
+ if (rp->ra)
+ (void) free((FREE_P *)rp->ra);
+ (void) free((FREE_P *)rp);
+ }
+ Rawsin6[h] = (struct rawsin *)NULL;
+ }
+ } else {
+ Rawsin6 = (struct rawsin **)calloc(INOBUCKS,
+ sizeof(struct rawsin *));
+ if (!Rawsin6) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d raw6 hash pointer bytes\n",
+ Pn, (int)(INOBUCKS * sizeof(struct rawsin *)));
+ Exit(1);
+ }
+ }
+/*
+ * Open the /proc/net/raw6 file, assign a page size buffer to the stream,
+ * and read it. Store raw6 socket info in the Rawsin6[] hash buckets.
+ */
+ if (!(xs = open_proc_stream(p, "r", &vbuf, &vsz, 0)))
+ return;
+ while (fgets(buf, sizeof(buf) - 1, xs)) {
+ if (get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0) < nf)
+ continue;
+ if (nf == 12) {
+
+ /*
+ * Check the column labels in the first line.
+ */
+ if (!fp[1] || strcmp(fp[1], "local_address")
+ || !fp[2] || strcmp(fp[2], "remote_address")
+ || !fp[3] || strcmp(fp[3], "st")
+ || !fp[11] || strcmp(fp[11], "inode"))
+ {
+ if (!Fwarn) {
+ (void) fprintf(stderr,
+ "%s: WARNING: unsupported format: %s\n",
+ Pn, p);
+ }
+ break;
+ }
+ nf = 10;
+ continue;
+ }
+ /*
+ * Assemble the inode number and see if the inode is already
+ * recorded.
+ */
+ ep = (char *)NULL;
+ if (!fp[9] || !*fp[9]
+ || (inode = strtoull(fp[9], &ep, 0)) == ULONG_MAX
+ || !ep || *ep)
+ continue;
+ h = INOHASH(inode);
+ for (rp = Rawsin6[h]; rp; rp = rp->next) {
+ if (inode == rp->inode)
+ break;
+ }
+ if (rp)
+ continue;
+ /*
+ * Save the local address, remote address, and state.
+ */
+ if (!fp[1] || !*fp[1] || (lal = strlen(fp[1])) < 1) {
+ la = (char *)NULL;
+ lal = (MALLOC_S)0;
+ } else {
+ if (!(la = (char *)malloc(lal + 1))) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d local raw6 address bytes: %s\n",
+ Pn, (int)(lal + 1), fp[1]);
+ Exit(1);
+ }
+ (void) snpf(la, lal + 1, "%s", fp[1]);
+ }
+ if (!fp[2] || !*fp[2] || (ral = strlen(fp[2])) < 1) {
+ ra = (char *)NULL;
+ ral = (MALLOC_S)0;
+ } else {
+ if (!(ra = (char *)malloc(ral + 1))) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d remote raw6 address bytes: %s\n",
+ Pn, (int)(ral + 1), fp[2]);
+ Exit(1);
+ }
+ (void) snpf(ra, ral + 1, "%s", fp[2]);
+ }
+ if (!fp[3] || !*fp[3] || (spl = strlen(fp[3])) < 1) {
+ sp = (char *)NULL;
+ spl = (MALLOC_S)0;
+ } else {
+ if (!(sp = (char *)malloc(spl + 1))) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d remote raw6 state bytes: %s\n",
+ Pn, (int)(spl + 1), fp[2]);
+ Exit(1);
+ }
+ (void) snpf(sp, spl + 1, "%s", fp[3]);
+ }
+ /*
+ * Allocate space for an rawsin entry, fill it, and link it to its
+ * hash bucket.
+ */
+ if (!(rp = (struct rawsin *)malloc(sizeof(struct rawsin)))) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d byte rawsin structure for IPv6\n",
+ Pn, (int)sizeof(struct rawsin));
+ Exit(1);
+ }
+ rp->inode = inode;
+ rp->la = la;
+ rp->lal = lal;
+ rp->ra = ra;
+ rp->ral = ral;
+ rp->sp = sp;
+ rp->spl = spl;
+ rp->next = Rawsin6[h];
+ Rawsin6[h] = rp;
+ }
+ (void) fclose(xs);
+}
+
+
+/*
+ * get_tcpudp6() - get IPv6 TCP, UDP or UDPLITE net info
+ */
+
+static void
+get_tcpudp6(p, pr, clr)
+ char *p; /* /proc/net/{tcp,udp} path */
+ int pr; /* protocol: 0 = TCP, 1 = UDP */
+ int clr; /* 1 == clear the table */
+{
+ char buf[MAXPATHLEN], *ep, **fp;
+ struct in6_addr faddr, laddr;
+ unsigned long fport, lport, rxq, state, txq;
+ FILE *fs;
+ int h, i, nf;
+ INODETYPE inode;
+ struct tcp_udp6 *np6, *tp6;
+ static char *vbuf = (char *)NULL;
+ static size_t vsz = (size_t)0;
+/*
+ * Delete previous table contents. Allocate a table for the first time.
+ */
+ if (TcpUdp6) {
+ if (clr) {
+ for (h = 0; h < TcpUdp6_bucks; h++) {
+ for (tp6 = TcpUdp6[h]; tp6; tp6 = np6) {
+ np6 = tp6->next;
+ (void) free((FREE_P *)tp6);
+ }
+ TcpUdp6[h] = (struct tcp_udp6 *)NULL;
+ }
+ }
+ } else {
+
+ /*
+ * Open the /proc/net/sockstat6 file and establish the hash bucket
+ * count from its "TCP6: inuse" and "UDP6: inuse" lines.
+ */
+ TcpUdp6_bucks = INOBUCKS;
+ h = i = nf = 0;
+ if ((fs = fopen(SockStatPath6, "r"))) {
+ while(fgets(buf, sizeof(buf) - 1, fs)) {
+ if (get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0) != 3)
+ continue;
+ if (!fp[0]
+ || !fp[1] || strcmp(fp[1], "inuse")
+ || !fp[2] || !*fp[2])
+ continue;
+ if (!strcmp(fp[0], "TCP6:")) {
+ nf |= 1;
+ if ((h = atoi(fp[2])) < 1)
+ h = INOBUCKS;
+ i += h;
+ } else if (!strcmp(fp[0], "UDP6:")) {
+ nf |= 2;
+ if ((h = atoi(fp[2])) < 1)
+ h = INOBUCKS;
+ i += h;
+ } else
+ continue;
+ if (nf == 3) {
+ while (TcpUdp6_bucks < i)
+ TcpUdp6_bucks *= 2;
+ break;
+ }
+ }
+ (void) fclose(fs);
+ }
+ if (!(TcpUdp6 = (struct tcp_udp6 **)calloc(TcpUdp6_bucks,
+ sizeof(struct tcp_udp6 *))))
+ {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d bytes for TCP6&UDP6 hash buckets\n",
+ Pn, (int)(TcpUdp6_bucks * sizeof(struct tcp_udp6 *)));
+ Exit(1);
+ }
+ }
+/*
+ * Open the /proc/net file, assign a page size buffer to the stream,
+ * and read it.
+ */
+ if (!(fs = open_proc_stream(p, "r", &vbuf, &vsz, 0)))
+ return;
+ nf = 12;
+ while(fgets(buf, sizeof(buf) - 1, fs)) {
+ if (get_fields(buf,
+ (nf == 12) ? (char *)NULL : ":",
+ &fp, (int *)NULL, 0)
+ < nf)
+ continue;
+ if (nf == 12) {
+ if (!fp[1] || strcmp(fp[1], "local_address")
+ || !fp[2] || strcmp(fp[2], "remote_address")
+ || !fp[3] || strcmp(fp[3], "st")
+ || !fp[4] || strcmp(fp[4], "tx_queue")
+ || !fp[5] || strcmp(fp[5], "rx_queue")
+ || !fp[11] || strcmp(fp[11], "inode"))
+ {
+ if (!Fwarn) {
+ (void) fprintf(stderr,
+ "%s: WARNING: unsupported format: %s\n",
+ Pn, p);
+ }
+ break;
+ }
+ nf = 14;
+ continue;
+ }
+ /*
+ * Get the local and remote addresses.
+ */
+ if (!fp[1] || !*fp[1] || net6a2in6(fp[1], &laddr))
+ continue;
+ ep = (char *)NULL;
+ if (!fp[2] || !*fp[2]
+ || (lport = strtoul(fp[2], &ep, 16)) == ULONG_MAX || !ep || *ep)
+ continue;
+ if (!fp[3] || !*fp[3] || net6a2in6(fp[3], &faddr))
+ continue;
+ ep = (char *)NULL;
+ if (!fp[4] || !*fp[4]
+ || (fport = strtoul(fp[4], &ep, 16)) == ULONG_MAX || !ep || *ep)
+ continue;
+ /*
+ * Get the state and queue sizes.
+ */
+ ep = (char *)NULL;
+ if (!fp[5] || !*fp[5]
+ || (state = strtoul(fp[5], &ep, 16)) == ULONG_MAX || !ep || *ep)
+ continue;
+ ep = (char *)NULL;
+ if (!fp[6] || !*fp[6]
+ || (txq = strtoul(fp[6], &ep, 16)) == ULONG_MAX || !ep || *ep)
+ continue;
+ ep = (char *)NULL;
+ if (!fp[7] || !*fp[7]
+ || (rxq = strtoul(fp[7], &ep, 16)) == ULONG_MAX || !ep || *ep)
+ continue;
+ /*
+ * Get the inode and use it for hashing and searching.
+ */
+ ep = (char *)NULL;
+ if (!fp[13] || !*fp[13]
+ || (inode = strtoull(fp[13], &ep, 0)) == ULONG_MAX || !ep || *ep)
+ continue;
+ h = TCPUDP6HASH(inode);
+ for (tp6 = TcpUdp6[h]; tp6; tp6 = tp6->next) {
+ if (tp6->inode == inode)
+ break;
+ }
+ if (tp6)
+ continue;
+ /*
+ * Create a new entry and link it to its hash bucket.
+ */
+ if (!(tp6 = (struct tcp_udp6 *)malloc(sizeof(struct tcp_udp6)))) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d bytes for tcp_udp6 struct\n",
+ Pn, (int)sizeof(struct tcp_udp6));
+ Exit(1);
+ }
+ tp6->inode = inode;
+ tp6->faddr = faddr;
+ tp6->fport = (int)(fport & 0xffff);
+ tp6->laddr = laddr;
+ tp6->lport = (int)(lport & 0xffff);
+ tp6->txq = txq;
+ tp6->rxq = rxq;
+ tp6->proto = pr;
+ tp6->state = (int)state;
+ tp6->next = TcpUdp6[h];
+ TcpUdp6[h] = tp6;
+ }
+ (void) fclose(fs);
+}
+#endif /* defined(HASIPv6) */
+
+
+/*
+ * get_unix() - get UNIX net info
+ */
+
+static void
+get_unix(p)
+ char *p; /* /proc/net/unix path */
+{
+ char buf[MAXPATHLEN], *ep, **fp, *path, *pcb;
+ int fl = 1;
+ int h, nf;
+ INODETYPE inode;
+ MALLOC_S len;
+ struct uxsin *np, *up;
+ FILE *us;
+ static char *vbuf = (char *)NULL;
+ static size_t vsz = (size_t)0;
+/*
+ * Do second time cleanup or first time setup.
+ */
+ if (Uxsin) {
+ for (h = 0; h < INOBUCKS; h++) {
+ for (up = Uxsin[h]; up; up = np) {
+ np = up->next;
+ if (up->path)
+ (void) free((FREE_P *)up->path);
+ if (up->pcb)
+ (void) free((FREE_P *)up->pcb);
+ (void) free((FREE_P *)up);
+ }
+ Uxsin[h] = (struct uxsin *)NULL;
+ }
+ } else {
+ Uxsin = (struct uxsin **)calloc(INOBUCKS, sizeof(struct uxsin *));
+ if (!Uxsin) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d bytes for Unix socket info\n",
+ Pn, (int)(INOBUCKS * sizeof(struct uxsin *)));
+ }
+ }
+/*
+ * Open the /proc/net/unix file, assign a page size buffer to the stream,
+ * read the file's contents, and add them to the Uxsin hash buckets.
+ */
+ if (!(us = open_proc_stream(p, "r", &vbuf, &vsz, 0)))
+ return;
+ while (fgets(buf, sizeof(buf) - 1, us)) {
+ if ((nf = get_fields(buf, ":", &fp, (int *)NULL, 0)) < 7)
+ continue;
+ if (fl) {
+
+ /*
+ * Check the first line for header words.
+ */
+ if (!fp[0] || strcmp(fp[0], "Num")
+ || !fp[1] || strcmp(fp[1], "RefCount")
+ || !fp[2] || strcmp(fp[2], "Protocol")
+ || !fp[3] || strcmp(fp[3], "Flags")
+ || !fp[4] || strcmp(fp[4], "Type")
+ || !fp[5] || strcmp(fp[5], "St")
+ || !fp[6] || strcmp(fp[6], "Inode")
+ || nf < 8
+ || !fp[7] || strcmp(fp[7], "Path"))
+ {
+ if (!Fwarn) {
+ (void) fprintf(stderr,
+ "%s: WARNING: unsupported format: %s\n",
+ Pn, p);
+ }
+ break;
+ }
+ fl = 0;
+ continue;
+ }
+ /*
+ * Assemble PCB address, inode number, and path name. If this
+ * inode is already represented in Uxsin, skip it.
+ */
+ ep = (char *)NULL;
+ if (!fp[6] || !*fp[6]
+ || (inode = strtoull(fp[6], &ep, 0)) == ULONG_MAX || !ep || *ep)
+ continue;
+ h = INOHASH(inode);
+ for (up = Uxsin[h]; up; up = up->next) {
+ if (inode == up->inode)
+ break;
+ }
+ if (up)
+ continue;
+ if (!fp[0] || !*fp[0])
+ pcb = (char *)NULL;
+ else {
+ len = strlen(fp[0]) + 2;
+ if (!(pcb = (char *)malloc(len + 1))) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d bytes for UNIX PCB: %s\n",
+ Pn, (int)(len + 1), fp[0]);
+ Exit(1);
+ }
+ (void) snpf(pcb, len + 1, "0x%s", fp[0]);
+ }
+ if (nf >= 8 && fp[7] && *fp[7] && (len = strlen(fp[7]))) {
+ if (!(path = (char *)malloc(len + 1))) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d bytes for UNIX path \"%s\"\n",
+ Pn, (int)(len + 1), fp[7]);
+ Exit(1);
+ }
+ (void) snpf(path, len + 1, "%s", fp[7]);
+ } else
+ path = (char *)NULL;
+ /*
+ * Allocate and fill a Unix socket info structure; link it to its
+ * hash bucket.
+ */
+ if (!(up = (struct uxsin *)malloc(sizeof(struct uxsin)))) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d bytes for uxsin struct\n",
+ Pn, (int)sizeof(struct uxsin));
+ Exit(1);
+ }
+ up->inode = inode;
+ up->pcb = pcb;
+ up->sb_def = 0;
+ if ((up->path = path) && (*path == '/')) {
+
+ /*
+ * If an absolute path (i.e., one that begins with a '/') exists
+ * for the line, attempt to stat(2) it and save the device and
+ * node numbers reported in the stat buffer.
+ */
+ struct stat sb;
+ int sr;
+
+ if (HasNFS)
+ sr = statsafely(path, &sb);
+ else
+ sr = stat(path, &sb);
+ if (sr && ((sb.st_mode & S_IFMT) == S_IFSOCK)) {
+ up->sb_def = 1;
+ up->sb_dev = sb.st_dev;
+ up->sb_ino = (INODETYPE)sb.st_ino;
+ up->sb_rdev = sb.st_rdev;
+ }
+ }
+ up->next = Uxsin[h];
+ Uxsin[h] = up;
+ }
+ (void) fclose(us);
+}
+
+
+#if defined(HASIPv6)
+/*
+ * net6a2in6() - convert ASCII IPv6 address in /proc/net/{tcp,udp} form to
+ * an in6_addr
+ */
+
+static int
+net6a2in6(as, ad)
+ char *as; /* address source */
+ struct in6_addr *ad; /* address destination */
+{
+ char buf[9], *ep;
+ int i;
+ size_t len;
+/*
+ * Assemble four uint32_t's from 4 X 8 hex digits into s6_addr32[].
+ */
+ for (i = 0, len = strlen(as);
+ (i < 4) && (len >= 8);
+ as += 8, i++, len -= 8)
+ {
+ (void) strncpy(buf, as, 8);
+ buf[8] = '\0';
+ ep = (char *)NULL;
+ if ((ad->s6_addr32[i] = (uint32_t)strtoul(buf, &ep, 16))
+ == (uint32_t)UINT32_MAX || !ep || *ep)
+ break;
+ }
+ return((*as || (i != 4) || len) ? 1 : 0);
+}
+#endif /* defined(HASIPv6) */
+
+
+/*
+ * isainb(a,b) is string a in string b
+ */
+
+static int
+isainb(a, b)
+ char *a; /*string a */
+ char *b; /* string b */
+{
+ char *cp, *pp;
+ MALLOC_S la, lb, lt;
+
+ if (!a || !b)
+ return(1);
+ if (!(la = strlen(a)) || !(lb = strlen(b)))
+ return(1);
+ if (!(cp = strchr(b, (int)','))) {
+ if (la != lb)
+ return(1);
+ return(strcmp(a, b));
+ }
+ for (pp = b; pp && *pp; ) {
+ lt = (MALLOC_S)(cp - pp);
+ if ((la == lt) && !strncmp(a, pp, lt))
+ return(0);
+ if (*cp) {
+ pp = cp + 1;
+ if (!(cp = strchr(pp, (int)',')))
+ cp = b + lb;
+ } else
+ pp = cp;
+ }
+ return(1);
+}
+
+
+/*
+ * print_ax25info() - print AX25 socket info
+ */
+
+static void
+print_ax25info(ap)
+ struct ax25sin *ap; /* AX25 socket info */
+{
+ char *cp, pbuf[1024];
+ int ds;
+ MALLOC_S pl = (MALLOC_S)0;
+
+ if (Lf->nma)
+ return;
+ if (ap->sa) {
+ ds = (ap->da && strcmp(ap->da, "*")) ? 1 : 0;
+ (void) snpf(&pbuf[pl], sizeof(pbuf) - pl, "%s%s%s ", ap->sa,
+ ds ? "->" : "",
+ ds ? ap->da : "");
+ pl = strlen(pbuf);
+ }
+ if (ap->sqs) {
+ (void) snpf(&pbuf[pl], sizeof(pbuf) - pl, "(Sq=%lu ", ap->sq);
+ pl = strlen(pbuf);
+ cp = "";
+ } else
+ cp = "(";
+ if (ap->rqs) {
+ (void) snpf(&pbuf[pl], sizeof(pbuf) - pl, "%sRq=%lu ", cp, ap->rq);
+ pl = strlen(pbuf);
+ cp = "";
+ }
+ (void) snpf(&pbuf[pl], sizeof(pbuf) - pl, "%sState=%d", cp, ap->state);
+ pl = strlen(pbuf);
+ if ((ap->state >= 0) && (ap->state < NAX25ST))
+ cp = ax25st[ap->state];
+ else
+ cp = NULL;
+ (void) snpf(&pbuf[pl], sizeof(pbuf) - pl, "%s%s)",
+ cp ? ", " : "",
+ cp ? cp : "");
+ pl = strlen(pbuf);
+ if (!(cp = (char *)malloc(pl + 1))) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d bytes for AX25 sock state, PID: %d\n",
+ Pn, (int)(pl + 1), Lp->pid);
+ Exit(1);
+ }
+ (void) snpf(cp, pl + 1, "%s", pbuf);
+ Lf->nma = cp;
+}
+
+
+/*
+ * print_ipxinfo() - print IPX socket info
+ */
+
+static void
+print_ipxinfo(ip)
+ struct ipxsin *ip; /* IPX socket info */
+{
+ char *cp, pbuf[256];
+ MALLOC_S pl;
+
+ if (Lf->nma)
+ return;
+ (void) snpf(pbuf, sizeof(pbuf), "(Tx=%lx Rx=%lx State=%02x)",
+ ip->txq, ip->rxq, ip->state);
+ pl = strlen(pbuf);
+ if (!(cp = (char *)malloc(pl + 1))) {
+ (void) fprintf(stderr,
+ "%s: can't allocate %d bytes for IPX sock state, PID: %d\n",
+ Pn, (int)(pl + 1), Lp->pid);
+ Exit(1);
+ }
+ (void) snpf(cp, pl + 1, "%s", pbuf);
+ Lf->nma = cp;
+}
+
+
+/*
+ * print_tcptpi() - print TCP/TPI state
+ */
+
+void
+print_tcptpi(nl)
+ int nl; /* 1 == '\n' required */
+{
+ char buf[128];
+ char *cp = (char *)NULL;
+ int ps = 0;
+ int s;
+
+ if ((Ftcptpi & TCPTPI_STATE) && Lf->lts.type == 0) {
+ if (!TcpSt)
+ (void) build_IPstates();
+ if ((s = Lf->lts.state.i + TcpStOff) < 0 || s >= TcpNstates) {
+ (void) snpf(buf, sizeof(buf), "UNKNOWN_TCP_STATE_%d",
+ Lf->lts.state.i);
+ cp = buf;
+ } else
+ cp = TcpSt[s];
+ if (cp) {
+ if (Ffield)
+ (void) printf("%cST=%s%c", LSOF_FID_TCPTPI, cp, Terminator);
+ else {
+ putchar('(');
+ (void) fputs(cp, stdout);
+ }
+ ps++;
+ }
+ }
+
+# if defined(HASTCPTPIQ)
+ if (Ftcptpi & TCPTPI_QUEUES) {
+ if (Lf->lts.rqs) {
+ if (Ffield)
+ putchar(LSOF_FID_TCPTPI);
+ else {
+ if (ps)
+ putchar(' ');
+ else
+ putchar('(');
+ }
+ (void) printf("QR=%lu", Lf->lts.rq);
+ if (Ffield)
+ putchar(Terminator);
+ ps++;
+ }
+ if (Lf->lts.sqs) {
+ if (Ffield)
+ putchar(LSOF_FID_TCPTPI);
+ else {
+ if (ps)
+ putchar(' ');
+ else
+ putchar('(');
+ }
+ (void) printf("QS=%lu", Lf->lts.sq);
+ if (Ffield)
+ putchar(Terminator);
+ ps++;
+ }
+ }
+# endif /* defined(HASTCPTPIQ) */
+
+# if defined(HASTCPTPIW)
+ if (Ftcptpi & TCPTPI_WINDOWS) {
+ if (Lf->lts.rws) {
+ if (Ffield)
+ putchar(LSOF_FID_TCPTPI);
+ else {
+ if (ps)
+ putchar(' ');
+ else
+ putchar('(');
+ }
+ (void) printf("WR=%lu", Lf->lts.rw);
+ if (Ffield)
+ putchar(Terminator);
+ ps++;
+ }
+ if (Lf->lts.wws) {
+ if (Ffield)
+ putchar(LSOF_FID_TCPTPI);
+ else {
+ if (ps)
+ putchar(' ');
+ else
+ putchar('(');
+ }
+ (void) printf("WW=%lu", Lf->lts.ww);
+ if (Ffield)
+ putchar(Terminator);
+ ps++;
+ }
+ }
+# endif /* defined(HASTCPTPIW) */
+
+ if (!Ffield && ps)
+ putchar(')');
+ if (nl)
+ putchar('\n');
+}
+
+
+/*
+ * process_proc_sock() - process /proc-based socket
+ */
+
+void
+process_proc_sock(p, pbr, s, ss, l, lss)
+ char *p; /* node's readlink() path */
+ char *pbr; /* node's path before readlink() */
+ struct stat *s; /* stat() result for path */
+ int ss; /* *s status -- i.e, SB_* values */
+ struct stat *l; /* lstat() result for FD (NULL for
+ * others) */
+ int lss; /* *l status -- i.e, SB_* values */
+{
+ struct ax25sin *ap;
+ char *cp, *path, tbuf[64];
+ unsigned char *fa, *la;
+ struct in_addr fs, ls;
+ struct icmpin *icmpp;
+ struct ipxsin *ip;
+ int i, len, nl;
+ struct nlksin *np;
+ struct packin *pp;
+ char *pr;
+ static char *prp = (char *)NULL;
+ struct rawsin *rp;
+ struct sctpsin *sp;
+ static ssize_t sz;
+ struct tcp_udp *tp;
+ struct uxsin *up;
+
+#if defined(HASIPv6)
+ int af;
+ struct tcp_udp6 *tp6;
+#endif /* defined(HASIPv6) */
+
+/*
+ * Enter offset, if possible.
+ */
+ if (Foffset || !Fsize) {
+ if (l && (lss & SB_SIZE) && OffType) {
+ Lf->off = (SZOFFTYPE)l->st_size;
+ Lf->off_def = 1;
+ }
+ }
+/*
+ * Check for socket's inode presence in the protocol info caches.
+ */
+ if (AX25path) {
+ (void) get_ax25(AX25path);
+ (void) free((FREE_P *)AX25path);
+ AX25path = (char *)NULL;
+ }
+ if ((ss & SB_INO)
+ && (ap = check_ax25((INODETYPE)s->st_ino))
+ ) {
+
+ /*
+ * The inode is connected to an AX25 /proc record.
+ *
+ * Set the type to "ax25"; save the device name; save the inode number;
+ * save the destination and source addresses; save the send and receive
+ * queue sizes; and save the connection state.
+ */
+ (void) snpf(Lf->type, sizeof(Lf->type), "ax25");
+ if (ap->dev_ch)
+ (void) enter_dev_ch(ap->dev_ch);
+ Lf->inode = ap->inode;
+ Lf->inp_ty = 1;
+ print_ax25info(ap);
+ return;
+ }
+ if (Ipxpath) {
+ (void) get_ipx(Ipxpath);
+ (void) free((FREE_P *)Ipxpath);
+ Ipxpath = (char *)NULL;
+ }
+ if ((ss & SB_INO)
+ && (ip = check_ipx((INODETYPE)s->st_ino))
+ ) {
+
+ /*
+ * The inode is connected to an IPX /proc record.
+ *
+ * Set the type to "ipx"; enter the inode and device numbers; store
+ * the addresses, queue sizes, and state in the NAME column.
+ */
+ (void) snpf(Lf->type, sizeof(Lf->type), "ipx");
+ if (ss & SB_INO) {
+ Lf->inode = (INODETYPE)s->st_ino;
+ Lf->inp_ty = 1;
+ }
+ if (ss & SB_DEV) {
+ Lf->dev = s->st_dev;
+ Lf->dev_def = 1;
+ }
+ cp = Namech;
+ nl = Namechl;
+ *cp = '\0';
+ if (ip->la && nl) {
+
+ /*
+ * Store the local IPX address.
+ */
+ len = strlen(ip->la);
+ if (len > nl)
+ len = nl;
+ (void) strncpy(cp, ip->la, len);
+ cp += len;
+ *cp = '\0';
+ nl -= len;
+ }
+ if (ip->ra && nl) {
+
+ /*
+ * Store the remote IPX address, prefixed with "->".
+ */
+ if (nl > 2) {
+ (void) snpf(cp, nl, "->");
+ cp += 2;
+ nl -= 2;
+ }
+ if (nl) {
+ (void) snpf(cp, nl, "%s", ip->ra);
+ cp += len;
+ nl -= len;
+ }
+ }
+ (void) print_ipxinfo(ip);
+ if (Namech[0])
+ enter_nm(Namech);
+ return;
+ }
+ if (Rawpath) {
+ (void) get_raw(Rawpath);
+ (void) free((FREE_P *)Rawpath);
+ Rawpath = (char *)NULL;
+ }
+ if ((ss & SB_INO)
+ && (rp = check_raw((INODETYPE)s->st_ino))
+ ) {
+
+ /*
+ * The inode is connected to a raw /proc record.
+ *
+ * Set the type to "raw"; enter the inode number; store the local
+ * address, remote address, and state in the NAME column.
+ */
+ (void) snpf(Lf->type, sizeof(Lf->type), "raw");
+ if (ss & SB_INO) {
+ Lf->inode = (INODETYPE)s->st_ino;
+ Lf->inp_ty = 1;
+ }
+ cp = Namech;
+ nl = Namechl - 2;
+ *cp = '\0';
+ if (rp->la && rp->lal) {
+
+ /*
+ * Store the local raw address.
+ */
+ if (nl > rp->lal) {
+ (void) snpf(cp, nl, "%s", rp->la);
+ cp += rp->lal;
+ *cp = '\0';
+ nl -= rp->lal;
+ }
+ }
+ if (rp->ra && rp->ral) {
+
+ /*
+ * Store the remote raw address, prefixed with "->".
+ */
+ if (nl > (rp->ral + 2)) {
+ (void) snpf(cp, nl, "->%s", rp->ra);
+ cp += (rp->ral + 2);
+ *cp = '\0';
+ nl -= (rp->ral + 2);
+ }
+ }
+ if (rp->sp && rp->spl) {
+
+ /*
+ * Store the state, optionally prefixed by a space, in the
+ * form "st=x...x".
+ */
+
+ if (nl > (len = ((cp == Namech) ? 0 : 1) + 3 + rp->spl)) {
+ (void) snpf(cp, nl, "%sst=%s",
+ (cp == Namech) ? "" : " ", rp->sp);
+ cp += len;
+ *cp = '\0';
+ nl -= len;
+ }
+ }
+ if (Namech[0])
+ enter_nm(Namech);
+ return;
+ }
+ if (Nlkpath) {
+ (void) get_netlink(Nlkpath);
+ (void) free((FREE_P *) Nlkpath);
+ Nlkpath = (char *)NULL;
+ }
+ if ((ss & SB_INO)
+ && (np = check_netlink((INODETYPE)s->st_ino))
+ ) {
+ /*
+ * The inode is connected to a Netlink /proc record.
+ *
+ * Set the type to "netlink" and store the protocol in the NAME
+ * column. Save the inode number.
+ */
+
+ (void) snpf(Lf->type, sizeof(Lf->type), "netlink");
+ switch (np->pr) {
+
+#if defined(NETLINK_ROUTE)
+ case NETLINK_ROUTE:
+ cp = "ROUTE";
+ break;
+#endif /* defined(NETLINK_ROUTE) */
+
+#if defined(NETLINK_UNUSED)
+ case NETLINK_UNUSED:
+ cp = "UNUSED";
+ break;
+#endif /* defined(NETLINK_UNUSED) */
+
+#if defined(NETLINK_USERSOCK)
+ case NETLINK_USERSOCK:
+ cp = "USERSOCK";
+ break;
+#endif /* defined(NETLINK_USERSOCK) */
+
+#if defined(NETLINK_FIREWALL)
+ case NETLINK_FIREWALL:
+ cp = "FIREWALL";
+ break;
+#endif /* defined(NETLINK_FIREWALL) */
+
+#if defined(NETLINK_INET_DIAG)
+ case NETLINK_INET_DIAG:
+ cp = "INET_DIAG";
+ break;
+#endif /* defined(NETLINK_INET_DIAG) */
+
+#if defined(NETLINK_NFLOG)
+ case NETLINK_NFLOG:
+ cp = "NFLOG";
+ break;
+#endif /* defined(NETLINK_NFLOG) */
+
+#if defined(NETLINK_XFRM)
+ case NETLINK_XFRM:
+ cp = "XFRM";
+ break;
+#endif /* defined(NETLINK_XFRM) */
+
+#if defined(NETLINK_SELINUX)
+ case NETLINK_SELINUX:
+ cp = "SELINUX";
+ break;
+#endif /* defined(NETLINK_SELINUX) */
+
+#if defined(NETLINK_ISCSI)
+ case NETLINK_ISCSI:
+ cp = "ISCSI";
+ break;
+#endif /* defined(NETLINK_ISCSI) */
+
+#if defined(NETLINK_AUDIT)
+ case NETLINK_AUDIT:
+ cp = "AUDIT";
+ break;
+#endif /* defined(NETLINK_AUDIT) */
+
+#if defined(NETLINK_FIB_LOOKUP)
+ case NETLINK_FIB_LOOKUP:
+ cp = "FIB_LOOKUP";
+ break;
+#endif /* defined(NETLINK_FIB_LOOKUP) */
+
+#if defined(NETLINK_CONNECTOR)
+ case NETLINK_CONNECTOR:
+ cp = "CONNECTOR";
+ break;
+#endif /* defined(NETLINK_CONNECTOR) */
+
+#if defined(NETLINK_NETFILTER)
+ case NETLINK_NETFILTER:
+ cp = "NETFILTER";
+ break;
+#endif /* defined(NETLINK_NETFILTER) */
+
+#if defined(NETLINK_IP6_FW)
+ case NETLINK_IP6_FW:
+ cp = "IP6_FW";
+ break;
+#endif /* defined(NETLINK_IP6_FW) */
+
+#if defined(NETLINK_DNRTMSG)
+ case NETLINK_DNRTMSG:
+ cp = "DNRTMSG";
+ break;
+#endif /* defined(NETLINK_DNRTMSG) */
+
+#if defined(NETLINK_KOBJECT_UEVENT)
+ case NETLINK_KOBJECT_UEVENT:
+ cp = "KOBJECT_UEVENT";
+ break;
+#endif /* defined(NETLINK_KOBJECT_UEVENT) */
+
+#if defined(NETLINK_GENERIC)
+ case NETLINK_GENERIC:
+ cp = "GENERIC";
+ break;
+#endif /* defined(NETLINK_GENERIC) */
+
+#if defined(NETLINK_SCSITRANSPORT)
+ case NETLINK_SCSITRANSPORT:
+ cp = "SCSITRANSPORT";
+ break;
+#endif /* defined(NETLINK_SCSITRANSPORT) */
+
+#if defined(NETLINK_ECRYPTFS)
+ case NETLINK_ECRYPTFS:
+ cp = "ECRYPTFS";
+ break;
+#endif /* defined(NETLINK_ECRYPTFS) */
+
+ default:
+ (void) snpf(Namech, Namechl, "unknown protocol: %d", np->pr);
+ cp = (char *)NULL;
+ }
+ if (cp)
+ (void) snpf(Namech, Namechl, "%s", cp);
+ Lf->inode = (INODETYPE)s->st_ino;
+ Lf->inp_ty = 1;
+ if (Namech[0])
+ enter_nm(Namech);
+ return;
+ }
+ if (Packpath) {
+ (void) get_pack(Packpath);
+ (void) free((FREE_P *)Packpath);
+ Packpath = (char *)NULL;
+ }
+ if ((ss & SB_INO)
+ && (pp = check_pack((INODETYPE)s->st_ino))
+ ) {
+
+ /*
+ * The inode is connected to a packet /proc record.
+ *
+ * Set the type to "pack" and store the socket type in the NAME
+ * column. Put the protocol name in the NODE column and the inode
+ * number in the DEVICE column.
+ */
+ (void) snpf(Lf->type, sizeof(Lf->type), "pack");
+ switch(pp->ty) {
+
+#if defined(SOCK_STREAM)
+ case SOCK_STREAM:
+ cp = "STREAM";
+ break;
+#endif /* defined(SOCK_STREAM) */
+
+#if defined(SOCK_DGRAM)
+ case SOCK_DGRAM:
+ cp = "DGRAM";
+ break;
+#endif /* defined(SOCK_DGRAM) */
+
+#if defined(SOCK_RAW)
+ case SOCK_RAW:
+ cp = "RAW";
+ break;
+#endif /* defined(SOCK_RAW) */
+
+#if defined(SOCK_RDM)
+ case SOCK_RDM:
+ cp = "RDM";
+ break;
+#endif /* defined(SOCK_RDM) */
+
+#if defined(SOCK_SEQPACKET)
+ case SOCK_SEQPACKET:
+ cp = "SEQPACKET";
+ break;
+#endif /* defined(SOCK_SEQPACKET) */
+
+#if defined(SOCK_PACKET)
+ case SOCK_PACKET:
+ cp = "PACKET";
+ break;
+#endif /* defined(SOCK_PACKET) */
+
+ default:
+ (void) snpf(Namech, Namechl, "unknown type: %d", pp->ty);
+ cp = (char *)NULL;
+ }
+ if (cp)
+ (void) snpf(Namech, Namechl, "type=SOCK_%s", cp);
+ switch (pp->pr) {
+
+#if defined(ETH_P_LOOP)
+ case ETH_P_LOOP:
+ cp = "LOOP";
+ break;
+#endif /* defined(ETH_P_LOOP) */
+
+#if defined(ETH_P_PUP)
+ case ETH_P_PUP:
+ cp = "PUP";
+ break;
+#endif /* defined(ETH_P_PUP) */
+
+#if defined(ETH_P_PUPAT)
+ case ETH_P_PUPAT:
+ cp = "PUPAT";
+ break;
+#endif /* defined(ETH_P_PUPAT) */
+
+#if defined(ETH_P_IP)
+ case ETH_P_IP:
+ cp = "IP";
+ break;
+#endif /* defined(ETH_P_IP) */
+
+#if defined(ETH_P_X25)
+ case ETH_P_X25:
+ cp = "X25";
+ break;
+#endif /* defined(ETH_P_X25) */
+
+#if defined(ETH_P_ARP)
+ case ETH_P_ARP:
+ cp = "ARP";
+ break;
+#endif /* defined(ETH_P_ARP) */
+
+#if defined(ETH_P_BPQ)
+ case ETH_P_BPQ:
+ cp = "BPQ";
+ break;
+#endif /* defined(ETH_P_BPQ) */
+
+#if defined(ETH_P_IEEEPUP)
+ case ETH_P_IEEEPUP:
+ cp = "I3EPUP";
+ break;
+#endif /* defined(ETH_P_IEEEPUP) */
+
+#if defined(ETH_P_IEEEPUPAT)
+ case ETH_P_IEEEPUPAT:
+ cp = "I3EPUPA";
+ break;
+#endif /* defined(ETH_P_IEEEPUPAT) */
+
+#if defined(ETH_P_DEC)
+ case ETH_P_DEC:
+ cp = "DEC";
+ break;
+#endif /* defined(ETH_P_DEC) */
+
+#if defined(ETH_P_DNA_DL)
+ case ETH_P_DNA_DL:
+ cp = "DNA_DL";
+ break;
+#endif /* defined(ETH_P_DNA_DL) */
+
+#if defined(ETH_P_DNA_RC)
+ case ETH_P_DNA_RC:
+ cp = "DNA_RC";
+ break;
+#endif /* defined(ETH_P_DNA_RC) */
+
+#if defined(ETH_P_DNA_RT)
+ case ETH_P_DNA_RT:
+ cp = "DNA_RT";
+ break;
+#endif /* defined(ETH_P_DNA_RT) */
+
+#if defined(ETH_P_LAT)
+ case ETH_P_LAT:
+ cp = "LAT";
+ break;
+#endif /* defined(ETH_P_LAT) */
+
+#if defined(ETH_P_DIAG)
+ case ETH_P_DIAG:
+ cp = "DIAG";
+ break;
+#endif /* defined(ETH_P_DIAG) */
+
+#if defined(ETH_P_CUST)
+ case ETH_P_CUST:
+ cp = "CUST";
+ break;
+#endif /* defined(ETH_P_CUST) */
+
+#if defined(ETH_P_SCA)
+ case ETH_P_SCA:
+ cp = "SCA";
+ break;
+#endif /* defined(ETH_P_SCA) */
+
+#if defined(ETH_P_RARP)
+ case ETH_P_RARP:
+ cp = "RARP";
+ break;
+#endif /* defined(ETH_P_RARP) */
+
+#if defined(ETH_P_ATALK)
+ case ETH_P_ATALK:
+ cp = "ATALK";
+ break;
+#endif /* defined(ETH_P_ATALK) */
+
+#if defined(ETH_P_AARP)
+ case ETH_P_AARP:
+ cp = "AARP";
+ break;
+#endif /* defined(ETH_P_AARP) */
+
+#if defined(ETH_P_8021Q)
+ case ETH_P_8021Q:
+ cp = "8021Q";
+ break;
+#endif /* defined(ETH_P_8021Q) */
+
+#if defined(ETH_P_IPX)
+ case ETH_P_IPX:
+ cp = "IPX";
+ break;
+#endif /* defined(ETH_P_IPX) */
+
+#if defined(ETH_P_IPV6)
+ case ETH_P_IPV6:
+ cp = "IPV6";
+ break;
+#endif /* defined(ETH_P_IPV6) */
+
+#if defined(ETH_P_SLOW)
+ case ETH_P_SLOW:
+ cp = "SLOW";
+ break;
+#endif /* defined(ETH_P_SLOW) */
+
+#if defined(ETH_P_WCCP)
+ case ETH_P_WCCP:
+ cp = "WCCP";
+ break;
+#endif /* defined(ETH_P_WCCP) */
+
+#if defined(ETH_P_PPP_DISC)
+ case ETH_P_PPP_DISC:
+ cp = "PPP_DIS";
+ break;
+#endif /* defined(ETH_P_PPP_DISC) */
+
+#if defined(ETH_P_PPP_SES)
+ case ETH_P_PPP_SES:
+ cp = "PPP_SES";
+ break;
+#endif /* defined(ETH_P_PPP_SES) */
+
+#if defined(ETH_P_MPLS_UC)
+ case ETH_P_MPLS_UC:
+ cp = "MPLS_UC";
+ break;
+#endif /* defined(ETH_P_MPLS_UC) */
+
+#if defined(ETH_P_ATMMPOA)
+ case ETH_P_ATMMPOA:
+ cp = "ATMMPOA";
+ break;
+#endif /* defined(ETH_P_ATMMPOA) */
+
+#if defined(ETH_P_MPLS_MC)
+ case ETH_P_MPLS_MC:
+ cp = "MPLS_MC";
+ break;
+#endif /* defined(ETH_P_MPLS_MC) */
+
+#if defined(ETH_P_ATMFATE)
+ case ETH_P_ATMFATE:
+ cp = "ATMFATE";
+ break;
+#endif /* defined(ETH_P_ATMFATE) */
+
+#if defined(ETH_P_AOE)
+ case ETH_P_AOE:
+ cp = "AOE";
+ break;
+#endif /* defined(ETH_P_AOE) */
+
+#if defined(ETH_P_TIPC)
+ case ETH_P_TIPC:
+ cp = "TIPC";
+ break;
+#endif /* defined(ETH_P_TIPC) */
+
+#if defined(ETH_P_802_3)
+ case ETH_P_802_3:
+ cp = "802.3";
+ break;
+#endif /* defined(ETH_P_802_3) */
+
+#if defined(ETH_P_AX25)
+ case ETH_P_AX25:
+ cp = "AX25";
+ break;
+#endif /* defined(ETH_P_AX25) */
+
+#if defined(ETH_P_ALL)
+ case ETH_P_ALL:
+ cp = "ALL";
+ break;
+#endif /* defined(ETH_P_ALL) */
+
+#if defined(ETH_P_802_2)
+ case ETH_P_802_2:
+ cp = "802.2";
+ break;
+#endif /* defined(ETH_P_802_2) */
+
+#if defined(ETH_P_SNAP)
+ case ETH_P_SNAP:
+ cp = "SNAP";
+ break;
+#endif /* defined(ETH_P_SNAP) */
+
+#if defined(ETH_P_DDCMP)
+ case ETH_P_DDCMP:
+ cp = "DDCMP";
+ break;
+#endif /* defined(ETH_P_DDCMP) */
+
+#if defined(ETH_P_WAN_PPP)
+ case ETH_P_WAN_PPP:
+ cp = "WAN_PPP";
+ break;
+#endif /* defined(ETH_P_WAN_PPP) */
+
+#if defined(ETH_P_PPP_MP)
+ case ETH_P_PPP_MP:
+ cp = "PPP MP";
+ break;
+#endif /* defined(ETH_P_PPP_MP) */
+
+#if defined(ETH_P_LOCALTALK)
+ case ETH_P_LOCALTALK:
+ cp = "LCLTALK";
+ break;
+#endif /* defined(ETH_P_LOCALTALK) */
+
+#if defined(ETH_P_PPPTALK)
+ case ETH_P_PPPTALK:
+ cp = "PPPTALK";
+ break;
+#endif /* defined(ETH_P_PPPTALK) */
+
+#if defined(ETH_P_TR_802_2)
+ case ETH_P_TR_802_2:
+ cp = "802.2";
+ break;
+#endif /* defined(ETH_P_TR_802_2) */
+
+#if defined(ETH_P_MOBITEX)
+ case ETH_P_MOBITEX:
+ cp = "MOBITEX";
+ break;
+#endif /* defined(ETH_P_MOBITEX) */
+
+#if defined(ETH_P_CONTROL)
+ case ETH_P_CONTROL:
+ cp = "CONTROL";
+ break;
+#endif /* defined(ETH_P_CONTROL) */
+
+#if defined(ETH_P_IRDA)
+ case ETH_P_IRDA:
+ cp = "IRDA";
+ break;
+#endif /* defined(ETH_P_IRDA) */
+
+#if defined(ETH_P_ECONET)
+ case ETH_P_ECONET:
+ cp = "ECONET";
+ break;
+#endif /* defined(ETH_P_ECONET) */
+
+#if defined(ETH_P_HDLC)
+ case ETH_P_HDLC:
+ cp = "HDLC";
+ break;
+#endif /* defined(ETH_P_HDLC) */
+
+#if defined(ETH_P_ARCNET)
+ case ETH_P_ARCNET:
+ cp = "ARCNET";
+ break;
+#endif /* defined(ETH_P_ARCNET) */
+
+ default:
+ (void) snpf(tbuf, sizeof(tbuf) - 1, "%d", pp->pr);
+ tbuf[sizeof(tbuf) - 1] = '\0';
+ cp = tbuf;
+ }
+ (void) snpf(Lf->iproto, sizeof(Lf->iproto), "%.*s", IPROTOL-1, cp);
+ Lf->inp_ty = 2;
+ if (ss & SB_INO) {
+ (void) snpf(tbuf, sizeof(tbuf), InodeFmt_d,
+ (INODETYPE)s->st_ino);
+ tbuf[sizeof(tbuf) - 1] = '\0';
+ enter_dev_ch(tbuf);
+ }
+ if (Namech[0])
+ enter_nm(Namech);
+ return;
+ }
+ if (UNIXpath) {
+ (void) get_unix(UNIXpath);
+ (void) free((FREE_P *)UNIXpath);
+ UNIXpath = (char *)NULL;
+ }
+ if ((ss & SB_INO)
+ && (up = check_unix((INODETYPE)s->st_ino))
+ ) {
+
+ /*
+ * The inode is connected to a UNIX /proc record.
+ *
+ * Set the type to "unix"; enter the PCB address in the DEVICE column;
+ * enter the inode number; and save the optional path.
+ */
+ if (Funix)
+ Lf->sf |= SELUNX;
+ (void) snpf(Lf->type, sizeof(Lf->type), "unix");
+ if (up->pcb)
+ enter_dev_ch(up->pcb);
+ if (ss & SB_INO) {
+ Lf->inode = (INODETYPE)s->st_ino;
+ Lf->inp_ty = 1;
+ }
+ path = up->path ? up->path : p;
+ (void) enter_nm(path);
+ if (Sfile) {
+
+ /*
+ * See if this UNIX domain socket was specified as a search
+ * argument.
+ *
+ * Search first by device and node numbers, if that is possible;
+ * then search by name.
+ */
+ unsigned char f = 0; /* file-found flag */
+
+ if (up->sb_def) {
+
+ /*
+ * If the UNIX socket information includes stat(2) results, do
+ * a device and node number search.
+ *
+ * Note: that requires the saving, temporary modification and
+ * restoration of some *Lf values.
+ */
+ unsigned char sv_dev_def; /* saved dev_def */
+ unsigned char sv_inp_ty; /* saved inp_ty */
+ unsigned char sv_rdev_def; /* saved rdev_def */
+ dev_t sv_dev; /* saved dev */
+ INODETYPE sv_inode; /* saved inode */
+ dev_t sv_rdev; /* saved rdev */
+
+ sv_dev_def = Lf->dev_def;
+ sv_dev = Lf->dev;
+ sv_inode = Lf->inode;
+ sv_inp_ty = Lf->inp_ty;
+ sv_rdev_def = Lf->rdev_def;
+ sv_rdev = Lf->rdev;
+ Lf->dev_def = Lf->inp_ty = Lf->rdev_def = 1;
+ Lf->dev = up->sb_dev;
+ Lf->inode = up->sb_ino;
+ Lf->rdev = up->sb_rdev;
+ if (is_file_named(0, path, (struct mounts *)NULL, 0)) {
+ f = 1;
+ Lf->sf |= SELNM;
+ }
+ Lf->dev_def = sv_dev_def;
+ Lf->dev = sv_dev;
+ Lf->inode = sv_inode;
+ Lf->inp_ty = sv_inp_ty;
+ Lf->rdev_def = sv_rdev_def;
+ Lf->rdev = sv_rdev;
+ }
+ if (!f && (ss & SB_MODE)) {
+
+ /*
+ * If the file has not yet been found and the stat buffer has
+ * st_mode, search for the file by full path.
+ */
+ if (is_file_named(2, path, (struct mounts *)NULL,
+ ((s->st_mode & S_IFMT) == S_IFCHR)) ? 1 : 0)
+ {
+ Lf->sf |= SELNM;
+ }
+ }
+ }
+ return;
+ }
+
+#if defined(HASIPv6)
+ if (Raw6path) {
+ if (!Fxopt)
+ (void) get_raw6(Raw6path);
+ (void) free((FREE_P *)Raw6path);
+ Raw6path = (char *)NULL;
+ }
+ if (!Fxopt && (ss & SB_INO)
+ && (rp = check_raw6((INODETYPE)s->st_ino))
+ ) {
+
+ /*
+ * The inode is connected to a raw IPv6 /proc record.
+ *
+ * Set the type to "raw6"; enter the inode number; store the local
+ * address, remote address, and state in the NAME column.
+ */
+ (void) snpf(Lf->type, sizeof(Lf->type), "raw6");
+ if (ss & SB_INO) {
+ Lf->inode = (INODETYPE)s->st_ino;
+ Lf->inp_ty = 1;
+ }
+ cp = Namech;
+ nl = MAXPATHLEN - 2;
+ if (rp->la && rp->lal) {
+
+ /*
+ * Store the local raw IPv6 address.
+ */
+ if (nl > rp->lal) {
+ (void) snpf(cp, nl, "%s", rp->la);
+ cp += rp->lal;
+ *cp = '\0';
+ nl -= rp->lal;
+ }
+ }
+ if (rp->ra && rp->ral) {
+
+ /*
+ * Store the remote raw address, prefixed with "->".
+ */
+ if (nl > (rp->ral + 2)) {
+ (void) snpf(cp, nl, "->%s", rp->ra);
+ cp += (rp->ral + 2);
+ nl -= (rp->ral + 2);
+ }
+ }
+ if (rp->sp && rp->spl) {
+
+ /*
+ * Store the state, optionally prefixed by a space, in the
+ * form "st=x...x".
+ */
+
+ if (nl > (len = ((cp == Namech) ? 0 : 1) + 3 + rp->spl)) {
+ (void) snpf(cp, nl, "%sst=%s",
+ (cp == Namech) ? "" : " ", rp->sp);
+ cp += len;
+ *cp = '\0';
+ nl -= len;
+ }
+ }
+ if (Namech[0])
+ enter_nm(Namech);
+ return;
+ }
+ if (TCP6path) {
+ if (!Fxopt)
+ (void) get_tcpudp6(TCP6path, 0, 1);
+ (void) free((FREE_P *)TCP6path);
+ TCP6path = (char *)NULL;
+ }
+ if (UDP6path) {
+ if (!Fxopt)
+ (void) get_tcpudp6(UDP6path, 1, 0);
+ (void) free((FREE_P *)UDP6path);
+ UDP6path = (char *)NULL;
+ }
+ if (UDPLITE6path) {
+ if (!Fxopt)
+ (void) get_tcpudp6(UDPLITE6path, 2, 0);
+ (void) free((FREE_P *)UDPLITE6path);
+ UDPLITE6path = (char *)NULL;
+ }
+ if (!Fxopt && (ss & SB_INO)
+ && (tp6 = check_tcpudp6((INODETYPE)s->st_ino, &pr))
+ ) {
+
+ /*
+ * The inode is connected to an IPv6 TCP or UDP /proc record.
+ *
+ * Set the type to "IPv6"; enter the protocol; put the inode number
+ * in the DEVICE column in lieu of the PCB address; save the local
+ * and foreign IPv6 addresses; save the type and protocol; and
+ * (optionally) save the queue sizes.
+ */
+ i = tp6->state + TcpStOff;
+ if (TcpStXn) {
+
+ /*
+ * Check for state exclusion.
+ */
+ if (i >= 0 && i < TcpNstates) {
+ if (TcpStX[i]) {
+ Lf->sf |= SELEXCLF;
+ return;
+ }
+ }
+ }
+ if (TcpStIn) {
+
+ /*
+ * Check for state inclusion.
+ */
+ if (i >= 0 && i < TcpNstates) {
+ if (TcpStI[i])
+ TcpStI[i] = 2;
+ else {
+ Lf->sf |= SELEXCLF;
+ return;
+ }
+ }
+ }
+ if (Fnet && (FnetTy != 4))
+ Lf->sf |= SELNET;
+ (void) snpf(Lf->type, sizeof(Lf->type), "IPv6");
+ (void) snpf(Lf->iproto, sizeof(Lf->iproto), "%.*s", IPROTOL-1, pr);
+ Lf->inp_ty = 2;
+ if (ss & SB_INO) {
+ (void) snpf(tbuf, sizeof(tbuf), InodeFmt_d,
+ (INODETYPE)s->st_ino);
+ tbuf[sizeof(tbuf) - 1] = '\0';
+ enter_dev_ch(tbuf);
+ }
+ af = AF_INET6;
+ if (!IN6_IS_ADDR_UNSPECIFIED(&tp6->faddr) || tp6->fport)
+ fa = (unsigned char *)&tp6->faddr;
+ else
+ fa = (unsigned char *)NULL;
+ if (!IN6_IS_ADDR_UNSPECIFIED(&tp6->laddr) || tp6->lport)
+ la = (unsigned char *)&tp6->laddr;
+ else
+ la = (unsigned char *)NULL;
+ if ((fa && IN6_IS_ADDR_V4MAPPED(&tp6->faddr))
+ || (la && IN6_IS_ADDR_V4MAPPED(&tp6->laddr))) {
+ af = AF_INET;
+ if (fa)
+ fa += 12;
+ if (la)
+ la += 12;
+ }
+ ent_inaddr(la, tp6->lport, fa, tp6->fport, af);
+ Lf->lts.type = tp6->proto;
+ Lf->lts.state.i = tp6->state;
+
+#if defined(HASTCPTPIQ)
+ Lf->lts.rq = tp6->rxq;
+ Lf->lts.sq = tp6->txq;
+ Lf->lts.rqs = Lf->lts.sqs = 1;
+#endif /* defined(HASTCPTPIQ) */
+
+ return;
+ }
+#endif /* defined(HASIPv6) */
+
+ if (TCPpath) {
+ if (!Fxopt)
+ (void) get_tcpudp(TCPpath, 0, 1);
+ (void) free((FREE_P *)TCPpath);
+ TCPpath = (char *)NULL;
+ }
+ if (UDPpath) {
+ if (!Fxopt)
+ (void) get_tcpudp(UDPpath, 1, 0);
+ (void) free((FREE_P *)UDPpath);
+ UDPpath = (char *)NULL;
+ }
+ if (UDPLITEpath) {
+ if (!Fxopt)
+ (void) get_tcpudp(UDPLITEpath, 2, 0);
+ (void) free((FREE_P *)UDPLITEpath);
+ UDPLITEpath = (char *)NULL;
+ }
+ if (!Fxopt && (ss & SB_INO)
+ && (tp = check_tcpudp((INODETYPE)s->st_ino, &pr))
+ ) {
+
+ /*
+ * The inode is connected to an IPv4 TCP or UDP /proc record.
+ *
+ * Set the type to "inet" or "IPv4"; enter the protocol; put the
+ * inode number in the DEVICE column in lieu of the PCB address;
+ * save the local and foreign IPv4 addresses; save the type and
+ * protocol; and (optionally) save the queue sizes.
+ */
+ i = tp->state + TcpStOff;
+ if (TcpStXn) {
+
+ /*
+ * Check for state exclusion.
+ */
+ if (i >= 0 && i < TcpNstates) {
+ if (TcpStX[i]) {
+ Lf->sf |= SELEXCLF;
+ return;
+ }
+ }
+ }
+ if (TcpStIn) {
+
+ /*
+ * Check for state inclusion.
+ */
+ if (i >= 0 && i < TcpNstates) {
+ if (TcpStI[i])
+ TcpStI[i] = 2;
+ else {
+ Lf->sf |= SELEXCLF;
+ return;
+ }
+ }
+ }
+ if (Fnet && (FnetTy != 6))
+ Lf->sf |= SELNET;
+
+#if defined(HASIPv6)
+ (void) snpf(Lf->type, sizeof(Lf->type), "IPv4");
+#else /* !defined(HASIPv6) */
+ (void) snpf(Lf->type, sizeof(Lf->type), "inet");
+#endif /* defined(HASIPv6) */
+
+ (void) snpf(Lf->iproto, sizeof(Lf->iproto), "%.*s", IPROTOL-1, pr);
+ Lf->inp_ty = 2;
+ if (ss & SB_INO) {
+ (void) snpf(tbuf, sizeof(tbuf), InodeFmt_d,
+ (INODETYPE)s->st_ino);
+ tbuf[sizeof(tbuf) - 1] = '\0';
+ enter_dev_ch(tbuf);
+ }
+ if (tp->faddr || tp->fport) {
+ fs.s_addr = tp->faddr;
+ fa = (unsigned char *)&fs;
+ } else
+ fa = (unsigned char *)NULL;
+ if (tp->laddr || tp->lport) {
+ ls.s_addr = tp->laddr;
+ la = (unsigned char *)&ls;
+ } else
+ la = (unsigned char *)NULL;
+ ent_inaddr(la, tp->lport, fa, tp->fport, AF_INET);
+ Lf->lts.type = tp->proto;
+ Lf->lts.state.i = tp->state;
+
+#if defined(HASTCPTPIQ)
+ Lf->lts.rq = tp->rxq;
+ Lf->lts.sq = tp->txq;
+ Lf->lts.rqs = Lf->lts.sqs = 1;
+#endif /* defined(HASTCPTPIQ) */
+
+ return;
+ }
+ if (SCTPPath[0]) {
+ (void) get_sctp();
+ for (i = 0; i < NSCTPPATHS; i++) {
+ (void) free((FREE_P *)SCTPPath[i]);
+ SCTPPath[i] = (char *)NULL;
+ }
+ }
+ if ((ss & SB_INO) && (sp = check_sctp((INODETYPE)s->st_ino))
+ ) {
+
+ /*
+ * The inode is connected to an SCTP /proc record.
+ *
+ * Set the type to "sock"; enter the inode number in the DEVICE
+ * column; set the protocol to SCTP; and fill in the NAME column
+ * with ASSOC, ASSOC-ID, ENDPT, LADDRS, LPORT, RADDRS and RPORT.
+ */
+ (void) snpf(Lf->type, sizeof(Lf->type), "sock");
+ (void) snpf(Lf->iproto, sizeof(Lf->iproto), "%.*s", IPROTOL-1,
+ "SCTP");
+ Lf->inp_ty = 2;
+ (void) snpf(tbuf, sizeof(tbuf), InodeFmt_d, (INODETYPE)s->st_ino);
+ tbuf[sizeof(tbuf) - 1] = '\0';
+ enter_dev_ch(tbuf);
+ Namech[0] = '\0';
+ if (sp->type == 1) {
+
+ /*
+ * This is an ENDPT SCTP file.
+ */
+ (void) snpf(Namech, Namechl,
+ "ENDPT: %s%s%s%s%s%s",
+ sp->addr ? sp->addr : "",
+ (sp->laddrs || sp->lport) ? " " : "",
+ sp->laddrs ? sp->laddrs : "",
+ sp->lport ? "[" : "",
+ sp->lport ? sp->lport : "",
+ sp->lport ? "]" : ""
+ );
+ } else {
+
+ /*
+ * This is an ASSOC, or ASSOC and ENDPT socket file.
+ */
+ (void) snpf(Namech, Namechl,
+ "%s: %s%s%s %s%s%s%s%s%s%s%s%s",
+ sp->type ? "ASSOC+ENDPT" : "ASSOC",
+ sp->addr ? sp->addr : "",
+ (sp->addr && sp->assocID) ? "," : "",
+ sp->assocID ? sp->assocID : "",
+ sp->laddrs ? sp->laddrs : "",
+ sp->lport ? "[" : "",
+ sp->lport ? sp->lport : "",
+ sp->lport ? "]" : "",
+ ((sp->laddrs || sp->lport) && (sp->raddrs || sp->rport))
+ ? "<->" : "",
+ sp->raddrs ? sp->raddrs : "",
+ sp->rport ? "[" : "",
+ sp->rport ? sp->rport : "",
+ sp->rport ? "]" : ""
+ );
+ }
+ if (Namech[0])
+ enter_nm(Namech);
+ return;
+ }
+ if (ICMPpath) {
+ (void) get_icmp(ICMPpath);
+ (void) free((FREE_P *)ICMPpath);
+ ICMPpath = (char *)NULL;
+ }
+ if ((ss & SB_INO)
+ && (icmpp = check_icmp((INODETYPE)s->st_ino))
+ ) {
+
+ /*
+ * The inode is connected to an ICMP /proc record.
+ *
+ * Set the type to "icmp" and store the type in the NAME
+ * column. Save the inode number.
+ */
+ (void) snpf(Lf->type, sizeof(Lf->type), "icmp");
+ Lf->inode = (INODETYPE)s->st_ino;
+ Lf->inp_ty = 1;
+ cp = Namech;
+ nl = Namechl- 2;
+ *cp = '\0';
+ if (icmpp->la && icmpp->lal) {
+
+ /*
+ * Store the local raw address.
+ */
+ if (nl > icmpp->lal) {
+ (void) snpf(cp, nl, "%s", icmpp->la);
+ cp += icmpp->lal;
+ *cp = '\0';
+ nl -= icmpp->lal;
+ }
+ }
+ if (icmpp->ra && icmpp->ral) {
+
+ /*
+ * Store the remote raw address, prefixed with "->".
+ */
+ if (nl > (icmpp->ral + 2)) {
+ (void) snpf(cp, nl, "->%s", icmpp->ra);
+ cp += (icmpp->ral + 2);
+ *cp = '\0';
+ nl -= (icmpp->ral + 2);
+ }
+ }
+ if (Namech[0])
+ enter_nm(Namech);
+ return;
+ }
+/*
+ * The socket's protocol can't be identified.
+ */
+ (void) snpf(Lf->type, sizeof(Lf->type), "sock");
+ if (ss & SB_INO) {
+ Lf->inode = (INODETYPE)s->st_ino;
+ Lf->inp_ty = 1;
+ }
+ if (ss & SB_DEV) {
+ Lf->dev = s->st_dev;
+ Lf->dev_def = 1;
+ }
+ if (Fxopt)
+ enter_nm("can't identify protocol (-X specified)");
+ else {
+ (void) snpf(Namech, Namechl, "protocol: ");
+ if (!prp) {
+ i = (int)strlen(Namech);
+ prp = &Namech[i];
+ sz = (ssize_t)(Namechl - i - 1);
+ }
+ if ((getxattr(pbr, "system.sockprotoname", prp, sz)) < 0)
+ enter_nm("can't identify protocol");
+ else
+ enter_nm(Namech);
+ }
+}
+
+
+/*
+ * set_net_paths() - set /proc/net paths
+ */
+
+void
+set_net_paths(p, pl)
+ char *p; /* path to /proc/net/ */
+ int pl; /* strlen(p) */
+{
+ int i;
+ int pathl;
+
+ pathl = 0;
+ (void) make_proc_path(p, pl, &AX25path, &pathl, "ax25");
+ pathl = 0;
+ (void) make_proc_path(p, pl, &ICMPpath, &pathl, "icmp");
+ pathl = 0;
+ (void) make_proc_path(p, pl, &Ipxpath, &pathl, "ipx");
+ pathl = 0;
+ (void) make_proc_path(p, pl, &Nlkpath, &pathl, "netlink");
+ pathl = 0;
+ (void) make_proc_path(p, pl, &Packpath, &pathl, "packet");
+ pathl = 0;
+ (void) make_proc_path(p, pl, &Rawpath, &pathl, "raw");
+ for (i = 0; i < NSCTPPATHS; i++) {
+ pathl = 0;
+ (void) make_proc_path(p, pl, &SCTPPath[i], &pathl, SCTPSfx[i]);
+ }
+ pathl = 0;
+ (void) make_proc_path(p, pl, &SockStatPath, &pathl, "sockstat");
+ pathl = 0;
+ (void) make_proc_path(p, pl, &TCPpath, &pathl, "tcp");
+ pathl = 0;
+ (void) make_proc_path(p, pl, &UDPpath, &pathl, "udp");
+ pathl = 0;
+ (void) make_proc_path(p, pl, &UDPLITEpath, &pathl, "udplite");
+
+#if defined(HASIPv6)
+ pathl = 0;
+ (void) make_proc_path(p, pl, &Raw6path, &pathl, "raw6");
+ pathl = 0;
+ (void) make_proc_path(p, pl, &SockStatPath6, &pathl, "sockstat6");
+ pathl = 0;
+ (void) make_proc_path(p, pl, &TCP6path, &pathl, "tcp6");
+ pathl = 0;
+ (void) make_proc_path(p, pl, &UDP6path, &pathl, "udp6");
+ pathl = 0;
+ (void) make_proc_path(p, pl, &UDPLITE6path, &pathl, "udplite6");
+#endif /* defined(HASIPv6) */
+
+ pathl = 0;
+ (void) make_proc_path(p, pl, &UNIXpath, &pathl, "unix");
+}
diff --git a/dialects/linux/dstore.c b/dialects/linux/dstore.c
new file mode 100644
index 0000000..80e2826
--- /dev/null
+++ b/dialects/linux/dstore.c
@@ -0,0 +1,114 @@
+/*
+ * dstore.c - Linux global storage for /proc-based lsof
+ */
+
+
+/*
+ * Copyright 1997 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 1997 Purdue Research Foundation.\nAll rights reserved.\n";
+static char *rcsid = "$Id: dstore.c,v 1.4 2011/09/07 19:07:45 abe Exp $";
+#endif
+
+
+#include "lsof.h"
+
+int HasNFS = 0; /* NFS mount point status:
+ * 1 == there is an NFS mount point,
+ * but its device number is
+ * unknown
+ * 2 == there is an NFS mount point
+ * and its device number is
+ * known
+ */
+int OffType = 0; /* offset type:
+ * 0 == unknown
+ * 1 == lstat's st_size
+ * 2 == from /proc/<PID>/fdinfo */
+
+/*
+ * Pff_tab[] - table for printing file flags
+ */
+
+struct pff_tab Pff_tab[] = {
+ { (long)O_WRONLY, FF_WRITE },
+ { (long)O_RDWR, FF_RDWR },
+ { (long)O_CREAT, FF_CREAT },
+ { (long)O_EXCL, FF_EXCL },
+ { (long)O_NOCTTY, FF_NOCTTY },
+ { (long)O_TRUNC, FF_TRUNC },
+ { (long)O_APPEND, FF_APPEND },
+ { (long)O_NDELAY, FF_NDELAY },
+ { (long)O_SYNC, FF_SYNC },
+ { (long)O_ASYNC, FF_ASYNC },
+
+#if defined(O_DIRECT)
+ { (long)O_DIRECT, FF_DIRECT },
+#endif /* defined(O_DIRECT) */
+
+#if defined(O_DIRECTORY)
+ { (long)O_DIRECTORY, FF_DIRECTORY },
+#endif /* defined(O_DIRECTORY) */
+
+#if defined(O_NOFOLLOW)
+ { (long)O_NOFOLLOW, FF_NOFOLNK },
+#endif /* defined(O_NOFOLLOW) */
+
+#if defined(O_NOATIME)
+ { (long)O_NOATIME, FF_NOATM },
+#endif /* defined(O_NOATIME) */
+
+#if defined(O_DSYNC)
+ { (long)O_DSYNC, FF_DSYNC },
+#endif /* defined(O_DSYNC) */
+
+#if defined(O_RSYNC)
+ { (long)O_RSYNC, FF_RSYNC },
+#endif /* defined(O_RSYNC) */
+
+#if defined(O_LARGEFILE)
+# if O_LARGEFILE==0
+ { (long)0100000, FF_LARGEFILE },
+# else /* O_LARGEFILE!=0 */
+ { (long)O_LARGEFILE, FF_LARGEFILE },
+# endif /* O_LARGEFILE==0 */
+#else /* !defined(O_LARGEFILE) */
+ { (long)0100000, FF_LARGEFILE },
+#endif /* defined(O_LARGEFILE) */
+
+ { (long)0, NULL }
+};
+
+
+/*
+ * Pof_tab[] - table for print process open file flags
+ */
+
+struct pff_tab Pof_tab[] = {
+ { (long)0, NULL }
+};
diff --git a/dialects/linux/machine.h b/dialects/linux/machine.h
new file mode 100644
index 0000000..2b33128
--- /dev/null
+++ b/dialects/linux/machine.h
@@ -0,0 +1,644 @@
+/*
+ * machine.h - Linux definitions for /proc-based lsof
+ */
+
+
+/*
+ * Copyright 1997 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.36 2012/04/10 16:39:50 abe Exp $
+ */
+
+
+#if !defined(LSOF_MACHINE_H)
+#define LSOF_MACHINE_H 1
+
+
+#include <sys/types.h>
+#include <sys/param.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.
+ *
+ * CAUTION!!! Do not enable HASDCACHE for /proc-based Linux lsof. The source
+ * code cannot support it.
+ *
+ * The presence of NEVER_HASDCACHE in this comment prevents the Customize
+ * script from offering to change HASDCACHE.
+ *
+ *
+ * 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.
+ *
+ * CAUTION!!! Do not enable HASDCACHE for /proc-based Linux lsof. The source
+ * code cannot support it.
+ */
+
+/* #define HASDCACHE 1 !!!DON'T ENABLE!!! -- see above comment */
+/* #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 */
+
+
+/*
+ * HASEOPT is defined for dialects that support the -e option
+ */
+
+#define HASEOPT 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 int ... */
+/* #define CLRLFILEADD(lf) (lf)->... = (type)NULL; */
+/* #define SETLFILEADD Lf->... */
+
+
+/*
+ * HASLWP is defined for dialects that have LWP support inside processes.
+ */
+
+#define HASLWP 1
+
+
+/*
+ * 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 <function name> */
+
+
+/*
+ * 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 <wctype.h>
+
+
+/*
+ * HASSNODE is defined for those dialects that have snodes.
+ */
+
+/* #define HASSNODE 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 */
+
+
+/*
+ * HASTASKS is defined for those dialects that have task reporting support.
+ */
+
+#define HASTASKS 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.
+ * 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 "skip TCP&UDP* files"
+#define HASXOPT_VALUE 0
+
+
+/*
+ * 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 u_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.
+ *
+ * CAUTION!!! Don't enable the WARNDEVACCESS definiton for /proc-based Linux
+ * lsof; it doesn't process /dev at all.
+ *
+ * The presence of NEVER_WARNDEVACCESS in this comment prevents the Customize
+ * script from offering to change WARNDEVACCESS.
+ */
+
+/* #define WARNDEVACCESS 1 DON'T ENABLE!!! -- see above comment */
+
+
+/*
+ * 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) bzero(a, l)
+
+#endif /* !defined(LSOF_MACHINE_H) */