Import lsof_4.99.3+dfsg.orig.tar.xz
authorAndres Salomon <dilinger@debian.org>
Wed, 13 Nov 2024 08:37:11 +0000 (08:37 +0000)
committerAndres Salomon <dilinger@debian.org>
Wed, 13 Nov 2024 08:37:11 +0000 (08:37 +0000)
[dgit import orig lsof_4.99.3+dfsg.orig.tar.xz]

308 files changed:
.builds/netbsd.yml [new file with mode: 0644]
.builds/openbsd.yml [new file with mode: 0644]
.circleci/config.yml [new file with mode: 0644]
.cirrus.yml [new file with mode: 0644]
.ck00MAN [new file with mode: 0644]
.clang-format [new file with mode: 0644]
.github/ISSUE_TEMPLATE/bug_report.md [new file with mode: 0644]
.github/ISSUE_TEMPLATE/feature_request.md [new file with mode: 0644]
.github/workflows/build.yml [new file with mode: 0644]
.gitignore [new file with mode: 0644]
.readthedocs.yaml [new file with mode: 0644]
.travis.yml [new file with mode: 0644]
0..README.BEFORE.README.FIRST [new symlink]
00.README.FIRST [new file with mode: 0644]
00CREDITS [new file with mode: 0644]
00DCACHE [new file with mode: 0644]
00DIALECTS [new file with mode: 0644]
00DIST [new file with mode: 0644]
00FAQ [new file with mode: 0644]
00LSOF-L [new file with mode: 0644]
00MANIFEST [new file with mode: 0644]
00PORTING [new file with mode: 0644]
00QUICKSTART [new file with mode: 0644]
00README [new file with mode: 0644]
00TEST [new file with mode: 0644]
00XCONFIG [new file with mode: 0644]
AFSConfig [new file with mode: 0755]
AUTHORS [new file with mode: 0644]
COPYING [new file with mode: 0644]
ChangeLog [new file with mode: 0644]
Configure [new file with mode: 0755]
Customize [new file with mode: 0755]
Doxyfile [new file with mode: 0644]
HOW_TO_MAINTAIN.rst [new file with mode: 0644]
HOW_TO_RELEASE.rst [new file with mode: 0644]
INSTALL [new file with mode: 0644]
Inventory [new file with mode: 0755]
Lsof.8 [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
NEWS [new file with mode: 0644]
README [new symlink]
README.md [new file with mode: 0644]
autotools/autotools.h.in [new file with mode: 0644]
autotools/version.h.in [new file with mode: 0644]
check.bash [new file with mode: 0755]
configure.ac [new file with mode: 0644]
default.nix [new file with mode: 0644]
docs/contributing.md [new file with mode: 0644]
docs/credits.md [new file with mode: 0644]
docs/faq.md [new file with mode: 0644]
docs/getting-started.md [new file with mode: 0644]
docs/index.md [new file with mode: 0644]
docs/maintaining.md [new file with mode: 0644]
docs/manpage.md [new file with mode: 0644]
docs/manpage.sh [new file with mode: 0755]
docs/options.md [new file with mode: 0644]
docs/requirements.in [new file with mode: 0644]
docs/requirements.txt [new file with mode: 0644]
docs/tutorial.md [new file with mode: 0644]
include/lsof.h [new file with mode: 0644]
include/lsof_fields.h [new file with mode: 0644]
lib/Makefile.skel [new file with mode: 0644]
lib/ckkv.c [new file with mode: 0644]
lib/common.h [new file with mode: 0644]
lib/cvfs.c [new file with mode: 0644]
lib/dialects/aix/Makefile [new file with mode: 0644]
lib/dialects/aix/Mksrc [new file with mode: 0755]
lib/dialects/aix/aix5/README [new file with mode: 0644]
lib/dialects/aix/aix5/j2/j2_lock.h [new file with mode: 0644]
lib/dialects/aix/aix5/j2/private_j2_snapshot.h [new file with mode: 0644]
lib/dialects/aix/ddev.c [new file with mode: 0644]
lib/dialects/aix/dfile.c [new file with mode: 0644]
lib/dialects/aix/dlsof.h [new file with mode: 0644]
lib/dialects/aix/dmnt.c [new file with mode: 0644]
lib/dialects/aix/dnode.c [new file with mode: 0644]
lib/dialects/aix/dnode1.c [new file with mode: 0644]
lib/dialects/aix/dnode2.c [new file with mode: 0644]
lib/dialects/aix/dproc.c [new file with mode: 0644]
lib/dialects/aix/dproto.h [new file with mode: 0644]
lib/dialects/aix/dsock.c [new file with mode: 0644]
lib/dialects/aix/dstore.c [new file with mode: 0644]
lib/dialects/aix/machine.h [new file with mode: 0644]
lib/dialects/hpux/kmem/Makefile [new file with mode: 0644]
lib/dialects/hpux/kmem/Mksrc [new file with mode: 0755]
lib/dialects/hpux/kmem/dfile.c [new file with mode: 0644]
lib/dialects/hpux/kmem/dlsof.h [new file with mode: 0644]
lib/dialects/hpux/kmem/dmnt.c [new file with mode: 0644]
lib/dialects/hpux/kmem/dnode.c [new file with mode: 0644]
lib/dialects/hpux/kmem/dnode1.c [new file with mode: 0644]
lib/dialects/hpux/kmem/dnode2.c [new file with mode: 0644]
lib/dialects/hpux/kmem/dproc.c [new file with mode: 0644]
lib/dialects/hpux/kmem/dproto.h [new file with mode: 0644]
lib/dialects/hpux/kmem/dsock.c [new file with mode: 0644]
lib/dialects/hpux/kmem/dstore.c [new file with mode: 0644]
lib/dialects/hpux/kmem/hpux11/ipc_s.h [new file with mode: 0644]
lib/dialects/hpux/kmem/hpux11/kernbits.h [new file with mode: 0644]
lib/dialects/hpux/kmem/hpux11/lla.h [new file with mode: 0644]
lib/dialects/hpux/kmem/hpux11/nfs_clnt.h [new file with mode: 0644]
lib/dialects/hpux/kmem/hpux11/proc.h [new file with mode: 0644]
lib/dialects/hpux/kmem/hpux11/rnode.h [new file with mode: 0644]
lib/dialects/hpux/kmem/hpux11/sth.h [new file with mode: 0644]
lib/dialects/hpux/kmem/hpux11/tcp_s.h [new file with mode: 0644]
lib/dialects/hpux/kmem/hpux11/udp_s.h [new file with mode: 0644]
lib/dialects/hpux/kmem/hpux11/vnode.h [new file with mode: 0644]
lib/dialects/hpux/kmem/machine.h [new file with mode: 0644]
lib/dialects/hpux/pstat/Makefile [new file with mode: 0644]
lib/dialects/hpux/pstat/Mksrc [new file with mode: 0755]
lib/dialects/hpux/pstat/dfile.c [new file with mode: 0644]
lib/dialects/hpux/pstat/dlsof.h [new file with mode: 0644]
lib/dialects/hpux/pstat/dproc.c [new file with mode: 0644]
lib/dialects/hpux/pstat/dproto.h [new file with mode: 0644]
lib/dialects/hpux/pstat/dsock.c [new file with mode: 0644]
lib/dialects/hpux/pstat/dstore.c [new file with mode: 0644]
lib/dialects/hpux/pstat/machine.h [new file with mode: 0644]
lib/dialects/linux/Makefile [new file with mode: 0644]
lib/dialects/linux/Mksrc [new file with mode: 0755]
lib/dialects/linux/dfile.c [new file with mode: 0644]
lib/dialects/linux/dlsof.h [new file with mode: 0644]
lib/dialects/linux/dmnt.c [new file with mode: 0644]
lib/dialects/linux/dnode.c [new file with mode: 0644]
lib/dialects/linux/dproc.c [new file with mode: 0644]
lib/dialects/linux/dproto.h [new file with mode: 0644]
lib/dialects/linux/dsock.c [new file with mode: 0644]
lib/dialects/linux/dstore.c [new file with mode: 0644]
lib/dialects/linux/machine.h [new file with mode: 0644]
lib/dialects/linux/tests/Makefile [new file with mode: 0644]
lib/dialects/linux/tests/case-00-linux-hello.bash [new file with mode: 0755]
lib/dialects/linux/tests/case-10-mqueue.bash [new file with mode: 0755]
lib/dialects/linux/tests/case-10-ux-socket-state.bash [new file with mode: 0755]
lib/dialects/linux/tests/case-20-epoll.bash [new file with mode: 0755]
lib/dialects/linux/tests/case-20-eventfd-endpoint.bash [new file with mode: 0755]
lib/dialects/linux/tests/case-20-inet-socket-endpoint.bash [new file with mode: 0755]
lib/dialects/linux/tests/case-20-inet6-ffffffff-handling.bash [new file with mode: 0755]
lib/dialects/linux/tests/case-20-inet6-socket-endpoint.bash [new file with mode: 0755]
lib/dialects/linux/tests/case-20-mmap.bash [new file with mode: 0755]
lib/dialects/linux/tests/case-20-mqueue-endpoint.bash [new file with mode: 0755]
lib/dialects/linux/tests/case-20-open-flags-cx.bash [new file with mode: 0755]
lib/dialects/linux/tests/case-20-open-flags-path.bash [new file with mode: 0755]
lib/dialects/linux/tests/case-20-open-flags-tmpf.bash [new file with mode: 0755]
lib/dialects/linux/tests/case-20-pidfd-pid.bash [new file with mode: 0755]
lib/dialects/linux/tests/case-20-pipe-endpoint.bash [new file with mode: 0755]
lib/dialects/linux/tests/case-20-pipe-no-close-endpoint.bash [new file with mode: 0755]
lib/dialects/linux/tests/case-20-pty-endpoint.bash [new file with mode: 0755]
lib/dialects/linux/tests/case-20-ux-socket-endpoint-unaccepted.bash [new file with mode: 0755]
lib/dialects/linux/tests/case-20-ux-socket-endpoint.bash [new file with mode: 0755]
lib/dialects/linux/tests/epoll.c [new file with mode: 0644]
lib/dialects/linux/tests/eventfd.c [new file with mode: 0644]
lib/dialects/linux/tests/mmap.c [new file with mode: 0644]
lib/dialects/linux/tests/mount-and-mmap.bash [new file with mode: 0755]
lib/dialects/linux/tests/mq_fork.c [new file with mode: 0644]
lib/dialects/linux/tests/mq_open.c [new file with mode: 0644]
lib/dialects/linux/tests/open_with_flags.c [new file with mode: 0644]
lib/dialects/linux/tests/pidfd.c [new file with mode: 0644]
lib/dialects/linux/tests/pipe.c [new file with mode: 0644]
lib/dialects/linux/tests/pty.c [new file with mode: 0644]
lib/dialects/linux/tests/util-open-flags.bash [new file with mode: 0644]
lib/dialects/linux/tests/ux.c [new file with mode: 0644]
lib/dialects/netbsd/Makefile [new file with mode: 0644]
lib/dialects/netbsd/Mksrc [new file with mode: 0755]
lib/dialects/netbsd/dlsof.h [new file with mode: 0644]
lib/dialects/netbsd/dmnt.c [new file with mode: 0644]
lib/dialects/netbsd/dnode.c [new file with mode: 0644]
lib/dialects/netbsd/dnode1.c [new file with mode: 0644]
lib/dialects/netbsd/dproc.c [new file with mode: 0644]
lib/dialects/netbsd/dproto.h [new file with mode: 0644]
lib/dialects/netbsd/dsock.c [new file with mode: 0644]
lib/dialects/netbsd/dstore.c [new file with mode: 0644]
lib/dialects/netbsd/machine.h [new file with mode: 0644]
lib/dialects/openbsd/Makefile [new file with mode: 0644]
lib/dialects/openbsd/Mksrc [new file with mode: 0755]
lib/dialects/openbsd/dfile.c [new file with mode: 0644]
lib/dialects/openbsd/dlsof.h [new file with mode: 0644]
lib/dialects/openbsd/dmnt.c [new file with mode: 0644]
lib/dialects/openbsd/dnode.c [new file with mode: 0644]
lib/dialects/openbsd/dproc.c [new file with mode: 0644]
lib/dialects/openbsd/dproto.h [new file with mode: 0644]
lib/dialects/openbsd/dsock.c [new file with mode: 0644]
lib/dialects/openbsd/dstore.c [new file with mode: 0644]
lib/dialects/openbsd/machine.h [new file with mode: 0644]
lib/dialects/openbsd/tests/case-00-openbsd-hello.bash [new file with mode: 0755]
lib/dialects/sun/Makefile [new file with mode: 0644]
lib/dialects/sun/Mksrc [new file with mode: 0755]
lib/dialects/sun/ddev.c [new file with mode: 0644]
lib/dialects/sun/dfile.c [new file with mode: 0644]
lib/dialects/sun/distfile.kvm [new file with mode: 0644]
lib/dialects/sun/dlsof.h [new file with mode: 0644]
lib/dialects/sun/dmnt.c [new file with mode: 0644]
lib/dialects/sun/dnode.c [new file with mode: 0644]
lib/dialects/sun/dnode1.c [new file with mode: 0644]
lib/dialects/sun/dnode2.c [new file with mode: 0644]
lib/dialects/sun/dproc.c [new file with mode: 0644]
lib/dialects/sun/dproto.h [new file with mode: 0644]
lib/dialects/sun/dsock.c [new file with mode: 0644]
lib/dialects/sun/dstore.c [new file with mode: 0644]
lib/dialects/sun/machine.h [new file with mode: 0644]
lib/dialects/sun/solaris_kaddr_filters [new file with mode: 0644]
lib/dvch.c [new file with mode: 0644]
lib/fino.c [new file with mode: 0644]
lib/hash.h [new file with mode: 0644]
lib/isfn.c [new file with mode: 0644]
lib/lkud.c [new file with mode: 0644]
lib/lsof.c [new file with mode: 0644]
lib/misc.c [new file with mode: 0644]
lib/node.c [new file with mode: 0644]
lib/pdvn.c [new file with mode: 0644]
lib/prfp.c [new file with mode: 0644]
lib/print.c [new file with mode: 0644]
lib/proc.c [new file with mode: 0644]
lib/proto.h [new file with mode: 0644]
lib/ptti.c [new file with mode: 0644]
lib/rdev.c [new file with mode: 0644]
lib/rmnt.c [new file with mode: 0644]
lib/rnam.c [new file with mode: 0644]
lib/rnch.c [new file with mode: 0644]
lib/rnmh.c [new file with mode: 0644]
lib/rnmt.c [new file with mode: 0644]
m4/.gitignore [new file with mode: 0644]
m4/header.m4 [new file with mode: 0644]
mkdocs.yml [new file with mode: 0644]
scripts/00MANIFEST [new file with mode: 0644]
scripts/00README [new file with mode: 0644]
scripts/big_brother.pl [new file with mode: 0755]
scripts/count_pf.pl [new file with mode: 0755]
scripts/identd.pl [new file with mode: 0755]
scripts/idrlogin.pl [new file with mode: 0755]
scripts/list_NULf.pl [new file with mode: 0755]
scripts/list_fields.awk [new file with mode: 0644]
scripts/list_fields.pl [new file with mode: 0755]
scripts/shared.pl [new file with mode: 0755]
scripts/sort_res.pl [new file with mode: 0755]
scripts/watch_a_file.pl [new file with mode: 0755]
scripts/xusers.awk [new file with mode: 0755]
src/arg.c [new file with mode: 0644]
src/cli.h [new file with mode: 0644]
src/dialects/linux/dprint.c [new file with mode: 0644]
src/main.c [new file with mode: 0644]
src/print.c [new file with mode: 0644]
src/ptti.c [new file with mode: 0644]
src/store.c [new file with mode: 0644]
src/usage.c [new file with mode: 0644]
src/util.c [new file with mode: 0644]
support/AIXDistrib [new file with mode: 0755]
support/DarwinDistrib [new file with mode: 0755]
support/Distfile.msrc [new file with mode: 0644]
support/FreeBSDDistrib [new file with mode: 0755]
support/GPGDistrib [new file with mode: 0755]
support/GenericCopy [new file with mode: 0755]
support/GenericDistrib [new file with mode: 0755]
support/GenericDistrib2 [new symlink]
support/GenericRdist [new file with mode: 0755]
support/GenericSubdir [new file with mode: 0755]
support/GitHub-release/00README [new file with mode: 0644]
support/GitHub-release/ITaP [new file with mode: 0644]
support/GitHub-release/Purdue [new file with mode: 0644]
support/HPUXDistrib [new file with mode: 0755]
support/NSDistrib [new file with mode: 0755]
support/NetBSDDistrib [new file with mode: 0755]
support/OSRDistrib [new file with mode: 0755]
support/OpenBSDDistrib [new file with mode: 0755]
support/SpecialRdist [new file with mode: 0755]
support/SunDistrib [new file with mode: 0755]
support/UWDistrib [new file with mode: 0755]
support/argtest [new file with mode: 0755]
support/binaries/README [new file with mode: 0644]
support/contrib.00INDEX [new file with mode: 0644]
support/contrib.README [new file with mode: 0644]
support/install-lsof [new file with mode: 0755]
support/install.log [new file with mode: 0644]
support/look_rlog [new file with mode: 0755]
support/lsof-log.xls [new file with mode: 0644]
support/lsof.00INDEX [new file with mode: 0644]
support/lsof.README [new file with mode: 0644]
support/makeman [new file with mode: 0755]
support/mentor [new file with mode: 0755]
support/mirrors [new file with mode: 0644]
support/rdist.distrib [new file with mode: 0755]
tests/00README [new file with mode: 0644]
tests/Add2TestDB [new file with mode: 0755]
tests/CkTestDB [new file with mode: 0755]
tests/LTbasic.c [new file with mode: 0644]
tests/LTbasic2.c [new file with mode: 0644]
tests/LTbigf.c [new file with mode: 0644]
tests/LTdnlc.c [new file with mode: 0644]
tests/LTlib.c [new file with mode: 0644]
tests/LTlock.c [new file with mode: 0644]
tests/LTnfs.c [new file with mode: 0644]
tests/LTnlink.c [new file with mode: 0644]
tests/LTsock.c [new file with mode: 0644]
tests/LTszoff.c [new file with mode: 0644]
tests/LTunix.c [new file with mode: 0644]
tests/LsofTest.h [new file with mode: 0644]
tests/Makefile [new file with mode: 0644]
tests/TestDB [new file with mode: 0644]
tests/case-00-hello.bash [new file with mode: 0755]
tests/case-01-version.bash [new file with mode: 0755]
tests/case-13-classic.bash [new file with mode: 0755]
tests/case-14-classic-opt.bash [new file with mode: 0755]
tests/case-20-exit-status.bash [new file with mode: 0755]
tests/case-20-fd-only-inclusion.bash [new file with mode: 0755]
tests/case-20-handle-missing-files.bash [new file with mode: 0755]
tests/case-20-offset-field.bash [new file with mode: 0755]
tests/case-20-repeat-count.bash [new file with mode: 0755]
tests/case-21-exit-Q-status.bash [new file with mode: 0755]
tests/case-22-empty-process-name.bash [new file with mode: 0755]
tests/common.bash [new file with mode: 0644]
version [new file with mode: 0644]
version.in [new file with mode: 0644]
zipme [new file with mode: 0755]

diff --git a/.builds/netbsd.yml b/.builds/netbsd.yml
new file mode 100644 (file)
index 0000000..f053658
--- /dev/null
@@ -0,0 +1,25 @@
+image: netbsd/9.x
+packages:
+  - autoconf
+  - automake
+  - pkg-config
+  - libtool
+  - groff
+tasks:
+  - syssrc: |
+      curl https://cdn.netbsd.org/pub/NetBSD/NetBSD-9.2/source/sets/syssrc.tgz -o syssrc.tgz
+      sudo mkdir -p /usr/src
+      cd / && sudo tar -zxf ~/syssrc.tgz
+  - setup: |
+      cd lsof
+      autoreconf -vif
+      ./configure
+  - build: |
+      cd lsof
+      export PATH=/usr/pkg/gnu/bin:$PATH
+      make
+  - test: |
+      cd lsof
+      export PATH=/usr/pkg/gnu/bin:$PATH
+      sudo make check
+      sudo make distcheck
diff --git a/.builds/openbsd.yml b/.builds/openbsd.yml
new file mode 100644 (file)
index 0000000..a74e21f
--- /dev/null
@@ -0,0 +1,29 @@
+image: openbsd/7.2
+packages:
+  - autoconf-2.71
+  - automake-1.16.5
+  - pkgconf
+  - libtool
+  - groff
+tasks:
+  - legacy: |
+      cd lsof
+      ./Configure -n openbsd
+      make
+      bash ./check.bash openbsd
+      git clean -fdx .
+  - setup: |
+      cd lsof
+      export AUTOCONF_VERSION=2.71
+      export AUTOMAKE_VERSION=1.16
+      autoreconf -vif
+      ./configure
+  - build: |
+      cd lsof
+      make
+  - test: |
+      cd lsof
+      export AUTOCONF_VERSION=2.71
+      export AUTOMAKE_VERSION=1.16
+      make check
+      make distcheck
diff --git a/.circleci/config.yml b/.circleci/config.yml
new file mode 100644 (file)
index 0000000..7baebeb
--- /dev/null
@@ -0,0 +1,173 @@
+# Use the latest 2.1 version of CircleCI pipeline process engine.
+# See: https://circleci.com/docs/2.0/configuration-reference
+version: 2.1
+
+executors:
+  ubuntu2204:
+    machine:
+      image: ubuntu-2204:2022.10.2 
+  alpine317:
+    docker:
+      - image: docker.io/alpine:3.17
+  opensuse15:
+    docker:
+      - image: docker.io/opensuse/leap:15
+  archlinux:
+    docker:
+      - image: docker.io/archlinux:latest
+  debian11:
+    docker:
+      - image: docker.io/debian:11
+  fedora37:
+    docker:
+      - image: docker.io/fedora:37
+  fedora38:
+    docker:
+      - image: docker.io/fedora:38
+  centos8:
+    docker:
+      - image: quay.io/centos/centos:stream8
+  centos9:
+    docker:
+      - image: quay.io/centos/centos:stream9
+
+# Define a job to be invoked later in a workflow.
+# See: https://circleci.com/docs/2.0/configuration-reference/#jobs
+jobs:
+  linux:
+    parameters:
+      distro:
+        type: executor
+    executor: << parameters.distro >>
+    steps:
+      - run:
+          name: Install build tools
+          command: |
+            dnf -y install autoconf automake gcc git iproute libtool make nmap-ncat pkg-config procps sudo || true
+            dnf -y install libtirpc-devel || true
+            dnf -y install make || true
+            apt update || true
+            apt install -y autoconf automake gcc git groff iproute2 libtirpc-dev libtool make ncat pkg-config procps sudo || true
+            pacman -Sy --noconfirm autoconf automake gcc git groff iproute2 libtool make pkg-config procps sudo || true
+            zypper install -y autoconf automake gcc git groff gzip iproute2 libtool make pkg-config procps sudo tar make || true
+            apk add sudo autoconf automake bash gcc git groff gzip iproute2 libtool linux-headers make musl-dev nmap-ncat pkgconf strace which || true
+      - when:
+          condition:
+            equal: [ fedora38, << parameters.distro >> ]
+          steps:
+            - run:
+                command: |
+                  dnf -y install lcov gem procps python3-pip
+                  pip3 install --user cpp-coveralls
+      - checkout
+      - run:
+          name: Configure
+          command: |
+            ./Configure -n linux
+      - when:
+          condition:
+            equal: [ fedora38, << parameters.distro >> ]
+          steps:
+            - run:
+                name: Build
+                command: |
+                  CC="cc"
+                  CC_EXTRA="--coverage"
+                  make -j 2 CDEF="${CC_EXTRA}" CC="${CC} ${CC_EXTRA}"
+      - when:
+          condition:
+            not:
+              equal: [ fedora38, << parameters.distro >> ]
+          steps:
+            - run:
+                name: Build
+                command: |
+                  make -j 2
+      - run:
+          name: Test
+          command: |
+            bash ./check.bash linux
+      - when:
+          condition:
+            equal: [ fedora38, << parameters.distro >> ]
+          steps:
+            - run:
+                name: Report coverage
+                command: |
+                  lcov -c -b . -d . -o coverage.info
+                  /root/.local/bin/coveralls --root .
+      - run:
+          name: Build and test using autotools
+          command: |
+            git clean -fdx .
+            autoreconf -vif
+            ./configure
+            make
+            sudo make install
+            make check
+            cat test-suite.log
+            make distcheck
+  nixos:
+    docker:
+      - image: docker.io/nixos/nix:latest
+    steps:
+      - checkout
+      - run:
+          name: Build
+          command: |
+            nix-channel --update
+            nix-build
+  bigsur:
+    macos:
+      xcode: 12.5.1
+    steps:
+      - checkout
+      - run:
+          name: Install pkg-config
+          command: |
+            brew install pkg-config libtool
+      - run:
+          name: Configure
+          command: |
+            LSOF_INCLUDE=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include ./Configure -n darwin
+      - run:
+          name: Build
+          command: |
+            make -j 2
+      - run:
+          name: Test
+          command: |
+            bash ./check.bash darwin
+      - run:
+          name: Build using autotools
+          command: |
+            git clean -fdx .
+            autoreconf -vif
+            ./configure
+            make
+            make install
+            make check
+      - run:
+          name: Rebuild and test using distribution tarball
+          command: |
+            make dist
+            mkdir temp
+            cd temp
+            tar xvf ../lsof-*.tar.gz
+            cd lsof-*
+            ./configure
+            make
+            make install
+            make check
+
+# Invoke jobs via workflows
+# See: https://circleci.com/docs/2.0/configuration-reference/#workflows
+workflows:
+  gnulinux-workflow:
+    jobs:
+      - linux:
+          matrix:
+            parameters:
+              distro: [fedora37, fedora38, centos8, centos9, debian11, ubuntu2204, archlinux, opensuse15, alpine317]
+      - nixos
+      - bigsur
diff --git a/.cirrus.yml b/.cirrus.yml
new file mode 100644 (file)
index 0000000..a81f0a0
--- /dev/null
@@ -0,0 +1,23 @@
+task:
+  freebsd_instance:
+    cpu: 1
+    matrix:
+      - image_family: freebsd-14-0-snap
+      - image_family: freebsd-13-1
+      - image_family: freebsd-12-3
+  install_script: pkg install -y bash git autoconf automake libtool groff pkgconf
+  build_script:
+    - ./Configure -n freebsd
+    - make
+  test_script:
+    - bash ./check.bash freebsd
+  autotools_build_script:
+    - git clean -fdx .
+    - autoreconf -vif
+    - ./configure
+    - make
+    - make install
+  autotools_test_script:
+    - make check
+    - cat test-suite.log
+    - make distcheck
diff --git a/.ck00MAN b/.ck00MAN
new file mode 100644 (file)
index 0000000..8b13789
--- /dev/null
+++ b/.ck00MAN
@@ -0,0 +1 @@
+
diff --git a/.clang-format b/.clang-format
new file mode 100644 (file)
index 0000000..4c5f9db
--- /dev/null
@@ -0,0 +1,4 @@
+BasedOnStyle: LLVM
+IndentWidth: 4
+SortIncludes: Never
+IndentPPDirectives: AfterHash
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644 (file)
index 0000000..32c0248
--- /dev/null
@@ -0,0 +1,32 @@
+---
+name: Bug report
+about: Create a bug report to help us improve
+title: "[BUG]"
+labels: ''
+assignees: ''
+
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**To Reproduce**
+Steps to reproduce the behavior:
+1. Run '...'
+2. See error
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Program output**
+If applicable, paste program output text here to help explain your problem.
+
+**Environment (please complete the following information):**
+
+ - Kernel: [e.g. Linux]
+ - OS: [e.g. Debian]
+ - lsof Version: [e.g. 4.xx.x]
+ - Origin: [e.g. installed by package manager, built from release tarball or git]
+
+**Additional context**
+Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644 (file)
index 0000000..e0c0168
--- /dev/null
@@ -0,0 +1,20 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+title: "[FEATURE]"
+labels: ''
+assignees: ''
+
+---
+
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered**
+A clear and concise description of any alternative solutions or features you've considered.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644 (file)
index 0000000..dddd2c2
--- /dev/null
@@ -0,0 +1,27 @@
+name: C/C++ CI
+
+on:
+  push:
+  pull_request:
+    branches: [ "master" ]
+
+jobs:
+  build:
+    strategy:
+      matrix:
+        os: [ubuntu-22.04, ubuntu-20.04]
+    runs-on: ${{ matrix.os }}
+    steps:
+    - uses: actions/checkout@v3
+    - name: install dependencies
+      run: sudo apt install -y pkg-config
+    - name: autoconf
+      run: autoreconf -vif
+    - name: configure
+      run: ./configure
+    - name: make
+      run: make
+    - name: make check
+      run: make check
+    - name: make distcheck
+      run: make distcheck
diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..372c43d
--- /dev/null
@@ -0,0 +1,169 @@
+#
+# Glob patterns generated by GitHub
+#
+# Prerequisites
+*.d
+
+# Object files
+*.o
+*.ko
+*.obj
+*.elf
+
+# Linker output
+*.ilk
+*.map
+*.exp
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Libraries
+*.lib
+*.a
+*.la
+*.lo
+
+# Shared objects (inc. Windows DLLs)
+*.dll
+*.so
+*.so.*
+*.dylib
+
+# Executables
+*.exe
+*.out
+*.app
+*.i*86
+*.x86_64
+*.hex
+
+# Debug files
+*.dSYM/
+*.su
+*.idb
+*.pdb
+
+# Kernel Module Compile Results
+*.mod*
+*.cmd
+.tmp_versions/
+modules.order
+Module.symvers
+Mkfile.old
+dkms.conf
+
+#
+# Lsof specific patterns
+#
+
+# Generated files
+*.gcda
+*.gcno
+*~
+/Makefile
+lib/Makefile
+TAGS
+lsof
+lsof-netstat
+tags
+tests/config.*
+version.h
+autotools.h
+lockf_owner.h
+lockf.h
+lsof.man
+/site
+lib/dialects/netbsd/include
+/solaris11
+
+#
+# Symbolic links to lsof cli
+#
+/arg.c
+/dprint.c
+/main.c
+/misc.c
+/node.c
+/print.c
+/ptti.c
+/store.c
+/usage.c
+/util.c
+
+#
+# Symbolic links to a dialect implementation
+#
+/ddev.c
+/dfile.c
+/dlsof.h
+/dmnt.c
+/dnode.c
+/dnode1.c
+/dproc.c
+/dproto.h
+/dsock.c
+/dstore.c
+/machine.h
+
+#
+# Traditional test related files
+#
+LTbasic
+LTbasic2
+LTbigf
+LTdnlc
+LTlock
+LTnfs
+LTnlink
+LTshm2
+LTsock
+LTszoff
+LTszoff2
+LTunix
+LTunix2
+
+#
+# Dialect specific test related files
+#
+lib/dialects/linux/tests/epoll
+lib/dialects/linux/tests/eventfd
+lib/dialects/linux/tests/mq_fork
+lib/dialects/linux/tests/mq_open
+lib/dialects/linux/tests/open_with_flags
+lib/dialects/linux/tests/pidfd
+lib/dialects/linux/tests/pipe
+lib/dialects/linux/tests/pty
+lib/dialects/linux/tests/ux
+lib/dialects/linux/tests/mmap
+
+# automake
+Makefile.in
+.libs/
+.deps/
+.dirstamp
+*.log
+*.trs
+
+# autoconf
+autom4te.cache
+/aclocal.m4
+/compile
+/config.guess
+/config.log
+/config.status
+/config.sub
+/config.h
+/config.h.in
+/configure
+/depcomp
+/install-sh
+/libtool
+/ltmain.sh
+/missing
+/stamp-h1
+/test-driver
+
+# Doxygen
+/output
diff --git a/.readthedocs.yaml b/.readthedocs.yaml
new file mode 100644 (file)
index 0000000..2f2f085
--- /dev/null
@@ -0,0 +1,21 @@
+# .readthedocs.yaml
+# Read the Docs configuration file
+# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
+
+# Required
+version: 2
+
+# Set the version of Python and other tools you might need
+build:
+  os: ubuntu-22.04
+  tools:
+    python: "3.10"
+
+mkdocs:
+  configuration: mkdocs.yml
+
+# Optionally declare the Python requirements required to build your docs
+python:
+   install:
+   - requirements: docs/requirements.txt
+
diff --git a/.travis.yml b/.travis.yml
new file mode 100644 (file)
index 0000000..e840122
--- /dev/null
@@ -0,0 +1,73 @@
+#
+# Derived from
+# https://github.com/steveno/ctags/blob/master/.travis.yml
+#
+
+dist: xenial
+
+language: c
+
+os:
+  - linux
+  - osx
+
+compiler:
+  - gcc
+  - clang
+
+sudo: true
+
+addons:
+  apt:
+    packages:
+      - lcov
+      - procps
+      - netcat
+before_install:
+  - |
+    gem install lcoveralls
+
+script:
+  - |
+    case $TRAVIS_OS_NAME in
+        linux) dialect=linux;;
+        osx)   dialect=darwin;;
+    esac
+    ./Configure -n $dialect
+
+  - |
+    if [ $CC = 'gcc' ]; then
+        CC_EXTRA="--coverage"
+    fi
+    make CDEF="${CC_EXTRA}" CC="${CC} ${CC_EXTRA}"
+
+  - |
+    case $TRAVIS_OS_NAME in
+        linux) dialect=linux;;
+        osx)   dialect=darwin;;
+    esac
+    tdir=dialects/${dialect}/tests
+    if [ -f ${tdir}/Makefile ]; then
+        make -C "${tdir}"
+    fi
+
+  - |
+    case $TRAVIS_OS_NAME in
+        linux) dialect=linux;;
+        osx)   dialect=darwin;;
+    esac
+    sudo -E bash ./check.bash $dialect
+
+after_success:
+  - |
+    if [ $CC = 'gcc' ] && [ $TRAVIS_OS_NAME = 'linux' ]; then
+    (
+            for f in /home/travis/.rvm/gems/ruby-2*/gems/lcoveralls-*/lib/lcoveralls/color_formatter.rb; do
+                    sed -i -e 's/severity.capitalize!/severity = severity.capitalize/' $f
+            done
+            for f in /home/travis/.rvm/gems/ruby-2*/gems/lcoveralls-*/lib/lcoveralls/runner.rb; do
+                    sed -i -e 's/\(.*format.*f\)\(%\)\('"'"'.*$\)/\1%%\3/' $f
+            done
+    ) || :
+    lcov -c -b . -d . -o coverage.info && lcoveralls --root . --retry-count 5 coverage.info
+    fi
diff --git a/0..README.BEFORE.README.FIRST b/0..README.BEFORE.README.FIRST
new file mode 120000 (symlink)
index 0000000..61cfe9a
--- /dev/null
@@ -0,0 +1 @@
+./README.md
\ No newline at end of file
diff --git a/00.README.FIRST b/00.README.FIRST
new file mode 100644 (file)
index 0000000..ea1355c
--- /dev/null
@@ -0,0 +1,48 @@
+Now that you have the lsof distribution, I suggest:
+
+*  If you're unfamiliar with lsof, read 00README for information on
+   Configuring and building lsof, 00QUICKSTART for tips on using lsof.
+
+   If you're too impatient for that, do this:
+
+      $ ./Configure <put your UNIX dialect's abbreviation here>
+        (Do the inventory step, as you prefer.)
+        (Do the customization step, as you prefer.)
+      $ make
+      $ ./lsof -h
+
+   To get a list of UNIX dialect abbreviations:
+
+      $ Configure -h
+
+   Please don't be impatient -- read the documentation first.
+
+*  Read the current distribution's details in 00DIST.  (The
+   ChangeLog file points to 00DIST.)
+
+*  If you want technical details, read 00DCACHE and 00PORTING.
+
+*  If you want to cross-configure, read 00XCONFIG.
+
+*  Use the test suite, described in 00TEST, by:
+
+       $ cd tests
+       $ make
+
+   and possibly:
+
+       $ make opt
+
+*  If you're having trouble, read 00FAQ.  (Please read 00FAQ before
+   you send a bug report.)
+
+*  Lsof contributors may find their names in 00CREDITS.  (Thanks, again.)
+
+*  Read the lsof.man page file.  Its nroff source is in lsof.8.
+
+*  Consider subscribing to the lsof-l mailing list -- read 00LSOF-L
+   for details.
+
+
+Vic Abell <abe@purdue.edu>
+January 2, 2013
diff --git a/00CREDITS b/00CREDITS
new file mode 100644 (file)
index 0000000..47fbb22
--- /dev/null
+++ b/00CREDITS
@@ -0,0 +1 @@
+This documentation has been replaced by docs/credits.md. Please refer to the new file or read it online.
\ No newline at end of file
diff --git a/00DCACHE b/00DCACHE
new file mode 100644 (file)
index 0000000..21984f4
--- /dev/null
+++ b/00DCACHE
@@ -0,0 +1,742 @@
+
+       Configuring The Device Cache File Path
+
+                           Contents
+
+               A.  Introduction and History
+               B.  Device Cache File Format
+                   1.  Integrity Checks
+                   2.  The Setgid and Setuid-root States
+               C. Device Cache File Path Options
+                   1.  Path Named by ``-D''
+                   2.  Path Named in Environment Variable
+                   3.  Default System-wide Path
+                       a.  Build Procedure
+                   4.  Default Personal Path
+                   5.  Modified Default Personal Path
+               D. Displaying the Default Path
+               Appendix A, Unix Dialects Without a Device Cache
+               Appendix B, Lsof Dialects and Their Permissions
+                   1.  Setuid-root Lsof Dialects
+                   2.  Setgid Lsof Dialects That Surrender Setgid
+                       Permission
+
+
+A. Introduction and History
+===========================
+
+Lsof writes a file of information about the contents of the nodes
+in /dev (or /devices) to reduce its startup overhead on later calls.
+It does this for all Unix dialects, except those noted in Appendix A.
+
+This file, called the device cache file, enables lsof to avoid
+calling the kernel stat(2) function on every node in /dev (or
+/devices) from which it builds a table of correspondence between
+major/minor device numbers and device names.
+
+A full scan of /dev (or /devices) on some systems may involve
+calling the sometimes-slow stat(2) function 10,000 times or more.
+Furthermore, each stat(2) call consumes space in the kernel's name
+cache, forcing from it path name components that would be more
+useful when lsof tries to associate them with open files.
+
+While it's hard to question the usefulness of the device cache,
+it's also hard to decide where it should be written.  When the
+feature was first added, the device cache file was written to /tmp,
+and its ownership was set to that of the real user ID (UID) under
+which the creating lsof process was run.  However, to enable any
+process to update it when /dev (or /devices) changed, lsof set its
+modes to 0666, thus allowing anyone to read or write it.
+
+The writing of a world-readable and world-writable device cache
+file to any place has security weaknesses.  A clever intruder who
+carefully preserves the integrity of the file might be able to
+remove devices that would prevent lsof from observing the intruder's
+files.  A clever intruder might also be able to put a symbolic link
+in place and trick lsof into writing to the link's destination with
+its effective permissions, thus bypassing the real user's (possibly
+weaker) permissions.
+
+Later the location of the device cache file was changed.  It was
+converted to a personal file, located in the home directory of each
+real UID that executed lsof, and owned by that UID.  Thus it was
+no longer possible for one user to affect lsof's access to the
+device cache file, nor was it possible for a user to mount a symbolic
+link attack on a restricted file, but the result was that each lsof
+user had a private copy of the device cache file.
+
+The device cache file feature has undergone some further refinements
+in path name formation to reach its present state.  This documentation
+describes the path name formation options open to the lsof builder
+and user after those refinements, and how lsof attempts to insure
+that none of the options presents a security risk.
+
+
+B. Device Cache File Format
+===========================
+
+The device cache file is a flat file of ASCII text.  It has an
+initial statement of how many sections the file might contain --
+the possible sections are character devices, block devices, clone
+devices, pseudo devices, and checksum.  The character devices and
+checksum sections are always present.
+
+Each section has a header that numbers the entries in the section.
+
+The last section is a checksum section that contains a 16 bit cyclic
+redundancy (CRC) checksum of everything in the file but the checksum
+section itself.
+
+Lsof always sets the permission modes of the device cache file to
+0600, and the owner to the real UID of the process that executes
+lsof; the group, the real group ID (GID) of the lsof process.
+
+Setting the permission modes to 0600 means that a system-wide device
+cache file won't be usable unless the procedure that builds it
+changes the modes after lsof has written it.  A suitable procedure
+for building a system-wide device cache that shows how to adjust
+these inadequate permission modes is given in the Default System-wide
+Path section.
+
+
+B.1. Integrity Checks
+=====================
+
+When lsof opens the device cache file it makes these integrity
+checks:
+
+    1.  Lsof must gain permission from access(2) to be able to
+       open the file for reading.  If lsof is writing the file,
+       it usually cedes permission control to the applicable
+       directory and file modes and ownerships.  (Some additional
+       checks apply and they're described in the sections on path
+       options.)
+
+       By explicit design lsof never writes to the system-wide
+       device cache file, even when the real UID of its process
+       is root.  The system-wide device cache file must be written
+       with a root-owned procedure via the ``-D[b|u<path>'' options
+       -- i.e., under the system administrator's control.  (See
+       the Build Procedure sub-section of the Default System-wide
+       Path section.)
+
+    2.  The device cache file's modes must be 0600 (0644 if lsof
+       is reading a system-wide device cache file) and its size
+       must be non-zero.
+
+    3.  There must be a correctly formatted section count line
+       at the beginning of the file.
+
+    4.  Each section must have a header line with a count that
+       properly numbers the lines in the section.  The first words
+       of legal section titles are "device", "block", "clone",
+       "pseudo", and "CRC".
+
+    5.  The lines of a section must have the proper format.
+
+    6.  All lines are included in a 16 bit CRC, and it is recorded
+       in a non-checksummed section line at the end of the file.
+
+    7.  The checksum computed when the file is read must match the
+       checksum recorded when the file was written.
+
+    8.  The checksum section line must be followed by end-of-
+       information.
+
+    9.  Lsof must be able to get matching results from stat(2)
+       on a randomly chosen entry of the device section.
+
+
+B.2. The Setgid and Setuid-root States
+======================================
+
+There are two fundamental ways in which lsof is granted access to
+restricted system resources.  Both access methods are related to the
+effective permissions given the lsof binary or executable.
+
+The first and preferable way to grant lsof access to system resources
+through the permissions endowed on its executable is the giving of
+set group ID (setgid) permission.  The group is the one that has
+permission to read the kernel memory and swap devices -- e.g., /dev/kmem,
+/dev/mem, /dev/swap, etc.
+
+This method of granting access is called setgid mode because it
+enables lsof to run with an effective group ID set to the one
+granted by the permissions of its executable file and by the group
+that owns the executable file.  See the getegid(2) man page for a
+further discussion of effective group ID.
+
+Usually lsof only needs setgid permission to open access to the
+kernel memory files.  After they're open, lsof drops its setgid
+permission.
+
+The second and least preferable way to grant lsof access to system
+resources through the permissions endowed on its executable is the
+giving of set user ID to root (setuid-root) permission.  This is
+much too strong a permission, but necessary: to use the -X option
+fully for the version of lsof for AIX 5 and above; to use the
+version of lsof for HP-UX 11.11 and above; and to use the version
+of lsof for Linux 2.1.72 and above.  These lsof implementations
+require setuid-root permission to be able to access restricted
+resources -- e.g., the individual files of the /proc file system.
+(But note that the setuid-root Linux lsof doesn't need and has no
+device cache support.)
+
+Lsof never drops setuid-root permission, because it needs that
+power throughout its execution.  However, when the lsof process is
+setuid-root, lsof disallows these device cache file path options:
+
+    1.  It ignores the ``-D[b|r|u]<path>'' options.  It accepts
+        only the ``-Di'' and ``-Dr'' options.
+
+    2. It refuses to recognize a path supplied via an environment
+       variable.
+
+    3.  It refuses to accept an additional path component from an
+       environment variable to be inserted in the middle of a
+       personal device cache file path.
+
+Each restriction is imposed because setuid-root power might allow
+a malicious user to form a device cache file path that would give
+read access to a normally inaccessible place (That's bad enough.),
+or write access to a critical system file (That's the worst case.)
+
+There is one further state that lsof can enter that is slightly
+different from the setuid-root and setgid states.  That state occurs
+when lsof is being run from a root shell -- i.e., the lsof real
+user ID is root.  To avoid accidental complications, when lsof is
+in this state, it ignores all environment variable options.
+
+In the rest of this document you will find more detailed discussion
+of the special restrictions caused by the type of permission that
+has been given the lsof executable.
+
+
+C. Device Cache File Path Options
+=================================
+
+Lsof offers five options for constructing the path to the device
+cache file.  Each has special conditions and safeguards that
+surround its use.  The options are:
+
+    1. A device cache file that is named in the <path> component
+       of the parameters of lsof's ``-D'' option.
+
+       =========================================================
+       * This is a default option of the lsof distribution.    *
+       *                                                       *
+       * Paths specified with this option are read-only unless *
+       * the real UID of the lsof process is root (0), or the  *
+       * lsof process is able to surrender setgid permission   *
+       * (See Appendix B) and it is not setuid-root.           *
+       =========================================================
+
+    2. A device cache file whose name is specified by an environment
+       variable.
+
+       =========================================================
+       * This is a default option of the lsof distribution.    *
+       *                                                       *
+       * This option is enabled when the lsof dialect is able  *
+       * to surrender setgid permission (See Appendix B.), and *
+       * the lsof process is not setuid-root.                  *
+       *                                                       *
+       * The environment variable path is read-only if the     *
+       * lsof process does not surrender setgid permission     *
+       * (See Appendix B.)                                     *
+       =========================================================
+
+    3. A system-wide default device cache file, located at a path
+       determined by the builder of lsof.  The lsof builder is also
+       responsible for building the device cache file, using a
+       different lsof path formation option at a suitable time --
+       e.g., when the system is booted.
+
+       =========================================================
+       * This is option is disabled by default in the lsof     *
+       * distribution.                                         *
+       *                                                       *
+       * The path specified with this option is read-only.     *
+       =========================================================
+
+    4. A default personal device cache file, located in the UID's
+       home directory.
+
+       =========================================================
+       * This is a default option of the lsof distribution.    *
+       =========================================================
+
+    5. A personal device cache file whose name is modified by an
+       environment variable.
+
+       =========================================================
+       * This is a default option of the lsof distribution.    *
+       *                                                       *
+       * The modified personal path is read-only if the lsof   *
+       * process does not surrender setgid permission.         *
+       *                                                       *
+       * This option is disabled when the lsof process is      *
+       * setuid-root or its real UID is root (0).              *
+       =========================================================
+
+When there are multiple choices for the device cache file path,
+lsof chooses from the above list in the order the list is given,
+subject to restrictions based on the effective group and user IDs
+that are in effect.
+
+Each possible path name is discussed in a later section that
+describes the restrictions that apply to it and the method for
+building lsof to use it.
+
+In one special case lsof will use two paths in order.  When a
+system-wide device cache file is enabled, and lsof finds that it
+doesn't exist, lsof will attempt to use a personal device cache
+file.
+
+
+C.1. Path Named by ``-D''
+=========================
+
+The ``-D[b|r|u]<path>'' option can name a path for the device cache
+file where it is unconditionally built (`b'); read, but never
+rebuilt (`r'); and read and rebuilt, if necessary (`u').
+
+If the lsof process is setuid-root, no path may be specified with
+the ``-D'' option -- i.e., only the `i' function is accepted.  The
+`r' option may be used if it doesn't have a path argument.
+
+If the lsof process is not setuid-root, nor is the real UID of the
+lsof process root, a path may accompany the `b', `r', and `u'
+functions if the lsof process surrenders setgid permission.  (See
+Appendix B.)  If the process doesn't surrender setgid permission,
+then a path may accompany only `r'.
+
+Lsof's permission to access a device cache file at a path specified
+with ``-D[b|r|u]<path>'' depends completely on the permission modes
+and ownerships of the file and its directory components.
+
+When the real UID of the lsof process is root (0), paths may be
+specified with ``-D[b|r|u]''.
+
+====================================================================
+*                                                                 *
+* The ``-D[b|r|u]<path>'' option is enabled by default in the lsof *
+* distribution by the following definition in the dialect's       *
+* machine.h header file:                                          *
+*                                                                 *
+*      #define HASDCACHE 1                                        *
+*                                                                 *
+* To disable all device cache file options, including all ``-D''   *
+* forms, change the above line in the dialect's machine.h file to: *
+*                                                                 *
+*      /* #define HASDCACHE 1 */                                  *
+*                                                                 *
+* or remove it.                                                           *
+*                                                                 *
+* The ``-D[b|r|u]<path>'' options are disabled when the lsof      *
+* process is setuid-root.  If the lsof process isn't setuid-root,  *
+* nor is its real UID root (0), and if the lsof process surrenders *
+* setgid permission, ``-D[b|r|u]'' may be accompanied by a path.   *
+*                                                                 *
+* A path may accompany ``-D[b|u]'' when the real UID of the lsof   *
+* process is root.                                                *
+*                                                                 *
+* ``-Dr'' without a path name argument is always acceptable.      *
+*                                                                 *
+====================================================================
+
+
+C.2. Path Named in Environment Variable
+=======================================
+
+A device cache file path may be declared in an environment variable.
+This option is defined in the dialect's machine.h header file with
+the HASENVDC definition.  The value of the HASENVDC definition is
+the environment variable's name.
+
+Lsof will use the value of the environment variable named by HASENVDC
+for the device cache file path unless either of the following
+conditions apply:
+
+    1. The lsof process is in the setuid-root state.
+or
+    2. The effective and real UIDs of the lsof process are root
+       (0).
+
+Lsof uses the value of the HASENVDC environment variable as the
+device cache file path after it senses there is no path declared by
+a ``-D'' option.
+
+A path from an environment variable is read-only unless the lsof
+process surrenders setgid permission.  (See Appendix B.)
+
+====================================================================
+*                                                                 *
+* The path name environment variable option is enabled by default, *
+* and the environment variable is named LSOFDEVCACHE in the lsof   *
+* distribution by the following definition in the dialect's       *
+* machine.h header file:                                          *
+*                                                                 *
+*      #define HASENVDC "LSOFDEVCACHE"                            *
+*                                                                 *
+* To disable the path name environment variable option, change    *
+* the above line in the dialect's machine.h header file to:       *
+*                                                                 *
+*      /* #define HASENVDC "LSOFDEVCACHE" */                      *
+*                                                                 *
+* or remove it.  To change the name of the environment variable,   *
+* change the quoted value of the HASENVDC definition -- e.g., this *
+* form changes the environment variable name to "FOOBAR":         *
+*                                                                 *
+*      #define HASENVDC "FOOBAR"                                  *
+*                                                                 *
+* You can disable the path name environment option by disabling           *
+* all device cache file processing when you remove or by disabling *
+* the HASDCACHE definition in the dialect's machine.h header file. *
+*                                                                 *
+* The path name environment option is disabled when the lsof      *
+* process is setuid-root or when the real UID of the lsof process  *
+* is root (0).                                                    *
+*                                                                 *
+* The path named in an environment variable is read-only unless    *
+* the lsof process surrenders setgid permission.  (See Appendix    *
+* B.)                                                             *
+*                                                                 *
+====================================================================
+
+
+C.3. Default System-wide Path
+=============================
+
+When a default system-wide device cache file path is defined (It's
+not enabled by default in the lsof distribution.), lsof will use
+it after it discovers no path has been specified by a ``-D'' option
+and no path has been specified in the environment variable named
+in the string #define HASENVDC of the dialect's machine.h header
+file.
+
+Lsof must be able to open the system-wide device cache file --
+i.e., it must have read access to the file and search access to
+the directories that lead it.  As part of its integrity checks,
+lsof requires that the system-wide device cache file's permission
+modes be 0644.
+
+When lsof discovers that the named system-wide device cache file
+doesn't exist, it will attempt to open a personal device cache file
+should that path formation option be enabled.  This is the *only*
+case where lsof will attempt to use two device cache file paths.
+
+The system-wide device cache file is read-only; lsof will never
+attempt to write to it.  However, when the real UID of the lsof
+process is root, that process may name the system-wide device
+cache file with ``-D[b|u]<path>''.
+
+====================================================================
+*                                                                 *
+* The system-wide file path option is disabled by default in the   *
+* lsof distribution.  This place-marking definition in a dialect's *
+* machine.h header file may be altered to enable a system-wide    *
+* device cache file path:                                         *
+*                                                                 *
+*      /* #define HASSYSDC "/your/choice/of/path" */              *
+*                                                                 *
+* To enable the system-wide name option, declaring that its path   *
+* is ``/foo/bar/lsof.dc'', change the above line in the dialect's   *
+* machine.h header file to:                                       *
+*                                                                 *
+*      #define HASSYSDC "/foo/bar/lsof.dc"                        *
+*                                                                 *
+* or change the quoted string of the definition to the path of    *
+* your choice.                                                    *
+*                                                                 *
+* You can disable the path name environment option by disabling           *
+* all device cache file processing when you remove or disable the  *
+* HASDCACHE definition in the dialect's machine.h header file.    *
+*                                                                 *
+* The system-wide device cache file is read-only.                 *
+*                                                                 *
+====================================================================
+
+
+C.3.a. Build Procedure
+======================
+
+The system administrator must build the system-wide device cache
+file at an appropriate time -- e.g., each time the system is booted,
+and each time a node is added, deleted or modified in /dev (or
+/devices).  The procedure that builds the system-wide device cache
+file must use lsof's ``-D[b|u]<path>'' options to build the file,
+and must change the file's permission modes to 0644 after it has
+been built.
+
+Here's a simple shell script procedure to build a system-wide device
+cache file.  It assumes:
+
+    1.  The Unix dialect's kernel supports the interpreter script
+       execution option -- i.e., a script whose first line has
+       the form ``#!<path_to_interpreter>''.
+
+    2. The chmod, echo, rm, sh, and test programs are located
+       in ``/bin''.
+
+    3. The string value of the HASSYSDC definition in the dialect's
+       machine.h header file is the path ``/your/choice/of/path''.
+
+    4. The lsof executable is located in ``/usr/local/etc''.
+
+       #!/bin/sh
+       #
+       # Simple script to build a system-wide device cache file
+       # for lsof.
+
+       HASSYSDC=/your/choice/of/path
+       /bin/rm -f $HASSYSDC
+       /usr/local/etc/lsof -Du$HASSYSDC > /dev/null 2>&1
+       if /bin/test $? -ne 0
+       then
+               /bin/echo "WARNING: failed to create $HASSYSDC"
+               exit 1
+       fi
+       /bin/chmod 0644 $HASSYSDC
+       exit 0
+
+The invocation of lsof uses the ``-Du$HASSYSDC'' option to read
+the device cache file and recreate it if necessary.  The invocation
+can be made more efficient if a known process PID -- e.g., ``-p1''
+-- can be specified.  However, if that PID is not always active
+when lsof is called, lsof might set its exit code non-zero, causing
+the subsequent test to believe that the lsof call failed.  When in
+doubt, omit the PID specification and accept the extra lsof processing
+time for reporting and discarding all open file information.
+
+
+C.4. Default Personal Path
+==========================
+
+The default personal path option is defined by default in the lsof
+distribution.  The path is formed of the home directory of the real
+UID of the lsof process, followed optionally by the contents of
+the HASPERSDCPATH environment variable, followed by ``.lsof_'',
+followed by the first component (characters up to the first period)
+of the name returned by gethostname(2).
+
+If gethostname(2) returns nothing, then nothing will follow the
+``.lsof_'' string.  If the first character of what gethostname(2)
+returns is a `.', then all the gethostname(2) value will follow
+the ``/lsof_'' string.  (See the ``%l'' conversion for a way to
+make lsof include the entire host name in the path.)
+
+====================================================================
+*                                                                 *
+* The personal path option is enabled by default in the lsof      *
+* distribution.  The HASPERSDC #define in a dialect's machine.h           *
+* header is a format specification that tells lsof how to form the *
+* personal device cache file path.  The conversions in the format  *
+* specification begin with `%' , ala the printf(3) function of the *
+* standard I/O library.  These conversions are supported:         *
+*                                                                 *
+*      ``%%''  causes a single `%' to appear in the path.         *
+*                                                                 *
+*      ``%0''  is a separator that marks the beginning of a path  *
+*              for a setuid-root lsof process or one whose real   *
+*              UID is 0.  When lsof reaches this conversion and   *
+*              the process is setuid-root or has a real UID of    *
+*              root, it erases any previously formed path and     *
+*              restarts with the next HASPERSDC format character. *
+*              If lsof reaches this conversion and the process is *
+*              not setuid-root and its real UID is not root, path *
+*              formation is ended.                                *
+*                                                                 *
+*      ``%h''  causes the home directory of the real UID of the   *
+*              lsof process to appear in the path.                *
+*                                                                 *
+*      ``%l''  causes the full name returned by gethostname(2) to *
+*              appear in the path.                                *
+*                                                                 *
+*      ``%L''  causes the first component of the name returned by *
+*              gethostname(2) to appear in the path.  The first   *
+*              component is defined to be what appears to the     *
+*              left of the first `.'.  If nothing appears to the  *
+*              left then everything will appear in the path.      *
+*                                                                 *
+*      ``%p''  causes the value of (HASPERSDCPATH) from the       *
+*              process environment to appear in the path.  If the *
+*              (HASPERSDCPATH) value doesn't end in a '/', one    *
+*              will be added.                                     *
+*                                                                 *
+*      ``%u''  causes the login name associated with the real UID *
+*              of the lsof process to appear in the path.         *
+*                                                                 *
+*      ``%U''  causes the real UID of the lsof process, converted *
+*              to a decimal string, to appear in the path.        *
+*                                                                 *
+*      All other characters are copied from the format to the     *
+*      path.  CAUTION: THINK VERY CAREFULLY ABOUT THE EFFECT OF   *
+*      USING CHARACTERS THAT FORM AN ABSOLUTE COMPONENT LIKE      *
+*      ``/tmp'' IN THE FORMAT.  Consider what power your dialect  *
+*      might have (e.g., if it is setuid-root) when lsof must     *
+*      create a device cache file at the path.  Consider using a  *
+*      ``%0'' conversion to declare an alternate path for lsof    *
+*      processes that are setuid-root or whose real uid is root.  *
+*      See the "How do I put the personal device cache file in    *
+*      /tmp?" question and answer in 00FAQ for an explanation of  *
+*      this example:                                              *
+*                                                                 *
+*          #define HASPERSDC "/tmp/.lsof_%u_%l_pers%0%h/.lsof_%L" *
+*                                                                 *
+* This is the format specification that appears in the machine.h   *
+* header files of the lsof distribution:                          *
+*                                                                 *
+*      #define HASPERSDC "%h/%p.lsof_%L"                          *
+*                                                                 *
+* It causes the path to be formed from the home directory of the   *
+* real UID of the lsof process (``%h''), followed by `/', followed *
+* by the contents of the environment variable named by            *
+* HASPERSDCPATH and a trailing `/', as needed (``%p''), followed   *
+* by the string ``.lsof_'', and terminated with the first         *
+* component of the host's name (``%L'').                          *
+*                                                                 *
+* To change the personal path option, change the HASPERSDC string  *
+* and recompile lsof.  To disable the personal path option, remove *
+* or disable HASPERSDC.  The personal path option is disabled when *
+* HASDCACHE is not defined.                                       *
+*                                                                 *
+====================================================================
+
+
+C.5. Modified Default Personal Path
+===================================
+
+The modified default personal path form is a special case of the
+default personal path.  In this form the value of the environment
+variable named by the HASPERSDCPATH #define is inserted in the
+personal path when the ``%p'' conversion appears in the HASPERSDC
+format specification.
+
+This allows, for example, the lsof user to move personal device
+cache files to another branch of the home directory, perhaps to a
+sub-directory where multiple device cache files may appear from
+different machines that use the same NFS- mounted home directory.
+
+The HASPERSDCPATH definition of the dialect's machine.h header file
+names the environment variable.  By default in the lsof distribution
+it is LSOFPERSDCPATH.
+
+The modified personal path component is ignored when lsof process
+is setuid-root is root, lest it be maliciously or accidentally used in
+some convoluted form to access paths the real UID cannot.  The
+modified personal path component is also ignored when the real UID
+of the lsof process is root (0), so that lsof will not accidentally
+use a personal environment value.
+
+If the lsof process surrenders setgid permission (See Appendix B.),
+lsof can read from and write to the modified personal path.  If,
+however, the lsof process doesn't surrender setgid permission, the
+modified personal path is read-only.
+
+If your dialect runs setuid-root or doesn't surrender its setgid
+permission, and you want to use the LSOFPERSDCPATH environment
+variable to address a collection of device cache files in a
+subdirectory, you will have to gather the collection in the
+subdirectory yourself with shell copy or move commands.
+
+====================================================================
+*                                                                 *
+* The modified personal path option is enabled by default in the   *
+* lsof distribution with these definitions in the dialect's       *
+* machine.h header file:                                          *
+*                                                                 *
+*      #define HASPERSDCPATH "LSOFPERSDCPATH"                     *
+* and                                                             *
+*      #define HASPERSDC "%h/%p.lsof_%L"                          *
+*                                                                 *
+* The value of the definition is the name of the environment      *
+* variable that contains the modified personal path name          *
+* component that is inserted in the personal path when ``%p''      *
+* appears in HASPERSDC.  See the Default Personal Path section    *
+* for a complete description of the ``%p'' conversion.            *
+*                                                                 *
+* To disable the modified personal path name component, disable           *
+* the HASPERSDCPATH definition in the dialect's machine.h header   *
+* file -- e.g., change it to:                                     *
+*                                                                 *
+*      /* #define HASPERSDCPATH "LSOFPERSDCPATH" */               *
+*                                                                 *
+* or remove the definition altogether.  If you do this, don't     *
+* forget to remove any ``%p'' conversion from HASPERSDC.          *
+*                                                                 *
+* The modified personal path option is disabled when HASDCACHE is  *
+* not defined.                                                    *
+*                                                                 *
+* The modified personal path environment variable value is ignored *
+* when the lsof process is setuid-root or when the real UID of    *
+* the lsof process is root (0).                                           *
+*                                                                 *
+* The modified personal path is read-only when the lsof process           *
+* doesn't surrender its setgid permission.                        *
+*                                                                 *
+====================================================================
+
+
+D. Displaying the Default Path
+==============================
+
+Whatever device cache file path formation options you decide to
+use, remember that the lsof help output, displayed in response to
+its ``-h'' or ``-?'' help options, will display the read-mode
+default (the highest numbered) path that lsof has been enabled to
+form from which it will read.
+
+Since some paths are read-only, the path displayed in help option
+output may not be the one to which lsof will write, should that
+become necessary.  To see the read-only and write device cache file
+paths, environment variable names, and the personal device cache
+file format specification (HASPERSDC), use the -D? option.
+
+
+Appendix A, Unix Dialects Without a Device Cache
+================================================
+
+Linux lsof implementations that obtain their information from files
+in the /proc file system do not have device cache support.  Generally
+lsof for Linux versions 2.1.72 and greater are /proc based.
+
+
+Appendix B, Lsof Dialects and Their Permissions
+===============================================
+
+These are the permissions recommended in the lsof distribution.
+
+
+Appendix B.1 Setuid-root Lsof Dialects
+======================================
+
+These dialect versions of lsof need root permission.  For general
+use they may have to be installed setuid-root.
+
+    Apple Darwin 9 and Mac OS X 10.[567]
+    HP-UX 11.11 and 11.23
+    Linux (no device cache support needed)
+
+
+Appendix B.2 Setgid Lsof Dialects That Surrender Setgid Permission
+==================================================================
+
+Lsof versions for these dialects have WILLDROPGID defined in their
+machine.h header files.
+
+    AIX 5.[12] and 5.3-ML1
+    FreeBSD 4.x, 4.1x, 5.x and [6789].x for x86-based systems
+    FreeBSD 5.x, [6789].x and 1[012].x for Alpha, AMD64 and Sparc64
+       based systems
+    HP-UX 11.00
+    NetBSD 1.[456], 2.x and 3.x for Alpha, x86, and SPARC-based
+       systems
+    OpenBSD 2.[89] and 3.[0-9] for x86-based systems
+    SCO OpenServer Release 5.0.4 for x86-based systems
+    SCO|Caldera UnixWare 7.1.4 for x86-based systems
+    Solaris 2.6, 8, 9 and 10
+
+
+Vic Abell <abe@purdue.edu>
+February 14, 2018
diff --git a/00DIALECTS b/00DIALECTS
new file mode 100644 (file)
index 0000000..831707d
--- /dev/null
@@ -0,0 +1,7 @@
+       Apple Darwin 9, Mac OS X 10, macOS 11 and above
+       FreeBSD 8.2 and above
+       Linux 2.1.72 and above
+       NetBSD 1.2 and above
+       OpenBSD 7.2 and above
+       Solaris 9, 10 and 11 and above
+       OpenIndiana 5.11 and above
diff --git a/00DIST b/00DIST
new file mode 100644 (file)
index 0000000..e4b9a97
--- /dev/null
+++ b/00DIST
@@ -0,0 +1,5594 @@
+           Notes for the distribution of lsof version 4
+
+********************************************************************
+| The latest release of lsof is always available from
+| https://github.com/lsof-org/lsof/releases
+|
+| From 4.92.1, git is introduced to manage changes.
+| You can consult the details of changes with git.
+********************************************************************
+
+               Contents
+
+           Dialects Supported
+           How Lsof Works
+           Lsof Output
+           Getting Started Quickly
+           Limiting, Filtering, and Selecting Lsof Output
+           Parsing Lsof Output with Another Program
+           Repeat Mode
+           Distribution Restrictions
+           Cautions
+           Distribution Contents
+           Warranty
+           Bug Reports
+           The lsof-l Mailing List
+           Version 3 Release Notes
+               3.0,  May 24, 1994
+               ...
+               3.88, February 17, 1997
+           What's New in Version 4
+           Version 4 Release Notes
+               4.0, February 24, 1997
+               4.01, March 3, 1997
+               4.02, March 21, 1997
+               4.03, April 7, 1997
+               4.04, April 17, 1997
+               4.04 supplement, April 18, 1997
+               4.05, April 24, 1997
+               4.06, April 30, 1997
+               4.07, May 12, 1997
+               4.08, May 23, 1997
+               4.09, June 1, 1997
+               4.10, June 8, 1997
+               4.11, June 12, 1997
+               4.12, June 24, 1997
+               4.13, July 9, 1997
+               4.14, July 22, 1997
+               4.15, August 15, 1997
+               4.16, September 25, 1997
+               4.17, October 14, 1997
+               4.18, October 25, 1997
+               4.19, October 30, 1997
+               4.20, November 11, 1997
+               4.21, December 1, 1997
+               4.22, December 15, 1997
+               4.23, January 16, 1998
+               4.24, January 28, 1998
+               4.25, February 7, 1998
+               4.26, February 17, 1998
+               4.27, March 6, 1998
+               4.28, March 10, 1998
+               4.29, March 26, 1998
+               4.30, April 9, 1998
+               4.31, April 21, 1998
+               4.32, May 13, 1998
+               4.33, May 22, 1998
+               4.34, June 26, 1998
+               4.35, July 17, 1998
+               4.36, August 4, 1998
+               4.37, September 15, 1998
+               4.38, November 25, 1998
+               4.39, December 29, 1998
+               4.40, January 25, 1999
+               4.41, February 27, 1999
+               4.42, March 30, 1999
+               4.43, May 11, 1999
+               4.44, June 24, 1999
+               4.45, July 30, 1999
+               4.46, October 23, 1999
+               4.47, November 29, 1999
+               4.48, January 14, 2000
+               4.49, April 3, 2000
+               4.50, June 29, 2000
+               4.51, August 21, 2000
+               4.52, November 8, 2000
+               4.53, December 6, 2000
+               4.54, January 19, 2001
+               4.55, February 15, 2001
+               4.56, May 3, 2001
+               4.57, July 19, 2001
+               4.58, September 13, 2001
+               4.59, October 20, 2001
+               4.60, November 9, 2001
+               4.61, January 22, 2002
+               4.62, March 7, 2002
+               4.63, April 23, 2002
+               4.64, June 26, 2002
+               4.65, October 10, 2002
+               4.66, December 22, 2002
+               4.67, March 27, 2003
+               4.68, June 18, 2003
+               4.69, October 16, 2003
+               4.70, January 16, 2004
+               4.71, March 11, 2004
+               4.72, July 13, 2004
+               4.73, October 21, 2004
+               4.74, January 17, 2005
+               4.75, May 16, 2005
+               4.76, August 30, 2005
+               4.77, April 10, 2006
+               4.78, April 24, 2007
+               4.79, April 15, 2008
+               4.80, May 12, 2008
+               4.81, October 21, 2008
+               4.82, March 25, 2009
+               4.83, January 18, 2010
+               4.84, July 29, 2010
+               4.85, September 27, 2011
+               4.86, April 10, 2012
+               4.87, January 2, 2013
+               4.88, October 13, 2014
+               4.89, July 7, 2015
+               4.90, February 14, 2018
+               4.91, March 26, 2018
+               4.92, May 5, 2018
+               4.93.0 May 7, 2019
+               4.93.1 May 7, 2019
+               4.93.2 May 8, 2019
+               4.94.0 November 11, 2020
+               4.95.0 April 28, 2022
+               4.96.0 September 16, 2022
+               4.96.1 September 16, 2022
+               4.96.2 September 16, 2022
+               4.96.3 September 16, 2022
+               4.96.4 October 18, 2022
+               4.96.5 December 26, 2022
+               4.97.0 January 17, 2023
+               4.98.0 January 22, 2023
+               4.99.0 November 10, 2023
+
+
+
+Dialects Supported
+==================
+
+Lsof (for LiSt Open Files) lists files opened by processes on
+selected Unix systems.  Version 4 is a source reorganization of
+version 3, itself a major revision of version 2.  Version 4 has
+been tested on:
+
+       Apple Darwin 9 and Mac OS X 10.[567]
+       FreeBSD 10.3, 11.0, 12.0 and 13.0 for AMD64-based systems
+       Solaris 9
+
+(The pub/tools/unix/lsof/contrib directory on lsof.itap.purdue.edu
+contains information on other ports.)
+
+If your favorite Unix dialect is not in the list, or if your version
+of it is more recent than the ones listed, please file a new issue at
+https://github.com/lsof-org/lsof.
+
+Version 3 of lsof was tested on:
+
+       AIX 3.2.5, 4.1[.[1234]], and 4.2
+       BSDI BSD/OS 2.0, 2.0.1, and 2.1 for x86-based systems
+       DC/OSx 1.1 for Pyramid systems
+       Digital UNIX (DEC OSF/1) 2.0, 3.0, 3.2, and 4.0
+       EP/IX 2.1.1 for the CDC 4680
+       FreeBSD 1.1.5.1, 2.0, 2.0.5, 2.1, 2.1.5 for x86-based
+               systems
+       HP-UX 8.x, 9.x, 10.01, 10.10, and 10.20
+       IRIX 5.2, 5.3, 6.0, 6.0.1, and 6.[124]
+       Linux through 2.0.27 for x86-based systems
+       NetBSD 1.0, 1.1, and 1.2 for x86 and SPARC-based
+               systems
+       NEXTSTEP 2.1 and 3.[0123]
+       OpenBSD 1.2 and 2.0 for x86-based systems
+       Reliant UNIX 5.43 for Pyramid systems
+       RISC/os 4.52 for MIPS R2000-based systems
+       SCO OpenServer Release 1.1, 3.0, and 5.0.x for x86-based
+               systems
+       SCO UnixWare 2.1 and 2.1.1 for x86-based systems
+       Sequent PTX 2.1.[1569], 4.0.[23], 4.1.[024], 4.2[.1],
+               and 4.3
+       Solaris 2.[12345], 2.5.1, and 2.6-Beta
+       SunOS 4.1.x
+       Ultrix 4.2, 4.3, 4.4, and 4.5
+
+Version 3 and its predecessor, version 2, may be found at:
+
+       ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/OLD
+
+
+How Lsof Works
+==============
+
+Using available kernel data access methods -- getproc(), getuser(),
+kvm_*(), nlist(), pstat(), read(), readx(), /proc -- lsof reads
+process table entries, task table entries, user areas and file
+pointers to reach the underlying structures that describe files
+opened by processes.
+
+Lsof interprets most file node structures -- advfsnodes, autonodes,
+cnodes, cdrnodes, devnodes, fifonodes, gnodes, hsnodes, inodes,
+mfsnodes, pcnodes, procnodes, rnodes, snodes, specnodes, s5inodes,
+tmpnodes.  It understands NFS connections.  It recognizes FIFOs,
+multiplexed files, Unix and Internet sockets.  It knows about
+streams.  It understands /proc file systems for some dialects.  On
+many dialects it recognizes execution text and library references.
+It knows about AFS on some Unix dialects.
+
+
+Lsof Output
+===========
+
+The lsof output describes:
+
+    * the identification number of the process (PID) that has opened
+      the file;
+
+    * the process group identification number (PGID) of the process
+      (optional);
+
+    * the process identification number of the parent process (PPID)
+      (optional);
+
+    * the command the process is executing;
+
+    * the owner of the process;
+
+    * for all files in use by the process, including the executing
+      text file and the shared libraries it is using:
+
+      * the file descriptor number of the file, if applicable;
+
+      * the file's access mode;
+
+      * the file's lock status;
+
+      * the file's device numbers;
+
+      * the file's inode number;
+
+      * the file's size or offset;
+
+      * the name of the file system containing the file;
+
+      * any available components of the file's path name;
+
+      * the names of the file's stream components;
+
+      * the file's local and remote network addresses;
+
+      * the TLI network (typically UDP) state of the file;
+
+      * the TCP state, read queue length, and write queue length
+       of the file;
+
+      * the file's TCP window read and write lengths (Solaris
+       only);
+
+      * other file or dialect-specific values.
+
+
+Getting Started Quickly
+=======================
+
+If you want to get started using lsof quickly, or see some examples
+of how lsof can be used, consult the 00QUICKSTART file of the lsof
+distribution.
+
+The 00QUICKSTART file won't help you build or install lsof, but it
+will cut through the density of the lsof man page, giving you more
+readily an idea of what you can do with lsof.
+
+For information on building and installing lsof, consult the 00README
+file of the lsof distribution.
+
+
+Limiting, Filtering, and Selecting Lsof Output
+==============================================
+
+Lsof accepts options to limit, filter, and select its output.
+These are the possible criteria:
+
+    * Process ID (PID) number -- to list the open files for a given
+      process;
+
+    * Process Group ID (PGID) -- to list the open files for all
+      the processes of a given process group;
+
+    * User ID number or login name -- to list the open files for
+      all the processes of a given user;
+
+    * Internet address -- to list the open files using a given
+      Internet address (host name), protocol, or port (number or
+      name); or to list all open Internet files;
+
+    * command name;
+
+    * file descriptor name or number;
+
+    * list all open NFS files;
+
+    * list all open Unix domain socket files;
+
+    * list all uses of a specific file;
+
+    * list all open files on a file system.
+
+Selection options are normally ORed -- i.e., an open file meeting
+any of the criteria is listed.  The selection options may be ANDed
+so that an open file will be listed only if it meets all the
+criteria.
+
+In the absence of any selection criteria, lsof lists files open to
+all processes.
+
+
+Parsing Lsof Output with Another Program
+========================================
+
+The lsof -F option directs it to produce "field" output that can
+easily be parsed by another program.  The lsof distribution contains
+sample awk, perl 4, and perl 5 scripts in its scripts subdirectory
+that show how to post-process field output.
+
+
+Repeat Mode
+===========
+
+Lsof can be directed to produce output, delay for a specified time,
+then repeat the output, cycling until stopped by an interrupt or
+quit signal.  This mode is useful for monitoring the status of some
+file operation -- e.g., an ftp transfer or a tape backup operation.
+
+Repeat mode is more efficient when combined with lsof's selection
+options, since they limit lsof overhead.
+
+It's possible to use lsof's field output options to supply repeat
+mode output to another process for its manipulation.  The scripts
+subdirectory of the lsof distribution has sample Perl scripts
+showing how to consume lsof repeat mode output from a pipe.
+
+
+Distribution Restrictions
+=========================
+
+Lsof may be used and distributed freely, subject to these limitations:
+
+1. Neither the author nor Purdue University is 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 author 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 from or altered in the lsof source
+   files.
+
+
+Cautions
+========
+
+Lsof is a tool that is closely tied to the Unix operating system
+version.  It uses header files that describe kernel structures and
+reads kernel structures that typically change from OS version to
+OS version.
+
+DON'T TRY TO USE AN LSOF BINARY, COMPILED FOR ONE UNIX OS VERSION,
+ON ANOTHER.
+
+On some Unix dialects, notably SunOS and Solaris, lsof versions
+may be even more restricted by architecture type.  An lsof binary,
+compiled for SunOS 4.1.3 on a sun4c machine, for example, won't
+work on a sun4m machine.
+
+AN LSOF BINARY, COMPILED FOR ONE SOLARIS 1.X ARCHITECTURE, ISN'T
+GUARANTEED TO WORK ON A DIFFERENT SOLARIS 1.X ARCHITECTURE.
+
+
+Distribution Contents
+=====================
+
+The lsof distribution is checked for completeness when it is
+constructed and by the Inventory script when you run the Configure
+script.  (See The Inventory Script section of the 00README file of
+this distribution.)
+
+Lsof is organized in these parts:
+
+    *  The main lsof directory, containing common sources,
+       configuration and setup scripts and three subdirectories:
+       dialects/, lib/, and scripts/.
+
+       Lsof is compiled in the main lsof directory after configuration.
+       The selected dialect sources are copied or linked from the
+       specified subdirectory.  (Symbolic linking is the standard
+       method.)
+
+       Common lsof definitions may be found in lsof.h; common
+       function prototypes, proto.h; and common storage, store.c.
+
+    *  The dialects/ subdirectory contains subdirectories with
+       sources specific to UNIX dialect implementations -- e.g.,
+       the dialects/sun/ subdirectory contains sources for the
+       SunOS (Solaris 1.x) and Solaris (2.x) implementations of
+       lsof.  The dialects subdirectories also contain Makefiles
+       and scripts for assisting dialect source configuration.
+
+       Dialect configuration definitions may be found in dlsof.h;
+       other dialect definitions, dlsof.h; dialect prototypes,
+       dproto.h; and dialect storage, dstore.c.
+
+    *  The lib/ subdirectory contains sources for common lsof
+       functions.  Not all dialects use the functions -- some have
+       their own versions of them.  The lib/ functions are enabled
+       and customized with #define's in the dialect machine.h header
+       files.
+
+    *  The scripts/ subdirectory contains sample scripts for
+       processing lsof field (-F) output.  The scripts are written
+       in AWK, Perl 4, and Perl 5.
+
+The 00PORTING file of the lsof distribution has more information
+on lsof components, configuration, and construction.
+
+
+Warranty
+========
+
+Lsof is provided as-is without any warranty of any kind, either
+expressed or implied, including, but not limited to, the implied
+warranties of merchantability and fitness for a particular purpose.
+The entire risk as to the quality and performance of lsof is with
+you.  Should lsof prove defective, you assume the cost of all
+necessary servicing, repair, or correction.
+
+
+Bug Reports
+===========
+
+Now that the obligatory disclaimer is out of the way, let me hasten
+to add that I accept lsof bug reports and try hard to respond to
+them.  I will also consider and discuss requests for new features,
+ports to new dialects, or ports to new OS versions.
+
+PLEASE DON'T SEND A BUG REPORT ABOUT LSOF TO THE UNIX DIALECT
+VENDOR.
+
+At worst such a bug report will confuse the vendor; at best, the
+vendor will forward the bug report to me.
+
+Please send all bug reports, requests, etc. to https://github.com/lsof-org/lsof.
+
+
+The lsof-l Mailing List
+=======================
+
+Information about lsof, including notices about the availability
+of new revisions, may be found in mailings of the lsof-l listserv.
+For more information about it, including instructions on how to
+subscribe, read the 00LSOF-L file of the lsof distribution.
+
+
+Version 3 Release Notes
+=======================
+
+See 00DIST in the last lsof 3 revision 3.88, for its complete
+set of release notes.  Lsof revision 3.88 may be found at:
+
+       ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/OLD
+
+3.0            May 24, 1994
+               This is the first official release of lsof 3.
+
+...
+
+3.88           February 17, 1997
+
+               +======================================+
+               | This is the last version 3 revision. |
+               +======================================+
+
+               Added documentation files -- 00.README.FIRST[_<version>]
+               and 00RELEASE.SUMMARY_<version> -- to the distribution.
+
+
+What's new in Version 4
+=======================
+
+The main goal of version 4 was to eliminate the confusing common/
+fragment source file technique.  Changing the version number also
+provided an opportunity to restart the numbering, which at 3.88
+had risen to a large value.
+
+The sources that appeared in the dialects/common subdirectory of
+version 3 in fragment files have been incorporated into the version
+4 liblsof.a library as *.c files.  This results in significant
+changes to many source files, scripts, and Makefiles of all dialect
+versions.  It allows elimination of some source files -- ddev.c,
+dfile.c, dmnt.c -- for dialects now obtaining functions from
+liblsof.a that formerly came from making dialect source files by
+combining fragment files.
+
+The version 4 liblsof.a sources are stored in the lib/ subdirectory
+of the main lsof directory.  The liblsof.a functions are activated
+and conditioned in their source files by values #define'd in the
+dialect dlsof.h and machine.h header files.
+
+Dialects that provide a private version of a library function refrain
+from #define'ing the symbol that would activate the library function
+code.
+
+
+Version 4 Release Notes
+=======================
+
+4.0            February 24, 1997
+
+               +====================================+
+               | This is the first lsof 4 revision. |
+               +====================================+
+
+               Reorganized sources: eliminated code fragment files
+               and created a library in their place.  Modified or
+               deleted many dialect source and header files.
+               Changed documentation accordingly.
+
+               Added a warning to sgi/Makefile and 00FAQ that advises
+               against using the IRIX C compiler -n32 option when
+               compiling lsof.  Thanks go to Peter Ilieve
+               <peter@memex.co.uk> for bringing this to my attention.
+
+               Dropped IRIX 5.2 in mid-stream, because my 5.2 test
+               system was upgraded to 5.3.
+
+4.01           March 3, 1997
+               Added TFS support for Pyramid dialects.
+
+               Added test to Configure and to the IRIX dnode.c
+               for the different cnode struct that appears in
+               <cachefs/cachefs_fs.h> on the 6.2 IMPACT distribution.
+               Heddy Boubaker <boubaker@amfou.cenatls.cena.dgac.fr>
+               alerted me to the cnode change and helped test this
+               lsof adjustment.
+
+               Shut down the lsof child process before doing a -r
+               sleep().  A comment from Dan Mercer <dam@mmm.com>
+               prompted this.
+
+4.02           March 21, 1997
+
+               Based on a report from Pasi Kaara <Pasi.Kaara@atk.tpo.fi>,
+               disabled HP-UX CCIT support in lsof for HP-UX
+               versions 10 and above.  Pasi's report also led to
+               changes in the HP-UX machine.h to support use of
+               gcc to compile lsof for HP-UX 10.20 and warnings
+               against using `cc -Aa` or `gcc -ansi` to compile
+               lsof under HP-UX 10.x.
+
+               With help from Richard Allen <ra@hp.is> taught
+               HP-UX 10.x lsof to name file systems better by
+               using the virtual file system device number.  Elias
+               Halldor Agustsson <elias@rhi.hi.is> provided a test
+               system.
+
+               Changed NEXTSTEP and UNIXWARE Makefiles to use
+               safer quoting when generating version.h.  The change
+               was suggested by Bob Farmer <ucs_brf@unx1.shsu.edu>.
+
+               Added SHELL=/bin/sh string to all Makefiles.
+
+               Added support for Linux 2.1.28 on a test system,
+               kindly provided by Jonathan Sergent <sergent@purdue.edu>.
+               Configure tests the Linux 2.1.x's C library lseek()
+               function for proper handling of kernel offsets.
+               If lseek() appears suspect, Configure activates
+               the use of a private lseek() function.  Changed
+               the private nlist() function to nlist_private()
+               and taught it to use the query_module() syscall in
+               place of the deprecated get_kernel_syms() one.
+               Added rudimentary AX.25 support for Pierfrancesco
+               Caci <ik5pvx@infogroup.it> who helped test it.
+               Updated the old get_kernel_syms() code to recognize
+               and skip module name entries.
+
+               Prompted by Marty Leisner <leisner@sdsp.mc.xerox.com>,
+               eased the requirement that service name lookup for
+               the -i option be accompanied by a protocol name.  The
+               name is not needed if both TCP and UDP names yield the
+               same port number.
+
+               Added xusers.awk script from Dan Mercer <damercer@mmm.com>
+               to the distribution scripts/ subdirectory.
+
+               Changed Configure script to use LSOF_VERS for all
+               UNIX dialect version numbers and to pass LSOF_VERS
+               to the dialect Mksrc functions.  Also added the
+               ability for a dialect stanza to declare a different
+               dialect Makefile source.  Modified dialect Mksrc
+               files -- e.g., linux and sun -- accordingly.
+
+               Added support for BSD/OS 3.0 with help from Jim
+               Reid <jim@mpn.cp.philips.com>.  Terry Kennedy
+               <TERRY@spcvxa.spc.edu> kindly provided a test
+               system.  During the port corrected a bug that
+               prevented proper handling of revoked files.
+
+4.03           April 7, 1997
+               At the suggestion of Dan Mercer <damercer@mmm.com>,
+               made HP-UX building of lsof aware of differences
+               between the HP-UX bundled and unbundled C compilers.
+
+               Added the ability for the lsof builder to define the
+               default warning message issuance state.  By default the
+               issuance of warning messages is disabled; defining
+               WARNINGSTATE in machine.h disables it.  The Customize
+               script was updated to handle WARNINGSTATE.  Dan Mercer
+               suggested this.
+
+               Eliminated compiler complaint about improperly cast
+               get_Nl_value() argument in ncache_load() in lib/rnch.c.
+
+               Corrected zeromem() argument error in SCO dproc.c.
+               Sped up parent directory cache lookup slightly.
+
+               Updated for PTX 4.4, including additional VxFS (EFS)
+               file system support.
+
+4.04           April 17, 1997
+               At the suggestion of Bela Lubkin <belal@sco.COM>
+               changed device cache handling to be more tolerant
+               of a device cache file whose [cm]times are older
+               than the ones on /dev or /devices.  The change
+               required adding information to Solaris device cache
+               file clone lines, so the first time lsof 4.04 is
+               run under Solaris it will complain about a bad
+               cached clone device in a previous device cache
+               file, then regenerate it.
+
+               Added boot file path detection for SCO OSR 5 and
+               above, based on information supplied by Bela.
+
+               Fixed two bugs in DEC OSF/1 lsof -- an error in
+               reporting locks and a missing continue statement
+               in readdev() after a failure to open a directory.
+               Jan Ole Suhr <josuhr@informatik.tu-clausthal.de>
+               reported the second bug and supplied a fix.
+
+               Fixed XFS problems with IRIX 6.2 by abandoning the
+               idea that SGI will distribute XFS header files and
+               defining an lsof-private xfs_inode structure.  John
+               Paul Morrison <John.Paul.Morrison@MultiActive.com>
+               helped develop and test the 5.3 definition.  John
+               R. Vanderpool <fish@daacdev1.gsfc.nasa.gov> helped
+               develop and test the 6.2 definition.
+
+               Remove obsolete comments about common/*.frag files.
+
+               Updated Linux lsof for Linux version 2.1.35.
+
+4.04           April 18, 1997
+Supplement     Regenerated the 4.04 distribution to correct a non-
+               device-cache #define misplacement in the Solaris and
+               SunOS dlsof.h.  Alexandre Oliva <oliva@dcc.unicamp.br>
+               reported the problem.
+
+4.05           April 24, 1997
+               Corrected an error in 00DCACHE.
+
+               Made sure SCO /etc/ps/booted.systems is closed.
+
+               Based on an observation by Bela Lubkin <belal@sco.COM>
+               that the lsof child had needless file descriptors
+               open, closed all but the open pipes between the
+               lsof parent and child.
+
+               Decommissioned CDC EP/IX support; I no longer have a
+               test system.
+
+               Based on a suggestion from Patrick Connor
+               <connor@phreak.csd.sgi.com>, added -xansi to CFLAGS
+               for IRIX 5.3 and 6.[234].
+
+               Also at Patrick's suggestion changed Configure to
+               propagate exact SunOS 4.1.x version to the main
+               and library Makefiles.  This allowed the sunos413
+               and sunos413cc Configure abbreviations to be
+               shortened to sunos and sunoscc.
+
+               Updated obsolete argument uses (-H changed to -n)
+               in count_pf.perl* and watch_a_file.perl scripts.
+
+               Adjusted Solaris 2.6 lsof for Beta_Update with tips
+               from Casper Dik <casper@holland.Sun.COM>.
+
+               Fixed a Solaris 2.4 TCP address reporting bug.
+
+4.06           April 30, 1997
+               Added a step to the Makefile clean rules that does
+               a make clean in the lib subdirectory; suggested by
+               Casper Dik <casper@holland.Sun.COM>.  (Configure's
+               -clean argument already did this.)
+
+               Fixed an incorrect awk argument in the sunos*)
+               Configure stanza, reported by Alexandre Oliva
+               <oliva@dcc.unicamp.br>.
+
+               Added CD9660 (aka ISO) file system support to
+               FreeBSD, NetBSD, and OpenBSD with mods and help
+               from Kenneth Stailey <kstailey@disclosure.com>.
+               (BSDI already had CD9660 support.)  While at it,
+               added file descriptor system support to BSDI and
+               FreeBSD.
+
+               Added /kern file system support to OpenBSD.  The
+               support wasn't extended to BSDI, FreeBSD, or NetBSD,
+               because it requires Kenneth Stailey's changes to
+               /sys/miscfs/kernfs/kernfs.h.
+
+               Updated IRIX 6.3 support after getting access to
+               a test system, provided by John Paul Morrison
+               <John.Paul.Morrison@MultiActive.com>.  Improved
+               the handling of IRIX 5.1 and greater FIFOs.
+
+4.07           May 12, 1997
+               Based on AIX problem reports from David Capshaw
+               <David.Capshaw@SEMATECH.Org>, changed the aix*
+               Configure script stanza to avoid -bnolibpath for
+               gcc (which the GNU loader doesn't grok) and AIX
+               below 4.1.4 (where -bnolibpath hasn't been tested
+               or is known to be unimplemented), and to refuse to
+               use gcc for compiling lsof in AIX versions below
+               4.1 (because of possible structure alignment
+               problems).  Updated 00FAQ appropriately.
+
+               Added OpenBSD support for EXT2FS.  This support
+               has yet to be tested.
+
+               Tested lsof under OpenBSD 2.1.
+
+               Activated /kern file system support for NetBSD when
+               Configure senses that /sys/miscfs/kernfs/kernfs.h
+               defines the kern_target structure.  This support
+               has not been tested under NetBSD, although it has
+               been tested under OpenBSD.
+
+               Made some simple changes to the BSDI machine.h,
+               suggested by Jeffrey C. Honig <jch@bsdi.com>.
+
+               Improved handling of alternate dialect Configure
+               abbreviations -- aix and aixgcc, hpux and hpuxgcc,
+               solaris and solariscc, and sunos and sunoscc.
+
+4.08           May 23, 1997
+               Cleaned up dialect Makefile's, staring with a suggestion
+               from Christopher Schanzle <chris@cam.nist.gov>.
+
+               Improved Configure's -clean processing.
+
+               Corrected bugs in Solaris lock reporting.
+
+               Changed NetBSD Configure stanza to put -I/usr/include
+               before -I/sys.
+
+4.09           June 1, 1997
+               Adjusted for latest FreeBSD 3.0 release.  This
+               required adding a new kernel name cache module for
+               reading BSD-form hashed kernel name cache entries,
+               rnmh.c, to the lsof library, and adding a #define
+               to each machine.h to select it.
+
+               Activated rnmh.c for BSDI 2.1, BSDI 3.0, NetBSD
+               1.2, and OpenBSD 2.1.
+
+4.10           June 8, 1997
+               Adjusted for Linux 2.1.x (x > 35) kernels with
+               hashed task structure pointers.  Marty Leisner
+               <leisner@sdsp.mc.xerox.com> and Jonathan Sergent
+               <sergent@io.com> tested the adjustment.
+
+               Replaced readdev() stat() calls with lstat() to
+               reduce device table and cache entries with the same
+               device number and inode values.  Added code to
+               remove all remaining duplicates.  This fixes a
+               Linux problem reported by Jonathan Sergent and
+               makes device node name output predictable.
+
+               Corrected a bug in UnixWare stream file handling
+               that prevented searching for the stream file by
+               its associated character device name.
+
+               Added Pyramid code to determine Reliant UNIX clone
+               major device number differently from that of DC/OSx.
+
+4.11           June 12, 1997
+               Changed Configure to sense that the PTX inp_[fl]addr
+               members of the inpcb structure of <netinet/in_pcb.h>
+               have a struct type and set HASINADDRSTR for use in
+               PTX dnode.c and dsock.c tests.
+
+               Changed PTX version 4.1.4 tests to use 4.1.3 instead.
+               Carson Wilson <carson@mcs.com> reported the need
+               to do this and tested the change.
+
+               Fixed a block device table indexing bug in lib/rdev.c,
+               reported by Carson Wilson.  The same bug was squashed
+               in pyramid/ddev.c.
+
+               Added code to the Pyramid Reliant UNIX kread()
+               function to compensate for an address boundary
+               error in the kernel's /dev/kmem driver.
+
+               Verified that lsof compiles and works under AIX
+               4.2.1.  Added an AIX test for the presence of NFS
+               header files, defined HAS_NFS and adjusted AIX
+               dialect sources accordingly.
+
+               Based on a suggestion from Gaylord Holder
+               <holder@phy.ucsf.EDU>, added DEC OSF/1 code to
+               auto-detect the booted file, whence kernel symbol
+               addresses are obtained.
+
+4.12           June 24, 1997
+               Corrected a device number sign extension problem
+               in the reading and writing of device cache file.
+               The problem was reported by Bela Lubkin <belal@sco.com>
+               and he suggested a fix.
+
+               Fixed an SCO stream device lookup problem.  The
+               report and solution came from Bela Lubkin
+
+               Enhanced the Configure script to enable cross-
+               configuration of lsof, based on suggestions from
+               Marty Leisner <leisner@sdsp.mc.xerox.com>.  A new
+               documentation file, 00XCONFIG, describes the process.
+
+               Made Pyramid OBJFS support conditional on the
+               presence of supporting header files.  Corrected
+               the Pyramid MkKernOpts script so it generates the
+               necessary -D's for the Nile/Jolt architecture.
+               Richard Coley <rcoley@pyra.co.uk> helped.
+
+               Added another IRIX xfs_inode variant for 6.2, 32
+               bits, no XFS rollup patch.
+
+               Tested under UnixWare 2.1.2.
+
+4.13           July 9, 1997
+               Taught Pyramid lsof to grok ttyfs vnodes with help
+               from Richard Coley <rcoley@pyra.co.uk>.  Fixed some
+               minor bugs in Pyramid FIFO reporting.  Eliminated
+               use of the Pyramid UCB compatibility library at
+               Richard's suggestion.
+
+               Eliminated reporting of "strange" inode numbers
+               for SCO OSR 3.2v5.0.x HPPS files with help from
+               Bela Lubkin <belal@sco.com>
+
+               Modified port to service name lookup to use a small
+               number of getservbyport() calls before reading the
+               entire map with getservent().  Changed port reporting
+               to represent a zero as `*' to be consistent with
+               other prt number reporting tools like netstat.
+               Casper Dik <casper@holland.Sun.COM> suggested these
+               changes -- the getserv*() one to improve performance
+               for large NIS service name maps.
+
+               Changed all readdev() functions to make the absence
+               of block devices a warning instead of a fatal error
+               after Brian Redman <ber@ms.com> reported his IRIX
+               6.4 system had no block devices.  (It really did
+               have block devices, but readdev()'s lstat() use
+               caused it to miss them in a directory symbolically
+               linked from /dev/dsk->/hw/disk.)  Fixed Brian's
+               real problem by changing the IRIX readdev() to use
+               stat() on /dev nodes if a Configure test shows /hw
+               is readable.  Extended the potential to do the same
+               to all readdev() functions.
+
+               For consistency and convenience changed some
+               Configure abbreviations and dialect subdirectory
+               names:  "decosf" abbreviation and "osf" dialect
+               subdirectory name to "du"; "netbsd" dialect
+               subdirectory name to "n+obsd"; "next3" abbreviation
+               and "next" dialect subdirectory name to "ns"; "sco"
+               abbreviation and dialect subdirectory name to "osr";
+               "sgi" dialect subdirectory name to "irix"; and
+               "unixware" abbreviation and dialect subdirectory
+               name to "uw".
+
+               Added #if/#endif clauses to the AIX rmdupdev()
+               function to avoid clone processing for AIX versions
+               less than 4.1.4.  The problem was reported by Toralf
+               Foerster <toralf.foerster@io-warnemuende.de>, who
+               supplied corrective code.
+
+               Added support for new style NetBSD inode with i_ffs
+               and i_e2fs union members.
+
+               Improved Configure and 00FAQ information on Digital
+               UNIX configuration subdirectory with suggestions
+               from Brad Krebs <brad@EECS.Berkeley.EDU>.
+
+4.14           July 22, 1997
+               Reorganized the Solaris handling of the inode
+               structure header file, ufs_inode.h, to eliminate
+               VxFS structure definition conflicts for Solaris
+               2.4, based on information from Greg Earle
+               <earle@netbsd4me.jpl.nasa.gov>.
+
+               Cleaned up some typos and confusion in Configure's
+               help output, based on comments from Bela Lubkin
+               <belal@sco.com>
+
+               Added a 00DIALECTS file, containing UNIX dialect
+               version numbers, that can be used by Configure and
+               the man page.
+
+4.15           August 15, 1997
+               Aligned `Configure -help` output better.  Removed
+               Configure's 2.6 Beta test adjustments.
+
+               Added improved Solaris VxFS configuration and
+               handling, based on information from Greg Earle
+               <earle@netbsd4me.jpl.nasa.gov>.
+
+               Added socket state -- TCO or TPI -- for socket
+               files at the suggestion of Ian Fitchet
+               <I.D.Fitchet@ftel.co.uk>.
+
+4.16           September 25, 1997
+               Added reporting of TCP/TPI queue lengths and window
+               sizes ala netstat to NAME column.  Added -T option
+               to select or de-select TCP/TPI info reporting.
+               (Window sizes are only reported for Solaris.)
+               Fixed anomalies along the way in SIZE/OFF processing
+               for some dialects.
+
+               Fixed service name argument processor to allow
+               minus signs as part of the name.  Consequently this
+               disallows names with embedded minus signs from
+               being specified as the start of a range.
+
+               Added 00FAQ entries explaining why lsof won't find
+               a file being edited with vi, why window sizes aren't
+               reported for all dialects, and what the "no more
+               information" message means.
+
+               Forced Pyramid CC to be /usr/ccs/bin/cc to avoid
+               accidental use of the BSD variant in /usr/ucb/cc.
+
+               Added support for Linux glibc2, including a Configure
+               test; cross-Configure support (00XCONFIG); and much
+               unfortunate and risky sleight-of-hand in lsof Linux
+               dialect header and source files, forced upon lsof
+               by incompatibilities between Linux kernel and glibc2
+               header files.
+
+               Included in scripts/identd.perl5 a Perl 5 implementation
+               of an identd server, using lsof, provided by Kapil
+               Chowksey <kchowksey@hss.hns.com>.
+
+               Updated IRIX 6.4 xfs_inode guess.
+
+4.17           October 14, 1997
+               Added -V option for verbose search result reporting.
+               Verbose reports are prepared for failure to locate
+               file names, command names, Internet addresses or
+               files, login names, NFS files, PIDs, PGIDs, and UIDs.
+
+               Augmented Linux NFS file test to cope with kernels
+               whose NFS code is in a loadable module.  Need for
+               the test was pointed out by Jonathan Sergent
+               <sergent@csociety.ecn.purdue.edu>.  The change
+               required that Linux have private dmnt.c source,
+
+               Completed a Linux 2.1.57 port on a system provided
+               by Jonathan Sergent.
+
+4.18           October 25, 1997
+               Eliminated memory leaks in alloc_lfile(), lkup_port(),
+               and NEXTSTEP's process_text() function.
+
+               Added recognition of OpenBSD 2.2 in Configure,
+               supplied by Kenneth Stailey <kstailey@disclosure.com>.
+
+               Consolidated print_file() functions to use the one
+               in lib/prtf.c.  Made it configurable and changed
+               it to size print columns dynamically.
+
+               !!! WARNING !!!
+
+               WITH DYNAMICALLY SIZED PRINT COLUMNS LSOF 4.18
+               PRODUCES OUTPUT SIGNIFICANTLY DIFFERENT FROM THAT
+               OF PREVIOUS REVISIONS.  LINES ARE GENERALLY SHORTER
+               AND THERE IS GENERALLY LESS BLANK SPACE BETWEEN
+               COLUMNS AND THE ITEMS IN THEM.  THERE ARE NO LONGER
+               ANY SPACES BETWEEN DEVICE NUMBER ELEMENTS, ONLY
+               COMMAS.
+
+               !!! WARNING !!!
+
+               Added special types and print specification modifiers
+               for file size and offset to handle UNIX dialects
+               with 64 bit sizes and offsets.  Paul Eggert
+               <eggert@twinsun.com> reported the need for this
+               addition.
+
+               With Paul Eggert's help picked lint from the lsof
+               library, the main level lsof sources, and the Sun
+               dialect sources.
+
+               Added documentation, including the file 00LSOF-L,
+               about the lsof-l LISTSERV.
+
+               Added support for Reliant UNIX on the RM600.  Bob
+               Passarella <rmpassar@pyramid.com> supplied the
+               changes.  Kevin Smith <kevin@pyramid.com> helped
+               arrange test systems.  While incorporating Bob's
+               changes, modified lib/rnch.c to handle kernel ncache
+               structs whose name is accessed via a char *, rather
+               than in a char array.
+
+               Changed #include order of <sys/socketvar.h> for
+               Solaris 2.x.  W. Richard Stevens <rstevens@kohala.com>
+               pointed out the need to do this.
+
+4.19           October 30, 1997
+               Changed Pyramid Reliant RM600 proc scan to skip
+               SSYS (p_flag) processes, since they don't seem to
+               have a readable u_cdir vnode.
+
+               Enabled Pyramid Reliant UNIX kread() work-around
+               for DC/OSx, too, since its read(/dev/kmem) kernel
+               driver seems to share the page boundary bug this
+               work-around circumvents.
+
+               Changed SzOffFtm_d and SzOffFtm_dv (new formats at
+               4.18 to print size and offset) from signed to
+               unsigned.  Setting them signed at 4.18 was an
+               oversight.
+
+               Plugged a memory leak that caused the loss of 130
+               bytes per repeat-mode pass.  Fixed it with a simple
+               work-around in main().  Lionel Cons <Lionel.Cons@cern.ch>
+               reported the leak.
+
+4.20           November 11, 1997
+               Tested under BSDI 3.1.
+
+               Added support for Reliant UNIX Mesh IPC files with
+               help from Billy Ho <bho@pyramid.com>.
+
+               Added support to Digital UNIX lsof that uses the
+               libmsfs tag_to_path() function (when it exists) to
+               look up AdvFS path names.  The idea and sample code
+               came from Dean Brock <brock@cs.unca.edu>.  Converted
+               Dean's code into more general purpose support for
+               private name cache lookups via the HASPRIVNMCACHE
+               #define in the dialect machine.h file and code
+               conditional on it in the printname() function.
+
+               Taught Digital UNIX lsof to recognize NFS3 file
+               systems.  Corrected Digital UNIX lsof DEVICE column
+               alignment.
+
+4.21           December 1, 1997
+               Squashed bug, introduced at revision 4.18, that
+               resulted in double reporting of each selected PID
+               when terse mode (-t) was specified.
+
+               Corrected minor bug, also introduced at 4.18, that
+               might cause an extra print_proc() pass when one
+               PID has been specified.
+
+               Added -R to lsof options in scripts/idrlogin.perl*.
+               The option should have been there -- it was supposed
+               to be mandatory for PGID reporting -- but a bug,
+               corrected in revision 4.18, previously made -R
+               unnecessary.
+
+               Enabled configuring for BSDI BSD/OS 4.0 per a
+               suggestion from Jeff Honig <jch@bsdi.com>.
+
+               Enabled replacement of scoff_t with off64_t (scoff_t
+               is used to type r_size and r_localsize in the rnode
+               struct) for IRIX 5.3 systems that have the NFS
+               kernel rollup patch (1477).  This compensates for
+               SGI's failure to distribute an updated <sys/fs/rnode.h>
+               with their patch.
+
+               Validated under Linux 2.0.3[12], Linux 2.1.64, and
+               NetBSD 1.3.
+
+               Added FreeBSD root directory reporting, courtesy
+               of Dan Nelson <dnelson@emsphone.com>.
+
+4.22           December 15, 1997
+               Made adjustments for Linux 2.1.7[02].
+
+               Improved NAME information for Linux UNIX domain
+               sockets.
+
+               Added option +|-M to control the reporting of
+               portmapper registration information in square
+               brackets after the TCP or UDP port or service name.
+               Kenneth Stailey <kstailey@disclosure.com> suggested
+               the feature and provided sample code from OpenBSD.
+               Reporting is disabled by default in the distribution
+               and may be enabled with +M; if lsof is compiled
+               with HASPMAPENABLED (e.g., from machine.h), reporting
+               will be enabled by default and can be disabled with
+               -M.
+
+               Changed the -w option to +|-w to match the syntax
+               of the +|-M option and to eliminate any options
+               that flip meaning when a symbol is defined at
+               compile time.  For both +|-M and +|-w, specifying
+               `-' when the default state is disabled or specifying
+               `+' when the default state is enabled causes no
+               problems.
+
+       !!!WARNING  The -w option has changed in lsof 4.22.  WARNING!!!
+
+               Made the +|- prefix legal for most options, but
+               didn't document it in the man page or help panel.
+               Most options that disable something -- e.g., -b,
+               -C, -n, -P -- now disable when the prefix is `-'
+               and enable when it is `+'.  Since the states these
+               options disable are enabled by default, I chose to
+               avoid documentation complexity and confusion by
+               not mentioning that they can be used with the `+'
+               prefix.
+
+               Condensed the help panel.
+
+               Made sure Digital UNIX Configure stanza puts normal
+               include path (e.g., /usr/include) before system
+               include paths.
+
+               Added IPX socket information reporting to Linux
+               with help from Jonathan Sergent <sergent@purdue.edu>.
+
+4.23           January 16, 1998
+               Fixed conflict arising from the quondam replacement
+               of the Sun Solaris <netdb.h> with a BIND/BSD version.
+
+               With help from Jonathan Sergent <sergent@purdue.edu>
+               developed a /proc file system based Linux lsof.
+               It needs some Linux 2.1.x release to work -- I'm
+               not sure which, but I tested under 2.1.72, 2.1.76,
+               and 2.1.79.  The Configure script selects special
+               sources for this lsof, so the full lsof distribution
+               now contains both /dev/kmem and /proc based sources
+               for Linux lsof.  An optional kernel mod, written
+               by Jonathan, enhances the /proc-based lsof ability
+               to recognize IPX socket files.  Reorganized and
+               augmented the Linux sections in 00FAQ to explain
+               the two types of Linux lsof.
+
+               Defined DOSTAT_FUNCTION for dostat() in misc.c to
+               select the function, stat() or lstat(), it will use.
+               DOSTAT_FUNCTION is normally undefined, defaults to
+               lstat(), and is only defined for the /proc-based
+               Linux lsof in its dlsof.h.
+
+               Made conditional on the presence of IRIX 6.4 XFS
+               rollup patch #6 an XFS node change introduced in
+               revision 4.16.   Identified the patch with help
+               from John R. Vanderpool <fish@daacdev1.gsfc.nasa.gov>.
+
+               Added NFS node compensation for NetBSD 1.3.  The
+               code and suggestion for it was supplied by Jean-Luc
+               Richier <richier@imag.fr>.
+
+               Added diagnostic messages to the /dev/kmem-based
+               Linux Mksrc script to report errors during the
+               construction of the kernel name cache header file,
+               kncache.h.  Added 00FAQ information on kncache.h.
+
+               Added a new Linux test host, running 2.0.33 and
+               GlibC, provided by Steve Logue <stevel@mail.cdsnet.net>.
+
+               Ported to PTX 4.1.3 and 4.4.2.  Adjusted lib/rnch.c
+               for 4.4.2 to allow customization f additional ncache
+               struct element names.
+
+4.24           January 28, 1998
+               Changed /proc-based Linux lsof offset test to use "/"
+               instead of "/etc/passwd".
+
+               To assist Jim Mintha <jim@geog.ubc.ca> with the
+               packaging of lsof for Debian Linux, added a
+               DEBIAN_LINUX_LSOF #define to trigger the activation
+               of special system map file location code in the
+               /dev/kmem-based dproc.c.
+
+               Applied modification to dialects/bsdi/dlsof.h from
+               Ingimar Robertson <iar@skyrr.is>, enabling lsof to
+               compile for BSDI BSD/OS 2.0.
+
+               Corrected a documentation error in 00DCACHE, pointed
+               out by Thomas Anders <anders@hmi.de>.  The error was
+               created when the -V option was added at lsof 4.17.
+
+               Made IRIX 5.3 through 6.3 lsof aware of IRIX SCSI
+               tape devices (e.g., /dev/tape).  Dave Olson of SGI
+               and Randolph J. Herber of FNAL provided valuable
+               advice, and Igor Schein <ischein@air-boston.com>
+               helped test.
+
+               Added a machine.h symbol (NEVER_HASDCACHE) that
+               prevents Customize from offering to change HASDCACHE.
+               The symbol may appear anywhere in machine.h --
+               e.g., in a comment.  Included the symbol in a
+               comment of the HASDCACHE section of the /proc-based
+               Linux lsof machine.h, and accompanied it with
+               warnings against #define'ing HASDCACHE.  Did the
+               same thing for WARNDEVACCESS (NEVER_WARNDEVACCESS
+               is the suppressant.)
+
+4.25           February 7, 1998
+               Corrected an IRIX mis-cast of file offset (position).
+               Igor Schein <ischein@air-boston.com> reported the
+               problem.  This was offered as a patch to 4.24.
+               Picked some lint Igor pointed out.
+
+               At Igor's suggestion added an optional decimal
+               digit size argument to the -o option.  This argument
+               specifies how many file offset decimal digits can
+               follow "0t" before lsof switches to a "0x..." form.
+               The argument size specification doesn't count the
+               two characters of the "0t".  A size of 0 means
+               unlimited.  The default is OFFDECDIG (8), preserving
+               compatibility with existing lsof output; it can be
+               changed by the lsof builder.  When size is specified
+               with -o it does not force offset display; -o without
+               a size still must be used to do that.
+
+               Added an IRIX 6.2, 32 bit system, XFS node patch,
+               courtesy of Ulrich Bernhard <rzubu@rzu.unizh.ch>.
+
+               For my own convenience enabled Configure to use
+               /usr/local/bin/gcc for NEXTSTEP.  This allows
+               circumvention of a gcc 2.8.0 ranlib problem on
+               my test 3.1 `040 cube.
+
+               Added flags recommended by the RISC/os and Ultrix
+               compilers for the updated (and longer) main.c.
+
+               Updated FreeBSD cd9660_node.h Configure test.
+
+4.26           February 17, 1998
+               Added shared process group processing for IRIX 5.3,
+               and IRIX 6.1 and above, based on investigation of
+               a bug report from Igor Schein <ischein@air-boston.com>.
+               Igor helped test this addition.
+
+               Improved handling of file system name arguments.
+               It's now done in a manner similar to fuser.  The
+               -f argument forces path names to be considered as
+               simple files, rather than as file system names.
+               The +f flag forces them to be considered as file
+               system names.  Normally path arguments are considered
+               file system names when they match a mounted-on
+               directory in the system's mount table, or when they
+               match a mounted file system's block device.  Igor
+               Schein helped test this change.
+
+               Igor also suggests that the proper compilation of
+               the IRIX 6.4 proc structure after patch 2536 has
+               been installed may need -DPIOMEMOPS.  So lsof's
+               MkKernOpts script was updated to propagate that
+               option from CCOPTS in /var/sysgen/system/irix.sm,
+               even though patch 2536 doesn't add -DPIOMEMOPS to
+               it.  Added a 00FAQ item on this patch.
+
+               Added a fatal warning message about names forced
+               to be file system names (with +f) that have no
+               match in the mount table.
+
+               Improved the -V message for files and file systems
+               for which no open files were found.  Added reporting
+               of /proc file and file system search failures.
+
+               Did some code reorganization to combine the multiple
+               ck_file_arg() functions into one.  Moved the new
+               function from the library to the top level and put
+               it in arg.c; moved the usage function from arg.c
+               to a new top-level source file, usage.c, to balance
+               top-level source file size.  The new usage.c depends
+               on version.h; arg.c no longer does.
+
+               Added flag recommended by the DU compiler for the
+               updated (and longer) main.c.
+
+4.27           March 6, 1998
+               At the request of Igor Schein <ischein@air-boston.com>
+               added a conditional repeat mode option, using the
+               `+' prefix to the `r' option.  +r operates as does
+               -r with the exception that it exits the first time
+               no open files have been listed during a cycle.
+               The exit code will be zero when any open files have
+               been listed; one, if none were ever listed.
+
+               Ported lsof to HP-UX 11.0 with the help of Richard
+               Allen.  This port hasn't been tested on a 64 bit
+               kernel; I'm sure it won't work there without more
+               mods.  It may not work on PA 2 architectures; I've
+               only tested it under PA 1 and a separate, busy
+               tester reported PA 2 problems that I've been unable
+               to investigate.
+
+               In anticipation of getting access to a 64 bit HP-UX
+               kernel and the pending start of the Solaris 2.7
+               Beta test (It will have 64 bit kernel addressing.),
+               started adding support for 64 bit kernel pointers.
+               This includes: ubiquitous use of the KA_T cast
+               for kernel pointers; a format to print them,
+               KA_T_FMT_X; a function to print them, print_kptr();
+               and modifications to most kernel-related functions
+               -- e.g., process_file(), process_node(),
+               process_socket(), readvfs() -- to process kernel
+               addresses as KA_T types.
+
+               Fixed minor bug in handling path name arguments
+               that end with a `/'.
+
+               Removed support for RISC/os; its test system is no
+               longer available.
+
+               Made modifications to insure that lsof output
+               doesn't contain non-printable characters.  All such
+               characters are now printed in the printf form
+               "\x%02x".  Several new common functions were
+               installed in misc.c to support "safe" printing.
+               This second major modification in 4.27 to common
+               and dialect code could have introduced bugs not
+               yet detected.
+
+4.28           March 10, 1998
+               Refined unprintable format to use \b, \f, \r, \n,
+               \t, and ^* (for CTRL) forms.  Corrected omission
+               of safestrprt() use for field output command name.
+               These changes were offered as patches to 4.27.
+
+               Made space an unprintable character (\x20) in the
+               COMMAND column; printable elsewhere, including the
+               NAME column, field output, and error messages.
+
+               Made sure FD column is parseable as a single entity
+               -- i.e., has no embedded space.  Thus, if the access
+               mode is unknown but there is a known lock mode, (a
+               very rare case) the access mode will be printed as
+               `-'.
+
+               Picked lint with gcc 2.8.0 under Solaris 2.6.
+
+               With the help of Dave Olson of SGI identified a
+               proc struct element that should have been added to
+               <sys/proc.h> by IRIX 6.4 patch 2536.  Added a
+               work-around for it to the lsof Configure script.
+               Igor Schein <ischein@air-boston.com> identified
+               that the patch caused a proc structure length
+               complaint from lsof.  Removed an obsolete 00FAQ
+               item on the patch, installed at lsof 4.26, explaining
+               that no solution was yet available.
+
+               Added a 00FAQ item on how BIND installs its own
+               header files, including <netdb.h>, which may cause
+               the rpcent struct definition to vanish.  Solaris
+               has an automatic lsof work-around, but that hasn't
+               been (and probably can't be) propagated to all
+               dialects supported by lsof.  The 00FAQ item recommends
+               re-installation of the vendor header files that
+               BIND has replaced.  (Others include <rpcent.h>,
+               <sys/bitypes.h>, and <sys/ctypes.h>.)
+
+               Made AIX AFS fixes.
+
+4.29           March 26, 1998
+               Corrected bug in Internet address matching.  The
+               matching formerly stopped if the foreign address
+               matched, thus failing to check the local address
+               for a match.  That led to a possible false "Internet
+               address not located" warning (i.e., in response to
+               -V) about the local address, when both foreign and
+               local addresses were specified with -i.  This
+               correction was offered as a patch to 4.28.
+
+               Changed readmnt() usage in an attempt to defer
+               mount readlink() and stat() delays until they are
+               necessary.
+
+               Corrected two bugs in the Digital UNIX readdev()
+               function.  Made the correction available as a patch
+               to 4.28 and regenerated the 4.28 DU binaries.
+
+               Added a missing argument to a print-kptr() call in
+               the HP-UX dsock.c.  The missing argument causes a
+               fatal gcc error.  The problem was reported by Eyal
+               Shaynis <eyal.shaynis@telrad.co.il>.  The fix was
+               offered as a 4.28 patch.
+
+               Adjusted for Digital UNIX 4.0D; the spec_node
+               structure is now defined in <sys/specdev.h>.  Kris
+               Chandrasekhar <Kris.Chandrasekhar@digital.com>
+               identified the need for the adjustment.
+
+               Incorporated a bug fix from Brian McAllister
+               <mcallister@mit.edu> to the DU readmnt() function.
+               This fix was offered as a patch to 4.28.
+
+               Added "safe" printing to a SunOS clone device error
+               message.
+
+               Corrected bug in tabling of Linux /proc-based lock
+               info.
+
+               Corrected bug in handling of SunOS TLI streams.
+               Dan Farmer <zen@trouble.org> reported the problem.
+
+               Added a Solaris 2.6 work-around to keep the BIND
+               <sys/bitypes.h> from colliding with the Solaris
+               <sys/int_types.h>.
+
+               Strengthened the Configure test for /proc-based
+               Linux lsof, based on a report from Marty Leisner
+               <leisner@sdsp.mc.xerox.com>.
+
+               Tested on OpenBSD 2.3.
+
+               Made AIX changes that allow use with 3.2.5.  The
+               changes were suggested and tested by Brett Hogden
+               <hogden@rge.com>.
+
+               Added Solaris 2.6 AFS support.  Disabled reporting
+               of some node numbers for Solaris 2.5 and above open
+               AFS files.  The node number computation algorithms
+               used for SunOS 4.1.x and Solaris less than 2.5 no
+               longer always work under Solaris 2.5 and above.
+
+4.30           April 9, 1998
+               Corrected a pid structure member naming error for
+               UnixWare < 2.1.2.  The problem was reported by
+               Richard van Meurs <vanmeurs.anva@atriserv.nl>.  He
+               supplied the correction.  This was offered as a
+               patch to 4.29.
+
+               Had a report from Igor Schein <ischein@air-boston.com>
+               that IRIX 6.4 patch 2839 is another SGI kernel
+               patch, along with 2536, that changes the size of
+               the proc structure in the kernel without changing
+               the proc structure in <sys/proc.h>.  Upon further
+               investigation found that the effect of these patches
+               on the proc structure is not consistent.  Therefore,
+               dropped the Configure patch test for IRIX 6.4 and
+               made the code in irix/dproc.c slightly more tolerant
+               of proc structure size differences for IRIX 6.4.
+               Igor help test the change.
+
+               Corrected Solaris >= 2.5 AFS inode number generation.
+               Craig Everhart <Craig_Everhart@transarc.com> helped
+               find the cause of the problem.  This was offered as
+               a patch to 4.29.
+
+               Refined the Linux /dev/kmem-based glibc evasion
+               for the timeval structure to make it work with
+               glibc version 2.0.7.  This required defining a new
+               global symbol, TIMEVAL_LSOF, default timeval, that
+               the /dev/kmem-based Linux lsof can set to its
+               private glibc timeval name, distinct from the kernel
+               timeval name.
+
+               Added support for Alpha to the /dev/kmem-based
+               Linux lsof.  Alexandre Oliva <oliva@dcc.unicamp.br>
+               provided a test system.  Added an item to 00FAQ
+               about lsof, the Alpha processor, and Linux.
+
+               Added a 00FAQ item about lsof year 2000 compliance.
+               Basically it says lsof is probably compliant,
+               because its only date or time computations are done
+               with time_t values, but I haven't done any specific
+               Y2K validation.  I don't have plans to do any.
+
+               Added support for UnixWare 7.  Chris Daniels
+               <chrisd@dlpco.com> provided a test system and Don
+               Draper <dond@sco.COM> provided technical information.
+               Added BFS and SFS file system support to lsof for
+               UW 2.1.[12] and 7.
+
+               Updated Solaris VxFS support for VxFS 3.2.1.  Greg
+               Earle <earle@netbsd4me.jpl.nasa.gov> reported the
+               need for the update.  Greg and Roger Klorese
+               <rogerk@veritas.com> provided technical information.
+               Scott McClung <mcclung@primenet.com> tested.
+
+               Changed IRIX XFS patch detection in anticipation of
+               learning there are multiple XFS patches for IRIX 6.4
+               that require different versions of the lsof-invented
+               xfs_inode structure.
+
+4.31           April 21, 1998
+               Added a VxFS #if/#endif wrap to a section of the
+               HP-UX dnode.c that wasn't properly protected.  The
+               problem was reported by  Peter Klosky <PKlosky@bdm.com>.
+               This was offered as a patch to 4.30.
+
+               Added support for Solaris 2.7 (first Beta release).
+               Mike Sullivan <Mike.Sullivan@Eng.Sun.COM> provided
+               technical advice and helped test.  Charles Stephens
+               <cfs@jurassic.eng.Sun.COM> also helped test.
+
+               Fixed bug in /proc-based Linux that caused it to
+               access /proc/mounts excessively.  Marty Leisner
+               <leisner@sdsp.mc.xerox.com> provided a syscall
+               trace that identified the bug.  The fix was offered
+               as a patch to 4.30.
+
+               Adjusted the IRIX 6.4 private structure definition
+               for the XFS node to accommodate patch 2970.  Igor
+               Schein <ischein@air-boston.com> identified the
+               patch and the required adjustment.
+
+4.32           May 11, 1998
+               Corrected Solaris 2.7 code for reporting PCFS
+               (floppy disk) node numbers.  Casper Dik
+               <casper@holland.sun.com> supplied the fix.  The
+               fix was offered as a patch to 4.31.
+
+               Corrected a bug in conditional repeat mode handling
+               pointed out by Igor Schein <ischein@air-boston.com>.
+               This was offered as a patch to 4.31.
+
+               Improved reporting of AIX open(/dev/memory device)
+               errors.
+
+               Corrected a Solaris < 2.5 KA_T declaration error,
+               pointed out by Robert Kiessling <robert@easynet.de>.
+               Changed KA_T from a #define to a typedef for all
+               dialects to prevent future problems of this kind.
+
+               Changed the sample Perl 5 script big_brother.perl5
+               to report a four digit year from localtime().
+
+               Added support for AIX 4.3[.1].  Bill Pemberton
+               <wfp5p@tigger.itc.virginia.edu> provided a test
+               system.  Andrew Kephart <akephart@austin.ibm.com>
+               and Tom Weaver <tvweaver@austin.ibm.com> provided
+               technical assistance.  Niklas Edmundsson
+               <nikke@ing.umu.se> did 4.3.1 testing.
+
+               Added -qmaxmem option to CFLAGs for an AIX compilation
+               with an xlc version 4.x compiler.
+
+               Adjusted Linux socket handling for changes in the
+               AX25 members of the sock struct.   Richard Green
+               <rtg@tir.com> pointed out the problem.  Tested
+               /dev/kmem-based lsof under Linux 2.0.34.
+
+4.33           May 22, 1998
+               Added generic IPv6 support to common lsof sources
+               and specific IPv6 support to AIX sources.  Andrew
+               Kephart <akephart@austin.ibm.com> supplied the
+               additions and helped with testing.  Bill Pemberton
+               <wfp5p@tigger.itc.virginia.edu> provided a test
+               system.  The modification affected sources for
+               every dialect, whether it supports IPv6 or not, by
+               changing the interfaces to the common Internet
+               address function ent_inaddr().
+
+               Added support for the NetBSD UVM virtual memory
+               system.  Paul Kranenburg <pk@cs.few.eur.nl> supplied
+               technical details.
+
+               Bracketed HP-UX 11 use of <sys/spinlock.h> with
+               #if/#endif _KERNEL.
+
+               Corrected printing of PCB address in DEVICE column
+               for IRIX.
+
+4.34           June 26, 1998
+               Updated 00FAQ to discuss TCP and UDP ports private
+               to the AIX kernel and 00README to describe how ACLs
+               can be used to give lsof permission to read the
+               kernel memory devices.  Add information to 00FAQ
+               and 00README about other OpenBSD architectures
+               where lsof is reported to compile and run.  Added
+               section to 00FAQ discussing how an incorrect loader
+               path environment variable value can prevent lsof
+               from loading correctly.
+
+               Improved Solaris namefs and doorfs support so that
+               it is now possible to search for an open VDOOR file
+               by the path name of its fattached file system
+               object.  Igor Schein <igor@txc.com> requested the
+               ability to do such a search.  Even with the change,
+               lsof can't always identify path names for open
+               VDOOR files.
+
+               Also at Igor's request, improved reporting of
+               information on open Solaris VCHR files that share
+               a common vnode, and Solaris UNIX domain socket
+               files.
+
+               Corrected print_kptr() argument error in PTX dnode.c,
+               reported by Mark Price <mprice@sequent.com>.
+               Compensated for ncache element naming differences,
+               introduced at PTX 4.4.2; Kurtis D. Rader
+               <krader@sequent.com> reported the problem.
+
+               Changed output column title from INODE to NODE to
+               better reflect the column's contents of node IDs
+               for more than just inodes.
+
+               Improved Configuration and processing for Solaris
+               AFS.  Corrected AIX AFS 3.4 afs_rwlock_t simulation.
+
+               Corrected a cast problem with two AIX knlist()
+               calls, thus quieting an AIX 4.2.1 compiler argument
+               type warning.  Jon Champlin <champlin@us.ibm.com>
+               reported the problem.
+
+               Added support to most dialect versions (exception:
+               /proc-based Linux) to warn when the identity of
+               the kernel where lsof was compiled doesn't match
+               the running identity.  The warning can be suppressed
+               with -w.  Note: determining AIX state requires
+               calling oslevel, a potentially slow operation.
+               Jon Champlin <champlin@us.ibm.com> suggested this
+               addition.
+
+       !!!! WARNING !!!!    !!!! WARNING !!!!    !!!! WARNING !!!!
+
+               Those using the lsof cross-configuration capability
+               (see 00XCONFIG), should be aware that the kernel
+               identity test feature introduces two new basic
+               cross configuration environment variables, LSOF_ARCH
+               and LSOF_VSTR.
+
+       !!!! WARNING !!!!    !!!! WARNING !!!!    !!!! WARNING !!!!
+
+               Identified a situation where a Solaris UNIX domain
+               socket name is known and can be searched for by
+               name; added the necessary code.
+
+4.35           July 17, 1998
+               Made the kernel identity check an option with the
+               HASKERNIDCK #define in machine.h.  Enabled altering
+               of HASKERNIDCK with the Customize script.  Added
+               a clause to the help output that indicates the
+               build-time HASKERNIDCK status.
+
+               Added more information to the NAME column for
+               Solaris UNIX domain sockets.  Made them searchable
+               by their clone device path name.  Igor Schein
+               <igor@txc.com> requested this.
+
+               Completed the HP-UX 11 port with support for its
+               optional 64 bit kernel.  Rich Rauenzahn
+               <rrauenza@cup.hp.com> provided a test system.
+               Corrected errors with HP-UX 11 lock reporting and
+               private kernel structure and type definitions.
+               Added support for HP-UX NFS3 files.
+
+               Limited mount table warnings -- e.g., when -b is
+               used -- to one set per mount point.
+
+               Fixed some mount table scanning and usage bugs,
+               including one in Solaris, reported by Kjetil Torgrim
+               Homme <kjetilho@ifi.uio.no>.
+
+4.36           August 4, 1998
+               Made corrections and additions to IPv6 support and
+               to AF_ROUTE socket handling, supplied by Jean-Luc
+               Richier <Jean-Luc.Richier@imag.fr>.  Jean-Luc's
+               additions provide IPv6 support for the Inria IPv6
+               implementations on FreeBSD and NetBSD.
+
+               Fixed two Solaris 2.5, 2.5.1, 2.6 and 2.7 TCP and
+               UDP host name or IP address reporting bugs, reported
+               by James Mathiesen <James-Mathiesen@deshaw.com>.
+               This fix was offered as a patch to 4.35.
+
+               Updated the Customize script to cause ENTER to use
+               all defaults.  Amir J. Katz <amir@ndsoft.com>
+               suggested this and helped test the changes.
+
+               Updated Solaris ICMP and IP stream handling, based
+               on a report from Igor Schein <igor@txc.com>.
+
+               Fixed a bug in the Digital UNIX mount table handling,
+               reported by Bob Ward <bward@thehartford.com>.
+               While working on the bug, found and updated some
+               obsolete AdvFS code.  This fix was offered as a
+               patch to 4.35.
+
+4.37           September 15, 1998
+               Deactivated SGI IRIX support and archived revision
+               4.36 sources and binaries in pub/tools/unix/lsof/OLD.
+
+               Improved performance of FD searching.  This was
+               offered as a patch to 4.36.
+
+               Amir J. Katz <amir@ndsoft.com> pointed out that
+               ranlib isn't needed for AIX or Solaris.  Made
+               appropriate Configure script changes.
+
+               Fixed a file offset reporting bug for HP-UX VCHR
+               and VBLK device nodes located on a VxFS root.  Doug
+               Siebert <douglas-siebert@iowa.edu> reported the
+               bug.  The fix was offered as a patch to 4.36.
+
+               Resolved an HP-UX root device name reporting bug,
+               partly caused by an out-dated local copy of the
+               <sys/mount.h> mount structure, by generating a
+               local header file with the structure that can be
+               compiled without needing _KERNEL defined.  Doug
+               Siebert also reported this bug.
+
+               Changed some dialect source code -- Digital UNIX,
+               Solaris, SunOS, and UnixWare -- to make more
+               consistent with ps the user ID lsof reports in the
+               USER column.  Added a 00FAQ entry about it.  Igor
+               Schein <igor@txc.com> reported the Solaris and
+               SunOS lsof inconsistencies with what ps(1) reports.
+
+               Ported lsof to Pyramid ReliantUNIX 5.44.
+
+               Added brackets as comments to case, do, done, else,
+               endif, esac, if, and while statements in Configure
+               to assist in navigating its clauses.
+
+               Added more Linux 2.0.x glibc work-arounds.
+
+               Added support for UnixWare 7.0.1.
+
+               Ralph Forsythe <ralph@contact-paging.com> provided
+               a new FreeBSD test system.
+
+4.38           November 25, 1998
+               Added support for recent FreeBSD 3.0 distributions.
+               A 3.0 test system was provided by David O'Brien
+               <obrien@NUXI.com>.  This was offered as a patch
+               to 4.37.
+
+               Updated the scripts/idrlogin.perl* files to look
+               for sshd processes in addition to rlogind and
+               telnetd ones.
+
+               Added support for DU 5.0 Beta.  Berkley Shands
+               <berkley@cs.wustl.edu> provided a test system.
+
+               Added support for OpenBSD 2.4 with changes supplied
+               by Kenneth Stailey <kstailey@disclosure.com>.
+
+               Changed the Solaris 2.7 tests and documentation to
+               Solaris 7.
+
+               Made some changes to the header files for NEXTSTEP
+               3.3 and added support for OPENSTEP 4.x with help
+               from Michael A. Hovan III <mhovan@BLaCKSMITH.com>
+               and Carl Lindberg <Carl_Lindberg@BLaCKSMITH.com>.
+               The combined dialect subdirectory is named n+os.
+               One of Carl's changes propagates RC_CFLAGS to the
+               library Makefile.  Timothy J. Luoma <luomat@peak.org>
+               helped test under NEXTSTEP 3.3 and OPENSTEP 4.2.
+
+               Made UW 7.x version sensitive to the presence of
+               ptf7038.  Added peer PCB address to Unix domain
+               socket Name column, even when a path name has been
+               located.  Information for these changes was supplied
+               by Francis Le Bourse <flebourse@intelcom.fr>.  Lee
+               Penn <lee@dlpco.com> provided a test system.
+
+               Tested lsof under OSR 5.0.5 on a test system also
+               provided by Lee Penn.
+
+               Made path name argument processing more tolerant
+               of errors per a suggestion from Julian Gordon
+               <julian@cadence.com>.
+
+               Acquired a new UnixWare 2.x test system, generously
+               provided by Computer Classroom, Inc. -- Matthew
+               Thurmaier <matt@compclass.com>, Ken Laing
+               <ken@compclass.com>, and Andrew Merril
+               <andrew@compclass.com>. Updated Configure to accept
+               a UnixWare version of 2.1.3.
+
+               Updated kmem-based lsof for Linux 2.0.36.
+
+               Updated NetBSD sources for a change in a UVM virtual
+               mapping header file.
+
+               Corrected a cache allocation bug in Sun format
+               kernel name cache handling.  The bug only shows up
+               when the kernel name cache is inaccessible.
+
+4.39           December 29, 1998
+               Corrected problems with large device number handling
+               for 64 bit Solaris 7.  The problems were reported
+               by Steve Bellenot <bellenot@math.fsu.edu>.  Steve
+               helped test the fixes.  The fixes were offered as
+               two patches to lsof 4.38.
+
+               Improved FreeBSD Configure operations for header
+               files that must be obtained from the kernel source
+               tree, based on a suggestion from David O'Brien
+               <obrien@NUXI.com>.
+
+               For Bela Lubkin <filbo@deepthought.armory.com> made
+               optional with +f[cfn] the display of file structure
+               address, shared use count, and node structure
+               address.  /proc-based Linux doesn't implement this
+               feature, because it doesn't read kernel structures
+               from kernel memory.  Modified the PTX -X option to
+               take advantage of the new file structure display
+               option.  Added shared.perl5 to the scripts/
+               subdirectory to provide an example of how +f[fn]
+               might be used to track shared file descriptors and
+               files.
+
+               Added more /dev/kmem-based Linux glibc evasions,
+               provided by Jeff Johnson <jbj@redhat.com> and Maciej
+               Lesniewski <nimir@kis.p.lodz.pl>.  Jeff helped test
+               them on various Linux architectures.
+
+               Tested on AIX 4.3.2; no changes were required.
+               Doug Crabill <dgc@purdue.edu> provided a test
+               system.
+
+               Fixed -c option to detect missing command name when
+               following option begins with `+'.
+
+4.40           January 25, 1999
+               Added support for using the CDS compiler for Reliant
+               Unix 5.44 and above.  Made Reliant Unix MIPC support
+               optional, dependent on the presence of <sys/mipc.h>.
+
+               Based on a report from Michael Schmitz <MSchmitz@lbl.gov>
+               that /dev/kmem-based lsof misbehaves on a Linux
+               2.0.x m68k kernel without module support, made the
+               absence of query_module() or get_kernel_syms()
+               Linux kernel support a fatal error.  Updated relevant
+               sections of 00FAQ to reflect the change.
+
+               Added the ability to force the Linux Configure
+               stanza to use the /proc or /dev/kmem source base
+               via a LINUX_BASE environment variable specification.
+               This is a cross-configuration assist.
+
+               Added "+D <dir>" and "+d <dir>" options for directory
+               searching.  +D searches the entire tree, starting
+               at <dir>, including <dir>, its contents, and its
+               subdirectory branches; +d searches only <dir> and
+               its contents, but not its subdirectory branches.
+               Improved lsof's searching of the specified name
+               list to compensate for anticipated long lists from
+               +d and +D.
+
+               Made an egrep in the Solaris Configure stanza usable
+               by the standard and XPG4 egrep's.  Kenneth Stailey
+               <kstailey@disclosure.com> pointed out the improvement.
+
+               Fixed bugs in /dev/kmem-based Linux and UnixWare
+               Unix domain socket name searching.
+
+               Changed a Linux Alpha #include to be conditional
+               on the presence of its named header file, so that
+               lsof will compile on Red Hat 5.1 and 5.2 (Linux
+               kernel 2.0.35) where the header file is absent.
+               The problem was reported by Alexandre Oliva
+               <oliva@dcc.unicamp.br>.
+
+               Fixed an AIX 4.3+ bug in procinfo struct space
+               allocation, reported by Jeff Stewart <jws@purdue.edu>.
+               This was offered as a patch to 4.39.
+
+               Added an lstatsafely() function to offer the same
+               isolation for lstat() calls that statsafely() offers
+               for stat() calls.  This made DOSTAT_FUNCTION no
+               longer necessary, so deleted it.
+
+               With help from Laurent P. Montaron <lpm@sequent.com>
+               ported lsof to PTX 4.4.4.  Laurent did a monumental
+               job of identifying TCP/IP changes by their TCP
+               version, rather than by their PTX (With mix 'n
+               match PTX and TCP/IP versions, the PTX version
+               often has no bearing on the TCP/IP version.), and
+               changed the Configure script and pre-processor
+               #if/#else/#endif blocks to match.  He also updated
+               Unix domain socket handling for PTX TCP/IP versions
+               4.5 and above.
+
+               Updated CLIENT handle acquisition of fill_portmap()
+               in print.c to use the more modern RPC function
+               clnt_create() in place of clnttcp_create() where
+               possible.  PTX 4.4.4 requires clnt_create().
+
+4.41           February 27, 1999
+               Added FreeBSD 3.1 and and 4.0 support with help
+               from Sheldon Hearn <axl@iafrica.com>, David O'Brien
+               <obrien@NUXI.com>, and John Polstra <jdp@polstra.com>.
+
+               Corrected bungled AIX 4.3+ patch that went into
+               lsof 4.40.
+
+               Reorganized the Configure script to improve Makefile
+               construction.  A specific impetus for this was to
+               allow FreeBSD system-wide make flags to be propagated
+               to the lsof Makefiles, but other goals were to make
+               sure that the DEBUG= make entry can over-ride
+               standard CFLAGS values, and to better manage the
+               identification of compilers and their versions.
+               Two compiler-related values may now be supplied in
+               environment variables: 1) the compiler path in
+               LSOF_CC; and 2) the compiler version in LSOF_CCV.
+               00XCONFIG documents them.
+
+               Added support for Pyramid Reliant Unix bsdsfs,
+               msockfs, and sockfs file systems.
+
+               Added an optional LSOF_CINFO string to Configure,
+               producing a CINFO string in selected Makefiles,
+               producing a #define LSOF_CINFO in selected version.h
+               header files.  The purpose of this is to allow
+               Configure the option to propagate information to
+               the lsof -v output.  It is now used for Linux to
+               identify the code base, and for HP-UX 10.30 and
+               11.0 and Solaris 7 to identify the kernel bit size.
+
+               Added system information to NEXTSTEP and OPENSTEP
+               -v output, from the second line of hostinfo's
+               output.
+
+               Fixed a login name buffer overflow problem in the
+               processing of -u option values.  This was offered
+               as a patch to 4.40.  !!!THIS IS A SERIOUS STACK
+               OVERFLOW BUG; A LINUX EXPLOIT EXISTS FOR IT THAT
+               OPENS A BASH SHELL WITH LSOF'S AUTHORITY -- E.G,
+               SETGID(KMEM) POWER!!!
+
+               Improved the Solaris mount table filter so the
+               volume manager's fake mount point, "/vol", is
+               ignored and doesn't supplant "/" in NAME column
+               path assemblies.  Igor Schein <igor@txc.com> reported
+               this bug and provided important help in finding
+               it.  This was offered as a patch to 4.40.
+
+               Changed the Linux /dev/kmem-based lock ownership
+               test to answer a problem reported by Tom Christiansen
+               <tchrist@jhereg.perl.com>.  This was offered as a
+               patch to 4.40.
+
+               Installed an HP-UX 11 patch, suggested by Kevin
+               Vajk <kvajk@cup.hp.com>, that adjusts a private
+               lsof kernel header file, derived via Q4, to correspond
+               to an HP-UX patch bundle.
+
+               Made NetBSD 1.3I sockproto structure adjustment.
+
+4.42           March 30, 1999
+               Fixed a typo in the HP-UX dfile.c that caused +fF
+               and +fN output controls to swap effect.
+
+               Enabled for OpenBSD 2.5 per notice from Kenneth
+               Stailey <kstailey@kstailey.tzo.com>
+
+               Made more VM accommodations for FreeBSD 4.0.
+
+               Improved file system search reporting to include
+               path name components when they're available, instead
+               of mindlessly reporting the file system name in
+               the NAME column.  Guy Dallaire <gdallair@geocities.com>
+               brought the need for this change to my attention.
+
+               Updated Solaris 2.6 VxFS for Veritas Oracle Database
+               Edition 2.0, VxFS version 3.3, and VxVm version
+               2.5.4, based on a report from Chris Kordish
+               <chris.kordish@East.Sun.COM>.  Chris kindly provided
+               a test system.
+
+               Improved HP-UX ipc_s patch detection in Configure,
+               response in .../dialects/hpux/hpux11/ipc_s.h, and
+               documentation in 00FAQ, Kevin Vajk <kvajk@cup.hp.com>
+               helped test.
+
+               Added to Customize the option to suppress HASKERNIDCK
+               selection for specified dialects.  Suppressed it
+               for /proc-based Linux lsof, and removed its test
+               and code from there.  Tin Le <tin@netimages.com>
+               alerted me to the need for this update.
+
+               Ported to official Digital UNIX 5.0 release.
+
+               Changed DU lsof to use the knlist(3) function when
+               no kernel file has been specified with -k.  This
+               change was suggested by Erich Wimmer
+               <Erich.Wimmer@digital.com>.
+
+               Updated Configure for latest NetBSD (1.3I?) with
+               UVM support the default.
+
+4.43           May 11, 1999
+               Corrected a typo in the Solaris gcc discussion in
+               00FAQ.  Made changes to the Solaris 2.5[.1] private
+               tcp_s structure.  Both changes were done in response
+               to reports from Igor Schein <igor@txc.com>, who
+               tested the Solaris 2.5 change.
+
+               Made more IPv6 adjustments to lsof for Tru64 UNIX
+               (Digital UNIX) 5.0, based on information obtained
+               from Compaq by Berkley Shands <berkley@cs.wustl.edu>.
+
+               Corrected HP-UX error message about HP-UX 11 q4 usage.
+               Amir Katz <amir@ndsoft.com> reported the correction.
+
+               Fixed a GlibC 2.1 conflict in /proc-based Linux lsof.
+
+               Fixed a man page typo reported by Vlad Harchev
+               <hvv@hippo.ru>.
+
+               Changed some Solaris 2.7 references to Solaris 7
+               in Configure and 00XPORTING.
+
+               Added a Solaris example to the echo statements that
+               are the install rule in the SunOS/Solaris Makefile.
+
+               Added a field to the file structure output --
+               FILE-FLAG (file structure open flags, f_flag[s],
+               and process file flags, typically u_pofile)) --
+               enabled with +f[gG].  Its field output character
+               is 'G'.
+
+               Figured out another piece of the HP-UX 11 patched
+               ipc_s structure puzzle with the help of Keith Kalet
+               <KEITH_KALET@HP-USA-om41.om.hp.com>.
+
+               Fixed a PTX real vnode to real inode interpretation
+               bug.
+
+               Added link count to lsof output.  Eric Dumazet
+               <dumazet@risgw.ris.fr> requested and helped test
+               it.  The new +L option enables and filters it.
+               Its field output character is `k'.
+
+               Updated Configure script to recognize NetBSD 1.4.
+
+               Updated AFSConfig to handle default answers to
+               questions.
+
+               Incorporated patch from Jonathan Sergent <sergent@io.com>
+               that enables /proc-based Linux lsof to run on both
+               32 and 64 bit kernels.
+
+               Updated Configure script with a patch from David
+               O'Brien <obrien@NUXI.com> that recognizes FreeBSD 3.2.
+
+4.44           June 24, 1999
+               Corrected use of nlink member of hsnode for SunOS
+               4.1.x High Sierra File System files.  John Dzubera
+               <zube@tlaloc.stat.colostate.edu> reported the
+               problem and helped test the fix.  Also fixed a
+               SunOS segmentation fault bug.  These fixes were
+               offered as a patch to 4.43.
+
+               Improved handling of /proc-based Linux UNIX PCB
+               address.
+
+               Fixed a NEXTSTEP and OPENSTEP bug that made repeat
+               option (-r) processing malfunction.  This fix was
+               offered as a patch to 4.43.
+
+               Fixed Configure so it doesn't use -O in the Cflags
+               for the bundled HP-UX C compiler.  Jim Ankenbrandt
+               <jankenbrandt@penton.com> reported the problem.
+
+               Corrected output ordering of parent PID and process
+               group ID when both -R and -g are specified.
+
+               Enhanced the pdev.c and pdvn.c library modules for
+               wider use.  These dialect versions use the new
+               library modules: DEC OSF/1, Digital UNIX, and Tru64
+               UNIX; Pyramid DC/OSx and Reliant UNIX; SCO OSR and
+               UnixWare; and Sequent PTX.
+
+               Added basic clone device support to /dev/kmem-based
+               HP-UX lsof for HP-UX 10.30 and higher.
+
+               Added raw socket support to /proc-based Linux lsof.
+
+               Changed NODE-ADDR column title to NODE-ID in
+               anticipation of using more general identification
+               information in the column.
+
+               Ported to UnixWare 7.1, using a test system kindly
+               provided by Matt Thurmaier <matt@compclass.com>
+               and Don Draper <dond@sco.com>.
+
+               Updated for NetBSD 1.4C VM changes, and a new
+               current and root working directory structure.
+
+               Made minor adjustment for latest Tru64 UNIX 5.0
+               Beta release.
+
+4.45           July 30, 1999
+               Fixed quoting problem in DEC OSF/1, Digital Unix,
+               and Tru64 UNIX Makefile's install rule.  The problem
+               was reported by Berkley Shands <berkley@cs.wustl.edu>.
+               Fixed bug in Tru64 UNIX 4 lsof that caused FDs to
+               be skipped.  These fixes were offered in a patch
+               to 4.44.
+
+               Fixed a repeat-mode /proc-based Linux lsof bug,
+               reported by Sami Farin <sfarin@ratol.fi>.  This
+               was offered as a patch to 4.44.
+
+               Picked lint, some reported by Sami Farin.
+
+               Corrected a 00DCACHE documentation error in a sample
+               shell script.  The problem was reported by Chad R.
+               Larson <chad@larsons.org>.  Changed commented-out
+               entries in machine.h files so they require more
+               thought and work when the comments are removed,
+               based on a remark by Chad.
+
+               Compensated for the practice of Solaris 7 and above
+               to record the dev= value in /etc/mnttab in 32 bit
+               mode, even on 64 bit systems.  This was offered as
+               a patch to 4.44.
+
+               Added a C library test for /proc-based Linux lsof,
+               so that the #include files can be adjusted for a
+               non-GlibC environment.  The need for this was
+               reported by Andrew Hill <andrewh@tirin.openworld.co.uk>.
+               This was offered as a patch to 4.44.
+
+               Added support for Auspex LFS 1.8.1 and 1.9.2 to
+               SunOS 4.1.4 lsof.  The support was requested by
+               Quentin Fennessy <quentin@dvorak.amd.com>, who
+               provided information and did testing.
+
+               Enabled IPv6 support code for NetBSD and OpenBSD,
+               conditional on Configure script tests.  Wolfgang
+               Rupprecht <wolfgang@wsrcc.com> supplied the NetBSD
+               code and tested it.  The OpenBSD code I constructed
+               has been compiled but not tested.
+
+               Updated the identd Perl 5 script, based on a report
+               from Wendy Lin <af5@taiyang.cc.purdue.edu> that
+               the space in its response line in front of the user
+               name violates RFC 1413.
+
+               Added IPv6 support to /proc-based Linux lsof.
+               Jonathan Sergent <sergent@ETLA.NET> and Andrew
+               Thomas Sydelko <sydelko@ecn.purdue.edu> kindly
+               provided a test system.
+
+               Updated man page description of AIX multiplexed
+               files to indicate that they might be /dev/ptc or
+               /dev/pts, depending on the AIX version.  The
+               correction was suggested by Onno van der Linden
+               <onno@simplex.nl>.
+
+               Sylvain Robitaille <syl@alcor.concordia.ca> reports
+               lsof passes his Y2K tests.
+
+4.46           October 23, 1999
+               Corrected /proc-based Linux lsof to detect that an
+               IPv6 address is a mapped IPv4 address.  The problem
+               was reported and analyzed by Arkadiusz Miskiewicz
+               <misiek@misiek.eu.org>, who also tested the fix.
+
+               Added a libc5 library /dev/kmem-based Linux lsof
+               circumvention, supplied by Jason Lingohr
+               <lingman@lucid.net.au>.
+
+               Corrected a bug in -t (terse) AIX output, reported
+               by Wendy Lin <af5@taiyang.cc.purdue.edu>.  I
+               introduced the bug at revision 4.43 when adding
+               FILE_FLAG reporting.  This was offered as a patch
+               to 4.45.
+
+               Added a work-around for a problem in the OpenBSD
+               2.3 <sys/pipe.h> header file.  Volker Borchert
+               <bt@teknon.de> provided and tested it.
+
+               Improved description of cross-building lsof for a
+               64 bit Solaris 7 system on a 32 bit system with
+               suggestions from Phillip Edwards
+               <Philip.Edwards@sn.wpafb.af.mil>.
+
+               Fixed a gawk POSIX-mode pattern error in the Linux
+               /dev/kmem-based Mksrc script, based on a tip from
+               Ambrose C. Li <acli@mingpaoxpress.com>.
+
+               Fixed a bug in the Tru64 UNIX IPv6 handling, courtesy
+               of a report from Casper Dik <casper@holland.sun.com>.
+
+               Enabled support for OpenBSD 2.6.
+
+               Enabled support for BSDI BSD/OS 4.1, based on a
+               report from Jeffrey C Honig <jch@bsdi.com> that
+               only a Configure script change is necessary.
+
+               Enabled Configure script to use gcc for building
+               lsof for a 64 bit Solaris 7 and 8 kernels, if the
+               gcc version is 2.95 or above.
+
+               Improved -i option handling for systems with IPv6
+               support so that it will search for a host name in
+               both IPv4 and IPv6 families, when that is possible.
+               As a companion modification, changed -V processing
+               to report a single error when a multiple host name
+               match is requested.  Casper Dik <casper@holland.Sun.COM>
+               helped test.
+
+               Fixed a DEC OSF/1, Digital UNIX, Tru64 UNIX repeat
+               mode bug, reported by Mayer Ilovitz <mayer@cooper.edu>.
+               Mayer helped test the fix.  The fix was offered as a
+               patch to 4.45.
+
+               Changed Solaris socket file recognition scheme, so it
+               is (nearly) the same through Solaris 8, where the
+               previous clone device scheme no longer works.
+
+               With significant assistance from Casper Dik, added
+               support for Solaris 8 Beta and Beta refresh.  The
+               IPv6 support in Solaris 8 is still in some flux,
+               so there are temporary compensations for the
+               differences between Beta IPv6 support and Beta
+               refresh IPv6 support.  Casper and I hope those
+               differences disappear by FCS.
+
+               Improved the delivery of information on Solaris
+               2.5.1, 2.6, 7, and 8 door files.
+
+               Fixed a repeat mode bug that surfaces when /etc/passwd
+               changes between cycles.  The bug report and diagnostic
+               help were supplied by Igor Schein <igor@txc.com>.
+               The fix was offered as a patch to 4.45.
+
+               Added support for INRIA IPv6 to NetBSD.  Jean-Luc
+               Richier <Jean-Luc.Richier@imag.fr> provided patches
+               and a test system on which to verify them.
+
+               Added support for AIX 4.3.3.  Jeff W. Stewart
+               <jws@anaconda.cc.purdue.edu> provided a test system.
+
+               Made adjustments for FreeBSD 4.0-current.
+
+               Improved reporting of information for AIX sockets that
+               lack protocol control blocks.
+
+4.47           November 29, 1999
+               Based on a query from Jean-Pierre Radley <jpr@jpr.com>,
+               changed the lsof top-level Makefile to propagate
+               CFGF to the library Makefile.  (DEBUG was already
+               being propagated.)  Added osrgcc and scogcc Configure
+               abbreviations (to use gcc) for Jean-Pierre.
+
+               In response to a query from Igor Schein <igor@txc.com>,
+               improved the Configure script test for Solaris 7
+               and 8 that decides if the compiler can produce 64
+               bit executables.
+
+               Made an ugly hack, based on making a private rnode
+               structure definition from q4 output, to compensate
+               for HP-UX 10.20 and lower recent NFS3 patches.  HP
+               didn't supply an updated <nfs/rnode.h> with the
+               patches.  The problem was reported by Will Partain
+               <partain@mekb2.sps.mot.com>.  Elias Halldor Agustsson
+               <elias@hi.is> helped identify the patches as
+               PHNE_18173, PHNE_19426, PHNE_19937, and PHNE_20091,
+               and provided a test system.
+
+               Switched BSDI test system from 2.1 and 3.1 to 4.0.1,
+               courtesy of Terry Kennedy <terry@tmk.com>.
+
+               Added some more dev_t hacks for Alpha FreeBSD 4.0.
+
+               Added support for IPv6 on BSD 4.x.  The support hasn't
+               yet been tested, just compiled.
+
+               Added support for the mnt file system (mntfs or
+               /etc/mnttab) on Solaris 8.  Tested on Solaris 8
+               BETA-Refresh.
+
+               Made selection of optional fields (e.g., PPID with
+               -FR) in a field output specification select the
+               optional field, too, so that the option selector
+               for the field (e.g., -R) isn't also required.  This
+               change was made in response to an inquiry from John
+               DuBois <spcecdt@armory.com>.  This may require some
+               revision to scripts that parse all field output;
+               two scripts in the lsof distribution's scripts/
+               subdirectory had to be updated.
+
+               Corrected handling of Linux IPv4 addresses mapped
+               in IPv6 addresses.
+
+               Tested under OpenBSD 2.6.
+
+4.48           January 14, 2000
+               Modified -i argument processing of colon-separated
+               IPv6 addresses to recognize an IPv4 address mapped
+               in an IPv6 address and handle it as an IPv4 address.
+               This was offered as a patch to 4.47.
+
+               Added a defined symbol (NOWARNBLKDEV) to control
+               (inhibit) the issuance of a warning when no block
+               devices are found.  This was done anticipating its
+               need in FreeBSD 4.x, but that dialect version no
+               longer has any block devices, so HASBLKDEV was
+               disabled for it instead.  NOWARNBLKDEV was left in
+               place for possible use in the future.
+
+               Enabled KAME IPv6 Configure support for FreeBSD
+               when <netinet6/in6.h> is found.
+
+               Disabled use of gcc to compile lsof for 64 bit
+               HP-UX 11.
+
+               Updated Configure to recognized FreeBSD 3.4.
+
+               Based on suggestions from Bernt Christandl
+               <beb@MPA-Garching.MPG.DE> improved AFS configuration
+               for AIX and Solaris, and updated AIX AFS 3.5 support.
+               Johannes Tax <tax@bluedog.oit.unc.edu>, Hung T.
+               Pham <hung_pham@unc.edu>, and Curt Freeland
+               <curt@grumpy.cse.nd.edu> provided test systems.
+
+               Updated lsof's private rnode definition for AIX
+               4.3.3, since IBM still doesn't ship the
+               <oncplus/nfs/rnode.h> header file and the rnode
+               structure definition in <nfs/rnode.h> doesn't match
+               what the kernel uses.  This was offered as a patch
+               to 4.47.
+
+               Weakened the test in the Linux /proc-based lsof of
+               the field count of data lines in /proc/net/{tcp,udp}.
+               It appears that recent 2.3.x Linux kernels have
+               added untitled fields to these files.  The bug
+               report came from Gabor Liptak <gaborliptak@usa.net>.
+
+               Adjusted for a FreeBSD 4.0 change in the definition
+               of [_]KERNEL.  David O'Brien <obrien@NUXI.com> reported
+               the problem and provided a test system.
+
+               Removed the HASPPID bracket from Fppid (the -R
+               option state variable) so that the field select
+               table will compile even when HASPPID is not defined.
+               This problem was introduced at revision 4.47 with
+               code that causes some field output characters to
+               set option states.  The problem was reported by
+               David Bacon <bacon@birch.eecs.lehigh.edu>.
+
+4.49           April 3, 2000
+               Made clearer in man page that "Lxx" FDs are AIX
+               loader table references.  Also updated the 00FAQ
+               discussion of the Stale Segment ID bug to include
+               AIX 4.3.x.
+
+               Modified support for NetBSD 1.4Q to include the
+               <sys/buf.h> header file to cope with an MFS change.
+
+               Added support for OpenBSD UVM virtual memory.
+
+               Added support for AIX systems with > 2GB of memory.
+               Chris Sylvain <csylvain@itg.ummc.umaryland.edu>
+               reported the problem and provided the solution.
+               Chris also supplied some minor code cleanup.  This
+               was offered as a patch to 4.48.
+
+               Based on new information from Igor Schein <igor@txc.com>
+               made additional compensation in Configure script
+               for 64 bit Solaris 7 and 8 gcc.
+
+               Added some 00FAQ info on the effect ordering of
+               the +fg and -FG options has on output format.
+
+               Improved NetBSD IPv6 configuration, based on a
+               suggestion from Thomas Klausner
+               <wiz@danbala.ifoer.tuwien.ac.at>.  Added code to
+               convert IPv4-mapped-in-IPv6 addresses to IPv4
+               addresses.
+
+               Updated the information in 00FAQ and the HP-UX 11
+               binary directory README files on the HP-UX 11 ipis_s
+               patch with new information supplied by Eric McWhorter
+               <emcwhorter@xsis.xerox.com>.
+
+               Added documentation on changes to HASFSTYPE and
+               HASNCACHE, and the new HASPRIVPRIPP.
+
+               Adjusted Configure for FreeBSD 5.0.  Made additional,
+               necessary changes to Configure and the BSDI sources
+               to eliminate load errors.
+
+               Added KAME IPv6 support to FreeBSD at the request
+               of Ollivier Robert <roberto@eurocontrol.fr>, who
+               provided a test system.
+
+               Corrected the script that generates the CHECKSUMS
+               files for binaries to correctly name the detached
+               PGP certificate.  The documentation bug was reported
+               by Michael Hennecke <hennecke@rz.uni-karlsruhe.de>.
+
+4.50           June 29, 2000
+               Added a NetBSD alpha test host, courtesy of Ray
+               Phillips <r.phillips@mailbox.uq.edu.au>.  An lsof
+               4.49 binary, built on Ray's 1.4.1 system was made
+               available prior to the 3.50 release.
+
+               Upgraded the system map file tests in /dev/kmem-based
+               Linux lsof, making the use of DEBIAN_LINUX_LSOF
+               unnecessary.  Tested the changes on a system made
+               available by Vincent Kujala <kujala@geog.ubc.ca>
+               and Jim Mintha <jim@ic.uva.nl>.
+
+               Forced AIX to use the large-file-enabled versions
+               of lstat (lstat64) and stat (stat64) if <sys/stat.h>
+               contains stat64.  This should allow lsof to stat()
+               AIX files > 2GB even when the builder has not
+               defined the "large file enabled programming
+               environment."  Configure tests <sys/stat.h> and
+               puts -DHASSTAT64 in the Makefile's CFLAGS to make
+               this happen.  Fernando A.B. Whitaker
+               <whitaker@cenapad.unicamp.br> reported the problem.
+               This was offered as a patch to 4.48.
+
+               Enabled Configure script to handle OpenBSD 2.7.
+               Angelos D. Keromytis <angelos@dsl.cis.upenn.edu>
+               reported the availability of OpenBSD 2.7 and supplied
+               the Configure script patch.
+
+               Improved handling of DOOR and fattach()'d files in
+               Solaris.
+
+               Changed message about missing kernel symbol file
+               from "not yet determined" to "none found".
+
+               Updated FreeBSD, NetBSD, NEXTSTEP, OpenBSD, and
+               OPENSTEP support to report "no PCB" and the values
+               of the SO_CANTSENDMORE and SO_CANTRCVMORE state
+               flags when a socket structure has no inpcb pointer.
+               This modification was made to AIX lsof at revision
+               4.46.  Added an entry to 00FAQ about sockets that
+               have no inpcb pointer.
+
+               Upgraded support for FreeBSD 5.0-CURRENT.  Ben
+               Smithurst <ben@scientia.demon.co.uk> supplied
+               patches and did testing.  David O'Brien <obrien@NUXI.com>
+               supplied a test system.  The update included dropping
+               the Fctty part of file descriptor file system
+               support, conditional on a Configure script test.
+               I propagated those changes to BSDI, NetBSD, and
+               OpenBSD in anticipation of their having the
+               modification in the future.  David also arranged
+               with Michael Haro <mharo@area51.fremont.ca.us> for
+               a FreeBSD 3.4 test system.
+
+               In response to an lsof 3.72 bug report from Jim Mewes
+               <jim@corp.phone.com>, added more kernel address
+               filtering to the lsof function, kread(), that reads
+               Solaris kernel data.
+
+               In response to a report from Marc Duponcheel
+               <marc@offline.be>, added tests to the /proc-based
+               Linux lsof to ignore file systems of types "autofs"
+               and "pipfs".
+
+               Based on a report and information supplied by Casper
+               Dik <casper@holland.Sun.COM>, updated the ncache_load()
+               function in lib/rnch.c with new code that deals
+               with a post Solaris 8 change in kernel name cache
+               (DNLC) handling.  Casper tested the update, which
+               should be invisible to Solaris versions without
+               the new DNLC code.
+
+               Added support for Solaris VxFS QIO files, based on
+               a report from Kieran Broadfoot <kieran.broadfoot@gs.com>.
+               Kieran help test the support.
+
+               Added support for PTX 4.4.6 and 4.5[.1] with help
+               from the usual cast of good people at Sequent.
+
+               Added support for 64 bit file sizes and offsets on
+               BSDI, FreeBSD, NetBSD, and OpenBSD, based on a
+               report from Dan Nelson <dnelson@emsphone.com>.
+               Dan supplied a patch and did FreeBSD testing.
+
+               Added Configure script recognition of NetBSD 1.5,
+               based on a report from Andrew Brown <atatat@atatdot.net>.
+               Thomas Klausner <wiz@danbala.ifoer.tuwien.ac.at> updated
+               the NetBSD port package to use a pre-release of this
+               addition.
+
+               At the last minute saw a notice via deja.com's
+               UseNet search service that FreeBSD 3.5 had been
+               released and lsof didn't grok it.  Added recognition
+               of 3.5 to lsof's Configure script, but didn't have
+               the opportunity to test lsof on 3.5.
+
+4.51           August 21, 2000
+               Added Configure script support for the upcoming
+               Solaris 9 release based on suggestions from Casper
+               Dik <Casper.Dik@holland.sun.com>.
+
+               Changed sample Perl scripts to assume that
+               /usr/local/bin/perl is Perl 5 and Perl 4 may be
+               found in /usr/local/bin/perl4.
+
+               Updated Configure to recognize FreeBSD 4.1 and made
+               a FreeBSD pre-release distribution available.
+
+               Bela Lubkin <belal@sco.COM> tested lsof on the
+               upcoming SCO OSR 5.0.6 release and reports that
+               lsof appears to work properly.
+
+               Updated the AIX compiler test in Configure to
+               recognize its version 5.
+
+               Updated AIX 4.3.3 support with automatic recognition
+               of the proper rnode structure, based on machine
+               bit width.  Also added code to detect when processing
+               the -X option that lsof has been compiled with the
+               "other" AIX 4.3.3 user structure and to apply
+               compensations.  When a compensation method works,
+               it's applied during subsequent -X processing; when
+               none works, further -X processing is disabled.
+
+               Added Tru64 UNIX 5.1 support.  Updated Tru64 UNIX
+               library text file support to recognize new kernel
+               support for AdvFS library files.  Berkley Shands
+               <berkley@cs.wustl.edu> and Klaus Saggerer USG
+               [saggerer@zk3.dec.com> helped put me in contact
+               with Chang Song <song@zk3.dec.com>, the developer
+               of 5.1's new kernel name cache and he helped me
+               develop new code in lsof to access it.
+
+               Corrected reporting of PTX fattach()'d address.
+
+               Changed Configure and dlsof.h for NetBSD and OpenBSD
+               to use /usr/include/uvm header files when available.
+               Andrew Brown <atatat@atatdot.net>, Thomas Klausner
+               <wiz@danbala.ifoer.tuwien.ac.at>, and Wolfgang
+               Rupprecht <wolfgang@wsrcc.com> pointed out the need
+               to do this for NetBSD.  Andrew provided access to
+               a NetBSD 1.5 system for verifying the changes.
+
+               Installed snprintf() support, including a private
+               version in the lsof library for those UNIX dialects
+               without the function.  Changed all sources to use
+               it instead of sprintf() and strcpy().
+
+               Fixed a memory leak in the readvfs() functions of
+               BSDI, DEC/OSF1, Digital UNIX, FreeBSD, NetBSD,
+               OpenBSD, and Tru64 UNIX.
+
+               Tested on Linux 2.4.
+
+               Modified the Pyramid MkKernOpts script to compensate
+               for `uname -s` configuration alternatives.  Robert
+               Dahlem <Robert.Dahlem@ffm2.siemens.de> supplied
+               the modification.
+
+               Obtained access to an FCS Solaris 8 64 bit system
+               and built lsof on it, using Sun Workshop C 5.0 and
+               gcc 2.96 20000814 (experimental).  Both compilers
+               produce a working lsof.
+
+
+4.52           November 8, 2000
+               Completed work on an HP-UX 11.11 port that uses a
+               pstat(2) interface provided by HP.  To distinguish
+               it from its predecessors for HP-UX, this lsof
+               version is called PSTAT-based and the predecessor
+               versions are now called /dev/kmem-based.  I am
+               indebted to the far-sightedness and support of
+               these good people at HP for making PSTAT-based lsof
+               possible: Carl Davidson, Louis Huemiller, Rich
+               Rauenzahn, and Sailu Yallapragada.  The PSTAT-based
+               sources are in lsof_4.52/dialects/hpux/pstat, the
+               /dev/kmem-based ones in lsof_4.52/dialects/hpux/kmem.
+
+               Ported to IBM Monterey for Merced|Itanium, aka AIX
+               5L.  It configures via the Configure script's "aix"
+               abbreviation and has been tested on AIX 5L Beta 3.
+               Jay Beck, Steve Dibbell, Loc Le, Nasser Momtaheni,
+               and Malcom Zung of IBM provided generous support.
+               Since AIX 5L is still in Beta testing, this port
+               can't be considered complete.
+
+               Added Configure support for OpenBSD 2.8.  David
+               Mazieres <dm@cs.nyu.edu> provided a test system.
+
+               Based on a report from Marc Christensen
+               <marc@mecworks.com> added sockfs to the mount scan
+               exemption list for /proc-based Linux lsof.
+
+               Added large file, CDFS, and DOSFS for UnixWare 7.x.
+               Added UnixWare device memory mapping support.  All
+               UnixWare changes were supplied by Eric Dumazet
+               <edumazet@cosmosbay.com>  Eric also supplied some
+               miscellaneous bug fixes.
+
+               Deferred name cache loading until printname() needs
+               to use the name cache.
+
+               Terminated Pyramid, SunOS 4.1.x, and Ultrix support,
+               because test systems are no longer available.
+               Final Pyramid and Ultrix source code distributions
+               for lsof revision 4.51 may be found on lsof.itap.purdue.edu
+               in pub/tools/unix/lsof/OLD/src.  The no longer
+               supported SunOS 4.1.x source code is still distributed
+               with the Solaris source code.
+
+               Added code to set Solaris node address to real vnode
+               address, when applicable.
+
+               John Speno <speno@lopan.isc-net.upenn.edu> provided
+               information that enabled me to update the Tru64
+               AdvFS (MSFS) node definition for AdvFS version 5.
+
+               Added Tru64 5.x CFS support with help from Kris
+               Chandrasekhar <Kris.Chandrasekhar@compaq.com>,
+               Diane Lebel <lebel@zk3.dec.com>, and John Speno.
+               The support only provides information about cached
+               file attributes.
+
+               Installed a Configure patch for HP-UX 11 supplied by
+               Kenneth Stailey <kstailey@disclosure.com> that adds
+               another command to q4 input.
+
+               Tested on FreeBSD 4.2.
+
+               Will Day <willday@rom.oit.gatech.edu> and Frank
+               Winkler <frank.winkler@germany.sun.com> graciously
+               supplied Solaris 8 binaries.
+
+               Added Solaris 9 text file support, supplied by
+               Casper Dik <Casper.Dik@holland.sun.com>.
+
+4.53           December 6, 2000
+               Added the AIX 5L j2_lock.h to the distribution with
+               a Configure script step to use it when it's missing
+               from /usr/include/j2.
+
+               Removed SunOS 4.1.x support.
+
+               Removed Linux 2.0.x /dev/kmem support.
+
+               Fixed VBLK and VCHR special device file reporting
+               to handle /dev information more accurately.
+
+               Added a Apple Darwin / Mac OS X 1.2 port, provided
+               by Allan Nathanson <ajn@apple.com>.  Allan also
+               arranged for a test system so I can maintain this
+               port.  An additional test system was provided by
+               Dale Talcott.
+
+               Dropped claims of support for all UnixWare versions
+               except 7.1.0, since that is the only version on
+               which I can test lsof.  Even though lsof 4.53 is
+               deprecated for UnixWare 2.1.3, installed a patch
+               for it with testing done by A. Channing Clark
+               <clark.channing@heb.com>.
+
+               Dropped claims of support for all SCO OpenServer
+               versions except 5.0.5, since that is the only
+               version on which I can test lsof.
+
+4.54           January 19, 2001
+               Added compensation for a change that made the
+               FreeBSD mount structure invisible.  I can only test
+               back to 3.2 and the compensation works there, so
+               it's been #ifdef'd for 3.2 and above.  David O'Brien
+               <obrien@FreeBSD.org> provided the necessary clue.
+
+               Based on a report from Valdis Kletnieks
+               <Valdis.Kletnieks@vt.edu>, changed all IPv6 support
+               to report a TYPE of IPv6 for sockets with IPv4
+               addresses mapped in IPv6 addresses.  The previous
+               lsof behavior was to report their TYPE as IPv4.
+
+               Restored the Linux GlibC test to Configure, removed
+               at revision 4.53, based on a report from John Dzubera
+               <zube@cs.colostate.edu>, that RedHat Linux 6.0 still
+               needs the test.
+
+               Made setting of link count for Solaris more selective.
+
+               Limited Readlink() recursion to MAXSYMLINKS.  The bug
+               was reported by Jan Dvorak <johnydog@go.cz>.
+
+               Dropped the *claim* that lsof runs on Solaris 2.5.1.
+               It may well do so, but I no longer have access to a
+               test system.
+
+               Fixed an #endif comment typo, reported by Igor Schein.
+
+               Fixed a typo in a cast for a Tru64 UNIX 5.1 function
+               and updated Configure for Tru64 UNIX 5.0 and 5.1 with
+               information from Jesse Perry <jesse.perry@compaq.com>.
+
+               Corrected non-fatal typos in the AdvFS support in
+               dnode.c for Tru64 UNIX.
+
+               Added msdos file system support for NetBSD and OpenBSD.
+               Andrew Brown <atatat@atatdot.net> requested and helped
+               test it.
+
+4.55           February 15, 2001
+               Based on a report from Bernd Eckenfels <ecki@lina.inka.de>
+               added support in lsof for files in /proc/<PID>/maps
+               that have been deleted.
+
+               Changed PGRP output title to PGID, conforming to
+               the most common current abbreviation for Process
+               Group ID (PGID).  While some systems continue to
+               use *pgrp for internal kernel variable names, most
+               systems that support the display of PGID via ps(1)
+               now title it PGID.  The lsof -g and -Fg options
+               operations are unchanged in function; only titles
+               and descriptions have changed.  Also changed internal
+               variable names from *PGRP and *pgrp to *PGID and
+               *pgid where possible.
+
+               Dropped the *claim* that lsof runs on HP-UX 9.x.
+               It may well do so, but I no longer have access to
+               a test system.
+
+               In response to a suggestion from Jeff Howie
+               <jeff.howie@federated.ca> added support for command
+               name selection by regular expression.  A new form
+               of the -c option value is use to identify and
+               specify a regular expression.
+
+               Restore the *claim* that lsof works on UnixWare
+               7.0, since I re-acquired a test system.
+
+4.56           May 3, 2001
+               Corrected some problems Amir Katz <Amir_Katz@bmc.com>
+               found with Insure++, one in lib/dvch.c, the rest
+               in Solaris sources.  Amir's report also helped me
+               find an error in an snpf() call that caused (the
+               unsupported) Solaris 2.5.1 lsof to crash.  Wally
+               Winzer, Jr. <wally.winzer@ChampUSA.COM> helped test.
+
+               Added support for UnixWare 7.1.1 and above in-kernel
+               UNIX sockets.  John Hughes <john@Calva.COM> kindly
+               provided code and access to a test system.  John
+               also provided a test system and advice for adding
+               UnixWare 7.1.1 NonStop Cluster and CFS support.
+               More help with that effort came from Kurt Gollhardt
+               (SCO), Barbara Howe (SCO), Bela Lubkin (SCO), and
+               Dewan Rashid <Dewan.Rashid@ir.com>.
+
+               Archived a set of compilation hints (patches) from
+               Bill Melvin <Bill.Melvin@esc.edu> that make it
+               possible to compile the old, unsupported lsof 3.08
+               sources on UnixWare 1.x without NFS or CDFS support.
+
+               Installed support supplied by Allan Nathanson
+               <ajn@apple.com> for the Darwin "Gold Master" release,
+               Mac OS X 10.0 (aka Darwin 1.3 in its public source
+               version).  Added Allan's CVS repository suggestions
+               to the script that gets additional header files
+               from an open source repository.
+
+               Tested an HP-UX 11.11 kernel patch from Sailu
+               Yallapragada that enables reporting of TCP/IP
+               information for telnetd processes that use the
+               telnet multiplexor.  I don't yet know the kernel
+               patch ID.
+
+               Made the Solaris inclusion of <inet/mi.h> conditional
+               on the Solaris version.  (It's apparently not needed
+               at 2.6 and above.)  Bill Watson <bill.watson@uk.sun.com>
+               brought this to my attention.
+
+               Added alternate Linux 2.4.x lock extent test, supplied
+               by Jim Mintha <jim@ic.uva.nl>.
+
+               Rearranged the lines and pre-processor tests in
+               regex.h, lib/regex.c, and lib/snpf.c so that unifdef
+               can be used to eliminate copyright and GPL statements
+               when the files aren't being used for a particular
+               dialect.  (USE_LIB_* definitions in a dialect's
+               machine.h header file determine if one or more of
+               those three files are to be used.)
+
+               Added preliminary support for Solaris 8 with VxFS
+               3.4.  This support will be refined as I get
+               information from Veritas about how they will
+               distribute the kernel header files lsof needs.
+               Those header files were omitted from the standard
+               VxFS 3.4 distribution.  Technical assistance and
+               testing were provided by Calle Dybedahl <cdy@algonet.se>,
+               Gary Millen <gary.millen@veritas.com>, Rainer Orth
+               <ro@TechFak.Uni-Bielefeld.DE>, Peter C. Vernam
+               <pvernam@draper.com>, and Donna Yobs
+               <Donna.Yobs@veritas.com>
+
+               Tested on FreeBSD 4.3-STABLE.
+
+               Dropped the *claim* that lsof works on UNIX dialects
+               where I no longer have test systems: BSDI 2.1,
+               3.[01] and 4.0; DEC OSF/1, Digital UNIX and True
+               64 UNIX 2.0 and 3.2; FreeBSD 2.1.[67], 2.2[.x],
+               3.[012345] and 4.[01]; HP-UX 10.20; NetBSD 1.[234];
+               SCO OpenServer 5.0.5; and SCO UnixWare 7.0
+
+               Tested on Solaris 9 BETA, s81_36.
+
+4.57           July 19, 2001
+               Help (-h) and version (-v) output now have URLs
+               for the newly created and timeliest lsof FAQ
+               (00FAQ in the lsof distribution) at:
+
+                 ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/FAQ
+
+               and the man page for the current lsof distribution
+               at:
+
+                 ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/lsof_man
+
+               Based on a report from Steve Laubscher
+               <slaubs@woodward.com>, modified dlsof.h for PTX
+               4.6[.1] to avoid a temporary dnlc_t definition
+               needed at PTX 4.5.1.
+
+               Corrected test for old Linux kernels in Configure.
+               Henri Karrenbeld <ishtar@cal044202.student.utwente.nl>
+               brought the error to my attention.  Limited Linux
+               claims to 2.1.72 and above in the documentation.
+
+               Improved HP-UX 11 Configure stanza and stream socket
+               handling.
+
+               Constructed a work-around for the HP-UX 11 optional
+               OnlineJFS package.  The work-around sadly requires
+               lsof to have a private version of the vx_inode
+               structure, since the OnlineJFS package doesn't
+               update <sys/fs/vx_inode.h>.  Troyan Krastev
+               <Troyan.Krastev@ricoh-usa.com> brought the bug to
+               my attention and Michael Bracewell
+               <michael@ra.TSS.PeachNet.EDU> provided a test system
+               where I developed the work-around.
+
+               Added locale support to lsof's isprint() test,
+               based on a suggestion from Dan Mercer <damercer@mmm.com>.
+               Lsof will use setlocale(), when that function and
+               its supporting <locale.h> header file are available.
+
+               Added OpenBSD 2.9 support.
+
+               Based on a report from Aaron Rhodes <arhodes@psionic.com>
+               and with testing help from Aaron, made the lsof
+               4.56 revision compile and work on OpenBSD 2.6.
+               While that OpenBSD version is no longer supported,
+               Aaron's report exposed a Configure script bug
+               affecting OpenBSD versions lsof does support.
+
+               Updated for FreeBSD 5.0-CURRENT.  Szilveszter Adam
+               <sziszi@petra.hos.u-szeged.hu> help test.  The lsof
+               FreeBSD ports packager, David O'Brien <obrien@FreeBSD.org>,
+               assisted.
+
+               Tested on AIX 5.1.  Loc Le and Nasser Momtaheni of
+               IBM provided test systems.
+
+4.58           September 13, 2001
+               Added options to safestrprt() and safestrprtn() to
+               surround the string with '"' and to suppress the
+               printing of an ending '\n'.  Use of these functions
+               in device cache file error message reporting answers
+               a suggestion for better error reporting from John
+               Jackson <jrj@purdue.edu>.
+
+               Fixed a Solaris 2.6 and above problem related to
+               searching for "large" (O_LARGEFILE) files by name;
+               lsof was using the wrong version of [l]stat(2).
+               The bug was reported by Daniel Trinkle
+               <trinkle@cs.purdue.edu>.
+
+               Added AIX 4.1.4 and above XTI socket support.
+
+               Added OSR Xenix Shared Data and Semaphore file type
+               support with modifications supplied by Bela Lubkin.
+
+               Updated OPENSTEP support with modifications from Carl
+               E. Lindberg <lindberg@clindberg.org>.  The changes
+               enable the correct reporting of executable and
+               library open files ("txt" type).
+
+               Limited claims of OpenServer support to the versions
+               where I currently test, 5.0.4 and 5.0.6.  (Lsof
+               probably works on 5.0.5.)
+
+               Enabled processing of -C option for PSTAT-based HP-UX
+               lsof.
+
+               Enabled and tested on FreeBSD 4.4.
+
+               Corrected a file system test example in 00QUICKSTART,
+               based on a report from Jun Biao WANG <wangjunb@cn.ibm.com>.
+
+               Made available for re-distribution a user-contributed
+               port of lsof 4.51 to Reliant UNIX 5.45.  Thomas
+               Mauterer <Thomas.Mauterer@philosys.de> contributed
+               the port.
+
+4.59           October 20, 2001
+               With the closing of the Sequent Synergy Links Lab
+               by IBM, terminated lsof support for PTX.  The last
+               tested PTX lsof revision, 4.58, is available on
+               lsof.itap.purdue.edu in .../lsof/OLD/src.
+
+               Adjusted for FreeBSD 5.0-CURRENT NFS header file
+               changes, based on a report from Jos Backus
+               <josb@cncdsl.com>.
+
+               Corrected a bug in the way Linux lsof identifies
+               the owner of a process.  Lionel Cons <lionel.cons@cern.ch>
+               reported the problem and tested the fix.  Added
+               code to avoid stat(2) calls on regular Linux files
+               whenever possible.  Lionel reported the need to do
+               this (AFS files) and tested the new code.
+
+               Added new output field for raw device number in
+               hex.  The field is identified with 'r'.  This field
+               is NOT selected when -F or -F0 is specified so that
+               its appearance won't disturb existing scripts that
+               process field output.
+
+               Added support for OpenUNIX 8.  A test system was
+               provided by Larry Rosenman <ler@lerctr.org>.
+               Matthew Thurmaier <matt@compclass.com> and many
+               people from Caldera provided technical assistance.
+
+               Added an additional UVM test to the NetBSD Configure
+               stanza.  Andrew Brown <atatat@atatdot.net> supplied
+               the test; it recognizes NetBSD 1.5Y UVM changes to
+               the vnode structure recently committed by Chuck
+               Silvers.
+
+               Applied Configure and get-xnu-headers.sh script
+               changes suppled by Allan Nathanson <ajn@apple.com>
+               for Darwin 1.4.
+
+               Added for Bela Lubkin <belal@mammoth.ca.caldera.com>
+               OSR-specific environment variables to supply values
+               to the Configure script.  The variables are described
+               in 00XCONFIG.
+
+               Added an IP version selector to the -i option
+               parameters.
+
+4.60           November 9, 2001
+               Added special handling to and corrected bugs in
+               the matching of IPv4 in IPv6 addresses to -i6:<...>
+               selectors.
+
+               Made 00FAQ corrections and updates, based on
+               discussions with Igor Schein <igor@txc.com>.
+
+               Modified Configure script to detect a 64 bit capable
+               gcc compiler and permit it to be used to build 64
+               bit (PA-RISC 2) lsof for HP-UX 11.00.  Tested with
+               HP's gcc package, which Rich Rauenzahn of HP kindly
+               installed on a test system at HP.  Stefan Marquardt
+               <stefan.marquardt@hagebau.de> helped test.
+
+               Made lsof's method of killing its child process
+               more robust, based on a suggestion from Bela Lubkin
+               <belal@caldera.com>.
+
+               Modified all dialect Makefile segments to accept
+               select -v #define's from the environment -- a
+               builder's comment, host, logname, system information
+               and user name.  This was done for Bela Lubkin, so
+               he can "tune" the -v output when he packages lsof
+               in the upcoming Caldera OSR 5.0.7 release.
+
+               Changed Perl scripts in scripts/ to put the lsof
+               path consistently in $LSOF.  Also added a fix from
+               Bela Lubkin to scripts/big_brother.perl5 that allows
+               it to tolerate SCO OSR "ago" clauses in open UDP
+               file information.  Strengthened emphasis in
+               scripts/00README that the scripts are examples that
+               shouldn't be expected to run on all UNIX dialects
+               without modification.
+
+               At Bela Lubkin's suggestion changed the device
+               cache file format examples in 00DCACHE and 00FAQ
+               to avoid "%U%".  That's an SCCS escape sequence.
+
+               Added support for OpenBSD 3.0.
+
+               Added +DAportable to CFLAGS for 32 bit HP-UX 11.
+               Amir Katz <Amir_Katz@bmc.com> suggested the addition.
+
+4.61           January 22, 2002
+               Updated field output example Perl scripts in the
+               scripts/ subdirectory to discover the lsof path,
+               starting at .. and proceeding through the PATH
+               environment variable's directories.
+
+               Added minor OSR Configure script fixes, provided
+               by Bela Lubkin <belal@caldera.com>.
+
+               In response to a report from Joshua Wright
+               <Joshua.Wright@jwu.edu> modified NetBSD and OpenBSD
+               Configure stanzas and sources so that lsof can be
+               built when there is no system source tree (e.g.,
+               /usr/src/sys).
+
+               In response to a report from Peter Valchev
+               <pvalchev@openbsd.org> improved the UVM test in
+               the OpenBSD Configure stanza.
+
+               Updated Configure script to recognize FreeBSD 4.5.
+               Updated for FreeBSD 5.0 procfs and pseudofs changes.
+
+               Updated HP-UX stanza to see if the compiler named
+               in the LSOF_CC environment variable is the bundled
+               compiler.  If it is, "-O" is omitted from the
+               compiler flags.
+
+               Updated Digital UNIX 4.x and Tru64 UNIX error message
+               related to kernel name list failures.  Added an FAQ
+               section about how a kloadsrv daemon failure can cause
+               knlist(3) to fail.  The condition was reported by
+               Douglas B. Jones <douglas@gpc.peachnet.edu>
+
+               Based on a report from Mark W. Eichin <eichin@thok.org>
+               made Linux lsof capable of handling and reporting
+               file sizes greater than 32 bits.
+
+               Tested on Solaris 9 BETA-Refresh.
+
+               Corrected a bug in the matching of IPv4 addresses,
+               mapped in IPv6 addresses, to an IPv4 parameter to
+               an -i option.
+
+               Ported to 64 bit Power AIX 5.1 kernel with advice
+               from David Clissold <cliss@austin.ibm.com> and Marc
+               Stephenson <marc@austin.ibm.com>, and on a test
+               system provided by Loc Le <lple@us.ibm.com>.
+
+4.62           March 7, 2002
+               Updated 00README to reflect the usefulness of gcc
+               for building AIX lsof.  Documented a report from
+               Brian L. Gentry <BGentry@nationsrent.com> of success
+               on AIX 4.3.3.  I documented my success on 32 bit
+               Power AIX 5.1 and my lack of success on ia64 AIX
+               5.1 and 64 bit Power AIX 5.1.
+
+               Improved UnixWare >=7.1.1 reporting of UNIX socket
+               NAME field information for NonStop Cluster systems
+               with a patch provided by John Hughes <john@Calva.COM>.
+               Offered John's improvement as a patch to lsof 4.61.
+
+               Corrected bugs in handling of open files on block
+               devices by OSR lsof.  The bugs were reported by
+               Bela Lubkin <filbo@deepthought.armory.com>.
+
+               Fixed bug in writing >32 bit device numbers for
+               block devices to the device cache file.
+
+               Added support for reporting block special nodes
+               not in /dev (or /devices).  That required "like
+               device special" be changed to "like block special"
+               and "like character special".  (00FAQ was updated.)
+
+               Based on a report from Peter Valchev <pvalchev@openbsd.org>
+               improved the definition of the source for NetBSD
+               and OpenBSD kernel symbols (the nlist() source
+               file).  NetBSD now defaults to getbootfile(3) if
+               it is available, /netbsd otherwise.  OpenBSD now
+               defaults to /dev/ksyms if it is available, /bsd
+               otherwise.
+
+               Made possible compilation under BSD/OS (BSDI) 5.0
+               with changes to Configure, dialects/bsdi/dlsof,
+               dialects/bsdi/dproc.c and lib/rnmh.c.  The changes
+               were suggested by Steven Hinkle <hinkle@bsdi.com>.
+               Note that these changes do not substantiate a claim
+               that lsof works on BSDI 5.0, because I haven't
+               tested it there.
+
+               Updated OpenUNIX private <sys/fs/memfs_mnode.h>,
+               based on a report from Larry Rosenman <ler@lerctr.org>
+               that it had been updated by Caldera patch OU800PK3.
+               Unfortunately the patch only corrects some of the
+               problems with the header file, so it is still
+               necessary to distribute a private patched version
+               of it with the lsof sources.
+
+               Applied a man page correction reported by Frederic
+               Delanoy <max_ok@yahoo.com>.
+
+               Corrected cast bugs related to using the HP-UX
+               bundled C compiler on HP-UX 11.11.
+
+4.63           April 23, 2002
+               Added HPUX_BOOTFILE environment variable for use
+               by the Configure script in determining HP-UX kernel
+               configuration information -- e.g., the state of
+               the ipis_s structure in the HP-UX 11 kernel.  The
+               change was suggested by Marc Bejarano <beej@alum.mit.edu>.
+               Marc also suggested some changes to the HP-UX
+               section in 00FAQ that discusses Configure's use of
+               q4 for HP-UX 11.
+
+               Fixed a bug in the Solaris lsof file system matching
+               code.  It was not reporting that VCHR files in
+               /devices were in / when /devices was in /, too.
+
+               Corrected bugs in device number, file size, file
+               offset, and raw device number field output generation.
+
+               Added recognition of OpenBSD 3.1 to the Configure
+               script with a suggestion from Peter Valchev
+               <pvalchev@sightly.net>.  Note that this change does
+               not constitute a claim that lsof works on OpenBSD
+               3.1, because I haven't tested it there.
+
+               Built an automated test suite.  (See 00TEST and
+               the tests/ sub-directory of the lsof main directory).
+               Bela Lubkin requested it.  Dale Talcott, John
+               Hughes, and Larry Rosenman helped me validate it
+               on their systems.
+
+               During the development of the test suite I discovered
+               the following lsof bugs or missing features, and
+               corrected or supplied them.
+
+               * Corrected the reporting of locks for:
+                 o Digital UNIX 4.0d and Tru64 Unix 5.[01];
+                 o HP-UX 10.30 and 11.00;
+                 o OpenUNIX 8;
+                 o UnixWare 7.1.1.
+
+               * Enabled HP-UX 10.30 and 11.00 to report open NFS
+                 file link counts.
+
+               * Corrected the reporting of UNIX domain socket
+                 names for Apple Darwin, FreeBSD 4.5 and above,
+                 NetBSD 1.4.1 and above, and for OpenBSD 3.0 and
+                 above.
+
+               * Enabled HP-UX 11.11 to stat(2) large files.
+
+               * Fixed handling of combination 32 and 64 bit
+                 device numbers in AIX 64 bit architectures.
+
+               Updated the AIX 4.3.3 NFS rnode recognition code,
+               first installed at revision 4.51.  It looks like
+               some IBM update has restored a single rnode structure
+               independent of the machine bit width.
+
+               Updated the NetBSD and OpenBSD sources so NetBSD
+               can process DTYPE_PIPE files, as OpenBSD was already
+               able to do.
+
+               Updated Darwin get-xnu-headers.sh script to reflect
+               information about a recent reorganization of the
+               Darwin CVS hierarchy, supplied by Allan Nathanson
+               <ajn@apple.com>.
+
+               Added defense against the standard I/O descriptor
+               attack.
+
+4.64           June 26, 2002
+               Corrected some FreeBSD pre-processor directives.
+               David O'Brien <obrien@NUXI.com> pointed them out.
+
+               Updated lsof's main() function to: 1) close all
+               open file descriptors above 2 before starting; and
+               2) to set a non-interfering umask.  Moved GET_MAX_FD
+               test from misc.c to proto.h, so that main() could
+               use it.  Added multiple-include protection to
+               proto.h.
+
+               Moved FAQ's test suite Q's & A's to a more appropriate
+               section.  Added a Q&A on HASSECURITY option and
+               its affect on searching for open files.  (That was
+               already in the man page.)
+
+               Updated hpux/kmem/dnode.c for HP-UX < 11 compilation
+               with information from John Dzubera <Zube@CS.ColoState.EDU>.
+               While lsof doesn't support HP-UX < 11 any more, I
+               try to avoid disabling it there when possible, and
+               a locking fix for HP-UX >= 11 in lsof 4.63
+               inadvertently disabled compilation of lsof for
+               HP-UX < 11.  Fixed long-standing bug in HP-UX 10.20
+               lock reporting.
+
+               Removed language from the test suite programs that
+               requires an ANSI-C compiler.  This allowed the test
+               suite to be validated with cc and gcc on the un-
+               supported HP-UX 10.20.
+
+               At the suggestion of Manuel Bouyer <bouyer@antioche.eu.org>
+               switched NetBSD and OpenBSD lsof from using nlist()
+               to using kvm_nlist().  Made the same change for
+               BSDI, Darwin, and FreeBSD.
+
+               Validated test suite on OPENSTEP 4.2.
+
+               In response to a suggestion from Jeff Stoner
+               <jstoner@blackboard.com> enhanced support for the
+               FD list of the -d option to allow it to be either
+               an exclusion or inclusion list, using the '^' prefix
+               to denote exclusions.
+
+               Made adjustments for FreeBSD 4.6 and 5.0-CURRENT.
+               Fixed a FreeBSD /etc/make.conf CFLAGS extraction
+               bug, reported by Kris Kennaway <kris@obsecurity.org>,
+               and new a bug in the fix, reported by Eric Cronin
+               <ecronin@eecs.umich.edu>
+
+               Added nullfs support for FreeBSD, NetBSD, and OpenBSD
+               at the request of Andrew Brown <atatat@atatdot.net>.
+
+               Modified all readmnt() functions to ignore mounted-on
+               directory names that don't begin with '/'.
+
+               Tested on NetBSD 1.6A and OpenBSD 3.1.
+
+               Upgraded to Solaris 9 FCS with two changes to the
+               BETA-Refresh support: 1) an adjustment to dnode.c
+               for a change in the so_so (sonode) structure; and
+               2) addition of Solaris 9 FCS specific DNLC code.
+               David Comay <David.Comay@Eng.Sun.COM> sent me the
+               dnode.c change and Casper Dik <Casper.Dik@sun.com>
+               helped with the new DNLC support code.
+
+               Applied OpenUNIX changes that permit lsof to compile
+               and run on the upcoming 8.0.1 release.  The changes
+               were supplied by Robert Lipe <robertl@caldera.com>.
+               Larry Rosenman <ler@lerctr.org> provided a test
+               system.
+
+               Added Solaris fd file system support.
+
+4.65           October 10, 2002
+               Adjusted for change in FreeBSD 5.0-CURRENT inode
+               structure, reported by David O'Brien <obrien@NUXI.com>.
+               Adjusted for changes in FreeBSD 5.0-CURRENT <sys/vnode.h>.
+               One change was reported by Anders Nordby
+               <anders@FreeBSD.org>.  Adjusted for FreeBSD 5.0-CURRENT
+               on sparc64 architecture.
+
+               Enhanced the error reporting of Solaris lsof when
+               it detects a kvm_open() failure, and added a 00FAQ
+               entry on the cause, based on a report from Peter
+               J. Bertoncini <pjb@anl.gov>.
+
+               Enabled compiling of lsof for NetBSD 1.5 with the
+               NULL file system, using a patch from Andrew Brown
+               <atatat@atatdot.net>.
+
+               Removed a hack in the LTbigf test program that was
+               once needed when it was compiled on Solaris 9 BETA-
+               Refresh with gcc.  The hack isn't needed on Solaris
+               9 FCS.  Janet Hempstead <jan@library.carleton.ca>
+               brought the need for this change to my attention.
+
+               Applied a patch, supplied by Andrew Brown
+               <atatat@atatdot.net>, that updates lsof for NetBSD
+               version 1.6F.  Corrected handling of the NetBSD
+               nullfs.
+
+               Updated to BSDI BSD/OS 4.3 on a test system kindly
+               provided by Terry Kennedy <terry@tmk.com>.
+
+               Updated to FreeBSD 4.7.
+
+               Updated to Apple Darwin 1.5, 5.x and 6.x with
+               patches supplied by Allan Nathanson <ajn@apple.com>.
+               The patches include IPv6 support.
+
+               Updated Configure to use the -bnolibpath loader
+               option when building lsof on a PowerPC, running
+               AIX 5 or greater.  Valdis Kletnieks
+               <Valdis.Kletnieks@vt.edu> informed me this was
+               needed.  Lsof for AIX 5.x was initially developed
+               on the IA64, where -bnolibpath can't be used and
+               I didn't think to restore it to PowerPC loads when
+               AIX 5.x became available for that architecture.
+
+               Updated to UnixWare 7.1.3 on a test system provided
+               by Larry Rosenman <ler@lerctr.org>.  Removed claims
+               that lsof works on OpenUNIX 8.0.1, because UnixWare
+               7.1.3 is the release name of OpenUNIX 8.0.1.
+
+               Based on a comment that his e-mail address was
+               wrong in the lsof distribution from Kenneth Stailey
+               <kstailey@disclosure.com>, removed all e-mail
+               addresses from lsof documentation files except this
+               one, 00DIST.  The addresses in 00DIST are used to
+               send revision release notices to those who contributed
+               to a revision, but the addresses in this file for
+               previous revisions and in other documentation files
+               sometimes grow stale and are never validated.
+
+4.66           December 22, 2002
+               Acquired Solaris 7 and 8 test systems, courtesy of
+               John Dzubera <Zube@CS.ColoState.EDU>.  Updated
+               00TEST and tests/TestDB accordingly.
+
+               Clarified FreeBSD 5.0 architecture claims at the
+               suggestion of David O'Brien <obrien@NUXI.com>.
+               Also implemented David's suggestion to change
+               Intel to x86.
+
+               Installed changes to DNLC handling in OSR lsof in
+               preparation for handling changes in the OSR 5.0.7
+               DNLC cache.  Information about the changes and
+               patches to handle them were supplied by Bela Lubkin
+               <filbo@deepthought.armory.com>.
+
+               Upgraded True 64 UNIX support to the 5.1B release
+               on a test system provided by Berkley Shands
+               <berkley@cse.wustl.edu>  Had to used relaxed ANSI
+               compilation because of an error in a system header
+               file and other lsof source usages.
+
+               Implemented the HASNOSOCKSECURITY compile-time
+               option.  When it and HASSECURITY are defined, lsof
+               will be built to list only the user's open files,
+               but will also list anyone else's open socket files,
+               provided the "-i" option selects their listing.
+               Updated the Customize script to ask about setting
+               HASNOSOCKSECURITY.  Left it undefined in all dialect
+               machine.h header files.  This change was requested
+               by Kenneth Stailey <kstailey@speakeasy.net> for
+               use with ntop.
+
+               Added support for OpenBSD 3.2 and its kernel trace
+               file.
+
+               Improved lsof help (-h) and version (-v) information
+               reporting.
+
+               Fixed a FreeBSD 4.7 and above off-by-two UNIX domain
+               socket path termination bug, reported by Ken Stailey
+               <kstailey@speakeasy.net>
+
+4.67           March 27, 2003
+               Began the transition of the lsof ftp server host
+               name from vic.cc.purdue.edu to lsof.itap.purdue.edu.
+               That reflects Purdue organizational changes.  This
+               first step makes the new name an alias to the old
+               one.   The old name, vic.cc.purdue.edu, will remain
+               usable for an extended period.
+
+               Corrected a revision number reference in section
+               17.17 of 00FAQ on the appearance of Solaris negative
+               DNLC caching handing.
+
+               Updated 00FAQ discussion of compilers for 64 bit
+               Solaris.
+
+               Validated test suite for 64 bit Solaris 8 and gcc.
+
+               At the request of Alek O. Komarnitsky <alek@komar.org>
+               added the "+c <width>" option to enable optional
+               changing of the COMMAND column output maximum width
+               from the default to <width>.  The default maximum
+               width remains CMDL, as defined in lsof.h.
+
+               Fixed three AIX kernel bit size detection bugs,
+               one in the AIX Configure script stanza, the second
+               and third in the AIX dproc.c get_kernel_access()
+               function.  The bugs were reported by Pierre-Yves
+               Fontaniere <pyf@cc.in2p3.fr>, who tested the fixes.
+
+               Added kernel event queue file support for FreeBSD,
+               NetBSD and OpenBSD.  Andrew Brown <atatat@atatdot.net>
+               supplied the code.
+
+               Updated to AIX 5.2 on a test system provided by
+               Dale Talcott <dtalcott@purdue.edu>.  Had to build
+               work-arounds for two missing AIX 5.2 header files,
+               <j2/j2_snapshot> and <proc/proc_public.h>.  Corrected
+               an off-by-one UNIX socket addressing bug.  Taught
+               AIX lsof to handle both jfs and jfs2 files at the
+               same time.  Adjusted for an IBM mistake in the
+               sizing of the fdsinfo structure in <procinfo.h>
+               Toshiya Nakamura <TOSHIYAN@jp.ibm.com> helped test,
+
+               Updated to FreeBSD 4.8.  Corrected another bug in
+               FreeBSD UNIX domain socket name handling.
+
+               Corrected gcc build problems on HP-UX 11i, reported
+               by Yuliy Minchev <yuliy@mobiltel.bg>.
+
+               Updated BSDI BSD/OS support to 4.3.1.
+
+               Augmented a lock ID test on NetBSD to check if the
+               ID is an LWP pointer.
+
+4.68           June 18, 2003
+               Enhanced Configure script's cleanup operations.
+
+               Added support for OpenBSD 3.3, based on a report
+               from Peter Valchev <pvalchev@sightly.net>.
+
+               Improved the description of the detached PGP
+               signature certificate file in the main lsof README
+               file, based on a suggestion from Diana Stockdale
+               <diana@mpl.ucsd.edu>.
+
+               Installed a work-around for FreeBSD 5.0-CURRENT on
+               Alpha to avoid a compiler register use complaint.
+
+               Corrected a 'c' option error message.  Gnele
+               <blaadeleng@yahoo.com> reported the problem.
+
+               Upgraded EXT2FS and UFS support for NetBSD and
+               OpenBSD to handle new inode information, and the
+               fast UFS1 and UFS2 file systems.
+
+               With the help of Andrew Brown <atatat@atatdot.net>
+               determined the NetBSD snapshot (1.6F) at which
+               <sys/mount.h> could be included under _KERNEL, thus
+               eliminating the lsof netexport.h hack.  The same
+               change applies to OpenBSD versions 3.3 and above.
+
+               Applied a patch from Armin Gruner <ag@muc.de> that
+               corrects the use of the HASPROCFS definition in the
+               FreeBSD dialect sources.
+
+               Corrected spelling errors in 00FAQ and in the
+               generated 00.README.FIRST_<version> file of the
+               distribution archive.  John Jackson <jrj@purdue.edu>
+               and Ray Phillips <r.phillips@jkmrc.uq.edu.au>
+               spotted and reported the errors.
+
+               Corrected a spelling error in a comment and incorrect
+               use of an alarm function in the LTsock test program.
+
+               At the suggestion of Stuart Anderson <sba@srl.caltech.edu>
+               added preliminary (and incomplete) SAM-FS file system
+               support to Solaris lsof.  Completion awaits availability
+               of SAM-FS internals.
+
+               Fixed a Solaris device name printing bug, reported by
+               Ric Anderson <ric@tick.Telcom.Arizona.EDU>, only
+               visible when HASDCACHE is not defined.  Ric helped
+               test the fix.
+
+               Fixed an AIX kernel bit size handling bug related
+               to the NFS node (rnode) structure.
+
+               Corrected a print_kptr() function call error in the AIX
+               AFS code, reported by David Steiner
+               <david.r.steiner@Dartmouth.EDU>.  Upon further reflection
+               and because I no longer have appropriate AIX AFS test
+               systems, disabled AIX AFS support in the Configure script
+               for AIX versions above 4.3.3.0 or AIX AFS versions above 3.5.
+
+               Added support for FreeBSD 5.1.
+
+               With advice from Allan Nathanson <ajn@apple.com> adjusted
+               the Darwin get-xnu-headers.sh script to access the kernel
+               header files needed by lsof from a new form of the Apple
+               open source repository.
+
+               Installed Linux and lsof library bug fixes and
+               improvements, supplied by Marian Jancar <mjancar@suse.cz>.
+               One Linux improvement handles mount strings that
+               have octal escapes in them, eg., \040 for embedded
+               blanks.  Marian tested the changes.
+
+4.69           October 16, 2003
+               Received and applied an OpenBSD patch from Peter Valchev
+               <pvalchev@sightly.net> that replaces a ctob() call with
+               a sysconf() call.  Peter claims sysconf() is needed for
+               OpenBSD on SPARC.  (It is not needed for NetBSD on SPARC.)
+
+               With the upgrade of my only Solaris 7 test system
+               to, Solaris 8, dropped the *claim* that lsof works
+               on Solaris 7.  That doesn't mean it won't work
+               there, so those who want lsof for Solaris 7 probably
+               should be able to build it there and it probably
+               will work there.
+
+               Revised lsof's DNLC handling for BSD derivatives,
+               including: BSDI; Darwin, DEC OSF/1, Digital UNIX
+               and Tru64 UNIX; FreeBSD; NetBSD; and OpenBSD.  The
+               latest NetBSD distribution's dropping of the vnode
+               capability ID (v_id) required the revision.
+
+               Adjusted to the latest FreeBSD 5.1-CURRENT.
+
+               Added NetBSD support for using kvm_getproc2().
+
+               Added a patch from Andrew Brown <atatat@atatdot.net>
+               to handle NetBSD enum conflicts and changes in the
+               <miscfs/kernfs/kernfs.h> and <miscfs/procfs/procfs.h>
+               header files.
+
+               Added a "#define _KERNEL" to the AIX dnode2.c source
+               file for compatibility with a new <j2/j2_inode.h>
+               AIX 5.2 header file version.  The addition was
+               supplied by Dick Dunbar <Dick.Dunbar@Siebel.com>
+               and was offered as a patch to lsof 4.68/
+
+               Added support for a second type of Solaris SAMFS.
+               Stuart Anderson <sba@srl.caltech.edu> provided the
+               support.  SAMFS support in lsof SOLARIS remains
+               scanty, because Sun won't release any details on
+               its kernel structures.
+
+               Dropped the *claim* that lsof works on AIX 4.3.3,
+               because I was unable to test it there.  That doesn't
+               mean it won't work there, so those who want lsof
+               for AIX 4.3.3 probably should be able to build it
+               there and it probably will work there.
+
+               Updated for Solaris 10 on test systems provided by
+               Mike Miscevic <miscevic@hotpop.com>.  Casper Dik
+               <casper@holland.sun.com> provided significant help.
+               During the Solaris 10 port found and fixed an lofs
+               handling bug that prevented reporting of open lofs
+               file lock status.
+
+               Updated the DNLC test, LTdnlc, to provide a possible
+               explanation about file systems on which the test
+               might fail.
+
+               Modified the procedure for obtaining missing Darwin
+               XNU kernel header files.  The new one requires more
+               manual intervention, but is the best that can be
+               done with the way Apple open sources are now
+               organized.  00FAQ explains the new procedures for
+               those not used to downloading Apple open source
+               files.
+
+               Added support for Apple Darwin 7.0 (Mac OS X 10.3)
+               with patches supplied by Allan Nathanson <ajn@apple.com>.
+               Dropped the *claim* that lsof builds and works on
+               Apple Darwin below 6.0.
+
+               Validated lsof on FreeBSD 4.9, using a test system
+               provided by Ben Lewis <bl@purdue.edu>.
+
+               Validated lsof on FreeBSD 5.1-CURRENT for Amd64.
+               David O'Brien <obrien@FreeBSD.org> provided a test
+               system.
+
+               Changed the NetBSD Configure stanza to do header
+               file searches in /usr/include by default.  The
+               LSOF_INCLUDE and NETBSD_SYS environment variables
+               may still be used to specify other search paths.
+               Discussions with Andrew Brown and Wolfgang S.
+               Rupprecht <wolfgang@wsrcc.com> led to the change.
+
+4.70           January 16, 2004
+               Improved shell-portability of the linux stanza of
+               the Configure script with a patch from Paul Jarc
+               <prj@po.cwru.edu>.
+
+               Added a "silent" rule to tests/Makefile for Paul.
+               Updated, extended and clarified the test suite
+               documentation in 00FAQ and 00TEST.
+
+               Fixed Solaris 10 dlsof.h typo, reported by Mike
+               Miscevic <miscevic@hotpop.com>.  The typo prevents lsof
+               from loading cleanly in Solaris 10 builds past 40.
+
+               Fixed a Solaris HSFS node number reporting bug and
+               added a structure definition work-around for Solaris
+               10.
+
+               Converted PGP signing to GPG.  My previous PGP key can
+               be used, but the gpg "--allow-non-selfsigned-uid"
+               option may have to be used when it is imported into a
+               GPG key ring.
+
+               Added bz2 compression.
+
+               Updated for OpenBSD 3.4.
+
+               Added a work-around for a missing header file in the
+               s10_44 Solaris 10 build.
+
+               Added support for FreeBSD 5.2-BETA and 5.2-CURRENT.
+
+               Updated Linux AX25 support with modifications supplied
+               by Lutz Poetschulat <dl9cu@db0zwi.de>.
+
+               Added raw IPv6 support to Linux lsof.
+
+               Improved handling of parameters after "-i@".
+
+               Improved file name test in LTdnlc.c.
+
+               Added loop count controls to the reading of Solaris
+               lock chains.  The change was implemented as a result of
+               a report from Steve Gonczi <steve@relicore.com>.
+
+               Based on a report from John Jackson <jrj@purdue.edu>,
+               enabled a Solaris 10 <sys/lgrp.h> work-around for
+               Solaris 9, too.  (Patch 112233 installs an lgrp.h on
+               Solaris 9 that needs the work-around.)
+
+               With help from Andrew Brown <atatat@atatdot.net> and
+               John Heasley <heas@netbsd.org> added log-structured
+               file system (LFS) support for NetBSD and OpenBSD.
+
+               Added AMD64 to the list of FreeBSD 5.x-CURRENT
+               supported architectures.  FreeBSD.org provides a test
+               system, courtesy of (I believe) David O'Brien
+               <obrien@FreeBSD.org>.
+
+               Added a cast to lseek() in the HP-UX /dev/kmem-based
+               kread() function to make it work properly with the
+               bundled HP C compiler.
+
+4.71           March 11, 2004
+               Added text file support to Apple Darwin lsof and
+               enabled the lsof executable portion of the LTbasic
+               test.  Added support for Darwin kernel queue, POSIX
+               semaphore and POSIX shared memory files.  Tested on
+               Darwin 7.2 (aka Mac OS 10.3.2).
+
+               Added process_kqueue() function prototypes for FreeBSD,
+               NetBSD and OpenBSD.
+
+               Picked some lint in AIX sources, lib/rnmh.c and
+               tests/LTsock.c.
+
+               Added "-x [fl]" cross-over option, which enables +d and
+               +D processing to cross over symbolic links and|or file
+               system mount points.  Discussion with Johan Lindquist
+               <johan@smilfinken.net> and Eric Williams (aka The Ghost
+               In The Machine) <ewill3@earthlink.net> on Linux news
+               groups revealed the need for the option.
+
+               Updated support for UnixWare 7.1.4.
+
+               Added support for the optional reporting of socket
+               options, socket states and TCP flags for most currently
+               supported dialects. John Smith <lbalbalba@hotmail.com>
+               and Tristan Nefzger <tn@bhtrader.com> requested the
+               information.  The dialects and their versions for which
+               this feature has become available include:
+
+                   AIX 4.3.2 and 5.[12]
+                   Apple Darwin 7.2
+                   BSDI BSD/OS 4.3.1
+                   Digital UNIX and Tru64 UNIX 4.0
+                   FreeBSD 4.9 and 5.2
+                   HP-UX 11 and 11.11 (aka 11i)
+                   NetBSD 1.6ZH
+                   OpenBSD 3.4
+                   OPENSTEP 4.2
+                   OpenUNIX 8
+                   SCO OpenServer Release 5.0.6
+                   Solaris 2.6, 8, 9 and 10
+                   UnixWare 7.1.[134]
+
+               Modified the Configure stanza for HP-UX 11 with better
+               q4 detection.  Steve Bonds <3vhmxxm02@sneakemail.com>
+               supplied the modification.
+
+               Applied a patch from Mike Miscevic <miscevic@hotpop.com>
+               to enable lsof to compile with the zone support in the
+               Solaris 10 s10_b51 release.  Added information on lsof
+               zone behavior to 00FAQ.
+
+               Added a "-z [z]" option to Solaris 10 lsof.  It enables
+               the listing of zone name and can also be used to select
+               the listing of processes and their files from specified
+               zones.
+
+4.72           July 13, 2004
+               Corrected Solaris 10 ZONE column title display bug with
+               a patch from Joep Vesseur <Joep.Vesseur@Sun.COM>.  Joep's
+               fix was offered as a patch to 4.71.
+
+               Based on a report from Jean-Pierre Radley <jpr@jpr.com>
+               about an unexpected GNU uname Configure interaction on
+               OSR, and working from information received from Bela
+               Lubkin, changed the OSR Configure stanza to use
+               /bin/uname instead of uname.  Added an FAQ entry about
+               Configure version detection problems.
+
+               Added the +m and "+m m" options in response to a dialog
+               with Robert T. Brown <rbrown@netmentor.com>.  The
+               options allow the creation of a mount table supplement
+               file which can be used on selected dialects to get
+               device numbers when stat(2) and lstat(2) can't deliver
+               them.  (That's generally the result of an inaccessible
+               NFS server.)  Currently the new options are supported
+               only on Linux.
+
+               Made cpumask_t typedef _KERNEL compensation for FreeBSD
+               5.2-CURRENT.  Refined it for 5.2.1-RELEASE with testing
+               help from Scott Ellentuch <tuc@ttsg.com>.
+
+               Added support for FreeBSD 4.10.  Larry Rosenman
+               <ler@lerctr.org> kindly provided a test system.
+
+               Added support for NetBSD 2.0 with patches supplied by
+               Andrew Brown <atatat@atatdot.net>.  Andrew also
+               provided two test systems.
+
+               Made handling of Linux maps file more robust, based on
+               a report from Jan Blunck <J.Blunck@tu-harburg.de>.  As
+               a side benefit, made handling of generated stat(2)
+               information more flexible.
+
+               As a result of a discussion with Jason Fortezzo
+               <fortezza@mechanicalism.net>, adjusted lsof for Solaris
+               to obtain the maximum user name length from ut_name of
+               the utmpx structure, if <utmpx.h> exists.
+
+               Tested under OpenBSD 3.5.
+
+               Updated 00README information about using gcc (via the
+               Configure aixgcc abbrevisiation) to compile lsof on
+               AIX.  Ann Janssen <ajanssen@nebook.com> made me aware
+               the information was out of date.
+
+               Added an AIX SIGDANGER handler and some 00FAQ sections
+               on lsof memory usage after a discussion with Tom Qin
+               <tom.qin@citigroup.com> about lsof memory usage.
+
+               Added scripts/sort_res.perl5, contributed by Fabian
+               Frederick <fabian.frederick@gmx.fr>.  The script
+               displays lsof output sorted by size and path name.
+
+               Improved handling of files on Linux NFS mount points
+               that use the root_squash option, based on discussions
+               with Paul Szabo <psz@maths.usyd.edu.au>.
+
+               Updated FreeBSD 5.2-CURRENT support, based on a problem
+               report from Filippo Natali <filippo@widestore.net>.
+
+               Corrected improper FreeeBSD 5.x-CURRENT #if condition,
+               reported by Kim Culhan <kimc@kim.net>.
+
+               Added a Configure script work-around for AIX 5.2 lsof
+               with JFS2, compiled by gcc >= 3.3.  The work-around
+               was supplied by Florian M. Weps <fmw@hactrn.ch>.
+
+4.73           October 21, 2004
+               Added an __XPG4_CHAR_CLASS__ #define before
+               #include'ing <ctype.h> on Solaris to restore lsof's
+               ability to display special characters such as acute-e.
+
+               Added wide-character (e.g., UTF-8) support where
+               possible, prompted by a request from Kyungjoon Lee
+               <kjoonlee@gmail.com>.  Some older dialects -- e.g.,
+               NetBSD 1.4.1 -- don't support wide characters, so the
+               wide character support is enabled by definitions in
+               each dialect's machine.h.  Dialects with wide-
+               character support are listed in 00FAQ.
+
+               Make a FreeBSD 5.2-CURRENT adjustment for <sys/pipe.h>,
+               supplied by Sergey A. Osokin <osa@FreeBSD.ORG>.
+
+               Implemented a Linux feature request made by Jakub
+               Jelinek <jakub@redhat.com> that enhances lsof's ability
+               to locate UNIX domain sockets whose paths are named as
+               arguments.  Jakub supplied suggested code.
+
+               Dropped *claims* that lsof works on AIX below 5.1, SCO
+               Dropped *claims* that lsof works on AIX below 5.1, SCO
+               Openserver 5.0.4, Tru64 UNIX 5.0, and UnixWare below
+               7.1.4.  Lsof will probably build and work on those UNIX
+               dialect versions, but I no longer have any way to test
+               lsof on them.
+
+               Added support for FreeBSD 5.3 and 6.0.  The FreeBSD
+               5.3 support hasn't been tested.
+
+               Added FD test code that will allow dialect versions to
+               test FD option selections.  Used the new code in the
+               PSTAT-based HP-UX lsof to enable it to avoid scanning
+               the mount table when its information is not needed.
+               The addition was made in response to a query from
+               Harvey Garner <Harvey.Garner@championusa.com> about
+               lsof performance in a busy NFS environment.
+
+               Upgraded lsof's AIX support level to AIX 5.3, based on
+               a report from Dick Dunbar <Dick.Dunbar@Siebel.com>.  (I
+               have not tested lsof under AIX 5.3.)  Based on Dick's
+               recommendation and local testing changed the C for AIX
+               version 6 and higher -qmaxmem option value to -1.
+
+               Made LSOF_AR environment variable more useful and
+               documented it in 00XCONFIG.
+
+               Corrected the use of sum(1) to generate signatures for
+               the lsof distribution and binaries to match the
+               documentation that claims it is sum -r output.  Jin
+               Guojun <jin@george.lbl.gov> noticed and reported the
+               problem.
+
+               Tested under OpenBSD 3.6.
+
+               Added checksum and GPG certificate files for the bz2,
+               gz and Z lsof distribution archives.  The new files
+               reside with the distribution archives and supplement
+               the signature information already inside the archives.
+
+               Validated on Solaris 10, i8xpc, build s10_63.
+
+4.74           January 17, 2005
+               Fixed a Solaris segment fault bug on systems that lack
+               a /dev/allkmem device.  Offered the fix as a patch to
+               lsof 4.73.  The bug was reported by Donald Zoch
+               <donald.zoch@amd.com>.
+
+               Updated lsof for FreeBSD 6.0 and higher for a change in
+               <sys/vnode.h>, based on a report from Sergey A. Osokin
+               <osa@FreeBSD.ORG>.  Made the update available in a 4.74
+               'A' edition pre-release.
+
+               Filed an HP bug report about missing pstat(2) CWD info
+               for LOFS on HP-UX 11.11 and higher.  The missing CWD
+               info was noticed by Ermin Borovac <e.borovac@bom.gov.au>.
+               Added info to 00FAQ about the problem, which can cause
+               the lsof test suite's LTbasic test to fail.
+
+               Updated the q4-generated tcp_s.h in the lsof
+               distribution and added socket option support for HP-UX
+               11.00.  Erwin Reyns <ereyns@europarl.eu.int> helped
+               test.
+
+               Updated for Solaris 10, build s10_69, with a patch
+               supplied by Mike Miscevic <miscevic@hotpop.com>.
+
+               Added v_path support to Solaris 10 lsof.  That relieves
+               it of having to read and decode the kernel DNLC, and
+               delivers full paths more reliably.
+
+               Added specialized NFS4 support to Solaris 10 lsof.
+
+               Applied Solaris 10 patches to lsof supplied by Casper
+               Dik <casper@holland.sun.com>.
+
+               Updated lsof for NetBSD 2.99.10 and tested it on a
+               system provided by Andrew Brown <atatat@atatdot.net>.
+
+               Added support for the FreeBSD 6.0-CURRENT f_vnode
+               pointer in the file structure.
+
+               Added BSDI, FreeBSD, NetBSD and OpenBSD support for the
+               *effnlink member of the inode structure.  This makes
+               the lsof LTnlink test run faster on all modified
+               dialects and correctly on OpenBSD.
+
+               Added ptyfs support for NetBSD, using modifications
+               provided by Andrew Brown.
+
+               Changed the netbsd Configure stanza to look by default
+               for system header files in both /usr/include and
+               /usr/src.  (The NETBSD_SYS environment variable can
+               still be used to select an alternate for /usr/src.)
+
+               Corrects two FreeBSD 4.10 RPC/XDR type definitions.
+
+               Added an FAQ Q&A about setuid and setgid restrictions
+               in HP-UX 11.11.  The information in the answer was
+               supplied by Frank Sanders <frank.sanders@siemens.com>.
+
+               Added abbreviations for AXI FCIO and FSNAPSHOT file
+               flags.  Holger VanKoll <Holger.VanKoll@swisscom.com>
+               reported the missing FCIO.
+
+               Adjusted lsof's private AIX 64 bit rnode structure for
+               64 bit AIX 5.2 systems.  (IBM doesn't distribute a
+               correct <nfs/rnode.h> for it.)
+
+               Corrected a Linux socket inode printing bug reported by
+               Igor Schein <igor@txc.com>.
+
+               Updated for FreeBSD 4.11.  The support compiles but
+               hasn't been tested.
+
+               Back-ported a FreeBSD 6.0-CURRENT fix to FreeBSD
+               5.3-RELEASE-p1.  That was done to solve a compilation
+               problem reported by Radko Keves <rado@daemon.sk>.
+
+4.75           May 16, 2005
+               Dropped the *claim* that lsof works on DEC OSF/1 and
+               Digital UNIX, since my last 4.0 test system has been
+               removed.  The last tested distribution of lsof on DEC OSF/1
+               and Digital UNIX was revision 4.74.  It has been archived
+               on lsof.itap.purdue.edu in pub/tools/unix/lsof/OLD/src.
+
+               Added negation forms to the values in the -g (PGID) and
+               -p (PID) lists.  Negated PGID and PID values, like
+               negated UID or login name values, are applied without
+               ORing or ANDing and take effect before any other
+               selection criteria are applied.
+
+               At the request of Marcin Gozdalik <gozdal@gmail.com>
+               added a -X option for Linux.  The option inhibits the
+               reading of the /proc/net/tcp* and /proc/net/udp*
+               files.
+
+               Based on a report from David Gutierrez
+               <davegu1@hotmail.com> changed DEC OSF/1 process table
+               allocation to request memory in smaller increments.
+
+               Based on a report from jayjwa <jayjwa@atr2.ath.cx>
+               updated the Customize script to use "tail -n 1" where
+               possible.
+
+               Enabled support for FreeBSD 5.4.
+
+               Improved the BSDI, FreeBSD, NetBSD, OpenBSD and Solaris
+               kvm_open() and kvm_openfiles() error messages.
+
+               Enabled support for NetBSD 2.99.12.
+
+               Improved HP-UX Configure stanza with help from Piet
+               Starreveld <pstarrev@csc.com>.  Picked some lint Piet
+               found.
+
+               Enabled IPv6 support for HP-UX > 11.  Piet Starreveld
+               helped test it on 11.23, among others.
+
+               Updated for HP-UX 11.23 on the ia64 architecture.
+
+               Updated to latest FreeBSD 6.0-CURRENT, using a test
+               system provided by Andrzej Tobola <ato@iem.pw.edu.pl>.
+
+               Added support for SCO OSR 6.0.0 and UnixWare 7.1.4 with
+               help from Richard at SCO.
+
+               Corrected a Linux bug in NFS handling, reported by Karel Zak
+               <kzak@redhat.com>.  Karel supplied a patch.
+
+               Improved the code for accessing an AIX 3.2 and higher
+               sockaddr_un structure, thus eliminating a segmentation
+               fault possibility.
+
+               Updated for AIX 5.3.
+
+               Added preliminary (DEBUG) support for the AIX SANFS
+               file system.
+
+               Fixed a bug in the Solaris 10 processing of the vnode's
+               v_path pointer with code supplied by Edward Jajko
+               <ejajko@portal.com>.  The fix was offered as a patch to
+               4.74.
+
+               Dropped support for OpenUNIX 8, since a test system is
+               no longer available.  Archived an OpenUNIX-only
+               distribution of the last revision (4.74) tested on
+               OpenUNIX in pub/tools/unix/lsof/OLD/src.
+
+               Tested under Openbsd 3.7.
+
+               Tested under Darwin 7.7.0.
+
+               Enabled building on amd64 Solaris 10 with hints from
+               Marc Aurele La France <tsi@ualberta.ca>.  Marc provided
+               a test system.
+
+               Supplied a missing quote in the FreeBSD Configure
+               stanza.  Carl Cook <Info@quantum-sci.com> reported the
+               problem.
+
+               Removed "-O" option from tests/Makefile so that the
+               HP-UX bundled compiler won't complain.
+
+4.76           August 30, 2005
+               Corrected an example and spelling errors in man page.
+
+               Updated for Apple Darwin 8.x with changes supplied by
+               Allan Nathanson <ajn@apple.com>.  Allan also provided a
+               test system.
+
+               Completed documentation of CLRLFILEADD in all machine.h
+               files.
+
+               At the request of Chris Markle <cmarkle@sendmail.com>
+               added partial listen queue length to socket options
+               displayed when -Tf is specified.  Partial queue length
+               is not reported for all dialects.  (00FAQ lists the
+               ones where it is reported.)
+
+               Updated for FreeBSD 7.0 with information supplied by
+               Andrzej Tobola <ato@iem.pw.edu.pl>.
+
+               Updated Solaris VxFS support for VxFS versions 4 and
+               above with technical advice from Craig Harmer
+               <craig_harmer@symantec.com>, Gary Millen
+               <gary_millen@symantec.com> and Chuck Silvers
+               <charles_silvers@symantec.com>.  Testing help was
+               provided by Michael Antlitz <mantlitz@prophasys.com>,
+               Steve Ginsberg <steve@dhapdigital.com> and Kenneth
+               Stailey <kstailey@yahoo.com>.
+
+               Fixed a Solaris address space map processing bug.
+               Janardhan Molumuri <mjanardhan@gmail.com> reported the
+               bug and help me identify it.  Made the fix available as
+               a patch to 4.75.
+
+               Added support for Solaris 10 port and CTFS files.  The
+               CTFS support is imcomplete, because I don't know how
+               to get inode number, size and link count.  (There's
+               a new 00FAQ entry about that.)
+
+               Investigated a report from Christopher J Warweg
+               <warwegc@GAO.GOV> that the CHECKSUMS for the lsof 4.75
+               binary for 64 bit Solaris 8 was incorrect.  It was my
+               packaging error.  I rebuilt and repackaged the binary.
+
+               Enabled support for Linux map file names with embedded
+               spaces.
+
+4.77           April 10, 2006
+               Added -X option support for Solaris 10 and above.  When
+               -X is specified lsof will report cached v_node path
+               names for unlinked files, followed by "(deleted)".
+               Improved cached vnode path name handling by adding
+               "(?)" to the end of path names of questionable accuracy.
+               Updated 00FAQ to reflect these changes.
+
+               Updated for FreeBSD 7.0-CURRENT.
+
+               Fixed name addition spacing bug, reported by Stuart
+               Anderson <anderson@ligo.caltech.edu>.  Also updated
+               Solaris 10 SAMFS support at Stuart's request.
+
+               Added missing "break;" and another HASSTATVFS test to
+               the NetBSD and OpenBSD dnode.c.  Bill Behr
+               <bbehr@networkstoragecorp.com> reported those needs.
+
+               Fixed an HP-UX 11 file descriptor "chunk" size problem,
+               reported by Per Allansson <per@appgate.com>.  Per helped
+               devise the fix and tested it.  This fix was offered as
+               a patch to lsof 4.76.
+
+               Updated for FreeBSD 6.0-STABLE and FreeBSD
+               6.1-PRERELEASE.
+
+               Updated scripts/sort_res.perl5 with changes supplied by
+               Frederick Fabian <fabian.frederick@skynet.be>, the
+               author of the script.
+
+               Corrected +|-M man page documentation error, reported
+               by Roger Cornelius <rac@tenzing.org>.
+
+               Improved FreeBSD user device random seed generation in
+               response to a problem report from Danny Braniss
+               <danny@cs.huji.ac.il>.
+
+               Eliminated three syntax error bugs and other compiler
+               complaints from the PSTAT-based lsof.  H. Merijn Brand
+               <h.m.brand@xs4all.nl> reported the problems and tested
+               the fixes.
+
+               Eliminated compiler complaints in the test suite.
+
+               Investigated problems with the building of lsof on
+               PA-RISC HP-UX 11.23, based on a report from John
+               Orndorff <John.Orndorff@sungard.com>.  Found that
+               neither the HP bundled C compiler nor gcc would build
+               lsof, but the the HP unbundled ANSI C compiler would.
+               Concluded that HP bundled C compiler can't handle
+               <gssapi/gssapi.h>.  Devised a work-around to gcc's
+               omission of the rpcent structure definition of
+               <netdb.h> that allows it to compile lsof's print.c, but
+               the resulting binary doesn't run reliably.  Documented
+               the situation in 00FAQ.
+
+               Changed reporting of unknown file types.  The number of
+               an unknown type is now reported as four octets.  The
+               change was made in response to a Linux lsof bug report
+               from Karel Zak <kzak@redhat.com>.
+
+               Dropped the *claim* that lsof works on BSDI BSD/OS
+               since my last test system has been removed.  The last
+               tested distribution of lsof for BSDI BSD/OS was
+               revision 4.76.  It has been archived on
+               lsof.itap.purdue.edu in pub/tools/unix/lsof/OLD/src.
+
+               As a result of discussing the lsof source tar's MD5
+               checksum with Andrew Bell <andrew.bell.ia@gmail.com>,
+               changed the description of a suitable MD5 tool in the
+               lsof distribution's documentation to name the openssl
+               "dgst" command.
+
+               Enabled compilation on Solaris 10 1/06 with a fix sent
+               by Jason Fortezzo <fortezza@mechanicalism.net>.  Made
+               the fix available as a patch to 4.76.
+
+               Adjusted to FreeBSD 5.5-PRERELEASE.
+
+               Corrected a bug in the lsof library's process_file()
+               function to enable the locating of AIX XTI sockets by
+               their TCP/IP address values.  The bug was reported by
+               Michel Dubois <Dubois@sears.ca>.
+
+               Based on a bug report from Karel Zak <kzak@redhat.com>
+               added command name length checking to as many dialects
+               as possible (Linux for Karel) for the "-c c" option.
+
+               Updated for OpenBSD 3.[89].  Tested the 3.9 update on a
+               system provided by David Mazieres.  I have not tested
+               on OpenBSD 3.8, but David reports lsof 4.76 worked
+               there.
+
+               Ended regression testing of lsof on 32 bit Solaris 8
+               with the ending of access to a test system.  Lsof
+               continues to be tested on 64 bit Solaris 8.
+
+4.78           April 24, 2007
+               Added more information to the lsof FAQ about missing
+               link counts and sizes on Linux files.
+
+               Simplified Linux stat() and lstat() usage.
+
+               Relocated #define's that prevent OpenBSD compilation on
+               systems without a /proc file system.  Pieter Bowman
+               <bowman@math.utah.edu> reported the problem.
+
+               Added code to avoid processing Linux /proc/<PID>/maps
+               file entries with zero device and node numbers.  Some
+               such entries now have names associated with them that
+               are not path names -- e.g., "[heap]", "[stack]" or
+               "[vdso]".  Scott Worley <sworley@chkno.net> reported
+               lsof's mishandling of such entries.
+
+               Added SELinux security context support, provided by
+               James Antill <james.antill@redhat.com>.  I have not
+               tested this, but James and Karel Zak <kzak@redhat.com>
+               have.
+
+               Added the #include of <sys/types.h> to Solaris lsof to
+               enabled compilation on Solaris 10 6/06.  Peter Harvey
+               Peter.Harvey@Sun.COM diagnosed the problem and supplied
+               a patch.
+
+               Added better support for JFS2 on AIX 5.2 and 5.3, based
+               on bug reports and help from Thomas Braunbeck
+               <BRAUNBEC@de.ibm.com> and Tom Whitty <TWHITTY@cerner.com>.
+
+               Documented that lsof supports AIX 5.3 only up through
+               maintenance level 1 (ML1).
+
+               Enabled Solaris lsof to locate the AFS vnode operation
+               address for OpenAFS 1.4.1.  The fix was supplied by
+               Robert Jelinek <Robert.Jelinek@MorganStanley.com>.
+
+               Enabled support for Solaris 10 ZFS.  If the necessary
+               ZFS header files aren't found, lsof offers the option
+               to drop ZFS support, to use internal, possibly
+               inaccurate structure definitions, or to supply a path
+               to the missing header files.  Horst Scheuermann
+               <Horst.Scheuermann@uni-trier.de> provided a development
+               system and helped test the support.
+
+               Corrected a typo in the man page, reported by Eric S.
+               Raymond <esr@thyrsus.com>.
+
+               Changed the spelling of macroes to macros in lsof
+               source and documentations files, based on a suggestion
+               from Josh Soref <timeless@gmail.com> and verification
+               with the OED.
+
+               The following dialects are no longer supported: 32 bit
+               AIX 5.2, HP-UX 11, OpenStep 4.2, Solaris 2.6, Solaris
+               8, True Unix 64 and UnixWare 7.1.4.  Lsof may work on
+               them, but I no longer have test systems for them.
+               Support for OpenBSD ends at its version 3.9 for lack of
+               interest in the port.
+
+4.79           April 15, 2008
+
+               **************** IMPORTANT NOTE ******************
+               *                                                *
+               * Lsof support has been reduced to the following *
+               * dialects: AIX, FreeBSD, Linux and Solaris, and *
+               * only in selected versions of those dialects.   *
+               * The selected versions are listed in this file  *
+               * and in other lsof documentation.               *
+               *                                                *
+               * I have made this move because of retirement    *
+               * and because I no longer have many test systems *
+               * available to me.                               *
+               *                                                *
+               * Vic Abell                                      *
+               *                                                *
+               **************************************************
+
+               Fixed a Solaris VXFS permission problem when accessing
+               the VXFS inode offsets.  The bug was reported by
+               Gregory A. Ivanov <ivga@mts.ru>.  Gregory tested the
+               fix.
+
+               Moved an #include <string.h> later in FreeBSD dlsof.h
+               to enable compilation on recent FreeBSD releases.  The
+               change was supplied by Roy Marples <uberlord@gentoo.org>.
+
+               Improved Linux /proc file stream reading speed by applying
+               an expanded version of a patch from Eric Dumazet
+               <dada1@cosmosbay.com> that allocates a page size buffer
+               to each stream.  Improved TCP, TCP6, UDP and UDP6 hashing
+               by determining the hash bucket count from the /proc/net
+               sockstat and sockstat6 files.  The improvement was
+               suggested by Eric and he provided sample code.  Eric also
+               tested both improvements.
+
+               Modified Configure script to build lsof on FreeBSD
+               6.2.  Tested it on a system provided by Larry Rosenman
+               <ler@lerctr.org>.
+
+               Fixed a Linux maps file processing bug that prevented path
+               names from having an embedded colon.  James Lingard
+               <jchl@arastra.com> reported the bug and helped with its
+               fix.
+
+               Based on reports from Eric Dumazet and Samuel Thibault
+               <samuel.thibault@ens-lyon.org> added support for the
+               Linux 2.6.22 kernel's /proc/<PID>/fdinfo files -- i.e.,
+               file offset and flags.  Samuel Thibault provided a test
+               system.
+
+               Fixed a Linux UNIX socket memory leak, reported by
+               Philip Shin <pshin@xceedium.com>.  Phillip supplied the
+               fix.
+
+               With generous assistance from HP added support for an HP-UX
+               11.23 patch that makes TLI/XTI socket address information
+               available.
+
+               Fixed a header file problem for FreeBSD 6.2 on the Alpha
+               architecture.  The problem was reported by Pekka Honkanen
+               <phonkane@cc.hut.fi>.  Pekka tested the fix.
+
+               Based on a report and using suggested fixes from Karel Zak
+               <kzak@redhat.com>, made these changes to Linux lsof: corrected
+               a getpidcon() error message; insured that inode numbers are
+               handled correctly for their unsigned long long type; and
+               improved SELinux handling.  At the request of Alon Bar-Lev
+               <alonbl@gentoo.org> added the LINUX_HASSELINUX environment
+               variable to enable or inhibit SElinux support unconditionally.
+
+               Updated Configure for FreeBSD 8.0-CURRENT and tested lsof on
+               AMD64 there.
+
+               Added a patch provided by Oles Hnatkevych
+               <don_oles@able.com.ua> for FreeBSD systems where the root
+               file system is on a CD9660 device.
+
+               Added compensation for the disappearance of FMARK and FDEFER
+               from the FreeBSD 8.0-CURRENT <sys/file.h>.
+
+               Updated FreeBSD lsof with ZFS support.  Larry Rosenman
+               <ler@lerctr.org>, Erwin Lansing <erwin@FreeBSD.org>, Wesley
+               Shields <wxs@atarininja.org> and Dmitry Morozovsky
+               <marck@rinet.ru> provided test systems.
+
+               Fixed a socket file identification problem reported by
+               Pavol Rusnak <stick@gk2.sk>.  Pavol also reported the
+               cause of the problem.
+
+               Added the ability to format the repeat mode marker line
+               with strftime(3), where the dialect supports the
+               localtime(3) and strftime(3) C library functions.  The
+               addition was suggested by Mike Depot <mdepot@comcast.net>,
+               who also tested it.  The addition required creating a new
+               main lsof source module, util.c, that contains functions
+               whose compilation conflicts with the general header file
+               tree defined by lsof.h and dlsof.h.
+
+               Based on reports from Andrei V. Lavreniyuk
+               <andy.lavr@reactor-xg.kiev.ua> and Pav Lucistnik
+               <pav@FreeBSD.org> updated the FreeBSD 7.0 and above
+               file lock handling to use new locking structures.  The
+               update requires a terrible hack to get a definition for
+               the lock owner structure from a kernel source module
+               into a local lsof header file.
+
+4.80           May 12, 2008
+               Updated for a FreeBSD 7.0 and above byte level locking
+               change.  The problem was reported by Conrad J. Sabatier
+               <conrads@cox.net>, who helped test the update.  Wesley
+               Shields <wxs@FreeBSD.org> provided an 8.0-CURRENT test
+               system.
+
+               Propagated the FreeBSD 7.0 and above locking changes to
+               FreeBSD 6.x, based on a report from Edwin Groothuis
+               <edwin@FreeBSD.org>.
+
+               Added warnings for unsupported dialects or versions.
+
+               Added Linux support for the UDPLITE protocol.  Eric
+               Dumazet <dada1@cosmosbay.com> supplied a patch.
+
+               Added a missing quote to the Configure script's
+               FreeBSD stanza.
+
+               Added a usage.o rule to the HP-UX PSTAT-based
+               Makefile.  I mistakenly deleted the rule at revision
+               4.79.  The missing rule was reported by Kawaljeet Kaur
+               <kawaljeet.malviya@gmail.com> who tested the corrected
+               Makefile.
+
+4.81           October 21, 2008
+               Updated the Darwin libproc sources with changes from
+               Allan Nathanson <ajn@apple.com>.  Tested them on a iMac
+               mini, provided by Apple Inc.
+
+               Changed dummy declarations in library source files to
+               eliminate complaints about unused variables and empty
+               object files.  This change may not work on dialects I
+               can no longer test; it has been tested on some versions
+               of AIX, Darwin, FreeBSD, Linux and Solaris.
+
+               At the request of Hal Brooks <hal@uga.edu> added support
+               for Linux /proc/net/packet files.  Hal tested it.
+
+               Added socket file only performance enhancements to Linux
+               and PSTAT-based HPUX lsof.
+
+               Added htonl call around improper usage of INADDR_LOOPBACK;
+               report from an Apple engineer forwarded by Allan Nathanson
+               <ajn@apple.com>.
+
+               Adjusted for FreeBSD-8.0 change in device number handling.
+               The adjustment should work for FreeBSD 5 and above, should
+               the 8.0 change be propagated downward.  The problem was
+               reported by Pav Lucistnik <pav@FreeBSD.org>.  An updated
+               test system was provided by Erwin Lansing <erwin@FreeBSD.org>.
+
+               Reduced AIX support to version 5.3, since test systems with
+               older versions are no longer available to me.
+
+               At the request of Marjo F. Mercado <mmercado@xceedium.com>
+               and Phil Shin <pshin@xceedium.com> applied some speed
+               improvements to lsof, particularly when the files of
+               interest are /Internet files -- i.e., selected with lsof's
+               "-i" option.  Added a two new options to assist the
+               improvements: 1) "-c^<command>" to tell lsof to exclude the
+               named command(s); and 2) "-stcp|ud>:[^]state' to tell lsof
+               to include in its reporting or exclude ('^') from its
+               reporting Internet files in the named states (e.g., LISTEN,
+               ^CLOSE_WAIT, IDLE, etc.)  For the most part these changes
+               apply only to AIX, Darwin, FreeBSD, PSTAT-based HP-UX, Linux
+               and Solaris, since those are the only places I could test
+               them.  They are controlled by the HASTCPUDPSTATE definition
+               in each dialect's machine.h header file.  Marjo and Phil
+               provided HP-UX 11.23 and 11.31 test systems.
+
+               Fixed a stat(2) problem on HP-UX 11.31 while testing the
+               speed improvements.
+
+               Adjusted for kernel header file changes in FreeBSD
+               8.0-CURRENT.  Larry Rosenman <ler@lerctr.org> provided
+               a test system.
+
+               Added a warning for Solaris systems where VxFS node info
+               can't be obtained from the VxFS utility library.  The
+               warning was requested by Tom Matthews <Tom.MATTHEWS@rbs.com>.
+
+               Corrected mishandling of file system path name arguments
+               that have trailing slashes, except, of course, the root
+               file system, "/".  Allan Nathanson <ajn@apple.com> reported
+               the bug.
+
+4.82           March 25, 2009
+               Corrected an over-zealous exclusion test that caused
+               lsof to report nothing when it was given no arguments
+               and built with HASSECURITY and HASNOSOCKSECURITY enabled.
+               Joshua Kinard <kumba@gentoo.org> reported the bug and
+               supplied information for reproducing it.
+
+               Based on a report from Dan Trinkle <trinkle@cs.purdue.edu>
+               corrected use of <sys/utsname.h> for 32 bit Solaris 10
+               and above compilations.  Simultaneously eliminated a
+               casting complaint in arg.c and updated Configure to use
+               the appropriate 64 bit compilation option (-xarch=v9 or
+               -m64) with the Solaris Sun C compiler.
+
+               Updated for FreeBSD 7.1-PRERELEASE with information
+               supplied by Larry Rosenman <ler@lerctr.org>.
+
+               Updated the Darwin libproc sources with changes from
+               Allan Nathanson <ajn@apple.com>.  Tested them on a iMac
+               mini, provided by Apple Inc.  Allan also provided man
+               page corrections.
+
+               Updated the FreeBSD Makefile to use the ${MAKE} variable
+               for ZFS dnode2.c module compilation, based on a suggestion
+               from Alexis Ballier <aballier@gentoo.org>.
+
+               Improved the Solaris VxFS library location test, based on a
+               suggestion from Jason Fortezzo <fortezza@mechanicalism.net>.
+               Jason tested the change.
+
+               Updated Solaris 10 ZFS support for ZFS version 4 and ZFS
+               pool version 10, using a test system kindly provided by
+               Vladislav Nespor <vladislav.nespor@id.ethz.ch>.  Renata
+               Maria Dart <renata@slac.stanford.edu> tested on ZFS
+               version 4, verifying that the update works there, too.
+               (ZFS pool version 10 is apparently the ZFS version shipped
+               with the 10/08 update to Solaris.  The original ZFS
+               support targeted ZFS version 3.)
+
+               I still consider ZFS support in Solaris lsof a hack,
+               because it depends on a znode structure definition that
+               I developed using dbx.  Sun is remiss in not distributing
+               the ZFS header files used to build the distributed kernel.
+
+               Because of the znode structure definition hack, I can't
+               guarantee that lsof ZFS support will work for any other
+               versions of ZFS.
+
+               Solaris 10: adjusted to a change in the way devices are
+               stored in the kernel; fixed a problem in zone handling;
+               and added rudimentary sharedfs support.  Carson Gaspar
+               <carson@taltos.org> reported the device number problem,
+               provided a test system, and tested the changes.  Peter
+               Vines <psv2b@eservices.virginia.edu> reported the zone
+               handling problem and tested the fix.
+
+               Adapted to FreeBSD 8.0-CURRENT changes in device number
+               computation.  Problem was reported by Erwin Lansing
+               <erwin@FreeBSD.org>.  Larry Rosenman <ler@lerctr.org>
+               provided a test system.
+
+               Corrected Solaris Configure test for appropriate VxFS
+               library when using gcc to compile lsof.
+
+               Updated for loss of KAME IPv6 FreeBSD accommodations.
+
+               Adapted to FreeBSD 7.2.  Made Configure script recognized
+               FreeBSD 6.3.
+
+4.83           January 18, 2010
+               Converted Solaris 10 and above ZFS support to use the CTF
+               debugger library, libctf.  Code was supplied by Robert
+               Byrnes <Robert.Byrnes@deshaw.com>.
+
+               Corrected a typo in the testing of the LINUX_HASSELINUX
+               environment variable in the Configure script.  The error
+               was reported by Mike Frysinger <vapier@gentoo.org>.
+               At Mike's request made Configure script accept LSOF_RANLIB
+               (ranlib command), LSOF_CFGF (additional configuration flags)
+               and LSOF_CFGL (additional library specifications) from the
+               environment.
+
+               Enabled complilation of Solaris 10 lsof after a recent Sun
+               patch which changed the PC file system's structure. Peter
+               Vernam <pvernam@draper.com> reported the problem and helped
+               with the fix.
+
+               Made the sort of configuration CFLAGS in the CkTestDB
+               script impervious to locale settings.
+
+               Ported to Solaris 11, using a test system kindly provided
+               by David Day <dday76@gmail.com>.
+
+               Adjusted to the disappearance of <nfs/rpcv2.h> in FreeBSD
+               8.0-BETA1.
+
+               Changed Solaris node type lookup to a hashed method and
+               added some ability for it to handle duplicate vnodeop names
+               in /dev/ksyms.
+
+               Updated for FreeBSD 9.0-CURRENT.  Andrzej Tobola
+               <ato@iem.pw.edu.pl> provided a test system.  Extends the
+               fix to FreeBSD 6.0 and above via a Configure test and a
+               compile-time definition.  The need for the extension was
+               reported by Erik Trulsson <ertr1013@student.uu.se>>
+
+               Made corrections to FAQ typographical errors, suggested
+               by Josh Soref <timeless@gmail.com>.
+
+               Added __UCLIBC__ test to Linux dlsof.h so lsof would compile
+               on an Intel ARM XScale processor.  The addition was provided
+               by Doug Kehn <rdkehn@yahoo.com>.
+
+               Added test for <utmpx.h> to FreeBSD configuration.  Improved
+               its use in lsof.h.  The changes were supplied by Martin Wilke
+               <miwi@FreeBSD.org>.
+
+4.84           July 29, 2010
+               Fixed a man page nroff command error with a correction
+               supplied by Josh Soref <timeless@gmail.com>.
+
+               Made Configure script recognize FreeBSD 7.3.  Larry Rosenman
+               <ler@lerctr.org> provided a test system.
+
+               Improved task support, initially for Linux only, with help
+               provided by Jerome Marchand <jmarchan@redhat.com> and
+               Miklos Szeredi <mszeredi@suse.cz>.  The support includes a
+               new compile-time definition, HASTASKS, and a new run time
+               option, "-K" to select task reporting.
+
+               While adding help output support for "-K", reorganized the
+               printing of help columns to make it much easier to add a new
+               option description.
+
+               Updated the Solaris PC file system structure patch in
+               revision 4.83 so it will compile with gcc.
+
+               Disabled the Solaris lgrp_root work-around in the Solaris
+               machine.h so it won't cause compilation problems on Solaris
+               11.  It no longer causes compilation problems on my Solaris
+               9 and 10 test systems, but some older Solaris 9 and 10
+               versions may still need it, so the work-around was left in
+               the Sun machine.h and a FAQ entry was created about it.
+
+               Updated for Solaris 11 b134, using a test system kindly
+               provided by Carson Gaspar <carson@taltos.org>.  Made
+               provisions for the next ZFS version.  Added info about
+               the failure of the LTnlink test on ZFS file systems.
+
+               Corrected typo in Configure script, reported by Dmitry
+               Berezin <dmitryb@oit.rutgers.edu>.
+
+4.85           September 27, 2011
+               John Dzubera <Zube@CS.ColoState.EDU> kindly provided a patched
+               Solaris 9 test system with the lgrp_root conflict and I was
+               able to devise an automatic work-around for the conflict.  The
+               special note in .../dialects/sun/machine.h was removed and
+               the 17.28.1 FAQ entry was modified to reflect the update.
+
+               Added a Solaris 11 work-around for a typedef problem with
+               <sys/mutex.h>.  Carson Gaspar <carson@taltos.org> reported
+               the problem and supplied the work-around.
+
+               Added support for FreeBSD 7.4 and 8.2; tested on systems
+               provided by Larry Rosenman <ler@lerctr.org>.
+
+               Added support for 32 bit Solaris 11 lsof with mods supplied
+               by Jan Wortelboer <J.H.P.Wortelboer@uva.nl>.
+
+               Added Solaris 11 support for using an alternate genunix
+               location.  Bill Goodridge <bill@its.brooklyn.cuny.edu>
+               reported the alternate location.
+
+               Added further Linux cross configuration support to lsof's
+               Configure script.  The additional support was supplied by
+               Grant Erickson <erick205@umn.edu>.  See the descriptions of
+               the LINUX_* environmen  variables in 00XCONFIG for more
+               information.  Tested lsof on Linux kernel 2.6.32 and picked
+               some lint that surfaced during the test.
+
+               Added fixes and changes for Apple Mac OS X 10.6, provided by
+               Allan Nathanson <ajn@apple.com>.  Allan also provided a test
+               system.
+
+               Tested on FreeBSD 6.4 i386, using a test system provided by
+               Terry Kennedy <TERRY@tmk.com>.  Updated for recent FreeBSD ZFS
+               changes on an 8.2 amd64 test system also provided by Terry.
+
+               Changed documentation to indicate FreeBSD 7.x is no longer
+               supported, since I no longer have a test system.
+
+               Made some changes to the lsof man page, suggested by Navid
+               <evi1m4chine@googlemail.com>.
+
+               Added compensation for Solaris 10 systems that have patch
+               144488-10.  The patch requires that the new header file
+               <sys/socket_proto.h> be included while _KERNEL is defined.
+               Brett Bartick <Brett.bartick@nomura.com> reported the problem
+               first, followed by Stuart Anderson <anderson@ligo.caltech.edu>.
+               Michael Hocke <michael.hocke@nyu.edu> suggested a work-around
+               which I refined to limit it to the specific Solaris 10 instance
+               and then tested on a system provided by Charles Stephens
+               <cfs@cowlabs.com>
+
+               Added the +|-e option for Linux.  It exempts file systems
+               named by path from function calls that might block in the
+               kernel -- i.e., stat(2) and lstat(2), and when the +e form
+               is used, readlink (2).  The new packager of lsof for the
+               Linux Fedora and RHEL distributions, Peter Schiffer
+               <pschiffe@redhat.com>, asked for the feature so it could
+               be used with Clearcase file systems, whose implementation
+               can block stat(2) calls.  I consider this feature very risky
+               and easy to misuse -- e.g., specifying the file system as
+               '/' would exempt all file systems.  I don't intend to
+               propagate this option to any other UNIX dialect that lsof
+               currently supports.
+
+               Made FreeBSD 9 adjustment.
+
+               Fixed a Linux bug that prevented the display of paths for
+               abstact UNIX sockets.  Masatake Yamato <yamato@redhat.com>
+               reported the bug and supplied a patch.
+
+               Added compensation for the removal of RPC header files from
+               GlibC 2.14 for Linux.  Marek Behun <kabel@blackhole.sk>
+               reported the problem and supplied a patch.
+
+               Added support for Linux Netlink protocol.  Masatake Yamato
+               requested the support and supplied a patch.  Peter Schiffer
+               <pschiffe@redhat.com> provided a test system.
+
+               Corrected Linux UDP6-lite path.  The error was reported by
+               Masatake Yamato and he also supplied a patch.
+
+4.86           April 10, 2012
+               Lsof for AIX is no longer supported on any versions of that
+               operating system.
+
+               Added information about the clang compiler for FreeBSD to the
+               FAQ.
+
+               Corrected an arg.c bug in the accumulation of +|-e option
+               values, reported by Peter Schiffer <pschiffe@redhat.com>.
+               This correction was supplied as a patch to revision 4.85.
+
+               Enabled FreeBSD 10 support and tested it there on a system
+               provided by Larry Rosenman <ler@lerctr.org>.
+
+               Updated for latest Solaris 11 with patches supplied by
+               Carson Gaspar <carson@taltos.org>.  Carson supplied a test
+               system.
+
+               Adjusted Linux file system search method to compensate for
+               NFS mounts that have duplicate device numbers.  The problem
+               was reported by Peter Schiffer <pschiffe@redhat.com>, who
+               provided a test system.
+
+               At the request of Peter Schiffer <pschiffe@redhat.com>, added
+               support for Linux SCTP socket files.  Peter provided a test
+               system.  Applied a warning patch supplied by Peter.
+
+               Added support for Mac OS X 10.7 (Lion), provided by Allan
+               Nathanson <ajn@apple.com>.  Allan also supplied a test
+               system.
+
+               Enabled FreeBSD 8.3 support and tested it there on a system
+               provided by Larry Rosenman <ler@lerctr.org>.
+
+               Corrected the FAQ information on ZFS with Solaris 10 after
+               Steven Blackmon <stblackm@cisco.com> and Prasad Jampala
+               <jampalp@cisco.com> pointed out that it was incorrect --
+               i.e., outdated by the libctf changes at revision 4.83.
+
+               Added code to handle a Linux NFS-mounted root.  Jia He
+               <hejianet@linux.vnet.ibm.com> reported the need for this.
+
+4.87           January 2, 2013
+               Added an entry to 00FAQ about lsof behavior when the
+               HASSECURITY and HASNOSOCKSECURITY options are defined.
+               Carson Gaspar <carson@taltos.org> pointed out the need
+               for this clarification.
+
+               Added a work-around for a missing definition of mach_port_t
+               in Darwin 9 (Mac OS/X 10.5.8).  The work-around was supplied
+               by Jim Reid <jim@rfc1035.com>.
+
+               Added support for Linux anon_inodefs, provided by Masatake
+               YAMATO <yamato@redhat.com>.
+
+               Documented a Solaris 9 and 10 portmap reporting problem
+               (+M) in 00FAQ.  The problem was reported by Clint
+               Roberts <Clint.Roberts@ttius.com>.  I have no solution
+               to the problem, but discuss a possible work-around in
+               the answer to this 00FAQ question: "Why doesn't lsof
+               report portmap registrations for some Solaris versions?"
+
+               Added FreeBSD support for the oldnfs and newnfs file system
+               types.  Daniel Braniss <danny@cs.huji.ac.il> reported the
+               need for the addition.
+
+               Added ICMP socket support for Linux with code provided by
+               Masatake YAMATO <yamato@redhat.com>.
+
+               Corrected the reporting of process group ID for libproc
+               versions of Mac OS X with a patch from Jeff Trawick
+               <trawick@gmail.com>.  The patch has not been applied to
+               Darwin kmem versions, because of little call for them
+               and inadequate test system access.  The patch has been
+               tested on Mac OS X 10.8 (Mountain Lion), courtesy of a
+               test system provided by Allan Nathanson <ajn@apple.com>.
+
+               Added thread support to those FreeBSD versions that have
+               ki_numthreads in their kinfo_proc structure.  This also
+               activates the -K option for those FreeBSD versions.  Jeff
+               Trawick reported problems with FreeBSD lsof when threads
+               are present and this addition solves those problems.
+
+               Made changes to 00FAQ and the distribution, suggested by
+               Warren Young <warren@etr-usa.com>.  The 00FAQ changes
+               center on sections that discuss the -s option.  The changes
+               to the distribution include a ChangeLog file that is either
+               a pointer to or a copy of 00DIST, the distribution notes.
+
+               Added support to FreeBSD for using the clang compiler.
+
+               Added Linux support for using the getxattr() call to obtain
+               socket protocol identification when it is can't be obtained
+               from the /proc/net files that lsof examines.  Masatake YAMATO
+               <yamato@redhat.com> developed the kernel patch to getxattr()
+               and supplied the lsof patch.
+
+4.88           October 13, 2014
+               Reduced to 50 the number of open file descriptors lsof
+               attempts to close while trying to protect itself from a
+               file descriptor exec() attack.  This limits the overhead
+               lsof incurs on systems that have large file descriptor
+               limits, yet provides sufficient open descriptors for the
+               library functions lsof calls.
+
+               Updated for changes in FreeBSD 10 with advice from Eygene
+               Ryabinkin <rea@freebsd.org>.  Taught Configure to recognize
+               FreeBSD 8.4.
+
+               Herein am noting that lsof for Solaris 10 or 11 is no longer
+               supported.  I no longer have test systems.  Some support is
+               still available from Casper Dik <Casper.Dik@oracle.com> and a
+               Solaris 11 patch he provided is included in this revision.
+
+               Initialized local variables in the Linux process_id() function.
+               Jia He <jiakernel@gmail.com> reported the problem.
+
+               Added support for FreeBSD 11.
+
+               Updated FreeBSD ZFS Configure stanza to supply a dummy
+               opt_kdtrace.h when needed.
+
+               Added tmpfs file system support for FreeBSD.
+
+               Since a test system is no longer available, dropped the
+               claim of FreeBSD 4.9 support.
+
+               Added the +|-E options for Linux.  -E displays endpoint info;
+               +E displays endpoint info and endpopint files.  Masatake YAMATO
+               <yamato@redhat.com> requested this support and suggested code
+               to implement it.
+
+               Fixed a Linux bug handling processes whose command includes a
+               non-printing character, particularly a NEWLINE character, and
+               clarified printing of single '\\' characters in command and
+               file names.  Stephane Chazelas <stephane.chazelas@gmail.com>
+               reported the problem.
+
+               Added support for Linux RDMA and CRYPTO protocal names and UNIX
+               socket type with code from Masatake YAMATO <yamato@redhat.com>.
+
+               Fixed field output to insure that the field descriptor field is
+               always selected, since it identifies the file set.  The bug was
+               reported by Gary Plewa <gary.m.plewa-1@lowes.com>.
+
+4.89           July 7, 2015
+               Applied correction from Casper Dik <Casper.Dik@oracle.com> to
+               his patch for Solaris 11 that I applied incorrectly in revision
+               4.88.
+
+               Updated for latest version of FreeBSD 11.0-CURRENT.
+
+               Compensated for a missing FreeBSD 10.0 typedef of bool on the
+               i386 architecture.  Allen Hewes <rallenh@hotmail.com> provided
+               a test system. Andrey Chernov <ache@freebsd.org> provided
+               useful advice.
+
+               Improved tests/Add2TestDB script with a patch from Peter
+               Schiffer <pschiffe@redhat.com>.  Added patches from Peter to
+               eliminate Linux gcc warnings.  Updated Lsof.8 with improvements
+               supplied by Bjarni Ingi Gislason <bjarniig@rhi.hi.is>.
+
+               Changed FreeBSD global CFLAGS extraction per Terry Kennedy
+               <TERRY@tmk.com>.  Also made sure -DNEEDS_BOOL_TYPEDEF is
+               #define'd when the resulting CFLAGS doesn't contain it.  Terry
+               reported that need.
+
+               Improved Linux test for tcp.h in response to a report from
+               Cato Auestad <cato@cato.ninja>.  Cato did the testing.
+
+               Fixed Linux UNIX socket search by name bug reported by
+               Stephane Chazelas <stephane.chazelas@gmail.com>.
+
+               Added Linux display of UNIX socket endpoint information with
+               code provided by Masatake YAMATO <yamato@redhat.com>.  Peter
+               Schiffer <pschiffe@redhat.com> provided a test system.
+
+               Insured that type definitions from <vm/vm.h> were again made
+               visible to lsof on FreeBSD 11 after a system header file change
+               hid them.
+
+4.90           February 14, 2018
+
+               !!!NOTE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+               !                                                        !
+               !   It is likely that this is the last lsof revision I   !
+               !   will issue, unless serious bugs are detected,  Stay  !
+               !   tuned to lsof-l for information about future support !
+               !   of lsof.                                             !
+               !                                                        !
+               !   I thank all the many contributors to lsof over the   !
+               !   many years (20+?) I have been distributing lsof      !
+               !   versions 1, 2, 3 and 4.                              !
+               !                                                        !
+               !   Vic Abell <abe@purdue.edu>                           !
+               !                                                        !
+               !!!NOTE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+               Taught the Configure script to create a dummy opt_random.h
+               for FreeBSD systems whose <sys/random.h> includes it.
+
+               Added support for the FreeBSD ZFUSE file system.
+
+               Corrected the quoting in a Darwin putchar() statement in the
+               dfile.c source file.  Andrew Janke <floss@apjanke.net> reported
+               my error.
+
+               Added support for the FreeBSD DTYPE_PTS file descriptor and
+               for unknown descriptors that reference the kernel's badfileops
+               operation switch.  Enabled FreeBSD 12.0 support. Tested the
+               changes on systems provided by Larry Rosenman <ler@lerctr.org>.
+
+               Enhanced -K option with the form "-K i" to direct lsof to
+               (i)gnore tasks.  A query from Rachel Kroll <rkroll@fb.com>
+               suggested this option.  Linux task reports now include both
+               process and task command names, making lsof's "-c <name>"
+               option work correctly.
+
+               Added a patch to prevent NFS blocking in Linux supplied by
+               Kristyna Streitova <kstreitova@suse.com>.
+
+               Installed a FreeBSD patch that prevents examining a TCP state
+               structure during a race condition.  The patch was supplied by
+               Bryan Drewery <bdrewery@FreeBSD.org>.
+
+               Updated FreeBSD for new UFS inode structure that lacks an i_dev
+               member in the most recent 12.0-CURRENT.  Larry Rosenman
+               <ler@lerctr.org> reported the problem and provided a test
+               system.
+
+               Added "#define KLD_MODULE" to dlsof.h and dnode2.c to prevent
+               <machine/cpuconf.h> from generating an "ARM_NARCH is 0" error.
+               This is needed so lsof can access kernel structures.  Larry
+               Rosenman supplied the addition.
+
+               Added recognition of the FreeBSD 11 file system name "nullfs".
+               Jamie Landeg-Jones <jamie@catflap.org> supplied the fix.
+
+               Added a patch from Larry Rosenman <ler@lerctr.org> that is
+               needed on FreeBSD 12 so the lsof compilation can obtain the
+               inpcb and tcpcb structures from their respective header files.
+
+               Updated FreeBSD dmnt.c for the ino64 changes.
+
+               Inserted a patch for Solaris 12.x to avoid compilation errors
+               from <sys/aio_req.h>, based on information provided by Jorn
+               Clausen <joern.clausen@uni-bielefeld.de>.  Jorn tested the
+               patch.
+
+               Added performance enhancement that uses the FreeBSD closefrom()
+               and dup2() C library functions when available.  The enhancement
+               was supplied by Conrad Meyer <cem@freebsd.org>.
+
+               Corrected FreeBSD lsof's gathering of ZFS file device numbers.
+
+               Updated lsof test library for FreeBSD.
+
+               Updated socket optons information collection from the socket
+               structure per changes supplied by Gleb Smirnoff
+               <glebius@FreeBSD.org>.
+
+               Added patch to dlsof.h that avoids a _KERNEL conflict with
+               bzero.  Mateusz Guzik <mjguzik@gmail.com> supplied the patch.
+
+               Corrected test library to handle 64 bit FreeBSD device numbers.
+
+               Added #defines for FreeBSD 12, src r324225, from Gleb Smirnoff
+               <glebius@FreeBSD.org>.
+
+               Incorporated Linux pseudoterminal endpoint processing (+|-E)
+               provided by Masatake YAMATO <yamato@redhat.com> with access to
+               test systems provided by Peter Schiffer <pschiffe@redhat.com>.
+
+               Corrected Linux command extraction for commands that include
+               parentheses -- e.g., "(sd-pam)".
+
+4.91           March 26, 2018
+
+               A bug has been reported in the PTY endpoint processing of
+               Linux lsof 4.90 by Peter Wu <peter@lekensteyn.nl>, making it
+               necessary for me to release another revision of lsof.
+
+               This revision applies two fixes that correct the Linux PTY
+               endpoint processing bug. Masatake YAMATO <yamato@redhat.com>
+               supplied the fixes.
+
+4.92           July 14, 2018
+               THIS IS A FREEBSD-ONLY DISTRIBUTION!
+
+               Fixes Configure script section that creates the FreeBSD
+               lockf_owner.h header file; fixes <string.h> conflicts with
+               FreeBSD kernel header files. Mateusz Gusik supplied part of
+               the fix.
+
+               Released lsof to GitHub with Purdue releases documented in
+               support/GitHub-release.
+
+
+4.92.1         May 6, 2019
+
+               !!!NOTE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+               !                                                        !
+               !  The maintainership is switched from Vic to lsof-org   !
+               !  at GitHub team officially.                            !
+               !  We thank Vic for working on lsof over the years.      !
+               !                                                        !
+               !  lsof-org at GitHub team (https://github.com/lsof-org) !
+               !!!NOTE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+               This is just for testing "Release" feature of GitHub.
+               Many documentations are not updated yet.
+               URLs in -v output and -h output are updated.
+
+4.93.0         May 7, 2019
+
+               [freebsd] Made FreeBSD 13 adjustment.
+               [darwin] Fix a typo causing a build error.
+               Fix a potential memory leak.
+               [linux] use tirpc for rpc if libc doesn't provide rpc.h.
+               Fix a typo in man page.
+               [linux] fix memory leaks detected by valgrind about unix
+               endpoint information.
+               Update the description about -fg and -fG options on linux.
+
+4.93.1         May 7, 2019
+
+               Fix a broken symbolic link.
+
+4.93.2         May 8, 2019
+
+               Update the version number embedded in lsof executable.
+
+4.94.0         November 11, 2020
+
+               (All changes in this version are ported from
+               lsof-org/lsof-linux repository at GitHub).
+
+               Introduced a new test harness. The harness can run
+               test cases specific to a dialect. It is designed for
+               running test cases on CI environment like Travis-CI.
+               However, it is runnable locally with following command
+               line:
+                       $ ./check.sh DIALECT
+               after making lsof executable.
+
+
+               [linux] Fixed a bug +|-E options output for pipe.
+               If two processes use the same fd number for a pipe
+               connecting them, the option didn't print the
+               information about it.
+
+
+               [linux] Fixed a bug +|-E options output for PTY.
+               If two processes use the same fd number for a PTY
+               connecting them, the option didn't print the
+               information about it.
+
+
+               [linux] Fixed a bug +|-E options output for PTY.
+               The code for detecting a slave device was incorrect.
+
+
+               [linux] Fixed a potential bug +|-E options output for
+               PTY. A structure field for the feature was not
+               initialized.
+
+
+               [linux] Added a code for decoding O_PATH flag in +fg
+               option.
+
+
+               [linux] Added a code for decoding O_CLOEXEC flag as CX
+               in +fg option.
+
+
+               [linux] Added a code for decoding O_TMPFILE flag as
+               TMPF in +fg option.
+
+
+               [linux] Added Linux display of INET socket endpoint
+               information with +|-E option. The option handles
+               INET sockets using IPC.
+
+
+               [linux] Added support for POSIX MQ of Linux
+               implementation.  A POSIX message queue (MQ) is
+               represented in a fd on Linux.  lsof reported it as a
+               regular file. lsof with this change reports it as a
+               file with PSXMQ type if mqueue file system is mounted.
+
+
+               [linux] Added Linux display of POSIX message queue
+               endpoint information with +|-E option. mqueue file system
+               must be mounted to display the information.
+
+
+               [linux] Added Linux display of INET6 socket endpoint
+               information with +|-E option. The option handles
+               INET6 sockets using IPC.
+
+
+               [FreeBSD] update to include <sys/_lock.h> on recent -CURRENT
+               since it is no longer implicitly included via header pollution.
+
+
+               [linux] Added Linux display of eventfd endpoint information
+               with +|-E option. The option handles eventfd using IPC.
+
+
+               [FreeBSD] include <stdbool.h> for recent change requiring
+               refcount(9).
+
+
+               Enhanced -r option. With `c<N>' specifier, lsof can stop itself
+               when the number of iterations reaches at <N>.
+
+
+               [linux] Fixed accessing an uninitialized local variable.
+               Detected by valgrind.
+
+
+               [linux] fix a crash when printing the endpoint for unaccepted
+               unix socket with +E option.
+               This closes the github issue #74 reported by @jolmg.
+
+
+               [linux] abort execution when failing in memory allocation for
+               socket private data.
+
+
+               [linux] decode the name of DCCP socket type.
+
+
+               [linux] decode more netlink protocol numbers (RDMA, CRYPTO, and
+               SMC).
+
+
+               [linux] print the connection state of unix domain socket
+               Lsof can print the state of TCP socket like:
+
+                        nc      22247 yamato    3u  IPv4 471409      0t0        TCP localhost:38802->localhost:9999 (ESTABLISHED)
+
+               This change exnteds this feature to support unix domain sockets.
+               LISTEN, UNCONNECTED, CONNECTING, CONNECTED, DISCONNECTING,
+               and UNKNOWN can be taken as a state.
+               An example of output:
+
+                        evince    17333  yamato    1u  unix 0x0000000054183795      0t0  89141 type=STREAM (CONNECTED)
+
+               This feature is enabled by default.
+               To turn off printing state information, use -T option.
+
+               Don't display command usage even when a file (or directory) listed
+               in command line doesn't exist.
+               This closes the github issue #90 reported by @rowlap.
+
+
+               [FreeBSD] merge all the FreeBSD specific fixes from the FreeBSD sysutils/lsof port
+
+
+               [linux] allow reproducible builds
+               In a reproducible build all varied information is removed.  This
+               change does so, by checking if the standard SOURCE_DATE_EPOCH
+               variable is set.  If it is, we are attempting a reproducible build
+               and will strip varying information.
+               About the standard, see https://reproducible-builds.org/specs/source-date-epoch/
+               Provided in github pull request #93 by @T4cC0re.
+
+
+
+               [freebsd] update for r363214
+               - no user visible changes
+
+
+               Added the way to include (or exclude) all numbered file descriptors
+               in -d option. "fd" is a pseudo file descriptor name for the purpose.
+               See the following output on Linux; lsof doesn't print cwd, rtd, txt,
+               and mem files.
+
+                 # ./lsof -p $$ -a -d fd
+                 COMMAND    PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
+                 bash    866421 root    0u   CHR  136,1      0t0    4 /dev/pts/1
+                 bash    866421 root    1u   CHR  136,1      0t0    4 /dev/pts/1
+                 bash    866421 root    2u   CHR  136,1      0t0    4 /dev/pts/1
+                 bash    866421 root  255u   CHR  136,1      0t0    4 /dev/pts/1
+
+
+
+               docs: fixed minor grammatical error in instructions in Customize file
+               The change is provided by @hardikpnsp.
+
+
+               man page: improve phrasing and add examples
+               The change is provided by Martin D Kealey.
+
+
+               man page: improve explanation of -t implying -w
+               The change is provided by Martin D Kealey.
+
+
+               test cases, [linux]: fix tests for large inode-numbers (i >= 2^32)
+               The change is provided by Henry Peteet.
+
+
+               [linux] handle ffff:ffff in ipv6 addr correctly
+               The listen address and port of an AF_INET6 socket were not display if
+               the socket listened at an ipv6 address including ffff:ffff.
+
+               Here is a command session demonstrating the bug:
+
+                   # ip -6 addr add abcd:ef10:ffff:ffff:ffff:ffff:ffff:ff62 dev lo
+                   # nc -6      -l  abcd:ef10:ffff:ffff:ffff:ffff:ffff:ff62 8888 &
+                   [1] 6762
+                   # ./lsof -p 6762 -a -d fd -P -n
+                   COMMAND  PID   USER   FD   TYPE DEVICE SIZE/OFF    NODE NAME
+                   nc      6762 yamato    0u   CHR  136,6      0t0       9 /dev/pts/6
+                   nc      6762 yamato    1u   CHR  136,6      0t0       9 /dev/pts/6
+                   nc      6762 yamato    2u   CHR  136,6      0t0       9 /dev/pts/6
+                   nc      6762 yamato    3u  sock    0,9      0t0 5833594 protocol: TCPv6
+
+               The last line should be:
+
+                   nc      6762 yamato    3u  IPv6 5833594      0t0  TCP [abcd:ef10:ffff:ffff:ffff:ffff:ffff:ff62]:8888 (LISTEN)
+
+               The original code decoding an ipv6 address uses UINT32_MAX constant
+               incorrect way.
+
+               @zhrf2020 reported this bug in #102.
+               @zhrf2020 provided the initial version of fix, #109.
+
+
+               man page,[linux]: enumerate abbreviated flags printed with '+f g' option
+
+
+               Make -Fo option work
+               -Fo option is for printing file offset. For regular files,
+               the option didn't work.
+
+               Here is a command session demonstrating the fix:
+
+                   # ./lsof -Fo -o0| grep ^o | sort | uniq -c
+                   90586 o0t0
+                      87 o0t101
+                      84 o0t103
+               ...
+               @JustAnotherArchivist reported this bug in #118.
+
+
+               man page: fix definition of the `o` field on programmatic output
+               The change is provided by @JustAnotherArchivist who reported
+               the original issue in #118.
+
+
+               [linux]: show the pid monitored by a pidfd
+               With this change, lsof prints pidfd in the following form:
+
+                   [pidfd:%d]
+
+               where %d represents the pid monitored by the pidfd.
+
+               Example output:
+
+                   # ./lsof -p 12573 -p 12710 | grep pidfd
+                   dbus-brok 12573  jet   11u  a_inode               0,13         0     13312 [pidfd:12575]
+                   dbus-brok 12710  jet   10u  a_inode               0,13         0     13312 [pidfd:12711]
+
+               fd 11 of pid 12573 monitors pid 12575.
+               fd 10 of pid 12710 monitors pid 12711.
+               This change closed #116.
+
+
+               Don't select the file descriptor field by default.
+               The version 4.88 introduced the change for selecting the file
+               descriptor field by default. However, the change is not
+               suitable for users who wants to print only PID field.
+               @po5857 suggests the use case and the way to improve the man page.
+
+
+               [linux]: enumerate fds monitored by an eventpoll fd
+               With this change, lsof prints an eventpoll fd in the following form:
+
+                   [eventpoll:<fd0>,<fd1>,...,<fdn>...]
+
+               Here fdX is a file descriptor monitored by the eventpoll fd.
+               If an eventpoll fd monitors too many file descriptors, lsof
+               truncates the list of fds. "..." at the end of list implies
+               the truncation.
+
+               Example output:
+
+                       # sudo ./lsof -p 1 -a -d 10,11,12
+                       COMMAND PID USER   FD      TYPE DEVICE SIZE/OFF  NODE NAME
+                       systemd   1 root   10u  a_inode   0,13        0 11624 [eventpoll:11,12]
+                       systemd   1 root   11r      REG    0,4        0 17680 /proc/1/mountinfo
+                       systemd   1 root   12r  a_inode   0,13        0 11624 inotify
+
+               systemd monitors fd 11 and fd 12 via eventpoll fd 10.
+
+
+               [linux]: implement "make check"
+               The target runs check.bash.
+
+4.95.0         April 28, 2022
+
+               [n+obsd] fix syntax error
+               Corrected end of comment.
+               This change closes #138.
+               @albert-github reported this issue in #138,
+               and provided the fix in #140
+
+
+               Don't ignore failures in test/Makefile
+               Tobias Geerinckx-Rice <me@tobias.gr> provides the fix.
+
+
+               Update perl scripts for the past few decades of progress
+               Generally, perl is available on base systems - people who are manually
+               installing perl into /usr/local/bin are the exception rather than the
+               rule. In addition, Perl 5 was release in 1994, so Perl 4 isn't relevant
+               any more. We've also standardized on the .pl extension, rather than
+               .perl5 or whatever.
+               Provided by @dilinger (Andres Salomon) in #149.
+               A commit in the pull request includes work of Nicholas Bamber.
+
+
+               Drop LSOF_CCDATE across all dialects to ensure reproducible builds
+               Simplify things for reproducible builds by just getting rid of
+               the embedded date/time string. With LSOF_CCDATE gone, keeping
+               SOURCE_DATE_EPOCH around doesn't make much sense, so drop that as
+               well. Folks doing reproducible builds should still override the
+               LSOF_HOST, LSOF_LOGNAME, LSOF_SYSINFO, and LSOF_USER variables (as
+               they were previously doing before SOURCE_DATE_EPOCH).
+               Provided by @dilinger (Andres Salomon) in #150.
+
+
+               [FreeBSD] get the ISO9660 filesystem working again
+               The ISO9660 filesystem broke starting with FreeBSD 7 due to the header
+               location changing. Fix the header search path to get it to be detected
+               again. Fix the header inclusion order. Also add the new way of finding
+               dev_t on more recent FreeBSD versions.
+               Provided by Damjan Jovanovic in #151.
+
+
+               [FreeBSD] add support for msdosfs on FreeBSD
+               Provided by Damjan Jovanovic in #151.
+
+
+               Fix FD field description.
+               In 811dc78 the output format was changed to not printf the `f`
+               field by default, however the field description in `lsof_fields.h`,
+               as seen in `-F?` output still included the `(always selected)` text.
+               Provided by @algorythmic (Grisha Levit) in #158.
+
+
+               Adjust alignment of buffer passed to stat().
+               The original code passes char[] buffer to stat(). This can be cause
+               a SIGBUS. #160 reported an actual crash on armv7a + glibc-2.33 platform.
+               See also https://sourceware.org/bugzilla/show_bug.cgi?id=27993.
+               Reported by @10ne1 in #160.
+
+
+               Clean up source code and documentats.
+               - remove trailing whitespace,
+               - fix some issues in scripts found through shellcheck, and
+               - fix spelling
+               Provided by @a1346054 in #163.
+
+
+               man page: fix hyphen issues
+               Properly use '-' and '\-' in the man page, ensuring that users
+               can cut & paste commandline options without issue. Original
+               patch from Raoul Gunnar Borenius <borenius@dfn.de>, and
+               submitted/expanded by @dilinger (Andres Salomon) in #168.
+
+
+
+               [FreeBSD] update for FreeBSD 13 & 14, and various internal changes
+               submitted by @DmitryAndric & @emaste.
+
+
+               [FreeBSD] remove various old FreeBSD versions from support
+               submitted by @emaste
+
+
+               [FreeBSD] configure: suggest variable to set if FreeBSD sys not
+               found
+               submitted by @emaste
+
+               [FreeBSD] Use user mode APIs on FreeBSD
+               Extensively changes the FreeBSD dialect to use user mode APIs
+               (sysctls and libutil's kinfo_getfile()), only falling back to kvm
+               access when it's available and required for certain features. lsof can
+               now run as an ordinary user, though not all processes may be visible
+               and some features will be absent without kvm access (file lock state,
+               kqueue info, some pipe details, nullfs details).
+               This also fixes numerous long standing issues: file lock state is now
+               visible on all filesystems, the cwd, root dir, jail dir, text file and
+               controlling TTY are now visible, filenames are shown for all
+               filesystems, procfs is working again and supports file searches even
+               when there are multiple procfs mountpoints, the code is shorter,
+               cleaner and should need much less future maintenance.
+               It builds and works from FreeBSD 9.0 to 14-CURRENT, though older
+               versions have less features (eg. 12 doesn't provide socket buffer
+               usage, 11 also lacks TCP flags and state).
+               Provided by @DamjanJovanovic in #184.
+
+
+               Fix broken LSOF_CFLAGS_OVERRIDE.
+               Provided by Fabrice Fontaine in #172.
+
+
+               [linux] Remove sysvlegacy function.
+               Provided by Fabrice Fontaine in #195.
+
+
+               [linux] use close_range instead of calling close repeatedly
+               At the starting up, lsof closes its file descriptors greater
+               than 2 by calling close(2) repeatedly. As reported in #186,
+               it can take long time. Linux 5.9 introduced close_range(2).
+               The new system call can close multiple file descriptors faster.
+               @qianzhangyl reported the original issue (#186).
+
+
+               Add -Q option for adjusting exit status when failed to find a
+               search item (#129)
+               In the original code, lsof returned 1 when it failed to find a
+               search item. With the new option, lsof returns 0 in the case.
+
+
+               Document -Q option in manpage/00QUICKSTART, and adjust -h
+               output by @dilinger (Andres Salomon) in #129.
+
+
+               Improve readability of complex adverbial clause by adding a
+               comma.
+               Provided by Danny Fowler in #156.
+
+4.96.0         September 16, 2022
+
+               [linux] fix hash functions used for finding local tcp/udp IPCs
+               There were typos in the code calculating hash values. The typos might
+               break the flatness of hashtables where the endpoint information about
+               locally used tcp/udp was stored. Theoretically, this fix may improve
+               the performance of lsof with [+|-]E option.
+               Inspired by the issue #206 reported by Tomasz Kłoczko (@kloczek).
+
+
+               Show copyright notice in --version output.
+
+
+               [linux] compile with -Wall option
+
+
+               [linux] Avoid some easy collissions for udp/udp6 sockets when hashing
+               
+               
+               [linux] Changing the number of ipcbuckets to 4096
+
+
+               [darwin] fix build with -fno-common (Cfp redefinition)
+               gcc-10 and llvm-11 changed the default from -fcommon to -fno-common:
+               https://gcc.gnu.org/PR85678
+               As a result build fails as:
+
+                       duplicate symbol '_Cfp' in: ddev.o dfile.o
+
+               Cfp is already explicitly defined in dstore.c. The change turns
+               header definition into declaration.
+               Provided by Sergei Trofimovich (@trofi) in #221. The same fix is
+               applied to libproc backend by Jiajie Chen (@jiegec) in #226.
+
+
+               [linux] Make build reproducible by checking SOURCE_DATE_EPOCH
+               and considering LSOF_{HOST,LOGNAME,SYSINFO,USER} as "none" when
+               it is set.
+               Provided by Danilo Spinella in #217
+
+
+               [darwin] remove /usr/include prefix from include for Darwin 19+
+               The /usr/include path is missing since macOS Catalina.
+               Fixes issue #234.
+               Provided by Jiajie Chen in #235
+
+
+               [linux] obtain correct information of memory-mapped file.
+               Provided by Teng Hu in #239
+
+
+               [FreeBSD] configure: suggest variable to set if FreeBSD sys not 
+               found
+               Submitted by @emaste
+
+
+               Updated 00FAQ with lookup to open files via mountpoint
+               Provided by Jacob Chapman in #240
+
+
+                [FreeBSD] modernize API usage and remove legacy FreeBSD releases
+                Contributor DamjanJovanovic (#184) Ed Maste (#250, #251, #252),
+                Warner Losh (#253)
+
+4.96.1         September 16, 2022
+
+                [FreeBSD] Unconditionally define HASKQUEUE (mjguzik) 
+
+4.96.2         September 16, 2022
+
+                [FreeBSD] fix FreeBSD < 14
+
+4.96.3         September 16, 2022
+
+                [FreeBSD] Fix kqueue compat for releases < 14
+
+4.96.4         October 18, 2022
+
+               [FreeBSD] sys/files.h no longer needs _KERNEL defined to 
+                include it (bsdimp #256)
+
+
+               docs: Describe fd number truncation in output (#261)
+
+4.96.5         December 26, 2022
+
+               [linux] Use correct scanf/printf format for uint64_t (#266)
+
+
+               Avoid C89-only constructs in Configure (#265)
+
+
+               [freebsd] add <sys/callout.h> for recent changes
+
+4.97.0         January 17, 2023
+
+               [decof/du/tru64] Remove support because the os is no longer
+               updated for more than 10 years
+
+
+               [openstep/nextstep] Remove support because the os is no longer
+               updated for more than 20 years
+
+
+               Add experimental build system based on Autotools (#270)
+
+
+               Fixed LTsock testing on darwin (#272)
+
+
+               Remove NEW and OLD folders (#6)
+
+
+               Fix FreeBSD testcases (#271)
+
+
+               Rewrite documentation and publish at https://lsof.readthedocs.io/
+
+4.98.0         January 22, 2023
+
+               Fix two potential null pointer access bug when gethostbyname2()
+               returns an empty address list
+
+
+               Add support for older automake versions (on e.g. CentOS 7)
+
+
+               Migrate testing scripts and programs to autotools
+
+
+               Extend CI to build on more Linux distros
+
+
+               [linux] Fix handling of empty command name, closing #246.
+               Add test from #246, where lsof returns stale command name when the
+               command name is empty. If getting command name failed, return
+               NULL instead of empty string
+
+
+               Add --with/without-libtirpc option to autotools-based build
+               system and automatically detect libtirpc by default
+
+
+               Add -H switch to print human readable size, e.g. 123.4K (#260)
+
+
+               [linux] Fix implicit declaration error when HASPTYEPT is undefined
+
+
+               Add support for musl libc-based Linux distros
+
+
+               Add --enable-security argument to configure to allow only the
+               root user to list all open files
+
+
+               Add --enable-no-sock-security argument to configure to allow
+               anyone to list anyone else's socket files when combined with
+               --enable-security
+
+
+               [linux] Always enable 64 bit off_t in configure.ac
+
+
+               [netbsd] Import patches from pkgsrc and port autotools-based build system to NetBSD
+
+
+               [netbsd] Fix lock status reading
+
+4.99.0         November 10, 2023
+
+               [netbsd] Get device numer of tmpfs instead of reporting zero
+
+
+               [openbsd] Rewrite OpenBSD support because OpenBSD disallows
+               kernel memory access and lsof has to switch to user mode API.
+               Currently, most features are working, but file path reporting
+               and lock status are not working for lack of kernel support.
+               As a consequence, OpenBSD dialect is separated in a new folder.
+
+
+               [darwin] Remove /dev/kmem backend because it no longer exists on
+               current macOS releases. Use libproc backend instead.
+
+               
+               [linux] Do not hard-code fd numbers in epoll test, fixing tests
+               on Void Linux
+
+
+               [freebsd] Use kf_file_nlink if provided by kernel instead of
+               stat(). This commit requires kernel with
+               https://reviews.freebsd.org/D38169. It brings back the ability
+               to list deleted files via `lsof +L1`. Closes #264.
+
+
+               [linux] Add --with-selinux configure option.
+
+
+               [solaris] Re-introduce support for recent Solaris & OpenIndiana
+               releases.
+
+
+               [darwin] Display kern ctl info, learned from apple lsof version.
+
+
+               [linux] Improve performance by using closefrom(). Closes #281.
+
+
+               [aix] Fix compilation on AIX 7.2 and add autotools build system
+               support for AIX.
+
+               [aix] Suppress warnings properly on AIX version greater than
+               5.0. Closes #187.
+               
+               Introduce alpha version of liblsof which allows users to use
+               lsof functionality via C functions instead of spawning a
+               subprocess and parsing the output. This version may contain BUGs
+               and memory leaks, and the API may change before it stablizes.
+
+4.99.1         December  16, 2023
+
+               Fix compilation error when HASIPv6 is not defined. (@chenrui333)
+
+               Add configure option --disable-liblsof to disable installation
+               of liblsof. (@subnut, #300)
+
+               [freebsd] fix segfault from fs info (FreeBSD bug 267760)
+
+4.99.2         December  16, 2023
+
+               fix version file
+
+4.99.3         December  16, 2023
+
+               fix 00DIST file <space> -> tabs
+
+Vic Abell <abe@purdue.edu>
+July 14, 2018
+
+The lsof-org team at GitHub
+December 28, 2022
diff --git a/00FAQ b/00FAQ
new file mode 100644 (file)
index 0000000..c626f65
--- /dev/null
+++ b/00FAQ
@@ -0,0 +1,7781 @@
+
+               Frequently Asked Questions about lsof
+
+**********************************************************************
+| The latest release of lsof is always available via anonymous ftp   |
+| from lsof.itap.purdue.edu.  Look in pub/lsof.README for its        |
+| location.                                                          |
+**********************************************************************
+
+______________________________________________________________________
+
+This file contains frequently asked questions about lsof and answers
+to them.
+
+Vic Abell <abe@purdue.edu>
+October 13, 2014
+______________________________________________________________________
+
+Table of Contents:
+
+1.0    General Concepts
+1.1    Lsof -- what is it?
+1.2    Where do I get lsof?
+1.2.1  Are there mirror sites?
+1.2.2  Are lsof executables available?
+1.2.3  How do I check the validity of an lsof distribution?
+1.2.4  Why can't I get the sum(1) result reported in
+       README.lsof_<revision>?
+1.2.5  Why won't gpg accept the lsof-signing PGP public key?
+1.3    Where can I get more lsof documentation?
+1.4    How do I report an lsof bug?
+1.5    Where can I get the lsof FAQ?
+1.5.1  How timely is the on-line FAQ?
+1.6    Is there a test suite?
+1.7    Is lsof vulnerable to the standard I/O descriptor attack?
+1.8    Can I alter lsof's make(1) behavior?
+1.9    Is there an lsof license?
+1.10   Language locale support
+1.10.1 Does lsof support language locales?  How do I use the support?
+1.10.2 Does lsof support wide characters in language locales?
+1.11   Are any files in the lsof distribution copyrighted?
+1.12   Are there other lsof-related resources?
+1.13   What does the "WARNING: unsupported dialect or version" mean?
+
+2.0    Lsof Ports
+2.1    What ports exist?
+2.2    What about a new port?
+2.2.1  User-contributed Ports
+2.3    Why isn't there an AT&T SVR4 port?
+2.4    Why isn't there an SGI IRIX port?
+2.5    Why does lsof's Configure script report "WARNING: unsupported
+       dialect or version"?
+
+3.0    Lsof Problems
+3.1    Configuration Problems
+3.1.1  Why can't Configure determine the UNIX dialect version?
+3.2    Compilation Problems
+3.2.1  Why does the compiler complain about missing header files?
+3.2.2   Why does gcc complain about the contents of header files
+       distributed by the system's vendor?
+3.2.3  Other header file problems
+3.3    Why doesn't lsof report full path names?
+3.3.1  Why do lsof -r reports show different path names?
+3.3.2  Why does lsof report the wrong path names?
+3.3.3  Why doesn't lsof report path names for unlinked (rm'd) files?
+3.3.4  Why doesn't lsof report the "correct" hard linked file path
+       name?
+3.3.5  When will lsof report path names for deleted files?
+3.4    Why is lsof so slow?
+3.5    Why doesn't lsof's setgid or setuid permission work?
+3.6    Does lsof have security problems?
+3.7    Will lsof show remote hosts using files via NFS?
+3.8    Why doesn't lsof report locks held on NFS files?
+3.8.1  Why does lsof report a one byte lock on byte zero as a full
+       file lock?
+3.9    Why does lsof report different values for open files on the
+       same file system (the automounter phenomenon)?
+3.10   Why don't lsof and netstat output match?
+3.10.1 Why can't lsof find accesses to some TCP and UDP ports?
+3.11   Why does lsof update the device cache file?
+3.12   Why doesn't lsof report state for UDP socket files?
+3.13   I am editing a file with vi; why doesn't lsof find the file?
+3.14   Why doesn't lsof report TCP/TPI window and queue sizes for my
+       dialect?
+3.14.1 Why doesn't lsof report socket options, socket states, and TCP
+       flags and values for my dialect?
+3.14.2 Why doesn't lsof report the partial listen queue connection
+       count for my dialect?
+3.15   What does "no more information" in the NAME column mean?
+3.16   Why doesn't lsof find a process that ps finds?
+3.17   Why doesn't -V report a search failure?
+3.18   Portmap problems
+3.18.1 Why isn't a name displayed for the portmap registration?
+3.18.2 How can I display only portmap registrations?
+3.18.3 Why doesn't lsof report portmap registrations for some ports?
+3.18.4 Why doesn't lsof report portmap registrations for some Solaris
+       versions?
+3.19   Why is `lsof | wc` bigger than my system's open file limit?
+3.20   Why doesn't lsof report file offset (position)?
+3.20.1 What does lsof report for size when the file doesn't really have
+       one?
+3.21   Problems with path name arguments
+3.21.1 How do I ask lsof to search a file system?
+3.21.2 Why doesn't lsof find all the open files in a file system?
+3.21.3 Why does the lsof exit code report it didn't find open files
+       when some files were listed?
+3.21.4 Why won't lsof find all the open files in a directory?
+3.21.5 Why are the +D and +d options so slow?
+3.21.6 Why do the +D and +d options produce warning messages?
+3.22   Why can't my C compiler find the rpcent structure definition?
+3.23   Why doesn't lsof report fully on file "foo" on UNIX dialect
+       "bar?"
+3.24   Why do I get a complaint when I execute lsof that some library
+       file can't be found?
+3.25   Why does lsof complain it can't open files?
+3.26   Why does lsof warn "compiled for x ... y; this is z."?
+3.27   How can I disable the kernel identity check?
+3.28   Why don't ps(1) and lsof agree on the owner of a process?
+3.29   Why doesn't lsof find an open socket file whose connection
+       state is past CLOSE_WAIT?
+3.30   Why don't machine.h definitions work when the surrounding
+       comments are removed?
+3.31   What do "can't read inpcb at 0x...", "no protocol control
+       block", "no PCB, CANTSENDMORE, CANTRCVMORE", etc. mean?
+3.32   What do the "unknown file system type" warnings mean?
+3.33   Installation
+3.33.1 How do I install lsof?
+3.33.2 How do I install a common lsof when I have machines that
+       need differently constructed lsof binaries?
+3.34   Why do lsof 4.53 and above reject device cache files built
+       by earlier lsof revisions?
+3.35   What do "like block special" and "like character special" mean
+       in the NAME column?
+3.36   Why does an lsof make fail because of undefined symbols?
+3.37   Command Regular Expressions (REs)
+3.37.1 What are basic and extended regular expressions?
+3.37.2 Why can't I put a slash in a command regular expression?
+3.37.3 Why does lsof say my command regular expression wasn't found?
+3.38   Why doesn't lsof report on shared memory segments?
+3.39   Why does lsof report two instances of itself?
+3.40   Why does lsof report '\n' in device cache file error messages?
+3.41   Kernel Symbol and Address Problems
+3.41.1 What does "lsof: WARNING: name cache hash size length error: 0"
+       mean?
+3.41.2 Why does lsof produce "garbage" output?
+3.42    Why does lsof report open files when run as super user that
+       it doesn't report when run with lesser privileges?
+3.43   Test Suite Problems
+3.43.1 Errors all tests can report:
+3.43.1.1 Why do tests complain "ERROR!!!  can't execute ../lsof"?
+3.43.1.2 Why do tests complain "ERROR!!! can't find ..." a file?
+3.43.1.3 Why do some tests fail to compile?
+3.43.1.4 Why do some tests always fail?
+3.43.1.5 Why does the test suite say it hasn't been validated on
+        my dialect?
+3.43.1.6 Why do the tests complain they can't stat() or open()
+        /dev/mem or /dev/kmem?
+3.43.2 LTbigf test issues
+3.43.2.1 Why does the LTbigf test say that the dialect doesn't
+        support large files?
+3.43.2.2 Why does LTbigf complain about operations on its config.LTbigf*
+        file?
+3.43.2.3 Why does LTbigf warn that lsof doesn't return file offsets?
+3.43.3 Why does the LTbasic test complain "ERROR!!! lsof this ..."
+       and "ERROR!!!  lsof that ..."?
+3.43.4 LTnfs test issues
+3.43.4.1 Why does the LTnfs test complain "couldn't find NFS file ..."?
+3.43.5 LTnlink test issues
+3.43.5.1 Why does the LTnlink test complain that its test file is on
+        an NFS file system?
+3.43.5.2 Why does LTnlink delay and report "waiting for link count
+        update: ..."?
+3.43.5.3 Why does LTnlink fail because of an unlink error?
+3.43.6 LTdnlc test issues
+3.43.6.1 Why won't the LTdnlc test run?
+3.43.6.2 What does the LTdnlc test mean by "... <path> found: 100.00%"?
+3.43.6.3 Why does the DNLC test fail?
+3.43.7 Why hasn't the test suite been qualified for 64 bit HP-UX
+       11 when lsof is compiled with gcc?
+3.43.8 LTszoff test issues
+3.43.8.1 Why does LTszoff warn that lsof doesn't return file offsets?
+3.43.9 LTlock test issues
+3.44   File descriptor list (the ``-d'' option) problems
+3.44.1 Why does lsof reject a ``-d'' FD list?
+3.44.2 Why are file descriptors other than those in my FD list
+       reported?
+3.45   How can I supply device numbers for inaccessible NFS file
+       systems?
+3.46   Why won't lsof find open files on over-mounted file systems?
+3.47   What can be done when lsof reports no more space?
+3.48   What if the lsof build encounters ar and ld problems?
+3.49   Why does lsof -i report an open socket file for a process, but
+       lsof -p on that process' ID report nothing?
+
+4.0    AIX Problems
+4.1    What is the Stale Segment ID bug and why is -X needed?
+4.1.1  Stale Segment ID APAR
+4.2    Gcc Work-around for AIX 4.1x
+4.3    Gcc and AIX 4.2
+4.4    Why won't lsof's Configure allow the use of gcc for AIX
+       below 4.1?
+4.5    What is an AIX SMT file type?
+4.6    Why does AIX lsof start so slowly?
+4.7    Why does exec complain it can't find libc.a[shr.o]?
+4.8    What does lsof mean when it says, "TCP no PCB, CANTSENDMORE,
+       CANTRCVMORE" in a socket file's NAME column?
+4.9    When the -X option is used on AIX 4.3.3, why does lsof disable
+       it, saying "WARNING: user struct mismatch; -X option disabled?"
+4.10   Why doesn't the -X option work on my AIX 5L or 5.[123] system?
+4.11   Why doesn't /usr/bin/oslevel report the correct AIX version?
+4.11.1 Why doesn't /usr/bin/oslevel report the correct AIX version
+       on AIX 5.1?
+4.12    Why does lsof for AIX 5.1 or above Power architecture
+       complain about kernel bit size?
+4.13   What can't gcc be used to compile lsof on the ia64 architecture
+       for AIX 5 and above?
+4.14   Why does lsof get a segmentation fault when compiled with gcc
+       for a 64 bit Power architecture AIX 5.1 kernel?
+4.15   Why does lsof ignore AFS on my AIX system?
+4.16   Why does lsof report "system paging space is low" and exit?
+4.17   Why does lsof have compilation and execution problems on AIX
+       5.3 above maintenance level 1?
+
+5.0    Apple Darwin Problems
+5.1    What do /dev/kmem-based and libproc-based mean?
+5.2    /dev/kmem-based Apple Darwin Questions
+5.2.1  Why does Configure ask for a path to the Darwin XNU kernel
+       header files?
+5.2.1.1        Why does Configure complain that Darwin XNU kernel header
+       files are missing?
+5.2.2  Why doesn't Apple Darwin lsof report text file information?
+5.2.3  Why doesn't Apple Darwin lsof support IPv6?
+5.2.4  Why does lsof complain about a mismatch between the release
+       for which lsof was compiled and the booted Mac OS X release?
+5.2.5  Why does lsof for Apple Darwin 8 and higher report
+       "stat(...): ..." in the NAME column?
+5.2.6  What are the limitations of Apple Darwin lsof link count
+       reporting?
+5.2.7  Why does Apple Darwin report process group IDs incorrectly?"ayy
+5.3    Libproc-based Apple Darwin Questions
+
+6.0    BSD/OS BSDI Problems
+6.0.5  Statement of deprecation
+
+8.0    FreeBSD Problems
+8.1    Why doesn't lsof report on open kernfs files?
+8.2    Why doesn't lsof work on my FreeBSD system?
+8.3    Why doesn't lsof work on the RELEASE version of CURRENT?
+8.4    Why can't kvm_open() can't find some file?
+8.5    FreeBSD ZFS Problems
+8.5.1  Why does FreeBSD lsof report "WARNING: no ZFS support has been
+8.6    Why can't Configure create lsof_owner.h for FreeBSD 6 and above?
+8.6.1  Why are there lockf structure compiler errors for FreeBSD 6.0
+       and higher lsof?
+8.6.2  Why don't /usr/src/sys/sys/lockf.h and /usr/include/sys/lockf.h
+       match?
+8.7    FreeBSD and clang
+8.7.1  Why does clang complain about VOP_FSYNC?
+
+9.0    HP-UX Problems
+9.1    What do /dev/kmem-based and PSTAT-based mean?
+9.2    /dev/kmem-based HP-UX lsof Questions
+9.2.1  Why doesn't a /dev/kmem-based HP-UX lsof compilation use -O?
+9.2.2  Why doesn't the /dev/kmem-based CCITT support work under 10.x?
+9.2.3  Why can't /dev/kmem-based lsof be compiled with `cc -Aa` or
+       `gcc -ansi` under HP-UX 10.x?
+9.2.4  Why does /dev/kmem-based lsof complain about no C compiler?
+9.2.5  Why does Configure complain about q4 for /dev/kmem-based lsof
+       for HP-UX 11?
+9.2.6  When compiling /dev/kmem-based lsof for HP-UX 11 what do the
+       "aCC runtime: ERROR..." messages mean?
+9.2.7  Why doesn't /dev/kmem-based lsof for HP-UX 11 report VxFS file
+       link counts, node numbers, and sizes correctly?
+9.2.8  Why can't /dev/kmem-based lsof be built with gcc for 64 bit
+       HP-UX 11?
+9.2.8.1        How can I acquire a gcc for building lsof for 64 bit HP-UX 11?
+9.2.9   Why does /dev/kmem-based lsof for HP-UX 11 report "unknown file
+       system type" for VxFS files?
+9.2.10 Why does the ANSI-C compiler complain about comments in HP-UX
+       11 header files?
+9.2.11  Why does dnode1.c cause the HP-UX 11 compiler to complain that
+       <sys/fs/vx_inode.h> is missing or incorrect?
+9.3    PSTAT-based HP-UX lsof Questions
+9.3.1  Why does PSTAT-based lsof complain about pst_static and
+       other PSTAT structures?
+9.3.2  Why does PSTAT-based lsof complain it can't read pst_*
+       structures?
+9.3.3  Why does PSTAT-based lsof rebuild the device cache file
+       after each reboot?
+9.3.4  Why doesn't PSTAT-based lsof report TCP addresses for
+       telnetd's open socket files?
+9.3.5   Why does PSTAT-based lsof cause an HP-UX 11.11 kernel panic?
+9.3.6   Why doesn't PSTAT-based lsof report a CWD that is on a loopback
+       (LOFS) file system?
+9.3.7  Why do some swinstall packages for PSTAT-based HP-UX 11.11
+       packages complain about setgid and setuid bits?
+9.3.8  Why won't the bundled C compiler build PSTAT-based lsof for
+       PA-RISC HP-UX 11.23?
+9.3.9  Why won't gcc build PSTAT-based lsof for PA-RISC HP-UX 11.23?
+9.3.10 Why does PSTAT-based lsof complain, "FATAL: pst_stream_size
+       should be: 672; is 72" on HP-UX 11.11 and above?
+9.4    Why won't the HP-UX depot install?
+
+10.0   Linux Problems
+10.1   What do /dev/kmem-based and /proc-based lsof mean?
+10.2   /proc-based Linux lsof Questions
+10.2.1 Why doesn't /proc-based lsof report file offsets (positions)?
+10.2.2 Why does /proc-based lsof report "can't identify protocol" for
+       some socket files?
+10.2.3 Why does /proc-based lsof warn about unsupported formats?
+10.2.4 Why does /proc-based lsof report "(deleted)" after a path name?
+10.2.5 Why doesn't /proc-based lsof report full open file information
+       for all processes?
+10.2.6 Why won't Customize offer to change HASDCACHE or WARNDEVACCESS
+       for /proc-based lsof?
+10.2.7 /proc-based lsof Linux NFS questions
+10.2.7.1 Why can't lsof find files on an accessible NFS file system?
+10.2.7.2 Why can't lsof find files on an inaccessible NFS file system?
+10.2.8 Why doesn't /proc-based Linux lsof report socket options and
+       values, socket state flags, and TCP options and values?
+10.2.9 Does /proc-based Linux lsof use a device cache?
+10.2.10        Why doesn't /proc-based Linux lsof report any or all file structure
+       values for its +fcfgGn option?
+10.3   Special Linux file types
+10.3.1 Why is ``DEL'' reported as a Linux file type?
+10.3.2 Why is ``unknown'' reported as a Linux file type?
+10.4   Linux ``mem'' Entry Problems
+10.4.1  What do ``path dev=xxx'' and ``path inode=yyy'' mean in the
+       NAME column of Linux ``mem'' file types?
+10.4.2  Why is neither link count nor size reported for some Linux
+       ``DEL'' and ``mem'' file types?
+10.5   Special Linux NAME column messages
+10.5.1  What does ``(stat: xxx)'' mean in the NAME column of Linux
+       files?
+10.5.2  What does ``(readlink: xxx)'' mean in the NAME column of
+       Linux files?
+10.6   Why is ``NOFD'' reported as a Linux file type?
+10.7    Why does Linux lsof report a NAME column value that begins with
+       ``/proc''?
+10.8   Linux /proc/net/tcp* and /proc/net/udp* issues
+10.8.1 Why use the Linux -X option?
+10.8.2 Why does lsof say ``-i is useless when -X is specified''?
+10.8.3 Why does lsof say ``can't identify protocol (-X specified)''?
+
+11.0   NetBSD Problems
+11.1   Why doesn't lsof report on open kernfs files?
+11.2   Why doesn't lsof report on open files on: file descriptor
+       file systems; /proc file systems; 9660 (CD-ROM) file systems;
+       MS-DOS (floppy disk) file systems; or kernel file systems?
+11.3    Why does lsof produce confusing results for nullfs file
+       systems?
+11.4   NetBSD header file problems
+11.4.1 Why can't the compiler find some NetBSD header files?
+11.4.2 Why does NetBSD lsof produce incorrect output?
+11.5   Why isn't lsof feature xxx enabled for NetBSD?
+
+13.0   OpenBSD Problems
+13.1   Why doesn't lsof support kernfs on my OpenBSD system?
+13.2   Will lsof work on OpenBSD on non-x86-based architectures?
+13.3   <sys/pipe.h> problems
+13.3.1 Why does the compiler claim nbpg isn't defined?
+13.3.2 What value should I assign to nbpg?
+13.4   Why doesn't lsof report on open MS-DOS file system (floppy
+       disk) files?
+13.5   Why isn't lsof feature xxx enabled for OpenBSD?
+
+14.0   Output problems
+14.1   Why do the lsof column sizes change?
+14.2   Why does the offset have ``0t' and ``0x'' prefixes?
+14.3   What are the values printed in the FILE_FLAG column
+       and why is 0x<value> sometimes included?
+14.3.1 Why doesn't lsof display FILE_FLAG values for my dialect?
+14.4   Network Addresses
+14.4.1 Why does lsof's -n option cause IPv4 addresses, mapped to
+       IPv6, to be displayed in IPv6 notation?
+14.5   Why does lsof output \x, ^x, or \xnn for characters
+       sometimes?
+14.5.1  Why is space considered a non-printable character in command
+       names?
+14.6   Why doesn't lsof print all the characters of a command name?
+14.7   Why does lsof reject some -c command names, saying their lengths
+       are "> what system provides (nn)"?
+14.8   Why does lsof sometimes print TYPE numbers instead of names?
+14.9   Marker line format problems
+14.9.1 Why won't lsof accept a marker line format?
+14.9.2 Why does lsof reject the NL (%n) marker line format?
+14.10  How are protocol state name exclusion and inclusion used?
+14.10.1        Why doesn't my dialect support state name exclusion and inclusion?
+
+15.0   Pyramid Version Problems
+15.0.5 Statement of deprecation
+
+16.0   SCO Problems
+16.1   SCO OpenServer Problems
+16.1.1 How can I avoid segmentation faults when compiling lsof?
+16.1.2 Where is libsocket.a?
+16.1.3 Why do I get "warning C4200" messages when I compile lsof?
+16.2   SCO|Caldera UnixWare Problems
+16.2.1  Why doesn't lsof compile on my UnixWare 7.1.1 or above
+       system?
+16.2.2 Why does lsof complain about node_self() on my UnixWare
+       7.1.1 or above system?
+16.2.3  Why does UnixWare 7.1.1 or above complain about -lcluster,
+       node_self(), or libcluster.so?
+16.2.4  Why does UnixWare 7.1.1 or above lsof complain it can't
+       read the kernel name list?
+16.2.5  Why doesn't lsof report link count, node number, and size
+       for some UnixWare 7.1.1 or above CFS files?
+16.2.6  Why doesn't lsof report open files on all UnixWare 7.1.1
+       NonStop Cluster (NSC) nodes?
+16.2.7 Why doesn't lsof report the UnixWare 7.1.1 NonStop Cluster
+       (NSC) node a process is using?
+16.2.8  Why does the compiler complain about missing UnixWare 2.1[.x]
+       header files?
+
+17.0   Sun Problems
+17.0.5 Statement of deprecation
+17.1   My Sun gcc-compiled lsof doesn't work -- why?
+17.2   How can I make lsof compile with gcc under Solaris 2.[456],
+       2.5.1, 7, 8 or 9?
+17.3   Why does Solaris Sun C complain about system header files?
+17.4   Why doesn't lsof work under my Solaris 2.4 system?
+17.5   Where are the Solaris header files?
+17.6   Where is the Solaris /usr/src/uts/<architecture>/sys/machparam.h?
+17.7   Why does Solaris lsof say ``can't read proc table''?
+17.8   Why does Solaris lsof complain about a bad cached clone device?
+17.9   Why doesn't Solaris make generate .o files?
+17.10  Why does lsof report some Solaris 2.3 and 2.4 lock types as `N'?
+17.11  Why does lsof Configure say "WARNING: no cc in ..."?
+17.12  Solaris 7, 8 and 9 Problems
+17.12.1        Why does lsof say the compiler isn't adequate for Solaris
+       7, 8 or 9?
+17.12.2 Why does Solaris 7, 8 or 9 lsof say "FATAL: lsof was compiled
+       for..."?
+17.12.3        How do I build lsof for a 64 bit Solaris kernel under a 32
+       bit Solaris kernel?
+17.12.4        How do I install lsof for Solaris 7, 8 or 9?
+17.12.5 Why does my Solaris 7, 8 or 9 system say it cannot execute
+       lsof?
+17.12.6 What gcc will produce 64 bit Solaris 7, 8 and 9 executables?
+17.12.7 Why does lsof on my Solaris 7, 8 or 9 system say, "can't
+       read namelist from /dev/ksyms?"
+17.13  Solaris and COMMON
+17.13.1        What does COMMON mean in the NAME column for a Solaris VCHR
+       file?
+17.13.2        Why does a COMMON Solaris VCHR file sometimes seem to have an
+       incorrect minor device number?
+17.14  Why don't lsof and Solaris pfiles reports always match?
+17.15  Why does lsof say, "kvm_open(namelist=default, core=default):
+       Permission denied?"
+17.16  Why is lsof slow on my busy Solaris UFS file system?
+17.17  Why is lsof so slow on my Solaris 8 or 9 system?
+17.18  Solaris and VxFS
+17.18.1        Why doesn't lsof support VxFS 3.4 on Solaris 2.6, and above?
+17.18.2        Why does lsof report "vx_inode: vxfsu_get_ioffsets error"
+       for open Solaris 2.6 and above VxFS 3.4 and above files?
+17.18.3        Why does Solaris Configure claim there is no VxFS library?
+17.18.4        Why doesn't Solaris lsof report VxFS path name components?
+17.18.5        Why does Solaris 10 lsof report scrambled VxFS paths?
+17.19  Large file problems
+17.19.1        Why does lsof complain it can't stat(2) a Solaris 2.5.1
+       large file?
+17.20   Why does lsof get a segmentation fault on 64 bit Solaris
+       8 using NIS+?
+17.21  Will lsof crash the Solaris kernel?
+17.22   Why does lsof on Solaris 7, 8, or 9 report a kvm_open()
+       failure?
+17.23  Solaris and SAM-FS
+17.23.1        Why does Solaris lsof report "(limited SAM-FS info)"?
+17.23.2        Why can't lsof locate named SAM-FS files?
+17.24  Lsof and Solaris 10 zones
+17.24.1        How can I make lsof list the Solaris zone?
+17.24.2        Why doesn't lsof work in a Solaris 10 zone?
+17.24.3 Why does lsof complain it can't stat() Solaris 10 zone file
+       systems?
+17.25  Solaris 10 problems
+17.25.1 Why does Solaris 10 lsof sometimes report the wrong path name?
+17.25.2 Why does Solaris 10 lsof sometimes report only the mounted-on
+       directory and device?
+17.25.3 What does "(deleted)" mean in the NAME column of a Solaris 10
+       open file?
+17.25.4 What does "(?)" mean in the NAME column of a Solaris 10 open
+       file?
+17.26  Solaris contract file problems
+17.26.1        Why doesn't lsof report size, link count and node number for
+       Solaris 10 contract files?
+17.26.2 Why can't lsof locate a Solaris 10 contract file by path name?
+17.27  Solaris 10 and above ZFS probblems
+17.27.1        Why does Configure warn that ZFS support is not enabled?
+17.28  Problems with Solaris 9 and above
+17.28.1        Why does the compiler complain about lgrp_root on Solaris 9
+       and above?
+
+18.0   Lsof Features
+18.1   Why doesn't lsof doesn't report on /proc entries on my
+       system?
+18.2   How do I disable the device cache file feature or alter
+       it's behavior?
+18.2.1 What's the risk with a perverted device cache file?
+18.2.2 How do I put the full host name in a personal device cache file
+       path?
+18.2.3 How do I put the personal device cache file in /tmp?
+18.3   Why doesn't lsof know about AFS files on my favorite dialect?
+18.3.1 Why doesn't lsof report node numbers for all AFS volume files,
+       or how do I reveal dynamic module addresses to lsof?
+______________________________________________________________________
+
+
+1.0    General Concepts
+
+1.1    Lsof -- what is it?
+
+       Lsof is a UNIX-specific tool.  Its name stands for LiSt
+       Open Files, and it does just that.  It lists information
+       about files that are open by the processes running on a
+       UNIX system.
+
+       See the lsof man page, the 00DIST file, the 00QUICKSTART
+       file, and the 00README file of the lsof distribution for
+       more information.
+
+1.2    Where do I get lsof?
+
+       Lsof is available via anonymous ftp from lsof.itap.purdue.edu.
+       Look in the pub/tools/unix/lsof sub-directory.
+
+           ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof
+
+       Bzip2'd, compressed and gzip'd tar files with GPG certificates
+       are available.
+
+1.2.1  Are there mirror sites?
+
+       On March 21, 2013 these sites appeared to have the latest
+       lsof revision:
+
+       ftp://ftp.fu-berlin.de/pub/unix/tools/lsof
+       ftp://sunsite.ualberta.ca/pub/Mirror/lsof
+       http://www.mirrorservice.org/sites/lsof.itap.purdue.edu/pub/tools/unix/lsof/
+       ftp://ftp.mirrorservice.org/sites/lsof.itap.purdue.edu/pub/tools/unix/lsof/
+       rsync://rsync.mirrorservice.org/lsof.itap.purdue.edu/pub/tools/unix/lsof/
+
+1.2.2  Are lsof executables available?
+
+       Some lsof executables are available in the subdirectory
+       tree pub/tools/unix/lsof/binaries  These are neither guaranteed
+       to be current nor cover every dialect and machine architecture.
+
+       I don't recommend you use pre-compiled lsof binaries; I
+       recommend you obtain the sources and build your own binary.
+       Even if you're a Sun user without a Sun C compiler, you
+       can use gcc to compile lsof.
+
+       If you must use a binary file, please be conscious of the
+       security and configuration implications in using an executable
+       of unknown or different origin.  The lsof binaries are
+       accompanied by GPG certificates.  Please use them!
+
+       Three additional cautions apply to executables:
+
+       1.  Don't try to use an lsof executable, compiled for one
+           version of a UNIX dialect, on another.  Patches can
+           make the dialect version different.
+
+       2.  If you want to use an lsof binary on multiple systems,
+           they must be running the same dialect OS version and
+           have the same patches and feature support.
+
+1.2.3  How do I check the validity of an lsof distribution?
+
+       There are two ways to check the validity of an lsof
+       distribution:
+
+       1.  Follow the instructions in the CHECKSUMS_<revision>
+           file found with the lsof distribution.
+
+           Checking with GPG is the best method.
+
+       2.  Follow the instructions in the "Security" section of the
+           README.lsof_<revision> file found inside the lsof
+           distribution.
+
+           Again, checking with GPG is the best method.
+
+1.2.4  Why can't I get the sum(1) result reported in
+       README.lsof_<revision>?
+
+       The "Security" section of the README.lsof_<revision> file found
+       inside the lsof distribution gives md5, sum, and GPG certificate
+       information.
+
+       The simplest, the sum(1) signature, seems to be the trickiest.
+       That's because there are different sum(1) methods, BSD systems
+       usually have cksum(1) instead of sum(1), and different systems
+       compute the block size value differently.
+
+       First, the lsof sum results are computed with the old,
+       "alternate" algorithm.  On newer systems, you can use sum's
+       "-r" option to get that computation result.
+
+       Second, on BSD systems you usually must use cksum(1) instead
+       of sum(1), because they have no sum(1).  To tell cksum(1)
+       to use the old, "alternate" algorithm, use its "-o1" option.
+
+       Third, the second value that sum reports, the block count, may
+       be computed differently on different systems -- usually block
+       size is considered to be 512 or 1,024.  The lsof block counts
+       were computed on a system with a sum(1) option that considers
+       block size to be 512.  The BSD system cksum(1) -o1 option
+       considers block size to be 1,024.  If your sum(1) or cksum(1)
+       doesn't report a block count that matches the sum(1) signature
+       given in README.lsof_<revision>, check its man page to see what
+       block size it uses, then adjust its reported block count
+       appropriately.
+
+1.2.5  Why won't gpg accept the lsof-signing PGP public key?
+
+       An older PGP key that once signed lsof distributions is
+       included in lsof revisions prior to 4.70.  The PGP key is
+       indeed my key, but is incompatible with GPG.  It was created
+       about ten years ago and is still acceptable to PGP versions
+       2.6.2 through 6.5.2.
+
+       Lsof revisions 4.70 and above are signed with a copy of my PGP
+       key that has been made acceptable for use with GPG by importing
+       it under GPG's "--allow-non-selfsigned-uid" option.
+
+       You can find my GPG compatible key in lsof revisions 4.70 and
+       above and at:
+
+           ftp://lsof.itap.purdue.edu/pub/Victor_A_Abell.gpg
+
+       If you have an older lsof revision with my PGP key, there are
+       two possible ways to use it:
+
+       * Use it with a PGP version from 2.6.2 through 6.5.2.
+
+       * Use GPG's "--allow-non-selfsigned-uid" option when you
+         import my PGP key into your GPG key ring.
+
+         $ gpg --allow-non-selfsigned-uid --import Victor_A_Abell.pgp
+
+1.3    Where can I get more lsof documentation?
+
+       A significant set of documentation may be found in the lsof
+       distribution (See "Where can I get lsof?).  There is a
+       manual page, copious documentation in files whose names
+       begin with 00, and a copy of this FAQ in the file 00FAQ
+       (perhaps slightly less recent than this file if you're
+       reading it via a web browser.)
+
+       Two URLs provide some documentation that appears in the
+       lsof distribution:
+
+       FAQ: ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/FAQ
+
+       man page: ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/lsof_man
+
+1.4    How do I report an lsof bug?
+
+       If you believe you have discovered a bug in lsof, you can report it to
+       https://github.com/lsof-org/lsof.  Do NOT report lsof bugs to the UNIX
+       dialect vendor.
+
+       Before you send a bug report, please read the "Bug Reports" section of
+       the 00README file of the lsof distribution.  It lists the steps you
+       should take before and when reporting a suspected bug.
+
+1.5    Where can I get the lsof FAQ?
+
+       This lsof FAQ is available in the file 00FAQ in the lsof
+       distribution and at the URL:
+
+           ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/FAQ
+
+1.5.1  How timely is the on-line FAQ?
+
+       The on-line FAQ is sometimes too timely.  :-)
+
+       I update it as soon as new information is available.   That may
+       include information about support that won't appear in the lsof
+       source distribution until the next revision.  If you encounter
+       something like that, please send me e-mail at <abe@purdue.edu>.  I
+       may be able to point you at a pre-release distribution that contains
+       the support of interest.  Make sure "lsof" appears in the "Subject:"
+       line so my e-mail filter won't classify your letter as Spam.
+
+1.6    Is there a test suite?
+
+       Yes, as of lsof revision 4.63 there's an automated lsof
+       test suite in the tests/ sub-directory of the lsof top-level
+       directory.
+
+       More information on using the test suite, what it does,
+       how to use it and how to configure it may be found in the
+       00TEST file of the lsof distribution.  That file also
+       explains where the test suite has been tested.
+
+       Frequently asked questions about the test suite will be
+       asked and answered here in the FAQ.  (See "Test Suite
+       Problems.")
+
+       After lsof has been configured with the Configure script,
+       lsof can be made and tested with:
+
+           $ make
+           $ cd tests
+           $ make
+
+       Under normal conditions -- i.e., unless the lsof tree has
+       been cleaned or purged severely -- all tests or individual
+       tests may be run by:
+
+           $ cd test
+           $ make
+        or
+           $ <run a single test>       (See 00TEST.)
+
+1.7    Is lsof vulnerable to the standard I/O descriptor attack?
+
+       Lsof revisions 4.63 and above are not vulnerable.
+
+       Lsof revisions 4.62 and below are vulnerable, but no damage
+       scenarios have so far been demonstrated.
+
+       The standard I/O descriptor attack is a local programmed
+       assault on setuid and setgid programs that tricks them into
+       opening a sensitive file with write access on a standard
+       descriptor, usually stderr (2), and writing error messages
+       to stderr.  If the attacker can control the content of the
+       error message, the attacker may gain elevated privileges.
+
+       The attack was first described in Pine Internet Advisory
+       PINE-CERT-20020401, available at:
+
+           http://www.pine.nl/advisories/pine-cert-20020401.txt
+
+       If you are using an lsof revision below 4.63, you should
+       remove any setuid or setgid permissions you might have
+       given its executable.  Then you should upgrade to lsof
+       revision 4.63.
+
+1.8    Can I alter lsof's make(1) behavior?
+
+       Yes.  There are at least two ways to do that.
+
+       You can put replacements for lsof Makefile strings in your
+       environment.  If you specify the -e make option, make will
+       give environment variable values precedence over strings
+       from the Makefile.  For example, to change the compiler
+       string CC from the environment, you might do this with the
+       Bourne shell:
+
+           $ CC=foobar; export CC
+           $ make -e
+
+       You can also replace lsof Makefile strings in the make
+       command invocation.  Here's the previous example done that
+       way:
+
+           $ make CC=foobar
+
+       Changing the CFGF, CFGL, and DEBUG strings used in lsof
+       Makefiles, either from the environment or from the make
+       invocation, can significantly alter lsof make(1) behavior.
+       I commonly use DEBUG to change the -O option to -g so I
+       can build an lsof executable for debugging -- e.g.,
+
+           $ make DEBUG=-g
+
+       (Look for DEBUG in this FAQ for other examples of its use.)
+
+       Consult the Makefiles to see what CFGL, CFGL, and other
+       lsof Makefile strings contain, and to see what influence
+       their alteration might have on lsof make(1) behavior.
+
+1.9    Is there an lsof license?
+
+       No.
+
+       The only restriction on the use or redistribution of lsof
+       is contained in this copyright statement, found in every
+       lsof source file.  (The copyright year in or format of the
+       notice may vary slightly.)
+
+       /*
+        * Copyright 2002 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.
+        */
+
+1.10   Language locale support
+
+1.10.1 Does lsof support language locales?  How do I use the support?
+
+       Most UNIX dialect versions of lsof support 8 bit language
+       locale characters -- e.g., the ability to print 8 bit
+       characters that have accents and other marks over them.
+
+       See the answer to the "Does lsof support wide characters in
+       language locales?" question for information on when lsof's
+       language locale support covers characters wider than 8 bits.
+
+       To see if lsof supports language locales for your dialect, look
+       in the dialect's machine.h header file for the HASSETLOCALE
+       definition.  If it is present and not disabled, then lsof has
+       language locale support for the dialect.
+
+       To enable lsof's language locale support, you must specify in a
+       locale environment variable (e.g., LANG) a language locale
+       known to your system that supports the printing of marked
+       characters -- e.g, en_US.  (On some dialects locale(1) may be
+       used to list the known language locales.)
+
+       Note that LANG=C and LANG=POSIX are NOT language locales that
+       support the printing of marked characters.
+
+       If the language locale doesn't support the printing of marked
+       characters, lsof's OUTPUT of them follows the rules for
+       non-printable characters described in the OUTPUT section of
+       lsof(8).
+
+       Consult your dialect's setlocale(3) man page for the names of
+       environment variables other than LANG  -- e.g., LC_ALL,
+       LC_TYPE, etc. -- which may be used to define language locales.
+
+1.10.2 Does lsof support wide characters in language locales?
+
+       When lsof's language locale support is enabled with the
+       HASSETLOCALE definition, for selected dialects lsof will also
+       print wide characters (e.g., from UTF-8) when iswprint(3)
+       reports them to be printable.
+
+       Wide character support is available when HASWIDECHAR is defined
+       in a dialect's machine.h header file.  As of this writing on
+       July 22, 2004, the following dialect versions have wide character
+       support:
+
+           AIX >= 4.3.2
+           Apple Darwin >= 7.3.0
+           FreeBSD >= 5.2
+           HP-UX >= 11.00
+           /proc-based Linux
+           NetBSD >= 1.6
+           SCO OpenServer >= 5.0.6
+           Solaris >= 2.6
+           Tru64 UNIX 5.1
+
+1.11   Are any files in the lsof distribution copyrighted?
+
+       Yes.  Most files carry the copyright of the Purdue Research
+       Foundation and may be redistributed under the terms that
+       accompany the copyright notice.  Those terms may also be found
+       in the answer to the question, "Is there an lsof license?")
+
+       A few files carry other copyright notices.  Some are BSD
+       notices and they explain the terms under which they are
+       included in the lsof distribution.
+
+       Those that carry vendor copyright notices have been reproduced
+       in their original or modified forms with permission from the
+       copyright owners.  That permission is indicated in the README
+       files that accompany the files.
+
+1.12   Are there other lsof-related resources?
+
+       There are other resources available, connected to lsof.  Among
+       them are FreeBSD and Linux packages whose products use lsof and
+       two particularly interesting resources.
+
+       The two interesting resources are a Gnome Tool Kit (GTK) GUI
+       for lsof and a Perl wrapper module.
+
+       The GTK GUI is called Glsof and was developed by Gnele.  It can
+       be found at:
+
+           http://www.sourceforge.net
+
+       The Perl wrapper module by Marc Beyer can be found at:
+
+           http://search.cpan.org/dist/Unix-Lsof/
+
+1.13   What does the "WARNING: unsupported dialect or version" mean?
+
+       The lsof configure script issues that message for UNIX dialects
+       or their versions where I have been unable to test the current
+       revision of lsof.  The message doesn't mean that lsof won't
+       work, just that I have no direct evidence that it will.
+
+       If the COnfigure script succeeds, except for the warning, try
+       compiling) lsof.  If that succeeds, try the lsof test suite.
+
+2.0    Lsof Ports
+
+2.1    What ports exist?
+
+       The pub/lsof.README file carries the latest port information:
+
+           AIX 5.[23] and 5.3
+           FreeBSD 4.9 and 6.4 for x86-based systems
+           FreeBSD 8.[234], 9.0, 10.0 and 11.0 for AMD64-based systems
+           Linux 2.1.72 and above for x86-based systems
+           Solaris 9, 10 and 11
+
+       In the above list the only UNIX dialects present are ones for
+       which I test the current lsof revision.  Lsof may still support
+       unlisted dialect versions -- e.g., HP-UX 10.20, Solaris 7, etc.
+       -- but I don't have access to systems where I could test lsof
+       on them, so I can't claim lsof works on them. If your dialect
+       isn't in the list, you should try building lsof on it anyway.
+
+       Lsof version 4 predecessors, versions 2 and 3, may support older
+       version of some dialects.  Contact me via e-mail at <abe@purdue.edu>
+       if you're interested in their distributions.  Make sure "lsof"
+       appears in the "Subject:" line so my e-mail filter won't classify
+       your letter as Spam.
+
+2.2    What about a new port?
+
+       The 00PORTING file in the distribution gives hints on doing
+       a port.  I will consider doing a port in exchange for
+       permanent access to a test host.  I require permanent access
+       so I can test new lsof revisions, because I will not offer
+       distributions of dialect ports I cannot upgrade and test.
+
+2.2.1  User-contributed Ports
+
+       Sometimes I receive contributions of ports of lsof to
+       systems where I can't test future revisions of lsof.  Hence,
+       I don't incorporate these contributions into my lsof
+       distribution.
+
+       However, I do make descriptions of these contributions
+       available.  You can find them in the 00INDEX and README
+       files at:
+
+           ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/contrib
+
+       Consult the 00INDEX file in the contrib/ directory for a
+       list of the available contributions and consult README
+       there for information on how to obtain them.
+
+2.3    Why isn't there an AT&T SVR4 port?
+
+       I haven't produced an AT&T SVR4 port because I haven't seen
+       a UNIX dialect that is strictly limited to the AT&T System
+       V, Release 4 source code.  Every one I have seen is a
+       derivative with vendor additions.
+
+       The vendor additions are significant to lsof because they
+       affect the internal kernel structures with which lsof does
+       business.  While some vendor derivatives of SVR4 are similar,
+       each one I have encounted so far has been different enough
+       from its siblings to require special source code.
+
+       If you're interested in an SVR4 version of lsof, here are
+       some existing ports you might consider:
+
+           DC/OSx (This obsolete port is only available upon
+                   special request.)
+           Reliant UNIX (This obsolete port is only available
+                         upon special request.)
+           SCO|Caldera UnixWare (This is the most likely choice.)
+           Solaris
+
+2.4    Why isn't there an SGI IRIX port?
+
+       Lsof support for IRIX was terminated at lsof revision 4.36,
+       because it had become increasingly difficult for me to
+       obtain information on the IRIX kernel structures lsof needs
+       to access.
+
+       At IRIX 6.5 I decided the obstacles were too large for me
+       to overcome, and I stopped supporting lsof on IRIX.  I have
+       sources to the last revision of lsof (4.36) for IRIX, but
+       that version of lsof does not work on IRIX 6.5 and is
+       vulnerable to the standard I/O descriptor attack.  (See
+       the "Is lsof vulnerable to the standard I/O descriptor
+       attack?" Q&A for more information.) Contact me to discuss
+       obtaining those sources.
+
+       If you wish to pursue the issue, don't contact me, contact
+       SGI.  This case was opened with SGI on the subject:
+
+           Case ID:    0982584
+           Category: Unix
+           Priority: 30-Moderate Impact
+
+           Problem Summary:
+           kernel structure header files needed for continued lsof
+           support
+
+           Problem Description:
+           Email In  07/17/98 19:09:23
+
+2.5    Why does lsof's Configure script report "WARNING: unsupported
+       dialect or version"?
+
+       Lsof's Configure script issues this message when it encounters
+       a dialect or its version that lsof once supported, but no
+       longer does.  Usually I drop support for a dialect or version
+       when I can no longer test lsof on it.
+
+       However, it's worth trying to compile and use lsof.  Be sure to
+       run the test suite.  (See the answer to the "Is there a test
+       suite?  question for information on the test suite.)
+
+       If you have problems with an unsupported dialect or version,
+       contact me via e-mail at <abe@purdue.edu> and I may be able to help.
+       Make sure "lsof" appears in the "Subject:" line so my e-mail filter
+       won't classify your letter as Spam.
+
+
+3.0    Lsof Problems
+
+3.1    Configuration Problems
+
+3.1.1  Why can't Configure determine the UNIX dialect version?
+
+       The lsof Configure script uses UNIX shell commands, often in a
+       command pipeline, to determine the UNIX dialect version.
+       (Consult the dialect stanza in Configure to determine which
+       commands are used.)  If Configure can't determine the dialect
+       version, probably one of the commands is not behaving as
+       Configure expects.
+
+       Symptoms of the failure include Configure warning messages and
+       incorrect version definitions in the Makefile CFLAGS.
+
+       If you suspect that the lsof Configure script is failing to
+       determine the dialect version correctly, try running the
+       commands from Configure stanza one at a time.  That will
+       usually reveal the source of the problem.  Be particularly
+       mindful that the PATH environment variable can cause commands
+       to be executed from non-standard directories.
+
+       If you can't determine the source of the problem, there is a
+       work-around.  You can supply the UNIX dialect version in the
+       LSOF_VSTR environment variable.  Use Configure as a guide to
+       forming what it expects in LSOF_VSTR.  There is also some
+       information on  LSOF_VSTR in the 00XCONFIG documentation file
+       of the lsof distribution.
+
+3.2    Compilation Problems
+
+3.2.1  Why does the compiler complain about missing header files?
+
+       When you use make to build lsof, the compiler may complain
+       that it can't find header files -- e.g.,
+
+           $ make
+           (cd lib; make DEBUG="-O" CFGF="-DAIXA=0 -DAIXV=4330 \
+           -DLSOF_VSTR=\"4.3.3.0\"")
+           gcc  -DAIXA=0 -DAIXV=4330 -DLSOF_VSTR="4.3.3.0" -O \
+           -c ckkv.c
+           In file included from ckkv.c:33: ../machine.h:70: \
+           sys/types.h: A file or directory in the path name \
+           does not exist. \
+
+       That type of complaint doesn't represent an lsof problem.
+       It represents a problem with a missing system header file
+       that probably should be found in /usr/include or in the
+       system source tree.
+
+       As a first step try using find(1) to locate the problem
+       header file.  If it's a system header file and can't be
+       found, here are some possible causes:
+
+       1. The file set, RPM or package containing the header files
+          has not been installed.  Instructions for doing that
+          are specific to the UNIX dialect and beyond the scope
+          of this document.
+
+       2. If the compiler is gcc, the private gcc header files:
+
+          * May not have been installed;
+
+          * May have been installed incorrectly;
+
+          * May not have been updated properly after the last
+            compiler or system update;
+
+          * Ones from a previous installation may not have been
+            removed.
+
+          A path leading to the gcc private header files can be
+          found with `gcc -v`.  Consult the gcc documentation for
+          instructions on proper installation of the private gcc
+          header files.
+
+       3. On some dialects -- e.g., FreeBSD, NetBSD, OpenBSD --
+          lsof may need to use header files that are located in
+          the system source tree -- /sys or /usr/src/sys, for
+          example.  Make sure the system source tree has been
+          installed.
+
+3.2.2   Why does gcc complain about the contents of header files
+       distributed by the system's vendor?
+
+       When you use make to build lsof and gcc to compile it, gcc
+       may complain that it finds errors in system header files
+       -- e.g.,
+
+           $ make
+           (cd lib; make DEBUG="-O" CFGF="-Dsolaris=80000 \
+            -DHASPR_GWINDOWS -m64 -DHASIPv6 -DHAS_VSOCK \
+            -DLSOF_VSTR=\"5.8\"")
+            gcc -Dsolaris=80000  -DHASPR_GWINDOWS -m64 -DHASIPv6 \
+            -DHAS_VSOCK -DLSOF_VSTR="5.8"  -O  -c  dvch.c
+           In file included from /usr/include/sys/proc.h:31, \
+             from /homes/abe/gnu/gcc-3.2.1/lib/gcc-lib/sparcv9-sun-solaris2/ \
+            3.2.1/include/sys/user.h:267, from /usr/include/kvm.h:13, \
+            from ../dlsof.h:53, from ../lsof.h:172, from dvch.c:43: \
+            /homes/abe/gnu/gcc-3.2.1/lib/gcc-lib/sparcv9-sun-solaris2/\
+             3.2.1/include/sys/task.h:59: parse error before "uint_t"
+
+       Errors like the above are most likely not problems in the
+       system's header files, but in the private copies of them
+       that were created when gcc was made or installed.  Note
+       the presense of
+       ".../gcc-3.2.1/lib/gcc-lib/sparcv9-sun-solaris2/3.2.1/include/..."
+       in the paths for user.h and task.h.  It indicates both
+       header files are gcc-specific.
+
+       To solve errors like this requires comparing the header
+       files in the vendor's /usr/include tree to the gcc-specific
+       ones in gcc's private gcc-lib/.../include tree.  It may be
+       necessary to regenerate gcc-specific header files, correct
+       them or remove them.  See the gcc distribution for the
+       appropriate tools.
+
+       A possible temporary work-around is to direct gcc to use
+       the vendor's header files instead of its temporary ones by
+       declaring -I/usr/include in the compilation flags.
+
+3.2.3  Other header file problems
+
+       Don't overlook any vendor tools that might validate the
+       vendor header files installed on the system  -- e.g., the
+       Solaris pkgchk tool can be used to check the header files
+       that were installed from the SUNWhea package.
+
+       For other header file problems contact me at <abe@purdue.edu>.
+       Please follow the reporting guidelines in the "How do I
+       report an lsof bug?" section of this FAQ.
+
+3.3    Why doesn't lsof report full path names?
+
+       Lsof reports the full path name when it is specified as a
+       search argument for open files that match the argument.
+       However, if the argument is a file system mounted-on
+       directory, and lsof finds additional path name components
+       from the kernel name cache, it will report them.
+
+       Lsof reports path name for file system types that have path
+       name lookup features -- e.g., some versions of AdvFS for
+       Digital and Tru64 UNIX.  The Linux /proc-based lsof reports
+       full path names, because the Linux /proc file system provides
+       them.  Lsof on recent builds of Solaris 10 also report full
+       path names, because those Solaris kernels record the full path
+       name in the vnode structure.
+
+       Otherwise, lsof uses the kernel name cache, where it exists
+       and can be accessed, and reports some or all path name
+       components (e.g., the sys and proc.h components of
+       /usr/include/sys/proc.h) for these dialects:
+
+               Apple Darwin
+               DC/OSx
+               FreeBSD
+               HP-UX, /dev/kmem and PSTAT based
+               Linux, /dev/kmem-based
+               NetBSD
+               OpenBSD
+               Reliant UNIX
+               SCO OpenServer
+               SCO|Caldera UnixWare
+               Solaris 2.x, 7, 8 and 9 (except for some VxFS versions;
+                                        see the "Why doesn't Solaris
+                                        lsof report VxFS path name
+                                        components?" section for more
+                                        information)
+               Solaris 10 (early builds) Tru64 UNIX
+
+       As far as I can determine, AFS path lookups don't share in
+       kernel name cache operations, so lsof can't identify open AFS
+       path name components.  Apparently Solaris VxFS versions 4 and
+       above don't share in kernel name cache operations, either, so
+       lsof can't display path name components for those open files.
+
+       Since the size of the kernel name cache is limited and the
+       cache is in constant flux, it does not always contain the names
+       of all components in an open file's path; sometimes it contains
+       none of them.
+
+       Lsof reports the file system directory name and whatever
+       components of the file's path it finds in the cache, starting
+       with the last component and working backwards through the
+       directories that contain it.  If lsof finds no path
+       components, lsof reports the file system device name instead.
+
+       When lsof does report some path components in the NAME
+       column, it prefixes them with the file system directory
+       name, followed by " -- ", followed by the components --
+       e.g., /usr -- sys/path.h for /usr/include/sys/path.h.  The
+       " -- " is omitted when lsof finds all the path name components
+       of a file's name.
+
+       The PSTAT-based HP-UX lsof relies on kernel name cache
+       contents, too, even though its information comes to lsof
+       via pstat() function calls.  Consequently, PSTAT-based
+       HP-UX lsof won't always report full paths, but may use the
+       " -- " partial path name notation, or may occasionally
+       report no path name at all but just the file system mounted-on
+       directory and device names.
+
+       Lsof can't obtain path name components from the kernel name
+       caches of the following dialects:
+
+           AIX
+
+       Only the Linux kernel records full path names in the
+       structures it maintains about open files; instead, most
+       kernels convert path names to device and node number doublets
+       and use them for subsequent file references once files have
+       been opened.
+
+       To convert the device and node number doublet into a
+       complete path name, lsof would have to start at the root
+       node (root directory) of the file system on which the node
+       resides, and search every branch for the node, building
+       possible path names along the way.  That would be a time
+       consuming operation and require access to the raw disk
+       device (usually implying setuid-root permission).
+
+       If the prospect of all that local disk activity doesn't
+       concern you, think about the cost when the device is
+       NFS-mounted.
+
+       Try using the file system mount point and node number lsof
+       reports as parameters to find -- e.g.,
+
+           $ find <mount_point> -inum <node_number> -print
+
+       and you may get an appreciation of what a file system
+       directory tree search would cost.
+
+3.3.1  Why do lsof -r reports show different path names?
+
+       When you run lsof with its repeat (``-r'') option, you may
+       notice that the extent to which it reports path names for
+       the same files may vary from cycle to cycle.  That happens
+       because other processes are making kernel calls affecting
+       the cache and causing entries to be removed from and added
+       to it.
+
+3.3.2  Why does lsof report the wrong path names?
+
+       Under some circumstances lsof may report an incorrect path
+       name component, especially for files in a rapidly changing
+       directory like /tmp.
+
+       In a rapidly changing directory, like /tmp, if the kernel
+       doesn't clear the cache entry when it removes a file, a
+       new file may be given the same keys and lead lsof to believe
+       that the old cache entry with the same keys belongs to the
+       new file.
+
+       Lsof tries to avoid this error by purging duplicate entries
+       from its copy of the kernel name cache when they have the
+       same device and inode number, but different names.
+
+       This error is less likely to occur in UNIX dialects where the
+       keys to the name cache are node address and possibly a
+       capability ID.  The Apple Darwin, Digital UNIX, FreeBSD, HP-UX,
+       NEXTSTEP, OPENSTEP, Solaris, Tru64 UNIX, and UnixWare dialects
+       use node address.  Apple Darwin, FreeBSD, NetBSD, OpenBSD,
+       Tru64 UNIX, and also use a capability ID to further identify
+       name cache entries.
+
+3.3.3  Why doesn't lsof report path names for unlinked (rm'd) files?
+
+       When lsof gets path name components from the kernel's name
+       cache, it does not report the path names of a file that has
+       been unlinked from its parent directory -- e.g., deleted via
+       rm, or the unlink() system call -- even when some process may
+       still hold the file open; lsof reports only the file system's
+       mounted-on directory and device.  That's because path name
+       components are removed from the kernel name cache when the file
+       is unlinked.
+
+       Unlinked open files are sometimes used by applications for
+       temporary, but invisible storage (i.e., ls won't show them,
+       and no other process can open them.)  However, they may
+       occasionally consume disk space to excess and cause concern
+       for a system administrator, who will be unable to locate
+       them with find, ls, du, or other tools that rely on finding
+       files by examining the directory tree.
+
+       By using lsof's +L option you can see the link count of
+       open files -- in the NLINK column.  An unlinked file will
+       have an NLINK value of zero.  By using the option +L1 you
+       can tell lsof to display only files whose link count is
+       less than one (i.e., zero).
+
+       There are some UNIX dialect-specific exceptions to lsof's
+       inability to report unlinked path names.  They are described in
+       the answer to the "When will lsof report path names for deleted
+       files?" question.
+
+3.3.4  Why doesn't lsof report the "correct" hard linked file path
+       name?
+
+       When lsof reports a rightmost path name component for a
+       file with hard links, the component may come from the
+       kernel's name cache.  Since the key which connects an open
+       file to the kernel name cache may be the same for each
+       differently named hard link, lsof may report only one name
+       for all open hard-linked files.   Sometimes that will be
+       "correct" in the eye of the beholder; sometimes it will
+       not.  Remember, the file identification keys significant
+       to the kernel are the device and node numbers, and they're
+       the same for all the hard linked names.
+
+3.3.5  When will lsof report path names for deleted files?
+
+       Lsof will report path names for deleted files for two
+       dialects:  Linux and later builds of Solaris 10.
+
+       Deleted Linux path names are reported by default and have
+       "(deleted)" at their ends.
+
+       The display of Solaris 10 deleted path names may be selected
+       with the -X option.  When selected they are also reported with
+       "(deleted)" at their ends.
+
+3.4    Why is lsof so slow?
+
+       Lsof may appear to be slow if network address to host name
+       resolution is slow.  This can happen, for example, when the
+       name server is unreachable, or when a Solaris PPP cache daemon
+       is malfunctioning.
+
+       To see if name lookup is causing lsof to be slow, turn it off
+       with the ``-n'' option.
+
+       Port service name lookup or portmap registration lookup may
+       also be causes of slow-down.  To suppress port service name
+       lookup, specify the ``-P'' option.
+
+       Lsof doesn't usually make direct portmap calls -- only when +M
+       is specified, or when HASPMAPENABLED is defined during lsof
+       construction.  (The lsof help panel, produced with `lsof -h`
+       will display the default portmap registration reporting
+       state.)  The quickest first step in checking if lsof is slow
+       because of the portmapper is to use lsof's ``-M'' option.
+
+       Lsof may be slow if UID to login name lookups are slow.
+       Suppress them with ``-l''.
+
+       On dialects where lsof uses the kernel name cache, try
+       disabling its use with ``-C''.  (You can tell if lsof uses the
+       kernel name cache by looking for ``-C'' in lsof's ``-h''
+       output.)  Of course, disabling kernel name cache use will mean
+       that lsof won't report full or partial path names, just file
+       system and character device names.
+
+       If you're just interested in the open files of one process, try
+       using the ``-p <Process-ID>'' option to limit lsof to that
+       process.  (The ``-p'' option may also be followed with a list
+       of Process-IDs.)
+
+       If you're interested in including or excluding certain
+       commands, try lsof's "-c[^]cmd" option.
+
+       If you're interested in certain Internet TCP and UDP states
+       (e.g., ESTABLISHED) or in excluding some (e.g., CLOSE_WAIT),
+       try lsof's "-s p:s" option, available where shown on the lsof
+       help output, obtained with -h or -?.  More information on it
+       may be found in the answer to the "How are protocol state name
+       exclusion and inclusion used?" question.
+
+       Your UNIX dialect may not support "-s p:s" and its associated
+       performance improvments to Internet-only file processing.  You
+       can find more information on those topics in the answer to the
+       "Why doesn't my dialect support state name exclusion and
+       inclusion?" question.
+
+       Older AIX lsof may be slow to start because of its oslevel
+       identity comparison.  (Newer AIX lsof uses uname(2).)  See the
+       "Why does AIX lsof start so slowly?" and "Why does lsof warn
+       "compiled for x ... y; this is z.?" sections for more
+       information.
+
+3.5    Why doesn't lsof's setgid or setuid permission work?
+
+       If you install lsof on an NFS file system that has been
+       mounted with the nosuid option, lsof may not be able to
+       use the setgid or setuid permission you give it, complaining
+       it can't open the kernel memory device -- e.g., /dev/kmem.
+
+       The only solution is to install lsof on a file system that
+       doesn't inhibit setgid or setuid permission.
+
+3.6    Does lsof have security problems?
+
+       I don't think so.  However, lsof does usually start with
+       setgid permission, and sometimes with setuid-root permission.
+       Any program that has setgid or setuid-root permission,
+       should always be regarded with suspicion.
+
+       Lsof drops setgid power, holding it only while it opens
+       access to kernel memory devices (e.g., /dev/kmem, /dev/mem,
+       /dev/swap).  That allows lsof to bypass the weaker security
+       of access(2) in favor of the stronger checks the kernel
+       makes when it examines the right of the lsof process to
+       open files declared with -k and -m.  Lsof also restricts
+       some device cache file naming options when it senses the
+       process has setuid-root power.
+
+       On a few dialects lsof requires setuid-root permission
+       during its full execution in order to access files in the
+       /proc file system.  These dialects include:
+
+           DC/OSx 1.1 for Pyramid systems
+           Reliant UNIX 5.4[34] for Pyramid systems
+
+       When lsof runs with setuid-root permission it severely
+       restricts all file accesses it might be asked to make with
+       its options.
+
+       The device cache file (typically .lsof_hostname in the home
+       directory of the real user ID that executes lsof) has 0600
+       modes.  (The suffix, hostname, is the first component of
+       the host's name returned by gethostname(2).)  However, even
+       when lsof runs setuid-root, it makes sure the file's
+       ownerships are changed to that of the real user and group.
+       In addition, lsof checks the file carefully before using
+       it (See the question "How do I disable the device cache
+       file feature or alter it's behavior?" for a description of
+       the checks.); discards the file if it fails the scrutiny;
+       complains about the condition of the file; then rebuilds
+       the file.
+
+       See the 00DCACHE file of the lsof distribution for more
+       information about device cache file handling and the risks
+       associated with the file.
+
+3.7    Will lsof show remote hosts using files via NFS?
+
+       No.  Remember, lsof displays open files for the processes
+       of the host on which it runs.  If the host on which lsof
+       is running is an NFS server, the remote NFS client processes
+       that are accessing files on the server leave no process
+       records on the server for lsof to examine.
+
+3.8    Why doesn't lsof report locks held on NFS files?
+
+       Generally lock information held by local processes on remote
+       NFS files is not recorded by the UNIX dialect kernel.  Hence,
+       lsof can't report it.
+
+       One exception is some patch levels of Solaris 2.3, and all
+       versions of Solaris 2.4 and above.  Lsof for those dialects
+       does report on locks held by local processes on remotely
+       mounted NFS files.
+
+3.8.1  Why does lsof report a one byte lock on byte zero as a full
+       file lock?
+
+       When a process has a lock of length one, starting at byte
+       zero, lsof can't distinguish it from a full file lock.
+       That's because most UNIX dialects represent both locks the
+       same way in their file lock (flock or eflock) structures.
+
+3.9    Why does lsof report different values for open files on the
+       same file system (the automounter phenomenon)?
+
+       On UNIX dialects where file systems may be mounted by an
+       automounter with the ``direct'' type, lsof may sometimes
+       report difference DEVICE, SIZE/OFF, INODE and NAME values
+       when asked to report files open on the file system.
+
+       This happens because some files open on the file system --
+       e.g., the current directory of a shell that changed its
+       directory to the file system as the file system's first
+       reference -- may be characterized in the kernel with
+       temporary automounter node information.  The cd doesn't
+       cause the file system to be mounted.
+
+       A subsequent reference to the file system -- e.g., an ls
+       of any place in it -- will cause the file system to be
+       mounted.  Processes with files open to the mounted file
+       system are characterized in the kernel with data that
+       reflects the mounted file system's parameters.
+
+       Unfortunately some kernels (e.g., some versions of Solaris
+       2.x) don't revisit the process that did only a change-directory
+       for the purpose of updating the data associated with the
+       open directory file.  The file continues to be characterized
+       with temporary automounter information until it does another
+       directory change, even a trivial ``cd .''.
+
+       Lsof will report on both reference types, when supplied
+       the file system name as an argument, but the data lsof
+       reports will reflect what it finds in the kernel.  For the
+       different types lsof will display different data, including
+       different major and minor device numbers in the DEVICE
+       column, different lengths in the SIZE/OFF column, different
+       node numbers in the INODE column, and slightly different
+       file system names in the NAME column.
+
+       In contrast, fuser, where available, can only report on
+       one reference type when supplied the file system name as
+       an argument.  Usually it will report on the one that is
+       associated with the mounted file system information.  If
+       the only reference type is the temporary automounter one,
+       fuser will often be silent about it.
+
+3.10   Why don't lsof and netstat output match?
+
+       Lsof and netstat output don't match because lsof reports
+       the network information it finds in open file system objects
+       -- e.g., socket files -- while netstat often gets its
+       information from separate kernel tables.
+
+       The information available to netstat may describe network
+       activities never or no longer associated with open files,
+       but necessary for proper network state machine operation.
+
+       For example, a TCP connection in the FIN_WAIT_[12] state
+       may no longer have an associated open file, because the
+       connection has been closed at the application layer and is
+       now being closed at the TCP/IP protocol layer.
+
+3.10.1 Why can't lsof find accesses to some TCP and UDP ports?
+
+       Lsof stands for LiSt Open Files.  If there is no open file
+       connected to a TCP or UDP port, lsof won't find it.  That's
+       the most common reason why lsof doesn't find a port netstat
+       might report open.
+
+       One reason I've found on some UNIX dialects is that their
+       kernels set aside TCP and UDP ports for communicating with
+       support activities, running in application layer servers
+       -- the automounter daemons, and the NFS biod and nfsd
+       daemons are examples.  Netstat may report the ports are in
+       use, but lsof doesn't.
+
+       Another reason is that netstat may also be able to report
+       a port is open on a particular dialect, because it uses a
+       source of data different from what lsof uses -- e.g.,
+       netstat might examine kernel tables or use streams messages
+       to MIB2, while lsof relies on the information it finds in
+       open file structures and their descendants.
+
+       Sometimes it's possible to search the data netstat and lsof
+       use.  For example, on Linux /proc/tcp and /proc/udp can be
+       examined.  There might an entry there for a particular
+       protocol and port, but if the line on which the port appears
+       doesn't have an inode number that matches an inode number
+       of an open file, lsof won't be able to identify the process
+       using the port.
+
+       This is a tough question to which there is no easy answer.
+
+3.11   Why does lsof update the device cache file?
+
+       At the end of the lsof output you may see the message:
+
+           lsof: WARNING: /Homes/abe/.lsof_vic was updated.
+
+       In this message /Homes/abe/.lsof_vic is the path to the
+       private device cache file for login abe.  (See 00DCACHE.)
+
+       Lsof issues this message when it finds it necessary to
+       recheck the system device directory (e.g., /dev or /devices)
+       and rebuild the device cache file during the open file
+       scan.  Lsof may need to do these things it finds that a
+       device directory node has changed, or if it cannot find a
+       device in the cache.
+
+3.12   Why doesn't lsof report state for UDP socket files?
+
+       Lsof reports UDP TPI connection state -- TS_IDLE (Idle),
+       TS_BOUND (Bound), etc. -- for some, but not all dialects.
+       TPI state is stream-based TCP/IP information that isn't
+       available in many dialects.
+
+       A fairly weak general rule is if netstat(1) reports UDP
+       TPI state, lsof may be able to report it, too.  But don't
+       be surprised if lsof fails to report UDP TPI state for your
+       dialect.  Other factors influence lsof's ability to report
+       UDP TPI state, including the availability of state number
+       data in kernel structures, and state number to state name
+       conversion data.
+
+3.13   I am editing a file with vi; why doesn't lsof find the file?
+
+       Classic implementations of vi usually don't keep open the file
+       being edited.  (Newer ones may do so in order to maintain an
+       advisory lock.)  Instead classic vi opens the file, makes a
+       temporary copy (usually in /tmp or /usr/tmp), and does its work
+       in that file.  When you save the file being edited from a
+       classic vi implementation, it reopens and rewrites the file.
+
+       During a classic vi session, except for the brief periods when
+       vi is reading or rewriting the file, lsof won't find an open
+       reference to the file from the vi process, because there is
+       none.
+
+3.14   Why doesn't lsof report TCP/TPI window and queue sizes for my
+       dialect?
+
+       Lsof only reports TCP/TPI window sizes for Solaris, because
+       only its netstat reports them.  The intent of providing
+       TCP/TPI information in lsof NAME column output is to make
+       it easier to match netstat output to lsof output.
+
+       In general lsof only reports queue sizes for both TCP and
+       UDP (TPI) connections on BSD-derived UNIX dialects, where
+       both sets of values appear in kernel socket queue structures.
+       SYSV-derived UNIX dialects whose TCP/IP implementations
+       are based on streams generally provide only TCP queue sizes,
+       not UDP (TPI) ones.
+
+       While you may find that netstat on some SYSV-derived UNIX
+       dialects with streams TCP/IP may report UDP (TPI) queue
+       sizes, you will probably also find that the sizes are always
+       zero -- netstat supplies a constant zero for UDP (TPI)
+       queue sizes to make its headers align the same for TCP and
+       UDP (TPI) connections.  Solaris seems to get it right --
+       i.e., its netstat does not report UDP (TPI) queue sizes.
+
+       When in doubt, I chose to avoid reporting UDP (TPI) queue
+       sizes for UNIX dialects whose netstat-reported values I
+       knew to be a constant zero or whose origin I couldn't
+       determine.  OSR is a dialect in this category.
+
+3.14.1 Why doesn't lsof report socket options, socket states, and TCP
+       flags and values for my dialect?
+
+       The lsof -T argument, 'f', that selects the reporting of socket
+       options, socket states and TCP flags was implemented at lsof
+       revision 4.71 for the following UNIX dialects, providing the
+       indicated information:
+
+           AIX 4.3.2 and 5.1 and above
+               All socket options and values, socket states, and TCP
+               flags and values described in lsof(8) are reported.
+           Apple Darwin 7.2 and above
+               All socket options and values, socket states, and TCP
+               flags and values described in lsof(8) are reported.
+           FreeBSD 4.9 and above
+               All socket options and values, socket states, and TCP
+               flags and values described in lsof(8) are reported.
+           HP-UX 11.00 (/dev/kmem-based lsof)
+               All socket options and values are reported.  No socket
+               states are reported.  Only the TF_NODELAY TCP flag and
+               the TF_MSS value are reported.
+           HP-UX 11.11 and iiiv2 (PSTAT-based lsof)
+               All socket options and values, and socket states are
+               reported.  No TCP flags or values are reported.
+           Linux
+               No socket options and values, socket states, or TCP
+               flags and values are reported.  The support for "-Tf"
+               could not be added to Linux, because socket options,
+               socket states, and TCP flags and values are not
+               available via the /proc file system.
+           NetBSD 1.6G and above
+               All socket options and values, socket states, and TCP
+               flags and values described in lsof(8) are reported.
+           OpenBSD 3.4 and above
+               All socket options and values, socket states, and TCP
+               flags and values described in lsof(8) are reported.
+           OpenUNIX 8
+               All socket options and values, socket states, and TCP
+               flags and values described in lsof(8) are reported.
+           SCO OpenServer Release 5.0.6
+               All socket options and values, socket states, and TCP
+               flags and values described in lsof(8) are reported.
+           Solaris 2.6, 8 and above
+               The socket option display is limited to BROADCAST,
+               DEBUG, DGRAM_ERRIND, DONTROUTE and OOBINLINE.  Socket
+               values are limited to KEEPALIVE and LINGER.  No socket
+               states are reported.  The TCP DELACK, NODELAY and
+               SENTFIN flags are reported.  The TCP MSS value is
+               reported.
+           UnixWare 7.1.[134]
+               All socket options and values, socket states, and TCP
+               flags and values described in lsof(8) are reported.
+
+3.14.2 Why doesn't lsof report the partial listen queue connection
+       count for my dialect?
+
+       The reporting of partial listen queue connections was added to
+       -Tf processing at lsof revision 4.76.  Currently it is reported
+       for these dialects:
+
+           AIX 4.3.2
+               This dialect is no longer supported, so no attempt
+               was made to add partial listen queue length support
+               for it.
+           AIX 5.1 and above
+               Partial listen queue information is available.
+           Apple Darwin 7.2 and above
+               Partial listen queue information is available.
+           FreeBSD 4.9 and above
+               Partial listen queue information is available.
+           HP-UX 11.00 (/dev/kmem-based lsof)
+               No partial listen queue information is available.
+           HP-UX 11.11 and iiiv2 (PSTAT-based lsof)
+               No partial listen queue information is available.
+           Linux
+               No partial listen queue information is available.
+           NetBSD 1.6G and above
+               Partial listen queue information is available.
+           OpenBSD 3.4 and above
+               Partial listen queue information is available.
+           OpenUNIX 8
+               This dialect is no longer supported, so no attempt
+               was made to add partial listen queue length support
+               for it.
+           SCO OpenServer Release 5.0.6
+               No partial listen queue information is available.
+           Solaris 2.6, 8 and above
+               Partial listen queue information is available.
+           Tru64 UNIX 5.0
+               This dialect is no longer supported, so no attempt
+               was made to add partial listen queue length support
+               for it.
+           Tru64 UNIX 5.1
+               Partial listen queue information is available.
+           UnixWare 7.1.[134]
+               Partial listen queue information is available.
+
+
+3.15   What does "no more information" in the NAME column mean?
+
+       When lsof can find no successor structures -- a gnode,
+       inode, socket, or vnode -- connected to the file structure
+       of an open descriptor of a process, it reports "no more
+       information" in the NAME column.  The TYPE, DEVICE, SIZE/OFF,
+       and INODE columns will be blank.
+
+       Because the file structure is supposed to contain a pointer
+       to the next structure of a file's processing support, if
+       the pointer is NUL, lsof can go no further.
+
+       Some UNIX dialects have file structures for system processes
+       -- e.g., the sched process -- that have no successor
+       structure pointers.  The "no more information" NAME will
+       commonly appear for these processes in lsof output.
+
+       It may also be the case that lsof has read the file structure
+       while it is being assembled and before a successor structure
+       pointer value has been set.  The "no more information" NAME
+       will again result.
+
+       Unless lsof output is filled with "no more information"
+       NAME column messages, the appearance of a few should be no
+       cause for alarm.
+
+3.16   Why doesn't lsof find a process that ps finds?
+
+       If lsof fails to display open files for a process that ps
+       indicates exists, there may be several reasons for the
+       difference.
+
+       The process may be a "zombie" for which ps displays the
+       "(defunct)" state.  In that case, the process has exited
+       and has no open file information lsof can display.  It does
+       still have a process structure, sufficient for the needs
+       of ps.
+
+       Another possible explanation is that kernel tables and
+       structures may have been changing when lsof looked for the
+       process, making lsof unable to find all relevant process
+       structures.  Try repeating the lsof request.
+
+3.17   Why doesn't -V report a search failure?
+
+       The usual reason that -V won't report a search failure is
+       that lsof located the search item, but was prevented from
+       listing it by an option that doesn't participate in search
+       failure reporting.
+
+       For example, this lsof invocation:
+
+           $ lsof -V -i TCP@foobar -a -d 999
+
+       won't report it can't find the Internet address TCP@foobar,
+       even if there is an open file connected to that address,
+       unless the open file also has a file descriptor number of
+       999 (the ``-a -d 999'' options).
+
+       Compile-time options can also affect -V results in much the
+       same way.  For example, if HASSECURITY and HASNOSOCKSECURITY
+       are defined at compile time, this lsof invocation, run by a
+       non-root user:
+
+           $ lsof -V -c inetd
+
+       won't report that it can't find the inetd command, even if
+       there is a process running the inetd command, because the
+       HASSECURITY and HASNOSOCKSECURITY options prevent the
+       listing of all but the socket files of another user, and
+       no socket file selector (e.g., "-i") was specified.
+
+
+3.18   Portmap problems
+
+3.18.1 Why isn't a name displayed for the portmap registration?
+
+       When portmap registration reporting is enabled, any time
+       there is a registration for a local TCP or UDP port, lsof
+       displays it in square brackets, following the port number
+       or service name -- e.g., ``:1234[name]'' or ``:name[100083]''.
+
+       The TCP or UDP port number or service number (what follows
+       the `:') is displayed under the control of the lsof -P
+       option.  The registration identity is held by the portmapper
+       and may be a name or a number, depending on how the
+       registration's owner declared it.  Lsof reports what the
+       port map holds and cannot derive a registration name from
+       a registration number.
+
+       Lsof can be compiled with registration reporting enabled
+       or disabled by default, under the control of the HASPMAPENABLED
+       #define (usually in machine.h).  The lsof help panel (`lsof
+       -h`) will show the default.  Lsof is distributed with
+       reporting disabled by default.
+
+3.18.2 How can I display only portmap registrations?
+
+       Lsof doesn't have an option that will display only TCP or
+       UDP ports with portmap registrations.  The +M option only
+       enables the reporting of registration information when
+       Internet socket files are displayed; +M doesn't select
+       the displaying of Internet socket files -- the -i option
+       does that.
+
+       This simple lsof pipe to grep will do the job:
+
+               $ lsof -i +M | grep "\["
+
+       This works because -i selects Internet socket files, +M
+       enables portmap registration reporting, and only output
+       lines with opening square brackets will have registrations.
+
+       When portmap registration reporting is enabled by default,
+       because the lsof builder constructed it that way, +M is
+       not necessary.  (The lsof help panel, produced with `lsof
+       -h` will display the default portmapper registration
+       reporting state.)  However, specifying +M when reporting
+       is already enabled is acceptable, as is specifying -M when
+       reporting is already disabled.
+
+       Digression: lsof will accept `+' or `-' as a prefix to most
+       options.  (That isn't documented in the man page or help
+       panel to reduce confusion and complexity.)  The -i option
+       is as acceptable as +i, so the above example could be
+       written a little more tersely as:
+
+               $ lsof +Mi | grep "\["
+
+       But be careful to use the ``Mi'' ordering, since ``iM''
+       implies M is an address argument to `i'.
+
+3.18.3 Why doesn't lsof report portmap registrations for some ports?
+
+       Lsof reports portmap registrations for local TCP and UDP
+       ports only.  It identifies local ports this way:
+
+       *  The port appears in the local address section of the
+          kernel structure that contains it.
+
+       *  The port appears in the foreign address section of a
+          kernel structure whose local and foreign Internet
+          addresses are the same.
+
+       *  The port appears in the foreign address section of a
+          kernel address structure whose Internet address is
+          INADDR_LOOPBACK (127.0.0.1).
+
+       Following these rules, lsof ignores foreign portmapped
+       ports.  That's done for reasons of efficiency and possible
+       security prohibitions.  Contacting all remote portmappers
+       could take a long time and be blocked by network difficulties
+       (i.e., be inefficient).  Many firewalls block portmapper
+       access for security reasons.
+
+       Lsof may occasionally ignore portmap registration information
+       for a legitimate local port by virtue of its local port
+       rules.  This can happen when a port appears in the foreign
+       part of its kernel structure and the local and foreign
+       Internet addresses don't match (perhaps because they're on
+       different interfaces), and the foreign Internet address
+       isn't INADDR_LOOPBACK (127.0.0.1).
+
+3.18.4 Why doesn't lsof report portmap registrations for some Solaris
+       versions?
+
+       In some versions of Solaris -- 9 and 10 are known to exhibit
+       this problem -- lsof is unable to display portmap registrations.
+
+       This portmap registration reporting failure occurs when the
+       Solaris netconfig field (in /etc or etc/inet) has its first two
+       non-comment lines enabling tcp6 and udp6.  When netconfig is
+       configured in that fashion, lsof's attempt to read the portmap
+       via an RPC function fails.
+
+       I don't have an explanation for the failure, but this comment
+       in the netconfig(4) man page appears to have some bearing on
+       the problem:
+
+           # The following two entries starting with udp6 and tcp6 are
+           # meant to be used for IPv6. If you have Ipv6 enabled on your
+           # machine then you can uncomment these two lines to enable
+           # RPC and NFS to use the Ipv6 stack.
+           ...
+           #udp6  tpi_clts      v  inet6  udp  /dev/udp6  -
+           #tcp6  tpi_cots_ord  v  inet6  tcp  /dev/tcp6  - "
+
+       My interpretation of that comment is that there is a different
+       RPC interface to the portmap when IPv6 is enabled.  However, I
+       can't find any documentation on it in the RPC man pages.  If
+       anyone has information on it, please send it to me at
+       <abe@purdue> and put "lsof Solaris portmap" in the subject
+       line.
+
+       A work-around may be to move the ucp6 and tcp6 lines after the
+       udp and tcxp lines in netconfig.  I don't know if that change
+       has any unacceptable consequences, but it works for me on my
+       Solaris 9 test system, and I have a report that it also works
+       on Solaris 10.
+
+
+3.19   Why is `lsof | wc` bigger than my system's open file limit?
+
+       There is a strong temptation to count open files by piping
+       lsof output to wc.  If your purpose is to compare the number
+       you get to some Unix system parameter that defines the
+       number of open files your system can have, resist the
+       temptation.
+
+       One reason is that lsof reports a number of "files" that
+       don't occupy Unix file table space -- current working
+       directories, root directories, jail directories, text files,
+       library files, memory mapped files are some.  Another reason
+       is that lsof can report a file shared by more than one
+       process that itself occupies only one file table slot.
+
+       If you want to know the number of open files that occupy
+       file table slots, use the +ff option and process the lsof
+       output's FILE_ADDR column information with standard Unix
+       tools like cut, grep, sed, and sort.
+
+       You might also consider using use lsof's field output with
+       +ff, selecting the file struct address with -FF, and
+       processing the output with an AWK or Perl script.  See the
+       list_fields.awk, list_fields.perl, and shared.perl5 scripts
+       in the scripts/ subdirectory of the lsof distribution for
+       hints on file struct post-processing filters.
+
+3.20   Why doesn't lsof report file offset (position)?
+
+       Lsof won't report a file offset (position) value if the -s
+       option (without parameters) has been specified, or if the
+       dialect doesn't support the displaying of file offset
+       (position).  (Note that on selected dialects the help output,
+       obtained with -h or -?, may show that the -s option can also be
+       supplied the "p:s" parameters; for more information on that
+       addition, see the answer to the "How are protocol state name
+       exclusion and inclusion used?" question.)
+
+       That lsof is reporting only file size is indicated by the
+       fact that the appropriate column header says SIZE instead
+       of SIZE/OFF.
+
+       If lsof doesn't support the displaying of file offset
+       (position) -- e.g., for Linux /proc-based lsof -- the -h
+       or -? output panel won't list the -o option.
+
+       Sometimes the availability of file offset information
+       depends on the dialect's kernel.  This is particularly true
+       for socket file offsets.
+
+       Maintenance of offsets for pseudo-terminal devices varies
+       by UNIX dialect and is related to how the dialect kernel
+       implements pseudo-terminal support.  Kernels like AIX, for
+       example, that short-circuit the transfer of data between
+       socket and pseudo devices to reduce TCP/IP daemon interrupt
+       rates won't advance offsets in the TCP/IP daemon socket
+       files.  Instead they will advance offsets in the open
+       standard I/O files of the shell child precess where the
+       pseudo-terminal devices are used.
+
+       When in doubt about the behavior of lsof in reporting file
+       offset information, do some carefully measured experiments,
+       consult the lsof sources, or contact me at <abe@purdue.edu>
+       to discuss the matter.  Please follow the reporting guidelines
+       in the "How do I report an lsof bug?" section of this FAQ.
+
+3.20.1 What does lsof report for size when the file doesn't really have
+       one?
+
+       When a file has no true size -- e.g., it's a socket, a
+       FIFO, or a pipe -- lsof tries to report the information it
+       finds in the kernel that describes the contents of associated
+       kernel buffers.
+
+       Thus, for example, size for most TCP/IP files is socket
+       buffer size.  The size of the socket read buffer is reported
+       for read-only files; the size of the write buffer for
+       write-only files; and the sum of the buffers sizes for
+       read-write files.
+
+3.21   Problems with path name arguments
+
+3.21.1 How do I ask lsof to search a file system?
+
+       You can ask lsof to search for all open files on a file
+       system by specifying its mounted path name as an lsof
+       argument -- e.g.,
+
+           $ lsof /
+
+       Output of the mount command will show file system mounted
+       path names.  It will also show the mounted-on device path
+       for the file system.
+
+       If the mounted-on device is a block device (the permission
+       field in output of `ls -l <device>` starts with a `b/),
+       you can specify it's name, too -- e.g.,
+
+           $ lsof /dev/sd0a
+
+       If the mounted-on device isn't a block device -- for example,
+       some UNIX dialects call a CD-ROM device a character device
+       (ls output starts with a `c') -- you can force lsof to
+       assume that the specified device names a file system with
+       the +f option -- e.g.,
+
+           $ lsof +f -- /dev/sd0a
+
+       (Note: you must use ``--'' after +f or -f if a file name
+       follows immediately, because  +f and -f can be followed by
+       characters that specify flag output selections.)
+
+       When you use +f and lsof can't match the device to a file
+       system, lsof will issue a complaint.
+
+       The +f option may be used in some dialects to ask lsof to
+       search for an NFS file system by its server name and server
+       mount point.  If the mount application reports an NFS file
+       system mounted-on value that way, then this sample lsof
+       request should work.
+
+           $ lsof +f -- fleet:/home/fleet/u5
+
+       Finally, you can use -f if you don't want a mounted file
+       system path name to be considered a request to report all
+       open files on the file system.  This is useful when you
+       want to know if anyone is using the file system's mounted
+       path name.  This example directs lsof to report on open
+       access to the `/' directory, including when it's being used
+       as a current working or root directory.
+
+           $ lsof -f -- /
+
+       The lsof -f option performs the same function as -f does
+       in some fuser implementations.  However, since the lsof -c
+       option was chosen for another purpose before the `f' option
+       was added to lsof, +f was selected as the analogue to the
+       fuser -c option.  (Sorry for the potential confusion.)
+
+3.21.2 Why doesn't lsof find all the open files in a file system?
+
+       Lsof may not find all the open files in a file system for
+       several reasons.
+
+       First, some processes with files open on the file system
+       may have been changing status when lsof examined the process
+       table, and lsof "missed" them.  Remember, the kernel changes
+       much faster than lsof can respond to the changes.
+
+       Second, be sure you have specified the file system correctly.
+       Perhaps you specified a file instead.  You can use lsof's
+       -V option to have lsof report in detail on what it couldn't
+       find.  Make sure the report for the file system you specified
+       says "file system."  Here's some -V output:
+
+           $ /lsof -V /tmp ./lsof.h ./lsof
+           COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF  INODE NAME
+           lsof    2688  abe  txt   VREG 18,1,7  1428583 226641 ./lsof
+           lsof    2689  abe  txt   VREG 18,1,7  1428583 226641 ./lsof
+           lsof: no file use located: ./lsof.h
+
+       You can also use lsof's +f option to force it to consider
+       a path name as a file system.  If lsof can't find a file
+       system by the specified name, it will issue a complaint --
+       e.g.,
+
+           $ lsof +f -- /usr
+           lsof: not a file system: /usr
+
+       (/usr is a directory in the / file system.)
+
+3.21.3 Why does the lsof exit code report it didn't find open files
+       when some files were listed?
+
+       Sometimes lsof will list some open files, yet return a
+       non-zero exit code, suggesting it hasn't found all the
+       specified files.
+
+       The first thing you should when you suspect lsof is incorrect
+       is to repeat the request, adding the -V option.  In the
+       resulting report you may find that your file system
+       specification really wasn't a file system specification,
+       just a file specification.
+
+       Finally, if you specify two files or two file systems twice,
+       lsof will credit all matches to the first of the two and
+       believe that there were no matches for the second.  It's
+       possible to specify a single file system twice with different
+       path names by using both its mounted directory path name
+       and mounted-one device name.
+
+           $ lsof +f -V spcuna:/sysprog /sysprog
+           COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF  INODE NAME
+           ksh     11092  abe  cwd   VDIR 39,0,1     1536 226562 /sysprog
+           (spcuna:/sysprog)
+           ...
+           lsof: no file system use located: spcuna:/sysprog
+
+       All matches were credited to /sysprog; none to spcuna:/sysprog.
+
+3.21.4 Why won't lsof find all the open files in a directory?
+
+       When you give lsof a simple directory path name argument
+       (not a file system mounted-on name), you are asking it to
+       search for processes that have the directory open as a
+       file, or as a process-specific directory -- e.g., root or
+       current working directory.
+
+       If you want to list instances of open files inside the
+       directory, you need to either specify the individual path names
+       of those files, their common mount point, or use the lsof +D 
+       and +d options.
+       
+       For example, if you wanted to check the files open in your /lsof 
+       folder then the following might be the quickest way to get
+       the answer you are looking for:
+
+       lsof / | grep /lsof | grep -v DIR
+
+       See the answer to the question "Why are the +D and +d
+       options so slow?" before you use +D or +d casually.
+
+       See the answer to the question "Why do the +D and +d options
+       produce warning messages?" for an explanation of some
+       process authority limitations of +D and +d.
+
+3.21.5 Why are the +D and +d options so slow?
+
+       The +D and +d options cause lsof to build a path name search
+       list for a specified directory.  +D causes lsof to descend
+       the directory to its furthest subdirectory, while +d
+       restricts it to the top level.  In both cases, the specified
+       directory itself is included in the search list.  In both
+       symbolic links are ignored.
+
+       Building such a search list can take considerable time,
+       especially when the specified directory contains many files
+       and subdirectories -- lsof must call the system readlink()
+       and stat() functions for each file and directory.  Storing
+       the search list can cause lsof to use more than its normal
+       amount of dynamic memory -- each file recorded in the search
+       list consumes dynamic memory for its path name, characteristics,
+       and search linkages.  Using the list means lsof must search
+       it for every open file in the system.
+
+       Building the search list for a directory specified on some
+       file systems can be slow -- e.g., for an NFS directory with
+       many files.  Some file systems have special logging features
+       that can introduce additional delays to the building of
+       the search list -- e.g., NFS logging, or logging on a
+       Solaris UFS file system.  The bottom line is that slow
+       search list construction may not be so much an lsof problem
+       as a file system problem.  (Hint: if you're using Solaris
+       UFS logging, consider specifying the "logging,noatime"
+       option pair to reduce the number of atime writes to the
+       UFS logging queue and disk.)
+
+       A somewhat risky way to speed up lsof's building of the
+       search list is to use lsof's ``-O'' option.  It forces lsof
+       to do all system calls needed to build the search list
+       directly, rather than in a child process.  While direct
+       system calls are much faster, they can block in the kernel
+       -- e.g., when an NFS server stops responding -- stopping
+       lsof until the kernel operation unblocks.
+
+       As an example of the load +D can impose, consider that an
+       `lsof +D /` on a lightly loaded NeXT '040 cube with a 1GB
+       root file system disk took 4+ minutes of real time.  It
+       also generated several hundred error messages about files
+       and directories the lsof process didn't have permission to
+       access with stat(2).
+
+       The bottom line is that +D and +d should be used cautiously.
+       +D is more costly than +d for deeply nested directory trees,
+       because of the full directory descent it causes.  So use
+       +d where possible.  And you might need to consider the
+       performance of the file system that holds the directory
+       you name with +d or +D.
+
+       In view of these warnings, when is it appropriate to use
+       +D or +d?  Probably the most appropriate time is when you
+       would specify the directory's contents to lsof with a shell
+       globbing construct -- e.g., `lsof *`.  If that's what you
+       need to do, `lsof +d .` is probably more efficient than
+       having the shell produce a directory list, form it into an
+       argument vector, and pass the vector to lsof for it to
+       unravel.
+
+       See the answer to the question "Why do the +D and +d options
+       produce warning messages?" for an explanation of some
+       process authority limitations of +D and +d.
+
+3.21.6 Why do the +D and +d options produce warning messages?
+
+       +D and +d option processing is limited by the authority of
+       the lsof process -- i.e., lsof can only examine (with
+       lstat(2) and stat(2)) files the owner of the process can
+       access.
+
+       If the ownership, group membership, or permissions of the
+       specified directory, file within it, or directory within
+       it prevents the owner of the lsof process from using lstat(2)
+       or stat(2) on it, lsof will issue a warning message, naming
+       the path and giving the system's (lstat(2's or stat(2)'s)
+       reason (errno explanation text) for refusing access.
+
+       As an example, assume user abc has a subdirectory in /tmp,
+       owned by abc and readable, writable and searchable by only
+       its owner.  If user def asks lsof to search for all /tmp
+       references with +D or +d, lsof will be unable to lstat(2)
+       or stat(2) anything in abc's private subdirectory, and will
+       issue an appropriate warning.
+
+       Lsof warnings can usually be suppressed with the -w option.
+       However, using -w with +D or +d means that there will be
+       no indication why lsof couldn't find an open reference to
+       a restricted directory or something contained in it.
+
+       Hint: if you need to use +D or +d and avoid authority
+       warnings, and if you have super-user power, su and use lsof
+       with +D or +d as root.
+
+3.22   Why can't my C compiler find the rpcent structure definition?
+
+       When you try to compile lsof your compiler may complain
+       that the rpcent structure is undefined.  The complaints
+       may look like this:
+
+           >print.c: In function `fill_portmap':
+           >print.c:213: dereferencing pointer to incomplete type
+           >...
+
+       The most likely cause is that someone has allowed a BIND
+       installation to update /usr/include/netdb.h (or perhaps
+       /usr/include/rpc/netdb.h), removing the rpcent structure
+       definition that lsof expects to find there.
+
+       Only Solaris has an automatic work-around.  (See dlsof.h
+       in dialects/sun.).  The Solaris work-around succeeds because
+       there is another header file, <rpc/rpcent.h>, with the rpcent
+       structure definition, and there is a Solaris C pre-processor
+       test that can tell when the BIND <netdb.h> is in place and
+       hence <rpc/rpcent.h> must be included.
+
+       Doubtlessly there are similar work-arounds possible in
+       other UNIX dialects whose header files have been "touched"
+       by BIND, but in general I recommend restoration of the
+       vendor's <netdb.h> and any other header files BIND might
+       have replaced.  (I think BIND replaces <resolv.h>,
+       <sys/bitypes.h>, <sys/cdefs.h> -- and maybe others.)
+
+3.23   Why doesn't lsof report fully on file "foo" on UNIX dialect
+       "bar?"
+
+       Lsof sometimes won't report much information on a given
+       file, or may even report an error message in its NAME
+       column.  That's usually because the file is of a special
+       type -- e.g., in a file system specific to the UNIX dialect
+       -- and I haven't used a system where the file appeared
+       during my testing.
+
+       If you encounter such a situation, send me e-mail at
+       <abe@purdue.edu> and we may be able to devise an addition to
+       lsof that will report on the file in question.  Please follow
+       the reporting guidelines in the "How do I report an lsof bug?"
+       section of this FAQ.  Make sure "lsof" appears in the
+       "Subject:" line so my e-mail filter won't classify your letter
+       as Spam.
+
+3.24   Why do I get a complaint when I execute lsof that some library
+       file can't be found?
+
+       On systems where the LIBPATH (or the equivalent) environment
+       variable is used to record the library search path in
+       executable files when they are built, an incorrect value
+       may make it impossible for the system to find the shared
+       libraries needed to load lsof for execution.
+
+       This may be particularly true on systems like AIX >= 4.1.4,
+       where the lsof Makefile takes the precautionary step of
+       using the -bnolibpath loader flag to insure that the path
+       to the private static lsof library is not recorded in the
+       lsof binary.  Should LIBPATH be invalid when lsof is built,
+       it will be recorded in the lsof binary as the default
+       library path search order and lead to an inability to find
+       libraries when lsof is executed.
+
+       So, if you get missing library complaints when you try to
+       execute lsof, check LIBPATH, or whatever environment variable
+       is used on your system to define library search order in
+       executable files.  Use the tools at your disposal to look
+       at the library paths recorded in the lsof binary -- e.g.,
+       chatr on HP-UX, dump on AIX, ldd on Solaris.
+
+       Make sure, too, that when the correct library search path
+       has been recorded in the executable file, the required
+       library files exist at one or more of the search paths.
+
+
+3.25   Why does lsof complain it can't open files?
+
+       When lsof begins execution, unless it has been asked to
+       report only help or version information, typically it will
+       attempt to access kernel memory and symbol files -- e.g.,
+       /unix, /dev/kmem.  Even though lsof needs only permission
+       to open these files for reading, read access to them might
+       be restricted by ownerships and permission modes.
+
+       So the first step to diagnosing lsof problems with opening
+       files is to use ls(1) to examine the ownerships and permission
+       modes of the files that lsof wants to open.  You may find
+       that lsof needs to be installed with some type of special
+       ownership or permission modes to enable it to open the
+       necessary files for reading.  See the "Installing Lsof"
+       section of 00README for more information.
+
+3.26   Why does lsof warn "compiled for x ... y; this is z."?
+
+       Unless warnings are suppressed (with -w) or the kernel
+       identity check symbol (HASKERNIDCK) definition has been
+       deleted, all but one lsof dialect version (exception:
+       /proc-based Linux lsof) compare the identity of the running
+       kernel to that of the one for which lsof was constructed.
+       If the identities don't match, lsof issues a warning like
+       this:
+
+           lsof: WARNING: compiled for Solaris release 5.7; this is 5.6.
+
+       Two kernel identity differences can generate this warning
+       -- the version number and the release number.
+
+       Build and running identity differences are usually significant,
+       because they usually indicate kernels whose structures are
+       different -- kernel structures commonly change at dialect
+       version releases.  Since lsof reads data from the kernel
+       in the form of structures, it is sensitive to changes in
+       them.  The general rule is that an lsof compiled for one
+       UNIX dialect version will not work correctly when run on
+       a different version.
+
+       There are three work-arounds: 1) use -w to suppress the
+       warning -- and risk missing other warnings; 2) permanently
+       disable the identity check by deleting the definition of
+       HASKERNIDCK in the dialect's machine.h header file -- with
+       the same risk; or 3) rebuild lsof on the system where it
+       is to be run.  (Deleting HASKERNIDCK can be done with the
+       Customize script or by editing machine.h.)
+
+       Generally checking kernel identity is a quick operation
+       for lsof.  However, it is potentially slow under AIX, where
+       lsof must run /usr/bin/oslevel.  To speed up lsof, use -w
+       to suppress the /usr/bin/oslevel test.  See "Why does AIX
+       lsof start so slowly?" for more information.
+
+3.27   How can I disable the kernel identity check?
+
+       The kernel identity check is controlled by the HASKERNIDCK
+       definition.  When it is defined, most dialects (exclusion:
+       /proc-based Linux lsof) will compare the build-time kernel
+       identity with the run-time one.
+
+       To disable the kernel identity check, disable the HASKERNIDCK
+       definition in the dialect's machine.h header file.  The
+       Customize script can be used to do that in its section
+       about the kernel identity check.
+
+       Caution: while disabling the kernel identity check may
+       result in smaller lsof startup overhead, it comes with the
+       risk of executing an lsof that may produce warning messages,
+       error messages, incorrect output, or no output at all.
+
+3.28   Why don't ps(1) and lsof agree on the owner of a process?
+
+       Generally the user ID lsof reports in its USER column is
+       the process effective user ID, as found in the process
+       structure.  Sometimes that may not agree with what ps(1)
+       reports for the same process.
+
+       There are sundry reasons for the difference.  Sometimes
+       ps(1) uses a different source for process information,
+       e.g., the /proc file system or the psinfo structure.
+       Sometimes the kernel is lax or confused (e.g., Solaris
+       2.5.1) about what ID to report as the effective user ID.
+       Sometimes the system carries only one user ID in its process
+       structure (some BSD derivatives), leaving lsof no choice.
+
+       The differences between lsof and ps(1) user identifications
+       should be small and normally it will be apparent that the
+       confusion is over a process whose application has changed
+       to an effective user ID different from the real one.
+
+3.29   Why doesn't lsof find an open socket file whose connection
+       state is past CLOSE_WAIT?
+
+       TCP/IP connections in states past CLOSE_WAIT -- e.g.,
+       FIN_WAIT_1, CLOSING, LAST_ACK, FIN_WAIT_2, and TIME_WAIT
+       -- don't always have open files associated with them.  When
+       they don't, lsof can't identify them.  When the connection
+       state advances from CLOSE_WAIT, sometimes the open file
+       associated with the connection is deleted.
+
+3.30   Why don't machine.h definitions work when the surrounding
+       comments are removed?
+
+       The machine.h header files in dialect subdirectories have
+       some commented-out definitions like:
+
+           /* #define HASSYSDC "/your/choice/of/path */
+
+       You can't simply remove the comments and expect the definition
+       to work.  That's intended to make you think about what
+       value you are assigning to the symbol.  The assigned value
+       might have a system-specific convention.  HASSYSDC, for
+       example, might be /var/db/lsof.dc for FreeBSD, but it might
+       be /var/adm/lsof.dc for Solaris.
+
+       Symbols defined in the lsof documentation are described in
+       00PORTING, other machine.h comments, and other lsof
+       documentation files.  HASSYSDC, for example, is discussed
+       in 00DCACHE.  When comments and documentation don't suffice,
+       consult the source code for hints on how the symbol is
+       used.
+
+3.31   What do "can't read inpcb at 0x...", "no protocol control
+       block", "no PCB, CANTSENDMORE, CANTRCVMORE", etc. mean?
+
+       Sometimes lsof will report "can't read inpcb at 0x00000000",
+       "no protocol control block", "no PCB, CANTSENDMORE,
+       CANTRCVMORE" or a similar message in the NAME column for
+       open TCP socket files.  These messages mean the file's socket
+       structure lacks a pointer to the INternet Protocol Control
+       Block (inpcb) where lsof expects to find connection addresses
+       -- local and foreign ports, local and foreign IP addresses.
+       The socket file has probably been submitted to the shutdown(2)
+       function for processing.
+
+       In some implementations lsof issues the "no PCB, CANTSENDMORE,
+       CANTRCVMORE" message, which tries to explain the absence
+       of a protocol control block by showing the socket state
+       settings that have been made by the shutdown(2) function.
+
+       If a non-zero address follows the "0x" in the "can't read
+       inpcb" message, it means lsof couldn't read inpcb contents
+       from the indicated address in kernel memory.
+
+3.32   What do the "unknown file system type" warnings mean?
+
+       Lsof may report a message similar to"
+
+           unknown file system type, v_op: 0x10472f10
+
+       in the NAME column for some files.
+
+       This means that lsof has encountered a vnode for the file
+       whose operation switch address (from v_op) references a
+       file system type for which there is no support in lsof.
+       After lsof identifies the file system type, it uses
+       pre-compiled code to locate the file system specific node
+       for the file where lsof finds information like file size,
+       device number, node number, etc.
+
+       To get some idea of what the file system type might be,
+       use nm on your kernel symbol file to locate the symbol name
+       that corresponds to the v_op address -- e.g., on Solaris
+       do:
+
+           $ nm -x /dev/ksyms | grep 0x10472f10
+           0x10472f10 ... |file_system_name_vnodeops
+
+       Where "file_system_name" is the clue to the unsupported
+       file system.
+
+       Lsof doesn't use the v_op address to identify file system
+       types on all dialects.  Sometimes it uses an index number
+       it finds in the vnode.  It will translate that symbol to
+       a short name in the warning message -- e.g., "nfs3" -- if
+       possible.
+
+3.33   Installation
+
+3.33.1 How do I install lsof?
+
+       There is no "standard" way to install lsof.  Too much
+       depends on local conditions for me to be able to provide
+       working install rules in the lsof make files.  (The skeleton
+       install rules you will find just give "hints.")  See the
+       "Installing Lsof" section of 00README for a fuller explanation.
+
+       To install lsof you will need to consider these questions:
+
+       *  Who should be able to use lsof?  (See HASSECURITY and
+           HASNOSOCKSECURITY in the "Security" section of 00README.)
+
+       *  Where should lsof be installed?  This is a decision
+          mostly dictated by local conditions.  Somewhere in
+          /usr/local -- etc/ or sbin/ -- is a common choice.
+
+       *  What permissions should I give the lsof executable?
+          The answer to this varies by dialect.  The make files
+          have install rules that give hints.  The "Installing
+          Lsof" section of 00README gives information, too.
+
+       *  What if I want to install lsof in a shared file system
+          for machines that require different lsof configurations?
+          See the next question and answer, "How do I install a
+          common lsof when I have machines that need differently
+          constructed lsof binaries?"
+
+3.33.2 How do I install a common lsof when I have machines that
+       need differently constructed lsof binaries?
+
+       A dilemma that faces some system administrators when they
+       install lsof in a shared file system -- e.g., NFS -- is
+       that they must have different lsof executables for different
+       systems.
+
+       The answer is to build an lsof wrapper script that is
+       executed in place of lsof.  The script can use system
+       commands to determine which lsof binary should be executed.
+
+       Consider this example.  You have HP-UX machines with 32
+       and 64 bit kernels that share the /usr/local/sbin directory
+       where you want to install lsof.  Consequently, on each
+       system you must use a different lsof executable, built for
+       the system's bit size.  (That's because lsof reads kernel
+       structures, sized by the kernel's bit size.)
+
+       One answer is to install three things in /usr/local/sbin:
+       1) a 32 bit lsof as lsof32; 2) a 64 bit lsof as lsof64;
+       and 3) an lsof script.  The script might look like this
+       one, based on work by Amir J. Katz:
+
+           #!/bin/sh
+           x=`/usr/bin/getconf KERNEL_BITS`  # returns 32 or 64
+           if /usr/bin/test "X$x" = "X32"
+           then
+             lsof32 $*
+           else
+             if /usr/bin/test "X$x" = "X64"
+             then
+               lsof64 $*
+             else
+               echo "Can't determine which lsof executable to use;"
+               echo "getconf KERNEL_BITS says: $x"
+               exit 1
+             fi
+           fi
+
+       Solaris users should consult "How do I install lsof for
+       Solaris 7, 8 or 9?" for information on a similar trick
+       using the Solaris isaexec command.
+
+       Users of other dialects might be able to use a command like
+       uname(1) that can identify a distinguishing feature of the
+       system to be incorporated in pre-installed lsof executable
+       names.  For example, use `uname -r` and install binaries
+       with suffixes that match `uname -r` output.
+
+3.34   Why do lsof 4.53 and above reject device cache files built
+       by earlier lsof revisions?
+
+       When lsof revisions 4.53 run and encounter a device cache
+       file built by an earlier revision, it will reject the file
+       and build a new one.  The rejection will be advertised with
+       these messages:
+
+           lsof: WARNING: no /dev device in <name>: 2 sections
+           ...
+           lsof: WARNING: created device cache file: <name>
+
+       This happens because the header line of the device cache
+       file was changed at revision 4.53 to contain the number of
+       the device on which the device directory resides.  The old
+       device cache file header line -- the "2 sections" line in
+       the above warning message, node reads "2 sections, dev=600".
+
+       This is not a serious problem, since lsof automatically
+       rebuilds the device cache file with the correct header
+       line.
+
+3.35   What do "like block special" and "like character special" mean
+       in the NAME column?
+
+       When lsof comes across an open block or character file
+       whose device, raw device and inode place it somewhere other
+       than /dev (or /devices), lsof doesn't report the /dev (or
+       /devices) name in the NAME column.  Instead lsof reports
+       the file system name and device or path name in the NAME
+       column and parenthetically adds "like block special <path>"
+       or "like character special <path>".
+
+       The value for <path> will point to a block or character
+       device in /dev (or /devices) whose raw device number matches
+       that of the open file being reported, but whose device
+       number or node number (or both) don't match.
+
+       Such an open file is connected to a device node that has
+       been created in a directory other than /dev (or /devices.)
+       See mknod(8) for information on how such nodes are created.
+       (Generally one needs root power to create device nodes with
+       mknod.)
+
+3.36   Why does an lsof make fail because of undefined symbols?
+
+       When lsof is compiled via the `make` step and the final
+       load step fails because of missing symbols, the problem
+       may not be lsof.  The problem may be that ld, called by
+       the compiler as part of the `make` step, can't find some
+       library that lsof needs.
+
+       First check the last compiler line of the make operation
+       -- e.g., the last line with cc or gcc in it before the
+       undefined symbol report -- for loader arguments, i.e.,
+       ones beginning with "-l".  Except for "-llsof" the rest
+       name system libraries.  ("-L./lib" precedes "-llsof" to
+       tell the loader its location.)
+
+       Check that all the named system libraries exist.  Look in
+       /lib and /usr/lib as a start, but that may not be the only
+       place system libraries live.  Consult your dialect's
+       documentation, e.g., the compiler and loader man pages,
+       for other possible locations.
+
+       If some system library doesn't exist, that may mean it was
+       never installed or was removed.  You'll have to re-install
+       the missing library.
+
+       You may find that all the system libraries lsof uses exist.
+       Your next step might be to use nm and grep to see if any
+       of them contain the undefined symbols.
+
+           $ nm library | grep symbol
+
+       If the undefined symbol exists in some library named by
+       the lsof make step, then you might have a problem with some
+       environment variable that controls the load step.  The most
+       common is LD_LIBRARY_PATH.  It may have a setting that
+       causes ld to ignore a directory containing a library lsof
+       names.  If this is the case, try unsetting LD_LIBRARY_PATH
+       in the environment of the ld process -- e.g., do:
+
+           $ unset LD_LIBRARY_PATH
+       or
+           % unsetenv LD_LIBRARY_PATH
+
+       Consult your ld man page for other environment variables
+       that might affect library searching -- e.g., LIBPATH, LPATH,
+       SHLIB_PATH, etc.
+
+       If the undefined function doesn't exist in any libraries
+       lsof names, check other libraries.  See if the function
+       has a man page that names its library.  If the latter is
+       true, please let me know, because that is an lsof problem
+       I need to fix.
+
+       If none of these solutions work for you, send me some
+       documentation via e-mail at <abe@purdue.edu>.  Include `uname
+       -a` output, the output of the lsof `Configure ...` and `make`
+       steps, and the contents of the environment in force when the
+       `make` step was executed -- e.g., `env` or `printenv` output.
+       If you've located the libraries lsof names, send me that
+       information, too.  Make sure "lsof" appears in the "Subject:"
+       line so my e-mail filter won't classify your letter as Spam.
+
+3.37   Command Regular Expressions (REs)
+
+3.37.1 What are basic and extended regular expressions?
+
+       Lsof's ``-c'' option allows the specification of regular
+       expressions (REs), enclosed in two slash ('/') characters and
+       followed by these modifiers:
+
+           b   the RE is a basic RE.
+           i   ignore case.
+           x   the RE is an extended RE (the default).
+
+       Note: the characters of the regular expression may need to
+       be quoted to prevent their expansion by the shell.
+
+       Example: this RE is an extended RE that matches exactly
+       four characters, whose third may be an upper ('O') or lower
+       case ('o') oh:
+
+           -c /^..o.$/i
+
+       For simplicity's sake, an RE that is acceptable to egrep(1)
+       is usually called an extended RE.
+
+       REs suitable for the old line editor, ed(1), are often
+       called basic REs (and sometimes also called obsolete).
+
+       These are some ways basic REs usually differ from extended
+       REs.  (There are other differences.)
+
+       *  `|', `+', `?', '{', and '}' are ordinary characters.
+
+       *  `^' is an ordinary character except at the beginning of
+          the RE.
+
+       *  `$' is an ordinary character except at the end of the
+          RE.
+
+       *  `*' is an ordinary character if it appears at the
+          beginning of the RE.
+
+       For more information on REs and the distinction between
+       basic and extended REs, consult your dialect's man pages
+       for ed(1), egrep(1), sed(1), and possibly regex(5) or
+       regex(7).
+
+3.37.2 Why can't I put a slash in a command regular expression?
+
+       Since a UNIX command name is the last part of a path to
+       the command's executable, the lsof command regular expression
+       (RE) syntax uses slash ('/') to mark the beginning and end
+       of an RE.  Slash may not appear in the RE and the `\'
+       back-slash escape is ineffective for "hiding" it.
+
+       More likely than not, if you try to put a slash in an lsof
+       command RE, you'll get this response:
+
+           $ lsof -s/.\// ...
+           lsof: invalid regexp modifier: /
+
+       Lsof is complaining the the first character it found after
+       the second slash isn't an lsof command RE modifier -- 'b',
+       'i', or 'x'.
+
+3.37.3 Why does lsof say my command regular expression wasn't found?
+
+       When you use both forms of lsof's -c option --
+       ``-c <command>'' and ``-c /RE/[m]'' -- and ask that lsof
+       do a verbose search (``-V''), you may be surprised that
+       lsof will say that the regular expression wasn't found.
+
+       This can happen if the ``-c <command>'' form matches first,
+       because then the ``-c/RE/[m]'' test will never have been
+       applied.  For example:
+
+           $ ./lsof -clsof -c/^..o.$/ -V -adcwd
+           COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF  NODE NAME
+           lsof    7850  abe  cwd   VDIR    6,0     2048 96442 / (/dev/sd0a)
+           lsof: no command found for regex: ^..o.$
+
+       The ``-clsof'' option matched first, so the ``-c/^..o.$/
+       option wasn't tested.
+
+3.38   Why doesn't lsof report on shared memory segments?
+
+       Lsof reports on shared memory segments only if they're
+       associated with an open file.  That's consistent with lsof's
+       mission -- to LiSt Open Files.  Shared memory segments with
+       no file associations aren't open files.
+
+       That's not to say that a report on shared memory segments
+       and their associated processes wouldn't be useful.  But it
+       calls for a new tool, not more baggage for lsof.
+
+3.39   Why does lsof report two instances of itself?
+
+       When you ask lsof to report all open files and it has
+       permission to do so, you may see two lsof processes in the
+       output.  The processes are connected via pipes -- e.g.,
+       here's an HP-UX 11 example.
+
+           COMMAND     PID USER   FD   TYPE     DEVICE ...
+           ...
+           lsof      29450  abe    7w  PIPE 0x48732408 ...
+           lsof      29450  abe    8r  PIPE 0x48970808 ...
+           ...
+           lsof      29451  abe    6r  PIPE 0x48732408 ...
+           lsof      29451  abe    9w  PIPE 0x48970808 ...
+
+       The first process will usually be the lsof you initiated;
+       the second, an lsof child process that is used to isolate
+       its parent process from kernel functions that can block --
+       e.g., readlink() or stat().
+
+       Information to and from the kernel functions is exchanged
+       via the two pipes.  When the parent process detects that
+       the child process has become blocked, it attempts to kill
+       the child.  Depending on the UNIX dialect that may succeed
+       or fail, but the parent won't be blocked in any event.
+
+       See the "BLOCKS AND TIMEOUTS" and "AVOIDING KERNEL BLOCKS"
+       sections of the lsof man page for more information on why
+       the child process is used and how you can specify lsof
+       options to avoid it.  (Caution: that may be risky.)
+
+3.40   Why does lsof report '\n' in device cache file error messages?
+
+       Lsof revisions prior to 4.58 may report '\n' in error
+       messages it delivers about problems in the device cache
+       file -- e.g.,
+
+           lsof: WARNING: no ...: 4 sections\n
+
+       That's deliberately done to show the exact contents of the
+       device cache file line about which lsof is complaining,
+       including its terminating NL (New Line) '\n' character.
+       In the above example the line in the device cache file
+       causing the lsof complaint contains "4 sections" and ends
+       with a '\n'.
+
+       At revision 4.58 and above, device cache error messages
+       like the one in the above example have been changed to
+       read:
+
+           lsof: WARNING: no ...: line "4 sections"
+
+       The terminal '\n' is no longer reported, the line contents
+       are enclosed in double quote marks ('"'), and the word
+       "line" has been added as a prefix to denote that what
+       follows is a line from the device cache file.
+
+3.41   Kernel Symbol and Address Problems
+
+3.41.1 What does "lsof: WARNING: name cache hash size length error: 0"
+       mean?
+
+       When run on some systems, lsof may issue this warning:
+
+           lsof: WARNING: name cache hash size length error: 0
+
+       That is an example from a FreeBSD system where lsof reads
+       the kernel's _nchash variable and finds its value is zero.
+
+       Similar warnings include:
+
+           WARNING: kernel name cache size:
+           WARNING: can't read kernel's name cache:
+           WARNING: no name cache address
+           WARNING: name cache hash size length error:
+           WARNING: unusable name cache size:
+
+       These warnings are issued when lsof is attempting to read
+       the kernel's name cache information.  They are usually the
+       result of a mis-match between the addresses for kernel
+       symbols lsof gets via nlist(2) and the addresses in use by
+       the kernel.
+
+       Lsof usually gets kernel symbol addresses from what it
+       believes to be the kernel boot file.  In FreeBSD, for
+       example, that's the path returned by getbootfile(3), usually
+       /kernel.  The boot file can have other names in other UNIX
+       dialects -- /unix, /vmunix, /bsd, /netbsd, /mach, /stand/vmunix,
+       etc.
+
+       Lsof will get incorrect (mismatched) addresses from the
+       boot file if it has been replaced by a newer one which
+       hasn't yet been booted -- e.g., if this is done in FreeBSD:
+
+           # mv /kernel /kernel.OLD
+           # mv /kernel.NEW /kernel
+
+       Until the FreeBSD system is rebooted, the booted kernel is
+       /kernel.OLD, but getbootfile() says it is /kernel.  If
+       symbol addresses important to lsof in /kernel.OLD and
+       /kernel don't match, the lsof WARNING messages result.
+
+3.41.2 Why does lsof produce "garbage" output?
+
+       Kernel name cache warnings may not be the only sign that
+       lsof is using incorrect symbol addresses to read kernel
+       values.  If there's no reasonable test lsof can make on
+       what it reads from the kernel, it may issue other warnings
+       or even report nonsensical results.
+
+       The warnings may appear on STDERR, such as:
+
+           lsof: can't read proc table info
+
+       Or the warnings may appear in the NAME column as messages
+       saying lsof can't read or interpret some kernel structure --
+       e.g.,
+
+           ... NAME
+           ... can't read file struct from 0x12345
+
+       One possible work-around is to point lsof's kernel symbol
+       address gathering at the proper boot file.  That can be
+       done with lsof's -k option -- e.g.,
+
+           $ lsof -k /kernel.OLD
+
+       The best work-around is to make sure the standard boot file
+       is properly sited -- e.g., if you've moved a new /kernel
+       in place, boot it.
+
+3.42    Why does lsof report open files when run as super user that
+       it doesn't report when run with lesser privileges?
+
+       The most likely cause is that the HASSECURITY option was
+       selected when the lsof executable was built.
+
+       If HASSECURITY is defined when lsof is built, and lsof is
+       run with the privileges of a non-ROOT user, it will only
+       list open files belonging to the user.  The same lsof
+       executable, when run with root user privileges, will list
+       all open files.
+
+       However, if HASSECURITY and HASNOSOCKSECURITY are both
+       defined when lsof is built, lsof will list open files
+       belonging to the user and will also list anyone else's open
+       socket files, provided their listing is selected with the
+       "-i" option.
+
+       So first ask yourself if the process whose open files lsof
+       won't list belong to a user other than the one under which
+       you're running lsof, and are not open socket files.  If
+       either is true, use lsof's help (-h or -?) option and look
+       for a line near the bottom of the help panel that says:
+
+           "... can list all files..."
+
+       If the leading "..." says "Only root" then HASSECURITY was
+       defined when lsof was built.  If the trailing "..." says
+       ", but anyone can list socket files" then HASNOSOCKSECURITY
+       was also defined.
+
+       Should you want an lsof not built with HASSECURITY defined,
+       rerun the lsof Configure script.  If you let Configure do
+       customization, make sure you answer 'n' when it asks if
+       you want to enable HASSECURITY and HASNOSOCKSECURITY.  If
+       you don't need to do customization, you can rebuild lsof
+       with the "-n" option to Configure.  Here's an example of
+       such a rebuild sequence:
+
+           $ Configure -clean
+           $ Configure -n <dialect-abbreviation>
+           $ make
+
+       More information on the HASSECURITY and HASNOSOCKSECURITY
+       options may be found in the "Security" section of the
+       00README file of the lsof distribution.
+
+3.43   Test Suite Problems
+
+3.43.1 Errors all tests can report:
+
+3.43.1.1 Why do tests complain "ERROR!!!  can't execute ../lsof"?
+
+       All tests in the test suite expect an executable lsof file
+       to exist in the tests parent directory, ../lsof.
+
+       If there's none there, the tests/Makefile has a rule to
+       make it, but there are probably circumstances where that
+       rule may fail.
+
+       The work-around is to re-Configure and re-make lsof, then
+       run the test suite.
+
+3.43.1.2 Why do tests complain "ERROR!!! can't find ..." a file?
+
+       Many tests create (or use from a supplied environment
+       variable path) a test file and use lsof to find it.  When
+       lsof can't file the file, the tests report the error with
+       messages of the form:
+
+           ERROR!!!  can't find ... : <some file path>
+        or
+           ERROR!!!  lsof couldn't find ...
+
+       These type of error messages mean that the lsof field output
+       delivered to the test didn't contain a file that the test
+       could identify as the one it intended lsof to find.  It
+       might also mean that the process information -- command
+       name, PID or parent PID -- didn't match what the test
+       expected.
+
+       This could imply a bug in the test or a bug in lsof.  Try
+       using lsof to find a known file that is open.  For example,
+       while in the tests sub-directory, do this:
+
+           $ sleep 30 < Makefile
+           $ ../lsof Makefile
+
+       If lsof doesn't report that Makefile is open, then the
+       fault may be with lsof.  If lsof reports the file is open,
+       search further in the test code for the failure cause.
+
+3.43.1.3 Why do some tests fail to compile?
+
+       If a test suite program fails to compile, it may be because
+       I've never had an opportunity to compile the test on the
+       particular UNIX version you are using.
+
+       See Appendix B in 00TEST for a list of the UNIX dialects
+       where the test suite has been validate.
+
+3.43.1.4 Why do some tests always fail?
+
+       There are several tests in the optional group that have
+       conflicting or special requirements:
+
+           LTbigf      needs a dialect and file system that support
+                       large files.
+
+           LTlock      won't work if the tests/ sub-directory is
+                       on an NFS file system.
+
+           LTnfs       won't work if the tests/ sub-directory is
+                       not on an NFS file system.
+
+       So for two tests in particular, LTlock and LTnfs, one will
+       generally fail.
+
+       Some failing tests can be run successfully by supplying to
+       them a path to the appropriate type of file system with
+       the -p option.
+
+3.43.1.5 Why does the test suite say it hasn't been validated on
+        my dialect?
+
+       When you use the default rule of the test suite's Makefile,
+       it may issue this complaint:
+
+           $ cd tests
+           $ make
+           !!!WARNING!!!
+
+           This dialect or its particular version may not have
+           been validated with the lsof test suite.  Consequently
+           some tests may fail or may not even compile.
+
+           !!!WARNING!!!
+
+       You are then given the opportunity to answer 'y' to have
+       the test suite operation continue.
+
+       This message means that the tests/TestDB file in the tests
+       sub-directory doesn't show that the test suite has been
+       run with the combination of compiler flags found in
+       tests/config.cflags.  The tests might nor run; they may
+       encounter compiler failures.
+
+       See 00TEST for more information on the UNIX dialects where
+       the test suite has been validated and on the workings of
+       TestDB and its supporting scripts.
+
+       When the tests/Makefile "auto" rule is used, the message
+       is more terse and the condition is fatal.
+
+           This suite has not been validated on:
+
+               <dialect_description>
+
+       No opportunity to continue is offered.
+
+       The tests/Makefile "silent" rule will skip checking for
+       the validation footprint.
+
+3.43.1.6 Why do the tests complain they can't stat() or open()
+        /dev/mem or /dev/kmem?
+
+       When the tests detect that lsof for the dialect reads its
+       information from kernel memory (i.e., the LT_KMEM definition
+       is present in tests/config.cflags), and when the lsof
+       executable path is ../lsof, the tests make sure they can
+       stat() and open() for read access the relevant kernel memory
+       devices, /dev/kmem and possibly /dev/mem.
+
+       If those stat() or open() operations fail, the tests issue
+       an error message and quit.  The message explains why the
+       system rejected the operation in terms of system "errno"
+       symbols and messages.  More often than not the explanation
+       will be that the process lacks permission to access the
+       indicated device node.
+
+       One work-around is to give the lsof executable being tested
+       the necessary permission -- e.g., via chgrp, chmod, etc.
+       -- and set its path in the LT_LSOF_PATH environment variable.
+       (See 00TEST.)
+
+       Another work-around is to make sure the process that runs
+       the tests has the necessary permissions -- e.g., run it as
+       root, or enable the process login to access the resources.
+       For example, I can run the tests on my personal work-station
+       because /dev/kmem and /dev/mem are readable by the "kmem"
+       group and my login is in that group.
+
+
+3.43.2 LTbigf test issues
+
+3.43.2.1 Why does the LTbigf test say that the dialect doesn't
+        support large files?
+
+       Large file support is defined dialect by dialect in the
+       lsof source files and Configure script.  If large file
+       support isn't defined there, it isn't defined in the LTbigf
+       test.
+
+       If you think that's wrong for a particular dialect, contact me
+       via e-mail at <abe@purdue.edu>.  Make sure "lsof" appears in the
+       "Subject:" line so my e-mail filter won't classify your letter
+       as Spam.
+
+3.43.2.2 Why does LTbigf complain about operations on its config.LTbigf*
+        file?
+
+       The LTbigf must be able to write a large file test (size
+       > 32 bits) and seek within it and the process file ulimit
+       size must permit the operation.  If the default location
+       for the test file, tests/, isn't on a file system enabled
+       for large file operations or if the process ulimit file
+       block size is too small, lsof will get file operation
+       errors, particularly when seeking
+
+       There may be a work-around.  Specify the path to a file
+       LTbigf can write in a file system enabled for large file
+       operations a the -poption.  Make sure that the ulimit file
+       block size permits writing a large file.  For example,
+       presuming /scratch23 is large-file-enabled, and presuming
+       you have permission to raise the ulimit file block size,
+       this shell commands will allow the LTbigf test to run on
+       AIX:
+
+           $ ./LTbigf -p /scratch23/abe/bigfile
+
+       (Note: syntax for the ulimit command varies by dialect and
+       by shell.  Discovering the proper variant is left to the
+       reader.)
+
+       More information on this subject can be found in the LTbigf
+       description in the 00TEST file.  If course, the LTbigf.c
+       source file in tests/ is the ultimate source of information,
+
+3.43.2.3 Why does LTbigf warn that lsof doesn't return file offsets?
+
+       On some dialects (e.g., Linux) lsof can't report file
+       offsets, because the data access method underlying lsof
+       doesn't provide them.  If LTbigf knows that lsof can't
+       report file offsets for the dialect, it issues this warning:
+
+           LTbigf ... WARNING!!!  lsof can't return file offsets
+                       for this dialect, so offset tests have
+                       been disabled.
+
+       LTbigf then performs the size test and skips the offset
+       tests.
+
+       For more information see 00TEST and the "Why doesn't
+       /proc-based lsof report file offsets (positions)?" Q&A of
+       this file.
+
+3.43.3 Why does the LTbasic test complain "ERROR!!! lsof this ..."
+       and "ERROR!!!  lsof that ..."?
+
+       The LTbasic test program uses lsof to examine a running
+       lsof process.  It looks for the lsof current working
+       directory, executable (if possible), and kernel memory file
+       (if applicable).
+
+       Failures to find those things result in the LTbasic error
+       messages.  More information on how LTbasic produces the error
+       messages may be found in the LTbasic.c source file.
+
+       On HP-UX 11.11 and higher, for example, if the test's current
+       working directory is on a loopback (LOFS) file system, LTbasic
+       won't be able to find the current working directory of the lsof
+       process because of a bug in the HP-UX kernel.
+
+       The solution for that HP-UX problem is to install an HP-UX
+       patch.  See the answer to the "Why doesn't PSTAT-based lsof
+       report a CWD that is on a loopback (LOFS) file system?"
+       question for more information on the patch.
+
+3.43.4 NFS test issues
+
+3.43.4.1 Why does the LTnfs test complain "couldn't find NFS file ..."?
+
+       The LTnfs test must work with an NFS test file.  After it
+       opens the file it asks lsof to find it on an NFS file system.
+       If the file isn't on an NFS file system, lsof won't find it,
+       and the NFS test script complains and fails.
+
+       The work-around is to use -p option to supply a path to a
+       regular NFS file (not a directory)  that is on an NFS file
+       system that LTnfs can read.  Presuming /share/bin/file is
+       such a file and can be opened for reading by the LTnfs
+       test, this sample shell command could be used to run the
+       LTnfs test successfully:
+
+           $ ./LTnfs -p /share/bin/file
+
+       (If the NFS file system is enabled for large files, the
+       NFS test will produce the error message described in the
+       following Q&A.)
+
+3.43.5 LTnlink test issues
+
+3.43.5.1 Why does the LTnlink test complain that its test file is on
+        an NFS file system?
+
+       The LTnlink test may complain:
+
+           LTnlink ... WARNING!!!  test file <path> is NFS mounted.
+
+       and then issue an explanation and a hint about using the
+       -p option.
+
+       The LTnlist test does this because of the way NFS file
+       links are managed when an NFS file is unlinked and the
+       unlinking process still has the file open.  Unlike with
+       files on a local file system, when an NFS file that is
+       still open is unlinked, its link count is not reduced.
+
+       The file name is changed to a name of the form .nfsxxxx
+       and the link count is left unchanged until the process
+       holding the file open closes it.  That's done by NFS so it
+       can keep proper track of the file on NFS clients and servers.
+
+       Since the link count isn't reduced when the LTnlink test
+       program closes the NFS test file it still has open, lsof
+       won't find it for LTnlink with a link count of zero.
+       Consequently, LTnlink disables that test section and issues
+       its warning.
+
+       The warning suggests that the unlink test section can be
+       run by giving LTnlink a path to a test file with the -p
+       option.  That path must name a file LTnlink can write and
+       unlink.  Presuming /scratch23/abe/nlinkfile is on a local
+       file system and the LTnlink test can write to it and unlink
+       it, this sample shell command can be used to run the complete
+       LTnlink test successfully:
+
+           $ LTnlink -p /scratch23/abe/nlinkfile
+
+3.43.5.2 Why does LTnlink delay and report "waiting for link count
+        update: ..."?
+
+       On some UNIX dialects and file system combinations the
+       updating of link count after a file has been unlinked can
+       be delayed.  Consequently, lsof won't be able to report
+       the updated link count to LTnlink for a while.
+
+       When lsof doesn't report the proper link count to LTnlink,
+       it sleeps and repeats the lsof call, using the "waiting
+       for link count update: ..." message as a signal that it is
+       waiting for the expected lsof response.  The wait cycle
+       duration is limited to approximately one minute.
+
+3.43.5.3 Why does LTnlink fail because of an unlink error?
+
+       LTnlink may fail with an error similar to:
+
+           LTnlink ... ERROR!! unlink(<name>) failed: (Permission denied).
+
+       That message will be followed by a short explanation.
+
+       The error means that the kernel support for the file system on
+       which the file <name> resides does not allow a process to
+       unlink a file while it has the file open.  (When LTnlink is run
+       without the "-p path" option, it creates a <name> that begins
+       with "./config.LTnlink" and ends with the LTnlink process ID
+       number.)
+
+       An unlink failure of this type runs counter to original UNIX
+       file system behavior, but it has been observed on some file
+       system types, especially on the ZFS file system.
+
+       The work-around is to run LTnlink on a file system that allows
+       a process to unlink a file it has open.  Usually /tmp has that
+       support.  So, try running LTnlink this way:
+
+           $ ./LTnlink -p /tmp/<name>
+
+       where <name> is a unique name in /tmp of your choosing.  To
+       be safe, create a subdirectory in /tmp, named by your login:
+
+           $ rm -f /tmp/<login>
+           $ mkdir /tmp/<login>
+           $ ./LTnlink -p /tmp/<login>/<name>
+
+3.43.6 LTdnlc test issues
+
+3.43.6.1 Why won't the LTdnlc test run?
+
+       Lsof is unable to access the DNLC cache on AIX, because the
+       kernel symbols for the DNLC aren't exported.  Contact IBM
+       to learn why that decision was made.
+
+       The LTdnlc test won't work on Apple Darwin because lsof
+       can't obtain reliable DNLC information.
+
+       The LTdnlc test may fail on other dialects.  Failure causes
+       include: a busy system with a DNLC that is changing rapidly;
+       path name components too large for the DNLC; a file system
+       -- e.g., NFS, /tmp, loopback -- which doesn't fully
+       participate in the DNLC; or DNLC limitations (Many DNLC
+       implementations will only store path name components if
+       they are 31 characters or less.)
+
+       If you suspect the file system doesn't fully participate
+       in kernel DNLC processing, as a work-around rebuild and
+       test lsof on one that does.
+
+3.43.6.2 What does the LTdnlc test mean by "... <path> found: 100.00%"?
+
+       Even when it succeeds the LTdnlc test will report:
+
+         LTdnlc ... /export/home/abe/src/lsof4/tests found: 100.00%
+
+       This message means that the LTdnlc test asked lsof to find
+       the file at the indicated path five times and lsof found
+       the full path name in the indicated percentage of calls.
+       The LTdnlc test considers it a failure if the percentage
+       falls below 50.0%
+
+3.43.6.3 Why does the DNLC test fail?
+
+       The DNLC test may fail when some component of the lsof
+       tests/ sub-directory can't be cached by the kernel DNLC.
+       Some kernels have a limit on the length of individual
+       components (typically) 32.
+
+3.43.7 Why hasn't the test suite been qualified for 64 bit HP-UX
+       11 when lsof is compiled with gcc?
+
+       When I attempted to qualify lsof for HP-UX 11, compiled
+       with gcc 3.0, the LTsock test failed.  I traced the failure
+       to a gcc compilation error.  Because LTsock is an important
+       test, I didn't feel that the test suite was qualified if
+       it failed.
+
+       LTsock compiles and runs correctly on 64 bit HP-UX 11 when
+       compiled with HP's ANSI-C.
+
+3.43.8 LTszoff test issues
+
+3.43.8.1 Why does LTszoff warn that lsof doesn't return file offsets?
+
+       On some dialects (e.g., Linux) lsof can't report file
+       offsets, because the data access method underlying lsof
+       doesn't provide them.  If LTszoff knows that lsof can't
+       report file offsets for the dialect, it issues this warning:
+
+           LTszoff ... WARNING!!!  lsof can't return file offsets
+                         for this dialect, so offset tests have
+                         been disabled.
+
+       LTszoff then performs the size test and skips the offset
+       tests.
+
+       For more information see 00TEST and the "Why doesn't
+       /proc-based lsof report file offsets (positions)?" Q&A of
+       this file.
+
+3.43.9 LTlock test issues
+
+3.44   File descriptor list (the ``-d'' option) problems
+
+3.44.1 Why does lsof reject a ``-d'' FD list?
+
+       Lsof rejects ``-d'' FD lists that contain both exclusions
+       and inclusions with messages like:
+
+           lsof: exclude in an include list: ^1
+           lsof: include in an exclude list: 2
+
+       That's because ``-d'' FD lists are processed as ORed lists,
+       so it makes no sense for them to contain both exclusions
+       and inclusions.
+
+       I.e.,, if a ``-d'' FD list were to contain ``^cwd,1'', the
+       ``^cwd'' member is useless, because the ``1'' member
+       dominates by saying "include only FD 1".  That effectively
+       excludes ``cwd'' FD.
+
+       Note that lists may have multiple members of the same type,
+       exclude or include.  They are processed as an ORed set.
+       If an FD isn't excluded by any member of an exclude list,
+       it is selected.  If an FD is included by any member of an
+       include list, it is selected.
+
+3.44.2 Why are file descriptors other than those in my FD list
+       reported?
+
+       The FD list that follows ``-d'' excludes or includes file
+       descriptors, but unless the ``-a'' (AND) option is specified,
+       the FD list selections are ORed to the other selections.
+
+       For example, the following lsof command will cause all file
+       descriptors to be listed for the lsof command, and all but
+       the cwd descriptor for all other commands, probably not
+       what was intended.
+
+           $ lsof -clsof -d^cwd
+
+       Hint: use ``-a'' -- e.g.,
+
+           $ lsof -clsof -a -d^cwd
+
+3.45   How can I supply device numbers for inaccessible NFS file
+       systems?
+
+       When lsof can't get device numbers for inaccessible NFS file
+       systems via stat(2) or lstat(2), it attempts to get them from
+       the mount table's dev=xxx options.  Successes are reported with
+       a warning message that indicates the source of the device
+       number and that output might be incomplete as a consequence of
+       the warnings.
+
+       Some system mount tables -- e.g., Linux /proc/mounts -- don't
+       have a dev=xxx option.  In that case, and provided lsof for the
+       dialect supports them, you can use the +m option to create a
+       mount table supplement file and the "+m m" option to use it.
+
+       First check the lsof -h (help) output to see if the +m and
+       "+m m" options are supported.  If they are, use +m to create a
+       mount table supplement file when all mounted file systems are
+       accessible.  Use "+m m" later to make the supplement available
+       when some mounted file systems might not be available.
+
+       Here's an example that creates a mount supplement file in
+       $HOME/mnt-sup and later makes it available to lsof.
+
+           $ rm -f $HOME/mnt-sup
+           $ lsof +m > $HOME/mnt-sup
+           ...
+           $ lsof +m $HOME/mnt-sup <other lsof options>
+
+       If lsof has to get the device number from the supplement, it
+       will issue an informative warning message.  The warning can be
+       suppressed with lsof's -w option.
+
+       Caution!  Since the mount table supplement file is static, it
+       is its supplier's responsibility to update it as file system
+       mounts change.
+
+       For more information, consult the lsof man page.  The
+       "ALTERNATE DEVICE NUMBERS" section has useful information on
+       how lsof acquires device numbers when stat(2) or lstat(2)
+       fail.
+
+3.46   Why won't lsof find open files on over-mounted file systems?
+
+       When a file system, /xyz for example, is mounted on the same
+       mount point as another file system, /abc for example, running
+       lsof with an argument of the path of the first file system's
+       mount point -- the over-mounted one, /abc -- probably will not
+       reveal any files open on /abc.
+
+       That's because lsof looks for open files on a file system by
+       looking for files with the file system's device number.  The
+       two file systems usually have different device numbers and lsof
+       determines the device number search key from the supplied name
+       of the second file system.
+
+       A general work-around exists only for Linux.  On that UNIX
+       dialect, when you know the over-mounted file system's mount
+       point path, you can ask lsof to report on all open files and
+       grep that output for the path of the over-mounted file system
+       mount point.
+
+3.47   What can be done when lsof reports no more space?
+
+       Many lsof methods cache information in memory, using the
+       dialects malloc() library function.  When malloc() can't
+       allocate the requested amount of memory, lsof exits with
+       warning messages similar to this AIX message:
+
+           lsof: no more dev-ch space at pid 2257750: 0x82a8e600
+
+       Lsof then exits immediately and produces no more output.
+
+       A possible work-around is to increase the memory foot print
+       of the shell that runs lsof.  That is often done with the
+       ulimit(1) shell command.
+
+3.48   What if the lsof build encounters ar and ld problems?
+
+       The lsof main and library Makefiles use the library archiver,
+       ar, and the system loader, ld, applications.  Improperly
+       located, installed or configured versions of them may cause the
+       lsof build to encounter errors with them.
+
+       The application producing the error should identify itself in
+       its error messages.
+
+       The first thing to check the path of the application that is
+       being used.  Try `which ar` or `which ld` to see if perhaps the
+       PATH used during the build might be causing the wrong archiver
+       or loader to be used.
+
+       If the problem is with the use of the wrong archiver, and it's
+       not possible to correct the PATH to it, try using the LSOF_AR
+       environment variable to specify the path to and arguments for
+       the correct archiver.  See 00XCONFIG for more information and
+       note that LSOF_AR must specify the path to the archive
+       application and the arguments for it, less the terminating
+       library and module name arguments.
+
+       If the problem is with the loader, there is no lsof work-
+       around.  That's because lsof calls the loader via the C
+       compiler, so the problem must be fixed at the compiler (system)
+       level.
+
+3.49   Why does lsof -i report an open socket file for a process, but
+       lsof -p on that process' ID report nothing?
+
+       The lsof in use was probably built with the HASSECURITY and
+       HASNOSOCKSECURITY options and the process in question does not
+       belong to the user of lsof.
+
+       The HASSECURITY option limits lsof output to processes owned
+       by the user invoking lsof and the HASNOSOCKSECURITY option
+       weakens that slightly to allow output of open socket file
+       information for all processes.
+
+       For example, if process PID 12345 is owned by some user other
+       than the one invoking lsof, and lsof has been compiled with the
+       HASSECURITY and HASNOSOCKSECURITY options, the following lsof
+       command will display the open socket files of process 12345:
+
+               $ lsof -p 12345 -a -i
+
+       This security restriction is described in the lsof(8) manual
+       page.
+
+
+4.0    AIX Problems
+
+4.1    What is the Stale Segment ID bug and why is -X needed?
+
+       Kevin Ruderman reports that he has been informed by IBM
+       that processes using the AIX 3.2.x, 4.1[.12345]], 4.2[.1],
+       and 4.3.x kernel's readx() function can cause other AIX
+       processes to hang because of what appears to be file system
+       corruption.
+
+       This failure, known as the Stale Segment ID bug, is caused
+       by an error in the AIX kernel's journaled segment memory
+       handler that causes the kernel's dir_search() function
+       erroneously to believe directory entries contain zeroes.
+       The process using the readx() call need not be doing anything
+       wrong.  Usually the system must be under such heavy load
+       that the segment ID being used in the readx() call has been
+       freed and then reallocated to another process since it was
+       obtained from kernel memory.
+
+       Lsof uses the readx() function to access library entry
+       structures, based on the segment ID it finds in the proc
+       structure of a process.  Since IBM probably will never fix
+       the kernel bug, I've added an AIX-specific option to lsof
+       that controls its use of the readx() function.
+
+       By default lsof readx() use is disabled; specifying the
+       ``-X'' option enables readx() use.
+
+       If you want to change the default readx() behavior of AIX
+       lsof, change the HASXOPT, HASXOPT_ROOT, and HASXOPT_VALUE
+       definitions in dialects/aix/machine.h.  You can also use
+       these definitions to enable or disable readx() -- consult
+       the comments in machine.h.  You may want to disable readx()
+       use permanently if you plan to make lsof publicly executable.
+
+       When HASXOPT_ROOT is defined, lsof will restrict use of
+       the -X option to processes whose real UID is root; if
+       HASXOPT_ROOT isn't defined, any user may specify the -X
+       option.  The Customize script offers the option to change
+       HASXOPT_ROOT when HASXOPT is defined and HASXOPT_ROOT is
+       named in any dialect's machine.h header file.
+
+       I have never seen lsof cause a problem with its use of
+       readx(), but I believe there is some chance it could, given
+       the right circumstances.
+
+4.1.1  Stale Segment ID APAR
+
+       Here are the details of the Stale Segment ID bug and IBM's
+       response, provided by Kevin Ruderman.
+
+       AIX V3
+         APAR=ix49183
+             user process hangs forever in kernel due to file
+             system corruption
+         STAT=closed prs  TID=tx2527 ISEV=2 SEV=2
+              (A "closed prs" is one closed with a Permanent
+              ReStriction.)
+         RCOMP=575603001 aix v3 for rs/6 RREL=r320
+
+       AIX V4  (internal defect, no apar #)
+         prefix        p
+         name          175671
+         abstract      KERMP: loop for ever in dir_search()
+
+       Problem description:
+
+       1. Some user application -- e.g., lsof -- gets the segment
+          ID (SID) for the process private segment of a target
+          process from the process table.
+
+       2. The target process exits, deleting the process private
+          segment.
+
+       3. The SID is reallocated for use as a persistent segment.
+
+       4. The user application runs again and tries to read the
+          user area structure from /dev/mem, using the SID it read
+          from the process table.
+
+       5. The loads done by the driver for /dev/mem cause faults
+          in the directory; new blocks are allocated; the size
+          changed; and zero pages created.
+
+       6. The next application that looks for a file in the affected
+          directory hangs in the kernel's dir_search() function
+          because of the zero pages.  This occurs because the
+          kernel's dir_search() function loops through the variable
+          length entries one at a time, moving from one to the
+          next by adding the length of the current entry to its
+          address to get the address of the next entry. This
+          process should end when the current pointer passes the
+          end of the known directory length.
+
+          However, while the directory length has increased, the
+          entry length data has not, so when dir_search() reaches
+          the zero pages, it loops forever, adding a length of
+          zero to the current pointer, never passing the end of
+          the directory length.  The application process is hung;
+          it can't be killed or stopped.
+
+       IBM closed the problem with a PRS code (Permanent ReStriction)
+       under AIX Version 3 and had targeted a fix for AIX 4.2.  They
+       have recently (I became aware of it September 10, 1996)
+       cancelled the defect report altogether and have indicated they
+       are not going to fix the defect.
+
+4.2    Gcc Work-around for AIX 4.1x
+
+       When gcc is used to compile lsof for AIX 4.1x, it doesn't
+       align one element of the user structure correctly.  Xlc
+       sees the U_irss element as a type "long long" and aligns
+       it on an 8 byte boundary.  That's because the default mode
+       of xlc is -qlonglong; when -qlonglong is enabled, the
+       _LONG_LONG symbol is also defined.
+
+       Gcc sees U_irss as a two element array of type long, because
+       _LONG_LONG isn't defined.  Hence gcc aligns the U_irss
+       element array on a 4 byte boundary, rather than an 8 byte
+       one, making the gcc incantation of the user structure 4
+       bytes shorter than xlc's.
+
+       When the length of gcc's user structure is supplied as
+       argument 4 to the undocumented getuser() function of the
+       AIX kernel, getuser() rejects it as an incorrect size and
+       returns EINVAL.
+
+       Lsof has a work-around for this problem.  It involves a
+       special test in the Configure script when the "aixgcc"
+       Configure abbreviation is used -- e.g.,
+
+               $ Configure -n aixgcc
+
+       The test is to compile a small program with gcc and check
+       the alignment of U_irss.  If it's not aligned on an 8 byte
+       boundary, the Configure script makes a special copy of
+       <sys/user.h> in ./dialects/aix/aix<AIX_version> whose
+       U_irss will align properly, and generates compile time
+       options to use it.
+
+       While I have tested this work-around only with 4.1.4, it
+       should work with earlier versions of AIX 4.1.  It does not
+       work for AIX 4.2; a different work-around is employed there.
+       (See the next section.)
+
+       If you want to use this technique to compile other AIX
+       4.1x programs with gcc for using getuser(), check the
+       Configure script.
+
+       Stuart D. Gathman identified this gcc AIX alignment problem.
+
+4.3    Gcc and AIX 4.2[.1]
+
+       Alignment problems with gcc and AIX 4.2[.1] inside the user
+       structure are more severe, because there are some new 64
+       bit types in AIX that gcc doesn't yet (as of 2.7.x) support.
+       The <sys/user.h> U_irss element problem, discussed in 4.3
+       above, doesn't exist in 4.2[.1].
+
+       The AIX lsof machine.h header file has a work-around,
+       provided by Henry Grebler, that bypasses gcc alignment
+       problems.  Later versions of gcc (e.g., 2.8.x) will probably
+       bypass the problems as well.
+
+4.4    Why won't lsof's Configure allow the use of gcc for AIX
+       below 4.1?
+
+       Gcc can't reliably be used to compile lsof for AIX versions
+       below AIX 4.1 because of possible kernel structure element
+       alignment differences between it and xlc.
+
+4.5    What is an AIX SMT file type?
+
+       When you run AIX X clients with the DISPLAY environment
+       variable set to ``:0.0'' they communicate with the AIX X
+       server via files whose kernel file structure has an undefined
+       type (f_type == 0xf) -- at least there's no definition for
+       it in <sys/file.h>.
+
+       These are Shared Memory Transport (SMT) sockets, an artifact
+       of AIXWindows, designed for more efficient data transfers
+       between the X server and its clients.
+
+       Henry Grebler and David J. Wilson alerted me to the existence
+       of these files.  Mike Feldman and others helped me identify
+       them as SMT sockets.
+
+       The curious reader can find more about SMT sockets in
+       /usr/lpp/X11/README.SMT.
+
+4.6    Why does AIX lsof start so slowly?
+
+       When AIX lsof starts it compares the running kernel's
+       identity to the one for which it was built, using
+       /usr/bin/oslevel.  That comparison can sometimes take a
+       long time to complete, depending on the system's maintenance
+       level and how recently it was examined with oslevel.
+
+       AIX revisions 4.67 and above for AIX 5 and above don't use
+       oslevel to determine the kernel identity.  They use uname(2)
+       instead, and it is much faster.
+
+       You can skip the oslevel test by suppressing warning messages
+       with lsof's -w option.  Doing that carries with it the risk
+       of missing other warning messages, however.
+
+       You can also disable the kernel identity check by disabling
+       the definition of the HASKERNIDCK symbol by editing AIX
+       machine.h header file or by using the Customize script to
+       disable it.
+
+       See the "Why does lsof warn "compiled for x ... y; this is
+       z.?" section for more information.
+
+4.7    Why does exec complain it can't find libc.a[shr.o]?
+
+       When you try to execute lsof you may get this complaint:
+
+           exec(): 0509-036 Cannot load program ./lsof because of
+                       the following errors:
+                   0509-022 Cannot load library libc.a[shr.o].
+                   0509-026 System error: A file or directory in
+                       the path name does not exist.
+
+       This is probably the result of making lsof when the LIBPATH
+       environment variable contained a directory path that doesn't
+       contain libc.a.  You can see what LIBPATH contained when
+       lsof was made by using the dump application on lsof.  For
+       example, if LIBPATH contained /foo/bar when lsof was made,
+       you will see this (partial) dump output:
+
+           $ dump -H lsof
+           ...
+                       ***Import File Strings***
+           INDEX  PATH                          BASE         ...
+           0      /foo/bar
+
+       To correct the problem, revisit the lsof source directory
+       and remake lsof this way:
+
+           $ unset LIBPATH; make               (sh or ksh)
+       or
+           % unsetenv LIBPATH; make            (csh or tcsh)
+
+4.8    What does lsof mean when it says, "no PCB, CANTSENDMORE,
+       CANTRCVMORE" in a socket file's NAME column?
+
+       When an AIX application calls shutdown(2) on an open socket
+       file, but hasn't called close(2) on the file, the file will
+       remain visible to lsof as an open socket file without any
+       extended protocol information.
+
+       Lsof reports that state in the NAME column by saying that
+       there is "no PCB" (Protocol Control Block) for the protocol
+       (e.g., TCP in the NODE column).  If the open socket file
+       has the state variables SO_CANTSENDMORE and SO_CANTRCVMORE
+       set -- i.e., from the shutdown(2) call -- lsof reports them
+       with the CANTSENDMORE and CANTRCVMORE notes in the NAME
+       column.
+
+4.9    When the -X option is used on AIX 4.3.3, why does lsof disable
+       it, saying "WARNING: user struct mismatch; -X option disabled?"
+
+       The -X option causes lsof to read the loader information
+       of the user structure from virtual memory via the readx()
+       system call.  It does that with the user structure definition
+       from <sys/user.h> that was compiled into the lsof executable.
+
+       On AIX 4.3.3 there are two different user structure
+       definitions in two separate <sys/user.h> header files,
+       distributed at different times by IBM.  If lsof was compiled
+       with one and the kernel on which lsof is being run was
+       compiled with the other, lsof normally won't get correct
+       loader information when it calls readx().
+
+       In an attempt to compensate for that difference, lsof makes
+       an independent check of the loader information by getting
+       the user structure's open file count via readx() and
+       comparing it to the open file count obtained independently
+       via getprocs().  When the two counts don't match, lsof
+       tries to read the count (and re-read the loader information)
+       with two offsets, based on observed differences between
+       the two user structures.
+
+       When one of the three attempts produces a correct open file
+       count, lsof uses its corresponding offset on subsequent
+       readings of the loader information.
+
+       When none of the three attempts produces a correct open
+       file count, lsof issues the WARNING message and disables
+       -X processing.
+
+       To eliminate this problem, obtain an lsof binary that
+       matches the kernel of the AIX 4.3.3 system where you want
+       to run lsof.  Compiling lsof on the target system is the
+       preferred way to get a matching binary.
+
+4.10   Why doesn't the -X option work on my AIX 5L or 5.[123] system?
+
+       If your AIX 5L or 5.[123] system uses the ia64 architecture,
+       lsof needs setuid-root permission to be able to do the
+       processing that -X requires.
+
+       Check the output of `uname -a` to determine the architecture
+       type.
+
+       The work-around is to give lsof setuid-root permission.
+
+4.11   Why doesn't /usr/bin/oslevel report the correct AIX version?
+
+       The oslevel man page says, "The oslevel command reports
+       the level of the operating system using a subset of all
+       filesets installed on your system."
+
+       You can see which fileset is below the expected level with
+       oslevel's -l option.  For example, if you believe your
+       system is at AIX level 4.3.3, but oslevel reports 4.3.2,
+       use this oslevel command to find the filesets below 4.3.3:
+
+           $ /usr/bin/oslevel -l 4.3.3.0
+
+       If you don't know what level argument to supply to oslevel's
+       -l option, use oslevel's -q option first.
+
+4.11.1 Why doesn't /usr/bin/oslevel report the correct AIX version
+       on AIX 5.1?
+
+       The subset list for oslevel on AIX 5.1 seems to include at
+       least two filesets, xlsmp.msg.en_US.rte and xlsmp.rte, that
+       do not install from AIX 5.1 media with a 5.1.0.0 level.
+       Hence, oslevel reports 5.0.0.0 instead of the expected
+       5.1.0.0.
+
+       If either xlsmp.msg.en_US.rte or xlsmp.rte is installed,
+       lsof's Configure script and run-time tests will identify
+       the AIX version incorrectly.  The run-time test will
+       issue a complaint message of this form:
+
+           lsof: WARNING: compiled for AIX version xxx; this is yyy.
+
+       You can correct the Configure test by pre-defining the
+       oslevel value, setting the correct value in the LSOF_VSTR
+       environment variable before running the Configure script
+       -- e.g., to pre-define AIX 5.1 when using ksh, do this:
+
+           $ LSOF_VSTR=5.1.0.0 Configure -n aix
+
+       You can't affect oslevel output without uninstalling
+       xlsmp.msg.en_US.rte and xlsmp.rte.  If you can't do that,
+       you'll have to put up with the run-time complaint.
+
+4.12    Why does lsof for AIX 5.1 or above Power architecture
+       complain about kernel bit size?
+
+       When you run an lsof binary on an AIX 5.1 or above Power
+       system, it might complain:
+
+           lsof: FATAL: compiled for a 32 bit kernel.
+                 The bit size of this kernel is 64.
+       or
+           exec: 0509-036 Cannot load program ./lsof because of
+                          the following errors:
+                 0509-032 Cannot run a 64-bit program on a 32-bit
+                          machine.
+
+       Starting at lsof revision 4.61, lsof binaries for Power
+       architecture systems running AIX 5.1 or above are closely
+       tied to the kernel bit size.  Lsof must do that so it can
+       read and understand kernel structures.
+
+       Lsof's Configure script tunes the lsof configuration so
+       that the binary built in the make(1) step is adjusted to
+       the kernel bit size.
+
+       An lsof binary knows the bit size for which it was constructed,
+       tests the bit size of the kernel under which it is running,
+       and objects if the two sizes don't match.  To see the bit
+       size for which lsof was constructed, run it with its -v
+       option and look for these lines in the output:
+
+           configuration info: 32 bit kernel
+        or
+           configuration info: 64 bit kernel
+
+       (Note: these lines will appear only in -v output for AIX
+       5.1 and above lsof binaries, built for Power architecture.)
+
+       You can see the kernel bit size test method in the aix
+       stanza of the lsof Configure script and in the get_kernel_access()
+       function of the lsof .../dialects/aix/dproc.c source file.
+
+       There is more information on pre-defining the kernel bit
+       size when building lsof in Configure, 00PORTING, and
+       00XCONFIG.
+
+       The only work-around is to use an lsof binary built to
+       match the running kernel bit size.
+
+4.13   What can't gcc be used to compile lsof on the ia64 architecture
+       for AIX 5 and above?
+
+       Gcc can't be used to compile lsof on the ia64 architecture
+       for AIX 5 and above because I haven't had access to a system
+       that has a working gcc compiler.  The gcc compiler on my
+       one and only ia64 AIX 5.1 test system, provided by IBM,
+       didn't work at all.
+
+4.14   Why does lsof get a segmentation fault when compiled with gcc
+       for a 64 bit Power architecture AIX 5.1 kernel?
+
+       When lsof is configured with the lsof "aixgcc" Configure
+       abbreviation, the resulting lsof executable may cause a
+       segmentation violation when it is run.  I've observed this
+       with gcc version 2.9-aix43-010414-7.
+
+       As far as I have been able to tell, the segmentation fault
+       is the result of a gcc compilation, loading, or library
+       error.  Watching lsof run with gcc's companion debugger,
+       gdb, shows no error in the lsof source code that might
+       explain the fault.
+
+       The only work-around I know is to use the IBM C compiler
+       in place of gcc -- i.e., use the "aix" lsof Configure
+       abbreviation.
+
+4.15   Why does lsof ignore AFS on my AIX system?
+
+       The lsof Configure script quits on AIX when AFS is present,
+       the AIX version is greater than 4.3.3.0 or the AFS version
+       is greater than 3.5.  That's because I have no test systems
+       available for those AIX and AFS version combinations.
+
+       When the lsof Configure script detects an AIX and AFS
+       version combination that is unsupported, it will report:
+
+         !!!FATAL: Lsof does not support AFS on this combination of
+                   AIX and AFS versions.  To disable AFS, set the
+                   value of the AIX_HAS_AFS environment variable to
+                   "no".
+
+       The only work-around is to set the AIX_HAS_AFS environment
+       variable as explained in the error message:
+
+           $ AIX_HAS_NSF=no; export AIX_HAS_NFS
+           $ ./Configure -n aix
+
+4.16   Why does lsof report "system paging space is low" and exit?
+
+       When AIX paging space runs low, the AIX kernel sends a SIGDANGER
+       signal to processes, warning them that they should reduce their
+       memory usage.
+
+       When lsof receives that signal, it issues the following fatal
+       error message and exits:
+
+           lsof: FATAL: system paging space is low.
+
+       A possible work-around is to limit the amount of information
+       lsof must cache in its process memory with the "-c", "-g", "-l"
+       and "-p" options.
+
+       Also see the answer to the "What can be done when lsof reports
+       no more space?" question.
+
+4.17    Why does lsof have a compilation problem on AIX 5.3 above
+       maintenance level 1?
+
+       On some AIX 5.3 systems with maintenance levels 2 and higher
+       installed, lsof 4.77 and below may not compile properly.  The
+       compiler complains the snapshotObject structure definition,
+       needed by <j2/j2_inode.h>, is missing.
+
+       That problem is fixed in the 4.78 revision.
+
+
+5.0    Apple Darwin Problems
+
+5.1    What do /dev/kmem-based and libproc-based mean?
+
+       Lsof for Apple Darwin currently uses /dev/kmem to read kernel
+       data structures from which it gathers and reports open file
+       information.  That version of lsof is called /dev/kmem-based
+       lsof.
+
+       At an upcoming release lsof will use a library called libproc
+       to obtain information about open files.  That version of lsof
+       wil be called libproc-based lsof.
+
+       The /dev/kmem-based lsof sources may be found in the kmem
+       subdirectory of the dialects/darwin branch of the lsof source
+       tree.  When the supporting version of Apple Darwin is released,
+       the libproc-based lsof sources will be found in
+       .../dialects/darwin/libproc.
+
+5.2    /dev/kmem-based Apple Darwin Questions
+
+5.2.1  Why does Configure ask for a path to the Darwin XNU kernel
+       header files?
+
+       When lsof was ported to Apple Darwin by Allan Nathanson at
+       revision 4.53, some kernel header files needed by lsof
+       weren't being exported by the developers.  (That's still
+       true at lsof revision 4.76.)
+
+       At first a shell script that Allan provided would get the
+       missing header files by checking them out from the CVS
+       root.  Although the script was updated from time to time,
+       eventually the re-organization of Darwin sources has made
+       it impossible to update the script to do an automatic
+       download of the missing header files.
+
+       At lsof revision 4.69 and above it is necessary for the Darwin
+       lsof builder to download the Darwin XNU kernel headers before
+       attempting to build lsof.  The download my be done via a web
+       browser, starting at this URL:
+
+           http://www.opensource.apple.com/darwinsource/index.html
+
+       Once there, select the link to the Mac OS X version that
+       matches the one on the system where lsof is to be built.
+
+       Follow that link's "[ Source ]" link.  Once there, select the
+       tar.gz link of the xnu* entry near the bottom of the page.
+       That entry should have a name that matches the xnu* name shown
+       by `uname -a` -- e.g., if uname reports:
+
+           $ uname -a
+           ... root:xnu/xnu-517.7.21 ...
+
+       Then the appropriate xnu* entry is xnu-517.7.21.  Clicking
+       its link should lead to an "Apple Open Source" page requesting
+       an Apple ID and password.
+
+       Enter them if they're available.  If an Apple ID and password
+       are not available, get them by following the instructions on
+       the page -- i.e., follow the signin.apple.com link.
+
+       Once a valid Apple ID and its password have been entered,
+       the download will begin.  Select the saving of the downloaded
+       xnu*.tar.gz file in an appropriate place on the Mac OS X
+       system.
+
+       Once the download completes, install it.  Use gunzip to
+       decompress the download and tar to extract the archive -- e.g.,
+
+           $ gunzip -c xnu-517.7.21.tar.gz | tar xf -
+
+       Remember the absolute path to the extracted archive.  That is
+       its installed place.  E.g., if the xnu-517.7.21.tar archive was
+       extracted to the lsof builder's home directory, its full
+       installation path will be something like:
+
+           ~/xnu-517.7.21
+
+       Now run the lsof Configure script.  When it asks for the path
+       to the installed Darwin XNU kernel header files, supply the
+       path to the gunzip'd and extracted xnu* archive -- e.g.,
+       ~/xnu-517.7.21.
+
+       The path to the Darwin XNU kernel headers may also be
+       supplied to the Configure script in the DARWIN_XNUDIR
+       environment variable, eliminating the need to enter it
+       interactively -- e.g.,
+
+           $ DARWIN_XNUDIR=~/xnu-344.49 ./Configure -n darwin
+
+5.2.1.1        Why does Configure complain that Darwin XNU kernel header
+       files are missing?
+
+       These are some reasons why the lsof Configure script might
+       claim that Darwin XNU header files are missing:
+
+           * The wrong path to them was specified.
+
+           * The files and directories in the path are not readable
+             and searchable -- i.e., check the modes and ownerships.
+
+           * The downloaded archive doesn't match the Mac OS X
+             version of the system.
+
+       If in doubt, revisit the Darwin XNU kernel header file
+       download instructions in the answer to the question "Why
+       does Configure ask for a path to the Darwin XNU kernel
+       header files?"
+
+       If Configure still can't find Darwin XNU kernel header
+       files, contact me via e-mail at <abe@purdue.edu> for help.
+       Make sure "lsof" appears in the "Subject:" line so my e-mail
+       filter won't classify your letter as Spam.
+
+5.2.2  Why doesn't Apple Darwin lsof report text file information?
+
+       At the first port of lsof to Apple Darwin, revision 4.53,
+       insufficient information was available -- logic and header
+       files -- to permit the installation of VM space scanning
+       for text files.  As of lsof 4.70 it is sill not available.
+
+       Text file support will be added to Apple Darwin lsof after
+       the necessary information becomes available.
+
+5.2.3  Why doesn't Apple Darwin lsof support IPv6?
+
+       At the first port of lsof to Apple Darwin, revision 4.53,
+       Apple Darwin lacked IPv6 support.  IPv6 became available
+       in Apple Darwin version 1.5 and support for it was added
+       to lsof then.
+
+5.2.4  Why does lsof complain about a mismatch between the release
+       for which lsof was compiled and the booted Mac OS X release?
+
+       When lsof is started on the "Gold Master" Darwin release
+       (aka Mac OS X), it complains:
+
+           lsof: compiled for 1.0 release; this is 1.3.2.
+
+       This happens because the lsof binary released with Mac OS
+       X was built on a system whose release number (1.0) doesn't
+       match that of the released system -- usually 1.3.x  Lsof
+       makes this check because UNIX dialect OS changes are often
+       accompanied by header file changes that affect lsof.
+
+       In this specific case, this error can be ignored.  If you
+       don't want to do that, get the lsof distribution and build
+       lsof so its built-on and running-on Mac OS X release numbers
+       match.
+
+5.2.5  Why does lsof for Apple Darwin 8 and higher report
+       "stat(...): ..." in the NAME column?
+
+       Lsof for Apple Darwin 8 may report messages like these in the
+       NAME column:
+
+           stat(/private/var/run/asl_prune): No such file or directory
+        or
+           stat(/private/var/db/netinfo/local.nidb/Config): Permission denied
+
+       Those messages indicate that lsof was unable to collect open
+       file information for the paths enclosed in "stat(...)" with the
+       stat(2) function, because the function encountered the reported
+       error.
+
+       A work-around for the "Permission denied" error is to run lsof
+       with elevated privileges -- e.g., when logged on as the super
+       user.
+
+       If the stat(2) error message is "No such file or directory",
+       the file probably has been unlinked (removed) and there is no
+       lsof work-around.
+
+5.2.6  What are the limitations of Apple Darwin lsof link count
+       reporting?
+
+       Lsof for Apple Darwin cannot report link count information
+       reliably.
+
+       For Apple Darwin below 8 link count information is not always
+       available in the kernel node structures available to lsof.
+       When link count information is available, however, it includes
+       link counts of zero.  Thus, using lsof's +L1 option may result
+       in the finding of some files whose link counts are zero.
+
+       Lsof can report only some link count information for Apple
+       Darwin 8 and above.  Link count information is only available
+       for files where lsof can assemble the full file path and has
+       permission to apply stat(2) to it.  (See the answer to the "Why
+       does lsof for Apple Darwin 8 and higher report "stat(...): ..."
+       in the NAME column?" question for more information on stat(2)
+       failures.)
+
+       Apple Darwin 8 and above files that have been unlinked and thus
+       have a link count of zero cannot be found by stat(2) -- i.e.,
+       stat(2) returns a "No such file or directory" error.  As a
+       result lsof never displays link counts of zero and the use of
+       lsof's +L1 option to find them always fails.
+
+5.2.7  Why does Apple Darwin report process group IDs incorrectly?"
+
+       The kmem version of lsof for Apple Darwin does not report
+       process group IDs correctly when requested to do so with its
+       ``-g'' option.  This is a bug that surfaced after the libproc
+       version was released and access to kmem test systems has
+       prevented patching the bug.
+
+       If you are using the kmem version and would like a fix for this
+       problem, please send e-mail to me <abe@purdue.edu>.  Make sure
+       "lsof" appears in the "Subject:" line so my e-mail filter won't
+       classify your letter as Spam.
+
+5.3    Libproc-based Apple Darwin Questions
+
+
+6.0    BSD/OS BSDI Problems
+
+6.0.5  Statement of deprecation
+
+       As of lsof revision 4.76 support for BSDI BSD/OS has been
+       dropped.  The 4.76 distribution of lsof for BSDI BSD/OS may be
+       found on lsof.itap.purdue.edu in pub/tools/unix/lsof/OLD/src.
+
+8.0    FreeBSD Problems
+
+8.1    Why doesn't lsof report on open kernfs files?
+
+       Lsof doesn't report on open FreeBSD kernfs files because
+       the structures lsof needs aren't defined in the kernfs.h
+       header file in /sys/misc/kernfs.
+
+8.2    Why doesn't lsof work on my FreeBSD system?
+
+       If lsof doesn't work on your FreeBSD system, first make
+       sure you have the latest lsof revision.  See the answer to
+       the "Where do I get lsof?" question for information on how
+       to get the latest lsof revision.
+
+       Once you have gotten the latest lsof revision, Configure
+       and make it.  If Configure fails -- e.g., it complains
+       about an unknown FreeBSD version -- then lsof probably
+       hasn't been ported to your FreeBSD version yet, and there's
+       no need to go any further.  Follow the answer to the "How
+       do I report an lsof bug" to report the Configure complaint
+       to me.
+
+       If you are able to Configure and make lsof, run its test
+       suite.  (See the answer to the "Is there a test suite?"
+       question for more information on how to use lsof's test
+       suite.)
+
+       If lsof still fails, make sure your kernel sources, kernel
+       header files, kernel boot file, standard header files and
+       libraries are synchronized.  They should all be built from the
+       same CVS refresh.  (Don't forget to do a "make buildworld"
+       followed by a "make installworld".)  If they aren't, then the
+       KVM library or lsof may be using kernel structure definitions
+       that don't match the booted kernel; or lsof may fail to compile
+       properly because of header files in /usr/src/sys/sys and
+       /usr/include/sys that don't match.
+
+       If you have synchronized your kernel, header files and
+       libraries, and still can't get lsof to work, follow the
+       steps in the answer to the "How do I report an lsof bug"
+       question to report the problem to me.
+
+8.3    Why doesn't lsof work on the RELEASE version of CURRENT?
+
+       Lsof tracks the CURRENT release of the current leading edge
+       FreeBSD version, because my access to leading edge FreeBSD is
+       limited to FreeBDSD.org reference systems, all running the
+       CURRENT release.
+
+       Sometimes that tracking leads to changes in lsof that won't
+       work on an earlier RELEASE version of the current leading edge
+       version.
+
+       When that happens, please send e-mail to me <abe@purdue.edu>.
+       Make sure "lsof" appears in the "Subject:" line so my e-mail
+       filter won't classify your letter as Spam.
+
+8.4    Why does kvm_open() complain it can't find some file?
+
+       If lsof issues this complaint:
+
+           lsof: kvm_open(execfile=/boot/kernel/kernel,
+                 corefile=/dev/mem: No such file or directory
+
+       Your FreeBSD system might not have a /dev/mem device.  If
+       not, create one -- e.g., as root do:
+
+           # mknod /dev/mem c <major> 0
+           # chmod 440 /dev/mem
+           # chgrp kmem /dev/mem
+
+       For <major> use /dev/kmem's major device number.
+
+       You may have to run kldload, too -- again as root do:
+
+           # kldload mem
+
+8.5    FreeBSD ZFS Problems
+
+8.5.1  Why does FreeBSD lsof report "WARNING: no ZFS support has been
+       defined."?
+
+       Lsof issues that message when it detects a file on a ZFS file
+       system, but has not been built with support for ZFS.  Lsof's
+       Configure script detects support can be added for ZFS when it
+       finds this file:
+
+       /usr/src/sys/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_znode.h
+
+       That header file and others in the OpenSolaris files in
+       /usr/src enable lsof to extract information about ZFS files
+       from the kernel structures associated with them.
+
+8.6    Why can't Configure create lsof_owner.h for FreeBSD 6 and above?
+
+       Lsof may report:
+
+           Creating ./lockf_owner.h from /usr/src/sys/kern/kern_lockf.c
+           FATAL ERROR: can't read /usr/src/sys/kern/kern_lockf.c
+           FATAL ERROR: ./lockf_owner.h creation failed (see 00FAQ)
+       or
+           Creating ./lockf_owner.h from /usr/src/sys/kern/kern_lockf.c
+           FATAL ERROR: ./lockf_owner.h creation failed (see 00FAQ)
+
+       Those messages mean that lsof's Configure script failed to
+       create a local header file, ./lockf_owner.h, needed to use the
+       new kernel file locking code of some versions of FreeBSD 6 and
+       above.
+
+       The changes that implement that new locking code alter the
+       lockf structure in <sys/lockf.h> and introduce a new structure,
+       lockf_entry, to that header file.  When Configure detects the
+       presence of the lockf_entry definition in <sys/lockf.h>, it
+       tries to construct the local header file, ./lockf_owner.h.
+
+       Configure has to do that  because an unfortunate side effect of
+       the new kernel file locking code is that <sys/lockf.h> doesn't
+       contain the lockf_owner structure definition referenced in its
+       own lockf structure.  Lsof needs to access elements of that
+       lockf_owner structure to determine if a lock belongs to the
+       process that has a file open.
+
+       The missing lockf_owner structure definition is in the kernel
+       source file, typically /usr/src/sys/kern/kern_lockf.c.
+       Configure tries to extract the lockf_owner structure definition
+       from kern_lockf.c into lsof's local header file, ./lockf_owner.h.
+       If Configure can't do that, it reports:
+
+           FATAL ERROR: ./lockf_owner.h creation failed
+
+       If Configure can't even read kern_lockf.c, it first reports:
+
+           FATAL ERROR: can't read /usr/src/sys/kern/kern_lockf.c
+
+       The work-around for this problem is to update the FreeBSD
+       kernel /usr/src tree (e.g., do a CVSup or csup) on the system
+       where lsof is to be built and then do a "make buildworld"
+       followed by a "make installworld".
+
+8.6.1  Why are there lockf structure compiler errors for FreeBSD 6.0
+       and higher lsof?
+
+       If, when compiling lsof, the compiler complains with error
+       messages like:
+
+           dnode.c: In function 'get_lock_state':
+           dnode.c:113: error: 'struct lockf' has no member named 'lf_flags'
+           dnode.c:115: error: 'struct lockf' has no member named 'lf_id'
+           ...
+
+       Then lsof is being built on a system that has new kernel file
+       locking code and lsof's Configure script failed to build a
+       local lockf_owner.h header file with a structure definition
+       lsof needs.
+
+       See the "Why can't Configure create lsof_owner.h for FreeBSD 6
+       and above?" section for more information and a work-around.
+
+8.6.2  Why don't /usr/src/sys/sys/lockf.h and /usr/include/sys/lockf.h
+       match?
+
+       This mismatch can cause the errors explained in the answer to
+       the "Why are there lockf structure compiler errors for FreeBSD
+       6.0 and higher lsof?" question.
+
+       If /usr/src/sys/sys/lockf.h has been updated with a CVSup or
+       csup, the new lockf.h won't be propagated to /usr/include/sys
+       until the "make buildworld" and "make installworld" steps have
+       been completed.
+
+8.7    FreeBSD and clang
+
+       As of lsof revision 4.87, lsof may be compiled with clang.
+
+8.7.1  Why does clang complain about VOP_FSYNC?
+
+       There is an error in the Solaris ZFS compatibility vnode.h
+       header file with use of VOP_FSYNC before it is defined.  No
+       work-around is possible that will eliminate the clang
+       compile-time warning message about the invalid declaration of
+       the VOP_FSYNC function.
+
+
+9.0    HP-UX Problems
+
+9.1    What do /dev/kmem-based and PSTAT-based mean?
+
+       Lsof for HP-UX 11.0 and below uses /dev/kmem to read kernel
+       data structures from which it gathers and reports open file
+       information.  That version of lsof is called /dev/kmem-based
+       lsof.
+
+       Starting with HP-UX 10.10, finding definitions for the
+       necessary kernel structures became more difficult as HP no
+       longer distributed header files in /usr/include that defined
+       all kernel structures.  So I started "inventing" structure
+       definitions by using Q4 to display them.
+
+       By HP-UX 11, the process of invention became extremely
+       intensive to support.  Following a patch to the ipc_s
+       structure in early 1999, my invented definition of that
+       structure became incorrect.  Although I was able to devise
+       a work-around test for the patch with Q4, it was clear that
+       my inventions were bound to cause more problems.
+
+       Discussion with HP about the patch led to my proposing that
+       an lsof API in the HP-UX kernel was the proper solution.
+       Much to my surprise, HP agreed.  I believe Carl Davidson
+       was the prime mover behind that decision, but I know others
+       participated, among them Louis Huemiller, Rich Rauenzahn,
+       and Sailu Yallapragada.  I am indebted to these folks and
+       HP for their willingness to do this work.
+
+       The API was added to the PSTAT interface in a project named
+       PEGL, Pstat Enhancements for Glance and Lsof.  Louis and
+       Sailu did the bulk of the design and implementation work
+       and testing began in March, 2000
+
+       HP-UX 11.11 is the first version that provides PSTAT support
+       for lsof.  HP-UX versions in between 11.0 and 11.11 -- all
+       Beta versions as far as I can determine -- have no lsof
+       support.
+
+       See the "PSTAT-based HP-UX lsof Questions" section for
+       questions and answers specific to PSTAT-based HP-UX lsof.
+       The next section, "Why doesn't a /dev/kmem-based HP-UX lsof
+       compilation use -O?" covers /dev/kmem-based HP-UX lsof.
+
+       The /dev/kmem-based lsof sources may be found in the kmem
+       subdirectory of the dialects/hpux branch of the lsof source
+       tree.  The PSTAT-based lsof sources may be found in
+       .../dialects/hpux/pstat.
+
+9.2    /dev/kmem-based HP-UX lsof Questions
+
+       The sources for /dev/kmem-based lsof for HP-UX may be found
+       in lsof_<revision>/dialects/hpux/kmem.
+
+       Lsof's Configure shell script decides to use these sources
+       when it finds that the /usr/include/sys/pstat subdirectory
+       doesn't exist.
+
+       Lsof can be forced to use the /dev/kmem sources by setting
+       "/dev/kmem" in the HPUX_BASE environment variable.  Consult
+       the Configure shell script and 00XPORTING for more information.
+
+9.2.1  Why doesn't a /dev/kmem-based HP-UX lsof compilation use -O?
+
+       If you only have the standard (bundled) HP-UX C compiler
+       and haven't purchased and installed the optional one, then
+       you can't use cc's -O option.  The HP-UX cc(1) man page
+       says this:
+
+         "Options
+            Note that in the following list, the cc and c89 options
+            -A , -G , -g , -O , -p , -v , -y , +z , and +Z are
+            not supported by the C compiler provided as part of
+            the standard HP-UX operating system.  They are supported
+            by the C compiler sold as an optional separate product."
+
+       Lsof's Configure script tries to detect what C compiler
+       product you have installed by examining your compiler.  If
+       that examination reveals a standard (bundled) compiler,
+       lsof avoids using -O.
+
+       If the Configure compiler test fails, the C compiler will
+       complain that it doesn't support -O.  You can suppress that
+       complaint with this make invocation:
+
+           $ make DEBUG=""
+
+9.2.2  Why doesn't the /dev/kmem-based CCITT support work under 10.x?
+
+       Pasi Kaara, who originally provided the HP-UX CCITT support,
+       reports that it no longer works under HP-UX 10.x.
+       Consequently, at lsof revision 4.02 it has been disabled.
+
+9.2.3  Why can't /dev/kmem-based lsof be compiled with `cc -Aa` or
+       `gcc -ansi` under HP-UX 10.x?
+
+       Some HP-UX 10.x header files, needed by lsof, can't be
+       compiled properly in ANSI_C mode; structure element definition
+       and alignment problems result.  The f_offset member of the
+       file structure, for example, is incorrect.
+
+       This ANSI-C obstacle extends to using the -Aa option of
+       the HP C compiler and the -ansi option of gcc.
+
+9.2.4  Why does /dev/kmem-based lsof complain about no C compiler?
+
+       Lsof's Configure script looks in /bin and /usr/ccs/bin for
+       an HP C compiler, because it needs to know if the compiler
+       is the standard (bundled) one or the optional separate
+       product.  If it finds no compiler in either place, Configure
+       quits after complaining:
+
+           No executable cc in /bin or /usr/ccs/bin
+
+       If you don't have a C compiler in either of these standard
+       places, you should consider installing it.  If you have
+       gcc installed, you can use it by declaring the ``hpuxgcc''
+       abbreviation to lsof's Configure script.
+
+       If you have a C compiler in a non-standard location, you
+       can use the HPUX_CCDIR[12] environment variables to name
+       the path to it.  Consult the 00XCONFIG file of the lsof
+       distribution for more information.
+
+9.2.5  Why does Configure complain about q4 for /dev/kmem-based lsof
+       for HP-UX 11?
+
+       When you run Configure on an HP-UX 11 system, it may complain:
+
+         !!!ERROR!!!     !!!ERROR!!!     !!!ERROR!!!     !!!ERROR!!!
+         Configure can't use /usr/contrib/bin/q4 to examine the ipis_s
+         structure.  You must do that yourself, report the result in
+         the HPUX_IPC_S_PATCH environment variable, then repeat the
+         Configure step.  Consult the Configure script's use of
+         /usr/contrib/bin/q4 and the 00XCONFIG file for information
+         on ipis_s testing and the setting of HPUX_IPC_S_PATCH.
+         !!!ERROR!!!     !!!ERROR!!!     !!!ERROR!!!     !!!ERROR!!!
+
+       This message states that Configure cannot use q4 from
+       /usr/contrib/bin to examine the kernel's boot image for
+       the ipis_s structure.  Maybe q4 hasn't been installed, or
+       perhaps Configure can't execute it.
+
+       Lsof needs to gather information about ipis_s to determine
+       if the ipis_s structure is defined in the kernel boot image,
+       if the ipis_s structure of the kernel boot image has an
+       ipis_msgsqueued member, and if the ipc_s structure of the
+       kernel boot image uses has an ipc_ipis member.
+
+       The ipis_s structure isn't described in any header file
+       HP-UX releases with HP-UX 11.  It appears in the private
+       lsof header file .../dialects/hpux/kmem/hpux11/ipc_s.h.
+       Lsof gets local and remote connection addresses (IP and
+       port numbers) from ipc_s, so an incorrect ipc_s definition
+       may cause incorrect reporting of TCP/IP connection addresses.
+       It definitely will cause incorrect reporting on 32 bit
+       kernels.  In any case lsof should be compiled with a correct
+       ipc_s definition no matter the kernel bit size, so the
+       Configure script always tests for it when the HP-UX version
+       is 11.
+
+       For lsof's Configure script to gather the necessary ipis_s
+       information q4 needs to be installed in /usr/contrib/bin
+       and the kernel boot image, /stand/vmunix, needs to have
+       been processed with pxdb.  If either is untrue, lsof issues
+       the above error message, perhaps preceded by q4 messages.
+       (Note: lsof's use of q4 may also fail if q4 can't execute
+       nm -- e.g., it can't find /usr/bin/nm, or there is a
+       conflicting, private version of nm earlier in the path.)
+
+       If /stand/vmunix hasn't been processed by pxdb, the q4
+       messages will include:
+
+           q4: (error) vmunix not pxdb'd
+       or
+           q4: (warning) /stand/vmunix has not been processed by pxdb.
+
+       It's possible to make a suitable private copy of /stand/vmunix
+       for configuring lsof.  That requires /opt/langtools/bin/pxdb
+       or the q4 version of pxdb from /usr/contrib/bin/q4pxdb.
+       The path to the result is supplied to the lsof Configure
+       script in the HPUX_BOOTFILE environment variable.  Configure
+       still requires /usr/contrib/bin/q4.
+
+       The following sample Bourne shell commands make a private
+       copy of /stand/vmunix in /tmp, process it with pxdb or
+       q4pxdb, and supply its path to lsof's Configure script in
+       HPUX_BOOTFILE.
+
+           $ cp /stand/vmunix /tmp/vmunix.lsof
+
+           $ /opt/langtools/bin/pxdb /tmp/vmunix.lsof
+         or
+           $ /usr/contrib/bin/q4pxdb /tmp/vmunix.lsof
+
+           ... pxdb messages ...
+           $ HPUX_BOOTFILE=/tmp/vmunix.lsof Configure -n hpux
+
+       It may also be necessary to use q4 outside the lsof Configure
+       script.  In that case q4 can be to determine the state of
+       ipis_s and ipc_s with these q4 commands:
+
+           $ /usr/contrib/bin/q4 /stand/vmunix
+           ...
+           q4> fields -c struct ipc_s
+           ...
+           q4> fields -c struct ipis_s
+
+       Look in the q4 output for the ipc_ipis member of the ipc_s
+       structure, and look in the q4 output for the ipis_s structure
+       for the ipis_msgsqueued member.  If ipc_s has ipc_ipis but
+       ipis_s lacks ipis_msgsqueued, set HPUX_IPC_S_PATCH environment
+       variable to "1".  If ipc_s has ipc_ipis and ipis_s has
+       ipis_msgsqueued, set HPUX_IPC_S_PATCH to "2" -- e.g.,
+
+           $ HPUX_IPC_S_PATCH=1 Configure -n hpux
+         or
+           $ HPUX_IPC_S_PATCH=2 Configure -n hpux
+
+       If ipc_s has no ipc_ipis member, set HPUX_IPC_S_PATCH to
+       "N" -- e.g., use this Configure step:
+
+           $ HPUX_IPC_S_PATCH=N Configure -n hpux
+
+9.2.6  When compiling /dev/kmem-based lsof for HP-UX 11 what do the
+       "aCC runtime: ERROR..." messages mean?
+
+       When the lsof Makefile asks the HP-UX unbundled compiler
+       to load lsof, it may complain:
+
+           /bin/cc -o lsof  -DHPUXV=1100 -DHASVXFS -DHPUXKERNBITS=64 \
+               -I/home/abe/src/lsof4/dialects/hpux/kmem/hpux11 +DD64 \
+               -DHAS_IPC_S_PATCH=2 -I/home/abe/src/lsof4/dialects/hpux/kmem \
+               -DLSOF_VSTR=\"B.11.00\"  -g dfile.o dmnt.o dnode.o dnode1.o \
+               dnode2.o dproc.o dsock.o  dstore.o  arg.o main.o misc.o \
+               node.o print.o proc.o store.o usage.o -L./lib -llsof  -lelf \
+               -lnsl
+           aCC runtime: ERROR: Unexpected use of shared libraries
+           aCC runtime: ERROR: Read aCC manpage, +A option
+           /usr/lib/nls/loc/locales.1//is_IS.iso88591
+
+       This is a bug in the HP-UX national language support.
+       (Notice the last message with "locales" in it?)  Complain
+       to HP -- then use this work-around before executing make:
+
+           $ unset LANG
+           $ make
+
+9.2.7  Why doesn't /dev/kmem-based lsof for HP-UX 11 report VxFS file
+       link counts, node numbers, and sizes correctly?
+
+       This is usually the result of running an lsof binary whose
+       revision number is less than 4.57 on a system that has
+       OnlineJFS support installed.  It can also happen with lsof
+       4.57 binaries when the OnlineJFS support with which they
+       were built doesn't match the OnlineJFS status of the system
+       on which they are run.
+
+       The OnlineJFS status of lsof 4.57 and higher binaries can
+       be determined by running:
+
+           $ lsof -v 2>&1 | grep HASONLINEJFS
+
+       If that shell pipe produces output, lsof was compiled with
+       OnlineJFS support enabled; no output, disabled.
+
+       If OnlineJFS is installed on an HP-UX 11 system the
+       /sbin/fs/vxfs/subtype executable exists and outputs "vxfs3.3"
+       when run.
+
+       The problem occurs because the optional OnlineJFS support
+       installation doesn't update <sys/fs/vx_inode.h>.  Consequently
+       lsof can be compiled with an incorrect definition of the
+       vx_inode structure and look for for link counts, node
+       numbers, and sizes in the wrong places in the structure.
+
+       The current response I have gotten from HP is that no
+       <sys/fs/vx_inode.h> update will be provided for OnlineJFS.
+
+       I've addressed this problem temporarily with a work-around
+       (hack) in lsof revision 4.57.
+
+9.2.8  Why can't /dev/kmem-based lsof be built with gcc for 64 bit
+       HP-UX 11?
+
+       When Configure is given the "hpuxgcc" abbreviation, the
+       HP-UX version is 11, and the kernel bit size is 64, the
+       lsof Configure script may abort with the messages:
+
+           !!!!!!!!!!!!!!!!! FATAL ERROR !!!!!!!!!!!!!!!!!!
+
+           APPARENTLY GCC CANNOT BUILD 64 BIT EXECUTABLES.
+           A COMPILER MUST BE USED THAT CAN.  SEE 00FAQ
+           FOR MORE INFORMATION.
+
+       (This is the "more information" in 00FAQ.)
+
+       This means the Configure script compiled a test program
+       with gcc the result wasn't an ELF-64 binary.  Lsof tries
+       two gcc modes, one with no options and another with the
+       -mlp64 option, before it concludes gcc can't be used.
+
+       See the "How can I acquire a gcc for building lsof for 64
+       bit HP-UX 11?" answer for information on where you might
+       be able to get a gcc for HP-UX 11 that can produce ELF-64
+       executables.
+
+9.2.8.1        How can I acquire a gcc for building lsof for 64 bit HP-UX 11?
+
+       Check this HP URL:
+
+         http://h21007.www2.hp.com/dspp/tech/tech_TechSoftwareDetailPage_IDX/1,1703,547,00.html
+
+       (That's one very long link; be careful you cut 'n paste it
+       all.)
+
+       In November 2001 that URL led to a web page whose title
+       was "gcc for hp-ux 11."  The page offered a link for
+       downloading a 64 bit gcc 3.0 compiler for HP-UX 11.0 and
+       11i.  Rich Rauenzahn of HP installed that compiler on an
+       HP test system he allows me to use and I successfully built
+       a 64 bit lsof with it.
+
+       The HP package may install the 64 bit capable gcc in
+       /usr/local/pa20_64/bin/gcc, so you may have to adjust your
+       path or set the LSOF_CC environment variable to compensate.
+
+9.2.9   Why does /dev/kmem-based lsof for HP-UX 11 report "unknown file
+       system type" for some open files?
+
+       The lsof binary being used probably doesn't have support for
+       the VxFS file system.
+
+       To confirm that, check `lsof -v` output for "-DHASVXFS".  If
+       it's not present, lsof doesn't have VxFS support.
+
+       You also need to establish that lsof really is complaining
+       about VxFS files by checking the kernel boot file for the
+       symbol associated with the hexadecimal address reported in the
+       "unknown file system type" message -- e.g., "v_op: 0x8711c8."
+       Use nm(1) to do that:
+
+           $ nm -x /stand/vmunix | grep 8711c8
+
+       If nm reports the symbol associated with the address is
+       vx_vnodeops, then lsof is complaining about an open VxFS file.
+
+       The solution in that case is to build lsof yourself (The
+       bundled C compiler will do it.), making sure that lsof's
+       Configure script detects the presence of VxFS.  Configure does
+       that by finding these two header files:
+
+           /usr/include/sys/fs/vx_hpux.h
+           /usr/include/sys/fs/vx_inode.h
+
+       If the system where you are building lsof doesn't have those
+       header files, but does have VxFS, you might be able to install
+       the header files by installing the HP JournalFS package from
+       the CoreOS CD -- in particular the file set JournalFS.VXFS-PRG
+       and its associated patch, PHKL_18543.  (My thanks to Steve
+       Bonds for that information.)
+
+       Finally, if you find that lsof isn't complaining about VxFS
+       when it complains about an unknown file system type, send
+       e-mail to me <abe@purdue.edu> for further assistance.  Make
+       sure "lsof" appears in the "Subject:" line so my e-mail filter
+       won't classify your letter as Spam.
+
+9.2.10 Why does the ANSI-C compiler complain about comments in HP-UX
+       11 header files?
+
+       When compiling lsof on HP-UX 11, the HP ANSI-C compiler's
+       pre-processor, cpp, may complain about comments in HP-UX header
+       files -- e.g.,
+
+           cpp: "/usr/include/sys/cdfs.h", line 232: warning 2028:
+               Found comment inside comment started on line 232.
+           cpp: "/usr/include/sys/cdnode.h", line 196: warning 2028:
+               Found comment inside comment started on line 196.
+           cpp: "/usr/include/nfs/snode.h", line 30: warning 2028:
+               Found comment inside comment started on line 30
+
+       This is not a problem with lsof.  It is a problem with the
+       HP-UX header files; they have non-compliant ANSI-C comment
+       sequences in them -- e.g.,
+
+           <sys/cdfs.h>: 232
+               /* struct  cdfs *cdfs_link;  /* linked list of file systems */
+
+       The initial "/*" is not terminated by an ending "*/" before the
+       appearance of a second "/*".
+
+9.2.11  Why does dnode1.c cause the HP-UX 11 compiler to complain that
+       <sys/fs/vx_inode.h> is missing or incorrect?
+
+       If CFLAGS in the lsof Makefile for an HP-UX 11 compilation
+       includes HASONLINEJFS, indicating the system has OnlineJFS
+       support, lsof needs the <sys/fs/vx_inode.h> header file.
+       Sometimes it is missing from /usr/include/sys/fs.
+
+       <sys/fs/vx_inode.h> is a header file that must be obtained from
+       Veritas.  If that proves impossible, please contact me via
+       e-mail at <abe@purdue.edu>.  Make sure "lsof" appears in the
+       "Subject:" line so my e-mail filter won't classify your letter
+       as Spam.
+
+
+9.3    PSTAT-based HP-UX lsof Questions
+
+       The sources for PSTAT-based lsof for HP-UX may be found in
+       lsof_<revision>/dialects/hpux/pstat.
+
+       Lsof's Configure shell script decides to use these sources
+       when it finds that the /usr/include/sys/pstat subdirectory
+       exists.
+
+       Lsof can be forced to use the PSTAT-based sources by setting
+       "pstat" in the HPUX_BASE environment variable.  Consult
+       the Configure shell script and 00XPORTING for more information.
+
+9.3.1  Why does PSTAT-based lsof complain about pst_static and
+       other PSTAT structures?
+
+       When lsof starts it may issue one of these fatal error
+       messages:
+
+           lsof: FATAL: can't determine PSTAT static size
+           lsof: FATAL: can't read <n> bytes of pst_static
+           lsof: FATAL: pst_static doesn't contain <name>_size
+           lsof: FATAL: <name>_size should be <n>
+
+       These messages indicate that lsof's tests for the proper
+       level of PSTAT support have failed.  The structure names,
+       given in <name>, and sizes, given in <n>, identify the
+       support deficiency more precisely.
+
+       You may need to upgrade the PSTAT support in your kernel
+       to be able to use PSTAT-based lsof.
+
+9.3.2  Why does PSTAT-based lsof complain it can't read pst_*
+       structures?
+
+       Lsof may put messages like the following in the NAME
+       column of its output.
+
+           can't read cwd pst_filedetails: Permission denied
+           can't read mem pst_filedetails: Permission denied
+           can't read rtd pst_filedetails: Permission denied
+           can't read txt pst_filedetails: Permission denied
+           can't read pst_filedetails: Permission denied
+           can't read 3 stream structures: Permission denied
+           can't read pst_socket: Permission denied
+
+       These messages indicate that the lsof binary lacks the
+       authority to read the name structures for processes other
+       than ones belonging to the UID under which lsof is running.
+       Authority to read the structures of other processes is
+       limited to root processes -- i.e., lsof must have setuid-root
+       permission if it is to list open files for arbitrary
+       processes.
+
+       If you want to eliminate these errors, you must run lsof
+       as root or install it with setuid-root permission.
+
+9.3.3  Why does PSTAT-based lsof rebuild the device cache file
+       after each reboot?
+
+       After each HP-UX rebuild, the first time a user runs lsof it
+       will report:
+
+           lsof: WARNING: device cache mismatch: /dev/tun...
+           lsof: WARNING: created device cache file: /<user_path>
+
+       This happens because the device numbers on /dev/tun* device
+       nodes are recalculated at each reboot.  When lsof detects
+       a change in the device number of a /dev/tun* file, it rebuilds
+       its local device cache file.
+
+9.3.4  Why doesn't PSTAT-based lsof report TCP addresses for
+       telnetd's open socket files?
+
+       When lsof can't report TCP addresses for telnetd's open
+       socket files it is because an unpatched PSTAT kernel
+       interface doesn't report the addresses to lsof.
+
+       This has been addressed in PSTAT kernel patch PHKL_24047.
+       It is available from the HP IT Resource Center at:
+
+           http://itrc.hp.com
+
+       In the page's "maintenance / support" box select the
+       "individual patches" link.  Once at its page, select the
+       "hp-ux" link.  On that page select the "Series 800" or
+       "Series 700" radio button and select "11.11" from the
+       pull-down list to the right of the button.  Under "search
+       or browse the path list" select "Search by Patch IDs" from
+       the pull down list, enter PHKL_24047 in the following text
+       box, and select search.  That should lead to information
+       about PHKL_24047 and a link for downloading it.  (You may
+       have to log in first and you may have to create a login
+       identity by registering before you can log in.)
+
+       Some time in March 2006 the PHKL_24047 patch was "lost"
+       by the HP-UX networking lab.  It has been "found" again
+       in August 2006 and will be re-released as a GRO patch
+       "some time."  I don't yet know when that will be.  You
+       must contact HP to learn about the availability of the
+       GRO patch.
+
+9.3.5  Why does PSTAT-based lsof cause an HP-UX 11.11 kernel panic?
+
+       When PSTAT-based lsof runs on some HP-UX 11.11 kernels,
+       the kernel may panic.  Symptoms include:
+
+         Console message:
+           0xFBE000301100EF00 00000000 0000EF00 -
+           type 31 = legacy PA HEX chassis-code
+
+         /var/adm/syslog:
+           ... vmunix: Trap Type 15 (Data page fault)
+           ... vmunix:   Instruction Address (pcsq.pcoq) = 0x...
+
+       The panic is caused by a bug in the way PSTAT's pstat_getstream()
+       function obtains module names from streams managed by the
+       otsam stream driver (part of OSI Transport Services).  Lsof
+       calls pstat_getstream() when it encounters an open otsam
+       stream file.  An HP-UX 11.11 system uses otsam if otsam
+       appears in /stand/system.
+
+       HP-UX 11.11 patch PHKL_24507 (available some time after
+       July 15, 2001) fixes the pstat_getstream() bug.  See the
+       information in the answer to the "Why doesn't PSTAT-based
+       lsof report TCP addresses for telnetd's open socket files?"
+       question for information on how to obtain the patch.
+
+9.3.6   Why doesn't PSTAT-based lsof report a CWD that is on a loopback
+       (LOFS) file system?
+
+       When PSTAT-based lsof reports on processes whose current
+       working directory (CWD) is on a loopback file system, lsof
+       can't report the open CWD file.  The reason is that the HP-UX
+       11.11 and above kernel's loopback file system code is not
+       passing the CWD file ID to the kernel's pstat(2) code.  Hence
+       lsof is given no information on the lofs CWD.
+
+       The problem was first reported to me by Ermin Borovac and an
+       internal bug report was filed with the HP-UX file system group
+       on October 26, 2004.  That report has now been answered by the
+       patch PHKL_33200 -- s700_800 11.11 lofs cumulative patch.  The
+       HP IT Resource Center (http://itrc.hp.com) is a source for the
+       patch.
+
+9.3.7  Why do some swinstall packages for PSTAT-based HP-UX 11.11
+       packages complain about setgid and setuid bits?
+
+       First, let me explain that I do not provide lsof swinstall
+       packages for lsof.  Others provide them and they should be
+       contacted about problems with their packages.
+
+       However, I have become aware of a problem with one package
+       about which I have some information I can share.  The problem
+       shows up in these swinstall messages:
+
+           ERROR:   Unknown owner and/or group for file
+                    "/usr/local/bin/lsof". SUID and/or SGID bit was
+                    not set.
+           ERROR:   Failed installing fileset "lsof.lsof-RUN,r=4.73".
+                    Check the above output for details.
+
+       The swpackage SUID/SGID functionality was restricted by changes
+       for POSIX compliance, breaking backward compatibility.  The
+       patch PHCO_27671 allows SUID/SGID for uid/gid of 0 only, as a
+       compromise between backward compatibility and POSIX conformance.
+
+       If the setuid bit is to be set on the executable, the UID and
+       GID of the executable must be 0 (zero).
+
+9.3.8  Why won't the bundled C compiler build PSTAT-based lsof for
+       PA-RISC HP-UX 11.23?
+
+       A PA-RISC HP-UX 11.23 bundled C compiler dated May 2005 or
+       later will not build PSTAT-based lsof.  It will deliver error
+       messages related to the system's <gssapi/gssapi.h> header
+       file.
+
+       There is nothing wrong with that header file or lsof.  The
+       problem is that the bundled C compiler can't cope with the
+       gssapi.h header file.
+
+       The work-around is to use the HP ANSI C compiler.   Using gcc
+       is not a satisfactory work-around.  See the answer to the "Why
+       won't gcc build PSTAT-based lsof for PA-RISC HP-UX 11.23?"
+       question for more information.
+
+9.3.9  Why won't gcc build PSTAT-based lsof for PA-RISC HP-UX 11.23?
+
+       Gcc will not even compile PSTAT-based lsof revisions below 4.77
+       for PA-RISC HP-UX 11.23 dated May 2005 or later.  It reports
+       errors in lsof's print.c fill_portmap() function about missing
+       members of the rpcent structure.  That happens because gcc
+       defines _XOPEN_SOURCE_EXTENDED which disables the definition of
+       the rpcent structure in <netdb.h>.
+
+       Using the HP bundled C compiler is not a viable work-around.
+       That is explained in the answer to the "Why won't the bundled C
+       compiler build PSTAT-based lsof for PA-RISC HP-UX 11.23?"
+
+       While an lsof revision 4.77 or higher can be compiled with gcc,
+       the results are unreliable.  Lsof will compile, but it
+       occasionally produces segment faults when it runs.  I have not
+       been able to reproduce the failure reliably or locate a
+       debugger that will work with the gcc-compiled lsof.
+
+       The only reliable work-around is to use the HP ANSI C
+       compiler.
+
+9.3.10 Why does PSTAT-based lsof complain, "FATAL: pst_stream_size
+       should be: 672; is 72" on HP-UX 11.11 and above?
+
+       This message indicates a mismatch between the PSTAT header
+       files used to build lsof (<sys/pstat.h> and those in the
+       /usr/include/sys/pstat subdirectory), and those that built the
+       running kernel.
+
+       Unfortunately the June 2008 patch set for HP-UX 11.23 creates
+       this inconsistency, because it does not contain all the patches
+       needed to match the kernel with the PSTAT header files.  Even
+       more serious is that the missing patches update the kernel's
+       PSTAT support to provide TCP/UDP endpoint information to lsof
+       from TCP/TLI streams.
+
+       The patch inconsistency comes about because, while the following
+       patch is installed,
+
+           PHKL_36577  1.0  PM-PSTAT section 2 manpage changes
+
+       other kernel patches are not.
+
+       The PHKL_36577 patch updates the PSTAT header files and manual
+       pages to match kernel changes that other patches with the
+       following numbers (or patches that contain or supersede them)
+       contain:
+
+           PHNE_36575  1.0  Cumulative STREAMS Patch
+           PHNE_37670  1.0  cumulative ARPA Transport patch
+           PHNE_37851  1.0  NFS cumulative patch
+
+       Those patches implement the kernel changes that support the
+       delivery of information promised in patch PHKL_36577.
+
+       The work-around is to install the missing patches.
+
+9.4    Why won't the HP-UX depot install?
+
+       I don't distribute lsof depots, so I can't support them.
+
+       From time to time depots prepared by various sites -- e.g.,
+       usually HP-UX software collection sites -- will contain errors
+       that cause installation of the depot to fail.
+
+       Do not contact me when this happens.  Instead, contact the
+       administrator of the site that prepared the depot.
+
+       As should be clear from the bulk of the lsof documentation, I
+       do not recommend you use pre-built lsof binaries in any form.
+       Instead, I recommend you obtain the lsof source distribution
+       and build lsof yourself.
+
+
+10.0   Linux
+
+10.1   What do /dev/kmem-based and /proc-based lsof mean?
+
+       At approximately Linux 2.1.72 and exactly at lsof revision
+       4.23 support for Linux forks.  The first fork, containing
+       the oldest lsof form is based on access to kernel memory
+       structures, and is called /dev/kmem-based lsof.  A
+       /dev/kmem-based lsof is heavily intertwined with the Linux
+       kernel version, its header files, and its system map file.
+       Typically a /dev/kmem-based lsof needs only setgid permission
+       to local all open file information.
+
+       After approximately Linux 2.1.72 and at revision 4.23 lsof
+       obtains all its information from the /proc file system.
+       That lsof is called the /proc-based lsof.  A /proc-based
+       lsof does not read kernel memory, needs neither kernel
+       header files nor the system map file, and is less likely
+       to be affected by Linux kernel changes.  However, it does
+       require setuid-root permission to list all open files, and
+       it can't report file offsets (positions).
+
+       After revision 4.52 the /dev/kmem-based Linux sources for
+       lsof are no longer distributed.  Information about them
+       may be found in the 00INDEX and README files at:
+
+           ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/OLD/src
+
+10.2   /proc-based Linux lsof Questions
+
+10.2.1 Why doesn't /proc-based lsof report file offsets (positions)?
+
+       /proc-based lsof revisions 4.79 and above can only report file
+       offsets (positions) for the files of Linux kernels 2.6.22 and
+       above.
+
+       During its initialization /proc-based lsof tests to see if
+       offset information can be obtained.  If it cannot, lsof
+       disables offset reporting.  If the -o option was selected, lsof
+       also issues this warning:
+
+           lsof: WARNING: can't report offset; disregarding -o.
+
+
+10.2.2 Why does /proc-based lsof report "can't identify protocol" for
+       some socket files?
+
+       /proc-based lsof may report:
+
+           COMMAND PID ... TYPE ... NODE NAME
+           pump    226 ... sock ...  309 can't identify protocol
+
+       This means that it can't identify the protocol (i.e., the
+       AF_* designation) being used by the open socket file.  Lsof
+       identifies protocols by matching the node number associated
+       with the /proc/<PID>/fd entry to the node numbers found in
+       selected files of the /proc/net sub-directory.  Currently
+       /proc-based lsof examines these protocol files:
+
+           /proc/net/ax25              (untested)
+           /proc/net/icmp
+           /proc/net/ipx               (needs kernel patch)
+           /proc/net/netlink
+           /proc/net/packet
+           /proc/net/raw
+           /proc/net/raw6
+           /proc/net/sctp/assocs
+           /proc/net/sctp/eps
+           /proc/net/sockstat
+           /proc/net/sockstat6
+           /proc/net/tcp
+           /proc/net/tcp6
+           /proc/net/udp
+           /proc/net/udp6
+           /proc/net/udplite
+           /proc/net/udplite6
+           /proc/net/unix
+
+       If /proc-based lsof says it can't identify the protocol
+       for an open socket file, you may be able to identify the
+       protocol yourself by using grep to look for the specific
+       node number in the files of /proc/net -- e.g.,
+
+           $ grep <node_number> /proc/net/*
+
+       You may not be able to find the desired node number, because
+       not all kernel protocol modules fully support /proc/net
+       information.
+
+       If you find a matching node number in a /proc/net file that is
+       not currently being processed by lsof, contact me via e-mail at
+       <abe@purdue.edu>.  I'll discuss adding support to /proc-based
+       lsof for the protocol of the /proc/net file with you.  Make
+       sure "lsof" appears in the "Subject:" line so my e-mail filter
+       won't classify your letter as Spam.
+
+       The code that matches node numbers of open IPX protocol
+       socket files to those in /proc/net/ipx requires Jonathan
+       Sergent's Linux 2.1.79 patch to /usr/src/linux/net/ipx/af_ipx.c.
+       The patch, suitable for input to Larry Wall's patch program,
+       may be found in the lsof distribution file:
+
+           .../dialects/linux/proc/patches/net_ipx_af_ipx.c.patch
+
+10.2.3 Why does /proc-based lsof warn about unsupported formats?
+
+       Lsof may issue the following warning:
+
+           lsof: WARNING: unsupported format: /proc/net/<file>
+
+       if the header line of the indicated <file> in /proc/net --
+       ax25, ipx, raw, tcp, udp, or unix -- doesn't match what
+       lsof expects to find.
+
+       When the header line of a /proc/net file isn't what lsof
+       expects, lsof probably can't parse the rest of the file
+       correctly and doesn't try.  As a result, lsof can't report
+       any NAME column information (e.g., local and remote addresses)
+       for socket files bound to the indicated network protocol.
+
+       If you get this warning, please send me e-mail at <abe@purdue.edu>.
+       Include the contents of the file lsof claims has an unsupported
+       format.  Make sure "lsof" appears in the "Subject:" line so my
+       e-mail filter won't classify your letter as Spam.
+
+10.2.4   Why does /proc-based lsof report "(deleted)" after a path name?
+
+       The "(deleted)" notation following a path name in /proc-based
+       lsof's NAME column comes from the /proc/<PID>/fd/<FD> entry
+       for the open file.  It's the Linux kernel's way of indicating
+       the file is open but has been unlinked (rm'd).
+
+10.2.5 Why doesn't /proc-based lsof report full open file information
+       for all processes?
+
+       /proc-based lsof can only report on processes whose /proc
+       files it has permission to read.  /proc normally grants
+       permission to read all its files only to root or to the
+       owning user ID.
+
+       Without permission to read most /proc files, lsof can only
+       report full information for processes belonging to the user
+       who is running lsof.  /proc-based lsof may be able to report
+       some information for all processes, depending on the
+       permissions of their associated /proc files, but usually
+       /proc-based lsof won't be able to access the files in
+       /proc/<PID>/fd/ that describe regular open files.
+
+       If you want /proc-based lsof to report on all processes, you
+       must install it with setuid-root permission.
+
+10.2.6 Why won't Customize offer to change HASDCACHE or WARNDEVACCESS
+       for /proc-based lsof?
+
+       /proc-based lsof doesn't read device information from /dev
+       or the device cache file, so it makes no sense to change
+       the state of device cache processing or /dev node accessibility
+       warnings.
+
+10.2.7 /proc-based lsof Linux NFS questions
+
+10.2.7.1 Why can't lsof find files on an accessible NFS file system?
+
+       On occasion lsof may be unable to identify that an open
+       file is on an NFS file system.  This is most likely the
+       result of a bug in the way the Linux kernel supplies
+       information to the reader of /proc/mounts (lsof) -- sometimes
+       that pseudo-file is truncated by the kernel.
+
+       One way to see if this is the case is to search for the
+       NFS file system in /proc/mounts -- e.g.,
+
+           $ grep <NFS_file_system_mount_point> /proc/mounts
+
+       If you get no output or the third word of the output isn't
+       "nfs", then lsof won't consider the file system an NFS file
+       system.
+
+       A second test is to look at the end of /proc/mounts --
+       e.g.,
+
+           $ tail /proc/mounts
+
+       If tail reports "# truncated" then /proc/mounts is incomplete
+       because of a Linux kernel bug.  The bug is documented at:
+
+           http://www.xss.co.at/sysinfo/mounts.html
+
+       The bug is fixed in Linux kernel 2.4.18, and possibly in
+       some earlier Linux kernel versions.
+
+10.2.7.2 Why can't lsof find files on an inaccessible NFS file system?
+
+       If lsof issues this message about a Linux file system,
+       mounted from an NFS server:
+
+           lsof: WARNING: can't stat() nfs file system /xxx/yyy
+
+       Then lsof won't be able to find any open files on the file
+       system.
+
+       That's because of an inadequacy in the Linux /proc file
+       system.  Its /proc/mounts file doesn't give the device
+       doublet (major and minor numbers) of the file system as do
+       many UNIX systems (e.g., Solaris).  The only way lsof can
+       get the device doublet for a Linux file system is to call
+       stat(2) on the file system path, which fails if the NFS
+       server isn't accessible.
+
+       When lsof doesn't know the device doublet of a file system,
+       it can't find open files on the inaccessible file system,
+       because it can't match the doublets of open files to the
+       doublet of the inaccessible file system.
+
+       This topic is covered extensively in lsof(8) it its ALTERNATE
+       DEVICE NUMBERS and BLOCKS AND TIMEOUTS sections.
+
+10.2.8 Why doesn't /proc-based Linux lsof report socket options and
+       values, socket state flags, and TCP options and values?
+
+       The Linux /proc file system doesn't report socket options
+       and values, socket states, and TCP options and values to
+       lsof.
+
+10.2.9 Does /proc-based Linux lsof use a device cache?
+
+       No.  The Linux /proc/<PID>/fd/* entries provide device names to
+       lsof via readlink(2).  It is not necessary to enable device
+       cache processing for /proc-based Linux lsof via the Customize
+       script or modifications to the Linux machine.h header file.
+
+10.2.10        Why doesn't /proc-based Linux lsof report any or all file structure
+       values for its +fcfgGn option?
+
+       /proc-based lsof revisions 4.79 and above can only report some
+       file structure values for Linux kernels below 2.6.22.
+
+       When running on Linux kernels at 2.6.22 and above lsof 4.79 can
+       report some file flag values -- i.e., in response to the +fg or
+       +fG options.  The flag values are obtained from the
+       /proc/<PID>/fdinfo/ files introduced at Linux kernel 2.6.22.
+
+       /proc-based Linux lsof tests its availability to obtain file
+       flag values at initialization.  If values are not available,
+       lsof disables file flag reporting.  If the flags were requested
+       with +fg or +fG, lsof displays this warning:
+
+           lsof: WARNING: can't report file flags; disregarding +f.
+
+       As a special note, when Linux lsof can report flag bits, it
+       will not report 'R' for a read-only file.  There is no
+       read-only flag bit O_* symbol in <fcntl.h> (or <bits/fcntl.h>)
+       and lsof reports only bits that are set.  The absence of O_RDWR
+       and O_WRONLY flag bits implies the file is read-only.
+
+10.3   Special Linux file types
+
+10.3.1 Why is ``DEL'' reported as a Linux file type?
+
+       Lsof usually reports entries from the Linux /proc/<PID>/maps
+       file with ``mem'' in the TYPE column.  However, when lsof can't
+       stat(2) a path in the process' ``maps'' file and the ``maps''
+       file entry contains ``(deleted)'', indicating the file was
+       deleted after it had been opened, lsof reports the file type as
+       ``DEL''.
+
+10.3.2 Why is ``unknown'' reported as a Linux file type?
+
+       Lsof may report a Linux file's type as ``unknown'' in the TYPE
+       column when lsof can't obtain complete stat(2) results for the
+       file.
+
+       Usually the NAME column will contain a ``(stat: xxx)'' error
+       message, but that could have been suppressed with the lsof
+       ``-w'' option.
+
+10.4   Linux ``mem'' Entry Problems
+
+10.4.1  What do ``path dev=xxx'' and ``path inode=yyy'' mean in the
+       NAME column of Linux ``mem'' file types?
+
+       When the device or inode number in the process' ``maps'' file
+       entry doesn't match the stat(2) results from the file path,
+       lsof reports the inconsistent information from the stat(2) of
+       the path parenthetically after the path in the NAME column
+       in one of these forms:
+
+           (path dev=xxx)              only the device number,
+                                       ``xxx'', from a stat(2) of the
+                                       ``maps'' file entry path
+                                       differs from the ``maps'' file
+                                       entry value reported in the
+                                       DEVICE column.
+
+           (path inode=yyy)            only the inode number,
+                                       ``yyy'', from a stat(2) of the
+                                       ``maps'' file entry path
+                                       differs from the ``maps'' file
+                                       entry value reported in the
+                                       NODE column.
+
+           (path dev=xxx inode=yyy)    Both device and inode numbers
+                                       differ.
+
+       Lsof reports the ``maps'' file device number in the DEVICE
+       column and the inode number in the NODE column.
+
+       When device and inode mismatches occur, lsof suppresses the
+       reporting of link count and size.  See the answer to the "Why
+       is neither link count nor size reported for some Linux ``DEL''
+       and ``mem'' file types?" question for more information.
+
+       Device and inode inconsistencies can occur when a file at a
+       ``maps'' path is replaced after the process has started, or
+       when a different file system with similar path names is mounted
+       on top of the original file system.
+
+       The device inconsistency parenthetical messages can be
+       suppressed with lsof's ``-w'' option.
+
+10.4.2  Why is neither link count nor size reported for some Linux
+       ``DEL'' and ``mem'' file types?
+
+       Link count and size are not reported for some entries from the
+       process' ``maps'' file because a stat(2) of the entry file path
+       failed or stat(2) delivered device or inode numbers that don't
+       match the ones in the ``maps'' entry.
+
+       When the stat(2) device or inode numbers don't match those in
+       the ``maps'' file entry, it is likely that the stat(2) results
+       don't apply to the file that was originally mapped by the
+       process and whose path appears in the ``maps'' file entry, so
+       lsof tries to avoid reporting possibly incorrect information.
+
+       See the answer to the "What do ``path dev=xxx'' and ``path
+       inode=yyy'' mean in the NAME column of Linux ``mem'' file
+       types?" for more information on how mismatched stat(2) device
+       and inode numbers are reported.
+
+10.5   Special Linux NAME column messages
+
+10.5.1  What does ``(stat: xxx)'' mean in the NAME column of Linux
+       files?
+
+       When lsof tried to stat(2) the path in the NAME column, the
+       stat(2) system call failed and produced an error message of
+       ``xxx''.
+
+       This situation usually occurs if the lsof process lacks
+       permission to stat(2) the path -- e.g., the lsof executable
+       lacks root permission, or lsof is attempting to stat(2) a path
+       on an NFS device mounted with the root_squash option.
+
+       The message can be suppressed with lsof's ``-w'' option.
+
+10.5.2  What does ``(readlink: xxx)'' mean in the NAME column of
+       Linux files?
+
+       When lsof tried to convert the /proc/<PID>/fd path, reported in
+       the NAME column, to its full and more meaningful path, the
+       readlink(2) system call used to do the conversion failed.  The
+       readlink(2) failure message is ``xxx''.
+
+       This situation usually occurs if the lsof process lacks
+       permission to readlink(2) some part of the path -- e.g., the
+       lsof executable lacks root permission, or lsof is attempting to
+       stat(2) a path on an NFS device mounted with the root_squash
+       option.
+
+       The message can be suppressed with lsof's ``-w'' option.
+
+10.6   Why is ``NOFD'' reported as a Linux file type?
+
+       When lsof lacks permission to use opendir() on the fd/
+       subdirectory of a process' /proc/<PID> directory, it reports a
+       single file of the type ``NOFD'' (for no file descriptors).
+
+       Lsof reports the the /proc/<PID>/path in the NAME column,
+       followed by "(opendir: xxx)", where ``xxx'' is the error
+       message returned by opendir().
+
+       The ``NOFD'' entry can be suppressed with lsof's ``-w'' option.
+
+10.7    Why does Linux lsof report a NAME column value that begins with
+       ``/proc''?
+
+       When lsof has problems processing a ``/proc/<PID>'' entry --
+       e.g., it can't convert the entry to a full and more meaningful
+       path name, or it can't access the /proc/<PID>/fd subdirectory
+       with opendir() -- it will report the /proc/<PID> path in the
+       NAME column.
+
+10.8   Linux /proc/net/tcp* and /proc/net/udp* issues
+
+10.8.1 Why use the Linux -X option?
+
+       If you're not interested in TCP/IP socket information for a
+       particular use of lsof, adding the -X option will make lsof run
+       more quickly, because -X inhibits the reading of the
+       /proc/net/tcp* and /proc/net/udp* files.  For example, you may
+       only be interested in knowing what process has a particular
+       file open.
+
+       When the Linux system has a large number of open TCP/IP socket
+       files, the time savings provided by -X can be significant.
+
+10.8.2 Why does lsof say ``-i is useless when -X is specified''?
+
+       If -X is specified, lsof can't report much information on open
+       TCP/IP socket files.  However, lsof's -i option requests that
+       information.  Hence, the two options conflict and can't be used
+       together.
+
+10.8.3 Why does lsof say ``can't identify protocol (-X specified)''?
+
+       If the Linux lsof -X option is specified and an open socket
+       file can't be identified without accessing the /proc/net/tcp*
+       and /proc/net/udp* files, lsof will report that it can't
+       identify the socket's protocol and that the failure may be
+       caused by the -X specification
+
+
+11.0   NetBSD Problems
+
+11.1   Why doesn't lsof report on open kernfs files?
+
+       Lsof doesn't report on open NetBSD kernfs files because the
+       structures lsof needs aren't defined in the kernfs.h header
+       file in /sys/misc/kernfs.
+
+11.2   Why doesn't lsof report on open files on: file descriptor
+       file systems; /proc file systems; 9660 (CD-ROM) file systems;
+       MS-DOS (floppy disk) file systems; or kernel file systems?
+
+       Lsof is not able to report on open files on certain file
+       system if /usr/src/sys/msdosfs didn't exist when the lsof
+       Configure script ran and lsof was made.  /usr/src/sys/msdosfs
+       contains header files lsof needs for collecting data on
+       certain file system files.
+
+       You can tell if an lsof executable above) lacks support
+       for a file system if the following test of `lsof -v` produces
+       nothing:
+
+           $ lsof -v 2>&1 | grep <support_enabled_definition>
+
+       The <support-enabled_definition> will be:
+
+           File System Type    Definition      Note
+           ----------------    ----------      ----
+           File descriptor     HASFDESCFS
+           /proc               HASPROCFS
+           9660                HAS9660FS
+           MS-DOS              HASMSDOSFS      (lsof 4.61 and above)
+           Kernel              HASKERNFS
+
+       The work-around is to install /usr/src/sys, rerun the lsof
+       Configure script, and remake lsof.
+
+11.3    Why does lsof produce confusing results for nullfs file
+       systems?
+
+       Consider this report from /sbin/mount:
+
+           /usr/home on /home type null (local)
+
+       (According to /sbin/mount /usr/home is the mounted-on device
+       and /home is the mounted-on directory.)
+
+       When lsof is asked to report on open files on /home, it
+       will report them as files on /usr/home instead.  That's an
+       artifact of the NetBSD kernel's dynamic name lookup cache
+       (DNLC) and the way the kernel handles nullfs mounted-on
+       directories.
+
+       While lsof will report all open files on /home when given
+       /home as a file system directory argument, even though
+       reporting them as located on /usr/home, lsof will not find
+       the same files when asked to report on all open files on
+       /usr/home when given /usr/home as a file system device
+       argument.  That's because from the mount perspective
+       /usr/home is equivalent to a device, but from the device
+       perspective it is still a directory.
+
+       So, what this lsof command reports:
+
+           $ lsof /home
+           ... NAME
+           ... /usr/home/...
+
+       Won't be duplicated by this lsof command:
+
+           $ lsof /usr/home
+
+       Another way to look at this confusing /home and /usr/home
+       example is to consider what stat(2) reports.  For /home
+       stat(2) reports a device doublet that matches what lsof
+       finds in open file node structures, while the device doublet
+       stat(2) reports for /usr/home won't match what lsof finds.
+       Nor does the mode reported by stat(2) indicate a block
+       devices, as is the expected case.
+
+       There is no simple answer to this confusion, nor is there
+       even a simple explanation.  Simply be aware that when
+       supplying file system arguments to lsof on NetBSD, use the
+       mounted-on directory name for a nullfs as the lsof argument,
+       and don't be surprised when the NAME column reports the
+       mounted-on device name.
+
+11.4   NetBSD header file problems
+
+11.4.1 Why can't the compiler find some NetBSD header files?
+
+       If the compiler's pre-processor complains it can't find some
+       header files when it compiles lsof source files, /usr/include
+       and /usr/src may not have all the header files lsof needs.
+
+       As a work-around use the NETBSD_SYS environment variable
+       to specify to lsof the location of the additional header
+       files -- e.g.,
+
+           % setenv NETBSD_SYS /my_source
+           % ./Configure -n netbsd
+
+        or
+            $ NETBSD_SYS=/mys_source ./Configure -n netbsd
+
+       Caution: using this work-around may cause the lsof Configure
+       script to activate or omit different features, depending
+       on where it finds the header files that determine the state
+       of the features.
+
+11.4.2 Why does NetBSD lsof produce incorrect output?
+
+       If the NetBSD system's kernel was built from header files that
+       don't match those in /usr/include -- e.g., //usr/src has the
+       ones from which the kernel was built -- lsof may build, but
+       won't produce correct output.
+
+       As a possible work-around, try directing the C compiler to
+       select header files from /usr/src before it selects them from
+       /usr/include.  That can be done with the DEBUG make string --
+       e.g.,
+
+           $ make DEBUG="-I/usr/src -I/usr/include"
+
+       If that work-around fails, try using the LSOF_INCLUDE and
+       NETBSD_SYS environment variables to swap /usr/include and
+       /usr/src when running the Configure script, then use the make
+       DEBUG string when running make -- e.g.,
+
+           $ LSOF_INCLUDE=/usr/src; export LSOF_INCLUDE
+           $ NETBSD_SYS=/usr/include; export NETBSD_SYS
+           $ ./Configure -n netbsd
+           $ make DEBUG="-I/usr/src -I/usr/include"
+
+11.5   Why isn't lsof feature xxx enabled for NetBSD?
+
+       Lsof's Configure script enables NetBSD features by locating
+       and examining header files associated with the features,
+       and based on what it finds, setting compile-time definitions
+       in Makefiles.  (See 00PORTING for a list of the definitions.)
+
+       When Configure doesn't find header files or doesn't find
+       appropriate values in header files, that may mean the header
+       file tree lsof is searching is incomplete or out of date.
+
+       Lsof normally looks for NetBSD header files in /usr/include.
+       It can also be directed to look in other directories --
+       e.g., /sys -- if told to do so with the contents of the
+       LSOF_INCLUDE and NETBSD_SYS environment variables.
+
+       To determine what header file enables a missing feature,
+       check the NetBSD stanza in the Configure script.  Then
+       check the locations it checks for the indicated header
+       files and contents.
+
+       See 00XCONFIG for more information on LSOF_INCLUDE and
+       and NETBSD_SYS.
+
+
+13.0   OpenBSD Problems
+
+13.1   Why doesn't lsof support kernfs on my OpenBSD system?
+
+       Lsof supports the kernel file system on OpenBSD versions
+       whose /sys/miscfs/kernfs/kernfs.h (or <miscfs/kernfs/kernfs.h>
+       header file correctly defines the kern_target structure.
+       The lsof Configure script's openbsd stanza checks for the
+       presence of the structure's kt_name element and activates
+       kernfs support for the CFLAGS -DHASKERNFS definition only
+       when it finds kt_name.
+
+       The kernfs.h header file is scheduled to be updated in the
+       OpenBSD 2.1 release, according to Kenneth Stailey, who
+       authored its changes.
+
+13.2   Will lsof work on OpenBSD on non-x86-based architectures?
+
+       I've not tested lsof on an OpenBSD system that uses a
+       non-x86-based architecture, but I've had one report that
+       lsof 4.33 compiles and works on OpenBSD for the pmax
+       architecture (decstation 3100).
+
+13.3   <sys/pipe.h> problems
+
+13.3.1 Why does the compiler claim nbpg isn't defined?
+
+       When compiling lsof on some (older) OpenBSD SPARC versions,
+       the compiler may complain:
+
+           In file included from ../dlsof.h:191,
+                from ../lsof.h:166,
+                from fino.c:52:
+           /usr/include/sys/pipe.h:83: `nbpg' undeclared here
+                                       (not in a function)
+           /usr/include/sys/pipe.h:83: size of array `ms' has
+                                       non-integer type
+
+       This happens because <sys/pipe.h> uses NBPG from
+       <machine/param.h> to size the `ms' array, and some OpenBSD
+       systems define NBPG in terms of a kernel integer variable,
+       nbpg.
+
+       Lsof revisions 4.46 and above have a hack to dlsof.h,
+       developed by Volker Borchert that avoids the compiler
+       problem for SPARC OpenBSD 2.3.  The hack might work for
+       other OpenBSD SPARC versions, but hasn't been tested there.
+
+       If you want to enable the hack for your OpenBSD SPARC
+       version, modify this code in .../dialects/openbsd/dlsof.h:
+
+           # if    defined(OPENBSDV)
+           #  if   OPENBSDV==2030 && defined(__sparc__)
+           #   if  defined(nbpg)
+           #undef  nbpg
+           #   endif       /* defined(nbpg) */
+           #define nbpg    4096            /* WARNING!!!  ... */
+           #  endif        /* OPENBSDV==2030 && defined(__sparc__) */
+           #include <sys/pipe.h>
+           #endif  /* defined(OPENBSDV) */
+
+       You will probably want to change the second #if test to
+       match your OpenBSD version.  You may also want to change
+       what value is assigned to nbpg.  See the next section,
+       "What value should I assign to nbpg?"
+
+13.3.2 What value should I assign to nbpg?
+
+       If you need to enable the nbpg hack, described in "Why does
+       the compiler claim nbpg isn't defined?", you may also need
+       to assign a value other than 4096 to nbpg.  4096 works for
+       the sun4c processor and should work for sun4m, but 8192
+       may be needed for sun4.
+
+       Check <machine/param.h> and other OpenBSD documentation to
+       determine the correct nbpg assignment.
+
+13.4   Why doesn't lsof report on open MS-DOS file system (floppy
+       disk) files?
+
+       Lsof is not able to report on open MS-DOS file system files
+       if /usr/src/sys/msdosfs didn't exist when the lsof Configure
+       script ran and lsof was made.  /usr/src/sys/msdosfs contains
+       header files lsof needs for collecting data on MS-DOS file
+       system files.
+
+       You can tell if an lsof executable (revisions 4.61 and
+       above) lacks MS-DOS file system support if the following
+       command reports nothing:
+
+           $ lsof -v 2>&1 | grep HASMSDOSFS
+
+       The work-around is to install /usr/src/sys, rerun the lsof
+       Configure script, and remake lsof.
+
+13.5   Why isn't lsof feature xxx enabled for OpenBSD?
+
+       Lsof's Configure script enables OpenBSD features by locating
+       and examining header files associated with the features,
+       and based on what if finds, setting compile-time definitions
+       in Makefiles.  (See 00PORTING for a list of the definitions.)
+
+       When Configure doesn't find header files or doesn't find
+       appropriate values in header files, that may mean the header
+       file tree lsof is searching is incomplete or out of date.
+
+       Lsof normally looks for OpenBSD header files in /usr/include
+       and /sys.  It can also be directed to look in other
+       directories if told to do so with the contents of the
+       LSOF_INCLUDE and NETBSD_SYS environment variables.
+
+       To determine what header file enables a missing feature,
+       check the OpenBSD stanza in the Configure script.  Then
+       check the locations it checks for the indicated header
+       files and contents.
+
+       See 00XCONFIG for more information on LSOF_INCLUDE and
+       and NETBSD_SYS.
+
+
+14.0   Output Problems
+
+14.1   Why do the lsof column sizes change?
+
+       Lsof dynamically sizes its output columns each time it runs
+       to make sure that each column takes the minimum space.
+       Column parsing -- e.g., with awk -- is possible, because
+       each column is guaranteed to be separated from the preceding
+       one by at lease one space, and no column except the last
+       (NAME) contains embedded spaces.
+
+14.2   Why does the offset have ``0t' and ``0x'' prefixes?
+
+       The offset value that appears in the SIZE/OFF column has
+       ``0t' and ``0x'' prefixes to distinguish it from size values
+       that may appear in the same column.
+
+       Normally if the offset value is less than 100,000,000 (8
+       digits), it appears in decimal with a ``0t' prefix; over
+       99,999,999, in hexadecimal with a ``0x'' prefix.
+
+       A decimal offset is handy, for example, when tracking the
+       progress of an outbound ftp transfer.  When lsof reports
+       on the ftp process, it will report the size of the file
+       being sent with its open descriptor; it will report the
+       progress of the transfer via the offset of the outbound
+       open ftp data socket descriptor.
+
+       The ``-o [n]'' option may be used to specify the maximum
+       number of decimal digits to be printed after ``0t'' before
+       lsof switches to the hexadecimal digits after `0x''.  As
+       already noted, the default decimal digit count is 8.
+
+14.3   What are the values printed in the FILE_FLAG column
+       and why is 0x<value> sometimes included?
+
+       The two comma separated lists, separated by a semicolon,
+       printed in the FILE-FLAG column (when the "+fg" option is
+       specified), are short-hand names or hexadecimal values for
+       the bits lsof finds in the f_flag or f_flags member of file
+       structures for files (the first list, the one before the
+       semicolon), and process open files flags found in various
+       kernel structures, often named "pofile" (the second list,
+       the one after the semicolon).
+
+       Lsof determines the short-hand names from symbols in the
+       <fcntl.h>, <linux/fs.h>, <sys/fcntl.h>, <sys/fcntlcom.h>,
+       o<sys/file.h>, and <sys/user.h> header files.
+
+       See the discussion of FILE-FLAG in the OUTPUT section of
+       the lsof man page, and the FF_* and POF_* symbols in lsof.h
+       for a list of the names.
+
+       Bits with no names defined for them are represented by an
+       0x<value> member of the comma-separated list -- a hexadecimal
+       integer.  When "+fG" is specified (instead of "+fg"), lsof
+       will list all flag values as two hexadecimal integers,
+       separated by a semicolon.
+
+       When "-FG" is specified to get the flags in an output field,
+       the format defaults to hexadecimal.  You can get names
+       instead by following "-FG" with "+fg" -- e.g.,
+
+           $ lsof -FG +fg ...
+
+       However, when you precede "-FG" with "+fg" -- e.g.,
+
+           $ lsof +fg -FG
+
+       the format will be hexadecimal; order is important.
+
+14.3.1 Why doesn't lsof display FILE_FLAG values for my dialect?
+
+       All versions of lsof except the /proc-based Linux lsof
+       report FILE-FLAG values.  Lsof can't obtain FILE-FLAG
+       information from the Linux /proc interface.
+
+14.4   Network Addresses
+
+14.4.1 Why does lsof's -n option cause IPv4 addresses, mapped to
+       IPv6, to be displayed in IPv6 notation?
+
+       When you use the -n option to tell lsof to display numeric
+       network addresses, and an IPv4 address has been mapped to
+       IPv6, lsof displays the address in IPv6 format and puts
+       "ipv4" in the TYPE column.  That combination indicates the
+       IPv4 address has been mapped to IPv6.
+
+       For example, the IPv4 address 1.2.3.4, when mapped to an
+       IPv6 address, will be displayed by lsof as:
+
+           [::ffff:1.2.3.4]
+
+       The enclosing brackets are lsof's signal that this is an
+       IPv6 address.  Inside the brackets is a standard IPv6
+       address, reported by inet_ntop().  The first two colons,
+       signifying zeroes in the first 64 bits of the IPv6 address,
+       and the hexadecimal ffff in the next 32 bits, indicate that
+       the last 32 bits contains a mapped IPv4 address, which is
+       then displayed in IPv4 dot notation.
+
+14.5   Why does lsof output \x, ^x, or \xnn for characters
+       sometimes?
+
+       Lsof displays only printable ASCII characters.  Lsof
+       considers a character printable if isprint(3) says it
+       is.  If isprint(3) says a character isn't printable,
+       the lsof may page explains:
+
+          "...  Non-printable characters are printed in one of
+           three forms: the C ``\[bfrnt]'' form; the control
+           character `^' form (e.g., ``^@''); or hexadecimal
+           leading ``\x'' form (e.g., ``\xab'').  Space is
+           non-printable in the COMMAND column (``\x20'') and
+           printable elsewhere."
+
+14.5.1  Why is space considered a non-printable character in command
+       names?
+
+       Space is considered an unprintable character in command
+       names because it is sometimes possible to hide the full
+       command name from scripts that parse ps(1) output by
+       embedding a space in the name.
+
+14.6   Why doesn't lsof print all the characters of a command name?
+
+       By default lsof prints the first nine characters of the
+       names of commands associated with processes.  If more
+       characters are required, the "w" value of the "+c w" option
+       may be used to specify a larger width.
+
+       If "w" is zero ('0') lsof will print all characters of all
+       command names up to the limit of the number of characters
+       supplied by the particular UNIX dialect.  When reporting
+       command names, lsof replaces non-printable characters as
+       discussed in the answer to " Why does lsof output \x, ^x, or
+       \xnn for characters sometimes?"
+
+       See the answer to the "Why is space considered a non-printable
+       character in command names?" question for an explanation of why
+       spaces are replaced by the ``\x20'' representation in command
+       names.
+
+       The number of command name characters supplied to lsof by UNIX
+       dialects in files and structures varies by dialect.  For
+       example, Linux 2.4.27 supplies lsof the first 15 characters of
+       command names and Solaris 9 supplies 16.  Thus, even if "w" is
+       zero ('0'), lsof can't report more characters for command names
+       on those two UNIX dialects than they provide lsof.
+
+14.7   Why does lsof reject some -c command names, saying their lengths
+       are "> what system provides (nn)"?
+
+       The command name length that a specific system provides varies
+       from dialect to dialect.  As noted in the answer to the "Why
+       doesn't lsof print all the characters of a command name?"
+       question, Linux and Solaris provide a limited number of command
+       name characters.
+
+       When more characters are specified in the parameter to the -c
+       option, lsof considers it an error and issues a fatal error
+       message -- e.g.,
+
+          lsof: "-c xxxxyyyy" length (8) > what system provides (7)
+
+       The only work-around is to specify no more characters to -c
+       that the system provides to lsof.
+
+14.8   Why does lsof sometimes print TYPE numbers instead of names?
+
+       When lsof can't convert a type number to a name for printing in
+       the TYPE column, it will report the number as four octets.
+
+14.9   Marker line format problems
+
+14.9.1 Why won't lsof accept a marker line format?
+
+       Lsof's Configure script must find the localtime(3) and
+       strftime(3) functions in the dialect's C library in order to
+       enable support for marker line formats.
+
+       Check the output of lsof's -v option for the presence of
+       -DHAS_STRFTIME in the compiler flags.  If it isn't there,
+       Configure didn't find the necessary two C library functions.
+
+       If you think lsof should have found the functions, make a copy
+       of the C test program in the Configure script that it uses to
+       find the functions.  Then use the copy, or a more informative
+       modification of it, to learn why Configure can't find the
+       functions.  You can find that program by searching for
+       strftime.
+
+14.9.2 Why does lsof reject the NL (%n) marker line format?
+
+       When repeat mode and field output (with -F) have both been
+       specified, lsof won't allow new line (NL) formats to be
+       specified with ``%n''.  That's because the marker line is
+       always guaranteed to be a single line.
+
+       There is no work-around to this restriction.
+
+14.10  How are protocol state name exclusion and inclusion used?
+
+       Protocol state name inclusion and exclusion with the ``-s p:s''
+       option and its arguments have some issues to consider.  Note:
+       the ``-s p:s'' option is only available when the help output,
+       obtained with -h or -?, shows it; it was a recent addition to
+       lsof and is supported only on dialects where it could be
+       tested.
+
+       First, there is the problem of determining what state names, if
+       any, the dialect produces.  Try running this lsof command to
+       find them:
+
+           $ lsof -i
+
+       Knowing the state names of interest, the next problem is to
+       decide on the lsof options and their parameters that will
+       produce the desired output.  Here some examples are probably
+       the most useful.
+
+       To list only TCP socket files in LISTEN and CLOSE_WAIT states,
+       use:
+
+           $ lsof -itcp -stcp:listen,close_wait
+       or
+           $ lsof -iTCP -sTCP:LISTEN,CLOSE_WAIT
+
+       Case isn't important to lsof in protocol and state names.
+
+       To exclude TCP socket files in CLOSE_WAIT state, use:
+
+           $ lsof -itcp -stcp:^close_wait
+
+       Note the `^' preceding close_wait; it selects exclusion.  You
+       can mix included and excluded names in a comma separated list,
+       but you may not include and exclude the same name for the same
+       protocol.
+
+       To list TCP files in LISTEN state and UDP files in Idle state,
+       use:
+
+           $ lsof -i -stcp:listen -sudp:idle
+
+       Note: if you don't accompany the ``-s p:s'' list option and
+       argguments with the -i option, lsof will list all other regular
+       files, while applying the specified inclusion and exclusion
+       specifications to network files.  Generally, then, you want to
+       use -i with -s.
+
+14.10.1        Why doesn't my dialect support state name exclusion and inclusion?
+
+       When state name inclusion and exclusion was added, I had access
+       to test systems for AIX, Darwin, FreeBSD, Linux, PSTAT-based
+       HP-UX and Solaris.
+
+       Therefore, I was unable to add and test the support to any other
+       UNIX dialects.
+
+       If a dialect has the support, then the HASTCPUDPSTATE definition
+       in its machine.h header file will be active; if not, it will be
+       absent or commented out.
+
+       If your dialect doesn't have the support and you want it added,
+       you will have to provide me Internet access to a test host, where
+       I can compile lsof and have the credentials to test the changes
+       the support requires.  If that's possible for you, please contact
+       me via e-mail at <abe@purdue.edu>.  Make sure "lsof" appears in
+       the "Subject:" line so my e-mail filter won't classify your letter
+       as Spam.
+
+
+15.0   Pyramid Version Problems
+
+15.0.5 Statement of deprecation
+
+       As of lsof revision 4.52 support for all Pyramid versions has
+       been dropped.  Contact me via e-mail at <abe@purdue.edu> if you
+       are interested in obtaining the last lsof Pyramid distribution.
+       Make sure "lsof" appears in the "Subject:" line so my e-mail
+       filter won't classify your letter as Spam.
+
+
+16.0   SCO Problems
+
+16.1   SCO OpenServer Problems
+
+16.1.1 How can I avoid segmentation faults when compiling lsof?
+
+       If you have an older SCO OpenServer compiler, it may get
+       a segmentation fault when compiling some lsof modules.
+       That appears to happen because of the -Ox optimization
+       action requested in the lsof Makefile.
+
+       Try changing -Ox to -O with this make invocation:
+
+           $ make DEBUG=-O
+
+       Bela Lubkin supplied this tip and Steve Williams verified
+       it.
+
+16.1.2 Where is libsocket.a?
+
+       If you compile lsof and the loader says it can't find the
+       socket library, libsocket.a, called by the -lsocket option
+       in the lsof compile flags, you probably are running an SCO
+       OpenServer release earlier than 5.0 and don't have the
+       TCP/IP Development System package installed.
+
+       You may have the necessary header files, because you have
+       the TCP/IP run-time package installed, but if you don't
+       have the TCP/IP Development System package installed, you
+       won't have libsocket.a.
+
+       Your choices are to install the TCP/IP Development System
+       package or upgrade to OpenServer Release 5.0.  You will
+       find libsocket.a in 5.0 -- you'll find all the libraries
+       and header files there, in fact -- and you can use gcc to
+       compile lsof if you don't want to install the 5.0 Development
+       System package.
+
+16.1.3 Why do I get "warning C4200" messages when I compile lsof?
+
+       When you compile lsof under OSR 3.2v4.2 (and perhaps under
+       earlier versions as well), you may get many compiler warning
+       messages of the form:
+
+           node.c(183) : warning C4200: previous declarator is not
+           compatible with default argument promotion
+
+       In my opinion this is a bug in the OSR compiler.  Because
+       the compiler cannot handle full ANSI-C prototypes, it
+       assumes default types for function parameters as it encounters
+       untyped in a function prototype -- e.g., in this function
+       declaration from node.c,
+
+           readrnode(ra, r)
+               KA_T ra;
+               struct rnode *r;
+           {
+           ...
+
+       the compiler assigns default int types to the ra and r
+       arguments.
+
+       Then, when the compiler encounters the fully typed parameters
+       after the function skeleton and sees parameters with types
+       that don't match the assumptions it previously made, it
+       whines about its own assumptions.
+
+       You can ignore these messages.
+
+16.2   SCO|Caldera UnixWare Problems
+
+16.2.1  Why doesn't lsof compile on my UnixWare 7.1.1 or above
+       system?
+
+       When you Configure lsof with the "uw" abbreviation and try
+       to compile it for UnixWare 7.1.1, you may get compiler
+       error messages like this:
+
+           UX:acomp: ERROR: "dproc.c", line 98:
+               undefined struct/union member: p_pgidp
+
+       This suggest that you probably have a non-stop cluster
+       UnixWare 7.1.1 system.  Its <sys/proc.h> header file differs
+       from the one on the system where I did the lsof port to
+       UnixWare 7.1.1.  I currently don't have access to a non-stop
+       cluster system to be able to develop changes to lsof that
+       would make it compile and work there.
+
+       If you have a non-stop cluster UnixWare 7.1.1 system, want lsof
+       for it, and can offer me a test account on the system, please
+       contact me via e-mail at <abe@purdue.edu>.  Make sure "lsof"
+       appears in the "Subject:" line so my e-mail filter won't
+       classify your letter as Spam.
+
+       If you have a system with nsc_cfs and can offer me a test
+       account on it, please contact me via e-mail at <abe@purdue.edu>.
+       Make sure "lsof" appears in the "Subject:" line so my e-mail
+       filter won't classify your letter as Spam.
+
+16.2.2  Why does lsof complain about node_self() on my UnixWare
+       7.1.1 or above system?
+
+       If lsof exits immediately after issuing this message:
+
+           can't identify process NSC node; node_self(): <message>
+
+       It means that lsof has been built to run on a NonStop
+       Cluster (NSC) UnixWare 7.1.1 or higher system and can't
+       get the number of the node on which it is running.  Lsof
+       uses the node number to determine the path to the kernel
+       boot file.
+
+       You can tell if lsof has been built for NSC by looking for
+       "-DHAS_UW_NSC" in lsof's "-v" option output.
+
+       If the system on which you're trying to run lsof isn't
+       running an NSC kernel, you will need to build a non-NSC
+       lsof.
+
+16.2.3  Why does UnixWare 7.1.1 or above complain about -lcluster,
+       node_self(), or libcluster.so?
+
+       When you build, compile, and load lsof for UnixWare 7.1.1
+       and above, ld may complain that it can't find the -lcluster
+       library or that the node_self symbol is undefined.  When
+       you try to run an existing lsof binary it may complain that
+       libcluster.so can't be found.
+
+       These messages mean the tests made by Configure on your
+       system led it to believe your system is running a NonStop
+       Cluster (NSC) kernel, or the lsof binary you're trying to
+       use was built on a NonStop Cluster system.  If an lsof
+       binary was built for NSC, this shell command produces
+       output:
+
+           $ strings <lsof_binary> | grep HAS_UW_NSC
+
+       If that's not the case, and you can rebuild lsof, set the
+       UW_HAS_NSC environment variable to "N" and do this:
+
+          $ Configure -n clean
+          $ UW_HAS_NSC=N
+          $ export UW_HAS_NSC
+          $ Configure -n uw
+          $ make
+
+       You can also edit Makefile and lib/Makefile.  Remove
+       -DHAS_UW_NSC from the CFGF strings.  Remove -lcluster from
+       the CFGL strings.  Then run make again.
+
+       If you have an existing NSC lsof binary and you want one
+       for a non-NSC system, you will have to build lsof yourself
+       on the system where you want to use it.  (That's always a
+       good idea anyway.)
+
+
+16.2.4  Why does UnixWare 7.1.1 or above lsof complain it can't
+       read the kernel name list?
+
+       If lsof complains:
+
+           can't read kernel name list from <path>
+
+       It means that lsof can't find the booted kernel image file
+       at <path>.  On NonStop Cluster (NSC) UnixWare 7.1.1 or
+       higher systems lsof determines the booted file path by
+       examining this file:
+
+           /stand/`node_self`/boot
+
+       If examining that file doesn't lead to an NSC path, lsof
+       uses:
+
+           /stand/1/unix
+
+       On non-NSC systems lsof expects the booted kernel image to
+       be in /stand/unix.
+
+       If your booted kernel image is in a different place, use
+       lsof's "-k <path>" option to specify its path.
+
+16.2.5  Why doesn't lsof report link count, node number, and size
+       for some UnixWare 7.1.1 or above CFS files?
+
+       Lsof reports link count, node number, and size for open
+       CFS files as recorded in their kernel node structure's
+       cached attributes.  Sometimes not all attributes are cached
+       on the node where lsof runs, so lsof cannot report them.
+
+16.2.6  Why doesn't lsof report open files on all UnixWare 7.1.1
+       NonStop Cluster (NSC) nodes?
+
+       Lsof can only report on files open on the node on which it
+       runs, because the information lsof reports comes from the
+       private kernel memory of the node.  This may mean that
+       asking lsof to find a specific open file, or use of a
+       specific Internet address or port, may not report all open
+       instances on nodes other than the one used to run lsof.
+
+       You can use the NSC onnode(1) command to run lsof on specific
+       nodes, or the onall(1) command to run lsof on all nodes --
+       e.g.,
+
+           $ onall lsof [options] 2>&1 | less
+        or
+           $ onnode node-number lsof [options] 2>&1 | less
+
+       Note that, when lsof is run all nodes, the path name
+       component assembly results it reports in its NAME column
+       may vary, because the dynamic name cache from which lsof
+       gets the components is private to the kernel of each node.
+
+       Also note the use of shell redirection in the examples to
+       merge the standard error file information from onnode and
+       onall with lsof's standard output file output.  That will
+       put the onnode and onall node announcements in proper
+       sequence with lsof's output.
+
+16.2.7 Why doesn't lsof report the UnixWare 7.1.1 NonStop Cluster
+       (NSC) node a process is using?
+
+       To induce lsof to report the node on which a process runs
+       would be a significant, non-standard modification to lsof.
+       It has much wider implications than merely the printing of
+       a number in an output column.  I'm not currently (April
+       2001) prepared to undertake such a modification.
+
+       If you want node-specific NSC information about open files,
+       run lsof under the control of onall(1) or onnode(1).
+
+           $ onall lsof [options] 2>&1 | less
+        or
+           $ onnode node-number lsof [options] 2>&1 | less
+
+16.2.8  Why does the compiler complain about missing UnixWare 2.1[.x]
+       header files?
+
+       SCO|Caldera didn't ship the following header files with
+       UnixWare 2.1 through 2.1.3:
+
+           <fs/proc/prdata.h>
+           <fs/procfs/prdata.h>
+           <sys/fs/fifonode.h>
+           <sys/fs/namenode.h>
+
+       Lsof needs those header files for its compilation.  Contact
+       SCO|Caldera to get copies of those header files.
+
+       If you can't get the header files from SCO|Caldera, please
+       contact me via e-mail at <abe@purdue.edu>.  Make sure "lsof"
+       appears in the "Subject:" line so my e-mail filter won't
+       classify your letter as Spam.
+
+
+17.0   Sun Problems
+
+17.0.5 Statement of deprecation
+
+       Lsof support for SunOS 4.1.x was last tested at revision 4.51.
+       Contact me via e-mail at <abe@purdue.edu> if you're interested in
+       obtaining it.  Make sure "lsof" appears in the "Subject:" line so
+       my e-mail filter won't classify your letter as Spam.
+
+17.1   My Sun gcc-compiled lsof doesn't work -- why?
+
+       Gcc can be used to build lsof successfully.  However, an
+       improperly installed Sun gcc compiler will usually not
+       produce a working lsof.
+
+       If your Sun gcc-compiled lsof doesn't report anything, or
+       reports ``can't read proc table,'' or gcc refuses to compile
+       lsof without error, check that the gcc step that "fixes"
+       Sun header files was run on the system where you're using
+       gcc to compile lsof.  As an alternative, if you have the
+       SunPro C 5.0 compiler or later available, use it to compile
+       lsof -- e.g., use the solariscc Configure abbreviations.
+
+17.2   How can I make lsof compile with gcc under Solaris 2.[456],
+       2.5.1, 7, 8 or 9?
+
+       Presuming your gcc-specific header files are wrong for
+       Solaris, edit the lsof Configure-generated Makefile and
+       lib/Makefile and make this change:
+
+               CFGF=   -Dsolaris=20400 ...
+       to
+               CFGF=   -Dsolaris=20400 -D__STDC__=0 -I/usr/include ...
+
+       or change:
+
+               CFGF=   -Dsolaris=20500 ...
+       to
+               CFGF=   -Dsolaris=20500 -D__STDC__=0 -I/usr/include ...
+
+       or change:
+
+               CFGF=   -Dsolaris=20501 ...
+       to
+               CFGF=   -Dsolaris=20501 -D__STDC__=0 -I/usr/include ...
+
+       This is only a temporary work-around.  You really should
+       instruct gcc to to update your gcc-specific header files
+       or install a recent gcc (e.g., 3.2), which has no need for
+       private copies of Solaris include files.
+
+17.3   Why does Solaris Sun C complain about system header files?
+
+       You're probably trying to use /usr/ucb/cc if you get compiler
+       complaints like:
+
+           cc -O -Dsun -Dsolaris=20300 ...
+           "/usr/include/sys/machsig.h", line 81: macro BUS_OBJERR
+           redefines previous macro at "/usr/ucbinclude/sys/signal.h",
+           line 444
+
+       Note the reference to "/usr/ucbinclude/sys/signal.h".  It
+       reveals that the BSD Compatibility Package C compiler is
+       in use.  Lsof requires the ANSI C version of the Solaris
+       C compiler, usually found in /usr/opt/bin/cc or
+       /opt/SUNWspro/bin/cc.
+
+       Try adding a CC string to the lsof Makefile that points to
+       the Sun ANSI C version of the Sun C compiler -- e.g.,
+
+           CC= /usr/opt/bin/cc
+       or
+           CC= /opt/SUNWspro/bin/cc.
+
+17.4   Why doesn't lsof work under my Solaris 2.4 system?
+
+       If lsof doesn't work under your Solaris 2.4 system -- e.g.,
+       it produces no output, little output, or the output is
+       missing command names or file descriptors -- you may have
+       a pair of conflicting Sun patches installed.
+
+       Solaris patch 101945-32 installs a kernel that was built
+       with a <sys/auxv.h> header file whose NUM_*_VECTORS
+       definitions don't match the ones in the <sys/auxv.h> updated
+       by Solaris patch 102303-02.
+
+       NUM_*_VECTORS in the kernel of patch 101945-32 are smaller
+       than the ones in the <sys/auxv.h> of patch 102303-02.  The
+       consequence is that when lsof is compiled with the <sys/auxv.h>
+       whose NUM_*_VECTORS definitions are larger than the ones
+       used to compile the patched kernel, lsof's user structure
+       does not align with the one that the kernel employs.
+
+       If you have these two patches installed, contact Sun and
+       complain about the mis-match.
+
+       You may be able to work around the problem by editing
+       /usr/include/sys/auxv.h to have the following NUM_*_VECTORS
+       definitions:
+
+                   #define NUM_GEN_VECTORS 4
+                   #define NUM_SUN_VECTORS 8
+
+       The Configure script issues a prominent WARNING that you should
+       try the work-around.
+
+       I thank Leif Hedstrom for identifying the offending patches.
+
+17.5   Where are the Solaris header files?
+
+       If you try to compile lsof under Solaris and get a compiler
+       complaint that it can't find system header files, perhaps
+       you forgot to add the header file package, SUNWhea.
+
+17.6   Where is the Solaris /usr/src/uts/<architecture>/sys/machparam.h?
+
+       When you try to Configure lsof for Solaris 2.[23456], 2.5.1,
+       and 7 -- e.g., on a `uname -m` == sun4m system -- Configure
+       complains:
+
+           grep: /usr/src/uts/sun4m/sys/machparam.h:
+                       No such file or directory
+           grep: /usr/src/uts/sun4m/sys/machparam.h:
+                       No such file or directory
+
+       And when you try to compile the configured lsof, cc or gcc
+       complains:
+
+           dproc.c:530: `KERNELBASE' undeclared (first use this function)
+
+       The explanation is that somehow your Solaris system doesn't
+       have the header files in /usr/src/uts it should have.  Perhaps
+       someone removed the directory to save space.  Perhaps you're
+       using a gcc installation, copied from another system.  In any
+       event, you will have to load the header files from the SUNWhea
+       package of your Solaris distribution.
+
+       KERNELBASE is an important symbol to lsof -- it keeps lsof
+       from sending an illegal kernel value to kvm_read() where
+       a segmentation violation might result (a bug in the kvm
+       library).  Lsof can get illegal kernel values because it
+       reads kernel values slowly with kvm_read() calls that the
+       kernel is changing rapidly.
+
+       Lsof doesn't need KERNELBASE at Solaris 2.5 and above,
+       because it has a KERNELBASE value whose address lsof can
+       find with /dev/ksyms and whose value it can read with
+       kvm_read().  Under Solaris 2.5 /usr/src/uts has moved to
+       /usr/platform.
+
+17.7   Why does Solaris lsof say ``can't read proc table''?
+
+       When lsof collects data on processes, using the kvm_*()
+       functions to scan the kernel's proc structure table, it
+       checks to make sure it has identified a reasonable number
+       of them -- a minimum of three.  When lsof can't identify
+       three processes during a scan, it repeats the scan.
+
+       When five scans fail to yield three processes, lsof issues
+       the fatal message:
+
+               lsof: can't read proc table
+
+       and exits.
+
+       Usually lsof fails to identify three processes during a
+       scan because its idea of the form of the proc structure
+       differs from that being used by the kernel.  Since the proc
+       structure is defined in <sys/proc.h> and other /usr/include
+       header files, the root cause of a proc structure discrepancy
+       usually can be found in the composition of /usr/include.
+
+       One common way that /usr/include header files can be
+       incorrect is that gcc was used to compile lsof, gcc used
+       its special (i.e., "fixed") header files instead of the
+       ones in /usr/include, and the special gcc header files
+       weren't updated when Solaris was.  Answers to these questions:
+
+           My Sun gcc-compiled lsof doesn't work -- why?
+
+           How can I make lsof compile with gcc under Solaris 2.[456],
+           2.5.1, 7, 8 or 9?
+
+           Why does Solaris Sun C complain about system header files?
+
+       discuss the gcc header file problem and offer suggestions
+       on how to fix it or work around it.
+
+       It may also be that you are trying to run a version of lsof
+       that was compiled on an older version of Solaris.  For
+       example, an lsof executable, compiled for Solaris 2.4, will
+       produce the ``can't read proc table'' message if you try
+       to run it under Solaris 2.5.  If you have compiled lsof
+       under Solaris 2.5 and it still won't work, see if the header
+       files in /usr/include have been updated to 2.5, or still
+       represent a previous version of Solaris.
+
+       Another source of header file discrepancies to consider is
+       the Solaris patch level and whether a binary kernel patch
+       was not matched with a corresponding header file update.
+       See the "Why doesn't lsof work under my Solaris 2.4 system?"
+       question for an example of one in Solaris 2.4 -- there may
+       be other such patch conflicts I don't know about.
+
+17.8    Why does Solaris lsof complain about a bad cached clone device?
+
+       When lsof revisions below 4.04 have been run on a Solaris
+       system and have been allowed to create a device cache file,
+       the running of revisions 4.04 and above on the same systems
+       may produce this complaint:
+
+           lsof: bad cached clone device: ...
+           lsof: WARNING: created device cache file: ...
+
+       This is the result of a change in the device cache file
+       that took place at lsof revision 4.04.  The change introduced
+       a node number into the clone device lines of the device
+       cache file and was done in such a way that lsof could detect
+       device cache files whose clone lines don't have node numbers
+       (lines created by previous lsof revisions) and recognize
+       the need to regenerate the device cache file.
+
+17.9   Why doesn't Solaris make generate .o files?
+
+       Solaris /usr/ccs/bin/make won't generate .o files from .c
+       files if /usr/share/lib/make/make.rules is missing.  It
+       may be found in and installed from the SUNWsport package.
+
+17.10  Why does lsof report some Solaris 2.3 and 2.4 lock types as `N'?
+
+       For Solaris 2.3 with patch P101318 installed at level 45
+       or above, and for all versions of Solaris 2.4, NFS locks
+       are represented by a NFS-specific kernel lock structure
+       that sometimes lacks a read or write lock type indicator.
+       When lsof encounters such a lock structure, it reports the
+       lock type as `N'.
+
+17.11  Why does lsof Configure say "WARNING: no cc in ..."?
+
+       When lsof's Configure script is executed with the solariscc
+       abbreviation it tries to make sure it's using the Sun C
+       compiler and not the UCB substitute from /usr/ucb/cc.
+       Thus, it looks for cc in the "standard" Sun compiler
+       location, /opt/SUNWspro/bin.
+
+       If Configure can't find cc there, it issues the warning:
+
+           lsof: WARNING: no cc in /opt/SUNWspro/bin;
+                 using cc without path.
+
+       and uses cc for the compiler name, letting the shell find
+       cc with its PATH environment variable.
+
+       You can tell Configure where to find your cc with the
+       SOLARIS_CCDIR cross-configuration environment variable.
+       (See 00XCONFIG for more information on SOLARIS_CCDIR).
+       For example, use this Configure shell command:
+
+           SOLARIS_CCDIR=/usr/special/bin Configure -n solariscc
+
+       (SOLARIS_CCDIR should be the full path to the directory
+       containing your cc.)
+
+17.12  Solaris 7, 8 and 9 Problems
+
+17.12.1        Why does lsof say the compiler isn't adequate for Solaris
+       7, 8 or 9?
+
+       Solaris 7, 8 and 9 kernels come in two flavors, 32 and 64
+       bit.  64 bit kernels run on machines that support the SPARC
+       v9 instruction set architecture.  Separate executables for
+       some programs, -- e.g., ones using libkvm like lsof -- must
+       be built for 32 and 64 bit kernels.
+
+       Previous Sun (e.g., SC4.0) and earlier gcc compilers will
+       build lsof for 32 bit kernels, but they won't build it for
+       64 bit kernels.  Compilers that will build lsof for 64 bit
+       Solaris 7, 8 and 9 kernels are the Sun WorkShop Compilers
+       C 5.0 and above, and recent gcc versions, e.g., 3.2.
+
+       When given the ``-xarch=v9'' flag, the C 5.0 compiler and
+       above, and associated loader and 64 bit libraries will
+       build a 64 bit lsof executable; when given the "-m64" or
+       "-mcpu=v9" (deprecated) flags, an appropriate gcc compiler
+       will build a 64 bit lsof executable.
+
+       When the lsof Configure script detects a 64 bit kernel is
+       in use (e.g., by executing `/bin/isainfo -kv`), and when
+       it finds that the specified compiler is inappropriate,
+       it complains with these messages:
+
+       For gcc:
+
+           "!!!WARNING!!!=========!!!WARNING!!!=========!!!WARNING!!!"
+           "!                                                       !"
+           "! LSOF NEEDS TO BE CONFIGURED FOR A 64 BIT KERNEL, BUT  !"
+           "! THIS GCC DOESN'T SUPPORT THE BUILDING OF 64 BIT       !"
+           "! SOLARIS EXECUTABLES.  LSOF WILL BE CONFIGURED FOR A   !"
+           "! 32 BIT echo KERNEL.                                   !"
+           "!                                                       !"
+           "!!!WARNING!!!=========!!!WARNING!!!=========!!!WARNING!!!"
+
+       For Sun C:
+
+         !!!WARNING!!!==========!!!WARNING!!!==========!!!WARNING!!!
+         !                                                         !
+         ! LSOF NEEDS TO BE CONFIGURED FOR A 64 BIT KERNEL, BUT    |
+         ! THE VERSION OF SUN C AVAILABLE DOESN'T SUPPORT THE      !
+         ! -xarch=v9 FLAG.  LSOF WILL BE CONFIGURED FOR A 32 BIT   !
+         ! KERNEL.                                                 !
+         !                                                         !
+         !!!WARNING!!!==========!!!WARNING!!!==========!!!WARNING!!!
+
+17.12.2 Why does Solaris 7, 8 or 9 lsof say "FATAL: lsof was compiled
+       for..."?
+
+       Solaris 7, 8 or 9 lsof may say:
+
+           lsof: FATAL: lsof was compiled for a xx bit kernel,
+                 but this machine has booted a yy bit kernel.
+
+           Where: xx = 32 or 64
+                  yy = 64 or 32
+
+           (xx and yy won't match.)
+
+       This message indicates that lsof was compiled for one size
+       kernel and is being asked to execute on a different size
+       one.  That's not possible for programs like lsof that use
+       libkvm.
+
+       Depending on the instruction sets for which you need Solaris
+       7, 8 or 9 lsof, you may need two or more versions of lsof,
+       compiled for each kernel size, installed for use with
+       /usr/lib/isaexec.  See the "How do I install lsof for
+       Solaris 7, 8 or 9?" section of this document for more
+       information on that.
+
+17.12.3        How do I build lsof for a 64 bit Solaris kernel under a 32
+       bit Solaris kernel?
+
+       If your Solaris system has an appropriate compiler (e.g.,
+       WorkShop Compilers C 5.0 and above, or a recent gcc like
+       3.2) and the 64 bit libraries have been installed, you can
+       force lsof's Configure script to build a 64 bit version of
+       lsof with:
+
+           $ SOLARIS_KERNBITS=64 Configure -n solariscc
+
+       The SOLARIS_KERNBITS environment variable is part of the
+       lsof cross-configuration support, described in the 00XCONFIG
+       file of the lsof distribution.
+
+17.12.4        How do I install lsof for Solaris 7, 8 or 9?
+
+       If you are installing lsof where it will be used only under
+       the bit size kernel for which it was built, no special
+       installation is required.
+
+       If, however, you are installing different versions of lsof
+       for different bit sizes -- e.g., for use on a 64 bit NFS
+       server and from its 32 bit clients -- you should read the
+       man page for isaexec(3C) and install lsof according to its
+       instructions.
+
+       The executable at the directory where lsof is to be found
+       should be a hard link to /usr/lib/isaexec or a copy of it.
+       In the directory there must be instruction architecture
+       subdirectories -- e.g., .../sparc/ and .../sparcv9/.  The
+       lsof for 64 bit size kernels is installed in the .../sparcv9/
+       subdirectory; the one for 32 bit size kernels, in .../sparc/.
+
+       For example, if you're installing 32 and 64 bit lsof
+       executables in /usr/local/etc, you would:
+
+               # cd /usr/local/etc
+               # ln /usr/lib/isaexec lsof
+               # mkdir sparc sparcv9
+               # install the 32 bit lsof as sparc/lsof
+               # install the 64 bit lsof as sparcv9/lsof
+               # chmod, chown, and chgrp sparc/lsof and
+                 sparcv9/lsof appropriately
+
+       Lsof permissions and ownerships are the same whether one
+       or more lsof executables are being installed, with or
+       without the /usr/lib/isaexec hard link.
+
+17.12.5 Why does my Solaris 7, 8 or 9 system say it cannot execute
+       lsof?
+
+       When you attempt to execute lsof, your Solaris 7, 8 or 9
+       shell may complain:
+
+           ksh: ./lsof: cannot execute
+
+       If the lsof executable exists and has the proper execution
+       permissions, this error may be the result of trying to
+       execute an lsof, built for a 64 bit kernel, on a 32 bit
+       kernel.
+
+       This will tell you about the lsof executable:
+
+           $ file lsof
+           lsof: ELF 64-bit MSB executable SPARCV9 Version 1,
+                 dynamically linked, not stripped
+
+       The "64-bit" notation indicates the binary was built for
+       a 64 bit kernel.  To see the running kernel bit size, use
+       this command:
+
+           $ isainfo -kv
+           32-bit sparc kernel modules
+
+       The "32-bit" notation indicates a 32 bit kernel has been
+       booted.
+
+       The only work-around is to obtain, or Configure and make,
+       an lsof for the appropriate kernel bit size.  If you
+       Configure and make lsof on the kernel where you wish to
+       run it the proper compiler, the lsof Configure step will
+       generate Makefiles that can be used with make to build an
+       appropriate lsof executable.
+
+       To compile a 64 bit lsof, you must have an appropriate
+       compiler -- i.e., Sun WorkShop Compilers C 5.0 or higher
+       or a recent gcc like 3.2.
+
+17.12.6 What gcc will produce 64 bit Solaris 7, 8 and 9 executables?
+       8 and 9 executables?
+
+       Properly built and installed recent gcc versions -- e.g.,
+       3.2 -- will build lsof for 64 bit Solaris kernels.
+
+       If you update your gcc version to 3.2 or later, make sure
+       the private gcc header files become current -- i.e., clear
+       out any private header files from a previous gcc or Solaris
+       installation before installing the new ones, or build to
+       a new --prefix root and replace the old root with it after
+       the build and installation are complete.
+
+17.12.7 Why does lsof on my Solaris 7, 8 or 9 system say, "can't
+       read namelist from /dev/ksyms?"
+
+       You're probably trying to use an lsof executable built for
+       an earlier Solaris release on a 64 bit Solaris 7, 8 or 9
+       kernel.  The output from `lsof -v` will tell you the build
+       environment of your lsof executable.  You should also have
+       gotten a warning message that lsof is compiled for a
+       different Solaris version than the one under which it is
+       running -- something like this:
+
+           lsof: WARNING: compiled for Solaris release X; this is Y
+
+       You need to build lsof on the system where you want to use
+       it.  For 64 bit Solaris 7, 8 and 9 you need a compiler that
+       can generate 64 bit Solaris executables -- e.g., the Sun
+       Workshop 5 C compiler or later, or a recent gcc version
+       like 3.2.  See the "Why does lsof say the compiler isn't
+       adequate for Solaris 7, 8 or 9?" section and the ones
+       following it for a discussion of building lsof for 64 bit
+       Solaris 7, 8 or 9.
+
+17.13  Solaris and COMMON
+
+17.13.1        What does COMMON mean in the NAME column for a Solaris VCHR
+       file?
+
+       When lsof puts COMMON or (COMMON) in the NAME column of a
+       Solaris VCHR file, it means that the file is handled by
+       the special file system functions of the kernel through a
+       common vnode.
+
+17.13.2        Why does a COMMON Solaris VCHR file sometimes seem to have an
+       incorrect minor device number?
+
+       When lsof reports on an open file in a Solaris special file
+       system that uses a COMMON vnode, and the file is a VCHR
+       file, lsof tries to locate the associated device node by
+       looking for matches on the major and minor device numbers
+       first.
+
+       If no major and minor match results, lsof then looks for
+       a match on pseudo and clone device files.  (See /devices/pseudo.)
+       Those device nodes are matched specially by either their
+       major or minor device numbers, but not both.  Hence, when
+       lsof finds a match under those special conditions, it may
+       report a value in its output DEVICE column that differs
+       from one of the major and minor numbers of the device node.
+
+       Here's an example from a sun4m Solaris 7 system:
+
+           $ ls -li /devices/pseudo/pm@0:pm
+           151261 crw-rw-rw-   1 root     sys      117,  0 ...
+           $ lsof /devices/pseudo/pm@0:pm
+           COMMAND ... DEVICE ...   NODE NAME
+           powerd       117,1 ... 151261 /devices/pseudo/pm@0:pm (COMMON)
+           Xsun    ...  117,0 ... 151261 /devices/pseudo/pm@0:pm
+
+       Note that the DEVICE value for the file with (COMMON) in
+       its name field has a different minor device number (1) from
+       what ls reports (0), while the DEVICE value for the file
+       without (COMMON) matches the ls output exactly.  Both match
+       on the major device number, 117.  The minor device number
+       mis-match is a result of the way the Solaris kernel handles
+       special file system common vnodes, and it's the reason lsof
+       puts (COMMON) after the name to signal that a mis-match is
+       possible.
+
+17.14  Why don't lsof and Solaris pfiles reports always match?
+
+       /usr/proc/bin/pfiles for Solaris 2.6, 7, 8, and 9 also
+       reports information on open files for processes.  Sometimes
+       the information it reports differs from what lsof reports.
+
+       There are several reasons why this might be true.  First,
+       because pfiles is a Sun product, based on Sun kernel
+       features, its developers have a better chance of knowing
+       exactly how open file information is organized.  I sometimes
+       have to guess at how kernel file structure linkages are
+       constructed by gleaning hints from header files.
+
+       Second, lsof is aimed at providing information, specifically
+       device and node numbers, that can be used to identify named
+       file system objects -- i.e., path names.  Thus, lsof tries
+       to make sure its device and node numbers match those reported
+       by stat(2).  Pfiles doesn't always report numbers that
+       match stat(2) -- e.g., for files using clone and pseudo
+       devices via common vnodes like the nlist() /dev/ksyms usage.
+
+       Here's the Solaris 7 COMMON VCHR example again with additional
+       pfiles output:
+
+           $ ls -li /devices/pseudo/pm@0:pm
+           151261 crw-rw-rw-   1 root     sys      117,  0 ...
+           $ lsof /devices/pseudo/pm@0:pm
+           vic1: 10 = lsof /dev/pm
+           COMMAND ... DEVICE ...   NODE NAME
+           powerd  ...  117,1 ... 151261 /devices/pseudo/pm@0:pm (COMMON)
+           Xsun    ...  117,0 ... 151261 /devices/pseudo/pm@0:pm
+           $ pfiles ...
+           0: S_IFCHR ... dev:32,24 ino:61945 ... rdev:117,1
+           ...
+           14: S_IFCHR ... dev:32,24 ino:151261 ... rdev:117,0
+
+       Note that the NODE number, reported by lsof, matches what
+       ls(1) and stat(2) report, while the ino value pfiles reports
+       doesn't.   Lsof also indicates with the (COMMON) notation
+       that the DEVICE number is a pseudo one, derived from the
+       character device's value.  The lsof DEVICE value matches
+       the pfiles rdev value, correct behavior for a character
+       device, but pfiles gives no sign that it's not possible to
+       find that character device number in /devices with ls(1)
+       or stat(2).
+
+17.15  Why does lsof say, "kvm_open(namelist=default, core=default):
+       Permission denied?"
+
+       Lsof needs permission to read from the /dev/kmem and /dev/mem
+       memory devices.  Access to them is opened via a call to
+       the kvm_open() library function and it reports the indicated
+       message.
+
+       You must give lsof permission to read the memory devices.
+       The super user can almost always do that, but other lsof
+       users can do it if some group -- e.g., sys -- has permission
+       to read the memory devices, and the lsof binary is installed
+       with the group's ownership and with the setgid permission
+       bit enabled.
+
+17.16  Why is lsof slow on my busy Solaris UFS file system?
+
+       Lsof may be slow on a busy Solaris UFS file system when
+       UFS logging has been enabled with the "logging" mount
+       option.  That option can significantly increase disk
+       operations under certain conditions -- e.g., when a lot of
+       files are accessed quickly.
+
+       When only the "logging" option is specified to mount, all
+       file accesses (atime updates) are logged to the UFS logging
+       queue.  Each atime update requires two writes to the disk
+       to complete it.
+
+       If you want to do UFS logging -- and there are reliability
+       advantages to it -- consider using the "logging,noatime"
+       mount options instead.  That will shift atime updates from
+       the logging queue to fewer and independent asynchronous
+       operations, consequently making the UFS logging queue a
+       smaller bottleneck.
+
+       Consult mount_ufs(1M) for more information on the logging
+       and noatime options.
+
+       (My thanks to Casper Dik for this tip on improving the
+       performance of UFS logging.)
+
+17.17  Why is lsof so slow on my Solaris 8 or 9 system?
+
+       Solaris 8 has a post-release feature upgrade modifying
+       kernel name cache (DNLC) handling that can slow lsof
+       throughput dramatically.  The feature, sometimes called
+       negative DNLC caching, is standard in Solaris 9.
+
+       As best I can tell, when you install the Solaris 8 MU1
+       package, you get negative DNLC caching.  If this pipe
+       produces any output, your system has negative DNLC caching.
+
+           $ nm /dev/ksyms | grep negative_cache_vnode
+
+       The reason negative DNLC caching perturbs lsof is that a
+       single vnode address (found in the negative_cache_vnode
+       kernel variable) is used to mark entries in the DNLC that
+       are not (the negative part) found on disk.
+
+       Since a single vnode address (the DNLC key lsof uses) can
+       represent many (I've seen upwards of 30,000.) DNLC entries,
+       their presence overloads lsof's internal DNLC hashing
+       function.  An overloaded hash function is a slow hash
+       function, and lsof's slows to a crawl when it encounters
+       thousands of keys that produce the same value when the lsof
+       DNLC hash function is applied to them.
+
+       The solution is simple -- ignore negative DNLC cache keys.
+       They don't represent path name components lsof can use.
+       Lsof revisions 4.50 and above have an addition that ignores
+       them and the performance of those lsof revisions improves
+       significantly when presented with negative DNLC cache keys.
+
+       If you don't have an lsof revision at 4.51 or later, there's
+       a work-around.  Use lsof's ``-C'' option.  It disables
+       lsof's DNLC caching.  Of course, that also inhibits the
+       reporting of any path name components from the kernel DNLC.
+       When ``-c'' is used, lsof will continue to report file
+       system and character device paths.
+
+17.18  Solaris and VxFS
+
+17.18.1        Why doesn't lsof support VxFS 3.4 on Solaris 2.6, and above?
+
+       Lsof will not support VxFS version 3.4 on Solaris 2.6 and above
+       unless some files from VxFS Update 2 have been installed.  VxFS
+       3.4 FCS and VxFS 3.4 update 1 lack the header files lsof
+       normally uses to obtain information from the VxFS 3.4 kernel
+       node structure, vx_inode.  VxFS 3.4 Update 2 provides a method
+       whereby lsof can obtain the necessary vx_inode information from
+       the vxfsu_get_ioffsets() function in Veritas utility
+       libraries.
+
+       The utility libraries (32 bit and 64 bit versions) may be
+       found in /opt/VRTSvxfs/lib.  An ancillary header file may
+       be found in /opt/VRTSvxfs/include/sys/fs/vx_libutil.h.
+       Documentation of the vxfsu_get_ioffsets(3) function may be
+       found in /opt/VRTS/man/man3/vxfsu_get_ioffsets.3.
+
+       Those files of VxFS 3.4 Update 2 may be downloaded from:
+
+           ftp://ftp.veritas.com/pub/support/vxfs_34.i64243.tar
+
+       The vxfs_34.i64243.tar archive will unpack into an i64243
+       directory containing these files:
+
+           $ ls i64243
+           README
+           libvxfsutil.sol26.sums
+           libvxfsutil.sol26.tar.Z
+           libvxfsutil.sol27.sums
+           libvxfsutil.sol27.tar.Z
+           libvxfsutil.sol28.sums
+           libvxfsutil.sol28.tar.Z
+
+       Read README.  Select the *.tar.Z file appropriate for your
+       Solaris version.  Its contents will unpack into /opt/VRTS
+       and /opt/VRTSvxfs, so you will need sufficient permission
+       -- e.g., do it as root -- to unpack the uncompressed archive.
+       Once you've done that, it's a good idea to compare the
+       checksums of the archive you unpacked with the ones recorded
+       in the appropriate *.sums file.  Use `sum -r` to verify
+       the checksums.
+
+       For example, if you want the Solaris 8 version, uncompress
+       and unpack libvxfsutil.sol28.tar.Z -- e.g.,
+
+           $ su
+           ...
+           # cd i6423
+           # zcat libvxfsutil.sol28.tar.Z | tar xf -
+
+       That should create these new files and subdirectories with
+       the indicated checksums:
+
+           File or subdirectory                        sum -r
+
+           /opt/VRTSvxfs/include/vxfsutil.h            03938
+           /opt/VRTSvxfs/lib/libvxfsutil.a             51794
+           /opt/VRTSvxfs/lib/sparcv9/
+           /opt/VRTSvxfs/lib/sparcv9/libvxfsutil.a     07420
+           /opt/VRTS/man/man3/
+           /opt/VRTS/man/man3/vxfsu_get_ioffsets.3     62480
+
+       Once these files are in place, run lsof's Configure script
+       for the solaris or solariscc abbreviation.  Configure will
+       locate the appropriate VxFS 3.4 Update 2 files and set up
+       for the making of an lsof that will properly display open
+       VxFS 3.4 file information.
+
+17.18.2        Why does lsof report "vx_inode: vxfsu_get_ioffsets error"
+       for open Solaris 2.6 and above VxFS 3.4 and above files?
+
+       Even when lsof supports VxFS 3.4 and above on Solaris 2.6 and
+       above, it may report "vx_inode: vxfsu_get_ioffsets error" in
+       the NAME column for all VxFS files.
+
+       The usual cause is that lsof doesn't have permission to
+       read the file at the end of the /dev/vxportal symbolic
+       link.  If, for example, lsof has been installed setgid(sys),
+       then the /dev/vxportal symbolic link destination should be
+       owned by the sys group and readable by it.
+
+       Update 2 for VxFS 3.4 sets the modes of the /dev/vxportal
+       symbolic link destination to 0640 and the group ownership
+       to sys.  But I have had a report that the modes are wrong
+       in a VxFS 4.0 installation.
+
+       Another cause may be that the system has more than one version
+       of VxFS installed (Only one can be active.), and lsof's
+       Configure script did not choose the header files and libraries
+       for the active VxFS version.  Configure opts for VxFS 4.0 and
+       above header files and libraries (in /opt/VRTS) in preference
+       to those for VxFS below 4.0 (in /opt/VRTSvxfs).
+
+       Look for the directories /opt/VRTS and /opt/VRTSvxfs.  If you
+       have /opt/VRTS, make sure its header and library symbolic links
+       point to those of the active VxFS version.
+
+       If you have both directories, look at the CFLAGS that Configure
+       constructed for making lsof and see which directory path
+       follows a -I option.  If that doesn't match the directory path
+       of the active VxFS version, try pointing Configure at the
+       correct directory with the SOLARIS_VXFSINCL environment
+       variable -- e.g.,
+
+           $ SOLARIS_VXFSINCL=/opt/.../include ./Configure -n solaris
+
+17.18.3        Why does Solaris Configure claim there is no VxFS library?
+
+       The lsof Configure script, when configuring for Solaris, may
+       report:
+
+           FATAL: no VxFS .../libvxfsutil.a
+
+       That fatal error message indicates lsof has found the VxFS
+       utility library's header files, but can't find the library
+       itself in the expected location adjacent to the header files.
+
+       One possible cause is an incorrect symbolic link from
+       /opt/VRTS/lib/sparcv9/libvxfsutil.a to the library's real
+       location.  (Some VxFS distributions declared the link
+       incorrectly.)  Use `ls -lL` on that path to see if it exists.
+       If it doesn't exist, the link may be missing an additional
+       leading "../" component.
+
+       If the problem is a missing "../" from the library's link, you
+       can correct the link or check with Veritas/Symantec for the
+       patch that corrects it.
+
+       If the problem is not a missing "../", and you know the
+       libvxfsutil.a location, you can define its path in the
+       SOLARIS_VXFSLIB environment variable before running the lsof
+       Configure script.  (See 00XCONFIG for information about using
+       the SOLARIS_VXFSLIB environment variable.)
+
+       If you have no libvxfsutil.a, you must obtain it from
+       Veritas/Symantec or find it in your VxFS installation package.
+
+17.18.4 Why doesn't Solaris lsof report VxFS path name components?
+
+       Solaris lsof will report path name components for VxFS versions
+       that use the common Solaris Dynamic Name Lookup Cache (DNLC) or
+       on some file systems of VxFS versions that support the VxFS
+       Reverse Name Lookup (RNL) facility.
+
+       VxFS versions 3.3 (approximately) and below use the common
+       Solaris DNLC.  (I haven't been able to determine exactly when
+       VxFS stopped using the DNLC.)  For versions above that boundary,
+       but below 4.0, lsof can't report path name components.
+
+       At VxFS 4.0 and above, lsof can be compiled to use the VxFS RNL
+       facility for reporting path names.  If "-DHASVXFSRNL" appears
+       in the compiler flags section of lsof "-v" option output, then
+       the lsof Configure script detected the VxFS RNL facility and
+       lsof has been compiled to use it.
+
+       Lsof's use of the RNL facility can fail when the VxFS file
+       system disk layout version is below 6.  In that case, lsof can
+       report no path name components.  For more information, see the
+       vxfs_inotopath(3) manual page.  any of the following commands
+       will show the disk layout version for a VxFS file system, when
+       supplied the block device or mount point on which the file
+       system is mounted.
+
+           fstyp -v <block_device>
+        or
+           mkfs -m <block_device>
+        or
+           vxupgrade <mount_point>
+
+       You must have permission to read the block device -- e.g., be
+       the root user.
+
+       You may also be able to upgrade an older disk layout to one
+       that will work with the RNL.  See the vxupgrade(1M) man page
+       for more information on that.
+
+       When lsof can't report VxFS path name components, it reports
+       the file system mount point and the path name of device on
+       which it is mounted.  The device path name is enclosed in
+       parentheses.
+
+17.18.5        Why does Solaris 10 lsof report scrambled VxFS paths?
+
+       Solaris 10 lsof may report a bogus, scrambled path for an open
+       VxFS file, when lsof obtains the path from a vnode's cached
+       path.  Veritas/Symantec reports that their Solaris 10
+       implementation has bugs in the way it handles the Solaris 10
+       vnode cached path and those bugs will be fixed in an upcoming
+       patch some time after August 15, 2005.
+
+       When Solaris 10 lsof reports a path for an open VxFs file
+       obtained via the VxFS Reverse Name Lookup facility, the path
+       will be correct.
+
+       Also see the answers to the questions "Why does Solaris 10 lsof
+       sometimes report the wrong path name?" and "Why doesn't Solaris
+       lsof report VxFS path name components?"
+
+17.19  Large file problems
+
+17.19.1        Why does lsof complain it can't stat(2) a Solaris 2.5.1
+       large file?
+
+       When given an argument that is the path to a Solaris 2.5.1
+       file, enable for large file operations with the O_LARGEFILE
+       open(2) option, lsof complains that it can't stat(2) the
+       file.  That's because lsof isn't using a stat(2) call and
+       associated structure enabled for large files.
+
+       This error has been fixed, starting at lsof revision 4.58
+       for Solaris 2.6 and above.  That fix won't work on Solaris
+       2.5.1 and I no longer have access to a Solaris 2.5.1 test
+       system to develop a separate fix.
+
+       The work-around is to avoid specifying a O_LARGEFILE path
+       as an argument to lsof on Solaris 2.5.1.  Instead use a
+       combination of lsof and grep to achieve the same results,
+       albeit more clumsily.
+
+17.20   Why does lsof get a segmentation fault on 64 bit Solaris
+       8 using NIS+?
+
+       I have received a report from Gary Craig that lsof produces
+       a segmentation fault on his 64 bit Solaris 8 system using
+       NIS+.  Via an independent test program we have exonerated
+       lsof and tracked the fault to the NIS+ __nis_server_name()
+       function in the C name server library, -lnsl.
+
+       Lsof causes the __nis_server_name() NIS+ function to be
+       called by calling getservent() to read entries of the port
+       number to service name map.
+
+       The only Sun bug ID that appears to describe the problem
+       is 4304244, although its text is unclear enough to leave
+       room for doubt.
+
+       Until Sun eliminates the __nis_server_name() segmentation
+       fault cause, a work-around for lsof is to use its "-P"
+       option, causing lsof to avoid port to service name lookups.
+
+17.21  Will lsof crash the Solaris kernel?
+
+       I've received and investigated one report that it has when
+       the Sun hardware (a QME interface) was faulty.  Today (May
+       23, 2002) I've learned that Sun has reports of kernel
+       crashes caused by adb, lsof, and mdb.
+
+       The Sun investigation pinpointed a problem in the /dev/kmem
+       kernel driver and there is a Sun bug report, 4344513, about
+       the problem.  There is a fix in Solaris 9, and patches for
+       Solaris 7 and 8 (SPARC and x86).
+
+       To see if your Solaris system is fixed, look for a
+       /devices/pseudo/*allkmem node.
+
+       Extensive address filtering was added to lsof revision 4.50
+       to forestall what I then (July 2001) believed to be only
+       the possibility that lsof might crash Solaris.  However,
+       the filtering isn't perfect, since a filtered address might
+       become invalid after lsof has filtered it but before lsof
+       has delivered it to /dev/kmem.  That filtering work is
+       described in .../dialects/sun/solaris_kaddr_filters, also
+       available at:
+
+       ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/solaris_kaddr_filters
+
+       The best and safest work-around is to upgrade to Solaris
+       9 or install an appropriate patch or its equivalent from
+       this list:
+
+           Solaris     SPARC           x86
+           Version     Patch           Patch
+           =======     =====           =====
+              7        106541-20       106542-20
+              8        108528-14       108529-14
+
+17.22   Why does lsof on Solaris 7, 8, or 9 report a kvm_open()
+       failure?
+
+       When lsof is started on some Solaris 7, 8, and 9 systems
+       it may report:
+
+           lsof: kvm_open(namelist=default, corefile=default): \
+                 No such file or directory
+
+       Lsof revisions 4.65 and later will first report:
+
+           lsof: cannot stat /dev/allkmem
+
+       The second message, not delivered in lsof revisions below
+       4.65, explains the cause of the kvm_open() failure; it
+       can't find /dev/allkmem.
+
+       /dev/allkmem is a device added to Solaris 7 and 8 in patches
+       and in the Solaris 9 FCS.  See the preceding "Will lsof
+       crash the Solaris kernel?" section for more information on
+       /dev/allkmem and the patches.
+
+       The kvm_open(3KVM) function in the KVM library of patched
+       Solaris 7 and 8 systems and in Solaris 9 expects to find
+       /dev/allkmem and exits on error when it does not.
+
+       If you have installed the patch that updated your KVM
+       library to a version that expects /dev/allkmem to be present
+       and it is not, you may need to reconfigure your system's
+       devices with devfsadm(1M) or enter "boot -r" to the OpenBoot
+       monitor's prompt (usually "ok").
+
+17.23  Solaris and SAM-FS
+
+17.23.1        Why does Solaris lsof report "(limited SAM-FS info)"?
+
+       Lsof 4.68 and above report "(limited SAM-FS info)" on
+       Solaris in the NAME column after the path or file system
+       name for all files it finds on SAM-FS file systems.
+
+       That's because no more information is known about the
+       composition of the nodes that follow SAM-FS vnodes.  If
+       you can provide that information, please contact me via
+       e-mail at <abe@purdue.edu>.  Make sure "lsof" appears in the
+       "Subject:" line so my e-mail filter won't classify your letter
+       as Spam.
+
+17.23.2        Why can't lsof locate named SAM-GS files?
+
+       Solaris lsof 4.68 and above can't locate files on SAM-FS
+       file systems when the files are named as lsof arguments
+       because lsof doesn't know how to locate open SAM-FS file
+       device and node number information.  (See also 'Why does
+       Solaris lsof report "(limited SAM-FS info)?')
+
+17.24  Lsof and Solaris 10 zones
+
+17.24.1        How can I make lsof list the Solaris zone?
+
+       Use the lsof "-z [z]" option.
+
+17.24.2        Why doesn't lsof work in a Solaris 10 zone?
+
+       When run from within a Solaris 10 zone, lsof will usually
+       report:
+
+           lsof: can't stat(/devices): No such file or directory
+
+       That's because a Solaris zone usually has no /devices
+       subdirectory, a restriction of the zone implementation intended
+       to limit the ability of zone processes to control global system
+       resources, including physical devices.
+
+       While a zone may have a /dev subdirectory, that subdirectory
+       usually lacks the /dev/allkmem, /dev/mem and /dev/kmem devices
+       lsof and the KVM library it uses require.
+
+       The work-around is to run lsof in the global zone.  When it is
+       run in a global zone lsof will be able to report on processes
+       running in any zone, including the global zone.
+
+17.24.3 Why does lsof complain it can't stat() Solaris 10 zone file
+       systems?
+
+       When run from the global zone on Solaris 10 lsof may complain:
+
+           lsof: WARNING: can't stat() 15 zone file systems;
+                          using dev= options
+
+       The warning message means lsof found the reported number of
+       file system entries in the mount table for which it didn't have
+       permission to get stat(2) results, but which had "zone=" and
+       "dev=" mount table options.
+
+       That is a normal restriction of Solaris 10 zones.  Since the
+       lsof warning message indicates it was able to find "dev="
+       options for the file systems, lsof will probably work
+       correctly.
+
+       One work-around is to relax the restrictions on zone mount
+       points, so that lsof can stat() them.  While that may be
+       possible by changing directory modes or group ownerships, it is
+       probably not a good idea, because it weakens the restrictions
+       zones are intended to provide.
+
+       Another work-around is to suppress the warning message with
+       lsof's "-w" option.  The down side of that is that it causes
+       the suppression of all warning messages, leading to the
+       possibility that some non-stat() warning messages will be
+       suppressed.
+
+17.25  Solaris 10 problems
+
+17.25.1 Why does Solaris 10 lsof sometimes report the wrong path name?
+
+       When a path name component is renamed -- e.g., with mv(1) --
+       Solaris 10 lsof may report the old component for an open file
+       that used the component in its path before the rename.  That's
+       because Solaris 10 lsof reports the path name cached in the
+       open file's vnode and the Solaris 10 kernel doesn't update the
+       open vnode's cached path name when a component of it is changed.
+
+       When an open file is deleted -- e.g., with rm(1) -- the path
+       name by which it was opened remains cached in the vnode.  Lsof
+       can be instructed to display that path name with the -X option.
+       The path name might be incorrect because of the rename problem
+       described above.  See the answer to the 'What does "(deleted)"
+       mean in the NAME column of a Solaris 10 open file?' question
+       for more information.
+
+       Lsof is sometimes able to detect that cached path name is
+       incorrect.  In that case lsof may report only the mounted-on
+       directory and device of the file system or it may report that
+       the path name is of questionable accuracy by appending a
+       trailing "(?)" to it in the NAME column.
+
+       See the answer to the "Why does Solaris 10 lsof sometimes
+       report only the mounted-on directory and device?" and 'What
+       does "(?)" mean in the NAME column of a Solaris 10 open file?'
+       questions for more information.
+
+17.25.2 Why does Solaris 10 lsof sometimes report only the mounted-on
+       directory and device?
+
+       For some regular open files lsof may report only the mounted-on
+       directory and device of the file system on which the file
+       resides.  That's because lsof was able to determine that the
+       path name cached in the open file's vnode is incorrect.
+
+       Lsof detects the cached path name is incorrect by applying
+       stat(2) to it, provided that no error was detected when stat(2)
+       was applied to the file system mounted-on directory during lsof
+       setup.  If a mounted-on directory stat(2) error was detected
+       during setup, lsof does no cached path name analysis and simply
+       reports it.
+
+       When the application of stat(2) to the cached path name returns
+       a no-entry reply (the ENOENT error number), lsof concludes the
+       path no longer exists (i.e., has been unlinked) and reports the
+       mounted-on directory and device of the file system.  That
+       behavior can be modified with the -X option in lsof revisions
+       4.77 and above.  See the answer to the 'What does "(deleted)"
+       mean in the NAME column of a Solaris 10 open file?' for more
+       information.
+
+       When the application of stat(2) to the cached path name returns
+       a permission error reply (the EACCES or EPERM error numbers),
+       lsof reports the cached path name and adds a trailing "(?)" to
+       indicate the reported path name is of questionable accuracy.
+       See the answer to the question 'What does "(?)" mean in the
+       NAME column of a Solaris 10 open file?' for more information.
+
+       If the application of stat(2) to the cached path name yields
+       any other error reply, lsof reports the mounted-on directory
+       and device of the file system.
+
+       When the application of stat(2) to the cached path name
+       succeeds, lsof compares the reported device and node numbers to
+       what it has obtained for the open file from kernel structures.
+       If they match, lsof reports the cached path name.  If they
+       don't match, lsof instead reports the mounted-on directory and
+       device of the file system.
+
+       A work-around that allows lsof to apply stat(2) successfully to
+       cached path names is to give lsof sufficient permission to do
+       it -- i.e., run lsof as the root user.
+
+17.25.3        What does "(deleted)" mean in the NAME column of a Solaris 10
+       open file?
+
+       When the -X option is specified to Solaris 10 lsof, it will
+       report in its NAME column the path name cached for a deleted
+       file in its vnode.  The path name will be followed by
+       "(deleted)".
+
+       Note that the path name cached in a file's vnode is the path
+       name by which the file was opened.  It is not updated by the
+       Solaris kernel when any path name component is changed.  Hence,
+       it may not represent the final path name the open file had.
+
+       See the answer to the "Why does Solaris 10 lsof sometimes
+       report the wrong path name?" question for more information on
+       how changing a path name component affects the correctness of a
+       what lsof reports.
+
+17.25.4 What does "(?)" mean in the NAME column of a Solaris 10 open
+       file?
+
+       When lsof encounters a path name cached in the open file's
+       vnode that stat(2) reports lsof lacks permission to access,
+       lsof adds "(?)" to the path name reported in the NAME column to
+       indicate the path name is of questionable accuracy.
+
+       See the answers to the "Why does Solaris 10 lsof sometimes
+       report the wrong path name?" and "Why does Solaris 10 lsof
+       sometimes report only the mounted-on directory and device?"
+       questions for more information on why lsof may report a path
+       name of questionable accuracy.
+
+       A work-around that allows lsof to apply stat(2) successfully to
+       cached path names is to give lsof sufficient permission to do
+       it -- i.e., run lsof as the root user.
+
+17.26  Solaris contract file problems
+
+17.26.1        Why doesn't lsof report size, link count and node number for
+       Solaris 10 contract files?
+
+       Lsof doesn't report size, link count or node number for Solaris
+       10 contract files because I don't know how to obtain them from
+       contract file kernel structures.
+
+17.26.2        Why can't lsof locate a Solaris 10 contract file by path name?
+
+       Because lsof can't find the node number of Solaris contract
+       files, it can't match the device and node numbers it gets from
+       applying stat(2) to the contract file path name with what it
+       finds in kernel data.
+
+17.27  Solaris 10 and above ZFS probblems
+
+17.27.1        Why does Configure warn that ZFS support is not enabled?
+
+       To provide ZFS support it is necessary that lsof have access to
+       the definitions of ZFS structures used by the kernel.  Those
+       definitions are made available to lsof when it runs by the
+       libctl library.
+
+       If lsof's Configure script finds that ZFS is indicated by the
+       presence of the <sys/fs/zfs.h> header file, but the libctl
+       library is not indicated via the <libctl.h> header file, the
+       script concludes that ZFS support is not possible and issues
+       the following warning:
+
+         WARNING: ZFS support not enabled; libctf.h missing.
+
+       Install libctf support to remedy this problem.
+
+
+17.28  Problems with Solaris 9 and above
+
+17.28.1        Why does the compiler complain about lgrp_root on Solaris 9
+       and above?
+
+       When compiling lsof 4.84 on later Solaris 9 and 10 systems, the
+       compiler may report the following error:
+
+         /usr/include/sys/lgrp.h", line ...: identifier redeclared: lgrp_root
+
+       This error results from a conflict between usage of lgrp_root
+       in both <sys/lgrp.h> and <sys/lgrp_user.h> when _KMEMUSER or
+       _KERNEL is #define'd before <sys/lgrp.h> is #include'd.  This
+       problem is noted in Sunsolve bug ID 5064229.
+
+       The work-around is to use lsof revision 4.85 sources.
+
+
+18.0   Lsof Features
+
+18.1   Why doesn't lsof doesn't report on /proc entries on my
+       system?
+
+       /proc file system support is generally available only for
+       BSD, SYSV R4 dialects, and Tru64 UNIX (Digital UNIX, DEC
+       OSF/1).  It's also available for Linux, and Pyramid DC/OSx
+       and Reliant UNIX.
+
+       Even on some SYSV R4 dialects I encountered many problems
+       while trying to incorporate /proc file system support.
+       The chief problem is that some vendors don't distribute
+       the header file that describes the /proc file system node
+       -- usually called prdata.h.
+
+18.2   How do I disable the device cache file feature or alter
+       it's behavior?
+
+       To disable the device cache file feature for a dialect,
+       remove the HASDCACHE definition from the machine.h file of
+       the dialect's machine.h header file.  You can also use
+       HASDCACHE to change the default prefix (``.lsof'') of the
+       device cache file.
+
+       Be sure you consider disabling the device cache file feature
+       carefully.  Having a device cache file significantly reduces
+       lsof startup overhead by eliminating a full scan of /dev
+       (or /devices) once the device cache file has been created.
+       That full scan also overloads the kernel's name cache with
+       the names of the /dev (or /devices) nodes, reducing the
+       opportunity for lsof to find path name components of open
+       files.
+
+       If you're worried about the presence of mode 0600 device
+       cache files in the home directories of the real user IDs
+       that execute lsof, consider these checks that lsof makes
+       on the file before using it:
+
+           1.  To read the device cache file, lsof must gain
+               permission from access(2).
+
+           2.  The device cache file's modes must be 0600 (0644
+               if lsof is reading a system-wide device cache file)
+               and its size non-zero.
+
+           3.  There must be a correctly formatted section count
+               line at the beginning of the file.
+
+           4.  Each section must have a header line with a count
+               that properly numbers the lines in the section.
+               Legal sections are device, clone, pseudo-device,
+               and CRC.
+
+           5.  The lines of a section must have the proper format.
+
+           6.  All lines are included in a 16 bit CRC, and it is
+               recorded in a non-checksummed section line at the
+               end of the file.
+
+           7.  The checksum computed when the file is read must
+               match the checksum recorded when the file was
+               written.
+
+           8.  The checksum section line must be followed by
+               end-of-information.
+
+           9.  Lsof must be able to get matching results from
+               stat(2) on a randomly chosen entry of the device
+               section.
+
+       For more information on the device cache file, read the
+       00DCACHE file of the lsof distribution.
+
+18.2.1 What's the risk with a perverted device cache file?
+
+       Even with the checks that lsof makes on the device cache
+       file, it's conceivable that an intruder could modify it so
+       it would pass lsof's tests.
+
+       The only serious consequence I know of this change is the
+       removal of a file whose major device number identifies a
+       socket from some user ID's device cache file.  When such
+       a device has been removed from the device cache file, and
+       when lsof doesn't detect the removal, lsof may not be able
+       to identify socket files when executed by the affected user
+       ID.  Only certain dialects are at risk to this attack --
+       e.g., SCO OpenServer and Solaris 2.x, 7, 8, and 9.
+
+       If you're tracking a network intruder with lsof, that could
+       be important to you.  If you suspect that someone has
+       corrupted the device cache file you're using, I recommend
+       you use lsof's -Di option to tell it to ignore it and use
+       the contents of /dev (or /devices) instead; or remove the
+       device cache file (usually .lsof_hostname, where hostname
+       is the first component of the host's name returned by
+       gethostname(2)) from the user ID's home directory and let
+       lsof create a new one for you.
+
+18.2.2 How do I put the full host name in a personal device cache file
+       path?
+
+       Lsof constructs the personal device cache file path name
+       from a format specified in the HASPERSDC #define in the
+       dialect's machine.h header file.  As distributed HASPERSDC
+       declares the path to be ``.lsof_'' plus the first component
+       of the host name with the format ``.lsof_%L''.
+
+       If you want to change the way lsof constructs the personal
+       device cache file path name, you can change the HASPERSDC
+       #define and recompile lsof.  If, for example, you #define
+       HASPERSDC to be ``.lsof_%l'' (note the lower case `l'),
+       Configure and remake lsof, then the personal device cache
+       file path will be ``.lsof_'' plus the host name returned
+       by gethostname(2).
+
+       See the 00DCACHE file of the lsof distribution for more
+       information on the formation of the personal device cache
+       file path and the use of the HASPERSDC #define.
+
+18.2.3 How do I put the personal device cache file in /tmp?
+
+       Change the HASPERSDC definition in your dialect's machine.h
+       header file.
+
+       When you redefine HASPERSDC, make sure you put at least
+       one user identification conversion in it to keep separate
+       the device cache files for each user of lsof.  Also give
+       some thought to including the ``%0'' conversion to define
+       an alternate path for setuid-root and root processes.
+
+       Here's a definition that puts a personal device cache file
+       in /tmp with the name ``.lsof_login_hostname_pers''.
+
+           #define HASPERSDC "/tmp/.lsof_%u_%l_pers"
+
+       Thus the /tmp personal device cache file path for login
+       "abe" on host "lsof.itap.purdue.edu" would be:
+
+           /tmp/.lsof_abe_lsof.itap.purdue.edu_pers
+
+       You can add the User ID (UID) with the "%U" conversion and
+       the first host name component with the ``%L'' conversion.
+
+       CAUTION: be careful using absolute paths like /tmp lest
+       lsof processes that are setuid-root or whose real UID is
+       root be used to exploit some security weakness via /tmp.
+       Elect instead to add an alternate path for those processes
+       with the ``%0'' conversion.  Here's an extension of the
+       previous HASPERSDC format for /tmp that declares an alternate
+       path:
+
+           #define HASPERSDC "/tmp/.lsof_%u_%l_pers%0%h/.lsof_%L"
+
+       When the lsof process is setuid-root or its real UID is
+       root, presuming root's home directory is `/' and the host's
+       name is ``lsof.itap.purdue.edu'', the extended format yields:
+
+           /.lsof_vic
+
+18.3   Why doesn't lsof know about AFS files on my favorite dialect?
+
+       Lsof currently supports AFS for these dialects:
+
+           AIX 4.1.4 (AFS 3.4a)
+           Linux 1.2.13 (AFS 3.3)
+           Solaris 2.[56] (AFS 3.4a)
+
+       It may recognize AFS files on other versions of these
+       dialects, but I have no way to test that.  Lsof may report
+       correct information for AFS files on other dialects, but
+       I can't test that either.
+
+       AFS support must be custom crafted for each UNIX dialect
+       and then tested.  If lsof supports your favorite dialect,
+       but doesn't recognize its AFS files, probably I don't have
+       access to a test system.  If you want AFS support badly
+       for your dialect, consider helping me do the development
+       and testing.
+
+18.3.1 Why doesn't lsof report node numbers for all AFS volume files,
+       or how do I reveal dynamic module addresses to lsof?
+
+       When AFS is implemented via dynamic kernel modules -- e.g.,
+       in NEXTSTEP -- lsof can't obtain the addresses of AFS
+       variables in the kernel that it uses to identify AFS vnodes.
+       It can guess that a vnode is assigned to an AFS file and
+       it can obtain other information about AFS files, but it
+       has trouble computing AFS volume node numbers.
+
+       To determine node numbers for AFS volumes other than the
+       root volume, /afs, lsof needs access to a hashed volume
+       structure pointer table.  When it can't find the address
+       of that table, because AFS support is implemented via
+       dynamic kernel modules, lsof will return blanks in the
+       INODE column for AFS volume files.  Lsof can identify the
+       root volume's node number (0), and can compute the node
+       numbers for all other AFS files.
+
+       If you have a name list file that contains the addresses
+       of the AFS dynamic modules -- e.g., you saved module symbols
+       when you created a loadable module kernel with modload(8)
+       by specifying -sym -- lsof may be able to find the kernel
+       addresses it needs in that file.
+
+       Lsof looks up AFS dynamic kernel addresses for these dialects
+       at these default paths:
+
+           NEXTSTEP 3.2        /usr/vice/etc/afs_loadable
+
+       A different path to a name list file with AFS dynamic kernel
+       addresses may be specified with the -A option, when the -A
+       option description appears in lsof's -h or -? (help) output.
+
+       If any addresses appear in the -A name list file that also
+       appear in the regular kernel name list file -- e.g., /vmunix
+       -- they must match, or lsof will silently ignore the -A
+       addresses on the presumption that they are out of date.
diff --git a/00LSOF-L b/00LSOF-L
new file mode 100644 (file)
index 0000000..4f2603a
--- /dev/null
+++ b/00LSOF-L
@@ -0,0 +1,99 @@
+
+                   The Lsof Mailing List, lsof-l
+
+Information on lsof is available via a GNU Mailman mailing list, named
+lsof-l.  The server is located on the host lists.purdue.edu.
+
+
+Subscribing
+===========
+
+You may subscribe to the lsof-l mailing list by sending e-mail to:
+
+  lsof-l-subscribe@lists.purdue.edu
+
+The body of your e-mail may be empty.  You will receive a confirmation
+reply, explaining one further step you must take to complete your
+subscription.
+
+The list manager uses the e-mail address and real name in the "From:"
+line of your request to set those values in your subscription.  If you
+want different values in your subscription, consult the Mailman help
+information to learn how to specify them on your subscription request.
+(See the next "Get Help" section on how to obtain Mailman help
+information.)
+
+
+Get Help
+========
+
+More information about the lists.purdue.edu GNU Mailman server is
+available by sending e-mail to lsof-l-request@lists.purdue.edu with
+"help" in the subject line.  The body of your e-mail may be empty.
+
+The other information will be delivered by return e-mail.
+
+You can also obtain information on the Mailman e-mail commands in
+section 3.2 of the GNU Mailman documentation at:
+
+  http://www.gnu.org/software/mailman/mailman-member/mailman-member.html
+
+
+The Web Interface
+=================
+
+There is a web interface at:
+
+  https://lists.purdue.edu/mailman/listinfo/lsof-l
+
+You can use it to manage your lsof-l list entry.
+
+
+Posting and Moderation
+======================
+
+Once you have subscribed to lsof-l (and have an e-mail confirmation
+that your subscription was accepted), you may post messages to the list
+by sending e-mail directly to:
+
+  lsof-l@lists.purdue.edu
+
+I moderate the lsof-l mailing list and try to keep its traffic low,
+mainly limiting it to announcements of new revisions, patches and
+security issues.  Postings don't appear until I've approved them.
+
+
+Send Bug Reports to lsof-l, too
+===============================
+
+Since I am no longer actively supporting lsof -- 4.91 is probably the
+last revision I will distribute --  bug reports should be sent to
+lsof-l.  There are readers of lsof-l who may be able to help you.
+
+
+Unsubscribing
+=============
+
+You can unsubscribe from lsof-l by sending e-mail to:
+
+  lsof-l-unsubscribe@lists.purdue.edu
+
+The body of your e-mail may be empty.  You will receive a confirmation
+reply, explaining one further step you must take to complete the
+removal of your subscription.
+
+
+Archive
+=======
+
+There is an archive; use the link:
+
+  https://lists.purdue.edu/mailman/private/lsof-l
+
+The archive link is the first one on the web page.  You will need the
+password you received or set when you subscribed, or later set via
+lsof-l-request or the web interface.
+
+
+Vic Abell <abe@purdue.edu>
+March ??? 2018
diff --git a/00MANIFEST b/00MANIFEST
new file mode 100644 (file)
index 0000000..951b93f
--- /dev/null
@@ -0,0 +1,343 @@
+.:
+00.README.FIRST
+00CREDITS
+00DCACHE
+00DIALECTS
+00DIST
+00FAQ
+00LSOF-L
+00MANIFEST
+00PORTING
+00QUICKSTART
+00README
+00TEST
+00XCONFIG
+AFSConfig*
+ChangeLog
+Configure*
+Customize*
+Inventory*
+arg.c
+dialects/
+lib/
+lsof.8
+common.h
+lsof.man
+lsof_fields.h
+main.c
+misc.c
+node.c
+print.c
+proc.c
+proto.h
+scripts/
+store.c
+tests/
+usage.c
+util.c
+version
+
+./dialects:
+aix/
+darwin/
+du/
+freebsd/
+hpux/
+linux/
+netbsd/
+n+os/
+openbsd/
+osr/
+sun/
+uw/
+
+./dialects/aix:
+Makefile
+Mksrc*
+aix5/
+ddev.c
+dfile.c
+dlsof.h
+dmnt.c
+dnode.c
+dnode1.c
+dnode2.c
+dproc.c
+dproto.h
+dsock.c
+dstore.c
+machine.h
+
+./dialects/aix/aix5:
+README
+j2/
+
+./dialects/aix/aix5/j2:
+j2_lock.h
+private_j2_snapshot.h
+
+./dialects/darwin:
+Makefile
+Mksrc*
+ddev.c
+dfile.c
+dlsof.h
+dmnt.c
+dproc.c
+dproto.h
+dsock.c
+dstore.c
+machine.h
+
+./dialects/du:
+Makefile
+Mksrc*
+ddev.c
+dfile.c
+dlsof.h
+dmnt.c
+dnode.c
+dproc.c
+dproto.h
+dsock.c
+dstore.c
+machine.h
+
+./dialects/freebsd:
+Makefile
+Makefile.zfs
+Mksrc*
+dlsof.h
+dmnt.c
+dnode.c
+dnode1.c
+dnode2.c
+dproc.c
+dproto.h
+dsock.c
+dstore.c
+dzfs.h
+include/
+machine.h
+
+./dialects/freebsd/include:
+procfs/
+
+./dialects/freebsd/include/procfs:
+pfsnode.h
+
+./dialects/hpux:
+kmem/
+pstat/
+
+./dialects/hpux/kmem:
+Makefile
+Mksrc*
+dfile.c
+dlsof.h
+dmnt.c
+dnode.c
+dnode1.c
+dnode2.c
+dproc.c
+dproto.h
+dsock.c
+dstore.c
+hpux11/
+machine.h
+
+./dialects/hpux/kmem/hpux11:
+ipc_s.h
+kernbits.h
+lla.h
+nfs_clnt.h
+proc.h
+rnode.h
+sth.h
+tcp_s.h
+udp_s.h
+vnode.h
+
+./dialects/hpux/pstat:
+Makefile
+Mksrc*
+dfile.c
+dlsof.h
+dproc.c
+dproto.h
+dsock.c
+dstore.c
+machine.h
+
+./dialects/linux:
+Makefile
+Mksrc*
+dfile.c
+dlsof.h
+dmnt.c
+dnode.c
+dproc.c
+dproto.h
+dsock.c
+dstore.c
+machine.h
+
+./dialects/netbsd:
+Makefile
+Mksrc*
+dlsof.h
+dmnt.c
+dnode.c
+dnode1.c
+dproc.c
+dproto.h
+dsock.c
+dstore.c
+machine.h
+
+./dialects/n+os:
+Makefile
+Mksrc*
+dlsof.h
+dnode.c
+dnode1.c
+dproc.c
+dproto.h
+dsock.c
+dstore.c
+machine.h
+
+./dialects/osr:
+Makefile
+Mksrc*
+dfile.c
+dlsof.h
+dmnt.c
+dnode.c
+dproc.c
+dproto.h
+dsock.c
+dstore.c
+include/
+machine.h
+
+./dialects/osr/include:
+netdb.h
+sys/
+
+./dialects/osr/include/sys:
+cdefs.h
+
+./dialects/sun:
+Makefile
+Mksrc*
+ddev.c
+dfile.c
+dlsof.h
+dmnt.c
+dnode.c
+dnode1.c
+dnode2.c
+dproc.c
+dproto.h
+dsock.c
+dstore.c
+machine.h
+solaris_kaddr_filters
+
+./dialects/uw:
+Makefile
+Mksrc*
+dfile.c
+dlsof.h
+dmnt.c
+dnode.c
+dnode1.c
+dnode2.c
+dnode3.c
+dproc.c
+dproto.h
+dsock.c
+dstore.c
+machine.h
+uw7/
+
+./dialects/uw/uw7:
+README
+fs/
+sys/
+vm/
+
+./dialects/uw/uw7/fs:
+nsc_cfs/
+procfs/
+
+./dialects/uw/uw7/fs/nsc_cfs:
+cnode.h
+
+./dialects/uw/uw7/fs/procfs:
+README
+prdata.h
+
+./dialects/uw/uw7/sys:
+fs/
+
+./dialects/uw/uw7/sys/fs:
+README
+fifonode.h
+namenode.h
+
+./dialects/uw/uw7/vm:
+
+./lib:
+Makefile.skel
+ckkv.c
+cvfs.c
+dvch.c
+fino.c
+isfn.c
+lkud.c
+pdvn.c
+prfp.c
+ptti.c
+rdev.c
+rmnt.c
+rnam.c
+rnch.c
+rnmh.c
+snpf.c
+
+./scripts:
+00MANIFEST
+00README
+big_brother.perl5*
+count_pf.perl*
+count_pf.perl5*
+identd.perl5*
+idrlogin.perl*
+idrlogin.perl5*
+list_NULf.perl5*
+list_fields.awk
+list_fields.perl*
+shared.perl5*
+sort_res.perl5*
+watch_a_file.perl*
+xusers.awk*
+
+./tests:
+00README
+Add2TestDB*
+CkTestDB*
+LTbasic.c
+LTbigf.c
+LTdnlc.c
+LTlib.c
+LTlock.c
+LTnfs.c
+LTnlink.c
+LTsock.c
+LTszoff.c
+LTunix.c
+LsofTest.h
+Makefile
+TestDB
diff --git a/00PORTING b/00PORTING
new file mode 100644 (file)
index 0000000..46cd142
--- /dev/null
+++ b/00PORTING
@@ -0,0 +1,1793 @@
+
+               Guide to Porting lsof 4 to Unix OS Dialects
+
+**********************************************************************
+| The latest release of lsof is always available via anonymous ftp   |
+| from lsof.itap.purdue.edu.  Look in pub/lsof.README for its        |
+| location.                                                          |
+**********************************************************************
+
+                           Contents
+
+       How Lsof Works
+       /proc-based Linux Lsof -- a Different Approach
+       General Guidelines
+       Organization
+       Source File Naming Conventions
+       Coding Philosophies
+       Data Requirements
+       Dlsof.h and #include's
+       Definitions That Affect Compilation
+       Options: Common and Special
+       Defining Dialect-Specific Symbols and Global Storage
+       Coding Dialect-specific Functions
+       Function Prototype Definitions and the _PROTOTYPE Macro
+       The Makefile
+       The Mksrc Shell Script
+       The MkKernOpts Shell Script
+       Testing and the lsof Test Suite
+       Where Next?
+
+
+How Lsof Works
+--------------
+
+Before getting on with porting guidelines, just a word or two about
+how lsof works.
+
+Lsof obtains data about open UNIX dialect files by reading the
+kernel's proc structure information, following it to the related
+user structure, then reading the open file structures stored
+(usually) in the user structure.  Typically lsof uses the kernel
+memory devices, /dev/kmem, /dev/mem, etc. to read kernel data.
+
+Lsof stores information from the proc and user structures in an
+internal, local proc structure table.  It then processes the open
+file structures by reading the file system nodes that lie behind
+them, extracting and storing relevant data in internal local file
+structures that are linked to the internal local process structure.
+
+Once all data has been gathered, lsof reports it from its internal,
+local tables.
+
+There are a few variants on this subject.  Some systems don't have
+just proc structures, but have task structures, too, (e.g., NeXTSTEP
+and OSF/1 derivatives).  For some dialects lsof gets proc structures
+or process information (See "/proc-based Linux Lsof -- a Different
+Approach) from files of the /proc file system.  It's not necessary
+for lsof to read user structures on some systems (recent versions
+of HP-UX), because the data lsof needs can be found in the task or
+proc structures.  In the end lsof gathers the same data, just from
+slightly different sources.
+
+
+/proc-based Linux Lsof -- a Different Approach
+==============================================
+
+For a completely different approach to lsof construction, take a
+look at the /proc-based Linux sources in .../dialects/linux/proc.
+(The sources in .../dialects/linux/kmem are for a traditional lsof
+that uses /dev/kmem to read information from kernel structures.)
+
+The /proc-based lsof obtains all its information from the Linux
+/proc file system.  Consequently, it is relatively immune to changes
+in Linux kernel structures and doesn't need to be re-compiled each
+time the Linux kernel version changes.
+
+There are some down-sides to the Linux /proc-based lsof:
+
+    *  It must run setuid-root in order to be able to read the
+       /proc file system branches for all processes.  In contrast,
+       the /dev/kmem-based Linux lsof usually needs only setgid
+       permission.
+
+    *  It depends on the exact character format of /proc files, so
+       it is sensitive to changes in /proc file composition.
+
+    *  It is limited to the information a /proc file system
+       implementor decides to provide.  For example, if a
+       /proc/net/<protocol> file lacks an inode number, the
+       /proc-based lsof can't connect open socket files to that
+       protocol.  Another deficiency is that the /proc-based may
+       not be able to report file offset (position) information,
+       when it isn't available in the /proc/<PID>/fd/ entry for a
+       file.
+
+       In contrast the /dev/kmem-based lsof has full access to
+       kernel structures and "sees" new data as soon as it appears.
+       Of course, that new data requires that lsof be recompiled
+       and usually also requires changes to lsof.
+
+Overall the switch from a /dev/kmem base to a /proc one is an
+advantage to Linux lsof.  The switch was made at lsof revision 4.23
+for Linux kernel versions 2.1.72 (approximately) and higher.  The
+reason I'm not certain at which Linux kernel version a /proc-based
+lsof becomes possible is that the /proc additions needed to implement
+it have been added gradually to Linux 2.1.x in ways that I cannot
+measure.
+
+/proc-based lsof functions in many ways the same as /dev/kmem-based
+lsof.  It scans the /proc directory, looking for <PID>/ subdirectories.
+Inside each one it collects process-related data from the cwd, exe,
+maps, root, and stat information files.
+
+It collects open file information from the fd/ subdirectory of each
+<PID>/ subdirectory.  The lstat(2), readlink(2), and stat(2) system
+calls gather information about the files from the kernel.
+
+Lock information comes from /proc/locks.  It is matched to open
+files by inode number.  Mount information comes from /proc/mounts.
+Per domain protocol information comes from the files of /proc/net;
+it's matched to open socket files by inode number.
+
+The Linux /proc file system implementors have done an amazing job
+of providing the information lsof needs.  The /proc-based lsof
+project has so far generated only two kernel modification:
+
+    *  A modification to /usr/src/linux/net/ipx/af_ipx.c adds the
+       inode number to the entries of /proc/net/ipx.
+
+       Jonathan Sergent did this kernel modification.
+
+       It may be found in the .../dialects/linux/proc/patches
+       subdirectory of the lsof distribution.
+
+    *  An experimental modification to /usr/src/linux/fs/stat.c
+       allows lstat(2) to return file position information for
+       /proc/<PID>/fd/<FD> files.
+
+       Contact me for this modification.
+
+
+One final note about the /proc-based Linux lsof: it doesn't need
+any functions from the lsof library in the lib/ subdirectory.
+
+FreeBSD is now also using a similar approach. Sysctls are used
+to retrieve processes, files, socket PCBs etc. Access to kernel
+memory is optional and only used as a last resort when data is
+not provided by the kernel.
+
+
+General Guidelines
+------------------
+
+These are the general guidelines for porting lsof 4 to a new Unix
+dialect:
+
+    *  Understand the organization of the lsof sources and the
+       philosophies that guide their coding.
+
+    *  Understand the data requirements and determine the methods
+       of locating the necessary data in the new dialect's kernel.
+
+    *  Pick a name for the subdirectory in lsof4/dialects for your
+       dialect.  Generally I use a vendor operating system name
+       abbreviation.
+
+    *  Locate the necessary header files and #include them in the
+       dialect's dlsof.h file.  (You may not be able to complete
+       this step until you have coded all dialect-specific functions.)
+
+    *  Determine the optional library functions of lsof to be used
+       and set their definitions in the dialect's machine.h file.
+
+    *  Define the dialect's specific symbols and global storage
+       in the dialect's dlsof.h and dstore.c files.
+
+    *  Code the dialect-specific functions in the appropriate
+       source files of the dialect's subdirectory.
+
+       Include the necessary prototype definitions of the dialect-
+       specific functions in the dproto.h file in the dialect's
+       subdirectory.
+
+    *  Define the dialect's Makefile and source construction shell
+       script, Mksrc.
+
+    *  If there are #define's that affect how kernel structures
+       are organized, and those #define's are needed when compiling
+       lsof, build a MkKernOpts shell script to locate the #define's
+       and supply them to the Configure shell script.
+
+
+Organization
+------------
+
+The code in a dialect-specific version of lsof comes from three
+sources:
+
+    1)  functions common to all versions, located in the top level
+       directory, lsof4;
+
+    2)  functions specific to the dialect, located in the dialect's
+       subdirectory -- e.g., lsof4/dialects/sun;
+
+    3)  functions that are common to several dialects, although
+       not to all, organized in a library, liblsof.a.  The functions
+       in the library source can be selected and customized with
+       definitions in the dialect machine.h header files.
+
+The tree looks like this:
+
+                           lsof4 ----------------------+ 3) library --
+                           |   \                            lsof4/lib
+  1) fully common functions +    \
+      e.g., lsof4/main.c         + lsof4/dialects/
+                          / / / / \
+                          + + + +  +
+  2) dialect-specific subdirectories -- e.g., lsof4/dialects/sun
+
+The code for a dialect-specific version is constructed from these
+three sources by the Configure shell script in the top level lsof4
+directory and definitions in the dialect machine.h header files.
+Configure uses the Mksrc shell script in each dialect's subdirectory,
+and may use an optional MkKernOpts shell script in selected dialect
+subdirectories.
+
+Configure calls the Mksrc shell script in each dialect's subdirectory
+to assemble the dialect-specific sources in the main lsof directory.
+Configure may call MkKernOpts to determine kernel compile-time
+options that are needed for compiling kernel structures correctly
+for use by lsof.  Configure puts the options in a dialect-specific
+Makefile it build, using a template in the dialect subdirectory.
+
+The assembly of dialect-specific sources in the main lsof directory
+is usually done by creating symbolic links from the top level to
+the dialect's subdirectory.  The LSOF_MKC environment variable may
+be defined prior to using Configure to change the technique used
+to assemble the sources -- most commonly to use cp instead of ln -s.
+
+The Configure script completes the dialect's Makefile by adding
+string definitions, including the necessary kernel compile-time
+options, to a dialect skeleton Makefile while copying it from the
+dialect subdirectory to the top level lsof4 directory.  Optionally
+Makefile may call the dialect's MkKernOpts script to add string
+definitions.
+
+When the lsof library, lsof4/lib/liblsof.a, is compiled its
+functions are selected and customized by #define's in the dialect
+machine.h header file.
+
+
+Source File Naming Conventions
+------------------------------
+
+With one exception, dialect-specific source files begin with a
+lower case `d' character -- ddev.c, dfile.c, dlsof.h.  The one
+exception is the header file that contains dialect-specific
+definitions for the optional features of the common functions.
+It's called machine.h for historical reasons.
+
+Currently all dialects use almost the same source file names.  One
+exception to the rule happens in dialects where there must be
+different source files -- e.g., dnode[123].c -- to eliminate node
+header file structure element name conflicts.  The source modules
+in a few subdirectories are organized that way.
+
+These are common files in lsof4/:
+
+    Configure  the configuration script
+
+    Customize  does some customization of the selected lsof
+               dialect
+
+    Inventory  takes an inventory of the files in an lsof
+               distribution
+
+    version    the version number
+
+    dialects/  the dialects subdirectory
+
+These are the common function source files in lsof4/:
+
+    arg.c      common argument processing functions
+
+    common.h   common header file that #include's the dialect-specific
+               header files
+
+    main.c     common main function for lsof 4
+
+    misc.c     common miscellaneous functions -- e.g., special versions
+               of stat() and readlink()
+
+    node.c     common node reading functions -- readinode(), readvnode()
+
+    print.c    common print support functions
+
+    proc.c     common process and file structure functions
+
+    proto.h    common prototype definitions, including the definition of
+               the _PROTOTYPE() macro
+
+    store.c    common global storage version.h the current lsof version
+               number, derived from the file version by the Makefile
+
+    usage.c    functions to display lsof usage panel
+
+These are the dialect-specific files:
+
+    Makefile   the Makefile skeleton
+
+    Mksrc      a shell script that assists the Configure script
+               in configuring dialect sources
+
+    MkKernOpts  an optional shell script that identifies kernel
+               compile-time options for selected dialects -- e.g.,
+               Pyramid DC/OSx and Reliant UNIX
+
+    ddev.c     device support functions -- readdev() -- may be
+               eliminated by functions from lsof4/lib/
+
+    dfile.c    file processing functions -- may be eliminated by
+               functions from lsof4/lib/
+
+    dlsof.h    dialect-specific header file -- contains #include's
+               for system header files and dialect-specific global
+               storage declarations
+
+    dmnt.c     mount support functions -- may be eliminated by
+               functions from lsof4/lib/
+
+    dnode.c    node processing functions -- e.g., for gnode or vnode
+
+    dnode?.c   additional node processing functions, used when node
+               header files have duplicate and conflicting element
+               names.
+
+    dproc.c    functions to access, read, examine and cache data about
+               dialect-specific process structures -- this file contains
+               the dialect-specific "main" function, gather_proc_info()
+
+    dproto.h   dialect-specific prototype declarations
+
+    dsock.c    dialect-specific socket processing functions
+
+    dstore.c   dialect-specific global storage -- e.g., the nlist()
+               structure
+
+    machine.h  dialect specific definitions of common function options --
+               e.g., a HASINODE definition to activate the readinode()
+               function in lsof4/node.c
+
+               The machine.h header file also selects and customizes
+               the functions of lsof4/lib/.
+
+These are the lib/ files.  Definitions in the dialect machine.h
+header files select and customize the contained functions that are
+to be compiled and archived to liblsof.a.
+
+    Makefile.skel      is a skeleton Makefile, used by Configure
+                       to construct the Makefile for the lsof
+                       library.
+
+    cvfs.c             completevfs() function
+
+                       USE_LIB_COMPLETEVFS selects it.
+
+                       CVFS_DEVSAVE, CVFS_NLKSAVE, CVFS_SZSAVE,
+                       and HASFSINO customize it.
+
+    dvch.c             device cache functions
+
+                       HASDCACHE selects them.
+
+                       DCACHE_CLONE, DCACHE_CLR, DCACHE_PSEUDO,
+                       DVCH_CHOWN, DVCH_DEVPATH, DVCH_EXPDEV,
+                       HASBLKDEV, HASENVDC, HASSYSDC, HASPERSDC,
+                       HASPERSDCPATH, and NOWARNBLKDEV customize
+                       them.
+
+    fino.c             find block and character device inode functions
+
+                       HASBLKDEV and USE_LIB_FIND_CH_INO select them.
+
+    isfn.c             hashSfile() and is_file_named() functions
+
+                       USE_LIB_IS_FILE_NAMED selects it.
+
+    lkud.c             device lookup functions
+
+                       HASBLKDEV and USE_LIB_LKUPDEV select them.
+
+    pdvn.c             print device name functions
+
+                       HASBLKDEV and USE_LIB_PRINTDEVNAME select them.
+
+    prfp.c             process_file() function
+
+                       USE_LIB_PROCESS_FILE selects it.
+
+                       FILEPTR, DTYPE_PIPE, HASPIPEFN, DTYPE_GNODE,
+                       DTYPE_INODE, DTYPE_PORT, DTYPE_VNODE, DTYPE_PTS,
+                       HASF_VNODE, HASKQUEUE, HASPRIVFILETYPE,
+                       HASPSXSHM, HASPSXSEM and HASPTSFN customize it.
+
+    ptti.c             print_tcptpi() function
+
+                       USE_LIB_PRINT_TCPTPI selects it.
+
+                       HASSOOPT, HASSBSTATE, HASSOSTATE, AHSTCPOPT,
+                       HASTCPTPIQ and HASTCPTPIW customize it.
+
+    rdev.c             readdev() function
+
+                       USE_LIB_READDEV selects it.
+
+                       DIRTYPE, HASBLKDEV, HASDCACHE, HASDNAMLEN,
+                       RDEV_EXPDEV, RDEV_STATFN, USE_STAT, and
+                       WARNDEVACCESS customize it.
+
+    rmnt.c             readmnt() function
+
+                       USE_LIB_READMNT selects it.
+
+                       HASFSTYPE, MNTSKIP, RMNT_EXPDEV, RMNT_FSTYPE,
+                       and MOUNTS_FSTYPE customize it.
+
+    rnam.c             BSD format name cache functions
+
+                       HASNCACHE and USE_LIB_RNAM select them.
+
+                       HASFSINO, NCACHE, NCACHE_NC_CAST, NCACHE_NM,
+                       NCACHE_NMLEN, NCACHE_NODEADDR, NCACHE_NODEID,
+                       NCACHE_NO_ROOT, NCACHE_NXT, NCACHE_PARADDR,
+                       NCACHE_PARID, NCACHE_SZ_CAST, NCHNAMLEN,
+                       X_NCACHE, and X_NCSIZE, customize them.
+
+    rnch.c             Sun format name cache functions
+
+                       HASNCACHE and USE_LIB_RNCH select them.
+
+                       ADDR_NCACHE, HASDNLCPTR, HASFSINO, NCACHE_DP,
+                       NCACHE_NAME, NCACHE_NAMLEN, NCACHE_NEGVN,
+                       NCACHE_NODEID, NCACHE_NXT, NCACHE_PARID,
+                       NCACHE_VP, X_NCACHE, and X_NCSIZE, customize
+                       them.
+
+
+The comments and the source code in these library files give more
+information on customization.
+
+
+Coding Philosophies
+-------------------
+
+A few basic philosophies govern the coding of lsof 4 functions:
+
+    *  Use as few #if/#else/#endif constructs as possible, even at
+       the cost of nearly-duplicate code.
+
+       When #if/#else/#endif constructs are necessary:
+
+       o  Use the form
+
+               #if     defined(s<symbol>)
+
+         in preference to
+
+               #ifdef  <symbol>
+
+         to allow easier addition of tests to the #if.
+
+       o  Indent them to signify their level -- e.g.,
+
+               #if     /* level one */
+               # if    /* level two */
+               # endif /* level two */
+               #else   /* level one */
+               #endif  /* level one */
+
+       o  Use ANSI standard comments on #else and #endif statements.
+
+    *  Document copiously.
+
+    *  Aim for ANSI-C compatibility:
+
+       o  Use function prototypes for all functions, hiding them
+         from compilers that cannot handle them with the _PROTOTYPE()
+         macro.
+
+       o  Use the compiler's ANSI conformance checking wherever
+         possible -- e.g., gcc's -ansi option.
+
+
+Data Requirements
+-----------------
+
+Lsof's strategy in obtaining open file information is to access
+the process table via its proc structures, then obtain the associated
+user area and open file structures.  The open file structures then
+lead lsof to file type specific structures -- cdrnodes, fifonodes,
+inodes, gnodes, hsfsnodes, pipenodes, pcnodes, rnodes, snodes,
+sockets, tmpnodes, and vnodes.
+
+The specific node structures must yield data about the open files.  The
+most important items and device number (raw and cooked) and node
+number.  (Lsof uses them to identify files and file systems named as
+arguments.)  Link counts and file sizes are important, too, as are the
+special characteristics of sockets, pipes, FIFOs, etc.
+
+This means that to begin an lsof port to a new Unix dialect you
+must understand how to obtain these structures from the dialect's
+kernel.  Look for kernel access functions -- e.g., the AIX readx()
+function, Sun and Sun-like kvm_*() functions, or SGI's syssgi()
+function.  Look for clues in header files -- e.g. external declarations
+and macros.
+
+If you have access to them, look at sources to programs like ps(1),
+or the freely available monitor and top programs.  They may give
+you important clues on reading proc and user area structures.  An
+appeal to readers of dialect-specific news groups may uncover
+correspondents who can help.
+
+Careful reading of system header files -- e.g., <sys/proc.h> --
+may give hints about how kernel storage is organized.  Look for
+global variables declared under a KERNEL or _KERNEL #if.  Run nm(1)
+across the kernel image (/vmunix, /unix, etc.) and look for references
+to structures of interest.
+
+Even if there are support functions for reading structures, like the
+kvm_*() functions, you must still understand how to read data from
+kernel memory.  Typically this requires an understanding of the
+nlist() function, and how to use /dev/kmem, /dev/mem, and /dev/swap.
+
+Don't overlook the possibility that you may have to use the process
+file system -- e.g., /proc.  I try to avoid using /proc when I can,
+since it usually requires that lsof have setuid(root) permission
+to read the individual /proc "files".
+
+Once you can access kernel structures, you must understand how
+they're connected.  You must answer questions like:
+
+    *  How big are kernel addresses?  How are they type cast?
+
+    *  How are kernel variable names converted to addresses?
+       Nlist()?
+
+    *  How are the proc structures organized?  Is it a static
+       table?  Are the proc structures linked?  Is there a
+       kernel pointer to the first proc structure?  Is there a
+       proc structure count?
+
+    *  How does one obtain copies of the proc structures?  Via
+       /dev/kmem?  Via a vendor API?
+
+    *  If this is a Mach derivative, is it necessary to obtain the
+       task and thread structures?  How?
+
+    *  How does one obtain the user area (or the utask area in Mach
+       systems) that corresponds to a process?
+
+    *  Where are the file structures located for open file
+       descriptors and how are they located?  Are all file
+       structures in the user area?  Is the file structure space
+       extensible?
+
+    *  Where do the private data pointers in file structures lead?
+       To gnodes?  To inodes?  To sockets?  To vnodes?  Hint: look
+       in <sys/file.h> for DTYPE_* instances and further pointers.
+
+    *  How are the nodes organized?  To what other nodes do they
+       lead and how?  Where are the common bits of information in
+       nodes -- device, node number, size -- stored?  Hint: look
+       in the header files for nodes for macros that may be used
+       to obtain the address of one node from another -- e.g., the
+       VTOI() macro that leads from a vnode to an inode.
+
+    *  Are text reference nodes identified and how?  Is it
+       necessary to examine the virtual memory map of a process or
+       a task to locate text references?  Some kernels have text
+       node pointers in the proc structures; some, in the user
+       area; Mach kernels may have text information in the task
+       structure, reached in various ways from the proc, user area,
+       or user task structure.
+
+    *  How is the device table -- e.g., /dev or /devices --
+       organized?  How is it read?  Using direct or dirent structures?
+
+       How are major/minor device numbers represented?  How are
+       device numbers assembled and disassembled?
+
+       Are there clone devices?  How are they identified?
+
+    *  How is mount information obtained?  Getmntinfo()?  Getmntent()?
+       Some special kernel call?
+
+    *  How are sockets identified and organized?  BSD-style?  As
+       streams?  Are there streams?
+
+    *  Are there special nodes -- CD-ROM nodes, FIFO nodes, etc.?
+
+    *  How is the kernel's name cache organized?  Can lsof access
+       it to get partial name components?
+
+
+Dlsof.h and #include's
+----------------------
+
+Once you have identified the kernel's data organization and know
+what structures it provides, you must add #include's to dlsof.h to
+access their definitions.  Sometimes it is difficult to locate the
+header files -- you may need to introduce -I specifications in the
+Makefile via the DINC shell variable in the Configure script.
+
+Sometimes it is necessary to define special symbols -- e.g., KERNEL,
+_KERNEL, _KMEMUSER -- to induce system header files to yield kernel
+structure definitions.  Sometimes making those symbol definitions
+cause other header file and definition conflicts.  There's no good
+general rule on how to proceed when conflicts occur.
+
+Rarely it may be necessary to extract structure definitions from
+system header files and move them to dlsof.h, create special versions
+of system header files, or obtain special copies of system header
+files from "friendly" (e.g., vendor) sources.  The dlsof.h header
+file in lsof4/dialects/sun shows examples of the first case; the
+second, no examples; the third, the irix5hdr subdirectory in
+lsof4/dialects/irix (a mixture of the first and third).
+
+Building up the necessary #includes in dlsof.h is an iterative
+process that requires attention as you build the dialect-specific
+functions that references kernel structures.  Be prepared to revisit
+dlsof.h frequently.
+
+
+Definitions That Affect Compilation
+-----------------------------------
+
+The source files at the top level and in the lib/ subdirectory
+contain optional functions that may be activated with definitions
+in a dialect's machine.h header file.  Some are functions for
+reading node structures that may not apply to all dialects -- e.g.
+CD-ROM nodes (cdrnode), or `G' nodes (gnode) -- and others are
+common functions that may occasionally be replaced by dialect-specific
+ones.  Once you understand your kernel's data organization, you'll
+be able to decide the optional common node functions to activate.
+
+Definitions in machine.h and dlsof.h also enable or disable other
+optional common features.  The following is an attempt to list all
+the definitions that affect lsof code, but CAUTION, it is only
+attempt and may be incomplete.  Always check lsof4 source code in
+lib/ and dialects/, and dialect machine.h header files for other
+possibilities
+
+    AFS_VICE           See 00XCONFIG.
+
+    AIX_KERNBITS       specifies the kernel bit size, 32 or 64, of the Power
+                       architecture AIX 5.x kernel for which lsof was built.
+
+    CAN_USE_CLNT_CREATE        is defined for dialects where the more modern
+                       RPC function clnt_create() can be used in
+                       place of the deprecated clnttcp_create().
+
+    CLONEMAJ            defines the name of the variable that
+                       contains the clone major device number.
+                       (Also see HAS_STD_CLONE and HAVECLONEMAJ.)
+
+    DEVDEV_PATH                defines the path to the directory where device
+                       nodes are stored, usually /dev.  Solaris 10
+                       uses /devices.
+
+    DIALECT_WARNING    may be defined by a dialect to provide a
+                       warning message that will be displayed with
+                       help (-h) and version (-v) output.
+
+    FSV_DEFAULT                defines the default file structure values to
+                       list.  It may be composed of or'd FSV_*
+                       (See common.h) values.  The default is none (0).
+
+    GET_MAJ_DEV         is a macro to get major portion from device
+                       number instead of via the standard major()
+                       macro.
+
+    GET_MIN_DEV                is a macro to get minor portion from device
+                       number instead of via the standard minor()
+                       macro.
+
+    GET_MAX_FD         the name of the function that returns an
+                       int for the maximum open file descriptor
+                       plus one.  If not defined, defaults to
+                       getdtablesize.
+
+    HAS9660FS           enables CD9660 file system support in a
+                       BSD dialect.
+
+    HAS_ADVLOCK_ARGS    is defined for NetBSD and OpenBSD dialects
+                       whose <sys/lockf.h> references vop_advlock_args.
+
+    HAS_AFS            enables AFS support code for the dialect.
+
+    HAS_AIO_REQ_STRUCT is defined for Solaris 10 and above systems that
+                       have the aio_req structure definition.
+
+    HASAOPT            indicates the dialect supports the AFS -A
+                       option when HAS_AFS is also defined.
+
+    HASBLKDEV          indicates the dialect has block device support.
+
+    HASBUFQ_H          indicates the *NSD dialect has the <sys/bufq.h>
+                       header file.
+
+    HASCACHEFS         enables cache file system support for the
+                       dialect.
+
+    HASCDRNODE         enables/disables readcdrnode() in node.c.
+
+    HAS_CLOSEFROM      is defined when the FreeBSD C library contains the
+                       closefrom() function.
+
+    HAS_CONN_NEW        indicates the Solaris version has the new form
+                       of the conn_s structure, introduced in b134 of
+                       Solaris 11.  This will always accompany the
+                       HAS_IPCLASSIFIER_H definition.
+
+    HAS_CONST          indicates that the compiler supports the
+                       const keyword.
+
+    HASCPUMASK_T       indicates the FreeBSD 5.2 or higher dialect
+                       has cpumask_t typedef's.
+
+    HAS_CRED_IMPL_H    indicates the Solaris 10 dialect has the
+                       <sys/cred_impl.h> header file available.
+
+    HASCWDINFO          indicates the cwdinfo structure is defined
+                       in the NetBSD <sys/filedesc.h>.
+
+    HASDCACHE           enables device file cache file support.
+                       The device cache file contains information
+                       about the names, device numbers and inode
+                       numbers of entries in the /dev (or /device)
+                       node subtree that lsof saves from call to
+                       call.  See the 00DCACHE file of the lsof
+                       distribution for more information on this
+                       feature.
+
+    HAS_DINODE_U       indicates the OpenBSD version has a dinode_u
+                       union in its inode structure.
+
+    HASDNLCPTR          is defined when the name cache entry of
+                       <sys/dnlc.h> has a name character pointer
+                       rather than a name character array.
+
+    HAS_DUP2           is defined when the FreeBSD C library contains the
+                       dup2() function.
+
+    HASEFFNLINK                indicates the *BSD system has the i_effnlink
+                       member in the inode structure.
+
+    HASENVDC            enables the use of an environment-defined
+                       device cache file path and defines the name
+                       of the environment variable from which lsof
+                       may take it.  (See the 00DCACHE file of
+                       the lsof distribution for information on
+                       when HASENVDC is used or ignored.)
+
+    HASEOPT            indicates the dialect supports the -e option to
+                       eliminate kernel blocks on a named file system.
+
+    HASEPTOPTS         indicates the dialect supports the +|-E end point
+                       options.
+
+    HASEXT2FS           is defined for BSD dialects for which ext2fs
+                       file system support can be provided.  A value
+                       of 1 indicates that the i_e2din member does not
+                       exist; 2, it exists.
+
+    HASF_VNODE         indicates the dialect's file structure has an
+                       f_vnode member in it.
+
+    HAS_FILEDESCENT    indicates the FreeBSD system has the filedescent
+                       definition in the <sys/filedesc.h> header file.
+
+    HASFDESCFS         enables file descriptor file system support
+                       for the dialect.   A value of 1 indicates
+                       <miscfs/fdesc.h> has a Fctty definition; 2,
+                       it does not.
+
+    HASFDLINK          indicates the file descriptor file system
+                       node has the fd_link member.
+
+    HASFIFONODE                enables/disables readfifonode() in node.c.
+
+    HAS_F_OPEN         indicates the UnixWare 7.x dialect has the
+                       f_open member in its file struct.
+
+    HASFSINO            enables the inclusion of the fs_ino element
+                       in the lfile structure definition in common.h.
+                       This contains the file system's inode number
+                       and may be needed when searching the kernel
+                       name cache.  See dialects/osr/dproc.c for
+                       an example.
+
+    HASFSTRUCT         indicates the dialect has a file structure
+                       the listing of whose element values can be
+                       enabled with +f[cfn].  FSV_DEFAULT defines
+                       the default listing values.
+
+    HASFSTYPE           enables/disables the use of the file system's
+                       stat(2) st_fstype member.
+
+                       If the HASFSTYPE value is 1, st_fstype is
+                       treated as a character array; 2, it is
+                       treated as an integer.
+
+                       See also the RMNT_EXPDEV and RMNT_FSTYPE
+                       documentation in lib/rmnt.c
+
+    HASGETBOOTFILE     indicates the NetBSD or OpenBSD dialect has
+                       a getbootfile() function.
+
+    HASGNODE           enables/disables readgnode() in node.c.
+
+    HASHSNODE          enables/disables readhsnode() in node.c.
+
+    HASI_E2FS_PTR      indicates the BSD dialect has a pointer in
+                       its inode to the EXTFS dinode.
+
+    HASI_FFS            indicates the BSD dialect has i_ffs_size
+                       in <ufs/ufs/inode.h>.
+
+    HASI_FFS1          indicates the BSD dialect supports the fast
+                       UFS1 and UFS2 file systems.
+
+    HAS_INKERNEL        indicates the SCO OSR 6.0.0 or higher, or
+                       UnixWare 7.1.4 or higher system uses the
+                       INKERNEL symbol in <netinet/in_pcb.h> or
+                       <netinet/tcp_var.h>.
+
+    HASINODE           enables/disables readinode() in node.c.
+
+    HASINRIAIPv6       is defined if the dialect has the INRIA IPv6
+                       support.  (HASIPv6 will also be defined.)
+
+    HASINT16TYPE       is defined when the dialect has a typedef
+                       for int16 that may conflict with some other
+                       header file's redefinition (e.g., <afs/std.h>).
+
+    HASINT32TYPE       is defined when the dialect has a typedef
+                       for int32 that may conflict with some other
+                       header file's redefinition (e.g., <afs/std.h>).
+
+    HASINTSIGNAL       is defined when signal() returns an int.
+
+    HAS_IPCLASSIFIER_H is defined for Solaris dialects that have the
+                       <inet/ipclassifier.h> header file.
+
+    HAS_IPC_S_PATCH    is defined when the HP-UX 11 dialect has the
+                       ipc_s patch installed.  It has a value of
+                       1 if the ipc_s structure has an ipc_ipis
+                       member, but the ipis_s structure lacks the
+                       ipis_msgsqueued member; 2, if ipc_s has
+                       ipc_ipis, but ipis_s lacks ipis_msgsqueued.
+
+    HASIPv6             indicates the dialect supports the IPv6
+                       Internet address family.
+
+    HAS_JFS2           The AIX >= 5.0 dialect has jfs2 support.
+
+    HASKERNFS           is defined for BSD dialects for which
+                       /kern file system support can be provided.
+
+    HASKERNFS_KFS_KT   indicates *kfs_kt is in the BSD dialect's
+                       <miscfs/kernfs/kernfs.h>.
+
+    HASKOPT            enables/disables the ability to read the
+                       kernel's name list from a file -- e.g., from
+                       a crash dump file.
+
+    HASKQUEUE           indicates the dialect supports the kqueue
+                       file type.
+
+    HASKVMGETPROC2      The *BSD dialect has the kvm_gettproc2()
+                       function.
+
+    HAS_KVM_VNODE      indicates the FreeBSD 5.3 or higher dialect has
+                       "defined(_KVM_VNODE)" in <sys/vnode.h>.
+
+    HASLFILEADD                defines additional, dialect-specific elements
+
+    SETLFILEADD                in the lfile structure (defined in common.h).
+                       HASLFILEADD is a macro. The accompanying SETFILEADD
+                       macro is used in the alloc_lfile() function of
+                       proc.c to preset the additional elements.
+
+    HAS_LF_LWP          is defined for BSD dialects where the lockf
+                       structure has an lf_lwp member.
+
+    HASLFS             indicates the *BSD dialect has log-structured
+                       file system support.
+
+    HAS_LGRP_ROOT_CONFLICT
+                       indicates the Solaris 9 or Solaris 10 system has
+                       a conflict over the lgrp_root symbol in the
+                       <sys/lgrp.h> and <sys/lgrp_user.h> header files.
+
+    HAS_LIBCTF         indicates the Solaris 10 and above system has
+                       the CTF library.
+
+    HAS_LOCKF_ENTRY    indicates the FreeBSD version has a lockf_entry
+                       structure in its <sys/lockf.h> header file.
+
+    HAS_LWP_H          is defined for BSD dialects that have the
+                       <sys/lwp.h> header file.
+
+    HASMOPT            enables/disables the ability to read kernel
+                       memory from a file -- e.g., from a crash
+                       dump file.
+
+    HASMSDOSFS         enables MS-DOS file system support in a
+                       BSD dialect.
+
+    HASMNTSTAT          indicates the dialect has a stat(2) status
+                       element in its mounts structure.
+
+    HASMNTSUP          indicates the dialect supports the mount supplement
+                       option.
+
+    HASNAMECACHE       indicates the FreeBSD dialect has a namecache
+                       structure definition in <sys/namei.h>.
+
+    HASNCACHE          enables the probing of the kernel's name cache
+                       to obtain path name components.  A value
+                       of 1 directs printname() to prefix the
+                       cache value with the file system directory
+                       name; 2, avoid the prefix.
+
+    HASNCVPID           The *BSD dialect namecache struct has an
+                       nc_vpid member.
+
+    HAS_NFS            enables NFS support for the dialect.
+
+    HASNFSPROTO         indicates the NetBSD or OpenBSD version
+                       has the nfsproto.h header file.
+
+    HASNFSVATTRP       indicates the n_vattr member of the nfsnode of
+                       the *BSD dialect is a pointer.
+
+    HASNLIST           enables/disables nlist() function support.
+                       (See NLIST_TYPE.)
+
+    HASNOFSADDR                is defined if the dialect has no file structure
+                       addresses.  (HASFSTRUCT must be defined.)
+
+    HASNOFSCOUNT       is defined if the dialect has no file structure counts.
+                       (HASFSTRUCT must be defined.)
+
+    HASNOFSFLAGS       is defined if the dialect has no file structure flags.
+                       (HASFSTRUCT must be defined.)
+
+    HASNOFSNADDR       is defined if the dialect has no file structure node
+                       addresses.  (HASFSTRUCT must be defined.)
+
+    HAS_NO_6PORT       is defined if the FreeBSD in_pcb.h has no in6p_.port
+                       definitions.
+
+    HAS_NO_6PPCB       is defined if the FreeBSD in_pcb.h has no in6p_ppcb
+                       definition.
+
+    HAS_NO_LONG_LONG   indicates the dialect has no support for the C
+                       long long type.  This definition is used by
+                       the built-in snprintf() support of lib/snpf.c.
+
+    HASNORPC_H         indicates the dialect has no /usr/include/rpc/rpc.h
+                       header file.
+
+    HASNOSOCKSECURITY   enables the listing of open socket files,
+                       even when HASSECURITY restricts listing of
+                       open files to the UID of the user who is
+                       running lsof, provided socket file listing
+                       is selected with the "-i" option.  This
+                       definition is only effective when HASSECURITY
+                       is also defined.
+
+    HASNULLFS           indicates the dialect (usually *BSD) has a
+                       null file system.
+
+    HASOBJFS            indicates the Pyramid version has OBJFS
+                       support.
+
+    HASONLINEJFS       indicates the HP-UX 11 dialect has the optional
+                       OnlineJFS package installed.
+
+    HAS_PC_DIRENTPERSEC
+                       indicates the Solaris 10 system's <sys/fs/pc_node.h>
+                       header file has the pc_direntpersec() macro.
+
+    HAS_PAD_MUTEX      indicates the Solaris 11 system has the pad_mutex_t
+                       typedef in its <sys/mutex.h> header file.
+
+    HASPERSDC           enables the use of a personal device cache
+                       file path and specifies a format by which
+                       it is constructed.  See the 00DCACHE file
+                       of the lsof distribution for more information
+                       on the format.
+
+    HASPERSDCPATH       enables the use of a modified personal
+                       device cache file path and specifies the
+                       name of the environment variable from which
+                       its component may be taken.  See the 00DCACHE
+                       file of the lsof distribution for more
+                       information on the modified personal device
+                       cache file path.
+
+    HASPINODEN         declares that the inode number of a /proc file
+                       should be stored in its procfsid structure.
+
+    HASPIPEFN           defines the function that processes DTYPE_PIPE
+                       file structures.  It's used in the prfp.c
+                       library source file.  See the FreeBSD
+                       dialect source for an example.
+
+    HASPIPENODE                enables/disables readpipenode() in node.c.
+
+    HASPMAPENABLED      enables the automatic reporting of portmapper
+                       registration information for TCP and UDP
+                       ports that have been registered.
+
+    HASPPID            indicates the dialect has parent PID support.
+
+    HASPR_LDT          indicates the Solaris dialect has a pr_ldt
+                       member in the pronodetype enum.
+
+    HASPR_GWINDOWS     indicates the Solaris dialect has a pr_windows
+                       member in the pronodetype enum.
+
+    HASPRINTDEV         this value defines a private function for
+                       printing the dialect's device number.  Used
+                       by print.c/print_file().  Takes one argument:
+
+                       char *HASPRINTDEV(struct lfile *)
+
+    HASPRINTINO         this value names a private function for
+                       printing the dialect's inode number.  Used
+                       by print.c/print_file(). Takes one argument:
+
+                       char *HASPRINTINO(struct lfile *)
+
+    HASPRINTNM          this value names a private function for
+                       printing the dialect's file name.  Used by
+                       print.c/print_file().  Takes one argument:
+
+                       void HASPRINTNM(struct lfile *)
+
+    HASPRIVFILETYPE     enables processing of the private file
+                       type, whose number (from f_type of the file
+                       struct) is defined by PRIVFILETYPE.
+                       HASPRIVFILETYPE defines the function that
+                       processes the file struct's f_data member.
+                       Processing is initiated from the process_file()
+                       function of the prfp.c library source file
+                       or from the dialect's own process_file()
+                       function.
+
+    HASPRIVNMCACHE      enables printing of a file path from a
+                       private name cache.  HASPRIVNMCACHE defines
+                       the name of the printing function.  The
+                       function takes one argument, a struct lfile
+                       pointer to the file, and returns non-zero
+                       if it prints a cached name to stdout.
+
+    HASPRIVPRIPP        is defined for dialects that have a private
+                       function for printing the IP protocol name.
+                       When this is not defined, the function to
+                       do that defaults to printiproto().
+
+    HASPROCFS          defines the name (if any) of the process file
+                       system -- e.g., /proc.
+
+    HASPROCFS_PFSROOT  indicates PFSroot is in the BSD dialect's
+                       <miscfs/procfs/procfs.h>.
+
+    HASPSEUDOFS         indicates the FreeBSD dialect has pseudofs
+                       file system support.
+
+    HASPSXSEM          indicates the dialect has support for the POSIX
+                       semaphore file type.
+
+    HASPSXSHM          indicates the dialect has support for the POSIX
+                       shared memory file type.
+
+    HASPTSFN           indicates the dialect has a DNODE_PTS file descriptor
+                       type and defines the function that processes it.
+
+    HASPTYEPT          indicates the Linux dialect has support for the
+                       pseudoterminal endpoint option.
+
+    HASPTYFS           indicates the *BSD dialect has a ptyfs file system.
+
+    HASRNODE           enables/disables readrnode() in node.c.
+
+    HASRNODE3          indicates the HPUX 10.20 or lower dialect has NFS3
+                       support with a modified rnode structure.
+
+    HASRPCV2H          The FreeBSD dialect has <nfs/rpcv2.h>.
+
+    HAS_SANFS           indicates the AIX system has SANFS file system
+                       support.
+
+    HAS_SB_CC          indicates the FreeBSD system's sockbuf structure has
+                       the sb_ccc member, rather than the sb_cc member.
+
+    HASSBSTATE          indicates the dialect has socket buffer state
+                       information (e.g., SBS_* symbols) available.
+
+    HASSECURITY         enables/disables restricting open file
+                       information access.  (Also see HASNOSOCKSECURITY.)
+
+    HASSELINUX          indicates the Linux dialect has SELinux security
+                       context support available.
+
+    HASSETLOCALE       is defined if the dialect has <locale.h> and
+                       setlocale().
+
+    HAS_SI_PRIV         indicates the FreeBSD 6.0 and higher cdev
+                       structure has an si_priv member.
+
+    HAS_SOCKET_PROTO_H indicates the Solaris 10 system has the header file
+                       <sys/socket_proto.h>.
+
+    HASSOUXSOUA                indicates that the Solaris <sys/socketvar.h> has
+                       soua_* members in its so_ux_addr structure.
+
+    HASSPECDEVD                indicates the dialect has a special device
+                       directory and defines the name of a function
+                       that processes the results of a successful
+                       stat(2) of a file in that directory.
+
+    HASSNODE           indicates the dialect has snode support.
+
+    HASSOOPT            indicates the dialect has socket option
+                       information (e.g., SO_* symbols) available.
+
+    HASSOSTATE          indicates the dialect has socket state
+                       information (e.g., SS_* symbols) available.
+
+    HASSTATVFS          indicates the NetBSD dialect has a statvfs
+                       struct definition.
+
+    HASSTAT64          indicates the dialect's <sys/stat.h> contains
+                       stat64.
+
+    HAS_STD_CLONE      indicates the dialect uses a standard clone
+                       device structure that can be used in common
+                       library function clone processing.  If the
+                       value is 1, the clone table will be built
+                       by readdev() and cached when HASDCACHE is
+                       defined; if the value is 2, it is assumed
+                       the clone table is built independently.
+                       (Also see CLONEMAJ and HAVECLONEMAJ.)
+
+    HASSTREAMS          enables/disables streams.  CAUTION, requires
+                       specific support code in the dialect sources.
+
+    HAS_STRFTIME       indicates the dialect has the gmtime() and
+                       strftime() C library functions that support
+                       the -r marker format option.  Configure tests
+                       for the functions and defines this symbol.
+
+    HASSYSDC            enables the use of a system-wide device
+                       cache file and defines its path.  See the
+                       00DCACHE file of the lsof distribution for
+                       more information on the system-wide device
+                       cache file path option.
+
+    HAS_SYS_PIPEH      indicates the dialect has a <sys/pipe.h>
+                       header file.
+
+    HAS_SYS_SX_H       indicates the FreeBSD 7.0 and higher system has
+                       a <sys/sx.h> header file.
+
+    HAS_TMPFS          indicates the FreeBSD system has the <fs/tmpfs.h>
+                       header file.
+
+    HASTMPNODE         enables/disables readtnode() in node.c.
+
+    HASTCPOPT           indicates the dialect has TCP option
+                       information (i.e., from TF_* symbols)
+                       available.
+
+    HASTCPTPIQ          is defined when the dialect can duplicate
+                       the receive and send queue sizes reported
+                       by netstat.
+
+    HASTCPTPIW          is defined when the dialect can duplicate
+                       the receive and send window sizes reported
+                       by netstat.
+
+    HASTCPUDPSTATE     is defined when the dialect has support for
+                       TCP and UDP state, including the "-s p:s"
+                       option and associated speed ehancements.
+
+    HASTFS             indicates that the Pyramid dialect has TFS
+                       file system support.
+
+    HAS_UFS1_2         indicates the FreeBSD 6 and higher system has
+                       UFS1 and UFS2 members in its inode structure.
+
+    HAS_UM_UFS         indicates the OpenBSD version has UM_UFS[12]
+                       definitions.
+
+    HASUINT16TYPE      is defined when the dialect has a typedef
+                       for u_int16 that may conflict with some other
+                       header file's redefinition (e.g., <afs/std.h>).
+
+    HASUXSOCKEPT       indicates the Linux version has support for the
+                       UNIX socket endpoint option.
+
+    HASUTMPX           indicates the dialect has a <utmpx.h> header
+                       file.
+
+    HAS_UVM_INCL       indicates the NetBSD or OpenBSD dialect has
+                       a <uvm> include directory.
+
+    HAS_UW_CFS         indicates the UnixWare 7.1.1 or above dialect
+                       has CFS file system support.
+
+    HAS_UW_NSC         indicates the UnixWare 7.1.1 or above dialect
+                       has a NonStop Cluster (NSC) kernel.
+
+    HAS_V_LOCKF                indicates the FreeBSD version has a v_lockf
+                       member in the vode structure, defined in
+                       <sys/vnode.h>.
+
+    HAS_VM_MEMATTR_T   indicates the FreeBSD <sys/conf.h> uses the
+                       vm_memattr_t typedef.
+
+    HASVMLOCKH         indicates the FreeBSD dialect has <vm/lock.h>.
+
+    HASVNODE           enables/disables readvnode() function in node.c.
+
+    HAS_V_PATH          indicates the dialect's vnode structure has a
+                       v_path member.
+
+    HAS_VSOCK          indicates that the Solaris version has a VSOCK
+                       member in the vtype enum
+
+    HASVXFS            enables Veritas VxFS file system support for
+                       the dialect.  CAUTION, the dialect sources
+                       must have the necessary support code.
+
+    HASVXFSDNLC         indicates the VxFS file system has its own
+                       name cache.
+
+    HASVXFS_FS_H       indicates <sys/fs/vx_fs.h> exists.
+
+    HASVXFS_MACHDEP_H  indicates <sys/fs/vx_machdep.h> exists.
+
+    HASVXFS_OFF64_T    indicates <sys/fs/vx_solaris.h> exists and
+                       has an off64_t typedef.
+
+    HASXVFSRNL         indicates the dialect has VxFS Reverse Name
+                       Lookup (RNL) support.
+
+    HASVXFS_SOL_H      indicates <sys/fs/vx_sol.h> exists.
+
+    HASVXFS_SOLARIS_H  indicates <sys/fs/vx_solaris.h> exists.
+
+    HASVXFS_U64_T       if HASVXFS_SOLARIS_H is defined, this
+                       variable indicates that <sys/fs/vx_solaris.h>
+                       has a vx_u64_t typedef.
+
+    HASVXFSUTIL         indicates the Solaris dialect has VxFS 3.4
+                       or higher and has the utility libraries,
+                       libvxfsutil.a (32 bit) and libvxfsutil64.a
+                       (64 bit).
+
+    HASVXFS_VX_INODE    indicates that <sys/fs/vx_inode.h> contains
+                       a vx_inode structure.
+
+    HASWCTYPE_H                indicates the FreeBSD version has wide-character
+                       support and the <wctype.h> header file.  Note:
+                       the HASWIDECHAR #define will also be set.
+
+    HASWIDECHAR         indicates the dialect has the wide-character
+                       support functions iswprint(), mblen() and mbtowc().
+
+    HASXNAMNODE         indicates the OSR dialect has <sys/fs/xnamnode.h>.
+
+    HASXOPT            defines help text for dialect-specific X option
+                       and enables X option processing in usage.c and
+                       main.c.
+
+    HASXOPT_ROOT        when defined, restricts the dialect-specific
+                       X option to processes whose real user ID
+                       is root.
+
+    HASXOPT_VALUE      defines the default binary value for the X option
+                       in store.c.
+
+    HAS_XTCPCB_TMAXSEG indicates that <netinet/tcp_var.h> in this FreeBSD
+                       version exists and its struct xtcpcb has a
+                       t_magseg field.
+
+    HAS_ZFS            indicates the dialect has support for the ZFS file
+                       system.
+
+    HASZONES           the Solaris dialect has zones.
+
+    HAVECLONEMAJ        defines the name of the status variable
+                       that indicates a clone major device number
+                       is available in CLONEMAJ.  (Also see CLONEMAJ
+                       and HAS_STD_CLONE.)
+
+    HPUX_KERNBITS      defines the number of bits in the HP-UX 10.30
+                       and above kernel "basic" word: 32 or 64.
+
+    KA_T               defines the type cast required to assign
+                       space to kernel pointers.  When not defined
+                       by a dialect header file, KA_T defaults to
+                       unsigned long.
+
+    KA_T_FMT_X          defines the printf format for printing a
+                       KA_T -- the default is "%#lx" for the
+                       default unsigned long KA_T cast.
+
+    LSOF_ARCH          See 00XCONFIG.
+
+    LSOF_BLDCMT                See 00XCONFIG.
+
+    LSOF_CC            See 00XCONFIG.
+
+    LSOF_CCV           See 00XCONFIG.
+
+    LSOF_HOST          See 00XCONFIG.
+
+    LSOF_INCLUDE       See 00XCONFIG.
+
+    LSOF_LOGNAME       See 00XCONFIG.
+
+    LSOF_MKC           See the "The Mksrc Shell Script" section of
+                       this file.
+
+    LSOF_SYSINFO       See 00XCONFIG.
+
+    LSOF_USER          See 00XCONFIG.
+
+    LSOF_VERS          See 00XCONFIG.
+
+    LSOF_VSTR          See 00XCONFIG.
+
+    MACH               defines a MACH system.
+
+    N_UNIXV            defines an alternate value for the N_UNIV symbol.
+
+    NCACHELDPFX                defines C code to be executed before calling
+                       ncache_load().
+
+    NCACHELDSFX                defines C code to be executed after calling
+                       ncache_load().
+
+    NEEDS_BOOL_TYPEDEF indicates the FreeBSD 10 system, being built on an
+                       i386 architecture systemn, needs typdef bool.
+
+    NEEDS_BOOLEAN_T    indicates the FreeBSD 9 and above system needs a
+                       boolean_t definition for <sys/conf.h>.
+
+    NEEDS_DEVICE_T     indicates the FreeBSD <sys/eventhandler.h> header file
+                       needs the device_t typedef.
+
+    NEEDS_MACH_PORT_T  is defined for Darwin versions that need the inclusion
+                       of the header file <device/device_types.h>.
+
+    NEEDS_NETINET_TCPH is defined when the Linux version needs to #include
+                       <netinet/tcp.h> in place of <linux/tcp.h> in order to
+                       have access to the TCP_* definitions.
+
+    NEVER_HASDCACHE    keeps the Customize script from offering to
+                       change HASDCACHE by its presence anywhere
+                       in a dialect's machine.h header file --
+                       e.g., in a comment.  See the Customize
+                       script or machine.h in dialects/linux/proc.
+
+    NEVER_WARNDEVACCESS        keeps the Customize script from offering to
+                       change WARNDEVACCESS by its presence anywhere
+                       in a dialect's machine.h header file --
+                       including in a comment.  See the Customize
+                       script or machine.h in dialects/linux/proc.
+
+    NLIST_TYPE         is the type of the nlist table, Nl[], if it is
+                       not nlist.  HASNLIST must be set for this
+                       definition to be effective.
+
+    NOWARNBLKDEV        specifies that no warning is to be issued
+                       when no block devices are found.  This
+                       definiton is used only when HASBLKDEV is
+                       also defined.
+
+    OFFDECDIG           specifies how many decimal digits will be
+                       printed for the file offset in a 0t form
+                       before switching to a 0x form.  The count
+                       includes the "0t".  A count of zero means
+                       the size is unlimited.
+
+    PRIVFILETYPE        is the number of a private file type, found
+                       in the f_type member of the file struct, to
+                       be processed by the HASPRIVFILETYPE function.
+                       See the AIX dialect sources for an example.
+
+    _PSTAT_STREAM_GET_XPORT
+                       indicates the HP-UX PSTAT header files require
+                       this symbol to be defined for proper handling of
+                       stream export data.
+
+    SAVE_MP_IN_SFILE   indicates the dialect needs to have the mounts
+                       structure pointer for a file system search argument
+                       recorded in the dialect's sfile structure.  This
+                       definition is made in the dialect's dlsof.h header
+                       file within the sfile structure.
+
+    TIMEVAL_LSOF        defines the name of the timeval structure.
+                       The default is timeval.  /dev/kmem-based
+                       Linux lsof redefines timeval with this
+                       symbol to avoid conflicts between glibc
+                       and kernel definitions.
+
+    TYPELOGSECSHIFT     defines the type of the cdfs_LogSecShift
+                       member of the cdfs structure for UnixWare
+                       7 and higher.
+
+    UID_ARG_T           defines the cast on a User ID when passed
+                       as a function argument.
+
+    USE_LIB_COMPLETEVFS
+                       selects the use of the completevfs() function
+                       in lsof4/lib/cvfs.c.
+
+    USE_LIB_FIND_CH_INO
+                       selects the use of the find_ch_ino() inode
+                       function in lsof4/lib/fino.c.
+
+                       Note: HASBLKDEV selects the has_bl_ino()
+                       function.
+
+    USE_LIB_IS_FILE_NAMED
+                       selects the use of the is_file_named() function
+                       in lsof4/lib/isfn.c.
+
+    USE_LIB_LKUPDEV    selects the use of the lkupdev() function
+                       in lsof4/lib/lkud.c.
+
+                       Note: HASBLKDEV selects the lkupbdev() function.
+
+    USE_LIB_PRINTDEVNAME
+                       selects the use of the printdevname() function
+                       in lsof4/lib/pdvn.c.
+
+                       Note: HASBLKDEV selects the printbdevname()
+                       function.
+
+    USE_LIB_PRINT_TCPTPI
+                       selects the use of the print_tcptpi() function
+                       in lsof4/lib/ptti.c.
+
+    USE_LIB_PROCESS_FILE
+                       selects the use of the process_file() function
+                       in lsof4/lib/prfp.c.
+
+    USE_LIB_READDEV    selects the use of the readdev() and stkdir()
+                       functions in lsof4/lib/rdev.c.
+
+    USE_LIB_READMNT    selects the use of the readmnt() function
+                       in lsof4/lib/rmnt.c.
+
+    USE_LIB_RNAM       selects the use of the device cache functions
+                       in lsof4/lib/rnam.c.
+
+                       Note: HASNCACHE must also be defined.
+
+    USE_LIB_RNCH       selects the use of the device cache functions
+                       in lsof4/lib/rnch.c.
+
+                       Note: HASNCACHE must also be defined.
+
+    USE_STAT            is defined for those dialects that must
+                       use the stat(2) function instead of lstat(2)
+                       to scan /dev -- i.e., in the readdev()
+                       function.
+
+    VNODE_VFLAG                is an alternate name for the vnode structure's
+                       v_flag member.
+
+    WARNDEVACCESS      enables the issuing of a warning message when
+                       lsof is unable to access /dev (or /device)
+                       or one of its subdirectories, or stat(2)
+                       a file in them. Some dialects (e.g., HP-UX)
+                       have many inaccessible subdirectories and
+                       it is appropriate to inhibit the warning
+                       for them with WARNDEVACCESS.  The -w option
+                       will also inhibit these warnings.
+
+    WARNINGSTATE        when defined, disables the default issuing
+                       of warning messages.  WARNINGSTATE is
+                       undefined by default for all dialects in
+                       the lsof distribution.
+
+    WIDECHARINCL        defines the header file to be included (if any)
+                       when wide-character support is enabled with
+                       HASWIDECHAR.
+
+    zeromem()          defines a macro to zero memory -- e.g., using
+                       bzero() or memset().
+
+Any dialect's machine.h file and Configure stanza can serve as a
+template for building your own.  All machine.h files usually have
+all definitions, disabling some (with comment prefix and suffix)
+and enabling others.
+
+
+Options: Common and Special
+---------------------------
+
+All but one lsof option is common; the specific option is ``-X''.
+If a dialect does not support a common option, the related #define
+in machine.h -- e.g., HASCOPT -- should be deselected.
+
+The specific option, ``-X'', may be used by any dialect for its
+own purpose.  Right now (May 30, 1995) the ``-X'' option is binary
+(i.e., it's not allowed arguments of its own, and its value must
+be 0 or 1) but that could be changed should the need arise.  The
+option is enabled with the HASXOPT definition in machine.h; its
+default value is defined by HASXOPT_VALUE.
+
+The value of HASXOPT should be the text displayed for ``-X'' by
+the usage() function in usage.c.  HASXOPT_VALUE should be the
+default value, 0 or 1.
+
+AIX for the IBM RICS System/6000 defines the ``-X'' option to
+control readx() usage, since there is a bug in AIX kernels that
+readx() can expose for other processes.
+
+
+Defining Dialect-Specific Symbols and Global Storage
+----------------------------------------------------
+
+A dialect's dlsof.h and dstore.c files contain dialect-specific
+symbol and global storage definitions.  There are symbol definitions,
+for example, for function and data casts, and for file paths.
+Dslof.h defines lookup names the nlist() table -- X_* symbols --
+when nlist() is being used.
+
+Global storage definitions include such things as structures for
+local Virtual File System (vfs) information; mount information;
+search file information; and kernel memory file descriptors --
+e.g., Kmem for /dev/kmem, Mem for /dev/mem, Swap for /dev/drum.
+
+
+Coding Dialect-specific Functions
+---------------------------------
+
+Each supported dialect must have some basic functions that the
+common functions of the top level may call.  Some of them may be
+obtained from the library in lsof4/lib, selected and customized by
+#define's in the dialect machine.h header file.  Others may have
+to be coded specifically for the dialect.
+
+Each supported dialect usually has private functions, too.  Those
+are wholly determined by the needs of the dialect's data organization
+and access.
+
+These are some of the basic functions that each dialect must supply
+-- they're all defined in proto.h:
+
+    initialize()               function to initialize the dialect
+
+    is_file_named()            function to check if a file was named
+                               by an optional file name argument
+                               (lsof4/lib/isfn.c)
+
+    gather_proc_info()         function to gather process table
+                               and related information and cache it
+
+    printchdevname()           function to locate and optionally
+                               print the name of a character device
+                               (lsof4/lib/pdvn.c)
+
+    print_tcptpistate()         function to print the TCP or TPI
+                               state for a TCP or UDP socket file,
+                               if the one in lib/ptti.c isn't
+                               suitable (define USE_LIB_PRINT_TCPTPI
+                               to activate lib/ptti.c)
+
+    process_file()             function to process an open file
+                               structure (lsof4/lib/prfp.c)
+
+    process_node()             function to process a primary node
+
+    process_socket()           function to process a socket
+
+    readdev() and stkdir()     functions to read and cache device
+                               information (lsof4/lib/rdev.c)
+
+    readmnt()                  function to read mount table information
+                               (lsof4/lib/rmnt.c)
+
+Other common functions may be needed, and might be obtained from
+lsof4/lib, depending on the needs of the dialect's node and socket
+file processing functions.
+
+Check the functions in lsof4/lib and specific lsof4/dialects/*
+files for examples.
+
+As you build these functions you will probably have to add #include's
+to dlsof.h.
+
+
+Function Prototype Definitions and the _PROTOTYPE Macro
+-------------------------------------------------------
+
+Once you've defined your dialect-specific definitions, you should
+define their prototypes in dproto.h or locally in the file where
+they occur and are used.  Do this even if your compiler is not ANSI
+compliant -- the _PROTOTYPE macro knows how to cope with that and
+will avoid creating prototypes that will confuse your compiler.
+
+
+The Makefile
+------------
+
+Here are some general rules for constructing the dialect Makefile.
+
+    *  Use an existing dialect's Makefile as a template.
+
+    *  Make sure the echo actions of the install rule are appropriate.
+
+    *  Use the DEBUG string to set debugging options, like ``-g''.
+       You may also need to use the -O option when forking and
+       SIGCHLD signals defeat your debugger.
+
+    *  Don't put ``\"'' in a compiler flags -D<symbol>=<string>
+       clause in your Makefile.  Leave off the ``\"'' even though
+       you want <string> to be a string literal and instead adapt
+       the N_UNIX* macros you'll find in Makefiles for FreeBSD
+       and Linux.  That will allow the Makefile's version.h rule
+       to put CFLAGS into version.h without having to worry about
+       the ``\"'' sequences.
+
+    *  Finally, remember that strings can be passed from the top
+       level's Configure shell script.  That's an appropriate way
+       to handle options, especially if there are multiple versions
+       of the Unix dialect to which you are porting lsof 4.
+
+
+The Mksrc Shell Script
+----------------------
+
+Pattern your Mksrc shell script after an existing one from another
+dialect.  Change the D shell variable to the name of your dialect's
+subdirectory in lsof4/dialects.  Adjust any other shell variable
+to your local conditions.  (Probably that won't be necessary.)
+
+Note that, if using symbolic links from the top level to your
+dialect subdirectory is impossible or impractical, you can set the
+LSOF_MKC shell variable in Configure to something other than
+"ln -s" -- e.g., "cp," and Configure will pass it to the Mksrc
+shell script in the M environment variable.
+
+
+The MkKernOpts Shell Script
+---------------------------
+
+The MkKernOptrs shell script is used by some dialects -- e.g.,
+Pyramid DC/OSx and Reliant UNIX -- to determine the compile-time
+options used to build the current kernel that affect kernel structure
+definitions, so those same options can be used to build lsof.
+Configure calls MkKernOpts for the selected dialects.
+
+If your kernel is built with options that affect structure definitions.
+-- most commonly affected are the proc structure from <sys/proc.h>
+and the user structure from <sys/user.h> -- check the MkKernOpts
+in lsof4/dialects/irix for a comprehensive example.
+
+
+Testing and the Lsof Test Suite
+-------------------------------
+
+Once you have managed to create a port, here are some tips for
+testing it.
+
+*  First look at the test suite in the tests/ sub-directory of the
+   lsof distribution.  While it will need to be customized to be
+   usable with a new port, it should provide ideas on things to
+   test.  Look for more information about the test suite in the
+   00TEST file.
+
+*  Pick a simple process whose open files you are likely to
+   know and see if the lsof output agrees with what you know.
+   (Hint: select the process with `lsof -p <process_PID>`.)
+
+   Are the device numbers and device names correct?
+
+   Are the file system names and mount points correct?
+
+   Are inode numbers and sizes correct?
+
+   Are command names, file descriptor numbers, UIDs, PIDs, PGIDs,
+   and PPIDs correct?
+
+   A simple tool that does a stat(2) of the files being examined
+   and reports the stat struct contents can provide a reference for
+   some values; so can `ls -l /dev/<device>`.
+
+*  Let lsof list information about all open files and ask the
+   same questions.  Look also for error messages about not being
+   able to read a node or structure.
+
+*  Pick a file that you know is open -- open it and hold it
+   that way with a C program (not vi), if you must.  Ask lsof to
+   find the file's open instance by specifying its path to lsof.
+
+*  Create a C program that opens a large number of files and holds
+   them open.  Background the test process and ask lsof to list
+   its files.
+
+*  Generate some locks -- you may need to write a C program to
+   do this, hold the locked file open, and see if lsof can identify
+   the lock properly.  You may need to write several C programs
+   if your dialect supports different lock functions -- fnctl(),
+   flock(), lockf(), locking().
+
+*  Identify a process with known Internet file usage -- inetd
+   is a good one -- and ask lsof to list its open files.  See if
+   protocols and service names are listed properly.
+
+   See if your lsof identifies Internet socket files properly for
+   rlogind or telnetd processes.
+
+*  Create a UNIX domain socket file, if your dialect allows it,
+   hold it open by backgrounding the process, and see if lsof can
+   identify the open UNIX domain socket file properly.
+
+*  Create a FIFO file and see what lsof says about it.
+
+*  Watch an open pipe -- `lsof -u <your_login>  | less` is a
+   good way to do this.
+
+*  See if lsof can identify NFS files and their devices properly.
+   Open and hold open an NFS file and see if lsof can find the open
+   instance by path.
+
+*  If your test system has CD-ROM and floppy disk devices, open
+   files on them and see if lsof reports their information correctly.
+   Such devices often have special kernel structures associated
+   with them and need special attention from lsof for their
+   identification.  Pay particular attention to the inode numbers
+   lsof reports for CD-ROM and floppy disk files -- often they are
+   calculated dynamically, rather than stored in a kernel node
+   structure.
+
+*  If your implementation can probe the kernel name cache, look
+   at some processes with open files whose paths you know to see
+   if lsof identifies any name components.  If it doesn't, make
+   sure the name components are in the name cache by accessing
+   the files yourself with ls or a similar tool.
+
+*  If your dialect supports the /proc file system, use a C program
+   to open files there, background a test process, and ask lsof to
+   report its open files.
+
+*  If your dialect supports fattach(), create a small test program
+   to use it, background a test process, and ask lsof to report
+   its open files.
+
+I can supply some quick-and-dirty tools for reporting stat buffer
+contents, holding files open, creating UNIX domain files, creating
+FIFOs, etc., if you need them.
+
+
+Where Next?
+-----------
+
+Is this document complete?  Certainly not!  One might wish that it
+were accompanied by man pages for all lsof functions, by free beer
+or chocolates, by ...  (You get the idea.)
+
+But those things are not likely to happen as long as lsof is a
+privately supported, one man operation.
+
+So, if you need more information on how lsof is constructed or
+works in order to do a port of your own, you'll have to read the
+lsof source code.  You can also ask me questions via email, but
+keep in mind the private, one-man nature of current lsof support.
+
+
+Vic Abell <abe@purdue.edu>
+July 14, 2018
diff --git a/00QUICKSTART b/00QUICKSTART
new file mode 100644 (file)
index 0000000..0df967c
--- /dev/null
@@ -0,0 +1 @@
+This documentation has been replaced by docs/tutorial.md, docs/faq.md and docs/options.md. Please refer to the new files or read them online.
\ No newline at end of file
diff --git a/00README b/00README
new file mode 100644 (file)
index 0000000..6a21eae
--- /dev/null
+++ b/00README
@@ -0,0 +1,1470 @@
+
+                       Making and Installing lsof 4
+
+********************************************************************
+| The latest release of lsof is always available via anonymous ftp |
+| from lsof.itap.purdue.edu.  Look in pub/tools/unix/lsof.         |
+********************************************************************
+
+                               Contents
+
+       Pre-built Lsof Binaries
+       Making Lsof
+           Other Configure Script Options
+           Environment Variables
+           Security
+           Run-time Warnings
+           Device Access Warnings
+           NFS Blocks
+           Caches -- Name and Device
+           Raw Sockets
+           Other Compile-time Definitions
+           The AFSConfig Script
+           The Inventory Script
+           The Customize Script
+           Cautions
+           Warranty
+           License
+           Bug Reports
+           The 00FAQ File
+           The lsof-l Mailing List
+           Field Output Example Scripts
+           Field Output C Library
+       Testing Lsof
+       Dialect Notes
+           AFS
+           AIX
+           Apple Darwin
+           Auspex LFS (no longer maintained)
+           BSDI BSD/OS
+           FreeBSD
+           HP-UX
+           IPv6
+           Linux
+           NetBSD
+           OpenBSD
+           Pyramid DC/OSx and Reliant UNIX (no longer available)
+           Caldera OpenUNIX
+           SCO OpenServer
+           SCO|Caldera UnixWare
+           Solaris 2.x, 7, 8, 9 and 10
+           Ultrix (no longer available)
+           Veritas VxFS and VxVM
+       User-contributed Dialect Support
+       Dialects No Longer Supported
+       Installing Lsof
+           Setuid-root Lsof Dialects
+           Setgid Lsof Dialects
+       Porting lsof 4 to a New UNIX Dialect
+       Quick Start to Using lsof
+       Cross-configuring Lsof
+       Environment Variables Affecting the Configure Script
+
+
+=======================
+Pre-built Lsof Binaries
+=======================
+
+Avoid using pre-built lsof binaries if you can; build your own
+instead.
+
+I do not support lsof binaries built and packaged by third parties nor
+lsof binaries built from anything but the latest lsof revision.  (See
+the Bug Reports section for more information on the details of lsof
+support.)
+
+One important reasone for those support restrictions is that when lsof
+is built its Configure script tunes lsof to the features available on
+the building system, often embodied in supporting header files and
+libraries.  If the building system doesn't have support for a
+particular feature, lsof won't be built to support the feature on any
+system.
+
+The Veritas VxFS file system is a good example of a feature that
+requires build-time support.
+
+UNIX dialect version differences --  Solaris 8 versus 9, AIX 4.3.3
+vesus 5.2, etc. -- can also render a pre-built lsof binary useless
+on a different version.  So can kernel bit size.
+
+There are so many potential pitfalls to using an lsof binary
+improperly that I strongly recommend lsof be used only where it is
+built.
+
+
+===========
+Making Lsof
+===========
+
+       $ cd <lsof source directory>
+       $ ./Configure <your dialect's abbreviation>
+       $ make
+
+(Consult the 00FAQ and 00XCONFIG files of the lsof distribution
+for information about using make command invocations and environment
+variables to override lsof default Makefile strings.)
+
+This lsof distribution can be used with many UNIX dialects.  However,
+it must be configured specifically for each dialect.  Configuration
+is done in three ways: 1) by changing definitions in the machine.h
+header file of the UNIX dialect of interest; 2) by defining
+environment variable values prior to calling Configure (see the
+00XCONFIG file, the Environment Variabls and Environment Variables
+Affecting the Configure Script sections of this file); and 3) by
+running the Configure shell script found in the top level of the
+distribution directory.
+
+You may not need to change any machine.h definitions, but you might
+want to look at them anyway.  Pay particular attention to the
+definitions that are discussed in the Security section of this
+file.  Please read that section.
+
+The Configure script calls three other scripts in the lsof
+distribution: AFSConfig; Inventory; and Customize.  The AFSConfig
+script is called for selected dialects (AIX, HP-UX, NEXTSTEP, and
+Solaris) to locate AFS header files and determine the AFS version.
+See The AFSConfig Script section of this file for more information.
+
+The Inventory script checks the completeness of the lsof distribution.
+Configure calls Inventory after it has accepted the dialect
+abbreviation, but before it configures the top-level directory for
+the dialect.  See The Inventory Script section of this file for
+more information.
+
+Configure calls the Customize script after it has configured the
+top-level lsof directory for the declared dialect.  Customize helps
+you modify some of the important compile-time definitions of
+machine.h.  See the The Customize Script section.
+
+You should also think about where you will install lsof and its
+man page, and whom you will let execute lsof.  Please read the
+Installing Lsof section of this file for information on installation
+considerations.
+
+Once you have inspected the machine.h file for the dialect for
+which you want to build lsof, and made any changes you need, run
+the Configure script, supplying it with the abbreviation for the
+dialect.  (See the following table.)  Configure selects the
+appropriate options for the dialect and runs the Mksrc shell script
+in the dialect sub-directory to construct the appropriate source
+files in the top-level distribution directory.
+
+Configure may also run the MkKernOpts script in the dialect
+sub-directory to propagate kernel build options to the dialect
+Makefile.  This is done for only a few dialects -- e.g., DC/OSx,
+and Reliant UNIX.
+
+Configure creates a dialect-specific Makefile.  You may want to
+inspect or edit this Makefile to make it conform to local conventions.
+If you want the Makefile to install lsof and its man page, you will
+have to create an appropriate install rule.
+
+Lsof may be configured using UNIX dialect abbreviations from the
+following table.  Alternative abbreviations are indicated by a
+separating `|'.   For example, for SCO OpenServer you can use either
+the ``osr'' or the ``sco'' abbreviation:
+
+       $ Configure osr
+    or
+       $ Configure sco
+
+ Abbreviations         UNIX Dialect
+ -------------         ------------
+
+    aix                        IBM AIX 5.[23] and 5.3-ML1 using IBM's C Compiler
+    aixgcc             IBM AIX 5.[12] and 5.3-ML1 using gcc
+    darwin             Apple Darwin 7.x and 8.x for Power Macintosh systems
+    freebsd            FreeBSD 4.x, 4.1x, 5.x and [67].x
+    hpux               HP-UX 11.00, 11.11 and 11.23, using HP's C
+                       Compiler, both /dev/kmem-based and PSTAT-based
+    hpuxgcc            HP-UX 11.00, 11.11 and 11.23, using gcc, both
+                       /dev/kmem-based and PSTAT-based
+    linux              Linux 2.1.72 and above for x86-based systems
+    netbsd             NetBSD 1.[456], 2.x and 3.x
+    openbsd            OpenBSD 2.[89] and 3.[0-9]
+    osr                        SCO OpenServer Release 5.0.6, using the C compiler
+                       from the SCO developer's kit
+    osrgcc             SCO OpenServer Release 5.0.6, using gcc
+    osr6               SCO Openserver 6.0.0, using the SCO C compiler
+    sco                        SCO OpenServer Release 5.0.6, using the C compiler
+                       from the SCO developer's kit
+    scogcc             SCO OpenServer Release 5.0.6, using gcc
+    solaris            Solaris 2.x, 7, 8, 9 and 10 using gcc
+    solariscc          Solaris 2.x, 7, 8, 9 and 10 using Sun's cc
+    unixware           SCO|Caldera UnixWare 7.1.4
+    uw                 SCO|Caldera UnixWare 7.1.4
+
+If you have an earlier version of a dialect not named in the above
+list, lsof may still work on your system.  I have no way of testing
+that myself.  Try configuring for the named dialect -- e.g., if
+you're using Solaris 2.1, try configuring for Solaris 2.5.1.
+
+After you have configured lsof for your UNIX dialect and have
+selected options via the Customize script (See the The Customize
+Script section.) , use the make command to build lsof -- e.g.,
+
+       $ make
+
+
+Other Configure Script Options
+==============================
+
+There are three other useful options to the Configure script besides
+the dialect abbreviation:
+
+       -clean          may be specified to remove all traces of
+                       a dialect configuration, including the
+                       Makefile, symbolic links, and library files.
+
+       -h              may be specified to obtain a list of
+       -help           Configure options, including dialect
+                       abbreviations.
+
+       -n              may be specified to stop the Configure
+                       script from calling the Customize and
+                       Inventory scripts.
+
+                       Caution: -n also suppresses the AFSConfig
+                       step.
+
+
+
+Environment Variables
+=====================
+
+Lsof configuration, building, and execution may be affected by
+environment variable settings.  See the Definitions That Affect
+Compilation section in the 00PORTING file, the General Environment
+Variables section in the 00XCONFIG file, the Dialect-Specific
+Environment Variables section in the 00XCONFIG file, and the
+Environment Variables Affecting the Configure Script section of
+this file for more information.
+
+Note in the General Environment Variables section of the 00XCONFIG
+file that there are five environment variables that can be used to
+pre-define values in lsof's -v output: LSOF_BLDCMT, LSOF_HOST,
+LSOF_LOGNAME, LSOF_SYSINFO, and LSOF_USER.
+
+
+Security
+========
+
+If the symbol HASSECURITY is defined, a security mode is enabled,
+and lsof will allow only the root user to list all open files.
+Non-root users may list only open files whose processes have the
+same user ID as the real user ID of the lsof process (the one that
+its user logged on with).
+
+However, if HASNOSOCKSECURITY is also defined, anyone may list
+anyone else's open socket files, provided their listing is enabled
+with the "-i" option.
+
+Lsof is distributed with the security mode disabled -- HASSECURITY
+is not defined.  (When HASSECURITY is not defined, the definition
+of HASNOSOCKSECURITY has no meaning.)  You can enable the security
+mode by defining HASSECURITY in the Makefile or in the machine.h
+header file for the specific dialect you're using -- e.g.
+dialects/aix/machine.h.
+
+The Customize script, run by Configure when it has finished its
+work, gives you the opportunity to define HASSECURITY and
+HASNOSOCKSECURITY.  (See the The Customize Script section.)
+
+The lsof -h output indicates the state HASSECURITY and HASNOSOCKSECURITY
+had when lsof was built, reporting:
+
+    "Only root can list all files;"
+       if HASSECURITY was defined and HASNOSOCKSECURITY wasn't
+       defined;
+
+    "Only root can list all files, but anyone can list socket files."
+       if HASSECURITY and HASNOSOCKSECURITY were both defined;
+
+    "Anyone can list all files;"
+       if HASSECURITY wasn't defined.  (The definition of
+       HASNOSOCKSECURITY doesn't matter when HASSECURITY isn't
+       defined.)
+
+You should carefully consider the implications of using the default
+security mode.  When lsof is compiled in the absence of the
+HASSECURITY definition, anyone who can execute lsof may be able to
+see the presence of all open files.  This may allow the lsof user
+to observe open files -- e.g., log files used to track intrusions
+-- whose presence you would rather not disclose.
+
+As distributed, lsof writes a user-readable and user-writable device
+cache file in the home directory of the real user ID executing
+lsof.  There are other options for constructing the device cache file
+path, and they each have security implications.
+
+The 00DCACHE file in the lsof distribution discusses device cache
+file path construction in great detail.   It tells how to disable
+the various device cache file path options, or how to disable the
+entire device cache file feature by removing the HASDCACHE definition
+from the dialect's machine.h file.  There is also information on
+the device cache file feature in the 00FAQ file.  (The 00DCACHE
+and 00FAQ files are part of the lsof distribution package.)
+
+The Customize script, run by Configure after it has finished its
+work, gives you the opportunity to change the compile-time options
+related to the device cache file.  (See The Customize Script
+section.)
+
+Since lsof may need setgid or setuid-root permission (See the Setgid
+Lsof Dialects and Setuid-root Lsof Dialects sections.), its security
+should always be viewed with skepticism.  Lest the setgid and
+setuid-root permissions allow lsof to read kernel name list or
+memory files, declared with the -k and -m options, that the lsof
+user can't normally access, lsof uses access(2) to establish its
+real user's authority to read such files when it can't surrender
+its power before opening them.  This change was added at the
+suggestion of Tim Ramsey.
+
+Lsof surrenders setgid permission on most dialects when it has
+gained access to the kernel's memory devices.  There are exceptions
+to this rule, and some lsof implementations need to run setuid-root.
+(The Setgid Lsof Dialects and Setuid-root Lsof Dialects sections
+contains a list of lsof implementations and the permissions
+recommended in the distribution's Makefiles.)
+
+The surrendering of setgid permission is controlled by the WILLDROPGID
+definition in the dialect machine.h header files.
+
+In the end you must judge for yourself and your installation the
+risks that lsof presents and restrict access to it according to
+your circumstances and judgement.
+
+
+Run-time Warnings
+=================
+
+Lsof can issue warning messages when it runs -- e.g., about the
+state of the device cache file, about an inability to access an
+NFS file system, etc.  Issuance of warnings are enabled by default
+in the lsof distribution.
+
+Issuance or warnings may be disabled by default by defining
+WARNINGSTATE in the dialect's machine.h.  The Customize script may
+also be used to change the default warning message issuance state.
+(See The Customize Script section.)
+
+The ``-w'' option description of the ``-h'' option (help) output
+will indicate the default warning issuance state.  Whatever the
+state may be, it can be reversed with ``-w''.
+
+
+Device Access Warnings
+======================
+
+When lsof encounters a /dev (or /devices) directory, one of its
+sub-directories, or one of their files that it cannot access with
+opendir(3) or stat(2), it issues a warning message and continues.
+Lsof will be more likely to issue such a warning when it has been
+installed with setgid(<some group name>) permission; it won't have
+trouble if it has been installed with setuid(root) permission or
+is being run under the root login.
+
+The lsof caller can inhibit or enable the warning with the -w
+option, depending on the issuance state of run-time warnings.  (See
+the Run-time Warnings section.)
+
+The warning messages do not appear when lsof obtains device
+information from a device cache file that it has built and believes
+to be current or when warning message issuance is disabled by
+default.  (See the "Caches -- Name and Device" section for more
+information on the device cache file.)
+
+The lsof builder can inhibit the warning by disabling the definition
+of WARNDEVACCESS in the dialect's machine.h or disable all warnings
+by defining WARNINGSTATE.  WARNDEVACCESS is defined by default for
+most dialects.  However, some dialects have some device directory
+elements that are private -- e.g., HP-UX -- and it is more convenient
+for the lsof user if warning messages about them are inhibited.
+
+Output from lsof's -h option indicates the status of WARNDEVACCESS.
+If it was defined when lsof was compiled, this message will appear:
+
+    /dev warnings = enabled
+
+If WARNDEVACCESS was not defined when lsof was compiled, this
+message will appear instead:
+
+    /dev warnings = disabled
+
+The Customize script, run by Configure after it has finished its
+work, gives you the opportunity to change the WARNDEVACCESS
+definition.  (See The Customize Script section.)
+
+
+NFS Blocks
+==========
+
+Lsof is susceptible to NFS blocks when it tries to lstat() mounted
+file systems and when it does further processing -- lstat() and
+readlink() -- on its optional file and file system arguments.
+
+Lsof tries to avoid being stopped completely by NFS blocks by doing
+the lstat() and readlink() functions in a child process, which
+returns the function response via a pipe.  The lsof parent limits
+the wait for data to arrive in the pipe with a SIGALRM, and, if
+the alarm trips, terminates the child process with a SIGINT and a
+SIGKILL.
+
+This is as reliable and portable a method for breaking NFS deadlocks
+as I have found, although it still fails under some combinations
+of NFS version, UNIX dialect, and NFS file system mount options.
+It generally succeeds when the "intr" or "soft" mount options are
+used; it generally fails when the "hard" mount option is used.
+
+When lsof cannot kill the child process, a second timeout causes
+it to stop waiting for the killed child to complete.  While the
+second timeout allows lsof to complete, it may leave behind a hung
+child process.  Unless warnings are inhibited by default or with
+the -w option, lsof reports the possible hung child.
+
+NFS block handling was updated with suggestions made by Andreas
+Stolcke.  Andreas suggested using the alternate device numbers that
+appear in the mount tables of some dialects when it is not possible
+to stat(2) the mount points.
+
+The -b option was added to direct lsof to avoid the stat(2) and
+readlink(2) calls that might block on NFS mount points and always
+use the alternate device numbers.  If warning message issuance is
+enabled and you don't want warning messages about what lsof is
+doing, use the -w option, too.
+
+The -O option directs lsof to avoid doing the potentially blocking
+operations in child processes.  Instead, when -O is specified, lsof
+does them directly.  While this consumes far less system overhead,
+it can cause lsof to hang, so I advise you to use -O sparingly.
+
+
+Caches -- Name and Device
+==========================
+
+Robert Ehrlich suggested that lsof obtain path name components for
+open files from the kernel's name cache.  Where possible, lsof
+dialect implementations do that.  The -C option inhibits kernel
+name cache examination.
+
+Since AFS apparently does not use the kernel's name cache, where
+lsof supports AFS it is unable to identify AFS files with path name
+components.
+
+Robert also suggested that lsof cache the information it obtains
+via stat(2) for nodes in /dev (or /devices) to reduce subsequent
+running time.  Lsof does that, too.
+
+In the default distribution the device cache file is stored in
+.lsof_hostname, mode 0600, in the home directory of the login of
+the user ID that executes lsof.  The suffix, hostname, is the first
+component of the host's name returned by gethostname(2).  If lsof
+is executed by a user ID whose home directory is NFS-mounted from
+several hosts, the user ID's home directory may collect several
+device cache files, one for each host from which it was executed.
+
+Lsof senses accidental or malicious damage to the device cache file
+with extensive integrity checks, including the use of a 16 bit CRC.
+It also tries to sense changes in /dev (or /devices) that indicate
+the device cache file is out of date.
+
+There are other options for forming the device cache file path.
+Methods the lsof builder can use to control and employ them are
+documented in the separate 00DCACHE file of the lsof distribution.
+
+
+Raw Sockets
+===========
+
+On many UNIX systems raw sockets use a separate network control
+block structure.  Display of files for applications using raw
+sockets -- ping, using ICMP, for example -- need special support
+for displaying their information.  This support is so dialect-specific
+and information to provide it so difficult to find that not all
+dialect revisions of lsof handle raw sockets completely.
+
+
+Other Compile-time Definitions
+==============================
+
+The machine.h and dlsof.h header files for each dialect contains
+definitions that affect the compilation of lsof.  Check the
+Definitions That Affect Compilation section of the 00PORTING file
+of the lsof distribution for their descriptions.  (Also see The
+Customize Script section.)
+
+
+The AFSConfig Script
+====================
+
+Lsof supports AFS on some combinations of UNIX dialect and AFS
+version.  See the AFS section of this document for a list of
+supported combinations.
+
+When configuring for dialects where AFS is supported, the Configure
+script calls the AFSConfig script to determine the location of AFS
+header files and the AFS version.  Configure will not call AFSConfig,
+even for the selected dialects, unless the file /usr/vice/etc/ThisCell
+exists.
+
+The AFS header file location is recorded in the AFSHeaders file;
+version, AFSVersion.  Once these values have been recorded, Configure
+can be told to skip the calling of AFSConfig by specifying its
+(Configure's) -n option.
+
+
+The Inventory Script
+====================
+
+The lsof distribution contains a script, called Inventory, that
+checks the distribution for completeness.  It uses the file 00MANIFEST
+in the distribution as a reference point.
+
+After the Configure script has accepted the dialect abbreviation,
+it normally calls the Inventory script to make sure the distribution
+is complete.
+
+After Inventory has run, it creates the file ".ck00MAN" in the
+top-level directory to record for itself the fact that the inventory
+has been check.  Should Inventory be called again, it senses this
+file and asks the caller if another check is in order, or if the
+check should be skipped.
+
+The -n option may be supplied to Configure to make it bypass the
+calling of the Inventory script.  (The option also causes Configure
+to avoid calling the Customize script.)
+
+The lsof power user may want to define (touch) the file ".neverInv".
+Configure avoids calling the Inventory script when ".neverInv"
+exists.
+
+
+The Customize Script
+====================
+
+Normally when the Configure script has finished its work, it calls
+another shell script in the lsof distribution called Customize.
+(You can tell Configure to bypass Customize with its -n option.)
+
+Customize leads you through the specification of these important
+compile-time definitions for the dialect's machine.h header file:
+
+       HASDCACHE               device cache file control
+           HASENVDC            device cache file environment
+                               variable name
+           HASPERSDC           personal device cache file path
+                               format
+           HASPERSDCPATH       name of environment variable that
+                               provides an additional component
+                               of the personal device cache file
+                               path
+           HASSYSDC            system-wide device cache file path
+       HASKERNIDCK             the build-time to run-time kernel
+                               identity check
+       HASSECURITY             the security option
+       HASNOSOCKSECURITY       the open socket listing option whe
+                               HASSECURITY is defined
+       WARNDEVACCESS           /dev (or /devices) warning message
+                               control
+       WARNINGSTATE            warning message issuance state
+
+The Customize script accompanies its prompting for entry of new
+values for these definitions with brief descriptions of each of
+them.  More information on these definitions may be found in this
+file or in the 00DCACHE and 00FAQ files of the lsof distribution.
+
+You don't need to run Customize after Configure.  You can run it
+later or you can edit machine.h directly.
+
+The -n option may be supplied to Configure to make it bypass the
+calling of the Customize script.  (The option also causes Configure
+to avoid calling the Inventory script.)
+
+The lsof power user may want to define (touch) the file ".neverCust".
+Configure avoids calling the Customize script when ".neverCust"
+exists.
+
+Customize CAUTION: the Customize script works best when it is
+applied to a newly configured lsof source base -- i.e., the machine.h
+header file has not been previously modified by the Customize
+script.  If you have previously configured lsof, and want to rerun
+the Customize script, I recommend you clean out the previous
+configuration and create a new one:
+
+       $ Configure -clean
+       $ Configure <dialect_abbreviation>
+       ...
+       Customize in response to the Customize script prompts.
+
+
+Cautions
+========
+
+Lsof is a tool that is closely tied to the UNIX operating system
+version.  It uses header files that describe kernel structures and
+reads kernel structures that typically change from OS version to
+OS version, and even within a version as vendor patches are applied.
+
+DON'T TRY TO USE AN LSOF BINARY, COMPILED FOR ONE UNIX OS VERSION,
+ON ANOTHER.  VENDOR PATCHES INFLUENCE THE VERSION IDENTITY.
+
+On some UNIX dialects lsof versions may be even more restricted by
+architecture type.
+
+The bottom line is use lsof where you built it.  If you intend to
+use a common lsof binary on multiple systems, make sure all systems
+run exactly the same OS version and have exactly the same patches.
+
+
+Warranty
+========
+
+Lsof is provided as-is without any warranty of any kind, either
+expressed or implied, including, but not limited to, the implied
+warranties of merchantability and fitness for a particular purpose.
+The entire risk as to the quality and performance of lsof is with
+you.  Should lsof prove defective, you assume the cost of all
+necessary servicing, repair, or correction.
+
+
+License
+=======
+
+Lsof has no license.  Its use and distribution are subject to these
+terms and conditions, found in each lsof source file.  (The copyright
+year in or format of the notice may vary slightly.)
+
+    /*
+     * Copyright 2002 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.
+     */
+
+
+Bug Reports
+===========
+
+Now that the obligatory disclaimer is out of the way, let me hasten to
+add that I accept lsof bug reports and try hard to respond to them.  I
+will also consider and discuss requests for new features, ports to new
+dialects, or ports to new OS versions.
+
+PLEASE DON'T SEND BUG REPORTS ABOUT LSOF TO THE UNIX DIALECT OR DIALECT
+OPTION VENDOR.
+
+At worst such bug reports will confuse the vendor; at best, the vendor
+will forward the bug report to me.
+
+PLEASE DON'T SEND BUG REPORTS ABOUT LSOF BINARIES BUILT OR DISTRIBUTED
+BY SOMEONE ELSE, BECAUSE I CAN'T SUPPORT THEM.
+
+Before you send me a bug report, please do these things:
+
+    *  Make sure you try the latest lsof revision.
+
+       +  Download the latest revision from:
+
+           ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof
+
+       +  Verify the signatures of what you have downloaded;
+
+       +  While connected to lsof.itap.purdue.edu, check for patches:
+
+           ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/patches
+
+       +  If patches exist, install them in the latest revision
+         you just downloaded.  Then build the latest revision and
+         see if it fixes your bug.
+
+    *  If you're having trouble compiling lsof with gcc, try the
+       UNIX dialect vendor's compiler.  I don't have access to gcc on
+       all test systems, so my support for it is hit-and-miss, and so
+       is my ability to respond to gcc compilation problem reports.
+
+    *  Check the lsof frequently asked questions file, 00FAQ,
+       to see if there's a question and answer relevant to your
+       problem.
+
+    *  Make sure you're running the lsof you think you are by
+       checking the path to it with which(1).  When in doubt, use an
+       absolute path to lsof.  Make sure that lsof binary has
+       sufficient permissions to do what you ask, including internal
+       permissions given it (e.g., restrictions on what files lsof may
+       report for whom) during its build.
+
+When you send a bug report, make sure you include output from your
+running of lsof's Configure script.  If you were able to compile a
+running lsof, please also include:
+
+    *  Output from which(1) that shows the absolute path to the
+       lsof binary in question;
+
+    *  Output from running lsof with its -h and -v options at
+       lsof's absolute path;
+
+    *  Output from "ls -l" directed to lsof's absolute path.
+
+If you weren't able to compile a running lsof, please send me: the
+compiler error output; identification of the lsof revision you're using
+(contents of the lsof version.c file); identification of your system
+(full uname output or output from whatever other tool identifies the
+system); and compiler identification (e.g., gcc -v output).
+
+Either set of output will help me understand how lsof was configured
+and what UNIX dialect and lsof revision is involved.
+
+Please send all bug reports, requests, etc. to me via e-mail at
+<abe@purdue.edu>.  Make sure "lsof" appears in the "Subject:" line so
+my e-mail filter won't classify your letter as Spam.
+
+
+The 00FAQ File
+==============
+
+The lsof distribution contains an extensive frequently asked
+questions file on lsof features and problems.  I recommend you
+consult it before sending me e-mail.  Use your favorite editor or
+pager to search 00FAQ -- e.g., supplying as a search argument some
+fixed text from an lsof error message.
+
+
+The lsof-l Mailing List
+=======================
+
+Information about lsof, including notices about the availability
+of new revisions, may be found in mailings of the lsof-l listserv.
+For more information about it, including instructions on how to
+subscribe, read the 00LSOF-L file of the lsof distribution.
+
+
+Field Output Example Scripts
+============================
+
+Example AWK and Perl 4 or 5 scripts for post-processing lsof field
+output are locate in the scripts sub-directory of the lsof distribution.
+The scripts sub-directory contains a 00README file with information
+about the scripts.
+
+
+Field Output C Library
+======================
+
+The lsof test suite (See "Testing Lsof."), checks basic lsof
+operations using field output.  The test suite has its own library
+of C functions for common test program operations, including
+processing of field output.  The library or selections of its
+functions could be adapted for use by C programs that want to
+process lsof field output.  See the library in the file LTlib.c
+in the tests/ sub-directory
+
+
+Testing Lsof
+============
+
+Lsof has an automated test suite in the tests/ sub-directory that
+can be used to test some basic lsof features -- once lsof has been
+configured and made.  Tests are arranged in three groups: basic
+tests that should run on all dialects; standard tests that should
+run on all dialects; and optional tests that may not run on all
+dialects or may need special resources to run.  See 00TEST for more
+information.)
+
+CAUTION!!!  Before you attempt to use the test suite make sure that
+the lsof you want to test can access the necessary kernel resources
+-- e.g., /dev/mem, /dev/kmem, /proc, etc.  Usually you want to test
+the lsof you just built, so this is an important check.  (See
+00TEST.)
+
+To run the basic and standard tests, using the lsof in the parent
+directory of tests/, do this:
+
+       $ cd tests
+       $ make test
+    or $ make std
+    or $ make standard
+
+The basic and standard tests may be run as silently as possible,
+using the lsof in the parent directory of tests/, with:
+
+       $ cd tests
+       $ make auto
+
+This is the "automatic" test mode, designed for use by scripts that
+build lsof.  The caller is expected to test the make exit code to
+determine if the tests succeeded.  The caller should divert standard
+output and standard error to /dev/null to suppress make's error
+exit message.
+
+The optional tests may be run, using the lsof in the parent directory
+of tests/, with:
+
+       $ cd tests
+       $ make opt
+    or $ make optional
+
+It's possible to excute individual tests, too.  See the 00TEST file
+of this distribution for more informaiton on the tests, what they
+do, and how to run and possibly customize each test.
+
+It's possible to run the tests, using an lsof other than the one
+in the parent directory of /tests, too.  See 00TEST for information
+about using the LT_LSOF_PATH environment variable to do that.
+
+
+=============
+Dialect Notes
+=============
+
+
+AFS
+===
+
+Lsof recognizes AFS files on the following combinations of UNIX
+dialect and AFS versions:
+
+       AIX 4.1.4 (AFS 3.4a)
+       Linux 1.2.13 (AFS 3.3)
+       Solaris 2.6 (AFS 3.4a)
+       Ultrix 4.2 RISC (AFS 3.2b) (no longer available)
+
+Lsof has not been tested under other combinations -- e.g. HP-UX
+10.10 and AFS 3.4a -- and probably won't even compile there.  Often
+when a UNIX dialect version or AFS version changes, the new header
+files come into conflict, causing compiler objections.
+
+
+AIX
+===
+
+Specify the aix Configure abbreviation for AIX 4.1.[45], 4.2[.1],
+4.3[.123], 5L, and 5.[123].
+
+Specify aixgcc on AIX above 4.1 to use the gcc compiler.  (Gcc can't be
+used to compile lsof on AIX 4.1 and below because of kernel structure
+alignment differences between it and xlc.)  Gcc results sometimes
+depend on the version of the gcc compiler that is used.
+
+Compilation of lsof with gcc on AIX 4.3[.123], 5L, and 5.[123] has been
+sparsely tested with varying degrees of success: it has been reported
+to succeed on AIX 4.3.3 and 32 bit Power AIX 5.1; to fail on ia64 AIX
+5.1 and 64 bit Power AIX 5.1; and to succeed on 32 and 64 bit Power AIX
+5.2.  Lsof compilation with gcc hasn't been tested on AIX 5.3.
+
+At revision 4.61 and above lsof is configured and built to match the
+bit size of the kernel of Power architecture AIX 5.1 systems.  Lsof
+binaries built for 32 and 64 bit kernels are not interchangeable.  See
+00FAQ for more information.
+
+The Configure script uses /usr/bin/oslevel to determine the AIX version
+for AIX less than 5 and ``uname -rv'' for AIX 5 and higher.  If
+/usr/bin/oslevel isn't executable on AIX less than 5, the Configure
+script issues a warning message and uses ``uname -rv'' to determine the
+AIX version.
+
+When Configure must use ``uname -rv'' on AIX less than 5 to determine
+the AIX version, the result will lack a correct third component --
+e.g., the `4' of ``4.1.4''.  If your AIX less than 5 system lacks lacks
+an executable oslevel, I suggest you edit the Configure-produced
+Makefile and complete the _AIXV definition in the CFGF string.
+
+By default lsof avoids using the kernel's readx() function, causing
+it to be unable to report information on some text and library file
+references.  The ``-X'' option allows the lsof user to ask for the
+information readx() supplies.
+
+Lsof avoids readx() to avoid the possibility of triggering a kernel
+problem, known as the Stale Segment ID kernel bug.  Kevin Ruderman
+reported this bug to me.  The bug shows up when the kernel's
+dir_search() function hangs, hanging the application process that
+called it so completely that the application process can neither
+be killed nor stopped.  The hang is the consequence of another
+process (perhaps lsof) making legitimate use of the kernel's readx()
+function to access the kernel memory that dir_search() is examining.
+IBM has indicated they have no plans to fix the bug.
+
+A fuller discussion of this bug may be found in the 00FAQ file of
+the lsof distribution.  There you will find a description of the
+Stale Segment ID bug, the APAR on it, and a discussion of the
+sequence of events that exposes it.
+
+I added the ``-X'' function so you can tell lsof to use readx(),
+but if you use ``-X'', you should be alert to its possibly serious
+side effects.  Although readx() is normally disabled, its state is
+controlled with the HASXOPT, HASXOPT_ROOT, and HASXOPT_VALUE
+definitions in dialects/aix/machine.h, and you can change its
+default state by changing those definitions.  You can also change
+HASXOPT_ROOT via the Customize script.
+
+You can also compile lsof with readx() use permanently enabled or
+disabled -- see the comments about the definitions in the
+dialects/aix/machine.h header file.  You may want to permanently
+disable lsof's use of readx() if you plan to make lsof publicly
+executable.  You can also restrict -X to processes whose real UID
+is root by defining HASXOPT_ROOT.
+
+I have never seen lsof cause the Stale Segment ID bug to occur and
+haven't had a report that it has, but I believe there is a possibility
+it could.
+
+AFS support for AIX was added with help help from Bob Cook and Jan
+Tax who provided test systems.
+
+Henry Grebler and David J. Wilson helped with lsof for AIX 4.2.
+
+Bill Pemberton provided an AIX 4.3 test system.  Andrew Kephart
+and Tom Weaver provided AIX 4.3 technical assistance.   Niklas
+Edmundsson did 4.3.1 testing.  Doug Crabill provided an AIX 4.3.2
+test system.  Jeff W. Stewart provided an AIX 4.3.3 test system.
+
+The SMT file type for AIX 4.1.[45], 4.2[.1], and 4.3[.12] is my
+fabrication.  See the 00FAQ file more information on it.
+
+Loc Le and Nasser Momtaheni of IBM provided test systems for AIX 5L and
+5.1.  Lsof for AIX 5L and 5.1 needs setuid-root permission to process
+the -X option on systems whose architecture type is ia64.
+
+Dale Talcott of Purdue provided AIX 5.1 and 5.2 test systems.  Dale and
+John Jackson of Purdue provided an AIX 5.3 test system.
+
+
+Apple Darwin
+============
+
+The Apple Darwin port was provided by Allan Nathanson for version
+1.2.  Allan also arranged for access to a test system for maintenance
+and regression testing.  Dale Talcott provided a test system, too.
+
+Allan supplied patches for updates to 1.4, 5.x, 6.x, 7.x and 8.x.
+
+
+BSDI BSD/OS
+===========
+
+As of lsof revision 4.77 support for BSDI BSD/OS has been
+discontinued.  Lsof revision 4.76 with BSDI BSD/OS support may be found
+on lsof.itap.purdue.edu in pub/tools/unix/lsof/src.
+
+
+FreeBSD
+=======
+
+Bill Bormann of Purdue University provided access to several FreeBSD
+test systems.  Ade Barkah, John Clear, Ralph Forsythe, Michael
+Haro, Kurt Jaeger, and William McVey have also provided FreeBSD
+test systems.
+
+The FreeBSD distribution header files are augmented by header files
+in the dialects/freebsd/include directory.
+
+Larry Rosenman maintains the lsof FreeBSD port package.
+
+
+HP-UX
+=====
+
+Lsof has two HP-UX bases: /dev/kmem for HP-UX 11.0 and earlier;
+and PSTAT for HP-UX 11.11 and later.  The lsof Configure script
+will pick the appropriate base.
+
+To use the CCITT x.25 socket support for HP-UX, you must have the
+x.25 header files in /etc/conf/x25
+
+Pasi Kaara helped with the HP-UX port, especially with its CCITT
+x.25 socket support.
+
+Richard Allen provided HP-UX 10.x and 11.x test systems, as did
+Mark Bixby, and Elias Halldor Agustsson.   Marc Winkler helped test
+the 10.20 port.  Richard J. Rauenzahn provided a 64 bit HP-UX 11
+test system and an HP-UX 11.11 development system.
+
+AFS support for HP-UX was added thanks to help from Chaskiel Moses
+Grundman, who provided a test system.
+
+The /dev/kmem-based HP-UX 11.00 support is extremely fragile.  It
+depends on privately developed kernel structure definitions.  (See
+.../dialects/hpux/hpux11 for the header files making the definitions.)
+Those header files and their definitions will not be updated by
+HP-UX 11.00 patches, making it likely that any patch changing a
+kernel structure critical to lsof will break lsof in some way.
+
+It's possible to build a 64 bit lsof for 64 bit HP-UX 11.00 with
+gcc, but you must have a gcc compiler capable of producing 64 bit
+executables.  See the 00FAQ file for more information.
+
+The PSTAT-based lsof for HP-UX 11.11 and later is much more solid.
+I am indebted to the vision of HP for providing an lsof kernel API
+through the PSTAT implementation.  Specifically I appreciate the
+help of HP staff members Carl Davidson, Louis Huemiller, Rich
+Rauenzahn, and Sailu Yallapragada that made PSTAT-based HP-UX lsof
+possible.
+
+
+IPv6
+====
+
+Lsof has IPv6 support that has been tested for these UNIX dialects:
+AIX 4.3.x; Apple Darwin 5.[12] and 6.0; the INRIA and KAME FreeBSD IPv6
+implementations; PSTAT-based HP-UX; /proc-based Linux; the INRIA and
+KAME NetBSD implementations; and Solaris 8 and 9.  Lsof has IPv6
+support that hasn't been tested for: OpenBSD (KAME); OpenUNIX 8; Tru64
+Unix 5.[01]; and UnixWare 7.1.[34].
+
+Please let me know if your UNIX dialect has IPv6 support and I'll
+see if it can be supported by lsof.
+
+
+Linux
+=====
+
+Tim Korb, Steve Logue, Joseph J. Nuspl Jr., and Jonathan Sergent
+have provided Linux test systems.
+
+Michael Shields helped add and test automatic handling of ELF/COFF
+form names in /System.map, Marty Leisner and Keith Parks have helped
+test many lsof revisions.  Marty has provided valuable suggestions,
+Linux hints, and code, too.
+
+The 00FAQ file gives some Linux tips, including information on
+coping with system map file problems.
+
+To determine the state of the Linux 2.1.x C library lseek() function,
+the lsof Configure script runs a test program that must have
+permission to read /dev/kmem.  The test determines if the lseek()
+function properly handles kernel offsets, which appear to be negative
+because their high order bit is set.  If the lseek() test reveals
+a faulty lseek(), Configure activates the use of a private lseek()
+function for kernel offset positioning.  See the Linux problems
+section of the 00FAQ file of the lsof distribution for more
+information.
+
+
+NetBSD
+======
+
+Greg Earle  and Paul Kranenburg have assisted with the NetBSD ports.
+Paul has provided test systems.  Ray Phillips provided a NetBSA
+Alpha test system.  Andrew Brown also provided a test system.
+
+The NetBSD dialect version of lsof is compiled using the dialect
+sources in the netbsd dialect sub-directory.
+
+
+OpenBSD
+=======
+
+David Mazieres has provided OpenBSD test systems.  The OpenBSD
+dialect version of lsof is compiled using the dialect sources it
+shares with NetBSD in the openbsd dialect sub-directory.
+
+Kenneth Stailey has provided OpenBSD testing and advice.
+
+John Dzubera (Zube) reports, "lsof 4.33 compiles and runs on OpenBSD
+2.3 for the pmax architecture (decstation 3100)."
+
+I have not tested lsof on OpenBSD 3.8, but David Mazieres reports
+revision 4.76 worked on OpenBSD 3.8.
+
+
+Pyramid DC/OSx and Reliant UNIX
+===============================
+
+As of lsof revision 4.52 support for all Pyramid dialects has been
+discontinued.  Lsof revision 4.51 with Pyramid support may be
+obtained upon request.  Send the request to abe@purdue.edu.
+
+These two UNIX dialects are very similar and share dialect-specific
+source files from the pyramid sub-directory.
+
+The Reliant Unix Pyramid C compiler issues warning messages that
+I haven't found a convenient way to suppress.  You can ignore
+warning messages about casts and conversions that lose bits.  The
+message "warning: undefining __STDC__" is intentionally caused by
+the lsof MkKernOpts configuration script to suppress warning messages
+about cast and conversion problems in standard system header files,
+such as <stdio.h> and <string.h>.
+
+Bruce Beare and Kevin Smith provided test systems.
+
+
+Caldera OpenUNIX
+================
+
+Larry Rosenman provided an OpenUNIX 8 test system.  Matthew Thurmaier
+provided technical assistance, along with these people from Caldera:
+Jack Craig, Robert Lipe, and Bela Lubkin.
+
+Robert Lipe supplied changes to lsof for OpenUNIX 8.0.1.  Those
+changes were also incorporated in UnixWare 7.1.3 when it became
+the release name for OpenUNIX 8.0.1.
+
+Support for lsof on OpenUNIX ended at lsof revision 4.74.  The last
+lsof revision, 4.74, tested on OpenUNIX, may be found at the lsof
+"home" ftp site, lsof.itap.purdue.edu, in pub/tools/unix/lsof/OLD/src.
+
+
+SCO OpenServer
+==============
+
+Dion Johnson, Bela Lubkin, and Nathan Peterson of SCO gave me copies
+of SCO OpenServer and the SCO OpenServer Development System 3.0
+and provided technical advice for the lsof port.
+
+Hugh Dickins, Bela Lubkin, Craig B. Olofson, and Nathan Peterson
+provided version 5.0 and gave technical advice for porting lsof to
+it.  Bela provided the 5.0.4 changes.  D. Chris Daniels provided
+a 5.0.4 test system, Lee Penn provided one for 5.0.5, and John
+Dubois for 5.0.6.
+
+The <netdb.h> header file was accidentally omitted from some SCO
+OpenServer Development System releases.  The Configure script will
+sense its absence and substitute an equivalent from the BSD
+distribution.  The BSD <netdb.h> and the <sys/cdefs.h> header file
+it includes are located in the dialects/os/include sub-directory
+tree.
+
+To compile lsof from its distribution sources you must have the
+TCP/IP and NSF headers in /usr/include.  While those are optional
+OpenServer packages, I have access to no system that doesn't have
+them, so I'm unable to build lsof for such a configuration.  However,
+it should be possible to modify the lsof Configure script and
+sources so lsof would compile and work without those optional
+packages.
+
+If you have an OpenServer system configured without the TCP/IP and
+NFS packages, and want to tackle the job of building lsof for it,
+contact me via e-mail at <abe@purdue.edu>.  I'll identify the
+Configure script, header file, and source file changes you will
+need to make.  (Caution: this is not a simple task, or I would have
+already done it.)
+
+The optional osrgcc and scogcc Configure abbreviations construct
+Makefiles for compiling lsof with gcc.
+
+The UnixWare 7.1.4 sources are used for OpenServer Release 6.0.0.
+Hence there is a separate Configure abbreviation for it, "osr6".
+Richard of SCO provided a test system and technical assistance.
+
+
+SCO|Caldera UnixWare
+============
+
+D. Chris Daniels, John Hughes, Ken Laing, Andrew Merril, Lee Penn, and
+Matthew Thurmaier provided test systems.  Bela Lubkin provided
+technical assistance.  Larry Rosenman provided 7.1.[34] test systems.
+
+
+Solaris 2.x, 7, 8, 9 and 10
+===========================
+
+SEE THE CAUTIONS SECTION OF THIS DOCUMENT.
+
+The latest Solaris revision of lsof 4 might work under Solaris
+2.[1-4] and 2.5[.1] and 7 but hasn't been tested there.  I have no
+test systems for those Solaris versions.
+
+Lsof will compile with gcc and the Sun C compiler under Solaris.
+If you want to use the Sun compiler, use the solariscc Configure
+abbreviation.  If you use a gcc version less than 2.8 on Solaris,
+make sure the gcc-specific includes have been updated for your
+version of Solaris -- i.e., run the gcc fixincludes script.
+
+Solaris 7, 8, 9 and 10 support for 64 bit kernels depends on a Sun
+WorkShop or Forte C compiler version that supports the "-xarch=v9"
+flag -- usually 5.0 or greater.  Gcc versions 2.95 and above *may*
+be configured and built for 64 bit support, but it takes some extra
+work, the resulting compiler may be fragile, and the gcc developers
+discourage it.  I've built 64 bit capable gcc compilers for Solaris
+7, 8 and 9 from gcc versions 2.95 through 3.0.1 and produced working
+lsof executables with them.  More information on 64 bit gcc for
+Solaris may be found in the 00FAQ file.
+
+Solaris 10 ZFS support is questionable, because Sun does not distribute
+the ZFS kernel structure definition header files.  The lsof Configure
+script and source code use some risky work-arounds.  ZFS file system
+support was made possible with help from Horst Scheuermann.
+
+Dave Curry and Steve Kirsch provided resources for Solaris 2.x
+ports.  Casper Dik and Gerry Singleton consulted and provided
+valuable assistance.
+
+Henry Katz, Joseph Kowalski, Charles Stephens, Mike Sullivan, and
+Mike Tracy provided technical assistance.
+
+AFS support was added to Solaris lsof with help from Curt Freeland,
+Heidi Hornstein, Michael L. Lewis, Terry McCoy, Phillip Moore, and
+Sushila R. Subramanian.
+
+Casper Dik provided valuable assistance for the Solaris 8 support.
+
+Sun has graciously provided me access to BETA versions of Solaris
+2.5, 2.6, 7, 8, and 9.
+
+John Dzubera provided Solaris 7 and 8 test systems.
+
+Mike Miscevic provided  Solaris 10 test systems.
+
+
+Ultrix
+======
+
+As of lsof revision 4.52 support for Ultrix is no longer available,
+because I no longer have an Ultrix test system.
+
+Terry Friedrichsen, Dwight McKay, and Jeffrey Mogul helped me with
+this port.
+
+DECnet support was added to Ultrix lsof with the help of John
+Beacom, who kindly provided a test system.  The Configure script
+decides that DECnet support is available if /usr/lib/libdnet.a and
+/usr/include/netdnet/dn.h exist and are readable.
+
+
+Veritas VxFS and VxVM
+=====================
+
+Lsof supports some versions of Veritas VxFS and VxVM on some UNIX
+dialects.  Consult the lsof Configure script for the specific
+dialect, and consult the lsof dialect-specific source files for
+the UNIX dialect of interest.  Veritas support will usually be
+found in a source file named dnode[1-9].c.
+
+Since Veritas rarely has a version number that can be extracted
+with shell commands, lsof doesn't use it.  Instead, when lsof
+supports Veritas, the Configure script will form compile-time
+definitions starting with HASVXFS.   Check the lsof 00PORTING
+documentation file for more information.
+
+Lsof Veritas support requires that the supporting Veritas header
+files be installed -- e.g., in /usr/include/sys/fs.  (The location
+will depend in the dialect's header file conventions.)
+
+Some information on lsof support for Veritas extensions may be
+found in the lsof 00DIST file.  (The ChangeLog file points to
+00DIST.)
+
+Chris Kordish and Andy Thomas have provided Solaris VxFS test
+systems.
+
+
+================================
+User-contributed Dialect Support
+================================
+
+There are some user-contributed dialect versions of lsof; more
+information on them can be found at:
+
+       ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/contrib
+
+Check the 00INDEX file there for details.
+
+
+============================
+Dialects No Longer Supported
+============================
+
+Because I don't have access to test systems, these UNIX dialects
+are no longer supported by lsof:
+
+       CDC EP/IX
+       /dev/kmem-based Linux
+       MIPS RISC/os
+       Motorola V/88
+       Pyramid DC/OSx
+       Pyramid Reliant UNIX
+       Sequent DYNIX
+       SGI IRIX
+       SunOS 4.x
+       Ultrix
+       UnixWare below 7.0
+
+Remnants of the support lsof once provided for these dialects may
+be found in:
+
+       ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/OLD/dialects
+
+
+===============
+Installing Lsof
+===============
+
+The distributed Makefiles do not have actions that will install
+lsof.  I've come to the conclusion there is no standard for installing
+lsof or its man page, so I no longer distribute make rules for
+installing them.  You should adjust the Makefile for your local
+preferences.
+
+The Makefile does have an install rule that will cause lsof to
+compile by virtue of its dependency clause.  Some Makefiles also
+have a dependency that causes the production of a man page that is
+ready to install.  However, the actions of the install rule will
+not cause the lsof executable or its man page to be installed in
+any UNIX system-wide directory.
+
+Instead, after the compilation and optional man page production
+are completed, the install rule will produce a brief description
+of what actions you might add to the install rule.  The description
+will suggest the possible modes, ownerships, permissions, and
+destinations your install rule might employ to install the lsof
+executable and man page.
+
+As you form your install rule, keep in mind that lsof usually needs
+some type of special permission to do its job.  That may be permission
+to read memory devices such as /dev/kmem, /dev/mem, or /dev/swap,
+or it may be authorization to read entries in the /proc file system.
+
+Memory device access can usually be provided by setting the modes
+of the lsof executable so that it's effective group identifier when
+it runs is the same as the group that has permission to read the
+memory devices -- i.e., it is setgid-group.  The privileged group
+is usually kmem, sys, or system.
+
+Don't overlook using ACLs -- e.g., on AIX or Solaris 8 -- to give
+lsof permission to access memory devices.  ACLs, coupled to a
+separate group like kmem, can be safer than giving lsof setgid
+authorization to a commonly used system group.
+
+When lsof needs to read /proc file system entries, it must be
+installed with modes that make its effective user identifier root
+when it runs -- i.e., it must be setuid-root.  If lsof must be
+installed setuid-root (only the AIX 5L, PSTAT-based HPUX, and
+/proc-based Linux, ports need such power.), then access to memory
+devices is automatic (or not needed in the case of /proc-based
+Linux).
+
+Your choice of permissions for lsof may also be affected by your
+desire to allow anyone to use it or your need to restrict its usage
+to specific individuals.  You will have to be guided by local policy
+and convention in this case.
+
+The next two sections, Setgid Lsof Dialect Versions and Setuid-root
+Lsof Dialect Versions, list recommended install permissions.
+
+The system directory where you install the lsof executable is also
+open to choice.  A traditional place for a tool like lsof is
+/usr/local/etc, but recent changes in directory structure organization
+suggest that somewhere in /opt may be more suitable.
+
+Bear one other factor in mind when choosing a location for the lsof
+executable -- it usually is a shared executable, requiring access
+to shared libraries.  Thus, locations like /sbin or /usr/sbin are
+probably unsuitable.
+
+Once you've chosen a location for the executable you may find that
+the location for the man page follows -- e.g., if the executable
+goes in /usr/local/etc, then the man page goes in /usr/local/man.
+If the executable location doesn't imply a location for the man
+page, you'll have to let local custom guide you.
+
+
+Setuid-root Lsof Dialect Versions
+=================================
+
+These dialect versions should be installed with setuid-root
+permission -- i.e., the lsof binary should be owned by root and
+its setuid execution bit (04000) should be set.
+
+       AIX 5L and above for full use of the -X option
+       Apple Darwin 8.x for Power Macintosh systems
+       PSTAT-based HP-UX 11.11 and 11.23
+       /proc-based Linux (generally 2.1.72 and above)
+
+
+Setgid Lsof Dialect Versions
+============================
+
+These dialect versions should be installed with setgid permission,
+owned by the group that can read kernel memory devices such as
+/dev/drum, /dev/kmem, /dev/ksyms, /dev/mem, /dev/swap.  ACLs may
+be another mechanism (e.g., under AIX or Solaris 8) you can use to
+grant read permission to the kernel memory devices.
+
+       AIX 4.1.[45], 4.2[.1], and 4.3[.123]
+       Apple Darwin 7.x for Power Macintosh systems
+       FreeBSD 2.1.6, 2.2[.x], 3.x, 4.x, 5.x, [6789].x and 1[012].x
+       NetBSD 1.[456], 2.x and 3.x
+       OpenBSD 2.[89] and 3.[0-9]
+       Caldera OpenUNIX 8
+       SCO OpenServer 5.0.[46]
+       SCO UnixWare 7.0 and 7.1.[0134]
+       Solaris 2.6, 8, 9 and 10
+       Ultrix 4.2 (no longer available)
+
+====================================
+Porting lsof 4 to a New UNIX Dialect
+====================================
+
+If you're brave enough to consider this, look at the 00PORTING
+file.  Please contact me before you start.  I might be able to help
+you or even do the port myself.
+
+Don't overlook the contrib/ directory in pub/tools/unix/lsof on my
+ftp server, lsof.itap.purdue.edu.  It contains user-contributed ports
+of lsof to dialects I don't distribute, because I can't test new
+revisions of lsof on them.
+
+
+=========================
+Quick Start to Using lsof
+=========================
+
+For information on how to get started quickly using lsof, consult
+the 00QUICKSTART file of the lsof distribution.  It cuts past the
+formal density of the lsof man page to provide quick examples of
+using lsof to solve common open file display problems.
+
+
+======================
+Cross-configuring Lsof
+======================
+
+Using environment variables it is possible to Configure (and possibly
+build) lsof for one UNIX dialect on a different one -- e.g., you
+are running Configure on a Linux 2.3 system and you want to Configure
+and build lsof for Linux 2.4.
+
+See the 00XCONFIG file of the lsof distribution for a discussion
+of how to do this.
+
+
+====================================================
+Environment Variables Affecting the Configure Script
+====================================================
+
+Configure script actions can be modified by introducing values to
+the script via environment variables.  In many cases the environment
+variable values take the place of test operations the Configure
+script makes.
+
+For more information on environment variables that can affect
+Configure, consult the 00XCONFIG file of the lsof distribution.
+See the General Environment Variables sections for descriptions of
+ones that affect all dialects.  Consult the Dialect-Specific
+Environment Variables section for ones that might affect the dialect
+you are trying to configure.
+
+
+Vic Abell <abe@purdue.edu>
+February 14, 2018
diff --git a/00TEST b/00TEST
new file mode 100644 (file)
index 0000000..fb22927
--- /dev/null
+++ b/00TEST
@@ -0,0 +1,1032 @@
+
+                       The Lsof Test Suite
+
+                           Contents
+
+               A.  Introduction
+                   1.  Test Suite Goals
+                   2.  Not a FAQ
+                   3.  Where have the tests been tested?
+               B.  Test Methodology
+                   1.  Test Limitations
+                   2.  Test Data Base and Scripts
+                   3.  The Makefile
+                       3.1 The CkTestDB Script
+                   4.  The Lsof Executable and LT_LSOF_PATH
+                   5.  Automated Testing
+               C.  Configure Script Participation
+                   1.  config.cc
+                   2.  config.cflags
+                       2.1  config.cflags Contents
+                   3.  config.ldflags
+                   4.  config.xobj
+               D.  Cleaning -- Quick or Spotless
+               E.  Test Libraries
+                   1.  LTlib.c
+               F.  The Individual Tests
+                   1.  LTbasic, a Basic Lsof Test
+                   2.  LTbigf, Test Sizes and Offsets for Large
+                       (> 32 bit) Files
+                   3.  LTdnlc, Test the Kernel's Dynamic Name Lookup
+                       Cache
+                   4.  LTlock, Lock Tests
+                   5.  LTnfs, NFS Test
+                   6.  LTnlink, Link Count Test
+                   7.  LTsock, Test IPv4 Sockets
+                   8.  LTszoff, Test Sizes and Offsets for Small
+                       (< 32 bit) Files
+                   9.  LTunix, Test UNIX Domain Sockets
+               Appendix A, Test Files
+               Appendix B, Test Validations
+               Appendix C, Test Failures
+
+
+A. Introduction
+===============
+
+Lsof has an automated test suite whose components are located in
+the tests/ sub-directory of the lsof top-level directory.  Configuring,
+building and testing lsof can be done with these shell commands:
+
+    $ Configure -n <dialect-abbreviation>
+    $ make
+    $ cd tests
+    $ make
+
+That's all there is to it!
+
+But read on for more dirty details.
+
+A.1. Test Suite Goals
+=====================
+
+The lsof test suite attempts to test basic lsof features.  It does
+not promise to test every lsof feature for every supported dialect.
+(That's a nearly impossible goal.)
+
+As a result, the test suite cannot promise that every lsof feature
+works as documented.  At best the test suite gives some assurance
+that basic, standard and some optional lsof features work.
+
+A.2. Not a FAQ
+==============
+
+One caution: this is not a frequently asked questions (FAQ) file
+for the lsof test suite.  FAQs on the lsof test suite will be found
+in the one and only lsof FAQ in file 00FAQ of the lsof distribution,
+or on-line at:
+
+    ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/FAQ
+
+A.3. Where have the tests been tested?
+======================================
+
+OK, I just said this isn't an FAQ and here comes a question and
+answer that looks like an FAQ.  Consider it a very frequently asked
+question and indulge me -- let me answer it here.
+
+The lsof test suite hasn't been tested everywhere it might be
+possible to build lsof successfully.  That "everywhere" includes
+dialect versions -- e.g., Solaris < 2.6 -- to which I no longer
+have access.  On some dialect versions to which I have access, some
+tests won't run because the test system lacks support.
+
+In "Appendix B, Test Validations" I've tried to list where I compiled
+and tested the test suite and information on any tests I was unable
+to run.  In "Appendix C, Test Failures" I list where the test suite
+fails and why it failed.
+
+A.4 Where are the tests?
+========================
+
+This is another FAQ whose answer is that the tests are in the tests/
+sub-directory of the main lsof source directory.
+
+
+B. Test Methodology
+===================
+
+The test suite is made up of individual C programs.  Test setup is
+performed by the lsof Configure script itself, which writes a set
+of dialect configuration files in the tests/ subdirectory.  (See
+"C. Configure Script Participation.")
+
+Each program or script performs a specialized tests.  Those tests
+are described below in "F. The Individual Tests".
+
+Each test measures lsof functionality by putting a specific lsof
+command execution at the end of an in-bound (to the test) pipe.
+The caller asks lsof to write its results to the pipe in field
+output form.  (See the -F option in the lsof man page.)
+
+Using an in-bound lsof pipe allows the tests to measure a great
+deal of lsof functionality, including as an interesting side effect,
+the performance of field output.  Consequently, there's no special
+field output test.
+
+B.1. Test Limitations
+=====================
+
+One limitation of the tests is that they don't measure lsof formatted
+output -- i.e., the output normally see when lsof is run.  There
+are just too many variants of lsof output produced across the range
+of dialects where lsof runs, so field output is a more consistent
+way to process lsof output.
+
+But using field output does mean that the test suite doesn't check
+for lsof formatting problems, except in the field output itself.
+
+B.2. Test Data Base and Scripts
+===============================
+
+The TestDB file contains a simple data base that describes where
+the tests have been validated.  Entries are formed from a combination
+of the lines in the config.cflags file produced by the lsof Configure
+script.  The entries can be considered "lsof dialect footprints,"
+hereafter simply called "dialect footprints" or just "footprints."
+
+Two shell scripts support TestDB.  The first, Add2TestDB, will add
+a footprint to TestDB.  I don't recommend you use this script.
+Mostly it's for my use when I find that the test suite has been
+validated on a new dialect.
+
+It's also possible to add a footprint to TestDB by simply editing
+TestDB and pasting into it a copy of the footprint reported by a
+failed Makefile rule.  I don't generally recommend this be done,
+either.
+
+There are Makefile rules that use (and avoid) the CkTestDB script.
+(See "B.3 The Makefile".)
+
+The default (i.e., "all") Makefile rule uses the CkTestDB script
+to look for the footprint in TestDB. If no footprint is found, the
+script issues a warning, displays the unfound footprint, and asks
+if running the test suite should continue.
+
+The "auto" Makefile rule also uses CkTestDB, but with a special
+call that causes CkTestDB to look in TestDB for the footprint,
+report it when it can't be found, and then fail.  That CkTestDB
+failure causes the "auto" rule to fail, too.
+
+The "silent" Makefile rule doesn't use CkTestDB to look in TestDB
+for the footprint.  It runs the standard and basic tests as silently
+as possible, then returns a failure or success exit code that
+signals the result of the running of the tests.  (Use the "silent"
+rule carefully, because it will skip proving the tests have previously
+run on the dialect.)
+
+B.3. The Makefile
+=======================
+
+The Makefile runs the tests in the test suite.  It has these rules.
+
+    all         runs the basic test and the standard tests,
+               interacting with the caller should the footprint
+               not be found in TestDB.
+
+               (This is the default rule.)
+
+    auto        runs the basic test and the standard tests on a
+               previously validated system as silently as possible.
+
+               The footprint must be found in TestDB for this rule
+               to succeed.  (See the "silent" rule for one that
+               avoids checking TestDB.)
+
+               This rule is designed for lsof build scripts that
+               want a quick noiseless test to make sure what they
+               built works as it previously did.
+
+               This rule calls CkTestDB in a way that inhibits
+               its normal go-ahead request. (See "B.2.1 The CkTestDB
+               Script".)  If CkTestDB finds the footprint and all
+               tests succeed, this rule returns a zero exit code
+               (success).  If the footprint isn't found or if any
+               test fails, a non-zero exit code (failure) is
+               returned.
+
+    ckDB        calls the CkTestDB script to look for a footprint.
+               If none is found, the way CkTestDB was called (See
+               "B.3.1 The CkTestDB Script".) causes it to return
+               a non-zero exit code (failure) to this rule, and
+               the rule then returns a non-zero exit code (failure)
+               itself.
+
+               This rule is used by the "auto" rule.  If this rule
+               succeeds (zero exit code), the "auto" rule then
+               uses the "silent" rule.
+
+    clean       removes test and compiler output.  (See the "D.
+               Cleaning -- Quick or Spotless" section.)
+
+    opt                runs the optional tests.
+    optional
+
+    silent      runs the lsof basic and standard tests as silently
+               as possible (as the "auto" rule does), but without
+               using CkTestDB to look for a footprint.  If all
+               tests succeed, the rule returns a zero exit code
+               (success).  If any test fails, the rule returns a
+               non-zero exit code (failure).
+
+               Use the "silent" rule carefully, because it will
+               skip proving the tests have previously run on the
+               dialect.
+
+    spotless    does what the clean rule does and also removes the
+               config.* files created by ../Configure.  (See the
+               "D. Cleaning -- Quick or Spotless" section.)
+
+    std                runs the basic test and the standard tests.
+    standard
+
+The Makefile cleaning rules are further described in "D.  Cleaning
+-- Quick or Spotless."
+
+B.3.1 The CkTestDB Script
+=========================
+
+Some Makefile rules (e.g., "all" and "auto") use the CkTestDB script
+to make sure the tests have been run previously on the dialect.
+CkTestDB does that by looking for the dialect's footprint in TestDB.
+
+If no footprint is found, and if standard input is a TTY, CkTestDB
+asks for a go-ahead signal.  If standard input isn't a TTY, CkTestDB
+aborts the test run.  (See "B.2. Test Data Base and Scripts".)
+
+The Makefile "silent" rule does not call CkTestDB.  use the "silent"
+rule carefully, because it will skip proving the tests have previously
+run on the dialect.
+
+B.4. The Lsof Executable and LT_LSOF_PATH
+=========================================
+
+Normally the programs in the test suite use the lsof executable in
+their parent directory, ../lsof.  Usually that lsof has just been
+built and testing it is the next logical step.
+
+Be careful that ../lsof has sufficient permission to access the
+necessary kernel resources -- e.g., /dev/kmem, /dev/mem, /proc,
+etc.  If it doesn't the tests will fail.  (The tests do check to
+see if they can open /dev/mem and /dev/kmem for read access if
+LT_KMEM is defined in config.cflags and if the path to the lsof
+executable is ../lsof.)
+
+Here are two possible ways you can make sure the lsof being tested
+has sufficient permission: 1) use chmod and chgrp to enable its
+running and put its path in LT_LSOF_PATH, thus disabling the check
+in the tests for kernel memory access; or 2) run the tests (and
+hence the lsof being tested) under a login that has sufficient
+permission -- e.g., is in a group that can read /dev/kmem.
+
+You can direct the tests to use a different lsof executable by
+specifying its path in the LT_LSOF_PATH environment variable.  To
+test an lsof executable already installed in /usr/local/etc --
+provided that lsof is at revision 4.63 or higher -- do this:
+
+    $ LT_LSOF_PATH=/usr/local/etc/lsof
+    $ export LT_LSOF_PATH
+    $ cd .../lsof_<version>/tests
+    $ make
+
+When you specify an alternate executable path via LT_LSOF_PATH,
+that also prevents the tests from checking to see if they have
+kernel memory access.
+
+B.5 Automated Testing
+=====================
+
+Normally the lsof test suite is wordy and may require interaction.
+When you want to avoid those interferences, use the Makefile "auto"
+or "silent" rules.  (See the description of the "auto" and "silent"
+rules in "B.3 The Makefile".)
+
+The footprint must be present in TestDB in order to use the "auto"
+rule.  If it is not, the "auto" rule will fail and report the
+missing footprint.  Footprints in TestDB proclaim that the tests
+have previously succeeded on the dialect.
+
+The footprint need not be present in TestDB in order to use the
+"silent" rule.  Use the "silent" rule carefully, because it will
+skip proving the tests have previously run on the dialect.
+
+
+C. Configure Script Participation
+=================================
+
+An important step in setting up the test suite is performed by the
+Configure script in the lsof home directory (the parent to tests/.)
+
+Configure writes four files in tests/ that describe how the tests
+are to be compiled, configured and loaded.  The files also describe
+options that Configure selected that are important to the test
+suite.
+
+C.1. config.cc
+==============
+
+This file, config.cc, contains the name of or the path to the C
+compiler used to compile lsof.  The Makefile uses this file in
+place of the standard make(1) CC string with a shell in-place
+execution statement -- i.e., `cat config.cc`.
+
+If the LSOF_CC environment variable is supplied to the lsof Configure
+script, its value will appear in the config.cc file.
+
+C.2. config.cflags
+==================
+
+This file, config.cflags, contains C compiler flags that Makefile
+uses to compile the C programs in the test suite.  As with the
+compiler file, config.cc, the make rules incorporate the contents
+of this file into C compiler options with `cat config.cflags`.
+
+This file is also used by the Add2TestDB and CkTestDB shell scripts
+to build and match footprints.  (See "B.2. Test Data Base and
+Scripts.")
+
+C.2.1 config.cflags Contents
+============================
+
+The config.cflags file may contain the following C compiler flags.
+
+
+    -DLT_AIXA               is present if lsof was built for AIX.
+                           It contains the AIX architecture flag.
+                           (See the lsof Configure script or
+                           dialects/aix/dlsof.h for more information
+                           on the AIX architecture flag.)
+
+    -DLT_BIGF              is present if lsof was built for a dialect
+                           that has large file (sizes and offsets >
+                           32 bits).
+
+    -DLT_CC                is present if the lsof compiler is cc.
+
+    -DLT_DEV64             is present if the FreeBSD dialect uses a 64
+                           devite type.
+
+
+    -DLT_DIAL_<abbr>       always ends in (the <abbr> part) the
+                           "canonical" -- i.e., usually the most
+                           common abbreviation by which the dialect
+                           is known.
+
+                           Example: -DLT_DIAL_solaris
+
+    -DLT_GCC               is present if the lsof compiler is gcc.
+
+    -DLT_K64               is present if lsof has been built for a
+                           64 bit kernel
+
+    -DLT_KMEM              is present if lsof has been built to
+                           use /dev/kmem to obtain kernel values.
+
+    -DLT_VERS=<vn>         contains the version number for the
+                           dialect, as used in lsof pre-processor
+                           tests.
+
+                           Example for Solaris 10: -DLT_VERS=100000
+
+    -DLT_VPATH             is present if the dialect has the v_path
+                           member in the vnode structure (e.g., some
+                           versions of Solaris 10).
+
+The config.cflags file may also contain dialect-specific compiler
+flags needed to activate a specific feature on the dialect.  For
+example, for HP-UX config.cflags might contain:
+
+    -D_LARGEFILE64_SOURCE   This compiler flag enables the use of
+                           large-file system library functions
+                           --e.g., open64().
+
+                           The lsof Configure script stanzas for
+                           the dialects select these options.
+
+
+C.3. config.ldflags
+===================
+
+This file, config.ldflags, contains the dialect loader flags --
+i.e., the equivalent to make(1) LFLAGS -- for loading the test
+programs.
+
+Example for Solaris: -lsocket           this adds the socket library
+                                       to the loading of the lsof
+                                       test programs.
+
+Example for UnixWare: -lsocket -lnsl    this adds the socket and
+                                       name server libraries to
+                                       the loading of the lsof
+                                       test programs.
+
+
+C.4. config.xobj
+================
+
+This file, config.xobj, contains the paths to any extra object
+files (.o's) that must be loaded when the test suite C programs
+are loaded.  Like config.cc and config.cflags, it's incorporated
+into the loader statements of the Makefile's rules with `cat
+config.xobj`.
+
+Examples for DEC OSF/1 and NEXTSTEP:
+
+    ../lib/snpf.o       this loads the private lsof object file
+                       that contains an snprintf() function.  (The
+                       DEC OSF/1 4.0 and NEXTSTEP 3.1 C libraries
+                       don't have snprintf().)
+
+
+D. Cleaning -- Quick or Spotless
+================================
+
+There are two Makefile rules that clean the tests/ subdirectory --
+"clean" and "spotless".  They cause different degrees of cleaning.
+
+    clean       a "quick" clean that removes compiled object files,
+               executables and test files.  It does NOT remove
+               the configuration files that ../Configure and the
+               config.perl rule wrote.
+
+    spotless    cleans out everything clean does -- plus the
+               configuration files that ../Configure and the
+               config.perl rule wrote.
+
+               This is the rule used when `./Configure -clean` is
+               specified.  If this rule is used, `../Configure -n
+               <abbr>` and `../make`) must be run again before
+               the test suite can be used.
+
+
+E. Test Library
+===============
+
+The lsof test suite provides a C library.
+
+E.1. LTlib.c
+============
+
+This is a C library of common functions used by tests.  Configured
+at compile time by the contents of config.cflags, it uses the single
+header file LsofTest.h.  LsofTest.h tailors its definitions to the
+dialect at compile time, using the LT_DIAL_* definitions in
+config.cflags.
+
+Two particularly useful functions in the library are: ExecLsof(),
+which will execute an lsof child process; and RdFromLsof(), which
+will read from the in-bound lsof pipe, and decode the fields into
+structures that are easy for C programs to process.
+
+This library is a good model for processing field output in a C
+program from an in-bound lsof pipe.
+
+The source for the library, LTlib.c, contains more documentation.
+
+
+F. The Individual Tests
+=======================
+
+The individual tests are listed in this section.  The listings
+explain what the tests do, a few errors they might report, and how
+to use options and environment variables to customize the tests.
+
+The test descriptions are listed in this section in alphabetical
+order, not in the order they are run by Makefile.
+
+The Makefile runs the tests in three groups, basic tests, standard
+tests, and optional tests.  The default make "all" rule runs the
+basic and standard tests.  (The "standard", "std", and "test"
+Makefile rules are synonyms to "all".) If the standard tests succeed,
+Makefile suggests running the optional tests with the "opt" (or
+"optional") rule.
+
+The Makefile "auto" and "silent" rules run only the basic and
+standard tests.  They do not run or suggest you run the optional
+tests.
+
+    The basic test:
+       LTbasic
+
+    Standard tests:
+       LTnlink
+       LTsock
+       LTszoff
+       LTunix
+
+    Optional tests:
+       LTbigf
+       LTdnlc
+       LTlock
+       LTnfs
+
+The basic and standard tests should all succeed on all dialects,
+although LTnlink may warn that it can't perform its unlink test on
+an NFS file system.
+
+The optional tests may run, they may be disabled for specific
+dialects, or they may fail because of special resource needs --
+e.g., LTbigf will run only on UNIX dialects where it knows how to
+handle files whose lengths exceed 32 bits, and LTnfs needs access
+to an NFS file system mounted from a remote NFS server.
+
+Tests that need special resources usually provide a hint about the
+resources when they fail.  Information about special resource needs
+may also be found in the following sections about the individual
+tests.
+
+G.1. LTbasic, a Basic Lsof Test
+===============================
+
+This is the basic lsof test.  If it doesn't run, it's not likely
+any other tests will run, either.  Hence, if it fails, no Makefile
+rule runs any other tests.
+
+This test uses lsof to locate files in the lsof process, including
+current working directory, the lsof executable, and the /dev/kmem
+open file.
+
+Finding the lsof executable may not be possible on AIX if lsof was
+compiled without support for its -X option.
+
+Finding /dev/kmem use by lsof is only possible on dialects where
+lsof uses /dev/kmem.  The -DLT_KMEM define indicates that.
+
+Run this test:
+
+    $ ./LTbasic
+
+Environment variables: LT_LSOF_PATH defines the path to the lsof
+                      executable.  (The default is ../lsof.)
+
+G.2. LTbigf, Test Sizes and Offsets for Large (> 32 bit) Files
+==============================================================
+
+This is a test in the optional test group.
+
+This test is effective only when ../Configure has put -DLT_BIGF in
+config.cflags.  Without that definition this test simply reports
+that the dialect doesn't support large files.  That report is
+accompanied by a successful test exit code, so that the runner of
+the test (e.g., the Makefile) won't believe the test failed.
+
+When a dialect does support large files, the test attempts to create
+a file that looks very large -- e.g., has a length as reported by
+ls(1) of 0x140000000 bytes.  However, the file really has only a
+small amount of data in it, the rest of the file consists of a
+large standard UNIX file system "hole."
+
+By default the test file is named config.LTbigf<PID>, where PID is
+the Process ID of the LTbigf process.
+
+When that file is not on a file system enabled for large files, or
+when the process that runs LTbigf can't create a big file, LTbigf
+will report an error.  The error will be accompanied by hints that
+the -p option may need to be used to define a path where the test
+can write a large file, or the process ulimit file block size may
+need to be raised -- e.g., to "unlimited."
+
+LTbigf can't test file offset reporting on Linux kernels below
+2.6.22, because the /proc file systems of those kernels don't make
+file offsets available to lsof.
+
+Run this test:
+
+    $ ./LTbigf [-p <path>]
+
+Environment variables: LT_LSOF_PATH defines the path to the lsof
+                      executable.  (The default is ../lsof.)
+
+G.3. LTdnlc, Test the Kernel's Dynamic Name Lookup Cache
+========================================================
+
+This is a test in the optional test group.
+
+This test asks lsof to locate the current working directory of its
+own process and report the path it has assembled from the components
+it found in the kernel's Dynamic Name Lookup Cache (DNLC) or via
+other dialect-specific methods.  (E.g., Linux, HP-UX 11.11, and
+some Tru64 UNIX versions have private name lookup methods.)
+
+The test checks what lsof reports as the current working directory
+path for any missing components and counts the number of full paths
+returned.  (Symbolic link complications prevent testing for exact
+path matches.)  The test is repeated.  If full paths are returned
+at least half the time, the test considers itself successful.
+
+This test can't be run on AIX, because lsof can't access the DNLC
+there.  It can't be run on Apple Darwin versions below 8.0, either,
+because insufficiently reliable DNLC information is available there.
+This test may fail on other dialects when the file system -- e.g., NFS.
+/tmp, loopback -- doesn't fully participate in the dialect's DNLC.
+
+Run this test:
+
+    $ ./LTdnlc
+
+Environment variables: LT_LSOF_PATH defines the path to the lsof
+                      executable.  (The default is ../lsof.)
+
+G.4. LTlock, Lock Tests
+=======================
+
+This is a test in the optional test group.
+
+This test uses flock() and fcntl() to set and clear file locks,
+and measures lsof's ability to report them.  The choice of system
+lock call is based on the dialect.  (There are LT_DIAL_* pre-processor
+tests in LTlock.c.)
+
+This test can't be run on an NFS client file system, because NFS
+lock information is kept on the server.  Lsof on the client can't
+see that server kernel data.
+
+By default the test attempts to create a file named config.LTlock<PID>,
+where PID is the Process ID of the locking test process.  It uses
+lsof to determine if the file is on a client NFS file system.  If
+it is, the test aborts, hinting that the -p option can be used to
+specify a non-client-NFS test file path.
+
+This test can't be run on Darwin, because insufficient file system
+lock information is available to lsof there.
+
+Run this test:
+
+    $ ./LTlock [-p <path>]
+
+Environment variables: LT_LSOF_PATH defines the path to the lsof
+                      executable.  (The default is ../lsof.)
+
+G.6. LTnfs, NFS Test
+====================
+
+This is a test in the optional test group.
+
+This test verifies that lsof can locate files mounted on a client
+NFS system from an NFS server.
+
+By default it creates a test file, config.LTnfs<PID>, where PID is
+the Process ID of the test process.  The test then uses lsof to
+find the file on an NFS file system.
+
+If lsof can't find the file the test warns that the test file might
+not be on an NFS file system and hints that the -p option may be
+used to specify the path of an NFS file, provided the test can have
+read access to it there.  The test warning also states that the
+file at the path specified with -p must be a regular file, not a
+directory.
+
+This test can't be run on Darwin versions below 8.0, because
+insufficient NFS file information is available to lsof there.
+
+Run this test:
+
+    $ ./LTnfs [-p <path>]
+
+Environment variables: LT_LSOF_PATH defines the path to the lsof
+                      executable.  (The default is ../lsof.)
+
+G.7. LTnlink, Link Count Test
+=============================
+
+This is a test in the standard test group.
+
+The test checks lsof's reporting of link count (nlink in UNIX
+argot.)
+
+It creates a test file in the current working directory named
+config.LTnlink<PID>, where  PID is the Process ID of the test
+process.  It then uses stat(2) and lsof to measure the link count
+of the file.
+
+If LTnlink creates the test file in the current working directory
+and it is on an NFS file system, LTnlink won't be able to perform
+one section of its test.  In that section the test file is unlinked
+so its link count will be zero and lsof is asked to find it among
+the set of files whose link counts are zero.
+
+When an NFS file is unlinked its link count isn't reduced until
+the last open instance is closed on either the NFS clients or the
+NFS.  That's a consequence of NFS statelessness and leads to the
+occasional presence of files with names of the form .nfsxxxx.
+
+Should LTnlink find its test file on an NFS file system, it disables
+the unlink section of its tests and issues a warning.  It also
+issues a hint that the test file path can be named via the -p option
+to give a test file location that isn't on an NFS file system.
+
+This test can't be run on Darwin, because insufficient file system link
+count information is available to lsof there.
+
+Because some UNIX dialects delay the reporting of a link count
+update after a file has been unlinked, LTnlink may not get its
+expected response from lsof for a while after the test file has
+been unlinked.  In that cause LTnlink may delay for up to a minute,
+calling lsof once every two seconds and displaying a "waiting for
+link count update: ..." message.
+
+Some file systems -- e.g., ZFS on Solaris 11 -- don't allow LTnlink to
+unlink its test file, because LTnlink has the file open.  LTnlink
+explains that failure and suggests that it be run with path of the "-p
+path" option set to a file on /tmp.  See 00FAQ for more information.
+
+Run this test:
+
+    $ ./LTnlink [-p <path>]
+
+Environment variables: LT_LSOF_PATH defines the path to the lsof
+                      executable.  (The default is ../lsof.)
+
+G.7. LTsock, Test IPv4 Sockets
+==============================
+
+This is a test in the standard test group.
+
+This test uses lsof to locate open IPv4 socket files that the test
+has created itself.  The test opens a server socket, then forks a
+child process to connect to that socket.  After both are running,
+the test uses lsof to find the open socket files at their known
+host and port addresses.
+
+Run this test:
+
+    $ ./LTsock
+
+Environment variables: LT_LSOF_PATH defines the path to the lsof
+                      executable.  (The default is ../lsof.)
+
+G.8. LTszoff, Test Sizes and Offsets for Small (< 32 bit) Files
+===============================================================
+
+This is a test in the standard test group.
+
+This test checks lsof's reporting of file size and offset for small
+(< 32 bits) files.
+
+It creates a test file in the current working directory named
+config.LTszoff<PID>.  PID is the Process ID of the test process.
+
+LTszoff can't test file offset reporting on Linux kernels below
+2.6.22, because the /proc file systems of those kernels don't make
+file offsets available to lsof.
+
+Run this test:
+
+    $ ./LTszoff [-p <path>]
+
+Environment variables: LT_LSOF_PATH defines the path to the lsof
+                      executable.  (The default is ../lsof.)
+
+G.9.  LTunix, Test UNIX Domain Sockets
+======================================
+
+This is a test in the standard test group.
+
+This test checks lsof's reporting of UNIX domain sockets.
+
+The test creates a pair of UNIX domain sockets and uses bind(2) to
+associate the file system names config.LT0U<PID> (client) and
+config.LT1U<PID> (server) with them.  (PID is the test process ID.)
+The test then uses lsof to find the two open UNIX domain socket
+files.
+
+Run this test:
+
+    $ ./LTunix
+
+Environment variables: LT_LSOF_PATH defines the path to the lsof
+                      executable.  (The default is ../lsof.)
+
+
+Appendix A, Test Files
+======================
+
+These files may be created by suite tests.
+
+                       Created
+    ./tests Name       by Test     Use
+    ============       =======     ===
+
+    config.LTbifg**     LTbigf      to test lsof's large file size
+                                   and offset reporting
+
+    config.LTlock*     LTlock      for locking tests
+
+    config.LTnfs*      LTnfs       for NFS tests
+
+    config.LTnlink*    LTnlink     for link count tests
+
+    config.LTszoff*     LTszoff     for small file size and and
+                                   offset reporting
+
+    config.LT[01]U*     LTunix      two UNIX domain sockets, used
+                                   to determine if lsof can report
+                                   their open instances properly
+
+
+Appendix B, Test Validations
+============================
+
+This appendix lists the UNIX dialects and their versions where I
+have validated the test suite.  The list indicates the particular
+tests I was unable to run, mostly LTnfs because the test systems
+I used had no NFS file systems mounted.
+
+The information in the following table is encoded in a test data
+base file, TestDB, as footprints, using the tests compiler options
+written to config.cflags by the lsof Configure script.  See "B.2.
+Test Data Base and Scripts" for more information on the test data
+base, footprints, and the scripts that support them.
+
+    UNIX
+    Dialect      Dialect Description           Untested Tests
+    =======      ===================           ==============
+    AIX                  4.3.3, Power, cc
+                 5.1, Power-32, cc
+                 5.1, Power-32, gcc
+                 5.1, Power-64, cc
+                 5.2, Power-32, cc
+                 5.2, Power-32, gcc
+                 5.2, Power-64, cc
+                 5.2, Power-64, gcc
+                 5.3, Power-64, cc
+    Darwin        1.4, 5.5, 6.x, 7.x gcc       Darwin lsof doesn't
+                                               have adequate support
+                                               to allow the LTbigf,
+                                               Ltdnlc, LTlock, LTnfs,
+                                               and LTnlink tests to
+                                               run.
+                 8.0, gcc                      Darwin lsof doesn't
+                                               have adequate support
+                                               to allow the LTbigf,
+                                               LTlock and LTnlink
+                                               tests to run.
+                 9.0, gcc                      Darwin lsof doesn't
+                                               have adequate support
+                                               to allow the LTlock
+                                               test to run.
+                 10.0, gcc                     Darwin lsof doesn't
+                                               have adequate support
+                                               to allow the LTlock test
+                                               to run.
+                 11.0, gcc                     Darwin lsof doesn't
+                                               have adequate support
+                                               to allow the LTlock test
+                                               to run.
+    FreeBSD       4.5, i386, gcc
+                 4.6, i386, gcc
+                 4.7, i386, gcc
+                 4.8, i386, gcc
+                 4.9, i386, gcc
+                 4.10, i386 gcc
+                 5.0, Alpha, gcc
+                 5.0, Sparc, gcc
+                 5.0, i386, gcc
+                 5.1, Alpha, gcc
+                 5.1, Amd64, gcc
+                 5.1, Sparc, gcc
+                 5.1, i386, gcc
+                 5.2, i386, gcc
+                 5.2, Alpha, gcc
+                 5.2, Amd64, gcc
+                 5.2, Sparc, gcc
+                 5.3, Alpha, gcc
+                 5.4, Alpha, gcc
+                 5.5, Alpha, gcc
+                 6.0, Alpha, gcc
+                 6.0, Amd64, gcc
+                 6.0, Sparc, gcc
+                 6.1, i386, gcc
+                 6.4, i386, gcc
+                 7.0 Alpha, gcc
+                 7.0 Amd64, gcc
+                 7.1 Amd64, gcc
+                 7.2 Amd64, gcc
+                 7.3 Amd64, gcc
+                 7.4 Amd64, gcc
+                 8.0 Amd64, gcc
+                 8.2 Amd64, gcc
+                 8.3 Amd64, gcc
+                 8.4 Amd64, gcc
+                 9.0 Amd64, gcc
+                10.0 Amd64, gcc
+                10.0 Amd64, clang
+                11.0 Amd64, clang
+                12.0 Amd64, clang
+    HP-UX        10.20, cc                     LTbigf
+                 10.20, gcc (1)                LTbigf
+                 11.00-32, ANSI-C              LTbigf, LTnfs
+                 11.00-64, ANSI-C
+                 11.11, ANSI-C
+                 11.23, ANSI-C
+    Linux         2.4.12-686                   LTbigf, no offset tests
+                                               LTszoff, no offset tests
+                 2.4.18-686                    LTbigf, no offset tests
+                                               LTszoff, no offset tests
+                 2.4.21-686                    LTbigf, no offset tests
+                                               LTszoff, no offset tests
+                 2.4.23-686                    LTbigf, no offset tests
+                                               LTszoff, no offset tests
+                 2.4.24-686                    LTbigf, no offset tests
+                                               LTszoff, no offset tests
+                 2.4.25-686                    LTbigf, no offset tests
+                                               LTszoff, no offset tests
+                 2.4.26-686                    LTbigf, no offset tests
+                                               LTszoff, no offset tests
+                 2.4.27-686                    LTbigf, no offset tests
+                                               LTszoff, no offset tests
+                 2.4.28-686                    LTbigf, no offset tests
+                                               LTszoff, no offset tests
+                 2.4.29-686                    LTbigf, no offset tests
+                                               LTszoff, no offset tests
+                 2.4.30-686                    LTbigf, no offset tests
+                                               LTszoff, no offset tests
+                 2.6.1-rc2                     LTbigf, no offset tests
+                                               LTszoff, no offset tests
+                 2.6.18-686                    LTbigf, no offset tests
+                                               LTszoff, no offset tests
+                 2.6.22-686                    (Note: this Linux kernel
+                                                supplies file offsets to
+                                                lsof.)
+                 2.6.32-686                    (Note: this Linux kernel
+                                                supplies file offsets to
+                                                lsof.)
+                 2.6.38-686
+                 3.10.004
+                 3.10.08
+                 4.14.14
+                 3.10.0-229.1.2.el7
+    NetBSD        1.4.1, Alpha, gcc            LTnfs
+                 1.5x, x86, gcc                LTnfs
+                 1.6x, Alpha, gcc              LTnfs
+                 1.6x, x86, gcc                LTnfs
+                 2.0x, alpha, gcc              LTnfs
+                 2.0x, sparc64, gcc            LTnfs
+                 2.0x, x86, gcc                LTnfs
+                 2.99.9, x86, gcc              LTnfs
+                 2.99.10, x86, gcc             LTnfs
+                 2.99.11, x86, gcc             LTnfs
+                 2.99.12, x86, gcc             LTnfs
+                 3.99., x86, gcc               LTnfs
+    OpenBSD       3.0, gcc
+                 3.1, gcc
+                 3.2, gcc
+                 3.3, gcc
+                 3.4, gcc
+                 3.5, gcc
+                 3.6, gcc
+                 3.7, gcc
+                 3.9, gcc
+    OSR           5.04, cc                     LTnfs
+                 5.06, cc                      LTnfs
+    Solaris       2.6, cc                      LTnfs
+                 2.6, gcc                      LTnfs
+                 7-32, cc
+                 7-32, gcc                     LTnfs
+                 8-32, cc
+                 8-32, gcc
+                 8-64, cc
+                 8-64, gcc
+                 9-64, Beta-Refresh, cc
+                 9-64, Beta-Refresh, gcc
+                 9-64, FCS, cc
+                 9-64, FCS, gcc
+                 10-32, i86pc, gcc
+                 10-32, i86pc, cc
+                 10-64, Sparc, cc
+                 10-64, Sparc, gcc
+                 11-64, Amd64, cc
+    UnixWare      7.1.1, NSC, cc               LTnfs
+                 7.1.3, cc
+                 7.1.4, cc
+
+If you are able to run the test suite on dialect versions other
+than the ones listed above, please send e-mail to <abe@purdue.edu>,
+indicating the dialect version where you were able to run the test
+suite.  Please send me the footprint formed by CkTestDB, or run
+the Add2TestDB script and send me the footprint it reports.
+
+If you encounter problems compiling the tests or running them on
+a dialect version listed above, please send e-mail to <abe@purdue.edu>,
+naming the dialect version and providing the output from the lsof
+Configure script and make operation.
+
+1) John Dzubera did the HP-UX 10.20 gcc testing and provided its
+   footprint.
+
+
+Appendix C, Test Failures
+=========================
+
+I was unable to make the test suite run on the following dialects.
+
+    UNIX Dialect
+    and Description     Failure
+    ===============     =======
+    HP-UX 11-64, gcc     64 bit gcc 3.0 didn't compile the LTsock
+                        test correctly on my 64 bit HP-UX 11 test
+                        system.
+
+
+Vic Abell <abe@purdue.edu>
+February 14, 2018
diff --git a/00XCONFIG b/00XCONFIG
new file mode 100644 (file)
index 0000000..f42c1fe
--- /dev/null
+++ b/00XCONFIG
@@ -0,0 +1,697 @@
+
+                       Cross-configuring Lsof
+
+Introduction
+============
+
+Lsof cross-configuration is useful when the target dialect or target
+dialect version for which lsof is to be configured and built differs
+from the one on which the Configure operation is done.
+
+Marty Leisner <leisner@sdsp.mc.xerox.com> suggested the method
+described here for lsof cross-configuration, and he supplied
+modifications to the Configure script for cross-configuring Linux
+lsof.
+
+Marty says:
+
+    "I used this to successfully compile (lsof) on the same machine
+     for (Linux) 2.0.30 and 2.1.42.  (I normally don't bring up a
+     2.1.42 machine all the time).  Also it (the 2.0.30 system)
+     doesn't have much storage and compiles on it are slow.
+
+     Set LSOF_VERS if it's not the (version of the) current system.
+     (Actually, you should get the version out of include/linux/version.h.)
+
+     Define LINUX_KERNEL to (the path) where the kernel sources
+     are (located).  (No longer necessary as of lsof revision 4.53.)
+
+     This should work on most systems; they put a kernel in
+     /usr/src/linux, which is the default.
+
+     Now I can just do:
+
+       LINUX_KERNEL=/some/other/kernel LSOF_VERS=2142 ./Configure linux
+
+     Comments?  Its very convenient when running multiple kernels.
+     (It would be (have been) very handy when the structures changed
+     between 2.0.2* and 2.0.30 , or whatever.)
+
+     I run multiple OSes at a time (not to mention multiple
+     architectures.  It's very pleasant to cross-build either
+     operating systems or versions."
+
+So, the situation is that you have lsof sources on a UNIX dialect
+version, and you want to configure them to build lsof for some
+other version of the same dialect, or perhaps for some other UNIX
+dialect altogether.
+
+
+The Cross-Configure Method
+==========================
+
+The lsof cross-configure method uses environment variables to tell
+the lsof Configure script about the target dialect.  The environment
+variables may specify alternate locations for Configure to examine
+when it determines characteristics of the target, or they may
+specify the values Configure would discover when it examined the
+target's characteristics.
+
+Consult each environment variable description for the UNIX dialect
+in which you're interested to see how it affects the operation of
+the Configure script.
+
+The number and values of the variables differ by dialect.  Each
+variable begins with an upper case version of the dialect's Configure
+abbreviation -- e.g., AIX for aix or aixgcc, LINUX for linux,
+UW for uw (UnixWare), etc.
+
+Of course, the UNIX dialect's version is probably different from
+that of the system on which you're doing the cross-configuration,
+so you will need to specify the new version, too.  For example, to
+configure for FreeBSD 3.0 on a 2.1.7 system, where the standard
+3.0 header files are in /3.0/usr/include and the 3.0 system sources
+are in /3.0/sys, do this:
+
+       LSOF_VERS=300 LSOF_INCLUDE=/3.0/usr/include \
+       FREEBSD_SYS=/3.0/sys Configure -n freebsd
+
+
+General Environment Variables
+=============================
+
+There are some environment variables whose names don't begin with
+an upper case rendering of a dialect abbreviation.  Generally they
+apply to all dialects.
+
+AFS_VICE        is for AFS configuration.   It need be set only if
+               lsof supports AFS on your dialect and you want to
+               specify an alternate path to the VICE files.
+
+               default: /usr/vice
+
+LSOF_AR         is the path to and arguments for the library archive
+               application that is used to build the lsof library,
+               liblsof.a.  When this value is placed in the library
+               Makefile as the contents of the AR make string, it is
+               followed by the path to the library and the relative
+               paths of the library module
+
+               default: ar cr
+
+LSOF_ARCH       is the architecture type string for the system.
+               Usually this is the output of `uname -m`.  Consult
+               the Configure script for details.  The LSOF_ARCH
+               value may have to be quoted if it contains spaces.
+
+               default: auto-detection (e.g., from `uname -m`)
+
+LSOF_BLDCMT     may be used to introduce a builder's comment into
+               lsof's -v output.  It defaults to the null string,
+               causing no builder's comment to appear in -v output.
+
+               default: none
+
+LSOF_CC         is the path to the C compiler.  You may need to
+               specify it if your C compiler is in a non-standard
+               place, not found by your path.  If you specify a
+               compiler different from the expected default, you
+               may have to change the compile time flags by
+               specifying new CFGF, CFGL, and DEBUG strings on
+               the make command line.
+
+               default: normally cc, but some dialects have other
+                        defaults and some have auto-detection.
+
+                        Check the dialect stanza in the lsof Configure
+                        script to see how LSOF_CC is set by default.
+
+LSOF_CCV        is the C compiler version.  You should specify it
+               if you have specified a compiler path in LSOF_CC.
+
+               default: the lsof Configure script knows how to find
+                        the version number of gcc and some other
+                        dialect-specific compilers.
+
+                        Check the dialect stanza in the lsof Configure
+                        script to see how lsof_CCV is set by default.
+
+LSOF_CFGF      may be used to specify additional configuration values
+               that will appear in the CFGF string of the Makefile.
+
+LSOF_CFGL      may be used to specify additional library specifications
+               that will appear in the CFGL string of the Makefile.
+
+LSOF_HOST       may be used to specify a value in lsof's -v output
+               other than the name of the host where lsof was
+               built.  A value of "none" inhibits host name display
+               in -v output.
+
+               default: the dialect's host name application -- e.g.,
+                        hostname or uname -n
+
+LSOF_INCLUDE    is the path to a tree of header files that is an exact
+               image of the the standard header file tree for the
+               target dialect.  You may need to specify it if you
+               want Configure to test header files in a tree different
+               from /usr/include and compile its test programs with
+               header files from that tree, then you want to compile
+               lsof from the header files in that different, duplicate
+               image tree.
+
+               Note: LSOF_INCLUDE should contain a single path
+               without any option flags, such as -I.  It is always
+               supplied to the compiler in CFLAGS following the -I
+               option flag.  If you want to specify other include
+               paths, use LSOF_OPINC.
+
+               ADDITIONAL NOTE: all the header files that lsof's
+               Configure tests for optional features and uses to
+               compile test programs must be in LSOF_CONFIGURE.
+               They can't be scattered in the other include path
+               that LSOF_OPINC names.
+
+LSOF_LOGNAME    may be used to specify a value in lsof's -v output
+               other than the one in the LOGNAME environment
+               variable for the login name of the person who built
+               lsof.  A value of "none" inhibits login name display
+               in -v output.
+
+               default: the LOGNAME environment variable
+
+LSOF_MAKE      is the path to the make command.
+
+               deafult: the output of `which make`, if it is not NULL;
+                        otherwise the string "make".
+
+LSOF_MKC        may be used to specify an alternate method of
+               connecting dialect sources to the top-level lsof
+               directory.  See 00PORTING for more information.
+
+               default: ln -s
+
+LSOF_OPINC     may be used to specify other include file search
+               paths.  Each must be preceded by the compiler's -I
+               option file and, if there are muliple paths, they
+               must be separated by spaces and the entire set must
+               be enclosed in double quote marks -- e.g.,
+
+               LSOF_OPINC="-I/path1 -I/path2 ..."
+
+               The optional include paths thus specified will be
+               appended to LSOF_INCLUDE and whatever special
+               include paths the lsof Configure script finds
+               necessary.
+
+LSOF_RANLIB    may be used to specify an alternate command for the
+               randomizing of the lsof library.
+
+               default: ranlib for most dialects
+                        none for: IBM AIX; HP-UX; SCO OpenServer; Solaris
+                                  and SCO|Caldera UnixWare
+
+LSOF_SYSINFO    may be used to specify a value in lsof's -v output
+               other than the standard system identification --
+               e.g., output from uname.  A value of "none" inhibits
+               system information display in -v output.
+
+               default: the dialect's standard system identification
+                        application output -- e.g., uname, sysinfo
+
+LSOF_USER      may be used to specify a value in lsof's -v output
+               other than the one in the USER environment variable
+               for the login name of the person who built lsof.
+               A value of "none" inhibits login name display in
+               -v output.
+
+               default: the USER environment variable
+
+LSOF_VERS       is the target dialect version number.  It must be
+               stated in the dialect's form -- e.g., FreeBSD 2.0.5
+               is given as 205, Solaris 7 as 70000, etc.  The
+               table, "Abbreviations, Variable Prefixes, and
+               Version Numbers," in this file gives the form for
+               LSOF_VERS for each dialect lsof supports.
+
+               default: auto-detection (e.g., from `uname -r`)
+
+LSOF_VSTR       is the version string from which LSOF_VERS is
+               derived.  Usually this is the output of `uname -r`
+               or `uname -v`.  Consult the Configure script for
+               details.   The LSOF_VSTR value may have to be quoted
+               if it contains spaces.
+
+               default: auto-detection (e.g., output from
+                        `hostname`, `uname -r`, or `uname -v)
+
+
+Make Strings
+============
+
+The CFGF, CFGL, and DEBUG strings can be specified on the make
+command line to change default values placed in the top-level and
+library Makefiles by Configure.  For example, Configure usually
+defines the compiler optimization level to be -O, but you can change
+that with "DEBUG=-g" on the make command -- e.g.,
+
+       $ make DEBUG=-g lsof
+
+Similarly, the CFGF string contains miscellaneous compile-time
+options, and CFGL contains loader options.  Consult the Makefiles
+generated by Configure for the values it defines by default for
+CFGF and CFGL.
+
+As an example, Configure might define CFGL to be "-L./lib -llsof -w"
+for NextStep 3.1; to remove "-w", use this make invocation:
+
+       $ make CFGL="-L./lib -llsof"
+
+
+Abbreviations, Variable Prefixes, and Version Numbers
+=====================================================
+
+The following table describes the relationship between Configure
+abbreviations, environment variable prefixes, and lsof UNIX dialect
+version numbers.  The lsof UNIX dialect version number must be
+declared exactly in the listed form when supplied via the LSOF_VERS
+environment variable.
+
+                               Dialect    Lsof Version
+   Configure   Variable        Version      Number for
+Abbreviation*    Prefix         Number       LSOF_VERS
+
+        aix         AIX          3.2.5            3250
+      aixgcc                     4.1.0            4100
+                                 4.1.4            4140
+                                 4.1.4            4150
+                                 4.2.0            4200
+                                 4.2.1            4210
+                                 4.3              4300
+                                 4.3.1            4310
+                                 4.3.2            4320
+                                 4.3.3            4330
+                                 5.0.x            5000
+                                 5.1.x            5100
+                                 5.2.x            5200
+                                 5.3.x            5300
+      darwin     DARWIN          1.2*              120
+                                 1.3*              130
+                                 1.4*              140
+                                 5.[012]           500
+                                 5.[3-9]           530
+                                 6.x               600
+                                 7.x               700
+                                 8.x               800
+     freebsd    FREEBSD          1.x              1000
+                                 2.x              2000
+                                 2.0.5            2005
+                                 2.1.x            2010
+                                 2.2.x            2020
+                                 3.x              30x0
+                                 4.x              40x0
+                                 4.1x             41x0
+                                 5.x              50x0
+                                 6.x              60x0
+                                 7.x              70x0
+                                 8.x              80x0
+                                 9.x              90x0
+       hpux        HPUX          9.1               901
+     hpuxgcc       HPUX          9.5               905
+                                 10.0             1000
+                                 10.10            1010
+                                 10.20            1020
+                                 11.00            1100
+                                 11.11            1111
+      linux       LINUX          2.1.x           21xxx
+                                 2.2.x           22xxx
+                                 2.3.x           23xxx
+                                 2.4.x           24xxx
+                                 2.6.x           26xxx
+     netbsd      NETBSD          1.2           1002000
+                                 1.3           1003000
+                                 1.4           1004000
+                                 1.5           1005000
+                                 1.6           1006000
+                                 2.0           2000000
+                                 2.99.9        2099009
+                                 2.99.10       2099010
+    openbsd     OPENBSD          1.2              1020
+                                 2.0              2000
+                                 2.1              2010
+                                 2.2              2020
+                                 2.3              2030
+                                 2.4              2040
+                                 2.5              2050
+                                 2.6              2060
+                                 2.7              2070
+                                 2.8              2080
+                                 2.9              2090
+                                 3.0              3000
+                                 3.1              3010
+                                 3.2              3020
+                                 3.3              3030
+                                 3.4              3040
+                                 3.5              3050
+                                 3.6              3060
+       osr          OSR          3.2v2.0            20
+                                 3.2v2.1            21
+                                 3.2v4.0            40
+                                 3.2v4.1            41
+                                 3.2v4.2            42
+                                 3.2v5.0.0         500
+                                 3.2v5.0.2         502
+                                 3.2v5.0.4         504
+                                 3.2v5.0.6         506
+         ou          OU          8.0.0           80000
+    solaris      SOLARIS         2.3             20300
+  solariscc     SOLARIS          2.4             20400
+                                 2.5             20500
+                                 2.5.1           20501
+                                 2.6             20600
+                                 7               70000
+                                 8               80000
+                                 9               90000
+                                 10             100000
+        uw           UW          7.0             70000
+                                 7.1.0           70100
+                                 7.1.1           70101
+                                 7.1.3           70103
+
+
+
+Dialect-Specific Environment Variables
+======================================
+
+Here are the dialect-specific environment variables, listed
+alphabetically.  The first part of any environment variable will
+be the dialect abbreviation, as specified to Configure, converted
+to upper case characters.  See the `Configure -help` output for a
+listing of the abbreviations.
+
+AIX_ARCH               specifies the AIX architecture when the AIX version is
+                       5.0 or higher.  A value of "" signifies POWER; "ia64",
+                       64 bit x86 (Itanium).
+
+                       default: none (tested via `uname -a`)
+
+AIX_HAS_AFS            specifies the state of AIX ADS support when the AIX
+                       version is 4.3.3 or lower.  (Lsof doesn't support AFS
+                       above AIX 4.3.3.)  A value of "" allows the Configure
+                       script to determine the AFS support state; "no",
+                       disables AFS support; and "yes", forces the enabling of
+                       AFS support.
+
+                       default: none (tested via presence of AFS files and the
+                                lsof AFSConfig shell script)
+
+AIX_KERNBITS           specifies the kernel bit size, 32 or 64, of the Power
+                       architecture AIX 5.x kernel for which lsof was built.
+
+                       default: determined by the Configure script with a test
+                                program that uses <sys/systemcfg.h> macros.
+
+AIX_USHACK             If this environment variable has a value of "Y" or "y",
+                       and if the aixgcc Configure abbreviation is selected,
+                       the AIX 4.1 and greater gcc user structure hack is
+                       activated; any other non-NULL value, it's not set; a
+                       NULL value, it's tested by compilation.
+
+                       default: none (tested by compilation)
+
+DARWIN_XNUDIR          If this environment variable has a value, the value is
+                       used as the path to the Darwin XNU kernel source code.
+
+                       default: none (entry requested)
+
+DARWIN_XNU_HEADERS     If this environment variable has a value, the value is
+                       used as the path to the Darwin XNU kernel header files.
+                       This path would match the DSTROOT environment variable
+                       used when a "make installhdrs" was executed from the
+                       Darwin XNU kernel source directory.
+
+                       default: none
+
+FREEBSD_KERNEL         specifies the path to the FreeBSD kernel for FreeBSD
+                       version less than 2.0.
+
+                       default: /386bsd
+
+FREEBSD_SYS            specifies the path to the FreeBSD system source
+                       directory.
+
+                       default: /sys
+
+HPUX_BASE              specifies the HP-UX lsof source code base, kmem or
+                       pstat, to be used.
+
+                       default: determined by testing for the
+                                /usr/include/sys/pstat subdirectory
+
+HPUX_BOOTFILE          specifies the file in which lsof's Configure script can
+                       find kernel information.  This specification may be
+                       useful for defining the path to a copy of /stand/vmunix
+                       that has been processed by pxdb or q4pxdb.
+
+                       default: /stand/vmunix
+
+HPUX_CCDIR1            specifies the first directory where Configure might
+                       find an HP-UX C compiler.  This is ignored when
+                       LSOF_CC has been specified.
+
+                       default: /bin
+
+HPUX_CCDIR2            specifies the second directory where Configure might
+                       find an HP-UX C compiler.  This is ignored when
+                       LSOF_CC has been specified.
+
+                       default: /usr/ccs/bin
+
+HPUX_HASONLINEJFS      If this environment variable has a value of "Y" or "y",
+                       the HASONLINEJFS definition will be enabled in the
+                       Makefile CFLAGS.  That will cause dnode1.c to use an
+                       alternate vx_inode.h header file in the hpux11 sub-
+                       directory of dialects/hpux/kmem.
+
+                       default: determined using nm and grep
+
+HPUX_IPC_S_PATCH       If this environment variable has a value of "1", the
+                       ipc_s structure of the HP-UX 11 kernel is assumed to
+                       have an ipc_ipis member, but it is assumed the ipis_s
+                       structure lacks the ipis_msgsqueued member; "2", ipc_s
+                       has ipc_ipis, but ipis_s has ipis_msgsqueued; "n" or
+                       "N", ipc_s lacks ipc_ipis; any other non-NULL value is
+                       considered an error; a NULL value, HPUX_IPC_S_PATCH is
+                       determined by testing.
+
+                       default: determined with q4 and grep
+
+HPUX_KERNBITS          specifies the number of bits (32 or 64) in the HP-UX
+                       11 "basic kernel word.
+
+                       default: `getconf _SC_KERNEL_BITS`
+
+HPUX_LIBC1             specifies the first directory that might contain the
+                       HP-UX C library, libc.sl.
+
+                       default: /usr/lib
+
+HPUX_LIBC2             specifies the second directory that might contain the
+                       HP-UX C library, libc.sl.
+
+                       default: /lib
+
+HPUX_RNODE3            If this environment variable has a value of "1", the
+                       Configure script will define HASRNODE3 in the Makefile
+                       CFGF flags.   If it is defined, but not "1", Configure
+                       will not define HASRNODE2.
+
+                       default: determined using `nm -x /stand/vmunix` and
+                                `grep r_fh3 /usr/include/nfs/rnode.h`
+
+HPUX_X25DIR            specifies path to the HP-UX X25 directory that contains
+                       configuration header files.
+
+                       default: /etc/conf
+
+LINUX_CLIB             specifies the definition of the Linux C library:
+
+                       default: ""             (standard C library)
+                       others: -DGLIBCV=2      (glibc2)
+
+LINUX_CONF_CC          specifies the location of the C compiler to use during
+                       the running of the Configure script:
+
+                       default: the value of the LSOF_CC variable, if defined,
+                                or cc
+
+LINUX_HASSELINUX       If this environment variable has a value of "Y" or "y",
+                       Configure unconditionally activates SELinux support.
+                       If it has any other value, Configure unconditionally
+                       inhibits SELinux suport.
+
+                       Default: assumed to be "Y" if <selinux/selinux.h>
+                                exists
+
+LINUX_INCL             specifies the path to the header file tree:
+
+                       default: /usr/include
+
+LINUX_LSEEK            If this environment variable has a value of "Y" or "y",
+                       Configure uses Makefile.lseek in place of Makefile in
+                       order to enable use of the private lseek() function for
+                       2.1.x kernels; any other non-NULL value, Makefile.lseek
+                       will isn't used; a NULL value, the alternate lseek()
+                       need is determined by compilation.
+
+                       default: determined by test program
+
+LINUX_VERSION_CODE     specifies the value of the LINUX_VERSION_CODE in the
+                       same decimal form as found in the LINUX_VERSION_CODE
+                       #define of /usr/include/linux/version.h:
+
+                       default: the value of LINUX_VERSION_CODE in
+                                /usr/include/linux/version.h
+
+NETBSD_SYS             specifies the path to the NetBSD system source
+                       directory.
+
+                       default: /usr/include
+
+NETBSD_UVM             If this environment variable has a value of "Y" or "y",
+                       the NetBSD system uses the UVM virtual memory system;
+                       any other non-NULL value, it does not; a NULL value,
+                       it will be determined by the contents of /etc/mk.conf.
+
+                       default: tested by grep'ping /etc/mk.conf
+
+OPENBSD_SYS            specifies the path to the OpenBSD system source
+                       directory.
+
+                       default: /sys
+
+OPENBSD_UVM            If this environment variable has a value of "Y" or "y",
+                       the OpenBSD system uses the UVM virtual memory system;
+                       any other non-NULL value, it does not; a NULL value,
+                       it will be determined by examining /bsd.
+
+                       default: tested by grep'ping `nm /bsd` output
+
+
+OSR_CFGF               The value of this environment variable is made the
+                       initial value for the compiler flags the lsof Configure
+                       script constructs for the Makefile CFGF macro.
+
+                       default: ""
+
+OSR_CFGL               The value of this environment variable is made the
+                       initial value for the loader flags the lsof Configure
+                       script constructs for the Makefile CFGL macro.
+
+                       default: ""
+
+OSR_STATLSTAT          If this environment variable has a value of "Y" or "y",
+                       HAS_STATLSTAT is defined in the Makefile's CFGL string;
+                       any other non-NULL value, it's not defined; a NULL
+                       value, it is determined with nm and grep.
+
+                       default: determined with nm and grep
+
+
+SOLARIS_23P101318      If this environment variable has a non-NULL value, the
+                       value is interpreted as the patch level of the Solaris
+                       2.3 P101318 patch.
+
+                       default: pkginfo tested with grep
+
+SOLARIS_24P101945      If this environment variable has a non-NULL value, the
+                       value is interpreted as the patch level of the Solaris
+                       2.4 P101945 patch.
+
+                       default: pkginfo tested with grep
+
+SOLARIS_24P102303      If this environment variable has a non-NULL value, the
+                       value is interpreted as the patch level of the Solaris
+                       2.4 P102303 patch.
+
+                       default: pkginfo tested with grep
+
+SOLARIS_26PR_GWINDOWS  If this environment variable has a value of "Y" or "y",
+                       the HASPR_GWINDOWS definition is set in the Solaris 2.6
+                       and 7 Makefile's CFG string; any other non-NULL value,
+                       it's not set; a NULL value, it's tested by compilation.
+
+                       default: tested by compilation
+
+SOLARIS_26PR_LDT       If this environment variable has a value of "Y" or "y",
+                       the HASPR_LDT definition is set in the Solaris 2.6
+                       Makefile's CFGL string; any other non-NULL value, it's
+                       not set; a NULL value, it's tested by compilation.
+
+                       default: tested by compilation
+
+SOLARIS_CCDIR          specifies the path to the Sun C compiler -- i.e., when
+                       `Configure solariscc` is used.  This is ignored when
+                       LSOF_CC has been specified.
+
+                       default: /opt/SUNWspro/bin
+
+SOLARIS_INSTR          specifies the Sun C compiler target instruction set
+                       when building lsof for a 64 bit kernel -- i.e., when
+                       the Configure abbreviation is "solariscc".  Possible
+                       values include amd64 and sparcv9.  This is ignored when
+                       the Configure abbreviation is "solaris" -- i.e., the
+                       compiler is gcc.
+
+                       default: tested with /bin/isainfo -k
+
+SOLARIS_KERNBITS       specifies the number of bits in the Solaris 7, 8, 9 or
+                       10 kernel: 32 or 64.
+
+                       default: tested with /bin/isainfo -kv
+
+SOLARIS_VSOCK          If this environment variable has a value of "Y" or "y",
+                       the HAS_VSOCK definition is in the Solaris Makefile's
+                       CFGL string; any other non-NULL value, it's not set; a
+                       NULL value, it's tested by compilation.
+
+                       default: tested by compilation
+
+SOLARIS_VXFSINCL       This environment variable defines the path to the
+                       header files of the VxFS 3.4 or greater version.  If
+                       SOLARIS_VXFSINCL is not set, the default is used.
+
+                       default: VxFS < 4.0:
+                                   /opt/VRTSvxfs/include
+                                VxFS 4.0 and above:
+                                   /opt/VRTSfssdk/<version>/include
+
+SOLARIS_VXFSLIB                This environment variable defines the path to the
+                       VxFS 3.4 or greater utility libraries, libvxfsutil.a
+                       (32 bit) and libvxfsutil64.a (64 bit).  If
+                       SOLARIS_VXFSLIB is not set, the default is used.
+
+                       Note:  end SOLARIS_VXFSLIB at the "/lib" component; do
+                              NOT put "/sparcv9" at its end.  The lsof
+                              Configure script will add "/sparcv9" if it is
+                              required; hence, if Configure finds that
+                              "/sparcv9" is needed, your SOLARIS_VXFSLIB
+                              directory tree must have a sparcv9 subdirectory.
+
+                       default: `dirname $SOLARIS_VXFSINCL`/lib
+
+SUN_AFSAPATHDEF                specifies the path to the AFS library modload file
+                       for either Solaris or SunOS.
+
+                       default: /usr/vice/etc/modload/libafs
+                                Verified with ls.
+
+                       Note: the SunOS support is no longer maintained.
+
+UW_HAS_NSC             If this environment variable has a value of "Y" or "y",
+                       lsof will be configured for a UnixWare 7.1.1 or above
+                       NonStop Cluster (NSC) system.
+
+                       default: tested via /bin/node_self
+
+Vic Abell <abe@purdue.edu>
+October 13, 2014
diff --git a/AFSConfig b/AFSConfig
new file mode 100755 (executable)
index 0000000..376eeec
--- /dev/null
+++ b/AFSConfig
@@ -0,0 +1,346 @@
+#!/bin/sh
+#
+# $Id: AFSConfig,v 1.2 99/05/09 14:49:54 abe Exp $
+#
+# AFSConfig: configure for AFS
+
+AFSD=/usr/vice/etc/afsd
+AH=AFSHeaders
+AV=AFSVersion
+STD=/usr/afsws/include
+
+# Establish trap and stty handling.
+
+ISIG=":"
+trap 'rm -f $AH $AV; $ISIG; exit 1'  1 2 3 15
+stty -a 2>&1 | grep isig > /dev/null
+if test $? -eq 0
+then
+  stty -a 2>&1 | grep -E -e -isig > /dev/null
+  if test $? -eq 0
+  then
+    ISIG="stty -isig"
+    stty isig
+  fi
+fi
+
+# Decide how to use echo.
+
+ECHO=$(echo -n "")
+if test "X$ECHO" = "X-n "
+then
+  EC="\c"
+  EO=""
+else
+  EC=""
+  EO="-n"
+fi
+
+# Decide (perhaps for a second time) that AFS is installed.
+
+CELL=""
+if test -r /usr/vice/etc/ThisCell
+then
+  cell=$(awk '{print $1}' /usr/vice/etc/ThisCell)
+  if test -d /afs/$cell
+  then
+    CELL=$cell
+  else
+    CELL=$(echo $cell | sed 's/\([^.]*\)\..*/\1/')
+    if test "X$CELL" != "X"
+    then
+      if test ! -d /afs/$CELL
+      then
+        CELL=""
+      fi
+    fi
+  fi
+fi
+if test "X$CELL" = "X"
+then
+  echo ""
+  echo "This system does not appear to have AFS installed."
+  exit 1
+fi
+
+# See if AFS configuration is wanted.
+
+cat << .CAT_MARK
+
+AFS appears to be installed on this system; cell name "$CELL".
+
+Lsof needs to be configured for AFS by identifying: 1) the directory
+that includes the AFS header files needed to compile AFS support into
+lsof; and 2) the version of AFS that is installed.
+.CAT_MARK
+
+END=0
+while test $END = 0
+do
+  echo ""
+  echo $EO "Do you want to configure lsof for AFS (y|n) [y]? $EC"
+  read ANS EXCESS
+  if test "X$ANS" = "Xn" -o "X$ANS" = "XN"
+  then
+    exit 1
+  fi
+  if test "X$ANS" = "Xy" -o "X$ANS" = "XY" -o "X$ANS" = "X"
+  then
+    END=1
+  else
+    echo ""
+    echo "Please answer y or n."
+  fi
+done
+
+# See if $AH exists and points to a likely place.
+
+AHOK=""
+echo ""
+echo "====================================================================="
+echo ""
+if test -r $AH
+then
+  AHP=$(cat $AH)
+  if test -r $AHP
+  then
+    if test -r $AHP/afs/afs.h
+    then
+      cat << .CAT_MARK
+The location of the AFS header files required by lsof has been
+previously identified as "$AHP".
+
+Since <afs/afs.h> can be found there, that's probably correct.
+.CAT_MARK
+
+      END=0
+      while test $END = 0
+      do
+       echo ""
+       echo $EO "Do you want to use $AHP again (y|n) [y]? $EC"
+       read ANS EXCESS
+       if test "X$ANS" = "Xy" -o "X$ANS" = "XY" -o "X$ANS" = "X"
+       then
+         AHOK="ok"
+         END=1
+       else
+         if test "X$ANS" = "Xn" -o "X$ANS" = "XN"
+         then
+           rm -f $AH
+           AHP=""
+           END=1
+         else
+           echo ""
+           echo "Please answer y or n."
+         fi
+       fi
+      done
+    else
+      echo "\"$AHP\" has been previously specified as the location of the"
+      echo "AFS header files, but it lacks an afs/afs.h header file."
+      rm -f $AH
+      AHP=""
+    fi
+  else
+    echo "The file ./$AH exists, but has no AFS header file path in it."
+    rm -f $AH
+    AHP=""
+  fi
+else
+  echo "No previous header location has been specified."
+  rm -f $AH
+  AHP=""
+fi
+
+# See if the header files are in the "standard" place.
+
+if test "X$AHOK" != "Xok"
+then
+  if test -r $STD
+  then
+    echo ""
+    echo "====================================================================="
+    echo ""
+    echo "The AFS header files appear to be in the \"standard\" location --"
+    echo "i.e.: \"$STD\"."
+    END=0
+    while test $END = 0
+    do
+      echo ""
+      echo $EO "Do you want to let lsof use them (y|n) [y]? $EC"
+      read ANS EXCESS
+      if test "X$ANS" = "Xy" -o "X$ANS" = "XY" -o "X$ANS" = "X"
+      then
+       echo $STD > $AH
+       AHOK="ok"
+       END=1
+      else
+       if test "X$ANS" = "Xn" -o "X$ANS" = "XN"
+       then
+         END=1
+       else
+         echo ""
+         echo "Please answer y or n."
+       fi
+      fi
+    done
+  fi
+fi
+
+# Ask for the AFS header file location.
+
+if test "X$AHOK" != "Xok"
+then
+  echo ""
+  echo "====================================================================="
+  echo ""
+  echo "Please specify the full path where lsof can find the AFS header"
+  echo "files.  A possible location is: \"/afs/$CELL/<sysname>/include\"."
+  cat << .CAT_MARK
+The <sysname> component of the path is the AFS system name that
+was used to configure and build AFS on this system.  It is usually
+constructed from a manufacturer or Unix operating system designation,
+followed by a version number -- e.g., hp800_ux90, sun4m_54, vax_ul43,
+etc.  You may have to consult your AFS documentation to determine
+what <sysname> applies to your configuration.
+.CAT_MARK
+
+  END=0
+  while test $END = 0
+  do
+    echo ""
+    echo $EO "Do you want to see the contents of /afs/$CELL (y|n) [y]? $EC"
+    read ANS EXCESS
+    if test "X$ANS" = "Xn" -o "X$ANS" = "XN"
+    then
+      END=1
+    else
+      if test "X$ANS" = "Xy" -o "X$ANS" = "XY" -o "X$ANS" = "X"
+      then
+       echo ""
+       ls -C /afs/$CELL
+       END=1
+      else
+       echo ""
+       echo "Please answer y or n."
+      fi
+    fi
+  done
+  END=0
+  while test $END = 0
+  do
+    echo ""
+    echo $EO "AFS header file path: $EC"
+    read ANS EXCESS
+    fc=$(expr "${ANS}X" : '\(.\).*')
+    if test "X$fc" = "X/"
+    then
+      if test -r $ANS/afs/afs.h
+      then
+       echo $ANS > $AH
+       AHOK="ok"
+       END=1
+      else
+       echo ""
+       echo "$ANS/afs/afs.h doesn't exist."
+       echo "Please enter a path whose afs subdirectory contains afs.h"
+      fi
+    else
+      echo ""
+      echo "Please enter an absolute path name."
+    fi
+  done
+fi
+if test "X$AHOK" != "Xok"
+then
+  echo "AFSConfig: unknown error"
+  exit 1
+fi
+
+# Determine AFS version.
+
+if test -r $AV
+then
+  echo ""
+  echo "====================================================================="
+  echo ""
+  AVN=$(cat $AV)
+  cat << .CAT_MARK
+The AFS version was previously specified as: $AVN
+.CAT_MARK
+
+  END=0
+  while test $END = 0
+  do
+    echo ""
+    echo $EO "Is this the correct version number (y|n) [y]? $EC"
+    read ANS EXCESS
+    if test "X$ANS" = "Xy" -o "X$ANS" = "XY" -o "X$ANS" = "X"
+    then
+      exit 0
+    fi
+    if test "X$ANS" = "Xn" -o "X$ANS" = "XN"
+    then
+      rm -f $AV
+      END=1
+    else
+      echo "Please answer y or n."
+    fi
+  done
+fi
+
+# See if the version number can be determined.
+
+if test -r $AFSD
+then
+  ANS=$(strings $AFSD | grep "Base configuration afs" | sed 's/^.*ion afs\([^ ]*\) .*/\1/')
+  TV=$(echo $ANS | sed 's/^\([0-9]*\)\.\([0-9]*\)\(.*\)/\1 \2 \3/' | awk '{printf "%d.%d%s\n",$1,$2,$3}')
+  if test "X$ANS" = "X$TV"
+  then
+    echo ""
+    echo "====================================================================="
+    echo ""
+    cat << .CAT_MARK
+Examining $AFSD the AFS version number appears to be: $TV
+.CAT_MARK
+
+    END=0
+    while test $END = 0
+    do
+      echo ""
+      echo $EO "Do you want to use this version number (y/n) [y]? $EC"
+      read ANS EXCESS
+      if test "X$ANS" = "Xn" -o "X$ANS" = "XN"
+      then
+       END=1
+      else
+       if test "X$ANS" = "Xy" -o "X$ANS" = "XY" -o "X$ANS" = "X"
+       then
+         echo $TV > $AV
+         exit 0
+       else
+         echo ""
+         echo "Please answer y or n."
+       fi
+      fi
+    done
+  fi
+fi
+
+# Ask for the version number.
+
+echo ""
+echo "====================================================================="
+END=0
+while test $END = 0
+do
+  echo ""
+  echo $EO "Please enter the AFS version number: $EC"
+  read ANS EXCESS
+  TV=$(echo $ANS | sed 's/^\([0-9]*\)\.\([0-9]*\)\(.*\)/\1 \2 \3/' | awk '{printf "%d.%d%s\n",$1,$2,$3}')
+  if test "X$ANS" = "X$TV"
+  then
+    echo $TV > $AV
+    exit 0
+  fi
+done
diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..279721a
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,26 @@
+Copyright 2002 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.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644 (file)
index 0000000..9c4dd81
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,6 @@
+
+For notes about changes to lsof see the 00DIST file.
+
+
+Vic Abell
+October 19, 2012
diff --git a/Configure b/Configure
new file mode 100755 (executable)
index 0000000..02b444d
--- /dev/null
+++ b/Configure
@@ -0,0 +1,5208 @@
+#!/bin/sh
+#
+# Configure -- configure lsof
+#
+# See the LSOF_HLP here document for usage.
+#
+# See the lsof distribution file 00XCONFIG for information on setting
+# environment variables for cross-configuring lsof -- e.g., for configuring
+# for Linux 2.3 on a machine running 2.4.  Marty Leisner suggested this
+# support and provided the Linux Configure stanza modifications.
+#
+# When configuring for a particular dialect, <target-dialect>, this script
+# requires that the subdirectory ./dialects/<target-dialect> contain a
+# shell script, named $LSOF_MK, that places its source modules in this
+# directory.
+#
+# $Id: Configure,v 1.166 2018/07/14 12:13:52 abe Exp $
+
+# LSOF_CFLAGS_OVERRIDE=1 may be introduced through the environment to cause
+#      the library Makefile's CFLAGS definition to override any in the
+#      environment.
+
+# LSOF_DISTRIBKVM may be introduced through the environment to specify the
+#      Sun4 kernel virtual memory type of distrib.cf
+
+LSOF_F="ddev.c dfile.c dlsof.h dmnt.c dnode*.c dproc.c dproto.h dsock.c dstore.c dzfs.h kernelbase.h machine.h machine.h.old new_machine.h __lseek.s"
+LSOF_HLP_BASE=./cfghlp.
+LSOF_HLP=${LSOF_HLP_BASE}$$
+
+# LSOF_LOCALSUFFIX may be introduced through the environment to select a local
+#      version of a Makefile.  It is used as a suffix to $LSOF_MKF.
+
+# LSOF_MAKE may be introduced through the environment to specify a path to the
+#      make command.   It defaults to `which make`, if that is non-NULL;
+#      otherwise to the string "make".
+
+if test "X$LSOF_MAKE" = "X"    # {
+then
+  LSOF_MAKE=`which make`
+  if test "X$LSOF_MAKE" = "X"  # {
+  then
+    LSOF_MAKE=make
+  fi   # }
+fi     # }
+
+LSOF_MK=Mksrc
+
+# LSOF_MKC is the dialect's Mksrc create command -- default "ln -s".
+
+# LSOF_MKFC may be introduced though the environment to change the name
+# used for the created make file.
+
+if test "X$LSOF_MKFC" = "X"    # {
+then
+  LSOF_MKFC=Makefile
+fi     # }
+
+LSOF_LIB=lib
+LSOF_MKF=Makefile
+LSOF_LIBMKF=Makefile
+LSOF_LIBMKFSKEL=Makefile.skel
+
+LSOF_VF=version
+
+# Make sure no other variable important to Makefile construction is
+# already set in the environment.
+#
+#      $AFS_VICE           locatiion of AFS VICE directory
+#                              (default = /usr/vice)
+#      $LSOF_AFS           AFS temporary
+#      $LSOF_AFS_NQ        AFS-not-qualified flag
+#      $LSOF_AFSV          AFS version
+#      $LSOF_AR            archive command and its arguments for making the
+#                          lsof library
+#      $LSOF_ARCH          Unix dialect architecture as a string (may be
+#                          supplied externally)
+#      $LSOF_CC            C compiler name (may be supplied externally)
+#      $LSOF_CCV           C compiler version (may be supplied externally)
+#      $LSOF_CDIR          configuration directory
+#      $LSOF_CFGD          depend options
+#      $LSOF_CFGDN         depend file name
+#      $LSOF_CFGF          C flags -- e.g., -D's
+#      $LSOF_CFGL          last lsof library loader flags -- e.g., -l's
+#      $LSOF_CINFO         Configure information for LSOF_CINFO in version.h
+#      $LSOF_CTFH          Solaris 10 and above libctf.h status
+#      $LSOF_CTFL          Solaris 10 and above -lctf status
+#      $LSOF_DEBUG         Makefile's DEBUG string
+#      $LSOF_DINC          include flags -- -I's
+#      $LSOF_DINC_ADD      include flags status
+#      $LSOF_DOC           special document (man page) directory path
+#      $LSOF_ERR           internal error flag
+#      $LSOF_FCFGL         first lsof library loader flags -- e.g., -l's
+#                          that must precede $LSOF_LIB
+#      $LSOF_FBSD_ZFS      FreeBSD $LSOF_FBSD_ZFS_MKF status
+#      $LSOF_FBSD_ZFS_CFGF FreeBSD ZFS configure flags
+#      $LSOF_FBSD_ZFS_MKF  FreeBSD ZFS Makefile name
+#      $LSOF_FBSD_ZFS_SYS  FreeBSD ZFS system sources location
+#      $LSOF_HOST          host name (e.g., from uname -n)
+#      $LSOF_INCLUDE       directory where header files are found
+#                          (default = /usr/include)
+#      $LSOF_LD            loader name if not $LSOF_CC
+#      $LSOF_LIB_NO        if "N" don't configure the lsof library
+#      $LSOF_LOCALSUFFIX   local suffix for Makefile
+#      $LSOF_NBSD_BUFQH    NetBSD <sys/bufq.h> copy status
+#      $LSOF_NBSD_PTYFS    NetBSD ${NETBSD_SYS}/sys/fs/ptyfs/ copy status
+#      $LSOF_N_UNIXV       *BSD system's kernel file
+#      $LSOF_OPINC         supplies additional -I/path arguments for the
+#                          Makefile's CFLAGS.
+#      $LSOF_PL            patch level
+#      $LSOF_RANLIB        randomizing command for the lsof library
+#      $LSOF_RANLIB_SUP    if non-NULL $LSOF_RANLIB was supplied
+#      $LSOF_SCRIPT_CALL   Customize and Inventory scripts call status
+#      $LSOF_SPMKF         Special Makefile name
+#      $LSOF_TGT           canonical target abbreviation (shortest)
+#      $LSOF_TMP           internal temporary
+#      $LSOF_TMP1          internal temporary
+#      $LSOF_TMP2          internal temporary
+#      $LSOF_TMP3          internal temporary
+#      $LSOF_TMP4          internal temporary
+#      $LSOF_TMP5          internal temporary
+#      $LSOF_TMP6          internal temporary
+#      $LSOF_TMPC_BASE     base name for $LSOF_TMPC
+#      $LSOF_TMPC          temporary C source file base name
+#      $LSOF_TSTBIGF       big file capability (for $LSOF_TSTCFLG)
+#      $LSOF_TSTCC         tests CC file
+#      $LSOF_TSTCFLG       tests CFLAGS file
+#      $LSOF_TSTDFLG       dialect-specific values for $LSOF_TSTCFLG
+#      $LSOF_TSTK64        status of 64 bit kernel (for $LSOF_TSTCFLG)
+#      $LSOF_TSTKMEM       /dev/kmem usage status (for $LSOF_TSTCFLG)
+#      $LSOF_TSTLFF        tests LDFLAGS file
+#      $LSOF_TSTLFLG       tests LDFLAGS values
+#      $LSOF_TSTSUBD       test subdirectory
+#      $LSOF_TSTVPATH      test v_path state (for $LSOF_TSTCFLG)
+#      $LSOF_TSTXO         test extra objects (for $LSOF_TSTXOC)
+#      $LSOF_TSTXOC        test extra objects file
+#      $LSOF_UNSUP         Lsof is unsupported on this dialect
+#      $LSOF_UNSUP2        Second message about lack of support
+#      $LSOF_VERS          Unix dialect version as a decimal number (may
+#                          be supplied externally)
+#      $LSOF_VSTR          Unix dialect version as a string -- may be supplied
+#                          externally
+
+if test "X$AFS_VICE" = "X"     # {
+then
+  AFS_VICE="/usr/vice"
+fi     # }
+LSOF_AFS=""
+LSOF_AFS_NQ=""
+LSOF_AFSV=""
+if test "X$LSOF_ARCH" = "X"    # {
+then
+  LSOF_ARCH=""
+fi     # }
+LSOF_CDIR=""
+LSOF_CFGD=""
+LSOF_CFGDN=""
+LSOF_CINFO=""
+LSOF_CTFH=0
+LSOF_CTFL=0
+LSOF_DEBUG=""
+LSOF_DOC=""
+LSOF_ERR=""
+LSOF_FCFGL=""
+LSOF_FBSD_ZFS=0
+LSOF_FBSD_ZFS_CFGF=""
+LSOF_FBSD_ZFS_MKF="Makefile.zfs"
+LSOF_FBSD_ZFS_SYS=""
+LSOF_HOST=""
+if test "X$LSOF_INCLUDE" = "X" # {
+then
+  LSOF_DINC=""
+  LSOF_INCLUDE="/usr/include"
+else
+  LSOF_DINC="-I$LSOF_INCLUDE"
+fi     # }
+LSOF_LD=""
+LSOF_LIB_NO=""
+LSOF_PL=""
+if test "X$LSOF_RANLIB" = "X"  # {
+then
+  LSOF_RANLIB="ranlib"
+  LSOF_RANLIB_SUP=""
+else
+  LSOF_RANLIB_SUP="Y"
+fi     # }
+LSOF_SCRIPT_CALL="yes"
+LSOF_SPMKF=""
+LSOF_TMP1=""
+LSOF_TMP2=""
+LSOF_TMPC_BASE=./lsof_Configure_tmp_
+LSOF_TMPC=${LSOF_TMPC_BASE}$$
+LSOF_TSTBIGF=""
+LSOF_TSTSUBD="./tests"
+LSOF_TSTCC="${LSOF_TSTSUBD}/config.cc"
+LSOF_TSTCFLG="${LSOF_TSTSUBD}/config.cflags"
+LSOF_TSTDFLG=""
+LSOF_TSTK64=0
+LSOF_TSTKMEM=1
+LSOF_TSTLFF="${LSOF_TSTSUBD}/config.ldflags"
+LSOF_TSTLFLG=""
+LSOF_TSTVPATH=0
+LSOF_TSTXO=""
+LSOF_TSTXOC="${LSOF_TSTSUBD}/config.xobj"
+LSOF_UNSUP="WARNING: unsupported dialect or version"
+LSOF_UNSUP2=""
+if test "X$LSOF_VERS" = "X"    # {
+then
+  LSOF_VERS=""
+fi     # }
+if test "X$LSOF_VSTR" = "X"    # {
+then
+  LSOF_VSTR=""
+fi     # }
+
+# Establish echo type -- Berkeley or SYSV.
+
+j=`echo -n ""`
+if test "X$j" = "X-n "
+then
+  EC="\c"
+  EO=""
+else
+  EC=""
+  EO="-n"
+fi
+
+# Make sure temporary files are removed before an abnormal exit.
+
+trap 'rm -f ${LSOF_HLP_BASE}* ${LSOF_TMPC_BASE}*; exit 1' 1 2 3 15
+
+rm -f $LSOF_HLP
+cat > $LSOF_HLP << LSOF_HLP
+Usage: Configure <options> <target-dialect>
+  <options>:  -clean        : clean up previous configuration
+              -d|-dialects  : display a list of supported dialect versions
+              -h|-help      : display help information
+              -n            : avoid AFS, customization, and inventory checks
+  <target-dialect> (****USE -d TO GET TESTED DIALECT VERSION NUMBERS****):
+    aix|aixgcc              : IBM AIX xlc (aix) or gcc (aixgcc)
+    darwin                  : Apple Darwin
+    freebsd                 : FreeBSD
+    hpux|hpuxgcc            : HP-UX cc (hpux) or gcc (hpuxgcc)
+    linux                   : Linux
+    netbsd                  : NetBSD
+    openbsd                 : OpenBSD
+    osr|sco                 : SCO OpenServer < 6.0.0, SCO devloper's compiler
+    osrgcc|scogcc           : SCO OpenServer < 6.0.0, gcc compiler
+    osr6                    : SCO OpenServer 6.0.0, SCO compiler
+    solaris|solariscc       : Solaris gcc (solaris) or cc (solariscc)
+    unixware|uw             : SCO|Caldera UnixWare
+LSOF_HLP
+
+LSOF_TGT="no-target"
+
+args=$#
+while test $args -gt 0 # {
+do
+  case $1 in   # {
+    -clean)
+      if test -r $LSOF_MKFC    # {
+      then
+       echo "$LSOF_MAKE -f $LSOF_MKFC clean"
+       $LSOF_MAKE -f $LSOF_MKFC clean
+      else
+       if test -r ${LSOF_LIB}/${LSOF_LIBMKF}   # {
+       then
+         echo "(cd ${LSOF_LIB}; $LSOF_MAKE -f ${LSOF_LIBMKF} clean)"
+         (cd ${LSOF_LIB}; $LSOF_MAKE -f ${LSOF_LIBMKF} clean)
+       else
+         if test -r ${LSOF_LIB}/${LSOF_LIBMKF}.skel    # {
+         then
+           echo "(cd ${LSOF_LIB}; $LSOF_MAKE -f ${LSOF_LIBMKF}.skel clean)"
+           (cd ${LSOF_LIB}; $LSOF_MAKE -f ${LSOF_LIBMKF}.skel clean)
+         fi    # }
+       fi      # }
+      fi       # }
+      if test -r ${LSOF_TSTSUBD}/Makefile      # {
+      then
+       echo "(cd ${LSOF_TSTSUBD}; $LSOF_MAKE spotless)"
+       (cd ${LSOF_TSTSUBD}; $LSOF_MAKE spotless)
+      else
+       echo '(cd ${LSOF_TSTSUBD}; rm *.o config.*)'
+       (cd ${LSOF_TSTSUBD}; rm *.o config.*)
+      fi       # }
+      rm -f $LSOF_F $LSOF_MKFC $LSOF_FBSD_ZFS_MKF ${LSOF_TMPC_BASE}*
+      echo rm -f $LSOF_F $LSOF_MKFC $LSOF_FBSD_ZFS_MKF ${LSOF_TMPC_BASE}*
+      rm -rf AFSHeaders AFSVersion solaris11 version.h vnode_if.h
+      echo "rm -rf AFSHeaders AFSVersion solaris11 version.h vnode_if.h"
+      rm -f ${LSOF_HLP_BASE}* cd9660_node.h lockf_owner.h fbsd_minor.h
+      echo "rm -f ${LSOF_HLP_BASE}* cd9660_node.h lockf_owner.h fbsd_minor.h"
+      rm -f opt_kdtrace.h opt_random.h
+      echo "rm -f opt_kdtrace.h opt_random.h"
+      rm -f lib/dialects/aix/aix5/j2/j2_snapshot.h
+      echo "rm -f lib/dialects/aix/aix5/j2/j2_snapshot.h"
+      rm -f dialects/sun/solaris10     # DEBUG -- for s10_44
+      echo "rm -f dialects/sun/solaris10"      # DEBUG -- for s10_44
+      rm -f dialects/hpux/kmem/hpux_mount.h
+      echo "rm -f dialects/hpux/kmem/hpux_mount.h"
+      rm -rf lib/dialects/netbsd/include
+      echo "rm -rf lib/dialects/netbsd/include"
+      rm -f dialects/uw/uw7/vm/swap.h
+      echo "rm -f dialects/uw/uw7/vm/swap.h"
+      rm -f ${LSOF_LIB}/${LSOF_LIBMKF}
+      echo "rm -f ${LSOF_LIB}/${LSOF_LIBMKF}"
+      exit 0
+      ;;
+
+    -d|-dialects)
+      if test -r ./00DIALECTS -a -r ./version  # {
+      then
+       V=`sed '/VN/s/.ds VN \(.*\)/\1/' version`
+       echo "lsof $V has been *tested* on these UNIX dialect versions:"
+       cat 00DIALECTS
+       echo Although "$V hasn't been tested on other versions of these dialects,"
+       echo "it may work.  Try \`Configure <dialect>\` and \`make\` to see."
+       rm -f $LSOF_HLP
+       exit 0
+      else
+       echo "Can't display UNIX dialect version information:"
+       if test ! -r ./00DIALECTS       # {
+       then
+         echo "        ./00DIALECTS is inaccessible."
+       fi      # }
+       if test ! -r ./version  # {
+       then
+         echo "        ./version is inaccessible."
+       fi      # }
+       rm -f $LSOF_HLP
+       exit 1
+      fi       # }
+      ;;
+
+    -h|-help) cat $LSOF_HLP
+      rm -f $LSOF_HLP
+      exit 0
+      ;;
+
+    -n*)
+      LSOF_SCRIPT_CALL="no"
+      ;;
+
+    *)
+      if test "X$LSOF_TGT" != "Xno-target"     # {
+      then
+       echo "Only one dialect may be configured at a time."
+       echo 'Both "$LSOF_TGT" and "$1" were specified.'
+       cat $LSOF_HLP
+       rm -f $LSOF_HLP
+       exit 1
+      else
+       LSOF_TGT=$1
+      fi       # }
+      ;;
+  esac # }
+  shift
+  args=`expr $args - 1`
+done   # }
+
+case $LSOF_TGT in      # {
+ no-target)
+   echo "No target dialect was specified."
+   cat $LSOF_HLP
+   rm -f $LSOF_HLP
+   exit 1
+   ;;
+
+# Configure for AIX xlc and AIX gcc.
+
+  aix|aixgcc)
+
+  # AIXA stands for AIX architecture.  It is assigned these values in this
+  # stanza:
+  #
+  #    0       The AIX version is < 5.0, or the AIX 5.0 architecture is
+  #            Power and the kernel bit size is 32.
+  #
+  #    1       The AIX version is >= 5.0, the AIX architecture is Power,
+  #            and the kernel bit size is 64.
+  #
+  #    2       The AIX version is >= 5.0 and the architecture is IA64.
+
+    if test "X$LSOF_RANLIB_SUP" = "X"  # {
+    then
+      LSOF_RANLIB="@echo \\\\\\\\c"    # AIX make doesn't like a null ${RANLIB}.
+    fi # }
+    if test "X$LSOF_VSTR" = "X"        # {
+    then
+
+      # If the AIX version isn't pre-defined, determine it.
+
+      LSOF_TMP1=`uname -v`
+      if test "X$LSOF_TMP1" = "X5"     # {
+      then
+
+       # If the AIX version is 5, build the version string with `uname -rv`
+       # output.
+
+         LSOF_VSTR=`uname -r | awk '{printf "5.%d.0.0\n",\$1}'`
+         echo "Uname reports the version is $LSOF_VSTR."
+      else
+
+       # See if oslevel can determine the version.
+
+       LSOF_TMP1=/usr/bin/oslevel
+       if test -x $LSOF_TMP1   # {
+       then
+         echo "Determining AIX version with $LSOF_TMP1."
+         echo "This may take a while, depending on your maintenance level."
+         LSOF_VSTR=`$LSOF_TMP1 | sed 's/[^0-9]*\([0-9\.]*\).*/\1/'`
+         echo "$LSOF_TMP1 reports the version is $LSOF_VSTR."
+       else
+
+         # If oslevel can't be used, build the version string with
+         # `uname -rv` and issue a warning.
+
+         LSOF_VSTR=`uname -rv | awk '{printf "%d.%d.0.0\n",\$2,\$1}'`
+         echo "WARNING: can't execute $LSOF_TMP1; uname -rv reports"
+         echo "         the version is $LSOF_VSTR; edit CFGF in Makefile and"
+         echo "         lib/Makefile to refine AIXV and LSOF_VSTR."
+       fi      # }
+      fi       # }
+    fi # }
+    if test "X$LSOF_VERS" = "X"        # {
+    then
+      LSOF_VERS=`echo $LSOF_VSTR | sed 's/\.//g'`
+    fi # }
+    if test $LSOF_VERS -ge 4320        # {
+    then
+      LSOF_TSTBIGF=" "
+    fi # }
+    if test "X$LSOF_CC" = "X"  # {
+    then
+      if test "X$LSOF_TGT" = "Xaixgcc" # {
+      then
+       LSOF_CC=gcc
+       LSOF_CCV=`$LSOF_CC -v 2>&1 | sed -n 's/.*version \(.*\)/\1/p'`
+      else
+       LSOF_CC=cc
+      fi       # }
+    fi # }
+    LSOF_TGT="aix"
+    echo $LSOF_CC | grep gcc > /dev/null
+    if test $? -eq 0   # {
+    then
+
+    # Prevent use of gcc for AIX below 4.1.
+
+      if test $LSOF_VERS -lt 4100      # {
+      then
+       echo "********************************************************"
+       echo "* Sorry, but gcc can't be used to compile lsof for AIX *"
+       echo "* versions less than 4.1, because of possible kernel   *"
+       echo "* structure alignment differences between it and xlc.  *"
+       echo "********************************************************"
+       rm -f $LSOF_HLP
+       exit 1
+      fi       # }
+    fi # }
+
+    # Test for AFS.
+
+    if test "X$AIX_HAS_AFS" != "X"     # {
+    then
+      LSOF_AFS=$AIX_HAS_AFS
+    fi # }
+    if test "X$LSOF_AFS" != "Xno"      # {
+    then
+      if test "X$LSOF_AFS" = "Xyes" -o -r ${AFS_VICE}/etc/ThisCell     # {
+      then
+       if test "X$LSOF_AFS" != "Xyes"  # {
+       then
+         if test "X$LSOF_SCRIPT_CALL" = "Xno"  # {
+         then
+           if test -r ./AFSHeaders -a -r ./AFSVersion  # {
+           then
+             LSOF_AFS="yes"
+           fi  # }
+         else
+           if test ! -x ./AFSConfig    # {
+           then
+             echo "Can't find or execute the AFSConfig script"
+             rm -f $LSOF_HLP
+             exit 1
+           fi  # }
+           ./AFSConfig
+           if test $? -eq 0 -a -r ./AFSHeaders -a -r ./AFSVersion      # {
+           then
+             LSOF_AFS="yes"
+           fi  # }
+         fi    # }
+       fi      # }
+       if test "X$LSOF_AFS" = "Xyes"   # {
+       then
+         if test "X$LSOF_AFSV" = "X"   # {
+         then
+           if test -r ./AFSVersion     # {
+           then
+             LSOF_AFSV=`cat ./AFSVersion | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1 \2/' | awk '{printf "%d%02d\n",\$1,\$2}'`
+           else
+             echo "!!!FATAL: no ./AFSVersion file.  It should have been"
+             echo "          created by a previous AFS configuration run."
+             rm -f $LSOF_HLP
+             exit 1
+           fi  # }
+         fi    # }
+         if test $LSOF_VERS -gt 4330 -o LSOF_AFSV -gt 305      # {
+         then
+           echo "!!!FATAL: Lsof does not support AFS on this combination of"
+           echo "          AIX ($LSOF_VERS) and AFS ($LSOF_AFSV) versions."
+           echo "          To disable AFS, set the value of the AIX_HAS_AFS"
+           echo "          environment variable to \"no\"."
+           rm -f $LSOF_HLP
+           exit 1
+         else
+           LSOF_CFGF="$LSOF_CFGF -DHAS_AFS=$LSOF_AFSV"
+           LSOF_DINC="$LSOF_DINC -I`cat ./AFSHeaders`"
+           if test -r ${LSOF_INCLUDE}/sys/inttypes.h  # {
+           then
+             grep "^typedef.*int16;" ${LSOF_INCLUDE}/sys/inttypes.h > /dev/null
+             if test $? -eq 0      # {
+             then
+               LSOF_CFGF="$LSOF_CFGF -DHASINT16TYPE"
+             fi    # }
+             grep "^typedef.*u_int32;" ${LSOF_INCLUDE}/sys/inttypes.h > /dev/null
+             if test $? -eq 0      # {
+             then
+               LSOF_CFGF="$LSOF_CFGF -DHASUINT16TYPE"
+             fi    # }
+             grep "^typedef.*int32;" ${LSOF_INCLUDE}/sys/inttypes.h > /dev/null
+             if test $? -eq 0      # {
+             then
+               LSOF_CFGF="$LSOF_CFGF -DHASINT32TYPE"
+             fi    # }
+           fi  # }
+         fi      # }
+       fi      # }
+      fi       # }
+    fi # }
+
+    # Miscellaneous AIX tests
+
+    if test -d ${LSOF_INCLUDE}/nfs     # {
+    then
+      LSOF_CFGF="$LSOF_CFGF -DHAS_NFS"
+    fi # }
+    echo $LSOF_CC | grep cc | grep -v gcc > /dev/null
+    if test $? -eq 0 -a $LSOF_VERS -ge 4140 -a $LSOF_VERS -lt 5000     # {
+    then
+      LSOF_CFGL="$LSOF_CFGL -bnolibpath"
+    fi # }
+    if test -r ${LSOF_INCLUDE}/sys/socket.h    # {
+    then
+      grep AF_INET6 ${LSOF_INCLUDE}/sys/socket.h > /dev/null
+      if test $? -eq 0 # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -DHASIPv6"
+      fi       # }
+    fi # }
+    if test -r ${LSOF_INCLUDE}/sys/stat.h      # {
+    then
+      grep stat64 ${LSOF_INCLUDE}/sys/stat.h > /dev/null
+      if test $? -eq 0 # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -DHASSTAT64"
+      fi       # }
+    fi # }
+#DEBUG SANFS    if test -r ${LSOF_INCLUDE}/sys/sanfs/sanfsnode.h???    # {
+#DEBUG SANFS    then
+#DEBUG SANFS      LSOF_CFGF="$LSOF_CFGF -DHAS_SANFS"
+#DEBUG SANFS    fi     # }
+    if test $LSOF_VERS -ge 5000        # {
+    then
+
+    # This is AIX 5 or greater.
+
+      if test -d ${LSOF_INCLUDE}/j2    # {
+      then
+
+      # The AIX > 5.0 system has jfs2 support.  Make the necesssary definitions
+      # and adjustments.
+
+       rm -f lib/dialects/aix/aix5/j2/j2_snapshot.h
+       (cd lib/dialects/aix/aix5/j2; ln -s private_j2_snapshot.h j2_snapshot.h)
+       LSOF_CFGF="$LSOF_CFGF -DHAS_JFS2"
+       LSOF_CFGF="$LSOF_CFGF -I`pwd`/lib/dialects/aix/aix5"
+       if test $LSOF_VERS -ge 5200     # {
+       then
+         if test -r ${LSOF_INCLUDE}/j2/j2_snapshot.h   # {
+         then
+
+         # The system has its own j2_snapshot.h, so make sure the
+         # private lsof copy is discarded.
+
+           rm -f lib/dialects/aix/aix5/j2/j2_snapshot.h
+         fi    # }
+         echo $LSOF_CC | grep gcc > /dev/null
+         if test $? -eq 0      # {
+         then
+
+         # Test gcc version for AIX 5.2.
+
+           LSOF_TMP1=`echo $LSOF_CCV | awk -F . '{printf "%d%02d",$1,$2}'`
+           if test $LSOF_TMP1 -ge 303  # {
+           then
+
+           # Add gcc >= 3.3 option to handle use of i_dev from the wInode
+           # anonymous structure reference in the JFS2 inode structure of
+           # <j2/j2_inode.h>.
+
+             LSOF_CFGF="$LSOF_CFGF -fms-extensions"
+           fi  # }
+         fi    #}
+       fi      # }
+      fi       # }
+
+      # Determine the AIX architecture type and set AIXA accordingly.
+
+      if test "X$AIX_ARCH" = "X"       # {
+      then
+       uname -a | grep -i ia64 > /dev/null
+       if test $? -eq 0        # {
+       then
+         AIX_ARCH="ia64"
+       else
+         AIX_ARCH=""
+       fi      # }
+      fi       # }
+      if test "X$AIX_ARCH" = "Xia64"   # {
+      then
+
+      # This is AIX >= 5 on ia64.
+
+       LSOF_TSTK64=1
+       echo $LSOF_CC | grep gcc > /dev/null
+       if test $? -eq 0        # {
+       then
+
+       # Quit if gcc was specified as the compiler, since the gcc options to
+       # do an ia64 lsof compilation are unknown.
+
+         echo "*************************************************************"
+         echo "*                                                           *"
+         echo "* !!!!!!!!!!!!!!!!!!!!! FATAL ERROR !!!!!!!!!!!!!!!!!!!!!!! *"
+         echo "*                                                           *"
+         echo "* Gcc can't be used to compile lsof for AIX 5 and above on  *"
+         echo "* the ia64 architecture.  Consult lsof's FAQ (in the file   *"
+         echo "* 00FAQ) for more information.                              *"
+         echo "*                                                           *"
+         echo "*************************************************************"
+         rm -f $LSOF_HLP
+         exit 1
+       fi      # }
+       LSOF_TMP1=2
+       if test "X$LSOF_AR" = "X"       # {
+       then
+         LSOF_AR="/usr/bin/ar cr"
+       fi      # }
+       LSOF_CFGF="$LSOF_CFGF -q64"
+       LSOF_CFGL="$LSOF_CFGL -lelf"
+      else
+
+      # This is AIX >= 5 on Power architecture.
+
+       echo $LSOF_CC | grep cc | grep -v gcc > /dev/null
+       if test $? -eq 0        # {
+       then
+         LSOF_CFGL="$LSOF_CFGL -bnolibpath"
+       fi      # }
+       if test "X$AIX_KERNBITS" = "X"  # {
+       then
+
+       # The kernel bit size wasn't predefined.  Determine it by compiling
+       # and executing a test program.
+
+         rm -f ${LSOF_TMPC}.*
+         echo "#include <sys/systemcfg.h>" > ${LSOF_TMPC}.c
+         echo 'int main(){ if (__KERNEL_32()) printf("32\\n");' >> ${LSOF_TMPC}.c
+         echo 'else if (__KERNEL_64()) printf("64\\n");' >> ${LSOF_TMPC}.c
+         echo 'else printf("0\\n");' >> ${LSOF_TMPC}.c
+         echo "return(0); }" >> ${LSOF_TMPC}.c
+         echo "Testing kernel bit size with $LSOF_CC"
+         $LSOF_CC ${LSOF_TMPC}.c -o ${LSOF_TMPC}.x
+         if test ! -x ${LSOF_TMPC}.x   # {
+         then
+           echo "!!!FATAL: can't compile test program, ${LSOF_TMPC}.c."
+           rm -f $LSOF_HLP rm -f ${LSOF_TMPC}.*
+           exit 1
+         fi    # }
+         AIX_KERNBITS=`./${LSOF_TMPC}.x`
+         rm -f ${LSOF_TMPC}.*
+       fi      # }
+
+      # Use the kernel bit size specification to select archiver and compiler
+      # options, and to update AIXA.
+
+       case $AIX_KERNBITS in   # {
+       32)
+         if test "X$LSOF_AR" = "X"     # {
+         then
+           LSOF_AR="/usr/bin/ar cr"
+         fi    # }
+         LSOF_TMP1=0
+         ;;
+       64)
+         if test "X$LSOF_AR" = "X"     # {
+         then
+           LSOF_AR="/usr/bin/ar -X 64 -v -q"
+         fi    # }
+         LSOF_TSTK64=1
+         LSOF_TMP1=1
+         echo $LSOF_CC | grep gcc > /dev/null
+         if test $? -eq 0      # {
+         then
+           LSOF_CFGF="$LSOF_CFGF -maix64"
+         else
+           LSOF_CFGF="$LSOF_CFGF -q64"
+         fi    # }
+         ;;
+       *)
+         echo "!!!FATAL: unrecognized kernel bit size: $AIX_KERNBITS"
+         rm -f $LSOF_HLP
+         exit 1
+       esac    # }
+
+      # Put kernel bit size information in $LSOF_CINFO and $LSOF_CFGF.
+
+       echo "Kernel bit size: $AIX_KERNBITS"
+       LSOF_TMP2="${AIX_KERNBITS} bit kernel"
+       if test "X$LSOF_CINFO" != "X"   # {
+       then
+         LSOF_CINFO="${LSOF_CINFO}  ${LSOF_TMP2}"
+       else
+         LSOF_CINFO="${LSOF_TMP2}"
+       fi      # }
+       LSOF_CFGF="$LSOF_CFGF -DAIX_KERNBITS=${AIX_KERNBITS}"
+      fi       # }
+      LSOF_CFGF="$LSOF_CFGF -DAIXA=$LSOF_TMP1"
+      if test "X$LSOF_TSTDFLG" = "X"   # {
+      then
+       LSOF_TSTDFLG="-DLT_AIXA=$LSOF_TMP1"
+      else
+       LSOF_TSTDFLG="$LSOF_TSTDFLG -DLT_AIXA=$LSOF_TMP1"
+      fi       # }
+    else
+
+    # AIX is < 5, so set AIXA accordingly.
+
+      LSOF_CFGF="$LSOF_CFGF -DAIXA=0"
+      if test "X$LSOF_TSTDFLG" = "X"   # {
+      then
+       LSOF_TSTDFLG="-DLT_AIXA=0"
+      else
+       LSOF_TSTDFLG="$LSOF_TSTDFLG -DLT_AIXA=0"
+      fi       # }
+    fi #}
+    LSOF_CFGF="$LSOF_CFGF -DAIXV=$LSOF_VERS"
+    LSOF_DIALECT_DIR=aix
+    echo $LSOF_CC | grep gcc > /dev/null
+    if test $? -eq 0   # {
+    then
+
+    # Do gcc tests.
+
+      if test $LSOF_VERS -ge 4100 -a $LSOF_VERS -lt 4200       # {
+      then
+       if test "X$AIX_USHACK" = "X"    # {
+       then
+
+         # Compile and run a gcc test program to evaluate the user structure.
+
+         rm -f ${LSOF_TMPC}.*
+         echo "#include <stddef.h>" > ${LSOF_TMPC}.c
+         echo "#include <sys/user.h>" >> ${LSOF_TMPC}.c
+         echo "int main(){exit((offsetof(struct user, U_irss) & 0x7) ? 1 : 0);}" >>${LSOF_TMPC}.c
+         echo "Testing user.h with $LSOF_CC"
+         $LSOF_CC ${LSOF_TMPC}.c -o ${LSOF_TMPC}.x
+         if ! ${LSOF_TMPC}.x   # {
+         then
+           LSOF_TMP1=1
+         else
+           LSOF_TMP1=0
+         fi    # }
+         rm -f ${LSOF_TMPC}.*
+       else
+         if test "$AIX_USHACK" = "Y" -o "$AIX_USHACK" = "y"    # {
+         then
+           LSOF_TMP1=1
+         else
+           LSOF_TMP1=0
+         fi    # }
+       fi      # }
+       if test ${LSOF_TMP1} -eq 1      # {
+       then
+         echo "Applying gcc AIX 4.1+ user struct alignment hack"
+         rm -rf ./dialects/aix/aix$LSOF_VERS
+         mkdir ./dialects/aix/aix$LSOF_VERS
+         mkdir ./dialects/aix/aix${LSOF_VERS}/sys
+           sed 's/U_irss\[/dummy_for_alignment, U_irss\[/' < ${LSOF_INCLUDE}/sys/user.h > ./dialects/aix/aix${LSOF_VERS}/sys/user.h
+           LSOF_CFGF="$LSOF_CFGF -U_LONG_LONG -I`pwd`/dialects/aix/aix$LSOF_VERS"
+       fi      # }
+      fi       # }
+    else
+
+      # Get xlc version number
+
+      rm -f ${LSOF_TMPC}.*
+      echo "int main(){}" > ${LSOF_TMPC}.c
+      echo "Getting version number of ${LSOF_CC}."
+      $LSOF_CC -c ${LSOF_TMPC}.c -I${LSOF_INCLUDE} -o ${LSOF_TMPC}.o -qlist > /dev/null 2>&1
+      LSOF_CCV=`head -1 ${LSOF_TMPC}.lst | sed 's/\(.*\) ---.*/\1/'`
+      rm ${LSOF_TMPC}.*
+      echo "The version is \"${LSOF_CCV}\"."
+      echo $LSOF_CCV | grep "Version [0-9]" > /dev/null
+      if test $? -eq 0 # {
+      then
+       LSOF_TMP=`echo $LSOF_CCV | sed 's/.*Version \([0-9]*\).*/\1/'`
+       if test "X$LSOF_TMP" != "X" -a $LSOF_TMP -ge 4    # {
+       then
+         if test $LSOF_TMP -ge 6       # {
+         then
+           LSOF_CFGF="$LSOF_CFGF -qmaxmem=-1"
+         else
+           LSOF_CFGF="$LSOF_CFGF -qmaxmem=16384"
+         fi    # }
+       fi      # }
+      fi       # }
+    fi # }
+    if test $LSOF_VERS -ge 5300        # {
+    then
+      LSOF_UNSUP=""
+    fi # }
+    ;;
+
+# Configure for Apple Darwin.
+
+  darwin)
+    if test "X$LSOF_CC" = "X"  # {
+    then
+      LSOF_CC=cc
+      LSOF_CCV=`$LSOF_CC -v 2>&1 | sed -n 's/.*version \(.*\)/\1/p'`
+    fi # }
+    if test "X$LSOF_VSTR" = "X"        # {
+    then
+      LSOF_VSTR=`uname -r`
+    fi # }
+    if test "X$LSOF_VERS" = "X"        # {
+    then
+
+    # If the Darwin / Mac OS X version isn't pre-defined, determine it.
+
+      case $LSOF_VSTR in       # {
+      1.2*)
+       LSOF_VERS=120
+       ;;
+      1.3*)
+       LSOF_VERS=130
+       ;;
+      1.4*)
+       LSOF_VERS=140
+       ;;
+      5.[012]*)
+       LSOF_VERS=500
+       ;;
+      5.[3-9]*)
+       LSOF_VERS=530
+       ;;
+      6.*)
+       LSOF_VERS=600
+       ;;
+      7.*)                     # Mac OS X 10.3 (Panther)
+       LSOF_VERS=700
+       ;;
+      8.*)                     # Mac OS X 10.4 (Tiger)
+       LSOF_VERS=800
+       ;;
+      9.*)                     # Mac OS X 10.5 (Leopard)
+       LSOF_VERS=900
+       ;;
+      10.*)                    # Mac OS X 10.6 (SnowLeopard)
+       LSOF_VERS=1000
+       ;;
+      11.*)                    # Mac OS X 10.7 (Lion)
+       LSOF_VERS=1100
+       ;;
+      12.*)                    # Mac OS X 10.8 (Mountain Lion)
+       LSOF_VERS=1200
+       ;;
+      13.*)                    # Mac OS X 10.9 (Mavericks)
+       LSOF_VERS=1300
+       ;;
+      14.*)                    # Mac OS X 10.10 (Yosemite)
+       LSOF_VERS=1400
+       ;;
+      15.*)                    # Mac OS X 10.11 (El Capitan)
+       LSOF_VERS=1500
+       ;;
+      16.*)                    # macOS 10.12 (Sierra)
+       LSOF_VERS=1600
+       ;;
+      17.*)                    # macOS 10.13 (High Sierra)
+       LSOF_VERS=1700
+       ;;
+      18.*)                    # macOS 10.14 (Mojave)
+       LSOF_VERS=1800
+       ;;
+      19.*)                    # macOS 10.15 (Catalina)
+       LSOF_VERS=1900
+       ;;
+      *)
+       echo Unknown Darwin release: `uname -r`
+       echo Assuming Darwin 19.0
+       LSOF_VERS=1900
+       ;;
+      esac     # }
+    fi # }
+
+    # Do Darwin version-specific stuff.
+
+    case $LSOF_VERS in # {
+    120|130)
+      LSOF_TMP1="hfs/hfs.h hfs/hfs_macos_defs.h miscfs/devfs/devfsdefs.h miscfs/devfs/devfs_proto.h miscfs/fdesc/fdesc.h"
+      ;;
+    140|500)
+      LSOF_TMP1="hfs/hfs.h hfs/hfs_macos_defs.h hfs/rangelist.h miscfs/devfs/devfsdefs.h miscfs/devfs/devfs_proto.h miscfs/fdesc/fdesc.h"
+      ;;
+    530)
+      LSOF_TMP1="hfs/hfs.h hfs/hfs_macos_defs.h hfs/rangelist.h miscfs/devfs/devfsdefs.h miscfs/devfs/devfs_proto.h miscfs/fdesc/fdesc.h net/ndrv.h net/ndrv_var.h"
+      ;;
+    600)
+      LSOF_CFGF="$LSOF_CFGF -DHASIPv6"
+      LSOF_TMP1="hfs/hfs.h hfs/hfs_catalog.h hfs/hfs_cnode.h hfs/hfs_macos_defs.h hfs/rangelist.h miscfs/devfs/devfsdefs.h miscfs/devfs/devfs_proto.h miscfs/fdesc/fdesc.h net/ndrv_var.h net/raw_cb.h netinet/ip_var.h netinet/tcp_var.h"
+      ;;
+    700)
+      LSOF_CFGF="$LSOF_CFGF -DHASIPv6"
+      LSOF_TMP1="hfs/hfs.h hfs/hfs_catalog.h hfs/hfs_cnode.h hfs/hfs_macos_defs.h hfs/rangelist.h miscfs/devfs/devfsdefs.h miscfs/devfs/devfs_proto.h miscfs/fdesc/fdesc.h net/ndrv_var.h net/raw_cb.h netinet/ip_var.h netinet/tcp_var.h sys/eventvar.h"
+      ;;
+    800)
+      LSOF_CFGF="$LSOF_CFGF -DHASIPv6"
+      LSOF_TMP1="net/ndrv_var.h net/raw_cb.h netinet/ip_var.h netinet/tcp_var.h sys/eventvar.h sys/file_internal.h sys/mount_internal.h sys/proc_internal.h sys/vnode_internal.h"
+      ;;
+    900|1000|1100|1200)
+      LSOF_CFGF="$LSOF_CFGF -DHASIPv6"
+      LSOF_TMP1=""
+      LSOF_UNSUP=""
+      LSOF_TSTBIGF=" "                 # enable LTbigf test
+      if test $LSOF_VERS -eq 900       # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -DNEEDS_MACH_PORT_T"
+      fi       # }
+      ;;
+    1300|1400|1500|1600|1700|1800|1900)
+      LSOF_CFGF="$LSOF_CFGF -DHASIPv6"
+      LSOF_TMP1=""
+      LSOF_UNSUP=""
+      LSOF_TSTBIGF=" "                 # enable LTbigf test
+      ;;
+    *)
+      echo "Unsupported Darwin version: $LSOF_VERS"
+      rm -f $LSOF_HLP
+      exit 1
+      ;;
+    esac       # }
+    LSOF_TMP2=""
+    LSOF_TMP3=""
+    LSOF_TMP4=""
+    LSOF_CFGF="$LSOF_CFGF -mdynamic-no-pic"
+    LSOF_CFGL="$LSOF_CFGL -lcurses"
+
+    # Test Darwin base.
+
+    if test "X$DARWIN_BASE" = "X" -o "X$DARWIN_BASE" = "Xlibproc"      # {
+    then
+      LSOF_TMP5=""
+      if test $LSOF_VERS -ge 800 -o "X$DARWIN_BASE" = "Xlibproc"       # {
+      then
+       if test -r ${LSOF_INCLUDE}/libproc.h    # {
+       then
+           DARWIN_BASE="libproc"
+       else
+         if test -r ${LSOF_INCLUDE}/../local/include/libproc.h # {
+         then
+           DARWIN_BASE="libproc"
+           LSOF_TMP5="${LSOF_INCLUDE}/../local/include"
+         else
+           if test -r /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/libproc.h        # {
+           then
+             DARWIN_BASE="libproc"
+             LSOF_TMP5="/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/"
+            else
+              echo "FATAL: can't find libproc.h"
+              rm -f $LSOF_HLP
+              exit 1
+            fi
+         fi    # }
+       fi      # }
+      else
+
+        # The default Darwin base is libproc
+
+       DARWIN_BASE="libproc"
+      fi       # }
+    fi # }
+
+    if test "X$DARWIN_BASE" = "Xlibproc"       # {
+    then
+
+      # Configure for libproc-based Darwin lsof.
+
+      echo "Configuring libproc-based Darwin lsof"
+      LSOF_CINFO="libproc-based"
+      LSOF_DIALECT_DIR=darwin
+      if test $LSOF_VERS -lt 1000      # {
+      then
+       LSOF_CFGL="$LSOF_CFGL -lproc"
+      fi       # }
+      LSOF_TSTKMEM=0
+      if test "X$LSOF_TMP5" != "X"  # {
+      then
+       LSOF_DINC="$LSOF_DINC -I$LSOF_TMP5"
+      fi  # }
+      if test ! -r ${LSOF_INCLUDE}/sys/proc_info.h     # {
+      then
+       if test "X$LSOF_TMP5" = "X" -o ! -r ${LSOF_TMP5}/sys/proc_info.h # {
+       then
+         echo "FATAL: can't find sys/proc_info.h"
+         rm -f $LSOF_HLP
+         exit 1
+       fi      # }
+      fi       # }
+
+    # Add header file paths for libproc-based Darwin lsof.
+
+      for i in $LSOF_TMP3 $LSOF_TMP4 $LSOF_INCLUDE     # {
+      do
+       if test -d $i -a "X$i" != "X/usr/include"       # {
+       then
+         LSOF_DINC="$LSOF_DINC -I${i}"
+       fi      # }
+      done     # }
+
+    # Do other libproc-based Darwin lsof setups.
+
+      if test -r ${LSOF_INCLUDE}/utmpx.h       # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -DHASUTMPX"
+      fi       # }
+    fi # }
+    LSOF_CFGF="$LSOF_CFGF -DDARWINV=$LSOF_VERS"
+    LSOF_CFLAGS_OVERRIDE=1
+    ;;
+
+# Configure for FreeBSD.
+
+  freebsd)
+    LSOF_FBSD_ZFS=0
+    LSOF_TSTKMEM=0
+    if test "X$LSOF_CC" = "X"  # {
+    then
+      LSOF_CC=cc
+      LSOF_CCV=`$LSOF_CC -v 2>&1 | sed -n 's/.*version \(.*\)/\1/p'`
+    fi # }
+    if test "X$LSOF_VSTR" = "X"        # {
+    then
+      LSOF_VSTR=`uname -r`
+    fi # }
+    if test "X$LSOF_VERS" = "X"        # {
+    then
+
+    # If the FreeBSD version isn't pre-defined, determine it.
+
+      case $LSOF_VSTR in       # {
+      12*)
+       LSOF_CFGL="$LSOF_CFGL -lutil"
+       LSOF_TSTBIGF=" "
+       LSOF_VERS=12000
+       ;;
+      13*)
+       LSOF_CFGL="$LSOF_CFGL -lutil"
+       LSOF_TSTBIGF=" "
+       LSOF_VERS=13000
+       ;;
+      14*)
+       LSOF_CFGL="$LSOF_CFGL -lutil"
+       LSOF_TSTBIGF=" "
+       LSOF_VERS=14000
+       ;;
+      *)
+       echo Unknown FreeBSD release: `uname -r`
+       rm -f $LSOF_HLP
+       exit 1
+       ;;
+      esac     # }
+    fi # }
+
+    # Clear LSOF_UNSUP message for supported versions of FreeBSD.
+
+    case $LSOF_VERS in  # {
+    12000|13000|14000)
+      LSOF_UNSUP=""
+      ;;
+    esac       # }
+
+    # Get system CFLAGS, if possible.
+
+    LSOF_TMP1=`echo "all:\n.include <bsd.prog.mk>" | $LSOF_MAKE -f- -VCFLAGS`
+    LSOF_TMP=1
+    while test $LSOF_TMP -eq 1 # {
+    do
+      echo $LSOF_TMP1 | grep -q -e '-O'
+      if test $? -eq 0 # {
+      then
+       if test "X$LSOF_DEBUG" = "X"
+         then  # {
+           LSOF_DEBUG=`echo $LSOF_TMP1 | sed 's/.*\(-O[^ $]*\).*/\1/'`
+        fi     # }
+       LSOF_TMP1=`echo $LSOF_TMP1 | sed 's/\(.*\)-O[^ $]*\(.*\)/\1 \2/' | sed 's/^  *//g' | sed 's/  */ /g' | sed 's/  *$//'`
+      else
+       LSOF_TMP=0
+      fi       # }
+      LSOF_FBSD_ZFS_CFGF="$LSOF_CFGF $LSOF_TMP1"
+    done       # }
+    LSOF_CFGF="$LSOF_CFGF $LSOF_TMP1"
+    echo $LSOF_CFGF | grep -q NEEDS_BOOL_TYPEDEF
+    if test $? -ne 0
+    then       # {
+      LSOF_CFGF="$LSOF_CFGF -DNEEDS_BOOL_TYPEDEF"
+      LSOF_FBSD_ZFS_CFGF="$LSOF_FBSD_ZFS_CFGF -DNEEDS_BOOL_TYPEDEF"
+    fi # }
+
+    # Determine path to FreeBSD sources.
+
+    LSOF_DINC_ADD=0
+    if test "X$FREEBSD_SYS" = "X"      # {
+    then
+      if test -d /usr/src/sys  # {
+      then
+       FREEBSD_SYS=/usr/src/sys
+      else
+       if test -d /sys # {
+       then
+         FREEBSD_SYS="/sys"
+       else
+         echo "!!!WARNING!!!  No kernel sources in /usr/src/sys or /sys (set FREEBSD_SYS)"
+       fi      # }
+      fi       # }
+    fi # }
+
+    # Test for thread (task) support.
+
+    if test -r ${LSOF_INCLUDE}/sys/user.h      # {
+    then
+      grep -q ki_numthreads ${LSOF_INCLUDE}/sys/user.h
+      if test $? -eq 0 # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -DHASTASKS"
+      fi       # }
+    else
+      echo "FATAL: can't find sys/user.h"
+      rm -f $LSOF_HLP
+      exit 1
+    fi # }
+
+    # All supported FreeBSD releases have closefrom and dup2.
+    LSOF_CFGF="$LSOF_CFGF -DHAS_DUP2"
+    LSOF_CFGF="$LSOF_CFGF -DHAS_CLOSEFROM"
+
+    # Do FreeBSD version-specific stuff.
+
+    case $LSOF_VERS in # {
+    1000)
+      LSOF_CFGF="$LSOF_CFGF"
+      LSOF_CFGL="$LSOF_CFGL -lutil"
+      LSOF_DINC="$LSOF_DINC -I`pwd`/dialects/freebsd/include"
+      if test "X$FREEBSD_KERNEL" = "X" # {
+      then
+       LSOF_N_UNIXV="/386bsd"
+      else
+       LSOF_N_UNIXV=$FREEBSD_KERNEL
+      fi       # }
+      ;;
+    2000|2005|2010)
+      LSOF_CFGL="$LSOF_CFGL -lkvm"
+      ;;
+    2020)
+      LSOF_CFGL="$LSOF_CFGL -lkvm"
+      if test -r ${LSOF_INCLUDE}/vm/lock.h     # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -DHASVMLOCKH"
+      fi       # }
+      ;;
+    3000|3010|3020|3030|3040|3050)
+      LSOF_CFGL="$LSOF_CFGL -lkvm"
+      if test -r ${LSOF_INCLUDE}/nfs/rpcv2.h   # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -DHASRPCV2H"
+      fi       # }
+      if test -r ${LSOF_INCLUDE}/vm/lock.h     # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -DHASVMLOCKH"
+      fi       # }
+      ;;
+    *)
+      if test -r ${LSOF_INCLUDE}/nfs/rpcv2.h   # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -DHASRPCV2H"
+      fi       # }
+      if test -r ${LSOF_INCLUDE}/sys/namei.h   # {
+      then
+       grep -q "^struct[       ]*namecache[    ]*{" ${LSOF_INCLUDE}/sys/namei.h
+       if test $? -eq 0        # {
+       then
+         LSOF_CFGF="$LSOF_CFGF -DHASNAMECACHE"
+       fi      # }
+      fi       # }
+      if test -r ${LSOF_INCLUDE}/ufs/ufs/inode.h       # {
+      then
+       grep -q i_effnlink ${LSOF_INCLUDE}/ufs/ufs/inode.h
+       if test $? -eq 0        # {
+       then
+         LSOF_CFGF="$LSOF_CFGF -DHASEFFNLINK=i_effnlink"
+       fi      # }
+      fi       # }
+      if test -r ${LSOF_INCLUDE}/sys/file.h    # {
+      then
+       grep -q f_vnode ${LSOF_INCLUDE}/sys/file.h
+       if test $? -eq 0        # {
+       then
+         LSOF_CFGF="$LSOF_CFGF -DHASF_VNODE"
+       fi      # }
+      fi       # }
+      LSOF_CFGL="$LSOF_CFGL -lkvm"
+      if test $LSOF_VERS -ge 5000      # {
+      then
+
+      # Do FreeBSD 5 and higher version-specific stuff.
+
+       if test -r ${LSOF_INCLUDE}/sys/vnode.h  # {
+       then
+         grep VT_FDESC ${LSOF_INCLUDE}/sys/vnode.h > /dev/null 2>&1
+         if test $? -eq 0      # {
+         then
+           if test ! -r ${LSOF_INCLUDE}/fs/devfs/devfs.h       # {
+           then
+             if test -r ${FREEBSD_SYS}/fs/devfs/devfs.h        # {
+             then
+               LSOF_DINC_ADD=1
+             else
+               echo "!!!FATAL: lsof cannot locate the devfs.h header file"
+               echo "          in ${LSOF_INCLUDE}/fs/devfs/devfs.h or"
+               echo "          ${FREEBSD_SYS}/fs/devfs/devfs.h.  Consult"
+               echo "          00FAQ for an explanation."
+               rm -f $LSOF_HLP
+               exit 1
+             fi        # }
+           fi  # }
+         fi    # }
+       fi      # }
+       if test -r ${FREEBSD_SYS}/sys/filedesc.h        # {
+       then
+         grep -q filedescent ${FREEBSD_SYS}/sys/filedesc.h
+         if test $? -eq 0      # {
+         then
+           LSOF_CFGF="$LSOF_CFGF -DHAS_FILEDESCENT"
+         fi    # }
+       fi      # }
+       if test -r ${FREEBSD_SYS}/fs/tmpfs/tmpfs.h      # {
+       then
+           LSOF_CFGF="$LSOF_CFGF -DHAS_TMPFS"
+       fi      #}
+
+      # Do FreeBSD 5.2 and higher version-specific stuff.
+
+       if test -r ${LSOF_INCLUDE}/wctype.h     # {
+       then
+         LSOF_CFGF="$LSOF_CFGF -DHASWCTYPE_H"
+       fi      # }
+       if test $LSOF_VERS -ge 5020     # {
+       then
+
+       # Determine the status of the cpumask_t typedef.
+
+         rm -f ${LSOF_TMPC}.*
+         cat > ${LSOF_TMPC}.c << .LSOF_END_HERE_DOC3
+#undef _KERNEL
+#include <sys/types.h>
+int main() {
+cpumask_t c;
+}
+.LSOF_END_HERE_DOC3
+         $LSOF_CC ${LSOF_TMPC}.c -o ${LSOF_TMPC}.x > /dev/null 2>&1
+         LSOF_TMP1=$?
+         rm -f ${LSOF_TMPC}.*
+         if test $LSOF_TMP1 -ne 0      # {
+         then
+
+         # The cpumask_t typedef is unknown when _KERNEL is not defined.
+
+           if test -r ${LSOF_INCLUDE}/sys/types.h \
+                   -a -r ${LSOF_INCLUDE}/machine/_types.h      # {
+           then
+             grep -q cpumask_t ${LSOF_INCLUDE}/sys/types.h
+             if test $? -eq 0  # {
+             then
+               grep -q __cpumask_t ${LSOF_INCLUDE}/machine/_types.h
+               if test $? -eq 0        # {
+               then
+                 LSOF_CFGF="$LSOF_CFGF -DHASCPUMASK_T"
+               else
+                 $LSOF_CC -E ${LSOF_INCLUDE}/machine/_types.h 2>/dev/null | grep -q __cpumask_t
+                 if test $? -eq 0  # {
+                 then
+                   LSOF_CFGF="$LSOF_CFGF -DHASCPUMASK_T"
+                 fi    # }
+               fi      # }
+             fi        # }
+           fi  # }
+         fi    # }
+         if test -r ${LSOF_INCLUDE}/sys/socketvar.h    # {
+         then
+           grep -q SBS_CANT ${LSOF_INCLUDE}/sys/socketvar.h
+           if test $? -eq 0    # {
+           then
+               LSOF_CFGF="$LSOF_CFGF -DHASSBSTATE"
+           fi  # }
+         fi    # }
+       fi      # }
+       if test $LSOF_VERS -ge 5030     # {
+       then
+
+       # Do FreeBSD 5.3 and higher version-specific stuff.
+
+         if test -r ${LSOF_INCLUDE}/sys/vnode.h        # {
+         then
+           grep -q "defined(_KVM_VNODE)" ${LSOF_INCLUDE}/sys/vnode.h
+           if test $? -eq 0    # {
+           then
+               LSOF_CFGF="$LSOF_CFGF -DHAS_KVM_VNODE"
+           fi  #}
+         fi    # }
+       fi      # }
+       if test $LSOF_VERS -ge 6000     # {
+       then
+
+       # Do FreeBSD 6.0 and higher version-specific stuff.
+
+         if test -r ${LSOF_INCLUDE}/sys/_types.h       # {
+         then
+           grep __dev_t ${LSOF_INCLUDE}/sys/_types.h | grep -q 64
+           if test $? -eq 0    # {
+           then
+             if test "X$LSOF_TSTDFLG" = "X"    # {
+             then
+               LSOF_TSTDFLG="-DLT_DEV64"
+             else
+               LSOF_TSTDFLG="$LSOF_TSTDFLG -DLT_DEV64"
+             fi        # }
+           fi  # }
+         fi    # }
+         if test -r ${LSOF_INCLUDE}/ufs/ufs/inode.h    # {
+         then
+           grep -q i_din2 ${LSOF_INCLUDE}/ufs/ufs/inode.h
+           if test $? -eq 0    # {
+           then
+             LSOF_CFGF="$LSOF_CFGF -DHAS_UFS1_2"
+           fi  # }
+         fi    # }
+         if test -r ${LSOF_INCLUDE}/sys/conf.h # {
+         then
+           grep -q vm_memattr_t ${LSOF_INCLUDE}/sys/conf.h
+           if test $? -eq 0    #{
+           then
+             LSOF_CFGF="$LSOF_CFGF -DHAS_VM_MEMATTR_T"
+           fi  # }
+           grep -q device_t ${LSOF_INCLUDE}/sys/eventhandler.h
+           if test $? -eq 0    # {
+           then
+             LSOF_CFGF="$LSOF_CFGF -DNEEDS_DEVICE_T"
+           fi  # }
+           grep -q "^#define   minor(" ${LSOF_INCLUDE}/sys/conf.h
+           if test $? -eq 0    # {
+           then
+             LSOF_CFGF="$LSOF_CFGF -DHAS_CONF_MINOR"
+             rm -f fbsd_minor.h
+             if test -r ${LSOF_INCLUDE}/sys/types.h    # {
+             then
+               LSOF_TMP1=`grep "^#define[      ]minor(" ${LSOF_INCLUDE}/sys/types.h`
+               if test "X$LSOF_TMP1" != "X"    # {
+               then
+                 echo "Creating fbsd_minor.h"
+                 cat > fbsd_minor.h << FBSD_MINOR1
+/*
+ * fbsd_minor.h -- created by lsof Configure script on
+FBSD_MINOR1
+                 echo $EO " * $EC" >> ./fbsd_minor.h
+                 date >> ./fbsd_minor.h
+                 cat >> ./fbsd_minor.h << FBSD_MINOR2
+ */
+
+#if    !defined(FBSD_MINOR_H)
+#define        FBSD_MINOR_H
+
+FBSD_MINOR2
+                 echo $EO "${LSOF_TMP1}${EC}" >> fbsd_minor.h
+                 cat >> ./fbsd_minor.h << FBSD_MINOR3
+
+#endif /* defined(FBSD_MINOR_H) */
+FBSD_MINOR3
+               fi      # }
+             fi        # }
+           else
+             if test -r ${FREEBSD_SYS}/fs/devfs/devfs_int.h    # {
+             then
+               grep -q cdev2priv ${FREEBSD_SYS}/fs/devfs/devfs_int.h
+               if test $? -eq 0        # {
+               then
+                 LSOF_CFGF="$LSOF_CFGF -DHAS_CDEV2PRIV"
+               fi      # }
+             fi        # }
+           fi  # }
+           grep -q si_priv ${LSOF_INCLUDE}/sys/conf.h
+           if test $? -eq 0    # {
+           then
+             LSOF_CFGF="$LSOF_CFGF -DHAS_SI_PRIV"
+           fi  # }
+         fi    # }
+         if test -r ${LSOF_INCLUDE}/sys/sx.h   # {
+         then
+           LSOF_CFGF="$LSOF_CFGF -DHAS_SYS_SX_H"
+         fi    # }
+
+       # Do msdosfs test.
+         if test -r ${FREEBSD_SYS}/fs/msdosfs/denode.h # {
+         then
+           LSOF_CFGF="$LSOF_CFGF -DHASMSDOSFS"
+         fi    # }
+       # Do ZFS test.  Try for the newer OpenSolaris files first -- i.e.,
+       # the ones in ${FREEBSD_SYS}/cddl/contrib/opensolaris.  If that fails,
+       # try for the older ones in ${FREEBSD}/contrib/opensolaris.
+
+         LSOF_FBSD_ZFS_SYS=${FREEBSD_SYS}/cddl
+         if test ! -r ${LSOF_FBSD_ZFS_SYS}/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_znode.h       # {
+         then
+           LSOF_FBSD_ZFS_SYS=${FREEBSD_SYS}
+           if test ! -r ${LSOF_FBSD_ZFS_SYS}/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_znode.h     # {
+           then
+             LSOF_FBSD_ZFS_SYS=""
+           fi  # }
+         fi    # }
+         if test "X$LSOF_FBSD_ZFS_SYS" != "X"  # {
+         then
+           LSOF_CFGF="$LSOF_CFGF -DHAS_ZFS"
+           LSOF_FBSD_ZFS=1
+           LSOF_FBSD_ZFS_CFGF="$LSOF_FBSD_ZFS_CFGF -DFREEBSDV=$LSOF_VERS"
+           LSOF_FBSD_ZFS_CFGF="$LSOF_FBSD_ZFS_CFGF -DHAS_ZFS"
+           grep -q z_phys ${LSOF_FBSD_ZFS_SYS}/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_znode.h
+           if test $? -eq 0    # {
+           then
+             LSOF_FBSD_ZFS_CFGF="$LSOF_FBSD_ZFS_CFGF -DHAS_Z_PHYS"
+           fi  # }
+           if test -r ${LSOF_FBSD_ZFS_SYS}/compat/opensolaris/sys/sdt.h  #{
+           then
+             grep -q opt_kdtrace.h ${LSOF_FBSD_ZFS_SYS}/compat/opensolaris/sys/sdt.h
+             if test $? -eq 0  # {
+             then
+               rm -f opt_kdtrace.h
+               touch opt_kdtrace.h
+             fi        # }
+           fi  # }
+           if test -r ${LSOF_FBSD_ZFS_SYS}/compat/opensolaris/sys/kcondvar.h #{
+           then
+               grep -q cv_timedwait_sbt ${LSOF_FBSD_ZFS_SYS}/compat/opensolaris/sys/kcondvar.h
+               if test $? -eq 0        # {
+               then
+                 LSOF_FBSD_ZFS_CFGF="$LSOF_FBSD_ZFS_CFGF -DHAS_CV_TIMEDWAIT_SBT"
+               fi      # }
+           fi  #}
+           if test -r /usr/include/sys/random.h        # {
+           then
+             grep -q opt_random.h /usr/include/sys/random.h
+             if test $? -eq 0  # {
+             then
+               rm -f opt_random.h
+               touch opt_random.h
+             fi        # }
+           fi  # }
+         fi    # }
+         if test -r ${LSOF_INCLUDE}/sys/vnode.h        # {
+         then
+
+         # See if the vnode contains the byte level lock pointer.
+
+           grep -q v_lockf ${LSOF_INCLUDE}/sys/vnode.h
+           if test $? -eq 0    # {
+           then
+             LSOF_CFGF="$LSOF_CFGF -DHAS_V_LOCKF"
+             if test $LSOF_FBSD_ZFS -eq 1      # {
+             then
+               LSOF_FBSD_ZFS_CFGF="$LSOF_FBSD_ZFS_CFGF -DHAS_V_LOCKF"
+             fi        # }
+           fi  # }
+         fi    # }
+         if test -r ${LSOF_INCLUDE}/sys/lockf.h        # {
+         then
+
+         # Determine the type of locking structure to which the inode or
+         # vnode points.
+
+           grep -q "^struct lockf_entry" ${LSOF_INCLUDE}/sys/lockf.h
+           if test $? -eq 0    # {
+           then
+
+           # Build the ./lockf_owner.h header file.
+
+             LSOF_TMP1=""
+             LSOF_TMP2=0
+             echo "Creating ./lockf_owner.h from ${FREEBSD_SYS}/kern/kern_lockf.c"
+             rm -f ./lockf_owner.h
+             if test -r ${FREEBSD_SYS}/kern/kern_lockf.c       # {
+             then
+               LSOF_TMP1=`grep -n "^struct lock_owner {" ${FREEBSD_SYS}/kern/kern_lockf.c | sed 's/\([0-9]*\):.*$/\1/'`
+               if test "X$LSOF_TMP1" != "X"    # {
+               then
+                 LSOF_TMP2=0
+                 for i in `grep -n "};" ${FREEBSD_SYS}/kern/kern_lockf.c | sed 's/\([0-9]*\):.*$/\1/'` # {
+                 do
+                   if test $LSOF_TMP2 -eq 0 -a $i -gt $LSOF_TMP1       # {
+                   then
+                     LSOF_TMP2=$i
+                   fi  # }
+                 done  # }
+                 if test $LSOF_TMP2 -eq 0      # {
+                 then
+                   LSOF_TMP1=""
+                 else
+                   cat > ./lockf_owner.h << LOCKF_OWNER1
+/*
+ * lockf_owner.h -- created by lsof Configure script on
+LOCKF_OWNER1
+                   echo $EO " * $EC" >> ./lockf_owner.h
+                   date >> ./lockf_owner.h
+                   cat >> ./lockf_owner.h << LOCKF_OWNER2
+ */
+
+#if    !defined(LOCKF_OWNER_H)
+#define        LOCKF_OWNER_H
+
+LOCKF_OWNER2
+                   ed -s ${FREEBSD_SYS}/kern/kern_lockf.c >> ./lockf_owner.h << LOCKF_OWNER3
+${LSOF_TMP1},${LSOF_TMP2}p
+LOCKF_OWNER3
+                   if test $? -ne 0    # {
+                   then
+                     LSOF_TMP1=""
+                   else
+                     cat >> ./lockf_owner.h << LOCKF_OWNER4
+
+#endif /* defined(LOCKF_OWNER_H) */
+LOCKF_OWNER4
+                   fi  # }
+                 fi    # }
+               fi      # }
+             else
+               echo "FATAL ERROR: can't read ${FREEBSD_SYS}/kern/kern_lockf.c"
+             fi        # }
+             if test "X$LSOF_TMP1" != "X" -a "X$LSOF_TMP2" != "X0" # {
+             then
+               echo "./lockf_owner.h creation succeeded."
+               LSOF_CFGF="$LSOF_CFGF -DHAS_LOCKF_ENTRY"
+             else
+               echo "FATAL ERROR: ./lockf_owner.h creation failed (see 00FAQ)"
+               rm -f $LSOF_HLP
+               exit 1
+             fi        # }
+           fi  # }
+
+         # Test for in6p_.port in inpcb structure.
+
+           if test -r ${LSOF_INCLUDE}/netinet/in_pcb.h # {
+           then
+             grep -q 'in6p_.port' ${LSOF_INCLUDE}/netinet/in_pcb.h
+             if test $? -ne 0  # {
+             then
+               LSOF_CFGF="$LSOF_CFGF -DHAS_NO_6PORT"
+             fi        # }
+           fi  # }
+
+         # Test for in6p_ppcb in inpcb structure.
+
+           if test -r ${LSOF_INCLUDE}/netinet/in_pcb.h # {
+           then
+             grep -q 'in6p_ppcb' ${LSOF_INCLUDE}/netinet/in_pcb.h
+             if test $? -ne 0  # {
+             then
+               LSOF_CFGF="$LSOF_CFGF -DHAS_NO_6PPCB"
+             fi        # }
+           fi  # }
+           if test -r ${LSOF_INCLUDE}/sys/conf.h       # {
+           then
+             grep -q 'doadump(boolean_t)' ${LSOF_INCLUDE}/sys/conf.h
+             if test $? -eq 0  # {
+             then
+               LSOF_CFGF="$LSOF_CFGF -DNEEDS_BOOLEAN_T"
+             fi        # }
+           fi  # }
+           if test -r ${LSOF_INCLUDE}/sys/sockbuf.h    # {
+           then
+             grep -q 'u_int    sb_ccc;' ${LSOF_INCLUDE}/sys/sockbuf.h
+             if test $? -eq 0  # {
+             then
+               LSOF_CFGF="$LSOF_CFGF -DHAS_SB_CCC"
+             fi        # }
+           fi  # }
+         fi    # }
+       fi      # }
+      fi       # }
+      if test $LSOF_VERS -eq 10000     # {
+      then
+
+      # Do specific FreeBSD 10 version-specific stuff.
+
+       LSOF_TMP1=`uname -m`
+       if test "X$LSOF_TMP1" = "Xi386" # {
+       then
+         LSOF_CFGF="$LSOF_CFGF -DNEEDS_BOOL_TYPEDEF"
+       fi      # }
+      fi       # }
+      ;;
+    esac       # }
+    LSOF_CFGF="$LSOF_CFGF -DFREEBSDV=$LSOF_VERS"
+    if test $LSOF_VERS -lt 2000 -a "X$FREEBSD_KERNEL" = "X"    # {
+    then
+      if test ! -x $LSOF_N_UNIXV       # {
+      then
+       echo "Hmmm -- $LSOF_N_UNIXV doesn't appear to be your kernel file."
+       echo "Please enter the name of the file in / that contains"
+       echo "the kernel for this host.  It must be a regular file,"
+       echo "not a directory, and must be executable."
+       LSOF_LOOP=1
+       while test $LSOF_LOOP = 1       # {
+       do
+         echo ""
+         echo "/ contains:"
+         echo ""
+         ls -CF /
+         echo ""
+         echo -n "Kernel file name? "
+         read LSOF_N_UNIXV LSOF_EXCESS
+         LSOF_N_UNIXV="/$LSOF_N_UNIXV"
+         if test ! -d $LSOF_N_UNIXV -a -x $LSOF_N_UNIXV        # {
+         then
+           LSOF_LOOP=0
+         else
+           echo ""
+           echo $LSOF_N_UNIXV is not a regular executable file.
+         fi    # }
+       done    # }
+      fi       # }
+      LSOF_N_UNIXV=`echo $LSOF_N_UNIXV | sed 's#^/*#/#'`
+      LSOF_CFGF="$LSOF_CFGF -DN_UNIXV=$LSOF_N_UNIXV"
+    fi # }
+    if test -r ${FREEBSD_SYS}/miscfs/fdesc/fdesc.h     # {
+    then
+      LSOF_TMP1=${FREEBSD_SYS}/miscfs/fdesc/fdesc.h
+    else
+      if test $LSOF_VERS -ge 5000 -a -r ${LSOF_INCLUDE}/fs/fdescfs/fdesc.h  # {
+      then
+       LSOF_TMP1=${LSOF_INCLUDE}/fs/fdescfs/fdesc.h
+      else
+       LSOF_TMP1=""
+      fi       # }
+    fi # }
+    if test "X$LSOF_TMP1" != "X"       # {
+    then
+      grep -q Fctty $LSOF_TMP1
+      if test $? -eq 0 # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -DHASFDESCFS=1"
+      else
+       LSOF_CFGF="$LSOF_CFGF -DHASFDESCFS=2"
+      fi       # }
+      grep -q fd_link $LSOF_TMP1
+      if test $? -eq 0 # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -DHASFDLINK"
+      fi       # }
+      LSOF_DINC_ADD=1
+    fi # }
+    if test $LSOF_VERS -ge 5000        # {
+    then
+      LSOF_TMP1="fs"
+    else
+      LSOF_TMP1="miscfs"
+    fi # }
+    LSOF_CFGF="$LSOF_CFGF -DHASPROCFS"
+    if test -d ${FREEBSD_SYS}/${LSOF_TMP1}/pseudofs    # {
+    then
+      LSOF_CFGF="$LSOF_CFGF -DHASPSEUDOFS"
+      LSOF_DINC_ADD=1
+    fi # }
+    if test -r ${LSOF_INCLUDE}/${LSOF_TMP1}/nullfs/null.h      # {
+    then
+      LSOF_CFGF="$LSOF_CFGF -DHASNULLFS"
+    else
+      if test -r ${FREEBSD_SYS}/${LSOF_TMP1}/nullfs/null.h     # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -DHASNULLFS"
+       LSOF_DINC_ADD=1
+      fi       # }
+    fi # }
+    if test -r ${FREEBSD_SYS}/isofs/cd9660/cd9660_node.h       # {
+    then
+      ISOFS_DIR="${FREEBSD_SYS}/isofs/cd9660"
+    else
+      if test -r ${FREEBSD_SYS}/fs/cd9660/cd9660_node.h                # {
+      then
+        ISOFS_DIR="${FREEBSD_SYS}/fs/cd9660"
+      fi       # }
+    fi # }
+    if test "X$ISOFS_DIR" != "X"                               # {
+    then
+      rm -f cd9660_node.h
+      grep -q "^#ifdef [_]*KERNEL" ${ISOFS_DIR}/cd9660_node.h
+      if test $? -eq 0 # {
+      then
+       ln -s ${ISOFS_DIR}/cd9660_node.h cd9660_node.h
+      else
+       sed -e '/^ \* Prototypes for ISOFS vnode operations/,$c\
+       \ The ISOFS prototypes were removed by Configure. */' \
+       < ${ISOFS_DIR}/cd9660_node.h > cd9660_node.h
+       echo "" >> cd9660_node.h
+      fi       # }
+      LSOF_CFGF="$LSOF_CFGF -DHAS9660FS"
+    fi # }
+    if test -r ${LSOF_INCLUDE}/sys/namei.h
+    then
+      grep -q nc_vpid ${LSOF_INCLUDE}/sys/namei.h
+      if test $? -eq 0 # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -DHASNCVPID"
+      fi       # }
+    fi # }
+    if test $LSOF_DINC_ADD -eq 1       # {
+    then
+      if test "X$LSOF_DINC" = "X"      # {
+      then
+       LSOF_DINC="-I${FREEBSD_SYS}"
+      else
+       LSOF_DINC="$LSOF_DINC -I${LSOF_INCLUDE} -I${FREEBSD_SYS}"
+      fi       # }
+    fi # }
+    if test -r ${LSOF_INCLUDE}/netinet/in.h    # {
+    then
+      grep IPV6_INRIA_VERSION ${LSOF_INCLUDE}/netinet/in.h > /dev/null
+      if test $? -eq 0 # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -DHASIPv6 -DHASINRIAIPv6"
+      fi       # }
+    fi # }
+    echo $CFGF | grep HASIPv6 > /dev/null
+    if test $? -ne 0 -a -r ${LSOF_INCLUDE}/netinet6/in6.h      # {
+    then
+      LSOF_CFGF="$LSOF_CFGF -DHASIPv6"
+    fi # }
+    if test -r ${LSOF_INCLUDE}/utmpx.h # {
+    then
+      LSOF_CFGF="$LSOF_CFGF -DHASUTMPX"
+    fi # }
+
+    # Does struct xtcpcb have t_maxseg?
+    rm -f ${LSOF_TMPC}.*
+    cat > ${LSOF_TMPC}.c << .LSOF_END_HERE_DOC4
+#undef _KERNEL
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/socketvar.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/in_pcb.h>
+#include <netinet/tcp_var.h>
+int main() {
+struct xtcpcb pcb; pcb.t_maxseg = 0;
+}
+.LSOF_END_HERE_DOC4
+    $LSOF_CC ${LSOF_TMPC}.c -o ${LSOF_TMPC}.x > /dev/null 2>&1
+    if test $? -eq 0   # {
+    then
+      LSOF_CFGF="$LSOF_CFGF -DHAS_XTCPCB_TMAXSEG"
+    fi # }
+    rm -f ${LSOF_TMPC}.*
+
+    # Does struct kinfo_file have kf_un.kf_sock.kf_sock_sendq?
+    grep -q kf_sock_sendq ${LSOF_INCLUDE}/sys/user.h
+    if test $? -eq 0   # {
+    then
+      LSOF_CFGF="$LSOF_CFGF -DHAS_KF_SOCK_SENDQ"
+    fi # }
+
+    # Does struct kinfo_file have kf_un.kf_file.kf_file_nlink?
+    grep -q kf_file_nlink ${LSOF_INCLUDE}/sys/user.h
+    if test $? -eq 0   # {
+    then
+      LSOF_CFGF="$LSOF_CFGF -DHAS_KF_FILE_NLINK"
+    fi # }
+
+    LSOF_DIALECT_DIR=freebsd
+    ;;
+
+# Configure for HP-UX and HP-UX gcc.
+
+  hpux|hpuxgcc)
+    if test "X$LSOF_RANLIB_SUP" = "X"  # {
+    then
+      LSOF_RANLIB=""
+    fi # }
+    if test "X$LSOF_VSTR" = "X"        # {
+    then
+      LSOF_VSTR=`uname -r`
+    fi # }
+    if test "X$LSOF_VERS" = "X"        # {
+    then
+
+      # If the HP-UX version isn't pre-defined, determine it.
+
+      LSOF_VERS=`echo $LSOF_VSTR | awk -F. '{printf "%d%02d",\$2,\$3}'`
+    fi # }
+    if test $LSOF_VERS -ge 1020        # {
+    then
+      LSOF_TSTBIGF="-D_LARGEFILE64_SOURCE"
+    fi # }
+
+    # Determine compiler.
+
+    if test "X$LSOF_CC" = "X"  # {
+    then
+      if test "X$LSOF_TGT" = "Xhpuxgcc"        # {
+      then
+       LSOF_CC=gcc
+      else
+       if test "X$HPUX_CCDIR1" = "X"   # {
+       then
+         HPUX_CCDIR1="/bin"
+       fi      # }
+       if test "X$HPUX_CCDIR2" = "X"   # {
+       then
+         HPUX_CCDIR2="/usr/ccs/bin"
+       fi      # }
+       if test -x ${HPUX_CCDIR1}/cc    # {
+       then
+         LSOF_CC=${HPUX_CCDIR1}/cc
+       else
+         if test -x ${HPUX_CCDIR2}/cc  # {
+         then
+           LSOF_CC=${HPUX_CCDIR2}/cc
+         else
+           echo "No executable cc in $HPUX_CCDIR1 or $HPUX_CCDIR2"
+           rm -f $LSOF_HLP
+           exit 1
+         fi    # }
+       fi      # }
+       $LSOF_CC -O < /dev/null 2>&1 | grep -q Bundled
+       if test $? -eq 0        # {
+       then
+         LSOF_DEBUG="No-O"                     # to disable -O
+         if test "X$HPUX_LIBC1" = "X"  # {
+         then
+           HPUX_LIBC1="/usr/lib"
+         fi    # }
+         if test -r ${HPUX_LIBC1}/libc.sl      # {
+         then
+           LSOF_FCFGL="-L$HPUX_LIBC -lc"
+         else
+           if test "X$HPUX_LIBC2" = "X"        # {
+           then
+             HPUX_LIBC2="/usr/lib"
+           fi  # }
+           if test -r ${HPUX_LIBC2}/libc.sl    # {
+           then
+             LSOF_FCFGL="-L$HPUX_LIBC2 -lc"
+           fi  # }
+         fi    # }
+       fi      # }
+      fi       # }
+    fi # }
+    echo $LSOF_CC | grep gcc > /dev/null
+    if test $? -eq 0   # {
+    then
+      LSOF_CCV=`$LSOF_CC -v 2>&1 | sed -n 's/.*version \(.*\)/\1/p'`
+    else
+      $LSOF_CC -O < /dev/null 2>&1 | grep -q Bundled
+      if test $? -eq 0 # {
+      then
+       LSOF_DEBUG="No-O"                       # to disable -O
+      fi       # }
+    fi # }
+    LSOF_TGT=hpux
+
+    # Test for "const void" support.
+
+    rm -f ${LSOF_TMPC}.*
+    echo "int main() { const void *x; return(0); }" >> $LSOF_TMPC.c
+    $LSOF_CC $LSOF_TMPC.c -o $LSOF_TMPC.x > /dev/null 2>&1
+    if test $? -eq 0   # {
+    then
+      LSOF_CFGF="$LSOF_CFGF -DHAS_CONST"
+    fi # }
+    rm -f ${LSOF_TMPC}.*
+
+    # Test HP-UX base.
+
+    if test "X$HPUX_BASE" = "X"        # {
+    then
+      if test -d $LSOF_INCLUDE/sys/pstat -a $LSOF_VERS -ge 1111        # {
+      then
+       HPUX_BASE="pstat"
+      else
+       HPUX_BASE="/dev/kmem"
+      fi       # }
+    fi # }
+    if test "X$HPUX_BASE" = "Xpstat"   # {
+    then
+
+      # Configure for pstat-based HP-UX lsof.
+
+      LSOF_CINFO="PSTAT-based"
+      echo "Configuring PSTAT-based HP-UX lsof"
+      LSOF_DIALECT_DIR=hpux/pstat
+      LSOF_CFGF="$LSOF_CFGF -DHPUXV=$LSOF_VERS -D_PSTAT64"
+      LSOF_CFGL="$LSOF_CFGL -lnsl"
+      LSOF_TSTKMEM=0
+      LSOF_TSTK64=1
+      ls -l $LSOF_CC | grep -q ansic
+      LSOF_TMP1=$?
+      ls -l $LSOF_CC | grep -q aCC
+      if test $? -eq 0 -o $LSOF_TMP1 -eq 0     # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -Ae +DD32"
+      else
+       echo $LSOF_CC | grep -q gcc
+       if test $? -ne 0        # {
+       then
+         LSOF_CFGF="$LSOF_CFGF +DD32"
+       fi      # }
+      fi       # }
+      if test -r ${LSOF_INCLUDE}/netinet/in6.h # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -DHASIPv6"
+      fi       # }
+      if test -r ${LSOF_INCLUDE}/sys/pstat/stream_pstat_body.h # {
+      then
+       grep -q PS_STR_XPORT_DATA ${LSOF_INCLUDE}/sys/pstat/stream_pstat_body.h
+       if test $? -eq 0        # {
+       then
+         LSOF_CFGF="$LSOF_CFGF -D_PSTAT_STREAM_GET_XPORT"
+       fi      # }
+      fi       # }
+      if test $LSOF_VERS -ge 1123      # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -D_LARGEFILE64_SOURCE"
+      fi       # }
+    else
+      if test "X$HPUX_BASE" = "X/dev/kmem"     # {
+      then
+
+       # Configure for /dev/kmem-based HP-UX lsof.
+
+       if test "X$HPUX_BOOTFILE" = "X" # {
+       then
+         HPUX_BOOTFILE="/stand/vmunix"
+       fi      # }
+       if test $LSOF_VERS -gt 1100     # {
+       then
+         echo ""
+         echo "************************************************"
+         echo "*                                              *"
+         echo "* !!!!!!!!!!!!!!! FATAL ERROR !!!!!!!!!!!!!!!! *"
+         echo "*                                              *"
+         echo "* LSOF DOES NOT SUPPORT THIS VERSION OF HP-UX. *"
+         echo "*                                              *"
+         echo "************************************************"
+         echo ""
+         rm -f $LSOF_HLP
+         exit 1
+       fi      # }
+       LSOF_CFGF="$LSOF_CFGF -DHPUXV=$LSOF_VERS"
+       LSOF_CINFO="/dev/kmem-based"
+       LSOF_DIALECT_DIR=hpux/kmem
+       echo "Configuring /dev/kmem-based HP-UX lsof"
+       if test $LSOF_VERS -lt 1000     # {
+       then
+         if test "X$HPUX_X25DIR" = "X" # {
+         then
+           HPUX_X25DIR="/etc/conf"
+         else
+           HPUX_X25DIR=$HPUX_X25DIR
+         fi    # }
+         if test -r ${HPUX_X25DIR}/x25/x25addrstr.h    # {
+         then
+           LSOF_CFGF="$LSOF_CFGF -DHPUX_CCITT"
+           LSOF_DINC="$LSOF_DINC -I$HPUX_X25DIR"
+         fi    # }
+       fi      # }
+       if test -r ${LSOF_INCLUDE}/sys/fs/vx_inode.h -a -r ${LSOF_INCLUDE}/sys/fs/vx_hpux.h     # {
+       then
+         LSOF_CFGF="$LSOF_CFGF -DHASVXFS"
+       fi      # }
+       if test $LSOF_VERS -ge 1030     # {
+       then
+         if test "X$HPUX_KERNBITS" = "X"       # {
+         then
+           HPUX_KERNBITS=`getconf _SC_KERNEL_BITS`
+         fi    # }
+         LSOF_CFGF="$LSOF_CFGF -DHPUXKERNBITS=${HPUX_KERNBITS} -I`pwd`/dialects/hpux/kmem/hpux11"
+         if test $HPUX_KERNBITS -eq 64 # {
+         then
+           LSOF_TSTK64=1
+           echo ""
+           echo "*****************************************"
+           echo "*                                       *"
+           echo "* NOTICE!  Configuring for 64 bit HP-UX *"
+           echo "*                                       *"
+           echo "*****************************************"
+           echo $LSOF_CC | grep gcc > /dev/null
+           if test $? -eq 0    # {
+           then
+
+           # Test gcc for 64 bit support, trying gcc with no options, then
+           # with -mlp64, testing the result with file.
+
+             echo ""
+             echo "Testing $LSOF_CC for 64 bit support"
+             rm -f ${LSOF_TMPC}.*
+             echo "int main(){}" > ${LSOF_TMPC}.c
+             LSOF_TMP1=""
+             $LSOF_CC ${LSOF_TMPC}.c -o ${LSOF_TMPC}.x > /dev/null 2>&1
+             if test $? -eq 0  # {
+             then
+               /bin/file ${LSOF_TMPC}.x | /bin/grep 64 > /dev/null
+               if test $? -eq 0        # {
+               then
+                   LSOF_TMP1=" "
+               fi      # }
+             fi        # }
+             if test "X$LSOF_TMP1" = "X"       # {
+             then
+               rm -f ${LSOF_TMPC}.x
+               $LSOF_CC ${LSOF_TMPC}.c -mlp64 -o ${LSOF_TMPC}.x > /dev/null 2>&1
+               if test $? -eq 0        # {
+               then
+                 /bin/file ${LSOF_TMPC}.x | /bin/grep 64 > /dev/null
+                 if test $? -eq 0      # {
+                 then
+                     LSOF_TMP1="-mlp64"
+                 fi    # }
+               fi      # }
+             fi        # }
+             rm -f ${LSOF_TMPC}.*
+             if test "X$LSOF_TMP1" = "X"       # {
+             then
+               echo ""
+               echo "***************************************************"
+               echo "*                                                 *"
+               echo "* !!!!!!!!!!!!!!!!! FATAL ERROR !!!!!!!!!!!!!!!!! *"
+               echo "*                                                 *"
+               echo "* APPARENTLY GCC CANNOT BUILD 64 BIT EXECUTABLES. *"
+               echo "* A COMPILER MUST BE USED THAT CAN.  SEE 00FAQ    *"
+               echo "* FOR MORE INFORMATION.                           *"
+               echo "*                                                 *"
+               echo "***************************************************"
+               echo ""
+               rm -f $LSOF_HLP
+               exit 1
+             else
+               if test "X$LSOF_TMP1" != "X "   # {
+               then
+                 LSOF_CFGF="$LSOF_CFGF $LSOF_TMP1"
+               fi      # }
+               LSOF_CFGL="$LSOF_CFGL -lelf"
+               LSOF_CINFO="${LSOF_CINFO}, 64 bit HP-UX"
+             fi        # }
+           else
+
+           # Set options for the HP-UX compiler.
+
+             LSOF_CFGF="$LSOF_CFGF +DD64"
+             LSOF_CFGL="$LSOF_CFGL -lelf"
+             LSOF_CINFO="${LSOF_CINFO}, 64 bit HP-UX"
+           fi  # }
+         else
+           LSOF_CFGF="$LSOF_CFGF -D_FILE_OFFSET_BITS=64"
+           LSOF_CINFO="${LSOF_CINFO}, 32 bit HP-UX"
+           echo $LSOF_CC | grep gcc > /dev/null
+           if test $? -ne 0    # {
+           then
+             LSOF_CFGF="$LSOF_CFGF +DAportable"
+           fi  # }
+         fi    # }
+         LSOF_CFGL="$LSOF_CFGL -lnsl"
+       else
+
+       # When HP-UX is less than 10.30, but greater than or equal to 10,
+       # check NFS3 rnode status.
+
+         if test $LSOF_VERS -ge 1000   # {
+         then
+           LSOF_TMP1=0
+           if test "X$HPUX_RNODE3" = "X"       # {
+           then
+             nm -x $HPUX_BOOTFILE | grep -q nfs_vnodeops3
+             if test $? -eq 0  # {
+             then
+               if test -r ${LSOF_INCLUDE}/nfs/rnode.h  # {
+               then
+                 grep -q r_fh3 ${LSOF_INCLUDE}/nfs/rnode.h
+                 if test $? -ne 0      # {
+                 then
+                   LSOF_TMP1=1
+                 fi    # }
+               fi      # }
+             fi        # }
+           else
+             if test "X$HPUX_RNODE3" = "X1"    # {
+             then
+               LSOF_TMP1=1
+             fi        # }
+           fi  # }
+           if test $LSOF_TMP1 -eq 1    # {
+           then
+             LSOF_CFGF="$LSOF_CFGF -DHASRNODE3"
+           fi  # }
+         fi # }
+       fi      # }
+       if test $LSOF_VERS -eq 1100     # {
+       then
+
+       # Test for the ipis_s structure.  If it is present, set HAS_IPC_S_PATCH.
+
+         if test "X$HPUX_IPC_S_PATCH" = "X"    # {
+         then
+           if test -x /usr/contrib/Q4/bin/q4exe        # {
+           then
+             LSOF_TMP=/usr/contrib/Q4/bin/q4exe
+           else
+             LSOF_TMP=/usr/contrib/bin/q4
+           fi  # }
+           if test -x $LSOF_TMP        # {
+           then
+             rm -f ${LSOF_TMPC}.out
+             echo ""
+             echo $EO "Looking in $HPUX_BOOTFILE for ipis_s with $LSOF_TMP ... $EC"
+             echo "yes\\nfields -c struct ipis_s" | $LSOF_TMP $HPUX_BOOTFILE > ${LSOF_TMPC}.out 2>&1
+             if test $? -ne 0  # {
+             then
+               echo ""
+               echo ""
+               echo "!!!ERROR!!! $LSOF_TMP failed and produced the following output."
+               echo ""
+               cat ${LSOF_TMPC}.out
+               HPUX_IPC_S_PATCH=fail
+             else
+               grep ipis_s ${LSOF_TMPC}.out > /dev/null 2>&1
+               if test $? -eq 0        # {
+               then
+                 echo "ipis_s exists."
+
+               # See if ipis_msgsqueued is present.
+
+                 grep ipis_msgsqueued ${LSOF_TMPC}.out > /dev/null 2>&1
+                 if test $? -eq 0      # {
+                 then
+                   HPUX_IPC_S_PATCH=2
+                 else
+                   HPUX_IPC_S_PATCH=1
+                 fi    # }
+               else
+                 echo "ipis_s doesn't exist."
+                 HPUX_IPC_S_PATCH=N
+               fi      # }
+             fi        # }
+             rm -f ${LSOF_TMPC}.out
+           else
+             echo "Can't locate or execute $LSOF_TMP"
+             echo $EO "ls says: $EC"
+             ls -ld $LSOF_TMP
+             HPUX_IPC_S_PATCH=fail
+           fi  # }
+         fi    # }
+         if test "X$HPUX_IPC_S_PATCH" = "Xfail"        # {
+         then
+           echo ""
+           echo "!!!ERROR!!!     !!!ERROR!!!     !!!ERROR!!!     !!!ERROR!!!"
+           echo "Configure can't use $LSOF_TMP to examine the ipis_s"
+           echo "structure.  You must do that yourself, report the result in"
+           echo "the HPUX_IPC_S_PATCH environment variable, then repeat the"
+           echo "Configure step.  Consult the Configure script's use of"
+           echo "$LSOF_TMP and the 00XCONFIG file for information"
+           echo "on ipis_s testing and the setting of HPUX_IPC_S_PATCH."
+           echo "!!!ERROR!!!     !!!ERROR!!!     !!!ERROR!!!     !!!ERROR!!!"
+           echo ""
+           rm -f $LSOF_HLP
+           exit 1
+         fi    # }
+         if test "X$HPUX_IPC_S_PATCH" = "X1" -o "X$HPUX_IPC_S_PATCH" = "X2" # {
+         then
+           LSOF_CFGF="$LSOF_CFGF -DHAS_IPC_S_PATCH=$HPUX_IPC_S_PATCH"
+         else
+           if test "X$HPUX_IPC_S_PATCH" != "Xn" -a "X$HPUX_IPC_S_PATCH" != "XN" # {
+           then
+             echo "Illegal value for HPUX_IPC_S_PATCH: $HPUX_IPC_S_PATCH"
+             rm -f $LSOF_HLP
+             exit 1
+           fi  # }
+         fi    # }
+       fi      #}
+
+       # Manufacture an hpux_mount.h header file with a mount struct in it, as
+       # required.
+
+       if test -r ${LSOF_INCLUDE}/sys/mount.h  # {
+       then
+         LSOF_TMP1="dialects/${LSOF_DIALECT_DIR}/hpux_mount.h"
+         rm -f $LSOF_TMP1
+         echo "#if !defined(MANUFACTURED_HPUX_SYS_MOUNT_H)" > $LSOF_TMP1
+         echo "#define MANUFACTURED_HPUX_SYS_MOUNT_H" >> $LSOF_TMP1
+         echo "/* By lsof Configure:" `date` " */" >> $LSOF_TMP1
+         echo "struct mount" >> $LSOF_TMP1
+         sed '1,/struct mount/d' ${LSOF_INCLUDE}/sys/mount.h | sed -n '1,/m_dev/p' >> $LSOF_TMP1
+         echo "};" >> $LSOF_TMP1
+         echo "#endif" >> $LSOF_TMP1
+         LSOF_CFGF="$LSOF_CFGF -I`pwd`/dialects/${LSOF_DIALECT_DIR}"
+       fi      # }
+
+       # Test for OnlineJFS.
+
+       if test $LSOF_VERS -ge 1100     # {
+       then
+         if test "X$HPUX_HASONLINEJFS" = "X" -a -x /sbin/fs/vxfs/subtype  # {
+         then
+           LSOF_TMP1=`/sbin/fs/vxfs/subtype`
+           if test "X$LSOF_TMP1" = "Xvxfs3.3"
+           then
+             HPUX_HASONLINEJFS="Y"
+           fi  # }
+         fi    # }
+         if test "X$HPUX_HASONLINEJFS" = "XY" -o "X$HPUX_HASONLINEJFS" = "Xy"
+         # {
+         then
+           LSOF_CFGF="$LSOF_CFGF -DHASONLINEJFS"
+         fi    # }
+       fi      # }
+
+       # Test for AFS.
+
+       if test -r ${AFS_VICE}/etc/ThisCell     # {
+       then
+         if test "X$LSOF_SCRIPT_CALL" = "Xno"  # {
+         then
+           if test -r ./AFSHeaders -a -r ./AFSVersion  # {
+           then
+             LSOF_AFS="yes"
+           fi  # }
+         else
+           if test ! -x ./AFSConfig    # {
+           then
+             echo "Can't find or execute the AFSConfig script"
+             rm -f $LSOF_HLP
+             exit 1
+           fi  # }
+           ./AFSConfig
+           if test $? -eq 0 -a -r ./AFSHeaders -a -r ./AFSVersion      # {
+           then
+             LSOF_AFS="yes"
+           fi  # }
+         fi    # }
+         if test "X$LSOF_AFS" = "Xyes" # {
+         then
+           LSOF_AFSV=`cat ./AFSVersion | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1 \2/' | awk '{printf "%d%02d\n",\$1,\$2}'`
+           LSOF_CFGF="$LSOF_CFGF -DHAS_AFS=$LSOF_AFSV"
+           LSOF_DINC="$LSOF_DINC -I`cat ./AFSHeaders`"
+         fi    # }
+       fi      # }
+      else
+       echo "HP-UX base unrecognized: $HPUX_BASE"
+       rm -f $LSOF_HLP
+       exit 1
+      fi       # }
+    fi # }
+    ;;
+
+# Configure for Linux.
+
+  linux)
+    LSOF_TSTBIGF="-D_FILE_OFFSET_BITS=64"
+    LSOF_TSTKMEM=0
+    if test "X$LSOF_CC" = "X"  # {
+    then
+      LSOF_CC=cc
+      LSOF_CCV=`$LSOF_CC -v 2>&1 | sed -n 's/.*version \(.*\)/\1/p'`
+    fi # }
+    if test "X$LINUX_CONF_CC" = "X"    # {
+    then
+      LINUX_CONF_CC=$LSOF_CC
+    fi #}
+    LSOF_DIALECT_DIR=""
+    if test "X$LINUX_INCL" = "X" # {
+    then
+      LINUX_INCL=/usr/include
+    else
+      LSOF_DINC="$LSOF_DINC -I${LINUX_INCL}"
+    fi # }
+    if test "X$LINUX_VERSION_CODE" = "X" # {
+    then
+      if test -r "$LINUX_INCL/linux/version.h" # {
+      then
+        LINUX_VERSION_CODE=`cat $LINUX_INCL/linux/version.h | sed -n 's/.\+LINUX_VERSION_CODE \([[:digit:]]\+\)$/\1/p'`
+      fi # }
+    fi # }
+    LSOF_VSTR=`echo $LINUX_VERSION_CODE | perl -e '$version=<STDIN>; chomp($version); printf("%d.%d.%d\n", ($version >> 16) & 0xFF, ($version >> 8) & 0xFF, $version & 0xFF);'`
+    if test "X$LSOF_VSTR" = "X"        # {
+    then
+      LSOF_VSTR=`uname -r`
+    fi # }
+    if test "X$LSOF_VERS" = "X"        # {
+    then
+
+      # If the Linux version isn't predefined, determine it.
+
+      LSOF_VERS=`echo $LSOF_VSTR | sed 's/\./ /g' | awk '{printf "%d%d%03d",\$1,\$2,\$3}'`
+    fi # }
+    LSOF_CFGF="$LSOF_CFGF -DLINUXV=$LSOF_VERS"
+    if test $LSOF_VERS -lt 21072       # {
+    then
+      echo ""
+       echo "!!!WARNING!!!==!!!WARNING!!!==!!!WARNING!!!==!!!WARNING!!!"
+       echo "!                                                        !"
+       echo "! THE /PROC-BASED LSOF SOURCES HAVE NOT BEEN TESTED ON   !"
+       echo "! LINUX KERNELS BELOW 2.1.72, AND MAY NOT WORK ON THIS   !"
+       echo "! KERNEL.  IT SHOULD USE A /DEV/KMEM-BASED LSOF.         !"
+       echo "!                                                        !"
+       echo "!!!WARNING!!!==!!!WARNING!!!==!!!WARNING!!!==!!!WARNING!!!"
+       echo ""
+    else
+      LSOF_UNSUP=""
+    fi # }
+
+    # If the Linux C library type isn't predefined, determine it.
+
+    if test "X$LINUX_CLIB" = "X"       # {
+    then
+      echo -n "Testing C library type with $LINUX_CONF_CC ... "
+      rm -f ${LSOF_TMPC}.*
+      cat > $LSOF_TMPC.c << .LSOF_END_HERE_DOC1
+#include <features.h>
+#include <stdio.h>
+int main() {
+#if defined(__GLIBC__) && defined(__GLIBC_MINOR__)
+printf("-DGLIBCV=%d\n",__GLIBC__*100+__GLIBC_MINOR__);
+#elif defined(__GLIBC__)
+printf("-DGLIBCV=%d00\n",__GLIBC__);
+#else
+printf("\n");
+#endif
+return(0); }
+.LSOF_END_HERE_DOC1
+      $LINUX_CONF_CC ${LSOF_TMPC}.c -I$LSOF_INCLUDE -o ${LSOF_TMPC}.x > /dev/null 2>&1
+      if test -x ${LSOF_TMPC}.x        # {
+      then
+       LINUX_CLIB=`${LSOF_TMPC}.x`
+       LSOF_TMP=$?
+      else
+       LINUX_CLIB=""
+       LSOF_TMP=1
+      fi       # }
+      rm -f ${LSOF_TMPC}.*
+      echo "done"
+      if test $LSOF_TMP -ne 0  # {
+      then
+       echo "Cannot determine C library type; assuming it is not glibc."
+       LINUX_CLIB=""
+      else
+       if test "X$LINUX_CLIB" = "X"    # {
+       then
+         echo "The C library type is not glibc."
+       else
+         echo "The C library type is glibc, version \"$LINUX_CLIB\"."
+       fi      # }
+      fi       # }
+    fi # }
+    if test "X$LINUX_CLIB" != "X"      # {
+    then
+      LSOF_CFGF="$LSOF_CFGF $LINUX_CLIB"
+    fi # }
+
+    # Test for IPv6 support.
+
+    if test -r ${LSOF_INCLUDE}/netinet/ip6.h   # {
+    then
+      LSOF_CFGF="$LSOF_CFGF -DHASIPv6"
+    fi # }
+
+    # Test for <rpc/rpc.h>.
+
+    if test -r ${LSOF_INCLUDE}/rpc/rpc.h       # {
+    then
+      :        # Do nothing
+    elif test -r ${LSOF_INCLUDE}/tirpc/rpc/rpc.h
+    then
+      LSOF_DINC="${LSOF_DINC} -I${LSOF_INCLUDE}/tirpc"
+      LSOF_CFGL="${LSOF_CFGL} -ltirpc"
+    else
+      LSOF_CFGF="$LSOF_CFGF -DHASNORPC_H"
+    fi # }
+
+    # Test for TCP_* symbols.
+
+    if test -r ${LSOF_INCLUDE}/netinet/tcp.h   # (
+    then
+      grep -q TCP_ESTABLISHED ${LSOF_INCLUDE}/netinet/tcp.h
+      if test $? -eq 0 # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -DNEEDS_NETINET_TCPH"
+      fi       #}
+    fi # }
+
+    # Test for SELinux support.
+
+    LSOF_TMP1=0
+    if test "X$LINUX_HASSELINUX" = "X" # {
+    then
+      if test -r ${LSOF_INCLUDE}/selinux/selinux.h     # {
+      then
+       LSOF_TMP1=1
+      fi       # }
+    else
+      if test "X$LINUX_HASSELINUX" = "XY" -o "X$LINUX_HASSELINUX" = "Xy" # {
+      then
+       LSOF_TMP1=1
+      fi       # }
+    fi # }
+    if test $LSOF_TMP1 -eq 1   # {
+    then
+      LSOF_CFGF="$LSOF_CFGF -DHASSELINUX"
+      LSOF_CFGL="$LSOF_CFGL -lselinux"
+    fi # }
+
+  # Test for UNIX socket endpoint support.
+
+    if test -r ${LSOF_INCLUDE}/linux/sock_diag.h -a -r ${LSOF_INCLUDE}/linux/unix_diag.h  # {
+    then
+      LSOF_CFGF="$LSOF_CFGF -DHASUXSOCKEPT"
+    fi # }
+
+  # Test for pseudoterminal endpoint support.
+
+    if test -r ${LSOF_INCLUDE}/linux/major.h # {
+    then
+      grep -q TTYAUX_MAJOR ${LSOF_INCLUDE}/linux/major.h
+      if test $? -eq 0 # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -DHASPTYEPT"
+      fi       # }
+    fi # }
+
+  # Test for (unix) socket state support.
+
+    if test -f ${LSOF_INCLUDE}/linux/net.h # {
+    then
+      grep -q SS_CONNECTED ${LSOF_INCLUDE}/linux/net.h
+      if test $? -eq 0 # {
+      then
+        LSOF_CFGF="$LSOF_CFGF -DHASSOSTATE -DHASSOOPT"
+      fi       # }
+    fi # }
+
+  # Test for dup2 and closefrom
+
+    if test -f ${LSOF_INCLUDE}/unistd.h # {
+    then
+      grep -q dup2 ${LSOF_INCLUDE}/unistd.h
+      if test $? -eq 0 # {
+      then
+        LSOF_CFGF="$LSOF_CFGF -DHAS_DUP2"
+      fi       # }
+
+      grep -q closefrom ${LSOF_INCLUDE}/unistd.h
+      if test $? -eq 0 # {
+      then
+        LSOF_CFGF="$LSOF_CFGF -DHAS_CLOSEFROM"
+      fi       # }
+    fi # }
+
+    LSOF_DIALECT_DIR="linux"
+    LSOF_CFGF="$LSOF_CFGF -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE"
+    ;;
+
+# Configure for NetBSD.
+
+  netbsd)
+    if test "X$LSOF_CC" = "X"  # {
+    then
+      LSOF_CC=cc
+      LSOF_CCV=`$LSOF_CC -v 2>&1 | sed -n 's/.*version \(.*\)/\1/p'`
+    fi # }
+    if test "X$LSOF_VSTR" = "X"        # {
+    then
+      LSOF_VSTR=`uname -r`
+    fi # }
+    if test "X$LSOF_VERS" = "X"        # {
+    then
+
+      # Validate the NetBSD version.
+
+      case $LSOF_VSTR in       # {
+      1.2*)
+       LSOF_VERS="1002000"
+       ;;
+      1.3*)
+       LSOF_VERS="1003000"
+       ;;
+      1.4*)
+       LSOF_VERS="1004000"
+       ;;
+      1.5*)
+       LSOF_TSTBIGF=" "
+       LSOF_VERS="1005000"
+       ;;
+      1.6*)
+       LSOF_TSTBIGF=" "
+       LSOF_VERS="1006000"
+       ;;
+      1.*)
+       LSOF_VERS="1006000"
+       echo "!!!WARNING!!!  Unsupported NetBSD version: $LSOF_VSTR"
+       echo "!!!WARNING!!!  Configuring for NetBSD 1.6"
+       ;;
+      2.0*)
+       LSOF_TSTBIGF=" "
+       LSOF_VERS="2000000"
+       ;;
+      2.99.9)
+       LSOF_TSTBIGF=" "
+       LSOF_VERS="2099009"
+       ;;
+      2.99.10)
+       LSOF_TSTBIGF=" "
+       LSOF_VERS="2099010"
+       ;;
+      2.99.*)
+       LSOF_TSTBIGF=" "
+       LSOF_VERS="2099010"
+       ;;
+      2.*)
+       LSOF_VERS="2000000"
+       echo "!!!WARNING!!!  Unsupported NetBSD version: $LSOF_VSTR"
+       echo "!!!WARNING!!!  Configuring for NetBSD 2.0"
+       ;;
+      3.0*)
+       LSOF_TSTBIGF=" "
+       LSOF_VERS="3000000"
+       ;;
+      3.99.*)
+       LSOF_TSTBIGF=" "
+       LSOF_VERS="3099000"
+       ;;
+      3.*)
+       LSOF_VERS="3000000"
+       echo "!!!WARNING!!!  Unsupported NetBSD version: $LSOF_VSTR"
+       echo "!!!WARNING!!!  Configuring for NetBSD 3.0"
+       ;;
+      4.0*)
+       LSOF_TSTBIGF=" "
+       LSOF_VERS="4000000"
+       ;;
+      4.99.*)
+       LSOF_TSTBIGF=" "
+       LSOF_VERS="4099000"
+       ;;
+      4.*)
+       LSOF_VERS="4000000"
+       echo "!!!WARNING!!!  Unsupported NetBSD version: $LSOF_VSTR"
+       echo "!!!WARNING!!!  Configuring for NetBSD 4.0"
+       ;;
+      5.[012]*)
+       LSOF_TSTBIGF=" "
+       LSOF_VERS="5000000"
+       ;;
+      5.99.*)
+       LSOF_TSTBIGF=" "
+       LSOF_VERS="5099000"
+       ;;
+      5.*)
+       LSOF_VERS="5000000"
+       echo "!!!WARNING!!!  Unsupported NetBSD version: $LSOF_VSTR"
+       echo "!!!WARNING!!!  Configuring for NetBSD 5.0"
+       ;;
+      6.[01]*)
+       LSOF_TSTBIGF=" "
+       LSOF_VERS="6000000"
+       ;;
+      6.99.*)
+       LSOF_TSTBIGF=" "
+       LSOF_VERS="6099000"
+       ;;
+      6.*)
+       LSOF_VERS="6000000"
+       echo "!!!WARNING!!!  Unsupported NetBSD version: $LSOF_VSTR"
+       echo "!!!WARNING!!!  Configuring for NetBSD 6.0"
+       ;;
+      7.[01]*)
+       LSOF_TSTBIGF=" "
+       LSOF_VERS="7000000"
+       ;;
+      7.99.*)
+       LSOF_TSTBIGF=" "
+       LSOF_VERS="7099000"
+       ;;
+      7.*)
+       LSOF_VERS="7000000"
+       echo "!!!WARNING!!!  Unsupported NetBSD version: $LSOF_VSTR"
+       echo "!!!WARNING!!!  Configuring for NetBSD 7.0"
+       ;;
+      8.[0123]*)
+       LSOF_TSTBIGF=" "
+       LSOF_VERS="8000000"
+       ;;
+      8.99.*)
+       LSOF_TSTBIGF=" "
+       LSOF_VERS="8099000"
+       ;;
+      8.*)
+       LSOF_VERS="8000000"
+       echo "!!!WARNING!!!  Unsupported NetBSD version: $LSOF_VSTR"
+       echo "!!!WARNING!!!  Configuring for NetBSD 8.0"
+       ;;
+      9.[0123]*)
+       LSOF_TSTBIGF=" "
+       LSOF_VERS="9000000"
+       ;;
+      9.99.10[45678])
+       LSOF_TSTBIGF=" "
+       LSOF_VERS="9099104"
+       ;;
+      9.99.*)
+       LSOF_TSTBIGF=" "
+       LSOF_VERS="9099000"
+       ;;
+      9.*)
+       LSOF_VERS="9000000"
+       echo "!!!WARNING!!!  Unsupported NetBSD version: $LSOF_VSTR"
+       echo "!!!WARNING!!!  Configuring for NetBSD 9.0"
+       ;;
+      10.99.*)
+       LSOF_TSTBIGF=" "
+       LSOF_VERS="10099000"
+       ;;
+      10.*)
+       LSOF_VERS="10000000"
+       echo "!!!WARNING!!!  Unsupported NetBSD version: $LSOF_VSTR"
+       echo "!!!WARNING!!!  Configuring for NetBSD 10.0"
+       ;;
+      *)
+       echo "Unknown NetBSD release: $LSOF_VSTR"
+       echo Assuming NetBSD 10.0
+       LSOF_VERS="10000000"
+       ;;
+      esac     # }
+    fi # }
+
+    LSOF_CFGF="$LSOF_CFGF -DNETBSDV=$LSOF_VERS"
+
+    # For paddr_t
+    LSOF_CFGF="$LSOF_CFGF -D_KMEMUSER"
+    # For struct namecache
+    LSOF_CFGF="$LSOF_CFGF -D__NAMECACHE_PRIVATE"
+
+    LSOF_TMP1="-DN_UNIXV=/netbsd"
+    if test -r /dev/ksyms              # {
+    then
+      LSOF_TMP1="-DN_UNIXV=/dev/ksyms"
+    elif test -r ${LSOF_INCLUDE}/util.h        # {
+    then
+      grep -q getbootfile ${LSOF_INCLUDE}/util.h
+      if test $? -eq 0 # {
+      then
+       LSOF_CFGL="$LSOF_CFGL -lutil"
+       LSOF_TMP1="-DHASGETBOOTFILE"
+      fi       # }
+    fi # }
+    LSOF_CFGF="$LSOF_CFGF $LSOF_TMP1"
+    if test -r ${LSOF_INCLUDE}/kvm.h   # {
+    then
+      grep -q kvm_getproc2 ${LSOF_INCLUDE}/kvm.h
+      if test $? -eq 0 # {
+      then
+         LSOF_CFGF="$LSOF_CFGF -DHASKVMGETPROC2"
+      fi       # }
+    fi # }
+
+  # Here begin the dual tests on header files that may be in $LSOF_INCLUDE
+  # or $NETBSD_SYS.
+  #
+  # Note that $LSOF_TMP1 holds an indicator of the need for -I$NETBSD_SYS.
+  # LSOF_TMP4 contains a temporary indicator of the use of $NETBSD_SYS.
+
+    LSOF_TMP1=0
+    if test "X$NETBSD_SYS" = "X"       # {
+    then
+      if test -d /usr/src      # {
+      then
+       NETBSD_SYS="/usr/src/sys"
+      else
+       NETBSD_SYS=$LSOF_INCLUDE
+      fi       # }
+    fi # }
+    LSOF_TMP2="nfs/nfsproto.h"
+    if test -r ${LSOF_INCLUDE}/$LSOF_TMP2      # {
+    then
+      LSOF_TMP3="${LSOF_INCLUDE}/$LSOF_TMP2"
+      LSOF_TMP4=0
+    else
+      if test -r ${NETBSD_SYS}/$LSOF_TMP2      # {
+      then
+       LSOF_TMP3="${NETBSD_SYS}/$LSOF_TMP2"
+       LSOF_TMP4=1
+      else
+       LSOF_TMP3=""
+      fi       # }
+    fi # }
+    if test "X$LSOF_TMP3" != "X"       # {
+    then
+      LSOF_CFGF="$LSOF_CFGF -DHASNFSPROTO"
+      if test $LSOF_TMP1 -eq 0 -a $LSOF_TMP4 -eq 1     # {
+      then
+       LSOF_TMP1=1
+      fi       # }
+    fi # }
+    LSOF_TMP2="netinet/ip6.h"
+    if test -r ${LSOF_INCLUDE}/$LSOF_TMP2      # {
+    then
+      LSOF_TMP3="${LSOF_INCLUDE}/$LSOF_TMP2"
+      LSOF_TMP4=0
+    else
+      if test -r ${NETBSD_SYS}/$LSOF_TMP2      # {
+      then
+       LSOF_TMP3="${NETBSD_SYS}/$LSOF_TMP2"
+       LSOF_TMP4=1
+      else
+       LSOF_TMP3=""
+      fi       # }
+    fi # }
+    if test "X$LSOF_TMP3" != "X"       # {
+    then
+      LSOF_CFGF="$LSOF_CFGF -DHASIPv6"
+      if test $LSOF_TMP1 -eq 0 -a $LSOF_TMP4 -eq 1     # {
+      then
+       LSOF_TMP1=1
+      fi       # }
+    else
+      LSOF_TMP2="netinet/in.h"
+      if test -r ${LSOF_INCLUDE}/$LSOF_TMP2    # {
+      then
+       LSOF_TMP3="${LSOF_INCLUDE}/$LSOF_TMP2"
+       LSOF_TMP4=0
+      else
+       if test -r ${NETBSD_SYS}/$LSOF_TMP2     # {
+       then
+         LSOF_TMP3="${NETBSD_SYS}/$LSOF_TMP2"
+         LSOF_TMP4=1
+       else
+         LSOF_TMP3=""
+       fi      # }
+      fi       # }
+      if test "X$LSOF_TMP3" != "X"     # {
+      then
+       grep -q IPV6_INRIA_VERSION $LSOF_TMP3
+       if test $? -eq 0        # {
+       then
+         LSOF_CFGF="$LSOF_CFGF -DHASIPv6 -DHASINRIAIPv6"
+         if test $LSOF_TMP1 -eq 0 -a $LSOF_TMP4 -eq 1  # {
+         then
+           LSOF_TMP1=1
+         fi    # }
+       fi      # }
+      fi # }
+    fi # }
+    LSOF_TMP2="miscfs/fdesc/fdesc.h"
+    if test -r ${LSOF_INCLUDE}/$LSOF_TMP2      # {
+    then
+      LSOF_TMP3="${LSOF_INCLUDE}/$LSOF_TMP2"
+    else
+      if test -r ${NETBSD_SYS}/$LSOF_TMP2      # {
+      then
+       LSOF_TMP3="${NETBSD_SYS}/$LSOF_TMP2"
+       LSOF_TMP4=1
+      else
+       LSOF_TMP3=""
+      fi       # }
+    fi # }
+    if test "X$LSOF_TMP3" != "X"       # {
+    then
+      grep -q Fctty $LSOF_TMP3
+      if test $? -eq 0 # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -DHASFDESCFS=1"
+      else
+       LSOF_CFGF="$LSOF_CFGF -DHASFDESCFS=2"
+      fi       # }
+      grep -q fd_link $LSOF_TMP3
+      if test $? -eq 0 # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -DHASFDLINK"
+      fi       # }
+      if test $LSOF_TMP1 -eq 0 -a $LSOF_TMP4 -eq 1     # {
+      then
+       LSOF_TMP1=1
+      fi       # }
+    fi # }
+    LSOF_TMP2="miscfs/nullfs/null.h"
+    if test -r ${LSOF_INCLUDE}/$LSOF_TMP2      # {
+    then
+      LSOF_TMP3="${LSOF_INCLUDE}/$LSOF_TMP2"
+      LSOF_TMP4=0
+    else
+      if test -r ${NETBSD_SYS}/$LSOF_TMP2      # {
+      then
+       LSOF_TMP3="${NETBSD_SYS}/$LSOF_TMP2"
+       LSOF_TMP4=1
+      else
+       LSOF_TMP3=""
+      fi       # }
+    fi # }
+    if test "X$LSOF_TMP3" != "X"       # {
+    then
+      LSOF_CFGF="$LSOF_CFGF -DHASNULLFS"
+      if test $LSOF_TMP1 -eq 0 -a $LSOF_TMP4 -eq 1     # {
+      then
+       LSOF_TMP1=1
+      fi       # }
+    fi # }
+    LSOF_TMP2="miscfs/procfs"
+    if test -d ${LSOF_INCLUDE}/$LSOF_TMP2      # {
+    then
+      LSOF_TMP3="${LSOF_INCLUDE}/$LSOF_TMP2"
+      LSOF_TMP4=0
+    else
+      if test -d ${NETBSD_SYS}/$LSOF_TMP2      # {
+      then
+       LSOF_TMP3="${NETBSD_SYS}/$LSOF_TMP2"
+       LSOF_TMP4=1
+      else
+       LSOF_TMP3=""
+      fi       # }
+    fi # }
+    if test "X$LSOF_TMP3" != "X"       # {
+    then
+      LSOF_CFGF="$LSOF_CFGF -DHASPROCFS"
+      if test $LSOF_TMP1 -eq 0 -a $LSOF_TMP4 -eq 1     # {
+      then
+       LSOF_TMP1=1
+      fi       # }
+      if test -r ${LSOF_TMP3}/procfs.h # {
+      then
+       grep -q PFSroot ${LSOF_TMP3}/procfs.h
+       if test $? -eq 0        # {
+       then
+         LSOF_CFGF="$LSOF_CFGF -DHASPROCFS_PFSROOT"
+       fi #    }
+      fi       # }
+    fi # }
+    LSOF_TMP2="sys/bufq.h"
+    LSOF_NBSD_BUFQH=0
+    if test -r ${LSOF_INCLUDE}/$LSOF_TMP2      # {
+    then
+      LSOF_CFGF="$LSOF_CFGF -DHASBUFQ_H"
+    else
+      if test -r ${NETBSD_SYS}/$LSOF_TMP2      # {
+      then
+       if test $NETBSD_SYS != $LSOF_INCLUDE    # {
+       then
+         LSOF_CFGF="$LSOF_CFGF -DHASBUFQ_H"
+         LSOF_NBSD_BUFQH=1
+       fi      # }
+      fi       # }
+    fi # }
+    LSOF_TMP2="isofs/cd9660"
+    if test -d ${LSOF_INCLUDE}/$LSOF_TMP2      # {
+    then
+      LSOF_TMP3="${LSOF_INCLUDE}/$LSOF_TMP2"
+      LSOF_TMP4=0
+    else
+      if test -d ${NETBSD_SYS}/$LSOF_TMP2      # {
+      then
+       LSOF_TMP3="${NETBSD_SYS}/$LSOF_TMP2"
+       LSOF_TMP4=1
+      else
+       LSOF_TMP3=""
+      fi       # }
+    fi # }
+    if test "X$LSOF_TMP3" != "X"       # {
+    then
+      LSOF_CFGF="$LSOF_CFGF -DHAS9660FS=1"
+      if test $LSOF_TMP1 -eq 0 -a $LSOF_TMP4 -eq 1     # {
+      then
+       LSOF_TMP1=1
+      fi       # }
+    else
+      LSOF_TMP2="fs/cd9660"
+      if test -d ${LSOF_INCLUDE}/$LSOF_TMP2    # {
+      then
+       LSOF_TMP3="${LSOF_INCLUDE}/$LSOF_TMP2"
+       LSOF_TMP4=0
+      else
+       if test -d ${NETBSD_SYS}/$LSOF_TMP2     # {
+       then
+         LSOF_TMP3="${NETBSD_SYS}/$LSOF_TMP2"
+         LSOF_TMP4=1
+       else
+         LSOF_TMP3=""
+       fi      # }
+      fi       # }
+      if test "X$LSOF_TMP3" != "X"     # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -DHAS9660FS=1"
+       if test $LSOF_TMP1 -eq 0 -a $LSOF_TMP4 -eq 1    # {
+       then
+         LSOF_TMP1=1
+       fi      # }
+      fi       # }
+    fi # }
+    LSOF_TMP2="msdosfs"
+    if test -d ${LSOF_INCLUDE}/$LSOF_TMP2      # {
+    then
+      LSOF_TMP3="${LSOF_INCLUDE}/$LSOF_TMP2"
+      LSOF_TMP4=0
+    else
+      if test -d ${NETBSD_SYS}/$LSOF_TMP2      # {
+      then
+       LSOF_TMP3="${NETBSD_SYS}/$LSOF_TMP2"
+       LSOF_TMP4=1
+      else
+       LSOF_TMP3=""
+      fi       # }
+    fi # }
+    if test "X$LSOF_TMP3" != "X"       # {
+    then
+      LSOF_CFGF="$LSOF_CFGF -DHASMSDOSFS=1"
+      if test $LSOF_TMP1 -eq 0 -a $LSOF_TMP4 -eq 1     # {
+      then
+       LSOF_TMP1=1
+      fi       # }
+    else
+      LSOF_TMP2="fs/msdosfs"
+      if test -d ${LSOF_INCLUDE}/$LSOF_TMP2    # {
+      then
+       LSOF_TMP3="${LSOF_INCLUDE}/$LSOF_TMP2"
+       LSOF_TMP4=0
+      else
+       if test -d ${NETBSD_SYS}/$LSOF_TMP2     # {
+       then
+         LSOF_TMP3="${NETBSD_SYS}/$LSOF_TMP2"
+         LSOF_TMP4=1
+       else
+         LSOF_TMP3=""
+       fi      # }
+      fi       # }
+      if test "X$LSOF_TMP3" != "X"     # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -DHASMSDOSFS=2"
+       if test $LSOF_TMP1 -eq 0 -a $LSOF_TMP4 -eq 1    # {
+       then
+         LSOF_TMP1=1
+       fi      # }
+      fi       # }
+    fi # }
+    LSOF_TMP2="miscfs/kernfs/kernfs.h"
+    if test -r ${LSOF_INCLUDE}/$LSOF_TMP2      # {
+    then
+      LSOF_TMP3="${LSOF_INCLUDE}/$LSOF_TMP2"
+      LSOF_TMP4=0
+    else
+      if test -r ${NETBSD_SYS}/$LSOF_TMP2      # {
+      then
+       LSOF_TMP3="${NETBSD_SYS}/$LSOF_TMP2"
+       LSOF_TMP4=1
+      else
+       LSOF_TMP3=""
+      fi       # }
+    fi # }
+    if test "X$LSOF_TMP3" != "X"       # {
+    then
+      grep -q "kt_name;" $LSOF_TMP3
+      if test $? -eq 0 # {
+       then
+         LSOF_CFGF="$LSOF_CFGF -DHASKERNFS"
+         if test $LSOF_TMP1 -eq 0 -a $LSOF_TMP4 -eq 1  # {
+         then
+           LSOF_TMP1=1
+         fi    # }
+         grep -q "*kfs_kt;" $LSOF_TMP3
+         if test $? -eq 0      # {
+         then
+           LSOF_CFGF="$LSOF_CFGF -DHASKERNFS_KFS_KT"
+         fi    # }
+      fi       # }
+    fi # }
+    LSOF_TMP2="sys/namei.h"
+    if test -r ${LSOF_INCLUDE}/$LSOF_TMP2      # {
+    then
+      LSOF_TMP3="${LSOF_INCLUDE}/$LSOF_TMP2"
+      LSOF_TMP4=0
+    else
+      if test -r ${NETBSD_SYS}/$LSOF_TMP2      # {
+      then
+       LSOF_TMP3="${NETBSD_SYS}/$LSOF_TMP2"
+       LSOF_TMP4=1
+      else
+       LSOF_TMP3=""
+      fi       # }
+    fi # }
+    if test "X$LSOF_TMP3" != "X"       # {
+    then
+      grep -q nc_vpid $LSOF_TMP3
+      if test $? -eq 0 # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -DHASNCVPID"
+       if test $LSOF_TMP1 -eq 0 -a $LSOF_TMP4 -eq 1    # {
+       then
+         LSOF_TMP1=1
+       fi      # }
+      fi       # }
+    fi # }
+    LSOF_TMP2="ufs/ufs/inode.h"
+    if test -r ${LSOF_INCLUDE}/$LSOF_TMP2      # {
+    then
+      LSOF_TMP3="${LSOF_INCLUDE}/$LSOF_TMP2"
+      LSOF_TMP4=0
+    else
+      if test -r ${NETBSD_SYS}/$LSOF_TMP2      # {
+      then
+       LSOF_TMP3="${NETBSD_SYS}/$LSOF_TMP2"
+       LSOF_TMP4=1
+      else
+       LSOF_TMP3=""
+      fi       # }
+    fi # }
+    if test "X$LSOF_TMP3" != "X"       # {
+    then
+      grep -q i_ffs_size $LSOF_TMP3
+      if test $? -eq 0 # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -DHASI_FFS"
+       if test $LSOF_TMP1 -eq 0 -a $LSOF_TMP4 -eq 1    # {
+       then
+         LSOF_TMP1=1
+       fi      # }
+      else
+       grep -q i_ffs1_size $LSOF_TMP3
+       if test $? -eq 0        # {
+       then
+         LSOF_CFGF="$LSOF_CFGF -DHASI_FFS1"
+         if test $LSOF_TMP1 -eq 0 -a $LSOF_TMP4 -eq 1  # {
+         then
+           LSOF_TMP1=1
+         fi    # }
+       fi      # }
+      fi       # }
+      grep -q i_ffs_effnlink $LSOF_TMP3
+      if test $? -eq 0 # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -DHASEFFNLINK=i_ffs_effnlink"
+       if test $LSOF_TMP1 -eq 0 -a $LSOF_TMP4 -eq 1    # {
+       then
+         LSOF_TMP1=1
+       fi      # }
+      fi       # }
+    fi # }
+    LSOF_TMP2="sys/vnode.h"
+    LSOF_NBSD_PTYFS=0
+    LSOF_NBSD_TMPFS=0
+    if test -r ${LSOF_INCLUDE}/$LSOF_TMP2      # {
+    then
+      LSOF_TMP3="${LSOF_INCLUDE}/$LSOF_TMP2"
+      LSOF_TMP4=0
+    else
+      if test -r ${NETBSD_SYS}/$LSOF_TMP2      # {
+      then
+       LSOF_TMP3="${NETBSD_SYS}/$LSOF_TMP2"
+       LSOF_TMP4=1
+      else
+       LSOF_TMP3=""
+      fi       # }
+    fi # }
+    if test "XLSOF_TMP3" != "X"        # {
+    then
+      grep -q VT_EXT2FS $LSOF_TMP3
+      if test $? -eq 0 # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -DHASEXT2FS"
+       if test $LSOF_TMP1 -eq 0 -a $LSOF_TMP4 -eq 1    # {
+       then
+         LSOF_TMP1=1
+       fi      # }
+       LSOF_TMP2="ufs/ufs/inode.h"
+       if test -r ${LSOF_INCLUDE}/$LSOF_TMP2   # {
+       then
+         LSOF_TMP5="${LSOF_INCLUDE}/$LSOF_TMP2"
+         LSOF_TMP6=0
+       else
+         if test -r ${NETBSD_SYS}/$LSOF_TMP2   # {
+         then
+           LSOF_TMP5="${NETBSD_SYS}/$LSOF_TMP2"
+           LSOF_TMP6=1
+         else
+           LSOF_TMP5=""
+         fi    # }
+       fi      # }
+       if test "X$LSOF_TMP5" != "X"    # {
+       then
+         grep -q "*e2fs_din" $LSOF_TMP5
+         if test $? -eq 0      # {
+         then
+           LSOF_CFGF="$LSOF_CFGF -DHASI_E2FS_PTR"
+           if test $LSOF_TMP1 -eq 0 -a $LSOF_TMP4 -eq 1        # {
+           then
+             LSOF_TMP1=$LSOF_TMP6
+           fi  # }
+         fi    # }
+       fi      # }
+      fi       # }
+      grep -q VT_LFS $LSOF_TMP3
+      if test $? -eq 0   # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -DHASLFS"
+       if test $LSOF_TMP1 -eq 0 -a $LSOF_TMP4 -eq 1    # {
+       then
+         LSOF_TMP1=1
+       fi      # }
+      fi       # }
+      grep -q VT_PTYFS $LSOF_TMP3
+      if test $? -eq 0   # {
+      then
+       LSOF_TMP2="fs/ptyfs/ptyfs.h"
+       if test -r ${LSOF_INCLUDE}/$LSOF_TMP2   # {
+       then
+         LSOF_CFGF="$LSOF_CFGF -DHASPTYFS"
+       else
+         if test -r ${NETBSD_SYS}/$LSOF_TMP2   # {
+         then
+           if test $NETBSD_SYS != $LSOF_INCLUDE        # {
+           then
+             LSOF_CFGF="$LSOF_CFGF -DHASPTYFS"
+             LSOF_NBSD_PTYFS=1
+           fi  # }
+         fi    # }
+       fi      # }
+      fi       # }
+      grep -q VT_TMPFS $LSOF_TMP3
+      if test $? -eq 0   # {
+      then
+       LSOF_TMP2="fs/tmpfs/tmpfs.h"
+       if test -r ${LSOF_INCLUDE}/$LSOF_TMP2   # {
+       then
+         LSOF_CFGF="$LSOF_CFGF -DHASTMPFS"
+       else
+         if test -r ${NETBSD_SYS}/$LSOF_TMP2   # {
+         then
+           if test $NETBSD_SYS != $LSOF_INCLUDE        # {
+           then
+             LSOF_CFGF="$LSOF_CFGF -DHASTMPFS"
+             LSOF_NBSD_TMPFS=1
+           fi  # }
+         fi    # }
+       fi      # }
+      fi       # }
+      if test "X$NETBSD_UVM" = "X"     # {
+      then
+       if test -r ${LSOF_INCLUDE}/uvm  # {
+       then
+         NETBSD_UVM="Y"
+       fi      # }
+      fi       # }
+    fi # }
+    LSOF_TMP2="nfs/nfsnode.h"
+    if test -r ${LSOF_INCLUDE}/$LSOF_TMP2      # {
+    then
+      LSOF_TMP3="${LSOF_INCLUDE}/$LSOF_TMP2"
+      LSOF_TMP4=0
+    else
+      if test -r ${NETBSD_SYS}/$LSOF_TMP2      # {
+      then
+       LSOF_TMP3="${NETBSD_SYS}/$LSOF_TMP2"
+       LSOF_TMP4=1
+      else
+       LSOF_TMP3=""
+      fi       # }
+    fi # }
+    if test "X$LSOF_TMP3" != "X"       # {
+    then
+      grep -q "*n_vattr" $LSOF_TMP3
+      if test $? -eq 0 # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -DHASNFSVATTRP"
+       if test $LSOF_TMP1 -eq 0 -a $LSOF_TMP4 -eq 1    # {
+       then
+         LSOF_TMP1=1
+       fi      # }
+      fi       # }
+    fi # }
+    LSOF_TMP2="sys/lockf.h"
+    if test -r ${LSOF_INCLUDE}/$LSOF_TMP2      # {
+    then
+      LSOF_TMP3="${LSOF_INCLUDE}/$LSOF_TMP2"
+      LSOF_TMP4=0
+    else
+      if test -r ${NETBSD_SYS}/$LSOF_TMP2      # {
+      then
+       LSOF_TMP3="${NETBSD_SYS}/$LSOF_TMP2"
+       LSOF_TMP4=1
+      else
+       LSOF_TMP3=""
+      fi       # }
+    fi # }
+    if test "X$LSOF_TMP3" != "X"       # {
+    then
+      grep -q vop_advlock_args $LSOF_TMP3
+      if test $? -eq 0 # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -DHAS_ADVLOCK_ARGS"
+       if test $LSOF_TMP1 -eq 0 -a $LSOF_TMP4 -eq 1    # {
+       then
+         LSOF_TMP1=1
+       fi      # }
+      fi       # }
+      grep -q lf_lwp $LSOF_TMP3
+      if test $? -eq 0 # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -DHAS_LF_LWP"
+       if test $LSOF_TMP1 -eq 0 -a $LSOF_TMP4 -eq 1    # {
+       then
+         LSOF_TMP1=1
+       fi      # }
+      fi       # }
+    fi # }
+    LSOF_TMP2="sys/lwp.h"
+    if test -r ${LSOF_INCLUDE}/$LSOF_TMP2      # {
+    then
+      LSOF_TMP3="${LSOF_INCLUDE}/$LSOF_TMP2"
+      LSOF_TMP4=0
+    else
+      if test -r ${NETBSD_SYS}/$LSOF_TMP2      # {
+      then
+       LSOF_TMP3="${NETBSD_SYS}/$LSOF_TMP2"
+       LSOF_TMP4=1
+      else
+       LSOF_TMP3=""
+      fi       # }
+    fi # }
+    if test "X$LSOF_TMP3" != "X"       # {
+    then
+      LSOF_CFGF="$LSOF_CFGF -DHAS_LWP_H"
+      if test $LSOF_TMP1 -eq 0 -a $LSOF_TMP4 -eq 1     # {
+      then
+       LSOF_TMP1=1
+      fi       # }
+    fi # }
+    LSOF_TMP2="sys/filedesc.h"
+    if test -r ${LSOF_INCLUDE}/$LSOF_TMP2      # {
+    then
+      LSOF_TMP3="${LSOF_INCLUDE}/$LSOF_TMP2"
+      LSOF_TMP4=0
+    else
+      if test -r ${NETBSD_SYS}/$LSOF_TMP2      # {
+      then
+       LSOF_TMP3="${NETBSD_SYS}/$LSOF_TMP2"
+       LSOF_TMP4=1
+      else
+       LSOF_TMP3=""
+      fi       # }
+    fi # }
+    if test "X$LSOF_TMP3" != "X"       # {
+    then
+      grep -q "^struct cwdinfo {" $LSOF_TMP3
+      if test $? -eq 0 # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -DHASCWDINFO"
+       if test $LSOF_TMP1 -eq 0 -a $LSOF_TMP4 -eq 1    # {
+       then
+         LSOF_TMP1=1
+       fi      # }
+      fi       # }
+    fi # }
+    LSOF_TMP2="sys/pipe.h"
+    if test -r ${LSOF_INCLUDE}/$LSOF_TMP2      # {
+    then
+      LSOF_TMP3="${LSOF_INCLUDE}/$LSOF_TMP2"
+      LSOF_TMP4=0
+    else
+      if test -r ${NETBSD_SYS}/$LSOF_TMP2      # {
+      then
+       LSOF_TMP3="${NETBSD_SYS}/$LSOF_TMP2"
+       LSOF_TMP4=1
+      else
+       LSOF_TMP3=""
+      fi       # }
+    fi # }
+    if test "X$LSOF_TMP3" != "X"       # {
+    then
+      LSOF_CFGF="$LSOF_CFGF -DHAS_SYS_PIPEH"
+      if test $LSOF_TMP1 -eq 0 -a $LSOF_TMP4 -eq 1     # {
+      then
+       LSOF_TMP1=1
+      fi       # }
+    fi # }
+    if test -r ${LSOF_INCLUDE}/sys/statvfs.h   # {
+    then
+      grep -q '^struct statvfs {' ${LSOF_INCLUDE}/sys/statvfs.h
+      if test $? -eq 0 # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -DHASSTATVFS"
+      fi       # }
+    fi # }
+
+  # Here end the dual NetBSD tests for header files in $LSOF_INCLUDE or
+  # NETBSD_SYS.
+  #
+  # After this LSOF_TMP1 may be reused.
+
+    if test $LSOF_TMP1 -eq 1   # {
+    then
+      LSOF_DINC="-I$LSOF_INCLUDE -I$NETBSD_SYS"
+    fi # }
+
+  # Build special header files, as required.
+
+    rm -rf lib/dialects/netbsd/include
+    if test "X$NETBSD_UVM" = "XY" -o "X$NETBSD_UVM" = "Xy"     # {
+    then
+      mkdir lib/dialects/netbsd/include
+      touch lib/dialects/netbsd/include/opt_uvmhist.h
+      touch lib/dialects/netbsd/include/opt_lockdebug.h
+      LSOF_CFGF="$LSOF_CFGF -DUVM -I`pwd`/lib/dialects/netbsd/include"
+      if test -d ${LSOF_INCLUDE}/uvm   # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -DHAS_UVM_INCL"
+      fi       # }
+    fi # }
+    LSOF_TMP2="sys/mount.h"
+    if test -r ${LSOF_INCLUDE}/$LSOF_TMP2      # {
+    then
+      LSOF_TMP3="${LSOF_INCLUDE}/$LSOF_TMP2"
+    else
+      if test -r ${NETBSD_SYS}/$LSOF_TMP2      # {
+      then
+       LSOF_TMP3="${NETBSD_SYS}/$LSOF_TMP2"
+      else
+       LSOF_TMP3=""
+      fi       # }
+    fi # }
+    if test "X$LSOF_TMP3" != "X"       # {
+    then
+
+      # Build a local NetBSD netexport.h header file for possible use by
+      # <msdosfs/msdosfsmount.h>.  Make sure CFGL contains a -I for it.
+
+      LSOF_TMP1=${LSOF_TMPC}.edscr
+      LSOF_TMP2=${LSOF_TMPC}.netcred
+      LSOF_TMP3=${LSOF_TMPC}.netexport
+      LSOF_TMP4=lib/dialects/netbsd/include/netexport.h
+      if test ! -d lib/dialects/netbsd/include # {
+      then
+       mkdir lib/dialects/netbsd/include
+      fi       # }
+      rm -f $LSOF_TMP1 $LSOF_TMP2 $LSOF_TMP3 $LSOF_TMP4
+      echo "/^struct netcred" > $LSOF_TMP1
+      echo "1,.-1d" >> $LSOF_TMP1
+      echo "/^};" >> $LSOF_TMP1
+      echo "1,.w $LSOF_TMP2" >> $LSOF_TMP1
+      ed ${LSOF_INCLUDE}/sys/mount.h < $LSOF_TMP1 > /dev/null 2>&1
+      rm -f $LSOF_TMP1
+      echo "/^struct netexport" > $LSOF_TMP1
+      echo "1,.-1d" >> $LSOF_TMP1
+      echo "/^};" >> $LSOF_TMP1
+      echo "1,.w $LSOF_TMP3" >> $LSOF_TMP1
+      ed ${LSOF_INCLUDE}/sys/mount.h < $LSOF_TMP1 > /dev/null 2>&1
+      echo "/*" > $LSOF_TMP4
+      echo " * netexport.h" >> $LSOF_TMP4
+      echo -n " * Created by Configure: " >> $LSOF_TMP4
+      echo `date` >> $LSOF_TMP4
+      echo " */" >> $LSOF_TMP4
+      echo "" >> $LSOF_TMP4
+      echo "#if        !defined(NETEXPORT_H)" >> $LSOF_TMP4
+      echo "#define    NETEXPORT_H" >> $LSOF_TMP4
+      echo "" >> $LSOF_TMP4
+      echo "#include <net/radix.h>" >> $LSOF_TMP4
+      echo "" >> $LSOF_TMP4
+      if test -r $LSOF_TMP2    # {
+      then
+       cat $LSOF_TMP2 >> $LSOF_TMP4
+       echo "" >> $LSOF_TMP4
+      fi       # }
+      if test -r $LSOF_TMP3    # {
+      then
+       cat $LSOF_TMP3 >> $LSOF_TMP4
+      fi       # }
+      echo "#endif     /* !defined(NETEXPORT_H) */" >> $LSOF_TMP4
+      rm -f $LSOF_TMP1 $LSOF_TMP2 $LSOF_TMP3
+      echo $LSOF_CFGF | grep /lib/dialects/netbsd/include > /dev/null 2>&1
+      if test $? -ne 0 # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -I`pwd`/lib/dialects/netbsd/include"
+      fi       # }
+    fi # }
+    if test $LSOF_NBSD_BUFQH -eq 1     # {
+    then
+
+    # Make a local copy of $NETBSD_SYS/sys/bufq.h.
+
+      if test ! -d lib/dialects/netbsd/include # {
+      then
+       mkdir lib/dialects/netbsd/include
+      fi       # }
+      if test ! -d lib/dialects/netbsd/include/sys     # {
+      then
+       mkdir lib/dialects/netbsd/include/sys
+      fi       # }
+      cp $NETBSD_SYS/sys/bufq.h lib/dialects/netbsd/include/sys
+      echo $LSOF_CFGF | grep lib/dialects/netbsd/include > /dev/null 2>&1
+      if test $? -ne 0 # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -I`pwd`lib/dialects/netbsd/include"
+      fi       # }
+    fi # }
+    if test $LSOF_NBSD_PTYFS -eq 1     # {
+    then
+
+    # Make a local copy of $NETBSD_SYS/sys/fs/ptyfs/.
+
+      if test ! -d lib/dialects/netbsd/include # {
+      then
+       mkdir lib/dialects/netbsd/include
+      fi       # }
+      if test ! -d lib/dialects/netbsd/include/fs      # {
+      then
+       mkdir lib/dialects/netbsd/include/fs
+      fi       # }
+      rm -rf lib/dialects/netbsd/include/fs/ptyfs
+      mkdir lib/dialects/netbsd/include/fs/ptyfs
+      cp $NETBSD_SYS/fs/ptyfs/*.h lib/dialects/netbsd/include/fs/ptyfs
+      echo $LSOF_CFGF | grep lib/dialects/netbsd/include > /dev/null 2>&1
+      if test $? -ne 0 # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -I`pwd`/lib/dialects/netbsd/include"
+      fi       # }
+    fi # }
+    if test $LSOF_NBSD_TMPFS -eq 1     # {
+    then
+
+    # Make a local copy of $NETBSD_SYS/sys/fs/tmpfs/tmpfs.h.
+
+      if test ! -d lib/dialects/netbsd/include     # {
+      then
+       mkdir lib/dialects/netbsd/include
+      fi       # }
+      if test ! -d lib/dialects/netbsd/include/fs  # {
+      then
+       mkdir lib/dialects/netbsd/include/fs
+      fi       # }
+      rm -rf lib/dialects/netbsd/include/fs/tmpfs
+      mkdir lib/dialects/netbsd/include/fs/tmpfs
+      cp $NETBSD_SYS/fs/tmpfs/tmpfs.h lib/dialects/netbsd/include/fs/tmpfs
+      echo $LSOF_CFGF | grep lib/dialects/netbsd/include > /dev/null 2>&1
+      if test $? -ne 0 # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -I`pwd`lib/dialects/netbsd/include"
+      fi       # }
+    fi # }
+
+    # Generate lockf.h from kern/vfs_lockf.c
+    rm -f ./lockf.h
+    if test -r ${NETBSD_SYS}/kern/vfs_lockf.c  # {
+    then
+      # Find the line number of TAILQ_HEAD
+      LSOF_TMP1=`grep -n "^TAILQ_HEAD" ${NETBSD_SYS}/kern/vfs_lockf.c | sed 's/\([0-9]*\):.*$/\1/'`
+      if test "X$LSOF_TMP1" != "X"     # {
+      then
+        LSOF_TMP2=0
+        # Find the end of struct lockf
+        for i in `grep -n "};" ${NETBSD_SYS}/kern/vfs_lockf.c | sed 's/\([0-9]*\):.*/\1/'` # {
+        do
+          if test $LSOF_TMP2 -eq 0 -a $i -gt $LSOF_TMP1        # {
+          then
+            LSOF_TMP2=$i
+          fi   # }
+        done   # }
+        if test $LSOF_TMP2 -eq 0       # {
+        then
+          LSOF_TMP1=""
+        else
+          cat > ./lockf.h << LOCKF1
+/*
+* lockf_owner.h -- created by lsof configure script on
+LOCKF1
+          printf " * " >> ./lockf.h
+          date >> ./lockf.h
+          cat >> ./lockf.h << LOCKF2
+*/
+
+#if    !defined(LOCKF_H)
+#define        LOCKF_H
+
+LOCKF2
+          ed -s ${NETBSD_SYS}/kern/vfs_lockf.c >> ./lockf.h << LOCKF3
+${LSOF_TMP1},${LSOF_TMP2}p
+LOCKF3
+          if test $? -ne 0     # {
+          then
+           LSOF_TMP1=""
+          else
+           cat >> ./lockf.h << LOCKF4
+
+#endif /* defined(LOCKF_H) */
+LOCKF4
+         fi    # }
+        fi     # }
+      fi       # }
+    else
+      echo "FATAL ERROR: can't read ${NETBSD_SYS}/kern/vfs_lockf.c"
+    fi # }
+
+    if test "X$LSOF_TMP1" != "X" -a "X$LSOF_TMP2" != "X0" # {
+    then
+      echo "lockf.h creation succeeded."
+      LSOF_CFGF="$LSOF_CFGF -DHAS_LOCKF_H"
+    else
+      echo "lockf.h creation failed (see 00FAQ)"
+    fi # }
+
+    LSOF_CFGL="$LSOF_CFGL -lkvm"
+    LSOF_DIALECT_DIR=netbsd
+    ;;
+
+# Configure for OpenBSD.  (OpenBSD uses NetBSD dialect sources and version
+# numbering.
+
+  openbsd)
+    LSOF_TSTKMEM=0
+    if test "X$LSOF_CC" = "X"  # {
+    then
+      LSOF_CC=cc
+      LSOF_CCV=`$LSOF_CC -v 2>&1 | sed -n 's/.*version \(.*\)/\1/p'`
+    fi # }
+    if test "X$LSOF_VSTR" = "X"        # {
+    then
+      LSOF_VSTR=`uname -r`
+    fi # }
+    if test "X$LSOF_VERS" = "X"        # {
+    then
+
+      # If the OpenBSD version isn't pre-defined, determine it.
+
+      case $LSOF_VSTR in       # {
+      1*)
+       LSOF_VERS=1020
+       echo "!!!WARNING!!!  Unsupported OpenBSD 1.x version: $LSOF_VSTR"
+       echo "!!!WARNING!!!  Configuring for OpenBSD 1.2"
+       ;;
+      2.5*)
+       LSOF_VERS=2050
+       ;;
+      2.6*)
+       LSOF_VERS=2060
+       ;;
+      2.7*)
+       LSOF_TSTBIGF=" "
+       LSOF_VERS=2070
+       ;;
+      2.8*)
+       LSOF_TSTBIGF=" "
+       LSOF_VERS=2080
+       ;;
+      2.9*)
+       LSOF_TSTBIGF=" "
+       LSOF_VERS=2090
+       ;;
+      2*)
+       LSOF_TSTBIGF=" "
+       LSOF_VERS=2090
+       echo "!!!WARNING!!!  Unsupported OpenBSD 2.x version: $LSOF_VSTR"
+       echo "!!!WARNING!!!  Configuring for OpenBSD 2.9"
+       ;;
+      3.0*)
+       LSOF_TSTBIGF=" "
+       LSOF_VERS=3000
+       ;;
+      3.1*)
+       LSOF_TSTBIGF=" "
+       LSOF_VERS=3010
+       ;;
+      3.2*)
+       LSOF_TSTBIGF=" "
+       LSOF_VERS=3020
+       ;;
+      3.3*)
+       LSOF_TSTBIGF=" "
+       LSOF_VERS=3030
+       ;;
+      3.4*)
+       LSOF_TSTBIGF=" "
+       LSOF_VERS=3040
+       ;;
+      3.5*)
+       LSOF_TSTBIGF=" "
+       LSOF_VERS=3050
+       ;;
+      3.6*)
+       LSOF_TSTBIGF=" "
+       LSOF_VERS=3060
+       ;;
+      3.7*)
+       LSOF_TSTBIGF=" "
+       LSOF_VERS=3070
+       ;;
+      3.8*)
+       LSOF_TSTBIGF=" "
+       LSOF_VERS=3080
+       ;;
+      3.9*)
+       LSOF_TSTBIGF=" "
+       LSOF_VERS=3090
+       ;;
+      3*)
+       LSOF_TSTBIGF=" "
+       LSOF_VERS=3090
+       echo "!!!WARNING!!!  Unsupported OpenBSD 3.x version: $LSOF_VSTR"
+       echo "!!!WARNING!!!  Configuring for OpenBSD 3.9"
+       ;;
+      7.2*)
+       LSOF_TSTBIGF=" "
+       LSOF_VERS=7020
+       ;;
+      7.3*)
+       LSOF_TSTBIGF=" "
+       LSOF_VERS=7030
+       ;;
+      *)
+       echo "Unknown OpenBSD release: $LSOF_VSTR"
+       echo Assuming OpenBSD 3.9
+       LSOF_VERS=3090
+       ;;
+      esac     # }
+    fi # }
+
+    # Test for legal OpenBSD version.
+
+    case $LSOF_VERS in # {
+    1020|2050|2060|2070|2080|2090|3000|3010|3020|3030|3040|3050|3060|3070|3080|3090|7020|7030)
+      ;;
+    *)
+      echo "Unknown OpenBSD version: $LSOF_VERS"
+      rm -f $LSOF_HLP
+      exit 1
+      ;;
+    esac       # }
+
+    LSOF_CFGF="$LSOF_CFGF -DOPENBSDV=$LSOF_VERS"
+
+    if test -r ${LSOF_INCLUDE}/netinet6/in6.h  # {
+    then
+      LSOF_CFGF="$LSOF_CFGF -DHASIPv6"
+    fi # }
+
+    if test "X$OPENBSD_SYS" = "X"      # {
+    then
+      OPENBSD_SYS="/sys"
+    fi # }
+
+    if test -d ${OPENBSD_SYS}/miscfs/procfs    # {
+    then
+      LSOF_CFGF="$LSOF_CFGF -DHASPROCFS"
+    fi # }
+
+    if test -r ${LSOF_INCLUDE}/sys/pipe.h      # {
+    then
+      LSOF_CFGF="$LSOF_CFGF -DHAS_SYS_PIPEH"
+    fi # }
+
+    LSOF_DIALECT_DIR=openbsd
+    ;;
+
+# Configure for SCO OpenServer.
+
+  osr|osrgcc|sco|scogcc)
+    if test "X$LSOF_RANLIB_SUP" = "X"  # {
+    then
+      LSOF_RANLIB=""
+    fi # }
+    if test "X$OSR_CFGF" != "X"        # {
+    then
+
+    # Adopt LSOF_CFGF from OSR_CFGF in environment.
+
+      LSOF_CFGF=$OSR_CFGF
+    fi # }
+    if test "X$OSR_CFGL" != "X"        # {
+    then
+
+    # Adopt LSOF_CFGL from OSR_CFGL in environment.
+
+      LSOF_CFGL=$OSR_CFGL
+    fi # }
+
+  # Evaluate compiler specification.
+
+    if test "X$LSOF_CC" = "X"  # {
+    then
+      if test "X$LSOF_TGT" = "Xosr" -o "X$LSOF_TGT" = "Xsco"   # {
+      then
+       LSOF_CC=cc
+       LSOF_TMP1=1
+      else
+       LSOF_CC=gcc
+       LSOF_CCV=`$LSOF_CC -v 2>&1 | sed -n 's/.*version \(.*\)/\1/p'`
+       LSOF_TMP1=2
+      fi       # }
+    else
+       LSOF_TMP1=0
+    fi # }
+    LSOF_TGT="osr"
+
+  # Determine version.
+
+    if test "X$LSOF_VSTR" = "X"        # {
+    then
+      LSOF_VSTR="`LANG=C_C.C /bin/uname -X 2>/dev/null | grep Release | sed 's/Release = \(.*\)/\1/'`"
+    fi # }
+    if test "X$LSOF_VERS" = "X"        # {
+    then
+
+      # If the SCO OpenServer release version isn't predefined, determine it.
+
+      case $LSOF_VSTR in       # {
+      3.2v2.0)
+       LSOF_VERS="20"
+       ;;
+      3.2v2.1)
+       LSOF_VERS="21"
+       ;;
+      3.2v4.0)
+       LSOF_VERS="40"
+       ;;
+      3.2v4.1)
+       LSOF_VERS="41"
+       ;;
+      3.2v4.2)
+       LSOF_VERS="42"
+       ;;
+      3.2v5.*)
+       LSOF_TSTLFLG="-lsocket"
+       LSOF_VERS="`echo $LSOF_VSTR | sed 's/3\.2v//; s/\.//g'`"
+       ;;
+      *)
+       echo Unknown SCO OpenServer release: $LSOF_VSTR
+       echo Assuming 3.2.0 or 3.2.1
+       LSOF_VERS="0"
+       ;;
+      esac     # }
+    fi # }
+
+    # Do SCO OpenServer specific stuff.
+
+    case $LSOF_VERS in # {
+    0)
+      if test $LSOF_TMP1 -eq 1 # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -nointl"
+       LSOF_DEBUG="-Ox"
+      fi       # }
+      LSOF_CFGL="$LSOF_CFGL -lrpc -lsocket -lc_s"
+      LSOF_MKC="cp"
+      ;;
+    20)
+      if test $LSOF_TMP1 -eq 1 # {
+      then
+       LSOF_DEBUG="-Ox"
+      fi       # }
+      LSOF_CFGL="$LSOF_CFGL -lrpc -lsocket -lc_s"
+      LSOF_MKC="cp"
+      ;;
+    21)
+      if test $LSOF_TMP1 -eq 1 # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -nointl"
+       LSOF_DEBUG="-Ox"
+      fi       # }
+      LSOF_CFGL="$LSOF_CFGL -lrpc -lsocket -lc_s"
+      LSOF_MKC="cp"
+      ;;
+    40)
+      if test $LSOF_TMP1 -eq 1 # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -nointl"
+       LSOF_DEBUG="-Ox"
+      fi       # }
+      LSOF_CFGL="$LSOF_CFGL -lrpc -lsocket -lc_s"
+      ;;
+    41)
+      if test $LSOF_TMP1 -eq 1 # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -nointl"
+       LSOF_DEBUG="-Ox"
+      fi       # }
+      LSOF_CFGL="$LSOF_CFGL -lrpc -lsocket -lc_s"
+      ;;
+    42)
+      if test $LSOF_TMP1 -eq 1 # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -nointl"
+       LSOF_DEBUG="-Ox"
+      fi       # }
+      LSOF_CFGL="$LSOF_CFGL -lrpc -lsocket -lc_s"
+      ;;
+    5*)
+      if test $LSOF_TMP1 -eq 1 # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -belf"
+       LSOF_DEBUG="-O3 -Kspace"
+      fi       # }
+      LSOF_CFGL="$LSOF_CFGL -lsocket"
+      ;;
+    *)
+      echo "Unsupported SCO OpenServer release: $LSOF_VERS"
+      rm -f $LSOF_HLP
+      exit 1
+      ;;
+    esac       # }
+    LSOF_CFGF="$LSOF_CFGF -DOSRV=$LSOF_VERS"
+    if test "X$OSR_STATLSTAT" = "X"    # {
+    then
+      echo "Testing libc.a for statlstat"
+      /bin/nm /lib/libc.a | grep statlstat > /dev/null 2>&1
+      if test $? -eq 0 # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -DHAS_STATLSTAT"
+      fi       # }
+    else
+      if test "X$OSR_STATLSTAT" = "XY" -o "X$OSR_STATLSTAT" = "Xy"     # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -DHAS_STATLSTAT"
+      fi       # }
+    fi # }
+    if test -r ${LSOF_INCLUDE}/sys/fs/nfs/rnode.h      # {
+    then
+      LSOF_CFGF="$LSOF_CFGF -DHAS_NFS"
+    fi # }
+    if test ! -r ${LSOF_INCLUDE}/netdb.h       # {
+    then
+      LSOF_DINC="$LSOF_DINC -I`pwd`/dialects/osr/include"
+    fi # }
+    LSOF_DIALECT_DIR=osr
+    ;;
+
+# Configure for Sun Solaris, SunPro C and gcc.
+
+  solaris|solariscc)
+    if test "X$LSOF_RANLIB_SUP" = "X"  # {
+    then
+      LSOF_RANLIB=""
+    fi # }
+    if test "X$LSOF_CC" = "X"  # {
+    then
+      if test "X$LSOF_TGT" = "Xsolariscc"      # {
+      then
+       if test "X$SOLARIS_CCDIR" = "X" # {
+       then
+         SOLARIS_CCDIR="/opt/SUNWspro/bin"
+       fi      # }
+       if test -x ${SOLARIS_CCDIR}/cc  # {
+       then
+         LSOF_CC=${SOLARIS_CCDIR}/cc
+       else
+         if test -x /opt/SunStudioExpress/bin/cc       # {
+         then
+           LSOF_CC=/opt/SunStudioExpress/bin/cc
+         else
+           echo "WARNING: no cc in ${SOLARIS_CCDIR}; using cc without path."
+           LSOF_CC=cc
+         fi    # }
+       fi      # }
+       LSOF_CCV=`$LSOF_CC -V 2>&1 | sed -n 's/^cc: \(.*\)/\1/p'`
+      else
+       LSOF_CC=gcc
+       LSOF_CCV=`$LSOF_CC -v 2>&1 | sed -n 's/.*version \(.*\)/\1/p'`
+      fi       # }
+    fi # }
+    LSOF_TGT="solaris"
+    if test "X$LSOF_VSTR" = "X"        # {
+    then
+      LSOF_VSTR=`uname -r`
+    fi # }
+    if test "X$LSOF_VERS" = "X"        # {
+    then
+
+      # If the Solaris version isn't predefined, determine it.
+
+      case $LSOF_VSTR in       # {
+      5.[0-2])
+       LSOF_VERS="20300"
+       ;;
+      5.3)
+       LSOF_VERS="20300"
+       ;;
+      5.4)
+       LSOF_VERS="20400"
+       ;;
+      5.5)
+       LSOF_VERS="20500"
+       ;;
+      5.5.1)
+       LSOF_VERS="20501"
+       ;;
+      5.6*)
+       LSOF_TSTLFLG="-lsocket -lnsl"
+       LSOF_VERS="20600"
+       ;;
+      5.7*)
+       LSOF_TSTBIGF=" "
+       LSOF_TSTLFLG="-lsocket -lnsl"
+       LSOF_VERS="70000"
+       ;;
+      5.8*)
+       LSOF_TSTBIGF=" "
+       LSOF_TSTLFLG="-lsocket -lnsl"
+       LSOF_VERS="80000"
+       ;;
+      5.9*)
+       LSOF_TSTBIGF=" "
+       LSOF_TSTLFLG="-lsocket -lnsl"
+       LSOF_VERS="90000"
+       ;;
+      5.10*)
+       LSOF_TSTBIGF=" "
+       LSOF_TSTLFLG="-lsocket -lnsl"
+       LSOF_VERS="100000"
+       ;;
+      5.11*)
+       LSOF_TSTBIGF=" "
+       LSOF_TSTLFLG="-lsocket -lnsl"
+       LSOF_VERS="110000"
+       ;;
+      *)
+       echo Unknown Solaris version: $LSOF_VSTR
+       rm -f $LSOF_HLP
+       exit 1
+      esac     # }
+    fi # }
+
+    # Clear LSOF_UNSUP message for selected Solaris versions.
+
+    case $LSOF_VERS in # {
+    90000|100000|110000)
+      LSOF_UNSUP=""
+      ;;
+    esac       # }
+
+    # Do Solaris version-specific stuff.
+
+    case $LSOF_VERS in # {
+    20300)
+
+      # Solaris patch 101318-32 creates a longer kernel tcp_s structure,
+      # and 101318-45 changes the way the vnode's v_filocks member is
+      # handled.  The following code creates a symbol definition for
+      # patch 101318 whose value is the patch level.  No symbol is defined
+      # if the patch level is not greater than zero.
+
+      if test "X$SOLARIS_23P101318" = "X"      # {
+      then
+       LSOF_PL=`grep -h SUNW_PATCHID=101318 /var/sadm/pkg/SUNWcar*/pkginfo | sed 's/.*-//' | sort -u | tail -1`
+       if test "X$LSOF_PL" = "X"       # {
+       then
+         LSOF_PL=0
+       fi      # }
+      else
+       LSOF_PL=$SOLARIS_23P101318
+      fi       # }
+      if test $LSOF_PL -gt 0   # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -DP101318=$LSOF_PL"
+      fi       # }
+      ;;
+    20400)
+      if test "X$SOLARIS_24P101945" = "X"      # {
+      then
+       LSOF_PL=`grep -h SUNW_PATCHID=101945 /var/sadm/pkg/SUNWcar*/pkginfo | sed 's/.*-//' | sort -u | tail -1`
+       if test "X$LSOF_PL" = "X"       # {
+       then
+         LSOF_PL=0
+       fi      # }
+      else
+       LSOF_PL=$SOLARIS_24P101945
+      fi       # }
+      if test $LSOF_PL -ge 32  # {
+      then
+       if test "X$SOLARIS_24P102303" = "X"     # {
+       then
+         LSOF_PL=`grep -h SUNW_PATCHID=102303 /var/sadm/pkg/SUNWhea*/pkginfo | sed 's/.*-//' | sort -u | tail -1`
+         if test "X$LSOF_PL" = "X"     # {
+         then
+           LSOF_PL=0
+         fi    # }
+       else
+         LSOF_PL=$SOLARIS_24P102303
+       fi      # }
+       if test $LSOF_PL -ge 2  # {
+       then
+         echo "WARNING: your Solaris 2.4 system appears to have patches 101945-32 and 102303-2"
+         echo "         installed.  This probably means the NUM_*_VECTORS definitions in"
+         echo "         <sys/auxv.h> don't match the ones used to build your kernel.  Consult"
+         echo "         the Sun Problems section of the 00FAQ file of the lsof distribution"
+         echo "         for more information on how to work around the problem."
+       fi      # }
+      fi       # }
+      ;;
+    20500|20501)
+      ;;
+    20600|70000|80000|90000|100000|110000)
+      if test "X$SOLARIS_26PR_GWINDOWS" = "X"  # {
+      then
+       rm -f ${LSOF_TMPC}.*
+       echo "#define _KMEMUSER" > ${LSOF_TMPC}.c
+       echo "#include <sys/proc/prdata.h>" >> ${LSOF_TMPC}.c
+       echo "int main(){" >> ${LSOF_TMPC}.c
+       echo "enum prnodetype p=PR_GWINDOWS;}" >> ${LSOF_TMPC}.c
+       echo "Testing prdata.h for PR_GWINDOWS, using $LSOF_CC"
+       echo $LSOF_CC | grep gcc > /dev/null
+       if test $? -eq 0        # {
+       then
+         $LSOF_CC ${LSOF_TMPC}.c -o ${LSOF_TMPC}.x  > /dev/null 2>&1
+       else
+         $LSOF_CC ${LSOF_TMPC}.c -I$LSOF_INCLUDE -o ${LSOF_TMPC}.x  > /dev/null 2>&1
+       fi      # }
+       if test $? -eq 0        # {
+       then
+         LSOF_CFGF="$LSOF_CFGF -DHASPR_GWINDOWS"
+       fi      # }
+      else
+       if test "X$SOLARIS_26PR_GWINDOWS" = "XY" -o "X$SOLARIS_26PR_GWINDOWS" = "Xy"    # {
+       then
+         LSOF_CFGF="$LSOF_CFGF -DHASPR_GWINDOWS"
+       fi      # }
+      fi       # }
+      if test "X$SOLARIS_26PR_LDT" = "X"       # {
+      then
+       rm -f ${LSOF_TMPC}.*
+       echo "#define _KMEMUSER" > ${LSOF_TMPC}.c
+       echo "#include <sys/proc/prdata.h>" >> ${LSOF_TMPC}.c
+       echo "int main(){" >> ${LSOF_TMPC}.c
+       echo "enum prnodetype p=PR_LDT;}" >> ${LSOF_TMPC}.c
+       echo "Testing prdata.h for PR_LDT, using $LSOF_CC"
+       echo $LSOF_CC | grep gcc > /dev/null
+       if test $? -eq 0        # {
+       then
+         $LSOF_CC ${LSOF_TMPC}.c -o ${LSOF_TMPC}.x > /dev/null 2>&1
+       else
+         $LSOF_CC ${LSOF_TMPC}.c -I$LSOF_INCLUDE -o ${LSOF_TMPC}.x > /dev/null 2>&1
+       fi      # }
+       if test $? -eq 0        # {
+       then
+         LSOF_CFGF="$LSOF_CFGF -DHASPR_LDT"
+       fi      # }
+       rm -f ${LSOF_TMPC}.*
+      else
+       if test "X$SOLARIS_26PR_LDT" = "XY" -o "X$SOLARIS_26PR_LDT" = "Xy"      # {
+       then
+         LSOF_CFGF="$LSOF_CFGF -DHASPR_LDT"
+       fi      # }
+      fi       # }
+      if test $LSOF_VERS -ge 70000     # {
+      then
+
+      # Do tests for Solaris 7 and above.
+
+       if test "X$SOLARIS_KERNBITS" = "X"      # {
+       then
+         SOLARIS_KERNBITS=`/bin/isainfo -kv`
+       fi      # }
+       if test "X$SOLARIS_INSTR" = "X" # {
+       then
+         SOLARIS_INSTR=`/bin/isainfo -k`
+       fi      #}
+       echo $SOLARIS_KERNBITS | grep 64 > /dev/null
+       if test $? -eq 0        # {
+       then
+         echo $LSOF_CC | grep gcc > /dev/null
+         if test $? -eq 0      # {
+         then
+
+       # Test gcc for 64 bit support.
+
+           echo "Testing $LSOF_CC for 64 bit support"
+           rm -f ${LSOF_TMPC}.*
+           echo "int main(){}" > ${LSOF_TMPC}.c
+           LSOF_TMP1=""
+
+       # First try gcc's -m64 option -- it's the most current possibility.
+
+           $LSOF_CC ${LSOF_TMPC}.c -m64 -o ${LSOF_TMPC}.x > /dev/null 2>&1
+           if test $? -eq 0    # {
+           then
+             /bin/file ${LSOF_TMPC}.x | /bin/grep 64 > /dev/null
+             if test $? -eq 0  # {
+             then
+               LSOF_TMP1="-m64"
+             fi        # }
+           fi  # }
+           rm -f ${LSOF_TMPC}.*
+           if test "X$LSOF_TMP1" = "X" # {
+           then
+
+           # Try using the older -mcpu=v9 option with gcc instead of -m64.
+
+             echo "int main(){}" > ${LSOF_TMPC}.c
+             $LSOF_CC ${LSOF_TMPC}.c -mcpu=v9 -o ${LSOF_TMPC}.x > /dev/null 2>&1
+             if test $? -eq 0  # {
+             then
+               /bin/file ${LSOF_TMPC}.x | /bin/grep 64 > /dev/null
+               if test $? -eq 0        # {
+               then
+                 LSOF_TMP1="-mcpu=v9"
+               fi      # }
+             fi        # }
+             rm -f ${LSOF_TMPC}.*
+           fi  # }
+           if test "X$LSOF_TMP1" = "X" # {
+           then
+             echo ""
+             echo "!!!WARNING!!!=========!!!WARNING!!!=========!!!WARNING!!!"
+             echo "!                                                       !"
+             echo "! LSOF NEEDS TO BE CONFIGURED FOR A 64 BIT KERNEL, BUT  !"
+             echo "! THIS GCC DOESN'T SUPPORT THE BUILDING OF 64 BIT       !"
+             echo "! SOLARIS EXECUTABLES.  LSOF WILL BE CONFIGURED FOR A   !"
+             echo "! 32 BIT KERNEL.                                        !"
+             echo "!                                                       !"
+             echo "!!!WARNING!!!=========!!!WARNING!!!=========!!!WARNING!!!"
+             echo ""
+           else
+             echo ""
+             echo "*********************************"
+             echo "* Configuring for 64 bit kernel *"
+             echo "*********************************"
+             echo ""
+             LSOF_CFGF="$LSOF_CFGF $LSOF_TMP1"
+             LSOF_CINFO="64 bit kernel"
+             LSOF_TSTK64=1
+           fi  # }
+         else
+
+         # Test Sun compiler for 64 bit support.
+
+           case $SOLARIS_INSTR in      # {
+           amd64*)
+             LSOF_TMP1="amd64"
+             LSOF_TMP2="amd64"
+             ;;
+           sparc*)
+             LSOF_TMP1="v9"
+             LSOF_TMP2="sparcv9"
+             ;;
+           *)
+             LSOF_TMP1=""
+             ;;
+           esac        # }
+           if test "X$LSOF_TMP1" != "X"        # {
+           then
+             echo "Testing $LSOF_CC for 64 bit $LSOF_TMP2 support"
+             rm -f ${LSOF_TMPC}.*
+             LSOF_TMP3="-xarch=$LSOF_TMP1"
+             echo "int main(){}" > ${LSOF_TMPC}.c
+             LSOF_TMP4=`$LSOF_CC ${LSOF_TMPC}.c $LSOF_TMP3 -o ${LSOF_TMPC}.x 2>&1`
+             if test $? -eq 0  # {
+             then
+               /bin/file ${LSOF_TMPC}.x | /bin/grep 64 > /dev/null
+               if test $? -ne 0        # {
+               then
+                 LSOF_TMP3=""
+               else
+                 echo "X$LSOF_TMP4" | grep "use -m64" > /dev/null 2>&1
+                 if test $? -eq 0      # {
+                 then
+                   LSOF_TMP3=-m64
+                 fi    # }
+               fi      # }
+             fi        # }
+             rm -f ${LSOF_TMPC}.*
+           else
+             LSOF_TMP3=""
+           fi  # }
+           if test "X$LSOF_TMP3" != "X"        # {
+           then
+             echo ""
+             echo "*********************************"
+             echo "* Configuring for 64 bit kernel *"
+             echo "*********************************"
+             echo ""
+             LSOF_CFGF="$LSOF_CFGF $LSOF_TMP3"
+             LSOF_CINFO="64 bit kernel"
+             LSOF_TSTK64=1
+           else
+             echo ""
+             echo "!!!WARNING!!!==========!!!WARNING!!!==========!!!WARNING!!!"
+             echo "!"
+             echo "! LSOF NEEDS TO BE CONFIGURED FOR A 64 BIT KERNEL, BUT"
+             echo "! THE VERSION OF SUN C AVAILABLE DOESN'T SUPPORT THE"
+             echo "! \"$LSOF_TMP2\" INSTRUCTION SET."
+             echo "!"
+             echo "! LSOF WILL BE CONFIGURED FOR A 32 BIT KERNEL."
+             echo "!"
+             echo "!!!WARNING!!!==========!!!WARNING!!!==========!!!WARNING!!!"
+             echo ""
+           fi  # }
+         fi    # }
+       else
+         echo ""
+         echo "*********************************"
+         echo "* Configuring for 32 bit kernel *"
+         echo "*********************************"
+         echo ""
+         LSOF_CINFO="32 bit kernel"
+       fi      # }
+      fi       # }
+
+      # Do tests specific to Solaris 8 and above.
+
+      if test $LSOF_VERS -ge 80000     # {
+      then
+       if test -r ${LSOF_INCLUDE}/netinet/ip6.h        # {
+       then
+         LSOF_CFGF="$LSOF_CFGF -DHASIPv6"
+       fi      # }
+      fi       # }
+
+      # Do tests specific to Solaris 9 and above.
+
+      if test $LSOF_VERS -ge 90000     # {
+      then
+       if test -r ${LSOF_INCLUDE}/sys/socketvar.h      # {
+       then
+         grep soua_vp ${LSOF_INCLUDE}/sys/socketvar.h > /dev/null 2>&1
+         if test $? -eq 0      # {
+         then
+           LSOF_CFGF="$LSOF_CFGF -DHASSOUXSOUA"
+         fi    # }
+       fi      # }
+       if test $LSOF_VERS -lt 110000   # {
+       then
+
+       # Do tests specific to Solaris 9 and 10.
+
+         if test -r ${LSOF_INCLUDE}/sys/lgrp_user.h      # {
+         then
+           if test -r ${LSOF_INCLUDE}/sys/lgrp.h      # {
+           then
+             grep lgrp_root ${LSOF_INCLUDE}/sys/lgrp_user.h > /dev/null 2>&1
+             if test $? -eq 0  # {
+             then
+               grep lgrp_root ${LSOF_INCLUDE}/sys/lgrp.h > /dev/null 2>&1
+               if test $? -eq 0
+               then
+                 LSOF_CFGF="$LSOF_CFGF -DHAS_LGRP_ROOT_CONFLICT"
+               fi      # }
+             fi        # }
+           fi  # }
+         fi    # }
+       fi      # }
+      fi       # }
+
+      # Do tests specific to Solaris 10 and above.
+
+      if test $LSOF_VERS -eq 100000    # {
+      then
+       if test -r ${LSOF_INCLUDE}/sys/socket_proto.h   # {
+       then
+           LSOF_CFGF="$LSOF_CFGF -DHAS_SOCKET_PROTO_H"
+       fi      # }
+      fi       # }
+      if test $LSOF_VERS -ge 100000    # {
+      then
+       if test -r ${LSOF_INCLUDE}/inet/ipclassifier.h  # {
+       then
+         LSOF_CFGF="$LSOF_CFGF -DHAS_IPCLASSIFIER_H"
+         grep conn_ixa ${LSOF_INCLUDE}/inet/ipclassifier.h > /dev/null 2>&1
+         if test $? -eq 0      # {
+         then
+           LSOF_CFGF="$LSOF_CFGF -DHAS_CONN_NEW"
+         fi    #}
+       fi      # }
+       if test -r ${LSOF_INCLUDE}/sys/cred_impl.h      # {
+       then
+         LSOF_CFGF="$LSOF_CFGF -DHAS_CRED_IMPL_H"
+
+         # DEBUG -- Begin temporary hack for Solaris 10, build s10_44.
+
+         grep "c2/audit.h" ${LSOF_INCLUDE}/sys/cred_impl.h > /dev/null
+         if test $? -eq 0      # {
+         then
+           rm -rf `pwd`/dialects/sun/solaris10
+           mkdir `pwd`/dialects/sun/solaris10
+           mkdir `pwd`/dialects/sun/solaris10/c2
+           touch `pwd`/dialects/sun/solaris10/c2/audit.h
+           LSOF_CFGF="$LSOF_CFGF -I`pwd`/dialects/sun/solaris10"
+         fi    # }
+
+         # DEBUG -- End temporary hack for Solaris 10, build s10_44.
+
+       fi      # }
+       if test -r ${LSOF_INCLUDE}/sys/vnode.h  # {
+       then
+         grep v_path ${LSOF_INCLUDE}/sys/vnode.h > /dev/null 2>&1
+         if test $? -eq 0      # {
+         then
+           LSOF_CFGF="$LSOF_CFGF -DHAS_V_PATH"
+           LSOF_TSTVPATH=1
+         fi    # }
+       fi      # }
+       if test -r ${LSOF_INCLUDE}/sys/fs/pc_fs.h       # {
+       then
+         grep pc_direntpersec ${LSOF_INCLUDE}/sys/fs/pc_fs.h > /dev/null 2>&1
+         if test $? -eq 0      # {
+         then
+           LSOF_CFGF="$LSOF_CFGF -DHAS_PC_DIRENTPERSEC"
+         fi    # }
+       fi      # }
+       if test -r ${LSOF_INCLUDE}/sys/aio_req.h        # {
+       then
+         grep "struct[         ]aio_req" ${LSOF_INCLUDE}/sys/aio_req.h > /dev/null 2>&1
+         if test $? -eq 0      # {
+         then
+           LSOF_CFGF="$LSOF_CFGF -DHAS_AIO_REQ_STRUCT"
+         fi    # }
+       fi      # }
+      fi       # }
+      if test -r ${LSOF_INCLUDE}/sys/zone.h    # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -DHASZONES"
+      fi       # }
+
+      # Check for Solaris 10 or higher CTF library and things that depend
+      # on it.
+
+      if test -r ${LSOF_INCLUDE}/libctf.h      # {
+      then
+       LSOF_CTFH=1
+      fi       # }
+      if test -r ${LSOF_INCLUDE}/sys/fs/zfs.h  # {
+      then
+       if test $LSOF_CTFH -eq 1        # {
+       then
+         LSOF_CFGF="$LSOF_CFGF -DHAS_ZFS"
+         LSOF_CTFL=1
+       else
+         echo "WARNING: ZFS support not enabled; libctf.h missing."
+       fi      # }
+      fi       # }
+      if test $LSOF_VERS -ge 110000    # {
+      then
+
+      # Do things specific to Solaris 11 and above.
+
+       if test $LSOF_CTFH -eq 1        # {
+       then
+         LSOF_CTFL=1
+       else
+         echo "WARNING: socket support not enabled; libctf.h missing."
+       fi      # }
+       rm -rf ./solaris11
+       mkdir ./solaris11
+       mkdir ./solaris11/sys
+       touch ./solaris11/sys/extdirent.h
+       echo "./solaris11/sys/extdirent.h created"
+       LSOF_CFGF="$LSOF_CFGF -I`pwd`/solaris11"
+       if test -r ${LSOF_INCLUDE}/sys/mutex.h  # {
+       then
+
+       # Check <sys/mutex.h> 'for pad_mutex_t;'.
+
+         grep 'pad_mutex_t;' ${LSOF_INCLUDE}/sys/mutex.h > /dev/null 2>&1
+         if test $? -eq 0      # {
+         then
+           LSOF_CFGF="$LSOF_CFGF -DHAS_PAD_MUTEX"
+         fi    # }
+       fi      # )
+      fi       # }
+
+      # If -lctf was added to LSOF_CFGL, define HAS_LIBCTF.
+
+      if test $LSOF_CTFL -eq 1 # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -DHAS_LIBCTF"
+       LSOF_CFGL="$LSOF_CFGL -lctf"
+      fi       # }
+      ;;
+    *)
+      echo "Unsupported Solaris version: $LSOF_VERS"
+      rm -f $LSOF_HLP
+      exit 1
+      ;;
+    esac       # }
+    LSOF_CFGF="$LSOF_CFGF -Dsolaris=$LSOF_VERS"
+
+    # Test for <sys/fs/cachefs_fs.h>.
+
+    if test -r ${LSOF_INCLUDE}/sys/fs/cachefs_fs.h     # {
+    then
+      LSOF_CFGF="$LSOF_CFGF -DHASCACHEFS"
+    fi # }
+
+
+    # Test for <sys/rgm.h>.
+
+    if test -r ${LSOF_INCLUDE}/sys/rgm.h {
+    then
+      LSOF_CFGF="$LSOF_CFGF -DHAS_SYS_RGM_H"
+    fi  # }
+
+    # Test for <rpc/rpc_tags.h>.
+
+    if test -r ${LSOF_INCLUDE}/rpc/rpc_tags.h {
+    then
+      LSOF_CFGF="$LSOF_CFGF -DHAS_RPC_RPC_TAGS_H"
+    fi  # }
+
+    # Test for <utmpx.h>
+
+    if test -r ${LSOF_INCLUDE}/utmpx.h # {
+    then
+      LSOF_CFGF="$LSOF_CFGF -DHASUTMPX"
+    fi # }
+
+    # Test for VSOCK.
+
+    if test "X$SOLARIS_VSOCK" = "X"    # {
+    then
+      rm -f ${LSOF_TMPC}.*
+      echo "#include <sys/vnode.h>" > ${LSOF_TMPC}.c
+      echo "int main(){" >> ${LSOF_TMPC}.c
+      echo "enum vtype p=VSOCK;}" >> ${LSOF_TMPC}.c
+      echo "Testing vnode.h for VSOCK, using $LSOF_CC"
+      echo $LSOF_CC | grep gcc > /dev/null
+      if test $? -eq 0 # {
+      then
+       $LSOF_CC ${LSOF_TMPC}.c -o ${LSOF_TMPC}.x > /dev/null 2>&1
+      else
+       $LSOF_CC ${LSOF_TMPC}.c -I$LSOF_INCLUDE -o ${LSOF_TMPC}.x > /dev/null 2>&1
+      fi       # }
+      if test $? -eq 0 # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -DHAS_VSOCK"
+      fi       # }
+      rm -f ${LSOF_TMPC}.*
+    else
+      if test "X$SOLARIS_VSOCK" = "XY" -o "X$SOLARIS_VSOCK" = "Xy"     # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -DHAS_VSOCK"
+      fi       # }
+    fi # }
+
+    # Test for AFS.
+
+    if test -r ${AFS_VICE}/etc/ThisCell        # {
+    then
+      if test "X$LSOF_SCRIPT_CALL" = "Xno"     # {
+      then
+       if test -r ./AFSHeaders -a -r ./AFSVersion      # {
+       then
+         LSOF_AFS="yes"
+       fi      # }
+      else
+       if test ! -x ./AFSConfig        # {
+       then
+         echo "Can't find or execute the AFSConfig script"
+         rm -f $LSOF_HLP
+         exit 1
+       fi      # }
+       ./AFSConfig
+       if test $? -eq 0 -a -r ./AFSHeaders -a -r ./AFSVersion  # {
+       then
+           LSOF_AFS="yes"
+       fi      # }
+      fi       # }
+      if test "X$LSOF_AFS" = "Xyes"    # {
+      then
+       if test "X$SUN_AFSAPATHDEF" = "X"       # {
+       then
+         ls /usr/vice/etc/modload/libafs > /dev/null 2>&1
+         if test $? -ne 0      # {
+         then
+           LSOF_TMP1=`ls /usr/vice/etc/modload/libafs* 2>/dev/null | wc -l`
+           if test $LSOF_TMP1 -ne 0    # {
+           then
+             SUN_AFSAPATHDEF=`ls -t /usr/vice/etc/modload/libafs* | head -1`
+           fi  # }
+         fi    # }
+       fi      # }
+       if test "X$SUN_AFSAPATHDEF" != "X"      # {
+       then
+         LSOF_CFGF="$LSOF_CFGF -DAFSAPATHDEF=\\\"$SUN_AFSAPATHDEF\\\""
+       fi      # }
+       LSOF_AFSV=`cat ./AFSVersion | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1 \2/' | awk '{printf "%d%02d\n",\$1,\$2}'`
+       LSOF_CFGF="$LSOF_CFGF -DHAS_AFS=$LSOF_AFSV"
+       LSOF_DINC="$LSOF_DINC -I`cat ./AFSHeaders`"
+      fi       # }
+    fi # }
+
+    # Test for VxFS.
+    #
+    # If the location of the VxFS header files hasn't been defined in the
+    # environment, establish their likely locations.
+
+    LSOF_TMP2=$SOLARIS_VXFSINCL
+    if test -d /opt/VRTS/include       # {
+    then
+      LSOF_TMP2="$LSOF_TMP2 /opt/VRTS/include"
+    fi # }
+    if test -d /opt/VRTSvxfs/include   # {
+    then
+      LSOF_TMP2="$LSOF_TMP2 /opt/VRTSvxfs/include"
+    fi # }
+    LSOF_TMP1=0
+    for i in $LSOF_TMP2        # {
+    do
+      if test -r ${i}/vxfsutil.h       # {
+      then
+       LSOF_TMP1=1
+       SOLARIS_VXFSINCL=$i
+       break
+      fi       # }
+    done       # }
+    if test $LSOF_TMP1 -eq 1   # {
+    then
+
+    # Warn that VxFS is unsupported.
+
+      LSOF_UNSUP2="WARNING: VxFS is no longer supported by Solaris lsof."
+
+    # The VxFS header files are for VxFS version 3.4 or above.  Enable VxFS
+    # for those versions.
+
+      LSOF_CFGF="$LSOF_CFGF -DHASVXFS -DHASVXFSUTIL -I$SOLARIS_VXFSINCL"
+
+    # Determine which libvxfsutil.a is required -- 32 or 64 bit.
+
+      LSOF_TMP2=""                     # assume 32 bit
+      echo "X$LSOF_CINFO" | grep "^X64" > /dev/null 2>&1
+      if test $? -eq 0-a "X$SOLARIS_INSTR" != "X"      # {
+      then
+       case $SOLARIS_INSTR in  # {
+       amd64*)
+         LSOF_TMP2="/amd64"
+         ;;
+       sparcv9*)
+         LSOF_TMP2="/sparcv9"
+         ;;
+       esac    # }
+      fi       # }
+
+    # See if the correct library has been specified and exists.
+
+      if test "X$SOLARIS_VXFSLIB" = "X"        # {
+      then
+       SOLARIS_VXFSLIB=`dirname $SOLARIS_VXFSINCL`/lib
+      fi       # }
+      LSOF_TMP3="${SOLARIS_VXFSLIB}${LSOF_TMP2}/libvxfsutil.a"
+      if test ! -r $LSOF_TMP3  # {
+      then
+       echo "!!!FATAL: no VxFS $LSOF_TMP3"
+       exit 1
+      fi       # }
+      LSOF_CFGL="$LSOF_CFGL -L$SOLARIS_VXFSLIB${LSOF_TMP2} -lvxfsutil -ldl"
+
+    # See if the library has the Reverse Name Lookup (RNL) function.
+
+      nm $LSOF_TMP3 | grep vxfs_inotopath > /dev/null 2>&1
+      if test $? -eq 0 # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -DHASVXFSRNL -DHASVXFSDNLC"
+      fi       # }
+    else
+
+    # See if there are VxFS header files for VxFS versions below 3.4.
+
+      if test -r ${LSOF_INCLUDE}/sys/fs/vx_inode.h     # {
+      then
+
+      # Define VxFS for VxFS versions below 3.4.  Make additional header
+      # file tests.
+
+       LSOF_CFGF="$LSOF_CFGF -DHASVXFS"
+       if test -r ${LSOF_INCLUDE}/sys/fs/vx_fs.h       # {
+       then
+         LSOF_CFGF="$LSOF_CFGF -DHASVXFS_FS_H"
+       fi      # }
+       if test -r ${LSOF_INCLUDE}/sys/fs/vx_sol.h      # {
+       then
+         LSOF_CFGF="$LSOF_CFGF -DHASVXFS_SOL_H"
+       fi      # }
+       if test -r ${LSOF_INCLUDE}/sys/fs/vx_machdep.h  # {
+       then
+         LSOF_CFGF="$LSOF_CFGF -DHASVXFS_MACHDEP_H"
+       fi      # }
+       if test -r ${LSOF_INCLUDE}/sys/fs/vx_solaris.h  # {
+       then
+         LSOF_CFGF="$LSOF_CFGF -DHASVXFS_SOLARIS_H"
+         grep "off32_t;" ${LSOF_INCLUDE}/sys/fs/vx_machdep.h > /dev/null
+         if test $? -eq 0      # {
+         then
+           LSOF_CFGF="$LSOF_CFGF -DHASVXFS_OFF32_T"
+         fi    # }
+         grep "off64_t;" ${LSOF_INCLUDE}/sys/fs/vx_solaris.h > /dev/null
+         if test $? -eq 0      # {
+         then
+           LSOF_CFGF="$LSOF_CFGF -DHASVXFS_OFF64_T"
+         fi    # }
+         grep "vx_u64_t;" ${LSOF_INCLUDE}/sys/fs/vx_solaris.h > /dev/null
+         if test $? -eq 0      # {
+         then
+           LSOF_CFGF="$LSOF_CFGF -DHASVXFS_U64_T"
+         fi    # }
+       fi      # }
+       egrep "struct[  ]vx_inode[      ]\{" ${LSOF_INCLUDE}/sys/fs/vx_inode.h > /dev/null
+       # } (dummy '}' to match '{' in above egrep)
+       if test $? -eq 0        # {
+       then
+         LSOF_CFGF="$LSOF_CFGF -DHASVXFS_VX_INODE"
+       fi      # }
+      fi       # }
+    fi # }
+
+    # Set libraries and dialect subdirectory.
+
+    LSOF_CFGL="$LSOF_CFGL -lkvm -lelf -lsocket -lnsl"
+    LSOF_DIALECT_DIR=sun
+
+    # Set local-specific stuff.
+
+    if test "X$LSOF_LOCALSUFFIX" = "XLOCAL"    # {
+    then
+      LSOF_DOC="\${DESTDIR}/usr/local/man"
+    fi # }
+    ;;
+
+# Configure for SCO|Caldera OpenServer Release 6.0.0 and UnixWare.
+
+  osr6|unixware|uw)
+    LSOF_TMP1=$LSOF_TGT
+    LSOF_TGT="uw"
+    if test "X$LSOF_RANLIB_SUP" = "X"  # {
+    then
+      LSOF_RANLIB=""
+    fi # }
+    if test "X$LSOF_VSTR" = "X"        # {
+    then
+      LSOF_VSTR=`uname -v`
+    fi # }
+    if test "X$LSOF_VERS" = "X"        # {
+    then
+
+      # If the Openserver Release 6.0.0 or UnixWare version isn't pre-defined,
+      # determine it.
+
+      LSOF_VERS=`echo $LSOF_VSTR | sed 's/\([0-9\.]*\).*/\1/; s/\./ /g' | awk '{printf "%d%02d%02d\n", $1, $2, $3;}'`
+    fi # }
+    if test $LSOF_TMP1 = "osr6"        # {
+    then
+      LSOF_CINFO="OSR6 support via UnixWare sources"
+
+    # Convert the OpenServer Release 6.0.0 version number to a UnixWare one.
+
+      case $LSOF_VERS in       # {
+      60000)
+       LSOF_VERS=70104
+       ;;
+      *)
+       echo "Unknown OpenServer Release version: $LSOF_VERS"
+       rm -f $LSOF_HLP
+       exit 1
+      esac     # }
+    fi # }
+    LSOF_CFGF="$LSOF_CFGF -DUNIXWAREV=$LSOF_VERS"
+
+    # Do OpenServer Release 6.0.0 and UnixWare version-specific stuff.
+
+    case $LSOF_VERS in # {
+    20100|20101|20102|20103)
+      if test -r ${LSOF_INCLUDE}/sys/fs/vx_inode.h     # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -DHASVXFS"
+      fi       # }
+      LSOF_CFGL="$LSOF_CFGL -lsocket -lnsl -lelf -lgen"
+      ;;
+    70000|70001|70100|70101|70103|70104)
+      LSOF_TSTBIGF=" "
+      LSOF_TSTLFLG="-lsocket -lnsl"
+      if test $LSOF_VERS -lt 70103     # {
+      then
+       LSOF_DINC="$LSOF_DINC -I`pwd`/dialects/uw/uw7"
+      else     # $LSOF_VERS -ge 70103
+
+      # Process 7.1.3 and above.
+
+       if test -r ${LSOF_INCLUDE}/netinet/in6.h        # {
+       then
+         LSOF_CFGF="$LSOF_CFGF -DHASIPv6"
+       fi      # }
+       if test $LSOF_VERS -ge 70104    # {
+       then
+
+       # Process 7.1.4 and above.
+
+         LSOF_TMP1=0
+         if test -r ${LSOF_INCLUDE}/netinet/in_pcb.h   # {
+         then
+           grep INKERNEL ${LSOF_INCLUDE}/netinet/in_pcb.h > /dev/null 2>&1
+           if test $? -eq 0    # {
+           then
+             LSOF_TMP1=1
+           fi  # }
+         fi    # }
+         if test $LSOF_TMP1 -eq 0 -a -r ${LSOF_INCLUDE}/netinet/tcp_var.h   # {
+         then
+           grep INKERNEL ${LSOF_INCLUDE}/netinet/tcp_var.h > /dev/null 2>&1
+           if test $? -eq 0    # {
+           then
+             LSOF_TMP1=1
+           fi  # }
+         fi    # }
+         if test $LSOF_TMP1 -eq 1      # {
+         then
+           LSOF_CFGF="$LSOF_CFGF -DHAS_INKERNEL"
+         fi    # }
+       fi      # }
+      fi       # }
+      if test ! -r ${LSOF_INCLUDE}/vm/swap.h -a -r ${LSOF_INCLUDE}/sys/swap.h  # {
+      then
+       (cd ./dialects/uw/uw7/vm; rm -f swap.h; ln -s ${LSOF_INCLUDE}/sys/swap.h swap.h)
+      fi       # }
+      if test -r ${LSOF_INCLUDE}/sys/fs/vx_gemini.h    # {
+      then
+       LSOF_CFGF="$LSOF_CFGF -DHASVXFS"
+      fi       # }
+      LSOF_CFGL="$LSOF_CFGL -lsocket -lnsl -lelf -lgen"
+      /bin/pkginfo 2> /dev/null | grep -i patch | grep -i ptf7038 > /dev/null
+      if test -r ${LSOF_INCLUDE}/sys/file.h    # {
+      then
+       grep f_open ${LSOF_INCLUDE}/sys/file.h > /dev/null
+       if test $? -eq 0        # {
+       then
+         LSOF_CFGF="$LSOF_CFGF -DHAS_F_OPEN"
+       fi      # }
+      fi       # }
+      if test -r ${LSOF_INCLUDE}/sys/fs/cdfs_fs.h      # {
+      then
+       grep "cdfs_LogSecShift;" ${LSOF_INCLUDE}/sys/fs/cdfs_fs.h > /dev/null 2>&1
+       if test $? -eq 0        # {
+       then
+         LSOF_TMP=`grep "cdfs_LogSecShift;" ${LSOF_INCLUDE}/sys/fs/cdfs_fs.h | sed 's/^[       ]*\([^  ]*\).*/\1/'`
+         if test "X$LSOF_TMP" != "X"   # {
+         then
+           LSOF_CFGF="$LSOF_CFGF -DTYPELOGSECSHIFT=$LSOF_TMP"
+         fi    # }
+       fi      # }
+      fi       # }
+      if test -r ${LSOF_INCLUDE}/sys/proc.h    # {
+      then
+       grep p_pgid ${LSOF_INCLUDE}/sys/proc.h > /dev/null
+       if test $? -eq 0        # {
+       then
+         LSOF_CFGF="$LSOF_CFGF -DHAS_P_PGID"
+       fi      # }
+      fi       # }
+      if test $LSOF_VERS -ge 70101     # {
+      then
+
+       # Do OpenServer Release 6.0.0 and UnixWare 7.1.1 and above tests, as
+       # required.
+
+       if test "X$UW_HAS_NSC" = "X"    # {
+       then
+         UW_HAS_NSC=N
+         if test -x /bin/node_self     # {
+         then
+           /bin/node_self > /dev/null 2>&1
+           if test $? -eq 0    # {
+           then
+             UW_HAS_NSC=Y
+           fi  # }
+         fi    # }
+       fi      # }
+       if test "X$UW_HAS_NSC" = "XY" -o "X$UW_HAS_NSC" = "Xy"  # {
+       then
+         LSOF_CFGF="$LSOF_CFGF -DHAS_UW_NSC"
+         LSOF_CFGL="$LSOF_CFGL -lcluster"
+       fi      # }
+       if test -r ${LSOF_INCLUDE}/sys/nsc_synch.h      # {
+       then
+         LSOF_CFGF="$LSOF_CFGF -DHAS_UW_CFS"
+       fi      # }
+      fi       # }
+      ;;
+    *)
+      echo Unsupported UnixWare version: `uname -v`
+      rm -f $LSOF_HLP
+      exit 1
+      ;;
+    esac       # }
+    if test -r ${LSOF_INCLUDE}/sys/fs/xnamnode.h       # {
+    then
+      LSOF_CFGF="$LSOF_CFGF -DHASXNAMNODE"
+    fi # }
+    LSOF_DIALECT_DIR=uw
+    ;;
+
+# Handle unknown abbreviation.
+
+  *)
+    echo "Can't configure for $LSOF_TGT."
+    cat $LSOF_HLP
+    rm -f $LSOF_HLP
+    exit 1
+    ;;
+
+# End of LSOF_TGT cases
+
+esac   # }
+
+# Do an inventory of the distribution, as required.
+
+if test "X$LSOF_SCRIPT_CALL" = "Xyes" -a ! -r ./.neverInv      # {
+then
+  if test ! -f ./Inventory     # Want -x, but Ultrix doesn't grok it.  # {
+  then
+    echo "Can't find Inventory script."
+    rm -f $LSOF_HLP
+    exit 1
+  fi   # }
+  ./Inventory
+fi     # }
+
+# Make sure target directory exists.
+
+if test ! -d ./lib/dialects/$LSOF_DIALECT_DIR  # {
+then
+  echo "Can't configure for $LSOF_TGT -- ./lib/dialects/$LSOF_DIALECT_DIR doesn't exist."
+  rm -f $LSOF_HLP
+  exit 1
+fi     # }
+
+# Make sure $LSOF_MK exists in the target directory.
+
+if test ! -r ./lib/dialects/$LSOF_DIALECT_DIR/$LSOF_MK # {
+then
+  echo "Can't configure for $LSOF_TGT -- ./lib/dialects/$LSOF_DIALECT_DIR/$LSOF_MK doesn't exist."
+  rm -f $LSOF_HLP
+  exit 1
+fi     # }
+
+# Make sure $LSOF_MKF, $LSOF_SPMKF, or $LSOF_MKF.$LSOF_LOCALSUFFIX) exists
+# in the target directory.
+
+if test "X$LSOF_SPMKF" != "X"  # {
+then
+  LSOF_TMP1=$LSOF_SPMKF
+else
+  LSOF_TMP1=$LSOF_MKF
+fi     # }
+if test "X$LSOF_LOCALSUFFIX" != "X"    # {
+then
+  LSOF_REST=$LSOF_TMP1.$LSOF_LOCALSUFFIX
+else
+  LSOF_REST=$LSOF_TMP1
+fi     # }
+if test ! -r ./lib/dialects/$LSOF_DIALECT_DIR/$LSOF_REST       # {
+then
+  echo "Can't configure for $LSOF_TGT -- ./lib/dialects/$LSOF_DIALECT_DIR/$LSOF_REST doesn't exist."
+  rm -f $LSOF_HLP
+  exit 1
+fi     # }
+
+# If this is FreeBSD, make sure $LSOF_FBSD_ZFS_MKF exists.
+
+if test $LSOF_FBSD_ZFS -eq 1   # {
+then
+  if test ! ./dialects/$LSOF_DIALECT_DIR/$LSOF_FBSD_ZFS_MKF    # {
+  then
+    echo "Can't configure for $LSOF_TGT -- ./dialects/$LSOF_DIALECT_DIR/$LSOF_FBSD_ZFS_MKF doesn't exist."
+    rm -f $LSOF_HLP
+    exit 1
+  fi   # }
+fi     # }}
+
+# Make sure $LSOF_VF exists.  Extract the version number from it.
+
+if test ! -r $LSOF_VF  # {
+then
+  echo "Version number file, ./$LSOF_VF, doesn't exist."
+  rm -f $LSOF_HLP
+  exit 1
+else
+  LSOF_VN=`sed "s/.ds VN \(.*\)/\1/" < $LSOF_VF`
+fi     # }
+
+# Clean up in advance.
+
+rm -f $LSOF_F $LSOF_MKFC $LSOF_FBSD_ZFS_MKF $LSOF_TSTCFLG $LSOF_TSTCC
+rm -f $LSOF_TSTXOC $LSOF_TSTLFF
+echo "rm -f $LSOF_F $LSOF_MKFC $LSOF_FBSD_ZFS_MKF $LSOF_TSTCFLG"
+echo "rm -f $LSOF_TSTCC $LSOF_TSTXOC $LSOF_TSTLFF"
+
+# Make sure there's a C compiler name.
+
+if test "X$LSOF_CC" = "X"      # {
+then
+  LSOF_CC=cc
+fi     # }
+
+# Do common feature analyses.
+
+# Check for localtime(3) and strftime(3).
+
+rm -f ${LSOF_TMPC}.*
+cat > $LSOF_TMPC.c << .LSOF_END_HERE_DOC2
+#include <time.h>
+int main(){
+  time_t cl;
+  struct tm *ts;
+  char bf[32];
+  if ((cl = time(NULL)) == (time_t)-1)
+    return(1);
+  ts = localtime(&cl);
+  if (strftime(bf, sizeof(bf), "%D", ts) != 8)
+    return(1);
+  if ((bf[2] != '/') || (bf[5] != '/'))
+    return (1);
+  return(0);
+}
+.LSOF_END_HERE_DOC2
+echo $EO "Testing C library for localtime() and strftime(), using $LSOF_CC ... $EC"
+$LSOF_CC ${LSOF_TMPC}.c -o ${LSOF_TMPC}.x > /dev/null 2>&1
+if test -x ${LSOF_TMPC}.x      # {
+then
+  ./${LSOF_TMPC}.x
+  if test $? -eq 0     # }
+  then
+    LSOF_CFGF="$LSOF_CFGF -DHAS_STRFTIME"
+    echo "present"
+  else
+    echo "unusable"
+  fi   # }
+else
+  echo "missing"
+fi     # }
+rm -f ${LSOF_TMPC}.[cox]
+
+# Make the dialect sources.
+
+if test "X$LSOF_MKC" = "X"     # {
+then
+  LSOF_MKC="ln -s"
+fi     # }
+LSOF_MKC=$LSOF_MKC ./lib/dialects/$LSOF_DIALECT_DIR/$LSOF_MK $LSOF_TGT $LSOF_VERS || exit 1
+
+# Make $LSOF_MKFC and ${LSOF_LIB}/$LSOF_LIBMKF.
+
+echo "# $LSOF_TGT Makefile for lsof revision $LSOF_VN" > $LSOF_MKFC
+echo "" >> $LSOF_MKFC
+echo "CC=      $LSOF_CC" >> $LSOF_MKFC
+if test "X$LSOF_CCV" != "X"    # {
+then
+  echo "" >> $LSOF_MKFC
+  echo "CCV=   $LSOF_CCV" >> $LSOF_MKFC
+fi     # }
+if test "X$LSOF_LIB_NO" = "X"  # {
+then
+  echo "" >> $LSOF_MKFC
+  echo "LIB=   ${LSOF_LIB}/liblsof.a" >> $LSOF_MKFC
+fi     # }
+if test "X$LSOF_LD" != "X"     # {
+then
+  echo "" >> $LSOF_MKFC
+  echo "LD=    $LSOF_LD" >> $LSOF_MKFC
+fi     # }
+if test "X$LSOF_CINFO" != "X"  # {
+then
+  echo "" >> $LSOF_MKFC
+  echo "CINFO= $LSOF_CINFO" >> $LSOF_MKFC
+fi     # }
+if test "X$LSOF_CFGD" != "X"   # {
+then
+  echo "CFGD=  $LSOF_CFGD" >> $LSOF_MKFC
+fi     # }
+if test "X$LSOF_CFGDN" != "X"  # {
+then
+  echo "CFGDN= $LSOF_CFGDN" >> $LSOF_MKFC
+fi     # }
+if test "X$LSOF_ARCH" != "X"   # {
+then
+  LSOF_CFGF="$LSOF_CFGF -DLSOF_ARCH=\\\"$LSOF_ARCH\\\""
+fi     # }
+if test "X$LSOF_VSTR" != "X"   # {
+then
+  LSOF_TMP=`echo $LSOF_VSTR | sed 's/(/\\\\(/g' | sed 's/)/\\\\)/g'`
+  LSOF_CFGF="$LSOF_CFGF -DLSOF_VSTR=\\\"$LSOF_TMP\\\""
+fi     # }
+echo "" >> $LSOF_MKFC
+echo "CFGF=    $LSOF_CFGF" >> $LSOF_MKFC
+if test "X$LSOF_LIB_NO" = "X"  # {
+then
+  echo "" >> $LSOF_MKFC
+  echo "CFGL=  $LSOF_FCFGL -L./$LSOF_LIB -llsof $LSOF_CFGL" >> $LSOF_MKFC
+fi     # }
+echo "" >> $LSOF_MKFC
+if test "X$LSOF_DEBUG" = "X"   # {
+then
+  LSOF_DEBUG=""
+else
+  if test "X$LSOF_DEBUG" = "XNo-O"     # {
+  then
+    LSOF_DEBUG=""
+  fi   # }
+fi     # }
+echo "DEBUG=   $LSOF_DEBUG" >> $LSOF_MKFC
+if test "X$LSOF_OPINC" != "X"  # {
+then
+  LSOF_DINC="$LSOF_DINC $LSOF_OPINC"
+fi     # }
+if test "X$LSOF_DINC" != "X"   # {
+then
+  echo "" >> $LSOF_MKFC
+  echo "DINC=  $LSOF_DINC" >> $LSOF_MKFC
+fi     # }
+if test "X$LSOF_DOC" != "X"    # {
+then
+  echo "" >> $LSOF_MKFC
+  echo "DOC=$LSOF_DOC" >> $LSOF_MKFC
+fi     # }
+if test "X$LSOF_DISTRIBKVM" != "X" -a "X$LSOF_DISTRIBKVM" != "XKVM"    # {
+then
+  echo "" >> $LSOF_MKFC
+  echo "KVM=   $LSOF_DISTRIBKVM" >> $LSOF_MKFC
+fi     # }
+echo "" >> $LSOF_MKFC
+echo "DIALECT_DIR=     $LSOF_DIALECT_DIR" >> $LSOF_MKFC
+rm -f ${LSOF_LIB}/$LSOF_LIBMKF
+if test "X$LSOF_LIB_NO" = "X"  # {
+then
+  cp $LSOF_MKFC ${LSOF_LIB}/$LSOF_LIBMKF
+fi     # }
+cat ./lib/dialects/$LSOF_DIALECT_DIR/$LSOF_REST >> $LSOF_MKFC
+if test "X$LSOF_CFLAGS_OVERRIDE" != "X"        # {
+then
+  sed -i -e 's/^CFLAGS=/override CFLAGS=/' $LSOF_MKFC
+fi     # }
+if test "X$LSOF_LIB_NO" = "X"  # {
+then
+
+  # Put archiving and optional randomizing strings in ${LSOF_LIB}/$LSOF_LIBMKF.
+  #
+  # Process optional CFLAGS override.
+  #
+  # Add the library Makefile skeleton section.
+
+  echo "" >> ${LSOF_LIB}/$LSOF_LIBMKF
+  echo "DIALECT_DIR=   $LSOF_DIALECT_DIR" >> ${LSOF_LIB}/$LSOF_LIBMKF
+  echo "" >> ${LSOF_LIB}/$LSOF_LIBMKF
+  if test "X$LSOF_AR" = "X"    # {
+  then
+    echo "AR=  ar cr \${LIB} \${OBJ}" >> ${LSOF_LIB}/$LSOF_LIBMKF
+  else
+    echo "AR=  $LSOF_AR \${LIB} \${OBJ}" >> ${LSOF_LIB}/$LSOF_LIBMKF
+  fi   # }
+  if test "X$LSOF_RANLIB" != "X"       # {
+  then
+    echo "" >> ${LSOF_LIB}/$LSOF_LIBMKF
+    echo "RANLIB=      $LSOF_RANLIB \${LIB}" >> ${LSOF_LIB}/$LSOF_LIBMKF
+  fi   # }
+  echo "" >> ${LSOF_LIB}/$LSOF_LIBMKF
+  if test "X$LSOF_CFLAGS_OVERRIDE" = "X"       # {
+  then
+    echo "CFLAGS=      \${CDEFS} \${INCL} \${DEBUG}" >> ${LSOF_LIB}/$LSOF_LIBMKF
+  else
+    echo "override CFLAGS=\${CDEFS} \${INCL} \${DEBUG}" >> ${LSOF_LIB}/$LSOF_LIBMKF
+  fi   # }
+  echo "" >> ${LSOF_LIB}/$LSOF_LIBMKF
+  cat ${LSOF_LIB}/$LSOF_LIBMKFSKEL >> ${LSOF_LIB}/$LSOF_LIBMKF
+  echo $LSOF_MKFC and ${LSOF_LIB}/$LSOF_LIBMKF created.
+else
+  echo $LSOF_MKFC created.
+fi     # }
+
+# If this is FreeBSD, create $LSOF_FBSD_ZFS_MKF.
+
+if test $LSOF_FBSD_ZFS -eq 1   # {
+then
+  rm -f $LSOF_FBSD_ZFS_MKF
+  echo "# $LSOF_TGT ZFS Makefile for lsof revision $LSOF_VN" > $LSOF_FBSD_ZFS_MKF
+  echo "" >> $LSOF_FBSD_ZFS_MKF
+  echo "CC=            $LSOF_CC" >> $LSOF_FBSD_ZFS_MKF
+  echo "" >> $LSOF_FBSD_ZFS_MKF
+  echo "CFLAGS=        $LSOF_FBSD_ZFS_CFGF" >> $LSOF_FBSD_ZFS_MKF
+  echo "" >> $LSOF_FBSD_ZFS_MKF
+  if test "X$LSOF_DEBUG" = "X" # {
+  then
+    LSOF_DEBUG="-O"
+  else
+    if test "X$LSOF_DEBUG" = "XNo-O"   # {
+    then
+      LSOF_DEBUG=""
+    fi # }
+  fi   # }
+  echo "DEBUG= $LSOF_DEBUG" >> $LSOF_FBSD_ZFS_MKF
+  echo "" >> $LSOF_FBSD_ZFS_MKF
+  echo "OPENSOLARIS=   $LSOF_FBSD_ZFS_SYS" >> $LSOF_FBSD_ZFS_MKF
+  echo "" >> $LSOF_FBSD_ZFS_MKF
+  cat ./dialects/$LSOF_DIALECT_DIR/$LSOF_FBSD_ZFS_MKF >> $LSOF_FBSD_ZFS_MKF
+  echo $LSOF_FBSD_ZFS_MKF created.
+fi     # }
+
+# Create test cc file.
+
+echo "$LSOF_CC" > $LSOF_TSTCC
+echo "$LSOF_TSTCC created"
+
+# Create test cflags file.
+
+echo "-DLT_DIAL_$LSOF_TGT" > $LSOF_TSTCFLG
+if test "X$LSOF_TSTBIGF" != "X"        # {
+then
+  echo "-DLT_BIGF" >> $LSOF_TSTCFLG
+  if test "X$LSOF_TSTBIGF" != "X "     # {
+  then
+    for i in $LSOF_TSTBIGF     # {
+    do
+      echo "$i" >> $LSOF_TSTCFLG
+    done       # }
+  fi   # }
+fi     # }
+if test "X$LSOF_TSTDFLG" != "X"        # {
+then
+  for i in $LSOF_TSTDFLG       # {
+  do
+    echo "$i" >> $LSOF_TSTCFLG
+  done # }
+fi     # }
+echo $LSOF_CC | grep gcc > /dev/null 2>&1
+if test $? -eq 0       # {
+then
+  echo "-DLT_GCC" >> $LSOF_TSTCFLG
+else
+  echo "-DLT_CC" >> $LSOF_TSTCFLG
+fi     # r}
+if test $LSOF_TSTKMEM -eq 1    # {
+then
+  echo "-DLT_KMEM" >> $LSOF_TSTCFLG
+fi     # }
+if test $LSOF_TSTK64 -eq 1     # {
+then
+  echo "-DLT_K64" >> $LSOF_TSTCFLG
+fi     # }
+echo "-DLT_VERS=$LSOF_VERS" >> $LSOF_TSTCFLG
+if test $LSOF_TSTVPATH -eq 1   # {
+then
+  echo "-DLT_VPATH" >> $LSOF_TSTCFLG
+fi     # }
+echo "$LSOF_TSTCFLG created"
+
+# Create tests loader flags file.
+
+echo $LSOF_TSTLFLG > $LSOF_TSTLFF
+echo "$LSOF_TSTLFF created"
+
+# Create test extra objects file.
+
+echo "$LSOF_TSTXO" > $LSOF_TSTXOC
+echo "$LSOF_TSTXOC created"
+
+rm -f $LSOF_HLP
+
+# Call Customize, as required.
+
+if test "X$LSOF_SCRIPT_CALL" = "Xyes" -a ! -r ./.neverCust     # {
+then
+  if test ! -f ./Customize     # {  Want -x, but Ultrix doesn't grok it.
+  then
+    echo "Can't find Customize script."
+    exit 1
+  fi   # }
+  ./Customize $LSOF_DIALECT_DIR
+fi     # }
+
+# Issue unsupported warnings, as appropriate.
+
+if test "X$LSOF_UNSUP" != "X"  # {
+then
+  echo "$LSOF_UNSUP"
+fi     #}
+if test "X$LSOF_UNSUP2" != "X" # {
+then
+  echo "$LSOF_UNSUP2"
+fi     #}
+exit 0
diff --git a/Customize b/Customize
new file mode 100755 (executable)
index 0000000..4607002
--- /dev/null
+++ b/Customize
@@ -0,0 +1,1151 @@
+#!/bin/sh
+#
+# $Id: Customize,v 1.9 2005/05/11 13:02:18 abe Exp $
+#
+# Customize: customize dialect's machine.h header file.
+#
+# Allows easy modification of some important compile-time definitions for
+# lsof, made in the dialect's machine.h header file, including:
+#
+#      HASSECURITY     the security option
+#      HASNOSOCKSECURITY
+#                      the socket oberalization of HASSECURITY
+#      HASDCACHE       enabling/disabling the device cache file
+#                      (Note: changing the device cache file option isn't
+#                             offered when machine.h contains NEVER_HASDCACHE
+#                             anywhere, including in a comment.)
+#      HASENVDC        enabling/disabling device cache path from environment
+#      HASKERNIDCK     enabling/disabling the kernel identity check
+#                      (not done for some dialects)
+#      HASPERSDC       enabling/disabling personal device cache path
+#                      construction
+#      HASPERSDCPATH   enabling/disabling additional personal device cache
+#                      path component
+#      HASSYSDC        enabling/disabling system-wide device cache file path
+#      HASXOPT_ROOT    enabling/disabling root use of the -X option
+#      WARNDEVACCESS   enabling inaccessible /dev node warnings
+#                      (Note: changing the inaccessible /dev/node warning
+#                             option isn't offered when machine.h contains
+#                             NEVER_WARNDEVACCESS anywhere, including in a
+#                             comment.)
+#      WARNINGSTATE    enable/disabling default warning message state
+#
+# Usage: Customize [dialect_directory]
+#
+# where: dialect_directory (optional) is the directory in which the dialect's
+#       dialect's sources, Makefile and scripts are found
+
+OLD=machine.h
+NEW=new_machine.h
+
+# Save optional dialect directory.
+
+if test $# -eq 1
+then
+  DialDir=$1
+else
+  DialDir=""
+fi
+
+# Establish trap and stty handling.
+
+ISIG=":"
+trap 'rm -f $NEW; $ISIG; exit 1' 1 2 3 15
+stty -a 2>&1 | grep isig > /dev/null
+if test $? -eq 0
+then
+  stty -a 2>&1 | egrep -e -isig > /dev/null
+  if test $? -eq 0
+  then
+    ISIG="stty -isig"
+    stty isig
+  fi
+fi
+
+# Decide how to use echo.
+
+ECHO=`echo -n ""`
+if test "X$ECHO" = "X-n "
+then
+  EC="\c"
+  EO=""
+else
+  EC=""
+  EO="-n"
+fi
+
+# Decide how to use tail(1).
+
+TMP1=`tail -n 1 $0 2> /dev/null`
+if test $? -eq 0 -a "X$TMP1" = "X#LAST_LINE"
+then
+  TA="-n 1"
+else
+  TA="-1"
+fi
+
+# Display the introduction and basic explanation.
+
+cat << .CAT_MARK
+
+You may now customize the machine.h header file for this UNIX
+dialect.  The customizations will take effect when you compile
+lsof.  You may also choose to skip customization and proceed to
+the compilation of lsof.
+
+If you don't know if you need to customize or want to know more
+about what you can customize, consult the 00DCACHE, 00FAQ, 00PORTING,
+and 00README files of the lsof distribution.  You might also find
+it helpful to examine the machine.h header file for the dialect
+you're customizing.
+
+You don't need to use this procedure to customize lsof; you can
+edit the machine.h header file directly.  If you later decide you
+want to use this procedure to customize machine.h, execute the
+./Customize script.
+.CAT_MARK
+
+END=0
+while test $END -eq 0
+do
+  echo ""
+  echo $EO "Do you want to customize (y|n) [y]? $EC"
+  read ANS EXCESS
+  if test "X$ANS" = "Xn" -o "X$ANS" = "XN"
+  then
+    exit 0
+  fi
+  if test "X$ANS" = "Xy" -o "X$ANS" = "XY" -o "X$ANS" = "X"
+  then
+    echo ""
+    echo "Customizing ..."
+    END=1
+  else
+    echo ""
+    echo "Please answer y|n [y]."
+  fi
+done
+
+# See if $OLD exists.
+
+if test ! -r $OLD
+then
+  echo ""
+  echo "FATAL: The file \"$OLD\" doesn't exist.  Customization can't"
+  echo "continue without it."
+  echo ""
+  echo "Did you run the Configure script?"
+  echo ""
+  echo "Customize quits."
+  echo ""
+  exit 1
+fi
+
+# See if $NEW exists.
+
+if test -r $NEW
+then
+  echo ""
+  echo "====================================================================="
+  echo ""
+  echo "WARNING: \"$NEW\" exists.  Customization will replace it."
+  END=0
+  while test $END -eq 0
+  do
+    echo ""
+    echo $EO "Do you want to remove $NEW (y|n) [y]? $EC"
+    read ANS EXCESS
+    if test "X$ANS" = "Xy" -o "X$ANS" = "XY" -o "X$ANS" = "X"
+    then
+      echo ""
+      echo "Removing $NEW"
+      echo ""
+      rm -f $NEW
+      END=1
+    else
+      if test "X$ANS" = "Xn" -o "X$ANS" = "XN"
+      then
+        echo ""
+        echo "FATAL: Customize quits; it must be able to create \"$NEW\"."
+        echo ""
+        exit 1
+      else
+        echo ""
+        echo "Please answer y|n [y]."
+      fi
+    fi
+  done
+fi
+
+# Process HASSECURITY.
+
+cat << .CAT_MARK
+
+=====================================================================
+
+When HASSECURITY is enabled, only the root user may use lsof to
+examine all open files; other users may examine only the files
+belonging to the real user ID of their lsof process.  If
+HASNOSOCKSECURITY is also defined, anyone may list anyone else's
+open socket files, provided their listing is selected with the "-i"
+option.
+
+When HASSECURITY is disabled, anyone may use lsof to examine all
+open files.
+
+.CAT_MARK
+
+grep HASSECURITY $OLD | tail $TA | egrep "^#define" > /dev/null
+if test $? -eq 0
+then
+  echo "HASSECURITY is enabled."
+  NSEC=1
+else
+  echo "HASSECURITY is disabled."
+  NSEC=0
+fi
+END=0
+while test $END -eq 0
+do
+  echo ""
+  if test $NSEC -eq 1
+  then
+    echo $EO "Disable HASSECURITY (y|n) [n]? $EC"
+  else
+    echo $EO "Enable HASSECURITY (y|n) [n]? $EC"
+  fi
+  read ANS EXCESS
+  if test "X$ANS" = "Xy" -o "X$ANS" = "XY"
+  then
+    echo ""
+    if test $NSEC -eq 1
+    then
+      NSEC=0
+      echo "HASSECURITY will be disabled."
+    else
+      NSEC=1
+      echo "HASSECURITY will be enabled."
+    fi
+    END=1
+  else
+    if test "X$ANS" = "Xn" -o "X$ANS" = "XN" -o "X$ANS" = "X"
+    then
+      echo ""
+      echo "HASSECURITY will not be changed."
+      END=1
+    else
+      echo ""
+      echo "Please answer y|n [n]."
+    fi
+  fi
+done
+
+# If HASSECURITY is enabled, see if HASNOSOCKSECURITY should also be defined.
+
+if test $NSEC -eq 1
+then
+  cat << .CAT_MARK
+
+====================================================================
+
+When HASSECURITY is enabled, you may also define HASNOSOCKSECURITY.
+
+When both are defined, no one but root may list all of anyone else's
+open files -- only their own open files -- but anyone may list
+anyone else's open socket files.
+
+This option is useful with ntop (http://www.ntop.org).
+
+.CAT_MARK
+
+  grep HASNOSOCKSECURITY $OLD | tail $TA | egrep "^#define" > /dev/null
+  if test $? -eq 0
+  then
+    echo "HASNOSOCKSECURITY is enabled."
+    SOCKSEC=1
+  else
+    echo "HASNOSOCKSECURITY is disabled."
+    SOCKSEC=0
+  fi
+  END=0
+  while test $END -eq 0
+  do
+    echo ""
+    if test $SOCKSEC -eq 1
+    then
+      echo $EO "Disable HASNOSOCKSECURITY (y|n) [n]? $EC"
+    else
+      echo $EO "Enable HASNOSOCKSECURITY (y|n) [n]? $EC"
+    fi
+    read ANS EXCESS
+    if test "X$ANS" = "Xy" -o "X$ANS" = "XY"
+    then
+      echo ""
+      if test $SOCKSEC -eq 1
+      then
+        SOCKSEC=0
+        echo "HASNOSOCKSECURITY will be disabled."
+      else
+        SOCKSEC=1
+        echo "HASNOSOCKSECURITY will be enabled."
+      fi
+      END=1
+    else
+      if test "X$ANS" = "Xn" -o "X$ANS" = "XN" -o "X$ANS" = "X"
+      then
+        echo ""
+        echo "HASNOSOCKSECURITY will not be changed."
+        END=1
+      else
+        echo ""
+        echo "Please answer y|n [n]."
+      fi
+    fi
+  done
+else
+  SOCKSEC=0
+fi
+
+# Process WARNINGSTATE.
+
+cat << .CAT_MARK
+
+=====================================================================
+
+When WARNINGSTATE is enabled, lsof will issue whatever warning
+messages it finds necessary.  When WARNINGSTATE is disabled, lsof
+will issue no warning messages.  For individual uses of lsof, -w
+disables warning state and +w enables it.
+
+.CAT_MARK
+
+grep WARNINGSTATE $OLD | tail $TA | egrep "^#define" > /dev/null
+if test $? -eq 0
+then
+  echo "WARNINGSTATE is disabled."
+  WST=0
+else
+  echo "WARNINGSTATE is enabled."
+  WST=1
+fi
+END=0
+NWST=$WST
+while test $END -eq 0
+do
+  echo ""
+  if test $NWST -eq 0
+  then
+    echo $EO "Enable WARNINGSTATE? (y|n) [n]? $EC"
+  else
+    echo $EO "Disable WARNINGSTATE? (y|n) [n]? $EC"
+  fi
+  read ANS EXCESS
+  if test "X$ANS" = "Xy" -o "X$ANS" = "XY"
+  then
+    echo ""
+    if test $NWST -eq 0
+    then
+      echo "WARNINGSTATE will be enabled."
+      NWST=1
+    else
+      echo "WARNINGSTATE will be disabled."
+      NWST=0
+    fi
+    END=1
+  else
+    if test "X$ANS" = "Xn" -o "X$ANS" = "XN" -o "X$ANS" = "X"
+    then
+      echo ""
+      echo "WARNINGSTATE will not be changed."
+      END=1
+    else
+      echo ""
+      echo "Please answer y|n [n]."
+    fi
+  fi
+done
+
+# Process WARNDEVACCESS, unless the dialect's machine.h header file contains
+# NEVER_WARNDEVACCESS.
+
+grep NEVER_WARNDEVACCESS $OLD > /dev/null
+if test $? -eq 0
+then
+  NEVERWDA=1
+  NWDA=0
+else
+  NEVERWDA=0
+  cat << .CAT_MARK
+
+=====================================================================
+
+When WARNDEVACCESS is enabled, lsof will issue warning messages
+when it can't access nodes in /dev (or /devices), subject to the
+default or explicit (-w) WARNINGSTATE.
+
+When WARNDEVACCESS is disabled, lsof will silently skip nodes in
+/dev (or /devices) that it can't access.
+
+.CAT_MARK
+
+  grep WARNDEVACCESS $OLD | tail $TA | egrep "^#define" > /dev/null
+  if test $? -eq 0
+  then
+    echo "WARNDEVACCESS is enabled."
+    WDA=1
+  else
+    echo "WARNDEVACCESS is disabled."
+    WDA=0
+  fi
+  END=0
+  NWDA=$WDA
+  while test $END -eq 0
+  do
+    echo ""
+    if test $NWDA -eq 1
+    then
+      echo $EO "Disable WARNDEVACCESS (y|n) [n]? $EC"
+    else
+      echo $EO "Enable WARNDEVACCESS (y|n) [n]? $EC"
+    fi
+    read ANS EXCESS
+    if test "X$ANS" = "Xy" -o "X$ANS" = "XY"
+    then
+      echo ""
+      if test $NWDA -eq 1
+      then
+        echo "WARNDEVACCESS will be disabled."
+        NWDA=0
+      else
+        echo "WARNDEVACCESS will be enabled."
+        NWDA=1
+      fi
+      END=1
+    else
+      if test "X$ANS" = "Xn" -o "X$ANS" = "XN" -o "X$ANS" = "X"
+      then
+       echo ""
+       echo "WARNDEVACCESS will not be changed."
+        END=1
+      else
+        echo ""
+        echo "Please answer y|n [n]."
+      fi
+    fi
+  done
+fi
+
+# Process HASDCACHE, unless the dialect's machine.h header file contains
+# NEVER_HASDCACHE.
+
+ENVV=""
+ENVN=0
+PDCV=""
+PDCN=0
+PDCPV=""
+PDCPN=0
+SDCV=""
+SDCN=0
+grep NEVER_HASDCACHE $OLD > /dev/null
+if test $? -eq 0
+then
+  NEVERDC=1
+  CDC=0
+  DC=0
+  NDC=0
+else
+  NEVERDC=0
+  cat << .CAT_MARK
+
+=====================================================================
+
+When HASDCACHE is enabled, lsof will write a device cache file that
+contains information about the nodes in /dev (or /devices).  The
+options HASENVDC, HASPERSDC, HASPERSDCPATH, and HASSYSDC define
+the device cache file path.
+
+When HASDCACHE is disabled, lsof won't write a device cache file.
+
+Consult the 00DCACHE and 00FAQ files of the lsof distribution for
+more information.
+
+.CAT_MARK
+
+  grep HASDCACHE $OLD | tail $TA | egrep "^#define" > /dev/null
+  if test $? -eq 0
+  then
+    echo "HASDCACHE is enabled."
+    DC=1
+  else
+    echo "HASDCACHE is disabled."
+    DC=0
+  fi
+  END=0
+  NDC=$DC
+  while test $END -eq 0
+  do
+    echo ""
+    if test $NDC -eq 1
+    then
+      echo $EO "Disable HASDCACHE (y|n) [n]? $EC"
+    else
+      echo $EO "Enable HASDCACHE (y|n) [n]? $EC"
+    fi
+    read ANS EXCESS
+    if test "X$ANS" = "Xy" -o "X$ANS" = "XY"
+    then
+      echo ""
+      if test $NDC -eq 1
+      then
+        echo "HASDCACHE will be disabled."
+        NDC=0
+      else
+        echo "HASDCACHE will be enabled."
+        NDC=1
+      fi
+      END=1
+    else
+      if test "X$ANS" = "Xn" -o "X$ANS" = "XN" -o "X$ANS" = "X"
+      then
+       echo ""
+       echo "HASDCACHE will not be changed."
+        END=1
+      else
+        echo ""
+        echo "Please answer y|n [n]."
+      fi
+    fi
+  done
+
+  # See if other device cache options need to be declared.
+
+  if test $DC -eq 1 -a $NDC -eq 1
+  then
+    cat << .CAT_MARK
+
+=====================================================================
+
+You have decided that HASDCACHE should be defined.  There are other
+definitions associated with HASDCACHE that specify options for the
+formation of the device cache file path.  You may change them.
+
+Consult the 00DCACHE and 00FAQ files of the lsof distribution for
+more information.
+
+The current path options are:
+
+.CAT_MARK
+
+    grep HASENVDC $OLD | tail $TA | egrep "^#define"
+    egrep "HASPERSDC$|HASPERSDC[       ]" $OLD | tail $TA | egrep "^#define"
+    grep HASPERSDCPATH $OLD | tail $TA | egrep "^#define"
+    grep HASSYSDC $OLD | tail $TA | egrep "^#define"
+    END=0
+    while test $END -eq 0
+    do
+      echo ""
+      echo $EO "Do you want to change path options (y|n) [n]? $EC"
+      read ANS EXCESS
+      if test "X$ANS" = "Xy" -o "X$ANS" = "XY"
+      then
+        CDC=1
+        END=1
+      else
+        if test "X$ANS" = "Xn" -o "X$ANS" = "XN"
+        then
+         CDC=0
+         END=1
+        else
+         if test "X$ANS" = "X"
+         then
+           echo ""
+           echo "The path options will not be changed."
+           CDC=0
+           END=1
+         else
+           echo ""
+           echo "Please answer y|n [n]."
+         fi
+        fi
+      fi
+    done
+  else
+    CDC=0
+  fi
+  if test \( $NDC -eq 1 -a $DC -eq 0 \) -o \( $DC -eq 1 -a $CDC -eq 1 \)
+  then
+    cat << .CAT_MARK
+
+=====================================================================
+
+You may specify for HASENVDC the name of the environment variable
+from which lsof should take the device cache file path for non-root
+users.  Press ENTER to use the current value of HASENVDC:
+
+.CAT_MARK
+
+    echo $EO "        $EC"
+    TMP1=`grep HASENVDC $OLD | tail $TA | egrep "^#define"`
+    if test "X$TMP1" != "X"
+    then
+      TMP1=`echo "$TMP1" | sed 's/^#define[    ]HASENVDC[      ]"\([^"]*\)".*$/\1/'`
+      echo "$TMP1"
+    else
+      echo "no current HASENVDC value"
+    fi
+    END=0
+    GV=0
+    while test $END -eq 0
+    do
+      echo ""
+      echo $EO "Do you want to define a name for HASENVDC (y|n) [n]? $EC"
+      read ANS EXCESS
+      if test "X$ANS" = "Xn" -o "X$ANS" = "XN"
+      then
+        ENVV=""
+        END=1
+      else
+        if test "X$ANS" = "Xy" -o "X$ANS" = "XY"
+        then
+         GV=1
+         END=1
+        else
+         if test "X$ANS" = "X"
+         then
+           echo ""
+           echo "HASENVDC will not be changed."
+           ENVV=$TMP1
+           END=1
+         else
+           echo ""
+           echo "Please answer y|n [n]."
+         fi
+        fi
+      fi
+    done
+    if test $GV -eq 1
+    then
+      echo ""
+      echo $EO "Please enter the HASENVDC name (no quotes): $EC"
+      read TMP1 EXCESS
+      ENVV=`echo $TMP1 | sed 's/^\"//' | sed 's/\"$//'`
+      if test "X$ENVV" = "X"
+      then
+       ENVN=1
+      fi
+    fi
+    cat << .CAT_MARK
+
+=====================================================================
+
+HASPERSDC is a format that specifies how the personal device cache
+path is constructed.  Consult the 00DCACHE and 00FAQ files of the
+lsof distribution for information on the conversions supported in
+HASPERSDC.  Press ENTER to use the curent HASPERSDC format:
+
+.CAT_MARK
+
+    echo $EO "        $EC"
+    TMP1=`egrep "HASPERSDC$|HASPERSDC[         ]" $OLD | tail $TA | egrep "^#define"`
+    if test "X$TMP1" != "X"
+    then
+      TMP1=`echo "$TMP1" | sed 's/^#define[    ]HASPERSDC[     ]"\([^"]*\)".*$/\1/'`
+      echo "$TMP1"
+    else
+      echo "no current HASPERSDC format"
+    fi
+    END=0
+    GV=0
+    while test $END -eq 0
+    do
+      echo ""
+      echo $EO "Do you want to define a format for HASPERSDC (y|n) [n]? $EC"
+      read ANS EXCESS
+      if test "X$ANS" = "Xn" -o "X$ANS" = "XN"
+      then
+        END=1
+      else
+        if test "X$ANS" = "Xy" -o "X$ANS" = "XY"
+        then
+         GV=1
+         END=1
+        else
+         if test "X$ANS" = "X"
+         then
+           echo ""
+           echo "HASPERSDC will not be changed."
+           PDCV=$TMP1
+           END=1
+         else
+           echo ""
+           echo "Please answer y|n [n]."
+         fi
+        fi
+      fi
+    done
+    if test $GV -eq 1
+    then
+      echo ""
+      echo $EO "Please enter the HASPERSDC format (no quotes): $EC"
+      read TMP1 EXCESS
+      PDCV=`echo $TMP1 | sed 's/^\"//' | sed 's/\"$//'`
+      if test "X$PDCV" = "X"
+      then
+       PDCN=1
+      fi
+    fi
+    cat << .CAT_MARK
+
+=====================================================================
+
+Specify for HASPERSDCPATH the name of the environment variable from
+which lsof should take a path name component to insert at the %p
+conversion in the HASPERSDC format.
+
+Consult the 00FAQ and 00DCACHE files of the lsof distribution for
+more information on HASPERSDCPATH usage.
+
+Press ENTER to use the current value for HASPERSDCPATH:
+
+.CAT_MARK
+
+    echo $EO "        $EC"
+    TMP1=`grep HASPERSDCPATH $OLD | tail $TA | egrep "^#define"`
+    if test "X$TMP1" != "X"
+    then
+      TMP1=`echo "$TMP1" | sed 's/^#define[    ]HASPERSDCPATH[         ]"\([^"]*\)".*$/\1/'`
+      echo "$TMP1"
+    else
+      echo "no current HASPERSDCPATH value"
+    fi
+    END=0
+    GV=0
+    while test $END -eq 0
+    do
+      echo ""
+      echo $EO "Do you want to change HASPERSDCPATH (y|n) [n]? $EC"
+      read ANS EXCESS
+      if test "X$ANS" = "Xn" -o "X$ANS" = "XN" -o "X$ANS" = "X"
+      then
+       echo ""
+       echo "HASPERSDCPATH will not be changed."
+       PDCPV=$TMP1
+        END=1
+      else
+        if test "X$ANS" = "Xy" -o "X$ANS" = "XY"
+        then
+         GV=1
+         END=1
+       else
+         echo ""
+         echo "Please answer y|n [n]."
+       fi
+      fi
+    done
+    if test $GV -eq 1
+    then
+      echo ""
+      echo $EO "Please enter the HASPERSDCPATH name (no quotes): $EC"
+      read TMP1 EXCESS
+      PDCPV=`echo $TMP1 | sed 's/^\"//' | sed 's/\"$//'`
+      if test "X$PDCPV" = "X"
+      then
+       PDCPN=1
+      fi
+    fi
+    cat << .CAT_MARK
+
+=====================================================================
+
+Specify for HASSYSDC the system-wide device cache file path.  Press
+ENTER to use the current HASSYSDC value:
+
+.CAT_MARK
+
+    echo $EO "        $EC"
+    TMP1=`grep HASSYSDC $OLD | tail $TA | egrep "^#define"`
+    if test "X$TMP1" != "X"
+    then
+      TMP1=`echo "$TMP1" | sed 's/^#define[    ]HASSYSDC[      ]"\([^"]*\)".*$/\1/'`
+      echo "$TMP1"
+    else
+      echo "no current HASSYSDC value"
+    fi
+    END=0
+    GV=0
+    while test $END -eq 0
+    do
+      echo ""
+      echo $EO "Do you want to define a system-device path (y|n) [n]? $EC"
+      read ANS EXCESS
+      if test "X$ANS" = "Xn" -o "X$ANS" = "XN"
+      then
+        END=1
+      else
+        if test "X$ANS" = "Xy" -o "X$ANS" = "XY"
+        then
+         GV=1
+         END=1
+        else
+         if test "X$ANS" = "X"
+         then
+           echo ""
+           echo "No HASSYSDC change will be made."
+           SDCV=$TMP1
+           END=1
+         else
+           echo ""
+           echo "Please answer y|n [n]."
+         fi
+        fi
+      fi
+    done
+    if test $GV -eq 1
+    then
+      echo ""
+      echo $EO "Please enter the system-wide path (no quotes): $EC"
+      read TMP1 EXCESS
+      SDCV=`echo $TMP1 | sed 's/^\"//' | sed 's/\"$//'`
+      if test "X$SDCV" = "X"
+      then
+       SDCN=1
+      fi
+    fi
+  fi
+fi
+
+# If HASXOPT is defined, and HASXOPT_ROOT is mentioned,
+# ask about changing HASXOPT_ROOT.
+
+HXRC=0
+grep HASXOPT $OLD | tail $TA | egrep "^#define" > /dev/null
+if test $? -eq 0
+then
+  grep HASXOPT_ROOT $OLD > /dev/null
+  if test $? -eq 0
+  then
+    cat << .CAT_MARK
+
+=====================================================================
+
+HASXOPT is defined.  If the dialect for which you are customizing
+appears in the following list, you may want to change the definition
+of HASXOPT_ROOT to restrict the use of the X option to lsof processes
+whose real user ID is root, or enable use of it by all user IDs.
+
+  AIX           the -X option enables the risky operation of letting
+               lsof read library entry structures with readx().
+               If HASXOPT_ROOT is defined, only processes whose
+               real user ID is root will be allowed to use -X.
+               If HASXOPT_ROOT is undefined, any process will be
+               allowed to use -X.  Consult the 00FAQ file of the
+               lsof distribution for more information on why
+               readx() may be risky.
+
+.CAT_MARK
+
+    grep HASXOPT_ROOT $OLD | tail $TA | egrep "^#define" > /dev/null
+    if test $? -eq 0
+    then
+      echo "HASXOPT_ROOT is defined."
+      HXR="undefine"
+      HXRS=1
+    else
+      echo "HASXOPT_ROOT is not defined."
+      HXR="define"
+      HXRS=0
+    fi
+    END=0
+    while test $END -eq 0
+    do
+      echo ""
+      echo $EO "Do you want to $HXR HASXOPT_ROOT (y|n) [n]? $EC"
+      read ANS EXCESS
+      if test "X$ANS" = "Xy" -o "X$ANS" = "XY"
+      then
+        HXRA=1
+        END=1
+      else
+        if test "X$ANS" = "Xn" -o "X$ANS" = "XN" -o "X$ANS" = "X"
+        then
+         echo ""
+         echo "HASXOPT_ROOT will not be changed."
+          HXRA=0
+          END=1
+        else
+          echo ""
+          echo "Please answer y|n [n]."
+        fi
+      fi
+    done
+    if test $HXRA -eq 1
+    then
+      HXRC=1
+    fi
+  fi
+fi
+
+# Process HASKERNIDCK.  Skip processing for selected dialect directories.
+
+case $DialDir in
+  linux/proc)
+    NIDCK=0
+    ;;
+  *)
+    cat << .CAT_MARK
+
+=====================================================================
+
+When HASKERNIDCK is enabled, lsof compares the identity of the
+kernel where it was built to the identity of the kernel where it
+is running.  This check can detect an lsof executable inappropriate
+for the system on which it is being run.
+
+The kernel identity check can take considerable time on some UNIX
+dialects -- e.g., AIX -- so there may be occasions when it is
+desirable to disable it, in spite of the increased risk of using
+an inappropriate lsof executable.
+
+.CAT_MARK
+
+    grep HASKERNIDCK $OLD | tail $TA | grep "^#define" > /dev/null
+    if test $? -eq 0
+    then
+      echo "HASKERNIDCK is enabled."
+      IDCK=1
+    else
+      echo "HASKERNIDCK is disabled."
+      IDCK=0
+    fi
+    END=0
+    NIDCK=$IDCK
+    while test $END -eq 0
+    do
+      echo ""
+      if test $NIDCK -eq 1
+      then
+        echo $EO "Disable HASKERNIDCK (y|n) [n]? $EC"
+      else
+        echo $EO "Enable HASKERNIDCK (y|n) [n]? $EC"
+      fi
+      read ANS EXCESS
+      if test "X$ANS" = "Xy" -o "X$ANS" = "XY"
+      then
+        echo ""
+        if test $NIDCK -eq 1
+        then
+          NIDCK=0
+          echo "HASKERNIDCK will be disabled."
+        else
+          NIDCK=1
+          echo "HASKERNIDCK will be enabled."
+        fi
+        END=1
+      else
+        if test "X$ANS" = "Xn" -o "X$ANS" = "XN" -o "X$ANS" = "X"
+        then
+          echo ""
+          echo "HASKERNIDCK will not be changed."
+          END=1
+          NIDCK=$IDCK
+        else
+          echo ""
+          echo "Please answer y|n [n]."
+        fi
+      fi
+    done
+    ;;
+esac
+
+# Initialize new machine.h.
+
+rm -f $NEW
+cp $OLD $NEW
+chmod 0644 $NEW
+echo "" >> $NEW
+echo "/*" >> $NEW
+echo $EO " * Added by Customize on $EC" >> $NEW
+date >> $NEW
+echo " */" >> $NEW
+echo "" >> $NEW
+
+# Change HASSECURITY and HASNOSOCKSECURITY, as required.
+
+echo "#undef   HASSECURITY" >> $NEW
+echo "#undef   HASNOSOCKSECURITY" >> $NEW
+if test $NSEC -eq 1
+then
+  echo "#define        HASSECURITY     1" >> $NEW
+  if test $SOCKSEC -eq 1
+  then
+    echo "#define      HASNOSOCKSECURITY       1" >> $NEW
+  fi
+fi
+
+# Change WARNDEVACCESS, as required.
+
+if test $NEVERWDA -eq 0
+then
+  echo "#undef WARNDEVACCESS" >> $NEW
+  if test $NWDA -eq 1
+  then
+    echo "#define      WARNDEVACCESS   1" >> $NEW
+  fi
+fi
+
+# Change WARNINGSTATE, as required.
+
+echo "#undef   WARNINGSTATE" >> $NEW
+if test $NWST -eq 0
+then
+  echo "#define        WARNINGSTATE    1" >> $NEW
+fi
+
+# Change device cache definitions, as required.
+
+if test \( $NDC -eq 1 -a $DC -eq 0 \) -o \( $DC -eq 1 -a $CDC -eq 1 \)
+then
+  if test "X$ENVV" = "X" -a "X$PDCV" = "X" -a "X$SDCV" = "X"
+  then
+    cat << .CAT_MARK
+
+FATAL: HASDCACHE is defined, but there is no definition for
+       any of HASENVDC, HASPERSDC, or HASSYSDC
+
+       No new machine.h has been created.
+
+       Customize quits.
+
+       Restart Customize and define at least one of HASENVDC,
+       HASPERSDC, or HASSYSDC.
+
+.CAT_MARK
+
+    rm -f $NEW
+    exit 1
+  fi
+fi
+if test "X$PDCV" != "X"
+then
+  echo "$PDCV" | grep "%p" > /dev/null
+  if test $? -eq 0 -a $PDCPN -eq 1
+  then
+    cat << .CAT_MARK
+
+FATAL: HASDCACHE is defined and HASPERSDC has a %p conversion,
+       but HASPERSDCPATH is NULL.
+
+       No new machine.h has been created.
+
+       Customize quits.
+
+       Restart Customize and define HASPERSDCPATH.
+
+.CAT_MARK
+
+    rm -f $NEW
+    exit 1
+  fi
+fi
+echo "#undef   HASDCACHE" >> $NEW
+if test $NEVERDC -eq 1
+then
+  echo "#undef HASENVDC" >> $NEW
+  echo "#undef HASPERSDC" >> $NEW
+  echo "#undef HASPERSDCPATH" >> $NEW
+  echo "#undef HASSYSDC" >> $NEW
+else
+  if test $NDC -eq 1
+  then
+    echo "#define      HASDCACHE       1" >> $NEW
+    if test "X$ENVV" != "X" -o $ENVN -eq 1
+    then
+      echo "#undef     HASENVDC" >> $NEW
+      if test $ENVN -eq 0
+      then
+        echo "#define  HASENVDC        \"$ENVV\"" >> $NEW
+      fi
+    fi
+    if test "X$PDCV" != "X" -o $PDCN -eq 1
+    then
+      echo "#undef     HASPERSDC" >> $NEW
+      if test $PDCN -eq 0
+      then
+        echo "#define  HASPERSDC       \"$PDCV\"" >> $NEW
+      fi
+    fi
+    if test "X$PDCPV" != "X" -o $PDCPN -eq 1
+    then
+      echo "#undef     HASPERSDCPATH" >> $NEW
+      if test $PDCPN -eq 0
+      then
+        echo "#define  HASPERSDCPATH   \"$PDCPV\"" >> $NEW
+      fi
+    fi
+    if test "X$SDCV" != "X" -o $SDCN -eq 1
+    then
+      echo "#undef     HASSYSDC" >> $NEW
+      if test $SDCN -eq 0
+      then
+        echo "#define  HASSYSDC        \"$SDCV\"" >> $NEW
+      fi
+    fi
+  fi
+fi
+
+# Change HASXOPT_ROOT, as required.
+
+if test $HXRC -eq 1
+then
+  if test $HXRS -eq 1
+  then
+    echo "#undef       HASXOPT_ROOT" >> $NEW
+  else
+    echo "#define      HASXOPT_ROOT    1" >> $NEW
+  fi
+fi
+
+# Change HASKERNIDCK, as required.
+
+echo "#undef   HASKERNIDCK" >> $NEW
+if test $NIDCK -eq 1
+then
+  echo "#define        HASKERNIDCK     1" >> $NEW
+fi
+
+# Replace the current machine.h with the new one, as requested.
+
+echo ""
+echo "====================================================================="
+echo ""
+echo "A new $OLD file has been created in \"$NEW\"."
+END=0
+while test $END -eq 0
+do
+  echo ""
+  echo "Do you want to rename $OLD to ${OLD}.old and replace it with"
+  echo $EO "$NEW (y|n) [y]? $EC"
+  read ANS EXCESS
+  if test "X$ANS" = "Xn" -o "X$ANS" = "XN"
+  then
+    END=1
+  else
+    if test "X$ANS" = "Xy" -o "X$ANS" = "XY" -o "X$ANS" = "X"
+    then
+      rm -f ${OLD}.old
+      mv $OLD ${OLD}.old
+      mv $NEW $OLD
+      END=1
+    else
+      echo ""
+      echo "Please answer y|n [y]."
+    fi
+  fi
+done
+echo ""
+echo "You may now run the make command -- e.g.,"
+echo ""
+echo "        $ make"
+echo ""
+exit 0
+#LAST_LINE
diff --git a/Doxyfile b/Doxyfile
new file mode 100644 (file)
index 0000000..82eea4c
--- /dev/null
+++ b/Doxyfile
@@ -0,0 +1,2733 @@
+# Doxyfile 1.9.4
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+#
+# Note:
+#
+# Use doxygen to compare the used configuration file with the template
+# configuration file:
+# doxygen -x [configFile]
+# Use doxygen to compare the used configuration file with the template
+# configuration file without replacing the environment variables:
+# doxygen -x_noenv [configFile]
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the configuration
+# file that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# https://www.gnu.org/software/libiconv/ for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME           = "lsof: LiSt Open Files"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER         =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          =
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO           =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = output
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096
+# sub-directories (in 2 levels) under the output directory of each output format
+# and will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to
+# control the number of sub-directories.
+# The default value is: NO.
+
+CREATE_SUBDIRS         = NO
+
+# Controls the number of sub-directories that will be created when
+# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every
+# level increment doubles the number of directories, resulting in 4096
+# directories at level 8 which is the default and also the maximum value. The
+# sub-directories are organized in 2 levels, the first level always has a fixed
+# numer of 16 directories.
+# Minimum value: 0, maximum value: 8, default value: 8.
+# This tag requires that the tag CREATE_SUBDIRS is set to YES.
+
+CREATE_SUBDIRS_LEVEL   = 8
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES    = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian,
+# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English
+# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek,
+# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with
+# English messages), Korean, Korean-en (Korean with English messages), Latvian,
+# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese,
+# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish,
+# Swedish, Turkish, Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF       = "The $name class" \
+                         "The $name widget" \
+                         "The $name file" \
+                         is \
+                         provides \
+                         specifies \
+                         contains \
+                         represents \
+                         a \
+                         an \
+                         the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES        = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF      = YES
+
+# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line
+# such as
+# /***************
+# as being the beginning of a Javadoc-style comment "banner". If set to NO, the
+# Javadoc-style will behave just like regular comments and it will not be
+# interpreted by doxygen.
+# The default value is: NO.
+
+JAVADOC_BANNER         = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# By default Python docstrings are displayed as preformatted text and doxygen's
+# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the
+# doxygen's special commands can be used and the contents of the docstring
+# documentation blocks is shown as doxygen documentation.
+# The default value is: YES.
+
+PYTHON_DOCSTRING       = YES
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE               = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:^^"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". Note that you cannot put \n's in the value part of an alias
+# to insert newlines (in the resulting output). You can put ^^ in the value part
+# of an alias to insert a newline as if a physical newline was in the original
+# file. When you need a literal { or } or , in the value part of an alias you
+# have to escape them by means of a backslash (\), this can lead to conflicts
+# with the commands \{ and \} for these it is advised to use the version @{ and
+# @} or use a double escape (\\{ and \\})
+
+ALIASES                =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice
+# sources only. Doxygen will then generate output that is more tailored for that
+# language. For instance, namespaces will be presented as modules, types will be
+# separated into more groups, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_SLICE  = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, JavaScript,
+# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice,
+# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:
+# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser
+# tries to guess whether the code is fixed or free formatted code, this is the
+# default for Fortran type files). For instance to make doxygen treat .inc files
+# as Fortran files (default is PHP), and .f files as C (default is Fortran),
+# use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen. When specifying no_extension you should add
+# * to the FILE_PATTERNS.
+#
+# Note see also the list of default file extension mappings.
+
+EXTENSION_MAPPING      =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See https://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT       = YES
+
+# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
+# to that level are automatically included in the table of contents, even if
+# they do not have an id attribute.
+# Note: This feature currently applies only to Markdown headings.
+# Minimum value: 0, maximum value: 99, default value: 5.
+# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
+
+TOC_INCLUDE_HEADINGS   = 5
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT       = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE      = 0
+
+# The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use
+# during processing. When set to 0 doxygen will based this on the number of
+# cores available in the system. You can set it explicitly to a value larger
+# than 0 to get more control over the balance between CPU load and processing
+# speed. At this moment only the input processing can be done using multiple
+# threads. Since this is still an experimental feature the default is set to 1,
+# which effectively disables parallel processing. Please report any issues you
+# encounter. Generating dot graphs in parallel is controlled by the
+# DOT_NUM_THREADS setting.
+# Minimum value: 0, maximum value: 32, default value: 1.
+
+NUM_PROC_THREADS       = 1
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual
+# methods of a class will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIV_VIRTUAL   = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If this flag is set to YES, the name of an unnamed parameter in a declaration
+# will be determined by the corresponding definition. By default unnamed
+# parameters remain unnamed in the output.
+# The default value is: YES.
+
+RESOLVE_UNNAMED_PARAMS = YES
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# declarations. If set to NO, these declarations will be included in the
+# documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS          = NO
+
+# With the correct setting of option CASE_SENSE_NAMES doxygen will better be
+# able to match the capabilities of the underlying filesystem. In case the
+# filesystem is case sensitive (i.e. it supports files in the same directory
+# whose names only differ in casing), the option must be set to YES to properly
+# deal with such files in case they appear in the input. For filesystems that
+# are not case sensitive the option should be set to NO to properly deal with
+# output files written for symbols that only differ in casing, such as for two
+# classes, one named CLASS and the other named Class, and to also support
+# references to files without having to specify the exact matching casing. On
+# Windows (including Cygwin) and MacOS, users should typically set this option
+# to NO, whereas on Linux or other Unix flavors it should typically be set to
+# YES.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class
+# will show which file needs to be included to use the class.
+# The default value is: YES.
+
+SHOW_HEADERFILE        = YES
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC  = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file. See also section "Changing the
+# layout of pages" for information.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE            =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS               = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as documenting some parameters in
+# a documented function twice, or documenting parameters that don't exist or
+# using markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR      = YES
+
+# If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete
+# function parameter documentation. If set to NO, doxygen will accept that some
+# parameters have no documentation without warning.
+# The default value is: YES.
+
+WARN_IF_INCOMPLETE_DOC = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong parameter
+# documentation, but not about the absence of documentation. If EXTRACT_ALL is
+# set to YES then this flag will automatically be disabled. See also
+# WARN_IF_INCOMPLETE_DOC
+# The default value is: NO.
+
+WARN_NO_PARAMDOC       = NO
+
+# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
+# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
+# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
+# at the end of the doxygen process doxygen will return with a non-zero status.
+# Possible values are: NO, YES and FAIL_ON_WARNINGS.
+# The default value is: NO.
+
+WARN_AS_ERROR          = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# See also: WARN_LINE_FORMAT
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# In the $text part of the WARN_FORMAT command it is possible that a reference
+# to a more specific place is given. To make it easier to jump to this place
+# (outside of doxygen) the user can define a custom "cut" / "paste" string.
+# Example:
+# WARN_LINE_FORMAT = "'vi $file +$line'"
+# See also: WARN_FORMAT
+# The default value is: at line $line of file $file.
+
+WARN_LINE_FORMAT       = "at line $line of file $file"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr). In case the file specified cannot be opened for writing the
+# warning and error messages are written to standard error. When as file - is
+# specified the warning and error messages are written to standard output
+# (stdout).
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
+# Note: If this tag is empty the current directory is searched.
+
+INPUT                  = include
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see:
+# https://www.gnu.org/software/libiconv/) for the list of possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# Note the list of default checked file patterns might differ from the list of
+# default file extension mappings.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
+# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
+# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml,
+# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C
+# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd,
+# *.vhdl, *.ucf, *.qsf and *.ice.
+
+FILE_PATTERNS          = *.c \
+                         *.cc \
+                         *.cxx \
+                         *.cpp \
+                         *.c++ \
+                         *.java \
+                         *.ii \
+                         *.ixx \
+                         *.ipp \
+                         *.i++ \
+                         *.inl \
+                         *.idl \
+                         *.ddl \
+                         *.odl \
+                         *.h \
+                         *.hh \
+                         *.hxx \
+                         *.hpp \
+                         *.h++ \
+                         *.l \
+                         *.cs \
+                         *.d \
+                         *.php \
+                         *.php4 \
+                         *.php5 \
+                         *.phtml \
+                         *.inc \
+                         *.m \
+                         *.markdown \
+                         *.md \
+                         *.mm \
+                         *.dox \
+                         *.py \
+                         *.pyw \
+                         *.f90 \
+                         *.f95 \
+                         *.f03 \
+                         *.f08 \
+                         *.f18 \
+                         *.f \
+                         *.for \
+                         *.vhd \
+                         *.vhdl \
+                         *.ucf \
+                         *.qsf \
+                         *.ice
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# ANamespace::AClass, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS       = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# entity all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS        = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see https://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS       = YES
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
+# clang parser (see:
+# http://clang.llvm.org/) for more accurate parsing at the cost of reduced
+# performance. This can be particularly helpful with template rich C++ code for
+# which doxygen's built-in parser lacks the necessary type information.
+# Note: The availability of this option depends on whether or not doxygen was
+# generated with the -Duse_libclang=ON option for CMake.
+# The default value is: NO.
+
+CLANG_ASSISTED_PARSING = NO
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES and the CLANG_ADD_INC_PATHS
+# tag is set to YES then doxygen will add the directory of each input to the
+# include path.
+# The default value is: YES.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_ADD_INC_PATHS    = YES
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by doxygen for the files and directories
+# specified with INPUT and INCLUDE_PATH.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_OPTIONS          =
+
+# If clang assisted parsing is enabled you can provide the clang parser with the
+# path to the directory containing a file called compile_commands.json. This
+# file is the compilation database (see:
+# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the
+# options used when the source files were built. This is equivalent to
+# specifying the -p option to a clang tool, such as clang-check. These options
+# will then be passed to the parser. Any options specified with CLANG_OPTIONS
+# will be added as well.
+# Note: The availability of this option depends on whether or not doxygen was
+# generated with the -Duse_libclang=ON option for CMake.
+
+CLANG_DATABASE_PATH    =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX     = YES
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET  =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a color-wheel, see
+# https://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use gray-scales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to YES can help to show when doxygen was last run and thus if the
+# documentation is up to date.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP         = NO
+
+# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
+# documentation will contain a main index with vertical navigation menus that
+# are dynamically created via JavaScript. If disabled, the navigation index will
+# consists of multiple levels of tabs that are statically embedded in every HTML
+# page. Disable this option to support browsers that do not have JavaScript,
+# like the Qt help browser.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_MENUS     = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see:
+# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To
+# create a documentation set, doxygen will generate a Makefile in the HTML
+# output directory. Running make will produce the docset in that directory and
+# running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy
+# genXcode/_index.html for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET        = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# This tag determines the URL of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDURL         =
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# on Windows. In the beginning of 2021 Microsoft took the original page, with
+# a.o. the download links, offline the HTML help workshop was already many years
+# in maintenance mode). You can download the HTML help workshop from the web
+# archives at Installation executable (see:
+# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo
+# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe).
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP      = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE               =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION           =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the main .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI           = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING     =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# The QHG_LOCATION tag can be used to specify the location (absolute path
+# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to
+# run qhelpgenerator on the generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine tune the look of the index (see "Fine-tuning the output"). As an
+# example, the default style sheet generated by doxygen has an example that
+# shows how to put an image at the root of the tree instead of the PROJECT_NAME.
+# Since the tree basically has the same information as the tab index, you could
+# consider setting DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW      = NO
+
+# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the
+# FULL_SIDEBAR option determines if the side bar is limited to only the treeview
+# area (value NO) or if it should extend to the full height of the window (value
+# YES). Setting this to YES gives a layout similar to
+# https://docs.readthedocs.io with more room for contents, but less room for the
+# project logo, title, and description. If either GENERATE_TREEVIEW or
+# DISABLE_INDEX is set to NO, this option has no effect.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FULL_SIDEBAR           = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH         = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email
+# addresses.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+OBFUSCATE_EMAILS       = YES
+
+# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg
+# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see
+# https://inkscape.org) to generate formulas as SVG images instead of PNGs for
+# the HTML output. These images will generally look nicer at scaled resolutions.
+# Possible values are: png (the default) and svg (looks nicer but requires the
+# pdf2svg or inkscape tool).
+# The default value is: png.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FORMULA_FORMAT    = png
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANSPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT    = YES
+
+# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands
+# to create new LaTeX commands to be used in formulas as building blocks. See
+# the section "Including formulas" for details.
+
+FORMULA_MACROFILE      =
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# https://www.mathjax.org) which uses client side JavaScript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX            = NO
+
+# With MATHJAX_VERSION it is possible to specify the MathJax version to be used.
+# Note that the different versions of MathJax have different requirements with
+# regards to the different settings, so it is possible that also other MathJax
+# settings have to be changed when switching between the different MathJax
+# versions.
+# Possible values are: MathJax_2 and MathJax_3.
+# The default value is: MathJax_2.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_VERSION        = MathJax_2
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. For more details about the output format see MathJax
+# version 2 (see:
+# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3
+# (see:
+# http://docs.mathjax.org/en/latest/web/components/output.html).
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility. This is the name for Mathjax version 2, for MathJax version 3
+# this will be translated into chtml), NativeMML (i.e. MathML. Only supported
+# for NathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This
+# is the name for Mathjax version 3, for MathJax version 2 this will be
+# translated into HTML-CSS) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from https://www.mathjax.org before deployment. The default value is:
+# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2
+# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH        =
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# for MathJax version 2 (see
+# https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions):
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# For example for MathJax version 3 (see
+# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html):
+# MATHJAX_EXTENSIONS = ams
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS     =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see:
+# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE       =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using JavaScript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH    = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see:
+# https://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see:
+# https://xapian.org/). See the section "External Indexing and Searching" for
+# details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX         = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when not enabling USE_PDFLATEX the default is latex when enabling
+# USE_PDFLATEX the default is pdflatex and when in the later case latex is
+# chosen this is overwritten by pdflatex. For specific output languages the
+# default can have been set differently, this depends on the implementation of
+# the output language.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME         =
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# Note: This tag is used in the Makefile / make.bat.
+# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file
+# (.tex).
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to
+# generate index for LaTeX. In case there is no backslash (\) as first character
+# it will be automatically added in the LaTeX code.
+# Note: This tag is used in the generated output file (.tex).
+# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat.
+# The default value is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_MAKEINDEX_CMD    = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE             = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a user-defined LaTeX header for
+# the generated LaTeX document. The header should contain everything until the
+# first chapter. If it is left blank doxygen will generate a standard header. It
+# is highly recommended to start with a default header using
+# doxygen -w latex new_header.tex new_footer.tex new_stylesheet.sty
+# and then modify the file new_header.tex. See also section "Doxygen usage" for
+# information on how to generate the default header that doxygen normally uses.
+#
+# Note: Only use a user-defined header if you know what you are doing!
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. The following
+# commands have a special meaning inside the header (and footer): For a
+# description of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a user-defined LaTeX footer for
+# the generated LaTeX document. The footer should contain everything after the
+# last chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer. See also section "Doxygen
+# usage" for information on how to generate the default footer that doxygen
+# normally uses. Note: Only use a user-defined footer if you know what you are
+# doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER           =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES      =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as
+# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX
+# files. Set this option to YES, to get a higher quality PDF documentation.
+#
+# See also section LATEX_CMD_NAME for selecting the engine.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE        = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES     = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# https://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE        = plain
+
+# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_TIMESTAMP        = NO
+
+# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
+# path from which the emoji images will be read. If a relative path is entered,
+# it will be relative to the LATEX_OUTPUT directory. If left blank the
+# LATEX_OUTPUT directory will be used.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EMOJI_DIRECTORY  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# configuration file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's configuration file. A template extensions file can be
+# generated using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION          = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR             =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT             = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING     = YES
+
+# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include
+# namespace members in file scope as well, matching the HTML output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_NS_MEMB_FILE_SCOPE = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT         = docbook
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures
+# the structure of the code including all documentation. Note that this feature
+# is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor. Note that the INCLUDE_PATH is not recursive, so the setting of
+# RECURSIVE has no effect here.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED             =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS        = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES         = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH               =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: YES.
+
+HAVE_DOT               = YES
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS        = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME           = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH tag is set to YES (or GRAPH) then doxygen will generate a
+# graph for each documented class showing the direct and indirect inheritance
+# relations. In case HAVE_DOT is set as well dot will be used to draw the graph,
+# otherwise the built-in generator will be used. If the CLASS_GRAPH tag is set
+# to TEXT the direct and indirect inheritance relations will be shown as texts /
+# links.
+# Possible values are: NO, YES, TEXT and GRAPH.
+# The default value is: YES.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies. See also the chapter Grouping
+# in the manual.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK               = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag UML_LOOK is set to YES.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and
+# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS
+# tag is set to YES, doxygen will add type and arguments for attributes and
+# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen
+# will not generate fields with class member information in the UML graphs. The
+# class diagrams will look similar to the default class diagrams but using UML
+# notation for the relationships.
+# Possible values are: NO, YES and NONE.
+# The default value is: NO.
+# This tag requires that the tag UML_LOOK is set to YES.
+
+DOT_UML_DETAILS        = NO
+
+# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters
+# to display on a single line. If the actual line length exceeds this threshold
+# significantly it will wrapped across multiple lines. Some heuristics are apply
+# to avoid ugly line breaks.
+# Minimum value: 0, maximum value: 1000, default value: 17.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_WRAP_THRESHOLD     = 17
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH          = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command. Disabling a call graph can be
+# accomplished by means of the command \hidecallgraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command. Disabling a caller graph can be
+# accomplished by means of the command \hidecallergraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH        = YES
+
+# The DIR_GRAPH_MAX_DEPTH tag can be used to limit the maximum number of levels
+# of child directories generated in directory dependency graphs by dot.
+# Minimum value: 1, maximum value: 25, default value: 1.
+# This tag requires that the tag DIRECTORY_GRAPH is set to YES.
+
+DIR_GRAPH_MAX_DEPTH    = 1
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. For an explanation of the image formats see the section
+# output formats in the documentation of the dot tool (Graphviz (see:
+# http://www.graphviz.org/)).
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd,
+# gif, gif:cairo, gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd,
+# png:cairo, png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
+# png:gdiplus:gdiplus.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT       = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG        = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS           =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS           =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file or to the filename of jar file
+# to be used. If left blank, it is assumed PlantUML is not used or called during
+# a preprocessing step. Doxygen will generate a warning when it encounters a
+# \startuml command in this case and will not generate output for the diagram.
+
+PLANTUML_JAR_PATH      =
+
+# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a
+# configuration file for plantuml.
+
+PLANTUML_CFG_FILE      =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH  =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# Note: This tag requires that UML_LOOK isn't set, i.e. the doxygen internal
+# graphical representation for inheritance and collaboration diagrams is used.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate
+# files that are used to generate the various graphs.
+#
+# Note: This setting is not only used for dot files but also for msc temporary
+# files.
+# The default value is: YES.
+
+DOT_CLEANUP            = YES
diff --git a/HOW_TO_MAINTAIN.rst b/HOW_TO_MAINTAIN.rst
new file mode 100644 (file)
index 0000000..2dae802
--- /dev/null
@@ -0,0 +1,2 @@
+
+This documentation has been replaced by docs/maintaining.md. Please refer to the new file or read it online.
\ No newline at end of file
diff --git a/HOW_TO_RELEASE.rst b/HOW_TO_RELEASE.rst
new file mode 100644 (file)
index 0000000..c5b7986
--- /dev/null
@@ -0,0 +1 @@
+This documentation has been replaced by docs/maintaining.md. Please refer to the new file or read it online.
diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..e82fd21
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,368 @@
+Installation Instructions
+*************************
+
+   Copyright (C) 1994-1996, 1999-2002, 2004-2017, 2020-2021 Free
+Software Foundation, Inc.
+
+   Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.  This file is offered as-is,
+without warranty of any kind.
+
+Basic Installation
+==================
+
+   Briefly, the shell command './configure && make && make install'
+should configure, build, and install this package.  The following
+more-detailed instructions are generic; see the 'README' file for
+instructions specific to this package.  Some packages provide this
+'INSTALL' file but do not implement all of the features documented
+below.  The lack of an optional feature in a given package is not
+necessarily a bug.  More recommendations for GNU packages can be found
+in *note Makefile Conventions: (standards)Makefile Conventions.
+
+   The 'configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation.  It uses
+those values to create a 'Makefile' in each directory of the package.
+It may also create one or more '.h' files containing system-dependent
+definitions.  Finally, it creates a shell script 'config.status' that
+you can run in the future to recreate the current configuration, and a
+file 'config.log' containing compiler output (useful mainly for
+debugging 'configure').
+
+   It can also use an optional file (typically called 'config.cache' and
+enabled with '--cache-file=config.cache' or simply '-C') that saves the
+results of its tests to speed up reconfiguring.  Caching is disabled by
+default to prevent problems with accidental use of stale cache files.
+
+   If you need to do unusual things to compile the package, please try
+to figure out how 'configure' could check whether to do them, and mail
+diffs or instructions to the address given in the 'README' so they can
+be considered for the next release.  If you are using the cache, and at
+some point 'config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+   The file 'configure.ac' (or 'configure.in') is used to create
+'configure' by a program called 'autoconf'.  You need 'configure.ac' if
+you want to change it or regenerate 'configure' using a newer version of
+'autoconf'.
+
+   The simplest way to compile this package is:
+
+  1. 'cd' to the directory containing the package's source code and type
+     './configure' to configure the package for your system.
+
+     Running 'configure' might take a while.  While running, it prints
+     some messages telling which features it is checking for.
+
+  2. Type 'make' to compile the package.
+
+  3. Optionally, type 'make check' to run any self-tests that come with
+     the package, generally using the just-built uninstalled binaries.
+
+  4. Type 'make install' to install the programs and any data files and
+     documentation.  When installing into a prefix owned by root, it is
+     recommended that the package be configured and built as a regular
+     user, and only the 'make install' phase executed with root
+     privileges.
+
+  5. Optionally, type 'make installcheck' to repeat any self-tests, but
+     this time using the binaries in their final installed location.
+     This target does not install anything.  Running this target as a
+     regular user, particularly if the prior 'make install' required
+     root privileges, verifies that the installation completed
+     correctly.
+
+  6. You can remove the program binaries and object files from the
+     source code directory by typing 'make clean'.  To also remove the
+     files that 'configure' created (so you can compile the package for
+     a different kind of computer), type 'make distclean'.  There is
+     also a 'make maintainer-clean' target, but that is intended mainly
+     for the package's developers.  If you use it, you may have to get
+     all sorts of other programs in order to regenerate files that came
+     with the distribution.
+
+  7. Often, you can also type 'make uninstall' to remove the installed
+     files again.  In practice, not all packages have tested that
+     uninstallation works correctly, even though it is required by the
+     GNU Coding Standards.
+
+  8. Some packages, particularly those that use Automake, provide 'make
+     distcheck', which can by used by developers to test that all other
+     targets like 'make install' and 'make uninstall' work correctly.
+     This target is generally not run by end users.
+
+Compilers and Options
+=====================
+
+   Some systems require unusual options for compilation or linking that
+the 'configure' script does not know about.  Run './configure --help'
+for details on some of the pertinent environment variables.
+
+   You can give 'configure' initial values for configuration parameters
+by setting variables in the command line or in the environment.  Here is
+an example:
+
+     ./configure CC=c99 CFLAGS=-g LIBS=-lposix
+
+   *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+   You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory.  To do this, you can use GNU 'make'.  'cd' to the
+directory where you want the object files and executables to go and run
+the 'configure' script.  'configure' automatically checks for the source
+code in the directory that 'configure' is in and in '..'.  This is known
+as a "VPATH" build.
+
+   With a non-GNU 'make', it is safer to compile the package for one
+architecture at a time in the source code directory.  After you have
+installed the package for one architecture, use 'make distclean' before
+reconfiguring for another architecture.
+
+   On MacOS X 10.5 and later systems, you can create libraries and
+executables that work on multiple system types--known as "fat" or
+"universal" binaries--by specifying multiple '-arch' options to the
+compiler but only a single '-arch' option to the preprocessor.  Like
+this:
+
+     ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+                 CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+                 CPP="gcc -E" CXXCPP="g++ -E"
+
+   This is not guaranteed to produce working output in all cases, you
+may have to build one architecture at a time and combine the results
+using the 'lipo' tool if you have problems.
+
+Installation Names
+==================
+
+   By default, 'make install' installs the package's commands under
+'/usr/local/bin', include files under '/usr/local/include', etc.  You
+can specify an installation prefix other than '/usr/local' by giving
+'configure' the option '--prefix=PREFIX', where PREFIX must be an
+absolute file name.
+
+   You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files.  If you
+pass the option '--exec-prefix=PREFIX' to 'configure', the package uses
+PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files still use the regular prefix.
+
+   In addition, if you use an unusual directory layout you can give
+options like '--bindir=DIR' to specify different values for particular
+kinds of files.  Run 'configure --help' for a list of the directories
+you can set and what kinds of files go in them.  In general, the default
+for these options is expressed in terms of '${prefix}', so that
+specifying just '--prefix' will affect all of the other directory
+specifications that were not explicitly provided.
+
+   The most portable way to affect installation locations is to pass the
+correct locations to 'configure'; however, many packages provide one or
+both of the following shortcuts of passing variable assignments to the
+'make install' command line to change installation locations without
+having to reconfigure or recompile.
+
+   The first method involves providing an override variable for each
+affected directory.  For example, 'make install
+prefix=/alternate/directory' will choose an alternate location for all
+directory configuration variables that were expressed in terms of
+'${prefix}'.  Any directories that were specified during 'configure',
+but not in terms of '${prefix}', must each be overridden at install time
+for the entire installation to be relocated.  The approach of makefile
+variable overrides for each directory variable is required by the GNU
+Coding Standards, and ideally causes no recompilation.  However, some
+platforms have known limitations with the semantics of shared libraries
+that end up requiring recompilation when using this method, particularly
+noticeable in packages that use GNU Libtool.
+
+   The second method involves providing the 'DESTDIR' variable.  For
+example, 'make install DESTDIR=/alternate/directory' will prepend
+'/alternate/directory' before all installation names.  The approach of
+'DESTDIR' overrides is not required by the GNU Coding Standards, and
+does not work on platforms that have drive letters.  On the other hand,
+it does better at avoiding recompilation issues, and works well even
+when some directory options were not specified in terms of '${prefix}'
+at 'configure' time.
+
+Optional Features
+=================
+
+   If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving 'configure' the
+option '--program-prefix=PREFIX' or '--program-suffix=SUFFIX'.
+
+   Some packages pay attention to '--enable-FEATURE' options to
+'configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to '--with-PACKAGE' options, where PACKAGE
+is something like 'gnu-as' or 'x' (for the X Window System).  The
+'README' should mention any '--enable-' and '--with-' options that the
+package recognizes.
+
+   For packages that use the X Window System, 'configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the 'configure' options '--x-includes=DIR' and
+'--x-libraries=DIR' to specify their locations.
+
+   Some packages offer the ability to configure how verbose the
+execution of 'make' will be.  For these packages, running './configure
+--enable-silent-rules' sets the default to minimal output, which can be
+overridden with 'make V=1'; while running './configure
+--disable-silent-rules' sets the default to verbose, which can be
+overridden with 'make V=0'.
+
+Particular systems
+==================
+
+   On HP-UX, the default C compiler is not ANSI C compatible.  If GNU CC
+is not installed, it is recommended to use the following options in
+order to use an ANSI C compiler:
+
+     ./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
+
+and if that doesn't work, install pre-built binaries of GCC for HP-UX.
+
+   HP-UX 'make' updates targets which have the same timestamps as their
+prerequisites, which makes it generally unusable when shipped generated
+files such as 'configure' are involved.  Use GNU 'make' instead.
+
+   On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
+parse its '<wchar.h>' header file.  The option '-nodtk' can be used as a
+workaround.  If GNU CC is not installed, it is therefore recommended to
+try
+
+     ./configure CC="cc"
+
+and if that doesn't work, try
+
+     ./configure CC="cc -nodtk"
+
+   On Solaris, don't put '/usr/ucb' early in your 'PATH'.  This
+directory contains several dysfunctional programs; working variants of
+these programs are available in '/usr/bin'.  So, if you need '/usr/ucb'
+in your 'PATH', put it _after_ '/usr/bin'.
+
+   On Haiku, software installed for all users goes in '/boot/common',
+not '/usr/local'.  It is recommended to use the following options:
+
+     ./configure --prefix=/boot/common
+
+Specifying the System Type
+==========================
+
+   There may be some features 'configure' cannot figure out
+automatically, but needs to determine by the type of machine the package
+will run on.  Usually, assuming the package is built to be run on the
+_same_ architectures, 'configure' can figure that out, but if it prints
+a message saying it cannot guess the machine type, give it the
+'--build=TYPE' option.  TYPE can either be a short name for the system
+type, such as 'sun4', or a canonical name which has the form:
+
+     CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+     OS
+     KERNEL-OS
+
+   See the file 'config.sub' for the possible values of each field.  If
+'config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+   If you are _building_ compiler tools for cross-compiling, you should
+use the option '--target=TYPE' to select the type of system they will
+produce code for.
+
+   If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with '--host=TYPE'.
+
+Sharing Defaults
+================
+
+   If you want to set default values for 'configure' scripts to share,
+you can create a site shell script called 'config.site' that gives
+default values for variables like 'CC', 'cache_file', and 'prefix'.
+'configure' looks for 'PREFIX/share/config.site' if it exists, then
+'PREFIX/etc/config.site' if it exists.  Or, you can set the
+'CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all 'configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+   Variables not defined in a site shell script can be set in the
+environment passed to 'configure'.  However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost.  In order to avoid this problem, you should set
+them in the 'configure' command line, using 'VAR=value'.  For example:
+
+     ./configure CC=/usr/local2/bin/gcc
+
+causes the specified 'gcc' to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+Unfortunately, this technique does not work for 'CONFIG_SHELL' due to an
+Autoconf limitation.  Until the limitation is lifted, you can use this
+workaround:
+
+     CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+'configure' Invocation
+======================
+
+   'configure' recognizes the following options to control how it
+operates.
+
+'--help'
+'-h'
+     Print a summary of all of the options to 'configure', and exit.
+
+'--help=short'
+'--help=recursive'
+     Print a summary of the options unique to this package's
+     'configure', and exit.  The 'short' variant lists options used only
+     in the top level, while the 'recursive' variant lists options also
+     present in any nested packages.
+
+'--version'
+'-V'
+     Print the version of Autoconf used to generate the 'configure'
+     script, and exit.
+
+'--cache-file=FILE'
+     Enable the cache: use and save the results of the tests in FILE,
+     traditionally 'config.cache'.  FILE defaults to '/dev/null' to
+     disable caching.
+
+'--config-cache'
+'-C'
+     Alias for '--cache-file=config.cache'.
+
+'--quiet'
+'--silent'
+'-q'
+     Do not print messages saying which checks are being made.  To
+     suppress all normal output, redirect it to '/dev/null' (any error
+     messages will still be shown).
+
+'--srcdir=DIR'
+     Look for the package's source code in directory DIR.  Usually
+     'configure' can determine that directory automatically.
+
+'--prefix=DIR'
+     Use DIR as the installation prefix.  *note Installation Names:: for
+     more details, including other options available for fine-tuning the
+     installation locations.
+
+'--no-create'
+'-n'
+     Run the configure checks, but stop before creating any output
+     files.
+
+'configure' also accepts some other, not widely useful, options.  Run
+'configure --help' for more details.
diff --git a/Inventory b/Inventory
new file mode 100755 (executable)
index 0000000..aa91e49
--- /dev/null
+++ b/Inventory
@@ -0,0 +1,204 @@
+#!/bin/sh
+#
+# Inventory -- take an inventory of the lsof distribution's 00MANIFEST
+
+# Establish trap and stty handling.
+
+ISIG=":"
+trap '$ISIG; exit 1'  1 2 3 15
+stty -a 2>&1 | grep isig > /dev/null
+if test $? -eq 0
+then
+  stty -a 2>&1 | grep -E -e -isig > /dev/null
+  if test $? -eq 0
+  then
+    ISIG="stty -isig"
+    stty isig
+  fi
+fi
+
+# Establish echo type -- Berkeley or SYSV.
+
+j=$(echo -n "")
+if test "X$j" = "X-n "
+then
+  EC="\c"
+  EO=""
+else
+  EC=""
+  EO="-n"
+fi
+
+# Display the introduction and basic explanation.
+
+cat << .CAT_MARK
+
+This configuration step (the Inventory script) takes inventory of
+the lsof distribution.  The script runs for a minute or two while
+it checks that all the subdirectories, information files, scripts,
+header files and source files that should be present really are.
+
+It's not absolutely necessary that you take inventory, but it's a
+good idea to do it right after the lsof distribution has been
+unpacked.  Once the inventory has been taken, this script creates
+the file ./.ck00MAN as a signal that the inventory step has been
+done.
+
+You can call the Inventory script directly at any time to take
+inventory.  You can inhibit the inventory step permanently by
+creating the file ./.neverInv, and you can tell the Configure script
+to skip the inventory and customization steps with the -n option.
+.CAT_MARK
+
+END=0
+while test $END = 0
+do
+  echo ""
+  echo $EO "Do you want to take inventory (y|n) [y]? $EC"
+  read ANS EXCESS
+  if test "X$ANS" = "Xn" -o "X$ANS" = "XN"
+  then
+    exit 0
+  fi
+  if test "X$ANS" = "Xy" -o "X$ANS" = "XY" -o "X$ANS" = "X"
+  then
+    END=1
+  else
+    echo ""
+    echo "Please answer y or n."
+  fi
+done
+
+# The current directory is assumed to be the lsof distribution home.
+
+D=$(pwd)
+
+# If .ck00MAN exists, the manifest has already been checked.
+# See if the caller wants to check it again.
+
+CK=$D/.ck00MAN
+if test -r $CK
+then
+  cat << .CAT_MARK
+
+======================================================================
+
+The lsof distribution inventory in 00MANIFEST has already been checked.
+.CAT_MARK
+
+  END=0
+  while test $END = 0
+  do
+    echo ""
+    echo $EO "Do you want to check the inventory again (y|n) [n]? $EC"
+    read ANS EXCESS
+    if test "X$ANS" = "Xn" -o "X$ANS" = "XN" -o "X$ANS" = "X"
+    then
+      exit 0
+    else
+      if test "X$ANS" = "Xy" -o "X$ANS" = "XY"
+      then
+       END=1
+      else
+       echo ""
+       echo "Please answer y or n."
+      fi
+    fi
+  done
+fi
+echo ""
+
+# See if manifest exists.  Exit if it does not.
+
+if test ! -r 00MANIFEST
+then
+  echo "FATAL: 00MANIFEST file not found or not readable; Inventory exits."
+  echo ""
+  exit 1
+fi
+
+# Start the inventory.
+
+S=""
+echo "Conducting an inventory of the lsof distribution; this will take a while."
+echo ""
+echo $EO "Examining ${D}:$EC"
+ERR=0
+OK=1
+for i in $(cat 00MANIFEST | sed 's/\*$//')
+do
+  if test "X$i" != "X"
+  then
+    j=$(expr $i : '\(.*\)/$')
+    if test "X$j" != "X" -a "X$j" != "X0"
+    then
+
+    # Check a subdirectory reference.
+
+      if test ! -d ${D}/${S}/$j
+      then
+       if test $OK = 1
+       then
+         echo ""
+       fi
+       echo "    Subdirectory ${S}/$j is missing. ++++"
+       ERR=1
+       OK=0
+      fi
+    else
+      s=$(expr $i : '\(.*\):$')
+      if test "X$s" != "X" -a "X$s" != "X0"
+      then
+
+      # Process a subdirectory change.
+
+       if test $OK -eq 1
+       then
+         echo " OK"
+       fi
+       OK=1
+       S=$s
+       echo $EO "Examining $S:$EC"
+       if test ! -d ${D}/$S
+       then
+         echo " ERROR"
+         echo "    Subdirectory $S is missing. ++++"
+         ERR=1
+         OK=0
+       fi
+      else
+
+       # Process a file reference.
+
+       if test ! -r ${D}/${S}/$i
+       then
+         if test $OK -eq 1
+         then
+           echo " ERROR"
+         fi
+         echo "    File ${S}/$i is missing. ++++"
+         ERR=1
+         OK=0
+       fi
+      fi
+    fi
+  fi
+done
+if test $OK -eq 1
+then
+  echo " OK"
+fi
+echo ""
+if test $ERR -ne 0
+then
+  echo "+++++++++++++++++++++++++++++++++++++++++++++++"
+  echo "+                                             +"
+  echo "+  SOME FILES OR DIRECTORIES MAY BE MISSING!  +"
+  echo "+                                             +"
+  echo "+++++++++++++++++++++++++++++++++++++++++++++++"
+else
+  echo "This lsof distribution seems to be complete."
+fi
+echo ""
+echo "" >> $CK
+exit $ERR
diff --git a/Lsof.8 b/Lsof.8
new file mode 100644 (file)
index 0000000..160830b
--- /dev/null
+++ b/Lsof.8
@@ -0,0 +1,4661 @@
+.so ./version
+.TH LSOF 8 Revision-\*(VN
+.\" Register )P is used neither by this file nor any groff macro.  However,
+.\" some versions of nroff require it.
+.if !\n(.g \{\
+.   if !\n()P .nr )P 1v
+.\}
+.SH NAME
+lsof \- list open files
+.SH SYNOPSIS
+.B lsof
+[
+.B \-?abChHlnNOPQRtUvVX
+] [
+.BI \-A " A"
+] [
+.BI \-c " c"
+] [
+.BI +c " c"
+] [
+.BI +|\-d " d"
+] [
+.BI +|\-D " D"
+] [
+.BI +|\-e " s"
+] [
+.B +|\-E
+] [
+.B +|\-f [cfgGn]
+] [
+.BI \-F " [f]"
+] [
+.BI \-g " [s]"
+] [
+.BI \-i " [i]"
+] [
+.BI \-k " k"
+] [
+.BI \-K " k"
+] [
+.BI +|\-L " [l]"
+] [
+.BI +|\-m " m"
+] [
+.B +|\-M
+] [
+.BI \-o " [o]"
+] [
+.BI \-p " s"
+] [
+.BI +|\-r " [t[m<fmt>]]"
+] [
+.BI \-s " [p:s]"
+] [
+.BI \-S " [t]"
+] [
+.BI \-T " [t]"
+] [
+.BI \-u " s"
+] [
+.B +|\-w
+] [
+.BI \-x " [fl]"
+] [
+.BI \-z " [z]"
+] [
+.BI \-Z " [Z]"
+] [
+.B \-\-
+] [\fInames\fP]
+.SH DESCRIPTION
+.I Lsof
+revision \*(VN lists on its standard output file information about files
+opened by processes for the following UNIX dialects:
+.PP
+.nf
+.so ./00DIALECTS
+.fi
+.PP
+(See the
+.B DISTRIBUTION
+section of this manual page for information on how to obtain the
+latest
+.I lsof
+revision.)
+.PP
+An open file may be a regular file, a directory, a block special file,
+a character special file, an executing text reference, a library,
+a stream or a network file (Internet socket, NFS file or UNIX domain socket.)
+A specific file or all the files in a file system may be selected by path.
+.PP
+Instead of a formatted display,
+.I lsof
+will produce output that can be parsed by other programs.
+See the
+.BR \-F ,
+option description, and the
+.B "OUTPUT FOR OTHER PROGRAMS"
+section for more information.
+.PP
+In addition to producing a single output list,
+.I lsof
+will run in repeat mode.
+In repeat mode it will produce output, delay, then repeat the output
+operation until stopped with an interrupt or quit signal.
+See the
+.BI +|\-r " [t[m<fmt>]]"
+option description for more information.
+.SH OPTIONS
+In the absence of any options,
+.I lsof
+lists all open files belonging to all active processes.
+.PP
+If any list request option is specified, other list requests must be
+specifically requested \- e.g., if
+.B \-U
+is specified for the listing of UNIX socket files, NFS files won't be
+listed unless
+.B \-N
+is also specified;
+or if a user list is specified with the
+.B \-u
+option, UNIX domain socket files, belonging to users not in the list,
+won't be listed unless the
+.B \-U
+option is also specified.
+.PP
+Normally, list options that are specifically stated are ORed \- i.e.,
+specifying the
+.B \-i
+option without an address and the \fB\-u\fPfoo option produces a
+listing of all network files OR files belonging to processes owned
+by user ``foo''.
+The exceptions are:
+.TP \w'1)\ 'u
+1)
+the `^' (negated) login name or user ID (UID), specified with the
+.B \-u
+option;
+.TP \w'1)\ 'u
+2)
+the `^' (negated) process ID (PID), specified with the
+.B \-p
+option;
+.TP \w'1)\ 'u
+3)
+the `^' (negated) process group ID (PGID), specified with the
+.B \-g
+option;
+.TP \w'1)\ 'u
+4)
+the `^' (negated) command, specified with the
+.B \-c
+option;
+.TP \w'1)\ 'u
+5)
+the (`^') negated TCP or UDP protocol state names, specified with the
+.BI \-s " [p:s]"
+option.
+.PP
+Since they represent exclusions, they are applied without ORing or ANDing
+and take effect before any other selection criteria are applied.
+.PP
+The
+.B \-a
+option may be used to AND the selections.
+For example, specifying
+.BR \-a ,
+.BR \-U ,
+and \fB\-u\fPfoo produces a listing of only UNIX socket files that
+belong to processes owned by user ``foo''.
+.PP
+Caution: the
+.B \-a
+option causes all list selection options to be ANDed; it can't
+be used to cause ANDing of selected pairs of selection options
+by placing it between them, even though its placement there is
+acceptable.
+Wherever
+.B \-a
+is placed, it causes the ANDing of all selection options.
+.PP
+Items of the same selection set \- command names, file descriptors,
+network addresses, process identifiers, user identifiers, zone names,
+security contexts \- are joined in a single ORed set and applied
+before the result participates in ANDing.
+Thus, for example, specifying \fB\-i\fP@aaa.bbb, \fB\-i\fP@ccc.ddd,
+.BR \-a ,
+and \fB\-u\fPfff,ggg will select the listing of files that belong to
+either login ``fff'' OR ``ggg'' AND have network connections to either
+host aaa.bbb OR ccc.ddd.
+.PP
+Options may be grouped together following a single prefix -- e.g.,
+the option set ``\fB\-a \-b \-C\fP'' may be stated as
+.BR \-abC .
+However, since values are optional following
+.BR +|\-f ,
+.BR \-F ,
+.BR \-g ,
+.BR \-i ,
+.BR +|\-L ,
+.BR \-o ,
+.BR +|\-r ,
+.BR \-s ,
+.BR \-S ,
+.BR \-T ,
+.B \-x
+and
+.BR \-z .
+when you have no values for them be careful that the
+following character isn't ambiguous.
+For example,
+.B \-Fn
+might represent the
+.B \-F
+and
+.B \-n
+options, or it might represent the
+.B n
+field identifier character following the
+.B \-F
+option.
+When ambiguity is possible, start a new option with a `\-'
+character \- e.g., ``\fB\-F \-n\fP''.
+If the next option is a file name, follow the possibly ambiguous
+option with ``\-\-'' \- e.g., ``\fB\-F \-\- \fIname\fR''.
+.PP
+Either the `+' or the `\-' prefix may be applied to a group of options.
+Options that don't take on separate meanings for each
+prefix \- e.g., \fB\-i\fP \- may be grouped under either prefix.
+Thus, for example, ``+M \-i'' may be stated as ``+Mi'' and the group
+means the same as the separate options.
+Be careful of prefix grouping when one or more options in the group
+does take on separate meanings under different prefixes \-
+e.g., \fB+|\-M\fP; ``\-iM'' is not the same request as ``\-i +M''.
+When in doubt, use separate options with appropriate prefixes.
+.TP \w'names'u+4
+.B \-? \-h
+These two equivalent options select a usage (help) output list.
+.I Lsof
+displays a shortened form of this output when it detects an error
+in the options supplied to it, after it has displayed messages
+explaining each error.
+(Escape the `?' character as your shell requires.)
+.TP \w'names'u+4
+.B \-a
+causes list selection options to be ANDed, as described above.
+.TP \w'names'u+4
+.BI \-A " A"
+is available on systems configured for AFS whose AFS
+kernel code is implemented via dynamic modules.
+It allows the
+.I lsof
+user to specify
+.I A
+as an alternate name list file where the kernel addresses of the dynamic
+modules might be found.
+See the
+.I lsof
+FAQ (The \fBFAQ\fP section gives its location.)
+for more information about dynamic modules, their
+symbols, and how they affect
+.IR lsof .
+.TP \w'names'u+4
+.B \-b
+causes
+.I lsof
+to avoid kernel functions that might block \-
+.IR lstat (2),
+.IR readlink (2),
+and
+.IR stat (2).
+.IP
+See the
+.B "BLOCKS AND TIMEOUTS"
+and
+.B "AVOIDING KERNEL BLOCKS"
+sections for information on using this option.
+.TP \w'names'u+4
+.BI \-c " c"
+selects the listing of files for processes executing the
+command that begins with the characters of
+.IR c .
+Multiple commands may be specified, using multiple
+.B \-c
+options.
+They are joined in a single ORed set before participating in
+AND option selection.
+.IP
+If
+.I c
+begins with a `^', then the following characters specify a command
+name whose processes are to be ignored (excluded.)
+.IP
+If
+.I c
+begins and ends with a slash ('/'), the characters between the slashes
+are interpreted as a regular expression.
+Shell meta\-characters in the regular expression must be quoted to prevent
+their interpretation by the shell.
+The closing slash may be followed by these modifiers:
+.IP
+.nf
+       b       the regular expression is a basic one.
+.br
+       i       ignore the case of letters.
+.br
+       x       the regular expression is an extended one
+.br
+               (default).
+.fi
+.IP
+See the
+.I lsof
+FAQ (The \fBFAQ\fP section gives its location.)
+for more information on basic and extended regular
+expressions.
+.IP
+The simple command specification is tested first.
+If that test fails, the command regular expression is applied.
+If the simple command test succeeds, the command regular expression
+test isn't made.
+This may result in ``no command found for regex:'' messages
+when lsof's
+.B \-V
+option is specified.
+.TP \w'names'u+4
+.BI +c " w"
+defines the maximum number of initial characters of the name,
+supplied by the UNIX dialect, of the UNIX command associated with a process
+to be printed in the COMMAND column.
+(The
+.I lsof
+default is nine.)
+.IP
+Note that many UNIX dialects do not supply all command name characters
+to
+.I lsof
+in the files and structures from which
+.I lsof
+obtains command name.
+Often dialects limit the number of characters supplied in those sources.
+For example, Linux 2.4.27 and Solaris 9 both limit command name length to
+16 characters.
+.IP
+If
+.I w
+is zero ('0'), all command characters supplied to
+.I lsof
+by the UNIX dialect will be printed.
+.IP
+If
+.I w
+is less than the length of the column title, ``COMMAND'', it will
+be raised to that length.
+.TP \w'names'u+4
+.B \-C
+disables the reporting of any path name
+components from the kernel's name cache.
+See the
+.B "KERNEL NAME CACHE"
+section for more information.
+.TP \w'names'u+4
+.BI +d " s"
+causes
+.I lsof
+to search for all open instances of directory
+.I s
+and the files and directories it contains at its top level.
+.B +d
+does NOT descend the directory tree, rooted at
+.IR s .
+The
+.BI +D " D"
+option may be used to request a full\-descent directory tree search,
+rooted at directory
+.IR D .
+.IP
+Processing of the
+.B +d
+option does not follow symbolic links within
+.I s
+unless the
+.B \-x
+or
+.B \-x " l"
+option is also specified.
+Nor does it
+search for open files on file system mount points on subdirectories of
+.I s
+unless the
+.B \-x
+or
+.B \-x " f"
+option is also specified.
+.IP
+Note: the authority of the user of this option limits it to searching for
+files that the user has permission to examine with the system
+.IR stat (2)
+function.
+.TP \w'names'u+4
+.BI \-d " s"
+specifies a list of file descriptors (FDs) to exclude from
+or include in the output listing.
+The file descriptors are specified in the comma\-separated set
+.I s
+\&\- e.g., ``cwd,1,3'', ``^6,^2''.
+(There should be no spaces in the set.)
+.IP
+The list is an exclusion list if all entries of the set begin with `^'.
+It is an inclusion list if no entry begins with `^'.
+Mixed lists are not permitted.
+.IP
+A file descriptor number range may be in the set as long as
+neither member is empty, both members are numbers, and the ending
+member is larger than the starting one \- e.g., ``0\-7'' or ``3\-10''.
+Ranges may be specified for exclusion if they have the `^' prefix \-
+e.g., ``^0\-7'' excludes all file descriptors 0 through 7.
+.IP
+Multiple file descriptor numbers are joined in a single ORed set before
+participating in AND option selection.
+.IP
+When there are exclusion and inclusion members in the set,
+.I lsof
+reports them as errors and exits with a non\-zero return code.
+.IP
+See the description of File Descriptor (FD) output values in the
+.B OUTPUT
+section for more information on file descriptor names.
+.IP
+\fBfd\fP is a pseudo file descriptor name for specifying
+the whole range of possible file descriptor numbers.
+\fBfd\fP does not appear in FD column of output.
+.TP \w'names'u+4
+.BI +D " D"
+causes
+.I lsof
+to search for all open instances of directory
+.I D
+and all the files and directories it contains to its complete depth.
+.IP
+Processing of the
+.B +D
+option does not follow symbolic links within
+.I D
+unless the
+.B \-x
+or
+.B \-x " l"
+option is also specified.
+Nor does it
+search for open files on file system mount points on subdirectories of
+.I D
+unless the
+.B \-x
+or
+.B \-x " f"
+option is also specified.
+.IP
+Note: the authority of the user of this option limits it to searching for
+files that the user has permission to examine with the system
+.IR stat (2)
+function.
+.IP
+Further note:
+.I lsof
+may process this option slowly and require a large amount of dynamic memory
+to do it.
+This is because it must descend the entire directory tree, rooted at
+.IR D ,
+calling
+.IR stat (2)
+for each file and directory, building a list of all the files it finds, and
+searching that list for a match with every open file.
+When directory
+.I D
+is large, these steps can take a long time, so use this option prudently.
+.TP \w'names'u+4
+.BI \-D " D"
+directs
+.I lsof's
+use of the device cache file.
+The use of this option is sometimes restricted.
+See the
+.B "DEVICE CACHE FILE"
+section and the sections that follow it for more information on this
+option.
+.IP
+.B \-D
+must be followed by a function letter; the function letter may optionally
+be followed by a path name.
+.I Lsof
+recognizes these function letters:
+.IP
+.nf
+       \fB?\fP \- report device cache file paths
+       \fBb\fP \- build the device cache file
+       \fBi\fP \- ignore the device cache file
+       \fBr\fP \- read the device cache file
+       \fBu\fP \- read and update the device cache file
+.fi
+.IP
+The
+.BR b ,
+.BR r ,
+and
+.B u
+functions, accompanied by a path name, are sometimes restricted.
+When these functions are restricted, they will not appear in
+the description of the
+.B \-D
+option that accompanies
+.B \-h
+or
+.B \-?
+option output.
+See the
+.B "DEVICE CACHE FILE"
+section and the sections that follow it for more information on these
+functions and when they're restricted.
+.IP
+The
+.B ?
+function reports the read\-only and write paths that lsof can
+use for the device cache file,
+the names of any environment variables whose values
+.I lsof
+will examine when forming the device cache file path,
+and the format for the personal device cache file path.
+(Escape the `?' character as your shell requires.)
+.IP
+When available, the
+.BR b ,
+.BR r ,
+and
+.B u
+functions may be followed by the device cache file's path.
+The standard default is
+.I .lsof_hostname
+in the home directory of the real user ID that executes
+.IR lsof ,
+but this could have been changed when
+.I lsof
+was configured and compiled.
+(The output of the
+.B \-h
+and
+.B \-?
+options show the current default prefix \- e.g., ``.lsof''.)
+The suffix,
+.IR hostname ,
+is the first component of the host's name returned by
+.IR gethostname (2).
+.IP
+When available, the
+.B b
+function directs
+.I lsof
+to build a new device cache file at the default or specified path.
+.IP
+The
+.B i
+function directs
+.I lsof
+to ignore the default device cache file and obtain its information
+about devices via direct calls to the kernel.
+.IP
+The
+.B r
+function directs
+.I lsof
+to read the device cache at the default or specified path, but
+prevents it from creating a new device cache file when none
+exists or the existing one is improperly structured.
+The
+.B r
+function, when specified without a path name, prevents
+.I lsof
+from updating an incorrect or outdated device cache file,
+or creating a new one in its place.
+The
+.B r
+function is always available when it is specified without a
+path name argument; it may be restricted by the permissions of the
+.I lsof
+process.
+.IP
+When available, the
+.B u
+function directs
+.I lsof
+to read the device cache file at the default or specified path,
+if possible, and to rebuild it, if necessary.
+This is the default device cache file function when no
+.B \-D
+option has been specified.
+.TP \w'names'u+4
+.BI +|\-e " s"
+exempts the file system whose path name is
+.I s
+from being subjected to kernel function calls that might block.
+The
+.B +e
+option exempts
+.IR stat (2),
+.IR lstat (2)
+and most
+.IR readlink (2)
+kernel function calls.
+The
+.B \-e
+option exempts only
+.IR stat(2)
+and
+.IR lstat (2)
+kernel function calls.
+Multiple file systems may be specified with separate
+.B +|\-e
+specifications and each may have
+.IR readlink (2)
+calls exempted or not.
+.IP
+This option is currently implemented only for Linux.
+.IP
+.B CAUTION:
+this option can easily be mis\-applied to other than
+the file system of interest, because it uses path name rather
+than the more reliable device and inode numbers.
+(Device and inode numbers are acquired via the potentially blocking
+.IR stat (2)
+kernel call and are thus not available, but see the
+.BI +|\-m " m"
+option as a possible alternative way to supply device numbers.)
+\fBUse this option with great care and fully specify the path name of the
+file system to be exempted.\fP
+.IP
+When open files on exempted file systems are reported, it may not be
+possible to obtain all their information.
+Therefore, some information columns will be blank, the characters ``UNKN''
+preface the values in the TYPE column, and the applicable exemption option
+is added in parentheses to the end of the NAME column.
+(Some device number information might be made available via the
+.BI +|\-m " m"
+option.)
+.TP \w'names'u+4
+.B +|\-E
+.B +E
+specifies that Linux pipe, Linux UNIX socket, Linux INET(6) socket closed in a local host, Linux pseudoterminal files,
+POSIX Message Queueue implementation in Linux, and Linux eventfd
+should be displayed with endpoint information and the files of the endpoints should also be displayed.
+.IP
+Note 1: UNIX socket file endpoint information is only available when the
+features enabled line of
+.B \-v
+output contains uxsockept, and psudoterminal endpoint information is only
+available when the features enabled line contains ptyept.
+.IP
+Note 2: POSIX Message Queue file endpoint information is only available when mqueue
+file system is mounted.
+.IP
+Pipe endpoint information is displayed in the NAME column in the
+form ``\fIPID,cmd,FDmode\fP'', where
+.I PID
+is the endpoint process ID;
+.I cmd
+is the endpoint process command;
+.I FD
+is the endpoint file's descriptor; and
+.I mode
+is the endpoint file's access mode.
+.IP
+Pseudoterminal
+endpoint information is displayed in the NAME column as
+``\->/dev/pts\fImin\fP\ \fIPID,cmd,FDmode\fP'' or ``\fIPID,cmd,FDmode\fP''.
+The first form is for a master device; the second, for a slave device.
+.I min
+is a slave device's minor device number; and
+.I "PID, cmd, FD"
+and
+.I mode
+are the same as with pipe endpoint information.
+Note: psudoterminal endpoint information is only available when the features
+enabled line of
+.B \-v
+output contains ptyept. In addition, this feature works on Linux kernels above 4.13.0.
+.IP
+UNIX socket file endpoint information is displayed in the NAME column
+in the form
+.br
+``type=\fITYPE\fP\ \->INO=\fIINODE\fP\ \fIPID,cmd,FDmode\fP'', where
+.I TYPE
+is the socket type;
+.I INODE
+is the i-node number of the connected socket;
+and
+.I "PID, cmd, FD"
+and
+.I mode
+are the same as with pipe endpoint information.
+Note: UNIX socket file endpoint information is available only when the
+features enabled line of
+.B \-v
+output contains uxsockept.
+.IP
+INET socket file endpoint information is inserted to the value at the
+NAME column in the form
+.br
+`` \-> \fIPID,cmd,FDmode\fP'', where
+.I "PID, cmd, FD"
+and
+.I mode
+are the same as with pipe endpoint information. The endpoint
+information is available only if the socket is used for local
+IPC; both endpoints bind to the same local IPv4 or IPv6 address.
+.IP
+POSIX Message Queue file endpoint information is displayed in the NAME
+column in the same form as that of pipe.
+.IP
+eventfd endpoint information is displayed in the NAME column in
+the same form as that of pipe. This feature works on Linux kernels
+above 5.2.0.
+.IP
+Multiple occurrences of this information can appear in a file's
+NAME column.
+.IP
+.B \-E
+specifies that endpoint supported files should be displayed
+with endpoint information, but not the files of the endpoints.
+.TP \w'names'u+4
+.B +|\-f [cfgGn]
+.B f
+by itself clarifies how path name arguments are to be interpreted.
+When followed by
+.BR c ,
+.BR f ,
+.BR g ,
+.BR G ,
+or
+.B n
+in any combination it specifies
+that the listing of kernel file structure information is to be enabled
+(`+') or inhibited (`\-').
+.IP
+Normally a path name argument is taken to be a file system name if
+it matches a mounted\-on directory name reported by
+.IR mount (8),
+or if it represents a block device, named in the
+.I mount
+output and associated with a mounted directory name.
+When
+.B +f
+is specified, all path name arguments will be taken to be file
+system names, and
+.I lsof
+will complain if any are not.
+This can be useful, for example, when the file system name
+(mounted\-on device) isn't a block device.
+This happens for some CD-ROM file systems.
+.IP
+When
+.B \-f
+is specified by itself, all path name arguments will be taken to be
+simple files.
+Thus, for example, the ``\fB\-f\fP\ \-\- /'' arguments direct lsof to search
+for open files with a `/' path name, not all open files in the `/'
+(root) file system.
+.IP
+Be careful to make sure
+.B +f
+and
+.B \-f
+are properly terminated and aren't followed by a character (e.g., of
+the file or file system name) that might be taken as a parameter.
+For example, use ``\-\-'' after
+.B +f
+and
+.B \-f
+as in these examples.
+.IP
+.nf
+       $ lsof +f \-\- /file/system/name
+       $ lsof \-f \-\- /file/name
+.fi
+.IP
+The listing of information from kernel file structures, requested with the
+.B +f [cfgGn]
+option form, is normally
+inhibited, and is not available in whole or part for some dialects \- e.g.,
+/proc\-based Linux kernels below 2.6.22.
+When the prefix to
+.B f
+is a plus sign (`+'), these characters request file structure information:
+.IP
+.nf
+       \fBc\fR file structure use count (not Linux)
+       \fBf\fR file structure address (not Linux)
+       \fBg\fR file flag abbreviations (Linux 2.6.22 and up)
+
+               Abbrev. Flag in C code (see open(2))
+
+               \fBW\fR         O_WRONLY
+               \fBRW\fR                O_RDWR
+               \fBCR\fR                O_CREAT
+               \fBEXCL\fR              O_EXCL
+               \fBNTTY\fR              O_NOCTTY
+               \fBTR\fR                O_TRUNC
+               \fBAP\fR                O_APPEND
+               \fBND\fR                O_NDELAY
+               \fBSYN\fR               O_SYNC
+               \fBASYN\fR              O_ASYNC
+               \fBDIR\fR               O_DIRECT
+               \fBDTY\fR               O_DIRECTORY
+               \fBNFLK\fR              O_NOFOLLOW
+               \fBNATM\fR              O_NOATIME
+               \fBDSYN\fR              O_DSYNC
+               \fBRSYN\fR              O_RSYNC
+               \fBLG\fR                O_LARGEFILE
+               \fBCX\fR                O_CLOEXEC
+               \fBTMPF\fR              O_TMPFILE
+
+       \fBG\fR file flags in hexadecimal (Linux 2.6.22 and up)
+       \fBn\fR file structure node address (not Linux)
+.fi
+.IP
+When the prefix is minus (`\-') the same characters disable the
+listing of the indicated values.
+.IP
+File structure addresses, use counts, flags, and node addresses may be
+used to detect more readily identical files inherited by child
+processes and identical files in use by different processes.
+.I Lsof
+column output can be sorted by output columns holding the values
+and listed to identify identical file use, or
+.I lsof
+field output can be parsed by an AWK or Perl post\-filter script,
+or by a C program.
+.TP \w'names'u+4
+.BI \-F " f"
+specifies a character list,
+.IR f ,
+that selects the fields to be output for processing by another program,
+and the character that terminates each output field.
+Each field to be output is specified with a single character in
+.IR f .
+The field terminator defaults to NL, but may be changed to NUL (000).
+See the
+.B "OUTPUT FOR OTHER PROGRAMS"
+section for a description of the field identification characters and
+the field output process.
+.IP
+When the field selection character list is empty, all standard fields are
+selected (except the raw device field, security context and zone field for
+compatibility reasons)
+and the NL field terminator is used.
+.IP
+When the field selection character list contains only a zero (`0'),
+all fields are selected (except the raw device field for compatibility
+reasons) and the NUL terminator character is used.
+.IP
+Other combinations of fields and their associated field terminator
+character must be set with explicit entries in
+.IR f ,
+as described in the
+.B "OUTPUT FOR OTHER PROGRAMS"
+section.
+.IP
+When a field selection character identifies an item
+.I lsof
+does not normally list \- e.g., PPID, selected with
+.BR \-R " \-"
+specification of the field character \- e.g., ``\fB\-FR\fP'' \-
+also selects the listing of the item.
+.IP
+When the field selection character list contains the single
+character `?',
+.I lsof
+will display a help list of the field identification characters.
+(Escape the `?' character as your shell requires.)
+.TP \w'names'u+4
+.BI \-g " [s]"
+excludes or selects the listing of files for the processes
+whose optional process group IDentification (PGID) numbers are in the
+comma\-separated set
+.I s
+\&\- e.g., ``123'' or ``123,^456''.
+(There should be no spaces in the set.)
+.IP
+PGID numbers that begin with `^' (negation) represent exclusions.
+.IP
+Multiple PGID numbers are joined in a single ORed set before participating
+in AND option selection.
+However, PGID exclusions are applied without ORing or ANDing
+and take effect before other selection criteria are applied.
+.IP
+The
+.B \-g
+option also enables the output display of PGID numbers.
+When specified without a PGID set that's all it does.
+.TP \w'names'u+4
+.B \-H
+directs lsof to print human readable sizes, e.g. 123.4K 456.7M.
+.TP \w'names'u+4
+.BI \-i " [i]"
+selects the listing of files any of whose Internet address
+matches the address specified in \fIi\fP.
+If no address is specified, this option selects the listing of all
+Internet and x.25 (HP\-UX) network files.
+.IP
+If
+.BI \-i 4
+or
+.BI \-i 6
+is specified with no following address, only files of the indicated
+IP version, IPv4 or IPv6, are displayed.
+(An IPv6 specification may be used only if the dialects supports IPv6,
+as indicated by ``[46]'' and ``IPv[46]'' in
+.I lsof's
+.B \-h
+or
+.B \-?
+output.)
+Sequentially specifying
+.BR \-i 4,
+followed by
+.BR \-i 6
+is the same as specifying
+.BR \-i ,
+and vice-versa.
+Specifying
+.BR \-i 4,
+or
+.BR \-i 6
+after
+.B \-i
+is the same as specifying
+.BR \-i 4
+or
+.BR \-i 6
+by itself.
+.IP
+Multiple addresses (up to a limit of 100) may be specified with multiple
+.B \-i
+options.
+(A port number or service name range is counted as one address.)
+They are joined in a single ORed set before participating in
+AND option selection.
+.IP
+An Internet address is specified in the form (Items in square
+brackets are optional.):
+.IP
+.ie !\n(.g \{
+[\fI46\fP][\fIprotocol\fP][@\fIhostname\fP\||\|\fIhostaddr\fP][:\fIservice\fP\||\|\fIport\fP]
+\}
+.el \{
+.RI [ 46 ][ protocol ][@ hostname \||\| hostaddr ][: service \||\| port ]
+\}
+.IP
+where:
+.nf
+.br
+       \fI46\fP specifies the IP version, IPv4 or IPv6
+.br
+               that applies to the following address.
+.br
+               '6' may be be specified only if the UNIX
+.br
+               dialect supports IPv6.  If neither '4' nor
+.br
+               '6' is specified, the following address
+.br
+               applies to all IP versions.
+.br
+       \fIprotocol\fP is a protocol name \- \fBTCP\fP, \fBUDP\fP or \fBUDPLITE\fP.
+.br
+.br
+       \fIhostname\fP is an Internet host name.  Unless a
+.br
+               specific IP version is specified, open
+.br
+               network files associated with host names
+.br
+               of all versions will be selected.
+.br
+       \fIhostaddr\fP is a numeric Internet IPv4 address in
+.br
+               dot form; or an IPv6 numeric address in
+.br
+               colon form, enclosed in brackets, if the
+.br
+               UNIX dialect supports IPv6.  When an IP
+.br
+               version is selected, only its numeric
+.br
+               addresses may be specified.
+.br
+       \fIservice\fP is an \fI/etc/services\fP name \- e.g., \fBsmtp\fP \-
+               or a list of them.
+.br
+       \fIport\fP is a port number, or a list of them.
+.fi
+.IP
+IPv6 options may be used only if the UNIX dialect supports IPv6.
+To see if the dialect supports IPv6, run
+.I lsof
+and specify the
+.B \-h
+or
+.B \-?
+(help) option.
+If the displayed description of the
+.B \-i
+option contains ``[46]'' and ``IPv[46]'', IPv6 is supported.
+.IP
+IPv4 host names and addresses may not be specified if network file selection
+is limited to IPv6 with
+.BR \-i " 6."
+IPv6 host names and addresses may not be specified if network file selection
+is limited to IPv4 with
+.BR \-i " 4."
+When an open IPv4 network file's address is mapped in an IPv6 address,
+the open file's type will be IPv6, not IPv4, and its display will be
+selected by '6', not '4'.
+.IP
+At least one address component \-
+.BR 4,
+.BR 6,
+.IR protocol ,
+.IR hostname ,
+.IR hostaddr ,
+or
+.I service
+\&\- must be supplied.
+The `@' character, leading the host specification, is always required;
+as is the `:', leading the port specification.
+Specify either
+.I hostname
+or
+.IR hostaddr .
+Specify either
+.I service
+name list or
+.I port
+number list.
+If a
+.I service
+name list is specified, the
+.I protocol
+may also need to be specified if the TCP, UDP and UDPLITE port numbers for
+the service name are different.
+Use any case \- lower or upper \- for
+.IR protocol .
+.IP
+.I Service
+names and
+.I port
+numbers may be combined in a list whose entries are separated by commas
+and whose numeric range entries are separated by minus signs.
+There may be no embedded spaces, and all service names must belong to
+the specified
+.IR protocol .
+Since service names may contain embedded minus signs, the starting entry
+of a range can't be a service name; it can be a port number, however.
+.IP
+Here are some sample addresses:
+.nf
+
+.br
+       \-i6 \- IPv6 only
+.br
+       TCP:25 \- TCP and port 25
+.br
+       @1.2.3.4 \- Internet IPv4 host address 1.2.3.4
+.br
+       @[3ffe:1ebc::1]:1234 \- Internet IPv6 host address
+               3ffe:1ebc::1, port 1234
+.br
+       UDP:who \- UDP who service port
+.br
+       TCP@lsof.itap:513 \- TCP, port 513 and host name lsof.itap
+.br
+       tcp@foo:1\-10,smtp,99 \- TCP, ports 1 through 10,
+               service name \fIsmtp\fP, port 99, host name foo
+.br
+       tcp@bar:1\-smtp \- TCP, ports 1 through \fIsmtp\fP, host bar
+.br
+       :time \- either TCP, UDP or UDPLITE time service port
+.fi
+.TP \w'names'u+4
+.BI \-K " k"
+selects the listing of tasks (threads) of processes, on dialects
+where task (thread) reporting is supported.
+(If help output \- i.e., the output of the
+.B \-h
+or
+.B \-?
+options \- shows this option, then task (thread) reporting is
+supported by the dialect.)
+.IP
+If
+.B \-K
+is followed by a value,
+.IR k ,
+it must be ``i''.  That causes
+.I lsof
+to ignore tasks, particularly in the default, list\-everything case
+when no other options are specified.
+.IP
+When
+.B \-K
+and
+.B \-a
+are both specified on Linux, and the tasks of a main process are
+selected by other options, the main process will also be listed
+as though it were a task, but without a task ID.
+(See the description of the TID column in the
+.B OUTPUT
+section.)
+.IP
+Where the FreeBSD version supports threads, all threads will be
+listed with their IDs.
+.IP
+In general threads and tasks inherit the files of the caller, but
+may close some and open others, so
+.I lsof
+always reports all the open files of threads and tasks.
+.TP \w'names'u+4
+.BI \-k " k"
+specifies a kernel name list file,
+.IR k ,
+in place of /vmunix, /mach, etc.
+.B \-k
+is not available under AIX on the IBM RISC/System 6000.
+.TP \w'names'u+4
+.B \-l
+inhibits the conversion of user ID numbers to login names.
+It is also useful when login name lookup is working improperly or slowly.
+.TP \w'names'u+4
+.BI +|\-L " [l]"
+enables (`+') or disables (`\-') the listing of file link
+counts, where they are available \- e.g., they aren't available
+for sockets, or most FIFOs and pipes.
+.IP
+When
+.B +L
+is specified without a following number, all link counts will be listed.
+When
+.B \-L
+is specified (the default), no link counts will be listed.
+.IP
+When
+.B +L
+is followed by a number, only files having a link count less than
+that number will be listed.
+(No number may follow
+.BR \-L .)
+A specification of the form ``\fB+L1\fP'' will select open files that
+have been unlinked.
+A specification of the form ``\fB+aL1\ \fI<file_system>\fR'' will select
+unlinked open files on the specified file system.
+.IP
+For other link count comparisons, use field output (\fB\-F\fP)
+and a post\-processing script or program.
+.TP \w'names'u+4
+.BI +|\-m " m"
+specifies an alternate kernel memory file or activates
+mount table supplement processing.
+.IP
+The option form
+.BI \-m " m"
+specifies a kernel memory file,
+.IR m ,
+in place of
+.I /dev/kmem
+or
+.I /dev/mem
+\&\- e.g., a crash dump file.
+.IP
+The option form
+.B +m
+requests that a mount supplement file be written to the standard output
+file.
+All other options are silently ignored.
+.IP
+There will be a line in the mount supplement file for each mounted file
+system, containing the mounted file system directory, followed by a single
+space, followed by the device number in hexadecimal "0x" format \- e.g.,
+.IP
+.nf
+       / 0x801
+.fi
+.IP
+.I Lsof
+can use the mount supplement file to get device numbers for file systems
+when it can't get them via
+.IR stat (2)
+or
+.IR lstat (2).
+.IP
+The option form
+.BI +m " m"
+identifies
+.I m
+as a mount supplement file.
+.IP
+Note: the
+.B +m
+and
+.BI +m " m"
+options are not available for all supported dialects.
+Check the output of
+.I lsof's
+.B \-h
+or
+.B \-?
+options to see if the
+.B +m
+and
+.BI +m " m"
+options are available.
+.TP \w'names'u+4
+.B +|\-M
+Enables (\fB+\fP) or disables (\fB\-\fP) the
+reporting of portmapper registrations for local TCP, UDP and UDPLITE ports,
+where port mapping is supported.
+(See the last paragraph of this option description for information about
+where portmapper registration reporting is supported.)
+.IP
+The default reporting mode is set by the
+.I lsof
+builder with the HASPMAPENABLED #define in the dialect's machine.h
+header file;
+.I lsof
+is distributed with the HASPMAPENABLED #define deactivated, so
+portmapper reporting is disabled by default and must be requested
+with
+.BR +M .
+Specifying
+.I lsof's
+.B \-h
+or
+.B \-?
+option will report the default mode.
+Disabling portmapper registration when it is already disabled or
+enabling it when already enabled is acceptable.
+When portmapper registration reporting is enabled,
+.I lsof
+displays the portmapper registration (if any) for local TCP, UDP or
+UDPLITE ports
+in square brackets immediately following the port numbers or service
+names \- e.g., ``:1234[name]'' or ``:name[100083]''.
+The registration information may be a name or number, depending
+on what the registering program supplied to the portmapper when
+it registered the port.
+.IP
+When portmapper registration reporting is enabled,
+.I lsof
+may run a little more slowly or even become blocked when access to the
+portmapper becomes congested or stopped.
+Reverse the reporting mode to determine if portmapper registration
+reporting is slowing or blocking
+.IR lsof .
+.IP
+For purposes of portmapper registration reporting
+.I lsof
+considers a TCP, UDP or UDPLITE port local if: it is found in the local part
+of its containing kernel structure;
+or if it is located in the foreign part of its containing kernel
+structure and the local and foreign Internet addresses are the same;
+or if it is located in the foreign part of its containing kernel
+structure and the foreign Internet address is INADDR_LOOPBACK (127.0.0.1).
+This rule may make
+.I lsof
+ignore some foreign ports on machines with multiple interfaces
+when the foreign Internet address is on a different interface
+from the local one.
+.IP
+See the
+.I lsof
+FAQ (The \fBFAQ\fP section gives its location.)
+for further discussion of portmapper registration
+reporting issues.
+.IP
+Portmapper registration reporting is supported only on dialects that
+have RPC header files.
+(Some Linux distributions with GlibC 2.14 do not have them.)
+When portmapper registration reporting is supported, the
+.B \-h
+or
+.B \-?
+help output will show the
+.B +|\-M
+option.
+.TP \w'names'u+4
+.B \-n
+inhibits the conversion of network numbers to
+host names for network files.
+Inhibiting conversion may make
+.I lsof
+run faster.
+It is also useful when host name lookup is not working properly.
+.TP \w'names'u+4
+.B \-N
+selects the listing of NFS files.
+.TP \w'names'u+4
+.BI \-o
+directs
+.I lsof
+to display file offset at all times.
+It causes the SIZE/OFF output column title to be changed to OFFSET.
+Note: on some UNIX dialects
+.I lsof
+can't obtain accurate or consistent file offset information from its
+kernel data sources, sometimes just for particular kinds of files
+(e.g., socket files.)
+Consult the
+.I lsof
+FAQ (The \fBFAQ\fP section gives its location.)
+for more information.
+.IP
+The
+.B \-o
+and
+.B \-s
+options are mutually exclusive; they can't both be specified.
+When neither is specified,
+.I lsof
+displays whatever value \- size or offset \- is appropriate and
+available for the type of the file.
+.TP \w'names'u+4
+.BI \-o " o"
+defines the number of decimal digits (\fIo\fP) to be
+printed after the ``0t'' for a file offset before the form is switched
+to ``0x...''.
+An
+.I o
+value of zero (unlimited) directs
+.I lsof
+to use the ``0t'' form for all offset output.
+.IP
+This option does NOT direct
+.I lsof
+to display offset at all times; specify
+.B \-o
+(without a trailing number) to do that.
+.BI \-o " o"
+only specifies the number of digits after ``0t'' in
+either mixed size and offset or offset\-only output.
+Thus, for example, to direct
+.I lsof
+to display offset at all times with a decimal digit count of 10, use:
+.IP
+.nf
+       \-o \-o 10
+or
+       \-oo10
+.fi
+.IP
+The default number of digits allowed after ``0t'' is normally 8,
+but may have been changed by the lsof builder.
+Consult the description of the
+.BI \-o " o"
+option in the output of the
+.B \-h
+or
+.B \-?
+option to determine the default that is in effect.
+.TP \w'names'u+4
+.B \-O
+directs
+.I lsof
+to bypass the strategy it uses to avoid being blocked by some
+kernel operations \- i.e., doing them in forked child processes.
+See the
+.B "BLOCKS AND TIMEOUTS"
+and
+.B "AVOIDING KERNEL BLOCKS"
+sections for more information on kernel operations that may block
+.IR lsof .
+.IP
+While use of this option will reduce
+.I lsof
+startup overhead, it may also cause
+.I lsof
+to hang when the kernel doesn't respond to a function.
+Use this option cautiously.
+.TP \w'names'u+4
+.BI \-p " s"
+excludes or selects the listing of files for the processes
+whose optional process IDentification (PID) numbers are in the
+comma\-separated set
+.I s
+\&\- e.g., ``123'' or ``123,^456''.
+(There should be no spaces in the set.)
+.IP
+PID numbers that begin with `^' (negation) represent exclusions.
+.IP
+Multiple process ID numbers are joined in a single ORed set before
+participating in AND option selection.
+However, PID exclusions are applied without ORing or ANDing
+and take effect before other selection criteria are applied.
+.TP \w'names'u+4
+.B \-P
+inhibits the conversion of port numbers to port
+names for network files.
+Inhibiting the conversion may make
+.I lsof
+run a little faster.
+It is also useful when port name lookup is not working properly.
+.TP \w'names'u+4
+.B \-Q
+ignore failed search terms. When
+.I lsof
+is told to search for users of a file, or for users of a device,
+or for a specific PID, or for certain protocols in use by that PID,
+and so on,
+.I lsof
+will return an error if any of the search results are empty. The
+.B \-Q
+option will change this behavior so that
+.I lsof
+will instead return a successful exit code (0) even if any of the
+search results are empty. In addition, missing search terms will not
+be reported to stderr.
+.TP \w'names'u+4
+.BI +|\-r " [t[c<N>][m<fmt>]]"
+puts
+.I lsof
+in repeat mode.
+There
+.I lsof
+lists open files as selected by other options, delays
+.I t
+seconds (default fifteen), then repeats the listing, delaying
+and listing repetitively until stopped by a condition defined by
+the prefix to the option.
+.IP
+If the prefix is a `\-', repeat mode is endless.
+.I Lsof
+must be terminated with an interrupt or quit signal.
+`c<N>' is for specifying the limits of repeating; if the number of
+iterations reaches at `<N>',
+.I Lsof
+stops itself.
+.IP
+If the prefix is `+', repeat mode will end the first cycle no open files
+are listed \- and of course when
+.I lsof
+is stopped with an interrupt or quit signal.
+When repeat mode ends because no files are listed, the process exit code
+will be zero if any open files were ever listed; one, if none were ever
+listed.
+.IP
+.I Lsof
+marks the end of each listing:
+if field output is in progress (the
+.BR \-F ,
+option has been specified), the default marker is `m'; otherwise the
+default marker is ``========''.
+The marker is followed by a NL character.
+.IP
+The optional "m<fmt>" argument specifies a format for the marker line.
+The <fmt> characters following `m' are interpreted as a format
+specification to the
+.IR strftime (3)
+function, when both it and the
+.IR localtime (3)
+function are available in the dialect's C library.
+Consult the
+.IR strftime (3)
+documentation for what may appear in its format specification.
+Note that when field output is requested with the
+.B \-F
+option, <fmt> cannot contain the NL format, ``%n''.
+Note also that when <fmt> contains spaces or other characters that
+affect the shell's interpretation of arguments, <fmt> must be
+quoted appropriately.
+.IP
+Repeat mode reduces
+.I lsof
+startup overhead, so it is more efficient to use this mode
+than to call
+.I lsof
+repetitively from a shell script, for example.
+.IP
+To use repeat mode most efficiently, accompany
+.B +|\-r
+with specification of other
+.I lsof
+selection options, so the amount of kernel memory access
+.I lsof
+does will be kept to a minimum.
+Options that filter at the process level \- e.g.,
+.BR \-c ,
+.BR \-g ,
+.BR \-p ,
+.B \-u
+\&\- are the most efficient selectors.
+.IP
+Repeat mode is useful when coupled with field output (see the
+.BR \-F ,
+option description) and a supervising
+.I awk
+or
+.I Perl
+script, or a C program.
+.TP \w'names'u+4
+.B \-R
+directs lsof to list the Parent Process IDentification
+number in the PPID column.
+.TP \w'names'u+4
+.BI \-s " [p:s]"
+.B s
+alone directs
+.I lsof
+to display file size at all times.
+It causes the SIZE/OFF output column title to be changed to SIZE.
+If the file does not have a size, nothing is displayed.
+.IP
+The optional
+.BI \-s " p:s"
+form is available only for selected dialects, and only when the
+.B \-h
+or
+.B \-?
+help output lists it.
+.IP
+When the optional form is available, the
+.B s
+may be followed by a protocol name (\fIp\fR), either TCP or UDP,
+a colon (`:') and a comma\-separated protocol state name list,
+the option causes open TCP and UDP files to be excluded if their
+state name(s) are in the list (\fIs\fP) preceded by a `^'; or
+included if their name(s) are not preceded by a `^'.
+.IP
+Dialects that support this option may support only one protocol.
+When an unsupported protocol is specified, a message will be
+displayed indicating state names for the protocol are unavailable.
+.IP
+When an inclusion list is defined, only network files with state
+names in the list will be present in the
+.I lsof
+output.
+Thus, specifying one state name means that only network files
+with that lone state name will be listed.
+.IP
+Case is unimportant in the protocol or state names, but there may
+be no spaces and the colon (`:') separating the protocol
+name (\fIp\fP) and the state name list (\fIs\fP) is required.
+.IP
+If only TCP and UDP files are to be listed, as controlled by
+the specified exclusions and inclusions, the
+.B \-i
+option must be specified, too.
+If only a single protocol's files are to be listed, add its name
+as an argument to the
+.B \-i
+option.
+.IP
+For example, to list only network files with TCP state LISTEN, use:
+.IP
+.nf
+       \-iTCP \-sTCP:LISTEN
+.fi
+.IP
+Or, for example, to list network files with all UDP states except
+Idle, use:
+.IP
+.nf
+       \-iUDP \-sUDP:^Idle
+.fi
+.IP
+State names vary with UNIX dialects, so it's not possible to
+provide a complete list.  Some common TCP state names are:
+CLOSED, IDLE, BOUND, LISTEN, ESTABLISHED, SYN_SENT, SYN_RCDV,
+ESTABLISHED, CLOSE_WAIT, FIN_WAIT1, CLOSING, LAST_ACK, FIN_WAIT_2,
+and TIME_WAIT.
+Two common UDP state names are Unbound and Idle.
+.IP
+See the
+.I lsof
+FAQ (The \fBFAQ\fP section gives its location.)
+for more information on how to use protocol state exclusion and
+inclusion, including examples.
+.IP
+The
+.B \-o
+(without a following decimal digit count) and
+.B \-s
+option (without a following protocol and state name list)
+are mutually exclusive; they can't both be specified.
+When neither is specified,
+.I lsof
+displays whatever value - size or offset - is appropriate and
+available for the type of file.
+.IP
+Since some types of files don't have true sizes - sockets, FIFOs,
+pipes, etc.\& - lsof displays for their sizes the content amounts in
+their associated kernel buffers, if possible.
+.TP \w'names'u+4
+.BI \-S " [t]"
+specifies an optional time-out seconds value for kernel functions \-
+.IR lstat (2),
+.IR readlink (2),
+and
+.IR stat (2)
+\- that might otherwise deadlock.
+The minimum for
+.I t
+is two;
+the default, fifteen; when no value is specified, the default is used.
+.IP
+See the
+.B "BLOCKS AND TIMEOUTS"
+section for more information.
+.TP \w'names'u+4
+.BI \-T " [t]"
+controls the reporting of some TCP/TPI information, also
+reported by
+.IR netstat (1),
+following the network addresses.
+In normal output the information appears in parentheses, each item
+except TCP or TPI state name identified by a keyword, followed by `=',
+separated from others by a single space:
+.IP
+.nf
+       <TCP or TPI state name>
+       QR=<read queue length>
+       QS=<send queue length>
+       SO=<socket options and values>
+       SS=<socket states>
+       TF=<TCP flags and values>
+       WR=<window read length>
+       WW=<window write length>
+.fi
+.IP
+Not all values are reported for all UNIX dialects.
+Items values (when available) are reported after the item name and '='.
+.IP
+When the field output mode is in effect (See
+.BR "OUTPUT FOR OTHER PROGRAMS" .)
+each item appears as a field with a `T' leading character.
+.IP
+.B \-T
+with no following key characters disables TCP/TPI information reporting.
+.IP
+.B \-T
+with following characters selects the reporting of specific TCP/TPI
+information:
+.IP
+.nf
+       \fBf\fP selects reporting of socket options,
+               states and values, and TCP flags and
+               values.
+       \fBq\fP selects queue length reporting.
+       \fBs\fP selects connection state reporting.
+       \fBw\fP selects window size reporting.
+.fi
+.IP
+Not all selections are enabled for some UNIX dialects.
+State may be selected for all dialects and is reported by default.
+The
+.B \-h
+or
+.B \-?
+help output for the
+.B \-T
+option will show what selections may be used with the UNIX dialect.
+.IP
+When
+.B \-T
+is used to select information \- i.e., it is followed by one or more
+selection characters \- the displaying of state is disabled by default,
+and it must be explicitly selected again in the characters following
+.BR \-T .
+(In effect, then, the default is equivalent to
+.BR \-Ts .)
+For example, if queue lengths and state are desired, use
+.BR \-Tqs .
+.IP
+Socket options, socket states, some socket values, TCP flags and
+one TCP value may be reported (when available in the UNIX dialect)
+in the form of the names that commonly appear after SO_, so_, SS_,
+TCP_  and TF_ in the dialect's header files \-
+most often <sys/socket.h>, <sys/socketvar.h> and <netinet/tcp_var.h>.
+Consult those header files for the meaning of the flags, options,
+states and values.
+.IP
+``SO='' precedes socket options and values; ``SS='', socket states;
+and ``TF='', TCP flags and values.
+.IP
+If a flag or option has a value, the value will follow an '=' and
+the name -- e.g., ``SO=LINGER=5'', ``SO=QLIM=5'', ``TF=MSS=512''.
+The following seven values may be reported:
+.IP
+.nf
+       Name
+       Reported        Description (Common Symbol)
+
+       KEEPALIVE       keep alive time (SO_KEEPALIVE)
+       LINGER  linger time (SO_LINGER)
+       MSS             maximum segment size (TCP_MAXSEG)
+       PQLEN           partial listen queue connections
+       QLEN            established listen queue connections
+       QLIM            established listen queue limit
+       RCVBUF  receive buffer length (SO_RCVBUF)
+       SNDBUF  send buffer length (SO_SNDBUF)
+.fi
+.IP
+Details on what socket options and values, socket states, and TCP flags
+and values may be displayed for particular UNIX dialects may be found in
+the answer to the ``Why doesn't lsof report socket options, socket states,
+and TCP flags and values for my dialect?'' and ``Why doesn't lsof report
+the partial listen queue connection count for my dialect?''
+questions in the
+.I lsof
+FAQ (The \fBFAQ\fP section gives its location.)
+On Linux this option also prints the state of UNIX domain sockets.
+.TP \w'names'u+4
+.B \-t
+produce terse output comprising only process identifiers (without a
+header), so that it is easy to use programmatically. e.g.
+.nf
+
+       # reload anything using old SSL
+       lsof \-t /lib/*/libssl.so.* | xargs \-r kill \-HUP
+
+       # get list of processes and then iterate over them (Bash only)
+       mapfile \-t pids < <(
+           lsof \-wt /var/log/your.log
+       )
+       for pid in "${pids[@]}" ; do
+           your_command \-p "$pid"
+       done
+
+.fi
+The
+.B \-t
+option implies the
+.B \-w
+option.
+.TP \w'names'u+4
+.BI \-u " s"
+selects the listing of files for the user whose login names
+or user ID numbers are in the comma\-separated set
+.I s
+\&\- e.g., ``abe'',
+or ``548,root''.
+(There should be no spaces in the set.)
+.IP
+Multiple login names or user ID numbers are joined in a single ORed set
+before participating in AND option selection.
+.IP
+If a login name or user ID is preceded by a `^', it becomes a negation \-
+i.e., files of processes owned by the login name or user ID will never
+be listed.
+A negated login name or user ID selection is neither ANDed nor ORed
+with other selections; it is applied before all other selections and
+absolutely excludes the listing of the files of the process.
+For example, to direct
+.I lsof
+to exclude the listing of files belonging to root processes,
+specify ``\-u^root'' or ``\-u^0''.
+.TP \w'names'u+4
+.B \-U
+selects the listing of UNIX domain socket files.
+.TP \w'names'u+4
+.B \-v
+selects the listing of
+.I lsof
+version information, including: revision number;
+when the
+.I lsof
+binary was constructed;
+who constructed the binary and where;
+the name of the compiler used to construct the
+.I lsof binary;
+the version number of the compiler when readily available;
+the compiler and loader flags used to construct the
+.I lsof
+binary;
+and system information, typically the output of
+.IR uname 's
+.B \-a
+option.
+.TP \w'names'u+4
+.B \-V
+directs
+.I lsof
+to indicate the items it was asked to list and failed to find \- command
+names, file names, Internet addresses or files, login names, NFS files,
+PIDs, PGIDs, and UIDs.
+.IP
+When other options are ANDed to search options, or compile\-time
+options restrict the listing of some files,
+.I lsof
+may not report that it failed to find a search item when an ANDed
+option or compile\-time option prevents the listing of the open file
+containing the located search item.
+.IP
+For example, ``lsof \-V \-iTCP@foobar \-a \-d 999'' may not report a
+failure to locate open files at ``TCP@foobar'' and may not list
+any, if none have a file descriptor number of 999.
+A similar situation arises when HASSECURITY and HASNOSOCKSECURITY are
+defined at compile time and they prevent the listing of open files.
+.TP \w'names'u+4
+.B +|\-w
+Enables (\fB+\fP) or disables (\fB\-\fP) the suppression of warning messages.
+.IP
+The
+.I lsof
+builder may choose to have warning messages disabled or enabled by
+default.
+The default warning message state is indicated in the output of the
+.B \-h
+or
+.B \-?
+option.
+Disabling warning messages when they are already disabled or enabling
+them when already enabled is acceptable.
+.IP
+The
+.B \-t
+option implies the
+.B \-w
+option.
+.TP \w'names'u+4
+.BI \-x " [fl]"
+may accompany the
+.B +d
+and
+.B +D
+options to direct their processing to cross over symbolic
+links and|or file system mount points encountered when
+scanning the directory (\fB+d\fP) or directory tree (\fB+D\fP).
+.IP
+If
+.B \-x
+is specified by itself without a following parameter, cross\-over
+processing of both symbolic links and file system mount points is
+enabled.
+Note that when
+.B \-x
+is specified without a parameter, the next argument must begin with '\-'
+or '+'.
+.IP
+The optional 'f' parameter enables file system mount point cross\-over
+processing; 'l', symbolic link cross\-over processing.
+.IP
+The
+.B \-x
+option may not be supplied without also supplying a
+.B +d
+or
+.B +D
+option.
+.TP \w'names'u+4
+.B \-X
+This is a dialect\-specific option.
+.HP \w'names'u+4
+\ \ \ \ AIX:
+.br
+This IBM AIX RISC/System 6000 option requests the reporting
+of executed text file and shared library references.
+.IP
+.B WARNING:
+because this option uses the kernel readx() function, its use on
+a busy AIX system might cause an application process to hang so
+completely that it can neither be killed nor stopped.
+I have never seen this happen or had a report of its happening,
+but I think there is a remote possibility it could happen.
+.IP
+By default use of readx() is disabled.
+On AIX 5L and above
+.I lsof
+may need setuid\-root permission to perform the actions this
+option requests.
+.IP
+The
+.I lsof
+builder may specify that the
+.B \-X
+option be restricted to processes whose real UID is root.
+If that has been done, the
+.B \-X
+option will not appear in the
+.B \-h
+or
+.B \-?
+help output unless the real UID of the
+.I lsof
+process is root.
+The default
+.I lsof
+distribution allows any UID to specify
+.BR \-X,
+so by default it will appear in the help output.
+.IP
+When AIX readx() use
+is disabled,
+.I lsof
+may not be able to report information for all text and loader file
+references, but it may also avoid exacerbating an AIX
+kernel directory search kernel error, known as the Stale Segment
+ID bug.
+.IP
+The readx() function, used by
+.I lsof
+or any other program to access some sections of kernel virtual
+memory, can trigger the Stale Segment ID bug.
+It can cause the kernel's dir_search() function to believe erroneously
+that part of an in\-memory copy of a file system directory has been
+zeroed.
+Another application process, distinct from
+.IR lsof ,
+asking the kernel to search the directory \- e.g., by using
+.IR open "(2) \-"
+can cause dir_search() to loop forever, thus hanging the application process.
+.IP
+Consult the
+.I lsof
+FAQ (The \fBFAQ\fP section gives its location.)
+and the
+.I 00README
+file of the
+.I lsof
+distribution for a more complete description of the Stale Segment ID bug,
+its APAR, and methods for defining readx() use when compiling
+.IR lsof .
+.HP \w'names'u+4
+\ \ \ \ Linux:
+.br
+This Linux option requests that
+.I lsof
+skip the reporting of information on all open TCP, UDP and UDPLITE IPv4
+and IPv6 files.
+.IP
+This Linux option is most useful when the system has an extremely
+large number of open TCP, UDP and UDPLITE files, the processing of whose
+information in the
+.I /proc/net/tcp*
+and
+.I /proc/net/udp*
+files would take
+.I lsof
+a long time, and whose reporting is not of interest.
+.IP
+Use this option with care and only when you are sure that the
+information you want
+.I lsof
+to display isn't associated with open TCP, UDP or UDPLITE socket files.
+.HP \w'names'u+4
+\ \ \ \ Solaris 10 and above:
+.br
+This Solaris 10 and above option requests the reporting of cached
+paths for files that have been deleted \- i.e., removed with
+.IR rm (1)
+or
+.IR unlink (2).
+.IP
+The cached path is followed by the string ``\ (deleted)'' to indicate
+that the path by which the file was opened has been deleted.
+.IP
+Because intervening changes made to the path \- i.e., renames with
+.IR mv (1)
+or
+.IR rename (2)
+\- are not recorded in the cached path, what
+.I lsof
+reports is only the path by which the file was opened, not its
+possibly different final path.
+.TP \w'names'u+4
+.BI \-z " [z]"
+specifies how Solaris 10 and higher zone information is to be handled.
+.IP
+Without a following argument \- e.g., NO
+.IR z " \-"
+the option specifies that zone names are to be listed in the ZONE
+output column.
+.IP
+The
+.B \-z
+option may be followed by a zone name,
+.BI z .
+That causes lsof to list only open files for processes in that zone.
+Multiple
+.BI \-z " z"
+option and argument pairs may be specified to form a list of named zones.
+Any open file of any process in any of the zones will be listed, subject
+to other conditions specified by other options and arguments.
+.TP \w'names'u+4
+.BI \-Z " [Z]"
+specifies how SELinux security contexts are to be handled.
+It and 'Z' field output character support are inhibited
+when SELinux is disabled in the running Linux kernel.
+See
+.B "OUTPUT FOR OTHER PROGRAMS"
+for more information on the 'Z' field output character.
+.IP
+Without a following argument \- e.g., NO
+.IR Z " \-"
+the option specifies that security contexts are to be listed in the
+SECURITY\-CONTEXT output column.
+.IP
+The
+.B \-Z
+option may be followed by a wildcard security context name,
+.BI Z .
+That causes lsof to list only open files for processes in that security
+context.
+Multiple
+.BI \-Z " Z"
+option and argument pairs may be specified to form a list of security
+contexts.
+Any open file of any process in any of the security contexts will be listed,
+subject to other conditions specified by other options and arguments.
+Note that
+.I Z
+can be A:B:C or *:B:C or A:B:* or *:*:C to match against the A:B:C context.
+.TP \w'names'u+4
+.B \-\-
+The double minus sign option is a marker that signals the end of
+the keyed options.
+It may be used, for example, when the first file name begins with
+a minus sign.
+It may also be used when the absence of a value for the last keyed
+option must be signified by the presence of a minus sign in the following
+option and before the start of the file names.
+.TP \w'names'u+4
+.I names
+These are path names of specific files to list.
+Symbolic links are resolved before use.
+The first name may be separated from the preceding options with
+the ``\-\-'' option.
+.IP
+If a
+.I name
+is the mounted\-on directory of a file system or the device of the
+file system,
+.I lsof
+will list all the files open on the file system.
+To be considered a file system, the
+.I name
+must match a mounted\-on directory name in
+.IR mount (8)
+output, or match the name of a block device associated with a mounted\-on
+directory name.
+The
+.B +|\-f
+option may be used to force
+.I lsof
+to consider a
+.I name
+a file system identifier (\fB+f\fP) or a simple file (\fB\-f\fP).
+.IP
+If
+.I name
+is a path to a directory that is not the mounted\-on directory name of
+a file system, it is treated just as a regular file is treated \- i.e.,
+its listing is restricted to processes that have it open as a file or
+as a process\-specific directory, such as the root or current working
+directory.
+To request that
+.I lsof
+look for open files inside a directory name, use the
+.BI +d " s"
+and
+.BI +D " D"
+options.
+.IP
+If a
+.I name
+is the base name of a family of multiplexed files \- e.g, AIX's
+.IR /dev/pt[cs] " \-"
+.I lsof
+will list all the associated multiplexed files on the device that
+are open \- e.g.,
+.IR /dev/pt[cs]/1 ,
+.IR /dev/pt[cs]/2 ,
+etc.
+.IP
+If a
+.I name
+is a UNIX domain socket name,
+.I lsof
+will usually search for it by the characters of the name alone \- exactly as
+it is specified and is recorded in the kernel socket structure.
+(See the next paragraph for an exception to that rule for Linux.)
+Specifying a relative path \- e.g.,
+.I ./file
+\&\- in place of the
+file's absolute path \- e.g.,
+.I /tmp/file
+\&\- won't work because
+.I lsof
+must match the characters you specify with what it finds in the
+kernel UNIX domain socket structures.
+.IP
+If a
+.I name
+is a Linux UNIX domain socket name, in one case
+.I lsof
+is able to search for it by its device and inode number, allowing
+.I name
+to be a relative path.
+The case requires that the absolute path -- i.e., one beginning with a
+slash ('/') be used by the process that created the socket, and hence be
+stored in the
+.I /proc/net/unix
+file; and it requires that
+.I lsof
+be able to obtain the device and node numbers of both the absolute path in
+.I /proc/net/unix
+and
+.I name
+via successful
+.IR stat (2)
+system calls.
+When those conditions are met,
+.I lsof
+will be able to search for the UNIX domain socket when some path to it is
+is specified in
+.IR name .
+Thus, for example, if the path is
+.IR /dev/log ,
+and an
+.I lsof
+search is initiated when the working directory is
+.IR /dev ,
+then
+.I name
+could be
+.IR ./log .
+.IP
+If a
+.I name
+is none of the above,
+.I lsof
+will list any open files whose device and inode match that of the
+specified path
+.IR name .
+.IP
+If you have also specified the
+.B \-b
+option,
+the only
+.I names
+you may safely specify are file systems for which your mount table
+supplies alternate device numbers.
+See the
+.B "AVOIDING KERNEL BLOCKS"
+and
+.B "ALTERNATE DEVICE NUMBERS"
+sections for more information.
+.IP
+Multiple file names are joined in a single ORed set before
+participating in AND option selection.
+.SH AFS
+.I Lsof
+supports the recognition of AFS files for these dialects (and AFS
+versions):
+.PP
+.nf
+       AIX 4.1.4 (AFS 3.4a)
+       HP\-UX 9.0.5 (AFS 3.4a)
+       Linux 1.2.13 (AFS 3.3)
+       Solaris 2.[56] (AFS 3.4a)
+.fi
+.PP
+It may recognize AFS files on other versions of these dialects,
+but has not been tested there.
+Depending on how AFS is implemented,
+.I lsof
+may recognize AFS files in other dialects, or may have difficulties
+recognizing AFS files in the supported dialects.
+.PP
+.I Lsof
+may have trouble identifying all aspects of AFS files in
+supported dialects when AFS kernel support is implemented via
+dynamic modules whose addresses do not appear in the kernel's
+variable name list.
+In that case,
+.I lsof
+may have to guess at the identity of AFS files, and might not be able to
+obtain volume information from the kernel that is needed for calculating
+AFS volume node numbers.
+When
+.I lsof
+can't compute volume node numbers, it reports blank in the NODE column.
+.PP
+The
+.BI \-A " A"
+option is available in some dialect implementations of
+.I lsof
+for specifying the name list file where dynamic module kernel
+addresses may be found.
+When this option is available, it will be listed in the
+.I lsof
+help output, presented in response to the
+.B \-h
+or
+.B \-?
+.PP
+See the
+.I lsof
+FAQ (The \fBFAQ\fP section gives its location.)
+for more information about dynamic modules, their
+symbols, and how they affect
+.I lsof
+options.
+.PP
+Because AFS path lookups don't seem to participate in the
+kernel's name cache operations,
+.I lsof
+can't identify path name components for AFS files.
+.SH SECURITY
+.I Lsof
+has three features that may cause security concerns.
+First, its default compilation mode allows anyone to list all
+open files with it.
+Second, by default it creates a user\-readable and user\-writable device
+cache file in the home directory of the real user ID that executes
+.IR lsof .
+(The list\-all\-open\-files and device cache features may be disabled when
+.I lsof
+is compiled.)
+Third, its
+.B \-k
+and
+.B \-m
+options name alternate kernel name list or memory files.
+.PP
+Restricting the listing of all open files is controlled by the
+compile\-time HASSECURITY and HASNOSOCKSECURITY options.
+When HASSECURITY is defined,
+.I lsof
+will allow only the root user to list all open files.
+The non\-root user may list only open files of processes with the same user
+IDentification number as the real user ID number of the
+.I lsof
+process (the one that its user logged on with).
+.PP
+However, if HASSECURITY and HASNOSOCKSECURITY are both defined,
+anyone may list open socket files, provided they are selected
+with the
+.B \-i
+option.
+.PP
+When HASSECURITY is not defined, anyone may list all open files.
+.PP
+Help output, presented in response to the
+.B \-h
+or
+.B \-?
+option, gives the status of the HASSECURITY and HASNOSOCKSECURITY definitions.
+.PP
+See the
+.B Security
+section of the
+.I 00README
+file of the
+.I lsof
+distribution for information on building
+.I lsof
+with the HASSECURITY and HASNOSOCKSECURITY options enabled.
+.PP
+Creation and use of a user\-readable and user\-writable device
+cache file is controlled by the compile\-time HASDCACHE option.
+See the
+.B "DEVICE CACHE FILE"
+section and the sections that follow it for details on how its path
+is formed.
+For security considerations it is important to note that in the default
+.I lsof
+distribution, if the real user ID under which
+.I lsof
+is executed is root, the device cache file will be written in root's
+home directory \- e.g.,
+.I /
+or
+.IR /root .
+When HASDCACHE is not defined,
+.I lsof
+does not write or attempt to read a device cache file.
+.PP
+When HASDCACHE is defined, the
+.I lsof
+help output, presented in response to the
+.BR \-h ,
+.BR \-D? ,
+or
+.B \-?
+options, will provide device cache file handling information.
+When HASDCACHE is not defined, the
+.B \-h
+or
+.B \-?
+output will have no
+.B \-D
+option description.
+.PP
+Before you decide to disable the device cache file feature \- enabling
+it improves the performance of
+.I lsof
+by reducing the startup overhead of examining all the nodes in
+.I /dev
+(or
+.IR /devices )
+\&\- read the discussion of it in the
+.I 00DCACHE
+file of the
+.I lsof
+distribution and the
+.I lsof
+FAQ (The \fBFAQ\fP section gives its location.)
+.PP
+WHEN IN DOUBT, YOU CAN TEMPORARILY DISABLE THE USE OF THE DEVICE CACHE FILE
+WITH THE
+.B \-Di
+OPTION.
+.PP
+When
+.I lsof
+user declares alternate kernel name list or memory files with the
+.B \-k
+and
+.B \-m
+options,
+.I lsof
+checks the user's authority to read them with
+.IR access (2).
+This is intended to prevent whatever special power
+.I lsof's
+modes might confer on it from letting it read files not normally
+accessible via the authority of the real user ID.
+.SH OUTPUT
+This section describes the information
+.I lsof
+lists for each open file.
+See the
+.B "OUTPUT FOR OTHER PROGRAMS"
+section for additional information on output that can be processed
+by another program.
+.PP
+.I Lsof
+only outputs printable (declared so by
+.IR isprint (3))
+8 bit characters.
+Non\-printable characters are printed in one of three forms:
+the C ``\\[bfrnt]'' form;
+the control character `^' form (e.g., ``^@'');
+or hexadecimal leading ``\\x'' form (e.g., ``\\xab'').
+Space is non\-printable in the COMMAND column (``\\x20'')
+and printable elsewhere.
+.PP
+For some dialects - if HASSETLOCALE is defined in the dialect's
+machine.h header file -
+.I lsof
+will print the extended 8 bit characters of a language locale.
+The
+.I lsof
+process must be supplied a language locale environment variable
+(e.g., LANG) whose value represents a known language locale
+in which the extended characters are considered printable by
+.IR isprint (3).
+Otherwise
+.I lsof
+considers the extended characters non-printable and prints them according
+to its rules for non-printable characters, stated above.
+Consult your dialect's
+.IR setlocale (3)
+man page for the names of other environment variables that may
+be used in place of LANG - e.g., LC_ALL, LC_CTYPE, etc.
+.PP
+.I Lsof's
+language locale support for a dialect also covers wide characters - e.g.,
+UTF-8 - when HASSETLOCALE and HASWIDECHAR are defined in the dialect's
+machine.h header file, and when a suitable language locale has been defined
+in the appropriate environment variable for the
+.I lsof
+process.
+Wide characters are printable under those conditions if
+.IR iswprint (3)
+reports them to be.
+If HASSETLOCALE, HASWIDECHAR and a suitable language locale aren't defined,
+or if
+.IR iswprint (3)
+reports wide characters that aren't printable,
+.I lsof
+considers the wide characters non\-printable and prints each of their
+8 bits according to its rules for non\-printable characters, stated above.
+.PP
+Consult the answers to the "Language locale support" questions in the
+lsof FAQ (The \fBFAQ\fP section gives its location.) for more information.
+.PP
+.I Lsof
+dynamically sizes the output columns each time it runs, guaranteeing
+that each column is a minimum size.
+It also guarantees that each column is separated from its predecessor
+by at least one space.
+.TP \w'COMMAND'u+4
+COMMAND
+contains the first nine characters of the name of the UNIX command
+associated with the process.
+If a non\-zero
+.I w
+value is specified to the
+.BI +c " w"
+option, the column contains the first
+.I w
+characters of the name of the UNIX command associated with the process
+up to the limit of characters supplied to
+.I lsof
+by the UNIX dialect.
+(See the description of the
+.BI +c " w"
+command or the
+.I lsof
+FAQ for more information.
+The \fBFAQ\fP section gives its location.)
+.IP
+If
+.I w
+is less than the length of the column title, ``COMMAND'', it will
+be raised to that length.
+.IP
+If a zero
+.I w
+value is specified to the
+.BI +c " w"
+option, the column contains all the characters of the name of the UNIX command
+associated with the process.
+.IP
+All command name characters maintained by the kernel in its structures
+are displayed in field output when the command name descriptor (`c')
+is specified.
+See the
+.B "OUTPUT FOR OTHER COMMANDS"
+section for information on selecting field output and the associated
+command name descriptor.
+.TP
+PID
+is the Process IDentification number of the process.
+.TP
+TID
+is the task (thread) IDentification number, if task (thread)
+reporting is supported by the dialect and a task (thread) is
+being listed.
+(If help output \- i.e., the output of the
+.B \-h
+or
+.B \-?
+options \- shows this option, then task (thread) reporting is
+supported by the dialect.)
+.IP
+A blank TID column in Linux indicates a process \- i.e., a non\-task.
+.TP
+TASKCMD
+is the task command name.
+Generally this will be the same as the process named in the COMMAND
+column, but some task implementations (e.g., Linux) permit a task to
+change its command name.
+.IP
+The TASKCMD column width is subject to the same size limitation as the
+COMMAND column.
+.TP
+ZONE
+is the Solaris 10 and higher zone name.
+This column must be selected with the
+.B \-z
+option.
+.TP
+SECURITY\-CONTEXT
+is the SELinux security context.
+This column must be selected with the
+.B \-Z
+option.
+Note that the
+.B \-Z
+option is inhibited when SELinux is disabled in the running Linux
+kernel.
+.TP
+PPID
+is the Parent Process IDentification number of the process.
+It is only displayed when the
+.B \-R
+option has been specified.
+.TP
+PGID
+is the process group IDentification number associated with
+the process.
+It is only displayed when the
+.B \-g
+option has been specified.
+.TP
+USER
+is the user ID number or login name of the user to whom
+the process belongs, usually the same as reported by
+.IR ps (1).
+However, on Linux USER is the user ID number or login that owns
+the directory in /proc where
+.I lsof
+finds information about the process.
+Usually that is the same value reported by
+.IR ps (1),
+but may differ when the process has changed its effective user ID.
+(See the
+.B \-l
+option description for information on when a user ID number or
+login name is displayed.)
+.TP
+FD
+is the File Descriptor number of the file or:
+.IP
+.nf
+       \fBcwd\fP       current working directory;
+.br
+       \fBL\fInn\fR    library references (AIX);
+.br
+       \fBctty\fR      character tty;
+.br
+       \fBDEL\fR       deleted file;
+.br
+       \fBerr\fR       FD information error (see NAME column);
+.br
+       \fBfp.\fR       Fileport (Darwin);
+.br
+       \fBjld\fR       jail directory (FreeBSD);
+.br
+       \fBltx\fP       shared library text (code and data);
+.br
+       \fBM\fIxx\fR    hex memory\-mapped type number xx.
+.br
+       \fBm86\fP       DOS Merge mapped file;
+.br
+       \fBmem\fP       memory\-mapped file;
+.br
+       \fBmmap\fP      memory\-mapped device;
+.br
+       \fBNOFD\fP      for a Linux /proc/<PID>/fd directory that can't be opened --
+               the directory path appears in the NAME column, followed by an error
+               message;
+.br
+       \fBpd\fP        parent directory;
+.br
+       \fBR\fInn\fR    unknown pregion number (HP-UX);
+.br
+       \fBrtd\fP       root directory;
+.br
+       \fBtwd\fP       per task current working directory;
+.br
+       \fBtxt\fP       program text (code and data);
+.br
+       \fBv86\fP       VP/ix mapped file;
+.fi
+.IP
+FD is followed by one of these characters, describing the mode under which
+the file is open:
+.IP
+       \fBr\fP for read access;
+.br
+       \fBw\fP for write access;
+.br
+       \fBu\fP for read and write access;
+.br
+       space if mode unknown and no lock
+.br
+               character follows;
+.br
+       `\-' if mode unknown and lock
+.br
+               character follows.
+.IP
+The mode character is followed by one of these lock characters, describing
+the type of lock applied to the file:
+.IP
+       \fBN\fP for a Solaris NFS lock of unknown type;
+.br
+       \fBr\fP for read lock on part of the file;
+.br
+       \fBR\fP for a read lock on the entire file;
+.br
+       \fBw\fP for a write lock on part of the file;
+.br
+       \fBW\fP for a write lock on the entire file;
+.br
+       \fBu\fP for a read and write lock of any length;
+.br
+       \fBU\fP for a lock of unknown type;
+.br
+       \fBx\fP for an SCO OpenServer Xenix lock on part of the file;
+.br
+       \fBX\fP for an SCO OpenServer Xenix lock on the entire file;
+.br
+       space if there is no lock.
+.IP
+See the
+.B LOCKS
+section for more information on the lock information character.
+.IP
+The FD column contents constitutes a single field for parsing in
+post\-processing scripts. FD numbers larger than 9999 are abbreviated
+to a ``*'' followed by the last three digits. E.g., 10001 appears as
+``*001''
+.TP
+TYPE
+is the type of the node associated with the file \- e.g., VDIR, VREG, etc.
+.IP
+or ``ax25'' for a Linux AX.25 socket;
+.IP
+or ``a_inode'' for anonymous inode;
+.IP
+or ``icmp'' for an ICMP socket;
+.IP
+or ``inet'' for an Internet domain socket;
+.IP
+or ``ipx'' for an IPX socket;
+.IP
+or ``key'' for an internal key management socket;
+.IP
+or ``lla'' for a HP\-UX link level access file;
+.IP
+or ``ndrv'' for a net driver socket;
+.IP
+or ``netlink'' for a netlink socket;
+.IP
+or ``pack'' for a packet socket;
+.IP
+or ``ppp'' for a PPP socket;
+.IP
+or ``raw'' for a raw socket;
+.IP
+or ``raw6'' for a raw IPv6 socket;
+.IP
+or ``rte'' for an AF_ROUTE socket;
+.IP
+or ``sock'' for a socket of unknown domain;
+.IP
+or ``systm'' for a system socket;
+.IP
+or ``unix'' for a UNIX domain socket;
+.IP
+or ``x.25'' for an HP\-UX x.25 socket;
+.IP
+or ``ATALK'' for an AppleTalk socket;
+.IP
+or ``BLK'' for a block special file;
+.IP
+or ``CHR'' for a character special file;
+.IP
+or ``DEL'' for a Linux map file that has been deleted;
+.IP
+or ``DIR'' for a directory;
+.IP
+or ``DOOR'' for a VDOOR file;
+.IP
+or ``EVENTFD'' for an eventfd;
+.IP
+or ``FIFO'' for a FIFO special file;
+.IP
+or ``FSEVENTS'' for fsevents;
+.IP
+or ``IPv4'' for an IPv4 socket;
+.IP
+or ``IPv6'' for an open IPv6 network file \- even if its address is
+IPv4, mapped in an IPv6 address;
+.IP
+or ``KQUEUE'' for a BSD style kernel event queue file;
+.IP
+or ``LINK'' for a symbolic link file;
+.IP
+or ``MPB'' for a multiplexed block file;
+.IP
+or ``MPC'' for a multiplexed character file;
+.IP
+or ``PAS'' for a
+.I /proc/as
+file;
+.IP
+or ``PAXV'' for a
+.I /proc/auxv
+file;
+.IP
+or ``PCRE'' for a
+.I /proc/cred
+file;
+.IP
+or ``PCTL'' for a
+.I /proc
+control file;
+.IP
+or ``PCUR'' for the current
+.I /proc
+process;
+.IP
+or ``PCWD'' for a
+.I /proc
+current working directory;
+.IP
+or ``PDIR'' for a
+.I /proc
+directory;
+.IP
+or ``PETY'' for a
+.I /proc
+executable type (\fIetype\fP);
+.IP
+or ``PFD'' for a
+.I /proc
+file descriptor;
+.IP
+or ``PFDR'' for a
+.I /proc
+file descriptor directory;
+.IP
+or ``PFIL'' for an executable
+.I /proc
+file;
+.IP
+or ``PFPR'' for a
+.I /proc
+FP register set;
+.IP
+or ``PGD'' for a
+.I /proc/pagedata
+file;
+.IP
+or ``PGID'' for a
+.I /proc
+group notifier file;
+.IP
+or ``PIPE'' for pipes;
+.IP
+or ``PLC'' for a
+.I /proc/lwpctl
+file;
+.IP
+or ``PLDR'' for a
+.I /proc/lpw
+directory;
+.IP
+or ``PLDT'' for a
+.I /proc/ldt
+file;
+.IP
+or ``PLPI'' for a
+.I /proc/lpsinfo
+file;
+.IP
+or ``PLST'' for a
+.I /proc/lstatus
+file;
+.IP
+or ``PLU'' for a
+.I /proc/lusage
+file;
+.IP
+or ``PLWG'' for a
+.I /proc/gwindows
+file;
+.IP
+or ``PLWI'' for a
+.I /proc/lwpsinfo
+file;
+.IP
+or ``PLWS'' for a
+.I /proc/lwpstatus
+file;
+.IP
+or ``PLWU'' for a
+.I /proc/lwpusage
+file;
+.IP
+or ``PLWX'' for a
+.I /proc/xregs
+file;
+.IP
+or ``PMAP'' for a
+.I /proc
+map file (\fImap\fP);
+.IP
+or ``PMPS'' for a
+.I /proc/maps
+file;
+.IP
+or ``PMEM'' for a
+.I /proc
+memory image file;
+.IP
+or ``PNTF'' for a
+.I /proc
+process notifier file;
+.IP
+or ``POBJ'' for a
+.I /proc/object
+file;
+.IP
+or ``PODR'' for a
+.I /proc/object
+directory;
+.IP
+or ``POLP'' for an old format
+.I /proc
+light weight process file;
+.IP
+or ``POPF'' for an old format
+.I /proc
+PID file;
+.IP
+or ``POPG'' for an old format
+.I /proc
+page data file;
+.IP
+or ``PORT'' for a SYSV named pipe;
+.IP
+or ``PREG'' for a
+.I /proc
+register file;
+.IP
+or ``PRMP'' for a
+.I /proc/rmap
+file;
+.IP
+or ``PROCDSC'' for a processor descriptor;
+.IP
+or ``PRTD'' for a
+.I /proc
+root directory;
+.IP
+or ``PSGA'' for a
+.I /proc/sigact
+file;
+.IP
+or ``PSIN'' for a
+.I /proc/psinfo
+file;
+.IP
+or ``PSTA'' for a
+.I /proc
+status file;
+.IP
+or ``PSXMQ'' for a POSIX message queue file;
+.IP
+or ``PSXSEM'' for a POSIX semaphore file;
+.IP
+or ``PSXSHM'' for a POSIX shared memory file;
+.IP
+or ``PTS'' for a
+.I /dev/pts
+file;
+.IP
+or ``PUSG'' for a
+.I /proc/usage
+file;
+.IP
+or ``PW'' for a
+.I /proc/watch
+file;
+.IP
+or ``PXMP'' for a
+.I /proc/xmap
+file;
+.IP
+or ``REG'' for a regular file;
+.IP
+or ``SHM'' for a shared memory file;
+.IP
+or ``SMT'' for a shared memory transport file;
+.IP
+or ``STR'' for streams;
+.IP
+or ``STSO'' for a stream socket;
+.IP
+or ``UNKN'' for an unknown file;
+.IP
+or ``UNKNcwd'' for unknown current working directory;
+.IP
+or ``UNKNdel'' for unknown deleted file;
+.IP
+or ``UNKNfd'' for unknown file descriptor;
+.IP
+or ``UNKNmem'' for unknown memory-mapped file;
+.IP
+or ``UNKNrtd'' for unknown root directory;
+.IP
+or ``UNKNtxt'' for unknown program text;
+.IP
+or ``UNNM'' for an unnamed type file;
+.IP
+or ``XNAM'' for an OpenServer Xenix special file of unknown type;
+.IP
+or ``XSEM'' for an OpenServer Xenix semaphore file;
+.IP
+or ``XSD'' for an OpenServer Xenix shared data file;
+.IP
+or ``UNSP'' for an unsupported file;
+.IP
+or the four type number octets if the corresponding name isn't known.
+.TP
+FILE\-ADDR
+contains the kernel file structure address when
+.B f
+has been specified to
+.BR +f ;
+.TP
+FCT
+contains the file reference count from the kernel file structure when
+.B c
+has been specified to
+.BR +f ;
+.TP
+FILE\-FLAG
+when
+.B g
+or
+.B G
+has been specified to
+.BR +f ,
+this field contains the contents of the f_flag[s] member of the kernel
+file structure and the kernel's per-process open file flags (if available);
+\&`G' causes them to be displayed in hexadecimal;
+\&`g', as short\-hand names;
+two lists may be displayed with entries separated by commas, the
+lists separated by a semicolon (`;');
+the first list may contain short\-hand names for f_flag[s] values from
+the following table:
+.IP
+.nf
+       AIO             asynchronous I/O (e.g., FAIO)
+       AP              append
+       ASYN            asynchronous I/O (e.g., FASYNC)
+       BAS             block, test, and set in use
+       BKIU            block if in use
+       BL              use block offsets
+       BSK             block seek
+       CA              copy avoid
+       CIO             concurrent I/O
+       CLON            clone
+       CLRD            CL read
+       CR              create
+       DF              defer
+       DFI             defer IND
+       DFLU            data flush
+       DIR             direct
+       DLY             delay
+       DOCL            do clone
+       DSYN            data-only integrity
+       DTY             must be a directory
+       EVO             event only
+       EX              open for exec
+       EXCL            exclusive open
+       FSYN            synchronous writes
+       GCDF            defer during unp_gc() (AIX)
+       GCMK            mark during unp_gc() (AIX)
+       GTTY            accessed via /dev/tty
+       HUP             HUP in progress
+       KERN            kernel
+       KIOC            kernel-issued ioctl
+       LCK             has lock
+       LG              large file
+       MBLK            stream message block
+       MK              mark
+       MNT             mount
+       MSYN            multiplex synchronization
+       NATM            don't update atime
+       NB              non\-blocking I/O
+       NBDR            no BDRM check
+       NBIO            SYSV non\-blocking I/O
+       NBF             n\-buffering in effect
+       NC              no cache
+       ND              no delay
+       NDSY            no data synchronization
+       NET             network
+       NFLK            don't follow links
+       NMFS            NM file system
+       NOTO            disable background stop
+       NSH             no share
+       NTTY            no controlling TTY
+       OLRM            OLR mirror
+       PAIO            POSIX asynchronous I/O
+       PATH            path
+       PP              POSIX pipe
+       R               read
+       RC              file and record locking cache
+       REV             revoked
+       RSH             shared read
+       RSYN            read synchronization
+       RW              read and write access
+       SL              shared lock
+       SNAP            cooked snapshot
+       SOCK            socket
+       SQSH            Sequent shared set on open
+       SQSV            Sequent SVM set on open
+       SQR             Sequent set repair on open
+       SQS1            Sequent full shared open
+       SQS2            Sequent partial shared open
+       STPI            stop I/O
+       SWR             synchronous read
+       SYN             file integrity while writing
+       TCPM            avoid TCP collision
+       TMPF            temporary file
+       TR              truncate
+       W               write
+       WKUP            parallel I/O synchronization
+       WTG             parallel I/O synchronization
+       VH              vhangup pending
+       VTXT            virtual text
+       XL              exclusive lock
+.fi
+.IP
+this list of names was derived from F* #define's in dialect header files
+<fcntl.h>, <linux</fs.h>, <sys/fcntl.c>, <sys/fcntlcom.h>, and <sys/file.h>;
+see the common.h header file for a list showing the correspondence
+between the above short-hand names and the header file definitions;
+.IP
+the second list (after the semicolon) may contain short-hand names
+for kernel per-process open file flags from this table:
+.IP
+.nf
+       ALLC            allocated
+       BR              the file has been read
+       BHUP            activity stopped by SIGHUP
+       BW              the file has been written
+       CLSG            closing
+       CX              close-on-exec (see fcntl(F_SETFD))
+       LCK             lock was applied
+       MP              memory-mapped
+       OPIP            open pending - in progress
+       RSVW            reserved wait
+       SHMT            UF_FSHMAT set (AIX)
+       USE             in use (multi-threaded)
+.fi
+.TP
+NODE\-ID
+(or INODE\-ADDR for some dialects)
+contains a unique identifier for the file node (usually the kernel
+vnode or inode address, but also occasionally a concatenation of
+device and node number) when
+.B n
+has been specified to
+.BR +f ;
+.TP
+DEVICE
+contains the device numbers, separated by commas, for a character special,
+block special, regular, directory or NFS file;
+.IP
+or ``memory'' for a memory file system node under Tru64 UNIX;
+.IP
+or the address of the private data area of a Solaris socket
+stream;
+.IP
+or a kernel reference address that identifies the file
+(The kernel reference address may be used for FIFO's, for example.);
+.IP
+or
+the base address or device name of a Linux AX.25 socket device.
+.IP
+Usually only the lower thirty two bits of Tru64 UNIX kernel addresses
+are displayed.
+.TP
+SIZE, SIZE/OFF, or OFFSET
+is the size of the file or the file offset in bytes.
+A value is displayed in this column only if it is available.
+.I Lsof
+displays whatever value \- size or offset \- is appropriate for the type
+of the file and the version of
+.IR lsof .
+.IP
+On some UNIX dialects
+.I lsof
+can't obtain accurate or consistent file offset information from its
+kernel data sources, sometimes just for particular kinds of files
+(e.g., socket files.)
+In other cases, files don't have true sizes \- e.g., sockets, FIFOs,
+pipes \- so
+.I lsof
+displays for their sizes the content amounts it finds in their kernel
+buffer descriptors (e.g., socket buffer size counts or TCP/IP window
+sizes.)
+Consult the
+.I lsof
+FAQ (The \fBFAQ\fP section gives its location.)
+for more information.
+.IP
+The file size is displayed in decimal;
+the offset is normally displayed in decimal with a leading ``0t'' if
+it contains 8 digits or less; in hexadecimal with a leading ``0x'' if
+it is longer than 8 digits.
+(Consult the
+.BI \-o " o"
+option description for information on when 8 might default to
+some other value.)
+.IP
+Thus the leading ``0t'' and ``0x'' identify an offset when the column
+may contain both a size and an offset (i.e., its title is SIZE/OFF).
+.IP
+If the
+.B \-o
+option is specified,
+.I lsof
+always displays the file offset (or nothing if no offset is available)
+and labels the column OFFSET.
+The offset always begins with ``0t'' or ``0x'' as described above.
+.IP
+The
+.I lsof
+user can control the switch from ``0t'' to ``0x'' with the
+.BI \-o " o"
+option.
+Consult its description for more information.
+.IP
+If the
+.B \-s
+option is specified,
+.I lsof
+always displays the file size (or nothing if no size is available)
+and labels the column SIZE.
+The
+.B \-o
+and
+.B \-s
+options are mutually exclusive; they can't both be specified.
+.IP
+If the
+.B \-H
+option is specified,
+.I lsof
+displays file size in human readable form.
+.IP
+For files that don't have a fixed size \- e.g., don't reside
+on a disk device \-
+.I lsof
+will display appropriate information about the current size or
+position of the file if it is available in the kernel structures
+that define the file.
+.TP
+NLINK
+contains the file link count when
+.B +L
+has been specified;
+.TP
+NODE
+is the node number of a local file;
+.IP
+or the inode number of an NFS file in the server host;
+.IP
+or the Internet protocol type \- e.g, ``TCP'';
+.IP
+or ``STR'' for a stream;
+.IP
+or ``CCITT'' for an HP\-UX x.25 socket;
+.IP
+or the IRQ or inode number of a Linux AX.25 socket device.
+.TP
+NAME
+is the name of the mount point and file system on which the file resides;
+.IP
+or the name of a file specified in the
+.I names
+option (after any symbolic links have been resolved);
+.IP
+or the name of a character special or block special device;
+.IP
+or the local and remote Internet addresses of a network file;
+the local host name or IP number is followed by a colon (':'), the
+port, ``\->'', and the two\-part remote address;
+IP addresses may be reported as numbers or names, depending on the
+.BR +|\-M ,
+.BR \-n ,
+and
+.B \-P
+options;
+colon\-separated IPv6 numbers are enclosed in square brackets;
+IPv4 INADDR_ANY and IPv6 IN6_IS_ADDR_UNSPECIFIED addresses, and
+zero port numbers are represented by an asterisk ('*');
+a UDP destination address may be followed by the amount of time
+elapsed since the last packet was sent to the destination;
+TCP, UDP and UDPLITE remote addresses may be followed by TCP/TPI
+information in parentheses \- state (e.g., ``(ESTABLISHED)'', ``(Unbound)''),
+queue sizes, and window sizes (not all dialects) \- in a fashion
+similar to what
+.IR netstat (1)
+reports;
+see the
+.B \-T
+option description or the description of the TCP/TPI field in
+.B "OUTPUT FOR OTHER PROGRAMS"
+for more information on state, queue size, and window size;
+.IP
+or the address or name of a UNIX domain socket, possibly including
+a stream clone device name, a file system object's path name, local
+and foreign kernel addresses, socket pair information, and a bound
+vnode address;
+.IP
+or the local and remote mount point names of an NFS file;
+.IP
+or ``STR'', followed by the stream name;
+.IP
+or a stream character device name, followed by ``\->'' and the stream name
+or a list of stream module names, separated by ``\->'';
+.IP
+or ``STR:'' followed by the SCO OpenServer stream device and module
+names, separated by ``\->'';
+.IP
+or system directory name, `` \-\- '', and as many components of the path
+name as
+.I lsof
+can find in the kernel's name cache for selected dialects
+(See the
+.B "KERNEL NAME CACHE"
+section for more information.);
+.IP
+or ``PIPE\->'', followed by a Solaris kernel pipe destination address;
+.IP
+or ``COMMON:'', followed by the vnode device information structure's
+device name, for a Solaris common vnode;
+.IP
+or the address family, followed by a slash (`/'), followed by fourteen
+comma\-separated bytes of a non\-Internet raw socket address;
+.IP
+or the HP\-UX x.25 local address, followed by the virtual connection
+number (if any), followed by the remote address (if any);
+.IP
+or ``(dead)'' for disassociated Tru64 UNIX files \- typically terminal files
+that have been flagged with the TIOCNOTTY ioctl and closed by daemons;
+.IP
+or ``rd=<offset>'' and ``wr=<offset>'' for the values of the
+read and write offsets of a FIFO;
+.IP
+or ``clone \fIn\fP:/dev/event'' for SCO OpenServer file clones of the
+.I /dev/event
+device, where
+.I n
+is the minor device number of the file;
+.IP
+or ``(socketpair: n)'' for a Solaris 2.6, 8, 9  or 10
+UNIX domain socket, created by the
+.IR socketpair (3N)
+network function;
+.IP
+or ``no PCB'' for socket files that do not have a protocol block
+associated with them, optionally followed by ``, CANTSENDMORE'' if
+sending on the socket has been disabled, or ``, CANTRCVMORE'' if
+receiving on the socket has been disabled (e.g., by the
+.IR shutdown (2)
+function);
+.IP
+or the local and remote addresses of a Linux IPX socket file
+in the form <net>:[<node>:]<port>, followed in parentheses
+by the transmit and receive queue sizes, and the connection state;
+.IP
+or ``dgram'' or ``stream'' for the type UnixWare 7.1.1 and above in\-kernel
+UNIX domain sockets, followed by a colon (':') and the local path name
+when available, followed by ``\->'' and the remote path name or kernel
+socket address in hexadecimal when available;
+.IP
+or the association value, association index, endpoint value, local address,
+local port, remote address and remote port for Linux SCTP sockets;
+.IP
+or ``protocol: '' followed by the Linux socket's protocol attribute.
+.PP
+For dialects that support a ``namefs'' file system, allowing one
+file to be attached to another with
+.IR fattach (3C),
+.I lsof
+will add ``(FA:<address1><direction><address2>)'' to the NAME column.
+<address1> and <address2> are hexadecimal vnode addresses.
+<direction> will be ``<\-'' if <address2> has been fattach'ed to
+this vnode whose address is <address1>;
+and ``\->'' if <address1>, the vnode address of this vnode, has been
+fattach'ed to <address2>.
+<address1> may be omitted if it already appears in the DEVICE column.
+.PP
+.I
+Lsof
+may add two parenthetical notes to the NAME column for open Solaris 10 files:
+\&``(?)'' if
+.I lsof
+considers the path name of questionable accuracy;
+and ``(deleted)'' if the
+.B \-X
+option has been specified and
+.I lsof
+detects the open file's path name has been deleted.
+Consult the
+.I lsof
+FAQ (The \fBFAQ\fP section gives its location.)
+for more information on these NAME column additions.
+.SH LOCKS
+.I Lsof
+can't adequately report the wide variety of UNIX dialect file locks
+in a single character.
+What it reports in a single character is a compromise between the
+information it finds in the kernel and the limitations of the reporting
+format.
+.PP
+Moreover, when a process holds several byte level locks on a file,
+.I lsof
+only reports the status of the first lock it encounters.
+If it is a byte level lock, then the lock character will be reported
+in lower case \- i.e., `r', `w', or `x' \- rather than the upper case
+equivalent reported for a full file lock.
+.PP
+Generally
+.I lsof
+can only report on locks held by local processes on local files.
+When a local process sets a lock on a remotely mounted (e.g., NFS)
+file, the remote server host usually records the lock state.
+One exception is Solaris \- at some patch levels of 2.3, and in all
+versions above 2.4, the Solaris kernel records information on remote
+locks in local structures.
+.PP
+.I Lsof
+has trouble reporting locks for some UNIX dialects.
+Consult the
+.B BUGS
+section of this manual page or the
+.I lsof
+FAQ (The \fBFAQ\fP section gives its location.)
+for more information.
+.SH "OUTPUT FOR OTHER PROGRAMS"
+When the
+.B \-F
+option is specified,
+.I lsof
+produces output that is suitable for processing by another program \- e.g, an
+.I awk
+or
+.I Perl
+script, or a C program.
+.PP
+Each unit of information is output in a field that is identified
+with a leading character and terminated by a NL (012) (or a NUL
+(000) if the 0 (zero) field identifier character is specified.)
+The data of the field follows immediately after the field identification
+character and extends to the field terminator.
+.PP
+It is possible to think of field output as process and file sets.
+A process set begins with a field whose identifier is `p' (for
+process IDentifier (PID)).
+It extends to the beginning of the next PID field or the beginning
+of the first file set of the process, whichever comes first.
+Included in the process set are fields that identify the command,
+the process group IDentification (PGID) number, the task (thread)
+ID (TID), and the user ID (UID) number or login name.
+.PP
+A file set begins with a field whose identifier is `f' (for
+file descriptor).
+It is followed by lines that describe the file's access mode,
+lock state, type, device, size, offset, inode, protocol, name
+and stream module names.
+It extends to the beginning of the next file or process set,
+whichever comes first.
+.PP
+When the NUL (000) field terminator has been selected with the
+0 (zero) field identifier character,
+.I lsof
+ends each process and file set with a NL (012) character.
+.PP
+.I Lsof
+always produces one field, the PID (`p') field.
+In repeat mode, the marker (`m') is also produced.
+All other fields may be declared optionally in the field identifier
+character list that follows the
+.B \-F
+option.
+When a field selection character identifies an item
+.I lsof
+does not normally list \- e.g., PPID, selected with
+.BR \-R " \-"
+specification of the field character \- e.g., ``\fB\-FR\fP'' \-
+also selects the listing of the item.
+.PP
+.I Lsof
+version from 4.88 to 4.93.2 always produced one more field,
+the file descriptor (`f') field. However,
+.I lsof
+in this version doesn't produce it. This change is for supporting
+the use case that a user needs only the PID field, and doesn't
+need the file descriptor field. Specify `f' explicitly if you
+need the field.
+.PP
+It is entirely possible to select a set of fields that cannot
+easily be parsed \- e.g., if the field descriptor field is not
+selected, it may be difficult to identify file sets.
+To help you avoid this difficulty,
+.I lsof
+supports the
+.B \-F
+option; it selects the output of all fields with NL terminators
+(the
+.B \-F0
+option pair selects the output of all fields with NUL terminators).
+For compatibility reasons neither
+.B \-F
+nor
+.B \-F0
+select the raw device field.
+.PP
+These are the fields that
+.I lsof
+will produce.
+The single character listed first is the field identifier.
+.PP
+.nf
+       a       file access mode
+       c       process command name (all characters from proc or
+               user structure)
+       C       file structure share count
+       d       file's device character code
+       D       file's major/minor device number (0x<hexadecimal>)
+       f       file descriptor
+       F       file structure address (0x<hexadecimal>)
+       G       file flaGs (0x<hexadecimal>; names if \fB+fg\fP follows)
+       g       process group ID
+       i       file's inode number
+       K       tasK ID
+       k       link count
+       l       file's lock status
+       L       process login name
+       m       marker between repeated output (always selected in repeat mode)
+       M       the task comMand name
+       n       file name, comment, Internet address
+       N       node identifier (ox<hexadecimal>
+       o       file's offset (0t<decimal> or 0x<hexadecimal>, see \fB\-o\fP \fIo\fP)
+       p       process ID (always selected)
+       P       protocol name
+       r       raw device number (0x<hexadecimal>)
+       R       parent process ID
+       s       file's size (decimal)
+       S       file's stream identification
+       t       file's type
+       T       TCP/TPI information, identified by prefixes (the
+               `=' is part of the prefix):
+                   QR=<read queue size>
+                   QS=<send queue size>
+                   SO=<socket options and values> (not all dialects)
+                   SS=<socket states> (not all dialects)
+                   ST=<connection state>
+                   TF=<TCP flags and values> (not all dialects)
+                   WR=<window read size>  (not all dialects)
+                   WW=<window write size>  (not all dialects)
+               (TCP/TPI information isn't reported for all supported
+                 UNIX dialects. The \fB\-h\fP or \fB\-?\fP help output for the
+                 \fB\-T\fP option will show what TCP/TPI reporting can be
+                 requested.)
+       u       process user ID
+       z       Solaris 10 and higher zone name
+       Z       SELinux security context (inhibited when SELinux is disabled)
+       0       use NUL field terminator character in place of NL
+       1\-9    dialect\-specific field identifiers (The output
+               of \fB\-F?\fP identifies the information to be found
+               in dialect\-specific fields.)
+.fi
+.PP
+You can get on\-line help information on these characters and their
+descriptions by specifying the
+.B \-F?
+option pair.
+(Escape the `?' character as your shell requires.)
+Additional information on field content can be found in the
+.B OUTPUT
+section.
+.PP
+As an example, ``\fB\-F pcfn\fP'' will select the process ID (`p'),
+command name (`c'), file descriptor (`f') and file name (`n')
+fields with an NL field terminator character; ``\fB\-F pcfn0\fP''
+selects the same output with a NUL (000) field terminator character.
+.PP
+.I Lsof
+doesn't produce all fields for every process or file set, only
+those that are available.
+Some fields are mutually exclusive: file device characters and
+file major/minor device numbers; file inode number and protocol
+name; file name and stream identification; file size and offset.
+One or the other member of these mutually exclusive sets will appear
+in field output, but not both.
+.PP
+Normally
+.I lsof
+ends each field with a NL (012) character.
+The
+0 (zero) field identifier character may be specified to change the
+field terminator character
+to a NUL (000).
+A NUL terminator may be easier to process with
+.I xargs (1),
+for example, or with programs whose quoting mechanisms may not
+easily cope with the range of characters in the field output.
+When the NUL field terminator is in use,
+.I lsof
+ends each process and file set with a NL (012).
+.PP
+Three aids to producing programs that can process
+.I lsof
+field output are included in the
+.I lsof
+distribution.
+The first is a C header file,
+.IR lsof_fields.h ,
+that contains symbols for the field identification characters, indexes for
+storing them in a table, and explanation strings that may be compiled into
+programs.
+.I Lsof
+uses this header file.
+.PP
+The second aid is a set of sample scripts that process field output,
+written in
+.IR awk ,
+.I Perl
+4, and
+.I Perl
+5.
+They're located in the
+.I scripts
+subdirectory of the
+.I lsof
+distribution.
+.PP
+The third aid is the C library used for the
+.I lsof
+test suite.
+The test suite is written in C and uses field output to validate
+the correct operation of
+.IR lsof .
+The library can be found in the
+.I tests/LTlib.c
+file of the
+.I lsof
+distribution.
+The library uses the first aid, the
+.I lsof_fields.h
+header file.
+.SH "BLOCKS AND TIMEOUTS"
+.I Lsof
+can be blocked by some kernel functions that it uses \-
+.IR lstat (2),
+.IR readlink (2),
+and
+.IR stat (2).
+These functions are stalled in the kernel, for example, when the
+hosts where mounted NFS file systems reside become inaccessible.
+.PP
+.I Lsof
+attempts to break these blocks with timers and child processes,
+but the techniques are not wholly reliable.
+When
+.I lsof
+does manage to break a block, it will report the break with an error
+message.
+The messages may be suppressed with the
+.B \-t
+and
+.B \-w
+options.
+.PP
+The default timeout value may be displayed with the
+.B \-h
+or
+.B \-?
+option, and it may be changed with the
+.BI \-S " [t]"
+option.
+The minimum for
+.I t
+is two seconds, but you should avoid small values, since slow system
+responsiveness can cause short timeouts to expire unexpectedly and
+perhaps stop
+.I lsof
+before it can produce any output.
+.PP
+When
+.I lsof
+has to break a block during its access of mounted file system
+information, it normally continues, although with less information
+available to display about open files.
+.PP
+.I Lsof
+can also be directed to avoid the protection of timers and child processes
+when using the kernel functions that might block by specifying the
+.B \-O
+option.
+While this will allow
+.I lsof
+to start up with less overhead, it exposes
+.I lsof
+completely to the kernel situations that might block it.
+Use this option cautiously.
+.SH "AVOIDING KERNEL BLOCKS"
+.PP
+You can use the
+.B \-b
+option to tell
+.I lsof
+to avoid using kernel functions that would block.
+Some cautions apply.
+.PP
+First, using this option usually requires that your system supply
+alternate device numbers in place of the device numbers that
+.I lsof
+would normally obtain with the
+.IR lstat (2)
+and
+.IR stat (2)
+kernel functions.
+See the
+.B "ALTERNATE DEVICE NUMBERS"
+section for more information on alternate device numbers.
+.PP
+Second, you can't specify
+.I names
+for
+.I lsof
+to locate unless they're file system names.
+This is because
+.I lsof
+needs to know the device and inode numbers of files listed with
+.I names
+in the
+.I lsof
+options, and the
+.B \-b
+option prevents
+.I lsof
+from obtaining them.
+Moreover, since
+.I lsof
+only has device numbers for the file systems that have alternates,
+its ability to locate files on file systems depends completely on the
+availability and accuracy of the alternates.
+If no alternates are available, or if they're incorrect,
+.I lsof
+won't be able to locate files on the named file systems.
+.PP
+Third, if the names of your file system directories that
+.I lsof
+obtains from your system's mount table are symbolic links,
+.I lsof
+won't be able to resolve the links.
+This is because the
+.B \-b
+option causes
+.I lsof
+to avoid the kernel
+.IR readlink (2)
+function it uses to resolve symbolic links.
+.PP
+Finally, using the
+.B \-b
+option causes
+.I lsof
+to issue warning messages when it needs to use the kernel functions
+that the
+.B \-b
+option directs it to avoid.
+You can suppress these messages by specifying the
+.B \-w
+option, but if you do, you won't see the alternate device numbers
+reported in the warning messages.
+.SH "ALTERNATE DEVICE NUMBERS"
+.PP
+On some dialects, when
+.I lsof
+has to break a block because it can't get information about a
+mounted file system via the
+.IR lstat (2)
+and
+.IR stat (2)
+kernel functions, or because you specified the
+.B \-b
+option,
+.I lsof
+can obtain some of the information it needs \- the device number and
+possibly the file system type \- from the system mount table.
+When that is possible,
+.I lsof
+will report the device number it obtained.
+(You can suppress the report by specifying the
+.B \-w
+option.)
+.PP
+You can assist this process if your mount table is supported with an
+.I /etc/mtab
+or
+.I /etc/mnttab
+file that contains an options field by adding a ``dev=xxxx'' field for
+mount points that do not have one in their options strings.
+Note: you must be able to edit the file \- i.e., some mount tables
+like recent Solaris /etc/mnttab or Linux /proc/mounts are read\-only
+and can't be modified.
+.PP
+You may also be able to supply device numbers using the
+.B +m
+and
+.BI +m " m"
+options, provided they are supported by your dialect.
+Check the output of
+.I lsof's
+.B \-h
+or
+.B \-?
+options to see if the
+.B +m
+and
+.BI +m " m"
+options are available.
+.PP
+The ``xxxx'' portion of the field is the hexadecimal value
+of the file system's device number.
+(Consult the
+.I st_dev
+field of the output of the
+.IR lstat (2)
+and
+.IR stat (2)
+functions for the appropriate values for your file systems.)
+Here's an example from a Sun Solaris 2.6
+.I /etc/mnttab
+for a file system remotely mounted via NFS:
+.PP
+.nf
+       nfs  ignore,noquota,dev=2a40001
+.fi
+.PP
+There's an advantage to having ``dev=xxxx'' entries in your mount
+table file, especially for file systems that are mounted from remote
+NFS servers.
+When a remote server crashes and you want to identify its users by running
+.I lsof
+on one of its clients,
+.I lsof
+probably won't be able to get output from the
+.IR lstat (2)
+and
+.IR stat (2)
+functions for the file system.
+If it can obtain the file system's device number from the mount table,
+it will be able to display the files open on the crashed NFS server.
+.PP
+Some dialects that do not use an ASCII
+.I /etc/mtab
+or
+.I /etc/mnttab
+file for the mount table may still provide an alternative device number
+in their internal mount tables.
+This includes AIX, Apple Darwin, FreeBSD, NetBSD, OpenBSD, and Tru64 UNIX.
+.I Lsof
+knows how to obtain the alternative device number for these dialects
+and uses it when its attempt to
+.IR lstat (2)
+or
+.IR stat (2)
+the file system is blocked.
+.PP
+If you're not sure your dialect supplies alternate device numbers
+for file systems from its mount table, use this
+.I lsof
+incantation to see if it reports any alternate device numbers:
+.PP
+.IP
+lsof \-b
+.PP
+Look for standard error file warning messages that
+begin ``assuming "dev=xxxx" from ...''.
+.SH "KERNEL NAME CACHE"
+.PP
+.I Lsof
+is able to examine the kernel's name cache or use other kernel
+facilities (e.g., the ADVFS 4.x tag_to_path() function under
+Tru64 UNIX) on some dialects for most file system types,
+excluding AFS, and extract recently used path name components from it.
+(AFS file system path lookups don't use the kernel's name cache; some
+Solaris VxFS file system operations apparently don't use it, either.)
+.PP
+.I Lsof
+reports the complete paths it finds in the NAME column.
+If
+.I lsof
+can't report all components in a path, it reports in the NAME column
+the file system name, followed by a space, two `\-' characters, another
+space, and the name components it has located, separated by
+the `/' character.
+.PP
+When
+.I lsof
+is run in repeat mode \- i.e., with the
+.B \-r
+option specified \- the extent to which it can report path name
+components for the same file may vary from cycle to cycle.
+That's because other running processes can cause the kernel to
+remove entries from its name cache and replace them with others.
+.PP
+.I Lsof's
+use of the kernel name cache to identify the paths of files
+can lead it to report incorrect components under some circumstances.
+This can happen when the kernel name cache uses device and node
+number as a key (e.g., SCO OpenServer) and a key on a rapidly
+changing file system is reused.
+If the UNIX dialect's kernel doesn't purge the name cache entry for
+a file when it is unlinked,
+.I lsof
+may find a reference to the wrong entry in the cache.
+The
+.I lsof
+FAQ (The \fBFAQ\fP section gives its location.)
+has more information on this situation.
+.PP
+.I Lsof
+can report path name components for these dialects:
+.PP
+.nf
+       FreeBSD
+       HP\-UX
+       Linux
+       NetBSD
+       SCO OpenServer
+       SCO|Caldera UnixWare
+       Solaris
+       Tru64 UNIX
+.fi
+.PP
+.I Lsof
+can't report path name components for these dialects:
+.PP
+.nf
+       AIX
+       OpenBSD
+.fi
+.PP
+If you want to know why
+.I lsof
+can't report path name components for some dialects, see the
+.I lsof
+FAQ (The \fBFAQ\fP section gives its location.)
+.SH "DEVICE CACHE FILE"
+.PP
+Examining all members of the
+.I /dev
+(or
+.IR /devices )
+node tree with
+.IR stat (2)
+functions can be time consuming.
+What's more, the information that
+.I lsof
+needs \- device number, inode number, and path \- rarely changes.
+.PP
+Consequently,
+.I lsof
+normally maintains an ASCII text file of cached
+.I /dev
+(or
+.IR /devices )
+information (exception: the /proc\-based Linux
+.I lsof
+where it's not needed.)
+The local system administrator who builds
+.I lsof
+can control the way the device cache file path is formed, selecting
+from these options:
+.PP
+.nf
+       Path from the \fB\-D\fP option;
+       Path from an environment variable;
+       System\-wide path;
+       Personal path (the default);
+       Personal path, modified by an environment variable.
+.fi
+.PP
+Consult the output of the
+.BR \-h ,
+.B \-D? ,
+or
+.B \-?
+help options for the current state of device cache support.
+The help output lists the default read\-mode device cache file path that
+is in effect for the current invocation of
+.IR lsof .
+The
+.B \-D?
+option output lists the read\-only and write device cache file paths,
+the names of any applicable environment variables, and the personal
+device cache path format.
+.PP
+.I Lsof
+can detect that the current device cache file has been accidentally
+or maliciously modified by integrity checks, including the computation
+and verification of a sixteen bit Cyclic Redundancy Check (CRC) sum on
+the file's contents.
+When
+.I lsof
+senses something wrong with the file, it issues a warning and attempts
+to remove the current cache file and create a new copy, but only to
+a path that the process can legitimately write.
+.PP
+The path from which a
+.I lsof
+process may attempt to read a device cache file may not be the same
+as the path to which it can legitimately write.
+Thus when
+.I lsof
+senses that it needs to update the device cache file, it may
+choose a different path for writing it from the path from which
+it read an incorrect or outdated version.
+.PP
+If available, the
+.B \-Dr
+option will inhibit the writing of a new device cache file.
+(It's always available when specified without a path name argument.)
+.PP
+When a new device is added to the system, the device cache file may
+need to be recreated.
+Since
+.I lsof
+compares the mtime of the device cache file with the mtime and ctime
+of the
+.I /dev
+(or
+.IR /devices )
+directory, it usually detects that a new device has been added;
+in that case
+.I lsof
+issues a warning message and attempts to rebuild the device cache file.
+.PP
+Whenever
+.I lsof
+writes a device cache file, it sets its ownership to the real UID
+of the executing process, and its permission modes to 0600, this
+restricting its reading and writing to the file's owner.
+.SH "LSOF PERMISSIONS THAT AFFECT DEVICE CACHE FILE ACCESS"
+.PP
+Two permissions of the
+.I lsof
+executable affect its ability to access device cache files.
+The permissions are set by the local system administrator when
+.I lsof
+is installed.
+.PP
+The first and rarer permission is setuid-root.
+It comes into effect when
+.I lsof
+is executed; its effective UID is then
+root, while its real (i.e., that of the logged\-on user) UID is not.
+The
+.I lsof
+distribution recommends that versions for these dialects run setuid\-root.
+.PP
+.nf
+       HP-UX 11.11 and 11.23
+       Linux
+.fi
+.PP
+The second and more common permission is setgid.
+It comes into effect when the effective group IDentification number (GID)
+of the
+.I lsof
+process is set to one that can access kernel memory devices \-
+e.g., ``kmem'', ``sys'', or ``system''.
+.PP
+An
+.I lsof
+process that has setgid permission usually surrenders the permission
+after it has accessed the kernel memory devices.
+When it does that,
+.I lsof
+can allow more liberal device cache path formations.
+The
+.I lsof
+distribution recommends that versions for these dialects run setgid
+and be allowed to surrender setgid permission.
+.PP
+.nf
+       AIX 5.[12] and 5.3-ML1
+       Apple Darwin 7.x Power Macintosh systems
+       FreeBSD 4.x, 4.1x, 5.x and [6789].x for x86-based systems
+       FreeBSD 5.x, [6789].x and 1[012].8for Alpha, AMD64 and Sparc64
+           based systems
+       HP\-UX 11.00
+       NetBSD 1.[456], 2.x and 3.x for Alpha, x86, and SPARC-based
+           systems
+       OpenBSD 2.[89] and 3.[0\-9] for x86-based systems
+       SCO OpenServer Release 5.0.6 for x86-based systems
+       SCO|Caldera UnixWare 7.1.4 for x86-based systems
+       Solaris 2.6, 8, 9 and 10
+       Tru64 UNIX 5.1
+.fi
+.PP
+(Note:
+.I lsof
+for AIX 5L and above needs setuid\-root permission if its
+.B \-X
+option is used.)
+.PP
+.I Lsof
+for these dialects does not support a device cache, so the permissions
+given to the executable don't apply to the device cache file.
+.PP
+.nf
+       Linux
+.fi
+.SH "DEVICE CACHE FILE PATH FROM THE \-D OPTION"
+.PP
+The
+.B \-D
+option provides limited means for specifying the device cache file path.
+Its
+.B ?
+function will report the read\-only and write device cache file paths that
+.I lsof
+will use.
+.PP
+When the
+.B \-D
+.BR b ,
+.BR r ,
+and
+.B u
+functions are available, you can use them to request that the cache file be
+built in a specific location (\fBb\fR[\fIpath\fR]);
+read but not rebuilt (\fBr\fR[\fIpath\fR]);
+or read and rebuilt (\fBu\fR[\fIpath\fR]).
+The
+.BR b ,
+.BR r ,
+and
+.B u
+functions are restricted under some conditions.
+They are restricted when the
+.I lsof
+process is setuid\-root.
+The path specified with the
+.B r
+function is always read\-only, even
+when it is available.
+.PP
+The
+.BR b ,
+.BR r ,
+and
+.B u
+functions are also restricted when the
+.I lsof
+process runs setgid and
+.I lsof
+doesn't surrender the setgid permission.
+(See the
+.B "LSOF PERMISSIONS THAT AFFECT DEVICE CACHE FILE ACCESS"
+section for a list of implementations that normally don't surrender
+their setgid permission.)
+.PP
+A further
+.B \-D
+function,
+.B i
+(for ignore), is always available.
+.PP
+When available, the
+.B b
+function tells
+.I lsof
+to read device information from the kernel with the
+.IR stat (2)
+function and build a device cache file at the indicated path.
+.PP
+When available, the
+.B r
+function tells
+.I lsof
+to read the device cache file, but not update it.
+When a path argument accompanies
+.BR \-Dr ,
+it names the device cache file path.
+The
+.B r
+function is always available when it is specified without a
+path name argument.
+If
+.I lsof
+is not running setuid\-root and surrenders its setgid permission,
+a path name argument may accompany the
+.B r
+function.
+.PP
+When available, the
+.B u
+function tells
+.I lsof
+to attempt to read and use the device cache file.
+If it can't read the file, or if it finds the contents of the
+file incorrect or outdated, it will read information from the kernel,
+and attempt to write an updated version of the device cache file,
+but only to a path it considers legitimate for the
+.I lsof
+process effective and real UIDs.
+.SH "DEVICE CACHE PATH FROM AN ENVIRONMENT VARIABLE"
+.PP
+.I Lsof's
+second choice for the device cache file is the contents of the
+LSOFDEVCACHE environment variable.
+It avoids this choice if the
+.I lsof
+process is setuid\-root, or the real UID of the process is root.
+.PP
+A further restriction applies to a device cache file path taken from
+the LSOFDEVCACHE environment variable:
+.I lsof
+will not write a device cache file to the path if the
+.I lsof
+process doesn't surrender its setgid permission.
+(See the
+.B "LSOF PERMISSIONS THAT AFFECT DEVICE CACHE FILE ACCESS"
+section for information on implementations that don't surrender
+their setgid permission.)
+.PP
+The local system administrator can disable the use of the LSOFDEVCACHE
+environment variable or change its name when building
+.IR lsof .
+Consult the output of
+.B \-D?
+for the environment variable's name.
+.SH "SYSTEM-WIDE DEVICE CACHE PATH"
+.PP
+The local system administrator may choose to have a system\-wide
+device cache file when building
+.IR lsof .
+That file will generally be constructed by a special system administration
+procedure when the system is booted or when the contents of
+.I /dev
+or
+.IR /devices )
+changes.
+If defined, it is
+.I lsof's
+third device cache file path choice.
+.PP
+You can tell that a system\-wide device cache file is in effect
+for your local installation by examining the
+.I lsof
+help option output \- i.e., the output from the
+.B \-h
+or
+.B \-?
+option.
+.PP
+.I Lsof
+will never write to the system\-wide device cache file path by
+default.
+It must be explicitly named with a
+.B \-D
+function in a root\-owned procedure.
+Once the file has been written, the procedure must change its permission
+modes to 0644 (owner\-read and owner\-write, group\-read, and other\-read).
+.SH "PERSONAL DEVICE CACHE PATH (DEFAULT)"
+.PP
+The default device cache file path of the
+.I lsof
+distribution is one recorded in the home directory of the real UID
+that executes
+.IR lsof .
+Added to the home directory is a second path component of the form
+.IR .lsof_hostname .
+.PP
+This is
+.I lsof's
+fourth device cache file path choice, and is
+usually the default.
+If a system\-wide device cache file path was defined when
+.I lsof
+was built,
+this fourth choice will be applied when
+.I lsof
+can't find the system\-wide device cache file.
+This is the
+.B only
+time
+.I lsof
+uses two paths when reading the device cache file.
+.PP
+The
+.I hostname
+part of the second component is the base
+name of the executing host, as returned by
+.IR gethostname (2).
+The base name is defined to be the characters preceding the first `.'
+in the
+.IR gethostname (2)
+output, or all the
+.IR gethostname (2)
+output if it contains no `.'.
+.PP
+The device cache file belongs to the user ID and is readable and
+writable by the user ID alone \- i.e., its modes are 0600.
+Each distinct real user ID on a given host that executes
+.I lsof
+has a distinct device cache file.
+The
+.I hostname
+part of the path distinguishes device cache files in an NFS\-mounted
+home directory into which device cache files are written from
+several different hosts.
+.PP
+The personal device cache file path formed by this method represents
+a device cache file that
+.I lsof
+will attempt to read, and will attempt to write should it not
+exist or should its contents be incorrect or outdated.
+.PP
+The
+.B \-Dr
+option without a path name argument will inhibit the writing of a new
+device cache file.
+.PP
+The
+.B \-D?
+option will list the format specification for constructing the
+personal device cache file.
+The conversions used in the format specification are described in the
+.I 00DCACHE
+file of the
+.I lsof
+distribution.
+.SH "MODIFIED PERSONAL DEVICE CACHE PATH"
+.PP
+If this option is defined by the local system administrator when
+.I lsof
+is built, the LSOFPERSDCPATH environment variable contents may
+be used to add a component of the personal device cache file path.
+.PP
+The LSOFPERSDCPATH variable contents are inserted in the path at the
+place marked by the local system administrator with the ``%p''
+conversion in the HASPERSDC format specification of the dialect's
+.I machine.h
+header file.
+(It's placed right after the home directory in the default
+.I lsof
+distribution.)
+.PP
+Thus, for example, if LSOFPERSDCPATH contains ``LSOF'', the home
+directory is ``/Homes/abe'', the host name is ``lsof.itap.purdue.edu'',
+and the HASPERSDC format is the default (``%h/%p.lsof_%L''), the
+modified personal device cache file path is:
+.PP
+.nf
+       /Homes/abe/LSOF/.lsof_vic
+.fi
+.PP
+The LSOFPERSDCPATH environment variable is ignored when the
+.I lsof
+process is setuid\-root or when the real UID of the process is root.
+.PP
+.I Lsof
+will not write to a modified personal device cache file path if the
+.I lsof
+process doesn't surrender setgid permission.
+(See the
+.B "LSOF PERMISSIONS THAT AFFECT DEVICE CACHE FILE ACCESS"
+section for a list of implementations that normally don't surrender
+their setgid permission.)
+.PP
+If, for example, you want to create a sub\-directory of personal
+device cache file paths by using the LSOFPERSDCPATH environment
+variable to name it, and
+.I lsof
+doesn't surrender its setgid permission, you will have to allow
+.I lsof
+to create device cache files at the standard personal path and
+move them to your subdirectory with shell commands.
+.PP
+The local system administrator may: disable this option when
+.I lsof
+is built; change the name of the environment variable from
+LSOFPERSDCPATH to something else; change the HASPERSDC
+format to include the personal path component in another place;
+or exclude the personal path component entirely.
+Consult the output of the
+.B \-D?
+option for the environment variable's name and the HASPERSDC
+format specification.
+.SH DIAGNOSTICS
+Errors are identified with messages on the standard error file.
+.PP
+.I Lsof
+returns a one (1) if any error was detected, including the failure to
+locate command names, file names, Internet addresses or files, login
+names, NFS files, PIDs, PGIDs, or UIDs it was asked to list.
+If the
+.B \-V
+option is specified,
+.I lsof
+will indicate the search items it failed to list.
+If the
+.B \-Q
+option is specified,
+.I lsof
+will ignore any search item failures and only return an error if
+something unusual and unrecoverable happened.
+.PP
+It returns a zero (0) if no errors were detected and if either the
+.B \-Q
+option was specified or it was able to list some information about
+all the specified search arguments.
+.PP
+.PP
+When
+.I lsof
+cannot open access to
+.I /dev
+(or
+.IR /devices )
+or one of its subdirectories, or get information on a file in them with
+.IR stat (2),
+it issues a warning message and continues.
+That
+.I lsof
+will issue warning messages about inaccessible files in
+.I /dev
+(or
+.IR /devices )
+is indicated in its help output \- requested with the
+.B \-h
+or
+>B \-?
+options \-  with the message:
+.PP
+.nf
+       Inaccessible /dev warnings are enabled.
+.fi
+.PP
+The warning message may be suppressed with the
+.B \-w
+option.
+It may also have been suppressed by the system administrator when
+.I lsof
+was compiled by the setting of the WARNDEVACCESS definition.
+In this case, the output from the help options will include the message:
+.PP
+.nf
+       Inaccessible /dev warnings are disabled.
+.fi
+.PP
+Inaccessible device warning messages usually disappear after
+.I lsof
+has created a working device cache file.
+.SH EXAMPLES
+For a more extensive set of examples, documented more fully, see the
+.I 00QUICKSTART
+file of the
+.I lsof
+distribution.
+.PP
+To list all open files, use:
+.IP
+lsof
+.PP
+To list all open Internet, x.25 (HP\-UX), and UNIX domain files, use:
+.IP
+lsof \-i \-U
+.PP
+To list all open IPv4 network files in use by the process whose PID is
+1234, use:
+.IP
+lsof \-i 4 \-a \-p 1234
+.PP
+If it's okay for PID 1234 to not exist, or for PID 1234 to not have any
+open IPv4 network files, add
+.B \-Q
+:
+.IP
+lsof \-Q \-i 4 \-a \-p 1234
+.PP
+Presuming the UNIX dialect supports IPv6, to list only open IPv6
+network files, use:
+.IP
+lsof \-i 6
+.PP
+To list all files using any protocol on ports 513, 514, or 515 of host
+wonderland.cc.purdue.edu, use:
+.IP
+lsof \-i @wonderland.cc.purdue.edu:513\-515
+.PP
+To list all files using any protocol on any port of mace.cc.purdue.edu
+(cc.purdue.edu is the default domain), use:
+.IP
+lsof \-i @mace
+.PP
+To list all open files for login name ``abe'', or user ID 1234, or
+process 456, or process 123, or process 789, use:
+.IP
+lsof \-p 456,123,789 \-u 1234,abe
+.PP
+To list all open files on device /dev/hd4, use:
+.IP
+lsof /dev/hd4
+.PP
+To find the process that has /u/abe/foo open without worrying if
+there are none, use:
+.IP
+lsof \-Q /u/abe/foo
+.PP
+To take action only if a process has /u/abe/foo open, use:
+.IP
+lsof /u/abe/foo \&\& echo "still in use"
+.PP
+To send a SIGHUP to the processes that have /u/abe/bar open, use:
+.IP
+kill \-HUP `lsof \-t /u/abe/bar`
+.PP
+To find any open file, including an open UNIX domain socket file,
+with the name
+.IR /dev/log ,
+use:
+.IP
+lsof /dev/log
+.PP
+To find processes with open files on the NFS file system named
+.I /nfs/mount/point
+whose server is inaccessible, and presuming your mount table supplies
+the device number for
+.IR /nfs/mount/point ,
+use:
+.IP
+lsof \-b /nfs/mount/point
+.PP
+To do the preceding search with warning messages suppressed, use:
+.IP
+lsof \-bw /nfs/mount/point
+.PP
+To ignore the device cache file, use:
+.IP
+lsof \-Di
+.PP
+To obtain PID and command name field output for each process, file
+descriptor, file device number, and file inode number for each file
+of each process, use:
+.IP
+lsof \-FpcfDi
+.PP
+To list the files at descriptors 1 and 3 of every process running the
+.I lsof
+command for login ID ``abe'' every 10 seconds, use:
+.IP
+lsof \-c lsof \-a \-d 1 \-d 3 \-u abe \-r10
+.PP
+To list the current working directory of processes running a command that
+is exactly four characters long and has an 'o' or 'O' in character three,
+use this regular expression form of the
+.BI \-c " c"
+option:
+.IP
+lsof \-c /^..o.$/i \-a \-d cwd
+.PP
+To find an IP version 4 socket file by its associated numeric dot\-form
+address, use:
+.IP
+lsof \-i@128.210.15.17
+.PP
+To find an IP version 6 socket file (when the UNIX dialect supports
+IPv6) by its associated numeric colon\-form address, use:
+.IP
+lsof \-i@[0:1:2:3:4:5:6:7]
+.PP
+To find an IP version 6 socket file (when the UNIX dialect supports
+IPv6) by an associated numeric colon\-form address that has a run of
+zeroes in it \- e.g., the loop\-back address \- use:
+.IP
+lsof \-i@[::1]
+.PP
+To obtain a repeat mode marker line that contains the current time, use:
+.IP
+lsof \-rm====%T====
+.PP
+To add spaces to the previous marker line, use:
+.IP
+lsof \-r "m==== %T ===="
+.SH BUGS
+Since
+.I lsof
+reads kernel memory in its search for open files, rapid changes in kernel
+memory may produce unpredictable results.
+.PP
+When a file has multiple record locks, the lock status character
+(following the file descriptor) is derived from a test of the first
+lock structure, not from any combination of the individual record
+locks that might be described by multiple lock structures.
+.PP
+.I Lsof
+can't search for files with restrictive access permissions by
+.I name
+unless it is installed with root set-UID permission.
+Otherwise it is limited to searching for files to which its user
+or its set-GID group (if any) has access permission.
+.PP
+The display of the destination address of a raw socket (e.g., for
+.IR ping )
+depends on the UNIX operating system.
+Some dialects store the destination address in the raw socket's protocol
+control block, some do not.
+.PP
+.I Lsof
+can't always represent Solaris device numbers in the same way that
+.IR ls (1)
+does.
+For example, the major and minor device numbers that the
+.IR lstat (2)
+and
+.IR stat (2)
+functions report for the directory on which CD-ROM files are mounted
+(typically
+.IR /cdrom )
+are not the same as the ones that it reports for the device on which
+CD-ROM files are mounted (typically
+.IR /dev/sr0 ).
+(\fILsof\fP reports the directory numbers.)
+.PP
+The support for
+.I /proc
+file systems is available only for BSD and Tru64 UNIX dialects, Linux, and
+dialects derived from SYSV R4 \- e.g., FreeBSD, NetBSD, OpenBSD, Solaris,
+UnixWare.
+.PP
+Some
+.I /proc
+file items \- device number, inode number, and file size \-
+are unavailable in some dialects.
+Searching for files in a
+.I /proc
+file system may require that the full path name be specified.
+.PP
+No text (\fBtxt\fP) file descriptors are displayed for Linux
+processes.
+All entries for files other than the current working directory,
+the root directory, and numerical file descriptors are labeled
+.B mem
+descriptors.
+.PP
+.I Lsof
+can't search for Tru64 UNIX named pipes by name, because their kernel
+implementation of lstat(2) returns an improper device number for a
+named pipe.
+.PP
+.I Lsof
+can't report fully or correctly on HP\-UX 9.01, 10.20, and 11.00 locks
+because of insufficient access to kernel data or errors in the
+kernel data.
+See the
+.I lsof
+FAQ (The \fBFAQ\fP section gives its location.)
+for details.
+.PP
+The AIX SMT file type is a fabrication.
+It's made up for file structures whose type (15) isn't defined in the AIX
+.I /usr/include/sys/file.h
+header file.
+One way to create such file structures is to run X clients with the DISPLAY
+variable set to ``:0.0''.
+.PP
+The
+.BI +|\-f [cfn]
+option is not supported under /proc\-based Linux
+.IR lsof ,
+because it doesn't read kernel structures from kernel memory.
+.SH ENVIRONMENT
+.I Lsof
+may access these environment variables.
+.TP \w'LSOFPERSDCPATH'u+4
+LANG
+defines a language locale.
+See
+.IR setlocale (3)
+for the names of other variables that can be used in place
+of LANG \- e.g., LC_ALL, LC_TYPE, etc.
+.TP
+LSOFDEVCACHE
+defines the path to a device cache file.
+See the
+.B "DEVICE CACHE PATH FROM AN ENVIRONMENT VARIABLE"
+section for more information.
+.TP
+LSOFPERSDCPATH
+defines the middle component of a modified personal device cache
+file path.
+See the
+.B "MODIFIED PERSONAL DEVICE CACHE PATH"
+section for more information.
+.SH FAQ
+Frequently-asked questions and their answers (an FAQ) are
+available in the
+.I 00FAQ
+file of the
+.I lsof
+distribution.
+.PP
+That latest version of the file is found at:
+.IP
+https://github.com/lsof\-org/lsof/blob/master/00FAQ
+.SH FILES
+.TP \w'.lsof_hostname'u+4
+.I /dev/kmem
+kernel virtual memory device
+.TP
+.I /dev/mem
+physical memory device
+.TP
+.I /dev/swap
+system paging device
+.TP
+.I .lsof_hostname
+.I lsof's
+device cache file
+(The suffix,
+.IR hostname ,
+is the first component of the host's name returned by
+.IR gethostname (2).)
+.SH AUTHORS
+.I Lsof
+was written by Victor A.\&Abell <abe@purdue.edu> of Purdue University.
+Since version 4.93.0, the lsof\-org team at GitHub maintains lsof.
+Many others have contributed to
+.IR lsof .
+They're listed in the
+.I 00CREDITS
+file of the
+.I lsof
+distribution.
+.SH DISTRIBUTION
+The latest distribution of
+.I lsof
+is available at
+.IP
+https://github.com/lsof\-org/lsof/releases
+.SH SEE ALSO
+.PP
+Not all the following manual pages may exist in every UNIX
+dialect to which
+.I lsof
+has been ported.
+.PP
+access(2),
+awk(1),
+crash(1),
+fattach(3C),
+ff(1),
+fstat(8),
+fuser(1),
+gethostname(2),
+isprint(3),
+kill(1),
+localtime(3),
+lstat(2),
+modload(8),
+mount(8),
+netstat(1),
+ofiles(8L),
+open(2),
+perl(1),
+ps(1),
+readlink(2),
+setlocale(3),
+stat(2),
+strftime(3),
+time(2),
+uname(1).
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..fbe28fa
--- /dev/null
@@ -0,0 +1,224 @@
+# liblsof
+liblsof_la_SOURCES = lib/ckkv.c lib/cvfs.c lib/dvch.c lib/fino.c lib/isfn.c lib/lkud.c lib/lsof.c lib/misc.c lib/node.c lib/pdvn.c lib/prfp.c lib/print.c lib/proc.c lib/ptti.c lib/rdev.c lib/rnmt.c lib/rmnt.c lib/rnam.c lib/rnch.c lib/rnmh.c
+liblsof_la_SOURCES += lib/common.h lib/proto.h lib/hash.h
+
+if INSTALL_LIBLSOF
+lib_LTLIBRARIES = liblsof.la
+include_HEADERS = include/lsof.h include/lsof_fields.h
+else
+noinst_LTLIBRARIES = liblsof.la
+endif
+
+# Hide internal functions
+AM_CFLAGS = -fvisibility=hidden
+
+DIALECT_ROOT = $(top_srcdir)/lib/dialects
+DIALECT_PATH = $(DIALECT_ROOT)/$(LSOF_DIALECT_DIR)
+
+# Dialect specific sources
+if LINUX
+liblsof_la_SOURCES += lib/dialects/linux/dfile.c \
+               lib/dialects/linux/dmnt.c \
+               lib/dialects/linux/dnode.c \
+               lib/dialects/linux/dproc.c \
+               lib/dialects/linux/dsock.c \
+               lib/dialects/linux/dstore.c \
+               lib/dialects/linux/dlsof.h \
+               lib/dialects/linux/dproto.h \
+               lib/dialects/linux/machine.h
+endif
+
+if DARWIN
+liblsof_la_SOURCES += lib/dialects/darwin/ddev.c \
+               lib/dialects/darwin/dfile.c \
+               lib/dialects/darwin/dmnt.c \
+               lib/dialects/darwin/dproc.c \
+               lib/dialects/darwin/dsock.c \
+               lib/dialects/darwin/dstore.c \
+               lib/dialects/darwin/dlsof.h \
+               lib/dialects/darwin/dproto.h \
+               lib/dialects/darwin/machine.h
+endif
+
+if FREEBSD
+liblsof_la_SOURCES += lib/dialects/freebsd/dmnt.c \
+               lib/dialects/freebsd/dnode.c \
+               lib/dialects/freebsd/dproc.c \
+               lib/dialects/freebsd/dsock.c \
+               lib/dialects/freebsd/dstore.c \
+               lib/dialects/freebsd/dlsof.h \
+               lib/dialects/freebsd/dproto.h \
+               lib/dialects/freebsd/machine.h
+endif
+
+if NETBSD
+liblsof_la_SOURCES += lib/dialects/netbsd/dmnt.c \
+               lib/dialects/netbsd/dnode.c \
+               lib/dialects/netbsd/dproc.c \
+               lib/dialects/netbsd/dsock.c \
+               lib/dialects/netbsd/dstore.c \
+               lib/dialects/netbsd/dlsof.h \
+               lib/dialects/netbsd/dproto.h \
+               lib/dialects/netbsd/machine.h
+endif
+
+if OPENBSD
+liblsof_la_SOURCES += lib/dialects/openbsd/dfile.c \
+               lib/dialects/openbsd/dmnt.c \
+               lib/dialects/openbsd/dnode.c \
+               lib/dialects/openbsd/dproc.c \
+               lib/dialects/openbsd/dsock.c \
+               lib/dialects/openbsd/dstore.c \
+               lib/dialects/openbsd/dlsof.h \
+               lib/dialects/openbsd/dproto.h \
+               lib/dialects/openbsd/machine.h
+endif
+
+if SOLARIS
+liblsof_la_SOURCES += lib/dialects/sun/ddev.c \
+               lib/dialects/sun/dfile.c \
+               lib/dialects/sun/dmnt.c \
+               lib/dialects/sun/dnode.c \
+               lib/dialects/sun/dproc.c \
+               lib/dialects/sun/dsock.c \
+               lib/dialects/sun/dstore.c \
+               lib/dialects/sun/dlsof.h \
+               lib/dialects/sun/dproto.h \
+               lib/dialects/sun/machine.h
+endif
+
+if AIX
+liblsof_la_SOURCES += lib/dialects/aix/ddev.c \
+               lib/dialects/aix/dfile.c \
+               lib/dialects/aix/dmnt.c \
+               lib/dialects/aix/dnode.c \
+               lib/dialects/aix/dnode2.c \
+               lib/dialects/aix/dproc.c \
+               lib/dialects/aix/dsock.c \
+               lib/dialects/aix/dstore.c \
+               lib/dialects/aix/dlsof.h \
+               lib/dialects/aix/dproto.h \
+               lib/dialects/aix/machine.h
+endif
+
+# Binary
+bin_PROGRAMS = lsof
+
+lsof_SOURCES = src/arg.c src/main.c src/print.c src/ptti.c src/store.c src/usage.c src/util.c
+lsof_SOURCES += src/cli.h
+
+if LINUX
+lsof_SOURCES += src/dialects/linux/dprint.c
+endif
+if DARWIN
+lsof_SOURCES += src/dialects/darwin/dprint.c
+endif
+# TODO: link to dynamic library instead after internal functions are no longer used
+lsof_SOURCES += $(liblsof_la_SOURCES)
+#lsof_LDADD = liblsof.la
+
+liblsof_la_CPPFLAGS = -I$(DIALECT_PATH) -Iautotools -DAUTOTOOLS -I$(top_srcdir)/lib -I$(top_srcdir)/include
+lsof_CPPFLAGS = -I$(DIALECT_PATH) -Iautotools -DAUTOTOOLS -I$(top_srcdir)/lib -I$(top_srcdir)/include -I$(top_srcdir)/src
+
+# Testing scripts
+AM_TESTS_ENVIRONMENT = export LSOF_DIALECT_DIR=$(LSOF_DIALECT_DIR); export LSOF_DIALECT=$(LSOF_DIALECT);
+EXTRA_DIST =
+# Dialect neutral
+DIALECT_NEUTRAL_TESTS = tests/case-00-hello.bash \
+       tests/case-01-version.bash \
+       tests/case-20-exit-status.bash \
+       tests/case-20-fd-only-inclusion.bash \
+       tests/case-20-handle-missing-files.bash \
+       tests/case-20-offset-field.bash \
+       tests/case-20-repeat-count.bash \
+       tests/case-21-exit-Q-status.bash \
+       tests/case-22-empty-process-name.bash
+TESTS = $(DIALECT_NEUTRAL_TESTS)
+EXTRA_DIST += $(DIALECT_NEUTRAL_TESTS) \
+       tests/case-13-classic.bash \
+       tests/case-14-classic-opt.bash \
+       tests/common.bash
+
+# Dialect specific
+check_PROGRAMS =
+
+# Linux
+LINUX_TESTS = lib/dialects/linux/tests/case-10-mqueue.bash \
+       lib/dialects/linux/tests/case-10-ux-socket-state.bash \
+       lib/dialects/linux/tests/case-20-epoll.bash \
+       lib/dialects/linux/tests/case-20-eventfd-endpoint.bash \
+       lib/dialects/linux/tests/case-20-inet6-ffffffff-handling.bash \
+       lib/dialects/linux/tests/case-20-inet6-socket-endpoint.bash \
+       lib/dialects/linux/tests/case-20-inet-socket-endpoint.bash \
+       lib/dialects/linux/tests/case-20-mmap.bash \
+       lib/dialects/linux/tests/case-20-mqueue-endpoint.bash \
+       lib/dialects/linux/tests/case-20-open-flags-cx.bash \
+       lib/dialects/linux/tests/case-20-open-flags-path.bash \
+       lib/dialects/linux/tests/case-20-open-flags-tmpf.bash \
+       lib/dialects/linux/tests/case-20-pidfd-pid.bash \
+       lib/dialects/linux/tests/case-20-pipe-endpoint.bash \
+       lib/dialects/linux/tests/case-20-pipe-no-close-endpoint.bash \
+       lib/dialects/linux/tests/case-20-pty-endpoint.bash \
+       lib/dialects/linux/tests/case-20-ux-socket-endpoint.bash \
+       lib/dialects/linux/tests/case-20-ux-socket-endpoint-unaccepted.bash
+EXTRA_DIST += $(LINUX_TESTS) lib/dialects/linux/tests/Makefile lib/dialects/linux/tests/case-00-linux-hello.bash
+if LINUX
+check_PROGRAMS += lib/dialects/linux/tests/epoll \
+       lib/dialects/linux/tests/eventfd \
+       lib/dialects/linux/tests/mmap \
+       lib/dialects/linux/tests/mq_fork \
+       lib/dialects/linux/tests/mq_open \
+       lib/dialects/linux/tests/open_with_flags \
+       lib/dialects/linux/tests/pidfd \
+       lib/dialects/linux/tests/pipe \
+       lib/dialects/linux/tests/pty \
+       lib/dialects/linux/tests/ux
+lib_dialects_linux_tests_mq_fork_LDADD = -lrt
+lib_dialects_linux_tests_mq_open_LDADD = -lrt
+
+TESTS += $(LINUX_TESTS)
+endif
+
+# Testing programs
+TESTS += tests/LTbasic tests/LTbigf tests/LTdnlc tests/LTlock tests/LTnfs tests/LTnlink tests/LTsock tests/LTszoff tests/LTunix
+
+check_PROGRAMS += tests/LTbasic tests/LTbigf tests/LTdnlc tests/LTlock tests/LTnfs tests/LTnlink tests/LTsock tests/LTszoff tests/LTunix
+tests_LTbasic_SOURCES = tests/LTbasic.c tests/LTlib.c
+tests_LTbasic_CFLAGS = @LSOF_TEST_CFLAGS@ -I$(top_srcdir)/include
+tests_LTbigf_SOURCES = tests/LTbigf.c tests/LTlib.c
+tests_LTbigf_CFLAGS = @LSOF_TEST_CFLAGS@ -I$(top_srcdir)/include
+tests_LTdnlc_SOURCES = tests/LTdnlc.c tests/LTlib.c
+tests_LTdnlc_CFLAGS = @LSOF_TEST_CFLAGS@ -I$(top_srcdir)/include
+tests_LTlock_SOURCES = tests/LTlock.c tests/LTlib.c
+tests_LTlock_CFLAGS = @LSOF_TEST_CFLAGS@ -I$(top_srcdir)/include
+tests_LTnfs_SOURCES = tests/LTnfs.c tests/LTlib.c
+tests_LTnfs_CFLAGS = @LSOF_TEST_CFLAGS@ -I$(top_srcdir)/include
+tests_LTnlink_SOURCES = tests/LTnlink.c tests/LTlib.c
+tests_LTnlink_CFLAGS = @LSOF_TEST_CFLAGS@ -I$(top_srcdir)/include
+tests_LTsock_SOURCES = tests/LTsock.c tests/LTlib.c
+tests_LTsock_CFLAGS = @LSOF_TEST_CFLAGS@ -I$(top_srcdir)/include
+tests_LTszoff_SOURCES = tests/LTszoff.c tests/LTlib.c
+tests_LTszoff_CFLAGS = @LSOF_TEST_CFLAGS@ -I$(top_srcdir)/include
+tests_LTunix_SOURCES = tests/LTunix.c tests/LTlib.c
+tests_LTunix_CFLAGS = @LSOF_TEST_CFLAGS@ -I$(top_srcdir)/include
+
+TESTS += tests/LTbasic2
+check_PROGRAMS += tests/LTbasic2
+tests_LTbasic2_CFLAGS = -I$(top_srcdir)/include
+tests_LTbasic2_LDADD = liblsof.la
+
+# Documentation
+EXTRA_DIST += 00.README.FIRST 00CREDITS 00DCACHE 00DIALECTS 00DIST 00FAQ 00LSOF-L 00MANIFEST 00PORTING 00QUICKSTART 00README 00TEST 00XCONFIG
+# Testing
+EXTRA_DIST += tests/00README tests/TestDB tests/CkTestDB tests/Makefile tests/LsofTest.h check.bash
+
+# Manpages
+lsof.man: Lsof.8 version 00DIALECTS
+       soelim < Lsof.8 > $@
+man8_MANS = lsof.man
+EXTRA_DIST += Lsof.8
+# Fix distcheck error
+clean-local:
+       rm -rf lsof.man
+distclean-local:
+       rm -rf lockf_owner.h lockf.h
diff --git a/NEWS b/NEWS
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/README b/README
new file mode 120000 (symlink)
index 0000000..42061c0
--- /dev/null
+++ b/README
@@ -0,0 +1 @@
+README.md
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..fc64e91
--- /dev/null
+++ b/README.md
@@ -0,0 +1,76 @@
+[![Circle CI](https://circleci.com/gh/lsof-org/lsof.svg?style=svg)](https://circleci.com/gh/lsof-org/lsof)
+[![Cirrus CI](https://img.shields.io/cirrus/github/lsof-org/lsof)](https://cirrus-ci.com/github/lsof-org/lsof)
+[![builds.sr.ht status](https://builds.sr.ht/~jiegec/lsof.svg)](https://builds.sr.ht/~jiegec/lsof?)
+[![Read the Docs](https://readthedocs.org/projects/lsof/badge/?version=latest)](https://lsof.readthedocs.io/en/latest/)
+
+# lsof
+
+[lsof](https://en.wikipedia.org/wiki/Lsof) is a command listing open files.
+
+## How it works:
+
+```
+$ cat > /tmp/LOG &
+cat > /tmp/LOG &
+[1] 18083
+$ lsof -p 18083
+lsof -p 18083
+COMMAND   PID   USER   FD   TYPE DEVICE  SIZE/OFF     NODE NAME
+cat     18083 yamato  cwd    DIR   0,44      1580 43460784 /tmp/lsof
+cat     18083 yamato  rtd    DIR  253,2      4096        2 /
+cat     18083 yamato  txt    REG  253,2     47432   678364 /usr/bin/cat
+cat     18083 yamato  mem    REG  253,2 111950656   681778 /usr/lib/locale/locale-archive
+cat     18083 yamato  mem    REG  253,2   2119256   679775 /usr/lib64/libc-2.27.so
+cat     18083 yamato  mem    REG  253,2    187632   655943 /usr/lib64/ld-2.27.so
+cat     18083 yamato  mem    REG  253,2     26370   662532 /usr/lib64/gconv/gconv-modules.cache
+cat     18083 yamato  mem    REG  253,2      3316  1578981 /usr/lib/locale/en_US.utf8/LC_TIME
+cat     18083 yamato    0u   CHR  136,3       0t0        6 /dev/pts/3
+cat     18083 yamato    1w   REG   0,44         0 54550934 /tmp/LOG
+cat     18083 yamato    2u   CHR  136,3       0t0        6 /dev/pts/3
+```
+
+Read the documentation at [lsof.readthedocs.io](https://lsof.readthedocs.io/)
+
+# lsof-org at GitHub
+
+The lsof-org team at GitHub takes over the maintainership of lsof originally
+developed and maintained by Vic Abell. This repository is for maintaining the
+final source tree of lsof inherited from Vic. "legacy" branch keeps the original
+source tree. We will not introduce any changes to the "legacy" branch. This
+branch is just for reference.
+
+"master" branch is used for maintenance. Bug fixes and enhancements go to
+"master" branch.
+
+lsof had supported many OSes. A term "dialect" represents code for supporting
+OSes. Because of limited resources, we will maintain the part of them. The
+current status of maintenance is as follows:
+
+<dl>
+<dt>FreeBSD</dt>
+<dd>fully maintained and tested on Cirrus CI</dd>
+<dt>Linux</dt>
+<dd>fully maintained, and tested on Circle CI</dd>
+<dt>Darwin</dt>
+<dd>fully maintained, and tested on Circle CI</dd>
+<dt>NetBSD</dt>
+<dd>fully maintained, and tested on SourceHut CI</dd>
+<dt>OpenBSD</dt>
+<dd>fully maintained, and tested on SourceHut CI</dd>
+<dt>Solaris/OpenIndiana</dt>
+<dd>fully maintained</dd>
+</dl>
+
+If you are interested in maintaining a dialect, let us know via the issue
+tracker of GitHub (https://github.com/lsof-org/lsof/issues). If we cannot find a
+volunteer for a dialect, we will remove the dialect.
+
+Many texts in the source tree still refers purdue.edu as the home of lsof
+development. It should be https://github.com/lsof-org/lsof, the new home. The
+updating is in progress.
+
+We ran another repository, lsof-org/"lsof-linux" derived from lsof-4.91 that was
+also released by Vic. The repository is no more used; all the changes made in
+the repository are now in lsof-org/"lsof" repository.
+
+The lsof-org team at GitHub
diff --git a/autotools/autotools.h.in b/autotools/autotools.h.in
new file mode 100644 (file)
index 0000000..3926081
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+ *  autotools.h: header shim for autotools
+ */
+
+/*
+ * Copyright 1998 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.
+ */
+
+#if    !defined(LSOF_AUTOTOOLS_H)
+#define        LSOF_AUTOTOOLS_H        1
+
+#ifndef AUTOTOOLS
+#error "This file should only be included when built using autotools"
+#endif
+
+#include "config.h"
+
+#if !HAVE_RPC_RPC_H && !HAVE_LIBTIRPC
+#define HASNORPC_H
+#endif
+
+#if HAVE_DECL___GLIBC__
+#define GLIBCV
+#endif
+
+#if HAVE_DECL_AF_INET6 || HAVE_NETINET6_IN6_H || HAVE_NETINET_IN6_H || HAVE_NETINET_IP6_H
+#define HASIPv6
+#endif
+
+#if HAVE_DECL_TCP_ESTABLISHED
+#define NEEDS_NETINET_TCPH
+#endif
+
+#if HAVE_LINUX_SOCK_DIAG_H && HAVE_LINUX_UNIX_DIAG_H
+#define HASUXSOCKEPT
+#endif
+
+#if HAVE_DECL_TTYAUX_MAJOR
+#define HASPTYEPT
+#endif
+
+#if HAVE_DECL_SS_CONNECTED
+#define HASSOSTATE
+#define HASSOOPT
+#endif
+
+#if HAVE_STRFTIME
+#define HAS_STRFTIME
+#endif
+
+#if HAVE_SELINUX_SELINUX_H
+#define HASSELINUX
+#endif
+
+#if HAVE_UTMPX_H
+#define HASUTMPX
+#endif
+
+#if HAVE_VM_MEMATTR_T
+#define HAS_VM_MEMATTR_T
+#endif
+
+#if HAVE_DECL_DOADUMP
+#define NEEDS_BOOLEAN_T
+#endif
+
+#if HAVE_KVM_VNODE
+#define HAS_KVM_VNODE
+#endif
+
+#if HAVE_DECL_SBS_CANTSENDMORE
+#define HASSBSTATE
+#endif
+
+#if HAVE_STRUCT_KINFO_PROC_KI_NUMTHREADS
+#define HASTASKS
+#endif
+
+#if HAVE_STRUCT_FILE_F_VNODE
+#define HASF_VNODE
+#endif
+
+#if HAVE_STRUCT_FILEDESCENT
+#define HAS_FILEDESCENT
+#endif
+
+/* Do not include wctype.h in AIX to avoid duplicate time error */
+#if HAVE_WCTYPE_H && !defined(AIXV)
+#define HASWCTYPE_H
+#endif
+
+#if HAVE_STRUCT_INODE_I_DIN2
+#define HAS_UFS1_2
+#endif
+
+#if HAVE_STRUCT_VNODE_V_LOCKF
+#define HAS_V_LOCKF
+#endif
+
+/* Check fdescfs v1 on FreeBSD if needed later */
+#if HAVE_FS_FDESCFS_FDESC_H
+#define HASFDESCFS 2
+#endif
+
+/* Check fdescfs v2 on NetBSD if needed later */
+#if HAVE_MISCFS_FDESC_FDESC_H
+#define HASFDESCFS 1
+#endif
+
+#if HAVE_FS_NULLFS_NULL_H || HAVE_MISCFS_NULLFS_NULL_H
+#define HASNULLFS
+#endif
+
+#if HAVE_STRUCT_XTCPCB_T_MAXSEG
+#define HAS_XTCPCB_TMAXSEG
+#endif
+
+#if HAVE_STRUCT_KINFO_FILE_KF_UN_KF_SOCK_KF_SOCK_SENDQ
+#define HAS_KF_SOCK_SENDQ
+#endif
+
+#if HAVE_STRUCT_KINFO_FILE_KF_UN_KF_FILE_KF_FILE_NLINK
+#define HAS_KF_FILE_NLINK
+#endif
+
+#if HAVE_NFS_NFSPROTO_H
+#define HASNFSPROTO
+#endif
+
+#if HAVE_UVM_UVM_H
+#define UVM
+#define HAS_UVM_INCL
+#endif
+
+#if HAVE_STRUCT_STATVFS
+#define HASSTATVFS
+#endif
+
+#if HAVE_STRUCT_INODE_I_FFS1_SIZE
+#define HASI_FFS1
+#endif
+
+#if HAVE_DECL_GETBOOTFILE
+#define HASGETBOOTFILE
+#endif
+
+#if HAVE_DECL_KVM_GETPROC2
+#define HASKVMGETPROC2
+#endif
+
+#if HAVE_FS_PTYFS_PTYFS_H
+#define HASPTYFS
+#endif
+
+#if HAVE_MISCFS_PROCFS_PROCFS_H
+#define HASPROCFS
+#endif
+
+#if HAVE_DECL_PFSROOT
+#define HASPROCFS_PFSROOT
+#endif
+
+#if HAVE_FS_TMPFS_TMPFS_H
+#define HASTMPFS
+#endif
+
+#if HAVE_SYS_PIPE_H
+#define HAS_SYS_PIPEH
+#endif
+
+#if HAVE_STRUCT_FDESCNODE_FD_LINK
+#define HASFDLINK
+#endif
+
+#if HAVE_INET_IPCLASSIFIER_H
+#define HAS_IPCLASSIFIER_H
+#endif
+
+#if HAVE_SYS_ZONE_H
+#define HASZONES
+#endif
+
+#if HAVE_PAD_MUTEX_T
+#define HAS_PAD_MUTEX
+#endif
+
+#if HAVE_LIBCTF_H
+#define HAS_LIBCTF
+#endif
+
+#if HAVE_DECL_PC_DIRENTPERSEC
+#define HAS_PC_DIRENTPERSEC
+#endif
+
+#if HAVE_SYS_FS_ZFS_H
+#define HAS_ZFS
+#endif
+
+#if HAVE_SYS_CRED_IMPL_H
+#define HAS_CRED_IMPL_H
+#endif
+
+#if HAVE_STRUCT_CONN_S_CONN_IXA
+#define HAS_CONN_NEW
+#endif
+
+#if HAVE_STRUCT_VNODE_V_PATH
+#define HAS_V_PATH
+#endif
+
+#if HAVE_DECL_VSOCK
+#define HAS_VSOCK
+#endif
+
+#if HAVE_STRUCT_AIO_REQ
+#define HAS_AIO_REQ_STRUCT
+#endif
+
+#if HAVE_SYS_RGM_H
+#define HAS_SYS_RGM_H
+#endif
+
+#if HAVE_RPC_RPC_TAGS_H
+#define HAS_RPC_RPC_TAGS_H
+#endif
+
+#if HAVE_DECL_DUP2
+#define HAS_DUP2
+#endif
+
+#if HAVE_DECL_CLOSEFROM
+#define HAS_CLOSEFROM
+#endif
+
+#endif
diff --git a/autotools/version.h.in b/autotools/version.h.in
new file mode 100644 (file)
index 0000000..aac0b80
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ *  version.h: generate version info for autotools
+ */
+
+/*
+ * Copyright 1998 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.
+ */
+
+#if    !defined(LSOF_VERSION_H)
+#define        LSOF_VERSION_H  1
+
+#ifndef AUTOTOOLS
+#error "This file should only be included when built using autotools"
+#endif
+
+#include "config.h"
+#define LSOF_VERSION PACKAGE_VERSION
+#define LSOF_HOST "@host@"
+#define LSOF_LOGNAME "@logname@"
+#define LSOF_USER "@user@"
+#define LSOF_CC "@cc@"
+#define LSOF_CCV "@ccv@"
+#define LSOF_CCFLAGS "@ccflags@"
+#define LSOF_LDFLAGS "@ldflags@"
+#define LSOF_SYSINFO "@sysinfo@"
+
+#endif
diff --git a/check.bash b/check.bash
new file mode 100755 (executable)
index 0000000..17486e7
--- /dev/null
@@ -0,0 +1,144 @@
+set -e
+
+if [ $# = 0 ]; then
+    echo "Usage: $0 DIALECT" 1>&2
+    exit 1
+fi
+
+if ! [ -d lib/dialects/$1 ]; then
+    echo "No such dialect: $1" 1>&2
+    exit 1
+fi
+
+echo
+echo RUNTIME ENVIRONMENT INFORMATION
+echo =============================================================================
+dialect=$1
+echo "$dialect"
+echo "$BASH_VERSION"
+shopt
+export
+
+uname
+
+lsof=$(pwd)/lsof
+$lsof -v
+
+export CI=1
+
+tdir=lib/dialects/${dialect}/tests
+
+nfailed=0
+nsuccessful=0
+nskipped=0
+ncases=0
+REPORTS=
+REPORTS_SKIPPED=
+
+
+run_one()
+{
+    local x=$1
+    local d=$2
+    local name
+    local prefix
+    local report
+    local s
+
+    chmod a+x $x
+    name=$(basename $x .bash)
+    if [ ${x%%/*} = "dialects" ]; then
+        prefix=${dialect}-
+    fi
+    report=/tmp/${prefix}$name-$$.report
+
+    printf "%s ... " $name
+
+    set +e
+    bash ./$x $lsof $report $d $dialect
+    s=$?
+    set -e
+    ncases=$((ncases + 1))
+    if [ "$s" = 0 ]; then
+        s=ok
+        nsuccessful=$((nsuccessful + 1))
+        rm -f "$report"
+    elif [ "$s" = 77 ]; then
+        s=skipped
+        nskipped=$((nskipped + 1))
+        REPORTS_SKIPPED="${REPORTS_SKIPPED} ${report}"
+    else
+        s=failed
+        nfailed=$((nfailed + 1))
+        REPORTS="${REPORTS} ${report}"
+    fi
+
+    printf "%s\n" $s
+}
+
+echo
+echo STARTING TEST '(' dialect neutral ')'
+echo =============================================================================
+for x in tests/case-*.bash; do
+    run_one $x ./tests
+done
+
+echo
+echo STARTING TEST '(' $dialect specific ')'
+echo =============================================================================
+for x in lib/dialects/${dialect}/tests/case-*.bash; do
+    run_one $x $tdir
+done
+
+report()
+{
+    for r in "$@"; do
+        echo
+        echo '[failed]' $r
+        echo -----------------------------------------------------------------------------
+        cat $r
+        rm $r
+    done
+}
+
+report_skipped()
+{
+    for r in "$@"; do
+        echo
+        echo '[skipped]' $r
+        echo -----------------------------------------------------------------------------
+        cat $r
+        rm $r
+    done
+}
+
+echo
+echo TEST SUMMARY
+echo =============================================================================
+printf "successful: %d\n" $nsuccessful
+printf "skipped: %d\n" $nskipped
+printf "failed: %d\n" $nfailed
+
+if [ $nfailed = 0 ]; then
+    printf "All %d test cases are passed successfully\n" $ncases
+    if [ $nskipped = 0 ]; then
+        :
+    elif [ $nskipped = 1 ]; then
+        printf "but 1 case is skipped\n"
+        report $REPORTS
+    else
+        printf "but %d cases are skipped\n" $nskipped
+        report $REPORTS
+    fi
+    exit 0
+elif [ $nfailed = 1 ]; then
+    printf "%d of %d case is failed\n" $nfailed $ncases
+    report $REPORTS
+    report_skipped $REPORTS_SKIPPED
+    exit 1
+else
+    printf "%d of %d cases are failed\n" $nfailed $ncases
+    report $REPORTS
+    report_skipped $REPORTS_SKIPPED    
+    exit 1
+fi
diff --git a/configure.ac b/configure.ac
new file mode 100644 (file)
index 0000000..65ab74b
--- /dev/null
@@ -0,0 +1,596 @@
+AC_INIT([lsof],[4.99.0])
+AM_INIT_AUTOMAKE([subdir-objects])
+LT_INIT([disable-fast-install]) # avoid lt-lsof naming
+# Locate custom m4 macros
+AC_CONFIG_MACRO_DIR([m4])
+
+# Require C compiler
+AC_PROG_CC
+# For legacy automake on e.g. CentOS 7
+AM_PROG_CC_C_O
+
+# Detect OS
+AC_CANONICAL_HOST
+
+LSOF_VSTR=$(uname -r)
+LSOF_DIALECT=unknown
+LSOF_DIALECT_DIR=unknown
+LSOF_TGT=unknown
+AS_CASE([${host_os}],
+[linux*], [
+       LSOF_DIALECT=linux
+       LSOF_DIALECT_DIR=linux
+       LSOF_TGT=linux
+
+       # Compute version
+       LSOF_VERS=$(echo $LSOF_VSTR | sed 's/\./ /g' | awk '{printf "%d%d%03d",$1,$2,$3}')
+
+       # Always use large file
+       CFLAGS="$CFLAGS -D_FILE_OFFSET_BITS=64"
+
+       # Enable LTbigf test
+       LSOF_TEST_CFLAGS="$LSOF_TEST_CFLAGS -DLT_BIGF -D_FILE_OFFSET_BITS=64"
+], [darwin*], [
+       LSOF_DIALECT=darwin
+       LSOF_DIALECT_DIR=darwin
+       LSOF_TGT=darwin
+
+       AS_CASE([$LSOF_VSTR],
+       [7.*],  [LSOF_VERS=700],                # Mac OS X 10.3 (Panther)
+       [8.*],  [LSOF_VERS=800],                # Mac OS X 10.4 (Tiger)
+       [9.*],  [LSOF_VERS=900],                # Mac OS X 10.5 (Leopard)
+       [10.*], [LSOF_VERS=1000],               # Mac OS X 10.6 (SnowLeopard)
+       [11.*], [LSOF_VERS=1100],               # Mac OS X 10.7 (Lion)
+       [12.*], [LSOF_VERS=1200],               # Mac OS X 10.8 (Mountain Lion)
+       [13.*], [LSOF_VERS=1300],               # Mac OS X 10.9 (Mavericks)
+       [14.*], [LSOF_VERS=1400],               # Mac OS X 10.10 (Yosemite)
+       [15.*], [LSOF_VERS=1500],               # Mac OS X 10.11 (El Capitan)
+       [16.*], [LSOF_VERS=1600],               # macOS 10.12 (Sierra)
+       [17.*], [LSOF_VERS=1700],               # macOS 10.13 (High Sierra)
+       [18.*], [LSOF_VERS=1800],               # macOS 10.14 (Mojave)
+       [19.*], [LSOF_VERS=1900],               # macOS 10.15 (Catalina)
+       [
+               AC_MSG_NOTICE([Unknown Darwin release: $(uname -r)])
+               AC_MSG_NOTICE([Assuming Darwin 19.0])
+               LSOF_VERS=1900
+       ])
+
+       # Add DARWINV to cflags
+       CFLAGS="$CFLAGS -DDARWINV=$LSOF_VERS"
+
+       # Enable LTbigf test
+       LSOF_TEST_CFLAGS="$LSOF_TEST_CFLAGS -DLT_BIGF"
+], [freebsd*], [
+       LSOF_DIALECT=freebsd
+       LSOF_DIALECT_DIR=freebsd
+       LSOF_TGT=freebsd
+
+       AS_CASE([$LSOF_VSTR],
+       [10*],  [LSOF_VERS=10000],
+       [11*],  [LSOF_VERS=11000],
+       [12*],  [LSOF_VERS=12000],
+       [13*],  [LSOF_VERS=13000],
+       [14*],  [LSOF_VERS=14000],
+       [15*],  [LSOF_VERS=15000], [
+               AC_MSG_ERROR([Unknown FreeBSD release: $(uname -r)])
+       ])
+
+       # Add FREEBSDV to cflags
+       CFLAGS="$CFLAGS -DFREEBSDV=$LSOF_VERS"
+
+       # Always define HASPROCFS
+       CFLAGS="$CFLAGS -DHASPROCFS"
+
+       # Always link libutil
+       LDFLAGS="$LDFLAGS -lutil"
+
+       # Detect FreeBSD source code
+       AS_IF([test -d /usr/src/sys], [
+               FREEBSD_SYS=/usr/src/sys
+       ], [test -d /sys], [
+               FREEBSD_SYS=/sys
+       ], [
+               AC_MSG_WARN([No kernel sources in /usr/src/sys or /sys])
+       ])
+
+       # Enable LTbigf test
+       LSOF_TEST_CFLAGS="$LSOF_TEST_CFLAGS -DLT_BIGF"
+], [netbsd*],  [
+       LSOF_DIALECT=netbsd
+       LSOF_DIALECT_DIR=netbsd
+       LSOF_TGT=netbsd
+
+       case $LSOF_VSTR in
+               8.[[0123]]*)
+                       LSOF_VERS="8000000"
+                       ;;
+               8.99.*)
+                       LSOF_VERS="8099000"
+                       ;;
+               8.*)
+                       LSOF_VERS="8000000"
+                       AC_MSG_WARN([Unsupported NetBSD release: $(uname -r)])
+                       AC_MSG_WARN([Configuring for NetBSD 8.0])
+                       ;;
+               9.[[0123]]*)
+                       LSOF_VERS="9000000"
+                       ;;
+               9.99.10[[45678]])
+                       LSOF_VERS="9099104"
+                       ;;
+               9.99.*)
+                       LSOF_VERS="9099000"
+                       ;;
+               9.*)
+                       LSOF_VERS="9000000"
+                       AC_MSG_WARN([Unsupported NetBSD release: $(uname -r)])
+                       AC_MSG_WARN([Configuring for NetBSD 9.0])
+                       ;;
+               10.99.*)
+                       LSOF_VERS="10099000"
+                       ;;
+               10.*)
+                       LSOF_VERS="10000000"
+                       AC_MSG_WARN([Unsupported NetBSD release: $(uname -r)])
+                       AC_MSG_WARN([Configuring for NetBSD 10.0])
+                       ;;
+               *)
+                       AC_MSG_ERROR([Unknown NetBSD release: $(uname -r)])
+                       ;;
+       esac
+
+       # Add NETBSDV to cflags
+       CFLAGS="$CFLAGS -DNETBSDV=$LSOF_VERS"
+
+       # Define _KMEMUSER for paddr_t and __NAMECACHE_PRIVATE for struct namecache
+       CFLAGS="$CFLAGS -D_KMEMUSER -D__NAMECACHE_PRIVATE"
+
+       # Define HASNFSVATTRP because the relevant change in kernel src is in 1997
+       # We can safely assume that n_vattr is a pointer
+       CFLAGS="$CFLAGS -DHASNFSVATTRP"
+
+       # Check /dev/kmem
+       LSOF_TEST_CFLAGS="$LSOF_TEST_CFLAGS -DLT_KMEM"
+
+       # Detect NetBSD source code
+       AS_IF([test -d /usr/src/sys], [
+               NETBSD_SYS=/usr/src/sys
+               CFLAGS="$CFLAGS -I$NETBSD_SYS"
+       ], [
+               AC_MSG_WARN([No kernel sources in /usr/src/sys])
+       ])
+], [openbsd*], [
+       LSOF_DIALECT=openbsd
+       LSOF_DIALECT_DIR=openbsd
+       LSOF_TGT=openbsd
+
+       AS_CASE([$LSOF_VSTR],
+       [7.2],  [LSOF_VERS=7020],
+       [7.3],  [LSOF_VERS=7030],
+       [
+               AC_MSG_NOTICE([Unknown OpenBSD release: $(uname -r)])
+               AC_MSG_NOTICE([Assuming OpenBSD 7.3])
+               LSOF_VERS=7030
+       ])
+], [solaris*], [
+       LSOF_DIALECT=solaris
+       LSOF_DIALECT_DIR=sun
+       LSOF_TGT=solaris
+
+       AS_CASE([$LSOF_VSTR],
+       [5.11], [LSOF_VERS=110000],
+       [
+               AC_MSG_NOTICE([Unknown Solaris release: $(uname -r)])
+               AC_MSG_NOTICE([Assuming Solaris 5.11])
+               LSOF_VERS=110000
+       ])
+
+       # Add solaris to cflags
+       CFLAGS="$CFLAGS -Dsolaris=$LSOF_VERS"
+
+       # Link system libraries
+       LIBS="$LIBS -lelf -lsocket -lnsl"
+
+       # Handle missing header
+       mkdir -p ./solaris11/sys
+       touch ./solaris11/sys/extdirent.h
+       CFLAGS="$CFLAGS -Isolaris11"
+], [aix*], [
+       LSOF_DIALECT=aix
+       LSOF_DIALECT_DIR=aix
+       LSOF_TGT=aix
+
+       LSOF_TMP1=/usr/bin/oslevel
+       AS_IF([test -x $LSOF_TMP1], [
+               echo "Determining AIX version with $LSOF_TMP1."
+               echo "This may take a while, depending on your maintenance level."
+               LSOF_VSTR=`$LSOF_TMP1 | sed 's/[^0-9]*\([0-9\.]*\).*/\1/'`
+               echo "$LSOF_TMP1 reports the version is $LSOF_VSTR."
+       ], [
+               # If oslevel can't be used, build the version string with
+               # `uname -rv` and issue a warning.
+
+               LSOF_VSTR=`uname -rv | awk '{printf "%d.%d.0.0\n",\$2,\$1}'`
+               echo "WARNING: can't execute $LSOF_TMP1; uname -rv reports"
+               echo "         the version is $LSOF_VSTR;"
+       ])
+
+       LSOF_VERS=`echo $LSOF_VSTR | sed 's/\.//g'`
+
+       # Add AIXV to cflags
+       CFLAGS="$CFLAGS -DAIXV=$LSOF_VERS"
+
+       # Assuming recent AIX on PowerPC64
+       CFLAGS="$CFLAGS -maix64 -DAIXA=1 -DAIX_KERNBITS=64 -DHASSTAT64"
+       LSOF_TEST_CFLAGS="$LSOF_TEST_CFLAGS -DLT_AIXA=1"
+
+       # JFS2 support
+       # Add -fms-extensions to handle use of i_dev from the wInode anonymous
+       # structure reference in the JFS2 inode structure of <j2/j2_inode.h>.
+       CFLAGS="$CFLAGS -DHAS_JFS2 -I./lib/dialects/aix/aix5 -fms-extensions"
+], [
+       AC_MSG_ERROR(["Host $host_os not supported"])
+])
+
+# Pass dialect info to Makefile.am
+AM_CONDITIONAL([LINUX], [test x$LSOF_DIALECT_DIR = xlinux])
+AM_CONDITIONAL([DARWIN], [test x$LSOF_DIALECT_DIR = xdarwin])
+AM_CONDITIONAL([FREEBSD], [test x$LSOF_DIALECT_DIR = xfreebsd])
+AM_CONDITIONAL([NETBSD], [test x$LSOF_DIALECT_DIR = xnetbsd])
+AM_CONDITIONAL([OPENBSD], [test x$LSOF_DIALECT_DIR = xopenbsd])
+AM_CONDITIONAL([SOLARIS], [test x$LSOF_DIALECT_DIR = xsun])
+AM_CONDITIONAL([AIX], [test x$LSOF_DIALECT_DIR = xaix])
+
+# Pass OS version
+LSOF_TMP=$(echo $LSOF_VSTR | sed 's/(/\\\\(/g' | sed 's/)/\\\\)/g')
+CFLAGS="$CFLAGS -DLSOF_VSTR=\\\"$LSOF_TMP\\\""
+
+# Pass LSOF_DIALECT/LSOF_DIALECT_DIR to Makefile.am
+AC_SUBST([LSOF_DIALECT])
+AC_SUBST([LSOF_DIALECT_DIR])
+
+# Export public function with default visibility
+AC_DEFINE([API_EXPORT], [__attribute__ ((visibility ("default")))],
+       [Set visibility to default for exported API functions.])
+
+# --enable-liblsof to install liblsof
+AC_ARG_ENABLE(liblsof, AS_HELP_STRING([--enable-liblsof],
+       [build and install liblsof @<:@default=yes@:>@]), [], [enable_liblsof=yes])
+AM_CONDITIONAL([INSTALL_LIBLSOF], [test "x$enable_liblsof" = xyes])
+
+# --enable-security to define HASSECURITY
+AC_ARG_ENABLE(security, AS_HELP_STRING([--enable-security],
+       [allow only the root user to list all open files @<:@default=no@:>@]), [], [enable_security=no])
+AS_IF([test "x$enable_security" = xyes], [
+       CFLAGS="$CFLAGS -DHASSECURITY"
+])
+
+# --enable-no-sock-security to define HASNOSOCKSECURITY
+AC_ARG_ENABLE(no_sock_security, AS_HELP_STRING([--enable-no-sock-security],
+       [combined with --enable-security, allow anyone to list anyone else's socket files @<:@default=no@:>@]), [], [enable_no_sock_security=no])
+AS_IF([test "x$enable_no_sock_security" = xyes], [
+       AS_IF([test "x$enable_security" = xyes], [
+               CFLAGS="$CFLAGS -DHASNOSOCKSECURITY"
+       ], [
+               AC_MSG_ERROR([--enable-no-sock-security must be used with --enable-security])
+       ])
+])
+
+# Check rpc/rpc.h or libtirpc
+# with_libtirpc=yes/no/auto
+AC_ARG_WITH(libtirpc, AS_HELP_STRING([--with-libtirpc],
+       [build with libtirpc support @<:@default=auto@:>@]), [], [with_libtirpc=auto])
+AS_IF([test "x$with_libtirpc" != xno], [
+       PKG_CHECK_MODULES([LIBTIRPC], [libtirpc], [
+               CFLAGS="$CFLAGS $LIBTIRPC_CFLAGS"
+               LIBS="$LIBS $LIBTIRPC_LIBS"
+               with_libtirpc=yes
+       ], [
+               AS_IF([test "x$with_libtirpc" = xyes], [
+                       AC_MSG_ERROR([--with-libtirpc specified, but libtirpc could not be found])
+               ])
+               with_libtirpc=no
+       ])
+])
+
+AS_IF([test "x$with_libtirpc" = "xyes"],
+        [AC_DEFINE(HAVE_LIBTIRPC, 1, [Enable libtirpc support])])
+
+AC_CHECK_HEADERS([rpc/rpc.h])
+
+# Detect glibc for GLIBCV
+AC_CHECK_DECLS([__GLIBC__])
+
+# Detect ipv6 headers and definitions for HASIPv6
+AC_CHECK_DECLS([AF_INET6], [], [], [[#include <sys/socket.h>]])
+AC_CHECK_HEADERS([netinet6/in6.h netinet/in6.h netinet/ip6.h])
+
+# Detect tcp definitions for NEEDS_NETINET_TCPH
+AC_CHECK_DECLS([TCP_ESTABLISHED], [], [], [[#include <netinet/tcp.h>]])
+
+# Detect unix socket endpoint headers for HASUXSOCKEPT
+AC_CHECK_HEADERS([linux/sock_diag.h linux/unix_diag.h])
+
+# Detect pty endpoint definition for HASPTYEPT
+AC_CHECK_DECLS([TTYAUX_MAJOR], [], [], [[#include <linux/major.h>]])
+
+# Detect socket state definition for HASSOSTATE and HASSOOPT
+AC_CHECK_DECLS([SS_CONNECTED], [], [], [[#include <linux/net.h>]])
+
+# Define _FILE_OFFSET_BITS if necessary
+AC_SYS_LARGEFILE
+
+# Detect strftime function for HAS_STRFTIME
+AC_CHECK_FUNCS([strftime])
+
+# Detect selinux headers for HASSELINUX
+# with_selinux=yes/no/auto
+AC_ARG_WITH(selinux, AS_HELP_STRING([--with-selinux],
+       [build with selinux support @<:@default=auto@:>@]), [], [with_selinux=auto])
+AS_IF([test "x$with_selinux" != xno], [
+       AC_CHECK_HEADERS([selinux/selinux.h], [LIBS="$LIBS -lselinux"], [
+               AS_IF([test "x$with_selinux" = xyes], [
+                       AC_MSG_ERROR([--with-selinux specified, but libselinux could not be found])
+               ])
+       ])
+])
+
+# Detect utmpx headers for HASUTMPX
+AC_CHECK_HEADERS([utmpx.h])
+
+# Detect vm_memattr_t definition for HAS_VM_MEMATTR_T
+AC_CHECK_TYPES([vm_memattr_t], [], [], [[#include <sys/types.h>
+               #include <vm/vm.h>]])
+
+# Detect doadump function for NEEDS_BOOLEAN_T
+AC_CHECK_DECLS([doadump], [], [], [[#define _KERNEL 1
+               #include <sys/types.h>
+               #include <sys/param.h>
+               #include <sys/conf.h>]])
+
+# Detect struct vnode definition for HAS_KVM_VNODE
+# Linking libkvm is not required in AIX
+AS_IF([test x$LSOF_DIALECT_DIR != xaix], [
+       AC_EGREP_CPP([struct vnode], [#define _KVM_VNODE 1
+                       #include <sys/vnode.h>], [AC_DEFINE([HAVE_KVM_VNODE], [1], ["Define to 1 if struct vnode exists"])
+                       LIBS="$LIBS -lkvm"])
+])
+
+# Detect SBS_CANTSENDMORE definition for HASSBSTATE
+AC_CHECK_DECLS([SBS_CANTSENDMORE], [], [], [[#include <sys/types.h>
+               #include <sys/socketvar.h>]])
+
+# Detect lockf_entry definition for HAS_LOCKF_ENTRY
+AC_CHECK_TYPES([struct lockf_entry], [
+       HEADER_GENERATE([lockf_owner.h], [${FREEBSD_SYS}/kern/kern_lockf.c], ["^struct lock_owner {"], ["^};"], [LOCKF_OWNER_H])
+       AC_MSG_NOTICE([lockf_owner.h creation succeeded.])
+       CFLAGS="$CFLAGS -DHAS_LOCKF_ENTRY"
+], [], [#include <sys/types.h>
+               #include <sys/lockf.h>])
+
+# Detect ki_numthreads definition for HASTASKS
+AC_CHECK_MEMBERS([struct kinfo_proc.ki_numthreads], [], [], [#include <sys/types.h>
+               #include <sys/user.h>])
+
+# Detect i_effnlink/i_ffs_effnlink for HASEFFNLINK
+AC_CHECK_MEMBERS([struct inode.i_effnlink], [CFLAGS="$CFLAGS -DHASEFFNLINK=i_effnlink"], [], [#define __BSD_VISIBLE 1
+               #include <sys/types.h>
+               #include <ufs/ufs/quota.h>
+               #include <ufs/ufs/inode.h>])
+
+# Detect struct file.f_vnode for HASF_VNODE
+AC_CHECK_MEMBERS([struct file.f_vnode], [], [], [#define __BSD_VISIBLE 1
+               #define _KERNEL 1
+               #define GENOFFSET
+               #include <sys/types.h>
+               #include <sys/file.h>])
+
+# Detect struct filedescent for HAS_FILEDESCENT
+AC_CHECK_TYPES([struct filedescent], [], [], [#define __BSD_VISIBLE 1
+               #include <sys/types.h>
+               #include <sys/filedesc.h>])
+
+# Detect fs/tmpfs/tmpfs.h for HAS_TMPFS
+AS_IF([test -r ${FREEBSD_SYS}/fs/tmpfs/tmpfs.h], [
+       AC_DEFINE([HAS_TMPFS], [1], [Define if fs/tmpfs/tmpfs.h is found])
+])
+
+# Detect wctype.h for HASWCTYPE_H
+AC_CHECK_HEADERS([wctype.h])
+
+# Detect struct inode.i_din2 for HAS_UFS1_2
+AC_CHECK_MEMBERS([struct inode.i_din2], [], [], [#define __BSD_VISIBLE 1
+               #include <sys/types.h>
+               #include <ufs/ufs/quota.h>
+               #include <ufs/ufs/inode.h>])
+
+# Detect struct vnode.v_lockf definition for HAS_V_LOCKF
+AC_CHECK_MEMBERS([struct vnode.v_lockf], [], [], [#define _KVM_VNODE 1
+               #define __BSD_VISIBLE 1
+               #include <sys/types.h>
+               #include <sys/vnode.h>])
+
+# Detect fdescfs version for HASFDESCFS
+AC_CHECK_HEADERS([fs/fdescfs/fdesc.h], [], [], [#define _KERNEL 1
+               #define __BSD_VISIBLE 1
+               #include <sys/types.h>
+               #include <sys/mount.h>])
+
+# Detect pseudofs for HASPSEUDOFS
+AS_IF([test -d ${FREEBSD_SYS}/fs/pseudofs], [
+       CFLAGS="$CFLAGS -DHASPSEUDOFS -I$FREEBSD_SYS"
+])
+
+# Detect nullfs for HASNULLFS
+AC_CHECK_HEADERS([fs/nullfs/null.h], [], [], [])
+
+# Detect struct xtcpcb.t_maxseg for HAS_XTCPCB_TMAXSEG
+AC_CHECK_MEMBERS([struct xtcpcb.t_maxseg], [], [], [#include <sys/types.h>
+       #include <sys/queue.h>
+       #include <sys/socketvar.h>
+       #include <sys/socket.h>
+       #include <netinet/in.h>
+       #include <netinet/in_pcb.h>
+       #include <netinet/tcp_var.h>])
+
+# Detect struct kinfo_file.kf_un.kf_sock.kf_sock_sendq for HAS_KF_SOCK_SENDQ
+AC_CHECK_MEMBERS([struct kinfo_file.kf_un.kf_sock.kf_sock_sendq], [], [], [#include <sys/types.h>
+       #include <sys/user.h>])
+
+# Detect struct kinfo_file.kf_un.kf_file.kf_file_nlink for HAS_KF_FILE_NLINK
+AC_CHECK_MEMBERS([struct kinfo_file.kf_un.kf_file.kf_file_nlink], [], [], [#include <sys/types.h>
+       #include <sys/user.h>])
+
+# Detect nfs/nfsproto.h for HASNFSPROTO
+AC_CHECK_HEADERS([nfs/nfsproto.h])
+
+# Detect uvm/uvm.h for HAS_UVM_INCL
+AC_CHECK_HEADERS([uvm/uvm.h])
+
+# Detect struct statvfs for HASSTATVFS
+AC_CHECK_TYPES([struct statvfs], [], [], [#include <sys/statvfs.h>])
+
+# Detect struct inode.i_ffs1_size for HASI_FFS1
+AC_CHECK_MEMBERS([struct inode.i_ffs1_size], [], [], [#include <ufs/ufs/inode.h>])
+
+# Detect getbootfile function for HASGETBOOTFILE
+AC_CHECK_DECLS([getbootfile()], [
+       LDFLAGS="$LDFLAGS -lutil"
+], [], [#include <util.h>])
+
+# Detect kvm_getproc2 function for HASKVMGETPROC2
+AC_CHECK_DECLS([kvm_getproc2], [], [], [#include <kvm.h>])
+
+# Detect fs/ptyfs/ptyfs.h header for HASPTYFS
+AC_CHECK_HEADERS([fs/ptyfs/ptyfs.h])
+
+# Detect fs/ptyfs/ptyfs.h header for HASPROCFS
+AC_CHECK_HEADERS([miscfs/procfs/procfs.h])
+
+# Detect PFSroot enum for HASPROCFS_PFSROOT
+AC_CHECK_DECLS([PFSroot], [], [], [#define _KERNEL
+       #include <sys/types.h>
+       #include <miscfs/procfs/procfs.h>])
+
+# Detect fs/tmpfs/tmpfs.h header for HASTMPFS
+AC_CHECK_HEADERS([fs/tmpfs/tmpfs.h])
+
+# Detect sys/pipe.h header for HAS_SYS_PIPEH
+AC_CHECK_HEADERS([sys/pipe.h])
+
+# Copy struct lockf definition from kernel source code for HAS_LOCKF_H
+AS_IF([test x$LSOF_DIALECT = xnetbsd], [
+       # Generate lockf.h from kern/vfs_lockf.c
+       HEADER_GENERATE([lockf.h], [${NETBSD_SYS}/kern/vfs_lockf.c], ["^TAILQ_HEAD"], ["^};"], [LOCKF_H])
+
+       AC_MSG_NOTICE([lockf.h creation succeeded])
+       CFLAGS="$CFLAGS -DHAS_LOCKF_H"
+])
+
+# Detect fdescfs version for HASFDESCFS
+AC_CHECK_HEADERS([miscfs/fdesc/fdesc.h])
+
+# Detect struct fdescnode.fd_link for HASFDLINK
+AC_CHECK_MEMBERS([struct fdescnode.fd_link], [], [], [#define _KERNEL
+       #include <sys/types.h>
+       #include <miscfs/fdesc/fdesc.h>])
+
+# Detect miscfs/nullfs/null.h header for HASNULLFS
+AC_CHECK_HEADERS([miscfs/nullfs/null.h], [], [], [#include <sys/mount.h>])
+
+# Detect dup2 for HAS_DUP2
+AC_CHECK_DECLS([dup2], [], [], [[#include <unistd.h>]])
+
+# Detect closefrom for HAS_CLOSEFROM
+AC_CHECK_DECLS([closefrom], [], [], [[#include <unistd.h>]])
+
+# Detect sizeof(dev_t) for LT_DEV64
+AC_CHECK_SIZEOF([dev_t])
+AS_IF([test "x$ac_cv_sizeof_dev_t" = x8], [
+       LSOF_TEST_CFLAGS="$LSOF_TEST_CFLAGS -DLT_DEV64"
+])
+
+# Detect inet/ipclassifier.h header for HAS_IPCLASSIFIER_H
+AC_CHECK_HEADERS([inet/ipclassifier.h], [], [], [#define _KERNEL
+       #include <inet/ip.h>])
+
+# Detect struct conn_s.conn_ixa header for HAS_CONN_NEW
+AC_CHECK_MEMBERS([struct conn_s.conn_ixa], [], [], [#define _KERNEL
+       #include <inet/ip.h>
+       #include <inet/ipclassifier.h>])
+
+# Detect sys/zone.h header for HASZONES
+AC_CHECK_HEADERS([sys/zone.h])
+
+# Detect pad_mutex_t for HAS_PAD_MUTEX
+AC_CHECK_TYPES([pad_mutex_t], [], [], [#define _KERNEL
+       #include <sys/mutex.h>])
+
+# Detect libctf.h header for HAS_LIBCTF
+AC_CHECK_HEADERS([libctf.h], [LIBS="$LIBS -lctf"])
+
+# Detect pc_direntpersec macro for HAS_PC_DIRENTPERSEC
+AC_CHECK_DECLS([pc_direntpersec((struct pcfs *)NULL)], [], [], [#include <sys/fs/pc_fs.h>])
+
+# Detect sys/fs/zfs.h header for HAS_ZFS
+AC_CHECK_HEADERS([sys/fs/zfs.h])
+
+# Detect sys/cred_impl.h header for HAS_CRED_IMPL_H
+AC_CHECK_HEADERS([sys/cred_impl.h])
+
+# Detect struct vnode.v_path for HAS_V_PATH
+AC_CHECK_MEMBERS([struct vnode.v_path], [
+       LSOF_TEST_CFLAGS="$LSOF_TEST_CFLAGS -DLT_VPATH"
+], [], [#include <sys/vnode.h>])
+
+# Detect VSOCK for HAS_VSOCK
+AC_CHECK_DECLS([VSOCK], [], [], [#include <sys/vnode.h>])
+
+# Detect struct aio_req for HAS_AIO_REQ_STRUCT
+AC_CHECK_TYPES([struct aio_req], [], [], [#define _KERNEL
+       #include <sys/aio_req.h>])
+
+# Detect sys/rgm.h header for HAS_SYS_RGM_H
+AC_CHECK_HEADERS([sys/rgm.h])
+
+# Detect rpc/rpc_tags.h header for HAS_RPC_RPC_TAGS_H
+AC_CHECK_HEADERS([rpc/rpc_tags.h])
+
+# Generate Makefile from Makefile.in/am
+AC_CONFIG_FILES([Makefile])
+
+# Pass build configurations to version.h.in
+AC_SUBST(cc, $CC)
+AC_SUBST(ccv, $($CC -v 2>&1 | sed -n 's/.*version \(.*\)/\1/p'))
+AC_SUBST(ccflags, $CFLAGS)
+AC_SUBST(ldflags, "$LDFLAGS$LIBS")
+# Reproducible build
+AS_IF([test "X$SOURCE_DATE_EPOCH" = "X"], [
+       AC_SUBST(host, $(uname -n))
+       AC_SUBST(logname, $LOGNAME)
+       AC_SUBST(user, $USER)
+       AC_SUBST(sysinfo, $(uname -a))
+])
+
+# Generate version.h/autotools.h
+AC_CONFIG_FILES([autotools/version.h autotools/autotools.h])
+
+# Generate version
+AC_CONFIG_FILES([version])
+
+# Generate config.h
+AC_CONFIG_HEADERS([config.h])
+
+# For VPATH building
+AC_CONFIG_LINKS([tests/common.bash:tests/common.bash
+       lib/dialects/linux/tests/util-open-flags.bash:lib/dialects/linux/tests/util-open-flags.bash
+       Lsof.8:Lsof.8 00DIALECTS:00DIALECTS 00DIST:00DIST])
+
+# Generate cflags for tests
+LSOF_TEST_CFLAGS="$LSOF_TEST_CFLAGS -DLT_DIAL_$LSOF_TGT -DLT_VERS=$LSOF_VERS"
+# Override default lsof path
+LSOF_TEST_CFLAGS="$LSOF_TEST_CFLAGS -DLT_DEF_LSOF_PATH=\\\"$PWD/lsof\\\""
+AC_SUBST([LSOF_TEST_CFLAGS])
+
+# Finish
+AC_OUTPUT
diff --git a/default.nix b/default.nix
new file mode 100644 (file)
index 0000000..74469d4
--- /dev/null
@@ -0,0 +1,24 @@
+with import <nixpkgs> {};
+
+stdenv.mkDerivation {
+  name = "lsof";
+  version = "1.0";
+
+  src = ./.;
+
+  postPatch = ''
+    patchShebangs .
+  '';
+
+  nativeBuildInputs = [
+    autoreconfHook
+    groff
+    pkg-config
+  ];
+
+  doCheck = true;
+  checkInputs = lib.optionals stdenv.isLinux [
+    util-linux
+    procps
+  ];
+}
diff --git a/docs/contributing.md b/docs/contributing.md
new file mode 100644 (file)
index 0000000..02d0eda
--- /dev/null
@@ -0,0 +1,68 @@
+# Contributing
+
+You can contribute to lsof via pull requests at [GitHub](https://github.com/lsof-org/lsof).
+
+## Commit message
+
+If a change is dialect specific, use `[dialect]` as the prefix of the
+header of the commit log like:
+
+       [linux] compile with -Wall option
+       [linux] delete unused variables
+       [freebsd] cirrus-ci: disabled
+
+If no `[dialect]` prefix is given to a commit, the change may have an impact
+across dialects.
+
+## Code style
+
+C sources should be formatted by `clang-format`, e.g.:
+
+```shell
+clang-format -i lib/dialcets/linux/dsock.c
+# or
+git-clang-format
+```
+
+The formatter may not function properly in some corner cases. You will have to
+rewrite the code to make it happy.
+
+Use as few #if/#else/#endif constructs as possible, even at
+the cost of nearly-duplicate code.
+
+When #if/#else/#endif constructs are necessary:
+
+Use the form
+
+```c
+#if defined(s<symbol>)
+```
+
+in preference to
+
+```c
+#ifdef <symbol>
+```
+
+to allow easier addition of tests to the #if.
+
+- Indent them to signify their level -- e.g.,
+
+```c
+#if            /* level one */
+#  if          /* level two */
+#  endif       /* level two */
+#else          /* level one */
+#endif         /* level one */
+```
+
+Use ANSI standard comments on #else and #endif statements.
+
+## Testing
+
+There are two test mechanism, the original one by Via Abell and a script-based
+one by Masatake YAMATO. About the original test mechanism, see tests/00README.
+About the script-based test mechanism, see tests/case-00-hello.bash and
+check.bash.
+
+Your pull request should pass all CI checks. If necessary, you can modify testcases.
\ No newline at end of file
diff --git a/docs/credits.md b/docs/credits.md
new file mode 100644 (file)
index 0000000..ec9b890
--- /dev/null
@@ -0,0 +1,597 @@
+## Credits
+
+I owe an enormous debt to the users of lsof who have contributed
+to its steady growth.  The size of the list of people who have
+helped me, while it has grown too large to include in the lsof man
+page any more, is a testimonial to their generosity.
+
+First I acknowledge a debt to the work of Dan Bernstein, Michael
+`Ford` Ditto, Tom Dunigan, Alexander Dupuy, Vik Lall, Ray Moody,
+C. Spencer, Michael Spitzer and those who wrote Berkeley's fstat
+program, all contributors to lsof's predecessors.
+
+I thank Doug McKenzie for his HP-UX proctor program and Rich Kulawiec
+for pointing it out.
+
+Finally I thank all the following people who have used lsof, pointed
+out its flaws, described its shortcomings, offered suggestions for
+improving it, supplied code for it, gave me technical advice, and
+provided test systems where I was able to do development work.
+
+       Szilveszter Adam
+       David Addison
+       Elias Halldor Agustsson
+       Per Allansson
+       Jim Ankenbrandt
+       Richard Allen
+       Thomas Anders
+       Ric Anderson
+       Stuart Anderson
+       Dimitry Andric
+       Michael Antlitz
+       Cato Auestad
+       Marc Auslander
+       Tigran Aivazian
+       Jos Backus
+       David Bacon
+       Alexis Ballier
+       Scott Ballew
+       Ade Barkah
+       Alon Bar-Lev
+       Brett Bartick
+       Anthony Baxter
+       John Beacom
+       Bruce Beare
+       M. Jay Beck
+       Marek Behun
+       Bill Behr
+       Michael Beirne
+       Marc Bejarano
+       Andrew Bell
+       Steve Bellenot
+       Robert Benites
+       Dmitry Berezin
+       Ulrich Bernhard
+       Peter J. Bertoncini
+       Dave Bianchi
+       Mark Bixby
+       Allan Black
+       Jan Blunck
+       Achim Bohnet
+       Steve Bonds
+       Mark Bonsack
+       Volker Borchert
+       Bill Bormann
+       Ermin Borovac
+       Heddy Boubaker
+       Pieter Bowman
+       Michael Bracewell
+       H. Merijn Brand
+       Danny Braniss
+       Thomas Braunbeck
+       Kieran Broadfoot
+       Dean Brock
+       Hal Brooks
+       Andrew Brown
+       Jim Brown
+       Michael Bryan
+       Matthew Burt
+       Robert Byrnes
+       Pierfrancesco Caci
+       Bill Campbell
+       David Capshaw
+       John Caruso
+       Jon Champlin
+       Kris Chandrasekhar
+       Stephane Chazelas
+       Andrey Chernov
+       Albert Chin-A-Young
+       Bernt Christandl
+       Marc Christensen
+       Hans Petter Christiansen
+       Tom Christiansen
+       Yves Christophe
+       Richard Chycoski
+       A. Channing Clark
+       Jorn Clausen
+       Axel Clauberg
+       John Clear
+       David Clissold
+       Richard Coley
+       John Colgrave
+       David Comay
+       Lionel Cons
+       Bob Cook
+       Patrick Connor
+       Carl Cook
+       Jim Cooper
+       Roger Cornelius
+       Doug Crabill
+       Eric Cronin
+       Kim Culhan
+       Dave Curry
+       Robert Dahlem
+       Guy Dallaire
+       D. Chris Daniels
+       Renata Maria Dart
+       Ian Darwin
+       Carl E. Davidson
+       David Day
+       Will Day
+       Frederic Delanoy
+       Mike Depot
+       Steve Dibbell
+       Hugh Dickins
+       David DiGiacomo
+       Casper Dik
+       John DiMarco
+       Don Draper
+       Bryan Drewery
+       Michel Dubois
+       Eric Dumazet
+       Dick Dunbar
+       Marc Duponcheel
+       Jan Dvorak
+       Calle Dybedahl
+       John Dzubera
+       Jeff Earickson
+       Greg Earle
+       Bernd Eckenfels
+       Niklas Edmundsson
+       Philip Edwards
+       Robert Ehrlich
+       Mark W. Eichin
+       Doug Eldred
+       Scott Ellentuch
+       Tom Endo
+       Grant Erickson
+       Craig Everhart
+       Chris Evert
+       Bob Farmer
+       Sami Farin
+       Mike Feldman
+       Quentin Fennessy
+       Ian Fitchet
+       Toralf Foerster
+       Bob Foertsch
+       Pierre-Yves Fontaniere
+       Ralph Forsythe
+       Jason Fortezzo
+       Mike Fraser
+       Curt Freeland
+       Terry Friedrichsen
+       Mike Frysinger
+       Harvey Garner
+       Carson Gaspar
+       Stuart D. Gathman
+       Brian L. Gentry
+       Dave Gilbert
+       Steve Ginsberg
+       Bjarni Ingi Gislason
+       Edwin Groothuis
+       Jin Guojun
+       Kurt Gollhardt
+       Roman Gollent
+       Steve Gonczi
+       Bill Goodridge
+       Julian Gordon
+       Marcin Gozdalik
+       Henry Grebler
+       Richard Green
+       Chaskiel Grundman
+       Armin Gruner
+       David Gutierrez
+       Mateusz Guzik
+       Robert Hall
+       Garner Halloran
+       Adam Hammer
+       Charles Hannum
+       Vlad Harchev
+       Craig Harmer
+       Michael Haro
+       Peter Harvey
+       Steinar Haug
+       Jia He
+       Sheldon Hearn
+       John Heasley
+       Wolfgang Hecht
+       Janet Hempstead
+       Michael Hennecke
+       Randolph J. Herber
+       Allen Hewes
+       Andrew Hill
+       Kurt Hillig
+       Steven Hinkle
+       Paul Hite
+       Billy Ho
+       Michael Hocke
+       Brett Hogden
+       Gaylord Holder
+       Kjetil Torgrim Homme
+       Pekka Honkanen
+       Jeffrey C. Honig
+       Heidi Hornstein
+       Michael A. Hovan III
+       Barbara Howe
+       J. Nelson Howell
+       Jeff Howie
+       Louis Huemiller
+       John Hughes
+       Gerrit Huizenga
+       Peter Ilieve
+       Mayer Ilovitz
+       Gregory A. Ivanov
+       John Jackson
+       Kurt Jaeger
+       Edward Jajko
+       Marian Jancar
+       Paul Jarc
+       Jakub Jelinek
+       Robert Jelinek
+       Bruce Jerrick
+       Carl Johnson
+       Dion Johnson
+       Jeff Johnson
+       Douglas B. Jones
+       LaMont Jones
+       Peter Jordan
+       Arne H. Juul
+       Pasi Kaara
+       Frank Kaefer
+       Keith Kalet
+       Claus Kalle
+       Henri Karrenbeld
+       Amir Katz
+       Henry Katz
+       Kawaljeet Kaur
+       Doug Kehn
+       Kris Kennaway
+       Terry Kennedy
+       Shane Kenney
+       Andrew Kephart
+       Robert Kiessling
+       Joshua Kinard
+       Don Kirouac
+       Steve Kirsch
+       Philip Kizer
+       Thomas Klausner
+       Ronald Klop
+       Roger Klorese
+       Peter Klosky
+       Przemek Klosowski
+       Angelos D. Keromytis
+       Radko Keves
+       Valdis Kletnieks
+       Chris Kordish
+       Alek O. Komarnitsky
+       Joseph Kowalski
+       Christian Krackowizer
+       Paul Kranenburg
+       Troyan Krastev
+       Brad Krebs
+       Alex Kreis
+       Johannes Kroeger
+       Vincent Kujala
+       Ken Laing
+       Shirley Lam
+       Erwin Lansing
+       Victoria H. Lau
+       Markus Lautenbacher
+       Steve Lacey
+       Marc Aurele La France
+       Chad R. Larson
+       Steve Laubscher
+       Andrei V. Lavreniyuk
+       Loc Le
+       Tin Le
+       Diane Lebel
+       Francis Le Bourse
+       Kyungjoon Lee
+       Marty Leisner
+       Maciej Lesniewski
+       Stuart Levy
+       Ben Lewis
+       Michael Lewis
+       Angel Li
+       Ambrose Li
+       Wendy Lin
+       Carl E. Lindberg
+       Onno van der Linden
+       Johan Lindquist
+       James Lingard
+       Jason Lingohr
+       Robert Lipe
+       Gabor Liptak
+       Friedel Loinger
+       Michael Long
+       Pete Lord
+       Steve Logue
+       Bela Lubkin
+       Pav Lucistnik
+       Horst Luehrsen
+       Andreas Luik
+       Timothy J. Luoma
+       Michael Mackenzie
+       Lawrence MacIntyre
+       Jerome Marchand
+       Benson Margulies
+       Claude Marinier
+       Chris Markle
+       Roy Marples
+        Ed Maste
+       Eberhard Mater
+       James Mathiesen
+       Tom Matthews
+       Fletcher Mattox
+       David Mazieres
+       Brian McAllister
+       Scott McClung
+       Dale McCluskey
+       Terry McCoy
+       Sean McDermott
+       Duncan McEwan
+       Dwight McKay
+       William McVey
+       Eric McWhorter
+       Marjo F. Mercado
+       Dan Mercer
+       Bill Melvin
+       Andrew Merril
+       Richard van Meurs
+       Jim Mewes
+       Ivan Melnikov
+       Conrad Meyer
+       Hendrik Meyer
+       Gary Millen
+       Timothy Miller
+       Davin Milun
+       Yuliy Minchev
+       Jim Mintha
+       Mike Miscevic
+       Arkadiusz Miskiewicz
+       Janardhan Molumuri
+       Nasser Momtaheni
+       Laurent Montaron
+       Doug Moore
+       Phillip Moore
+       Dmitry Morozovsky
+       John Paul Morrison
+       John Gardiner Myers
+       Jeffrey Mogul
+       Dave Morrison
+       Pat Myrto
+       Toshiya Nakamura
+       Filippo Natali
+       Allan Nathanson
+       Chance Neale
+       Dan Nelson
+       Vladislav Nespor
+       Bjorn S. Nilsson
+       Anders Nordby
+       Joseph J. Nuspl Jr.
+       David O'Brien
+       Alexandre Oliva
+       Craig B. Olofson
+       Dave Olson
+       Rainer Orth
+       Sergey A. Osokin
+       Keith Parks
+       Will Partain
+       Vasco Pedro
+       Mark Peek
+       Ezra Peisach
+       Bill Pemberton
+       Lee Penn
+       Gildas Perrot
+       Jesse Perry
+       Nathan Peterson
+       Dominique Petitpierre
+       Hung Pham
+       Ray Phillips
+       Francois Pinard
+       Gary Plewa
+       Alex Podlecki
+       Lutz Poetschulat,
+       John Polstra
+       Scott Presnell
+       Mark Price
+       Philippe-Andre Prindeville
+       Kristof Provost
+       David Putz
+       Tom Qin
+       Jan Rybar
+       Kurtis Rader
+       Peter Radig
+       Jean-Pierre Radley
+       Tim Ramsey
+       Dewan Rashid
+       Richard J. Rauenzahn
+       Louis Rayman
+       Brian Redman
+       Eric S. Raymond
+       Erwin Reyns
+       Aaron Rhodes
+       Jim Reid
+       Jean-Luc Richier
+       Clint Roberts
+       Ingimar Robertson
+       Sylvain Robitaille
+       Larry Rogers
+       Malgorzata Roos
+       Larry Rosenman
+       Stephan Rossi
+       Kevin Ruderman
+       Wolfgang Rupprecht
+       Pavol Rusnak
+       Eygene Ryabinkin
+       Conrad J. Sabatier
+       Klaus Saggerer
+       Chris Schanzle
+       Igor Schein
+       Horst Scheuermann
+       Peter Schiffer
+       Michael Schmitz
+       Larry Schwimmer
+       Cy Schubert
+       Hendrik G. Seliger
+       Igor V. Semenyuk
+       Jonathan Sergent
+       Frank Sanders
+       Berkley Shands
+       Gregory Neil Shapiro
+       Eyal Shaynis
+       Michael Shields
+       Wesley Shields
+       Philip Shin
+       Anthony Shortland
+       Dave Sill
+       John Silva
+       Chuck Silvers
+       Gerry Singleton
+       Leonard Sitongia
+       Kevin Smallwood
+       Gleb Smirnoff
+       Curt Smith
+       Ben Smithurst
+       Douglas R. Smith
+       Kevin Smith
+       Chang Song
+       Josh Soref
+       John Speno
+       Kenneth Stailey
+       Piet Starreveld
+       David Steiner
+       Charles Stephens
+       Marc Stephenson
+       Chip Stettler
+       Dave Stevens
+       Jeff Stewart
+       Diana Stockdale
+       Andreas Stolcke
+       Jeff Stoner
+       Kristyna Streitova
+       Sushila Subramanian
+       Jan Ole Suhr
+       Mike Sullivan
+       Patrick D. Sullivan
+       Peter Svensson
+       Chris Sylvain
+       Miklos Szeredi
+       Paul Szabo
+       Dale Talcott
+       Jon A. Tankersley
+       Jan Tax
+       Samuel Thibault
+       Andy Thomas
+       Matthew Thurmaier
+       Chris Timmons
+       Andrzej Tobola
+       R. Lindsay Todd
+       Zdenko Tomasic
+       Michael Townsend
+       Linus Torvalds
+       Mike Tracy
+       Jeff Trawick
+       Dan Trinkle
+       Erik Trulsson
+       Lars Tunkrans
+       Lenny Turetsky
+       Kevin Vajk
+       Peter Valchev
+       John R. Vanderpool
+       Peter Van Epp
+       Peter C. Vernam
+       Peter Vines
+       Bob Ward
+       Jules van Weerden
+       Tom Weaver
+       Fernando A.B. Whitaker
+       Tom Whitty
+       Carson Wilson
+       David J. Wilson
+       Frank Winkler
+       Marc Winkler
+       Mark Vasoll
+       Holger VanKoll
+       Robert Vernon
+       Joep Vesseur
+       Larry Virden
+       Jos Vos
+       Jun Biao Wang
+       Christopher J Warweg
+       Bill Watson
+       Florian M. Weps
+       Joel White
+       Paul Wickman
+       Martin Wilke
+       Eric Williams
+       Steve Williams
+       Steve Wilson
+       Erich Wimmer
+       Wally Winzer, Jr.
+       Patrick Wolfe
+       Stephen Woods
+       James Woodward
+       Scott Worley
+       Jan Wortelboer
+       Joshua Wright
+       Sailu Yallapragada
+       Masatake YAMATO
+       Donna Yobs
+       Ron Young
+       Warren Young
+       Blair Zajac
+       Karel Zak
+       Donald Zoch
+       Malcom Zung
+       Waldemar Zurowski
+       @eranik (github account)
+       @jolmg  (github account)
+       yasu@utahime.org (email)
+       jamie@catflap.org (email)
+       @hardikpnsp (github account)
+       Martin D Kealey
+       Henry Peteet
+       @zhrf2020
+       @JustAnotherArchivist
+       @po5857
+       @albert-github
+       Tobias Geerinckx-Rice
+       Andres Salomon
+       Nicholas Bamber
+       Grisha Levit
+       @10ne1 (github account)
+       @a1346054
+       Damjan Jovanovic
+       Fabrice Fontaine
+       Danny Fowler
+       Benny "BenBE" Baumann
+       Robert Geislinger (Alienmaster)
+       Subhaditya Nath
+       Sergei Trofimovich (@trofi)
+       Danilo Spinella (@danyspin97)
+       Jiajie Chen (@jiegec)
+       Jacob Chapman (@chapmanjacobd)
+       Teng Hu (@Hunter1016)
+       Li Zeming (@likunyur)
+       Sam James (@thesamesam)
+       Warner Losh (@bsdimp)
+       Andrew Athan (@aathan)
+       Florian Weimer (@fweimer-rh)
+       Andreas Schwab (@andreas-schwab)
+       @oldmanhere
+       @mjoerg
+       Subhaditya Nath (@subnut)
+       Linjie Li (@uniontech-lilinjie)
+       Clement Martin (@clementmartin)
+       Kalin KOZHUHAROV (@thinrope) and
+       Rui Chen (@chenrui333)
+
+If I have omitted a contributor's name, the fault is wholly mine,
+and I apologize for the error.
+
+Vic Abell <abe@purdue.edu>
+March 27, 2018
+
+Masatake YAMATO <yamato@redhat.com> (since revision 4.92.1)
+October 4, 2020
diff --git a/docs/faq.md b/docs/faq.md
new file mode 100644 (file)
index 0000000..2b42765
--- /dev/null
@@ -0,0 +1,3085 @@
+# Frequently Asked Questions
+
+Caveat: most of the FAQ comes from the original lsof, which may be outdated.
+
+## When Lsof Seems to Hang
+
+On occasion when you run lsof it seems to hang and produce no
+output.  This may result from system conditions beyond the control
+of lsof.  Lsof has a number of options that may allow you to
+bypass the blockage.
+
+### Kernel lstat(), readlink(), and stat() Blockages
+
+Lsof uses the kernel (system) calls lstat(), readlink(), and
+stat() to locate mounted file system information.  When a file
+system has been mounted from an NFS server and that server is
+temporarily unavailable, the calls lsof uses may block in the
+kernel.
+
+Lsof will announce that it is being blocked with warning messages
+(unless they have been suppressed by the lsof builder), but
+only after a default waiting period of fifteen seconds has
+expired for each file system whose server is unavailable.  If
+you have a number of such file systems, the total wait may be
+unacceptably long.
+
+You can do two things to shorten your suffering: 1) reduce the
+wait time with the -S option; or 2) tell lsof to avoid the
+kernel calls that might block by specifying the -b option.
+
+```shell
+$ lsof -S 5
+# or
+$ lsof -b
+```
+
+Avoiding the kernel calls that might block may result in the
+lack of some information that lsof needs to know about mounted
+file systems.  Thus, when you use -b, lsof warns that it might
+lack important information.
+
+The warnings that result from using -b (unless suppressed by
+the lsof builder) can themselves be annoying.  You can suppress
+them by adding the -w option.  (Of course, if you do, you won't
+know what warning messages lsof might have issued.)
+
+```shell
+$ lsof -bw
+```
+
+Note: if the lsof builder suppressed warning message issuance,
+you don't need to use -w to suppress them.  You can tell what
+the default state of message warning issuance is by looking at
+the -h (help) output.  If it says `-w enable warnings` then
+warnings are disabled by default; `-w disable warnings`, they
+are enabled by default.
+
+### Problems with /dev or /devices
+
+Lsof scans the /dev or /devices branch of your file system to
+obtain information about your system's devices.  (The scan isn't
+necessary when a device cache file exists.)
+
+Sometimes that scan can take a very long time, especially if
+you have a large number of devices, and if your kernel is
+relatively slow to process the stat() system call on device
+nodes.  You can't do anything about the stat() system call
+speed.
+
+However, you can make sure that lsof is allowed to use its
+device cache file feature.  When lsof can use a device cache
+file, it retains information it gleans via the stat() calls
+on /dev or /devices in a separate file for later, faster
+access.
+
+The device cache file feature is described in the lsof man
+page.  See the DEVICE CACHE FILE, LSOF PERMISSIONS THAT AFFECT
+DEVICE CACHE FILE ACCESS, DEVICE CACHE FILE PATH FROM THE -D
+OPTION, DEVICE CACHE PATH FROM AN ENVIRONMENT VARIABLE,
+SYSTEM-WIDE DEVICE CACHE PATH, PERSONAL DEVICE CACHE PATH
+(DEFAULT), and MODIFIED PERSONAL DEVICE CACHE PATH sections.
+
+There is also a separate file in the lsof distribution, named
+00DCACHE, that describes the device cache file in detail,
+including information about possible security problems.
+
+One final observation: don't overlook the possibility that your
+/dev or /devices tree might be damaged.  See if
+
+```shell
+$ ls -R /dev
+# or
+$ ls -R /devices
+```
+
+completes or hangs.  If it hangs, then lsof will probably hang,
+too, and you should try to discover why ls hangs.
+
+### Host and Service Name Lookup Hangs
+
+Lsof can hang up when it tries to convert an Internet dot-form
+address to a host name, or a port number to a service name.  Both
+hangs are caused by the lookup functions of your system.
+
+An independent check for both types of hangs can be made with
+the netstat program.  Run it without arguments.  If it hangs,
+then it is probably having lookup difficulties.  When you run
+it with -n it shouldn't hang and should report network and port
+numbers instead of names.
+
+Lsof has two options that serve the same purpose as netstat's
+-n option.  The lsof -n option tells it to avoid host name
+lookups; and -P, service name lookups.  Try those options when
+you suspect lsof may be hanging because of lookup problems.
+
+```shell
+$ lsof -n
+# or
+$ lsof -P
+# or
+$ lsof -nP
+```
+
+### UID to Login Name Conversion Delays
+
+By default lsof converts User IDentification (UID) numbers to
+login names when it produces output.  That conversion process
+may sometimes hang because of system problems or interlocks.
+
+You can tell lsof to skip the lookup with the -l option; it
+will then report UIDs in the USER column.
+
+```shell
+$ lsof -l
+```
+
+## General Concepts
+
+### Lsof -- what is it?
+
+Lsof is a UNIX-specific tool.  Its name stands for LiSt
+Open Files, and it does just that.  It lists information
+about files that are open by the processes running on a
+UNIX system.
+
+See the lsof [man page](./manpage.md), the 00DIST file, the
+[tutorial](./tutorial.md) and the README.md file of the lsof distribution for
+more information.
+
+### Where do I get lsof?
+
+Lsof is available at [GitHub lsof-org/lsof](https://github.com/lsof-org/lsof).
+
+You can find the latest releases from [GitHub Releases](https://github.com/lsof-org/lsof/releases)
+
+### Are lsof executable available?
+
+You can install lsof from package managers.
+
+If you must use a binary file, please be conscious of the
+security and configuration implications in using an executable.
+
+Three additional cautions apply to executables:
+
+1.  Don't try to use an lsof executable, compiled for one
+       version of a UNIX dialect, on another.  Patches can
+       make the dialect version different.
+
+2.  If you want to use an lsof binary on multiple systems,
+       they must be running the same dialect OS version and
+       have the same patches and feature support.
+
+### Where can I get more lsof documentation?
+
+A significant set of documentation may be found in the lsof distribution (See
+"Where can I get lsof?).  There is a [manual page](./manpage.md), and a copy of
+this FAQ in the file docs/faq.md (perhaps slightly less recent than this file if
+you're reading it via a web browser.)
+
+Two URLs provide some documentation that appears in the
+lsof distribution:
+
+FAQ: [https://lsof.readthedocs.io/en/latest/faq](https://lsof.readthedocs.io/en/latest/faq)
+
+man page: [https://lsof.readthedocs.io/en/latest/manpage](https://lsof.readthedocs.io/en/latest/manpage)
+
+### How do I report an lsof bug?
+
+If you believe you have discovered a bug in lsof, you can report it to
+https://github.com/lsof-org/lsof.  Do NOT report lsof bugs to the UNIX
+dialect vendor.
+
+Before you send a bug report, please read the "Bug Reports" section of
+the 00README file of the lsof distribution.  It lists the steps you
+should take before and when reporting a suspected bug.
+
+### Where can I get the lsof FAQ?
+
+This lsof FAQ is available in the file 00FAQ in the lsof
+distribution and at the URL:
+
+[https://lsof.readthedocs.io/en/latest/faq/](https://lsof.readthedocs.io/en/latest/faq/)
+
+### How timely is the on-line FAQ?
+
+The on-line FAQ is sometimes too timely.  :-)
+
+I update it as soon as new information is available.   That may include
+information about support that won't appear in the lsof source distribution
+until the next revision.  If you encounter something like that, please file a
+new issue at GitHub. 
+
+### Is there a test suite?
+
+Yes, as of lsof revision 4.63 there's an automated lsof
+test suite in the tests/ sub-directory of the lsof top-level
+directory.
+
+More information on using the test suite, what it does,
+how to use it and how to configure it may be found in the
+00TEST file of the lsof distribution.  That file also
+explains where the test suite has been tested.
+
+Frequently asked questions about the test suite will be
+asked and answered here in the FAQ.  (See "Test Suite
+Problems.")
+
+After lsof has been configured with the Configure script,
+lsof can be made and tested with:
+
+       $ make
+       $ cd tests
+       $ make
+
+Under normal conditions -- i.e., unless the lsof tree has
+been cleaned or purged severely -- all tests or individual
+tests may be run by:
+
+       $ cd test
+       $ make
+       # or
+       $ <run a single test>   (See 00TEST.)
+
+### Is lsof vulnerable to the standard I/O descriptor attack?
+
+Lsof revisions 4.63 and above are not vulnerable.
+
+Lsof revisions 4.62 and below are vulnerable, but no damage
+scenarios have so far been demonstrated.
+
+The standard I/O descriptor attack is a local programmed
+assault on setuid and setgid programs that tricks them into
+opening a sensitive file with write access on a standard
+descriptor, usually stderr (2), and writing error messages
+to stderr.  If the attacker can control the content of the
+error message, the attacker may gain elevated privileges.
+
+The attack was first described in Pine Internet Advisory
+PINE-CERT-20020401, available at:
+
+       http://www.pine.nl/advisories/pine-cert-20020401.txt
+
+If you are using an lsof revision below 4.63, you should
+remove any setuid or setgid permissions you might have
+given its executable.  Then you should upgrade to lsof
+revision 4.63.
+
+### Can I alter lsof's make(1) behavior?
+
+Yes.  There are at least two ways to do that.
+
+You can put replacements for lsof Makefile strings in your
+environment.  If you specify the -e make option, make will
+give environment variable values precedence over strings
+from the Makefile.  For example, to change the compiler
+string CC from the environment, you might do this with the
+Bourne shell:
+
+       $ CC=foobar; export CC
+       $ make -e
+
+You can also replace lsof Makefile strings in the make
+command invocation.  Here's the previous example done that
+way:
+
+       $ make CC=foobar
+
+Changing the CFGF, CFGL, and DEBUG strings used in lsof
+Makefiles, either from the environment or from the make
+invocation, can significantly alter lsof make(1) behavior.
+I commonly use DEBUG to change the -O option to -g so I
+can build an lsof executable for debugging -- e.g.,
+
+       $ make DEBUG=-g
+
+(Look for DEBUG in this FAQ for other examples of its use.)
+
+Consult the Makefiles to see what CFGL, CFGL, and other
+lsof Makefile strings contain, and to see what influence
+their alteration might have on lsof make(1) behavior.
+
+### Is there an lsof license?
+
+No.
+
+The only restriction on the use or redistribution of lsof
+is contained in this copyright statement, found in every
+lsof source file.  (The copyright year in or format of the
+notice may vary slightly.)
+
+       /*
+        * Copyright 2002 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.
+        */
+
+### Language locale support
+
+#### Does lsof support language locales?  How do I use the support?
+
+Most UNIX dialect versions of lsof support 8 bit language
+locale characters -- e.g., the ability to print 8 bit
+characters that have accents and other marks over them.
+
+See the answer to the "Does lsof support wide characters in
+language locales?" question for information on when lsof's
+language locale support covers characters wider than 8 bits.
+
+To see if lsof supports language locales for your dialect, look
+in the dialect's machine.h header file for the HASSETLOCALE
+definition.  If it is present and not disabled, then lsof has
+language locale support for the dialect.
+
+To enable lsof's language locale support, you must specify in a
+locale environment variable (e.g., LANG) a language locale
+known to your system that supports the printing of marked
+characters -- e.g, en_US.  (On some dialects locale(1) may be
+used to list the known language locales.)
+
+Note that LANG=C and LANG=POSIX are NOT language locales that
+support the printing of marked characters.
+
+If the language locale doesn't support the printing of marked
+characters, lsof's OUTPUT of them follows the rules for
+non-printable characters described in the OUTPUT section of
+lsof(8).
+
+Consult your dialect's setlocale(3) man page for the names of
+environment variables other than LANG  -- e.g., LC_ALL,
+LC_TYPE, etc. -- which may be used to define language locales.
+
+#### Does lsof support wide characters in language locales?
+
+When lsof's language locale support is enabled with the
+HASSETLOCALE definition, for selected dialects lsof will also
+print wide characters (e.g., from UTF-8) when iswprint(3)
+reports them to be printable.
+
+Wide character support is available when HASWIDECHAR is defined
+in a dialect's machine.h header file.  As of this writing on
+July 22, 2004, the following dialect versions have wide character
+support:
+
+       AIX >= 4.3.2
+       Apple Darwin >= 7.3.0
+       FreeBSD >= 5.2
+       HP-UX >= 11.00
+       /proc-based Linux
+       NetBSD >= 1.6
+       SCO OpenServer >= 5.0.6
+       Solaris >= 2.6
+       Tru64 UNIX 5.1
+
+### Are any files in the lsof distribution copyrighted?
+
+Yes.  Most files carry the copyright of the Purdue Research
+Foundation and may be redistributed under the terms that
+accompany the copyright notice.  Those terms may also be found
+in the answer to the question, "Is there an lsof license?")
+
+A few files carry other copyright notices.  Some are BSD
+notices and they explain the terms under which they are
+included in the lsof distribution.
+
+Those that carry vendor copyright notices have been reproduced
+in their original or modified forms with permission from the
+copyright owners.  That permission is indicated in the README
+files that accompany the files.
+
+### Are there other lsof-related resources?
+
+There are other resources available, connected to lsof.  Among
+them are FreeBSD and Linux packages whose products use lsof and
+two particularly interesting resources.
+
+The two interesting resources are a Gnome Tool Kit (GTK) GUI
+for lsof and a Perl wrapper module.
+
+The GTK GUI is called Glsof and was developed by Gnele.  It can
+be found at:
+
+       http://www.sourceforge.net
+
+The Perl wrapper module by Marc Beyer can be found at:
+
+       http://search.cpan.org/dist/Unix-Lsof/
+
+### What does the "WARNING: unsupported dialect or version" mean?
+
+The lsof configure script issues that message for UNIX dialects
+or their versions where I have been unable to test the current
+revision of lsof.  The message doesn't mean that lsof won't
+work, just that I have no direct evidence that it will.
+
+If the Configure script succeeds, except for the warning, try
+compiling) lsof.  If that succeeds, try the lsof test suite.
+
+## Lsof Ports
+
+### What ports exist?
+
+The pub/lsof.README file carries the latest port information:
+
+       AIX 5.[23] and 5.3
+       FreeBSD 4.9 and 6.4 for x86-based systems
+       FreeBSD 8.[234], 9.0, 10.0 and 11.0 for AMD64-based systems
+       Darwin(macOS) for AMD64/ARM64-based systemd
+       Linux 2.1.72 and above for x86-based systems
+       Solaris 9, 10 and 11
+
+In the above list the only UNIX dialects present are ones for
+which I test the current lsof revision.  Lsof may still support
+unlisted dialect versions -- e.g., HP-UX 10.20, Solaris 7, etc.
+-- but I don't have access to systems where I could test lsof
+on them, so I can't claim lsof works on them. If your dialect
+isn't in the list, you should try building lsof on it anyway.
+
+Lsof version 4 predecessors, versions 2 and 3, may support older
+version of some dialects.  Contact me via e-mail at <abe@purdue.edu>
+if you're interested in their distributions.  Make sure "lsof"
+appears in the "Subject:" line so my e-mail filter won't classify
+your letter as Spam.
+
+### What about a new port?
+
+The 00PORTING file in the distribution gives hints on doing
+a port.  I will consider doing a port in exchange for
+permanent access to a test host.  I require permanent access
+so I can test new lsof revisions, because I will not offer
+distributions of dialect ports I cannot upgrade and test.
+
+#### User-contributed Ports
+
+Sometimes I receive contributions of ports of lsof to
+systems where I can't test future revisions of lsof.  Hence,
+I don't incorporate these contributions into my lsof
+distribution.
+
+However, I do make descriptions of these contributions
+available.  You can find them in the 00INDEX and README
+files at:
+
+       ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/contrib
+
+Consult the 00INDEX file in the contrib/ directory for a
+list of the available contributions and consult README
+there for information on how to obtain them.
+
+### Why isn't there an AT&T SVR4 port?
+
+I haven't produced an AT&T SVR4 port because I haven't seen
+a UNIX dialect that is strictly limited to the AT&T System
+V, Release 4 source code.  Every one I have seen is a
+derivative with vendor additions.
+
+The vendor additions are significant to lsof because they
+affect the internal kernel structures with which lsof does
+business.  While some vendor derivatives of SVR4 are similar,
+each one I have encountered so far has been different enough
+from its siblings to require special source code.
+
+If you're interested in an SVR4 version of lsof, here are
+some existing ports you might consider:
+
+       DC/OSx (This obsolete port is only available upon
+               special request.)
+       Reliant UNIX (This obsolete port is only available
+                       upon special request.)
+       SCO|Caldera UnixWare (This is the most likely choice.)
+       Solaris
+
+### Why isn't there an SGI IRIX port?
+
+Lsof support for IRIX was terminated at lsof revision 4.36,
+because it had become increasingly difficult for me to
+obtain information on the IRIX kernel structures lsof needs
+to access.
+
+At IRIX 6.5 I decided the obstacles were too large for me
+to overcome, and I stopped supporting lsof on IRIX.  I have
+sources to the last revision of lsof (4.36) for IRIX, but
+that version of lsof does not work on IRIX 6.5 and is
+vulnerable to the standard I/O descriptor attack.  (See
+the "Is lsof vulnerable to the standard I/O descriptor
+attack?" Q&A for more information.) Contact me to discuss
+obtaining those sources.
+
+If you wish to pursue the issue, don't contact me, contact
+SGI.  This case was opened with SGI on the subject:
+
+       Case ID:        0982584
+       Category: Unix
+       Priority: 30-Moderate Impact
+
+       Problem Summary:
+       kernel structure header files needed for continued lsof
+       support
+
+       Problem Description:
+       Email In  07/17/98 19:09:23
+
+### Why does lsof's Configure script report "WARNING: unsupported
+dialect or version"?
+
+Lsof's Configure script issues this message when it encounters
+a dialect or its version that lsof once supported, but no
+longer does.  Usually I drop support for a dialect or version
+when I can no longer test lsof on it.
+
+However, it's worth trying to compile and use lsof.  Be sure to
+run the test suite.  (See the answer to the "Is there a test
+suite?  question for information on the test suite.)
+
+If you have problems with an unsupported dialect or version,
+file a new GitHub issue and I may be able to help.
+
+
+## Lsof Problems
+
+### Configuration Problems
+
+#### Why can't Configure determine the UNIX dialect version?
+
+The lsof Configure script uses UNIX shell commands, often in a
+command pipeline, to determine the UNIX dialect version.
+(Consult the dialect stanza in Configure to determine which
+commands are used.)  If Configure can't determine the dialect
+version, probably one of the commands is not behaving as
+Configure expects.
+
+Symptoms of the failure include Configure warning messages and
+incorrect version definitions in the Makefile CFLAGS.
+
+If you suspect that the lsof Configure script is failing to
+determine the dialect version correctly, try running the
+commands from Configure stanza one at a time.  That will
+usually reveal the source of the problem.  Be particularly
+mindful that the PATH environment variable can cause commands
+to be executed from non-standard directories.
+
+If you can't determine the source of the problem, there is a
+work-around.  You can supply the UNIX dialect version in the
+LSOF_VSTR environment variable.  Use Configure as a guide to
+forming what it expects in LSOF_VSTR.  There is also some
+information on  LSOF_VSTR in the 00XCONFIG documentation file
+of the lsof distribution.
+
+### Compilation Problems
+
+#### Why does the compiler complain about missing header files?
+
+When you use make to build lsof, the compiler may complain
+that it can't find header files -- e.g.,
+
+       $ make
+       (cd lib; make DEBUG="-O" CFGF="-DAIXA=0 -DAIXV=4330 \
+       -DLSOF_VSTR=\"4.3.3.0\"")
+       gcc  -DAIXA=0 -DAIXV=4330 -DLSOF_VSTR="4.3.3.0" -O \
+       -c ckkv.c
+       In file included from ckkv.c:33: ../machine.h:70: \
+       sys/types.h: A file or directory in the path name \
+       does not exist. \
+
+That type of complaint doesn't represent an lsof problem.
+It represents a problem with a missing system header file
+that probably should be found in /usr/include or in the
+system source tree.
+
+As a first step try using find(1) to locate the problem
+header file.  If it's a system header file and can't be
+found, here are some possible causes:
+
+1. The file set, RPM or package containing the header files
+       has not been installed.  Instructions for doing that
+       are specific to the UNIX dialect and beyond the scope
+       of this document.
+
+2. If the compiler is gcc, the private gcc header files:
+
+       * May not have been installed;
+
+       * May have been installed incorrectly;
+
+       * May not have been updated properly after the last
+       compiler or system update;
+
+       * Ones from a previous installation may not have been
+       removed.
+
+       A path leading to the gcc private header files can be
+       found with `gcc -v`.  Consult the gcc documentation for
+       instructions on proper installation of the private gcc
+       header files.
+
+3. On some dialects -- e.g., FreeBSD, NetBSD, OpenBSD --
+       lsof may need to use header files that are located in
+       the system source tree -- /sys or /usr/src/sys, for
+       example.  Make sure the system source tree has been
+       installed.
+
+#### Why does gcc complain about the contents of header files
+distributed by the system's vendor?
+
+When you use make to build lsof and gcc to compile it, gcc
+may complain that it finds errors in system header files
+-- e.g.,
+
+       $ make
+       (cd lib; make DEBUG="-O" CFGF="-Dsolaris=80000 \
+       -DHASPR_GWINDOWS -m64 -DHASIPv6 -DHAS_VSOCK \
+       -DLSOF_VSTR=\"5.8\"")
+       gcc -Dsolaris=80000  -DHASPR_GWINDOWS -m64 -DHASIPv6 \
+       -DHAS_VSOCK -DLSOF_VSTR="5.8"  -O  -c  dvch.c
+       In file included from /usr/include/sys/proc.h:31, \
+       from /homes/abe/gnu/gcc-3.2.1/lib/gcc-lib/sparcv9-sun-solaris2/ \
+       3.2.1/include/sys/user.h:267, from /usr/include/kvm.h:13, \
+       from ../dlsof.h:53, from ../lsof.h:172, from dvch.c:43: \
+       /homes/abe/gnu/gcc-3.2.1/lib/gcc-lib/sparcv9-sun-solaris2/\
+       3.2.1/include/sys/task.h:59: parse error before "uint_t"
+
+Errors like the above are most likely not problems in the
+system's header files, but in the private copies of them
+that were created when gcc was made or installed.  Note
+the presense of
+".../gcc-3.2.1/lib/gcc-lib/sparcv9-sun-solaris2/3.2.1/include/..."
+in the paths for user.h and task.h.  It indicates both
+header files are gcc-specific.
+
+To solve errors like this requires comparing the header
+files in the vendor's /usr/include tree to the gcc-specific
+ones in gcc's private gcc-lib/.../include tree.  It may be
+necessary to regenerate gcc-specific header files, correct
+them or remove them.  See the gcc distribution for the
+appropriate tools.
+
+A possible temporary work-around is to direct gcc to use
+the vendor's header files instead of its temporary ones by
+declaring -I/usr/include in the compilation flags.
+
+#### Other header file problems
+
+Don't overlook any vendor tools that might validate the
+vendor header files installed on the system  -- e.g., the
+Solaris pkgchk tool can be used to check the header files
+that were installed from the SUNWhea package.
+
+For other header file problems contact me at <abe@purdue.edu>.
+Please follow the reporting guidelines in the "How do I
+report an lsof bug?" section of this FAQ.
+
+### Why doesn't lsof report full path names?
+
+Lsof reports the full path name when it is specified as a
+search argument for open files that match the argument.
+However, if the argument is a file system mounted-on
+directory, and lsof finds additional path name components
+from the kernel name cache, it will report them.
+
+Lsof reports path name for file system types that have path
+name lookup features -- e.g., some versions of AdvFS for
+Digital and Tru64 UNIX.  The Linux /proc-based lsof reports
+full path names, because the Linux /proc file system provides
+them.  Lsof on recent builds of Solaris 10 also report full
+path names, because those Solaris kernels record the full path
+name in the vnode structure.
+
+Otherwise, lsof uses the kernel name cache, where it exists
+and can be accessed, and reports some or all path name
+components (e.g., the sys and proc.h components of
+/usr/include/sys/proc.h) for these dialects:
+
+       Apple Darwin
+       DC/OSx
+       FreeBSD
+       HP-UX, /dev/kmem and PSTAT based
+       Linux, /dev/kmem-based
+       NetBSD
+       OpenBSD
+       Reliant UNIX
+       SCO OpenServer
+       SCO|Caldera UnixWare
+       Solaris 2.x, 7, 8 and 9 (except for some VxFS versions;
+                                       see the "Why doesn't Solaris
+                                       lsof report VxFS path name
+                                       components?" section for more
+                                       information)
+       Solaris 10 (early builds) Tru64 UNIX
+
+As far as I can determine, AFS path lookups don't share in
+kernel name cache operations, so lsof can't identify open AFS
+path name components.  Apparently Solaris VxFS versions 4 and
+above don't share in kernel name cache operations, either, so
+lsof can't display path name components for those open files.
+
+Since the size of the kernel name cache is limited and the
+cache is in constant flux, it does not always contain the names
+of all components in an open file's path; sometimes it contains
+none of them.
+
+Lsof reports the file system directory name and whatever
+components of the file's path it finds in the cache, starting
+with the last component and working backwards through the
+directories that contain it.  If lsof finds no path
+components, lsof reports the file system device name instead.
+
+When lsof does report some path components in the NAME
+column, it prefixes them with the file system directory
+name, followed by " -- ", followed by the components --
+e.g., /usr -- sys/path.h for /usr/include/sys/path.h.  The
+" -- " is omitted when lsof finds all the path name components
+of a file's name.
+
+The PSTAT-based HP-UX lsof relies on kernel name cache
+contents, too, even though its information comes to lsof
+via pstat() function calls.  Consequently, PSTAT-based
+HP-UX lsof won't always report full paths, but may use the
+" -- " partial path name notation, or may occasionally
+report no path name at all but just the file system mounted-on
+directory and device names.
+
+Lsof can't obtain path name components from the kernel name
+caches of the following dialects:
+
+       AIX
+
+Only the Linux kernel records full path names in the
+structures it maintains about open files; instead, most
+kernels convert path names to device and node number doublets
+and use them for subsequent file references once files have
+been opened.
+
+To convert the device and node number doublet into a
+complete path name, lsof would have to start at the root
+node (root directory) of the file system on which the node
+resides, and search every branch for the node, building
+possible path names along the way.  That would be a time
+consuming operation and require access to the raw disk
+device (usually implying setuid-root permission).
+
+If the prospect of all that local disk activity doesn't
+concern you, think about the cost when the device is
+NFS-mounted.
+
+Try using the file system mount point and node number lsof
+reports as parameters to find -- e.g.,
+
+       $ find <mount_point> -inum <node_number> -print
+
+and you may get an appreciation of what a file system
+directory tree search would cost.
+
+#### Why do lsof -r reports show different path names?
+
+When you run lsof with its repeat (`-r`) option, you may
+notice that the extent to which it reports path names for
+the same files may vary from cycle to cycle.  That happens
+because other processes are making kernel calls affecting
+the cache and causing entries to be removed from and added
+to it.
+
+#### Why does lsof report the wrong path names?
+
+Under some circumstances lsof may report an incorrect path
+name component, especially for files in a rapidly changing
+directory like /tmp.
+
+In a rapidly changing directory, like /tmp, if the kernel
+doesn't clear the cache entry when it removes a file, a
+new file may be given the same keys and lead lsof to believe
+that the old cache entry with the same keys belongs to the
+new file.
+
+Lsof tries to avoid this error by purging duplicate entries
+from its copy of the kernel name cache when they have the
+same device and inode number, but different names.
+
+This error is less likely to occur in UNIX dialects where the
+keys to the name cache are node address and possibly a
+capability ID.  The Apple Darwin, Digital UNIX, FreeBSD, HP-UX,
+NEXTSTEP, OPENSTEP, Solaris, Tru64 UNIX, and UnixWare dialects
+use node address.  Apple Darwin, FreeBSD, NetBSD, OpenBSD,
+Tru64 UNIX, and also use a capability ID to further identify
+name cache entries.
+
+#### Why doesn't lsof report path names for unlinked (rm'd) files?
+
+When lsof gets path name components from the kernel's name
+cache, it does not report the path names of a file that has
+been unlinked from its parent directory -- e.g., deleted via
+rm, or the unlink() system call -- even when some process may
+still hold the file open; lsof reports only the file system's
+mounted-on directory and device.  That's because path name
+components are removed from the kernel name cache when the file
+is unlinked.
+
+Unlinked open files are sometimes used by applications for
+temporary, but invisible storage (i.e., ls won't show them,
+and no other process can open them.)  However, they may
+occasionally consume disk space to excess and cause concern
+for a system administrator, who will be unable to locate
+them with find, ls, du, or other tools that rely on finding
+files by examining the directory tree.
+
+By using lsof's +L option you can see the link count of
+open files -- in the NLINK column.  An unlinked file will
+have an NLINK value of zero.  By using the option +L1 you
+can tell lsof to display only files whose link count is
+less than one (i.e., zero).
+
+There are some UNIX dialect-specific exceptions to lsof's
+inability to report unlinked path names.  They are described in
+the answer to the "When will lsof report path names for deleted
+files?" question.
+
+#### Why doesn't lsof report the "correct" hard linked file path
+name?
+
+When lsof reports a rightmost path name component for a
+file with hard links, the component may come from the
+kernel's name cache.  Since the key which connects an open
+file to the kernel name cache may be the same for each
+differently named hard link, lsof may report only one name
+for all open hard-linked files.   Sometimes that will be
+"correct" in the eye of the beholder; sometimes it will
+not.  Remember, the file identification keys significant
+to the kernel are the device and node numbers, and they're
+the same for all the hard linked names.
+
+#### When will lsof report path names for deleted files?
+
+Lsof will report path names for deleted files for two
+dialects:  Linux and later builds of Solaris 10.
+
+Deleted Linux path names are reported by default and have
+"(deleted)" at their ends.
+
+The display of Solaris 10 deleted path names may be selected
+with the -X option.  When selected they are also reported with
+"(deleted)" at their ends.
+
+### Why is lsof so slow?
+
+Lsof may appear to be slow if network address to host name
+resolution is slow.  This can happen, for example, when the
+name server is unreachable, or when a Solaris PPP cache daemon
+is malfunctioning.
+
+To see if name lookup is causing lsof to be slow, turn it off
+with the `-n` option.
+
+Port service name lookup or portmap registration lookup may
+also be causes of slow-down.  To suppress port service name
+lookup, specify the `-P` option.
+
+Lsof doesn't usually make direct portmap calls -- only when +M
+is specified, or when HASPMAPENABLED is defined during lsof
+construction.  (The lsof help panel, produced with `lsof -h`
+will display the default portmap registration reporting
+state.)  The quickest first step in checking if lsof is slow
+because of the portmapper is to use lsof's `-M` option.
+
+Lsof may be slow if UID to login name lookups are slow.
+Suppress them with `-l`.
+
+On dialects where lsof uses the kernel name cache, try
+disabling its use with `-C`.  (You can tell if lsof uses the
+kernel name cache by looking for `-C` in lsof's `-h`
+output.)  Of course, disabling kernel name cache use will mean
+that lsof won't report full or partial path names, just file
+system and character device names.
+
+If you're just interested in the open files of one process, try
+using the `-p <Process-ID>` option to limit lsof to that
+process.  (The `-p` option may also be followed with a list
+of Process-IDs.)
+
+If you're interested in including or excluding certain
+commands, try lsof's "-c[^]cmd" option.
+
+If you're interested in certain Internet TCP and UDP states
+(e.g., ESTABLISHED) or in excluding some (e.g., CLOSE_WAIT),
+try lsof's "-s p:s" option, available where shown on the lsof
+help output, obtained with -h or -?.  More information on it
+may be found in the answer to the "How are protocol state name
+exclusion and inclusion used?" question.
+
+Your UNIX dialect may not support "-s p:s" and its associated
+performance improvments to Internet-only file processing.  You
+can find more information on those topics in the answer to the
+"Why doesn't my dialect support state name exclusion and
+inclusion?" question.
+
+Older AIX lsof may be slow to start because of its oslevel
+identity comparison.  (Newer AIX lsof uses uname(2).)  See the
+"Why does AIX lsof start so slowly?" and "Why does lsof warn
+"compiled for x ... y; this is z.?" sections for more
+information.
+
+### Why doesn't lsof's setgid or setuid permission work?
+
+If you install lsof on an NFS file system that has been
+mounted with the nosuid option, lsof may not be able to
+use the setgid or setuid permission you give it, complaining
+it can't open the kernel memory device -- e.g., /dev/kmem.
+
+The only solution is to install lsof on a file system that
+doesn't inhibit setgid or setuid permission.
+
+### Does lsof have security problems?
+
+I don't think so.  However, lsof does usually start with
+setgid permission, and sometimes with setuid-root permission.
+Any program that has setgid or setuid-root permission,
+should always be regarded with suspicion.
+
+Lsof drops setgid power, holding it only while it opens
+access to kernel memory devices (e.g., /dev/kmem, /dev/mem,
+/dev/swap).  That allows lsof to bypass the weaker security
+of access(2) in favor of the stronger checks the kernel
+makes when it examines the right of the lsof process to
+open files declared with -k and -m.  Lsof also restricts
+some device cache file naming options when it senses the
+process has setuid-root power.
+
+On a few dialects lsof requires setuid-root permission
+during its full execution in order to access files in the
+/proc file system.  These dialects include:
+
+       DC/OSx 1.1 for Pyramid systems
+       Reliant UNIX 5.4[34] for Pyramid systems
+
+When lsof runs with setuid-root permission it severely
+restricts all file accesses it might be asked to make with
+its options.
+
+The device cache file (typically .lsof_hostname in the home
+directory of the real user ID that executes lsof) has 0600
+modes.  (The suffix, hostname, is the first component of
+the host's name returned by gethostname(2).)  However, even
+when lsof runs setuid-root, it makes sure the file's
+ownerships are changed to that of the real user and group.
+In addition, lsof checks the file carefully before using
+it (See the question "How do I disable the device cache
+file feature or alter it's behavior?" for a description of
+the checks.); discards the file if it fails the scrutiny;
+complains about the condition of the file; then rebuilds
+the file.
+
+See the 00DCACHE file of the lsof distribution for more
+information about device cache file handling and the risks
+associated with the file.
+
+### Will lsof show remote hosts using files via NFS?
+
+No.  Remember, lsof displays open files for the processes
+of the host on which it runs.  If the host on which lsof
+is running is an NFS server, the remote NFS client processes
+that are accessing files on the server leave no process
+records on the server for lsof to examine.
+
+### Why doesn't lsof report locks held on NFS files?
+
+Generally lock information held by local processes on remote
+NFS files is not recorded by the UNIX dialect kernel.  Hence,
+lsof can't report it.
+
+One exception is some patch levels of Solaris 2.3, and all
+versions of Solaris 2.4 and above.  Lsof for those dialects
+does report on locks held by local processes on remotely
+mounted NFS files.
+
+#### Why does lsof report a one byte lock on byte zero as a full
+file lock?
+
+When a process has a lock of length one, starting at byte
+zero, lsof can't distinguish it from a full file lock.
+That's because most UNIX dialects represent both locks the
+same way in their file lock (flock or eflock) structures.
+
+### Why does lsof report different values for open files on the same file system (the automounter phenomenon)?
+
+On UNIX dialects where file systems may be mounted by an
+automounter with the `direct` type, lsof may sometimes
+report difference DEVICE, SIZE/OFF, INODE and NAME values
+when asked to report files open on the file system.
+
+This happens because some files open on the file system --
+e.g., the current directory of a shell that changed its
+directory to the file system as the file system's first
+reference -- may be characterized in the kernel with
+temporary automounter node information.  The cd doesn't
+cause the file system to be mounted.
+
+A subsequent reference to the file system -- e.g., an ls
+of any place in it -- will cause the file system to be
+mounted.  Processes with files open to the mounted file
+system are characterized in the kernel with data that
+reflects the mounted file system's parameters.
+
+Unfortunately some kernels (e.g., some versions of Solaris
+2.x) don't revisit the process that did only a change-directory
+for the purpose of updating the data associated with the
+open directory file.  The file continues to be characterized
+with temporary automounter information until it does another
+directory change, even a trivial `cd .`.
+
+Lsof will report on both reference types, when supplied
+the file system name as an argument, but the data lsof
+reports will reflect what it finds in the kernel.  For the
+different types lsof will display different data, including
+different major and minor device numbers in the DEVICE
+column, different lengths in the SIZE/OFF column, different
+node numbers in the INODE column, and slightly different
+file system names in the NAME column.
+
+In contrast, fuser, where available, can only report on
+one reference type when supplied the file system name as
+an argument.  Usually it will report on the one that is
+associated with the mounted file system information.  If
+the only reference type is the temporary automounter one,
+fuser will often be silent about it.
+
+### Why don't lsof and netstat output match?
+
+Lsof and netstat output don't match because lsof reports
+the network information it finds in open file system objects
+-- e.g., socket files -- while netstat often gets its
+information from separate kernel tables.
+
+The information available to netstat may describe network
+activities never or no longer associated with open files,
+but necessary for proper network state machine operation.
+
+For example, a TCP connection in the FIN_WAIT_[12] state
+may no longer have an associated open file, because the
+connection has been closed at the application layer and is
+now being closed at the TCP/IP protocol layer.
+
+#### Why can't lsof find accesses to some TCP and UDP ports?
+
+Lsof stands for LiSt Open Files.  If there is no open file
+connected to a TCP or UDP port, lsof won't find it.  That's
+the most common reason why lsof doesn't find a port netstat
+might report open.
+
+One reason I've found on some UNIX dialects is that their
+kernels set aside TCP and UDP ports for communicating with
+support activities, running in application layer servers
+-- the automounter daemons, and the NFS biod and nfsd
+daemons are examples.  Netstat may report the ports are in
+use, but lsof doesn't.
+
+Another reason is that netstat may also be able to report
+a port is open on a particular dialect, because it uses a
+source of data different from what lsof uses -- e.g.,
+netstat might examine kernel tables or use streams messages
+to MIB2, while lsof relies on the information it finds in
+open file structures and their descendants.
+
+Sometimes it's possible to search the data netstat and lsof
+use.  For example, on Linux /proc/tcp and /proc/udp can be
+examined.  There might an entry there for a particular
+protocol and port, but if the line on which the port appears
+doesn't have an inode number that matches an inode number
+of an open file, lsof won't be able to identify the process
+using the port.
+
+This is a tough question to which there is no easy answer.
+
+### Why does lsof update the device cache file?
+
+At the end of the lsof output you may see the message:
+
+       lsof: WARNING: /Homes/abe/.lsof_vic was updated.
+
+In this message /Homes/abe/.lsof_vic is the path to the
+private device cache file for login abe.  (See 00DCACHE.)
+
+Lsof issues this message when it finds it necessary to
+recheck the system device directory (e.g., /dev or /devices)
+and rebuild the device cache file during the open file
+scan.  Lsof may need to do these things it finds that a
+device directory node has changed, or if it cannot find a
+device in the cache.
+
+### Why doesn't lsof report state for UDP socket files?
+
+Lsof reports UDP TPI connection state -- TS_IDLE (Idle),
+TS_BOUND (Bound), etc. -- for some, but not all dialects.
+TPI state is stream-based TCP/IP information that isn't
+available in many dialects.
+
+A fairly weak general rule is if netstat(1) reports UDP
+TPI state, lsof may be able to report it, too.  But don't
+be surprised if lsof fails to report UDP TPI state for your
+dialect.  Other factors influence lsof's ability to report
+UDP TPI state, including the availability of state number
+data in kernel structures, and state number to state name
+conversion data.
+
+### I am editing a file with vi; why doesn't lsof find the file?
+
+Classic implementations of vi usually don't keep open the file
+being edited.  (Newer ones may do so in order to maintain an
+advisory lock.)  Instead classic vi opens the file, makes a
+temporary copy (usually in /tmp or /usr/tmp), and does its work
+in that file.  When you save the file being edited from a
+classic vi implementation, it reopens and rewrites the file.
+
+During a classic vi session, except for the brief periods when
+vi is reading or rewriting the file, lsof won't find an open
+reference to the file from the vi process, because there is
+none.
+
+### Why doesn't lsof report TCP/TPI window and queue sizes for my
+dialect?
+
+Lsof only reports TCP/TPI window sizes for Solaris, because
+only its netstat reports them.  The intent of providing
+TCP/TPI information in lsof NAME column output is to make
+it easier to match netstat output to lsof output.
+
+In general lsof only reports queue sizes for both TCP and
+UDP (TPI) connections on BSD-derived UNIX dialects, where
+both sets of values appear in kernel socket queue structures.
+SYSV-derived UNIX dialects whose TCP/IP implementations
+are based on streams generally provide only TCP queue sizes,
+not UDP (TPI) ones.
+
+While you may find that netstat on some SYSV-derived UNIX
+dialects with streams TCP/IP may report UDP (TPI) queue
+sizes, you will probably also find that the sizes are always
+zero -- netstat supplies a constant zero for UDP (TPI)
+queue sizes to make its headers align the same for TCP and
+UDP (TPI) connections.  Solaris seems to get it right --
+i.e., its netstat does not report UDP (TPI) queue sizes.
+
+When in doubt, I chose to avoid reporting UDP (TPI) queue
+sizes for UNIX dialects whose netstat-reported values I
+knew to be a constant zero or whose origin I couldn't
+determine.  OSR is a dialect in this category.
+
+#### Why doesn't lsof report socket options, socket states, and TCP
+flags and values for my dialect?
+
+The lsof -T argument, 'f', that selects the reporting of socket
+options, socket states and TCP flags was implemented at lsof
+revision 4.71 for the following UNIX dialects, providing the
+indicated information:
+
+       AIX 4.3.2 and 5.1 and above
+       All socket options and values, socket states, and TCP
+       flags and values described in lsof(8) are reported.
+       Apple Darwin 7.2 and above
+       All socket options and values, socket states, and TCP
+       flags and values described in lsof(8) are reported.
+       FreeBSD 4.9 and above
+       All socket options and values, socket states, and TCP
+       flags and values described in lsof(8) are reported.
+       HP-UX 11.00 (/dev/kmem-based lsof)
+       All socket options and values are reported.  No socket
+       states are reported.  Only the TF_NODELAY TCP flag and
+       the TF_MSS value are reported.
+       HP-UX 11.11 and iiiv2 (PSTAT-based lsof)
+       All socket options and values, and socket states are
+       reported.  No TCP flags or values are reported.
+       Linux
+       No socket options and values, socket states, or TCP
+       flags and values are reported.  The support for "-Tf"
+       could not be added to Linux, because socket options,
+       socket states, and TCP flags and values are not
+       available via the /proc file system.
+       NetBSD 1.6G and above
+       All socket options and values, socket states, and TCP
+       flags and values described in lsof(8) are reported.
+       OpenBSD 3.4 and above
+       All socket options and values, socket states, and TCP
+       flags and values described in lsof(8) are reported.
+       OpenUNIX 8
+       All socket options and values, socket states, and TCP
+       flags and values described in lsof(8) are reported.
+       SCO OpenServer Release 5.0.6
+       All socket options and values, socket states, and TCP
+       flags and values described in lsof(8) are reported.
+       Solaris 2.6, 8 and above
+       The socket option display is limited to BROADCAST,
+       DEBUG, DGRAM_ERRIND, DONTROUTE and OOBINLINE.  Socket
+       values are limited to KEEPALIVE and LINGER.  No socket
+       states are reported.  The TCP DELACK, NODELAY and
+       SENTFIN flags are reported.  The TCP MSS value is
+       reported.
+       UnixWare 7.1.[134]
+       All socket options and values, socket states, and TCP
+       flags and values described in lsof(8) are reported.
+
+#### Why doesn't lsof report the partial listen queue connection
+count for my dialect?
+
+The reporting of partial listen queue connections was added to
+-Tf processing at lsof revision 4.76.  Currently it is reported
+for these dialects:
+
+       AIX 4.3.2
+       This dialect is no longer supported, so no attempt
+       was made to add partial listen queue length support
+       for it.
+       AIX 5.1 and above
+       Partial listen queue information is available.
+       Apple Darwin 7.2 and above
+       Partial listen queue information is available.
+       FreeBSD 4.9 and above
+       Partial listen queue information is available.
+       HP-UX 11.00 (/dev/kmem-based lsof)
+       No partial listen queue information is available.
+       HP-UX 11.11 and iiiv2 (PSTAT-based lsof)
+       No partial listen queue information is available.
+       Linux
+       No partial listen queue information is available.
+       NetBSD 1.6G and above
+       Partial listen queue information is available.
+       OpenBSD 3.4 and above
+       Partial listen queue information is available.
+       OpenUNIX 8
+       This dialect is no longer supported, so no attempt
+       was made to add partial listen queue length support
+       for it.
+       SCO OpenServer Release 5.0.6
+       No partial listen queue information is available.
+       Solaris 2.6, 8 and above
+       Partial listen queue information is available.
+       Tru64 UNIX 5.0
+       This dialect is no longer supported, so no attempt
+       was made to add partial listen queue length support
+       for it.
+       Tru64 UNIX 5.1
+       Partial listen queue information is available.
+       UnixWare 7.1.[134]
+       Partial listen queue information is available.
+
+
+### What does "no more information" in the NAME column mean?
+
+When lsof can find no successor structures -- a gnode,
+inode, socket, or vnode -- connected to the file structure
+of an open descriptor of a process, it reports "no more
+information" in the NAME column.  The TYPE, DEVICE, SIZE/OFF,
+and INODE columns will be blank.
+
+Because the file structure is supposed to contain a pointer
+to the next structure of a file's processing support, if
+the pointer is NUL, lsof can go no further.
+
+Some UNIX dialects have file structures for system processes
+-- e.g., the sched process -- that have no successor
+structure pointers.  The "no more information" NAME will
+commonly appear for these processes in lsof output.
+
+It may also be the case that lsof has read the file structure
+while it is being assembled and before a successor structure
+pointer value has been set.  The "no more information" NAME
+will again result.
+
+Unless lsof output is filled with "no more information"
+NAME column messages, the appearance of a few should be no
+cause for alarm.
+
+### Why doesn't lsof find a process that ps finds?
+
+If lsof fails to display open files for a process that ps
+indicates exists, there may be several reasons for the
+difference.
+
+The process may be a "zombie" for which ps displays the
+"(defunct)" state.  In that case, the process has exited
+and has no open file information lsof can display.  It does
+still have a process structure, sufficient for the needs
+of ps.
+
+Another possible explanation is that kernel tables and
+structures may have been changing when lsof looked for the
+process, making lsof unable to find all relevant process
+structures.  Try repeating the lsof request.
+
+### Why doesn't -V report a search failure?
+
+The usual reason that -V won't report a search failure is
+that lsof located the search item, but was prevented from
+listing it by an option that doesn't participate in search
+failure reporting.
+
+For example, this lsof invocation:
+
+       $ lsof -V -i TCP@foobar -a -d 999
+
+won't report it can't find the Internet address TCP@foobar,
+even if there is an open file connected to that address,
+unless the open file also has a file descriptor number of
+999 (the `-a -d 999` options).
+
+Compile-time options can also affect -V results in much the
+same way.  For example, if HASSECURITY and HASNOSOCKSECURITY
+are defined at compile time, this lsof invocation, run by a
+non-root user:
+
+       $ lsof -V -c inetd
+
+won't report that it can't find the inetd command, even if
+there is a process running the inetd command, because the
+HASSECURITY and HASNOSOCKSECURITY options prevent the
+listing of all but the socket files of another user, and
+no socket file selector (e.g., "-i") was specified.
+
+
+### Portmap problems
+
+#### Why isn't a name displayed for the portmap registration?
+
+When portmap registration reporting is enabled, any time
+there is a registration for a local TCP or UDP port, lsof
+displays it in square brackets, following the port number
+or service name -- e.g., `:1234[name]` or `:name[100083]`.
+
+The TCP or UDP port number or service number (what follows
+the `:') is displayed under the control of the lsof -P
+option.  The registration identity is held by the portmapper
+and may be a name or a number, depending on how the
+registration's owner declared it.  Lsof reports what the
+port map holds and cannot derive a registration name from
+a registration number.
+
+Lsof can be compiled with registration reporting enabled
+or disabled by default, under the control of the HASPMAPENABLED
+#define (usually in machine.h).  The lsof help panel (`lsof
+-h`) will show the default.  Lsof is distributed with
+reporting disabled by default.
+
+#### How can I display only portmap registrations?
+
+Lsof doesn't have an option that will display only TCP or
+UDP ports with portmap registrations.  The +M option only
+enables the reporting of registration information when
+Internet socket files are displayed; +M doesn't select
+the displaying of Internet socket files -- the -i option
+does that.
+
+This simple lsof pipe to grep will do the job:
+
+       $ lsof -i +M | grep "\["
+
+This works because -i selects Internet socket files, +M
+enables portmap registration reporting, and only output
+lines with opening square brackets will have registrations.
+
+When portmap registration reporting is enabled by default,
+because the lsof builder constructed it that way, +M is
+not necessary.  (The lsof help panel, produced with `lsof
+-h` will display the default portmapper registration
+reporting state.)  However, specifying +M when reporting
+is already enabled is acceptable, as is specifying -M when
+reporting is already disabled.
+
+Digression: lsof will accept `+' or `-' as a prefix to most
+options.  (That isn't documented in the man page or help
+panel to reduce confusion and complexity.)  The -i option
+is as acceptable as +i, so the above example could be
+written a little more tersely as:
+
+       $ lsof +Mi | grep "\["
+
+But be careful to use the `Mi` ordering, since `iM`
+implies M is an address argument to `i`.
+
+#### Why doesn't lsof report portmap registrations for some ports?
+
+Lsof reports portmap registrations for local TCP and UDP
+ports only.  It identifies local ports this way:
+
+*  The port appears in the local address section of the
+       kernel structure that contains it.
+
+*  The port appears in the foreign address section of a
+       kernel structure whose local and foreign Internet
+       addresses are the same.
+
+*  The port appears in the foreign address section of a
+       kernel address structure whose Internet address is
+       INADDR_LOOPBACK (127.0.0.1).
+
+Following these rules, lsof ignores foreign portmapped
+ports.  That's done for reasons of efficiency and possible
+security prohibitions.  Contacting all remote portmappers
+could take a long time and be blocked by network difficulties
+(i.e., be inefficient).  Many firewalls block portmapper
+access for security reasons.
+
+Lsof may occasionally ignore portmap registration information
+for a legitimate local port by virtue of its local port
+rules.  This can happen when a port appears in the foreign
+part of its kernel structure and the local and foreign
+Internet addresses don't match (perhaps because they're on
+different interfaces), and the foreign Internet address
+isn't INADDR_LOOPBACK (127.0.0.1).
+
+#### Why doesn't lsof report portmap registrations for some Solaris
+versions?
+
+In some versions of Solaris -- 9 and 10 are known to exhibit
+this problem -- lsof is unable to display portmap registrations.
+
+This portmap registration reporting failure occurs when the
+Solaris netconfig field (in /etc or etc/inet) has its first two
+non-comment lines enabling tcp6 and udp6.  When netconfig is
+configured in that fashion, lsof's attempt to read the portmap
+via an RPC function fails.
+
+I don't have an explanation for the failure, but this comment
+in the netconfig(4) man page appears to have some bearing on
+the problem:
+
+       # The following two entries starting with udp6 and tcp6 are
+       # meant to be used for IPv6. If you have Ipv6 enabled on your
+       # machine then you can uncomment these two lines to enable
+       # RPC and NFS to use the Ipv6 stack.
+       ...
+       #udp6  tpi_clts      v  inet6  udp  /dev/udp6  -
+       #tcp6  tpi_cots_ord  v  inet6  tcp  /dev/tcp6  - "
+
+My interpretation of that comment is that there is a different
+RPC interface to the portmap when IPv6 is enabled.  However, I
+can't find any documentation on it in the RPC man pages.  If
+anyone has information on it, please send it to me at
+<abe@purdue> and put "lsof Solaris portmap" in the subject
+line.
+
+A work-around may be to move the ucp6 and tcp6 lines after the
+udp and tcxp lines in netconfig.  I don't know if that change
+has any unacceptable consequences, but it works for me on my
+Solaris 9 test system, and I have a report that it also works
+on Solaris 10.
+
+
+### Why is `lsof | wc` bigger than my system's open file limit?
+
+There is a strong temptation to count open files by piping
+lsof output to wc.  If your purpose is to compare the number
+you get to some Unix system parameter that defines the
+number of open files your system can have, resist the
+temptation.
+
+One reason is that lsof reports a number of "files" that
+don't occupy Unix file table space -- current working
+directories, root directories, jail directories, text files,
+library files, memory mapped files are some.  Another reason
+is that lsof can report a file shared by more than one
+process that itself occupies only one file table slot.
+
+If you want to know the number of open files that occupy
+file table slots, use the +ff option and process the lsof
+output's FILE_ADDR column information with standard Unix
+tools like cut, grep, sed, and sort.
+
+You might also consider using use lsof's field output with
++ff, selecting the file struct address with -FF, and
+processing the output with an AWK or Perl script.  See the
+list_fields.awk, list_fields.perl, and shared.perl5 scripts
+in the scripts/ subdirectory of the lsof distribution for
+hints on file struct post-processing filters.
+
+### Why doesn't lsof report file offset (position)?
+
+Lsof won't report a file offset (position) value if the -s
+option (without parameters) has been specified, or if the
+dialect doesn't support the displaying of file offset
+(position).  (Note that on selected dialects the help output,
+obtained with -h or -?, may show that the -s option can also be
+supplied the "p:s" parameters; for more information on that
+addition, see the answer to the "How are protocol state name
+exclusion and inclusion used?" question.)
+
+That lsof is reporting only file size is indicated by the
+fact that the appropriate column header says SIZE instead
+of SIZE/OFF.
+
+If lsof doesn't support the displaying of file offset
+(position) -- e.g., for Linux /proc-based lsof -- the -h
+or -? output panel won't list the -o option.
+
+Sometimes the availability of file offset information
+depends on the dialect's kernel.  This is particularly true
+for socket file offsets.
+
+Maintenance of offsets for pseudo-terminal devices varies
+by UNIX dialect and is related to how the dialect kernel
+implements pseudo-terminal support.  Kernels like AIX, for
+example, that short-circuit the transfer of data between
+socket and pseudo devices to reduce TCP/IP daemon interrupt
+rates won't advance offsets in the TCP/IP daemon socket
+files.  Instead they will advance offsets in the open
+standard I/O files of the shell child precess where the
+pseudo-terminal devices are used.
+
+When in doubt about the behavior of lsof in reporting file
+offset information, do some carefully measured experiments,
+consult the lsof sources, or contact me at <abe@purdue.edu>
+to discuss the matter.  Please follow the reporting guidelines
+in the "How do I report an lsof bug?" section of this FAQ.
+
+#### What does lsof report for size when the file doesn't really have one?
+
+When a file has no true size -- e.g., it's a socket, a
+FIFO, or a pipe -- lsof tries to report the information it
+finds in the kernel that describes the contents of associated
+kernel buffers.
+
+Thus, for example, size for most TCP/IP files is socket
+buffer size.  The size of the socket read buffer is reported
+for read-only files; the size of the write buffer for
+write-only files; and the sum of the buffers sizes for
+read-write files.
+
+### Problems with path name arguments
+
+#### How do I ask lsof to search a file system?
+
+You can ask lsof to search for all open files on a file
+system by specifying its mounted path name as an lsof
+argument -- e.g.,
+
+       $ lsof /
+
+Output of the mount command will show file system mounted
+path names.  It will also show the mounted-on device path
+for the file system.
+
+If the mounted-on device is a block device (the permission
+field in output of `ls -l <device>` starts with a `b/),
+you can specify it's name, too -- e.g.,
+
+       $ lsof /dev/sd0a
+
+If the mounted-on device isn't a block device -- for example,
+some UNIX dialects call a CD-ROM device a character device
+(ls output starts with a `c') -- you can force lsof to
+assume that the specified device names a file system with
+the +f option -- e.g.,
+
+       $ lsof +f -- /dev/sd0a
+
+(Note: you must use ``--'' after +f or -f if a file name
+follows immediately, because  +f and -f can be followed by
+characters that specify flag output selections.)
+
+When you use +f and lsof can't match the device to a file
+system, lsof will issue a complaint.
+
+The +f option may be used in some dialects to ask lsof to
+search for an NFS file system by its server name and server
+mount point.  If the mount application reports an NFS file
+system mounted-on value that way, then this sample lsof
+request should work.
+
+       $ lsof +f -- fleet:/home/fleet/u5
+
+Finally, you can use -f if you don't want a mounted file
+system path name to be considered a request to report all
+open files on the file system.  This is useful when you
+want to know if anyone is using the file system's mounted
+path name.  This example directs lsof to report on open
+access to the `/' directory, including when it's being used
+as a current working or root directory.
+
+       $ lsof -f -- /
+
+The lsof -f option performs the same function as -f does
+in some fuser implementations.  However, since the lsof -c
+option was chosen for another purpose before the `f' option
+was added to lsof, +f was selected as the analogue to the
+fuser -c option.  (Sorry for the potential confusion.)
+
+#### Why doesn't lsof find all the open files in a file system?
+
+Lsof may not find all the open files in a file system for
+several reasons.
+
+First, some processes with files open on the file system
+may have been changing status when lsof examined the process
+table, and lsof "missed" them.  Remember, the kernel changes
+much faster than lsof can respond to the changes.
+
+Second, be sure you have specified the file system correctly.
+Perhaps you specified a file instead.  You can use lsof's
+-V option to have lsof report in detail on what it couldn't
+find.  Make sure the report for the file system you specified
+says "file system."  Here's some -V output:
+
+       $ /lsof -V /tmp ./lsof.h ./lsof
+       COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF  INODE NAME
+       lsof    2688  abe  txt   VREG 18,1,7  1428583 226641 ./lsof
+       lsof    2689  abe  txt   VREG 18,1,7  1428583 226641 ./lsof
+       lsof: no file use located: ./lsof.h
+
+You can also use lsof's +f option to force it to consider
+a path name as a file system.  If lsof can't find a file
+system by the specified name, it will issue a complaint --
+e.g.,
+
+       $ lsof +f -- /usr
+       lsof: not a file system: /usr
+
+(/usr is a directory in the / file system.)
+
+#### Why does the lsof exit code report it didn't find open files
+when some files were listed?
+
+Sometimes lsof will list some open files, yet return a
+non-zero exit code, suggesting it hasn't found all the
+specified files.
+
+The first thing you should when you suspect lsof is incorrect
+is to repeat the request, adding the -V option.  In the
+resulting report you may find that your file system
+specification really wasn't a file system specification,
+just a file specification.
+
+Finally, if you specify two files or two file systems twice,
+lsof will credit all matches to the first of the two and
+believe that there were no matches for the second.  It's
+possible to specify a single file system twice with different
+path names by using both its mounted directory path name
+and mounted-one device name.
+
+       $ lsof +f -V spcuna:/sysprog /sysprog
+       COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF  INODE NAME
+       ksh     11092  abe  cwd   VDIR 39,0,1     1536 226562 /sysprog
+       (spcuna:/sysprog)
+       ...
+       lsof: no file system use located: spcuna:/sysprog
+
+All matches were credited to /sysprog; none to spcuna:/sysprog.
+
+#### Why won't lsof find all the open files in a directory?
+
+When you give lsof a simple directory path name argument
+(not a file system mounted-on name), you are asking it to
+search for processes that have the directory open as a
+file, or as a process-specific directory -- e.g., root or
+current working directory.
+
+If you want to list instances of open files inside the
+directory, you need to either specify the individual path names
+of those files, their common mount point, or use the lsof +D 
+and +d options.
+
+For example, if you wanted to check the files open in your /lsof 
+folder then the following might be the quickest way to get
+the answer you are looking for:
+
+lsof / | grep /lsof | grep -v DIR
+
+See the answer to the question "Why are the +D and +d
+options so slow?" before you use +D or +d casually.
+
+See the answer to the question "Why do the +D and +d options
+produce warning messages?" for an explanation of some
+process authority limitations of +D and +d.
+
+#### Why are the +D and +d options so slow?
+
+The +D and +d options cause lsof to build a path name search
+list for a specified directory.  +D causes lsof to descend
+the directory to its furthest subdirectory, while +d
+restricts it to the top level.  In both cases, the specified
+directory itself is included in the search list.  In both
+symbolic links are ignored.
+
+Building such a search list can take considerable time,
+especially when the specified directory contains many files
+and subdirectories -- lsof must call the system readlink()
+and stat() functions for each file and directory.  Storing
+the search list can cause lsof to use more than its normal
+amount of dynamic memory -- each file recorded in the search
+list consumes dynamic memory for its path name, characteristics,
+and search linkages.  Using the list means lsof must search
+it for every open file in the system.
+
+Building the search list for a directory specified on some
+file systems can be slow -- e.g., for an NFS directory with
+many files.  Some file systems have special logging features
+that can introduce additional delays to the building of
+the search list -- e.g., NFS logging, or logging on a
+Solaris UFS file system.  The bottom line is that slow
+search list construction may not be so much an lsof problem
+as a file system problem.  (Hint: if you're using Solaris
+UFS logging, consider specifying the "logging,noatime"
+option pair to reduce the number of atime writes to the
+UFS logging queue and disk.)
+
+A somewhat risky way to speed up lsof's building of the
+search list is to use lsof's ``-O'' option.  It forces lsof
+to do all system calls needed to build the search list
+directly, rather than in a child process.  While direct
+system calls are much faster, they can block in the kernel
+-- e.g., when an NFS server stops responding -- stopping
+lsof until the kernel operation unblocks.
+
+As an example of the load +D can impose, consider that an
+`lsof +D /` on a lightly loaded NeXT '040 cube with a 1GB
+root file system disk took 4+ minutes of real time.  It
+also generated several hundred error messages about files
+and directories the lsof process didn't have permission to
+access with stat(2).
+
+The bottom line is that +D and +d should be used cautiously.
++D is more costly than +d for deeply nested directory trees,
+because of the full directory descent it causes.  So use
++d where possible.  And you might need to consider the
+performance of the file system that holds the directory
+you name with +d or +D.
+
+In view of these warnings, when is it appropriate to use
++D or +d?  Probably the most appropriate time is when you
+would specify the directory's contents to lsof with a shell
+globbing construct -- e.g., `lsof *`.  If that's what you
+need to do, `lsof +d .` is probably more efficient than
+having the shell produce a directory list, form it into an
+argument vector, and pass the vector to lsof for it to
+unravel.
+
+See the answer to the question "Why do the +D and +d options
+produce warning messages?" for an explanation of some
+process authority limitations of +D and +d.
+
+#### Why do the +D and +d options produce warning messages?
+
++D and +d option processing is limited by the authority of
+the lsof process -- i.e., lsof can only examine (with
+lstat(2) and stat(2)) files the owner of the process can
+access.
+
+If the ownership, group membership, or permissions of the
+specified directory, file within it, or directory within
+it prevents the owner of the lsof process from using lstat(2)
+or stat(2) on it, lsof will issue a warning message, naming
+the path and giving the system's (lstat(2's or stat(2)'s)
+reason (errno explanation text) for refusing access.
+
+As an example, assume user abc has a subdirectory in /tmp,
+owned by abc and readable, writable and searchable by only
+its owner.  If user def asks lsof to search for all /tmp
+references with +D or +d, lsof will be unable to lstat(2)
+or stat(2) anything in abc's private subdirectory, and will
+issue an appropriate warning.
+
+Lsof warnings can usually be suppressed with the -w option.
+However, using -w with +D or +d means that there will be
+no indication why lsof couldn't find an open reference to
+a restricted directory or something contained in it.
+
+Hint: if you need to use +D or +d and avoid authority
+warnings, and if you have super-user power, su and use lsof
+with +D or +d as root.
+
+### Why can't my C compiler find the rpcent structure definition?
+
+When you try to compile lsof your compiler may complain
+that the rpcent structure is undefined.  The complaints
+may look like this:
+
+       >print.c: In function `fill_portmap':
+       >print.c:213: dereferencing pointer to incomplete type
+       >...
+
+The most likely cause is that someone has allowed a BIND
+installation to update /usr/include/netdb.h (or perhaps
+/usr/include/rpc/netdb.h), removing the rpcent structure
+definition that lsof expects to find there.
+
+Only Solaris has an automatic work-around.  (See dlsof.h
+in dialects/sun.).  The Solaris work-around succeeds because
+there is another header file, <rpc/rpcent.h>, with the rpcent
+structure definition, and there is a Solaris C pre-processor
+test that can tell when the BIND <netdb.h> is in place and
+hence <rpc/rpcent.h> must be included.
+
+Doubtlessly there are similar work-arounds possible in
+other UNIX dialects whose header files have been "touched"
+by BIND, but in general I recommend restoration of the
+vendor's <netdb.h> and any other header files BIND might
+have replaced.  (I think BIND replaces <resolv.h>,
+<sys/bitypes.h>, <sys/cdefs.h> -- and maybe others.)
+
+### Why doesn't lsof report fully on file "foo" on UNIX dialect "bar?"
+
+Lsof sometimes won't report much information on a given
+file, or may even report an error message in its NAME
+column.  That's usually because the file is of a special
+type -- e.g., in a file system specific to the UNIX dialect
+-- and I haven't used a system where the file appeared
+during my testing.
+
+If you encounter such a situation, send me e-mail at
+<abe@purdue.edu> and we may be able to devise an addition to
+lsof that will report on the file in question.  Please follow
+the reporting guidelines in the "How do I report an lsof bug?"
+section of this FAQ.  Make sure "lsof" appears in the
+"Subject:" line so my e-mail filter won't classify your letter
+as Spam.
+
+### Why do I get a complaint when I execute lsof that some library file can't be found?
+
+On systems where the LIBPATH (or the equivalent) environment
+variable is used to record the library search path in
+executable files when they are built, an incorrect value
+may make it impossible for the system to find the shared
+libraries needed to load lsof for execution.
+
+This may be particularly true on systems like AIX >= 4.1.4,
+where the lsof Makefile takes the precautionary step of
+using the -bnolibpath loader flag to insure that the path
+to the private static lsof library is not recorded in the
+lsof binary.  Should LIBPATH be invalid when lsof is built,
+it will be recorded in the lsof binary as the default
+library path search order and lead to an inability to find
+libraries when lsof is executed.
+
+So, if you get missing library complaints when you try to
+execute lsof, check LIBPATH, or whatever environment variable
+is used on your system to define library search order in
+executable files.  Use the tools at your disposal to look
+at the library paths recorded in the lsof binary -- e.g.,
+chatr on HP-UX, dump on AIX, ldd on Solaris.
+
+Make sure, too, that when the correct library search path
+has been recorded in the executable file, the required
+library files exist at one or more of the search paths.
+
+
+### Why does lsof complain it can't open files?
+
+When lsof begins execution, unless it has been asked to
+report only help or version information, typically it will
+attempt to access kernel memory and symbol files -- e.g.,
+/unix, /dev/kmem.  Even though lsof needs only permission
+to open these files for reading, read access to them might
+be restricted by ownerships and permission modes.
+
+So the first step to diagnosing lsof problems with opening
+files is to use ls(1) to examine the ownerships and permission
+modes of the files that lsof wants to open.  You may find
+that lsof needs to be installed with some type of special
+ownership or permission modes to enable it to open the
+necessary files for reading.  See the "Installing Lsof"
+section of 00README for more information.
+
+### Why does lsof warn "compiled for x ... y; this is z."?
+
+Unless warnings are suppressed (with -w) or the kernel
+identity check symbol (HASKERNIDCK) definition has been
+deleted, all but one lsof dialect version (exception:
+/proc-based Linux lsof) compare the identity of the running
+kernel to that of the one for which lsof was constructed.
+If the identities don't match, lsof issues a warning like
+this:
+
+       lsof: WARNING: compiled for Solaris release 5.7; this is 5.6.
+
+Two kernel identity differences can generate this warning
+-- the version number and the release number.
+
+Build and running identity differences are usually significant,
+because they usually indicate kernels whose structures are
+different -- kernel structures commonly change at dialect
+version releases.  Since lsof reads data from the kernel
+in the form of structures, it is sensitive to changes in
+them.  The general rule is that an lsof compiled for one
+UNIX dialect version will not work correctly when run on
+a different version.
+
+There are three work-arounds: 1) use -w to suppress the
+warning -- and risk missing other warnings; 2) permanently
+disable the identity check by deleting the definition of
+HASKERNIDCK in the dialect's machine.h header file -- with
+the same risk; or 3) rebuild lsof on the system where it
+is to be run.  (Deleting HASKERNIDCK can be done with the
+Customize script or by editing machine.h.)
+
+Generally checking kernel identity is a quick operation
+for lsof.  However, it is potentially slow under AIX, where
+lsof must run /usr/bin/oslevel.  To speed up lsof, use -w
+to suppress the /usr/bin/oslevel test.  See "Why does AIX
+lsof start so slowly?" for more information.
+
+### How can I disable the kernel identity check?
+
+The kernel identity check is controlled by the HASKERNIDCK
+definition.  When it is defined, most dialects (exclusion:
+/proc-based Linux lsof) will compare the build-time kernel
+identity with the run-time one.
+
+To disable the kernel identity check, disable the HASKERNIDCK
+definition in the dialect's machine.h header file.  The
+Customize script can be used to do that in its section
+about the kernel identity check.
+
+Caution: while disabling the kernel identity check may
+result in smaller lsof startup overhead, it comes with the
+risk of executing an lsof that may produce warning messages,
+error messages, incorrect output, or no output at all.
+
+### Why don't ps(1) and lsof agree on the owner of a process?
+
+Generally the user ID lsof reports in its USER column is
+the process effective user ID, as found in the process
+structure.  Sometimes that may not agree with what ps(1)
+reports for the same process.
+
+There are sundry reasons for the difference.  Sometimes
+ps(1) uses a different source for process information,
+e.g., the /proc file system or the psinfo structure.
+Sometimes the kernel is lax or confused (e.g., Solaris
+2.5.1) about what ID to report as the effective user ID.
+Sometimes the system carries only one user ID in its process
+structure (some BSD derivatives), leaving lsof no choice.
+
+The differences between lsof and ps(1) user identifications
+should be small and normally it will be apparent that the
+confusion is over a process whose application has changed
+to an effective user ID different from the real one.
+
+### Why doesn't lsof find an open socket file whose connection
+state is past CLOSE_WAIT?
+
+TCP/IP connections in states past CLOSE_WAIT -- e.g.,
+FIN_WAIT_1, CLOSING, LAST_ACK, FIN_WAIT_2, and TIME_WAIT
+-- don't always have open files associated with them.  When
+they don't, lsof can't identify them.  When the connection
+state advances from CLOSE_WAIT, sometimes the open file
+associated with the connection is deleted.
+
+### Why don't machine.h definitions work when the surrounding
+comments are removed?
+
+The machine.h header files in dialect subdirectories have
+some commented-out definitions like:
+
+       /* #define HASSYSDC "/your/choice/of/path */
+
+You can't simply remove the comments and expect the definition
+to work.  That's intended to make you think about what
+value you are assigning to the symbol.  The assigned value
+might have a system-specific convention.  HASSYSDC, for
+example, might be /var/db/lsof.dc for FreeBSD, but it might
+be /var/adm/lsof.dc for Solaris.
+
+Symbols defined in the lsof documentation are described in
+00PORTING, other machine.h comments, and other lsof
+documentation files.  HASSYSDC, for example, is discussed
+in 00DCACHE.  When comments and documentation don't suffice,
+consult the source code for hints on how the symbol is
+used.
+
+### What do "can't read inpcb at 0x...", "no protocol control block", "no PCB, CANTSENDMORE, CANTRCVMORE", etc. mean?
+
+Sometimes lsof will report "can't read inpcb at 0x00000000",
+"no protocol control block", "no PCB, CANTSENDMORE,
+CANTRCVMORE" or a similar message in the NAME column for
+open TCP socket files.  These messages mean the file's socket
+structure lacks a pointer to the INternet Protocol Control
+Block (inpcb) where lsof expects to find connection addresses
+-- local and foreign ports, local and foreign IP addresses.
+The socket file has probably been submitted to the shutdown(2)
+function for processing.
+
+In some implementations lsof issues the "no PCB, CANTSENDMORE,
+CANTRCVMORE" message, which tries to explain the absence
+of a protocol control block by showing the socket state
+settings that have been made by the shutdown(2) function.
+
+If a non-zero address follows the "0x" in the "can't read
+inpcb" message, it means lsof couldn't read inpcb contents
+from the indicated address in kernel memory.
+
+### What do the "unknown file system type" warnings mean?
+
+Lsof may report a message similar to"
+
+       unknown file system type, v_op: 0x10472f10
+
+in the NAME column for some files.
+
+This means that lsof has encountered a vnode for the file
+whose operation switch address (from v_op) references a
+file system type for which there is no support in lsof.
+After lsof identifies the file system type, it uses
+pre-compiled code to locate the file system specific node
+for the file where lsof finds information like file size,
+device number, node number, etc.
+
+To get some idea of what the file system type might be,
+use nm on your kernel symbol file to locate the symbol name
+that corresponds to the v_op address -- e.g., on Solaris
+do:
+
+       $ nm -x /dev/ksyms | grep 0x10472f10
+       0x10472f10 ... |file_system_name_vnodeops
+
+Where "file_system_name" is the clue to the unsupported
+file system.
+
+Lsof doesn't use the v_op address to identify file system
+types on all dialects.  Sometimes it uses an index number
+it finds in the vnode.  It will translate that symbol to
+a short name in the warning message -- e.g., "nfs3" -- if
+possible.
+
+### Installation
+
+#### How do I install lsof?
+
+There is no "standard" way to install lsof.  Too much
+depends on local conditions for me to be able to provide
+working install rules in the lsof make files.  (The skeleton
+install rules you will find just give "hints.")  See the
+"Installing Lsof" section of 00README for a fuller explanation.
+
+To install lsof you will need to consider these questions:
+
+*  Who should be able to use lsof?  (See HASSECURITY and
+       HASNOSOCKSECURITY in the "Security" section of 00README.)
+
+*  Where should lsof be installed?  This is a decision
+       mostly dictated by local conditions.  Somewhere in
+       /usr/local -- etc/ or sbin/ -- is a common choice.
+
+*  What permissions should I give the lsof executable?
+       The answer to this varies by dialect.  The make files
+       have install rules that give hints.  The "Installing
+       Lsof" section of 00README gives information, too.
+
+*  What if I want to install lsof in a shared file system
+       for machines that require different lsof configurations?
+       See the next question and answer, "How do I install a
+       common lsof when I have machines that need differently
+       constructed lsof binaries?"
+
+#### How do I install a common lsof when I have machines that need differently constructed lsof binaries?
+
+A dilemma that faces some system administrators when they
+install lsof in a shared file system -- e.g., NFS -- is
+that they must have different lsof executables for different
+systems.
+
+The answer is to build an lsof wrapper script that is
+executed in place of lsof.  The script can use system
+commands to determine which lsof binary should be executed.
+
+Consider this example.  You have HP-UX machines with 32
+and 64 bit kernels that share the /usr/local/sbin directory
+where you want to install lsof.  Consequently, on each
+system you must use a different lsof executable, built for
+the system's bit size.  (That's because lsof reads kernel
+structures, sized by the kernel's bit size.)
+
+One answer is to install three things in /usr/local/sbin:
+1) a 32 bit lsof as lsof32; 2) a 64 bit lsof as lsof64;
+and 3) an lsof script.  The script might look like this
+one, based on work by Amir J. Katz:
+
+       #!/bin/sh
+       x=`/usr/bin/getconf KERNEL_BITS`  # returns 32 or 64
+       if /usr/bin/test "X$x" = "X32"
+       then
+       lsof32 $*
+       else
+       if /usr/bin/test "X$x" = "X64"
+       then
+       lsof64 $*
+       else
+       echo "Can't determine which lsof executable to use;"
+       echo "getconf KERNEL_BITS says: $x"
+       exit 1
+       fi
+       fi
+
+Solaris users should consult "How do I install lsof for
+Solaris 7, 8 or 9?" for information on a similar trick
+using the Solaris isaexec command.
+
+Users of other dialects might be able to use a command like
+uname(1) that can identify a distinguishing feature of the
+system to be incorporated in pre-installed lsof executable
+names.  For example, use `uname -r` and install binaries
+with suffixes that match `uname -r` output.
+
+### Why do lsof 4.53 and above reject device cache files built by earlier lsof revisions?
+
+When lsof revisions 4.53 run and encounter a device cache
+file built by an earlier revision, it will reject the file
+and build a new one.  The rejection will be advertised with
+these messages:
+
+       lsof: WARNING: no /dev device in <name>: 2 sections
+       ...
+       lsof: WARNING: created device cache file: <name>
+
+This happens because the header line of the device cache
+file was changed at revision 4.53 to contain the number of
+the device on which the device directory resides.  The old
+device cache file header line -- the "2 sections" line in
+the above warning message, node reads "2 sections, dev=600".
+
+This is not a serious problem, since lsof automatically
+rebuilds the device cache file with the correct header
+line.
+
+### What do "like block special" and "like character special" mean in the NAME column?
+
+When lsof comes across an open block or character file
+whose device, raw device and inode place it somewhere other
+than /dev (or /devices), lsof doesn't report the /dev (or
+/devices) name in the NAME column.  Instead lsof reports
+the file system name and device or path name in the NAME
+column and parenthetically adds "like block special <path>"
+or "like character special <path>".
+
+The value for <path> will point to a block or character
+device in /dev (or /devices) whose raw device number matches
+that of the open file being reported, but whose device
+number or node number (or both) don't match.
+
+Such an open file is connected to a device node that has
+been created in a directory other than /dev (or /devices.)
+See mknod(8) for information on how such nodes are created.
+(Generally one needs root power to create device nodes with
+mknod.)
+
+### Why does an lsof make fail because of undefined symbols?
+
+When lsof is compiled via the `make` step and the final
+load step fails because of missing symbols, the problem
+may not be lsof.  The problem may be that ld, called by
+the compiler as part of the `make` step, can't find some
+library that lsof needs.
+
+First check the last compiler line of the make operation
+-- e.g., the last line with cc or gcc in it before the
+undefined symbol report -- for loader arguments, i.e.,
+ones beginning with "-l".  Except for "-llsof" the rest
+name system libraries.  ("-L./lib" precedes "-llsof" to
+tell the loader its location.)
+
+Check that all the named system libraries exist.  Look in
+/lib and /usr/lib as a start, but that may not be the only
+place system libraries live.  Consult your dialect's
+documentation, e.g., the compiler and loader man pages,
+for other possible locations.
+
+If some system library doesn't exist, that may mean it was
+never installed or was removed.  You'll have to re-install
+the missing library.
+
+You may find that all the system libraries lsof uses exist.
+Your next step might be to use nm and grep to see if any
+of them contain the undefined symbols.
+
+       $ nm library | grep symbol
+
+If the undefined symbol exists in some library named by
+the lsof make step, then you might have a problem with some
+environment variable that controls the load step.  The most
+common is LD_LIBRARY_PATH.  It may have a setting that
+causes ld to ignore a directory containing a library lsof
+names.  If this is the case, try unsetting LD_LIBRARY_PATH
+in the environment of the ld process -- e.g., do:
+
+       $ unset LD_LIBRARY_PATH
+or
+       % unsetenv LD_LIBRARY_PATH
+
+Consult your ld man page for other environment variables
+that might affect library searching -- e.g., LIBPATH, LPATH,
+SHLIB_PATH, etc.
+
+If the undefined function doesn't exist in any libraries
+lsof names, check other libraries.  See if the function
+has a man page that names its library.  If the latter is
+true, please let me know, because that is an lsof problem
+I need to fix.
+
+If none of these solutions work for you, send me some
+documentation via e-mail at <abe@purdue.edu>.  Include `uname
+-a` output, the output of the lsof `Configure ...` and `make`
+steps, and the contents of the environment in force when the
+`make` step was executed -- e.g., `env` or `printenv` output.
+If you've located the libraries lsof names, send me that
+information, too.  Make sure "lsof" appears in the "Subject:"
+line so my e-mail filter won't classify your letter as Spam.
+
+### Command Regular Expressions (REs)
+
+#### What are basic and extended regular expressions?
+
+Lsof's ``-c'' option allows the specification of regular
+expressions (REs), enclosed in two slash ('/') characters and
+followed by these modifiers:
+
+       b       the RE is a basic RE.
+       i       ignore case.
+       x       the RE is an extended RE (the default).
+
+Note: the characters of the regular expression may need to
+be quoted to prevent their expansion by the shell.
+
+Example: this RE is an extended RE that matches exactly
+four characters, whose third may be an upper ('O') or lower
+case ('o') oh:
+
+       -c /^..o.$/i
+
+For simplicity's sake, an RE that is acceptable to egrep(1)
+is usually called an extended RE.
+
+REs suitable for the old line editor, ed(1), are often
+called basic REs (and sometimes also called obsolete).
+
+These are some ways basic REs usually differ from extended
+REs.  (There are other differences.)
+
+*  `|', `+', `?', '{', and '}' are ordinary characters.
+
+*  `^' is an ordinary character except at the beginning of
+       the RE.
+
+*  `$' is an ordinary character except at the end of the
+       RE.
+
+*  `*' is an ordinary character if it appears at the
+       beginning of the RE.
+
+For more information on REs and the distinction between
+basic and extended REs, consult your dialect's man pages
+for ed(1), egrep(1), sed(1), and possibly regex(5) or
+regex(7).
+
+#### Why can't I put a slash in a command regular expression?
+
+Since a UNIX command name is the last part of a path to
+the command's executable, the lsof command regular expression
+(RE) syntax uses slash ('/') to mark the beginning and end
+of an RE.  Slash may not appear in the RE and the `\'
+back-slash escape is ineffective for "hiding" it.
+
+More likely than not, if you try to put a slash in an lsof
+command RE, you'll get this response:
+
+       $ lsof -s/.\// ...
+       lsof: invalid regexp modifier: /
+
+Lsof is complaining the the first character it found after
+the second slash isn't an lsof command RE modifier -- 'b',
+'i', or 'x'.
+
+#### Why does lsof say my command regular expression wasn't found?
+
+When you use both forms of lsof's -c option --
+``-c <command>'' and ``-c /RE/[m]'' -- and ask that lsof
+do a verbose search (``-V''), you may be surprised that
+lsof will say that the regular expression wasn't found.
+
+This can happen if the ``-c <command>'' form matches first,
+because then the ``-c/RE/[m]'' test will never have been
+applied.  For example:
+
+       $ ./lsof -clsof -c/^..o.$/ -V -adcwd
+       COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF  NODE NAME
+       lsof    7850  abe  cwd   VDIR    6,0     2048 96442 / (/dev/sd0a)
+       lsof: no command found for regex: ^..o.$
+
+The ``-clsof'' option matched first, so the ``-c/^..o.$/
+option wasn't tested.
+
+### Why doesn't lsof report on shared memory segments?
+
+Lsof reports on shared memory segments only if they're
+associated with an open file.  That's consistent with lsof's
+mission -- to LiSt Open Files.  Shared memory segments with
+no file associations aren't open files.
+
+That's not to say that a report on shared memory segments
+and their associated processes wouldn't be useful.  But it
+calls for a new tool, not more baggage for lsof.
+
+### Why does lsof report two instances of itself?
+
+When you ask lsof to report all open files and it has
+permission to do so, you may see two lsof processes in the
+output.  The processes are connected via pipes -- e.g.,
+here's an HP-UX 11 example.
+
+       COMMAND     PID USER   FD   TYPE     DEVICE ...
+       ...
+       lsof      29450  abe    7w  PIPE 0x48732408 ...
+       lsof      29450  abe    8r  PIPE 0x48970808 ...
+       ...
+       lsof      29451  abe    6r  PIPE 0x48732408 ...
+       lsof      29451  abe    9w  PIPE 0x48970808 ...
+
+The first process will usually be the lsof you initiated;
+the second, an lsof child process that is used to isolate
+its parent process from kernel functions that can block --
+e.g., readlink() or stat().
+
+Information to and from the kernel functions is exchanged
+via the two pipes.  When the parent process detects that
+the child process has become blocked, it attempts to kill
+the child.  Depending on the UNIX dialect that may succeed
+or fail, but the parent won't be blocked in any event.
+
+See the "BLOCKS AND TIMEOUTS" and "AVOIDING KERNEL BLOCKS"
+sections of the lsof man page for more information on why
+the child process is used and how you can specify lsof
+options to avoid it.  (Caution: that may be risky.)
+
+### Why does lsof report '\n' in device cache file error messages?
+
+Lsof revisions prior to 4.58 may report '\n' in error
+messages it delivers about problems in the device cache
+file -- e.g.,
+
+       lsof: WARNING: no ...: 4 sections\n
+
+That's deliberately done to show the exact contents of the
+device cache file line about which lsof is complaining,
+including its terminating NL (New Line) '\n' character.
+In the above example the line in the device cache file
+causing the lsof complaint contains "4 sections" and ends
+with a '\n'.
+
+At revision 4.58 and above, device cache error messages
+like the one in the above example have been changed to
+read:
+
+       lsof: WARNING: no ...: line "4 sections"
+
+The terminal '\n' is no longer reported, the line contents
+are enclosed in double quote marks ('"'), and the word
+"line" has been added as a prefix to denote that what
+follows is a line from the device cache file.
+
+### Kernel Symbol and Address Problems
+
+#### What does "lsof: WARNING: name cache hash size length error: 0" mean?
+
+When run on some systems, lsof may issue this warning:
+
+       lsof: WARNING: name cache hash size length error: 0
+
+That is an example from a FreeBSD system where lsof reads
+the kernel's _nchash variable and finds its value is zero.
+
+Similar warnings include:
+
+       WARNING: kernel name cache size:
+       WARNING: can't read kernel's name cache:
+       WARNING: no name cache address
+       WARNING: name cache hash size length error:
+       WARNING: unusable name cache size:
+
+These warnings are issued when lsof is attempting to read
+the kernel's name cache information.  They are usually the
+result of a mis-match between the addresses for kernel
+symbols lsof gets via nlist(2) and the addresses in use by
+the kernel.
+
+Lsof usually gets kernel symbol addresses from what it
+believes to be the kernel boot file.  In FreeBSD, for
+example, that's the path returned by getbootfile(3), usually
+/kernel.  The boot file can have other names in other UNIX
+dialects -- /unix, /vmunix, /bsd, /netbsd, /mach, /stand/vmunix,
+etc.
+
+Lsof will get incorrect (mismatched) addresses from the
+boot file if it has been replaced by a newer one which
+hasn't yet been booted -- e.g., if this is done in FreeBSD:
+
+       # mv /kernel /kernel.OLD
+       # mv /kernel.NEW /kernel
+
+Until the FreeBSD system is rebooted, the booted kernel is
+/kernel.OLD, but getbootfile() says it is /kernel.  If
+symbol addresses important to lsof in /kernel.OLD and
+/kernel don't match, the lsof WARNING messages result.
+
+#### Why does lsof produce "garbage" output?
+
+Kernel name cache warnings may not be the only sign that
+lsof is using incorrect symbol addresses to read kernel
+values.  If there's no reasonable test lsof can make on
+what it reads from the kernel, it may issue other warnings
+or even report nonsensical results.
+
+The warnings may appear on STDERR, such as:
+
+       lsof: can't read proc table info
+
+Or the warnings may appear in the NAME column as messages
+saying lsof can't read or interpret some kernel structure --
+e.g.,
+
+       ... NAME
+       ... can't read file struct from 0x12345
+
+One possible work-around is to point lsof's kernel symbol
+address gathering at the proper boot file.  That can be
+done with lsof's -k option -- e.g.,
+
+       $ lsof -k /kernel.OLD
+
+The best work-around is to make sure the standard boot file
+is properly sited -- e.g., if you've moved a new /kernel
+in place, boot it.
+
+### Why does lsof report open files when run as super user that it doesn't report when run with lesser privileges?
+
+The most likely cause is that the HASSECURITY option was
+selected when the lsof executable was built.
+
+If HASSECURITY is defined when lsof is built, and lsof is
+run with the privileges of a non-ROOT user, it will only
+list open files belonging to the user.  The same lsof
+executable, when run with root user privileges, will list
+all open files.
+
+However, if HASSECURITY and HASNOSOCKSECURITY are both
+defined when lsof is built, lsof will list open files
+belonging to the user and will also list anyone else's open
+socket files, provided their listing is selected with the
+"-i" option.
+
+So first ask yourself if the process whose open files lsof
+won't list belong to a user other than the one under which
+you're running lsof, and are not open socket files.  If
+either is true, use lsof's help (-h or -?) option and look
+for a line near the bottom of the help panel that says:
+
+       "... can list all files..."
+
+If the leading "..." says "Only root" then HASSECURITY was
+defined when lsof was built.  If the trailing "..." says
+", but anyone can list socket files" then HASNOSOCKSECURITY
+was also defined.
+
+Should you want an lsof not built with HASSECURITY defined,
+rerun the lsof Configure script.  If you let Configure do
+customization, make sure you answer 'n' when it asks if
+you want to enable HASSECURITY and HASNOSOCKSECURITY.  If
+you don't need to do customization, you can rebuild lsof
+with the "-n" option to Configure.  Here's an example of
+such a rebuild sequence:
+
+       $ Configure -clean
+       $ Configure -n <dialect-abbreviation>
+       $ make
+
+More information on the HASSECURITY and HASNOSOCKSECURITY
+options may be found in the "Security" section of the
+00README file of the lsof distribution.
+
+### Test Suite Problems
+
+#### Errors all tests can report:
+
+##### Why do tests complain "ERROR!!!  can't execute ../lsof"?
+
+All tests in the test suite expect an executable lsof file
+to exist in the tests parent directory, ../lsof.
+
+If there's none there, the tests/Makefile has a rule to
+make it, but there are probably circumstances where that
+rule may fail.
+
+The work-around is to re-Configure and re-make lsof, then
+run the test suite.
+
+##### Why do tests complain "ERROR!!! can't find ..." a file?
+
+Many tests create (or use from a supplied environment
+variable path) a test file and use lsof to find it.  When
+lsof can't file the file, the tests report the error with
+messages of the form:
+
+       ERROR!!!  can't find ... : <some file path>
+       or
+       ERROR!!!  lsof couldn't find ...
+
+These type of error messages mean that the lsof field output
+delivered to the test didn't contain a file that the test
+could identify as the one it intended lsof to find.  It
+might also mean that the process information -- command
+name, PID or parent PID -- didn't match what the test
+expected.
+
+This could imply a bug in the test or a bug in lsof.  Try
+using lsof to find a known file that is open.  For example,
+while in the tests sub-directory, do this:
+
+       $ sleep 30 < Makefile
+       $ ../lsof Makefile
+
+If lsof doesn't report that Makefile is open, then the
+fault may be with lsof.  If lsof reports the file is open,
+search further in the test code for the failure cause.
+
+##### Why do some tests fail to compile?
+
+If a test suite program fails to compile, it may be because
+I've never had an opportunity to compile the test on the
+particular UNIX version you are using.
+
+See Appendix B in 00TEST for a list of the UNIX dialects
+where the test suite has been validate.
+
+##### Why do some tests always fail?
+
+There are several tests in the optional group that have
+conflicting or special requirements:
+
+       LTbigf      needs a dialect and file system that support
+               large files.
+
+       LTlock      won't work if the tests/ sub-directory is
+               on an NFS file system.
+
+       LTnfs       won't work if the tests/ sub-directory is
+               not on an NFS file system.
+
+So for two tests in particular, LTlock and LTnfs, one will
+generally fail.
+
+Some failing tests can be run successfully by supplying to
+them a path to the appropriate type of file system with
+the -p option.
+
+##### Why does the test suite say it hasn't been validated on my dialect?
+
+When you use the default rule of the test suite's Makefile,
+it may issue this complaint:
+
+       $ cd tests
+       $ make
+       !!!WARNING!!!
+
+       This dialect or its particular version may not have
+       been validated with the lsof test suite.  Consequently
+       some tests may fail or may not even compile.
+
+       !!!WARNING!!!
+
+You are then given the opportunity to answer 'y' to have
+the test suite operation continue.
+
+This message means that the tests/TestDB file in the tests
+sub-directory doesn't show that the test suite has been
+run with the combination of compiler flags found in
+tests/config.cflags.  The tests might nor run; they may
+encounter compiler failures.
+
+See 00TEST for more information on the UNIX dialects where
+the test suite has been validated and on the workings of
+TestDB and its supporting scripts.
+
+When the tests/Makefile "auto" rule is used, the message
+is more terse and the condition is fatal.
+
+       This suite has not been validated on:
+
+       <dialect_description>
+
+No opportunity to continue is offered.
+
+The tests/Makefile "silent" rule will skip checking for
+the validation footprint.
+
+##### Why do the tests complain they can't stat() or open() /dev/mem or /dev/kmem?
+
+When the tests detect that lsof for the dialect reads its
+information from kernel memory (i.e., the LT_KMEM definition
+is present in tests/config.cflags), and when the lsof
+executable path is ../lsof, the tests make sure they can
+stat() and open() for read access the relevant kernel memory
+devices, /dev/kmem and possibly /dev/mem.
+
+If those stat() or open() operations fail, the tests issue
+an error message and quit.  The message explains why the
+system rejected the operation in terms of system "errno"
+symbols and messages.  More often than not the explanation
+will be that the process lacks permission to access the
+indicated device node.
+
+One work-around is to give the lsof executable being tested
+the necessary permission -- e.g., via chgrp, chmod, etc.
+-- and set its path in the LT_LSOF_PATH environment variable.
+(See 00TEST.)
+
+Another work-around is to make sure the process that runs
+the tests has the necessary permissions -- e.g., run it as
+root, or enable the process login to access the resources.
+For example, I can run the tests on my personal work-station
+because /dev/kmem and /dev/mem are readable by the "kmem"
+group and my login is in that group.
+
+
+#### LTbigf test issues
+
+##### Why does the LTbigf test say that the dialect doesn't support large files?
+
+Large file support is defined dialect by dialect in the
+lsof source files and Configure script.  If large file
+support isn't defined there, it isn't defined in the LTbigf
+test.
+
+If you think that's wrong for a particular dialect, contact me
+via e-mail at <abe@purdue.edu>.  Make sure "lsof" appears in the
+"Subject:" line so my e-mail filter won't classify your letter
+as Spam.
+
+##### Why does LTbigf complain about operations on its config.LTbigf*
+       file?
+
+The LTbigf must be able to write a large file test (size
+> 32 bits) and seek within it and the process file ulimit
+size must permit the operation.  If the default location
+for the test file, tests/, isn't on a file system enabled
+for large file operations or if the process ulimit file
+block size is too small, lsof will get file operation
+errors, particularly when seeking
+
+There may be a work-around.  Specify the path to a file
+LTbigf can write in a file system enabled for large file
+operations a the -poption.  Make sure that the ulimit file
+block size permits writing a large file.  For example,
+presuming /scratch23 is large-file-enabled, and presuming
+you have permission to raise the ulimit file block size,
+this shell commands will allow the LTbigf test to run on
+AIX:
+
+       $ ./LTbigf -p /scratch23/abe/bigfile
+
+(Note: syntax for the ulimit command varies by dialect and
+by shell.  Discovering the proper variant is left to the
+reader.)
+
+More information on this subject can be found in the LTbigf
+description in the 00TEST file.  If course, the LTbigf.c
+source file in tests/ is the ultimate source of information,
+
+##### Why does LTbigf warn that lsof doesn't return file offsets?
+
+On some dialects (e.g., Linux) lsof can't report file
+offsets, because the data access method underlying lsof
+doesn't provide them.  If LTbigf knows that lsof can't
+report file offsets for the dialect, it issues this warning:
+
+       LTbigf ... WARNING!!!  lsof can't return file offsets
+               for this dialect, so offset tests have
+               been disabled.
+
+LTbigf then performs the size test and skips the offset
+tests.
+
+For more information see 00TEST and the "Why doesn't
+/proc-based lsof report file offsets (positions)?" Q&A of
+this file.
+
+#### Why does the LTbasic test complain "ERROR!!! lsof this ..." and "ERROR!!!  lsof that ..."?
+
+The LTbasic test program uses lsof to examine a running
+lsof process.  It looks for the lsof current working
+directory, executable (if possible), and kernel memory file
+(if applicable).
+
+Failures to find those things result in the LTbasic error
+messages.  More information on how LTbasic produces the error
+messages may be found in the LTbasic.c source file.
+
+On HP-UX 11.11 and higher, for example, if the test's current
+working directory is on a loopback (LOFS) file system, LTbasic
+won't be able to find the current working directory of the lsof
+process because of a bug in the HP-UX kernel.
+
+The solution for that HP-UX problem is to install an HP-UX
+patch.  See the answer to the "Why doesn't PSTAT-based lsof
+report a CWD that is on a loopback (LOFS) file system?"
+question for more information on the patch.
+
+#### NFS test issues
+
+##### Why does the LTnfs test complain "couldn't find NFS file ..."?
+
+The LTnfs test must work with an NFS test file.  After it
+opens the file it asks lsof to find it on an NFS file system.
+If the file isn't on an NFS file system, lsof won't find it,
+and the NFS test script complains and fails.
+
+The work-around is to use -p option to supply a path to a
+regular NFS file (not a directory)  that is on an NFS file
+system that LTnfs can read.  Presuming /share/bin/file is
+such a file and can be opened for reading by the LTnfs
+test, this sample shell command could be used to run the
+LTnfs test successfully:
+
+       $ ./LTnfs -p /share/bin/file
+
+(If the NFS file system is enabled for large files, the
+NFS test will produce the error message described in the
+following Q&A.)
+
+#### LTnlink test issues
+
+##### Why does the LTnlink test complain that its test file is on an NFS file system?
+
+The LTnlink test may complain:
+
+       LTnlink ... WARNING!!!  test file <path> is NFS mounted.
+
+and then issue an explanation and a hint about using the
+-p option.
+
+The LTnlist test does this because of the way NFS file
+links are managed when an NFS file is unlinked and the
+unlinking process still has the file open.  Unlike with
+files on a local file system, when an NFS file that is
+still open is unlinked, its link count is not reduced.
+
+The file name is changed to a name of the form .nfsxxxx
+and the link count is left unchanged until the process
+holding the file open closes it.  That's done by NFS so it
+can keep proper track of the file on NFS clients and servers.
+
+Since the link count isn't reduced when the LTnlink test
+program closes the NFS test file it still has open, lsof
+won't find it for LTnlink with a link count of zero.
+Consequently, LTnlink disables that test section and issues
+its warning.
+
+The warning suggests that the unlink test section can be
+run by giving LTnlink a path to a test file with the -p
+option.  That path must name a file LTnlink can write and
+unlink.  Presuming /scratch23/abe/nlinkfile is on a local
+file system and the LTnlink test can write to it and unlink
+it, this sample shell command can be used to run the complete
+LTnlink test successfully:
+
+       $ LTnlink -p /scratch23/abe/nlinkfile
+
+##### Why does LTnlink delay and report "waiting for link count update: ..."?
+
+On some UNIX dialects and file system combinations the
+updating of link count after a file has been unlinked can
+be delayed.  Consequently, lsof won't be able to report
+the updated link count to LTnlink for a while.
+
+When lsof doesn't report the proper link count to LTnlink,
+it sleeps and repeats the lsof call, using the "waiting
+for link count update: ..." message as a signal that it is
+waiting for the expected lsof response.  The wait cycle
+duration is limited to approximately one minute.
+
+##### Why does LTnlink fail because of an unlink error?
+
+LTnlink may fail with an error similar to:
+
+       LTnlink ... ERROR!! unlink(<name>) failed: (Permission denied).
+
+That message will be followed by a short explanation.
+
+The error means that the kernel support for the file system on
+which the file <name> resides does not allow a process to
+unlink a file while it has the file open.  (When LTnlink is run
+without the "-p path" option, it creates a <name> that begins
+with "./config.LTnlink" and ends with the LTnlink process ID
+number.)
+
+An unlink failure of this type runs counter to original UNIX
+file system behavior, but it has been observed on some file
+system types, especially on the ZFS file system.
+
+The work-around is to run LTnlink on a file system that allows
+a process to unlink a file it has open.  Usually /tmp has that
+support.  So, try running LTnlink this way:
+
+       $ ./LTnlink -p /tmp/<name>
+
+where <name> is a unique name in /tmp of your choosing.  To
+be safe, create a subdirectory in /tmp, named by your login:
+
+       $ rm -f /tmp/<login>
+       $ mkdir /tmp/<login>
+       $ ./LTnlink -p /tmp/<login>/<name>
+
+#### LTdnlc test issues
+
+##### Why won't the LTdnlc test run?
+
+Lsof is unable to access the DNLC cache on AIX, because the
+kernel symbols for the DNLC aren't exported.  Contact IBM
+to learn why that decision was made.
+
+The LTdnlc test won't work on Apple Darwin because lsof
+can't obtain reliable DNLC information.
+
+The LTdnlc test may fail on other dialects.  Failure causes
+include: a busy system with a DNLC that is changing rapidly;
+path name components too large for the DNLC; a file system
+-- e.g., NFS, /tmp, loopback -- which doesn't fully
+participate in the DNLC; or DNLC limitations (Many DNLC
+implementations will only store path name components if
+they are 31 characters or less.)
+
+If you suspect the file system doesn't fully participate
+in kernel DNLC processing, as a work-around rebuild and
+test lsof on one that does.
+
+##### What does the LTdnlc test mean by "... <path> found: 100.00%"?
+
+Even when it succeeds the LTdnlc test will report:
+
+       LTdnlc ... /export/home/abe/src/lsof4/tests found: 100.00%
+
+This message means that the LTdnlc test asked lsof to find
+the file at the indicated path five times and lsof found
+the full path name in the indicated percentage of calls.
+The LTdnlc test considers it a failure if the percentage
+falls below 50.0%
+
+##### Why does the DNLC test fail?
+
+The DNLC test may fail when some component of the lsof
+tests/ sub-directory can't be cached by the kernel DNLC.
+Some kernels have a limit on the length of individual
+components (typically) 32.
+
+#### Why hasn't the test suite been qualified for 64 bit HP-UX 11 when lsof is compiled with gcc?
+
+When I attempted to qualify lsof for HP-UX 11, compiled
+with gcc 3.0, the LTsock test failed.  I traced the failure
+to a gcc compilation error.  Because LTsock is an important
+test, I didn't feel that the test suite was qualified if
+it failed.
+
+LTsock compiles and runs correctly on 64 bit HP-UX 11 when
+compiled with HP's ANSI-C.
+
+#### LTszoff test issues
+
+##### Why does LTszoff warn that lsof doesn't return file offsets?
+
+On some dialects (e.g., Linux) lsof can't report file
+offsets, because the data access method underlying lsof
+doesn't provide them.  If LTszoff knows that lsof can't
+report file offsets for the dialect, it issues this warning:
+
+       LTszoff ... WARNING!!!  lsof can't return file offsets
+                       for this dialect, so offset tests have
+                       been disabled.
+
+LTszoff then performs the size test and skips the offset
+tests.
+
+For more information see 00TEST and the "Why doesn't
+/proc-based lsof report file offsets (positions)?" Q&A of
+this file.
+
+#### LTlock test issues
+
+### File descriptor list (the ``-d'' option) problems
+
+#### Why does lsof reject a ``-d'' FD list?
+
+Lsof rejects ``-d'' FD lists that contain both exclusions
+and inclusions with messages like:
+
+       lsof: exclude in an include list: ^1
+       lsof: include in an exclude list: 2
+
+That's because ``-d'' FD lists are processed as ORed lists,
+so it makes no sense for them to contain both exclusions
+and inclusions.
+
+I.e.,, if a ``-d'' FD list were to contain ``^cwd,1'', the
+``^cwd'' member is useless, because the ``1'' member
+dominates by saying "include only FD 1".  That effectively
+excludes ``cwd'' FD.
+
+Note that lists may have multiple members of the same type,
+exclude or include.  They are processed as an ORed set.
+If an FD isn't excluded by any member of an exclude list,
+it is selected.  If an FD is included by any member of an
+include list, it is selected.
+
+#### Why are file descriptors other than those in my FD list reported?
+
+The FD list that follows ``-d'' excludes or includes file
+descriptors, but unless the ``-a'' (AND) option is specified,
+the FD list selections are ORed to the other selections.
+
+For example, the following lsof command will cause all file
+descriptors to be listed for the lsof command, and all but
+the cwd descriptor for all other commands, probably not
+what was intended.
+
+       $ lsof -clsof -d^cwd
+
+Hint: use ``-a'' -- e.g.,
+
+       $ lsof -clsof -a -d^cwd
+
+### How can I supply device numbers for inaccessible NFS file systems?
+
+When lsof can't get device numbers for inaccessible NFS file
+systems via stat(2) or lstat(2), it attempts to get them from
+the mount table's dev=xxx options.  Successes are reported with
+a warning message that indicates the source of the device
+number and that output might be incomplete as a consequence of
+the warnings.
+
+Some system mount tables -- e.g., Linux /proc/mounts -- don't
+have a dev=xxx option.  In that case, and provided lsof for the
+dialect supports them, you can use the +m option to create a
+mount table supplement file and the "+m m" option to use it.
+
+First check the lsof -h (help) output to see if the +m and
+"+m m" options are supported.  If they are, use +m to create a
+mount table supplement file when all mounted file systems are
+accessible.  Use "+m m" later to make the supplement available
+when some mounted file systems might not be available.
+
+Here's an example that creates a mount supplement file in
+$HOME/mnt-sup and later makes it available to lsof.
+
+       $ rm -f $HOME/mnt-sup
+       $ lsof +m > $HOME/mnt-sup
+       ...
+       $ lsof +m $HOME/mnt-sup <other lsof options>
+
+If lsof has to get the device number from the supplement, it
+will issue an informative warning message.  The warning can be
+suppressed with lsof's -w option.
+
+Caution!  Since the mount table supplement file is static, it
+is its supplier's responsibility to update it as file system
+mounts change.
+
+For more information, consult the lsof man page.  The
+"ALTERNATE DEVICE NUMBERS" section has useful information on
+how lsof acquires device numbers when stat(2) or lstat(2)
+fail.
+
+### Why won't lsof find open files on over-mounted file systems?
+
+When a file system, /xyz for example, is mounted on the same
+mount point as another file system, /abc for example, running
+lsof with an argument of the path of the first file system's
+mount point -- the over-mounted one, /abc -- probably will not
+reveal any files open on /abc.
+
+That's because lsof looks for open files on a file system by
+looking for files with the file system's device number.  The
+two file systems usually have different device numbers and lsof
+determines the device number search key from the supplied name
+of the second file system.
+
+A general work-around exists only for Linux.  On that UNIX
+dialect, when you know the over-mounted file system's mount
+point path, you can ask lsof to report on all open files and
+grep that output for the path of the over-mounted file system
+mount point.
+
+### What can be done when lsof reports no more space?
+
+Many lsof methods cache information in memory, using the
+dialects malloc() library function.  When malloc() can't
+allocate the requested amount of memory, lsof exits with
+warning messages similar to this AIX message:
+
+       lsof: no more dev-ch space at pid 2257750: 0x82a8e600
+
+Lsof then exits immediately and produces no more output.
+
+A possible work-around is to increase the memory foot print
+of the shell that runs lsof.  That is often done with the
+ulimit(1) shell command.
+
+### What if the lsof build encounters ar and ld problems?
+
+The lsof main and library Makefiles use the library archiver,
+ar, and the system loader, ld, applications.  Improperly
+located, installed or configured versions of them may cause the
+lsof build to encounter errors with them.
+
+The application producing the error should identify itself in
+its error messages.
+
+The first thing to check the path of the application that is
+being used.  Try `which ar` or `which ld` to see if perhaps the
+PATH used during the build might be causing the wrong archiver
+or loader to be used.
+
+If the problem is with the use of the wrong archiver, and it's
+not possible to correct the PATH to it, try using the LSOF_AR
+environment variable to specify the path to and arguments for
+the correct archiver.  See 00XCONFIG for more information and
+note that LSOF_AR must specify the path to the archive
+application and the arguments for it, less the terminating
+library and module name arguments.
+
+If the problem is with the loader, there is no lsof work-
+around.  That's because lsof calls the loader via the C
+compiler, so the problem must be fixed at the compiler (system)
+level.
+
+### Why does lsof -i report an open socket file for a process, but
+lsof -p on that process' ID report nothing?
+
+The lsof in use was probably built with the HASSECURITY and
+HASNOSOCKSECURITY options and the process in question does not
+belong to the user of lsof.
+
+The HASSECURITY option limits lsof output to processes owned
+by the user invoking lsof and the HASNOSOCKSECURITY option
+weakens that slightly to allow output of open socket file
+information for all processes.
+
+For example, if process PID 12345 is owned by some user other
+than the one invoking lsof, and lsof has been compiled with the
+HASSECURITY and HASNOSOCKSECURITY options, the following lsof
+command will display the open socket files of process 12345:
+
+       $ lsof -p 12345 -a -i
+
+This security restriction is described in the lsof(8) manual
+page.
diff --git a/docs/getting-started.md b/docs/getting-started.md
new file mode 100644 (file)
index 0000000..f508a49
--- /dev/null
@@ -0,0 +1,107 @@
+# Getting started
+
+You can get lsof by building from source or installing from package managers.
+
+Due to the nature that lsof talks to the kernel, it requires many build-time checks to enable support for optional features. If you are installing lsof from package manager, chances are that the build machine has a different configuration from your own ones.
+
+If the prebuilt binary from package manager misses some feature or malfunctions, you should build lsof from source.
+
+## Build from source
+
+You can retrieve lsof sources from [GitHub Releases](https://github.com/lsof-org/lsof/releases) or via git. lsof currently uses two build systems:
+
+- Legacy: supports more OSes
+- Autotools(experimental): supports Linux/Darwin/FreeBSD
+
+### Legacy build system
+
+You should use the legacy build system if you are building lsof on old OSes or do not want to risk. The legacy build system supports the following UNIX dialects:
+
+- aix|aixgcc              : IBM AIX xlc (aix) or gcc (aixgcc)
+- darwin                  : Apple Darwin
+- freebsd                 : FreeBSD
+- hpux|hpuxgcc            : HP-UX cc (hpux) or gcc (hpuxgcc)
+- linux                   : Linux
+- netbsd                  : NetBSD
+- openbsd                 : OpenBSD
+- osr|sco                 : SCO OpenServer < 6.0.0, SCO devloper's compiler
+- osrgcc|scogcc           : SCO OpenServer < 6.0.0, gcc compiler
+- osr6                    : SCO OpenServer 6.0.0, SCO compiler
+- solaris|solariscc       : Solaris gcc (solaris) or cc (solariscc)
+- unixware|uw             : SCO|Caldera UnixWare
+
+You can build lsof with the following commands:
+
+```shell
+./Configure <dialect>
+make
+```
+
+Testing:
+
+```shell
+bash check.bash <dialect>
+```
+
+### Autotools-based build system
+
+Since 4.97.0, lsof introduces a new experimental autotools-based build system. It supports the following OSes:
+
+- Linux
+- Darwin
+- FreeBSD
+- NetBSD
+
+Build dependencies:
+
+- c compiler: gcc/clang/etc
+- autotools: autoconf/automake
+- make
+- pkg-config: for package detection
+- groff: to process manpages
+- libtirpc(optional): if your libc does not provide rpc
+- nc/iproute2(optional): for testing
+
+You can build lsof with the following commands:
+
+```shell
+# If you are building from git sources
+# autoreconf -vif
+./configure
+make
+make install
+```
+
+Testing:
+
+```shell
+make check
+```
+
+## Install from package managers
+
+lsof is packaged in many OSes. You can install lsof from package managers:
+
+If you use Debian/Ubuntu/apt-based Linux distros:
+
+```shell
+sudo apt install lsof
+```
+
+If you use RHEL/CentOS/yum-based Linux distros:
+
+```shell
+sudo yum install lsof
+```
+
+If you use Arch/pacman-based Linux distros:
+
+```shell
+sudo pacman -Syu lsof
+```
+
+If you use NixOS/nix-based Linux distros:
+
+```shell
+nix-env -i lsof
+```
\ No newline at end of file
diff --git a/docs/index.md b/docs/index.md
new file mode 100644 (file)
index 0000000..d92224d
--- /dev/null
@@ -0,0 +1,59 @@
+# lsof (LiSt Open Files)
+
+**lsof** is a command for `LiSting Open Files`. You can use lsof for example to:
+
+- Find uses of a specific open file: `lsof /path/to/file`
+- Find an unlinked open file: `lsof +L1`
+- Find processes blocking umount: `lsof /mnt`
+- Find tcp/udp sockets: `lsof -i`
+- Find files open to a process with known PID: `lsof -p 1234`
+- Find files open to a named command: `lsof -c bash`
+- Find files open by a specific user: `lsof -u somebody`
+
+## History
+
+lsof was originally developed and maintained by Vic Abell since 1994. The [lsof-org team at GitHub](https://github.com/lsof-org/lsof) takes over the maintainership of lsof. You can find the latest release at [GitHub Release](https://github.com/lsof-org/lsof/releases).
+
+## OS Support
+
+Actively maintained and supported:
+
+- Linux
+- FreeBSD
+- Darwin(macOS)
+- NetBSD
+- OpenBSD
+- Solaris/OpenIndiana
+
+Not maintained for lack of maintainers but pull requests are welcome:
+
+- IBM AIX
+- HP-UX
+- SCO OpenServer
+- UnixWare
+
+lsof is tested in ci on the following platforms:
+
+- Alpine Linux 3.17
+- Arch Linux
+- CentOS 8/9
+- Debian 11
+- Fedora 36/37
+- FreeBSD 12/13/14
+- macOS Big Sur
+- NixOS
+- openSUSE Leap 15
+- Ubuntu 18.04/20.04/22.04
+- NetBSD 9
+- OpenBSD 7
+
+Additionally, lsof is tested by maintainers manually on the following platforms:
+
+- Solaris 11
+- OpenIndiana 5
+
+lsof is provided by package manager in the following repositories:
+
+<a href="https://repology.org/project/lsof/versions">
+    <img src="https://repology.org/badge/vertical-allrepos/lsof.svg" alt="Packaging status">
+</a>
\ No newline at end of file
diff --git a/docs/maintaining.md b/docs/maintaining.md
new file mode 100644 (file)
index 0000000..eac50c1
--- /dev/null
@@ -0,0 +1,246 @@
+# Maintaining
+
+## The basic rules
+
+a Dialect maintainer can do as one's want as far as what one's will do
+has no impact on the other dialects.
+
+The following three dialects have ACTIVE maintainers:
+
+FreeBSD
+
+       @lrosenman
+       @jiegec
+
+Linux
+       
+       @dilinger
+       @masatake
+       @jiegec
+
+NetBSD
+
+       @tnn2
+       @jiegec
+
+Darwin
+
+       @jiegec
+
+OpenBSD
+
+       @jiegec
+
+Solaris/OpenIndiana
+
+       @jiegec
+
+
+@masatake is going to step down. See https://github.com/lsof-org/lsof/issues/192 .
+
+If you find a good person who has interested in maintain a dialect
+that none maintains, you can invite the person to the lsof-org
+organization.
+
+See also https://github.com/lsof-org/lsof/issues/157#issuecomment-941591778 .
+
+## Git
+
+A dialect maintainer must know Git.
+
+### Sophisticated commits
+
+You will change the repository. You will write the code or you will merge
+the code submitted by a contributor via pull request.
+
+About your dialect, you can do as you want. However, I recommend you to
+accept only SOPHISTICATED commits only. About a change for the common code
+between dialect, we accept only sophisticated commits. About a change having
+impact on the other dialects, we accept only sophisticated commits.
+
+One sophisticated commit does one thing.
+e.g. a commit including a change for adjusting white-spaces and a change for
+adding an option is not a sophisticated commit.
+
+* https://github.com/lsof-org/lsof/pull/195#discussion_r825328892
+* https://github.com/lsof-org/lsof/pull/208
+
+Sophisticated commits help reviewers.
+Understanding sophisticated commits is easy.
+
+https://github.com/lsof-org/lsof/pull/213
+This is not a sophisticated commit. Improving the way to hash and fixing
+a typo are done in a commit. I didn't have energy to ask the contributor
+to split the commit into two.
+
+"Try-and-error" commits should not be merged. It makes the git log of
+lsof dirty. Such dirtiness make us hard to read and understand git-log
+and to do git-bisect effectively. You can ask the contributor to
+squash the commits into one as far as the commits are for doing one
+thing; squashed commit should be sophisticated.
+
+### Commit logs
+
+If a change is dialect specific, use `[dialect]` as the prefix of the
+header of the commit log like::
+
+   [linux] compile with -Wall option
+   [linux] delete unused variables
+   [freebsd] cirrus-ci: disabled
+
+We should the force this rule to us and contributors. So we can know
+who should review the change/pull request. If no `[dialect]` prefix is
+given to a commit, the change may have an impact across dialects; all
+we must review the commit.
+
+I have seen contributors write much expiation about their change
+at the first comment of their pull request. However, their commit
+log is very short. We should ask them to copy the first comment to
+the commit log.
+
+## Reviewing and merging
+
+A dialect maintainer has a responsibility to review pull requests that
+change the code of one's dialect.
+
+After merging you may have to update two documents:
+
+00DIST
+
+       If a pull request you merged changes user visible aspect of lsof,
+       put the change at the end of 00DIST file. You can ask the contributor
+       making a pull request to put an entry for the one's change instead.
+
+00CREDITS
+
+       If this is the first time for the contributor to contribute to lsof,
+       add one's name to 00CREDITS.
+
+You may have to the contributor to update the lsof.8 man page.
+If a pull request fixes the issue already reported, put
+`Close #issueNumber` to the first comment of the pull request.
+
+e.g. https://github.com/lsof-org/lsof/pull/199#issue-1193523123
+
+## Testing
+
+Having a test case for a change is nice. The original lsof developed
+and maintained by Vic Abell has a test mechanism. However, I started
+developing my own test mechanism (the github test mechanism) written
+in bash.
+
+About the original test mechanism, see tests/00README.
+
+About the the github test mechanism, see tests/case-00-hello.bash .
+You can put a test case non-dialect specific, put tests/.
+dialects/linux/tests/ is for testing linux specific code.
+
+## Releasing
+
+A dialect maintainer can release a new version of lsof FOR YOUR
+DIALECT without getting permission from maintainers of the other
+dialects.  So we can work asynchronously.
+
+### Install ksh
+
+The script for making an archive needs ksh.
+
+
+### Implement "make dist" for your favorite dialect
+
+See https://github.com/lsof-org/lsof/pull/131 how @masatake does for
+linux dialect.
+
+Merge the changes.
+
+
+### Update the version and release date in the source tree if you need
+
+You should update the version and release date in the following files:
+
+- 00DIST
+- version
+- configure.ac
+
+And then re-generated `docs/manpapage.md` by running `manpage.sh` in `docs` folder.
+
+The version number has following form MAJOR.MINOR.MICRO.  When making a
+release, update the version number.  If the change from the last release
+is small, increment MICRO. If it is large, increment MINOR.
+
+Merge the changes.
+
+If you just want to make a release for a version already released in
+another dialect, you don't need this step. Release the version number.
+
+e.g.
+
+conditions and situations:
+@masatake already released 4.94.0 for linux.
+No user visible change is committed to our git repo.
+You may want to make the same release but for dialect freebsd.
+
+In this case, you can use 4.94.0 as the version number.  If the
+condition doesn't meet, use 4.94.1 (or 4.95.0).
+
+### Put a tag with Git
+
+NOTE: this step is an optional if the commit for releasing is already
+tagged via another dialect.
+
+The tag you will put should have the same name as the version given in
+the step 2.
+
+Do "git tag" like:
+
+  $ git tag 4.95.0-this-is-an-example
+  $ git push upstream 4.95.0-this-is-an-example
+
+If you took a mistake, you can delete the tag like:
+
+  $ git tag -d 4.95.0-this-is-an-example
+  $ git push upstream :4.95.0-this-is-an-example
+
+### Make the source archive for the release
+
+   $ ./Configure [dialect]
+   $ make dist
+
+The archive is put at support/ directory.
+
+Checking whether you can build a lsof executable from the archive is
+good idea.
+
+e.g.
+
+   $ cp support/lsof_4.94.0.linux.tar.bz2 /tmp
+   $ cd /tmp
+   $ tar jxvf lsof_4.94.0.linux.tar.bz2
+   $ cd lsof_4.94.0.linux
+   $ ./Configure linux
+   $ make
+   $ make check (if your dialect support the target)
+
+### Visit https://github.com/lsof-org/lsof/releases
+
+1. Click [Draft new release]
+2. Choose a tag. Choose with the tag given in the step 3.
+3. Fill "Release title". Use the following form lsof-${theVersionNumber}-${dialect}. e.g. lsof-4.94.0-linux
+4. Fill "Describe this release". Copy and paste the changes described in 00DIST since the last release in your dialect.
+5. Record the release date. Put the date of the release at the end of "Contents" of 00DIST.
+       "Contents" is at the beginning of 00DIST.
+6. Put the source archive generated step in 4. Click "Attach binaries by dropping them here or selecting them. ", then specify the archive file.
+7. Check "This is a pre-release"
+8. Click [Publish release]
+9. Verify the release
+
+After step 8, the browser may show the page for the release. You can
+re-read the description and the source code archives. You can verify
+what you did here.
+
+If you find a fault or something, click the [Edit] in the page. You can
+update the pre-release.
+
+If you convince it is ready, click the [Edit] in the page, remove the
+check at "This is a pre-release", then [Publish release]. The new
+version is available at https://github.com/lsof-org/lsof/releases.
diff --git a/docs/manpage.md b/docs/manpage.md
new file mode 100644 (file)
index 0000000..9676882
--- /dev/null
@@ -0,0 +1,2919 @@
+# Manpage
+```manpage
+LSOF(8)                     System Manager's Manual                    LSOF(8)
+
+NAME
+       lsof - list open files
+
+SYNOPSIS
+       lsof  [  -?abChHlnNOPQRtUvVX  ] [ -A A ] [ -c c ] [ +c c ] [ +|-d d ] [
+       +|-D D ] [ +|-e s ] [ +|-E ] [ +|-f [cfgGn] ] [ -F [f] ] [ -g [s]  ]  [
+       -i  [i] ] [ -k k ] [ -K k ] [ +|-L [l] ] [ +|-m m ] [ +|-M ] [ -o [o] ]
+       [ -p s ] [ +|-r [t[m<fmt>]] ] [ -s [p:s] ] [ -S [t] ] [ -T [t] ] [ -u s
+       ] [ +|-w ] [ -x [fl] ] [ -z [z] ] [ -Z [Z] ] [ -- ] [names]
+
+DESCRIPTION
+       Lsof  revision  4.99.0  lists  on  its standard output file information
+       about files opened by processes for the following UNIX dialects:
+
+            Apple Darwin 9, Mac OS X 10, macOS 11 and above
+            FreeBSD 8.2 and above
+            Linux 2.1.72 and above
+            NetBSD 1.2 and above
+            OpenBSD 7.2 and above
+            Solaris 9, 10 and 11 and above
+            OpenIndiana 5.11 and above
+
+       (See the DISTRIBUTION section of this manual page  for  information  on
+       how to obtain the latest lsof revision.)
+
+       An  open file may be a regular file, a directory, a block special file,
+       a character special file, an executing text  reference,  a  library,  a
+       stream  or  a  network  file  (Internet socket, NFS file or UNIX domain
+       socket.)  A specific file or all the files in a file system may be  se‐
+       lected by path.
+
+       Instead  of  a  formatted display, lsof will produce output that can be
+       parsed by other programs.  See the -F, option description, and the OUT‐
+       PUT FOR OTHER PROGRAMS section for more information.
+
+       In  addition to producing a single output list, lsof will run in repeat
+       mode.  In repeat mode it will produce output, delay,  then  repeat  the
+       output  operation  until stopped with an interrupt or quit signal.  See
+       the +|-r [t[m<fmt>]] option description for more information.
+
+OPTIONS
+       In the absence of any options, lsof lists all open files  belonging  to
+       all active processes.
+
+       If  any  list  request option is specified, other list requests must be
+       specifically requested - e.g., if -U is specified for  the  listing  of
+       UNIX  socket  files, NFS files won't be listed unless -N is also speci‐
+       fied; or if a user list is specified with the -u  option,  UNIX  domain
+       socket  files,  belonging to users not in the list, won't be listed un‐
+       less the -U option is also specified.
+
+       Normally, list options that are specifically stated are  ORed  -  i.e.,
+       specifying  the  -i option without an address and the -ufoo option pro‐
+       duces a listing of all network files OR files  belonging  to  processes
+       owned by user ``foo''.  The exceptions are:
+
+       1) the `^' (negated) login name or user ID (UID), specified with the -u
+          option;
+
+       2) the `^' (negated) process ID (PID), specified with the -p option;
+
+       3) the `^' (negated) process group ID (PGID), specified with the -g op‐
+          tion;
+
+       4) the `^' (negated) command, specified with the -c option;
+
+       5) the  (`^')  negated  TCP or UDP protocol state names, specified with
+          the -s [p:s] option.
+
+       Since they represent exclusions, they are applied without ORing or AND‐
+       ing and take effect before any other selection criteria are applied.
+
+       The -a option may be used to AND the selections.  For example, specify‐
+       ing -a, -U, and -ufoo produces a listing of only UNIX socket files that
+       belong to processes owned by user ``foo''.
+
+       Caution:  the  -a option causes all list selection options to be ANDed;
+       it can't be used to cause ANDing of selected pairs of selection options
+       by  placing it between them, even though its placement there is accept‐
+       able.  Wherever -a is placed, it causes the ANDing of all selection op‐
+       tions.
+
+       Items of the same selection set - command names, file descriptors, net‐
+       work addresses, process identifiers, user identifiers, zone names,  se‐
+       curity  contexts  -  are joined in a single ORed set and applied before
+       the result participates  in  ANDing.   Thus,  for  example,  specifying
+       -i@aaa.bbb,  -i@ccc.ddd,  -a,  and -ufff,ggg will select the listing of
+       files that belong to either login ``fff'' OR ``ggg'' AND  have  network
+       connections to either host aaa.bbb OR ccc.ddd.
+
+       Options  may be grouped together following a single prefix -- e.g., the
+       option set ``-a -b -C'' may be stated as -abC.  However,  since  values
+       are optional following +|-f, -F, -g, -i, +|-L, -o, +|-r, -s, -S, -T, -x
+       and -z.  when you have no values for them be careful that the following
+       character isn't ambiguous.  For example, -Fn might represent the -F and
+       -n options, or it might represent the n field identifier character fol‐
+       lowing  the  -F option.  When ambiguity is possible, start a new option
+       with a `-' character - e.g., ``-F -n''.  If the next option is  a  file
+       name,  follow the possibly ambiguous option with ``--'' - e.g., ``-F --
+       name''.
+
+       Either the `+' or the `-' prefix may be applied to a group of  options.
+       Options that don't take on separate meanings for each prefix - e.g., -i
+       - may be grouped under either prefix.  Thus, for example, ``+M -i'' may
+       be  stated  as ``+Mi'' and the group means the same as the separate op‐
+       tions.  Be careful of prefix grouping when one or more options  in  the
+       group  does  take on separate meanings under different prefixes - e.g.,
+       +|-M; ``-iM'' is not the same request as ``-i +M''.  When in doubt, use
+       separate options with appropriate prefixes.
+
+       -? -h    These  two  equivalent  options  select  a usage (help) output
+                list.  Lsof displays a shortened form of this output  when  it
+                detects  an  error in the options supplied to it, after it has
+                displayed messages explaining each  error.   (Escape  the  `?'
+                character as your shell requires.)
+
+       -a       causes list selection options to be ANDed, as described above.
+
+       -A A     is  available  on  systems configured for AFS whose AFS kernel
+                code is implemented via dynamic modules.  It allows  the  lsof
+                user  to  specify  A  as an alternate name list file where the
+                kernel addresses of the dynamic modules might be  found.   See
+                the  lsof  FAQ (The FAQ section gives its location.)  for more
+                information about dynamic modules, their symbols, and how they
+                affect lsof.
+
+       -b       causes  lsof  to  avoid  kernel  functions  that might block -
+                lstat(2), readlink(2), and stat(2).
+
+                See the BLOCKS AND TIMEOUTS and AVOIDING  KERNEL  BLOCKS  sec‐
+                tions for information on using this option.
+
+       -c c     selects  the listing of files for processes executing the com‐
+                mand that begins with the characters of c.  Multiple  commands
+                may  be specified, using multiple -c options.  They are joined
+                in a single ORed set before participating in AND option selec‐
+                tion.
+
+                If  c begins with a `^', then the following characters specify
+                a command name whose processes are to be ignored (excluded.)
+
+                If c begins and ends with a slash ('/'),  the  characters  be‐
+                tween  the  slashes  are  interpreted as a regular expression.
+                Shell meta-characters in the regular expression must be quoted
+                to  prevent  their  interpretation  by the shell.  The closing
+                slash may be followed by these modifiers:
+
+                     b    the regular expression is a basic one.
+                     i    ignore the case of letters.
+                     x    the regular expression is an extended one
+                          (default).
+
+                See the lsof FAQ (The FAQ section gives  its  location.)   for
+                more information on basic and extended regular expressions.
+
+                The  simple  command  specification  is tested first.  If that
+                test fails, the command regular expression is applied.  If the
+                simple  command  test succeeds, the command regular expression
+                test isn't made.  This may result in ``no  command  found  for
+                regex:'' messages when lsof's -V option is specified.
+
+       +c w     defines  the maximum number of initial characters of the name,
+                supplied by the UNIX dialect, of the UNIX  command  associated
+                with a process to be printed in the COMMAND column.  (The lsof
+                default is nine.)
+
+                Note that many UNIX dialects do not supply  all  command  name
+                characters to lsof in the files and structures from which lsof
+                obtains command name.  Often  dialects  limit  the  number  of
+                characters  supplied  in  those  sources.   For example, Linux
+                2.4.27 and Solaris 9 both limit  command  name  length  to  16
+                characters.
+
+                If w is zero ('0'), all command characters supplied to lsof by
+                the UNIX dialect will be printed.
+
+                If w is less than the length of the column title, ``COMMAND'',
+                it will be raised to that length.
+
+       -C       disables  the  reporting  of any path name components from the
+                kernel's name cache.  See the KERNEL NAME  CACHE  section  for
+                more information.
+
+       +d s     causes  lsof  to  search for all open instances of directory s
+                and the files and directories it contains at  its  top  level.
+                +d does NOT descend the directory tree, rooted at s.  The +D D
+                option may be used to request a  full-descent  directory  tree
+                search, rooted at directory D.
+
+                Processing  of  the  +d  option does not follow symbolic links
+                within s unless the -x or -x  l option is also specified.  Nor
+                does  it  search for open files on file system mount points on
+                subdirectories of s unless the -x or  -x   f  option  is  also
+                specified.
+
+                Note:  the  authority  of the user of this option limits it to
+                searching for files that the user has  permission  to  examine
+                with the system stat(2) function.
+
+       -d s     specifies  a list of file descriptors (FDs) to exclude from or
+                include in the output listing.  The file descriptors are spec‐
+                ified  in  the  comma-separated  set  s  -  e.g., ``cwd,1,3'',
+                ``^6,^2''.  (There should be no spaces in the set.)
+
+                The list is an exclusion list if all entries of the set  begin
+                with  `^'.   It  is  an inclusion list if no entry begins with
+                `^'.  Mixed lists are not permitted.
+
+                A file descriptor number range may be in the set  as  long  as
+                neither  member  is  empty,  both members are numbers, and the
+                ending member is larger than the starting one - e.g.,  ``0-7''
+                or  ``3-10''.   Ranges  may be specified for exclusion if they
+                have the `^' prefix - e.g., ``^0-7''  excludes  all  file  de‐
+                scriptors 0 through 7.
+
+                Multiple  file  descriptor numbers are joined in a single ORed
+                set before participating in AND option selection.
+
+                When there are exclusion and inclusion  members  in  the  set,
+                lsof  reports  them as errors and exits with a non-zero return
+                code.
+
+                See the description of File Descriptor (FD) output  values  in
+                the  OUTPUT  section  for  more information on file descriptor
+                names.
+
+                fd is a pseudo file descriptor name for specifying  the  whole
+                range of possible file descriptor numbers.  fd does not appear
+                in FD column of output.
+
+       +D D     causes lsof to search for all open instances  of  directory  D
+                and  all the files and directories it contains to its complete
+                depth.
+
+                Processing of the +D option does  not  follow  symbolic  links
+                within D unless the -x or -x  l option is also specified.  Nor
+                does it search for open files on file system mount  points  on
+                subdirectories  of  D  unless  the  -x or -x  f option is also
+                specified.
+
+                Note: the authority of the user of this option  limits  it  to
+                searching  for  files  that the user has permission to examine
+                with the system stat(2) function.
+
+                Further note: lsof may process this option slowly and  require
+                a large amount of dynamic memory to do it.  This is because it
+                must descend the entire directory tree, rooted at  D,  calling
+                stat(2)  for  each  file and directory, building a list of all
+                the files it finds, and searching that list for a  match  with
+                every  open  file.  When directory D is large, these steps can
+                take a long time, so use this option prudently.
+
+       -D D     directs lsof's use of the device cache file.  The use of  this
+                option  is  sometimes  restricted.   See the DEVICE CACHE FILE
+                section and the sections that follow it for  more  information
+                on this option.
+
+                -D  must be followed by a function letter; the function letter
+                may optionally be followed by a path  name.   Lsof  recognizes
+                these function letters:
+
+                     ? - report device cache file paths
+                     b - build the device cache file
+                     i - ignore the device cache file
+                     r - read the device cache file
+                     u - read and update the device cache file
+
+                The  b,  r,  and  u functions, accompanied by a path name, are
+                sometimes restricted.  When these  functions  are  restricted,
+                they  will not appear in the description of the -D option that
+                accompanies -h or -?  option output.   See  the  DEVICE  CACHE
+                FILE section and the sections that follow it for more informa‐
+                tion on these functions and when they're restricted.
+
+                The ?  function reports the read-only  and  write  paths  that
+                lsof can use for the device cache file, the names of any envi‐
+                ronment variables whose values lsof will examine when  forming
+                the  device  cache  file path, and the format for the personal
+                device cache file path.  (Escape the  `?'  character  as  your
+                shell requires.)
+
+                When  available,  the b, r, and u functions may be followed by
+                the  device  cache  file's  path.   The  standard  default  is
+                .lsof_hostname  in the home directory of the real user ID that
+                executes lsof, but this could have been changed when lsof  was
+                configured  and  compiled.   (The output of the -h and -?  op‐
+                tions show the current default prefix - e.g., ``.lsof''.)  The
+                suffix,  hostname,  is  the first component of the host's name
+                returned by gethostname(2).
+
+                When available, the b function directs lsof to build a new de‐
+                vice cache file at the default or specified path.
+
+                The i function directs lsof to ignore the default device cache
+                file and obtain its information about devices via direct calls
+                to the kernel.
+
+                The  r  function  directs lsof to read the device cache at the
+                default or specified path, but prevents it from creating a new
+                device  cache file when none exists or the existing one is im‐
+                properly structured.  The r function, when specified without a
+                path  name,  prevents  lsof from updating an incorrect or out‐
+                dated device cache file, or creating a new one in  its  place.
+                The  r function is always available when it is specified with‐
+                out a path name argument; it may be restricted by the  permis‐
+                sions of the lsof process.
+
+                When available, the u function directs lsof to read the device
+                cache file at the default or specified path, if possible,  and
+                to rebuild it, if necessary.  This is the default device cache
+                file function when no -D option has been specified.
+
+       +|-e s   exempts the file system whose path name is s from  being  sub‐
+                jected  to kernel function calls that might block.  The +e op‐
+                tion exempts stat(2), lstat(2)  and  most  readlink(2)  kernel
+                function  calls.   The  -e  option  exempts  only  stat(2) and
+                lstat(2) kernel function calls.  Multiple file systems may  be
+                specified  with separate +|-e specifications and each may have
+                readlink(2) calls exempted or not.
+
+                This option is currently implemented only for Linux.
+
+                CAUTION: this option can easily be mis-applied to  other  than
+                the  file system of interest, because it uses path name rather
+                than the more reliable device and inode numbers.  (Device  and
+                inode  numbers  are  acquired  via  the  potentially  blocking
+                stat(2) kernel call and are thus not available,  but  see  the
+                +|-m  m  option as a possible alternative way to supply device
+                numbers.)  Use this option with great care and  fully  specify
+                the path name of the file system to be exempted.
+
+                When  open files on exempted file systems are reported, it may
+                not be possible to obtain all their  information.   Therefore,
+                some   information  columns  will  be  blank,  the  characters
+                ``UNKN'' preface the values in the TYPE column, and the appli‐
+                cable  exemption  option is added in parentheses to the end of
+                the NAME column.  (Some device  number  information  might  be
+                made available via the +|-m m option.)
+
+       +|-E     +E specifies that Linux pipe, Linux UNIX socket, Linux INET(6)
+                socket closed in a local  host,  Linux  pseudoterminal  files,
+                POSIX  Message  Queueue  implementation  in  Linux,  and Linux
+                eventfd should be displayed with endpoint information and  the
+                files of the endpoints should also be displayed.
+
+                Note  1:  UNIX socket file endpoint information is only avail‐
+                able when the features enabled line of -v output contains  ux‐
+                sockept, and psudoterminal endpoint information is only avail‐
+                able when the features enabled line contains ptyept.
+
+                Note 2: POSIX Message Queue file endpoint information is  only
+                available when mqueue file system is mounted.
+
+                Pipe  endpoint  information is displayed in the NAME column in
+                the form ``PID,cmd,FDmode'', where PID is the endpoint process
+                ID;  cmd  is  the endpoint process command; FD is the endpoint
+                file's descriptor; and mode  is  the  endpoint  file's  access
+                mode.
+
+                Pseudoterminal  endpoint  information is displayed in the NAME
+                column as  ``->/dev/ptsmin PID,cmd,FDmode''  or  ``PID,cmd,FD‐
+                mode''.   The  first  form is for a master device; the second,
+                for a slave device.  min is a slave device's minor device num‐
+                ber;  and PID, cmd, FD and mode are the same as with pipe end‐
+                point information.  Note: psudoterminal  endpoint  information
+                is  only available when the features enabled line of -v output
+                contains ptyept. In addition, this feature works on Linux ker‐
+                nels above 4.13.0.
+
+                UNIX socket file endpoint information is displayed in the NAME
+                column in the form
+                ``type=TYPE ->INO=INODE PID,cmd,FDmode'', where  TYPE  is  the
+                socket  type;  INODE  is  the  i-node  number of the connected
+                socket; and PID, cmd, FD and mode are the same  as  with  pipe
+                endpoint  information.  Note: UNIX socket file endpoint infor‐
+                mation is available only when the features enabled line of  -v
+                output contains uxsockept.
+
+                INET socket file endpoint information is inserted to the value
+                at the NAME column in the form
+                `` -> PID,cmd,FDmode'', where PID, cmd, FD and  mode  are  the
+                same  as with pipe endpoint information. The endpoint informa‐
+                tion is available only if the socket is used  for  local  IPC;
+                both endpoints bind to the same local IPv4 or IPv6 address.
+
+                POSIX  Message Queue file endpoint information is displayed in
+                the NAME column in the same form as that of pipe.
+
+                eventfd endpoint information is displayed in the  NAME  column
+                in  the same form as that of pipe. This feature works on Linux
+                kernels above 5.2.0.
+
+                Multiple occurrences of  this  information  can  appear  in  a
+                file's NAME column.
+
+                -E specifies that endpoint supported files should be displayed
+                with endpoint information, but not the files of the endpoints.
+
+       +|-f [cfgGn]
+                f by itself clarifies how path name arguments are to be inter‐
+                preted.   When followed by c, f, g, G, or n in any combination
+                it specifies that the listing of kernel file structure  infor‐
+                mation is to be enabled (`+') or inhibited (`-').
+
+                Normally  a  path  name  argument is taken to be a file system
+                name if it matches a mounted-on  directory  name  reported  by
+                mount(8),  or  if  it  represents a block device, named in the
+                mount output and associated with  a  mounted  directory  name.
+                When +f is specified, all path name arguments will be taken to
+                be file system names, and lsof will complain if any  are  not.
+                This  can  be  useful,  for example, when the file system name
+                (mounted-on device) isn't a block device.   This  happens  for
+                some CD-ROM file systems.
+
+                When  -f  is specified by itself, all path name arguments will
+                be taken to be simple files.  Thus, for example,  the  ``-f --
+                /''  arguments direct lsof to search for open files with a `/'
+                path name, not all open files in the `/' (root) file system.
+
+                Be careful to make sure +f and -f are properly terminated  and
+                aren't followed by a character (e.g., of the file or file sys‐
+                tem name) that might be taken as a  parameter.   For  example,
+                use ``--'' after +f and -f as in these examples.
+
+                     $ lsof +f -- /file/system/name
+                     $ lsof -f -- /file/name
+
+                The  listing  of  information from kernel file structures, re‐
+                quested with the +f [cfgGn] option form,  is  normally  inhib‐
+                ited,  and is not available in whole or part for some dialects
+                - e.g., /proc-based Linux kernels below 2.6.22.  When the pre‐
+                fix  to  f is a plus sign (`+'), these characters request file
+                structure information:
+
+                     c    file structure use count (not Linux)
+                     f    file structure address (not Linux)
+                     g    file flag abbreviations (Linux 2.6.22 and up)
+
+                          Abbrev.   Flag in C code (see open(2))
+
+                          W         O_WRONLY
+                          RW        O_RDWR
+                          CR        O_CREAT
+                          EXCL      O_EXCL
+                          NTTY      O_NOCTTY
+                          TR        O_TRUNC
+                          AP        O_APPEND
+                          ND        O_NDELAY
+                          SYN       O_SYNC
+                          ASYN      O_ASYNC
+                          DIR       O_DIRECT
+                          DTY       O_DIRECTORY
+                          NFLK      O_NOFOLLOW
+                          NATM      O_NOATIME
+                          DSYN      O_DSYNC
+                          RSYN      O_RSYNC
+                          LG        O_LARGEFILE
+                          CX        O_CLOEXEC
+                          TMPF      O_TMPFILE
+
+                     G    file flags in hexadecimal (Linux 2.6.22 and up)
+                     n    file structure node address (not Linux)
+
+                When the prefix is minus (`-') the same characters disable the
+                listing of the indicated values.
+
+                File  structure  addresses,  use  counts,  flags, and node ad‐
+                dresses may be used to detect more readily identical files in‐
+                herited  by child processes and identical files in use by dif‐
+                ferent processes.  Lsof column output can be sorted by  output
+                columns  holding  the  values and listed to identify identical
+                file use, or lsof field output can be parsed by an AWK or Perl
+                post-filter script, or by a C program.
+
+       -F f     specifies  a  character list, f, that selects the fields to be
+                output for processing by another program,  and  the  character
+                that terminates each output field.  Each field to be output is
+                specified with a single character in f.  The field  terminator
+                defaults to NL, but may be changed to NUL (000).  See the OUT‐
+                PUT FOR OTHER PROGRAMS section for a description of the  field
+                identification characters and the field output process.
+
+                When the field selection character list is empty, all standard
+                fields are selected (except the  raw  device  field,  security
+                context  and  zone field for compatibility reasons) and the NL
+                field terminator is used.
+
+                When the field selection character list contains only  a  zero
+                (`0'),  all  fields  are selected (except the raw device field
+                for compatibility reasons) and the NUL terminator character is
+                used.
+
+                Other combinations of fields and their associated field termi‐
+                nator character must be set with explicit entries in f, as de‐
+                scribed in the OUTPUT FOR OTHER PROGRAMS section.
+
+                When  a field selection character identifies an item lsof does
+                not normally list - e.g., PPID, selected with -R -  specifica‐
+                tion of the field character - e.g., ``-FR'' - also selects the
+                listing of the item.
+
+                When the field selection character list  contains  the  single
+                character  `?',  lsof  will  display  a help list of the field
+                identification characters.  (Escape the `?' character as  your
+                shell requires.)
+
+       -g [s]   excludes  or  selects  the  listing of files for the processes
+                whose optional process group IDentification (PGID) numbers are
+                in  the comma-separated set s - e.g., ``123'' or ``123,^456''.
+                (There should be no spaces in the set.)
+
+                PGID numbers that begin with `^' (negation)  represent  exclu‐
+                sions.
+
+                Multiple  PGID  numbers are joined in a single ORed set before
+                participating in AND option selection.  However,  PGID  exclu‐
+                sions  are applied without ORing or ANDing and take effect be‐
+                fore other selection criteria are applied.
+
+                The -g option also enables the output display of PGID numbers.
+                When specified without a PGID set that's all it does.
+
+       -H       directs  lsof  to  print  human  readable  sizes,  e.g. 123.4K
+                456.7M.
+
+       -i [i]   selects the listing of files any  of  whose  Internet  address
+                matches  the  address specified in i.  If no address is speci‐
+                fied, this option selects the listing of all Internet and x.25
+                (HP-UX) network files.
+
+                If  -i4  or  -i6  is specified with no following address, only
+                files of the indicated IP version,  IPv4  or  IPv6,  are  dis‐
+                played.   (An  IPv6  specification may be used only if the di‐
+                alects supports IPv6, as indicated by ``[46]'' and ``IPv[46]''
+                in  lsof's  -h  or  -?  output.)  Sequentially specifying -i4,
+                followed by -i6 is the same as specifying -i, and  vice-versa.
+                Specifying  -i4, or -i6 after -i is the same as specifying -i4
+                or -i6 by itself.
+
+                Multiple addresses (up to a limit of  100)  may  be  specified
+                with  multiple  -i  options.   (A  port number or service name
+                range is counted as one address.)  They are joined in a single
+                ORed set before participating in AND option selection.
+
+                An  Internet address is specified in the form (Items in square
+                brackets are optional.):
+
+                [46][protocol][@hostname|hostaddr][:service|port]
+
+                where:
+                     46 specifies the IP version, IPv4 or IPv6
+                          that applies to the following address.
+                          '6' may be be specified only if the UNIX
+                          dialect supports IPv6.  If neither '4' nor
+                          '6' is specified, the following address
+                          applies to all IP versions.
+                     protocol is a protocol name - TCP, UDP or UDPLITE.
+                     hostname is an Internet host name.  Unless a
+                          specific IP version is specified, open
+                          network files associated with host names
+                          of all versions will be selected.
+                     hostaddr is a numeric Internet IPv4 address in
+                          dot form; or an IPv6 numeric address in
+                          colon form, enclosed in brackets, if the
+                          UNIX dialect supports IPv6.  When an IP
+                          version is selected, only its numeric
+                          addresses may be specified.
+                     service is an /etc/services name - e.g., smtp -
+                          or a list of them.
+                     port is a port number, or a list of them.
+
+                IPv6 options may be used only if  the  UNIX  dialect  supports
+                IPv6.  To see if the dialect supports IPv6, run lsof and spec‐
+                ify the -h or -?  (help) option.  If the displayed description
+                of  the  -i  option contains ``[46]'' and ``IPv[46]'', IPv6 is
+                supported.
+
+                IPv4 host names and addresses may not be specified if  network
+                file  selection is limited to IPv6 with -i 6.  IPv6 host names
+                and addresses may not be specified if network  file  selection
+                is  limited  to  IPv4  with  -i  4.  When an open IPv4 network
+                file's address is mapped in an IPv6 address, the  open  file's
+                type  will be IPv6, not IPv4, and its display will be selected
+                by '6', not '4'.
+
+                At least one address component -  4,  6,  protocol,  hostname,
+                hostaddr,  or  service - must be supplied.  The `@' character,
+                leading the host specification, is always required; as is  the
+                `:',  leading the port specification.  Specify either hostname
+                or hostaddr.  Specify either service name list or port  number
+                list.   If  a service name list is specified, the protocol may
+                also need to be specified if the TCP,  UDP  and  UDPLITE  port
+                numbers  for  the  service name are different.  Use any case -
+                lower or upper - for protocol.
+
+                Service names and port numbers may be combined in a list whose
+                entries  are  separated  by commas and whose numeric range en‐
+                tries are separated by minus signs.  There may be no  embedded
+                spaces,  and  all  service  names must belong to the specified
+                protocol.  Since service  names  may  contain  embedded  minus
+                signs,  the starting entry of a range can't be a service name;
+                it can be a port number, however.
+
+                Here are some sample addresses:
+
+                     -i6 - IPv6 only
+                     TCP:25 - TCP and port 25
+                     @1.2.3.4 - Internet IPv4 host address 1.2.3.4
+                     @[3ffe:1ebc::1]:1234 - Internet IPv6 host address
+                          3ffe:1ebc::1, port 1234
+                     UDP:who - UDP who service port
+                     TCP@lsof.itap:513 - TCP, port 513 and host name lsof.itap
+                     tcp@foo:1-10,smtp,99 - TCP, ports 1 through 10,
+                          service name smtp, port 99, host name foo
+                     tcp@bar:1-smtp - TCP, ports 1 through smtp, host bar
+                     :time - either TCP, UDP or UDPLITE time service port
+
+       -K k     selects the listing of tasks (threads) of  processes,  on  di‐
+                alects  where  task (thread) reporting is supported.  (If help
+                output - i.e., the output of the -h or  -?   options  -  shows
+                this  option, then task (thread) reporting is supported by the
+                dialect.)
+
+                If -K is followed by a value,  k,  it  must  be  ``i''.   That
+                causes  lsof  to  ignore  tasks,  particularly in the default,
+                list-everything case when no other options are specified.
+
+                When -K and -a are both specified on Linux, and the tasks of a
+                main  process  are selected by other options, the main process
+                will also be listed as though it were a task,  but  without  a
+                task ID.  (See the description of the TID column in the OUTPUT
+                section.)
+
+                Where the FreeBSD version supports threads, all  threads  will
+                be listed with their IDs.
+
+                In  general threads and tasks inherit the files of the caller,
+                but may close some and open others, so lsof always reports all
+                the open files of threads and tasks.
+
+       -k k     specifies  a  kernel  name  list file, k, in place of /vmunix,
+                /mach, etc.   -k  is  not  available  under  AIX  on  the  IBM
+                RISC/System 6000.
+
+       -l       inhibits the conversion of user ID numbers to login names.  It
+                is also useful when login name lookup is working improperly or
+                slowly.
+
+       +|-L [l] enables  (`+')  or  disables  (`-')  the  listing of file link
+                counts, where they are available - e.g., they aren't available
+                for sockets, or most FIFOs and pipes.
+
+                When  +L  is  specified  without  a following number, all link
+                counts will be listed.  When -L is specified (the default), no
+                link counts will be listed.
+
+                When  +L  is  followed  by  a number, only files having a link
+                count less than that number will be listed.   (No  number  may
+                follow  -L.)   A specification of the form ``+L1'' will select
+                open files that have been unlinked.  A  specification  of  the
+                form ``+aL1 <file_system>'' will select unlinked open files on
+                the specified file system.
+
+                For other link count comparisons, use field output (-F) and  a
+                post-processing script or program.
+
+       +|-m m   specifies  an  alternate kernel memory file or activates mount
+                table supplement processing.
+
+                The option form -m m specifies a kernel  memory  file,  m,  in
+                place of /dev/kmem or /dev/mem - e.g., a crash dump file.
+
+                The  option  form  +m requests that a mount supplement file be
+                written to the standard output file.  All  other  options  are
+                silently ignored.
+
+                There  will  be  a  line in the mount supplement file for each
+                mounted file system, containing the mounted file system direc‐
+                tory,  followed by a single space, followed by the device num‐
+                ber in hexadecimal "0x" format - e.g.,
+
+                     / 0x801
+
+                Lsof can use the mount supplement file to get  device  numbers
+                for  file  systems  when  it  can't  get  them  via stat(2) or
+                lstat(2).
+
+                The option form +m m identifies m as a mount supplement file.
+
+                Note: the +m and +m m options are not available for  all  sup‐
+                ported dialects.  Check the output of lsof's -h or -?  options
+                to see if the +m and +m m options are available.
+
+       +|-M     Enables (+) or disables (-) the reporting of portmapper regis‐
+                trations for local TCP, UDP and UDPLITE ports, where port map‐
+                ping is supported.  (See the last paragraph of this option de‐
+                scription  for information about where portmapper registration
+                reporting is supported.)
+
+                The default reporting mode is set by the lsof builder with the
+                HASPMAPENABLED #define in the dialect's machine.h header file;
+                lsof is distributed with the  HASPMAPENABLED  #define  deacti‐
+                vated, so portmapper reporting is disabled by default and must
+                be requested with +M.  Specifying lsof's -h or -?  option will
+                report  the  default  mode.  Disabling portmapper registration
+                when it is already disabled or enabling it  when  already  en‐
+                abled  is  acceptable.  When portmapper registration reporting
+                is enabled, lsof displays the portmapper registration (if any)
+                for local TCP, UDP or UDPLITE ports in square brackets immedi‐
+                ately following the port numbers  or  service  names  -  e.g.,
+                ``:1234[name]'' or ``:name[100083]''.  The registration infor‐
+                mation may be a name or number, depending on what  the  regis‐
+                tering  program  supplied to the portmapper when it registered
+                the port.
+
+                When portmapper registration reporting is  enabled,  lsof  may
+                run a little more slowly or even become blocked when access to
+                the portmapper becomes congested or stopped.  Reverse the  re‐
+                porting mode to determine if portmapper registration reporting
+                is slowing or blocking lsof.
+
+                For purposes of portmapper registration reporting lsof consid‐
+                ers  a  TCP,  UDP or UDPLITE port local if: it is found in the
+                local part of its containing kernel structure; or if it is lo‐
+                cated  in  the foreign part of its containing kernel structure
+                and the local and foreign Internet addresses are the same;  or
+                if  it is located in the foreign part of its containing kernel
+                structure and the foreign Internet address is  INADDR_LOOPBACK
+                (127.0.0.1).   This  rule  may  make  lsof ignore some foreign
+                ports on machines with multiple interfaces  when  the  foreign
+                Internet  address  is  on a different interface from the local
+                one.
+
+                See the lsof FAQ (The FAQ section gives  its  location.)   for
+                further  discussion  of  portmapper registration reporting is‐
+                sues.
+
+                Portmapper registration reporting is  supported  only  on  di‐
+                alects  that have RPC header files.  (Some Linux distributions
+                with GlibC 2.14 do not have them.)  When portmapper  registra‐
+                tion  reporting  is  supported, the -h or -?  help output will
+                show the +|-M option.
+
+       -n       inhibits the conversion of network numbers to host  names  for
+                network  files.   Inhibiting  conversion  may  make  lsof  run
+                faster.  It is also useful when host name lookup is not  work‐
+                ing properly.
+
+       -N       selects the listing of NFS files.
+
+       -o       directs  lsof  to display file offset at all times.  It causes
+                the SIZE/OFF output column title  to  be  changed  to  OFFSET.
+                Note: on some UNIX dialects lsof can't obtain accurate or con‐
+                sistent file offset information from its kernel data  sources,
+                sometimes  just  for  particular  kinds of files (e.g., socket
+                files.)  Consult the lsof FAQ (The FAQ section gives its loca‐
+                tion.)  for more information.
+
+                The  -o and -s options are mutually exclusive; they can't both
+                be specified.  When neither is specified, lsof displays  what‐
+                ever value - size or offset - is appropriate and available for
+                the type of the file.
+
+       -o o     defines the number of decimal digits (o) to be  printed  after
+                the  ``0t''  for  a file offset before the form is switched to
+                ``0x...''.  An o value of zero (unlimited) directs lsof to use
+                the ``0t'' form for all offset output.
+
+                This  option  does  NOT  direct  lsof to display offset at all
+                times; specify -o (without a trailing number) to do that.   -o
+                o  only  specifies the number of digits after ``0t'' in either
+                mixed size and offset or offset-only output.  Thus, for  exam‐
+                ple, to direct lsof to display offset at all times with a dec‐
+                imal digit count of 10, use:
+
+                     -o -o 10
+                or
+                     -oo10
+
+                The default number of digits allowed after ``0t'' is  normally
+                8, but may have been changed by the lsof builder.  Consult the
+                description of the -o o option in the output of the -h  or  -?
+                option to determine the default that is in effect.
+
+       -O       directs  lsof  to  bypass  the strategy it uses to avoid being
+                blocked by some kernel operations - i.e., doing them in forked
+                child  processes.   See  the  BLOCKS AND TIMEOUTS and AVOIDING
+                KERNEL BLOCKS sections for more information on  kernel  opera‐
+                tions that may block lsof.
+
+                While use of this option will reduce lsof startup overhead, it
+                may also cause lsof to hang when the kernel doesn't respond to
+                a function.  Use this option cautiously.
+
+       -p s     excludes  or  selects  the  listing of files for the processes
+                whose optional process IDentification (PID) numbers are in the
+                comma-separated set s - e.g., ``123'' or ``123,^456''.  (There
+                should be no spaces in the set.)
+
+                PID numbers that begin with `^'  (negation)  represent  exclu‐
+                sions.
+
+                Multiple  process  ID  numbers are joined in a single ORed set
+                before participating in AND option  selection.   However,  PID
+                exclusions are applied without ORing or ANDing and take effect
+                before other selection criteria are applied.
+
+       -P       inhibits the conversion of port numbers to port names for net‐
+                work  files.   Inhibiting  the  conversion may make lsof run a
+                little faster.  It is also useful when port name lookup is not
+                working properly.
+
+       -Q       ignore  failed  search  terms. When lsof is told to search for
+                users of a file, or for users of a device, or for  a  specific
+                PID,  or  for certain protocols in use by that PID, and so on,
+                lsof will return an error if any of  the  search  results  are
+                empty.  The  -Q  option will change this behavior so that lsof
+                will instead return a successful exit code (0) even if any  of
+                the  search  results  are  empty.  In addition, missing search
+                terms will not be reported to stderr.
+
+       +|-r [t[c<N>][m<fmt>]]
+                puts lsof in repeat mode.  There lsof lists open files as  se‐
+                lected  by  other options, delays t seconds (default fifteen),
+                then repeats the listing, delaying  and  listing  repetitively
+                until  stopped by a condition defined by the prefix to the op‐
+                tion.
+
+                If the prefix is a `-', repeat mode is endless.  Lsof must  be
+                terminated  with  an  interrupt or quit signal.  `c<N>' is for
+                specifying the limits of repeating; if the  number  of  itera‐
+                tions reaches at `<N>', Lsof stops itself.
+
+                If  the prefix is `+', repeat mode will end the first cycle no
+                open files are listed - and of course  when  lsof  is  stopped
+                with  an  interrupt or quit signal.  When repeat mode ends be‐
+                cause no files are listed, the process exit code will be  zero
+                if  any  open  files  were ever listed; one, if none were ever
+                listed.
+
+                Lsof marks the end of each listing:  if  field  output  is  in
+                progress  (the  -F,  option  has  been specified), the default
+                marker is `m'; otherwise the default marker  is  ``========''.
+                The marker is followed by a NL character.
+
+                The  optional  "m<fmt>"  argument  specifies  a format for the
+                marker line.  The <fmt> characters following  `m'  are  inter‐
+                preted  as a format specification to the strftime(3) function,
+                when both it and the localtime(3) function  are  available  in
+                the  dialect's  C library.  Consult the strftime(3) documenta‐
+                tion for what may appear in its  format  specification.   Note
+                that  when field output is requested with the -F option, <fmt>
+                cannot contain the NL format, ``%n''.   Note  also  that  when
+                <fmt>  contains  spaces  or  other  characters that affect the
+                shell's interpretation of arguments, <fmt> must be quoted  ap‐
+                propriately.
+
+                Repeat mode reduces lsof startup overhead, so it is more effi‐
+                cient to use this mode than to call lsof repetitively  from  a
+                shell script, for example.
+
+                To use repeat mode most efficiently, accompany +|-r with spec‐
+                ification of other lsof selection options, so  the  amount  of
+                kernel memory access lsof does will be kept to a minimum.  Op‐
+                tions that filter at the process level - e.g., -c, -g, -p,  -u
+                - are the most efficient selectors.
+
+                Repeat  mode is useful when coupled with field output (see the
+                -F, option description) and a supervising awk or Perl  script,
+                or a C program.
+
+       -R       directs  lsof to list the Parent Process IDentification number
+                in the PPID column.
+
+       -s [p:s] s alone directs lsof to display file size at  all  times.   It
+                causes the SIZE/OFF output column title to be changed to SIZE.
+                If the file does not have a size, nothing is displayed.
+
+                The optional -s p:s form is available only  for  selected  di‐
+                alects, and only when the -h or -?  help output lists it.
+
+                When  the optional form is available, the s may be followed by
+                a protocol name (p), either TCP or UDP, a colon  (`:')  and  a
+                comma-separated  protocol  state  name list, the option causes
+                open TCP and UDP files to be excluded if their  state  name(s)
+                are  in  the  list (s) preceded by a `^'; or included if their
+                name(s) are not preceded by a `^'.
+
+                Dialects that support this option may support only one  proto‐
+                col.   When  an  unsupported  protocol is specified, a message
+                will be displayed indicating state names for the protocol  are
+                unavailable.
+
+                When  an  inclusion  list  is defined, only network files with
+                state names in the list will be present in  the  lsof  output.
+                Thus,  specifying one state name means that only network files
+                with that lone state name will be listed.
+
+                Case is unimportant in the protocol or state names, but  there
+                may  be  no spaces and the colon (`:') separating the protocol
+                name (p) and the state name list (s) is required.
+
+                If only TCP and UDP files are to be listed, as  controlled  by
+                the specified exclusions and inclusions, the -i option must be
+                specified, too.  If only a single protocol's files are  to  be
+                listed, add its name as an argument to the -i option.
+
+                For example, to list only network files with TCP state LISTEN,
+                use:
+
+                     -iTCP -sTCP:LISTEN
+
+                Or, for example, to list network files with all UDP states ex‐
+                cept Idle, use:
+
+                     -iUDP -sUDP:^Idle
+
+                State  names  vary with UNIX dialects, so it's not possible to
+                provide a complete list.  Some common  TCP  state  names  are:
+                CLOSED,  IDLE, BOUND, LISTEN, ESTABLISHED, SYN_SENT, SYN_RCDV,
+                ESTABLISHED,   CLOSE_WAIT,   FIN_WAIT1,   CLOSING,   LAST_ACK,
+                FIN_WAIT_2, and TIME_WAIT.  Two common UDP state names are Un‐
+                bound and Idle.
+
+                See the lsof FAQ (The FAQ section gives  its  location.)   for
+                more  information  on  how to use protocol state exclusion and
+                inclusion, including examples.
+
+                The -o (without a following decimal digit count) and -s option
+                (without  a  following protocol and state name list) are mutu‐
+                ally exclusive; they can't both be specified.  When neither is
+                specified,  lsof displays whatever value - size or offset - is
+                appropriate and available for the type of file.
+
+                Since some types of files don't have true sizes - sockets, FI‐
+                FOs,  pipes,  etc. - lsof displays for their sizes the content
+                amounts in their associated kernel buffers, if possible.
+
+       -S [t]   specifies an optional time-out seconds value for kernel  func‐
+                tions - lstat(2), readlink(2), and stat(2) - that might other‐
+                wise deadlock.  The minimum for t is two;  the  default,  fif‐
+                teen; when no value is specified, the default is used.
+
+                See the BLOCKS AND TIMEOUTS section for more information.
+
+       -T [t]   controls  the  reporting of some TCP/TPI information, also re‐
+                ported by netstat(1), following  the  network  addresses.   In
+                normal  output  the  information  appears in parentheses, each
+                item except TCP or TPI state name  identified  by  a  keyword,
+                followed by `=', separated from others by a single space:
+
+                     <TCP or TPI state name>
+                     QR=<read queue length>
+                     QS=<send queue length>
+                     SO=<socket options and values>
+                     SS=<socket states>
+                     TF=<TCP flags and values>
+                     WR=<window read length>
+                     WW=<window write length>
+
+                Not all values are reported for all UNIX dialects.  Items val‐
+                ues (when available) are reported after the item name and '='.
+
+                When the field output mode is in effect (See OUTPUT FOR  OTHER
+                PROGRAMS.)   each  item  appears as a field with a `T' leading
+                character.
+
+                -T with no following key characters disables TCP/TPI  informa‐
+                tion reporting.
+
+                -T with following characters selects the reporting of specific
+                TCP/TPI information:
+
+                     f    selects reporting of socket options,
+                          states and values, and TCP flags and
+                          values.
+                     q    selects queue length reporting.
+                     s    selects connection state reporting.
+                     w    selects window size reporting.
+
+                Not all selections are enabled for some UNIX dialects.   State
+                may  be  selected for all dialects and is reported by default.
+                The -h or -?  help output for the -T option will show what se‐
+                lections may be used with the UNIX dialect.
+
+                When  -T  is used to select information - i.e., it is followed
+                by one or more selection characters - the displaying of  state
+                is  disabled  by  default,  and it must be explicitly selected
+                again in the characters following -T.  (In effect,  then,  the
+                default  is equivalent to -Ts.)  For example, if queue lengths
+                and state are desired, use -Tqs.
+
+                Socket options, socket states, some socket values,  TCP  flags
+                and  one TCP value may be reported (when available in the UNIX
+                dialect) in the form of the names that commonly  appear  after
+                SO_,  so_,  SS_, TCP_  and TF_ in the dialect's header files -
+                most    often    <sys/socket.h>,     <sys/socketvar.h>     and
+                <netinet/tcp_var.h>.  Consult those header files for the mean‐
+                ing of the flags, options, states and values.
+
+                ``SO='' precedes socket options and  values;  ``SS='',  socket
+                states; and ``TF='', TCP flags and values.
+
+                If  a flag or option has a value, the value will follow an '='
+                and  the  name  --   e.g.,   ``SO=LINGER=5'',   ``SO=QLIM=5'',
+                ``TF=MSS=512''.  The following seven values may be reported:
+
+                     Name
+                     Reported  Description (Common Symbol)
+
+                     KEEPALIVE keep alive time (SO_KEEPALIVE)
+                     LINGER    linger time (SO_LINGER)
+                     MSS       maximum segment size (TCP_MAXSEG)
+                     PQLEN          partial listen queue connections
+                     QLEN      established listen queue connections
+                     QLIM      established listen queue limit
+                     RCVBUF    receive buffer length (SO_RCVBUF)
+                     SNDBUF    send buffer length (SO_SNDBUF)
+
+                Details  on what socket options and values, socket states, and
+                TCP flags and values may be displayed for particular UNIX  di‐
+                alects  may  be  found in the answer to the ``Why doesn't lsof
+                report socket options, socket states, and TCP flags and values
+                for  my  dialect?''  and ``Why doesn't lsof report the partial
+                listen queue connection count for my dialect?''  questions  in
+                the  lsof  FAQ (The FAQ section gives its location.)  On Linux
+                this option also prints the state of UNIX domain sockets.
+
+       -t       produce  terse  output  comprising  only  process  identifiers
+                (without  a  header),  so  that it is easy to use programmati‐
+                cally. e.g.
+
+                     # reload anything using old SSL
+                     lsof -t /lib/*/libssl.so.* | xargs -r kill -HUP
+
+                     # get list of processes and then iterate over them (Bash only)
+                     mapfile -t pids < <(
+                         lsof -wt /var/log/your.log
+                     )
+                     for pid in "${pids[@]}" ; do
+                         your_command -p "$pid"
+                     done
+
+                The -t option implies the -w option.
+
+       -u s     selects the listing of files for the user whose login names or
+                user  ID  numbers  are  in  the  comma-separated set s - e.g.,
+                ``abe'', or ``548,root''.  (There should be no spaces  in  the
+                set.)
+
+                Multiple login names or user ID numbers are joined in a single
+                ORed set before participating in AND option selection.
+
+                If a login name or user ID is preceded by a `^', it becomes  a
+                negation - i.e., files of processes owned by the login name or
+                user ID will never be listed.  A negated login name or user ID
+                selection  is neither ANDed nor ORed with other selections; it
+                is applied before all other selections and absolutely excludes
+                the  listing of the files of the process.  For example, to di‐
+                rect lsof to exclude the listing of files  belonging  to  root
+                processes, specify ``-u^root'' or ``-u^0''.
+
+       -U       selects the listing of UNIX domain socket files.
+
+       -v       selects  the  listing  of lsof version information, including:
+                revision number; when the lsof  binary  was  constructed;  who
+                constructed  the  binary  and  where; the name of the compiler
+                used to construct the lsof binary; the version number  of  the
+                compiler when readily available; the compiler and loader flags
+                used to construct the lsof  binary;  and  system  information,
+                typically the output of uname's -a option.
+
+       -V       directs  lsof  to  indicate the items it was asked to list and
+                failed to find - command names, file names, Internet addresses
+                or files, login names, NFS files, PIDs, PGIDs, and UIDs.
+
+                When  other  options  are  ANDed  to  search  options, or com‐
+                pile-time options restrict the listing of some files, lsof may
+                not  report that it failed to find a search item when an ANDed
+                option or compile-time option prevents the listing of the open
+                file containing the located search item.
+
+                For example, ``lsof -V -iTCP@foobar -a -d 999'' may not report
+                a failure to locate open files at ``TCP@foobar'' and  may  not
+                list  any,  if  none  have a file descriptor number of 999.  A
+                similar situation arises when HASSECURITY  and  HASNOSOCKSECU‐
+                RITY  are defined at compile time and they prevent the listing
+                of open files.
+
+       +|-w     Enables (+) or disables (-) the suppression  of  warning  mes‐
+                sages.
+
+                The  lsof builder may choose to have warning messages disabled
+                or enabled by default.  The default warning message  state  is
+                indicated  in  the  output of the -h or -?  option.  Disabling
+                warning messages when they are already  disabled  or  enabling
+                them when already enabled is acceptable.
+
+                The -t option implies the -w option.
+
+       -x [fl]  may accompany the +d and +D options to direct their processing
+                to cross over symbolic links and|or file system  mount  points
+                encountered when scanning the directory (+d) or directory tree
+                (+D).
+
+                If -x is specified by itself without  a  following  parameter,
+                cross-over  processing  of both symbolic links and file system
+                mount points is enabled.  Note that when -x is specified with‐
+                out a parameter, the next argument must begin with '-' or '+'.
+
+                The  optional  'f'  parameter  enables file system mount point
+                cross-over processing; 'l', symbolic link cross-over  process‐
+                ing.
+
+                The  -x option may not be supplied without also supplying a +d
+                or +D option.
+
+       -X       This is a dialect-specific option.
+
+           AIX:
+                This IBM AIX RISC/System 6000 option requests the reporting of
+                executed text file and shared library references.
+
+                WARNING: because this option uses the kernel readx() function,
+                its use on a  busy  AIX  system  might  cause  an  application
+                process  to  hang  so completely that it can neither be killed
+                nor stopped.  I have never seen this happen or had a report of
+                its  happening,  but  I think there is a remote possibility it
+                could happen.
+
+                By default use of readx() is disabled.  On AIX  5L  and  above
+                lsof  may  need  setuid-root permission to perform the actions
+                this option requests.
+
+                The lsof builder may specify that the -X option be  restricted
+                to  processes  whose real UID is root.  If that has been done,
+                the -X option will not appear in the -h or -?  help output un‐
+                less  the  real  UID of the lsof process is root.  The default
+                lsof distribution allows any UID to specify -X, so by  default
+                it will appear in the help output.
+
+                When  AIX readx() use is disabled, lsof may not be able to re‐
+                port information for all text and loader file references,  but
+                it  may also avoid exacerbating an AIX kernel directory search
+                kernel error, known as the Stale Segment ID bug.
+
+                The readx() function, used by lsof or any other program to ac‐
+                cess  some  sections of kernel virtual memory, can trigger the
+                Stale Segment ID bug.  It can cause the kernel's  dir_search()
+                function to believe erroneously that part of an in-memory copy
+                of a file system directory has been zeroed.  Another  applica‐
+                tion  process, distinct from lsof, asking the kernel to search
+                the  directory  -  e.g.,  by  using  open(2)   -   can   cause
+                dir_search()  to  loop  forever,  thus hanging the application
+                process.
+
+                Consult the lsof FAQ (The FAQ  section  gives  its  location.)
+                and the 00README file of the lsof distribution for a more com‐
+                plete description of the Stale Segment ID bug, its  APAR,  and
+                methods for defining readx() use when compiling lsof.
+
+           Linux:
+                This Linux option requests that lsof skip the reporting of in‐
+                formation on all open TCP,  UDP  and  UDPLITE  IPv4  and  IPv6
+                files.
+
+                This  Linux  option  is most useful when the system has an ex‐
+                tremely large number of open TCP, UDP and UDPLITE  files,  the
+                processing  of  whose  information  in  the /proc/net/tcp* and
+                /proc/net/udp* files would take lsof a long  time,  and  whose
+                reporting is not of interest.
+
+                Use  this option with care and only when you are sure that the
+                information you want lsof to  display  isn't  associated  with
+                open TCP, UDP or UDPLITE socket files.
+
+           Solaris 10 and above:
+                This  Solaris  10  and  above option requests the reporting of
+                cached paths for files that have been deleted - i.e.,  removed
+                with rm(1) or unlink(2).
+
+                The  cached  path  is followed by the string `` (deleted)'' to
+                indicate that the path by which the file was opened  has  been
+                deleted.
+
+                Because  intervening  changes made to the path - i.e., renames
+                with mv(1) or rename(2) - are not recorded in the cached path,
+                what  lsof  reports  is  only  the  path by which the file was
+                opened, not its possibly different final path.
+
+       -z [z]   specifies how Solaris 10 and higher zone information is to  be
+                handled.
+
+                Without  a following argument - e.g., NO z - the option speci‐
+                fies that zone names are to be listed in the ZONE output  col‐
+                umn.
+
+                The  -z option may be followed by a zone name, z.  That causes
+                lsof to list only open files for processes in that zone.  Mul‐
+                tiple  -z z option and argument pairs may be specified to form
+                a list of named zones.  Any open file of any process in any of
+                the  zones  will be listed, subject to other conditions speci‐
+                fied by other options and arguments.
+
+       -Z [Z]   specifies how SELinux security contexts are to be handled.  It
+                and  'Z'  field  output  character  support are inhibited when
+                SELinux is disabled in the running Linux kernel.   See  OUTPUT
+                FOR  OTHER PROGRAMS for more information on the 'Z' field out‐
+                put character.
+
+                Without a following argument - e.g., NO Z - the option  speci‐
+                fies  that  security  contexts  are  to be listed in the SECU‐
+                RITY-CONTEXT output column.
+
+                The -Z option may be followed by a wildcard  security  context
+                name,  Z.   That  causes lsof to list only open files for pro‐
+                cesses in that security context.  Multiple -Z Z option and ar‐
+                gument  pairs may be specified to form a list of security con‐
+                texts.  Any open file of any process in any  of  the  security
+                contexts will be listed, subject to other conditions specified
+                by other options and arguments.  Note that Z can be  A:B:C  or
+                *:B:C or A:B:* or *:*:C to match against the A:B:C context.
+
+       --       The  double minus sign option is a marker that signals the end
+                of the keyed options.  It may be used, for example,  when  the
+                first file name begins with a minus sign.  It may also be used
+                when the absence of a value for the last keyed option must  be
+                signified by the presence of a minus sign in the following op‐
+                tion and before the start of the file names.
+
+       names    These are path names of  specific  files  to  list.   Symbolic
+                links  are  resolved  before use.  The first name may be sepa‐
+                rated from the preceding options with the ``--'' option.
+
+                If a name is the mounted-on directory of a file system or  the
+                device  of  the file system, lsof will list all the files open
+                on the file system.  To be considered a file system, the  name
+                must  match a mounted-on directory name in mount(8) output, or
+                match the name of a block device associated with a  mounted-on
+                directory  name.  The +|-f option may be used to force lsof to
+                consider a name a file system identifier (+f) or a simple file
+                (-f).
+
+                If  name  is  a path to a directory that is not the mounted-on
+                directory name of a file system, it is treated just as a regu‐
+                lar  file is treated - i.e., its listing is restricted to pro‐
+                cesses that have it open as a file or  as  a  process-specific
+                directory,  such as the root or current working directory.  To
+                request that lsof look for open files inside a directory name,
+                use the +d s and +D D options.
+
+                If  a name is the base name of a family of multiplexed files -
+                e.g, AIX's /dev/pt[cs] - lsof will  list  all  the  associated
+                multiplexed  files  on  the  device  that  are  open  -  e.g.,
+                /dev/pt[cs]/1, /dev/pt[cs]/2, etc.
+
+                If a name is a UNIX domain  socket  name,  lsof  will  usually
+                search for it by the characters of the name alone - exactly as
+                it is specified and is recorded in the  kernel  socket  struc‐
+                ture.   (See  the next paragraph for an exception to that rule
+                for Linux.)  Specifying a relative path - e.g.,  ./file  -  in
+                place  of  the  file's absolute path - e.g., /tmp/file - won't
+                work because lsof must match the characters you  specify  with
+                what it finds in the kernel UNIX domain socket structures.
+
+                If a name is a Linux UNIX domain socket name, in one case lsof
+                is able to search for it by its device and inode  number,  al‐
+                lowing name to be a relative path.  The case requires that the
+                absolute path -- i.e., one beginning with  a  slash  ('/')  be
+                used  by  the  process  that  created the socket, and hence be
+                stored in the /proc/net/unix file; and it requires  that  lsof
+                be  able to obtain the device and node numbers of both the ab‐
+                solute path in /proc/net/unix and name via successful  stat(2)
+                system  calls.   When  those  conditions are met, lsof will be
+                able to search for the UNIX domain socket when some path to it
+                is  is  specified  in name.  Thus, for example, if the path is
+                /dev/log, and an lsof search is initiated when the working di‐
+                rectory is /dev, then name could be ./log.
+
+                If  a name is none of the above, lsof will list any open files
+                whose device and inode match that of the specified path name.
+
+                If you have also specified the -b option, the only  names  you
+                may safely specify are file systems for which your mount table
+                supplies alternate device numbers.  See  the  AVOIDING  KERNEL
+                BLOCKS and ALTERNATE DEVICE NUMBERS sections for more informa‐
+                tion.
+
+                Multiple file names are joined in a  single  ORed  set  before
+                participating in AND option selection.
+
+AFS
+       Lsof  supports the recognition of AFS files for these dialects (and AFS
+       versions):
+
+            AIX 4.1.4 (AFS 3.4a)
+            HP-UX 9.0.5 (AFS 3.4a)
+            Linux 1.2.13 (AFS 3.3)
+            Solaris 2.[56] (AFS 3.4a)
+
+       It may recognize AFS files on other versions of these dialects, but has
+       not  been  tested there.  Depending on how AFS is implemented, lsof may
+       recognize AFS files in other dialects, or may have difficulties  recog‐
+       nizing AFS files in the supported dialects.
+
+       Lsof may have trouble identifying all aspects of AFS files in supported
+       dialects when AFS kernel support is  implemented  via  dynamic  modules
+       whose  addresses  do not appear in the kernel's variable name list.  In
+       that case, lsof may have to guess at the identity  of  AFS  files,  and
+       might  not be able to obtain volume information from the kernel that is
+       needed for calculating AFS volume node numbers.  When lsof  can't  com‐
+       pute volume node numbers, it reports blank in the NODE column.
+
+       The  -A  A  option is available in some dialect implementations of lsof
+       for specifying the name list file where dynamic module kernel addresses
+       may  be found.  When this option is available, it will be listed in the
+       lsof help output, presented in response to the -h or -?
+
+       See the lsof FAQ (The FAQ section gives its location.)  for more infor‐
+       mation  about  dynamic modules, their symbols, and how they affect lsof
+       options.
+
+       Because AFS path lookups don't seem to participate in the kernel's name
+       cache  operations,  lsof  can't  identify  path name components for AFS
+       files.
+
+SECURITY
+       Lsof has three features that may cause security concerns.   First,  its
+       default  compilation mode allows anyone to list all open files with it.
+       Second, by default it creates a user-readable and user-writable  device
+       cache  file  in  the  home  directory of the real user ID that executes
+       lsof.  (The list-all-open-files and device cache features may  be  dis‐
+       abled when lsof is compiled.)  Third, its -k and -m options name alter‐
+       nate kernel name list or memory files.
+
+       Restricting the listing of all open files is  controlled  by  the  com‐
+       pile-time  HASSECURITY and HASNOSOCKSECURITY options.  When HASSECURITY
+       is defined, lsof will allow only the root user to list all open  files.
+       The  non-root  user may list only open files of processes with the same
+       user IDentification number as the real  user  ID  number  of  the  lsof
+       process (the one that its user logged on with).
+
+       However,  if HASSECURITY and HASNOSOCKSECURITY are both defined, anyone
+       may list open socket files, provided they are selected with the -i  op‐
+       tion.
+
+       When HASSECURITY is not defined, anyone may list all open files.
+
+       Help  output,  presented in response to the -h or -?  option, gives the
+       status of the HASSECURITY and HASNOSOCKSECURITY definitions.
+
+       See the Security section of the 00README file of the lsof  distribution
+       for  information on building lsof with the HASSECURITY and HASNOSOCKSE‐
+       CURITY options enabled.
+
+       Creation and use of a user-readable and user-writable device cache file
+       is  controlled  by  the  compile-time HASDCACHE option.  See the DEVICE
+       CACHE FILE section and the sections that follow it for details  on  how
+       its  path  is  formed.   For security considerations it is important to
+       note that in the default lsof distribution, if the real user  ID  under
+       which  lsof  is executed is root, the device cache file will be written
+       in root's home directory - e.g., / or /root.  When HASDCACHE is not de‐
+       fined, lsof does not write or attempt to read a device cache file.
+
+       When  HASDCACHE is defined, the lsof help output, presented in response
+       to the -h, -D?, or -?  options, will provide device cache file handling
+       information.   When HASDCACHE is not defined, the -h or -?  output will
+       have no -D option description.
+
+       Before you decide to disable the device cache file feature  -  enabling
+       it improves the performance of lsof by reducing the startup overhead of
+       examining all the nodes in /dev (or /devices) - read the discussion  of
+       it  in the 00DCACHE file of the lsof distribution and the lsof FAQ (The
+       FAQ section gives its location.)
+
+       WHEN IN DOUBT, YOU CAN TEMPORARILY DISABLE THE USE OF THE DEVICE  CACHE
+       FILE WITH THE -Di OPTION.
+
+       When lsof user declares alternate kernel name list or memory files with
+       the -k and -m options, lsof checks the user's authority  to  read  them
+       with  access(2).   This  is  intended to prevent whatever special power
+       lsof's modes might confer on it from letting it read files not normally
+       accessible via the authority of the real user ID.
+
+OUTPUT
+       This  section  describes the information lsof lists for each open file.
+       See the OUTPUT FOR OTHER PROGRAMS section for additional information on
+       output that can be processed by another program.
+
+       Lsof  only  outputs printable (declared so by isprint(3)) 8 bit charac‐
+       ters.  Non-printable characters are printed in one of three forms:  the
+       C  ``\[bfrnt]'' form; the control character `^' form (e.g., ``^@''); or
+       hexadecimal leading ``\x'' form (e.g., ``\xab'').  Space is  non-print‐
+       able in the COMMAND column (``\x20'') and printable elsewhere.
+
+       For  some  dialects  -  if HASSETLOCALE is defined in the dialect's ma‐
+       chine.h header file - lsof will print the extended 8 bit characters  of
+       a language locale.  The lsof process must be supplied a language locale
+       environment variable (e.g., LANG) whose value represents a  known  lan‐
+       guage  locale in which the extended characters are considered printable
+       by isprint(3).  Otherwise lsof considers the extended  characters  non-
+       printable  and  prints  them  according  to its rules for non-printable
+       characters, stated above.  Consult your dialect's setlocale(3) man page
+       for  the names of other environment variables that may be used in place
+       of LANG - e.g., LC_ALL, LC_CTYPE, etc.
+
+       Lsof's language locale support for a dialect also covers  wide  charac‐
+       ters  -  e.g., UTF-8 - when HASSETLOCALE and HASWIDECHAR are defined in
+       the dialect's machine.h header file, and when a suitable  language  lo‐
+       cale  has  been defined in the appropriate environment variable for the
+       lsof process.  Wide characters are printable under those conditions  if
+       iswprint(3)  reports  them  to  be.  If HASSETLOCALE, HASWIDECHAR and a
+       suitable language locale aren't defined, or if iswprint(3) reports wide
+       characters  that  aren't  printable, lsof considers the wide characters
+       non-printable and prints each of their 8 bits according  to  its  rules
+       for non-printable characters, stated above.
+
+       Consult  the  answers to the "Language locale support" questions in the
+       lsof FAQ (The FAQ section gives its location.) for more information.
+
+       Lsof dynamically sizes the output columns each time it runs, guarantee‐
+       ing  that  each column is a minimum size.  It also guarantees that each
+       column is separated from its predecessor by at least one space.
+
+       COMMAND    contains the first nine characters of the name of  the  UNIX
+                  command  associated with the process.  If a non-zero w value
+                  is specified to the +c w option,  the  column  contains  the
+                  first  w  characters of the name of the UNIX command associ‐
+                  ated with the process up to the limit of characters supplied
+                  to lsof by the UNIX dialect.  (See the description of the +c
+                  w command or the lsof FAQ for  more  information.   The  FAQ
+                  section gives its location.)
+
+                  If  w  is  less  than the length of the column title, ``COM‐
+                  MAND'', it will be raised to that length.
+
+                  If a zero w value is specified to the +c w option, the  col‐
+                  umn contains all the characters of the name of the UNIX com‐
+                  mand associated with the process.
+
+                  All command name characters maintained by the kernel in  its
+                  structures  are  displayed  in field output when the command
+                  name descriptor (`c') is  specified.   See  the  OUTPUT  FOR
+                  OTHER  COMMANDS  section  for information on selecting field
+                  output and the associated command name descriptor.
+
+       PID        is the Process IDentification number of the process.
+
+       TID        is the task (thread) IDentification number, if task (thread)
+                  reporting is supported by the dialect and a task (thread) is
+                  being listed.  (If help output - i.e., the output of the  -h
+                  or  -?   options - shows this option, then task (thread) re‐
+                  porting is supported by the dialect.)
+
+                  A blank TID column in Linux indicates a process  -  i.e.,  a
+                  non-task.
+
+       TASKCMD    is  the  task command name.  Generally this will be the same
+                  as the process named in the COMMAND column,  but  some  task
+                  implementations  (e.g.,  Linux)  permit a task to change its
+                  command name.
+
+                  The TASKCMD column width is subject to the same size limita‐
+                  tion as the COMMAND column.
+
+       ZONE       is the Solaris 10 and higher zone name.  This column must be
+                  selected with the -z option.
+
+       SECURITY-CONTEXT
+                  is the SELinux security context.  This column  must  be  se‐
+                  lected  with  the -Z option.  Note that the -Z option is in‐
+                  hibited when SELinux is disabled in the running  Linux  ker‐
+                  nel.
+
+       PPID       is  the Parent Process IDentification number of the process.
+                  It is only displayed when the -R option has been specified.
+
+       PGID       is the process group IDentification number  associated  with
+                  the  process.   It  is only displayed when the -g option has
+                  been specified.
+
+       USER       is the user ID number or login name of the user to whom  the
+                  process  belongs,  usually  the  same  as reported by ps(1).
+                  However, on Linux USER is the user ID number or  login  that
+                  owns  the  directory  in  /proc where lsof finds information
+                  about the process.  Usually that is the same value  reported
+                  by  ps(1),  but  may differ when the process has changed its
+                  effective user ID.  (See the -l option description  for  in‐
+                  formation  on  when  a  user ID number or login name is dis‐
+                  played.)
+
+       FD         is the File Descriptor number of the file or:
+
+                       cwd  current working directory;
+                       Lnn  library references (AIX);
+                       ctty character tty;
+                       DEL  deleted file;
+                       err  FD information error (see NAME column);
+                       fp.  Fileport (Darwin);
+                       jld  jail directory (FreeBSD);
+                       ltx  shared library text (code and data);
+                       Mxx  hex memory-mapped type number xx.
+                       m86  DOS Merge mapped file;
+                       mem  memory-mapped file;
+                       mmap memory-mapped device;
+                       NOFD for a Linux /proc/<PID>/fd directory that can't be opened --
+                            the directory path appears in the NAME column, followed by an error
+                            message;
+                       pd   parent directory;
+                       Rnn  unknown pregion number (HP-UX);
+                       rtd  root directory;
+                       twd  per task current working directory;
+                       txt  program text (code and data);
+                       v86  VP/ix mapped file;
+
+                  FD is followed by one of these  characters,  describing  the
+                  mode under which the file is open:
+
+                       r for read access;
+                       w for write access;
+                       u for read and write access;
+                       space if mode unknown and no lock
+                            character follows;
+                       `-' if mode unknown and lock
+                            character follows.
+
+                  The  mode character is followed by one of these lock charac‐
+                  ters, describing the type of lock applied to the file:
+
+                       N for a Solaris NFS lock of unknown type;
+                       r for read lock on part of the file;
+                       R for a read lock on the entire file;
+                       w for a write lock on part of the file;
+                       W for a write lock on the entire file;
+                       u for a read and write lock of any length;
+                       U for a lock of unknown type;
+                       x for an SCO OpenServer Xenix lock on part of the file;
+                       X for an SCO OpenServer Xenix lock on the entire file;
+                       space if there is no lock.
+
+                  See the LOCKS section for more information on the  lock  in‐
+                  formation character.
+
+                  The  FD column contents constitutes a single field for pars‐
+                  ing in post-processing scripts. FD numbers larger than  9999
+                  are  abbreviated  to a ``*'' followed by the last three dig‐
+                  its. E.g., 10001 appears as ``*001''
+
+       TYPE       is the type of the node associated with  the  file  -  e.g.,
+                  VDIR, VREG, etc.
+
+                  or ``ax25'' for a Linux AX.25 socket;
+
+                  or ``a_inode'' for anonymous inode;
+
+                  or ``icmp'' for an ICMP socket;
+
+                  or ``inet'' for an Internet domain socket;
+
+                  or ``ipx'' for an IPX socket;
+
+                  or ``key'' for an internal key management socket;
+
+                  or ``lla'' for a HP-UX link level access file;
+
+                  or ``ndrv'' for a net driver socket;
+
+                  or ``netlink'' for a netlink socket;
+
+                  or ``pack'' for a packet socket;
+
+                  or ``ppp'' for a PPP socket;
+
+                  or ``raw'' for a raw socket;
+
+                  or ``raw6'' for a raw IPv6 socket;
+
+                  or ``rte'' for an AF_ROUTE socket;
+
+                  or ``sock'' for a socket of unknown domain;
+
+                  or ``systm'' for a system socket;
+
+                  or ``unix'' for a UNIX domain socket;
+
+                  or ``x.25'' for an HP-UX x.25 socket;
+
+                  or ``ATALK'' for an AppleTalk socket;
+
+                  or ``BLK'' for a block special file;
+
+                  or ``CHR'' for a character special file;
+
+                  or ``DEL'' for a Linux map file that has been deleted;
+
+                  or ``DIR'' for a directory;
+
+                  or ``DOOR'' for a VDOOR file;
+
+                  or ``EVENTFD'' for an eventfd;
+
+                  or ``FIFO'' for a FIFO special file;
+
+                  or ``FSEVENTS'' for fsevents;
+
+                  or ``IPv4'' for an IPv4 socket;
+
+                  or  ``IPv6'' for an open IPv6 network file - even if its ad‐
+                  dress is IPv4, mapped in an IPv6 address;
+
+                  or ``KQUEUE'' for a BSD style kernel event queue file;
+
+                  or ``LINK'' for a symbolic link file;
+
+                  or ``MPB'' for a multiplexed block file;
+
+                  or ``MPC'' for a multiplexed character file;
+
+                  or ``PAS'' for a /proc/as file;
+
+                  or ``PAXV'' for a /proc/auxv file;
+
+                  or ``PCRE'' for a /proc/cred file;
+
+                  or ``PCTL'' for a /proc control file;
+
+                  or ``PCUR'' for the current /proc process;
+
+                  or ``PCWD'' for a /proc current working directory;
+
+                  or ``PDIR'' for a /proc directory;
+
+                  or ``PETY'' for a /proc executable type (etype);
+
+                  or ``PFD'' for a /proc file descriptor;
+
+                  or ``PFDR'' for a /proc file descriptor directory;
+
+                  or ``PFIL'' for an executable /proc file;
+
+                  or ``PFPR'' for a /proc FP register set;
+
+                  or ``PGD'' for a /proc/pagedata file;
+
+                  or ``PGID'' for a /proc group notifier file;
+
+                  or ``PIPE'' for pipes;
+
+                  or ``PLC'' for a /proc/lwpctl file;
+
+                  or ``PLDR'' for a /proc/lpw directory;
+
+                  or ``PLDT'' for a /proc/ldt file;
+
+                  or ``PLPI'' for a /proc/lpsinfo file;
+
+                  or ``PLST'' for a /proc/lstatus file;
+
+                  or ``PLU'' for a /proc/lusage file;
+
+                  or ``PLWG'' for a /proc/gwindows file;
+
+                  or ``PLWI'' for a /proc/lwpsinfo file;
+
+                  or ``PLWS'' for a /proc/lwpstatus file;
+
+                  or ``PLWU'' for a /proc/lwpusage file;
+
+                  or ``PLWX'' for a /proc/xregs file;
+
+                  or ``PMAP'' for a /proc map file (map);
+
+                  or ``PMPS'' for a /proc/maps file;
+
+                  or ``PMEM'' for a /proc memory image file;
+
+                  or ``PNTF'' for a /proc process notifier file;
+
+                  or ``POBJ'' for a /proc/object file;
+
+                  or ``PODR'' for a /proc/object directory;
+
+                  or ``POLP'' for an old format  /proc  light  weight  process
+                  file;
+
+                  or ``POPF'' for an old format /proc PID file;
+
+                  or ``POPG'' for an old format /proc page data file;
+
+                  or ``PORT'' for a SYSV named pipe;
+
+                  or ``PREG'' for a /proc register file;
+
+                  or ``PRMP'' for a /proc/rmap file;
+
+                  or ``PROCDSC'' for a processor descriptor;
+
+                  or ``PRTD'' for a /proc root directory;
+
+                  or ``PSGA'' for a /proc/sigact file;
+
+                  or ``PSIN'' for a /proc/psinfo file;
+
+                  or ``PSTA'' for a /proc status file;
+
+                  or ``PSXMQ'' for a POSIX message queue file;
+
+                  or ``PSXSEM'' for a POSIX semaphore file;
+
+                  or ``PSXSHM'' for a POSIX shared memory file;
+
+                  or ``PTS'' for a /dev/pts file;
+
+                  or ``PUSG'' for a /proc/usage file;
+
+                  or ``PW'' for a /proc/watch file;
+
+                  or ``PXMP'' for a /proc/xmap file;
+
+                  or ``REG'' for a regular file;
+
+                  or ``SHM'' for a shared memory file;
+
+                  or ``SMT'' for a shared memory transport file;
+
+                  or ``STR'' for streams;
+
+                  or ``STSO'' for a stream socket;
+
+                  or ``UNKN'' for an unknown file;
+
+                  or ``UNKNcwd'' for unknown current working directory;
+
+                  or ``UNKNdel'' for unknown deleted file;
+
+                  or ``UNKNfd'' for unknown file descriptor;
+
+                  or ``UNKNmem'' for unknown memory-mapped file;
+
+                  or ``UNKNrtd'' for unknown root directory;
+
+                  or ``UNKNtxt'' for unknown program text;
+
+                  or ``UNNM'' for an unnamed type file;
+
+                  or  ``XNAM'' for an OpenServer Xenix special file of unknown
+                  type;
+
+                  or ``XSEM'' for an OpenServer Xenix semaphore file;
+
+                  or ``XSD'' for an OpenServer Xenix shared data file;
+
+                  or ``UNSP'' for an unsupported file;
+
+                  or the four type number octets  if  the  corresponding  name
+                  isn't known.
+
+       FILE-ADDR  contains  the  kernel file structure address when f has been
+                  specified to +f;
+
+       FCT        contains the file  reference  count  from  the  kernel  file
+                  structure when c has been specified to +f;
+
+       FILE-FLAG  when  g  or  G has been specified to +f, this field contains
+                  the contents of the f_flag[s]  member  of  the  kernel  file
+                  structure  and  the kernel's per-process open file flags (if
+                  available); `G' causes them to be displayed in  hexadecimal;
+                  `g',  as  short-hand  names; two lists may be displayed with
+                  entries separated by commas, the lists separated by a  semi‐
+                  colon (`;'); the first list may contain short-hand names for
+                  f_flag[s] values from the following table:
+
+                       AIO       asynchronous I/O (e.g., FAIO)
+                       AP        append
+                       ASYN      asynchronous I/O (e.g., FASYNC)
+                       BAS       block, test, and set in use
+                       BKIU      block if in use
+                       BL        use block offsets
+                       BSK       block seek
+                       CA        copy avoid
+                       CIO       concurrent I/O
+                       CLON      clone
+                       CLRD      CL read
+                       CR        create
+                       DF        defer
+                       DFI       defer IND
+                       DFLU      data flush
+                       DIR       direct
+                       DLY       delay
+                       DOCL      do clone
+                       DSYN      data-only integrity
+                       DTY       must be a directory
+                       EVO       event only
+                       EX        open for exec
+                       EXCL      exclusive open
+                       FSYN      synchronous writes
+                       GCDF      defer during unp_gc() (AIX)
+                       GCMK      mark during unp_gc() (AIX)
+                       GTTY      accessed via /dev/tty
+                       HUP       HUP in progress
+                       KERN      kernel
+                       KIOC      kernel-issued ioctl
+                       LCK       has lock
+                       LG        large file
+                       MBLK      stream message block
+                       MK        mark
+                       MNT       mount
+                       MSYN      multiplex synchronization
+                       NATM      don't update atime
+                       NB        non-blocking I/O
+                       NBDR      no BDRM check
+                       NBIO      SYSV non-blocking I/O
+                       NBF       n-buffering in effect
+                       NC        no cache
+                       ND        no delay
+                       NDSY      no data synchronization
+                       NET       network
+                       NFLK      don't follow links
+                       NMFS      NM file system
+                       NOTO      disable background stop
+                       NSH       no share
+                       NTTY      no controlling TTY
+                       OLRM      OLR mirror
+                       PAIO      POSIX asynchronous I/O
+                       PATH      path
+                       PP        POSIX pipe
+                       R         read
+                       RC        file and record locking cache
+                       REV       revoked
+                       RSH       shared read
+                       RSYN      read synchronization
+                       RW        read and write access
+                       SL        shared lock
+                       SNAP      cooked snapshot
+                       SOCK      socket
+                       SQSH      Sequent shared set on open
+                       SQSV      Sequent SVM set on open
+                       SQR       Sequent set repair on open
+                       SQS1      Sequent full shared open
+                       SQS2      Sequent partial shared open
+                       STPI      stop I/O
+                       SWR       synchronous read
+                       SYN       file integrity while writing
+                       TCPM      avoid TCP collision
+                       TMPF      temporary file
+                       TR        truncate
+                       W         write
+                       WKUP      parallel I/O synchronization
+                       WTG       parallel I/O synchronization
+                       VH        vhangup pending
+                       VTXT      virtual text
+                       XL        exclusive lock
+
+                  this list of names was derived from F* #define's in  dialect
+                  header   files   <fcntl.h>,   <linux</fs.h>,  <sys/fcntl.c>,
+                  <sys/fcntlcom.h>, and <sys/file.h>; see the common.h  header
+                  file for a list showing the correspondence between the above
+                  short-hand names and the header file definitions;
+
+                  the second list (after the semicolon) may contain short-hand
+                  names  for  kernel per-process open file flags from this ta‐
+                  ble:
+
+                       ALLC      allocated
+                       BR        the file has been read
+                       BHUP      activity stopped by SIGHUP
+                       BW        the file has been written
+                       CLSG      closing
+                       CX        close-on-exec (see fcntl(F_SETFD))
+                       LCK       lock was applied
+                       MP        memory-mapped
+                       OPIP      open pending - in progress
+                       RSVW      reserved wait
+                       SHMT      UF_FSHMAT set (AIX)
+                       USE       in use (multi-threaded)
+
+       NODE-ID    (or INODE-ADDR for some dialects) contains a unique  identi‐
+                  fier  for  the  file node (usually the kernel vnode or inode
+                  address, but also occasionally a concatenation of device and
+                  node number) when n has been specified to +f;
+
+       DEVICE     contains  the  device  numbers,  separated  by commas, for a
+                  character special, block special, regular, directory or  NFS
+                  file;
+
+                  or  ``memory''  for  a  memory  file system node under Tru64
+                  UNIX;
+
+                  or the address of the private data area of a Solaris  socket
+                  stream;
+
+                  or  a kernel reference address that identifies the file (The
+                  kernel reference address may be used for FIFO's,  for  exam‐
+                  ple.);
+
+                  or  the  base address or device name of a Linux AX.25 socket
+                  device.
+
+                  Usually only the lower thirty two bits of Tru64 UNIX  kernel
+                  addresses are displayed.
+
+       SIZE, SIZE/OFF, or OFFSET
+                  is  the  size  of  the  file or the file offset in bytes.  A
+                  value is displayed in this column only if it  is  available.
+                  Lsof displays whatever value - size or offset - is appropri‐
+                  ate for the type of the file and the version of lsof.
+
+                  On some UNIX dialects lsof can't obtain accurate or  consis‐
+                  tent  file  offset information from its kernel data sources,
+                  sometimes just for particular kinds of files  (e.g.,  socket
+                  files.)  In other cases, files don't have true sizes - e.g.,
+                  sockets, FIFOs, pipes - so lsof displays for their sizes the
+                  content  amounts it finds in their kernel buffer descriptors
+                  (e.g., socket buffer size counts or  TCP/IP  window  sizes.)
+                  Consult  the  lsof FAQ (The FAQ section gives its location.)
+                  for more information.
+
+                  The file size is displayed in decimal; the  offset  is  nor‐
+                  mally  displayed in decimal with a leading ``0t'' if it con‐
+                  tains 8 digits or less; in hexadecimal with a leading ``0x''
+                  if it is longer than 8 digits.  (Consult the -o o option de‐
+                  scription for information on when 8 might  default  to  some
+                  other value.)
+
+                  Thus  the  leading ``0t'' and ``0x'' identify an offset when
+                  the column may contain both a size and an offset (i.e.,  its
+                  title is SIZE/OFF).
+
+                  If the -o option is specified, lsof always displays the file
+                  offset (or nothing if no offset is available) and labels the
+                  column  OFFSET.   The  offset  always  begins with ``0t'' or
+                  ``0x'' as described above.
+
+                  The lsof user can control the switch from ``0t''  to  ``0x''
+                  with  the -o o option.  Consult its description for more in‐
+                  formation.
+
+                  If the -s option is specified, lsof always displays the file
+                  size  (or  nothing  if  no size is available) and labels the
+                  column SIZE.  The -o and -s options are mutually  exclusive;
+                  they can't both be specified.
+
+                  If  the  -H  option is specified, lsof displays file size in
+                  human readable form.
+
+                  For files that don't have a fixed size - e.g., don't  reside
+                  on a disk device - lsof will display appropriate information
+                  about the current size or position of  the  file  if  it  is
+                  available in the kernel structures that define the file.
+
+       NLINK      contains the file link count when +L has been specified;
+
+       NODE       is the node number of a local file;
+
+                  or the inode number of an NFS file in the server host;
+
+                  or the Internet protocol type - e.g, ``TCP'';
+
+                  or ``STR'' for a stream;
+
+                  or ``CCITT'' for an HP-UX x.25 socket;
+
+                  or the IRQ or inode number of a Linux AX.25 socket device.
+
+       NAME       is  the name of the mount point and file system on which the
+                  file resides;
+
+                  or the name of a file specified in the names  option  (after
+                  any symbolic links have been resolved);
+
+                  or the name of a character special or block special device;
+
+                  or  the  local  and  remote  Internet addresses of a network
+                  file; the local host name or IP  number  is  followed  by  a
+                  colon  (':'),  the port, ``->'', and the two-part remote ad‐
+                  dress; IP addresses may be reported as numbers or names, de‐
+                  pending  on  the  +|-M,  -n, and -P options; colon-separated
+                  IPv6 numbers are  enclosed  in  square  brackets;  IPv4  IN‐
+                  ADDR_ANY  and  IPv6  IN6_IS_ADDR_UNSPECIFIED  addresses, and
+                  zero port numbers are represented by an  asterisk  ('*');  a
+                  UDP  destination  address  may  be followed by the amount of
+                  time elapsed since the last packet was sent to the  destina‐
+                  tion;  TCP, UDP and UDPLITE remote addresses may be followed
+                  by TCP/TPI information in parentheses - state (e.g.,  ``(ES‐
+                  TABLISHED)'',  ``(Unbound)''), queue sizes, and window sizes
+                  (not all dialects) - in a fashion similar to what netstat(1)
+                  reports; see the -T option description or the description of
+                  the TCP/TPI field in OUTPUT FOR OTHER PROGRAMS for more  in‐
+                  formation on state, queue size, and window size;
+
+                  or the address or name of a UNIX domain socket, possibly in‐
+                  cluding a stream clone device name, a file  system  object's
+                  path  name,  local and foreign kernel addresses, socket pair
+                  information, and a bound vnode address;
+
+                  or the local and remote mount point names of an NFS file;
+
+                  or ``STR'', followed by the stream name;
+
+                  or a stream character device name, followed  by  ``->''  and
+                  the  stream name or a list of stream module names, separated
+                  by ``->'';
+
+                  or ``STR:'' followed by the SCO OpenServer stream device and
+                  module names, separated by ``->'';
+
+                  or  system  directory name, `` -- '', and as many components
+                  of the path name as lsof can find in the kernel's name cache
+                  for selected dialects (See the KERNEL NAME CACHE section for
+                  more information.);
+
+                  or ``PIPE->'', followed by a Solaris kernel pipe destination
+                  address;
+
+                  or  ``COMMON:'',  followed  by  the vnode device information
+                  structure's device name, for a Solaris common vnode;
+
+                  or the address family, followed by a slash  (`/'),  followed
+                  by  fourteen  comma-separated  bytes  of  a non-Internet raw
+                  socket address;
+
+                  or the HP-UX x.25 local address,  followed  by  the  virtual
+                  connection  number  (if any), followed by the remote address
+                  (if any);
+
+                  or ``(dead)'' for disassociated Tru64 UNIX files - typically
+                  terminal  files  that  have  been flagged with the TIOCNOTTY
+                  ioctl and closed by daemons;
+
+                  or ``rd=<offset>'' and ``wr=<offset>'' for the values of the
+                  read and write offsets of a FIFO;
+
+                  or  ``clone n:/dev/event'' for SCO OpenServer file clones of
+                  the /dev/event device, where n is the minor device number of
+                  the file;
+
+                  or  ``(socketpair:  n)'' for a Solaris 2.6, 8, 9  or 10 UNIX
+                  domain socket, created by the socketpair(3N)  network  func‐
+                  tion;
+
+                  or  ``no  PCB'' for socket files that do not have a protocol
+                  block associated  with  them,  optionally  followed  by  ``,
+                  CANTSENDMORE''  if  sending on the socket has been disabled,
+                  or ``, CANTRCVMORE'' if receiving on  the  socket  has  been
+                  disabled (e.g., by the shutdown(2) function);
+
+                  or the local and remote addresses of a Linux IPX socket file
+                  in the form <net>:[<node>:]<port>, followed  in  parentheses
+                  by  the transmit and receive queue sizes, and the connection
+                  state;
+
+                  or ``dgram'' or ``stream'' for the type UnixWare  7.1.1  and
+                  above  in-kernel  UNIX  domain  sockets, followed by a colon
+                  (':') and the local path name when  available,  followed  by
+                  ``->''  and the remote path name or kernel socket address in
+                  hexadecimal when available;
+
+                  or the association value, association index, endpoint value,
+                  local  address,  local  port, remote address and remote port
+                  for Linux SCTP sockets;
+
+                  or ``protocol: '' followed by the  Linux  socket's  protocol
+                  attribute.
+
+       For  dialects  that support a ``namefs'' file system, allowing one file
+       to be attached to another with fattach(3C), lsof  will  add  ``(FA:<ad‐
+       dress1><direction><address2>)''  to  the  NAME  column.  <address1> and
+       <address2> are hexadecimal vnode addresses.  <direction> will be ``<-''
+       if  <address2>  has been fattach'ed to this vnode whose address is <ad‐
+       dress1>; and ``->'' if <address1>, the vnode address of this vnode, has
+       been fattach'ed to <address2>.  <address1> may be omitted if it already
+       appears in the DEVICE column.
+
+       Lsof may add two parenthetical notes to the NAME column  for  open  So‐
+       laris 10 files: ``(?)'' if lsof considers the path name of questionable
+       accuracy; and ``(deleted)'' if the -X option  has  been  specified  and
+       lsof  detects  the open file's path name has been deleted.  Consult the
+       lsof FAQ (The FAQ section gives its location.)  for more information on
+       these NAME column additions.
+
+LOCKS
+       Lsof  can't  adequately  report  the  wide variety of UNIX dialect file
+       locks in a single character.  What it reports in a single character  is
+       a  compromise  between  the  information it finds in the kernel and the
+       limitations of the reporting format.
+
+       Moreover, when a process holds several byte level locks on a file, lsof
+       only  reports  the  status of the first lock it encounters.  If it is a
+       byte level lock, then the lock character will be reported in lower case
+       -  i.e.,  `r',  `w', or `x' - rather than the upper case equivalent re‐
+       ported for a full file lock.
+
+       Generally lsof can only report on locks held by local processes on  lo‐
+       cal  files.   When  a  local  process sets a lock on a remotely mounted
+       (e.g., NFS) file, the remote  server  host  usually  records  the  lock
+       state.   One exception is Solaris - at some patch levels of 2.3, and in
+       all versions above 2.4, the Solaris kernel records information  on  re‐
+       mote locks in local structures.
+
+       Lsof  has  trouble reporting locks for some UNIX dialects.  Consult the
+       BUGS section of this manual page or the lsof FAQ (The FAQ section gives
+       its location.)  for more information.
+
+OUTPUT FOR OTHER PROGRAMS
+       When  the -F option is specified, lsof produces output that is suitable
+       for processing by another program - e.g, an awk or Perl script, or a  C
+       program.
+
+       Each unit of information is output in a field that is identified with a
+       leading character and terminated by a NL (012) (or a NUL (000) if the 0
+       (zero) field identifier character is specified.)  The data of the field
+       follows immediately after the field identification  character  and  ex‐
+       tends to the field terminator.
+
+       It  is  possible  to think of field output as process and file sets.  A
+       process set begins with a field whose identifier is  `p'  (for  process
+       IDentifier  (PID)).   It extends to the beginning of the next PID field
+       or the beginning of the first file set of the process, whichever  comes
+       first.   Included  in the process set are fields that identify the com‐
+       mand, the process group IDentification (PGID) number, the task (thread)
+       ID (TID), and the user ID (UID) number or login name.
+
+       A  file  set  begins with a field whose identifier is `f' (for file de‐
+       scriptor).  It is followed by lines that  describe  the  file's  access
+       mode, lock state, type, device, size, offset, inode, protocol, name and
+       stream module names.  It extends to the beginning of the next  file  or
+       process set, whichever comes first.
+
+       When the NUL (000) field terminator has been selected with the 0 (zero)
+       field identifier character, lsof ends each process and file set with  a
+       NL (012) character.
+
+       Lsof  always  produces one field, the PID (`p') field.  In repeat mode,
+       the marker (`m') is also produced.  All other fields  may  be  declared
+       optionally  in  the field identifier character list that follows the -F
+       option.  When a field selection character identifies an item lsof  does
+       not normally list - e.g., PPID, selected with -R - specification of the
+       field character - e.g., ``-FR'' - also selects the listing of the item.
+
+       Lsof version from 4.88 to 4.93.2 always produced one  more  field,  the
+       file descriptor (`f') field. However, lsof in this version doesn't pro‐
+       duce it. This change is for supporting the use case that a  user  needs
+       only the PID field, and doesn't need the file descriptor field. Specify
+       `f' explicitly if you need the field.
+
+       It is entirely possible to select a set of fields that cannot easily be
+       parsed - e.g., if the field descriptor field is not selected, it may be
+       difficult to identify file sets.  To help you  avoid  this  difficulty,
+       lsof  supports  the -F option; it selects the output of all fields with
+       NL terminators (the -F0 option pair selects the output  of  all  fields
+       with  NUL  terminators).   For compatibility reasons neither -F nor -F0
+       select the raw device field.
+
+       These are the fields that lsof  will  produce.   The  single  character
+       listed first is the field identifier.
+
+            a    file access mode
+            c    process command name (all characters from proc or
+                 user structure)
+            C    file structure share count
+            d    file's device character code
+            D    file's major/minor device number (0x<hexadecimal>)
+            f    file descriptor
+            F    file structure address (0x<hexadecimal>)
+            G    file flaGs (0x<hexadecimal>; names if +fg follows)
+            g    process group ID
+            i    file's inode number
+            K    tasK ID
+            k    link count
+            l    file's lock status
+            L    process login name
+            m    marker between repeated output (always selected in repeat mode)
+            M    the task comMand name
+            n    file name, comment, Internet address
+            N    node identifier (ox<hexadecimal>
+            o    file's offset (0t<decimal> or 0x<hexadecimal>, see -o o)
+            p    process ID (always selected)
+            P    protocol name
+            r    raw device number (0x<hexadecimal>)
+            R    parent process ID
+            s    file's size (decimal)
+            S    file's stream identification
+            t    file's type
+            T    TCP/TPI information, identified by prefixes (the
+                 `=' is part of the prefix):
+                     QR=<read queue size>
+                     QS=<send queue size>
+                     SO=<socket options and values> (not all dialects)
+                     SS=<socket states> (not all dialects)
+                     ST=<connection state>
+                     TF=<TCP flags and values> (not all dialects)
+                     WR=<window read size>  (not all dialects)
+                     WW=<window write size>  (not all dialects)
+                 (TCP/TPI information isn't reported for all supported
+                   UNIX dialects. The -h or -? help output for the
+                   -T option will show what TCP/TPI reporting can be
+                   requested.)
+            u    process user ID
+            z    Solaris 10 and higher zone name
+            Z    SELinux security context (inhibited when SELinux is disabled)
+            0    use NUL field terminator character in place of NL
+            1-9  dialect-specific field identifiers (The output
+                 of -F? identifies the information to be found
+                 in dialect-specific fields.)
+
+       You  can get on-line help information on these characters and their de‐
+       scriptions by specifying the -F?  option pair.  (Escape the `?' charac‐
+       ter  as  your shell requires.)  Additional information on field content
+       can be found in the OUTPUT section.
+
+       As an example, ``-F pcfn'' will select the process  ID  (`p'),  command
+       name (`c'), file descriptor (`f') and file name (`n') fields with an NL
+       field terminator character; ``-F pcfn0'' selects the same output with a
+       NUL (000) field terminator character.
+
+       Lsof  doesn't  produce  all  fields for every process or file set, only
+       those that are available.  Some fields are mutually exclusive: file de‐
+       vice  characters and file major/minor device numbers; file inode number
+       and protocol name; file name and stream identification; file  size  and
+       offset.   One or the other member of these mutually exclusive sets will
+       appear in field output, but not both.
+
+       Normally lsof ends each field with a NL (012) character.  The 0  (zero)
+       field  identifier character may be specified to change the field termi‐
+       nator character to a NUL (000).  A NUL  terminator  may  be  easier  to
+       process  with  xargs  (1),  for example, or with programs whose quoting
+       mechanisms may not easily cope with the  range  of  characters  in  the
+       field  output.  When the NUL field terminator is in use, lsof ends each
+       process and file set with a NL (012).
+
+       Three aids to producing programs that can process lsof field output are
+       included  in  the  lsof  distribution.   The  first is a C header file,
+       lsof_fields.h, that contains symbols for the field identification char‐
+       acters,  indexes  for  storing them in a table, and explanation strings
+       that may be compiled into programs.  Lsof uses this header file.
+
+       The second aid is a set of sample scripts that  process  field  output,
+       written  in  awk,  Perl  4, and Perl 5.  They're located in the scripts
+       subdirectory of the lsof distribution.
+
+       The third aid is the C library used for the lsof test suite.  The  test
+       suite is written in C and uses field output to validate the correct op‐
+       eration of lsof.  The library can be found in the tests/LTlib.c file of
+       the   lsof   distribution.    The  library  uses  the  first  aid,  the
+       lsof_fields.h header file.
+
+BLOCKS AND TIMEOUTS
+       Lsof can be blocked by some kernel functions that it uses  -  lstat(2),
+       readlink(2),  and  stat(2).  These functions are stalled in the kernel,
+       for example, when the hosts where mounted NFS file systems  reside  be‐
+       come inaccessible.
+
+       Lsof  attempts  to  break these blocks with timers and child processes,
+       but the techniques are not wholly reliable.  When lsof does  manage  to
+       break  a  block,  it  will report the break with an error message.  The
+       messages may be suppressed with the -t and -w options.
+
+       The default timeout value may be displayed with the -h or  -?   option,
+       and it may be changed with the -S [t] option.  The minimum for t is two
+       seconds, but you should avoid small values, since slow  system  respon‐
+       siveness  can  cause  short timeouts to expire unexpectedly and perhaps
+       stop lsof before it can produce any output.
+
+       When lsof has to break a block during its access of mounted file system
+       information,  it  normally  continues,  although  with less information
+       available to display about open files.
+
+       Lsof can also be directed to avoid the protection of timers  and  child
+       processes  when using the kernel functions that might block by specify‐
+       ing the -O option.  While this will allow lsof to start  up  with  less
+       overhead,  it  exposes  lsof  completely  to the kernel situations that
+       might block it.  Use this option cautiously.
+
+AVOIDING KERNEL BLOCKS
+       You can use the -b option to tell lsof to avoid using kernel  functions
+       that would block.  Some cautions apply.
+
+       First,  using  this option usually requires that your system supply al‐
+       ternate device numbers in place of the device numbers that  lsof  would
+       normally  obtain  with  the lstat(2) and stat(2) kernel functions.  See
+       the ALTERNATE DEVICE NUMBERS section for more information on  alternate
+       device numbers.
+
+       Second,  you can't specify names for lsof to locate unless they're file
+       system names.  This is because lsof needs to know the device and  inode
+       numbers  of files listed with names in the lsof options, and the -b op‐
+       tion prevents lsof from obtaining them.  Moreover, since lsof only  has
+       device  numbers  for the file systems that have alternates, its ability
+       to locate files on file systems depends completely on the  availability
+       and  accuracy of the alternates.  If no alternates are available, or if
+       they're incorrect, lsof won't be able to locate files on the named file
+       systems.
+
+       Third,  if  the names of your file system directories that lsof obtains
+       from your system's mount table are symbolic links, lsof won't  be  able
+       to  resolve  the  links.   This is because the -b option causes lsof to
+       avoid the kernel readlink(2)  function  it  uses  to  resolve  symbolic
+       links.
+
+       Finally, using the -b option causes lsof to issue warning messages when
+       it needs to use the kernel functions that the -b option directs  it  to
+       avoid.   You  can  suppress these messages by specifying the -w option,
+       but if you do, you won't see the alternate device numbers  reported  in
+       the warning messages.
+
+ALTERNATE DEVICE NUMBERS
+       On  some  dialects, when lsof has to break a block because it can't get
+       information about a mounted file system via the  lstat(2)  and  stat(2)
+       kernel  functions, or because you specified the -b option, lsof can ob‐
+       tain some of the information it needs - the device number and  possibly
+       the  file system type - from the system mount table.  When that is pos‐
+       sible, lsof will report the device number it obtained.  (You  can  sup‐
+       press the report by specifying the -w option.)
+
+       You  can  assist  this process if your mount table is supported with an
+       /etc/mtab or /etc/mnttab file that contains an options field by  adding
+       a ``dev=xxxx'' field for mount points that do not have one in their op‐
+       tions strings.  Note: you must be able to edit the file  -  i.e.,  some
+       mount  tables like recent Solaris /etc/mnttab or Linux /proc/mounts are
+       read-only and can't be modified.
+
+       You may also be able to supply device numbers using the +m and +m m op‐
+       tions,  provided  they are supported by your dialect.  Check the output
+       of lsof's -h or -?  options to see if the  +m  and  +m  m  options  are
+       available.
+
+       The  ``xxxx'' portion of the field is the hexadecimal value of the file
+       system's device number.  (Consult the st_dev field of the output of the
+       lstat(2) and stat(2) functions for the appropriate values for your file
+       systems.)  Here's an example from a Sun Solaris 2.6 /etc/mnttab  for  a
+       file system remotely mounted via NFS:
+
+            nfs  ignore,noquota,dev=2a40001
+
+       There's an advantage to having ``dev=xxxx'' entries in your mount table
+       file, especially for file systems that  are  mounted  from  remote  NFS
+       servers.   When  a  remote  server crashes and you want to identify its
+       users by running lsof on one of its clients,  lsof  probably  won't  be
+       able to get output from the lstat(2) and stat(2) functions for the file
+       system.  If it can obtain the file  system's  device  number  from  the
+       mount  table,  it will be able to display the files open on the crashed
+       NFS server.
+
+       Some dialects that do not use an ASCII /etc/mtab  or  /etc/mnttab  file
+       for  the  mount table may still provide an alternative device number in
+       their internal mount tables.  This includes AIX, Apple Darwin, FreeBSD,
+       NetBSD, OpenBSD, and Tru64 UNIX.  Lsof knows how to obtain the alterna‐
+       tive device number for these dialects and uses it when its  attempt  to
+       lstat(2) or stat(2) the file system is blocked.
+
+       If  you're  not sure your dialect supplies alternate device numbers for
+       file systems from its mount table, use this lsof incantation to see  if
+       it reports any alternate device numbers:
+
+              lsof -b
+
+       Look  for  standard  error  file warning messages that begin ``assuming
+       "dev=xxxx" from ...''.
+
+KERNEL NAME CACHE
+       Lsof is able to examine the kernel's name cache or use other kernel fa‐
+       cilities  (e.g., the ADVFS 4.x tag_to_path() function under Tru64 UNIX)
+       on some dialects for most file system types, excluding AFS, and extract
+       recently  used  path  name  components  from it.  (AFS file system path
+       lookups don't use the kernel's name cache; some Solaris VxFS file  sys‐
+       tem operations apparently don't use it, either.)
+
+       Lsof  reports  the complete paths it finds in the NAME column.  If lsof
+       can't report all components in a path, it reports in  the  NAME  column
+       the  file system name, followed by a space, two `-' characters, another
+       space, and the name components it has located,  separated  by  the  `/'
+       character.
+
+       When  lsof is run in repeat mode - i.e., with the -r option specified -
+       the extent to which it can report path name  components  for  the  same
+       file  may  vary from cycle to cycle.  That's because other running pro‐
+       cesses can cause the kernel to remove entries from its name  cache  and
+       replace them with others.
+
+       Lsof's  use of the kernel name cache to identify the paths of files can
+       lead it to report incorrect components under some circumstances.   This
+       can  happen when the kernel name cache uses device and node number as a
+       key (e.g., SCO OpenServer) and a key on a rapidly changing file  system
+       is  reused.   If the UNIX dialect's kernel doesn't purge the name cache
+       entry for a file when it is unlinked, lsof may find a reference to  the
+       wrong  entry in the cache.  The lsof FAQ (The FAQ section gives its lo‐
+       cation.)  has more information on this situation.
+
+       Lsof can report path name components for these dialects:
+
+            FreeBSD
+            HP-UX
+            Linux
+            NetBSD
+            SCO OpenServer
+            SCO|Caldera UnixWare
+            Solaris
+            Tru64 UNIX
+
+       Lsof can't report path name components for these dialects:
+
+            AIX
+            OpenBSD
+
+       If you want to know why lsof can't report path name components for some
+       dialects, see the lsof FAQ (The FAQ section gives its location.)
+
+DEVICE CACHE FILE
+       Examining  all members of the /dev (or /devices) node tree with stat(2)
+       functions can be time consuming.  What's  more,  the  information  that
+       lsof needs - device number, inode number, and path - rarely changes.
+
+       Consequently, lsof normally maintains an ASCII text file of cached /dev
+       (or /devices) information (exception: the /proc-based Linux lsof  where
+       it's  not  needed.)  The local system administrator who builds lsof can
+       control the way the device cache file path is  formed,  selecting  from
+       these options:
+
+            Path from the -D option;
+            Path from an environment variable;
+            System-wide path;
+            Personal path (the default);
+            Personal path, modified by an environment variable.
+
+       Consult the output of the -h, -D? , or -?  help options for the current
+       state of device cache support.   The  help  output  lists  the  default
+       read-mode  device cache file path that is in effect for the current in‐
+       vocation of lsof.  The -D?  option output lists the read-only and write
+       device  cache file paths, the names of any applicable environment vari‐
+       ables, and the personal device cache path format.
+
+       Lsof can detect that the current device cache file  has  been  acciden‐
+       tally or maliciously modified by integrity checks, including the compu‐
+       tation and verification of a sixteen bit Cyclic Redundancy Check  (CRC)
+       sum  on the file's contents.  When lsof senses something wrong with the
+       file, it issues a warning and attempts to remove the current cache file
+       and  create a new copy, but only to a path that the process can legiti‐
+       mately write.
+
+       The path from which a lsof process may attempt to read a  device  cache
+       file  may  not  be  the  same  as the path to which it can legitimately
+       write.  Thus when lsof senses that it needs to update the device  cache
+       file,  it may choose a different path for writing it from the path from
+       which it read an incorrect or outdated version.
+
+       If available, the -Dr option will inhibit the writing of a  new  device
+       cache  file.  (It's always available when specified without a path name
+       argument.)
+
+       When a new device is added to the system, the  device  cache  file  may
+       need  to  be  recreated.   Since  lsof compares the mtime of the device
+       cache file with the mtime and ctime of the /dev  (or  /devices)  direc‐
+       tory, it usually detects that a new device has been added; in that case
+       lsof issues a warning message and attempts to rebuild the device  cache
+       file.
+
+       Whenever  lsof writes a device cache file, it sets its ownership to the
+       real UID of the executing process, and its permission  modes  to  0600,
+       this restricting its reading and writing to the file's owner.
+
+LSOF PERMISSIONS THAT AFFECT DEVICE CACHE FILE ACCESS
+       Two permissions of the lsof executable affect its ability to access de‐
+       vice cache files.  The permissions are set by the local system adminis‐
+       trator when lsof is installed.
+
+       The  first  and  rarer permission is setuid-root.  It comes into effect
+       when lsof is executed; its effective UID is then root, while  its  real
+       (i.e.,  that  of the logged-on user) UID is not.  The lsof distribution
+       recommends that versions for these dialects run setuid-root.
+
+            HP-UX 11.11 and 11.23
+            Linux
+
+       The second and more common permission is setgid.  It comes into  effect
+       when  the  effective  group  IDentification  number  (GID)  of the lsof
+       process is set to one that can access kernel  memory  devices  -  e.g.,
+       ``kmem'', ``sys'', or ``system''.
+
+       An  lsof process that has setgid permission usually surrenders the per‐
+       mission after it has accessed the kernel memory devices.  When it  does
+       that,  lsof  can  allow more liberal device cache path formations.  The
+       lsof distribution recommends that versions for these dialects run  set‐
+       gid and be allowed to surrender setgid permission.
+
+            AIX 5.[12] and 5.3-ML1
+            Apple Darwin 7.x Power Macintosh systems
+            FreeBSD 4.x, 4.1x, 5.x and [6789].x for x86-based systems
+            FreeBSD 5.x, [6789].x and 1[012].8for Alpha, AMD64 and Sparc64
+                based systems
+            HP-UX 11.00
+            NetBSD 1.[456], 2.x and 3.x for Alpha, x86, and SPARC-based
+                systems
+            OpenBSD 2.[89] and 3.[0-9] for x86-based systems
+            SCO OpenServer Release 5.0.6 for x86-based systems
+            SCO|Caldera UnixWare 7.1.4 for x86-based systems
+            Solaris 2.6, 8, 9 and 10
+            Tru64 UNIX 5.1
+
+       (Note: lsof for AIX 5L and above needs setuid-root permission if its -X
+       option is used.)
+
+       Lsof for these dialects does not support a device cache, so the permis‐
+       sions given to the executable don't apply to the device cache file.
+
+            Linux
+
+DEVICE CACHE FILE PATH FROM THE -D OPTION
+       The  -D  option  provides limited means for specifying the device cache
+       file path.  Its ?  function will report the read-only and write  device
+       cache file paths that lsof will use.
+
+       When  the  -D  b, r, and u functions are available, you can use them to
+       request that the cache file be built in a specific location  (b[path]);
+       read  but not rebuilt (r[path]); or read and rebuilt (u[path]).  The b,
+       r, and u functions are restricted under some conditions.  They are  re‐
+       stricted when the lsof process is setuid-root.  The path specified with
+       the r function is always read-only, even when it is available.
+
+       The b, r, and u functions are also restricted  when  the  lsof  process
+       runs setgid and lsof doesn't surrender the setgid permission.  (See the
+       LSOF PERMISSIONS THAT AFFECT DEVICE CACHE FILE  ACCESS  section  for  a
+       list of implementations that normally don't surrender their setgid per‐
+       mission.)
+
+       A further -D function, i (for ignore), is always available.
+
+       When available, the b function tells lsof to  read  device  information
+       from the kernel with the stat(2) function and build a device cache file
+       at the indicated path.
+
+       When available, the r function tells lsof  to  read  the  device  cache
+       file,  but  not  update  it.   When a path argument accompanies -Dr, it
+       names the device cache file path.  The r function is  always  available
+       when it is specified without a path name argument.  If lsof is not run‐
+       ning setuid-root and surrenders its setgid permission, a path name  ar‐
+       gument may accompany the r function.
+
+       When  available,  the  u function tells lsof to attempt to read and use
+       the device cache file.  If it can't read the file, or if it  finds  the
+       contents  of  the  file incorrect or outdated, it will read information
+       from the kernel, and attempt to write an updated version of the  device
+       cache  file,  but  only  to a path it considers legitimate for the lsof
+       process effective and real UIDs.
+
+DEVICE CACHE PATH FROM AN ENVIRONMENT VARIABLE
+       Lsof's second choice for the device cache file is the contents  of  the
+       LSOFDEVCACHE  environment  variable.  It avoids this choice if the lsof
+       process is setuid-root, or the real UID of the process is root.
+
+       A further restriction applies to a device cache file  path  taken  from
+       the  LSOFDEVCACHE  environment  variable:  lsof will not write a device
+       cache file to the path if the lsof process doesn't surrender its setgid
+       permission.   (See  the  LSOF PERMISSIONS THAT AFFECT DEVICE CACHE FILE
+       ACCESS section for information on implementations that don't  surrender
+       their setgid permission.)
+
+       The  local system administrator can disable the use of the LSOFDEVCACHE
+       environment variable or change its name when  building  lsof.   Consult
+       the output of -D?  for the environment variable's name.
+
+SYSTEM-WIDE DEVICE CACHE PATH
+       The  local system administrator may choose to have a system-wide device
+       cache file when building lsof.  That file will generally be constructed
+       by  a special system administration procedure when the system is booted
+       or when the contents of /dev or /devices) changes.  If defined,  it  is
+       lsof's third device cache file path choice.
+
+       You can tell that a system-wide device cache file is in effect for your
+       local installation by examining the lsof help option output - i.e., the
+       output from the -h or -?  option.
+
+       Lsof  will never write to the system-wide device cache file path by de‐
+       fault.  It must be explicitly named with a -D function in a  root-owned
+       procedure.   Once  the file has been written, the procedure must change
+       its permission modes to 0644 (owner-read and  owner-write,  group-read,
+       and other-read).
+
+PERSONAL DEVICE CACHE PATH (DEFAULT)
+       The  default  device  cache  file  path of the lsof distribution is one
+       recorded in the home directory of the  real  UID  that  executes  lsof.
+       Added  to  the  home  directory  is a second path component of the form
+       .lsof_hostname.
+
+       This is lsof's fourth device cache file path choice, and is usually the
+       default.  If a system-wide device cache file path was defined when lsof
+       was built, this fourth choice will be applied when lsof can't find  the
+       system-wide  device  cache  file.   This is the only time lsof uses two
+       paths when reading the device cache file.
+
+       The hostname part of the second component is the base name of the  exe‐
+       cuting  host,  as returned by gethostname(2).  The base name is defined
+       to be the characters preceding the first  `.'   in  the  gethostname(2)
+       output, or all the gethostname(2) output if it contains no `.'.
+
+       The  device  cache  file  belongs  to  the  user ID and is readable and
+       writable by the user ID alone - i.e., its modes are  0600.   Each  dis‐
+       tinct  real  user  ID on a given host that executes lsof has a distinct
+       device cache file.  The hostname part of the path distinguishes  device
+       cache  files  in  an NFS-mounted home directory into which device cache
+       files are written from several different hosts.
+
+       The personal device cache file path formed by this method represents  a
+       device  cache  file that lsof will attempt to read, and will attempt to
+       write should it not exist or should its contents be incorrect  or  out‐
+       dated.
+
+       The -Dr option without a path name argument will inhibit the writing of
+       a new device cache file.
+
+       The -D?  option will list the format specification for constructing the
+       personal  device cache file.  The conversions used in the format speci‐
+       fication are described in the 00DCACHE file of the lsof distribution.
+
+MODIFIED PERSONAL DEVICE CACHE PATH
+       If this option is defined by the local system administrator  when  lsof
+       is  built, the LSOFPERSDCPATH environment variable contents may be used
+       to add a component of the personal device cache file path.
+
+       The LSOFPERSDCPATH variable contents are inserted in the  path  at  the
+       place  marked by the local system administrator with the ``%p'' conver‐
+       sion in the HASPERSDC format specification of the  dialect's  machine.h
+       header  file.   (It's  placed right after the home directory in the de‐
+       fault lsof distribution.)
+
+       Thus, for example, if LSOFPERSDCPATH contains ``LSOF'', the home direc‐
+       tory  is ``/Homes/abe'', the host name is ``lsof.itap.purdue.edu'', and
+       the HASPERSDC format is the default (``%h/%p.lsof_%L''),  the  modified
+       personal device cache file path is:
+
+            /Homes/abe/LSOF/.lsof_vic
+
+       The  LSOFPERSDCPATH  environment  variable  is  ignored  when  the lsof
+       process is setuid-root or when the real UID of the process is root.
+
+       Lsof will not write to a modified personal device cache  file  path  if
+       the  lsof  process  doesn't surrender setgid permission.  (See the LSOF
+       PERMISSIONS THAT AFFECT DEVICE CACHE FILE ACCESS section for a list  of
+       implementations that normally don't surrender their setgid permission.)
+
+       If,  for example, you want to create a sub-directory of personal device
+       cache file paths by using the LSOFPERSDCPATH  environment  variable  to
+       name  it,  and  lsof  doesn't surrender its setgid permission, you will
+       have to allow lsof to create device cache files at  the  standard  per‐
+       sonal path and move them to your subdirectory with shell commands.
+
+       The  local  system  administrator may: disable this option when lsof is
+       built; change the name of the environment variable from  LSOFPERSDCPATH
+       to  something else; change the HASPERSDC format to include the personal
+       path component in another place; or exclude the personal path component
+       entirely.   Consult  the  output of the -D?  option for the environment
+       variable's name and the HASPERSDC format specification.
+
+DIAGNOSTICS
+       Errors are identified with messages on the standard error file.
+
+       Lsof returns a one (1) if any error was detected, including the failure
+       to locate command names, file names, Internet addresses or files, login
+       names, NFS files, PIDs, PGIDs, or UIDs it was asked to list.  If the -V
+       option  is  specified, lsof will indicate the search items it failed to
+       list.  If the -Q option is specified, lsof will ignore any search  item
+       failures  and  only return an error if something unusual and unrecover‐
+       able happened.
+
+       It returns a zero (0) if no errors were detected and if either  the  -Q
+       option  was specified or it was able to list some information about all
+       the specified search arguments.
+
+       When lsof cannot open access to /dev (or /devices) or one of its subdi‐
+       rectories, or get information on a file in them with stat(2), it issues
+       a warning message and continues.  That lsof will issue warning messages
+       about inaccessible files in /dev (or /devices) is indicated in its help
+       output - requested with the -h or >B -?  options -  with the message:
+
+            Inaccessible /dev warnings are enabled.
+
+       The warning message may be suppressed with the -w option.  It may  also
+       have been suppressed by the system administrator when lsof was compiled
+       by the setting of the WARNDEVACCESS definition.  In this case, the out‐
+       put from the help options will include the message:
+
+            Inaccessible /dev warnings are disabled.
+
+       Inaccessible  device  warning messages usually disappear after lsof has
+       created a working device cache file.
+
+EXAMPLES
+       For a more extensive set of examples, documented more  fully,  see  the
+       00QUICKSTART file of the lsof distribution.
+
+       To list all open files, use:
+
+              lsof
+
+       To list all open Internet, x.25 (HP-UX), and UNIX domain files, use:
+
+              lsof -i -U
+
+       To  list all open IPv4 network files in use by the process whose PID is
+       1234, use:
+
+              lsof -i 4 -a -p 1234
+
+       If it's okay for PID 1234 to not exist, or for PID 1234 to not have any
+       open IPv4 network files, add -Q :
+
+              lsof -Q -i 4 -a -p 1234
+
+       Presuming  the  UNIX dialect supports IPv6, to list only open IPv6 net‐
+       work files, use:
+
+              lsof -i 6
+
+       To list all files using any protocol on ports 513, 514, or 515 of  host
+       wonderland.cc.purdue.edu, use:
+
+              lsof -i @wonderland.cc.purdue.edu:513-515
+
+       To  list all files using any protocol on any port of mace.cc.purdue.edu
+       (cc.purdue.edu is the default domain), use:
+
+              lsof -i @mace
+
+       To list all open files for login name ``abe'',  or  user  ID  1234,  or
+       process 456, or process 123, or process 789, use:
+
+              lsof -p 456,123,789 -u 1234,abe
+
+       To list all open files on device /dev/hd4, use:
+
+              lsof /dev/hd4
+
+       To  find the process that has /u/abe/foo open without worrying if there
+       are none, use:
+
+              lsof -Q /u/abe/foo
+
+       To take action only if a process has /u/abe/foo open, use:
+
+              lsof /u/abe/foo  echo "still in use"
+
+       To send a SIGHUP to the processes that have /u/abe/bar open, use:
+
+              kill -HUP `lsof -t /u/abe/bar`
+
+       To find any open file, including an open UNIX domain socket file,  with
+       the name /dev/log, use:
+
+              lsof /dev/log
+
+       To  find  processes  with  open  files  on  the  NFS  file system named
+       /nfs/mount/point whose server is inaccessible, and presuming your mount
+       table supplies the device number for /nfs/mount/point, use:
+
+              lsof -b /nfs/mount/point
+
+       To do the preceding search with warning messages suppressed, use:
+
+              lsof -bw /nfs/mount/point
+
+       To ignore the device cache file, use:
+
+              lsof -Di
+
+       To  obtain PID and command name field output for each process, file de‐
+       scriptor, file device number, and file inode number for  each  file  of
+       each process, use:
+
+              lsof -FpcfDi
+
+       To  list  the files at descriptors 1 and 3 of every process running the
+       lsof command for login ID ``abe'' every 10 seconds, use:
+
+              lsof -c lsof -a -d 1 -d 3 -u abe -r10
+
+       To list the current working directory of processes  running  a  command
+       that is exactly four characters long and has an 'o' or 'O' in character
+       three, use this regular expression form of the -c c option:
+
+              lsof -c /^..o.$/i -a -d cwd
+
+       To find an IP version 4 socket file by its associated numeric  dot-form
+       address, use:
+
+              lsof -i@128.210.15.17
+
+       To  find  an  IP  version 6 socket file (when the UNIX dialect supports
+       IPv6) by its associated numeric colon-form address, use:
+
+              lsof -i@[0:1:2:3:4:5:6:7]
+
+       To find an IP version 6 socket file (when  the  UNIX  dialect  supports
+       IPv6) by an associated numeric colon-form address that has a run of ze‐
+       roes in it - e.g., the loop-back address - use:
+
+              lsof -i@[::1]
+
+       To obtain a repeat mode marker line that  contains  the  current  time,
+       use:
+
+              lsof -rm====%T====
+
+       To add spaces to the previous marker line, use:
+
+              lsof -r "m==== %T ===="
+
+BUGS
+       Since  lsof  reads  kernel  memory  in its search for open files, rapid
+       changes in kernel memory may produce unpredictable results.
+
+       When a file has multiple record locks, the lock status character  (fol‐
+       lowing  the  file  descriptor) is derived from a test of the first lock
+       structure, not from any combination of the individual record locks that
+       might be described by multiple lock structures.
+
+       Lsof can't search for files with restrictive access permissions by name
+       unless it is installed with root set-UID permission.  Otherwise  it  is
+       limited  to  searching for files to which its user or its set-GID group
+       (if any) has access permission.
+
+       The display of the destination address of a raw socket (e.g., for ping)
+       depends on the UNIX operating system.  Some dialects store the destina‐
+       tion address in the raw socket's protocol control block, some do not.
+
+       Lsof can't always represent Solaris device numbers in the same way that
+       ls(1)  does.   For example, the major and minor device numbers that the
+       lstat(2) and stat(2) functions report for the directory on which CD-ROM
+       files  are mounted (typically /cdrom) are not the same as the ones that
+       it reports for the device on which CD-ROM files are mounted  (typically
+       /dev/sr0).  (Lsof reports the directory numbers.)
+
+       The  support for /proc file systems is available only for BSD and Tru64
+       UNIX dialects, Linux, and dialects derived from SYSV R4 -  e.g.,  Free‐
+       BSD, NetBSD, OpenBSD, Solaris, UnixWare.
+
+       Some  /proc  file  items - device number, inode number, and file size -
+       are unavailable in some dialects.  Searching for files in a /proc  file
+       system may require that the full path name be specified.
+
+       No  text (txt) file descriptors are displayed for Linux processes.  All
+       entries for files other than the current working  directory,  the  root
+       directory, and numerical file descriptors are labeled mem descriptors.
+
+       Lsof  can't  search  for  Tru64 UNIX named pipes by name, because their
+       kernel implementation of lstat(2) returns an improper device number for
+       a named pipe.
+
+       Lsof  can't  report  fully or correctly on HP-UX 9.01, 10.20, and 11.00
+       locks because of insufficient access to kernel data or  errors  in  the
+       kernel  data.   See  the lsof FAQ (The FAQ section gives its location.)
+       for details.
+
+       The AIX SMT file type is a fabrication.  It's made up for  file  struc‐
+       tures  whose type (15) isn't defined in the AIX /usr/include/sys/file.h
+       header file.  One way to create  such  file  structures  is  to  run  X
+       clients with the DISPLAY variable set to ``:0.0''.
+
+       The +|-f[cfn] option is not supported under /proc-based Linux lsof, be‐
+       cause it doesn't read kernel structures from kernel memory.
+
+ENVIRONMENT
+       Lsof may access these environment variables.
+
+       LANG              defines a language locale.  See setlocale(3) for  the
+                         names of other variables that can be used in place of
+                         LANG - e.g., LC_ALL, LC_TYPE, etc.
+
+       LSOFDEVCACHE      defines the path to a device cache file.  See the DE‐
+                         VICE  CACHE PATH FROM AN ENVIRONMENT VARIABLE section
+                         for more information.
+
+       LSOFPERSDCPATH    defines the middle component of a  modified  personal
+                         device  cache  file  path.  See the MODIFIED PERSONAL
+                         DEVICE CACHE PATH section for more information.
+
+FAQ
+       Frequently-asked questions and their answers (an FAQ) are available  in
+       the 00FAQ file of the lsof distribution.
+
+       That latest version of the file is found at:
+
+              https://github.com/lsof-org/lsof/blob/master/00FAQ
+
+FILES
+       /dev/kmem         kernel virtual memory device
+
+       /dev/mem          physical memory device
+
+       /dev/swap         system paging device
+
+       .lsof_hostname    lsof's  device  cache  file (The suffix, hostname, is
+                         the first component of the host's  name  returned  by
+                         gethostname(2).)
+
+AUTHORS
+       Lsof  was  written by Victor A.Abell <abe@purdue.edu> of Purdue Univer‐
+       sity.  Since version 4.93.0, the  lsof-org  team  at  GitHub  maintains
+       lsof.   Many  others  have  contributed to lsof.  They're listed in the
+       00CREDITS file of the lsof distribution.
+
+DISTRIBUTION
+       The latest distribution of lsof is available at
+
+              https://github.com/lsof-org/lsof/releases
+
+SEE ALSO
+       Not all the following manual pages may exist in every UNIX  dialect  to
+       which lsof has been ported.
+
+       access(2),  awk(1),  crash(1),  fattach(3C), ff(1), fstat(8), fuser(1),
+       gethostname(2),  isprint(3),  kill(1),  localtime(3),  lstat(2),   mod‐
+       load(8),  mount(8),  netstat(1),  ofiles(8L),  open(2), perl(1), ps(1),
+       readlink(2), setlocale(3), stat(2), strftime(3), time(2), uname(1).
+
+                                Revision-4.99.0                        LSOF(8)
+```
diff --git a/docs/manpage.sh b/docs/manpage.sh
new file mode 100755 (executable)
index 0000000..d106e96
--- /dev/null
@@ -0,0 +1,8 @@
+#!/bin/sh
+echo "# Manpage" > manpage.md
+echo "\`\`\`manpage" >> manpage.md
+# nroff: render manpage
+# col: -b remove backspace, -x use spaces instead of tabs
+# cat: -s remove consecutive blank lines
+nroff -man ../lsof.man | col -bx | cat -s >> manpage.md
+echo "\`\`\`" >> manpage.md
diff --git a/docs/options.md b/docs/options.md
new file mode 100644 (file)
index 0000000..010010f
--- /dev/null
@@ -0,0 +1,207 @@
+# Options
+
+The document describes the lsof options in detail.
+
+## Selection Options
+
+Lsof has a rich set of options for selecting the files to be
+displayed.  These include:
+
+- -a   tells lsof to AND the set of selection options that
+       are specified.  Normally lsof ORs them.
+
+       For example, if you specify the -p<PID> and -u<UID>
+       options, lsof will display all files for the
+       specified PID or for the specified UID.
+
+       By adding -a, you specify that the listed files
+       should be limited to PIDs owned by the specified
+       UIDs -- i.e., they match the PIDs *and* the UIDs.
+
+               $ lsof -p1234 -au 5678
+
+- -c   specifies that lsof should list files belonging
+       to processes having the associated command name.
+
+       Hint: if you want to select files based on more than
+       one command name, use multiple -c<name> specifications.
+
+               $ lsof -clsof -cksh
+
+- -d      tells lsof to select by the associated file descriptor
+       (FD) set.  An FD set is a comma-separated list of
+       numbers and the names lsof normally displays in
+       its FD column:  cwd, Lnn, ltx, <number>, etc.  See
+       the OUTPUT section of the lsof man page for the
+       complete list of possible file descriptors.  Example:
+
+               $ lsof -dcwd,0,1,2
+
+- -g      tells lsof to select by the associated process
+       group ID (PGID) set.  The PGID set is a comma-separated
+       list of PGID numbers.  When -g is specified, it also
+       enables the display of PGID numbers.
+
+       Note: when -g isn't followed by a PGID set, it
+       simply selects the listing of PGID for all processes.
+       Examples:
+
+               $ lsof -g
+               $ lsof -g1234,5678
+
+- -i   tells lsof to display Internet socket files.  If no
+       protocol/address/port specification follows -i,
+       lsof lists all Internet socket files.
+
+       If a specification follows -i, lsof lists only the
+       socket files whose Internet addresses match the
+       specification.
+
+       Hint: multiple addresses may be specified with
+       multiple -i options.  Examples:
+
+               $ lsof -iTCP
+               $ lsof -i@lsof.itap.purdue.edu:sendmail
+
+- -N   selects the listing of files mounted on NFS devices.
+
+- -U   selects the listing of socket files in the Unix
+       domain.
+
+
+## Output Options
+
+Lsof has these options to control its output format:
+
+- -F   produce output that can be parsed by a subsequent
+       program.
+
+- -g   print process group (PGID) IDs.
+
+- -l   list UID numbers instead of login names.
+
+- -n   list network numbers instead of host names.
+
+- -o   always list file offset.
+
+- -P   list port numbers instead of port service names.
+
+- -s   always list file size.
+
+## Precautionary Options
+
+Lsof uses system functions that can block or take a long time,
+depending on the health of the Unix dialect supporting it.  These
+include:
+
+- -b   directs lsof to avoid system functions -- e.g.,
+       lstat(2), readlink(2), stat(2) -- that might block
+       in the kernel.  See the BLOCKS AND TIMEOUTS
+       section of the lsof man page.
+
+       You might want to use this option when you have
+       a mount from an NFS server that is not responding.
+
+- -C   tells lsof to ignore the kernel's name cache.  As
+       a precaution this option will have little effect on
+       lsof performance, but might be useful if the kernel's
+       name cache is scrambled.  (I've never seen that
+       happen.)
+
+- -D   might be used to direct lsof to ignore an existing
+       device cache file and generate a new one from /dev
+       (and /devices).  This might be useful if you have
+       doubts about the integrity of an existing device
+       cache file.
+
+- -l      tells lsof to list UID numbers instead of login
+       names -- this is useful when UID to login name
+       conversion is slow or inoperative.
+
+- -n   tells lsof to avoid converting Internet addresses
+       to host numbers.  This might be useful when your
+       host name lookup (e.g., DNS) is inoperative.
+
+- -O      tells lsof to avoid its strategy of forking to
+       perform potentially blocking kernel operations.
+       While the forking allows lsof to detect that a
+       block has occurred (and possibly break it), the
+       fork operation is a costly one.  Use the -O option
+       with care, lest your lsof be blocked.
+
+- -P      directs lsof to list port numbers instead of trying
+       to convert them to port service names.  This might
+       be useful if port to service name lookups (e.g.,
+       via NIS) are slow or failing.
+
+- -S      can be used to change the lstat/readlink/stat
+       timeout interval that governs how long lsof waits
+       for response from the kernel.  This might be useful
+       when an NFS server is slow or unresponsive.  When
+       lsof times out of a kernel function, it may have
+       less information to display.  Example:
+
+               $ lsof -S2
+
+- -w   tells lsof to avoid issuing warning messages, if
+       they are enabled by default, or enable them if they
+       are disabled by default.  Check the -h (help) output
+       to determine their status.  If it says `-w enable warnings`, then warning messages are disabled by
+       default; `-w disable warnings`, they are enabled
+       by default.
+
+       This may be a useful option, for example, when you
+       specify -b, if warning messages are enabled, because
+       it will suppress the warning messages lsof issues
+       about avoiding functions that might block in the
+       kernel.
+
+## Miscellaneous Lsof Options
+
+There are some lsof options that are hard to classify, including:
+
+- -?, -h       these options select help output.
+
+- -F      selects field output.  Field output is a mode where
+       lsof produces output that can be parsed easily by
+       subsequent programs -- e.g., AWK or Perl scripts.
+       See ``15. Output for Other Programs'' for more
+       information.
+
+- -k   specifies an alternate kernel symbol file -- i.e.,
+       where nlist() will get its information.  Example:
+
+               $ lsof -k/usr/crash/vmunix.1
+
+- -m   specifies an alternate kernel memory file from
+       which lsof will read kernel structures in place
+       of /dev/kmem or kvm_read().  Example:
+
+               $ lsof -m/usr/crash/vmcore.n
+
+- -r   tells lsof to repeat its scan every 15 seconds (the
+       default when no associated value is specified).  A
+       repeat time, different from the default, can follow
+       -r.  Example:
+
+               $ lsof -r30
+
+- -Q   tells lsof not to consider it an error if it was
+       given search terms and any part of the search came
+       up empty. This will silence any reports of missing
+       files to stderr. Additionally, lsof will exit with
+       a non-error code despite any missing files or
+       filesystems with no open files.
+
+- -v   displays information about the building of the
+       lsof executable.
+
+- --      The double minus sign option may be used to
+       signal the end of options.  It's particularly useful
+       when arguments to the last option are optional and
+       you want to supply a file path that could be confused
+       for arguments to the last option.  Example:
+
+               $ lsof -g -- 1
+
+       Where `1' is a file path, not PGID ID 1.
diff --git a/docs/requirements.in b/docs/requirements.in
new file mode 100644 (file)
index 0000000..b854bca
--- /dev/null
@@ -0,0 +1 @@
+mkdocs
\ No newline at end of file
diff --git a/docs/requirements.txt b/docs/requirements.txt
new file mode 100644 (file)
index 0000000..f6f40d5
--- /dev/null
@@ -0,0 +1,40 @@
+#
+# This file is autogenerated by pip-compile with Python 3.9
+# by the following command:
+#
+#    pip-compile docs/requirements.in
+#
+click==8.1.3
+    # via mkdocs
+ghp-import==2.1.0
+    # via mkdocs
+importlib-metadata==6.0.0
+    # via
+    #   markdown
+    #   mkdocs
+jinja2==3.1.2
+    # via mkdocs
+markdown==3.3.7
+    # via mkdocs
+markupsafe==2.1.1
+    # via jinja2
+mergedeep==1.3.4
+    # via mkdocs
+mkdocs==1.4.2
+    # via -r docs/requirements.in
+packaging==23.0
+    # via mkdocs
+python-dateutil==2.8.2
+    # via ghp-import
+pyyaml==6.0
+    # via
+    #   mkdocs
+    #   pyyaml-env-tag
+pyyaml-env-tag==0.1
+    # via mkdocs
+six==1.16.0
+    # via python-dateutil
+watchdog==2.2.1
+    # via mkdocs
+zipp==3.11.0
+    # via importlib-metadata
diff --git a/docs/tutorial.md b/docs/tutorial.md
new file mode 100644 (file)
index 0000000..14b0644
--- /dev/null
@@ -0,0 +1,699 @@
+# Tutorial
+
+## Finding Uses of a Specific Open File
+
+Often you're interested in knowing who is using a specific file.
+You know the path to it and you want lsof to tell you the processes
+that have open references to it.
+
+Simple -- execute lsof and give it the path name of the file of interest --
+e.g.,
+
+```shell
+$ lsof /etc/passwd
+```
+
+Caveat: this only works if lsof has permission to get the status (via stat(2))
+of the file at the named path.  Unless the lsof process has enough authority  --
+e.g., it is being run with a real User ID (UID) of root.
+
+Further caveat: this use of lsof will fail if the stat(2) kernel syscall returns
+different file parameters -- particularly device and inode numbers -- than lsof
+finds in kernel node structures.  This condition is rare and is usually
+documented in the FAQ.
+
+```shell
+$ lsof /etc/security/passwd
+lsof: status error on /etc/security/passwd: Permission denied
+```
+
+## Finding Open Files Filling a File System
+
+Oh! Oh!  /tmp is filling and ls doesn't show that any large files are being
+created.  Can lsof help?
+
+Maybe.  If there's a process that is writing to a file that has been unlinked,
+lsof may be able to discover the process for you.  You ask it to list all open
+files on the file system where /tmp is located.
+
+Sometimes /tmp is a file system by itself.  In that case,
+
+```shell
+$ lsof /tmp
+```
+
+is the appropriate command.  If, however, /tmp is part of another file system,
+typically /, then you may have to ask lsof to list all files open on the
+containing file system and locate the offending file and its process by
+inspection -- e.g.,
+
+```shell
+$ lsof / | more
+# or
+$ lsof / | grep ...
+```
+
+Caveat: there must be a file open to a for the lsof search to succeed.
+Sometimes the kernel may cause a file reference to persist, even where there's
+no file open to a process.  (Can you say kernel bug?  Maybe.)  In any event,
+lsof won't be able to help in this case.
+
+## Finding an Unlinked Open File
+
+A pesky variant of a file that is filling a file system is an unlinked file to
+which some process is still writing.  When a process opens a file and then
+unlinks it, the file's resources remain in use by the process, but the file's
+directory entries are removed.  Hence, even when you know the directory where
+the file once resided, you can't detect it with ls.
+
+This can be an administrative problem when the unlinked file is large, and the
+process that holds it open continues to write to it.  Only when the process
+closes the file will its resources, particularly disk space, be released.
+
+Lsof can help you find unlinked files on local disks.  It has an option, +L,
+that will list the link counts of open files.  That helps because an unlinked
+file on a local disk has a zero link count.  Note: this is NOT true for NFS
+files, accessed from a remote server.
+
+You could use the option to list all files and look for a zero link count in the
+NLINK column -- e.g.,
+
+```shell
+$ lsof +L
+COMMAND   PID USER   FD  TYPE DEVICE SIZE/OFF NLINK  NODE NAME
+...
+less    25366  abe  txt  VREG    6,0    40960     1 76319 /usr/...
+...
+> less    25366  abe    3r VREG    6,0    17360     0 98768 / (/dev/sd0a)
+```
+
+Better yet, you can specify an upper bound to the +L option, and
+lsof will select only files that have a link count less than the
+upper bound.  For example:
+
+```shell
+$ lsof +L1
+COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NLINK  NODE NAME
+less    25366  abe    3r  VREG    6,0    17360     0 98768 / (/dev/sd0a)
+```
+
+You can use lsof's -a (AND) option to narrow the link count search
+to a particular file system.  For example, to look for zero link
+counts on the /home file system, use:
+
+```shell
+$ lsof -a +L1 /home
+```
+
+CAUTION: lsof can't always report link counts for all file types
+-- e.g., it may not report them for FIFOs, pipes, or sockets.
+Remember also that link counts for NFS files on an NFS client
+host don't behave as do link counts for files on local disks.
+
+## Finding Processes Blocking Umount
+
+When you need to unmount a file system with the umount command, you may find the
+operation blocked by a process that has a file open on the file systems.  Lsof
+may be able to help you find the process.  In response to:
+
+```shell
+$ lsof <file_system_name>
+```
+
+Lsof will display all open files on the named file system.  It will also set its
+exit code zero when it finds some open files and non-zero when it doesn't,
+making this type of lsof call useful in shell scripts.  (See section 16.)
+
+Consult the output of the df command for file system names.
+
+See the caveat in the preceding section about file references that persist in
+the kernel without open file traces.  That situation may hamper lsof's ability
+to help with umount, too.
+
+## Finding Listening Sockets
+
+Sooner or later you may wonder if someone has installed a network
+server that you don't know about.  Lsof can list for you all the
+network socket files open on your machine with:
+
+```shell
+$ lsof -i
+```
+
+The -i option without further qualification lists all open Internet socket
+files.  You can add network names or addresses, protocol names, and service
+names or port numbers to the -i option to refine the search.  (See the next
+section.)
+
+## Finding a Particular Network Connection
+
+When you know the source or destination of a network connection whose open files
+and process you'd like to identify, the -i option may help.
+
+If, for example, you want to know what process has a connection open to or from
+the Internet host named aaa.bbb.ccc, you can ask lsof to search for it with:
+
+```shell
+$ lsof -i@aaa.bbb.ccc
+```
+
+If you're interested in a particular protocol -- TCP or UDP --
+and a specific port number or service name, you can add those
+discriminators to the -i information:
+
+```shell
+$ lsof -iTCP@aaa.bbb.ccc:ftp-data
+```
+
+If you're interested in a particular IP version -- IPv4 or IPv6
+-- and your UNIX dialect supports both (It does if "IPv[46]"
+appears in the lsof -h output.), you can add the '4' or '6'
+selector immediately after -i:
+
+```shell
+$ lsof -i4
+$ lsof -i6
+```
+
+## Identifying a Netstat Connection
+
+How do I identify the process that has a network connection
+described in netstat output?  For example, if netstat says:
+
+```
+Proto Recv-Q Send-Q  Local Address          Foreign Address        (state)
+tcp        0      0  vic.1023               ipscgate.login         ESTABLISHED
+```
+
+What process is connected to service name `login` on ipscgate?
+
+Use lsof's -i option:
+
+```
+$ lsof -iTCP@ipscgate:login
+COMMAND     PID     USER   FD   TYPE     DEVICE   SIZE/OFF  INODE NAME
+rlogin    25023      abe    3u  inet 0x10144168      0t184    TCP lsof.itap.purdue.edu:1023->ipscgate.cc.purdue.edu:login
+...
+```
+
+There's another way.  Notice the 0x10144168 in the DEVICE column
+of the lsof output?  That's the protocol control block (PCB)
+address.  Many netstat applications will display it when given
+the -A option:
+
+```shell
+$ netstat -A
+PCB      Proto Recv-Q Send-Q  Local Address      Foreign Address    (state)
+10144168 tcp        0      0  vic.1023           ipscgate.login     ESTABLISHED
+...
+```
+
+Using the PCB address, lsof, and grep, you can find the process this
+way, too:
+
+```shell
+$ lsof -i | grep 10144168
+rlogin    25023      abe    3u  inet 0x10144168      0t184    TCP lsof.itap.purdue.edu:1023->ipscgate.cc.purdue.edu:login
+...
+```
+
+If the file is a UNIX socket and netstat reveals and address for it,
+like this Solaris 11 example:
+
+```shell
+$ netstat -a -f unix
+Active UNIX domain sockets
+Address  Type          Vnode     Conn  Local Addr      Remote Addr
+ffffff0084253b68 stream-ord 0000000 0000000
+```
+
+Using lsof's -U option and its output piped to a grep on the address
+yields:
+
+```shell
+$ lsof -U | grep ffffff0084253b68
+squid 1638 nobody 12u unix 18,98 0t10 9437188 /devices/pseudo/tl@0:ticots->0xffffff0084253b68 stream-ord
+```
+
+## Finding Files Open to a Named Command
+
+When you want to look at the files open to a particular command,
+you can look up the PID of the process running the command and
+use lsof's -p option to specify it.
+
+```shell
+$ lsof -p <PID>
+```
+
+However, there's a quicker way, using lsof's -c option, provided
+you don't mind seeing output for every process running the named
+command.
+
+```shell
+$ lsof -c <first_characters_of_command_name_that_interest_you>
+```
+
+The lsof -c option is useful when you want to see how many instances
+of a given command are executing and what their open files are.
+One useful example is for the sendmail command.
+
+```shell
+$ lsof -c sendmail
+```
+
+## Deciphering the Remote Login Trail
+
+If the network connection you're interested in tracing has been initiated
+externally and is connected to an rlogind, sshd, or telnetd process, asking lsof
+to identify that process might not give a wholly satisfying answer.  The report
+may be that the connection exists, but to a process owned by root.
+
+### The Fundamentals
+
+How do you get from there to the login name really using the connection?  You
+have to know a little about how real and pseudo ttys are paired in your system,
+and then use several lsof probes to identify the login.
+
+This example comes from a Solaris 2.4 system, named klaatu.cc.  I've logged on
+to it via rlogin from lsof.itap.  The first lsof probe,
+
+```shell
+$ lsof -i@lsof.itap
+```
+
+yields (among other things):
+
+```shell
+COMMAND     PID     USER   FD   TYPE     DEVICE   SIZE/OFF  INODE NAME
+in.rlogin  7362     root    0u  inet 0xfc0193b0      0t242    TCP klaatu.cc.purdue.edu:login->lsof.itap.purdue.edu:1023
+...
+```
+
+This confirms that a connection exists.  A second lsof probe
+shows:
+
+```shell
+$ lsof -p7362
+COMMAND     PID     USER   FD   TYPE     DEVICE   SIZE/OFF  INODE NAME
+...
+in.rlogin  7362     root    0u  inet 0xfc0193b0      0t242    TCP klaatu.cc.purdue.edu:login->lsof.itap.purdue.edu:1023
+...
+in.rlogin  7362     root    3u  VCHR    23,   0       0t66  52928 /devices/pseudo/clone@0:ptmx->pckt->ptm
+```
+
+7362 is the Process ID (PID) of the in.rlogin process, discovered
+in the first lsof probe.  (I've abbreviated the output to simplify
+the example.)  Now comes a need to understand Solaris pseudo-ttys.
+The key indicator is in the DEVICE column for FD 3, the major/minor
+device number of 23,0.  This translates to /dev/pts/0, so a third
+lsof probe,
+
+```shell
+$ lsof /dev/pts/0
+COMMAND     PID     USER   FD   TYPE     DEVICE   SIZE/OFF  INODE NAME
+ksh        7364      abe    0u  VCHR    24,   0     0t2410  53410 /dev/pts/../../devices/pseudo/pts@0:0
+```
+
+shows in part that login abe has a ksh process on /dev/pts/0.
+(The NAME that lsof shows is not /dev/pts/0 but the full expansion
+of the symbolic link that lsof finds at /dev/pts/0.)
+
+Here's a second example, done on an HP-UX 9.01 host named ghg.ecn.
+Again, I've logged on to it from lsof.itap, so I start with:
+
+```shell
+$ lsof -i@lsof.itap
+COMMAND     PID     USER   FD   TYPE       DEVICE   SIZE/OFF  INODE NAME
+rlogind   10214     root    0u  inet   0x041d5f00     0t1536    TCP ghg.ecn.purdue.edu:login->lsof.itap.purdue.edu:1023
+...
+```
+
+Then,
+
+```shell
+$ lsof -p10214
+COMMAND     PID     USER   FD   TYPE       DEVICE   SIZE/OFF  INODE NAME
+...
+rlogind   10214     root    0u  inet   0x041d5f00     0t2005    TCP ghg.ecn.purdue.edu:login->lsof.itap.purdue.edu:1023
+...
+rlogind   10214     root    3u  VCHR  16,0x000030     0t2037  24642 /dev/ptym/ptys0
+```
+
+Here the key is the NAME /dev/ptym/ptys0.  In HP-UX 9.01 tty and
+pseudo tty devices are paired with the names like /dev/ptym/ptys0
+and /dev/pty/ttys0, so the following lsof probe is the final step.
+
+```shell
+$ lsof /dev/pty/ttys0
+COMMAND     PID     USER   FD   TYPE       DEVICE   SIZE/OFF  INODE NAME
+ksh       10215      abe    0u  VCHR  17,0x000030     0t3399  22607 /dev/pty/ttys0
+...
+```
+
+Here's a third example for an AIX 4.1.4 system.  I've used telnet
+to connect to it from lsof.itap.purdue.edu.  I start with:
+
+```shell
+$ lsof -i@lsof.itap.purdue.edu
+COMMAND     PID     USER   FD   TYPE     DEVICE   SIZE/OFF      INODE NAME
+...
+telnetd   15616     root    0u  inet 0x05a93400     0t5156        TCP cloud.cc.purdue.edu:telnet->lsof.itap.purdue.edu:3369
+```
+
+Then I look at the telnetd process:
+
+```shell
+$ lsof -p15616
+COMMAND     PID     USER   FD   TYPE     DEVICE   SIZE/OFF      INODE NAME
+...
+telnetd   15616     root    0u  inet 0x05a93400     0t5641        TCP cloud.cc.purdue.edu:telnet->lsof.itap.purdue.edu:3369
+...
+telnetd   15616     root    3u  VCHR    25,   0     0t5493        103 /dev/ptc/0
+```
+
+Here the key is /dev/ptc/0.  In AIX it's paired with /dev/pts/0.
+The last probe for that shows:
+
+```shell
+$ lsof /dev/pts/0
+COMMAND     PID     USER   FD   TYPE     DEVICE   SIZE/OFF      INODE NAME
+...
+ksh       16642      abe    0u  VCHR    26,   0     0t6461        360 /dev/pts/0
+```
+
+### The idrlogin.perl[5] Scripts
+
+There's another, perhaps easier way, to go about the job of
+tracing a network connection.  The lsof distribution contains
+two Perl scripts, idrlogin.perl (Perl 4) and idrlogin.perl5
+(Perl 5), that use lsof field output to display values for
+shells that are parented by rlogind, sshd, or telnetd, or
+connected directly to TCP sockets.  The lsof test suite contains
+a C library that can be adapted for use with C programs that
+need to call lsof and process its field output.
+
+The two Perl scripts use the lsof -R option; it causes the
+paRent process ID (PPID) to be listed in the lsof output.  The
+scripts identify all shell processes -- e.g., ones whose command
+names end in ``sh'' -- and determine if: 1) the ultimate ancestor
+process before a PID greater than 2 (e.g., init's PID is 1) is
+rlogind, sshd, or telnetd; or 2) the shell process has open
+TCP socket files.
+
+Here's an example of output from idlogin.perl on a Solaris 2.4
+system:
+
+```shell
+centurion: 1 = cd src/lsof4/scripts
+centurion: 2 = ./idrlogin.perl
+Login    Shell       PID Via           PID TTY        From
+oboyle   ksh       12640 in.telnetd  12638 pts/5      opal.cc.purdue.edu
+icdtest  ksh       15158 in.rlogind  15155 pts/6      localhost
+sh       csh       18207 in.rlogind  18205 pts/1      babylon5.cc.purdue.edu
+root     csh       18242 in.rlogind  18205 pts/1      babylon5.cc.purdue.edu
+trouble  ksh       19208 in.rlogind  18205 pts/1      babylon5.cc.purdue.edu
+abe      ksh       21334 in.rlogind  21332 pts/2      lsof.itap.purdue.edu
+```
+
+The scripts assume that its parent directory contains an
+executable lsof.  If you decide to use one of the scripts, you
+may want to customize it for your local lsof and perl paths.
+
+Note that processes executing as remote shells are also
+identified.
+
+Here's another example from a UnixWare 7.1.0 system.
+
+```shell
+tweeker: 1 = cd src/lsof4/scripts
+tweeker: 9 = ./idrlogin.perl
+Login    Shell       PID Via           PID TTY        From
+abe      ksh        9438 in.telnetd   9436 pts/3      lsof.itap.purdue.edu
+```
+
+## Watching an Ftp or Rcp Transfer
+
+The nature of the Internet being one of unpredictable performance
+at times, occasionally you want to know if a file transfer, being
+done by ftp or rcp, is making any progress.
+
+To use lsof for watching a file transfer, you need to know the
+PID of the file transfer process.  You can use ps to find that.
+Then use lsof,
+
+```shell
+$ lsof -p<PID>
+```
+
+to examine the files open to the transfer process.  Usually the
+ftp files or interest are at file descriptors 9 and 10 or 10 and
+11; for rcp, 3 and 4.  They describe the network socket file and
+the local data file.
+
+If you want to watch only those file descriptors as the file
+transfer progresses, try these lsof forms (for ftp in the example):
+
+```shell
+$ lsof -p<PID> -ad9,10 -r
+# or
+$ lsof -p<PID> -ad10,11 -r
+```
+
+Some options need explaining:
+
+- -p<PID>      specifies that lsof is to restrict its attention
+       to the process whose ID is <PID>.  You can specify
+       a set of PIDs by separating them with commas.
+
+               $ lsof -p 1234,5678,9012
+
+- -a           specifies that lsof is to AND its tests together.
+       The two tests that are specified are tests on the
+       PID and tests on file descriptions (`d9,10`).
+
+- d9,10        specifies that lsof is to test only file descriptors
+       9 and 10.  Note that the `-` is absent, since `-a`
+       is a unary option and can be followed immediately
+       by another lsof option.
+
+- -r          tells lsof to list the requested open file information,
+       sleep for a default 15 seconds, then list the open
+       file information again.  You can specify a different
+       time (in seconds) after -r and override the default.
+       Lsof issues a short line of equal signs between
+       each set of output to distinguish it.
+
+For an rcp transfer, the above example becomes:
+
+```shell
+$ lsof -p<PID> -ad3,4 -r
+```
+
+## Listing Open NFS Files
+
+Lsof will list all files open on remote file systems, supported
+by an NFS server.  Just use:
+
+```shell
+$ lsof -N
+```
+
+Note, however, that when run on an NFS server, lsof will not list
+files open to the server from one of its clients.  That's because
+lsof can only examine the processes running on the machine where
+it is called -- i.e., on the NFS server.
+
+If you run lsof on the NFS client, using the -N option, it will
+list files open by processes on the client that are on remote
+NFS file systems.
+
+## Listing Files Open by a Specific Login
+
+If you're interested in knowing what files the processes owned
+by a particular login name have open, lsof can help.
+
+```shell
+$ lsof -u<login>
+# or
+$ lsof -u<User ID number>
+```
+
+You can specify either the login name or the UID associated with
+it.  You can specify multiple login names and UID numbers, mixed
+together, by separating them with commas.
+
+```shell
+$ lsof -u548,abe
+```
+
+On the subject of login names and UIDs, it's worth noting that
+lsof can be told to report either.  By default it reports login
+names; the -l option switches reporting to UIDs.  You might want
+to use -l if login name lookup is slow for some reason.
+
+### Ignoring a Specific Login
+
+The -u option can also be used to direct lsof to ignore a
+specific login name or UID, or a list of them.  Simply prefix
+the login names or UIDs with a `^` character, as you might do
+in a regular expression.  The `^` prefix is useful, for example,
+when you want to have lsof ignore the files open to system
+processes, owned by the root (UID 0) login.  Try:
+
+```shell
+$ lsof -u ^root
+# or
+$ lsof -u ^0
+```
+
+## Listing Files Open to a Specific Process Group
+
+There's a Unix collection of processes called a process group.
+The name indicates that the processes of the group have a common
+association and are grouped so that a signal sent to one (e.g.,
+a keyboard kill stroke) is delivered to all.
+
+This causes Unix to create a two element process group:
+
+```shell
+$ lsof | less
+```
+
+You can use lsof to look at the open files of all members of a
+process group, if you know the process group ID number.  Assuming
+that it is 12717 for the above example, this lsof command:
+
+```shell
+$ lsof -g12717 -adcwd
+```
+
+would produce on a Solaris 8 system:
+
+```shell
+$ lsof -g12717 -adcwd
+COMMAND   PID  PGID USER  FD TYPE DEVICE SIZE/OFF    NODE NAME
+sshd    11369 12717 root cwd VDIR    0,2      189 1449175 /tmp (swap)
+sshd    12717 12717 root cwd VDIR  136,0     1024       2 /
+```
+
+The `-g12717'` option specifies the process group ID of interest;
+the `-adcwd` option specifies that options are to be ANDed and
+that lsof should limit file output to information about current
+working directory (`cwd`) files.
+
+
+## Output for Other Programs
+
+The -F option allows you to specify that lsof should describe
+open files with a special form of output, called field output,
+that can be parsed easily by a subsequent program.  The lsof
+distribution comes with sample AWK, Perl 4, and Perl 5 scripts
+that post-process field output.  The lsof test suite has a C
+library that could be adapted for use by C programs that want to
+process lsof field output from an in-bound pipe.
+
+The lsof manual page describes field output in detail in its
+OUTPUT FOR OTHER PROGRAMS section.  A quick look at a sample
+script in the scripts/ subdirectory of the lsof distribution will
+also give you an idea how field output works.
+
+The most important thing about field output is that it is relatively
+homogeneous across Unix dialects.  Thus, if you write a script
+to post-process field output for AIX, it probably will work for
+HP-UX, Solaris, and Ultrix as well.
+
+Support for other formats e.g. JSON is planned.
+
+## The Lsof Exit Code and Shell Scripts
+
+When lsof executes successfully, it returns an exit code based on
+the result of its search for specified files.  (If no files were
+specified, then the successful exit code is 0 (zero).)
+
+If lsof was asked to search for specific files, including any
+files on specified file systems, it returns an exit code of 0
+(zero) if it found all the specified files and at least one file
+on each specified file system.  Otherwise it returns a 1 (one) if
+any part of the search failed.
+
+This behavior can be modified by calling lsof with -Q, which will
+tell it to provide a successful exit code of 0 (zero) even if any
+part of the file or filesystem search failed.
+
+If lsof detects a generic (non-search) error during its execution,
+it returns an exit code of 1 (one).  The -Q option will not
+affect this behavior.
+
+You can use the exit code in a shell script to search for files
+on a file system and take action based on the result -- e.g.,
+
+```shell
+#!/bin/sh
+lsof <file_system_name> > /dev/null 2>&1
+if test $? -eq 0
+then
+echo "<file_system_name> has some users."
+else
+echo "<file_system_name> may have no users."
+fi
+```
+
+The -Q option can help in certain circumstances.  For example, if
+you want to log filesystem users without caring if there are no
+users:
+
+```shell
+#!/bin/sh
+lsof -Q <file_system_name>  > fs_users.log
+if test $? -ne 0
+then
+echo "Error: Something actually went wrong!" 1>&2
+exit 1
+fi
+```
+
+## Strange messages in the NAME column
+
+When lsof encounters problems analyzing a particular file, it may
+put a message in the file's NAME column.  Many of those messages
+are explained in the 00FAQ file of the lsof distribution.
+
+So consult 00FAQ first if you encounter a NAME column message you
+don't understand.  (00FAQ is a possible source of information
+about other unfamiliar things in lsof output, too.)
+
+If you can't find help in 00FAQ, you can use grep to look in the
+lsof source files for the message -- e.g.,
+
+```shell
+$ cd .../lsof_4.76_src
+$ grep "can't identify protocol" *.[ch]
+```
+
+The code associated with the message will usually make clear the
+reason for the message.
+
+If you have an lsof source tree that has been processed by the
+lsof Configure script, you need grep only there.  If, however,
+your source tree hasn't been processed by Configure, you may
+have to look in the top-level lsof source directory and in the
+dialects sub-directory for the UNIX dialect you are using - e.g.,
+
+```shell
+$ cd .../lsof_4.76_src
+$ grep "can't identify protocol" *.[ch]
+$ cd dialects/Linux
+$ grep "can't identify protocol" *.[ch]
+```
+
+In rare cases you may have to look in the lsof library, too --
+e.g.,
+
+```
+$ cd .../lsof_4.76_src
+$ grep "can't identify protocol" *.[ch]
+$ cd dialects/Linux
+$ grep "can't identify protocol" *.[ch]
+$ cd ../../lib
+$ grep "can't identify protocol" *.[ch]
+```
diff --git a/include/lsof.h b/include/lsof.h
new file mode 100644 (file)
index 0000000..d6cae57
--- /dev/null
@@ -0,0 +1,586 @@
+/** @file
+ * lsof.h - header file for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+/*
+ * $Id: lsof.h,v 1.70 2018/03/26 21:50:45 abe Exp $
+ */
+
+#if !defined(LSOF_H)
+#    define LSOF_H 1
+
+#    include <stdint.h>
+#    include <stdio.h>
+
+/** lsof error returns */
+enum lsof_error {
+    LSOF_SUCCESS = 0,            /**< Success */
+    LSOF_ERROR_INVALID_ARGUMENT, /**< Invalid argument */
+    LSOF_ERROR_NO_MEMORY,        /**< No memory */
+    LSOF_ERROR_UNSUPPORTED,      /**< Unsupported operation */
+};
+
+/** File access mode */
+enum lsof_file_access_mode {
+    LSOF_FILE_ACCESS_NONE = 0,  /**< None */
+    LSOF_FILE_ACCESS_READ = 1,  /**< Read */
+    LSOF_FILE_ACCESS_WRITE = 2, /**< Write */
+    LSOF_FILE_ACCESS_READ_WRITE =
+        LSOF_FILE_ACCESS_READ | LSOF_FILE_ACCESS_WRITE, /**< Read and write */
+};
+
+/** File lock mode */
+enum lsof_lock_mode {
+    LSOF_LOCK_NONE,          /**< None */
+    LSOF_LOCK_UNKNOWN,       /**< Unknown */
+    LSOF_LOCK_READ_PARTIAL,  /**< Read lock on part of the file */
+    LSOF_LOCK_READ_FULL,     /**< Read lock on the entire file */
+    LSOF_LOCK_WRITE_PARTIAL, /**< Write lock on part of the file */
+    LSOF_LOCK_WRITE_FULL,    /**< Write lock on the entire file */
+    LSOF_LOCK_READ_WRITE,    /**< Read and write lock */
+    LSOF_LOCK_SOLARIS_NFS,   /**< Solaris NFS lock */
+    LSOF_LOCK_SCO_PARTIAL,   /**< SCO OpenServer lock on part of the file */
+    LSOF_LOCK_SCO_FULL,      /**< SCO OpenServer lock on the entire file */
+};
+
+/** File descriptor type */
+enum lsof_fd_type {
+    LSOF_FD_NUMERIC,         /**< Numeric fd opened in process */
+    LSOF_FD_UNKNOWN,         /**< Unknown fd type */
+    LSOF_FD_CWD,             /**< Current working directory */
+    LSOF_FD_ERROR,           /**< Failed to get fd information */
+    LSOF_FD_NOFD,            /**< No file descriptors */
+    LSOF_FD_ROOT_DIR,        /**< Root directory */
+    LSOF_FD_PARENT_DIR,      /**< Parent directory */
+    LSOF_FD_PROGRAM_TEXT,    /**< Program text */
+    LSOF_FD_LIBRARY_TEXT,    /**< Library text */
+    LSOF_FD_MEMORY,          /**< Memory-mapped file */
+    LSOF_FD_DELETED,         /**< Deleted file */
+    LSOF_FD_FILEPORT,        /**< Darwin fileport */
+    LSOF_FD_TASK_CWD,        /**< Per task/thread cwd */
+    LSOF_FD_CTTY,            /**< Character TTY */
+    LSOF_FD_JAIL_DIR,        /**< Jail directory */
+    LSOF_FD_VIRTUAL_8086,    /**< Virtual 8086 */
+    LSOF_FD_MERGE_386,       /**< MERGE386 vm86 region */
+    LSOF_FD_MMAP_DEVICE,     /**< Memory-mapped device */
+    LSOF_FD_LIBRARY_REF,     /**< Library references */
+    LSOF_FD_MMAP_UNKNOWN,    /**< Unknown memory-mapped file */
+    LSOF_FD_PREGION_UNKNOWN, /**< Unknown HP-UX pregion */
+};
+
+/** File type */
+enum lsof_file_type {
+    LSOF_FILE_NONE, /**< No file type */
+
+    /* struct stat S_IFMT modes */
+    LSOF_FILE_FIFO,    /**< FIFO special file */
+    LSOF_FILE_CHAR,    /**< Character special file */
+    LSOF_FILE_DIR,     /**< Directory */
+    LSOF_FILE_BLOCK,   /**< Block special file */
+    LSOF_FILE_REGULAR, /**< Regular file */
+    LSOF_FILE_LINK,    /**< Symolic link */
+    LSOF_FILE_SOCKET,  /**< Socket of unknown domain */
+
+    /* Network */
+    LSOF_FILE_IPV4,              /**< IPv4 socket */
+    LSOF_FILE_IPV6,              /**< IPv6 socket */
+    LSOF_FILE_AX25,              /**< AX.25 socket */
+    LSOF_FILE_INET,              /**< Internet(either IPv4 or IPv6) socket */
+    LSOF_FILE_LINK_LEVEL_ACCESS, /**< HP-UX link level access file */
+    LSOF_FILE_ROUTE,             /**< AF_ROUTE socket */
+    LSOF_FILE_UNIX,              /**< UNIX domain socket */
+    LSOF_FILE_X25,               /**< HP-UX x.25 socket */
+    LSOF_FILE_APPLETALK,         /**< Appletalk socket */
+    LSOF_FILE_NET_DRIVER,        /**< AF_NDRV network driver raw socket */
+    LSOF_FILE_INTERNAL_KEY,      /**< Darwin internal key-management socket */
+    LSOF_FILE_SYSTEM,            /**< AF_SYSTEM kernel event messages socket */
+    LSOF_FILE_PPP,               /**< PPP socket */
+    LSOF_FILE_IPX,               /**< IPX socket */
+    LSOF_FILE_RAW,               /**< raw socket */
+    LSOF_FILE_RAW6,              /**< raw IPv6 socket */
+    LSOF_FILE_NETLINK,           /**< netlink socket */
+    LSOF_FILE_PACKET,            /**< packet socket */
+    LSOF_FILE_ICMP,              /**< icmp socket */
+
+    /* procfs */
+    LSOF_FILE_PROC_AS,             /**< Solaris /proc/<PID>/as file */
+    LSOF_FILE_PROC_AUXV,           /**< /proc/<PID>/auxv file */
+    LSOF_FILE_PROC_CRED,           /**< Solaris /proc/<PID>/cred file */
+    LSOF_FILE_PROC_CTRL,           /**< /proc/<PID>/ctl control file */
+    LSOF_FILE_PROC_CUR_PROC,       /**< NetBSD /proc/curproc file */
+    LSOF_FILE_PROC_CWD,            /**< Solaris /proc/<PID>/cwd folder */
+    LSOF_FILE_PROC_DIR,            /**< /proc directory */
+    LSOF_FILE_PROC_EXEC_TYPE,      /**< FreeBSD /proc executable type (etype) */
+    LSOF_FILE_PROC_FD,             /**< /proc/<PID>/fd/<FD> file */
+    LSOF_FILE_PROC_FD_DIR,         /**< /proc/<PID>/fd directory */
+    LSOF_FILE_PROC_FILE,           /**< /proc/<PID>/file executable file */
+    LSOF_FILE_PROC_FP_REGS,        /**< /proc/<PID>/fpregs fp registers */
+    LSOF_FILE_PROC_PAGE_DATA,      /**< Solaris /proc/<PID>/pagedata file */
+    LSOF_FILE_PROC_GROUP_NOTIFIER, /**< /proc/<PID>/notepg group notifier */
+    LSOF_FILE_PROC_LDT,            /**< Solaris /proc/<PID>/ldt file */
+    LSOF_FILE_PROC_LPS_INFO,       /**< Solaris /proc/<PID>/lpsinfo file */
+    LSOF_FILE_PROC_LSTATUS,        /**< Solaris /proc/<PID>/lstatus file */
+    LSOF_FILE_PROC_LUSAGE,         /**< Solaris /proc/<PID>/lusage file */
+    LSOF_FILE_PROC_LWP_GWINDOWS,   /**< Solaris /proc/<PID>/lwp/<LWPID>/gwindows
+                                    */
+    LSOF_FILE_PROC_LWP_CTL, /**< Solaris /proc/<PID>/lwp/<LWPID>/lwpctl file */
+    LSOF_FILE_PROC_LWP_DIR, /**< Solaris /proc/<PID>/lwp or
+                               /proc/<PID>/lwp/<LWPID> directory */
+    LSOF_FILE_PROC_LWP_SINFO, /**< Solaris /proc/<PID>/lwp/<LWPID>/lwpsinfo file
+                               */
+    LSOF_FILE_PROC_LWP_STATUS, /**< Solaris /proc/<PID>/lwp/<LWPID>/lwpstatus
+                                  file */
+    LSOF_FILE_PROC_LWP_USAGE, /**< Solaris /proc/<PID>/lwp/<LWPID>/lwpusage file
+                               */
+    LSOF_FILE_PROC_LWP_XREGS, /**< Solaris /proc/<PID>/lwp/<LWPID>/xregs file */
+    LSOF_FILE_PROC_MAP,       /**< /proc/<PID>/map memory mapping file */
+    LSOF_FILE_PROC_MAPS,      /**< /proc/<PID>/maps memory mapping file */
+    LSOF_FILE_PROC_MEMORY,    /**< /proc/<PID>/mem memory image file */
+    LSOF_FILE_PROC_PROC_NOTIFIER, /**< /proc/<PID>/note process notifier file */
+    LSOF_FILE_PROC_OBJ,           /**< Solaris /proc/<PID>/object file */
+    LSOF_FILE_PROC_OBJ_DIR,       /**< Solaris /proc/<PID>/object directory */
+    LSOF_FILE_PROC_OLD_LWP,       /**< Solaris old format /proc/<LWPID> file */
+    LSOF_FILE_PROC_OLD_PID,       /**< Solaris old format /proc/<PID> file */
+    LSOF_FILE_PROC_OLD_PAGE,      /**< Solaris old /proc/<PID> page data file */
+    LSOF_FILE_PROC_REGS,          /**< /proc/<PID>/regs register set */
+    LSOF_FILE_PROC_RMAP,          /**< Solaris /proc/<PID>/rmap file */
+    LSOF_FILE_PROC_ROOT,          /**< Solaris /proc/<PID>/root directory */
+    LSOF_FILE_PROC_SIGACT,        /**< Solaris /proc/<PID>/sigact file */
+    LSOF_FILE_PROC_PSINFO,        /**< Solaris /proc/<PID>/psinfo file */
+    LSOF_FILE_PROC_STATUS,        /**< /proc/<PID>/status status file */
+    LSOF_FILE_PROC_USAGE,         /**< Solaris /proc/<PID>/usage file */
+    LSOF_FILE_PROC_WATCH,         /**< Solaris /proc/<PID>/watch file */
+    LSOF_FILE_PROC_XMAP,          /**< Solaris /proc/<PID>/xmap file */
+
+    /* Others */
+    LSOF_FILE_ANON_INODE,        /**< anonymous inode */
+    LSOF_FILE_DEL,               /**< Linux map file that has been deleted */
+    LSOF_FILE_DOOR,              /**< Solaris VDOOR file */
+    LSOF_FILE_KQUEUE,            /**< BSD style kernel event file */
+    LSOF_FILE_FSEVENTS,          /**< fsevents file */
+    LSOF_FILE_EVENTFD,           /**< eventfd file */
+    LSOF_FILE_PROCDESC,          /**< process descriptor file */
+    LSOF_FILE_MULTIPLEXED_BLOCK, /**< SCO OpenServer multiplexed block file */
+    LSOF_FILE_MULTIPLEXED_CHAR,  /**< SCO OpenServer multiplexed char file */
+    LSOF_FILE_UNKNOWN_DELETED,   /**< Linux unknown deleted file */
+    LSOF_FILE_UNKNOWN_MEMORY,    /**< Linux unknown memory file */
+    LSOF_FILE_UNKNOWN_FD,        /**< Linux unknown fd */
+    LSOF_FILE_UNKNOWN_CWD,       /**< Linux unknown cwd */
+    LSOF_FILE_UNKNOWN_ROOT_DIR,  /**< Linux unknown root dir */
+    LSOF_FILE_UNKNOWN_PROGRAM_TEXT, /**< Linux unknown program text */
+    LSOF_FILE_UNKNOWN_STAT,         /**< Linux unknown due to failed stat() */
+    LSOF_FILE_UNKNOWN_RAW, /**< Unknown file type, raw numbers provided in
+                              unknown_file_type_number */
+    LSOF_FILE_UNKNOWN,     /**< Unknown file type without raw number */
+    LSOF_FILE_PIPE,        /**< pipes */
+    LSOF_FILE_PORT,        /**< Solaris SYSV named pipe */
+    LSOF_FILE_POSIX_MQ,    /**< POSIX named message queue file */
+    LSOF_FILE_POSIX_SEMA,  /**< POSIX named semaphore file */
+    LSOF_FILE_POSIX_SHM,   /**< POSIX named shared memory file */
+    LSOF_FILE_SHM,         /**< SystemV shared memory file */
+    LSOF_FILE_PTS,         /**< FreeBSD /dev/pts file */
+    LSOF_FILE_SHARED_MEM_TRANSPORT, /**< AIX Shared memory transport file */
+    LSOF_FILE_STREAM,               /**< HP-UX streams */
+    LSOF_FILE_STREAM_SOCKET,        /**< HP-UX stream socket */
+    LSOF_FILE_SCO_UNKNOWN, /**< SCO OpenServer Xenix special file of unknown
+                              type */
+    LSOF_FILE_SCO_SEMA,    /**< SCO OpenServer Xenix semaphore file */
+    LSOF_FILE_SCO_SHARED,  /**< SCO OpenServer Xenix shared data file */
+    LSOF_FILE_UNSUPPORTED, /**< unsupported file type */
+
+    /* types from struct vnode */
+    LSOF_FILE_VNODE_VNON,  /**< The vnode has no type */
+    LSOF_FILE_VNODE_VREG,  /**< The vnode represents a regular file */
+    LSOF_FILE_VNODE_VDIR,  /**< The vnode represents a directory */
+    LSOF_FILE_VNODE_VBLK,  /**< The vnode represents a block special device */
+    LSOF_FILE_VNODE_VCHR,  /**< The vnode represents a char special device */
+    LSOF_FILE_VNODE_VLNK,  /**< The vnode represents a symbolic link */
+    LSOF_FILE_VNODE_VSOCK, /**< The vnode represents a socket */
+    LSOF_FILE_VNODE_VBAD,  /**< The vnode represents a bad file */
+    LSOF_FILE_VNODE_VMPC,  /**< The vnode represents a multiplexed character
+                              special device */
+    LSOF_FILE_VNODE_VFIFO, /**< The vnode represents a FIFO file */
+    LSOF_FILE_VNODE_VUNNAMED, /**< The vnode represents an unnamed file */
+    LSOF_FILE_VNODE_VDOOR,    /**< The vnode represents a door */
+    LSOF_FILE_VNODE_VPORT,    /**< The vnode represents a port */
+};
+
+/** @struct lsof_context
+ * Hidden struct of lsof context, use `lsof_new()` to get one
+ */
+struct lsof_context;
+
+/** @enum struct lsof_file flags */
+enum lsof_file_flag {
+    LSOF_FILE_FLAG_NONE,
+    /** \ref struct lsof_file.dev field is valid */
+    LSOF_FILE_FLAG_DEV_VALID = 0x00000001,
+    /** \ref struct lsof_file.rdev field is valid */
+    LSOF_FILE_FLAG_RDEV_VALID = 0x00000002,
+    /** \ref struct lsof_file.size field is valid */
+    LSOF_FILE_FLAG_SIZE_VALID = 0x00000004,
+    /** \ref struct lsof_file.offset field is valid */
+    LSOF_FILE_FLAG_OFFSET_VALID = 0x00000008,
+    /** \ref struct lsof_file.num_links field is valid */
+    LSOF_FILE_FLAG_NUM_LINKS_VALID = 0x00000010,
+    /** \ref struct lsof_file.inode field is valid */
+    LSOF_FILE_FLAG_INODE_VALID = 0x00000020,
+};
+
+/** An open file
+ */
+struct lsof_file {
+    /** Flags, see \ref lsof_file_flag */
+    uint64_t flags;
+
+    /* FD column */
+    /** File desciptor type */
+    enum lsof_fd_type fd_type;
+
+    /** File descriptor number, valid if \ref fd_type == \ref LSOF_FD_NUMERIC */
+    uint32_t fd_num;
+
+    /** File access mode */
+    enum lsof_file_access_mode access;
+
+    /** File lock mode */
+    enum lsof_lock_mode lock;
+
+    /* TYPE column */
+    /** File type */
+    enum lsof_file_type file_type;
+    /** Store raw file type number when \ref file_type == \ref LSOF_FILE_UNKNOWN
+     */
+    uint32_t unknown_file_type_number;
+
+    /* DEVICE column */
+    /** Device ID of device containing file, use major() and minor() to extract
+     * components. Valid if \ref flags & \ref LSOF_FILE_FLAG_DEV_VALID */
+    uint64_t dev;
+    /** Device ID of special character/block file, use major() and minor() to
+     * extract components. Valid if \ref flags & \ref
+     * LSOF_FILE_FLAG_RDEV_VALID */
+    uint64_t rdev;
+
+    /* SIZE, SIZE/OFF, OFFSET column */
+    /** File size, valid if \ref flags & \ref LSOF_FILE_FLAG_SIZE_VALID */
+    uint64_t size;
+
+    /** File offset, valid if \ref flags & \ref LSOF_FILE_FLAG_OFFSET_VALID */
+    uint64_t offset;
+
+    /* NLINK column */
+    /** Link count, valid if \ref flags & \ref LSOF_FILE_FLAG_NUM_LINKS_VALID */
+    uint64_t num_links;
+
+    /* NODE column */
+    /** File inode, valid if \ref flags & \ref LSOF_FILE_FLAG_INODE_VALID */
+    uint64_t inode;
+
+    /* NAME column */
+    /** File name or description */
+    char *name;
+};
+
+/** The result of lsof_gather(), grouped by process
+ *
+ * For each process, you can find a linked list of open files at `files`
+ */
+struct lsof_process {
+    /* COMMAND column */
+    char *command; /**< command name */
+    /* PID column */
+    uint32_t pid; /**< process ID */
+
+    /* TID column */
+    uint32_t tid; /**< task ID */
+    /* TASKCMD column */
+    char *task_cmd; /**< task command name */
+
+    /* ZONES column */
+    char *solaris_zone; /**< solaris zone name */
+    /* SECURITY-CONTEXT column */
+    char *selinux_context; /**< seLinux context name */
+
+    /* PGID column */
+    uint32_t pgid; /**< process group ID */
+    /* PPID column */
+    uint32_t ppid; /**< parent process ID */
+    /* USER column */
+    uint32_t uid; /**< user ID */
+
+    uint32_t num_files;      /**< length of files array */
+    struct lsof_file *files; /**< array of open files */
+};
+
+/** selection types */
+enum lsof_selection_type {
+    LSOF_SELECTION_COMMAND,         /**< select by command */
+    LSOF_SELECTION_COMMAND_REGEX,   /**< select by command regex */
+    LSOF_SELECTION_PATH,            /**< select by file path */
+    LSOF_SELECTION_FILE_SYSTEM,     /**< select by file system */
+    LSOF_SELECTION_NETWORK_ADDRESS, /**< select by network address */
+    LSOF_SELECTION_INTERNET,        /**< select by internet protocol */
+    LSOF_SELECTION_PROTOCOL_STATE,  /**< select by tcp/tpi state */
+    LSOF_SELECTION_NFS,             /**< select by nfs */
+    LSOF_SELECTION_PID,             /**< select by pid */
+    LSOF_SELECTION_PGID,            /**< select by pgid */
+    LSOF_SELECTION_UID,             /**< select by uid */
+    LSOF_SELECTION_TASK,            /**< select by tasks */
+    LSOF_SELECTION_SOLARIS_ZONE,    /**< select by Solaris zones */
+    LSOF_SELECTION_SELINUX_CONTEXT, /**< select by SELinux context */
+};
+
+/** Report selection status */
+struct lsof_selection {
+    enum lsof_selection_type type; /**< selection type */
+    int found;                     /**< whether selection matches file */
+    /** string selection argument, valid if type is one of
+     * LSOF_SELECTION_COMMAND, LSOF_SELECTION_COMMAND_REGEX,
+     * LSOF_SELECTION_PATH, LSOF_SELECTION_FILE_SYSTEM,
+     * LSOF_SELECTION_NETWORK_ADDRESS, LSOF_SELECTION_PROTOCOL_STATE,
+     * LSOF_SELECTION_UID, LSOF_SELECTION_SOLARIS_ZONE,
+     * LSOF_SELECTION_SELINUX_CONTEXT
+     */
+    char *string;
+    /** integer selection argument, valid if type is one of
+     * LSOF_SELECTION_PID, LSOF_SELECTION_PGID, LSOF_SELECTION_UID
+     */
+    uint64_t integer;
+};
+
+/** The result of lsof_gather() */
+struct lsof_result {
+    size_t num_processes;           /**< length of processes array */
+    struct lsof_process *processes; /**< array of processes */
+
+    /* Report selection status */
+    size_t num_selections;             /**< length of selections array */
+    struct lsof_selection *selections; /**< array of selections */
+};
+
+/** API version of liblsof
+ * you may use this macro to check the existence of
+ * functions
+ */
+#    define LSOF_API_VERSION 1
+
+/** Get runtime API version of liblsof
+ *
+ * liblsof might not function properly if API version mismatched between compile
+ * time and runtime.
+ *
+ * \since API version 1
+ */
+int lsof_get_api_version();
+
+/** Get library version of liblsof
+ *
+ * \return a string like "4.xx.x". The caller must not free it.
+ *
+ * \since API version 1
+ */
+char *lsof_get_library_version();
+
+/** Create a new lsof context
+ *
+ * The context should be freed via `lsof_destroy()`.
+ *
+ * \since API version 1
+ */
+struct lsof_context *lsof_new();
+
+/** Set output stream for warning and error messages
+ *
+ * lsof may want to print warning and error messages to the user. You can allow
+ * printing by setting the output stream and whether prints warning or not. You
+ * should also supply `program_name` so that the output starts with your program
+ * name.
+ *
+ * By default, the output is suppressed. You can set fp to NULL to suppress
+ * output.
+ *
+ * \since API version 1
+ */
+enum lsof_error lsof_set_output_stream(struct lsof_context *ctx, FILE *fp,
+                                       char *program_name, int warn);
+
+/** Ask lsof to avoid using blocking functions
+ *
+ * lsof may block when calling lstat(), readlink() or stat(). Call this function
+ * with `avoid=1` to let lsof avoid calling these functions.
+ *
+ * \since API version 1
+ */
+enum lsof_error lsof_avoid_blocking(struct lsof_context *ctx, int avoid);
+
+/** Ask lsof to avoid forking
+ *
+ * To avoid being blocked by some kernel operations, liblsof does them in forked
+ * child processes. Call this function to change this behavior.
+ *
+ * \since API version 1
+ */
+enum lsof_error lsof_avoid_forking(struct lsof_context *ctx, int avoid);
+
+/** Ask lsof to AND the selections
+ *
+ * By default, lsof OR the selections, for example, if you call
+ * lsof_select_unix_socket() and lsof_select_login(), it will report unix
+ * sockets OR open files by the user. If lsof_logic_and() is called, it will
+ * report unix sockets open by the specified user.
+ *
+ * \since API version 1
+ */
+enum lsof_error lsof_logic_and(struct lsof_context *ctx);
+
+/** Ask lsof to select process by command
+ *
+ * Select process executing the command that begins with the characters of
+ * `command`. You can specify exclusion by setting `exclude` to 1.
+ *
+ * You can call this function multiple times to add more search conditions.
+ *
+ * \since API version 1
+ */
+enum lsof_error lsof_select_process(struct lsof_context *ctx, char *command,
+                                    int exclude);
+
+/** Ask lsof to select process by matching regex
+ *
+ * Select process executing the command that matches with the
+ * `regex`.
+ *
+ * `regex` must begin and end with a slash ('/'), the characters between the
+ * slashes are interpreted as a regular expression.
+ *
+ * The closing slash may be followed by these modifiers:
+ * - b the regular expression is a basic one.
+ * - i ignore the case of letters.
+ * - x the regular expression is an extended one (default).
+ *
+ * You can call this function multiple times to add more search conditions.
+ *
+ * \since API version 1
+ */
+enum lsof_error lsof_select_process_regex(struct lsof_context *ctx,
+                                          char *regex);
+
+/** Ask lsof to select process by pid (process id)
+ *
+ * Select process by comparing pid. You can specify exclusion by setting
+ * `exclude` to 1.
+ *
+ * You can call this function multiple times to add more search conditions.
+ *
+ * \since API version 1
+ */
+enum lsof_error lsof_select_pid(struct lsof_context *ctx, uint32_t pid,
+                                int exclude);
+
+/** Ask lsof to select process by pgid (process group id)
+ *
+ * Select process by comparing pgid. You can specify exclusion by setting
+ * `exclude` to 1.
+ *
+ * You can call this function multiple times to add more search conditions.
+ *
+ * \since API version 1
+ */
+enum lsof_error lsof_select_pgid(struct lsof_context *ctx, uint32_t pgid,
+                                 int exclude);
+
+/** Ask lsof to select process by uid
+ *
+ * Select process whose user id equals to or not equals to `uid`
+ *
+ * You can call this function multiple times to add more search conditions.
+ *
+ * \since API version 1
+ */
+enum lsof_error lsof_select_uid(struct lsof_context *ctx, uint32_t uid,
+                                int exclude);
+
+/** Ask lsof to select process by user login
+ *
+ * Select process whose user login name equals to or not equals to `login`
+ *
+ * You can call this function multiple times to add more search conditions.
+ *
+ * \since API version 1
+ */
+enum lsof_error lsof_select_login(struct lsof_context *ctx, char *login,
+                                  int exclude);
+
+/** Freeze the lsof context
+ *
+ * You can only call it once per context. After this call, no more options can
+ * be changed.
+ *
+ * The function allows liblsof to do some preprocessing to improve performance.
+ *
+ * \since API version 1
+ */
+enum lsof_error lsof_freeze(struct lsof_context *ctx);
+
+/** List open files, grouped by processes
+ *
+ * The result is a struct lsof_result, saved into `result` paramter.
+ *
+ * You should not alter the content of `result`, nor call `free()` to
+ * pointers within. You should free `result` by calling
+ * `lsof_free_result()`
+ *
+ * If the context is not frozen, lsof_freeze() will be called.
+ *
+ * \return LSOF_INVALID_ARGUMENT if either pointer argument is NULL
+ *
+ * \since API version 1
+ */
+enum lsof_error lsof_gather(struct lsof_context *ctx,
+                            struct lsof_result **result);
+
+/** Destroy a lsof context
+ *
+ * You should call `lsof_free_result` to free all `struct lsof_result`
+ * before destroying the context.
+ *
+ * You must not use the context anymore after this call.
+ *
+ * \since API version 1
+ */
+void lsof_destroy(struct lsof_context *ctx);
+
+/** Free struct lsof_result
+ *
+ * \since API version 1
+ */
+void lsof_free_result(struct lsof_result *result);
+
+#endif
\ No newline at end of file
diff --git a/include/lsof_fields.h b/include/lsof_fields.h
new file mode 100644 (file)
index 0000000..05d97f5
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * lsof_field.sh - field ID characters for lsof output that can be parsed
+ *                (selected with -f or -F)
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+/*
+ * $Id: lsof_fields.h,v 1.14 2018/02/14 14:19:25 abe Exp $
+ */
+
+#if !defined(LSOF_FORMAT_H)
+#    define LSOF_FORMAT_H 1
+
+/*
+ * Codes for output fields:
+ *
+ *     LSOF_FID_*      ID character
+ *     LSOF_FIX_*      ID index
+ *     LSOF_FNM_*      name
+ *
+ * A field is displayed in the form:
+ *             <ID_character><data><field_terminator>
+ *
+ * Output fields are normally terminated with a NL ('\n'), but the field
+ * terminator can be set to NUL with the -0 (zero) option to lsof.
+ *
+ * Field sets -- process-specific information or information specific
+ * to a single file descriptor -- are terminated with NL when the field
+ * terminator is NUL.
+ */
+
+#    define LSOF_FID_ACCESS 'a'
+#    define LSOF_FIX_ACCESS 0
+#    define LSOF_FNM_ACCESS "access: r = read; w = write; u = read/write"
+
+#    define LSOF_FID_CMD 'c'
+#    define LSOF_FIX_CMD 1
+#    define LSOF_FNM_CMD "command name"
+
+#    define LSOF_FID_CT 'C'
+#    define LSOF_FIX_CT 2
+#    define LSOF_FNM_CT "file struct share count"
+
+#    define LSOF_FID_DEVCH 'd'
+#    define LSOF_FIX_DEVCH 3
+#    define LSOF_FNM_DEVCH "device character code"
+
+#    define LSOF_FID_DEVN 'D'
+#    define LSOF_FIX_DEVN 4
+#    define LSOF_FNM_DEVN "major/minor device number as 0x<hex>"
+
+#    define LSOF_FID_FD 'f'
+#    define LSOF_FIX_FD 5
+#    define LSOF_FNM_FD "file descriptor"
+
+#    define LSOF_FID_FA 'F'
+#    define LSOF_FIX_FA 6
+#    define LSOF_FNM_FA "file struct address as 0x<hex>"
+
+#    define LSOF_FID_FG 'G'
+#    define LSOF_FIX_FG 7
+#    define LSOF_FNM_FG "file flaGs"
+
+#    define LSOF_FID_INODE 'i'
+#    define LSOF_FIX_INODE 8
+#    define LSOF_FNM_INODE "inode number"
+
+#    define LSOF_FID_NLINK 'k'
+#    define LSOF_FIX_NLINK 9
+#    define LSOF_FNM_NLINK "link count"
+
+#    define LSOF_FID_TID 'K'
+#    define LSOF_FIX_TID 10
+#    define LSOF_FNM_TID "task ID (TID)"
+
+#    define LSOF_FID_LOCK 'l'
+#    define LSOF_FIX_LOCK 11
+#    define LSOF_FNM_LOCK "lock: r/R = read; w/W = write; u = read/write"
+
+#    define LSOF_FID_LOGIN 'L'
+#    define LSOF_FIX_LOGIN 12
+#    define LSOF_FNM_LOGIN "login name"
+
+#    define LSOF_FID_MARK 'm'
+#    define LSOF_FIX_MARK 13
+#    define LSOF_FNM_MARK "marker between repeated output"
+
+#    define LSOF_FID_TCMD 'M'
+#    define LSOF_FIX_TCMD 14
+#    define LSOF_FNM_TCMD "task comMand name"
+
+#    define LSOF_FID_NAME 'n'
+#    define LSOF_FIX_NAME 15
+#    define LSOF_FNM_NAME "comment, name, Internet addresses"
+
+#    define LSOF_FID_NI 'N'
+#    define LSOF_FIX_NI 16
+#    define LSOF_FNM_NI "file struct node ID as 0x<hex>"
+
+#    define LSOF_FID_OFFSET 'o'
+#    define LSOF_FIX_OFFSET 17
+#    define LSOF_FNM_OFFSET "file offset as 0t<dec> or 0x<hex>"
+
+#    define LSOF_FID_PID 'p'
+#    define LSOF_FIX_PID 18
+#    define LSOF_FNM_PID "process ID (PID)"
+
+#    define LSOF_FID_PGID 'g'
+#    define LSOF_FIX_PGID 19
+#    define LSOF_FNM_PGID "process group ID (PGID)"
+
+#    define LSOF_FID_PROTO 'P'
+#    define LSOF_FIX_PROTO 20
+#    define LSOF_FNM_PROTO "protocol name"
+
+#    define LSOF_FID_RDEV 'r'
+#    define LSOF_FIX_RDEV 21
+#    define LSOF_FNM_RDEV "raw device number as 0x<hex>"
+
+#    define LSOF_FID_PPID 'R'
+#    define LSOF_FIX_PPID 22
+#    define LSOF_FNM_PPID "paRent PID"
+
+#    define LSOF_FID_SIZE 's'
+#    define LSOF_FIX_SIZE 23
+#    define LSOF_FNM_SIZE "file size"
+
+#    define LSOF_FID_STREAM 'S'
+#    define LSOF_FIX_STREAM 24
+#    define LSOF_FNM_STREAM "stream module and device names"
+
+#    define LSOF_FID_TYPE 't'
+#    define LSOF_FIX_TYPE 25
+#    define LSOF_FNM_TYPE "file type"
+
+#    define LSOF_FID_TCPTPI 'T'
+#    define LSOF_FIX_TCPTPI 26
+#    define LSOF_FNM_TCPTPI "TCP/TPI info"
+
+#    define LSOF_FID_UID 'u'
+#    define LSOF_FIX_UID 27
+#    define LSOF_FNM_UID "user ID (UID)"
+
+#    define LSOF_FID_ZONE 'z'
+#    define LSOF_FIX_ZONE 28
+#    define LSOF_FNM_ZONE "zone name"
+
+#    define LSOF_FID_CNTX 'Z'
+#    define LSOF_FIX_CNTX 29
+#    define LSOF_FNM_CNTX "security context"
+
+#    define LSOF_FID_TERM '0'
+#    define LSOF_FIX_TERM 30
+#    define LSOF_FNM_TERM "(zero) use NUL field terminator instead of NL"
+
+#endif /* !defined(LSOF_FORMAT_H) */
diff --git a/lib/Makefile.skel b/lib/Makefile.skel
new file mode 100644 (file)
index 0000000..58c0d55
--- /dev/null
@@ -0,0 +1,60 @@
+# Lsof library Makefile skeleton
+#
+# This skeleton is added to definitions established by Configure.
+#
+# $Id: Makefile.skel,v 1.13 2001/02/13 02:12:16 abe Exp $
+
+LIB=   liblsof.a
+
+CDEF=  ${RC_CFLAGS}
+CDEFS= ${CDEF} ${CFGF}
+INCL=  ${DINC} -I.. -I../include -Idialects/${DIALECT_DIR}
+
+HDR=   common.h proto.h proto.h
+
+SRC=   ckkv.c cvfs.c dvch.c fino.c isfn.c lkud.c lsof.c misc.c node.c pdvn.c prfp.c \
+       print.c proc.c ptti.c rdev.c rmnt.c rnam.c rnch.c rnmh.c rnmt.c
+
+OBJ=   ckkv.o cvfs.o dvch.o fino.o isfn.o lkud.o lsof.o misc.o node.o pdvn.o prfp.o \
+       print.o proc.o ptti.o rdev.o rmnt.o rnam.o rnch.o rnmh.o rnmt.o
+
+all:   ${LIB}
+
+${LIB}:        ${OBJ}
+       ${AR}
+       ${RANLIB}
+
+clean: FRC
+       rm -f ${LIB} ${OBJ} errs Makefile.bak a.out core
+
+FRC:
+
+ckkv.o: ${HDR} ckkv.c
+
+cvfs.o: ${HDR} cvfs.c
+
+dvch.o: ${HDR} dvch.c
+
+fino.o: ${HDR} fino.c
+
+isfn.o: ${HDR} isfn.c
+
+lkud.o: ${HDR} lkud.c
+
+pdvn.o: ${HDR} pdvn.c
+
+prfp.o: ${HDR} prfp.c
+
+ptti.o:        ${HDR} ptti.c
+
+rdev.o: ${HDR} rdev.c
+
+rmnt.o: ${HDR} rmnt.c
+
+rnam.o: ${HDR} rnam.c
+
+rnch.o: ${HDR} rnch.c
+
+rnmh.o: ${HDR} rnmh.c
+
+rnmt.o: ${HDR} rnmt.c
diff --git a/lib/ckkv.c b/lib/ckkv.c
new file mode 100644 (file)
index 0000000..4526048
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * cvfs.c -- ckkv() function for lsof library
+ */
+
+/*
+ * Copyright 1998 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.
+ */
+
+#include "common.h"
+#include "machine.h"
+
+#if defined(USE_LIB_CKKV)
+
+#    include <sys/utsname.h>
+
+/*
+ * ckkv() - check kernel version
+ */
+
+void ckkv(struct lsof_context *ctx, /* context */
+          char *d,                  /* dialect */
+          char *er,                 /* expected revision; NULL, no test */
+          char *ev,                 /* expected version; NULL, no test */
+          char *ea)                 /* expected architecture; NULL, no test */
+{
+
+#    if defined(HASKERNIDCK)
+    struct utsname u;
+
+    if (Fwarn)
+        return;
+    /*
+     * Read the system information via uname(2).
+     */
+    if (uname(&u) < 0) {
+        (void)fprintf(stderr, "%s: uname error: %s\n", Pn, strerror(errno));
+        Error(ctx);
+    }
+    if (er && strcmp(er, u.release)) {
+        (void)fprintf(stderr,
+                      "%s: WARNING: compiled for %s release %s; this is %s.\n",
+                      Pn, d, er, u.release);
+    }
+    if (ev && strcmp(ev, u.version)) {
+        (void)fprintf(stderr,
+                      "%s: WARNING: compiled for %s version %s; this is %s.\n",
+                      Pn, d, ev, u.version);
+    }
+    if (ea && strcmp(ea, u.machine)) {
+        (void)fprintf(
+            stderr,
+            "%s: WARNING: compiled for %s architecture %s; this is %s.\n", Pn,
+            d, ea, u.machine);
+    }
+#    endif /* defined(HASKERNIDCK) */
+}
+#else  /* !defined(USE_LIB_CKKV) */
+char ckkv_d1[] = "d";
+char *ckkv_d2 = ckkv_d1;
+#endif /* defined(USE_LIB_CKKV) */
diff --git a/lib/common.h b/lib/common.h
new file mode 100644 (file)
index 0000000..6014510
--- /dev/null
@@ -0,0 +1,1543 @@
+/*
+ * common.h - common header file for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+/*
+ * $Id: common.h,v 1.70 2018/03/26 21:50:45 abe Exp $
+ */
+
+#if !defined(COMMON_H)
+#    define COMMON_H 1
+
+#    include "lsof.h"
+#    if defined(AUTOTOOLS)
+#        include "autotools.h"
+#    endif
+#    include "machine.h"
+
+#    if !defined(FSV_DEFAULT)
+#        define FSV_DEFAULT 0
+#    endif /* !defined(FSV_DEFAULT) */
+
+#    include "lsof_fields.h"
+
+#    include <ctype.h>
+#    include <errno.h>
+
+#    if defined(HASSETLOCALE)
+#        include <locale.h>
+#    endif /* defined(HASSETLOCALE) */
+
+#    include <netdb.h>
+#    include <pwd.h>
+#    include <stdio.h>
+
+#    include <sys/stat.h>
+#    include <sys/wait.h>
+
+/*
+ * Definitions and structures that may be needed by dlsof.h
+ */
+
+#    if !defined(INODETYPE)
+#        define INODETYPE unsigned long /* node number storage type */
+#        define INODEPSPEC                                                     \
+            "l" /* node number printf specification                            \
+                 * modifier */
+#    endif      /* !defined(INODETYPE) */
+
+struct l_dev {
+    dev_t rdev;      /* device */
+    INODETYPE inode; /* inode number */
+    char *name;      /* name */
+    int v;           /* has been verified
+                      * (when DCUnsafe == 1) */
+};
+
+#    if defined(HASEPTOPTS)
+/*
+ * End point definitions
+ */
+
+#        define CHEND_PIPE 0x01 /* pipe endpoint ID */
+#        define CHEND_PTY 0x02  /* pseudoterminal endpoint ID */
+
+#        if defined(HASUXSOCKEPT)
+#            define CHEND_UXS 0x04 /* UNIX socket endpoint ID */
+#        endif                     /* defined(HASUXSOCKEPT) */
+
+#        define CHEND_NETS 0x08  /* INET socket endpoint ID */
+#        define CHEND_PSXMQ 0x10 /* Posix MQ endpoint ID */
+
+#        if defined(HASIPv6)
+#            define CHEND_NETS6 0x20 /* INET6 socket endpoint ID */
+#        endif                       /* defined(HASIPv6) */
+
+#        define CHEND_EVTFD 0x40 /* eventfd endpoint ID */
+
+#        define EPT_PIPE 0x01     /* process has pipe file */
+#        define EPT_PIPE_END 0x02 /* process has pipe end point file */
+#        define EPT_PTY 0x04      /* process has a pseudoterminal file */
+#        define EPT_PTY_END                                                    \
+            0x08 /* process has a pseudoterminal end                           \
+                  * point file */
+
+#        if defined(HASUXSOCKEPT)
+#            define EPT_UXS 0x10 /* process has a UNIX socket file */
+#            define EPT_UXS_END                                                \
+                0x20 /* process has a UNIX socket end point                    \
+                      * file */
+#        endif       /* defined(HASUXSOCKEPT) */
+
+#        define EPT_NETS 0x40 /* process has a INET socket file */
+#        define EPT_NETS_END                                                   \
+            0x80 /* process has a INET socket end point                        \
+                  * file */
+
+#        define EPT_PSXMQ 0x100 /* process has a POSIX MQ file*/
+#        define EPT_PSXMQ_END                                                  \
+            0x200 /* process has a POSIX MQ end point                          \
+                   * file*/
+
+#        if defined(HASIPv6)
+#            define EPT_NETS6 0x400 /* process has a INET6 socket file */
+#            define EPT_NETS6_END                                              \
+                0x800 /* process has a INET6 socket end point                  \
+                       * file */
+#        endif        /* defined(HASIPv6) */
+
+#        define EPT_EVTFD 0x1000 /* process has a eventfd file*/
+#        define EPT_EVTFD_END                                                  \
+            0x2000 /* process has a eventfd end point                          \
+                    * file*/
+#    endif         /* defined(HASEPTOPTS) */
+
+/*
+ * FILE_FLAG column names
+ */
+
+#    define FF_AIO "AIO"
+#    define FF_APPEND "AP"
+#    define FF_ASYNC "ASYN"
+#    define FF_BLKANDSET "BAS"
+#    define FF_BLKINUSE "BKIU"
+#    define FF_BLKSEEK "BSK"
+#    define FF_CIO "CIO"
+#    define FF_CLONE "CLON"
+#    define FF_CLREAD "CLRD"
+#    define FF_COPYAVOID "CA"
+#    define FF_CREAT "CR"
+#    define FF_DATAFLUSH "DFLU"
+#    define FF_DEFER "DF"
+#    define FF_DEFERIND "DFI"
+#    define FF_DELAY "DLY"
+#    define FF_DIRECT "DIR"
+#    define FF_DIRECTORY "DTY"
+#    define FF_DOCLONE "DOCL"
+#    define FF_DSYNC "DSYN"
+#    define FF_EVTONLY "EVO"
+#    define FF_EXCL "EXCL"
+#    define FF_EXEC "EX"
+#    define FF_EXLOCK "XL"
+#    define FF_FILE_MBLK "MBLK"
+#    define FF_FSYNC "FSYN"
+#    define FF_GCFDEFER "GCDF"
+#    define FF_GCFMARK "GCMK"
+#    define FF_GENTTY "GTTY"
+#    define FF_HASLOCK "LCK"
+#    define FF_HUP "HUP"
+#    define FF_KERNEL "KERN"
+#    define FF_KIOCTL "KIOC"
+#    define FF_LARGEFILE "LG"
+#    define FF_MARK "MK"
+#    define FF_MOUNT "MNT"
+#    define FF_MSYNC "MSYN"
+#    define FF_NBDRM "NBDR"
+#    define FF_NBIO "NBIO"
+#    define FF_NBLOCK "NB"
+#    define FF_NBUF "NBF"
+#    define FF_NMFS "NMFS"
+#    define FF_NDELAY "ND"
+#    define FF_NET "NET"
+#    define FF_NOATM "NATM"
+#    define FF_NOCACHE "NC"
+#    define FF_NOCTTY "NTTY"
+#    define FF_NODSYNC "NDSY"
+#    define FF_NOFOLNK "NFLK"
+#    define FF_NOTOSTOP "NOTO"
+#    define FF_NSHARE "NSH"
+#    define FF_OLRMIRROR "OLRM"
+#    define FF_PATH "PATH"
+#    define FF_POSIX_AIO "PAIO"
+#    define FF_POSIX_PIPE "PP"
+#    define FF_RAIOSIG "RAIO"
+#    define FF_RCACH "RC"
+#    define FF_RDWR "RW"
+#    define FF_READ "R"
+#    define FF_REVOKED "REV"
+#    define FF_RSHARE "RSH"
+#    define FF_RSYNC "RSYN"
+#    define FF_SETBLK "BL"
+#    define FF_SHLOCK "SL"
+#    define FF_SNAP "SNAP"
+#    define FF_SOCKET "SOCK"
+#    define FF_SQTSH1 "SQS1"
+#    define FF_SQTSH2 "SQS2"
+#    define FF_SQTREPAIR "SQR"
+#    define FF_SQTSH "SQSH"
+#    define FF_SQTSVM "SQSV"
+#    define FF_STOPIO "STPI"
+#    define FF_SYNC "SYN"
+#    define FF_SYNCRON "SWR"
+#    define FF_TCP_MDEVONLY "TCPM"
+#    define FF_TERMIO "TIO"
+#    define FF_TMPFILE "TMPF"
+#    define FF_TRUNC "TR"
+#    define FF_VHANGUP "VH"
+#    define FF_VTEXT "VTXT"
+#    define FF_WAKEUP "WKUP"
+#    define FF_WAITING "WTG"
+#    define FF_WRITE "W"
+
+/*
+ * Process open file flag names
+ */
+
+#    define POF_ALLOCATED "ALLC"
+#    define POF_BNRD "BR"
+#    define POF_BNWR "BW"
+#    define POF_BNHUP "BHUP"
+#    define POF_CLOEXEC "CX"
+#    define POF_CLOSING "CLSG"
+#    define POF_FDLOCK "LCK"
+#    define POF_INUSE "USE"
+#    define POF_MAPPED "MP"
+#    define POF_FSHMAT "SHMT"
+#    define POF_RESERVED "OPIP"
+#    define POF_RSVWT "RSVW"
+
+/*
+ * Cross-over (-x) option values
+ */
+
+#    define XO_FILESYS 0x1 /* file system mount points */
+#    define XO_SYMLINK 0x2 /* symbolic links */
+#    define XO_ALL (XO_FILESYS | XO_SYMLINK)
+
+#    include "dlsof.h"
+
+#    include <sys/types.h> /* just in case -- because utmp.h
+                            * may need it */
+#    include <regex.h>
+
+#    if defined(EMPTY)
+#        undef EMPTY
+#    endif /* defined(EMPTY) */
+
+#    if defined(HASUTMPX)
+#        include <utmpx.h>
+#    else /* !defined(HASUTMPX) */
+#        include <utmp.h>
+#    endif /* defined(HASUTMPX) */
+
+extern int errno;
+extern char *optarg;
+extern int optind;
+
+#    define ACCESSERRFMT "%s: WARNING: access %s: %s\n"
+
+#    if defined(HASDCACHE)
+#        define CRC_POLY 0120001 /* CRC-16 polynomial */
+#        define CRC_TBLL 256     /* crc table length for software */
+#        define CRC_BITS 8       /* number of bits contributing */
+#    endif                       /* defined(HASDCACHE) */
+#    define CMDL                                                               \
+        9              /* maximum number of characters from                    \
+                        * command name to print in COMMAND                     \
+                        * column */
+#    define CWD " cwd" /* current working directory fd name */
+#    define FDLEN 8    /* fd printing array length */
+#    define FSV_FA 0x1 /* file struct addr status */
+#    define FSV_CT 0x2 /* file struct count status */
+#    define FSV_FG 0x4 /* file struct flags */
+#    define FSV_NI 0x8 /* file struct node ID status */
+
+#    if !defined(GET_MAJ_DEV)
+#        define GET_MAJ_DEV                                                    \
+            major /* if no dialect specific macro has                          \
+                   * been defined, use standard major()                        \
+                   * macro */
+#    endif        /* !defined(GET_MAJ_DEV) */
+
+#    if !defined(GET_MIN_DEV)
+#        define GET_MIN_DEV                                                    \
+            minor /* if no dialect specific macro has                          \
+                   * been defined, use standard minor()                        \
+                   * macro */
+#    endif        /* !defined(GET_MIN_DEV) */
+
+#    if defined(HASSELINUX)
+#        define HASHCNTX                                                       \
+            128 /* security context hash bucket count                          \
+                 * -- MUST BE A POWER OF 2!!! */
+#    endif      /* defined(HASSELINUX) */
+
+#    if defined(HASZONES)
+#        define HASHZONE                                                       \
+            128 /* zone hash bucket count -- MUST BE                           \
+                 * A POWER OF 2!!! */
+#    endif      /* defined(HASZONES) */
+
+#    define IDINCR 10 /* PID/PGID table malloc() increment */
+
+#    if !defined(INADDR_LOOPBACK)
+#        define INADDR_LOOPBACK (u_long)0x7f000001
+#    endif /* !defined(INADDR_LOOPBACK) */
+
+#    define IPROTOL 8 /* Internet protocol length */
+
+#    if !defined(KA_T_FMT_X)
+#        define KA_T_FMT_X                                                     \
+            "0x%08lx" /* format for printing kernel                            \
+                       * addresses in 0x... format */
+#    endif            /* !defined(KA_T_FMT_X) */
+
+#    if !defined(LOGINML)
+#        if defined(HASUTMPX)
+#            define LOGINML sizeof(((struct utmpx *)0)->ut_user)
+/* login name length */
+#        else /* !defined(HASUTMPX) */
+#            define LOGINML sizeof(((struct utmp *)0)->ut_name)
+/* login name length */
+#        endif /* defined(HASUTMPX) */
+#    endif     /* !defined(LOGINML) */
+
+#    define LPROCINCR 128 /* Lproc[] allocation increment */
+#    define LSOF_GITHUB_URL "https://github.com/lsof-org"
+#    define LSOF_REPO "lsof"
+#    define LSOF_BRANCH "master"
+#    define LSOF_REPO_URL LSOF_GITHUB_URL "/" LSOF_REPO
+#    define LSOF_FAQ_URL LSOF_REPO_URL "/blob/" LSOF_BRANCH "/00FAQ"
+#    define LSOF_MAN_URL LSOF_REPO_URL "/blob/" LSOF_BRANCH "/Lsof.8"
+#    define MIN_AF_ADDR sizeof(struct in_addr)
+/* minimum AF_* address length */
+
+#    if defined(HASIPv6)
+#        define MAX_AF_ADDR sizeof(struct in6_addr)
+/* maximum AF_* address length */
+#    else                               /* !defined(HASIPv6) */
+#        define MAX_AF_ADDR MIN_AF_ADDR /* maximum AF_* address length */
+#    endif                              /* defined(HASIPv6) */
+
+#    define MAXDCPATH 4 /* paths in DCpath[] */
+#    define MAXNWAD 100 /* maximum network addresses */
+
+#    if !defined(MEMMOVE)
+#        define MEMMOVE memmove
+#    endif /* !defined*MEMMOVE) */
+
+#    define N_REGLR 0      /* regular file system node */
+#    define N_AFS 1        /* AFS node */
+#    define N_AFPFS 2      /* Apple Darwin AppleShare */
+#    define N_ANON_INODE 3 /* Linux anon_inodefs node */
+#    define N_AUSX 4       /* Auspex LFS node */
+#    define N_AUTO 5       /* automount node */
+#    define N_BLK 6        /* block device node */
+#    define N_CACHE 7      /* cached file system node */
+#    define N_CDFS 8       /* CD-ROM node */
+#    define N_CFS 9        /* CFS node */
+#    define N_CHR 10       /* character device node */
+#    define N_COM 11       /* streams common device node */
+#    define N_CTFSADIR 12  /* Solaris CTFS adir node */
+#    define N_CTFSBUND 13  /* Solaris CTFS bundle node */
+#    define N_CTFSCDIR 14  /* Solaris CTFS cdir node */
+#    define N_CTFSCTL 15   /* Solaris CTFS ctl node */
+#    define N_CTFSEVT 16   /* Solaris CTFS events node */
+#    define N_CTFSLATE 17  /* Solaris CTFS latest node */
+#    define N_CTFSROOT 18  /* Solaris CTFS root node */
+#    define N_CTFSSTAT 19  /* Solaris CTFS status node */
+#    define N_CTFSSYM 20   /* Solaris CTFS symbolic node */
+#    define N_CTFSTDIR 21  /* Solaris CTFS type node */
+#    define N_CTFSTMPL 22  /* Solaris CTFS template node */
+#    define N_DEV 23       /* DEV FS node */
+#    define N_DOOR 24      /* DOOR node */
+#    define N_FD 25        /* FD node */
+#    define N_FIFO 26      /* FIFO node */
+#    define N_HSFS 27      /* High Sierra node */
+#    define N_KERN 28      /* BSD /kern node */
+#    define N_LOFS 29      /* loopback node */
+#    define N_MNT 30       /* mount file system device node */
+#    define N_MPC 31       /* multiplexed device node */
+#    define N_MVFS 32      /* multi-volume file system node (?) */
+#    define N_NFS 33       /* NFS node */
+#    define N_NFS4 34      /* NFS version 4 node */
+#    define N_NM 35        /* named file system node */
+#    define N_OBJF 36      /* objfs file system node */
+#    define N_PCFS 37      /* PC file system node */
+#    define N_PIPE 38      /* pipe device node */
+#    define N_PORT 39      /* port node */
+#    define N_PROC 40      /* /proc node */
+#    define N_PSEU 41      /* pseudofs node */
+#    define N_SAMFS 42     /* Solaris SAM-FS */
+#    define N_SANFS 43     /* AIX SANFS */
+#    define N_SDEV 44      /* Solaris sdev file system node */
+#    define N_SHARED 45    /* Solaris sharedfs */
+#    define N_SOCK 46      /* sock_vnodeops node */
+#    define N_SPEC 47      /* spec_vnodeops node */
+#    define N_STREAM 48    /* stream node */
+#    define N_TMP 49       /* tmpfs node */
+#    define N_UFS 50       /* UNIX file system node */
+#    define N_UNKN 51      /* unknown node type */
+#    define N_VXFS 52      /* Veritas file system node */
+#    define N_XFS 53       /* XFS node */
+#    define N_ZFS 54       /* ZFS node */
+#    define N_MQUEUE 55    /* Posix mqueue node on Linux */
+
+#    if !defined(OFFDECDIG)
+#        define OFFDECDIG                                                      \
+            8 /* maximum number of digits in the                               \
+               * offset decimal form (0t...) */
+#    endif    /* !defined(OFFDECDIG) */
+
+#    if !defined(USELOCALREADDIR)
+#        define CloseDir closedir /* use standard closedir() */
+#        define OpenDir opendir   /* use standard opendir() */
+#        define ReadDir readdir   /* use standard readdir() */
+#    endif                        /* !defined(USELOCALREADDIR) */
+
+#    define RPTTM 15   /* default repeat seconds */
+#    define RTD " rtd" /* root directory fd name */
+#    define TASKCMDL                                                           \
+        9 /* maximum number of characters from                                 \
+           * command name to print in TASKCMD                                  \
+           * column */
+#    define TCPTPI_FLAGS                                                       \
+        0x0001                    /* report TCP/TPI socket options and         \
+                                   * state, and TCP_NODELAY state */
+#    define TCPTPI_QUEUES 0x0002  /* report TCP/TPI queue lengths */
+#    define TCPTPI_STATE 0x0004   /* report TCP/TPI state */
+#    define TCPTPI_WINDOWS 0x0008 /* report TCP/TPI window sizes */
+#    define TCPTPI_ALL (TCPTPI_QUEUES | TCPTPI_STATE | TCPTPI_WINDOWS)
+/* report all TCP/TPI info */
+#    define TCPUDPALLOC                                                        \
+        32                 /* allocation amount for TCP and UDP                \
+                            * state tables */
+#    define TMLIMIT 15     /* readlink() & stat() timeout sec */
+#    define TMLIMMIN 2     /* minimum timeout */
+#    define TYPEL 8        /* type character length */
+#    define UIDCACHEL 1024 /* UID cache length */
+#    define UIDINCR 10     /* UID table malloc() increment */
+#    define USERPRTL 8     /* UID/login print length limit */
+
+#    if !defined(SZOFFTYPE)
+#        define SZOFFTYPE unsigned long /* type for size and offset */
+#        undef SZOFFPSPEC
+#        define SZOFFPSPEC                                                     \
+            "l" /* SZOFFTYPE printf specification                              \
+                 * modifier */
+#    endif      /* !defined(SZOFFTYPE) */
+
+#    if !defined(TIMEVAL_LSOF)
+#        define TIMEVAL_LSOF timeval
+#    endif /* !defined(TIMEVAL_LSOF) */
+
+#    if !defined(XDR_PMAPLIST)
+#        define XDR_PMAPLIST xdr_pmaplist
+#    endif /* !defined(XDR_PMAPLIST) */
+
+#    if !defined(XDR_VOID)
+#        define XDR_VOID xdr_void
+#    endif /* !defined(XDR_VOID) */
+
+/*
+ * Output title definitions
+ */
+
+#    define CMDTTL "COMMAND"
+extern int CmdColW;
+#    define CNTXTTL "SECURITY-CONTEXT"
+extern int CntxColW;
+#    define DEVTTL "DEVICE"
+extern int DevColW;
+#    define FCTTL "FCT"
+extern int FcColW;
+#    define FDTTL "FD"
+extern int FdColW;
+#    define FGTTL "FILE-FLAG"
+extern int FgColW;
+#    define FSTTL "FILE-ADDR"
+extern int FsColW;
+#    define NITTL "NODE-ID"
+extern int NiColW;
+extern char *NiTtl;
+#    define NLTTL "NLINK"
+extern int NlColW;
+#    define NMTTL "NAME"
+extern int NmColW;
+#    define NODETTL "NODE"
+extern int NodeColW;
+#    define OFFTTL "OFFSET"
+#    define PGIDTTL "PGID"
+extern int PgidColW;
+#    define PIDTTL "PID"
+extern int PidColW;
+#    define PPIDTTL "PPID"
+extern int PpidColW;
+#    define SZTTL "SIZE"
+#    define SZOFFTTL "SIZE/OFF"
+extern int SzOffColW;
+#    define TASKCMDTTL "TASKCMD"
+extern int TaskCmdColW;
+#    define TASKTIDTTL "TID"
+extern int TaskTidColW;
+#    define TYPETTL "TYPE"
+extern int TypeColW;
+#    define USERTTL "USER"
+extern int UserColW;
+#    define ZONETTL "ZONE"
+extern int ZoneColW;
+
+/*
+ * Selection flags
+ */
+
+#    define PS_PRI                                                             \
+        1 /* primary process selection -- e.g.,                                \
+           * by PID or UID */
+#    define PS_SEC                                                             \
+        2                   /* secondary process selection -- e.g.,            \
+                             * by directory or file */
+#    define SELCMD 0x0001   /* select process by command name */
+#    define SELCNTX 0x0002  /* select security context (-Z) */
+#    define SELFD 0x0004    /* select file by descriptor name */
+#    define SELNA 0x0008    /* select socket by address (-i@...) */
+#    define SELNET 0x0010   /* select Internet socket files (-i) */
+#    define SELNFS 0x0020   /* select NFS files (-N) */
+#    define SELNLINK 0x0040 /* select based on link count */
+#    define SELNM 0x0080    /* select by name */
+#    define SELPGID 0x0100  /* select process group IDs (-g) */
+#    define SELPID 0x0200   /* select PIDs (-p) */
+#    define SELUID 0x0400   /* select UIDs (-u) */
+#    define SELUNX 0x0800   /* select UNIX socket (-U) */
+#    define SELZONE 0x1000  /* select zone (-z) */
+#    define SELEXCLF 0x2000 /* file selection excluded */
+#    define SELTASK 0x4000  /* select tasks (-K) */
+#    define SELPINFO                                                           \
+        0x8000 /* selected for pipe info (cleared in                           \
+                * link_lfile() */
+#    define SELUXSINFO                                                         \
+        0x10000 /* selected for UNIX socket info;                              \
+                 * cleared in link_lfile() */
+#    define SELPTYINFO                                                         \
+        0x20000 /* selected for pseudoterminal info;                           \
+                 * cleared in link_lfile() */
+#    define SELNETSINFO                                                        \
+        0x40000 /* selected for INET socket info;                              \
+                 * cleared in link_lfile() */
+#    define SELPSXMQINFO                                                       \
+        0x80000 /* selected for POSIX MQ socket info;                          \
+    cleared in link_lfile() */
+#    define SELNETS6INFO                                                       \
+        0x100000 /* selected for INET6 socket info;                            \
+                  * cleared in link_lfile() */
+#    define SELEVTFDINFO                                                       \
+        0x200000 /* selected for evetnfd info;                                 \
+                  * cleared in link_lfile() */
+
+#    define SELALL                                                             \
+        (SELCMD | SELCNTX | SELFD | SELNA | SELNET | SELNM | SELNFS | SELPID | \
+         SELUID | SELUNX | SELZONE | SELTASK)
+#    define SELPROC                                                            \
+        (SELCMD | SELCNTX | SELPGID | SELPID | SELUID | SELZONE | SELTASK)
+/* process selecters */
+#    define SELFILE (SELFD | SELNFS | SELNLINK | SELNM) /* file selecters */
+#    define SELNW (SELNA | SELNET | SELUNX)             /* network selecters */
+
+/*
+ * Exit Status
+ */
+
+enum ExitStatus {
+    LSOF_EXIT_SUCCESS,
+    LSOF_EXIT_ERROR,
+};
+#    define LSOF_SEARCH_FAILURE                                                \
+        (FsearchErr ? LSOF_EXIT_ERROR : LSOF_EXIT_SUCCESS)
+
+/*
+ * Structure definitions
+ */
+
+#    if defined(HAS_AFS)
+struct afsnode { /* AFS pseudo-node structure */
+    dev_t dev;
+    unsigned char ino_st;   /* 1 if inode has a value */
+    unsigned char nlink_st; /* 1 if nlink has a value */
+    INODETYPE inode;
+    unsigned long size;
+    long nlink;
+};
+#    endif /* defined(HAS_AFS) */
+
+#    if defined(HAS_STD_CLONE)
+struct clone {
+    int dx;             /* index of device entry in Devtp[] */
+    struct clone *next; /* forward link */
+};
+extern struct clone *Clone;
+#    endif /* defined(HAS_STD_CLONE) */
+
+#    if defined(HASNLIST)
+struct drive_Nl { /* data to drive build_Nl() */
+    char *nn;     /* nickname for lookups */
+    char *knm;    /* kernel variable for name list */
+};
+extern struct drive_Nl Drive_Nl[]; /* defined in dstore.c */
+#    endif                         /* defined(HASNLIST) */
+
+/*
+ * Global storage definitions (including their structure definitions)
+ */
+
+typedef struct efsys_list {
+    char *path;              /* path to file system for which kernel
+                              * blocks are to be eliminated */
+    int pathl;               /* path length */
+    int rdlnk;               /* avoid readlink(2) if non-zero */
+    struct mounts *mp;       /* local mount table entry pointer */
+    struct efsys_list *next; /* next efsys_list entry pointer */
+} efsys_list_t;
+
+struct int_lst {
+    int i; /* integer argument */
+    int f; /* find state -- meaningful only if
+            * x == 0 */
+    int x; /* excluded state */
+};
+
+typedef struct lsof_rx { /* regular expression table entry */
+    char *exp;           /* original regular expression */
+    regex_t cx;          /* compiled expression */
+    int mc;              /* match count */
+} lsof_rx_t;
+
+#    if defined(HASFSTRUCT)
+struct pff_tab { /* print file flags table structure */
+    long val;    /* flag value */
+    char *nm;    /* name to print for flag */
+};
+#    endif /* defined(HASFSTRUCT) */
+
+struct seluid {
+    uid_t uid;          /* User ID */
+    char *lnm;          /* specified login name (NULL = none) */
+    unsigned char excl; /* excluded state */
+    unsigned char f;    /* selected User ID find state
+                         * (meaningful only if excl == 0) */
+};
+
+extern int CkPasswd;
+
+struct str_lst {
+    char *str;            /* string */
+    int len;              /* string length */
+    short f;              /* selected string find state */
+    short x;              /* exclusion (if non-zero) */
+    struct str_lst *next; /* next list entry */
+};
+
+typedef struct cntxlist {
+    char *cntx;            /* zone name */
+    int f;                 /* "find" flag (used only in CntxArg) */
+    struct cntxlist *next; /* next zone hash entry */
+} cntxlist_t;
+extern int CntxStatus;
+
+extern int DChelp;
+extern int ErrStat;
+extern uid_t Euid;
+extern int Fcntx;
+extern int Ffield;
+extern int Ffilesys;
+extern int Fhelp;
+extern int Fhost;
+
+#    if defined(HASNCACHE)
+extern int NcacheReload;
+#    endif /* defined(HASNCACHE) */
+
+extern int Fnlink;
+extern int Fport;
+
+#    if !defined(HASNORPC_H)
+extern int FportMap;
+#    endif /* !defined(HASNORPC_H) */
+
+extern int Fpgid;
+extern int Fppid;
+extern int FsearchErr;
+extern int Fhuman;
+extern int Fsv;
+extern int Ftcptpi;
+extern int Fterse;
+extern int Funix;
+extern int Futol;
+extern int Fverbose;
+
+extern int Fxover;
+extern int Fzone;
+
+struct fd_lst {
+    enum lsof_fd_type fd_type; /* file descriptor type;
+                                * range if LSOF_FD_NUMERIC */
+    int lo;                    /* range start (if nm NULL) */
+    int hi;                    /* range end (if nm NULL) */
+    struct fd_lst *next;
+};
+
+struct fieldsel {
+    char id;          /* field ID character */
+    unsigned char st; /* field status */
+    char *nm;         /* field name */
+    int *opt;         /* option variable address */
+    int ov;           /* value to OR with option variable */
+};
+extern struct fieldsel FieldSel[];
+
+extern int Hdr;
+
+enum IDType { PGID, PID };
+extern char *InodeFmt_d;
+extern char *InodeFmt_x;
+extern int LastPid;
+
+struct lfile {
+    enum lsof_file_access_mode access;
+    enum lsof_lock_mode lock;
+    unsigned char dev_def;   /* device number definition status */
+    unsigned char inp_ty;    /* inode/iproto type
+                              * 0: neither inode nor iproto
+                              * 1: print inode in decimal
+                              * 2: iproto contains string
+                              * 3: print inode in hex
+                              */
+    unsigned char is_com;    /* common stream status */
+    unsigned char is_nfs;    /* NFS file status */
+    unsigned char is_stream; /* stream device status */
+
+#    if defined(HASVXFS) && defined(HASVXFSDNLC)
+    unsigned char is_vxfs; /* VxFS file status */
+#    endif                 /* defined(HASVXFS) && defined(HASVXFSDNLC) */
+
+    unsigned char lmi_srch; /* local mount info search status:
+                             * 1 = printname() search required */
+
+#    if defined(HASMNTSTAT)
+    unsigned char mnt_stat; /* mount point stat(2) status */
+#    endif                  /* defined(HASMNTSTAT) */
+
+    unsigned char nlink_def; /* link count definition status */
+    unsigned char off_def;   /* offset definition status */
+
+#    if defined(HASEPTOPTS)
+    unsigned char chend; /* communication channel endpoint
+                          * file */
+    int eventfd_id;      /* evntfd id taken from
+                    /proc/$pid/fdinfo */
+#        if defined(HASPTYEPT)
+    int tty_index; /* pseudoterminal index of slave side
+                    * (if this is the master side) */
+#        endif     /* defined(HASPTYEPT) */
+#    endif         /* defined(HASEPTOPTS) */
+
+    unsigned char rdev_def; /* rdev definition status */
+    unsigned char sz_def;   /* size definition status */
+
+#    if defined(HASFSTRUCT)
+    unsigned char fsv; /* file struct value status */
+#    endif             /* defined(HASFSTRUCT) */
+
+    /* FD column */
+    enum lsof_fd_type fd_type;
+    int fd_num; /* stores fd number when fd_type is LSOF_FD_NUMERIC,
+                   stores raw number when fd_type is one of
+                   {LSOF_FD_LIBRARY_REF, LSOF_FD_MMAP_UNKNOWN,
+                   LSOF_FD_PREGION_UNKNOWN}, otherwise -1 */
+
+    char iproto[IPROTOL];
+    enum lsof_file_type type;
+    uint32_t unknown_file_type_number; /* store file type when type ==
+                                      LSOF_FILE_UNKNOWN_RAW */
+
+    unsigned int sf; /* select flags -- SEL* symbols */
+    int ch;          /* VMPC channel: -1 = none */
+    int ntype;       /* node type -- N_* value */
+    SZOFFTYPE off;
+    SZOFFTYPE sz;
+    dev_t dev;
+    dev_t rdev;
+    INODETYPE inode;
+    long nlink; /* link count */
+    char *dev_ch;
+    char *fsdir; /* file system directory */
+    char *fsdev; /* file system device */
+
+#    if defined(HASFSINO)
+    INODETYPE fs_ino; /* file system inode number */
+#    endif            /* defined HASFSINO) */
+
+    struct linaddr { /* local Internet address information */
+        int af;      /* address family: 0 for none; AF_INET;
+                      * or AF_INET6 */
+        int p;       /* port */
+        union {
+            struct in_addr a4; /* AF_INET Internet address */
+
+#    if defined(HASIPv6)
+            struct in6_addr a6; /* AF_INET6 Internet address */
+#    endif                      /* defined(HASIPv6) */
+
+        } ia;
+    } li[2];         /* li[0]: local
+                      * li[1]: foreign */
+    struct ltstate { /* local TCP/TPI state */
+        int type;    /* state type:
+                      *   -1 == none
+                      *    0 == TCP
+                      *    1 == TPI or socket (SS_*) */
+        union {
+            int i;           /* integer state */
+            unsigned int ui; /* unsigned integer state */
+        } state;
+
+#    if defined(HASSOOPT)
+        unsigned char pqlens; /* pqlen status: 0 = none */
+        unsigned char qlens;  /* qlen status:  0 = none */
+        unsigned char qlims;  /* qlim status:  0 = none */
+        unsigned char rbszs;  /* rbsz status:  0 = none */
+        unsigned char sbszs;  /* sbsz status:  0 = none */
+        int kai;              /* TCP keep-alive interval */
+        int ltm;              /* TCP linger time */
+        unsigned int opt;     /* socket options */
+        unsigned int pqlen;   /* partial connection queue length */
+        unsigned int qlen;    /* connection queue length */
+        unsigned int qlim;    /* connection queue limit */
+        unsigned long rbsz;   /* receive buffer size */
+        unsigned long sbsz;   /* send buffer size */
+#    endif                    /* defined(HASSOOPT) */
+
+#    if defined(HASSOSTATE)
+        unsigned int ss; /* socket state */
+#        if defined(HASSBSTATE)
+        unsigned int sbs_rcv; /* receive socket buffer state */
+        unsigned int sbs_snd; /* send socket buffer state */
+#        endif                /* defined(HASSBSTATE) */
+#    endif                    /* defined(HASSOSTATE) */
+
+#    if defined(HASTCPOPT)
+        unsigned int topt;  /* TCP options */
+        unsigned char msss; /* mss status: 0 = none */
+        unsigned long mss;  /* TCP maximum segment size */
+#    endif                  /* defined(HASTCPOPT) */
+
+#    if defined(HASTCPTPIQ)
+        unsigned long rq;  /* receive queue length */
+        unsigned long sq;  /* send queue length */
+        unsigned char rqs; /* rq status: 0 = none */
+        unsigned char sqs; /* sq status: 0 = none */
+#    endif                 /* defined(HASTCPTPIQ) */
+
+#    if defined(HASTCPTPIW)
+        unsigned char rws; /* rw status: 0 = none */
+        unsigned char wws; /* ww status: 0 = none */
+        unsigned long rw;  /* read window size */
+        unsigned long ww;  /* write window size */
+#    endif                 /* defined(HASTCPTPIW) */
+
+    } lts;
+    char *nm;
+    char *nma; /* NAME column addition */
+
+#    if defined(HASNCACHE) && HASNCACHE < 2
+    KA_T na; /* file structure's node address */
+#    endif   /* defined(HASNCACHE) && HASNCACHE<2 */
+
+#    if defined(HASNCACHE) && defined(HASNCVPID)
+    unsigned long id; /* capability ID */
+#    endif            /* defined(HASNCACHE) && defined(HASNCVPID) */
+
+#    if defined(HASLFILEADD)
+    HASLFILEADD
+#    endif /* defined(HASLFILEADD) */
+
+#    if defined(HASFSTRUCT)
+    KA_T fsa; /* file structure address */
+    long fct; /* file structure's f_count */
+    long ffg; /* file structure's f_flag */
+    long pof; /* process open-file flags */
+    KA_T fna; /* file structure node address */
+#    endif    /* defined(HASFSTRUCT) */
+
+    struct lfile *next;
+};
+
+struct lproc {
+    char *cmd; /* command name */
+
+#    if defined(HASSELINUX)
+    char *cntx; /* security context */
+#    endif      /* defined(HASSELINUX) */
+
+    short sf;  /* select flags -- SEL* symbols */
+    short pss; /* state: 0 = not selected
+                *        1 = wholly selected
+                *        2 = partially selected */
+#    if defined(HASEPTOPTS)
+    short ept; /* end point status -- EPT_* values */
+#    endif     /* defined(HASEPTOPTS) */
+
+    int pid; /* process ID */
+
+#    if defined(HASTASKS)
+    int tid;    /* task ID */
+    char *tcmd; /* task command name */
+#    endif      /* HASTASKS */
+
+    int pgid;  /* process group ID */
+    int ppid;  /* parent process ID */
+    uid_t uid; /* user ID */
+
+#    if defined(HASZONES)
+    char *zn; /* zone name */
+#    endif    /* defined(HASZONES) */
+
+    struct lfile *file; /* open files of process */
+};
+
+extern char *Memory;
+
+#    if defined(HASPROCFS)
+extern struct mounts *Mtprocfs;
+#    endif
+
+#    if defined(HASNLIST)
+#        if !defined(NLIST_TYPE)
+#            define NLIST_TYPE nlist
+#        endif /* !defined(NLIST_TYPE) */
+extern struct NLIST_TYPE *Nl;
+extern int Nll;
+#    endif /* defined(HASNLIST) */
+extern char *Nmlst;
+
+struct nwad {
+    char *arg;                    /* argument */
+    char *proto;                  /* protocol */
+    int af;                       /* address family -- e.g.,
+                                   * AF_INET, AF_INET6 */
+    unsigned char a[MAX_AF_ADDR]; /* address */
+    int sport;                    /* starting port */
+    int eport;                    /* ending port */
+    int f;                        /* find state */
+    struct nwad *next;            /* forward link */
+};
+extern struct nwad *Nwad;
+
+extern int OffDecDig;
+
+#    if defined(HASFSTRUCT)
+extern struct pff_tab Pff_tab[]; /* file flags table */
+extern struct pff_tab Pof_tab[]; /* process open file flags table */
+#    endif                       /* defined(HASFSTRUCT) */
+
+#    if defined(HASPROCFS)
+struct procfsid {
+    pid_t pid;       /* search PID */
+    char *nm;        /* search name */
+    unsigned char f; /* match found if == 1 */
+
+#        if defined(HASPINODEN)
+    INODETYPE inode; /* search inode number */
+#        endif       /* defined(HASPINODEN) */
+
+    struct procfsid *next; /* forward link */
+};
+
+extern int Procfind;
+extern struct procfsid *Procfsid;
+extern int Procsrch;
+#    endif /* defined(HASPROCFS) */
+
+extern int PrPass;
+extern int RptMaxCount;
+extern char *SzOffFmt_0t;
+extern char *SzOffFmt_d;
+extern char *SzOffFmt_dv;
+extern char *SzOffFmt_x;
+extern int TaskCmdLim;
+extern int TaskPrtCmd;
+extern int TaskPrtTid;
+extern int TcpStAlloc;
+extern unsigned char *TcpStI;
+extern int TcpStIn;
+extern int TcpStOff;
+extern unsigned char *TcpStX;
+extern int TcpStXn;
+extern int TcpNstates;
+extern char **TcpSt;
+extern char Terminator;
+extern int UdpStAlloc;
+extern unsigned char *UdpStI;
+extern int UdpStIn;
+extern int UdpStOff;
+extern unsigned char *UdpStX;
+extern int UdpStXn;
+extern int UdpNstates;
+extern char **UdpSt;
+
+struct hsfile {
+    struct sfile *s;     /* the Sfile table address */
+    struct hsfile *next; /* the next hash bucket entry */
+};
+
+typedef struct znhash {
+    char *zn;            /* zone name */
+    int f;               /* "find" flag (used only in ZoneArg) */
+    struct znhash *next; /* next zone hash entry */
+} znhash_t;
+
+struct lsof_context {
+    /** Parameters */
+    /** Linked list of files to search */
+    struct sfile *select_files;
+
+    /* file systems for which kernel blocks are
+     * to be eliminated */
+    efsys_list_t *elim_fs_list;
+
+    /* User IDs to include or exclude */
+    struct seluid *sel_uid;
+    /* -u option count */
+    int sel_uid_size;
+    /* capacity of sel_uid */
+    int sel_uid_cap;
+    /* -u option count of UIDs excluded */
+    int num_uid_excluded;
+    /* -u option count of UIDs included */
+    int num_uid_included;
+
+    /* process group IDs to search for */
+    struct int_lst *sel_pgid;
+    int sel_pgid_size;     /* -g option count */
+    int sel_pgid_cap;      /* capacity of sel_pgid */
+    int sel_pgid_incl_num; /* -g option inclusion count */
+    int sel_pgid_excl_num; /* -g option exclusion count */
+
+    /* Process IDs to search for */
+    struct int_lst *sel_pid;
+    int sel_pid_size;  /* -p option count */
+    int num_unsel_pid; /* number of unselected PIDs (starts at sel_pid_size) for
+                          optimization in examine_lproc() */
+    int sel_pid_cap;   /* capacity of sel_pid */
+    int sel_pid_incl_num; /* -p option inclusion count */
+    int sel_pid_excl_num; /* -p option exclusion count */
+
+    /* Whether all processes are selected */
+    int sel_all_proc;
+
+    /* command names selected with -c */
+    struct str_lst *sel_cmds;
+    int sel_cmd_incl; /* number of command name inclusions selected with -c */
+    int sel_cmd_excl; /* number of command name exclusions selected with -c */
+
+    /* command regular expression table for -c option */
+    lsof_rx_t *cmd_regex;
+    int cmd_regex_size; /* number of cmd_regex[] entries */
+    int cmd_regex_cap;  /* capacity of cmd_regex[] */
+
+    /* select by network address */
+    struct nwad *sel_net_addr;
+
+    /* security context arguments supplied with -Z */
+    cntxlist_t *sel_selinux_context;
+
+    /* device cache paths, indexed by DCpathX
+     * when it's >= 0 */
+    char *dev_cache_paths[4];
+    int dev_cache_path_index;    /* device cache path index:
+                                  * -1 = path not defined
+                                  *  0 = defined via -D
+                                  *  1 = defined via HASENVDC
+                                  *  2 = defined via HASSYSDC
+                                  *  3 = defined via HASPERSDC and
+                                  *      HASPERSDCPATH */
+    char *dev_cache_path_arg;    /* device cache path from -D[b|r|u]<path> */
+    unsigned dev_cache_checksum; /* device cache file checksum */
+    int dev_cache_fd;            /* device cache file descriptor */
+    FILE *dev_cache_fp;          /* stream pointer for DCfd */
+    int dev_cache_rebuilt;       /* an unsafe device cache file has been
+                                  * rebuilt */
+    int dev_cache_state;         /* device cache state:
+                                  * 0 = ignore (-Di)
+                                  * 1 = build (-Db[path])
+                                  * 2 = read; don't rebuild (-Dr[path])
+                                  * 3 = update; read and rebuild if
+                                  *     necessary (-Du[path])
+                                  */
+    int dev_cache_unsafe;        /* device cache file is potentially unsafe,
+                                  * (The [cm]time check failed.) */
+
+#    if defined(HASNLIST)
+    /* kernel name list */
+    struct NLIST_TYPE *name_list;
+    int name_list_size;
+#    endif                /* defined(HASNLIST) */
+    char *name_list_path; /* namelist file path */
+    char *core_file_path; /* core file path */
+
+#    if defined(HASPROCFS)
+    /* /proc mount entry */
+    struct mounts *procfs_mount;
+    int procfs_found; /* 1 when searching for an proc file system
+                       * file and one was found */
+    /* proc file system PID search table */
+    struct procfsid *procfs_table;
+    /* 1 if searching for any proc file system
+     * file */
+    int procfs_search;
+#    endif /* defined(HASPROCFS) */
+
+    /* name cache */
+    int name_cache_enable; /* -C option status */
+
+    /* local mount info */
+    struct mounts *local_mount_info;
+    int local_mount_info_valid;
+
+    /** hashSfile() buckets */
+    /* hash by file (dev,ino) buckets */
+    struct hsfile *sfile_hash_file_dev_inode;
+    int sfile_hash_file_dev_inode_count;
+    /* hash by file raw device buckets */
+    struct hsfile *sfile_hash_file_raw_device;
+    int sfile_hash_file_raw_device_count;
+    /* hash by file system buckets */
+    struct hsfile *sfile_hash_file_system;
+    int sfile_hash_file_system_count;
+    /* hash by name buckets */
+    struct hsfile *sfile_hash_name;
+    int sfile_hash_name_count;
+    /* hash by clone buckets */
+    struct hsfile *sfile_hash_clone;
+    int sfile_hash_clone_count;
+
+    /* zone arguments supplied with -z */
+    znhash_t **sel_zone;
+
+    /* command name limit */
+    int cmd_limit;
+
+    /** When frozen, parameters must not be changed */
+    uint8_t frozen;
+
+    /* node type (see N_* symbols) */
+    int node_type;
+
+    /* device table pointer */
+    struct l_dev *dev_table;
+    int dev_table_size; /* number of entries in dev_table[] */
+    /* pointer to dev_table[] pointers, sorted
+     * by device */
+    struct l_dev **dev_table_sorted;
+
+    /* block device table pointer */
+    struct l_dev *block_dev_table;
+    int block_dev_table_size; /* number of entries in block_dev_table[] */
+    /* pointer to BDevtp[] pointers, sorted
+     * by device */
+    struct l_dev **block_dev_table_sorted;
+
+    /* selection flags -- see SEL* macros */
+    int sel_flags;
+    /* SELPROC flags, modified by IgnTasks */
+    int sel_proc;
+    /* SELALL flags, modified by IgnTasks */
+    int sel_all;
+    /* select only Internet socket files */
+    int sel_inet;
+
+    /* -N option status: 0==none, 1==find all,
+     * 2==some found*/
+    int sel_nfs;
+
+    /* -K option value */
+    int sel_task;
+
+    /* -a option status */
+    int logic_and;
+
+    /* -b option status */
+    int avoid_blocking;
+
+    /* -O option status */
+    int avoid_forking;
+
+    /* -X option status */
+    int x_opt;
+
+    /* -E option status:
+     * 0==none,
+     * 1==info,
+     * 2==info+files */
+    int endpoint_status;
+
+    /* ignore tasks when non-zero */
+    int ign_tasks;
+
+    /* maximum file descriptors to close */
+    int max_fd;
+
+    /* file descriptors selected with -d */
+    struct fd_lst *fd_list;
+    /* fd_list[] type:
+     * -1 == none
+     * 0 == include
+     * 1 == exclude */
+    int fd_list_ty;
+
+    /* mount supplement state:
+     * 0 == none
+     * 1 == create
+     * 2 == read */
+    int mnt_sup_state;
+    /* mount supplement path -- if MntSup == 2 */
+    char *mnt_sup_path;
+
+    /* report nlink values below this number
+     * (0 = report all nlink values) */
+    long nlink;
+
+    /* Readlink() and stat() timeout (seconds) */
+    int time_limit;
+
+    int my_pid;      /* lsof's process ID */
+    uid_t my_uid;    /* real UID of this lsof process */
+    gid_t my_gid;    /* real GID of this lsof process */
+    int setgid;      /* setgid state */
+    int setuid_root; /* setuid-root state */
+
+    /* directory stack */
+    char **dir_stack;    /* the directory stack */
+    int dir_stack_index; /* dir_stack[] index */
+    int dir_stack_size;  /* dir_stack[] entries allocated */
+
+    /* allocated (possibly unused) entries in TCP
+     * state tables */
+    int tcp_state_alloc;
+    /* included TCP states */
+    unsigned char *tcp_state_incl;
+    int tcp_state_incl_num; /* number of entries in tcp_state_incl[] */
+    int tcp_state_off;      /* offset for TCP state number to adjust
+                             * negative numbers to an index into tcp_states[],
+                             * tcp_state_incl[] and tcp_state_excl[] */
+    /* excluded TCP states */
+    unsigned char *tcp_state_excl;
+    int tcp_state_excl_num; /* number of entries in tcp_state_excl[] */
+    int tcp_num_states;     /* number of TCP states -- either in
+                             * tcpstates[] or tcp_states[] */
+    char **tcp_states;      /* local TCP state names, indexed by system
+                             * state value */
+
+    /* allocated (possibly unused) entries in UDP
+     * state tables */
+    int udp_state_alloc;
+    /* included UDP states */
+    unsigned char *udp_state_incl;
+    int udp_state_incl_num; /* number of entries in udp_state_incl[] */
+    int udp_state_off;      /* offset for UDP state number to adjust
+                             * negative numbers to an index into udp_states[],
+                             * udp_state_incl[] and udp_state_excl[] */
+    unsigned char *udp_state_excl;
+    /* excluded UDP states */
+    int udp_state_excl_num; /* number of entries in udp_state_excl[] */
+    int udp_num_states;     /* number of UDP states in udp_states[] */
+    char **udp_states;      /* local UDP state names, indexed by system
+                             * state number */
+
+    int unix_socket; /* -U option status */
+
+    dev_t dev_dev; /* device number of /dev or its equivalent */
+
+    int net;      /* -i option status: 0==none
+                   *                   1==find all
+                   *                   2==some found */
+    int net_type; /* Fnet type request: AF_UNSPEC==all
+                   *                    AF_INET==IPv4
+                   *                    AF_INET6==IPv6 */
+
+    /* Fsv was set by +f */
+    int fsv_set_f;
+
+    /* hex format status for FSV_FG */
+    int fsv_hex;
+
+    /* repeat time -- set by -r */
+    int repeat_time;
+
+    /* -o option status */
+    int show_offset;
+
+    /* -s option status */
+    int show_size;
+
+    /** Temporary */
+    /* name characters for printing */
+    char *name_buf;
+    /* sizeof(name_buf) */
+    size_t name_buf_size;
+
+    /** Output */
+    /** Pointer to current process */
+    struct lproc *cur_proc;
+    /** Pointer to all processes */
+    struct lproc *procs;
+    /** Length and capacity of `procs` */
+    size_t procs_size;
+    size_t procs_cap;
+
+    /** Pointer to current file */
+    struct lfile *cur_file;
+    /** Pointer to previous file */
+    struct lfile *prev_file;
+
+    /** Warnings and errors */
+    FILE *err;
+    char *program_name;
+    int warn; /* 1=suppress warnings */
+
+    /** dialect specific fields, see dlsof.h */
+    struct lsof_context_dialect dialect;
+};
+
+/** Convenience macros to access context */
+/* Local process */
+#    define Lp (ctx->cur_proc)
+/* All local processes */
+#    define Lproc (ctx->procs)
+/* Local file */
+#    define Lf (ctx->cur_file)
+/* Previous local file */
+#    define Plf (ctx->prev_file)
+/* Length of local processes */
+#    define Nlproc (ctx->procs_size)
+/* Error output */
+#    define Pn (ctx->program_name)
+/* Suppress warnings */
+#    define Fwarn (ctx->warn)
+/* Name buffer */
+#    define Namech (ctx->name_buf)
+#    define Namechl (ctx->name_buf_size)
+/* Selection flags */
+#    define SelAll (ctx->sel_all)
+#    define Selflags (ctx->sel_flags)
+#    define SelProc (ctx->sel_proc)
+#    define Selinet (ctx->sel_inet)
+/* dev_t of /dev */
+#    define DevDev (ctx->dev_dev)
+/* TCP states */
+#    define TcpNstates (ctx->tcp_num_states)
+#    define TcpSt (ctx->tcp_states)
+#    define TcpStI (ctx->tcp_state_incl)
+#    define TcpStIn (ctx->tcp_state_incl_num)
+#    define TcpStX (ctx->tcp_state_excl)
+#    define TcpStXn (ctx->tcp_state_excl_num)
+#    define TcpStOff (ctx->tcp_state_off)
+#    define TcpStAlloc (ctx->tcp_state_alloc)
+/* UDP states */
+#    define UdpNstates (ctx->udp_num_states)
+#    define UdpSt (ctx->udp_states)
+#    define UdpStI (ctx->udp_state_incl)
+#    define UdpStIn (ctx->udp_state_incl_num)
+#    define UdpStX (ctx->udp_state_excl)
+#    define UdpStXn (ctx->udp_state_excl_num)
+#    define UdpStOff (ctx->udp_state_off)
+#    define UdpStAlloc (ctx->udp_state_alloc)
+/* select unix socket */
+#    define Funix (ctx->unix_socket)
+/* select inet socket */
+#    define Fnet (ctx->net)
+#    define FnetTy (ctx->net_type)
+/* select nfs files */
+#    define Fnfs (ctx->sel_nfs)
+/* -a option */
+#    define Fand (ctx->logic_and)
+/* -x option */
+#    define Fxopt (ctx->x_opt)
+/* avoid blocking */
+#    define Fblock (ctx->avoid_blocking)
+/* avoid forking overhead */
+#    define Fovhd (ctx->avoid_forking)
+/* endpoint status */
+#    define FeptE (ctx->endpoint_status)
+/* select tasks */
+#    define Ftask (ctx->sel_task)
+/* fd list */
+#    define Fdl (ctx->fd_list)
+#    define FdlTy (ctx->fd_list_ty)
+/* ignore tasks */
+#    define IgnTasks (ctx->ign_tasks)
+/* maximum fd number */
+#    define MaxFd (ctx->max_fd)
+/* mount supplement */
+#    define MntSup (ctx->mnt_sup_state)
+#    define MntSupP (ctx->mnt_sup_path)
+/* nlink limit */
+#    define Nlink (ctx->nlink)
+/* Time limit */
+#    define TmLimit (ctx->time_limit)
+/* number of unselected PIDs */
+#    define Npuns (ctx->num_unsel_pid)
+/* pid/uid/gid of current process */
+#    define Mypid (ctx->my_pid)
+#    define Myuid (ctx->my_uid)
+#    define Mygid (ctx->my_gid)
+/* setgid state */
+#    define Setgid (ctx->setgid)
+/* setuid-root state */
+#    define Setuidroot (ctx->setuid_root)
+/* directory stack */
+#    define Dstk (ctx->dir_stack)
+#    define Dstkx (ctx->dir_stack_index)
+#    define Dstkn (ctx->dir_stack_size)
+/* selection files */
+#    define Sfile (ctx->select_files)
+/* fs to eliminate blocking syscalls */
+#    define Efsysl (ctx->elim_fs_list)
+/* select uid */
+#    define Suid (ctx->sel_uid)
+#    define Nuid (ctx->sel_uid_size)
+#    define Nuidincl (ctx->num_uid_included)
+#    define Nuidexcl (ctx->num_uid_excluded)
+#    define Mxuid (ctx->sel_uid_cap)
+/* select pid */
+#    define Spid (ctx->sel_pid)
+#    define Npid (ctx->sel_pid_size)
+#    define Npidi (ctx->sel_pid_incl_num)
+#    define Npidx (ctx->sel_pid_excl_num)
+#    define Mxpid (ctx->sel_pid_cap)
+/* select pgid */
+#    define Spgid (ctx->sel_pgid)
+#    define Npgid (ctx->sel_pgid_size)
+#    define Npgidi (ctx->sel_pgid_incl_num)
+#    define Npgidx (ctx->sel_pgid_excl_num)
+#    define Mxpgid (ctx->sel_pgid_cap)
+/* select all procs */
+#    define AllProc (ctx->sel_all_proc)
+/* select command */
+#    define Cmdl (ctx->sel_cmds)
+#    define Cmdni (ctx->sel_cmd_incl)
+#    define Cmdnx (ctx->sel_cmd_excl)
+#    define CmdRx (ctx->cmd_regex)
+#    define NCmdRxA (ctx->cmd_regex_cap)
+#    define NCmdRxU (ctx->cmd_regex_size)
+/* select by network address */
+#    define Nwad (ctx->sel_net_addr)
+/* device table pointer */
+#    define Devtp (ctx->dev_table)
+#    define Ndev (ctx->dev_table_size)
+#    define Sdev (ctx->dev_table_sorted)
+/* block device table */
+#    define BDevtp (ctx->block_dev_table)
+#    define BNdev (ctx->block_dev_table_size)
+#    define BSdev (ctx->block_dev_table_sorted)
+/* select selinux context */
+#    define CntxArg (ctx->sel_selinux_context)
+/* device cache */
+#    define DCpath (ctx->dev_cache_paths)
+#    define DCpathArg (ctx->dev_cache_path_arg)
+#    define DCpathX (ctx->dev_cache_path_index)
+#    define DCcksum (ctx->dev_cache_checksum)
+#    define DCfd (ctx->dev_cache_fd)
+#    define DCfs (ctx->dev_cache_fp)
+#    define DCrebuilt (ctx->dev_cache_rebuilt)
+#    define DCstate (ctx->dev_cache_state)
+#    define DCunsafe (ctx->dev_cache_unsafe)
+/* name list */
+#    define Nl (ctx->name_list)
+#    define Nll (ctx->name_list_size)
+#    define Nmlst (ctx->name_list_path)
+#    define Memory (ctx->core_file_path)
+/* procfs */
+#    define Mtprocfs (ctx->procfs_mount)
+#    define Procsrch (ctx->procfs_search)
+#    define Procfsid (ctx->procfs_table)
+#    define Procfind (ctx->procfs_found)
+/* name cache */
+#    define Fncache (ctx->name_cache_enable)
+/* local mount info */
+#    define Lmi (ctx->local_mount_info)
+#    define Lmist (ctx->local_mount_info_valid)
+/* hash buckets in hashSfile() */
+#    define HbyFdi (ctx->sfile_hash_file_dev_inode)
+#    define HbyFdiCt (ctx->sfile_hash_file_dev_inode_count)
+#    define HbyFrd (ctx->sfile_hash_file_raw_device)
+#    define HbyFrdCt (ctx->sfile_hash_file_raw_device_count)
+#    define HbyFsd (ctx->sfile_hash_file_system)
+#    define HbyFsdCt (ctx->sfile_hash_file_system_count)
+#    define HbyNm (ctx->sfile_hash_name)
+#    define HbyNmCt (ctx->sfile_hash_name_count)
+#    define HbyCd (ctx->sfile_hash_clone)
+#    define HbyCdCt (ctx->sfile_hash_clone_count)
+/* solaris zone */
+#    define ZoneArg (ctx->sel_zone)
+/* command name limit */
+#    define CmdLim (ctx->cmd_limit)
+/* node type */
+#    define Ntype (ctx->node_type)
+/* Fsv was set by +f */
+#    define FsvByf (ctx->fsv_set_f)
+/* hex format status for FSV_FG */
+#    define FsvFlagX (ctx->fsv_hex)
+/* repeat time */
+#    define RptTm (ctx->repeat_time)
+/* -o option status */
+#    define Foffset (ctx->show_offset)
+/* -s option status */
+#    define Fsize (ctx->show_size)
+
+/* Utility macro to free if non-null and set the pointer to null */
+#    define CLEAN(ptr)                                                         \
+        do {                                                                   \
+            free(ptr);                                                         \
+            ptr = NULL;                                                        \
+        } while (0);
+
+#    include "proto.h"
+#    include "dproto.h"
+
+#endif /* COMMON_H */
diff --git a/lib/cvfs.c b/lib/cvfs.c
new file mode 100644 (file)
index 0000000..59d01f5
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * cvfs.c -- completevfs() function for lsof library
+ */
+
+/*
+ * 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.
+ */
+
+/*
+ * The caller must define CVFS_DEVSAVE to have the device number moved
+ * from the mounts entry to the local vfs structure.
+ *
+ * The caller must define CVFS_NLKSAVE to have the link count moved from
+ * the mounts entry to the local vfs structure.
+ *
+ * The caller must define CVFS_SZSAVE to have the size moved from the
+ * mounts entry to the local vfs structure.
+ */
+
+#include "common.h"
+#include "machine.h"
+
+#if defined(USE_LIB_COMPLETEVFS)
+
+/*
+ * completevfs() - complete local vfs structure
+ */
+
+void completevfs(struct lsof_context *ctx, /* context */
+                 struct l_vfs *vfs,        /* local vfs structure pointer */
+                 dev_t *dev)               /* device */
+{
+    struct mounts *mp;
+    /*
+     * If only Internet socket files are selected, don't bother completing the
+     * local vfs structure.
+     */
+    if (Selinet)
+        return;
+    /*
+     * Search for a match on device number.
+     */
+    for (mp = readmnt(ctx); mp; mp = mp->next) {
+        if (mp->dev == *dev) {
+
+#    if defined(CVFS_DEVSAVE)
+            vfs->dev = mp->dev;
+#    endif /* defined(CVFS_DEVSAVE) */
+
+#    if defined(CVFS_NLKSAVE)
+            vfs->nlink = mp->nlink;
+#    endif /* defined(CVFS_NLKSAVE) */
+
+#    if defined(CVFS_SZSAVE)
+            vfs->size = mp->size;
+#    endif /* defined(CVFS_SZSAVE) */
+
+            vfs->dir = mp->dir;
+            vfs->fsname = mp->fsname;
+
+#    if defined(HASFSINO)
+            vfs->fs_ino = mp->inode;
+#    endif /* defined(HASFSINO) */
+
+#    if defined(HASMNTSTAT)
+            vfs->mnt_stat = mp->stat;
+#    endif /* defined(HASMNTSTAT) */
+
+            return;
+        }
+    }
+}
+#else  /* !defined(USE_LIB_COMPLETEVFS) */
+char cvfs_d1[] = "d";
+char *cvfs_d2 = cvfs_d1;
+#endif /* defined(USE_LIB_COMPLETEVFS) */
diff --git a/lib/dialects/aix/Makefile b/lib/dialects/aix/Makefile
new file mode 100644 (file)
index 0000000..980e78f
--- /dev/null
@@ -0,0 +1,168 @@
+
+# AIX Makefile
+#
+# $Id: Makefile,v 1.14 2008/04/15 13:28:12 abe Exp $
+
+PROG=  lsof
+
+BIN=   ${DESTDIR}
+
+DOC=   ${DESTDIR}
+
+I=/usr/include
+S=/usr/include/sys
+L=/usr/include/local
+P=
+
+CDEF=
+CDEFS=  ${CDEF} ${CFGF}
+INCL=  ${DINC} -Iinclude -Ilib -Isrc -I.
+CFLAGS=        ${CDEFS} ${INCL} ${DEBUG}
+
+GRP=
+
+HDR=    lib/common.h include/lsof_fields.h dlsof.h machine.h lib/proto.h dproto.h
+
+SRC=    ddev.c dfile.c dmnt.c dnode.c dnode1.c dnode2.c dproc.c dsock.c \
+       dstore.c arg.c main.c print.c ptti.c store.c usage.c \
+       util.o
+
+OBJ=   ddev.o dfile.o dmnt.o dnode.o dnode1.o dnode2.o dproc.o dsock.o \
+       dstore.o arg.o main.o print.o ptti.o store.o usage.o \
+       util.o
+
+MAN=   lsof.8
+
+OTHER= 
+
+SHELL= /bin/sh
+
+SOURCE=        Makefile ${OTHER} ${MAN} ${HDR} ${SRC}
+
+all: ${PROG}
+
+${PROG}: ${LIB} ${P} ${OBJ}
+       ${CC} -o $@ ${CFLAGS} ${OBJ} ${CFGL}
+
+clean: FRC
+       rm -f Makefile.bak ${PROG} a.out core errs lint.out tags *.o version.h
+       rm -f machine.h.old new_machine.h
+       (cd lib; ${MAKE} -f Makefile.skel clean)
+
+install: all FRC
+       @echo ''
+       @echo 'Please write your own install rule.  Lsof Needs to be able to'
+       @echo 'read /dev/kmem and /dev/mem'.  Installing it segid to the group'
+       @echo 'that can read those devices is one way to allow it to read them.'
+       @echo 'normally that group is the system group and your install rule'
+       @echo 'might look something like this:'
+       @echo ''
+       @echo '    install -f $${BIN} -S -M 2755 -G $${GRP} $${PROG}'
+       @echo '    install -f $${DOC} -M 444 $${MAN}'
+       @echo ''
+       @echo 'You will have to complete the skeletons for the BIN, DOC, and'
+       @echo 'GRP strings given at the beginning of this Makefile, e.g.,'
+       @echo ''
+       @echo '    BIN= $${DESTDIR}/usr/local/etc'
+       @echo '    DOC= $${DESTDIR}/usr/man/man8'
+       @echo '    GRP= system'
+       @echo ''
+       @echo 'You might also consider giving lsof permission to read /dev/kmem'
+       @echo 'and /dev/mem via ACLs.  First, establish a new group to which'
+       @echo 'you will setgid lsof -- e.g., group kmem.  Next, change the ACLs'
+       @echo 'for /dev/kmem and /dev/mem to permit group kmem members to read'
+       @echo 'them.  Finally, install lsof setgid the kmem group with:
+       @echo ''
+       @echo '    GRP= kmem'
+
+${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_CCFLAGS    "'`echo ${CFLAGS} | sed 's/\\\\(/\\(/g' | sed 's/\\\\)/\\)/g' | sed 's/"/\\\\"/g'`'"' >> version.h
+       @echo '#define  LSOF_CINFO      "${CINFO}"' >> version.h
+       @if [ "X${LSOF_HOST}" = "X" ]; then \
+         echo '#define LSOF_HOST       "'`uname -n`'"' >> version.h; \
+       else \
+         if [ "${LSOF_HOST}" = "none" ]; then \
+           echo '#define       LSOF_HOST       ""' >> version.h; \
+         else \
+           echo '#define       LSOF_HOST       "${LSOF_HOST}"' >> version.h; \
+         fi \
+       fi
+       @echo '#define  LSOF_LDFLAGS    "${CFGL}"' >> version.h
+       @if [ "X${LSOF_LOGNAME}" = "X" ]; then \
+         echo '#define LSOF_LOGNAME    "${LOGNAME}"' >> version.h; \
+       else \
+         if [ "${LSOF_LOGNAME}" = "none" ]; then \
+           echo '#define       LSOF_LOGNAME    ""' >> version.h; \
+         else \
+           echo '#define       LSOF_LOGNAME    "${LSOF_LOGNAME}"' >> version.h; \
+         fi; \
+       fi
+       @if [ "X${LSOF_SYSINFO}" = "X" ]; then \
+           echo '#define       LSOF_SYSINFO    "'`uname -a`'"' >> version.h; \
+       else \
+         if [ "${LSOF_SYSINFO}" = "none" ]; then \
+           echo '#define       LSOF_SYSINFO    ""' >> version.h; \
+         else \
+           echo '#define       LSOF_SYSINFO    "${LSOF_SYSINFO}"' >> version.h; \
+         fi \
+       fi
+       @if [ "X${LSOF_USER}" = "X" ]; then \
+         echo '#define LSOF_USER       "${USER}"' >> version.h; \
+       else \
+         if [ "${LSOF_USER}" = "none" ]; then \
+           echo '#define       LSOF_USER       ""' >> version.h; \
+         else \
+           echo '#define       LSOF_USER       "${LSOF_USER}"' >> version.h; \
+         fi \
+       fi
+       @sed '/VN/s/.ds VN \(.*\)/#define       LSOF_VERSION    "\1"/' < version >> version.h
+
+FRC:
+
+# DO NOT DELETE THIS LINE - make depend DEPENDS ON IT
+
+ddev.o:                ${HDR} ddev.c
+
+dfile.o:       ${HDR} dfile.c
+
+dmnt.o:                ${HDR} dmnt.c
+
+dnode.o:       ${HDR} dnode.c
+
+dnode1.o:      ${HDR} dnode1.c
+
+dproc.o:       ${HDR} dproc.c
+
+dnode2.o:      ${HDR} dnode2.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/lib/dialects/aix/Mksrc b/lib/dialects/aix/Mksrc
new file mode 100755 (executable)
index 0000000..edf726c
--- /dev/null
@@ -0,0 +1,34 @@
+#!/bin/sh
+#
+# Mksrc - make AIX source files
+#
+# WARNING: This script assumes it is running from the main directory
+#         of the lsof, version 4 distribution.
+#
+# One environment variable applies:
+#
+# LSOF_MKC     is the method for creating the source files.
+#              It defaults to "ln -s".  A common alternative is "cp".
+#
+# $Id: Mksrc,v 1.3 2003/03/21 17:39:46 abe Exp $
+
+mksrc() {
+  for i in $L
+  do
+    rm -f $i
+    $LSOF_MKC $D/$i $i
+    echo "$LSOF_MKC $D/$i $i"
+  done
+}
+
+
+D=lib/dialects/aix
+L="dlsof.h ddev.c dfile.c dmnt.c dnode.c dnode1.c dnode2.c dproc.c dproto.h dsock.c dstore.c machine.h"
+
+mksrc
+
+D=src
+L="arg.c main.c print.c ptti.c store.c usage.c util.c"
+
+mksrc
+
diff --git a/lib/dialects/aix/aix5/README b/lib/dialects/aix/aix5/README
new file mode 100644 (file)
index 0000000..28adc0c
--- /dev/null
@@ -0,0 +1,7 @@
+This directory exists to supply missing /usr/include/j2 header
+files for AIX 5 and above, or to supply alternatives that can be
+#include'd when distributed AIX 5 and above header files can't be
+used -- e.g., they #include missing header files.
+
+Vic Abell
+March 2, 2003
diff --git a/lib/dialects/aix/aix5/j2/j2_lock.h b/lib/dialects/aix/aix5/j2/j2_lock.h
new file mode 100644 (file)
index 0000000..b97102b
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * j2_lock.h -- lsof private copy
+ *
+ * Needed for:
+ *
+ *     AIX 5L, because it's missing there;
+ *     AIX 5.2, because it includes <proc/proc_public.h> and that header
+ *         file is missing from AIX 5.2.
+ *
+ * V. Abell <abe@purdue.edu>
+ * Purdue University
+ */
+
+#if !defined(LSOF_J2_LOCK_H)
+#    define LSOF_J2_LOCK_H
+typedef long event_t;
+#    define MUTEXLOCK_T Simple_lock
+#    define RDWRLOCK_T Complex_lock
+#endif /* !defined(LSOF_J2_LOCK_H) */
diff --git a/lib/dialects/aix/aix5/j2/private_j2_snapshot.h b/lib/dialects/aix/aix5/j2/private_j2_snapshot.h
new file mode 100644 (file)
index 0000000..f8b3ad9
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * j2_snapshot.h -- lsof private copy
+ *
+ * Needed for:
+ *
+ *     AIX 5.2, because this header file is missing and j2_inode.h #includes
+ *         it.  The dummy snapshotObject structure definition is needed by
+ *          some releases of AIX 5.2 and above, but the structure's size does
+ *         not affect lsof's use of the JFS2 inode structure.
+ */
+
+#if !defined(_H_J2_SNAPSHOT)
+#    define _H_J2_SNAPSHOT
+struct snapshotObject {
+    uint64 d1;
+};
+#endif /* !defined(_H_J2_SNAPSHOT) */
diff --git a/lib/dialects/aix/ddev.c b/lib/dialects/aix/ddev.c
new file mode 100644 (file)
index 0000000..e110d6d
--- /dev/null
@@ -0,0 +1,686 @@
+/*
+ * ddev.c - AIX device support functions for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#ifndef lint
+static char copyright[] =
+    "@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
+#endif
+
+#include "common.h"
+
+/*
+ * Local definitions
+ */
+
+#define LIKE_BLK_SPEC "like block special"
+#define LIKE_CHR_SPEC "like character special"
+
+/*
+ * Local function prototypes
+ */
+
+static int rmdupdev(struct lsof_context *ctx, struct l_dev ***dp, int n,
+                    char *nm);
+
+#if defined(HASDCACHE) && AIXV >= 4140
+
+/*
+ * clr_sect() - clear cached clone and pseudo sections
+ */
+
+void clr_sect(struct lsof_context *ctx) {
+    struct clone *c, *c1;
+
+    if (Clone) {
+        for (c = Clone; c; c = c1) {
+            c1 = c->next;
+            if (c->cd.name)
+                (void)free((FREE_P *)c->cd.name);
+            (void)free((FREE_P *)c);
+        }
+        Clone = (struct clone *)NULL;
+    }
+}
+#endif /* defined(HASDCACHE) && AIXV>=4140 */
+
+/*
+ * getchan() - get channel from file path name
+ */
+
+int getchan(char *p) /* file path name */
+{
+    int ch;
+    char *s;
+
+    if (!(s = strrchr(p, '/')))
+        return (-1);
+    if (*(++s) == '\0')
+        return (-1);
+    for (ch = 0; *s; s++) {
+
+#if defined(__STDC__)
+        if (!isdigit(*s))
+#else
+        if (!isascii(*s) || !isdigit(*s))
+#endif /* __STDC__ */
+
+            return (-1);
+        ch = (ch * 10) + *s - '0';
+    }
+    return (ch);
+}
+
+/*
+ * printdevname() - print device name
+ */
+
+int printdevname(struct lsof_context *ctx, /* context */
+                 dev_t *dev,               /* device */
+                 dev_t *rdev,              /* raw device */
+                 int f,                    /* 1 = follow with '\n' */
+                 int nty)                  /* node type: N_BLK or N_CHR */
+{
+    struct l_dev *dp;
+    /*
+     * Search device table for a full match.
+     */
+    if ((dp = lkupdev(ctx, dev, rdev, 1, 1))) {
+        if (Lf->ch < 0)
+            safestrprt(dp->name, stdout, f);
+        else {
+            safestrprt(dp->name, stdout, 0);
+            (void)printf("/%d%s", Lf->ch, f ? "\n" : "");
+        }
+        return (1);
+    }
+    /*
+     * Search device table for a match without inode number and dev.
+     */
+    if ((dp = lkupdev(ctx, &DevDev, rdev, 0, 1))) {
+
+        /*
+         * A raw device match was found.  Record it as a name column addition.
+         */
+        char *cp, *ttl;
+        int len;
+
+        ttl = (nty == N_BLK) ? LIKE_BLK_SPEC : LIKE_CHR_SPEC;
+        len = (int)(1 + strlen(ttl) + 1 + strlen(dp->name) + 1);
+        if (!(cp = (char *)malloc((MALLOC_S)(len + 1)))) {
+            (void)fprintf(stderr, "%s: no nma space for: (%s %s)\n", Pn, ttl,
+                          dp->name);
+            Error(ctx);
+        }
+        (void)snpf(cp, len + 1, "(%s %s)", ttl, dp->name);
+        (void)add_nma(ctx, cp, len);
+        (void)free((MALLOC_P *)cp);
+        return (0);
+    }
+    return (0);
+}
+
+/*
+ * readdev() - read device names, modes and types
+ */
+
+void readdev(struct lsof_context *ctx, /* context */
+             int skip)                 /* skip device cache read if 1 */
+{
+
+#if defined(HASDCACHE)
+    int dcrd;
+#endif /* defined(HASDCACHE) */
+
+    DIR *dfp;
+    struct dirent *dp;
+    char *fp = (char *)NULL;
+    int i = 0;
+
+#if defined(HASBLKDEV)
+    int j = 0;
+#endif /* defined(HASBLKDEV) */
+
+    char *path = (char *)NULL;
+    MALLOC_S pl;
+    struct stat sb;
+
+#if AIXV >= 4140
+    struct clone *c;
+    dev_t cd;
+#endif /* AIXV >=4140 */
+
+    if (Sdev)
+        return;
+
+#if defined(HASDCACHE)
+    /*
+     * Read device cache, as directed.
+     */
+    if (!skip) {
+        if (DCstate == 2 || DCstate == 3) {
+            if ((dcrd = read_dcache(ctx)) == 0)
+                return;
+        }
+    } else
+        dcrd = 1;
+#endif /* defined(HASDCACHE) */
+
+#if AIXV >= 4140
+    /*
+     * Establish the clone major device for AIX 4.1.4 and above.
+     */
+    if (stat("/dev/clone", &sb) == 0) {
+        cd = sb.st_rdev;
+        CloneMaj = GET_MAJ_DEV(cd);
+    }
+#endif /* AIXV >=4140 */
+
+    Dstk = (char **)NULL;
+    Dstkn = Dstkx = 0;
+    (void)stkdir(ctx, "/dev");
+    /*
+     * Unstack the next /dev or /dev/<subdirectory> directory.
+     */
+    while (--Dstkx >= 0) {
+        if (!(dfp = opendir(Dstk[Dstkx]))) {
+
+#if defined(WARNDEVACCESS)
+            if (!Fwarn) {
+                (void)fprintf(stderr, "%s: WARNING: can't open: ", Pn);
+                safestrprt(Dstk[Dstkx], stderr, 1);
+            }
+#endif /* defined(WARNDEVACCESS) */
+
+            (void)free((FREE_P *)Dstk[Dstkx]);
+            Dstk[Dstkx] = (char *)NULL;
+            continue;
+        }
+        if (path) {
+            (void)free((FREE_P *)path);
+            path = (char *)NULL;
+        }
+        if (!(path =
+                  mkstrcat(Dstk[Dstkx], -1, "/", 1, (char *)NULL, -1, &pl))) {
+            (void)fprintf(stderr, "%s: no space for: ", Pn);
+            safestrprt(Dstk[Dstkx], stderr, 1);
+            Error(ctx);
+        }
+        (void)free((FREE_P *)Dstk[Dstkx]);
+        Dstk[Dstkx] = (char *)NULL;
+        /*
+         * Scan the directory.
+         */
+        for (dp = readdir(dfp); dp; dp = readdir(dfp)) {
+            if (!dp->d_ino || (dp->d_name[0] == '.'))
+                continue;
+            /*
+             * Form the full path name and get its status.
+             */
+            if (fp) {
+                (void)free((FREE_P *)fp);
+                fp = (char *)NULL;
+            }
+            if (!(fp = mkstrcat(path, (int)pl, dp->d_name, dp->d_namlen,
+                                (char *)NULL, -1, (MALLOC_S *)NULL))) {
+                (void)fprintf(stderr, "%s: no space for: ", Pn);
+                safestrprt(path, stderr, 0);
+                safestrprt(dp->d_name, stderr, 1);
+                Error(ctx);
+            }
+
+#if defined(USE_STAT)
+            if (stat(fp, &sb) != 0)
+#else  /* !defined(USE_STAT) */
+            if (lstat(fp, &sb) != 0)
+#endif /* defined(USE_STAT) */
+
+            {
+                if (errno == ENOENT) /* symbolic link to nowhere? */
+                    continue;
+
+#if defined(WARNDEVACCESS)
+                if (!Fwarn) {
+                    int errno_save = errno;
+
+                    (void)fprintf(stderr, "%s: can't stat: ", Pn);
+                    safestrprt(fp, stderr, 0);
+                    (void)fprintf(stderr, ": %s\n", strerror(errno_save));
+                }
+#endif /* defined(WARNDEVACCESS) */
+
+                continue;
+            }
+            /*
+             * If it's a subdirectory, stack its name for later processing.
+             */
+            if ((sb.st_mode & S_IFMT) == S_IFDIR) {
+                (void)stkdir(ctx, fp);
+                continue;
+            }
+            if ((sb.st_mode & S_IFMT) == S_IFCHR) {
+
+                /*
+                 * Save character device information.
+                 */
+                if (i >= Ndev) {
+                    Ndev += DEVINCR;
+                    if (!Devtp)
+                        Devtp = (struct l_dev *)malloc(
+                            (MALLOC_S)(sizeof(struct l_dev) * Ndev));
+                    else
+                        Devtp = (struct l_dev *)realloc(
+                            (MALLOC_P *)Devtp,
+                            (MALLOC_S)(sizeof(struct l_dev) * Ndev));
+                    if (!Devtp) {
+                        (void)fprintf(
+                            stderr, "%s: no space for character device\n", Pn);
+                        Error(ctx);
+                    }
+                }
+                Devtp[i].rdev = sb.st_rdev;
+                Devtp[i].inode = (INODETYPE)sb.st_ino;
+                if (!(Devtp[i].name = mkstrcpy(fp, (MALLOC_S *)NULL))) {
+                    (void)fprintf(stderr, "%s: no space for: ", Pn);
+                    safestrprt(fp, stderr, 1);
+                    Error(ctx);
+                }
+                Devtp[i].v = 0;
+                i++;
+
+#if AIXV >= 4140
+                /*
+                 * Save information on AIX 4.1.4 and above clone devices.
+                 */
+                if (CloneMaj >= 0 && CloneMaj == GET_MAJ_DEV(sb.st_rdev)) {
+                    if (!(c = (struct clone *)malloc(
+                              (MALLOC_S)sizeof(struct clone)))) {
+                        (void)fprintf(stderr,
+                                      "%s: no space for clone device: ", Pn);
+                        safestrprt(fp, stderr, 1);
+                        Error(ctx);
+                    }
+                    if (!(c->cd.name = mkstrcpy(fp, (MALLOC_S)NULL))) {
+                        (void)fprintf(stderr,
+                                      "%s: no space for clone name: ", Pn);
+                        safestrprt(fp, stderr, 1);
+                        Error(ctx);
+                    }
+                    c->cd.inode = (INODETYPE)sb.st_ino;
+                    c->cd.rdev = sb.st_rdev;
+                    c->cd.v = 0;
+                    c->next = Clone;
+                    Clone = c;
+                    if (ClonePtc < 0 && strcmp(path, "/dev/ptc") == 0)
+                        ClonePtc = GET_MIN_DEV(sb.st_rdev);
+                }
+#endif /* AIXV >=4140 */
+            }
+
+#if defined(HASBLKDEV)
+            if ((sb.st_mode & S_IFMT) == S_IFBLK) {
+
+                /*
+                 * Save block device information in BDevtp[].
+                 */
+                if (j >= BNdev) {
+                    BNdev += DEVINCR;
+                    if (!BDevtp)
+                        BDevtp = (struct l_dev *)malloc(
+                            (MALLOC_S)(sizeof(struct l_dev) * BNdev));
+                    else
+                        BDevtp = (struct l_dev *)realloc(
+                            (MALLOC_P *)BDevtp,
+                            (MALLOC_S)(sizeof(struct l_dev) * BNdev));
+                    if (!BDevtp) {
+                        (void)fprintf(stderr, "%s: no space for block device\n",
+                                      Pn);
+                        Error(ctx);
+                    }
+                }
+                BDevtp[j].rdev = sb.st_rdev;
+                BDevtp[j].inode = (INODETYPE)sb.st_ino;
+                BDevtp[j].name = fp;
+                fp = (char *)NULL;
+                BDevtp[j].v = 0;
+                j++;
+            }
+#endif /* defined(HASBLKDEV) */
+        }
+        (void)closedir(dfp);
+    }
+    /*
+     * Free any allocated space.
+     */
+    if (Dstk) {
+        (void)free((FREE_P *)Dstk);
+        Dstk = (char **)NULL;
+        Dstkn = Dstkx = 0;
+    }
+    if (fp)
+        (void)free((FREE_P *)fp);
+    if (path)
+        (void)free((FREE_P *)path);
+        /*
+         * Reduce the BDevtp[] (optional) and Devtp[] tables to their minimum
+         * sizes; allocate and build sort pointer lists; and sort the tables by
+         * device number.
+         */
+
+#if defined(HASBLKDEV)
+    if (BNdev) {
+        if (BNdev > j) {
+            BNdev = j;
+            BDevtp = (struct l_dev *)realloc(
+                (MALLOC_P *)BDevtp, (MALLOC_S)(sizeof(struct l_dev) * BNdev));
+        }
+        if (!(BSdev = (struct l_dev **)malloc(
+                  (MALLOC_S)(sizeof(struct l_dev *) * BNdev)))) {
+            (void)fprintf(stderr,
+                          "%s: no space for block device sort pointers\n", Pn);
+            Error(ctx);
+        }
+        for (j = 0; j < BNdev; j++) {
+            BSdev[j] = &BDevtp[j];
+        }
+        (void)qsort((QSORT_P *)BSdev, (size_t)BNdev,
+                    (size_t)sizeof(struct l_dev *), compdev);
+        BNdev = rmdupdev(ctx, &BSdev, BNdev, "block");
+    } else {
+        if (!Fwarn)
+            (void)fprintf(stderr, "%s: WARNING: no block devices found\n", Pn);
+    }
+#endif /* defined(HASBLKDEV) */
+
+    if (Ndev) {
+        if (Ndev > i) {
+            Ndev = i;
+            Devtp = (struct l_dev *)realloc(
+                (MALLOC_P *)Devtp, (MALLOC_S)(sizeof(struct l_dev) * Ndev));
+        }
+        if (!(Sdev = (struct l_dev **)malloc(
+                  (MALLOC_S)(sizeof(struct l_dev *) * Ndev)))) {
+            (void)fprintf(stderr,
+                          "%s: no space for character device sort pointers\n",
+                          Pn);
+            Error(ctx);
+        }
+        for (i = 0; i < Ndev; i++) {
+            Sdev[i] = &Devtp[i];
+        }
+        (void)qsort((QSORT_P *)Sdev, (size_t)Ndev,
+                    (size_t)sizeof(struct l_dev *), compdev);
+        Ndev = rmdupdev(ctx, &Sdev, Ndev, "char");
+    } else {
+        (void)fprintf(stderr, "%s: no character devices found\n", Pn);
+        Error(ctx);
+    }
+
+#if defined(HASDCACHE)
+    /*
+     * Write device cache file, as required.
+     */
+    if (DCstate == 1 || (DCstate == 3 && dcrd))
+        write_dcache(ctx);
+#endif /* defined(HASDCACHE) */
+}
+
+#if defined(HASDCACHE)
+/*
+ * rereaddev() - reread device names, modes and types
+ */
+
+void rereaddev(struct lsof_context *ctx) {
+    (void)clr_devtab(ctx);
+
+#    if defined(DCACHE_CLR)
+    (void)DCACHE_CLR(ctx);
+#    endif /* defined(DCACHE_CLR) */
+
+    readdev(ctx, 1);
+    DCunsafe = 0;
+}
+#endif /* defined(HASDCACHE) */
+
+/*
+ * rmdupdev() - remove duplicate (major/minor/inode) devices
+ */
+
+static int rmdupdev(struct lsof_context *ctx, /* context */
+                    struct l_dev ***dp, /* device table pointers address */
+                    int n,              /* number of pointers */
+                    char *nm) /* device table name for error message */
+{
+
+#if AIXV >= 4140
+    struct clone *c, *cp;
+#endif /* AIXV>=4140 */
+
+    int i, j, k;
+    struct l_dev **p;
+
+    for (i = j = 0, p = *dp; i < n;) {
+        for (k = i + 1; k < n; k++) {
+            if (p[i]->rdev != p[k]->rdev || p[i]->inode != p[k]->inode)
+                break;
+
+#if AIXV >= 4140
+            /*
+             * See if we're deleting a duplicate clone device.  If so,
+             * delete its clone table entry.
+             */
+            for (c = Clone, cp = (struct clone *)NULL; c; cp = c, c = c->next) {
+                if (c->cd.rdev != p[k]->rdev || c->cd.inode != p[k]->inode ||
+                    strcmp(c->cd.name, p[k]->name))
+                    continue;
+                if (!cp)
+                    Clone = c->next;
+                else
+                    cp->next = c->next;
+                if (c->cd.name)
+                    (void)free((FREE_P *)c->cd.name);
+                (void)free((FREE_P *)c);
+                break;
+            }
+#endif /* AIXV>=4140 */
+        }
+        if (i != j)
+            p[j] = p[i];
+        j++;
+        i = k;
+    }
+    if (n == j)
+        return (n);
+    if (!(*dp = (struct l_dev **)realloc(
+              (MALLOC_P *)*dp, (MALLOC_S)(j * sizeof(struct l_dev *))))) {
+        (void)fprintf(stderr, "%s: can't realloc %s device pointers\n", Pn, nm);
+        Error(ctx);
+    }
+    return (j);
+}
+
+#if defined(HASDCACHE) && AIXV >= 4140
+/*
+ * rw_clone_sect() - read/write the device cache file clone section
+ */
+
+int rw_clone_sect(struct lsof_context *ctx, /* context */
+                  int m)                    /* mode: 1 = read; 2 = write */
+{
+    char buf[MAXPATHLEN * 2], *cp;
+    struct clone *c;
+    int i, len, n;
+
+    if (m == 1) {
+
+        /*
+         * Read the clone section header and validate it.
+         */
+        if (!fgets(buf, sizeof(buf), DCfs)) {
+
+        bad_clone_sect:
+
+            if (!Fwarn) {
+                (void)fprintf(stderr,
+                              "%s: bad clone section header in %s: ", Pn,
+                              DCpath[DCpathX]);
+                safestrprt(buf, stderr, 1);
+            }
+            return (1);
+        }
+        (void)crc(buf, strlen(buf), &DCcksum);
+        len = strlen("clone section: ");
+        if (strncmp(buf, "clone section: ", len) != 0)
+            goto bad_clone_sect;
+        if ((n = atoi(&buf[len])) < 0)
+            goto bad_clone_sect;
+        /*
+         * Read the clone section lines and create the Clone list.
+         */
+        for (i = 0; i < n; i++) {
+            if (!fgets(buf, sizeof(buf), DCfs)) {
+                if (!Fwarn) {
+                    (void)fprintf(stderr, "%s: bad clone line in %s: ", Pn,
+                                  DCpath[DCpathX]);
+                    safestrprt(buf, stderr, 1);
+                }
+                return (1);
+            }
+            (void)crc(buf, strlen(buf), &DCcksum);
+            /*
+             * Allocate a clone structure.
+             */
+            if (!(c = (struct clone *)calloc(1, sizeof(struct clone)))) {
+                (void)fprintf(stderr, "%s: no space for cached clone: ", Pn);
+                safestrprt(buf, stderr, 1);
+                Error(ctx);
+            }
+            /*
+             * Enter the clone device number.
+             */
+            if (!(cp = x2dev(buf, &c->cd.rdev)) || *cp++ != ' ') {
+
+            bad_cached_clone:
+                if (!Fwarn) {
+                    (void)fprintf(stderr, "%s: bad cached clone device: ", Pn);
+                    safestrprt(buf, stderr, 1);
+                }
+                return (1);
+            }
+            CloneMaj = GET_MAJ_DEV(c->cd.rdev);
+            /*
+             * Enter the clone inode number.
+             */
+            for (c->cd.inode = (INODETYPE)0; *cp != ' '; cp++) {
+                if (*cp < '0' || *cp > '9')
+                    goto bad_cached_clone;
+                c->cd.inode = (INODETYPE)((c->cd.inode * 10) + (*cp - '0'));
+            }
+            /*
+             * Enter the clone path name.
+             */
+            if ((len = strlen(++cp)) < 2 || *(cp + len - 1) != '\n') {
+                if (!Fwarn) {
+                    (void)fprintf(stderr, "%s: bad cached clone path: ", Pn);
+                    safestrprt(buf, stderr, 1);
+                }
+                return (1);
+            }
+            *(cp + len - 1) = '\0';
+            if (!(c->cd.name = mkstrcpy(cp, (MALLOC_S *)NULL))) {
+                (void)fprintf(stderr,
+                              "%s: no space for cached clone path: ", Pn);
+                safestrprt(buf, stderr, 1);
+                Error(ctx);
+            }
+            c->cd.v = 0;
+            c->next = Clone;
+            Clone = c;
+            if (ClonePtc < 0 && strcmp(c->cd.name, "/dev/ptc") == 0)
+                ClonePtc = GET_MIN_DEV(c->cd.rdev);
+        }
+        return (0);
+    } else if (m == 2) {
+
+        /*
+         * Write the clone section header.
+         */
+        for (c = Clone, n = 0; c; c = c->next, n++)
+            ;
+        (void)snpf(buf, sizeof(buf), "clone section: %d\n", n);
+        if (wr2DCfd(buf, &DCcksum))
+            return (1);
+        /*
+         * Write the clone section lines.
+         */
+        for (c = Clone; c; c = c->next) {
+            (void)snpf(buf, sizeof(buf), "%x %ld %s\n", c->cd.rdev,
+                       (long)c->cd.inode, c->cd.name);
+            if (wr2DCfd(buf, &DCcksum))
+                return (1);
+        }
+        return (0);
+    }
+    /*
+     * A shouldn't-happen case: mode neither 1 nor 2.
+     */
+    (void)fprintf(stderr, "%s: internal rw_clone_sect error: %d\n", Pn, m);
+    Error(ctx);
+}
+#endif /* defined(HASDCACHE) && AIXV>=4140 */
+
+#if defined(HASDCACHE)
+/*
+ * vfy_dev() - verify a device table entry (usually when DCunsafe == 1)
+ *
+ * Note: rereads entire device table when an entry can't be verified.
+ */
+
+int vfy_dev(struct lsof_context *ctx, /* context */
+            struct l_dev *dp)         /* device table pointer */
+{
+    struct stat sb;
+
+    if (!DCunsafe || dp->v)
+        return (1);
+
+#    if defined(USE_STAT)
+    if (stat(dp->name, &sb) != 0
+#    else  /* !defined(USE_STAT) */
+    if (lstat(dp->name, &sb) != 0
+#    endif /* defined(USE_STAT) */
+
+        || dp->rdev != sb.st_rdev || dp->inode != (INODETYPE)sb.st_ino) {
+        (void)rereaddev(ctx);
+        return (0);
+    }
+    dp->v = 1;
+    return (1);
+}
+#endif /* defined(HASDCACHE) */
diff --git a/lib/dialects/aix/dfile.c b/lib/dialects/aix/dfile.c
new file mode 100644 (file)
index 0000000..cc70cc9
--- /dev/null
@@ -0,0 +1,523 @@
+/*
+ * dfile.c - AIX file processing functions for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#ifndef lint
+static char copyright[] =
+    "@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
+#endif
+
+#include "common.h"
+
+/*
+ * Local structures
+ */
+
+/*
+ * Local static variables
+ */
+
+static struct hsfile *HbyMPC = /* hash by MPC file buckets */
+    (struct hsfile *)NULL;
+static int HbyMPCCt = 0; /* HbyMPC entry count */
+
+/*
+ * Local definitions
+ */
+
+#define SFDIHASH                                                               \
+    4094 /* Sfile hash by (device,inode) number                                \
+          * pair bucket count (power of 2!) */
+#define SFFSHASH                                                               \
+    128 /* 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 m
+ * (m must be a power of 2) */
+#define SFMPCHASH 1024 /* Sfile hash by MPC device number */
+#define SFNMHASH                                                               \
+    4096 /* Sfile hash by name bucket count                                    \
+  (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) */
+
+/*
+ * hashSfile() - hash Sfile entries for use in is_file_named() searches
+ */
+
+void hashSfile(struct lsof_context *ctx) {
+    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, MPC 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);
+        Error(ctx);
+    }
+    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);
+        Error(ctx);
+    }
+    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);
+        Error(ctx);
+    }
+    if (!(HbyMPC = (struct hsfile *)calloc((MALLOC_S)SFMPCHASH,
+                                           sizeof(struct hsfile)))) {
+        (void)fprintf(stderr,
+                      "%s: can't allocate space for %d MPC file hash buckets\n",
+                      Pn, SFMPCHASH);
+        Error(ctx);
+    }
+    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);
+        Error(ctx);
+    }
+    hs++;
+    /*
+     * Scan the Sfile chain, building file, file system, MPC file, and file
+     * name hash bucket chains.
+     */
+    for (s = Sfile; s; s = s->next) {
+        for (i = 0; i < 4; i++) {
+            if (i == 0) {
+                if (!s->aname)
+                    continue;
+                sh = &HbyNm[hashbyname(s->aname, SFNMHASH)];
+                HbyNmCt++;
+            } else if (i == 1) {
+                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++;
+                }
+            } else if (i == 2) {
+                if (s->type && (s->ch < 0) && (s->mode == S_IFCHR)) {
+                    sh = &HbyMPC[SFHASHDEVINO(GET_MAJ_DEV(s->dev),
+                                              GET_MIN_DEV(s->dev), 0,
+                                              SFMPCHASH)];
+                    HbyMPCCt++;
+                } else
+                    continue;
+            } else if (i == 3) {
+                if (s->type && (((s->mode == S_IFCHR) && (s->ch < 0)) ||
+                                ((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;
+            }
+            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);
+                    Error(ctx);
+                }
+                sn->s = s;
+                sn->next = sh->next;
+                sh->next = sn;
+            }
+        }
+    }
+}
+
+/*
+ * is_file_named() - is file named?
+ */
+
+int is_file_named(struct lsof_context *ctx, /* context */
+                  char *p,       /* path name; NULL = search by device
+                                  * and inode (from *Lf) */
+                  enum vtype ty, /* vnode type */
+                  chan_t ch,     /* gnode channel */
+                  int ic)        /* is clone file (4.1.4 and above) */
+{
+    int dmaj, dmin, maj, min, rmaj, rmin;
+    static int dsplit = 0;
+    char *ep;
+    int f = 0;
+    struct sfile *s;
+    struct hsfile *sh;
+    size_t sz;
+    /*
+     * Split the device numbers into their major and minor numbers.
+     *
+     * THis is necessitated by 64 bit AIX architectures, which store two
+     * different types of device numbers in 64 bit dev_t's.  The two types can't
+     * be compared directly, but must be compared by extracting their major and
+     * minor numbers and comparing them.
+     */
+    readdev(ctx, 0);
+    if (!dsplit) {
+        dmaj = GET_MAJ_DEV(DevDev);
+        dmin = GET_MIN_DEV(DevDev);
+        dsplit = 1;
+    }
+    if (Lf->dev_def) {
+        maj = GET_MAJ_DEV(Lf->dev);
+        min = GET_MIN_DEV(Lf->dev);
+    }
+    if (Lf->rdev_def) {
+        rmaj = GET_MAJ_DEV(Lf->rdev);
+        rmin = GET_MIN_DEV(Lf->rdev);
+    }
+
+#if AIXV >= 4140
+    /*
+     * Check for a clone match.
+     */
+    if (ic && HbyFdiCt && CloneMaj >= 0 &&
+        (Lf->dev_def && (maj = dmaj) && (min == dmin)) && Lf->rdev_def &&
+        (Lf->inp_ty == 1 || Lf->inp_ty == 3)) {
+        for (sh = &HbyFdi[SFHASHDEVINO(CloneMaj, rmaj, Lf->inode, SFDIHASH)];
+             sh; sh = sh->next) {
+            if ((s = sh->s) && (GET_MAJ_DEV(s->rdev) == CloneMaj) &&
+                (GET_MIN_DEV(s->rdev) == rmaj) && (s->i == Lf->inode)) {
+                f = 3;
+                break;
+            }
+        }
+    }
+#endif /* AIXV>=4140 */
+
+    /*
+     * Check for a path name match, as requested.
+     */
+    if (!f && 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 AIX multiplexed file, matching the channel if
+     * it was supplied by the caller.
+     */
+    if (!f && HbyMPCCt && ty == VMPC &&
+        (Lf->dev_def && (maj == dmaj) && (min == dmin)) && Lf->rdev_def) {
+        for (sh = &HbyMPC[SFHASHDEVINO(rmaj, rmin, 0, SFMPCHASH)]; sh;
+             sh = sh->next) {
+            if ((s = sh->s) && (GET_MAJ_DEV(s->dev) == rmaj) &&
+                (GET_MIN_DEV(s->dev) == rmin) && (s->ch < 0 || ch == s->ch)) {
+                f = 1;
+                break;
+            }
+        }
+    }
+    /*
+     * Check for a regular file.
+     */
+    if (!f && HbyFdiCt && Lf->dev_def && (Lf->inp_ty == 1 || Lf->inp_ty == 3)) {
+        for (sh = &HbyFdi[SFHASHDEVINO(maj, min, Lf->inode, SFDIHASH)]; sh;
+             sh = sh->next) {
+            if ((s = sh->s) && (maj == GET_MAJ_DEV(s->dev)) &&
+                (min == GET_MIN_DEV(s->dev)) && (Lf->inode == s->i)) {
+                f = 1;
+                break;
+            }
+        }
+    }
+    /*
+     * Check for a file system.
+     */
+    if (!f && HbyFsdCt && Lf->dev_def) {
+        for (sh = &HbyFsd[SFHASHDEVINO(maj, min, 0, SFFSHASH)]; sh;
+             sh = sh->next) {
+            if ((s = sh->s) && (maj == GET_MAJ_DEV(s->dev)) &&
+                (min == GET_MIN_DEV(s->dev))) {
+                f = 1;
+                break;
+            }
+        }
+    }
+    /*
+     * Check for a character or block device file.
+     */
+    if (!f && HbyFrdCt && ((ty == VCHR) || (ty == VBLK)) &&
+        (Lf->dev_def && (maj == dmaj) && (min == dmin)) && Lf->rdev_def &&
+        (Lf->inp_ty == 1 || Lf->inp_ty == 3)) {
+        for (sh = &HbyFrd[SFHASHRDEVI(maj, min, rmaj, rmin, Lf->inode,
+                                      SFRDHASH)];
+             sh; sh = sh->next) {
+            if ((s = sh->s) && (GET_MAJ_DEV(s->rdev) == rmaj) &&
+                (GET_MIN_DEV(s->rdev) == rmin) &&
+                (((ty == VCHR) && (s->mode == S_IFCHR) && (s->ch < 0)) ||
+                 ((ty == VBLK) && (s->mode == S_IFBLK)))) {
+                f = 1;
+                break;
+            }
+        }
+    }
+    /*
+     * Convert the name if a match occurred.
+     */
+    if (f) {
+        if (f == 2) {
+            (void)snpf(Namech, Namechl, "%s", p);
+
+#if AIXV >= 4140
+        } else if (f == 3 && ClonePtc >= 0 && (maj == ClonePtc)) {
+            (void)snpf(Namech, Namechl, "%s/%d", s->name, min);
+
+#endif /* AIXV>=4140 */
+
+        } else 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 (ty == VMPC && s->ch < 0) {
+                ep = endnm(ctx, &sz);
+                (void)snpf(ep, sz, "/%d", ch);
+            }
+            if (s->devnm) {
+                ep = endnm(ctx, &sz);
+                (void)snpf(ep, sz, " (%s)", s->devnm);
+            }
+        }
+        s->f = 1;
+        return (1);
+    }
+    return (0);
+}
+
+/*
+ * print_dev() - print device
+ */
+
+char *print_dev(struct lfile *lf, /* file whose device to be printed */
+                dev_t *dev)       /* pointer to device to be printed */
+{
+    static char buf[128];
+    int maj = GET_MAJ_DEV(*dev);
+    int min = GET_MIN_DEV(*dev);
+
+#if AIXV >= 3200
+    if (*dev & SDEV_REMOTE) {
+        (void)snpf(buf, sizeof(buf), "NFS,%d", (min & ~SDEV_REMOTE));
+        return (buf);
+    }
+#endif /* AIXV>=3200 */
+
+    (void)snpf(buf, sizeof(buf), "%d,%d", maj, min);
+    return (buf);
+}
+
+/*
+ * readvfs() - read vfs structure
+ */
+
+struct l_vfs *readvfs(struct lsof_context *ctx, /* context */
+                      struct vnode *vn)         /* vnode */
+{
+    struct gfs g;
+    void *mp;
+    char *s1, *s2;
+    uint ul;
+    struct vfs v;
+    struct vmount *vm;
+    struct l_vfs *vp;
+
+    if (!vn->v_vfsp)
+        return ((struct l_vfs *)NULL);
+    for (vp = Lvfs; vp; vp = vp->next) {
+        if ((KA_T)vn->v_vfsp == vp->addr)
+            return (vp);
+    }
+    if (!(vp = (struct l_vfs *)malloc((MALLOC_S)sizeof(struct l_vfs)))) {
+        (void)fprintf(stderr, "%s: PID %d, no space for vfs\n", Pn, Lp->pid);
+        Error(ctx);
+    }
+    vp->dir = (char *)NULL;
+    vp->fsname = (char *)NULL;
+    /*
+     * Read the vfs structure.
+     */
+    if (kread(ctx, (KA_T)vn->v_vfsp, (char *)&v, sizeof(v))) {
+
+    vfs_exit:
+        (void)free((FREE_P *)vp);
+        return ((struct l_vfs *)NULL);
+    }
+    /*
+     * Locate AIX mount information.
+     */
+    if (!v.vfs_gfs || kread(ctx, (KA_T)v.vfs_gfs, (char *)&g, sizeof(g)))
+        goto vfs_exit;
+    if (!v.vfs_mdata ||
+        kread(ctx,
+              (KA_T)((char *)v.vfs_mdata + offsetof(struct vmount, vmt_length)),
+              (char *)&ul, sizeof(ul)))
+        goto vfs_exit;
+    if (!(mp = (void *)malloc((MALLOC_S)ul))) {
+        (void)fprintf(stderr, "%s: PID %d, no space for mount data\n", Pn,
+                      Lp->pid);
+        Error(ctx);
+    }
+    if (kread(ctx, (KA_T)v.vfs_mdata, (char *)mp, (int)ul)) {
+        (void)free((FREE_P *)mp);
+        goto vfs_exit;
+    }
+    vm = (struct vmount *)mp;
+    vp->vmt_flags = vm->vmt_flags;
+    vp->vmt_gfstype = vm->vmt_gfstype;
+
+#if AIXV >= 3200
+    if ((vp->vmt_flags & MNT_REMOTE)
+
+#    if defined(HAS_SANFS) && defined(MNT_SANFS)
+        && (vp->vmt_gfstype != MNT_SANFS)
+#    endif /* defined(HAS_SANFS) && defined(MNT_SANFS) */
+
+    ) {
+        vp->dev = 0x80000000 | vm->vmt_vfsnumber;
+#    if AIXA >= 1
+        vp->dev |= 0x8000000000000000;
+#    endif /* AIXA>=1 */
+    } else
+#endif /* AIXV>=3200 */
+
+#if defined(HAS_AFS)
+        if (vm->vmt_gfstype == MNT_AFS)
+        vp->dev = AFSDEV;
+    else
+#endif /* defined(HAS_AFS) */
+
+#if AIXA > 1
+        if (vm->vmt_gfstype == MNT_PROCFS) {
+
+        /*
+         * !!!DEBUG!!!   !!!DEBUG!!!   !!!DEBUG!!!   !!!DEBUG!!!   !!!DEBUG!!!
+         *
+         * The following *hack* is required to make the vmount structure's
+         * device number match what stat(2) errnoneously returns in ia64
+         * AIX >= 5.
+         *
+         * REMOVE THIS CODE WHEN STAT(2) IS FIXED!!!
+         */
+        vp->dev = (dev_t)(vm->vmt_fsid.fsid_dev & 0x7fffffffffffffff);
+        /*
+         * !!!DEBUG!!!   !!!DEBUG!!!   !!!DEBUG!!!   !!!DEBUG!!!   !!!DEBUG!!!
+         */
+
+    } else
+#endif /* AIXA>1 */
+
+        vp->dev = (dev_t)vm->vmt_fsid.fsid_dev;
+    if ((s1 = vmt2dataptr(vm, VMT_STUB))) {
+        if (!(vp->dir = mkstrcpy(s1, (MALLOC_S *)NULL))) {
+
+        readvfs_aix1:
+            (void)fprintf(stderr, "%s: PID %d, readvfs, no space\n", Pn,
+                          Lp->pid);
+            Error(ctx);
+        }
+    } else
+        vp->dir = (char *)NULL;
+    s1 = vmt2dataptr(vm, VMT_HOST);
+    if (!(s2 = vmt2dataptr(vm, VMT_OBJECT)) || *s1 == '\0')
+        s2 = g.gfs_name;
+    if (!s1 && !s2)
+        vp->fsname = (char *)NULL;
+    else {
+        if (vm->vmt_flags & MNT_REMOTE) {
+            if (!(vp->fsname =
+                      mkstrcat(s1 ? s1 : "", -1, (s1 && *s1) ? ":" : "", -1, s2,
+                               -1, (MALLOC_S *)NULL)))
+                goto readvfs_aix1;
+        } else {
+            if (!(vp->fsname = mkstrcpy(s2, (MALLOC_S *)NULL)))
+                goto readvfs_aix1;
+        }
+    }
+    (void)free((FREE_P *)mp);
+    vp->next = Lvfs;
+    vp->addr = (KA_T)vn->v_vfsp;
+
+#if defined(HAS_AFS)
+    if (!AFSVfsp && vm->vmt_gfstype == MNT_AFS)
+        AFSVfsp = (KA_T)vn->v_vfsp;
+#endif /* defined(HAS_AFS) */
+
+    Lvfs = vp;
+    return (vp);
+}
diff --git a/lib/dialects/aix/dlsof.h b/lib/dialects/aix/dlsof.h
new file mode 100644 (file)
index 0000000..6293ffc
--- /dev/null
@@ -0,0 +1,432 @@
+/*
+ * dlsof.h - AIX header file for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+/*
+ * $Id: dlsof.h,v 1.32 2006/03/27 23:09:21 abe Exp $
+ */
+
+#if !defined(AIX_LSOF_H)
+#    define AIX_LSOF_H 1
+
+/*
+ * AIXA stands for AIX architecure.  It is given these values in the
+ * aix stanza of the lsof Configure script:
+ *
+ *     0       The AIX version is < 5, or the AIX architecture is power and
+ *             the kernel bit size is 32.
+ *
+ *     1       The AIX version is >= 5, the AIX architecture is Power, and
+ *             the kernel bit size is 64.
+ *
+ *     2       The AIX version is > 5 and the architecture is IA64.
+ */
+
+#    if AIXA > 1
+#        include <nlist.h>
+#    endif /* AIXA>1 */
+
+#    include <stdlib.h>
+#    include <string.h>
+#    include <dirent.h>
+#    include <setjmp.h>
+#    include <unistd.h>
+
+#    if !defined(_KERNEL)
+#        define _KERNEL 1
+#    endif /* !defined(_KERNEL) */
+
+#    include <sys/vnode.h>
+#    include <sys/file.h>
+#    include <procinfo.h> /* <procinfo.h> #includes <sys/user.h> */
+#    define p_pid pi_pid
+#    define p_pgid pi_pgrp
+#    define p_ppid pi_ppid
+
+#    if AIXV < 4300
+#        define p_stat pi_stat
+#    else /* AIXV>=4300 */
+#        define p_stat pi_state
+#        include <sys/systemcfg.h>
+#    endif /* AIXV<4300 */
+
+#    define p_uid pi_uid
+#    undef sleep
+#    undef _KERNEL
+
+#    if AIXA > 1
+#        define _NET_NET_MALLOC /* to keep <sys/mbuf.h> from #include'ing      \
+                                 * <sys/ppda.h>, which is missing from         \
+                                 * ia64 AIX 5L */
+#    endif                      /* AIXA>1 */
+
+#    include <sys/mbuf.h>
+#    include <sys/mntctl.h>
+#    include <sys/protosw.h>
+#    include <sys/socket.h>
+#    include <sys/socketvar.h>
+
+#    if AIXV >= 4140
+#        include <sys/stream.h>
+#    endif /* AIXV>=4140 */
+
+#    include <sys/sysmacros.h>
+#    include <sys/un.h>
+#    include <sys/unpcb.h>
+
+#    if defined(HASKERNIDCK) && AIXV >= 5000
+#        include <sys/utsname.h>
+#    endif /* defined(HASKERNIDCK) && AIXV>=5000 */
+
+#    include <netinet/in.h>
+#    include <net/route.h>
+#    include <net/raw_cb.h>
+
+#    if AIXV >= 4100
+#        include <netinet/ip.h>
+#    endif /* AIXV>=4100 */
+
+#    include <netinet/in_pcb.h>
+#    include <netinet/ip_var.h>
+#    include <netinet/tcp.h>
+#    include <netinet/tcpip.h>
+#    include <netinet/tcp_fsm.h>
+#    include <netinet/tcp_timer.h>
+#    include <netinet/tcp_var.h>
+#    include <sys/vattr.h>
+#    include <sys/statfs.h>
+
+#    include <rpc/rpc.h>
+#    include <rpc/pmap_prot.h>
+
+#    if defined(HAS_AFS)
+#        define __XDR_INCLUDE__
+#    endif /* defined(HAS_AFS) */
+
+#    include <sys/vfs.h>
+#    include <sys/vmount.h>
+
+#    if defined(HAS_SANFS) && !defined(MNT_SANFS)
+#        define MNT_SANFS 20
+#    endif /* defined(HAS_SANFS) && !defined(MNT_SANFS) */
+
+#    if AIXV >= 4100
+#        if AIXV >= 4110
+#            undef u
+#            undef u_comm
+#            undef u_cdir
+#            undef u_rdir
+#            undef u_maxofile
+#            undef u_ufd
+#            undef u_loader
+#        endif /* AIXV>=4110 */
+
+#        define u_comm U_comm
+#        define u_cdir U_cdir
+#        define u_rdir U_rdir
+#        define u_maxofile U_maxofile
+#        define u_ufd U_ufd
+#        define u_loader U_loader
+#    endif /* AIXV>=4100 */
+
+#    if AIXV >= 3200
+#        include <sys/specnode.h>
+#    endif /* AIXV>=3200 */
+
+/*
+ * AIX doesn't supply cdrnode.h.
+ */
+
+struct cdrnode {
+    caddr_t f1[4];
+    struct gnode f2;
+    dev_t f3;
+    ino_t cn_inumber; /* inode number */
+    caddr_t f4;
+    cnt_t f5[2];
+    u_short f6;
+    uint f7[2];
+    uchar f8[3];
+    off_t cn_size; /* size of file in bytes */
+};
+
+#    if defined(HAS_AFS)
+
+/*
+ *  Avoid typdef conflicts in <afs/stds.h>.
+ */
+
+#        if defined(HASINT16TYPE)
+#            define int16 AFS_int16
+#        endif /* defined(HASINT16TYPE */
+#        if defined(HASUINT16TYPE)
+#            define u_int16 AFS_u_int16
+#        endif /* defined(HASUINT16TYPE */
+#        if defined(HASINT32TYPE)
+#            define int32 AFS_int32
+#        endif /* defined(HASINT32TYPE) */
+
+#        include <afs/stds.h>
+#        include <afs/param.h>
+#        include <afs/afsint.h>
+#        include <afs/vldbint.h>
+#    endif /* defined(HAS_AFS) */
+
+/*
+ * Miscellaneous definitions.
+ */
+
+#    if defined(HAS_AFS)
+#        define AFSAPATHDEF "/usr/vice/etc/dkload/???"
+#        define AFSDEV 1 /* AFS "fake" device number */
+
+#        if !defined(MNT_AFS)
+#            define MNT_AFS AFS_MOUNT_AFS
+#        endif /* !defined(MNT_AFS) */
+#    endif     /* defined(HAS_AFS) */
+
+#    define COMP_P const void
+#    define DEVINCR 1024 /* device table malloc() increment */
+
+#    if AIXV < 4200
+typedef off_t KA_T;
+#    else /* AIXV>=4200 */
+#        if AIXA < 1
+typedef unsigned int KA_T;
+#        else /* AIXA>=1 */
+typedef u_longlong_t KA_T;
+#            define GET_MAJ_DEV(d)                                             \
+                (ISDEVNO64(d) ? major64(d) : major(d & ~SDEV_REMOTE))
+#            define GET_MIN_DEV(d)                                             \
+                (ISDEVNO64(d) ? (minor64(d) & ~SDEV_REMOTE) : minor(d))
+#            define KA_T_FMT_X "%#llx"
+#        endif /* AIXA<1 */
+#    endif     /* AIXV<4200 */
+
+#    define KMEM "/dev/kmem"
+
+#    if defined(HASSTAT64)
+#        define fstat fstat64
+#        define lstat lstat64
+#        define stat stat64
+#    endif /* defined(HASSTAT64) */
+
+#    define MALLOC_P char
+#    define FREE_P MALLOC_P
+#    define MALLOC_S size_t
+#    define MAXSYSCMDL MAXCOMLEN /* max system command name length */
+#    define N_UNIX "/unix"
+#    define QSORT_P void
+#    define READLEN_T size_t
+#    define STRNCPY_L size_t
+
+#    if AIXV >= 4200
+#        define SZOFFTYPE unsigned long long
+/* size and offset type definition */
+#        define SZOFFPSPEC "ll" /* SZOFFTYPE print specification modifier */
+#    endif                      /* AIXV>=4200 */
+
+#    define U_SIZE sizeof(struct user)
+
+/*
+ * Name list (Nl[]) indexes
+ */
+
+#    define X_UADDR 0
+#    define X_NL_NUM 1
+
+/*
+ * Definition for ckfa.c
+ */
+
+#    define CKFA_MPXCHAN 1
+
+/*
+ * Definitions for dvch.c
+ */
+
+#    if AIXV >= 4140
+#        define DCACHE_CLONE rw_clone_sect /* clone function for read_dcache   \
+                                            */
+#        define DCACHE_CLR                                                     \
+            clr_sect /* function to clear clone and                            \
+                      * pseudo caches when reading the                         \
+                      * device cache file fails */
+#    endif           /* AIXV>=4140 */
+
+/*
+ * Definitions for enter_dir()
+ */
+
+#    define DIRTYPE dirent
+#    define HASDNAMLEN 1
+
+#    if defined(HAS_AFS)
+/*
+ * AFS name list (AFSnl[]) indexes
+ */
+
+#        define X_AFS_FID 0
+#        define X_AFS_VOL 1
+#        define X_AFSNL_NUM 2
+#    endif /* defined(HAS_AFS) */
+
+#    if AIXV >= 4140
+/*
+ * Local clone information
+ */
+
+struct clone {
+    struct l_dev cd;    /* device, inode, name, verify status */
+    struct clone *next; /* next entry */
+};
+extern struct clone *Clone;
+extern int CloneMaj;
+extern int ClonePtc;
+#    endif /* AIXV>=4140 */
+
+/*
+ * Local inode information
+ */
+
+struct l_ino {
+    dev_t dev;                /* device */
+    long nlink;               /* link count */
+    INODETYPE number;         /* inode number */
+    SZOFFTYPE size;           /* file size */
+    unsigned char dev_def;    /* link count is defined */
+    unsigned char nlink_def;  /* link count is defined */
+    unsigned char number_def; /* number is defined */
+    unsigned char size_def;   /* size is defined */
+};
+
+/*
+ * Local vfs information
+ */
+
+struct l_vfs {
+    KA_T addr;          /* kernel address */
+    dev_t dev;          /* device */
+    char *dir;          /* mounted directory */
+    char *fsname;       /* file system name */
+    int vmt_flags;      /* vmount flags */
+    int vmt_gfstype;    /* vmount gfs type */
+    struct l_vfs *next; /* forward link */
+};
+extern struct l_vfs *Lvfs;
+
+/*
+ * Local mount information
+ */
+
+struct mounts {
+    char *dir;       /* directory (mounted on) */
+    char *fsname;    /* file system
+                      * (symbolic links unresolved) */
+    char *fsnmres;   /* file system
+                      * (symbolic links resolved) */
+    dev_t dev;       /* directory st_dev */
+    dev_t rdev;      /* directory st_rdev */
+    INODETYPE inode; /* directory st_ino */
+    u_short mode;    /* directory st_mode */
+    u_short fs_mode; /* file system st_mode */
+
+#    if defined(HASFSTYPE)
+    int fstype; /* fs type */
+#    endif      /* defined(HASFSTYPE) */
+
+    struct mounts *next; /* forward link */
+};
+extern struct mounts *Mtab;
+
+/*
+ * Search file information
+ */
+
+struct sfile {
+    char *aname;        /* file name argument */
+    char *name;         /* file name (after readlink()) */
+    char *devnm;        /* device name (optional) */
+    dev_t dev;          /* device */
+    dev_t rdev;         /* raw device */
+    chan_t ch;          /* channel (last path component,
+                         * (if numeric) */
+    u_short mode;       /* S_IFMT mode bits from stat() */
+    int type;           /* file type: 0 = file system
+                         *           1 = regular file */
+    INODETYPE i;        /* inode number */
+    int f;              /* file found flag */
+    struct sfile *next; /* forward link */
+};
+
+/*
+ * Miscellaneous external definitions
+ */
+
+#    if defined(HAS_AFS)
+extern struct nlist AFSnl[]; /* AFS kernel symbol name list table */
+
+#        if defined(HASAOPT)
+extern char *AFSApath; /* alternate AFS name list path (from -a) */
+#        endif         /* defined(HASAOPT) */
+
+extern KA_T AFSVfsp; /* AFS struct vfs kernel pointer */
+#    endif           /* defined(HAS_AFS) */
+
+extern int Kd;
+extern int Km;
+extern struct nlist Nl[];
+
+#    if defined(TCPSTATES) && AIXV <= 3250
+/*
+ * For AIX 3.2.5 and below, there is no header file with the  definition
+ * of tcpstates[], needed by ptti.c's print_tcptpi() function.
+ */
+
+static char *tcpstates[] = {"CLOSED",     "LISTEN",      "SYN_SENT",
+                            "SYN_RCVD",   "ESTABLISHED", "CLOSE_WAIT",
+                            "FIN_WAIT_1", "CLOSING",     "LAST_ACK",
+                            "FIN_WAIT_2", "TIME_WAIT"};
+#    endif /* defined(TCPSTATES) && AIXV<=3250 */
+
+#    if AIXA > 1
+/*
+ * This AIX 5 or above ia64 hack prevents the loader from linking lsof's
+ * kread() in preference to the kread() that read() uses.  The very existence
+ * of a system kread() is an unwarrranted invasion of user name space!
+ */
+
+#        define kread                                                          \
+            lsof_kread /* avoid conflict with the kread()                      \
+                        * in libc.so */
+#    endif             /* AIXA>1 */
+
+struct lsof_context_dialect {};
+
+#endif /* AIX_LSOF_H */
diff --git a/lib/dialects/aix/dmnt.c b/lib/dialects/aix/dmnt.c
new file mode 100644 (file)
index 0000000..dc2d2fe
--- /dev/null
@@ -0,0 +1,289 @@
+/*
+ * dmnt.c - AIX mount support functions for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#ifndef lint
+static char copyright[] =
+    "@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
+#endif
+
+#include "common.h"
+
+/*
+ * Local static definitions
+ */
+
+/*
+ * readmnt() - read mount table
+ */
+
+struct mounts *readmnt(struct lsof_context *ctx) {
+    char *dir, *fs, *h, *ln, *ty;
+    char *dn = (char *)NULL;
+    struct mounts *mtp;
+    int nm;
+    struct stat sb;
+    MALLOC_S sz;
+    struct vmount *v;
+    struct vmount *vt = (struct vmount *)NULL;
+
+    if (Lmi || Lmist)
+        return (Lmi);
+    /*
+     * Read the table of vmount structures.
+     */
+    for (sz = sizeof(struct vmount);;) {
+        if (!(vt = (struct vmount *)malloc(sz))) {
+            (void)fprintf(stderr, "%s: no space for vmount table\n", Pn);
+            return (0);
+        }
+        nm = mntctl(MCTL_QUERY, sz, (unsigned char *)vt);
+        if (nm > 0) {
+            if (vt->vmt_revision != VMT_REVISION) {
+                (void)fprintf(stderr, "%s: stale file system, rev %d != %d\n",
+                              Pn, vt->vmt_revision, VMT_REVISION);
+                return (0);
+            }
+            break;
+        }
+        if (nm == 0) {
+            sz = (unsigned)vt->vmt_revision;
+            (void)free((FREE_P *)vt);
+        } else {
+            (void)fprintf(stderr, "%s: mntctl error: %s\n", Pn,
+                          strerror(errno));
+            return (0);
+        }
+    }
+    /*
+     * Scan the vmount structures and build Lmi.
+     */
+    for (v = vt; nm--; v = (struct vmount *)((char *)v + v->vmt_length)) {
+        dir = (char *)vmt2dataptr(v, VMT_STUB);
+        fs = (char *)vmt2dataptr(v, VMT_OBJECT);
+        h = (char *)vmt2dataptr(v, VMT_HOST);
+        if (statsafely(ctx, dir, &sb)) {
+            if (!Fwarn) {
+
+                /*
+                 * Issue stat() failure warning.
+                 */
+                switch (v->vmt_gfstype) {
+
+#if defined(HAS_AFS)
+                case MNT_AFS:
+                    ty = "afs";
+                    break;
+#endif /* defined(HAS_AFS) */
+
+#if defined(MNT_AIX) && defined(MNT_J2) && MNT_AIX == MNT_J2
+                case MNT_AIX:
+                    ty = "jfs2";
+                    break;
+#else /* !defined(MNT_AIX) || !defined(MNT_J2) || MNT_AIX!=MNT_J2 */
+#    if defined(MNT_AIX)
+                case MNT_AIX:
+                    ty = "oaix";
+                    break;
+#    endif /* defined(MNT_AIX) */
+#    if defined(MNT_J2)
+                case MNT_J2:
+                    ty = "jfs2";
+                    break;
+#    endif /* defined(MNT_J2) */
+#endif     /* defined(MNT_AIX) && defined(MNT_H2) && MNT_AIX==MNT_J2 */
+
+                case MNT_CDROM:
+                    ty = "cdrom";
+                    break;
+                case MNT_JFS:
+                    ty = "jfs";
+                    break;
+                case MNT_NFS:
+                    ty = "nfs";
+                    break;
+
+#if defined(MNT_NFS3)
+                case MNT_NFS3:
+                    ty = "nfs3";
+                    break;
+#endif /* defined(MNT_NFS3) */
+
+#if defined(HASPROCFS)
+                case MNT_PROCFS:
+                    ty = HASPROCFS;
+                    break;
+#endif /* defined(HASPROCFS) */
+
+#if defined(MNT_SANFS)
+                case MNT_SANFS:
+                    ty = "sanfs";
+                    break;
+#endif /* defined(MNT_SANFS) */
+
+                default:
+                    ty = "unknown";
+                }
+                (void)fprintf(stderr,
+                              "%s: WARNING: can't stat() %s file system %s\n",
+                              Pn, ty, dir);
+                (void)fprintf(stderr,
+                              "      Output information may be incomplete.\n");
+            }
+            /*
+             * Assemble alternate device number and mode flags.
+             */
+            (void)bzero((char *)&sb, sizeof(sb));
+            if (v->vmt_flags & MNT_REMOTE) {
+
+#if AIXA < 2
+                sb.st_dev = (dev_t)(SDEV_REMOTE | v->vmt_vfsnumber);
+#else  /* AIXA>=2 */
+                sb.st_dev = (dev_t)(SDEV_REMOTE | (SDEV_REMOTE << 32) |
+                                    v->vmt_vfsnumber);
+#endif /* AIXA<2 */
+
+            } else {
+
+#if defined(HAS_AFS)
+                if (v->vmt_gfstype == MNT_AFS)
+                    sb.st_dev = AFSDEV;
+                else
+#endif /* defined(HAS_AFS) */
+
+#if AIXA >= 2 && defined(HASPROCFS)
+                    if (v->vmt_gfstype == MNT_PROCFS) {
+
+                    /*
+                     * !!!DEBUG!!!   !!!DEBUG!!!   !!!DEBUG!!!   !!!DEBUG!!!
+                     *
+                     * The following *hack* is required to make the vmount
+                     * structure's device number match what stat(2)
+                     * errnoneously returns on ia64 AIX 5L.
+                     *
+                     * REMOVE THIS CODE WHEN STAT(2) IS FIXED!!!
+                     */
+                    sb.st_dev =
+                        (dev_t)(v->vmt_fsid.val[0] & 0x7fffffffffffffff);
+                    /*
+                     * !!!DEBUG!!!   !!!DEBUG!!!   !!!DEBUG!!!   !!!DEBUG!!!
+                     */
+
+                } else
+#endif /* AIXA>=2 && defined(HASPROCFS) */
+
+                    sb.st_dev = (dev_t)v->vmt_fsid.val[0];
+            }
+            if (!Fwarn)
+                (void)fprintf(stderr,
+                              "      assuming \"dev=%#lx\" from mount table\n",
+                              sb.st_dev);
+            sb.st_mode = S_IFDIR | 0777;
+        }
+        /*
+         * Allocate space for the directory (mounted on) and resolve
+         * any symbolic links.
+         */
+        if (dn)
+            (void)free((FREE_P *)dn);
+        if (!(dn = mkstrcpy(dir, (MALLOC_S *)NULL))) {
+
+        no_space_for_mount:
+
+            (void)fprintf(stderr, "%s: no space for mount at %s (%s)\n", Pn, fs,
+                          dir);
+            Error(ctx);
+        }
+        if (!(ln = Readlink(ctx, 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;
+        /*
+         * Allocate a local mounts structure and fill the directory information.
+         */
+        if (!(mtp = (struct mounts *)malloc((MALLOC_S)sizeof(struct mounts))))
+            goto no_space_for_mount;
+        mtp->dir = dn;
+        dn = (char *)NULL;
+        mtp->dev = sb.st_dev;
+        mtp->inode = (INODETYPE)sb.st_ino;
+        mtp->mode = sb.st_mode;
+        mtp->rdev = sb.st_rdev;
+
+#if defined(HASFSTYPE)
+        mtp->fstype = sb.st_vfstype;
+#endif /* defined(HASFSTYPE) */
+
+        mtp->next = Lmi;
+        /*
+         * Form the file system (mounted-on) device name.  Resolve any
+         * symbolic links.  Allocate space for the result and store it in
+         * the local mounts structure.
+         */
+        if (h && (v->vmt_flags & MNT_REMOTE)) {
+            if (!(dn = mkstrcat(h, -1, *h ? ":" : "", 1, fs, -1,
+                                (MALLOC_S *)NULL)))
+                goto no_space_for_mount;
+        } else {
+            if (!(dn = mkstrcpy(fs, (MALLOC_S *)NULL)))
+                goto no_space_for_mount;
+        }
+        mtp->fsname = dn;
+        ln = Readlink(ctx, dn);
+        dn = (char *)NULL;
+        /*
+         * Stat the file system (mounted-on) device name to get its modes.
+         * Set the modes to zero if the stat fails.  Add file system
+         * (mounted-on) device information to the local mountsstructure.
+         */
+        if (!ln || statsafely(ctx, ln, &sb))
+            sb.st_mode = 0;
+        mtp->fsnmres = ln;
+        mtp->fs_mode = sb.st_mode;
+        Lmi = mtp;
+    }
+    /*
+     * Clean up and return local mount info table address.
+     */
+    if (dn)
+        (void)free((FREE_P *)dn);
+    if (vt)
+        (void)free((FREE_P *)vt);
+    Lmist = 1;
+    return (Lmi);
+}
diff --git a/lib/dialects/aix/dnode.c b/lib/dialects/aix/dnode.c
new file mode 100644 (file)
index 0000000..c220cfc
--- /dev/null
@@ -0,0 +1,1257 @@
+/*
+ * dnode.c - AIX node reading functions for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#ifndef lint
+static char copyright[] =
+    "@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
+#endif
+
+#include "common.h"
+
+/*
+ * Local definitions
+ */
+
+#if AIXV < 5000
+#    define FL_NEXT next
+#else /* AIXV>=5000 */
+#    define FL_NEXT fl_next
+#    if !defined(ISVDEV)
+#        define ISVDEV(t)                                                      \
+            (((t) == VBLK) || ((t) == VCHR) || ((t) == VFIFO) || ((t) == VMPC))
+#    endif /* !defined(ISVDEV) */
+#endif     /* AIXV<5000 */
+
+#if defined(HAS_NFS)
+#    if AIXV < 4210
+#        include <nfs/rnode.h>
+#    else /* AIXV>=4210 */
+#        if AIXA < 2
+/*
+ * Private rnode struct definitions for AIX 4.2.1 and above
+ *
+ * The rnode struct IBM ships in <nfs/rnode.h> doesn't match the one
+ * the kernel uses.  The kernel's rnode struct definition comes from
+ * <oncplus/nfs/rnode.h>, a header file IBM does not ship with AIX.
+ *
+ * The rnode64 struct is for AIX above 4.3.3 whose "width" is 64.
+ * (See dnode.c for the method used to determine width.)
+ */
+
+struct rnode {
+    caddr_t r_d1[11];     /* dummies; links? */
+    struct vnode r_vnode; /* vnode for remote file */
+    struct gnode r_gnode; /* gnode for remote file */
+    caddr_t r_d2[29];     /* dummies; rnode elements? */
+    off_t r_size;         /* client's view of file size (long)*/
+    struct vattr r_attr;  /* cached vnode attributes */
+};
+
+#            if AIXV > 4330
+struct rnode64 {
+
+#                if AIXV < 5200
+    caddr_t r_d1[11]; /* dummies; links? */
+#                else /* AIXV>=5200 */
+#                    if AIXV < 5300
+    caddr_t r_d1[12]; /* dummies; links? */
+#                    else  /* AIXV>=5300 */
+    caddr_t r_d1[7]; /* dummies; links? */
+#                    endif /* AIXV<5300 */
+#                endif     /* AIXV<5200 */
+
+    struct vnode r_vnode; /* vnode for remote file */
+    struct gnode r_gnode; /* gnode for remote file */
+
+#                if AIXV < 5300
+    caddr_t r_d2[15];     /* dummies; rnode elements? */
+#                else  /* AIXV>=5300 */
+    caddr_t r_d2[11]; /* dummies; rnode elements? */
+#                endif /* AIXV<5300 */
+
+    off_t r_size;        /* client's view of file size (long)*/
+    struct vattr r_attr; /* cached vnode attributes */
+};
+#            endif     /* AIXV>4330 */
+#        else          /* AIXA>=2 */
+struct rnode {
+    KA_T d1[7];           /* dummies */
+    struct vnode r_vnode; /* vnode for remote file */
+    struct gnode r_gnode; /* gnode for remote file */
+    KA_T d2[19];          /* dummies */
+    off_t r_size;         /* client's view of file size (long)*/
+    struct vattr r_attr;  /* cached vnode attributes */
+};
+#        endif         /* AIXA<2 */
+#    endif             /* AIXV<4210 */
+#endif                 /* defined(HAS_NFS) */
+
+/*
+ * isglocked() - is a gnode locked
+ */
+
+enum lsof_lock_mode isglocked(struct lsof_context *ctx, /* context */
+                              struct gnode *ga) /* local gnode address */
+{
+
+    struct filock *cfp, f, *ffp;
+    int l;
+
+    if (!(ffp = ga->gn_filocks))
+        return LSOF_LOCK_NONE;
+    cfp = ffp;
+
+#if AIXV >= 4140
+    do {
+#endif /* AIXV>=4140 */
+
+        if (kread(ctx, (KA_T)cfp, (char *)&f, sizeof(f)))
+            return LSOF_LOCK_NONE;
+
+#if AIXV >= 4140
+        if (f.set.l_sysid || f.set.l_pid != (pid_t)Lp->pid)
+            continue;
+#endif /* AIXV>=4140 */
+
+        if (f.set.l_whence == 0 && f.set.l_start == 0
+
+#if AIXV >= 4200
+            && f.set.l_end == 0x7fffffffffffffffLL
+#else  /* AIXV<4200 */
+        && f.set.l_end == 0x7fffffff
+#endif /* AIXV>=4200 */
+
+        )
+            l = 1;
+        else
+            l = 0;
+        switch (f.set.l_type & (F_RDLCK | F_WRLCK)) {
+
+        case F_RDLCK:
+            return l ? LSOF_LOCK_READ_FULL : LSOF_LOCK_READ_PARTIAL;
+        case F_WRLCK:
+            return (l) ? LSOF_LOCK_WRITE_FULL : LSOF_LOCK_WRITE_PARTIAL;
+        case (F_RDLCK + F_WRLCK):
+            return LSOF_LOCK_READ_WRITE;
+        }
+        return LSOF_LOCK_NONE;
+
+#if AIXV >= 4140
+    } while ((cfp = f.FL_NEXT) && cfp != ffp);
+    return LSOF_LOCK_NONE;
+#endif /* AIXV>=4140 */
+}
+
+/*
+ * process_node() - process vnode
+ */
+
+void process_node(struct lsof_context *ctx, /* context */
+                  KA_T va)                  /* vnode kernel space address */
+{
+    struct cdrnode c;
+    dev_t dev, rdev;
+    int devs = 0;
+    struct gnode g;
+    struct l_ino i;
+    int ic = 0;
+    int ins = 0;
+    struct vfs *la = NULL;
+    int rdevs = 0;
+    size_t sz;
+    char tbuf[32];
+    enum vtype type;
+    struct l_vfs *vfs;
+    static struct vnode *v = (struct vnode *)NULL;
+
+#if AIXV >= 3200
+    struct devnode dn;
+    struct gnode pg;
+    struct specnode sn;
+    struct fifonode f;
+#endif /* AIXV>=3200 */
+
+#if defined(HAS_AFS)
+    static int afs = 0; /* AFS test status: -1 = no AFS
+                         *                  0 = not tested
+                         *                  1 = AFS present */
+    struct afsnode an;
+#endif /* defined(HAS_AFS) */
+
+#if defined(HAS_NFS)
+    struct vattr nfs_attr;
+    int nfss = 0;
+    static struct rnode r;
+    static char *rp = (char *)&r;
+    static int rsz = sizeof(r);
+
+#    if AIXV > 4330 && AIXA < 2
+    static struct rnode64 r64;
+#    endif /* AIXV>4330 && AIXA<2 */
+
+#    if AIXA < 2
+    static int width = -1;
+#    else  /* AIXA>=2 */
+    static width = 64;
+#    endif /* AIXA<2 */
+#endif     /* defined(HAS_NFS) */
+
+#if defined(HAS_SANFS)
+    struct sanfs_node { /* DEBUG */
+
+        /*
+         * This is a DEBUG version of the SANFS node structure.  When IBM makes
+         * the SANFS header files available in /usr/include, this definition
+         * will be removed.
+         */
+        u_long san_d1[20];      /* DEBUG */
+        struct gnode san_gnode; /* DEBUG */
+        u_long san_d2[128];     /* DEBUG */
+    } san;
+    int sans = 0;
+#endif /* defined(HAS_SANFS) */
+
+#if AIXV >= 4140
+    struct clone *cl;
+    KA_T ka;
+    struct module_info mi;
+    int ml, nx;
+    char mn[32];
+    struct queue q;
+    struct qinit qi;
+    KA_T qp, xp;
+    int ql;
+    struct sth_s {    /* stream head */
+        KA_T *dummy;  /* dummy */
+        KA_T *sth_wq; /* write queue */
+    } sh;
+    struct xticb { /* XTI control block */
+        int d1;
+        long d2;
+        int d3;
+        struct socket *xti_so; /* socket pointer */
+    } xt;
+#endif /* AIXV>=4140 */
+
+    /*
+     * Read the vnode.
+     */
+    if (!va) {
+        enter_nm(ctx, "no vnode address");
+        return;
+    }
+    if (!v) {
+
+        /*
+         * Allocate space for the vnode or AFS vcache structure.
+         */
+
+#if defined(HAS_AFS)
+        v = alloc_vcache();
+#else  /* !defined(HAS_AFS) */
+        v = (struct vnode *)malloc((MALLOC_S)sizeof(struct vnode));
+#endif /* defined(HAS_AFS) */
+
+        if (!v) {
+            (void)fprintf(stderr, "%s: can't allocate %s space\n", Pn,
+
+#if defined(HAS_AFS)
+                          "vcache"
+#else  /* !defined(HAS_AFS) */
+                          "vnode"
+#endif /* defined(HAS_AFS) */
+
+            );
+            Error(ctx);
+        }
+    }
+    /*
+     * Read the vnode.
+     */
+    if (readvnode(ctx, va, v)) {
+        enter_nm(ctx, Namech);
+        return;
+    }
+
+#if defined(HASFSTRUCT)
+    Lf->fsv |= FSV_NI;
+    Lf->fna = va;
+#endif /* defined(HASFSTRUCT) */
+
+    /*
+     * Read the gnode.
+     */
+    if (!v->v_gnode || readgnode(ctx, (KA_T)v->v_gnode, &g)) {
+        if (Selinet) {
+            Lf->sf = SELEXCLF;
+            return;
+        }
+        (void)snpf(Namech, Namechl, "vnode at %s has no gnode\n",
+                   print_kptr(va, (char *)NULL, 0));
+        enter_nm(ctx, Namech);
+        return;
+    }
+
+#if AIXV >= 3200
+
+    /*
+     * Under AIX 3.2 and above, if the vnode type is ISVDEV, then there is a
+     * special node and a fifonode or devnode.  Behind them are the "real"
+     * gnode, inode and vnode.
+     */
+    if (ISVDEV(g.gn_type)) {
+        switch (g.gn_type) {
+        case VBLK:
+            Ntype = N_BLK;
+            break;
+        case VCHR:
+            Ntype = N_CHR;
+            break;
+        case VFIFO:
+            Ntype = N_FIFO;
+            break;
+        case VMPC:
+            Ntype = N_MPC;
+            break;
+        default:
+            (void)snpf(Namech, Namechl, "vnode at %s: unknown ISVDEV(%#x)",
+                       print_kptr(va, (char *)NULL, 0), g.gn_type);
+            enter_nm(ctx, Namech);
+            return;
+        }
+        /*
+         * Read the special node.
+         */
+        if (!g.gn_data ||
+            kread(ctx, (KA_T)g.gn_data, (char *)&sn, sizeof(sn))) {
+            if (Selinet) {
+                Lf->sf = SELEXCLF;
+                return;
+            }
+            (void)snpf(Namech, Namechl, "vnode at %s: can't read specnode (%s)",
+                       print_kptr(va, tbuf, sizeof(tbuf)),
+                       print_kptr((KA_T)g.gn_data, (char *)NULL, 0));
+            enter_nm(ctx, Namech);
+            return;
+        }
+        /*
+         * Read the PFS gnode and its inode and vnode.
+         */
+        if (sn.sn_pfsgnode) {
+            if (Selinet) {
+                Lf->sf = SELEXCLF;
+                return;
+            }
+            if (readgnode(ctx, (KA_T)sn.sn_pfsgnode, &g)) {
+                (void)snpf(Namech, Namechl,
+                           "vnode at %s: can't read pfsgnode (%s)",
+                           print_kptr(va, tbuf, sizeof(tbuf)),
+                           print_kptr((KA_T)sn.sn_pfsgnode, (char *)NULL, 0));
+                enter_nm(ctx, Namech);
+                return;
+            }
+            if (!g.gn_data || readlino(ctx, &g, &i)) {
+                (void)snpf(Namech, Namechl,
+                           "pfsgnode at %s: can't read inode (%s)",
+                           print_kptr((KA_T)sn.sn_pfsgnode, tbuf, sizeof(tbuf)),
+                           print_kptr((KA_T)g.gn_data, (char *)NULL, 0));
+                enter_nm(ctx, Namech);
+                return;
+            }
+            ins = 1;
+            if (!g.gn_vnode || readvnode(ctx, (KA_T)g.gn_vnode, v)) {
+                (void)snpf(Namech, Namechl,
+                           "pfsgnode at %s: can't read vnode (%s)",
+                           print_kptr((KA_T)sn.sn_pfsgnode, tbuf, sizeof(tbuf)),
+                           print_kptr((KA_T)g.gn_vnode, (char *)NULL, 0));
+                enter_nm(ctx, Namech);
+                return;
+            }
+        } else {
+            (void)zeromem((char *)&i, sizeof(i));
+
+#    if AIXV >= 4140
+            /*
+             * See if this is a clone device, connected to a stream.
+             *
+             *     the clone major device number must be known;
+             *     the specnode must have a devnode pointer;
+             *     and the devnode must have a stream head pointer.
+             */
+            if (CloneMaj >= 0 && sn.sn_devnode &&
+                kread(ctx, (KA_T)sn.sn_devnode, (char *)&dn, sizeof(dn)) == 0 &&
+                (ka = (KA_T)dn.dv_pdata)) {
+
+#        if defined(HASDCACHE)
+
+            process_clone_again:
+
+#        endif /* defined(HASDCACHE) */
+
+                for (cl = Clone; cl; cl = cl->next) {
+                    if (GET_MAJ_DEV(g.gn_rdev) == GET_MIN_DEV(cl->cd.rdev)) {
+
+#        if defined(HASDCACHE)
+                        if (DCunsafe && !cl->cd.v && !vfy_dev(ctx, &cl->cd))
+                            goto process_clone_again;
+#        endif /* defined(HASDCACHE) */
+
+                        /*
+                         * Identify this file as a clone.  Save the clone
+                         * device inode number as the file's inode number.
+                         */
+                        ic = 1;
+                        Lf->inode = cl->cd.inode;
+                        Lf->inp_ty = 1;
+                        if (ClonePtc >= 0 &&
+                            GET_MAJ_DEV(g.gn_rdev) == ClonePtc) {
+                            if (Selinet) {
+                                Lf->sf = SELEXCLF;
+                                return;
+                            }
+                            /*
+                             * If this is a /dev/ptc stream, enter the device
+                             * name and the channel.
+                             */
+                            (void)snpf(Namech, Namechl, "%s/%d", cl->cd.name,
+                                       (int)GET_MIN_DEV(g.gn_rdev));
+                            break;
+                        }
+                        /*
+                         * If this isn't a /dev/ptc stream, collect the names
+                         * of the modules on the stream.  Ignore the stream
+                         * head and look for an "xtiso" module.  Limit the
+                         * module depth to 25.
+                         */
+                        (void)snpf(Namech, Namechl, "STR:%s", cl->cd.name);
+                        nx = (int)strlen(Namech);
+                        if (!kread(ctx, ka, (char *)&sh, sizeof(sh)))
+                            qp = (KA_T)sh.sth_wq;
+                        else
+                            qp = (KA_T)NULL;
+                        for (mn[sizeof(mn) - 1] = '\0', ql = 0; qp && (ql < 25);
+                             ql++, qp = (KA_T)q.q_next) {
+
+                            /*
+                             * Read the queue structure.  If it can't be read,
+                             * end module name collection.
+                             *
+                             * The queue structure should lead to a qinfo
+                             * structure, and the qinfo structure should lead
+                             * to a module_info structure, where the module
+                             * name should be found.  If there's no queue
+                             * structure.
+                             *
+                             * If the qinfo or module_info structures can't be
+                             * read, skip to the next queue structure.
+                             */
+                            if (kread(ctx, qp, (char *)&q, sizeof(q)))
+                                break;
+                            if (!(ka = (KA_T)q.q_qinfo) ||
+                                kread(ctx, ka, (char *)&qi, sizeof(qi)))
+                                continue;
+                            if (!(ka = (KA_T)qi.qi_minfo) ||
+                                kread(ctx, ka, (char *)&mi, sizeof(mi)))
+                                continue;
+                            if (!(ka = (KA_T)mi.mi_idname) ||
+                                kread(ctx, ka, mn, sizeof(mn) - 1) ||
+                                !(ml = (int)strlen(mn)) || !strcmp(mn, "sth"))
+                                continue;
+                            if (!strcmp(mn, "xtiso") && (xp = (KA_T)q.q_ptr) &&
+                                !kread(ctx, xp, (char *)&xt, sizeof(xt)) &&
+                                (ka = (KA_T)xt.xti_so)) {
+
+                                /*
+                                 * The xtiso module's private queue pointer
+                                 * leads to an xticb with a non-NULL socket
+                                 * pointer.  Process the stream as a socket.
+                                 */
+                                Namech[0] = '\0';
+                                Lf->inp_ty = 0;
+                                (void)process_socket(ka);
+                                return;
+                            }
+                            /*
+                             * Save the module name in Mamech[] as a "->"
+                             * prefixed chain, beginning with "STR:<device>".
+                             */
+                            if ((nx + ml + 2) > (Namechl - 1))
+                                continue;
+                            (void)snpf(&Namech[nx], Namechl, "->%s", mn);
+                            nx += (ml + 2);
+                        }
+                        break;
+                    }
+                }
+            }
+#    endif /* AIXV>=4140 */
+
+            if (Selinet) {
+                Lf->sf = SELEXCLF;
+                return;
+            }
+        }
+        /*
+         * If it's a FIFO, read its fifonode.
+         */
+        if (Ntype == N_FIFO) {
+            if (!sn.sn_fifonode ||
+                readfifonode(ctx, (KA_T)sn.sn_fifonode, &f)) {
+                (void)snpf(Namech, Namechl,
+                           "vnode at %s: can't read fifonode (%s)",
+                           print_kptr(va, tbuf, sizeof(tbuf)),
+                           print_kptr((KA_T)sn.sn_fifonode, (char *)NULL, 0));
+                enter_nm(ctx, Namech);
+                return;
+            }
+            /*
+             * Otherwise, read the devnode and its gnode.
+             */
+        } else {
+            if (!sn.sn_devnode ||
+                kread(ctx, (KA_T)sn.sn_devnode, (char *)&dn, sizeof(dn))) {
+                (void)snpf(Namech, Namechl,
+                           "vnode at %s: can't read devnode (%s)",
+                           print_kptr(va, tbuf, sizeof(tbuf)),
+                           print_kptr((KA_T)sn.sn_devnode, (char *)NULL, 0));
+                enter_nm(ctx, Namech);
+                return;
+            }
+            g = dn.dv_gnode;
+        }
+    }
+#endif /* AIXV>=3200 */
+
+    /*
+     * Read the AIX virtual file system structure.
+     */
+    if (Ntype != N_AFS && g.gn_rdev == NODEVICE) {
+        vfs = (struct l_vfs *)NULL;
+        enter_dev_ch(ctx, print_kptr(va, (char *)NULL, 0));
+    } else {
+        if (!(vfs = readvfs(ctx, v))) {
+            (void)snpf(Namech, Namechl, "can't read vfs for %s at %s",
+                       print_kptr(va, tbuf, sizeof(tbuf)),
+                       print_kptr((KA_T)v->v_vfsp, (char *)NULL, 0));
+            enter_nm(ctx, Namech);
+            return;
+        }
+    }
+    /*
+     * Set special node types: NFS, PROC or SANFS.
+     */
+
+#if defined(MNT_REMOTE)
+    if (vfs && vfs->vmt_flags & MNT_REMOTE) {
+        switch (vfs->vmt_gfstype) {
+
+#    if defined(HAS_NFS)
+        case MNT_NFS:
+
+#        if defined(MNT_NFS3)
+        case MNT_NFS3:
+#        endif /* defined(MNT_NFS3) */
+
+#        if defined(MNT_NFS4)
+        case MNT_NFS4:
+#        endif /* defined(MNT_NFS4) */
+
+#        if defined(HAS_AFS)
+            if (!AFSVfsp || (KA_T)v->v_vfsp != AFSVfsp)
+#        endif /* defined(HAS_AFS) && defined(HAS_NFS) */
+
+                Ntype = N_NFS;
+#    endif /* defined(HAS_NFS) */
+            break;
+
+#    if defined(HAS_SANFS) && defined(MNT_SANFS)
+        case MNT_SANFS:
+            Ntype = N_SANFS;
+            break;
+#    endif /* defined(HAS_SANFS) && defined(MNT_SANFS) */
+        }
+    }
+#endif /* defined(MNT_REMOTE) */
+
+#if defined(HASPROCFS)
+    if (vfs && (vfs->vmt_gfstype == MNT_PROCFS))
+        Ntype = N_PROC;
+#endif /* defined(HASPROCFS) */
+
+    /*
+     * Get the lock status.
+     */
+    Lf->lock = isglocked(ctx, &g);
+    switch (Ntype) {
+
+#if defined(HAS_NFS)
+        /*
+         * Read an NFS rnode.
+         */
+    case N_NFS:
+
+#    if AIXA < 2
+        if (width == -1) {
+
+            /*
+             * Establish the architecture's bit width and set NFS rnode
+             * access parameters accordingly.
+             */
+
+#        if AIXV <= 4330
+            width = 32;
+#        else  /* AIXV>4330 */
+            if (__KERNEL_64()) {
+                width = 64;
+                rp = (char *)&r64;
+                rsz = sizeof(r64);
+            } else if (__KERNEL_32()) {
+                width = 32;
+            } else {
+                if (!Fwarn)
+                    (void)fprintf(stderr,
+                                  "%s: WARNING: unknown kernel bit size\n", Pn);
+                width = -2;
+            }
+#        endif /* AIXV<-4330 */
+        }
+#    endif /* AIXA<2 */
+
+        if (width > 0) {
+            if (!g.gn_data || kread(ctx, (KA_T)g.gn_data, rp, rsz)) {
+                (void)snpf(Namech, Namechl, "remote gnode at %s has no rnode",
+                           print_kptr((KA_T)v->v_gnode, (char *)NULL, 0));
+                enter_nm(ctx, Namech);
+                return;
+            }
+
+#    if AIXV <= 4330 || AIXA >= 2
+            nfs_attr = r.r_attr;
+            nfss = 1;
+#    else  /* AIXV>4330 && AIXA<2 */
+            switch (width) {
+            case 32:
+                nfs_attr = r.r_attr;
+                nfss = 1;
+                break;
+            case 64:
+                nfs_attr = r64.r_attr;
+                nfss = 1;
+                break;
+            }
+#    endif /* AIXV<=4330 || AIXA>=2 */
+        }
+        break;
+#endif /* defined(HAS_NFS) */
+
+#if defined(HAS_SANFS)
+        /*
+         * Read SANFS node and associated structures.
+         */
+    case N_SANFS:
+        if (!g.gn_data || kread(ctx, (KA_T)g.gn_data, &san, sizeof(san))) {
+            (void)snpf(Namech, Namechl, "gnode at %s has no SANFS node",
+                       print_kptr((KA_T)v->v_gnode, (char *)NULL, 0));
+            enter_nm(ctx, Namech);
+            return;
+        }
+        /*
+         * DEBUG: this code is insufficient.  It can't be completed until IBM
+         * makes the SANFS header files available in /usr/include.  There are
+         * apparently two node structures following the SANFS node and file
+         * attributes (size, etc.) are in the second structure.
+         */
+        sans = 1;
+        break;
+#endif /* defined(HAS_SANFS) */
+
+        /*
+         * Read N_REGLR nodes.
+         */
+    case N_REGLR:
+        if (vfs && vfs->vmt_gfstype == MNT_CDROM) {
+
+            /*
+             * Read a CD-ROM cdrnode.
+             */
+            if (!g.gn_data || readcdrnode(ctx, (KA_T)g.gn_data, &c)) {
+                (void)snpf(Namech, Namechl, "gnode at %s has no cdrnode",
+                           print_kptr((KA_T)v->v_gnode, (char *)NULL, 0));
+                enter_nm(ctx, Namech);
+                return;
+            }
+            (void)zeromem((char *)&i, sizeof(i));
+            i.number = (INODETYPE)c.cn_inumber;
+            i.size = (off_t)c.cn_size;
+            i.number_def = i.size_def = 1;
+            /*
+             * Otherwise, read the inode.
+             */
+
+        } else if (g.gn_data) {
+            if (readlino(ctx, &g, &i)) {
+                (void)snpf(Namech, Namechl, "gnode at %s can't read inode: %s",
+                           print_kptr((KA_T)v->v_gnode, tbuf, sizeof(tbuf)),
+                           print_kptr((KA_T)g.gn_data, (char *)NULL, 0));
+                enter_nm(ctx, Namech);
+                return;
+            }
+            ins = 1;
+        }
+
+#if defined(HAS_AFS)
+        else {
+
+            /*
+             * See if this is an AFS node.
+             */
+            if (AFSVfsp && (KA_T)v->v_vfsp == AFSVfsp)
+                Ntype = N_AFS;
+            else if (v->v_vfsp) {
+                switch (afs) {
+                case -1:
+                    break;
+                case 0:
+                    if (!hasAFS(ctx, v)) {
+                        afs = 1;
+                        break;
+                    }
+                    afs = 1;
+                    Ntype = N_AFS;
+                    break;
+                case 1:
+                    if ((KA_T)v->v_vfsp == AFSVfsp)
+                        Ntype = N_AFS;
+                }
+            }
+            /*
+             * If this is an AFS node, read the afsnode.
+             */
+            if (Ntype == N_AFS) {
+                if (readafsnode(ctx, va, v, &an))
+                    return;
+            } else {
+                (void)snpf(Namech, Namechl, "gnode at %s has no inode",
+                           print_kptr((KA_T)v->v_gnode, (char *)NULL, 0));
+                enter_nm(ctx, Namech);
+                return;
+            }
+        }
+#else  /* !defined(HAS_AFS) */
+
+        else {
+            (void)snpf(Namech, Namechl, "gnode at %s has no inode",
+                       print_kptr((KA_T)v->v_gnode, (char *)NULL, 0));
+            enter_nm(ctx, Namech);
+            return;
+        }
+#endif /* defined(HAS_AFS) */
+    }
+    /*
+     * Get device and type for printing.
+     */
+
+#if defined(HAS_NFS)
+    if (Ntype == N_NFS) {
+        if (vfs) {
+            dev = vfs->dev;
+            devs = 1;
+        }
+    } else
+#endif /* defined(HAS_NFS) */
+
+#if defined(HAS_AFS)
+        if (Ntype == N_AFS) {
+        dev = an.dev;
+        devs = 1;
+    } else
+#endif /* defined(HAS_AFS) */
+
+#if defined(HASPROCFS)
+        if (Ntype == N_PROC) {
+
+        /* WARNING!!!   WARNING!!!   The following hack should be removed
+         * ASAP!!! */
+        dev = vfs ? (vfs->dev & 0x7fffffffffffffff) : 0;
+        /* WARNING!!!   WARNING!!!   The above hack should be removed ASAP!!! */
+
+        devs = 1;
+    } else
+#endif /* defined(HASPROCFS) */
+
+#if defined(HAS_SANFS)
+        if ((Ntype == N_SANFS) && vfs) {
+        dev = vfs->dev;
+        devs = 1;
+    } else
+#endif /* defined(HAS_SANFS) */
+
+    {
+        if (vfs) {
+            dev = vfs->dev;
+            devs = 1;
+        }
+        rdev = g.gn_rdev;
+        rdevs = 1;
+    }
+
+#if AIXV >= 3200
+    if (Ntype == N_MPC)
+        type = VMPC;
+    else
+#endif /* AIXV>=3200 */
+
+        type = g.gn_type;
+    /*
+     * Obtain the inode number.
+     */
+    switch (Ntype) {
+
+#if defined(HAS_AFS)
+    case N_AFS:
+        if (an.ino_st) {
+            Lf->inode = (INODETYPE)an.inode;
+            Lf->inp_ty = 1;
+        }
+        break;
+#endif /* defined(HAS_AFS) */
+
+#if defined(HAS_NFS)
+    case N_NFS:
+        if (nfss) {
+            Lf->inode = (INODETYPE)nfs_attr.va_serialno;
+            Lf->inp_ty = 1;
+        }
+        break;
+#endif /* defined(HAS_NFS) */
+
+#if defined(HAS_SANFS)
+    case N_SANFS:
+        if (sans) {
+
+            /*
+             * DEBUG: this code is insufficient.  It can't be completed until
+             * IBM makes the SANFS header files available in /usr/include.
+             */
+            /* Lf->inode = ??? DEBUG */
+            Lf->inp_ty = 1;
+        }
+        break;
+#endif /* defined(HAS_SANFS) */
+
+#if AIXV >= 3200
+    case N_BLK:
+    case N_CHR:
+    case N_FIFO:
+    case N_MPC:
+#endif /* AIXV>=3200 */
+
+    case N_REGLR:
+        if (ins) {
+            Lf->inode = (INODETYPE)i.number;
+            Lf->inp_ty = i.number_def;
+        }
+    }
+    /*
+     * Obtain the file size.
+     */
+    switch (Ntype) {
+#if defined(HAS_AFS)
+    case N_AFS:
+        Lf->sz = (SZOFFTYPE)an.size;
+        Lf->sz_def = 1;
+        break;
+#endif /* defined(HAS_AFS) */
+
+#if AIXV >= 3200
+    case N_FIFO:
+        Lf->sz = (SZOFFTYPE)f.ff_size;
+        Lf->sz_def = 1;
+        break;
+#endif /* AIXV>=3200 */
+
+#if defined(HAS_NFS)
+    case N_NFS:
+        if (nfss) {
+            Lf->sz = (SZOFFTYPE)nfs_attr.va_size;
+            Lf->sz_def = 1;
+        }
+        break;
+#endif /* defined(HAS_NFS) */
+
+#if defined(HAS_SANFS)
+    case N_SANFS:
+        if (sans) {
+
+            /*
+             * DEBUG: this code is insufficient.  It can't be completed
+             * until IBM makes the SANFS header files available in
+             * /usr/include.
+             */
+            /* Lf->sz = (SZOFFTYPE)??? DEBUG */
+            Lf->sz_def = 1;
+        }
+        break;
+#endif /* defined(HAS_SANFS) */
+
+#if AIXV >= 3200
+    case N_BLK:
+        break;
+    case N_CHR:
+    case N_MPC:
+        break;
+#endif /* AIXV>=3200 */
+
+    case N_REGLR:
+        if (type == VREG || type == VDIR) {
+            if (ins) {
+                Lf->sz = (SZOFFTYPE)i.size;
+                Lf->sz_def = i.size_def;
+            }
+        }
+        break;
+    }
+    /*
+     * Record link count.
+     */
+    switch (Ntype) {
+
+#if defined(HAS_AFS)
+    case N_AFS:
+        Lf->nlink = an.nlink;
+        Lf->nlink_def = an.nlink_st;
+        break;
+#endif /* defined(HAS_AFS) */
+
+#if defined(HAS_NFS)
+    case N_NFS:
+        if (nfss) {
+            Lf->nlink = (long)nfs_attr.va_nlink;
+            Lf->nlink_def = 1;
+        }
+        break;
+#endif /* defined(HAS_NFS) */
+
+#if defined(HAS_SANFS)
+    case N_SANFS:
+        if (sans) {
+
+            /*
+             * DEBUG: this code is insufficient.  It can't be completed
+             * until IBM makes the SANFS header files available in
+             * /usr/include.
+             */
+            /* Lf->nlink = (long)???   DEBUG */
+            Lf->nlink_def = 1;
+        }
+        break;
+#endif /* defined(HAS_SANFS) */
+
+#if AIXV >= 3200
+    case N_BLK:
+    case N_CHR:
+    case N_FIFO:
+    case N_MPC:
+#endif /* AIXV>=3200 */
+
+    case N_REGLR:
+        if (ins) {
+            Lf->nlink = (long)i.nlink;
+            Lf->nlink_def = i.nlink_def;
+        }
+        break;
+    }
+    if (Nlink && Lf->nlink_def && (Lf->nlink < Nlink))
+        Lf->sf |= SELNLINK;
+
+#if defined(HAS_NFS)
+    /*
+     * Record an NFS file selection.
+     */
+    if (Ntype == N_NFS && Fnfs)
+        Lf->sf |= SELNFS;
+#endif /* defined(HAS_NFS) */
+
+    /*
+     * Save the file system names.
+     */
+    if (vfs) {
+        Lf->fsdir = vfs->dir;
+        Lf->fsdev = vfs->fsname;
+    }
+    /*
+     * Save the device numbers and their states.
+     *
+     * Format the vnode type.
+     */
+    switch (type) {
+
+    case VNON:
+        Lf->type = LSOF_FILE_VNODE_VNON;
+        Lf->dev = dev;
+        Lf->dev_def = devs;
+        Lf->rdev = rdev;
+        Lf->rdev_def = rdevs;
+        break;
+    case VREG:
+    case VDIR:
+        Lf->type = (type == VREG) ? LSOF_FILE_VNODE_VREG : LSOF_FILE_VNODE_VDIR;
+        Lf->dev = dev;
+        Lf->dev_def = devs;
+        Lf->rdev = rdev;
+        Lf->rdev_def = rdevs;
+        break;
+    case VBLK:
+        Lf->type = LSOF_FILE_VNODE_VBLK;
+        Lf->dev = dev;
+        Lf->dev_def = devs;
+        Lf->rdev = rdev;
+        Lf->rdev_def = rdevs;
+        Ntype = N_BLK;
+        break;
+    case VCHR:
+        Lf->type = LSOF_FILE_VNODE_VCHR;
+        Lf->dev = dev;
+        Lf->dev_def = devs;
+        Lf->rdev = rdev;
+        Lf->rdev_def = rdevs;
+        Ntype = N_CHR;
+        break;
+    case VLNK:
+        Lf->type = LSOF_FILE_VNODE_VLNK;
+        Lf->dev = dev;
+        Lf->dev_def = devs;
+        Lf->rdev = rdev;
+        Lf->rdev_def = rdevs;
+        break;
+
+#if defined(VSOCK)
+    case VSOCK:
+        Lf->type = LSOF_FILE_VNODE_VSOCK;
+        Lf->dev = dev;
+        Lf->dev_def = devs;
+        Lf->rdev = rdev;
+        Lf->rdev_def = rdevs;
+        break;
+#endif
+
+    case VBAD:
+        Lf->type = LSOF_FILE_VNODE_VBAD;
+        Lf->dev = dev;
+        Lf->dev_def = devs;
+        Lf->rdev = rdev;
+        Lf->rdev_def = rdevs;
+        break;
+    case VFIFO:
+        if (!Lf->dev_ch || Lf->dev_ch[0] == '\0') {
+            Lf->dev = dev;
+            Lf->dev_def = devs;
+            Lf->rdev = rdev;
+            Lf->rdev_def = rdevs;
+        }
+        Lf->type = LSOF_FILE_VNODE_VFIFO;
+        break;
+    case VMPC:
+        Lf->rdev = g.gn_rdev;
+        Lf->rdev_def = 1;
+        if (vfs) {
+            Lf->dev = vfs->dev;
+            Lf->dev_def = 1;
+        }
+        Lf->ch = g.gn_chan;
+
+#if AIXV < 3200
+        Lf->inp_ty = 0;
+#endif /* AIXV<3200 */
+
+        Ntype = N_CHR;
+        Lf->type = LSOF_FILE_VNODE_VMPC;
+        break;
+    default:
+        Lf->dev = dev;
+        Lf->dev_def = devs;
+        Lf->rdev = rdev;
+        Lf->rdev_def = rdevs;
+        Lf->type = LSOF_FILE_UNKNOWN_RAW;
+        Lf->unknown_file_type_number = type;
+    }
+    Lf->ntype = Ntype;
+
+#if defined(HASBLKDEV)
+    /*
+     * If this is a VBLK file and it's missing an inode number, try to
+     * supply one.
+     */
+    if ((Lf->inp_ty == 0) && (type == VBLK))
+        find_bl_ino(ctx);
+#endif /* defined(HASBLKDEV) */
+
+    /*
+     * If this is a VCHR file and it's missing an inode number, try to
+     * supply one.
+     */
+    if ((Lf->inp_ty == 0) && (type == VCHR))
+        find_ch_ino(ctx);
+    /*
+     * Test for specified file.
+     */
+    if (Sfile && is_file_named(ctx, NULL, type, g.gn_chan, ic))
+        Lf->sf |= SELNM;
+    /*
+     * Enter name characters.
+     */
+    if (Namech[0])
+        enter_nm(ctx, Namech);
+}
+
+#if defined(HASPRIVFILETYPE)
+/*
+ * process_shmt() -- process shared memory transport file
+ */
+
+void process_shmt(struct lsof_context *ctx, /* context */
+                  KA_T sa) /* shared memory transport node struct
+                            * address ??? */
+{
+    struct shmtnode { /* shared memory transport node
+                       * struct ??? */
+
+        struct shmtnode *peer; /* peer shmtnode struct */
+        caddr_t d1[2];         /* dummy to fill space */
+        int sz;                /* buffer size */
+        caddr_t d2[3];         /* dyummy to fill space */
+        int free;              /* free bytes in buffer */
+        caddr_t d3[17];        /* dummy to fill space */
+        pid_t pid;             /* process ID */
+    } mn, pn;
+    /*
+     * Ignore this file if only Internet files are selected.
+     */
+    if (Selinet) {
+        Lf->sf |= SELEXCLF;
+        return;
+    }
+    /*
+     * Set type to " SMT" and put shmtnode structure address in device column.
+     */
+    Lf->type = LSOF_FILE_SHARED_MEM_TRANSPORT;
+    if (!sa || kread(ctx, (KA_T)sa, (char *)&mn, sizeof(mn))) {
+        (void)snpf(Namech, Namechl, "can't read shmtnode: %s",
+                   print_kptr(sa, (char *)NULL, 0));
+        enter_nm(ctx, Namech);
+        return;
+    }
+    enter_dev_ch(ctx, print_kptr(sa, (char *)NULL, 0));
+    /*
+     * If buffer size is less than free bytes, enable offset display. Otherwise
+     * set the file size as buffer size less free bytes.
+     */
+    if (mn.free <= mn.sz) {
+        Lf->sz = (SZOFFTYPE)(mn.sz - mn.free);
+        Lf->sz_def = 1;
+    }
+    /*
+     * If there is a peer, read its shmtnode structure.
+     */
+    if (!mn.peer)
+        (void)snpf(Namech, Namechl, "->(unknown)");
+    else {
+        if (kread(ctx, (KA_T)mn.peer, (char *)&pn, sizeof(pn)))
+            (void)snpf(Namech, Namechl, "can't read peer shmtnode: %s",
+                       print_kptr((KA_T)mn.peer, (char *)NULL, 0));
+        else {
+            if (pn.pid)
+                (void)snpf(Namech, Namechl, "->%s (PID %d)",
+                           print_kptr((KA_T)mn.peer, (char *)NULL, 0), pn.pid);
+            else
+                (void)snpf(Namech, Namechl, "->%s",
+                           print_kptr((KA_T)mn.peer, (char *)NULL, 0));
+        }
+    }
+    enter_nm(ctx, Namech);
+}
+#endif /* AIXV>=4200 */
+
+/*
+ * readlino() -- read local inode
+ */
+
+int readlino(struct lsof_context *ctx, /* context */
+             struct gnode *ga,         /* gnode address */
+             struct l_ino *li)         /* local inode receiver */
+{
+    struct inode i; /* "regular" inode */
+
+#if defined(HAS_JFS2)
+    static struct vnodeops *j2va = (struct vnodeops *)NULL;
+    /* j2_vnops address */
+    static int j2vas = 0; /* j2nl[] status */
+#endif                    /* defined(HAS_JFS2) */
+
+    zeromem((char *)li, sizeof(struct l_ino));
+    if (!ga || !ga->gn_data)
+        return (0);
+
+#if defined(HAS_JFS2)
+    if (!j2vas) {
+
+        /*
+         * Get the j2_vnops address once.
+         */
+        struct nlist j2nl[] = {{"j2_vnops"}, {(char *)NULL}};
+
+        if (nlist(N_UNIX, j2nl) == 0)
+            j2va = (struct vnodeops *)j2nl[0].n_value;
+        if (!j2va && !Fwarn) {
+            (void)fprintf(stderr, "%s: WARNING: can't identify jfs2 files\n",
+                          Pn);
+        }
+        j2vas = 1;
+    }
+    /*
+     * If this system has jfs2, see if this gnode's operation structure pointer
+     * references j2_vnops.
+     */
+    if (ga->gn_ops && j2va && (ga->gn_ops == j2va))
+        return (readj2lino(ctx, ga, li));
+#endif /* defined(HAS_JFS2) */
+
+    /*
+     * Read a "standard" inode.
+     */
+    if (readinode(ctx, (KA_T)ga->gn_data, &i))
+        return (1);
+    li->dev = i.i_dev;
+    li->nlink = i.i_nlink;
+    li->number = (INODETYPE)i.i_number;
+    li->size = i.i_size;
+    li->dev_def = li->nlink_def = li->number_def = li->size_def = 1;
+    return (0);
+}
diff --git a/lib/dialects/aix/dnode1.c b/lib/dialects/aix/dnode1.c
new file mode 100644 (file)
index 0000000..11c1a35
--- /dev/null
@@ -0,0 +1,296 @@
+/*
+ * dnode1.c - AIX AFS support
+ */
+
+/*
+ * Copyright 1996 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 1996 Purdue Research Foundation.\nAll rights reserved.\n";
+#endif
+
+#if defined(HAS_AFS)
+#    include "common.h"
+
+/*
+ * This is an emulation of the afs_rwlock_t definition that appears in
+ * the AFS sources in afs/lock.h.
+ */
+
+struct afs_lock {
+
+#    if HAS_AFS < 304
+    unsigned long d1[4];
+#    else  /* HAS_AFS>=304 */
+    unsigned char d1[2];
+    unsigned short d2[3];
+    struct timeval d3;
+    unsigned int d4[3];
+#    endif /* HAS_AFS<304 */
+};
+typedef struct afs_lock afs_lock_t;
+typedef struct afs_lock afs_rwlock_t;
+
+#    define KERNEL
+#    include <afs/afs.h>
+#    undef KERNEL
+
+/*
+ * Local function prototypes
+ */
+
+static struct volume *getvolume(struct lsof_context *ctx, struct VenusFid *f,
+                                int *vols);
+static int is_rootFid(struct lsof_context *ctx, struct vcache *vc, int *rfid);
+
+/*
+ * alloc_vcache() - allocate space for vcache structure
+ */
+
+struct vnode *alloc_vcache() {
+    return ((struct vnode *)malloc((MALLOC_S)sizeof(struct vcache)));
+}
+
+/*
+ * getvolume() - get volume structure
+ */
+
+static struct volume *getvolume(struct lsof_context *ctx, /* context */
+                                struct VenusFid *f,       /* file ID pointer */
+                                int *vols) /* afs_volumes status return */
+{
+    int i;
+    static KA_T ka = 0;
+    KA_T kh;
+    static struct volume v;
+    struct volume *vp;
+    static int w = 0;
+
+    if (!ka) {
+        if ((ka = (KA_T)AFSnl[X_AFS_VOL].n_value) == (KA_T)0) {
+            if (!w && !Fwarn) {
+                (void)fprintf(stderr,
+                              "%s: WARNING: no kernel address for: %s\n", Pn,
+                              AFSnl[X_AFS_VOL]._n._n_name);
+                (void)fprintf(
+                    stderr,
+                    "      This may hamper AFS node number reporting.\n");
+                w = 1;
+            }
+            *vols = 0;
+            return ((struct volume *)NULL);
+        }
+    }
+    *vols = 1;
+    i = (NVOLS - 1) & f->Fid.Volume;
+    kh = (KA_T)((char *)ka + (i * sizeof(struct volume *)));
+    if (kread(ctx, kh, (char *)&vp, sizeof(vp)))
+        return ((struct volume *)NULL);
+    while (vp) {
+        if (kread(ctx, (KA_T)vp, (char *)&v, sizeof(v)))
+            return ((struct volume *)NULL);
+        if (v.volume == f->Fid.Volume && v.cell == f->Cell)
+            return (&v);
+        vp = v.next;
+    }
+    return ((struct volume *)NULL);
+}
+
+/*
+ * hasAFS() - test for AFS presence via vfs structure
+ */
+
+int hasAFS(struct lsof_context *ctx, /* context */
+           struct vnode *vp)         /* vnode pointer */
+{
+    struct vmount vm;
+    struct vfs v;
+    /*
+     * If this vnode has a v_data pointer, then it probably isn't an AFS vnode;
+     * return FALSE.
+     *
+     * If the vfs struct address of /afs is known and this vnode's v_vfsp
+     * matches it, return TRUE.
+     *
+     * Read this vnode's vfs structure and its mount data.  If the gfs type
+     * isn't AFS, return FALSE.  If it is, save the vnode's v_vfsp as AFSVfsp
+     * and return TRUE.
+     */
+    if (AFSVfsp && !vp->v_data && (KA_T)vp->v_vfsp == AFSVfsp)
+        return (1);
+    if (vp->v_data || !vp->v_vfsp)
+        return (0);
+    if (kread(ctx, (KA_T)vp->v_vfsp, (char *)&v, sizeof(v)))
+        return (0);
+    if (!v.vfs_mdata || kread(ctx, (KA_T)v.vfs_mdata, (char *)&vm, sizeof(vm)))
+        return (0);
+    if (vm.vmt_gfstype != MNT_AFS)
+        return (0);
+    AFSVfsp = (KA_T)vp->v_vfsp;
+    return (1);
+}
+
+/*
+ * is_rootFid() - is the file ID the root file ID
+ *
+ * return: 0   = is not root file ID
+ *        1    = is root file ID
+ *        rfid = 0 if root file ID structure address not available
+ *               1 if root file ID structure address available
+ */
+
+static int is_rootFid(struct lsof_context *ctx, /* context */
+                      struct vcache *vc,        /* vcache entry */
+                      int *rfid) /* root file ID pointer status return */
+{
+    int err;
+    static int f = 0; /* rootFID structure status:
+                       *     -1 = unavailable
+                       *       0 = not yet accessed
+                       *       1 = available */
+    static struct VenusFid r;
+    static int w = 0;
+
+    switch (f) {
+    case -1:
+        if (vc->v.v_flag & V_ROOT) {
+            *rfid = 1;
+            return (1);
+        }
+        *rfid = 0;
+        return (0);
+    case 0:
+        if (!AFSnl[X_AFS_FID].n_value) {
+            err = 1;
+
+        rfid_unavailable:
+
+            if (!w && !Fwarn) {
+                (void)fprintf(stderr, "%s: WARNING: %s: %s\n", Pn,
+                              err ? "no kernel address"
+                                  : "can't read from kernel",
+                              AFSnl[X_AFS_VOL]._n._n_name);
+                (void)fprintf(
+                    stderr,
+                    "      This may hamper AFS node number reporting.\n");
+                w = 1;
+            }
+            f = -1;
+            if (vc->v.v_flag & V_ROOT) {
+                *rfid = 1;
+                return (1);
+            }
+            *rfid = 0;
+            return (0);
+        }
+        if (kread(ctx, (KA_T)AFSnl[X_AFS_FID].n_value, (char *)&r, sizeof(r))) {
+            err = 0;
+            goto rfid_unavailable;
+        }
+        f = 1;
+        /* fall through */
+    case 1:
+        *rfid = 1;
+        if (vc->fid.Fid.Unique == r.Fid.Unique &&
+            vc->fid.Fid.Vnode == r.Fid.Vnode &&
+            vc->fid.Fid.Volume == r.Fid.Volume && vc->fid.Cell == r.Cell)
+            return (1);
+    }
+    *rfid = 0;
+    return (0);
+}
+
+/*
+ * readafsnode() - read AFS node
+ */
+
+int readafsnode(struct lsof_context *ctx, /* context */
+                KA_T va,                  /* kernel vnode address */
+                struct vnode *v,          /* vnode buffer pointer */
+                struct afsnode *an)       /* afsnode recipient */
+{
+    char *cp, tbuf[32];
+    KA_T ka;
+    int len, rfid, vols;
+    struct vcache *vc;
+    struct volume *vp;
+
+    cp = ((char *)v + sizeof(struct vnode));
+    ka = (KA_T)((char *)va + sizeof(struct vnode));
+    len = sizeof(struct vcache) - sizeof(struct vnode);
+    if (kread(ctx, ka, cp, len)) {
+        (void)snpf(Namech, Namechl,
+                   "vnode at %s: can't read vcache remainder from %s",
+                   print_kptr(va, tbuf, sizeof(tbuf)),
+                   print_kptr(ka, (char *)NULL, 0));
+        enter_nm(Namech);
+        return (1);
+    }
+    vc = (struct vcache *)v;
+    an->dev = AFSDEV;
+    an->size = (unsigned long)vc->m.Length;
+    an->nlink = (long)vc->m.LinkCount;
+    an->nlink_st = 1;
+    /*
+     * Manufacture the "inode" number.
+     */
+    if (vc->mvstat == 2) {
+        if ((vp = getvolume(ctx, &vc->fid, &vols))) {
+            an->inode = (INODETYPE)((vp->mtpoint.Fid.Vnode +
+                                     (vp->mtpoint.Fid.Volume << 16)) &
+                                    0x7fffffff);
+            if (an->inode == (INODETYPE)0) {
+                if (is_rootFid(ctx, vc, &rfid))
+                    an->ino_st = 1;
+                else if (rfid) {
+                    an->inode = (INODETYPE)2;
+                    an->ino_st = 1;
+                } else
+                    an->ino_st = 0;
+            } else
+                an->ino_st = 1;
+        } else {
+            if (vols) {
+                an->inode = (INODETYPE)2;
+                an->ino_st = 1;
+            } else {
+                if (v->v_flag & V_ROOT) {
+                    an->inode = (INODETYPE)0;
+                    an->ino_st = 1;
+                } else
+                    an->ino_st = 0;
+            }
+        }
+    } else {
+        an->inode =
+            (INODETYPE)((vc->fid.Fid.Vnode + (vc->fid.Fid.Volume << 16)) &
+                        0x7fffffff);
+        an->ino_st = 1;
+    }
+    return (0);
+}
+#endif /* defined(HAS_AFS) */
diff --git a/lib/dialects/aix/dnode2.c b/lib/dialects/aix/dnode2.c
new file mode 100644 (file)
index 0000000..2b080d8
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * dnode2.c - AIX jfs2 support
+ *
+ * V. Abell
+ * Purdue University
+ */
+
+/*
+ * Copyright 2003 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 2003 Purdue Research Foundation.\nAll rights reserved.\n";
+#endif
+
+#if defined(HAS_JFS2)
+#    define _H_JFS_INO   /* prevent <jfs_ino.h> */
+#    define _H_JFS_INODE /* prevent <jfs_inode.h> */
+#    define PROTO_H      /* prevent "proto.h" and                              \
+                          * "dproto.h" until struct                            \
+                          * inode is available from                            \
+                          * <j2/j2_inode.h> */
+#    define DPROTO_H
+#    include "common.h"
+#    define _KERNEL
+#    include <j2/j2_inode.h>
+#    undef PROTO_H  /* enable "proto.h" */
+#    undef DPROTO_H /* enable "dproto.h" */
+#    include "proto.h"
+#    include "dproto.h"
+
+int readj2lino(struct lsof_context *ctx, /* context */
+               struct gnode *ga,         /* gnode address */
+               struct l_ino *li)         /* local inode receiver */
+{
+    struct inode i; /* jfs2 inode */
+                    /*
+                     * Read the jfs2 inode and fill in the local inode receiver.
+                     *
+                     * Note: the caller is responsible for initializing *li to zeroes.
+                     */
+    if (!ga || !ga->gn_data ||
+        kread(ctx, (KA_T)ga->gn_data, (char *)&i, sizeof(i)))
+        return (1);
+    li->dev = i.i_dev;
+    li->nlink = i.i_nlink;
+    li->number = (INODETYPE)i.i_number;
+    li->size = i.i_size;
+    li->dev_def = li->nlink_def = li->number_def = li->size_def = 1;
+    return (0);
+}
+#endif /* defined(HAS_JFS2) */
diff --git a/lib/dialects/aix/dproc.c b/lib/dialects/aix/dproc.c
new file mode 100644 (file)
index 0000000..81949ad
--- /dev/null
@@ -0,0 +1,1424 @@
+/*
+ * dproc.c - AIX process access functions for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#ifndef lint
+static char copyright[] =
+    "@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
+#endif
+
+#include "common.h"
+
+static void get_kernel_access(struct lsof_context *ctx);
+
+#if AIXA < 2
+static struct le *getle(struct lsof_context *ctx, KA_T a, KA_T sid, char **err);
+#endif /* AIXA<2 */
+
+#if AIXV >= 4110
+static void getlenm(struct lsof_context *ctx, struct le *le, KA_T sid);
+#endif /* AIXV>=4110 */
+
+static int kreadx(KA_T addr, char *buf, int len, KA_T sid);
+
+#if AIXA < 2
+static void process_text(struct lsof_context *ctx, KA_T sid);
+#else  /* AIXA>=2 */
+static void getsoinfo(void);
+static void process_text(struct lsof_context *ctx, pid_t pid);
+#endif /* AIXA<2 */
+
+#if defined(SIGDANGER)
+#    if defined(HASINTSIGNAL)
+static int lowpgsp(struct lsof_context *ctx, int sig);
+#    else  /* !defined(HASINTSIGNAL) */
+static void lowpgsp(struct lsof_context *ctx, int sig);
+#    endif /* defined(HASINTSIGNAL) */
+#endif     /* defined(SIGDANGER) */
+
+/*
+ * Local definitions
+ */
+
+#if AIXV < 4300
+#    define PROCINFO procinfo
+#else /* AIXV>=4300 */
+#    define PROCINFO_INCR 256
+#    if AIXA < 1
+#        define FDSINFO fdsinfo
+#        define GETPROCS getprocs
+#        define PROCINFO procsinfo
+#    else /* AIXA>=1 */
+#        define FDSINFO fdsinfo64
+#        define GETPROCS getprocs64
+#        define PROCINFO procentry64
+
+#        if AIXA > 1
+/*
+ * AIX 5 and greater ia64 loader definitions
+ */
+
+#            include <sys/ldr.h>
+
+#            define SOHASHBUCKS                                                \
+                128 /* SoHash[] bucket count                                   \
+                     * MUST BE A POWER OF 2!!! */
+#            define SOHASH(d, n)                                               \
+                ((((int)(((GET_MIN_DEV(d) & 0x7fffffff) * SOHASHBUCKS) + n) *  \
+                   31415) >>                                                   \
+                  7) &                                                         \
+                 (SOHASHBUCKS - 1))
+
+typedef struct so_hash {
+    dev_t dev;            /* device (st_dev) */
+    int nlink;            /* link count (st_nlink) */
+    char *nm;             /* name (mi_name) */
+    INODETYPE node;       /* node number (st_ino) */
+    struct so_hash *next; /* next entry in hash bucket */
+    SZOFFTYPE sz;         /* size (st_size) */
+} so_hash_t;
+
+so_hash_t **SoHash = (so_hash_t **)NULL;
+#        endif /* AIXA>1 */
+#    endif     /* AIXA<1 */
+#endif         /* AIXV<4300 */
+
+#define PROCSIZE sizeof(struct PROCINFO)
+
+/*
+ * Create the FDSINFOSIZE definition for allocating FDSINFO space.  (This
+ * isn't as straightforward as it might seem, because someone made a bad
+ * decision to change the struct fdsinfo* family at AIX 5.2.)
+ */
+
+#define FDSINFOSIZE sizeof(struct FDSINFO) /* (If we're lucky.) */
+
+#if defined(OPEN_SHRT_MAX)
+#    if OPEN_SHRT_MAX < OPEN_MAX
+#        undef FDSINFOSIZE /* (We weren't lucky.) */
+#        define FDSELEMSIZE (sizeof(struct FDSINFO) / OPEN_SHRT_MAX)
+#        define FDSINFOSIZE (OPEN_MAX * FDSELEMSIZE)
+#    endif /* OPEN_SHRT_MAX<OPEN_MAX */
+#endif     /* defined(OPEN_SHRT_MAX) */
+
+#if AIXV >= 4110
+/*
+ * Loader access definitions for AIX 4.1.1 and above.
+ */
+
+#    define LIBNMLN                                                            \
+        40 /* maximum library table name                                       \
+            * length */
+
+#    define LIBMASK 0xf0000000 /* library table mask */
+#    define LIBNMCOMP                                                          \
+        0xd0000000 /* library table name has                                   \
+                    * multiple components */
+#    if AIXA < 1
+#        define RDXMASK 0x0fffffff          /* kreadx() address mask */
+#    else                                   /* AIXA>=1 */
+#        define RDXMASK 0x0fffffffffffffff  /* kreadx() address mask */
+#        define URDXMASK 0x0fffffff00000000 /* upper part of RDXMASK */
+#    endif                                  /* AIXA<1 */
+#endif                                      /* AIXV>=4110 */
+
+/*
+ * Loader structure definitions.  (AIX doesn't supply ld_data.h.)
+ */
+
+struct le { /* loader entry */
+
+    struct le *next; /* next entry pointer */
+
+#if AIXV < 4300
+    ushort dummy1;
+    ushort dummy2;
+    uint dummy3;
+    struct file *fp; /* file table entry pointer */
+
+#    if AIXV >= 4110
+    int ft; /* file type indicator */
+    unsigned dummy4;
+    char *dummy5;
+    unsigned dummy6;
+    char *dummy7[3];
+    char *nm; /* name */
+#    endif    /* AIXV>=4110 */
+#else         /* AIXV>=4300 */
+#    if AIXA < 2
+    uint flags;
+    struct file *fp; /* file table entry pointer */
+    char *nm;        /* name */
+#    else  /* AIXA>=2 */
+    KA_T d1[2];
+    KA_T nm; /* name */
+    KA_T d2[10];
+    struct file *fp; /* file table entry pointer */
+#    endif /* AIXA<2 */
+#endif     /* AIXV<4300 */
+};
+
+#if AIXV >= 4300
+/*
+ * The elements of interest from the AIX >= 4.3 loader anchor structure.
+ */
+struct la { /* loader anchor */
+
+#    if AIXA < 2
+    struct le *list;
+    struct le *exec;
+#    else  /* AIXA>=2 */
+    KA_T exec;
+    KA_T list;
+#    endif /* AIXA<2 */
+};
+#endif /* AIXV>=4300 */
+
+/*
+ * Local static values
+ */
+
+static int Np = 0; /* number of processes */
+static struct PROCINFO *P = (struct PROCINFO *)NULL;
+/* the process table */
+static struct user *Up; /* user structure */
+
+#if AIXV >= 4110
+#    if AIXA < 2
+static KA_T Soff;  /* shared library VM offset */
+int Soff_stat = 0; /* Soff-available status */
+#    endif         /* AIXA<2 */
+static KA_T Uo;    /* user area VM offset */
+#endif             /* AIXV>=4110 */
+
+/*
+ * ckkv() - check kernel version
+ */
+
+void ckkv(struct lsof_context *ctx, /* context */
+          char *d,                  /* dialect */
+          char *er,                 /* expected release */
+          char *ev,                 /* expected version */
+          char *ea)                 /* expected architecture */
+{
+
+#if defined(HASKERNIDCK)
+#    if AIXV < 5000
+
+    /*
+     * Use oslevel below AIX 5.
+     */
+    int br, p[2], pid;
+    char buf[128], *cp;
+    struct stat sb;
+
+    if (Fwarn)
+        return;
+        /*
+         * Make sure we can execute OSLEVEL.  If OSLEVEL doesn't exist and the
+         * AIX version is below 4.1, return quietly.
+         */
+
+#        define OSLEVEL "oslevel"
+#        define OSLEVELPATH "/usr/bin/oslevel"
+
+    if (stat(OSLEVELPATH, &sb)) {
+
+#        if AIXV < 4100
+        if (errno == ENOENT)
+            return;
+#        endif /* AIXV<4100 */
+
+        (void)fprintf(stderr, "%s: can't execute %s: %s\n", Pn, OSLEVELPATH,
+                      strerror(errno));
+        Error(ctx);
+    }
+    if ((sb.st_mode & (S_IROTH | S_IXOTH)) != (S_IROTH | S_IXOTH)) {
+        (void)fprintf(stderr, "%s: can't execute %s, modes: %o\n", Pn,
+                      OSLEVELPATH, sb.st_mode);
+        Error(ctx);
+    }
+    /*
+     * Open a pipe for receiving the version number from OSLEVEL.  Fork a
+     * child to run OSLEVEL.  Retrieve the OSLEVEL output.
+     */
+    if (pipe(p)) {
+        (void)fprintf(stderr, "%s: can't create pipe to: %s\n", Pn,
+                      OSLEVELPATH);
+        Error(ctx);
+    }
+    if ((pid = fork()) == 0) {
+        (void)close(1);
+        (void)close(2);
+        (void)close(p[0]);
+        dup2(p[1], 1);
+        dup2(p[1], 2);
+        (void)close(p[1]);
+        execl(OSLEVELPATH, OSLEVEL, NULL);
+        _exit(0);
+    }
+    if (pid < 0) {
+        (void)fprintf(stderr, "%s: can't fork a child for %s: %s\n", Pn,
+                      OSLEVELPATH, strerror(errno));
+        Error(ctx);
+    }
+    (void)close(p[1]);
+    br = read(p[0], buf, sizeof(buf) - 1);
+    (void)close(p[0]);
+    (void)wait(NULL);
+    /*
+     * Warn if the actual and expected versions don't match.
+     */
+    if (br > 0) {
+        buf[br] = '\0';
+        if ((cp = strrchr(buf, '\n')))
+            *cp = '\0';
+    } else
+        (void)snpf(buf, sizeof(buf), "UNKNOWN");
+#    else  /* AIXV>=5000 */
+
+    /*
+     * Use uname() for AIX 5 and above.
+     */
+    char buf[64];
+    struct utsname u;
+
+    if (Fwarn)
+        return;
+
+    (void)memset((void *)&u, 0, sizeof(u));
+    (void)uname(&u);
+    (void)snpf(buf, sizeof(buf) - 1, "%s.%s.0.0", u.version, u.release);
+    buf[sizeof(buf) - 1] = '\0';
+#    endif /* AIXV<5000 */
+    if (!ev || strcmp(buf, ev))
+        (void)fprintf(stderr,
+                      "%s: WARNING: compiled for %s version %s; this is %s.\n",
+                      Pn, d, ev ? ev : "UNKNOWN", buf);
+#endif /* defined(HASKERNIDCK) */
+}
+
+/*
+ * gather_proc_info() - gather process information
+ */
+
+void gather_proc_info(struct lsof_context *ctx) {
+    short cckreg; /* conditional status of regular file
+                   * checking:
+                   *     0 = unconditionally check
+                   *     1 = conditionally check */
+    short ckscko; /* socket file only checking status:
+                   *     0 = none
+                   *     1 = check only socket files,
+                   *      including TCP and UDP
+                   *      streams with eXPORT data,
+                   *      where supported */
+    KA_T cdir, fp, pdir, rdir;
+    char *cmd;
+    int hl, i, nf, np;
+    struct PROCINFO *p;
+    short pss, sf;
+    struct user us;
+
+#if AIXV >= 4300
+    static struct FDSINFO *fds = (struct FDSINFO *)NULL;
+    MALLOC_S msz;
+#    if AIXA == 1
+    pid32_t pid; /* Since we're operating with types defined
+                  * under _KERNEL (see machine.), but
+                  * getprocs64() expects application types
+                  * (where pid_t is 32 bits), the pid variable
+                  * must be cast in an application-compatible
+                  * manner.
+                  */
+#    else        /* AIXA!=1 */
+    pid_t pid;
+#    endif       /* AIXA==1 */
+#    if AIXV == 4330
+    static int trx = 0;
+    unsigned int mxof;
+    static int uo = 0;
+#    endif /* AIXV==4330 */
+#endif     /* AIXV>=4300 */
+
+    /*
+     * Define socket and regular file conditional processing flags.
+     *
+     * If only socket files have been selected, or socket files have been
+     * selected, ANDed with other selection options, enable the skipping of
+     * regular files.
+     *
+     * If socket files and some process options have been selected, enable
+     * conditional skipping of regular file; i.e., regular files will be skipped
+     * unless they belong to a process selected by one of the specified options.
+     */
+    if (Selflags & SELNW) {
+
+        /*
+         * Some network files selection options have been specified.
+         */
+        if (Fand || !(Selflags & ~SELNW)) {
+
+            /*
+             * Selection ANDing or only network file options have been
+             * specified, so set unconditional skipping of regular files
+             * and socket file only checking.
+             */
+            cckreg = 0;
+            ckscko = 1;
+        } else {
+
+            /*
+             * If ORed file selection options have been specified, or no
+             * ORed process selection options have been specified, enable
+             * unconditional file checking and clear socket file only
+             * checking.
+             *
+             * If only ORed process selection options have been specified,
+             * enable conditional file skipping and socket file only checking.
+             */
+            if ((Selflags & SELFILE) || !(Selflags & SelProc))
+                cckreg = ckscko = 0;
+            else
+                cckreg = ckscko = 1;
+        }
+    } else {
+
+        /*
+         * No network file selection options were specified.  Enable
+         * unconditional file checking and clear socket file only checking.
+         */
+        cckreg = ckscko = 0;
+    }
+    /*
+     * Read the process table.
+     */
+
+#if AIXV < 4300
+    if (!P) {
+        if (!(P = (struct PROCINFO *)malloc((MALLOC_S)PROCSIZE))) {
+            (void)fprintf(stderr, "%s: can't allocate space for 1 proc\n", Pn);
+            Error(ctx);
+        }
+        Np = 1;
+    }
+    while (((np = getproc(P, Np, PROCSIZE)) == -1) && errno == ENOSPC) {
+        Np = P->p_pid + 10;
+        if (!(P = (struct PROCINFO *)realloc((MALLOC_P *)P,
+                                             (size_t)(Np * PROCSIZE)))) {
+            (void)fprintf(stderr, "%s: no space for %d procinfo's\n", Pn, Np);
+            Error(ctx);
+        }
+    }
+#else  /* AIXV>=4300 */
+    if (!P) {
+        msz = (MALLOC_S)(PROCSIZE * PROCINFO_INCR);
+        if (!(P = (struct PROCINFO *)malloc(msz))) {
+            (void)fprintf(stderr, "%s: can't allocate space for %d procs\n", Pn,
+                          PROCINFO_INCR);
+            Error(ctx);
+        }
+        Np = PROCINFO_INCR;
+    }
+    np = pid = 0;
+    p = P;
+    while ((i = GETPROCS(p, PROCSIZE, (struct FDSINFO *)NULL, 0, &pid,
+                         PROCINFO_INCR)) == PROCINFO_INCR) {
+        np += PROCINFO_INCR;
+        if (np >= Np) {
+            msz = (MALLOC_S)(PROCSIZE * (Np + PROCINFO_INCR));
+            if (!(P = (struct PROCINFO *)realloc((MALLOC_P *)P, msz))) {
+                (void)fprintf(stderr, "%s: no more space for proc storage\n",
+                              Pn);
+                Error(ctx);
+            }
+            Np += PROCINFO_INCR;
+        }
+        p = (struct PROCINFO *)((char *)P + (np * PROCSIZE));
+    }
+    if (i > 0)
+        np += i;
+#endif /* AIXV<4300 */
+
+    /*
+     * Loop through processes.
+     */
+    for (p = P, Up = &us; np > 0; np--, p++) {
+        if (p->p_stat == 0 || p->p_stat == SZOMB)
+            continue;
+        if (is_proc_excl(ctx, p->p_pid, (int)p->p_pgid, (UID_ARG)p->p_uid, &pss,
+                         &sf))
+            continue;
+
+#if AIXV < 4300
+            /*
+             * Get user structure for AIX < 4.3.
+             *
+             * If AIX version is below 4.1.1, use getuser().
+             *
+             * If AIX version is 4.1.1 or above: if readx() is disabled (no -X
+             * option, use  getuser(); if readx() is enabled (-X), use readx().
+             */
+
+#    if AIXV >= 4110
+        if (Fxopt && kreadx(Uo, (char *)Up, U_SIZE, (KA_T)p->pi_adspace) == 0)
+            i = 1;
+        else
+            i = 0;
+        if (i == 0) {
+            if (getuser(p, PROCSIZE, Up, U_SIZE) != 0)
+                continue;
+        }
+        hl = i;
+#    else  /* AIXV<4110 */
+        if (getuser(p, PROCSIZE, Up, U_SIZE) != 0)
+            continue;
+        hl = 1;
+#    endif /* AIXV>=4110 */
+           /*
+            * Save directory vnode addresses, command name address, and open file
+            * count from user structure.
+            *
+            * Skip processes excluded by the user structure command name.
+            */
+        cdir = (KA_T)Up->u_cdir;
+
+#    if AIXV < 4100
+        pdir = (KA_T)Up->u_pdir;
+#    endif /* AIXV<4100 */
+
+        rdir = (KA_T)Up->u_rdir;
+        cmd = Up->u_comm;
+        nf = Up->u_maxofile;
+        if (is_cmd_excl(ctx, cmd, &pss, &sf))
+            continue;
+        if (cckreg) {
+
+            /*
+             * If conditional checking of regular files is enabled, enable
+             * socket file only checking, based on the process' selection
+             * status.
+             */
+            ckscko = (sf & SelProc) ? 0 : 1;
+        }
+
+#else /* AIXV>=4300 */
+        /*
+         * For AIX 4.3 and above, skip processes excluded by the procsinfo
+         * command name.  Use getprocs() to get the file descriptors for
+         * included processes.
+         *
+         * If readx is enabled (-X), use it to get the loader_anchor structure.
+         */
+        if (is_cmd_excl(ctx, p->pi_comm, &pss, &sf))
+            continue;
+        if (cckreg) {
+
+            /*
+             * If conditional checking of regular files is enabled, enable
+             * socket file only checking, based on the process' selection
+             * status.
+             */
+            ckscko = (sf & SelProc) ? 0 : 1;
+        }
+        if (!fds) {
+            if (!(fds = (struct FDSINFO *)malloc((MALLOC_S)FDSINFOSIZE))) {
+                (void)fprintf(stderr,
+                              "%s: can't allocate fdsinfo struct for PID %d\n",
+                              Pn, pid);
+                Error(ctx);
+            }
+        }
+        pid = p->p_pid;
+        if (GETPROCS((struct PROCINFO *)NULL, PROCSIZE, fds, FDSINFOSIZE, &pid,
+                     1) != 1)
+            continue;
+        hl = 0;
+
+#    if AIXV == 4330
+        /*
+         * Handle readx() for AIX 4.3.3 specially, because 4.3.3 was released
+         * with two different user struct definitions in <sys/user.h> and
+         * their form affects using readx() to get the loader table pointers
+         * from U_loader of the user structure (when -X is specified).
+         */
+        if (Fxopt) {
+            for (;;) {
+
+                /*
+                 * Read the AIX 4.3.3 U_loader pointers.
+                 */
+                if (kreadx((KA_T)((char *)Uo + offsetof(struct user, U_loader) +
+                                  uo),
+                           (char *)&Up->U_loader, sizeof(struct la),
+                           (KA_T)p->pi_adspace))
+                    break;
+                if (trx) {
+                    hl = 1;
+                    break;
+                }
+                /*
+                 * Until the correct size of the U_loader offset in lo has been
+                 * established, read U_maxofile and match it to pi_maxofile
+                 * from the PROCINFO structure.  Try the offsets 0, 48, and
+                 * -48.  Note: these offsets are heuristic attempts to adjust
+                 * to differences in the user struct as observed on two systems
+                 * whose <sys/user.h> header files differed.  U_maxofile
+                 * follows U_loader by the same number of elements in both
+                 * user structs, so the U_loader offset should be the same as
+                 * the U_maxofile offset.
+                 */
+                if (!kreadx((KA_T)((char *)Uo +
+                                   offsetof(struct user, U_maxofile) + uo),
+                            (char *)&mxof, sizeof(mxof), (KA_T)p->pi_adspace) &&
+                    (mxof == p->pi_maxofile)) {
+                    hl = trx = 1;
+                    break;
+                }
+                if (uo == 0)
+                    uo = 48;
+                else if (uo == 48)
+                    uo = -48;
+                else {
+                    Fxopt = hl = 0;
+                    trx = 1;
+                    if (!Fwarn) {
+                        (void)fprintf(stderr,
+                                      "%s: WARNING: user struct mismatch;", Pn);
+                        (void)fprintf(stderr, " -X option disabled.\n");
+                    }
+                    break;
+                }
+            }
+        }
+#    else  /* AIXV!=4330 */
+        if (Fxopt &&
+            kreadx((KA_T)((char *)Uo + offsetof(struct user, U_loader)),
+                   (char *)&Up->U_loader, sizeof(struct la),
+                   (KA_T)p->pi_adspace) == 0)
+            hl = 1;
+#    endif /* AIXV==4330 */
+
+        /*
+         * Save directory vnode addresses, command name, and open file count
+         * from procinfo structure.
+         */
+        cdir = (KA_T)p->pi_cdir;
+        pdir = (KA_T)NULL;
+        rdir = (KA_T)p->pi_rdir;
+        cmd = p->pi_comm;
+        nf = p->pi_maxofile;
+#endif     /* AIXV<4300 */
+
+        /*
+         * Allocate a local process structure and start filling it.
+         */
+        alloc_lproc(ctx, p->p_pid, (int)p->p_pgid, (int)p->p_ppid,
+                    (UID_ARG)p->p_uid, cmd, (int)pss, (int)sf);
+        Plf = (struct lfile *)NULL;
+        /*
+         * Save current working directory information.
+         */
+        if (!ckscko && cdir) {
+            alloc_lfile(ctx, LSOF_FD_CWD, -1);
+            process_node(ctx, cdir);
+            if (Lf->sf)
+                link_lfile(ctx);
+        }
+        /*
+         * Save root directory information.
+         */
+        if (!ckscko && rdir) {
+            alloc_lfile(ctx, LSOF_FD_ROOT_DIR, -1);
+            process_node(ctx, rdir);
+            if (Lf->sf)
+                link_lfile(ctx);
+        }
+
+#if AIXV < 4100
+        /*
+         * Save parent directory information.
+         */
+        if (!ckscko && pdir) {
+            alloc_lfile(ctx, LSOF_FD_PARENT_DIR, -1);
+            process_node(ctx, pdir);
+            if (Lf->sf)
+                link_lfile(ctx);
+        }
+#endif /* AIXV<4100 */
+
+        /*
+         * Save information on text files.
+         */
+        if (!ckscko && hl) {
+
+#if AIXA < 2
+#    if AIXA < 1
+            process_text((KA_T)p->pi_adspace);
+#    else  /* AIXA==1 */
+            {
+                int ck = 1;
+                KA_T sid = (KA_T)p->pi_adspace;
+
+                if ((Up->U_loader[0] & URDXMASK) ||
+                    (Up->U_loader[1] & URDXMASK)) {
+
+                    /*
+                     * If the upper part of either loader map address is
+                     * non-zero and this is not the lsof process, skip the
+                     * processing of text files.  If this is the lsof process,
+                     * set the segment address to zero, forcing text file
+                     * information to come from kmem rather than mem.
+                     */
+                    if (Mypid == p->p_pid)
+                        sid = (KA_T)0;
+                    else
+                        ck = 0;
+                }
+                if (ck)
+                    process_text(ctx, sid);
+            }
+#    endif /* AIXA<1 */
+#else      /* AIXA>=2 */
+            process_text(ctx, p->p_pid);
+#endif     /* AIXA<2 */
+        }
+        /*
+         * Save information on file descriptors.
+         */
+        for (i = 0; i < nf; i++) {
+
+#if AIXV < 4300
+            fp = (KA_T)Up->u_ufd[i].fp;
+#else  /* AIXV>=4300 */
+            fp = (KA_T)fds->pi_ufd[i].fp;
+#endif /* AIXV<4300 */
+
+            if (fp) {
+                alloc_lfile(ctx, LSOF_FD_NUMERIC, i);
+                process_file(ctx, fp);
+                if (Lf->sf) {
+
+#if defined(HASFSTRUCT)
+
+#    if AIXV < 4300
+                    Lf->pof = (long)(Up->u_ufd[i].flags & 0x7f);
+#    else  /* AIXV>=4300 */
+                    Lf->pof = (long)(fds->pi_ufd[i].flags & 0x7f);
+#    endif /* AIXV<4300 */
+#endif     /* defined(HASFSTRUCT) */
+
+                    link_lfile(ctx);
+                }
+            }
+        }
+        /*
+         * Examine results.
+         */
+        if (examine_lproc(ctx))
+            return;
+    }
+}
+
+/*
+ * get_kernel_access() - get access to kernel memory
+ */
+
+static void get_kernel_access(struct lsof_context *ctx) {
+    int oe = 0;
+
+#if defined(AIX_KERNBITS)
+    int kb;
+    char *kbb, *kbr;
+    /*
+     * Check the kernel bit size against the size for which this executable was
+     * configured.
+     */
+    if (__KERNEL_32()) {
+        kb = 32;
+        kbr = "32";
+    } else if (__KERNEL_64()) {
+        kb = 64;
+        kbr = "64";
+    } else {
+        kb = 0;
+        kbr = "unknown";
+    }
+    if ((AIX_KERNBITS == 0) || !kb || (kb != AIX_KERNBITS)) {
+        if (AIX_KERNBITS == 32)
+            kbb = "32";
+        else if (AIX_KERNBITS == 64)
+            kbb = "64";
+        else
+            kbb = "unknown";
+        (void)fprintf(stderr,
+                      "%s: FATAL: compiled for a kernel of %s bit size.\n", Pn,
+                      kbb);
+        (void)fprintf(stderr, "      The bit size of this kernel is %s.\n",
+                      kbr);
+        Error(ctx);
+    }
+#endif /* defined(AIX_KERNBITS) */
+
+    /*
+     * Access /dev/mem.
+     */
+    if ((Km = open("/dev/mem", O_RDONLY, 0)) < 0) {
+        (void)fprintf(stderr, "%s: can't open /dev/mem: %s\n", Pn,
+                      strerror(errno));
+        oe++;
+    }
+
+#if defined(WILLDROPGID)
+    /*
+     * If kernel memory isn't coming from KMEM, drop setgid permission
+     * before attempting to open the (Memory) file.
+     */
+    if (Memory)
+        (void)dropgid(ctx);
+#else  /* !defined(WILLDROPGID) */
+    /*
+     * See if the non-KMEM memory file is readable.
+     */
+    if (Memory && !is_readable(ctx, Memory, 1))
+        Error(ctx);
+#endif /* defined(WILLDROPGID) */
+
+    /*
+     * Access kernel memory file.
+     */
+    if ((Kd = open(Memory ? Memory : KMEM, O_RDONLY, 0)) < 0) {
+        (void)fprintf(stderr, "%s: can't open %s: %s\n", Pn,
+                      Memory ? Memory : KMEM, strerror(errno));
+        oe++;
+    }
+    if (oe)
+        Error(ctx);
+
+#if defined(WILLDROPGID)
+    /*
+     * Drop setgid permission, if necessary.
+     */
+    if (!Memory)
+        (void)dropgid(ctx);
+#endif /* defined(WILLDROPGID) */
+
+    /*
+     * Get kernel symbols.
+     */
+    if (knlist(Nl, X_NL_NUM, sizeof(struct nlist)) || !Nl[X_UADDR].n_value) {
+        (void)fprintf(stderr, "%s: can't get kernel's %s address\n", Pn,
+                      Nl[X_UADDR].n_name);
+        Error(ctx);
+    }
+
+#if defined(HAS_AFS)
+    (void)knlist(AFSnl, X_AFSNL_NUM, sizeof(struct nlist));
+#endif /* defined(HAS_AFS) */
+
+#if AIXV >= 4110
+    /*
+     * Get user area and shared library VM offsets for AIX 4.1.1 and above.
+     */
+    if (Fxopt) {
+        struct ublock *ub;
+
+#    if AIXA < 2
+        struct nlist ll[] = {
+            {"library_anchor"},
+
+#        if AIXV >= 4330
+            {"library_le_handle"},
+#        else  /* AIXV<4330 */
+            {"library_data_handle"},
+#        endif /* AIXV>=4330 */
+
+            {(char *)NULL}
+        };
+
+        if (nlist(N_UNIX, ll) == 0 && ll[0].n_value != (long)0 &&
+            ll[1].n_value != (long)0 &&
+            kreadx((KA_T)(ll[1].n_value & RDXMASK), (char *)&Soff, sizeof(Soff),
+                   (KA_T)0) == 0)
+            Soff_stat++;
+#    endif /* AIXA<2 */
+
+        ub = (struct ublock *)Nl[X_UADDR].n_value;
+        Uo = (KA_T)((KA_T)&ub->ub_user & RDXMASK);
+    }
+#endif /* AIXV>=4110 */
+
+    /*
+     * Check the kernel version number.
+     */
+    (void)ckkv(ctx, "AIX", (char *)NULL, LSOF_VSTR, (char *)NULL);
+
+#if defined(SIGDANGER)
+    /*
+     * If SIGDANGER is defined, enable its handler.
+     */
+    (void)signal(SIGDANGER, lowpgsp);
+#endif /* defined(SIGDANGER) */
+}
+
+#if AIXA < 2
+/*
+ * getle() - get loader entry structure
+ */
+
+static struct le *getle(struct lsof_context *ctx, /* context */
+                        KA_T a,     /* loader entry kernel address */
+                        KA_T sid,   /* user structure segment ID */
+                        char **err) /* error message (if return is NULL) */
+{
+    static struct le le;
+
+#    if AIXV < 4110
+    if (a < Nl[X_UADDR].n_value) {
+        *err = "address too small";
+        return ((struct le *)NULL);
+    }
+    if (((char *)a + sizeof(le)) <= ((char *)Nl[X_UADDR].n_value + U_SIZE))
+        return ((struct le *)((char *)Up + a - Nl[X_UADDR].n_value));
+#    endif /* AIXV<4110 */
+
+    if (!Fxopt) {
+        *err = "readx() disabled for Stale Segment ID bug (see -X)";
+        return ((struct le *)NULL);
+    }
+
+#    if AIXV >= 4110
+    if (!sid) {
+        if (!kread(ctx, a, (char *)&le, sizeof(le)))
+            return (&le);
+    } else {
+        if (!kreadx((KA_T)(a & RDXMASK), (char *)&le, sizeof(le), (KA_T)sid))
+            return (&le);
+    }
+#    else  /* AIXV<4110 */
+    if (!kreadx((KA_T)a, (char *)&le, sizeof(le), (KA_T)sid))
+        return (&le);
+#    endif /* AIXV>=4110 */
+
+getle_err:
+
+    *err = "can't readx()";
+    return ((struct le *)NULL);
+}
+#endif /* AIXA<2 */
+
+#if AIXV >= 4110
+/*
+ * getlenm() - get loader entry file name for AIX >= 4.1.1
+ */
+
+static void getlenm(struct lsof_context *ctx, /* context */
+                    struct le *le,            /* loader entry structure */
+                    KA_T sid)                 /* segment ID */
+{
+    char buf[LIBNMLN];
+    int i;
+
+#    if AIXV < 4300
+    if ((le->ft & LIBMASK) != LIBNMCOMP)
+        return;
+#    else /* AIXV>=4300 */
+#        if AIXA < 2
+    if (!sid) {
+        if (kread(ctx, (KA_T)le->nm, buf, LIBNMLN))
+            return;
+    } else {
+        if (!Soff_stat || !le->nm ||
+            kreadx((KA_T)le->nm & (KA_T)RDXMASK, buf, LIBNMLN, (KA_T)Soff))
+            return;
+    }
+    buf[LIBNMLN - 1] = '\0';
+    i = strlen(buf);
+    if (i < (LIBNMLN - 3) && buf[i + 1])
+        enter_nm(ctx, &buf[i + 1]);
+    else if (buf[0])
+        enter_nm(ctx, buf);
+#        else  /* AIXA>=2 */
+    if (!le->nm || kread(ctx, le->nm, buf, sizeof(buf)))
+        return;
+    buf[LIBNMLN - 1] = '\0';
+    if (!strlen(buf))
+        return;
+    enter_nm(ctx, buf);
+#        endif /* AIXA<2 */
+#    endif     /* AIXV<4300 */
+}
+#endif /* AIXV>=4110 */
+
+#if AIXA > 1
+/*
+ * getsoinfo() - get *.so information for ia64 AIX >= 5
+ */
+
+static void getsoinfo() {
+    char buf[65536];
+    uint bufsz = (uint)sizeof(buf);
+    int ct, h;
+    char *ln = (char *)NULL;
+    char *rn = (char *)NULL;
+    LDR_Mod_info_t *lp;
+    struct stat sb;
+    so_hash_t *sp;
+    /*
+     * See if loader information is needed.  Warn if this process has
+     * insufficient permission to acquire it from all processes.
+     */
+    if (!Fxopt)
+        return;
+    if ((Myuid != 0) && !Setuidroot && !Fwarn) {
+        (void)fprintf(stderr,
+                      "%s: WARNING: insufficient permission to access all", Pn);
+        (void)fprintf(stderr, " /%s/object sub-\n", HASPROCFS);
+        (void)fprintf(stderr, "      directories; some loader information may",
+                      Pn);
+        (void)fprintf(stderr, " be unavailable.\n");
+    }
+    /*
+     * Get the loader module table.  Allocate hash space for it.
+     */
+    if ((ct = ldr_get_modules(SOL_GLOBAL, (void *)buf, &bufsz)) < 1)
+        return;
+    if (!(SoHash = (so_hash_t **)calloc((MALLOC_S)SOHASHBUCKS,
+                                        sizeof(so_hash_t *)))) {
+        (void)fprintf(stderr, "%s: no space for *.so hash buckets\n", Pn);
+        Error(ctx);
+    }
+    /*
+     * Cache the loader module information, complete with stat(2) results.
+     */
+    for (lp = (LDR_Mod_info_t *)buf; ct; ct--, lp++) {
+
+        /*
+         * Release previous name space allocations.
+         */
+        if (ln) {
+            (void)free((MALLOC_P *)ln);
+            ln = (char *)NULL;
+        }
+        if (rn) {
+            (void)free((MALLOC_P *)rn);
+            rn = (char *)NULL;
+        }
+        /*
+         * Make a copy of the loader module name.
+         */
+        if (!(rn = mkstrcpy(lp->mi_name, (MALLOC_S *)NULL))) {
+            (void)fprintf(stderr, "%s: no space for name: %s\n", Pn,
+                          lp->mi_name);
+            Error(ctx);
+        }
+        /*
+         * Resolve symbolic links.
+         */
+        ln = Readlink(rn);
+        if (ln == rn)
+            rn = (char *)NULL;
+        /*
+         * Get stat(2) information.
+         */
+        if (statsafely(ln, &sb)) {
+            if (!Fwarn)
+                (void)fprintf(stderr, "%s: WARNING: can't stat: %s\n", Pn, ln);
+            continue;
+        }
+        /*
+         * Allocate and fill a loader information hash structure.
+         */
+        if (!(sp = (so_hash_t *)malloc((MALLOC_S)sizeof(so_hash_t)))) {
+            (void)fprintf(stderr, "%s: no space for *.so hash entry: %s\n", Pn,
+                          ln);
+            Error(ctx);
+        }
+        sp->dev = sb.st_dev;
+        sp->nlink = (int)sb.st_nlink;
+        sp->nm = ln;
+        ln = (char *)NULL;
+        sp->node = (INODETYPE)sb.st_ino;
+        sp->sz = (SZOFFTYPE)sb.st_size;
+        /*
+         * Link the structure to the appropriate hash bucket.
+         */
+        h = SOHASH(sb.st_dev, (INODETYPE)sb.st_ino);
+        if (SoHash[h])
+            sp->next = SoHash[h];
+        else
+            sp->next = (so_hash_t *)NULL;
+        SoHash[h] = sp;
+    }
+    /*
+     * Free any unused name space that was allocated.
+     */
+    if (ln)
+        (void)free((MALLOC_P *)ln);
+    if (rn)
+        (void)free((MALLOC_P *)rn);
+}
+#endif /* AIXA>1 */
+
+/*
+ * initialize() - perform all initialization
+ */
+
+void initialize(struct lsof_context *ctx) {
+    get_kernel_access(ctx);
+
+#if AIXA > 1
+    (void)getsoinfo();
+#endif /* AIXA>1 */
+}
+
+/*
+ * kread() - read from kernel memory
+ */
+
+int kread(struct lsof_context *ctx, /* context */
+          KA_T addr,                /* kernel memory address */
+          char *buf,                /* buffer to receive data */
+          READLEN_T len)            /* length to read */
+{
+    int br;
+
+#if AIXV < 4200
+    if (lseek(Kd, (off_t)addr, L_SET) == (off_t)-1)
+#else  /* AIXV>=4200 */
+    if (lseek64(Kd, (off64_t)addr, L_SET) == (off64_t)-1)
+#endif /* AIXV<4200 */
+
+        return (1);
+    br = read(Kd, buf, len);
+    return ((br == len) ? 0 : 1);
+}
+
+/*
+ * kreadx() - read kernel segmented memory
+ */
+
+int kreadx(KA_T addr, /* kernel address */
+           char *buf, /* destination buffer */
+           int len,   /* length */
+           KA_T sid)  /* segment ID */
+{
+    int br;
+
+#if AIXV < 4200
+    if (lseek(Km, addr, L_SET) == (off_t)-1)
+#else  /* AIXV>=4200 */
+    if (lseek64(Km, (off64_t)addr, L_SET) == (off64_t)-1)
+#endif /* AIXV<4200 */
+
+        return (1);
+    br = readx(Km, buf, len, sid);
+    return (br == len ? 0 : 1);
+}
+
+#if defined(SIGDANGER)
+/*
+ * lowpgsp() - hangle a SIGDANGER signal about low paging space
+ */
+
+#    if defined(HASINTSIGNAL)
+static int
+#    else  /* !defined(HASINTSIGNAL) */
+static void
+#    endif /* defined(HASINTSIGNAL) */
+
+lowpgsp(struct lsof_context *ctx, int sig) {
+    (void)fprintf(stderr, "%s: FATAL: system paging space is low.\n", Pn);
+    Error(ctx);
+}
+#endif /* defined(SIGDANGER) */
+
+#if AIXA < 2
+/*
+ * process_text() - process text file information for non-ia64 AIX
+ */
+
+static void process_text(struct lsof_context *ctx, /* context */
+                         KA_T sid)                 /* user area segment ID */
+{
+    char *err, fd[8];
+    static struct file **f = (struct file **)NULL;
+    int i, j, n;
+    struct le *le;
+    KA_T ll;
+    MALLOC_S msz;
+    static MALLOC_S nf = 0;
+    struct file *xf = (struct file *)NULL;
+
+#    if AIXV >= 4300
+    struct la *la = (struct la *)&Up->U_loader;
+#    endif /* AIXV>=4300 */
+
+    /*
+     * Display information on the exec'd entry.
+     */
+
+#    if AIXV < 4300
+    if ((ll = (KA_T)Up->u_loader[1]))
+#    else  /* AIXV>=4300 */
+    if ((ll = (KA_T)la->exec))
+#    endif /* AIXV<4300 */
+
+    {
+        alloc_lfile(ctx, LSOF_FD_PROGRAM_TEXT, -1);
+        if ((le = getle(ctx, ll, sid, &err))) {
+            if ((xf = le->fp)) {
+                process_file(ctx, (KA_T)xf);
+                if (Lf->sf) {
+
+#    if AIXV >= 4110 && AIXV < 4300
+                    if (!Lf->nm || !Lf->nm[0])
+                        getlenm(le, sid);
+#    endif /* AIXV>=4110 && AIXV<4300 */
+
+                    link_lfile(ctx);
+                }
+            }
+        } else {
+            (void)snpf(Namech, Namechl, "text entry at %s: %s",
+                       print_kptr((KA_T)ll, (char *)NULL, 0), err);
+            enter_nm(ctx, Namech);
+            if (Lf->sf)
+                link_lfile(ctx);
+        }
+    }
+    /*
+     * Display the loader list.
+     */
+    for (i = n = 0,
+
+#    if AIXV < 4300
+        ll = (KA_T)Up->u_loader[0];
+#    else  /* AIXV>=4300 */
+        ll = (KA_T)la->list;
+#    endif /* AIXV<4300 */
+
+         ll; ll = (KA_T)le->next) {
+        alloc_lfile(ctx, LSOF_FD_LIBRARY_REF, i);
+        if (!(le = getle(ctx, ll, sid, &err))) {
+            (void)snpf(Namech, Namechl, "loader entry at %s: %s",
+                       print_kptr((KA_T)ll, (char *)NULL, 0), err);
+            enter_nm(ctx, Namech);
+            if (Lf->sf)
+                link_lfile(ctx);
+            return;
+        }
+        /*
+         * Skip entries with no file pointers, the exec'd file, and entries
+         * that have already been processed.
+         */
+        if (!le->fp || (le->fp == xf))
+            continue;
+        for (j = 0; j < n; j++) {
+            if (f[j] == le->fp)
+                break;
+        }
+        if (j < n)
+            continue;
+        if (n >= nf) {
+
+            /*
+             * Allocate file structure address cache space.
+             */
+            nf += 10;
+            msz = (MALLOC_S)(nf * sizeof(struct file *));
+            if (f)
+                f = (struct file **)realloc((MALLOC_P *)f, msz);
+            else
+                f = (struct file **)malloc(msz);
+            if (!f) {
+                (void)fprintf(stderr, "%s: no space for text file pointers\n",
+                              Pn);
+                Error(ctx);
+            }
+        }
+        f[n++] = le->fp;
+        /*
+         * Save the loader entry.
+         */
+        process_file(ctx, (KA_T)le->fp);
+        if (Lf->sf) {
+
+#    if AIXV >= 4110
+            if (!Lf->nm || !Lf->nm[0])
+                getlenm(ctx, le, sid);
+#    endif /* AIXV>=4110 */
+
+            link_lfile(ctx);
+            i++;
+        }
+    }
+}
+#else /* AIXA>=2 */
+/*
+ * process_text() - process text file information for ia64 AIX >= 5
+ */
+
+static void process_text(pid_t pid) /* process PID */
+{
+    char buf[MAXPATHLEN + 1], fd[8], *nm, *pp;
+    size_t bufl = sizeof(buf);
+    DIR *dfp;
+    struct dirent *dp;
+    int i;
+    struct la *la = (struct la *)&Up->U_loader;
+    struct le le;
+    struct lfile *lf;
+    struct stat sb;
+    so_hash_t *sp;
+    size_t sz;
+    dev_t xdev;
+    INODETYPE xnode;
+    int xs = 0;
+    /*
+     * Display information on the exec'd entry.
+     */
+    if (la->exec && !kread(ctx, (KA_T)la->exec, (char *)&le, sizeof(le)) &&
+        le.fp) {
+        alloc_lfile(ctx, LSOF_FD_PROGRAM_TEXT, -1);
+        process_file(ctx, (KA_T)le.fp);
+        if (Lf->dev_def && (Lf->inp_ty == 1)) {
+            xdev = Lf->dev;
+            xnode = Lf->inode;
+            xs = 1;
+        }
+        if (Lf->sf) {
+            if (!Lf->nm || !Lf->nm[0])
+                getlenm(&le, (KA_T)0);
+            link_lfile(ctx);
+        }
+    }
+    /*
+     * Collect devices and names for the entries in /HASPROCFS/PID/object -- the
+     * AIX 5 loader list equivalent.  When things fail in this processing --
+     * most likely for insufficient permissions -- be silent; a warning was
+     * issued by getsoinfo().
+     */
+    (void)snpf(buf, bufl, "/%s/%ld/object", HASPROCFS, (long)pid);
+    if (!(dfp = opendir(buf)))
+        return;
+    if ((sz = strlen(buf)) >= bufl)
+        return;
+    buf[sz++] = '/';
+    pp = &buf[sz];
+    sz = bufl - sz;
+    /*
+     * Read the entries in the /HASPROCFS/PID/object subdirectory.
+     */
+    for (dp = readdir(dfp), i = 0; dp; dp = readdir(dfp)) {
+
+        /*
+         * Skip '.', "..", entries with no node number, and entries whose
+         * names are too long.
+         */
+        if (!dp->d_ino || (dp->d_name[0] == '.'))
+            continue;
+        if ((dp->d_namlen + 1) >= sz)
+            continue;
+        (void)strncpy(pp, dp->d_name, dp->d_namlen);
+        pp[dp->d_namlen] = '\0';
+        /*
+         * Get stat(2) information.
+         */
+        if (statsafely(buf, &sb))
+            continue;
+        /*
+         * Ignore the exec'd and non-regular files.
+         */
+        if (xs && (xdev == sb.st_dev) && (xnode == (INODETYPE)sb.st_ino))
+            continue;
+        if (!S_ISREG(sb.st_mode))
+            continue;
+        /*
+         * Allocate space for a file entry.  Set its basic characteristics.
+         */
+        alloc_lfile(ctx, LSOF_FD_LIBRARY_REF, i++);
+        Lf->dev_def = Lf->inp_ty = Lf->nlink_def = 1;
+        Lf->dev = sb.st_dev;
+        Lf->inode = (INODETYPE)sb.st_ino;
+        Lf->type = LSOF_FILE_VNODE_VREG;
+        /*
+         * Look for a match on device and node numbers in the *.so cache.
+         */
+        for (sp = SoHash[SOHASH(sb.st_dev, (INODETYPE)sb.st_ino)]; sp;
+             sp = sp->next) {
+            if ((sp->dev == sb.st_dev) && (sp->node == (INODETYPE)sb.st_ino)) {
+
+                /*
+                 * A match was found; use its name, link count, and size.
+                 */
+                nm = sp->nm;
+                Lf->nlink = sp->nlink;
+                Lf->sz = sp->sz;
+                Lf->sz_def = 1;
+                break;
+            }
+        }
+        if (!sp) {
+
+            /*
+             * No match was found; use the /HASPROCFS/object name, its link
+             * count, and its size.
+             */
+            nm = pp;
+            Lf->nlink_def = sb.st_nlink;
+            Lf->sz = sb.st_size;
+            Lf->sz_def = 1;
+        }
+        /*
+         * Do selection tests: NFS; link count; file name; and file system.
+         */
+
+#    if defined(HAS_NFS)
+        if (Fnfs && (GET_MIN_DEV(Lf->dev_def) & SDEV_REMOTE))
+            Lf->sf |= SELNFS;
+#    endif /* defined(HAS_NFS) */
+
+        if (Nlink && (Lf->nlink < Nlink))
+            Lf->sf |= SELNLINK;
+        if (Sfile && is_file_named(NULL, VREG, 0, 0))
+            Lf->sf |= SELNM;
+        if (Lf->sf) {
+
+            /*
+             * If the file was selected, enter its name and link it to the
+             * other files of the process.
+             */
+            enter_nm(ctx, nm);
+            link_lfile(ctx);
+        }
+    }
+    (void)closedir(dfp);
+}
+#endif     /* AIXA<2 */
diff --git a/lib/dialects/aix/dproto.h b/lib/dialects/aix/dproto.h
new file mode 100644 (file)
index 0000000..70b1568
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * dproto.h - AIX function prototypes for lsof
+ *
+ * The _PROTOTYPE macro is defined in the common proto.h.
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+/*
+ * $Id: dproto.h,v 1.4 2004/03/10 23:49:13 abe Exp $
+ */
+
+#if !defined(DPROTO_H)
+#    define DPROTO_H
+
+#    if defined(HAS_AFS)
+extern struct vnode *alloc_vcache(void);
+extern int hasAFS(struct lsof_context *ctx, struct vnode *vp);
+extern int readafsnode(struct lsof_context *ctx, KA_T va, struct vnode *v,
+                       struct afsnode *an);
+#    endif /* defined(HAS_AFS) */
+
+#    if defined(HAS_JFS2)
+extern int readj2lino(struct lsof_context *ctx, struct gnode *ga, struct l_ino *li);
+#    endif /* defined(HAS_JFS2) */
+
+extern int getchan(char *p);
+extern int is_file_named(struct lsof_context *ctx, char *p, enum vtype ty, chan_t ch, int ic);
+extern char isglocked(struct lsof_context *ctx, struct gnode *ga);
+extern int readlino(struct lsof_context *ctx, struct gnode *ga, struct l_ino *li);
+extern struct l_vfs *readvfs(struct lsof_context *ctx, struct vnode *vn);
+
+#    if AIXV >= 4200
+extern void process_shmt(struct lsof_context *ctx, KA_T sa);
+#    endif /* AIV>=4200 */
+
+#    if defined(HASDCACHE) && AIXV >= 4140
+extern void clr_sect(struct lsof_context *ctx);
+extern int rw_clone_sect(struct lsof_context *ctx, int m);
+#    endif /* defined(HASDCACHE) && AIXV>=4140 */
+
+#endif /* !defined(DPROTO_H) */
diff --git a/lib/dialects/aix/dsock.c b/lib/dialects/aix/dsock.c
new file mode 100644 (file)
index 0000000..1a130ec
--- /dev/null
@@ -0,0 +1,418 @@
+/*
+ * dsock.c - AIX socket processing functions for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#ifndef lint
+static char copyright[] =
+    "@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
+#endif
+
+#include "common.h"
+
+/*
+ * We include <sys/domain.h> here instead of "dlsof.h" for gcc's benefit.
+ * Its loader can't handle the multiple CONST u_char arrays declared in
+ * <net/net_globals.h> -- e.g., etherbroadcastaddr[].  (<sys/domain.h>
+ * #include's <net/net_globals.h>.)
+ */
+
+#include <net/netopt.h>
+#include <sys/domain.h>
+
+/*
+ * process_socket() - process socket file
+ */
+
+void process_socket(struct lsof_context *ctx, /* context */
+                    KA_T sa)                  /* socket address in kernel */
+{
+    struct domain d;
+    unsigned char *fa = (unsigned char *)NULL;
+    int fam;
+    int fp, lp, uo;
+    struct gnode g;
+    struct l_ino i;
+    struct inpcb inp;
+    int is = 0;
+    unsigned char *la = (unsigned char *)NULL;
+    struct protosw p;
+    struct socket s;
+    struct tcpcb t;
+    int ts = 0;
+    int tsn, tsnx;
+    struct unpcb uc, unp;
+    struct sockaddr_un *ua = (struct sockaddr_un *)NULL;
+    struct sockaddr_un un;
+    struct vnode v;
+    struct mbuf mb;
+    /*
+     * Set socket file variables.
+     */
+    Lf->type = LSOF_FILE_SOCKET;
+    Lf->inp_ty = 2;
+    /*
+     * Read socket and protocol switch structures.
+     */
+    if (!sa) {
+        enter_nm(ctx, "no socket address");
+        return;
+    }
+    if (kread(ctx, sa, (char *)&s, sizeof(s))) {
+        (void)snpf(Namech, Namechl, "can't read socket struct from %s",
+                   print_kptr(sa, (char *)NULL, 0));
+        enter_nm(ctx, Namech);
+        return;
+    }
+    if (!s.so_type) {
+        enter_nm(ctx, "no socket type");
+        return;
+    }
+    if (!s.so_proto || kread(ctx, (KA_T)s.so_proto, (char *)&p, sizeof(p))) {
+        (void)snpf(Namech, Namechl, "can't read protocol switch from %s",
+                   print_kptr((KA_T)s.so_proto, (char *)NULL, 0));
+        enter_nm(ctx, Namech);
+        return;
+    }
+    /*
+     * Save size information.
+     */
+    if (Lf->access == LSOF_FILE_ACCESS_READ)
+        Lf->sz = (SZOFFTYPE)s.so_rcv.sb_cc;
+    else if (Lf->access == LSOF_FILE_ACCESS_WRITE)
+        Lf->sz = (SZOFFTYPE)s.so_snd.sb_cc;
+    else
+        Lf->sz = (SZOFFTYPE)(s.so_rcv.sb_cc + s.so_snd.sb_cc);
+    Lf->sz_def = 1;
+
+#if defined(HASTCPTPIQ)
+    Lf->lts.rq = s.so_rcv.sb_cc;
+    Lf->lts.sq = s.so_snd.sb_cc;
+    Lf->lts.rqs = Lf->lts.sqs = 1;
+#endif /* defined(HASTCPTPIQ) */
+
+#if defined(HASSOOPT)
+    Lf->lts.ltm = (unsigned int)s.so_linger;
+    Lf->lts.opt = (unsigned int)s.so_options;
+    Lf->lts.pqlen = (unsigned int)s.so_q0len;
+    Lf->lts.qlen = (unsigned int)s.so_qlen;
+    Lf->lts.qlim = (unsigned int)s.so_qlimit;
+    Lf->lts.rbsz = (unsigned long)s.so_rcv.sb_mbmax;
+    Lf->lts.sbsz = (unsigned long)s.so_snd.sb_mbmax;
+    Lf->lts.pqlens = Lf->lts.qlens = Lf->lts.qlims = Lf->lts.rbszs =
+        Lf->lts.sbszs = (unsigned char)1;
+#endif /* defined(HASSOOPT) */
+
+#if defined(HASSOSTATE)
+    Lf->lts.ss = (unsigned int)s.so_state;
+#endif /* defined(HASSOSTATE) */
+
+    /*
+     * Process socket by the associated domain family.
+     */
+    if (!p.pr_domain || kread(ctx, (KA_T)p.pr_domain, (char *)&d, sizeof(d))) {
+        (void)snpf(Namech, Namechl, "can't read domain struct from %s",
+                   print_kptr((KA_T)p.pr_domain, (char *)NULL, 0));
+        enter_nm(ctx, Namech);
+        return;
+    }
+    switch ((fam = d.dom_family)) {
+        /*
+         * Process an Internet domain socket.
+         */
+    case AF_INET:
+
+#if defined(HASIPv6)
+    case AF_INET6:
+#endif /* defined(HASIPv6) */
+
+        /*
+         * Read protocol control block.
+         */
+        if (!s.so_pcb ||
+            kread(ctx, (KA_T)s.so_pcb, (char *)&inp, sizeof(inp))) {
+            if (!s.so_pcb) {
+                (void)snpf(
+                    Namech, Namechl, "no PCB%s%s",
+                    (s.so_state & SS_CANTSENDMORE) ? ", CANTSENDMORE" : "",
+                    (s.so_state & SS_CANTRCVMORE) ? ", CANTRCVMORE" : "");
+            } else {
+                (void)snpf(Namech, Namechl, "can't read inpcb at %s",
+                           print_kptr((KA_T)s.so_pcb, (char *)NULL, 0));
+            }
+            enter_nm(ctx, Namech);
+            return;
+        }
+        if (p.pr_protocol == IPPROTO_TCP) {
+
+            /*
+             * If this is a TCP socket, read its control block.
+             */
+            if (inp.inp_ppcb &&
+                !kread(ctx, (KA_T)inp.inp_ppcb, (char *)&t, sizeof(t))) {
+                ts = 1;
+                tsn = (int)t.t_state;
+                tsnx = tsn + TcpStOff;
+            }
+        }
+        if (ts && (TcpStIn || TcpStXn) && (tsnx >= 0) && (tsnx < TcpNstates)) {
+
+            /*
+             * Check TCP state name inclusion and exclusions.
+             */
+            if (TcpStXn) {
+                if (TcpStX[tsnx]) {
+                    Lf->sf |= SELEXCLF;
+                    return;
+                }
+            }
+            if (TcpStIn) {
+                if (TcpStI[tsnx])
+                    TcpStI[tsnx] = 2;
+                else {
+                    Lf->sf |= SELEXCLF;
+                    return;
+                }
+            }
+        }
+        if (Fnet) {
+
+            /*
+             * Set SELNET flag for the file, as requested.
+             */
+            if (!FnetTy || ((FnetTy == 4) && (fam == AF_INET))
+
+#if defined(HASIPv6)
+                || ((FnetTy == 6) && (fam == AF_INET6))
+#endif /* defined(HASIPv6) */
+            )
+
+                Lf->sf |= SELNET;
+        }
+        printiproto(ctx, p.pr_protocol);
+
+#if defined(HASIPv6)
+        Lf->type = fam == AF_INET ? LSOF_FILE_IPV4 : LSOF_FILE_IPV6;
+#else  /* !defined(HASIPv6) */
+        Lf->type = LSOF_FILE_INET;
+#endif /* defined(HASIPv6) */
+
+        /*
+         * Save Internet socket information.
+         */
+        enter_dev_ch(ctx,
+                     print_kptr((KA_T)(inp.inp_ppcb ? inp.inp_ppcb : s.so_pcb),
+                                (char *)NULL, 0));
+
+#if defined(HASIPv6)
+        /*
+         * If this is an IPv6 (AF_INET6) socket and IPv4 compatibility
+         * mode is enabled, use the IPv4 address, change the family
+         * indicator from AF_INET6 to AF_INET.  Otherwise, use the IPv6
+         * address.  Don't ignore empty addresses.
+         */
+        if (fam == AF_INET6) {
+            if (inp.inp_flags & INP_COMPATV4) {
+                fam = AF_INET;
+                la = (unsigned char *)&inp.inp_laddr;
+            } else
+                la = (unsigned char *)&inp.inp_laddr6;
+        } else
+#endif /* defined(HASIPv6) */
+
+            la = (unsigned char *)&inp.inp_laddr;
+        lp = (int)ntohs(inp.inp_lport);
+        if (fam == AF_INET &&
+            (inp.inp_faddr.s_addr != INADDR_ANY || inp.inp_fport != 0)) {
+            fa = (unsigned char *)&inp.inp_faddr;
+            fp = (int)ntohs(inp.inp_fport);
+        }
+
+#if defined(HASIPv6)
+        else if (fam == AF_INET6) {
+
+            /*
+             * If this is an IPv6 (AF_INET6) socket and IPv4 compatibility
+             * mode is enabled, use the IPv4 address, change the family
+             * indicator from AF_INET6 to AF_INET.  Otherwise, use the IPv6
+             * address.  Ignore empty addresses.
+             */
+            if (inp.inp_flags & INP_COMPATV4) {
+                fam = AF_INET;
+                if (inp.inp_faddr.s_addr != INADDR_ANY || inp.inp_fport != 0) {
+                    fa = (unsigned char *)&inp.inp_faddr;
+                    fp = (int)ntohs(inp.inp_fport);
+                }
+            } else {
+                if (!IN6_IS_ADDR_UNSPECIFIED(&inp.inp_faddr6)) {
+                    fa = (unsigned char *)&inp.inp_faddr6;
+                    fp = (int)ntohs(inp.inp_fport);
+                }
+            }
+        }
+#endif /* defined(HASIPv6) */
+
+        if (fa || la)
+            (void)ent_inaddr(ctx, la, lp, fa, fp, fam);
+        if (ts) {
+            Lf->lts.type = 0;
+            Lf->lts.state.i = tsn;
+
+#if defined(HASSOOPT)
+            Lf->lts.kai = (unsigned int)t.t_timer[TCPT_KEEP];
+#endif /* defined(HASSOOPT) */
+
+#if defined(HASTCPOPT)
+            Lf->lts.mss = (unsigned long)t.t_maxseg;
+            Lf->lts.msss = (unsigned char)1;
+            Lf->lts.topt = (unsigned int)t.t_flags;
+#endif /* defined(HASTCPOPT) */
+        }
+        break;
+        /*
+         * Process a ROUTE domain socket.
+         */
+    case AF_ROUTE:
+        Lf->type = LSOF_FILE_ROUTE;
+        if (s.so_pcb)
+            enter_dev_ch(ctx, print_kptr((KA_T)(s.so_pcb), (char *)NULL, 0));
+        else
+            (void)snpf(Namech, Namechl, "no protocol control block");
+        break;
+        /*
+         * Process a Unix domain socket.
+         */
+    case AF_UNIX:
+        if (Funix)
+            Lf->sf |= SELUNX;
+        Lf->type = LSOF_FILE_UNIX;
+        /*
+         * Read Unix protocol control block and the Unix address structure.
+         */
+        enter_dev_ch(ctx, print_kptr(sa, (char *)NULL, 0));
+        if (kread(ctx, (KA_T)s.so_pcb, (char *)&unp, sizeof(unp))) {
+            (void)snpf(Namech, Namechl, "can't read unpcb at %s",
+                       print_kptr((KA_T)s.so_pcb, (char *)NULL, 0));
+            break;
+        }
+        if ((struct socket *)sa != unp.unp_socket) {
+            (void)snpf(Namech, Namechl, "unp_socket (%s) mismatch",
+                       print_kptr((KA_T)unp.unp_socket, (char *)NULL, 0));
+            break;
+        }
+        if (unp.unp_addr) {
+            if (kread(ctx, (KA_T)unp.unp_addr, (char *)&mb, sizeof(mb))) {
+                (void)snpf(Namech, Namechl, "can't read unp_addr at %s",
+                           print_kptr((KA_T)unp.unp_addr, (char *)NULL, 0));
+                break;
+            }
+
+#if AIXV >= 3200
+            uo = (int)(mb.m_hdr.mh_data - (caddr_t)unp.unp_addr);
+            if ((uo + sizeof(struct sockaddr)) <= sizeof(mb))
+                ua = (struct sockaddr_un *)((char *)&mb + uo);
+            else {
+                if (mb.m_hdr.mh_data && !kread(ctx, (KA_T)mb.m_hdr.mh_data,
+                                               (char *)&un, sizeof(un))) {
+                    ua = &un;
+                }
+            }
+#else  /* AIXV<3200 */
+            ua = (struct sockaddr_un *)(((char *)&mb) + mb.m_off);
+#endif /* AIXV>=3200 */
+        }
+        if (!ua) {
+            ua = &un;
+            (void)bzero((char *)ua, sizeof(un));
+            ua->sun_family = AF_UNSPEC;
+        }
+        /*
+         * Print information on Unix socket that has no address bound
+         * to it, although it may be connected to another Unix domain
+         * socket as a pipe.
+         */
+        if (ua->sun_family != AF_UNIX) {
+            if (ua->sun_family == AF_UNSPEC) {
+                if (unp.unp_conn) {
+                    if (kread(ctx, (KA_T)unp.unp_conn, (char *)&uc, sizeof(uc)))
+                        (void)snpf(
+                            Namech, Namechl, "can't read unp_conn at %s",
+                            print_kptr((KA_T)unp.unp_conn, (char *)NULL, 0));
+                    else
+                        (void)snpf(
+                            Namech, Namechl, "->%s",
+                            print_kptr((KA_T)uc.unp_socket, (char *)NULL, 0));
+                } else
+                    (void)snpf(Namech, Namechl, "->(none)");
+            } else
+                (void)snpf(Namech, Namechl, "unknown sun_family (%d)",
+                           ua->sun_family);
+            break;
+        }
+        /*
+         * Read any associated vnode and then read its gnode and inode.
+         */
+        g.gn_type = VSOCK;
+        if (unp.unp_vnode && !readvnode(ctx, (KA_T)unp.unp_vnode, &v)) {
+            if (v.v_gnode && !readgnode(ctx, (KA_T)v.v_gnode, &g)) {
+                Lf->lock = isglocked(ctx, &g);
+                if (g.gn_type == VSOCK && g.gn_data && !readlino(ctx, &g, &i))
+                    is = 1;
+            }
+        }
+        /*
+         * Print Unix socket information.
+         */
+        if (is) {
+            Lf->dev = i.dev;
+            Lf->dev_def = i.dev_def;
+            if (Lf->dev_ch) {
+                (void)free((FREE_P *)Lf->dev_ch);
+                Lf->dev_ch = (char *)NULL;
+            }
+            Lf->inode = (INODETYPE)i.number;
+            Lf->inp_ty = i.number_def;
+        }
+        if (ua->sun_path[0]) {
+            if (mb.m_len > sizeof(struct sockaddr_un))
+                mb.m_len = sizeof(struct sockaddr_un);
+            *((char *)ua + mb.m_len - 1) = '\0';
+            if (Sfile && is_file_named(ctx, ua->sun_path, VSOCK, 0, 0))
+                Lf->sf |= SELNM;
+            if (!Namech[0])
+                (void)snpf(Namech, Namechl, "%s", ua->sun_path);
+        } else
+            (void)snpf(Namech, Namechl, "no address");
+        break;
+
+    default:
+        printunkaf(ctx, fam, 1);
+    }
+    if (Namech[0])
+        enter_nm(ctx, Namech);
+}
diff --git a/lib/dialects/aix/dstore.c b/lib/dialects/aix/dstore.c
new file mode 100644 (file)
index 0000000..11d6ff0
--- /dev/null
@@ -0,0 +1,398 @@
+/*
+ * dstore.c - AIX global storage for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#ifndef lint
+static char copyright[] =
+    "@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
+#endif
+
+#include "common.h"
+
+/*
+ * Global storage definitions
+ */
+
+#if defined(HAS_AFS)
+struct nlist AFSnl[] = {
+    {"afs_rootFid", 0, 0, 0, 0, 0},
+    {"afs_volumes", 0, 0, 0, 0, 0},
+};
+
+#    if defined(HASAOPT)
+char *AFSApath = (char *)NULL; /* alternate AFS name list path
+                                * (from -a) */
+#    endif                     /* defined(HASAOPT) */
+
+KA_T AFSVfsp = (KA_T)NULL; /* AFS vfs struct kernel address */
+#endif                     /* defined(HAS_AFS) */
+
+#if AIXV >= 4140
+struct clone *Clone = (struct clone *)NULL;
+/* local clone information */
+int CloneMaj = -1; /* clone major device number */
+int ClonePtc = -1; /* /dev/ptc minor device number */
+#endif             /* AIXV>=4140 */
+
+int Kd = -1;               /* /dev/kmem file descriptor */
+struct l_vfs *Lvfs = NULL; /* local vfs structure table */
+int Km = -1;               /* /dev/mem file descriptor */
+
+struct nlist Nl[] = {
+
+#if AIXV < 4100
+    {"u", 0, 0, 0, 0, 0},
+#else  /* AIXV>=4100 */
+    {"__ublock", 0, 0, 0, 0, 0},
+#endif /* AIXV<4100 */
+
+};
+
+#if defined(HASFSTRUCT)
+/*
+ * Pff_tab[] - table for printing file flags
+ */
+
+struct pff_tab Pff_tab[] = {
+
+#    if defined(FREAD)
+    {(long)FREAD, FF_READ},
+#    else /* !defined(FREAD) */
+#        if defined(_FREAD)
+    {(long)_FREAD, FF_READ},
+#        endif /* defined(_FREAD) */
+#    endif     /* defined(FREAD) */
+
+#    if defined(FWRITE)
+    {(long)FWRITE, FF_WRITE},
+#    else /* !defined(FWRITE) */
+#        if defined(_FWRITE)
+    {(long)_FWRITE, FF_WRITE},
+#        endif /* defined(_FWRITE) */
+#    endif     /* defined(FWRITE) */
+
+#    if defined(FNONBLOCK)
+    {(long)FNONBLOCK, FF_NBLOCK},
+#    else /* !defined(FNONBLOCK) */
+#        if defined(_FNONBLOCK)
+    {(long)_FNONBLOCK, FF_NBLOCK},
+#        endif /* defined(_FNONBLOCK) */
+#    endif     /* defined(FNONBLOCK) */
+
+#    if defined(FAPPEND)
+    {(long)FAPPEND, FF_APPEND},
+#    else /* !defined(FAPPEND) */
+#        if defined(_FAPPEND)
+    {(long)_FAPPEND, FF_APPEND},
+#        endif /* defined(_FAPPEND) */
+#    endif     /* defined(FAPPEND) */
+
+#    if defined(FSYNC)
+    {(long)FSYNC, FF_SYNC},
+#    else /* !defined(FSYNC) */
+#        if defined(_FSYNC)
+    {(long)_FSYNC, FF_SYNC},
+#        endif /* defined(_FSYNC) */
+#    endif     /* defined(FSYNC) */
+
+#    if defined(FEXEC)
+    {(long)FEXEC, FF_EXEC},
+#    else /* !defined(FEXEC) */
+#        if defined(_FEXEC)
+    {(long)_FEXEC, FF_EXEC},
+#        endif /* defined(_FEXEC) */
+#    endif     /* defined(FEXEC) */
+
+#    if defined(FCREAT)
+    {(long)FCREAT, FF_CREAT},
+#    else /* !defined(FCREAT) */
+#        if defined(_FCREAT)
+    {(long)_FCREAT, FF_CREAT},
+#        endif /* defined(_FCREAT) */
+#    endif     /* defined(FCREAT) */
+
+#    if defined(FTRUNC)
+    {(long)FTRUNC, FF_TRUNC},
+#    else /* !defined(FTRUNC) */
+#        if defined(_FTRUNC)
+    {(long)_FTRUNC, FF_TRUNC},
+#        endif /* defined(_FTRUNC) */
+#    endif     /* defined(FTRUNC) */
+
+#    if defined(FEXCL)
+    {(long)FEXCL, FF_EXCL},
+#    else /* !defined(FEXCL) */
+#        if defined(_FEXCL)
+    {(long)_EXCL, FF_EXCL},
+#        endif /* defined(_FEXCL) */
+#    endif     /* defined(FEXCL) */
+
+#    if defined(FNOCTTY)
+    {(long)FNOCTTY, FF_NOCTTY},
+#    else /* !defined(FNOCTTY) */
+#        if defined(_FNOCTTY)
+    {(long)_FNOCTTY, FF_NOCTTY},
+#        endif /* defined(_FNOCTTY) */
+#    endif     /* defined(FNOCTTY) */
+
+#    if defined(FRSHARE)
+    {(long)FRSHARE, FF_RSHARE},
+#    else /* !defined(FRSHARE) */
+#        if defined(_FRSHARE)
+    {(long)_FRSHARE, FF_RSHARE},
+#        endif /* defined(_FRSHARE) */
+#    endif     /* defined(FRSHARE) */
+
+#    if defined(FDEFER)
+    {(long)FDEFER, FF_DEFER},
+#    else /* !defined(FDEFER) */
+#        if defined(_FDEFER)
+    {(long)_FDEFER, FF_DEFER},
+#        endif /* defined(_FDEFER) */
+#    endif     /* defined(FDEFER) */
+
+#    if defined(FDELAY)
+    {(long)FDELAY, FF_DELAY},
+#    else /* !defined(FDELAY) */
+#        if defined(_FDELAY)
+    {(long)_FDELAY, FF_DELAY},
+#        endif /* defined(_FDELAY) */
+#    endif     /* defined(FDELAY) */
+
+#    if defined(FNDELAY)
+    {(long)FNDELAY, FF_NDELAY},
+#    else /* !defined(FNDELAY) */
+#        if defined(_FNDELAY)
+    {(long)_FNDELAY, FF_NDELAY},
+#        endif /* defined(_FNDELAY) */
+#    endif     /* defined(FNDELAY) */
+
+#    if defined(FNSHARE)
+    {(long)FNSHARE, FF_NSHARE},
+#    else /* !defined(FNSHARE) */
+#        if defined(_FNSHARE)
+    {(long)_FNSHARE, FF_NSHARE},
+#        endif /* defined(_FNSHARE) */
+#    endif     /* defined(FNSHARE) */
+
+#    if defined(FASYNC)
+    {(long)FASYNC, FF_ASYNC},
+#    else /* !defined(FASYNC) */
+#        if defined(_FASYNC)
+    {(long)_FASYNC, FF_ASYNC},
+#        endif /* defined(_FASYNC) */
+#    endif     /* defined(FASYNC) */
+
+#    if defined(FAIO)
+    {(long)FAIO, FF_AIO},
+#    else /* !defined(FAIO) */
+#        if defined(_FAIO)
+    {(long)_FAIO, FF_AIO},
+#        endif /* defined(_FAIO) */
+#    endif     /* defined(FAIO) */
+
+#    if defined(FCIO)
+    {(long)FCIO, FF_CIO},
+#    else /* !defined(FCIO) */
+#        if defined(_FCIO)
+    {(long)_FCIO, FF_CIO},
+#        endif /* defined(_FCIO) */
+#    endif     /* defined(FCIO) */
+
+#    if defined(FMOUNT)
+    {(long)FMOUNT, FF_MOUNT},
+#    else /* !defined(FMOUNT) */
+#        if defined(_FMOUNT)
+    {(long)_FMOUNT, FF_MOUNT},
+#        endif /* defined(_FMOUNT) */
+#    endif     /* defined(FMOUNT) */
+
+#    if defined(FSYNCALL)
+    {(long)FSYNCALL, FF_SYNC},
+#    else /* !defined(FSYNCALL) */
+#        if defined(_FSYNCALL)
+    {(long)_FSYNCALL, FF_SYNC},
+#        endif /* defined(_FSYNCALL) */
+#    endif     /* defined(FSYNCALL) */
+
+#    if defined(FNOCACHE)
+    {(long)FNOCACHE, FF_NOCACHE},
+#    else /* defined(FNOCACHE) */
+#        if defined(_FNOCACHE)
+    {(long)_FNOCACHE, FF_NOCACHE},
+#        endif /* defined(_FNOCACHE) */
+#    endif     /* defined(FNOCACHE) */
+
+#    if defined(FREADSYNC)
+    {(long)FREADSYNC, FF_RSYNC},
+#    else /* !defined(FREADSYNC) */
+#        if defined(_FREADSYNC)
+    {(long)_FREADSYNC, FF_RSYNC},
+#        endif /* defined(_FREADSYNC) */
+#    endif     /* defined(FREADSYNC) */
+
+#    if defined(FDATASYNC)
+    {(long)FDATASYNC, FF_DSYNC},
+#    else /* !defined(FDATASYNC) */
+#        if defined(_FDATASYNC)
+    {(long)_FDATASYNC, FF_DSYNC},
+#        endif /* defined(_FDATASYNC) */
+#    endif     /* defined(FDATASYNC) */
+
+#    if defined(FDEFERIND)
+    {(long)FDEFERIND, FF_DEFERIND},
+#    else /* !defined(FDEFERIND) */
+#        if defined(_FDEFERIND)
+    {(long)_FDEFERIND, FF_DEFERIND},
+#        endif /* defined(_FDEFERIND) */
+#    endif     /* defined(FDEFERIND) */
+
+#    if defined(FDATAFLUSH)
+    {(long)FDATAFLUSH, FF_DATAFLUSH},
+#    else /* !defined(FDATAFLUSH) */
+#        if defined(_FDATAFLUSH)
+    {(long)_FDATAFLUSH, FF_DATAFLUSH},
+#        endif /* defined(_FDATAFLUSH) */
+#    endif     /* defined(FDATAFLUSH) */
+
+#    if defined(FCLREAD)
+    {(long)FCLREAD, FF_CLREAD},
+#    else /* !defined(FCLREAD) */
+#        if defined(_FCLREAD)
+    {(long)_FCLREAD, FF_CLREAD},
+#        endif /* defined(_FCLREAD) */
+#    endif     /* defined(FCLREAD) */
+
+#    if defined(FLARGEFILE)
+    {(long)FLARGEFILE, FF_LARGEFILE},
+#    else /* !defined(FLARGEFILE) */
+#        if defined(_FLARGEFILE)
+    {(long)_FLARGEFILE, FF_LARGEFILE},
+#        endif /* defined(_FLARGEFILE) */
+#    endif     /* defined(FLARGEFILE) */
+
+#    if defined(FDIRECT)
+    {(long)FDIRECT, FF_DIRECT},
+#    else /* !defined(FDIRECT) */
+#        if defined(_FDIRECT)
+    {(long)_FDIRECT, FF_DIRECT},
+#        endif /* defined(_FDIRECT) */
+#    endif     /* defined(FDIRECT) */
+
+#    if defined(FSNAPSHOT)
+    {(long)FSNAPSHOT, FF_SNAP},
+#    else /* !defined(FSNAPSHOT) */
+#        if defined(_FSNAPSHOT)
+    {(long)_FSNAPSHOT, FF_SNAP},
+#        endif /* defined(_FSNAPSHOT) */
+#    endif     /* defined(FAIO) */
+
+#    if defined(FDOCLONE)
+    {(long)FDOCLONE, FF_DOCLONE},
+#    else /* !defined(FDOCLONE) */
+#        if defined(_FDOCLONE)
+    {(long)_FDOCLONE, FF_DOCLONE},
+#        endif /* defined(_FDOCLONE) */
+#    endif     /* defined(FDOCLONE) */
+
+#    if defined(FKERNEL)
+    {(long)FKERNEL, FF_KERNEL},
+#    else /* !defined(FKERNEL) */
+#        if defined(_FKERNEL)
+    {(long)_FKERNEL, FF_KERNEL},
+#        endif /* defined(_FKERNEL) */
+#    endif     /* defined(FKERNEL) */
+
+#    if defined(FMSYNC)
+    {(long)FMSYNC, FF_MSYNC},
+#    else /* !defined(FMSYNC) */
+#        if defined(_FMSYNC)
+    {(long)_FMSYNC, FF_MSYNC},
+#        endif /* defined(_FMSYNC) */
+#    endif     /* defined(FMSYNC) */
+
+#    if defined(GCFDEFER)
+    {(long)GCFDEFER, FF_GCFDEFER},
+#    endif /* defined(GCFDEFER) */
+
+#    if defined(GCFMARK)
+    {(long)GCFMARK, FF_GCFMARK},
+#    endif /* defined(GCFMARK) */
+
+    {(long)0, NULL}};
+
+/*
+ * Pof_tab[] - table for print process open file flags
+ */
+
+struct pff_tab Pof_tab[] = {
+
+#    if defined(UF_EXCLOSE)
+    {(long)UF_EXCLOSE, POF_CLOEXEC},
+#    endif /* defined(UF_EXCLOSE) */
+
+#    if defined(UF_MAPPED)
+    {(long)UF_MAPPED, POF_MAPPED},
+#    endif /* defined(UF_MAPPED) */
+
+#    if defined(UF_FDLOCK)
+    {(long)UF_FDLOCK, POF_FDLOCK},
+#    endif /* defined(UF_FDLOCK) */
+
+#    if defined(UF_AUD_READ)
+    {(long)UF_AUD_READ, POF_BNRD},
+#    endif /* defined(UF_AUD_READ) */
+
+#    if defined(UF_AUD_WRITE)
+    {(long)UF_AUD_WRITE, POF_BNWR},
+#    endif /* defined(UF_AUD_WRITE) */
+
+#    if defined(UF_FSHMAT)
+    {(long)UF_FSHMAT, POF_FSHMAT},
+#    endif /* defined(UF_FSHMAT) */
+
+#    if defined(UF_CLOSING)
+    {(long)UF_CLOSING, POF_CLOSING},
+#    endif /* defined(UF_CLOSING) */
+
+#    if defined(UF_ALLOCATED)
+    {(long)UF_ALLOCATED, POF_ALLOCATED},
+#    endif /* defined(UF_ALLOCATED) */
+
+    {(long)0, NULL}};
+#endif /* defined(HASFSTRUCT) */
+
+#if AIXV >= 4110
+struct ublock __ublock; /* dummy so we can define _KERNEL
+                         * for <sys/user.h> */
+
+#    if AIXA > 2
+void aix_dstore_dummy_function() {} /* for ia64 idebug */
+#    endif                          /* AIXA>2 */
+#endif                              /* AIXV>=4110 */
diff --git a/lib/dialects/aix/machine.h b/lib/dialects/aix/machine.h
new file mode 100644 (file)
index 0000000..3c6a955
--- /dev/null
@@ -0,0 +1,631 @@
+/*
+ * machine.h - AIX definitions for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+/*
+ * $Id: machine.h,v 1.43 2010/07/29 16:02:44 abe Exp $
+ */
+
+#if !defined(LSOF_MACHINE_H)
+#    define LSOF_MACHINE_H 1
+
+#    if AIXV <= 3250
+/*
+ * The AIX 3.2.5 and below <netdb.h> requires that _SUN be defined to
+ * be able to get the rpcent structure definition.
+ */
+
+#        define _SUN
+#        include <netdb.h>
+#        undef _SUN
+#    endif /* AIXV<=3250 */
+
+#    if AIXV >= 4200
+/*
+ * AIX 4.2 requires that <sys/mstsave.h> be #include'd early.  It needs
+ * <sys/types.h> and _KERNEL.
+ *
+ * AIX 4.3 requires that _KERNEL be defined before the #include of
+ * <sys/types.h>
+ *
+ * For gcc's sake, some redefinitions after including <sys/types.h> insure
+ * the off64_t and offset_t types are aligned on an 8 byte boundary.
+ */
+
+#        if AIXV >= 4300
+#            define _KERNEL 1
+#        endif /* AIXV>=4300 */
+
+#        include <sys/types.h>
+
+#        if AIXA > 0
+#            include <sys/resource.h>
+#        endif /* AIXA>0 */
+
+#        if defined(__GNUC__)
+typedef long long aligned_off64_t __attribute__((aligned(8)));
+typedef long long aligned_offset_t __attribute__((aligned(8)));
+#            define off64_t aligned_off64_t
+#            define offset_t aligned_offset_t
+#        endif /* defined(__GNUC__) */
+
+#        if AIXV < 4300
+#            define _KERNEL 1
+#        endif /* AIXV<4300 */
+
+#        include <sys/mstsave.h>
+#        undef _KERNEL
+#    endif /* AIXV>=4200 */
+
+/*
+ * 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().
+ */
+
+#    if AIXV >= 4200
+#        define CAN_USE_CLNT_CREATE 1
+#    endif /* AIXV>=4200 */
+
+/*
+ * DEVDEV_PATH defines the path to the directory that contains device
+ * nodes.
+ */
+
+#    define DEVDEV_PATH "/dev"
+
+/*
+ * GET_MAX_FD is defined for those dialects that provide a function other than
+ * getdtablesize() to obtain the maximum file descriptor number plus one.
+ */
+
+/* #define     GET_MAX_FD      ?       */
+
+/*
+ * HASAOPT is defined for those dialects that have AFS support; it specifies
+ * that the default path to an alternate AFS kernel name list file may be
+ * supplied with the -A <path> option.
+ */
+
+/* #define     HASAOPT         1 */
+
+/*
+ * HASBLKDEV is defined for those dialects that want block device information
+ * recorded in BDevtp[].
+ */
+
+#    define HASBLKDEV 1
+
+/*
+ * HASDCACHE is defined for those dialects that support a device cache
+ * file.
+ *
+ * HASENVDC defined the name of an environment variable that contains the
+ * device cache file path.  The HASENVDC environment variable is ignored when
+ * the lsof process is setuid(root) or its real UID is 0.
+ *
+ * HASPERSDC defines the format for the last component of a personal device
+ * cache file path.  The first will be the home directory of the real UID that
+ * executes lsof.
+ *
+ * HASPERSDCPATH defines the environment variable whose value is the middle
+ * component of the personal device cache file path.  The middle component
+ * follows the home directory and precedes the results of applying HASPERSDC.
+ * The HASPERSDCPATH environment variable is ignored when the lsof process is
+ * setuid(root) or its real UID is 0.
+ *
+ * HASSYSDC defines a public device cache file path.  When it's defined, it's
+ * used as the path from which to read the device cache.
+ *
+ * Consult the 00DCACHE and 00FAQ files of the lsof distribution for more
+ * information on device cache file path construction.
+ */
+
+#    define HASDCACHE 1
+#    define HASENVDC "LSOFDEVCACHE"
+#    define HASPERSDC "%h/%p.lsof_%L"
+#    define HASPERSDCPATH "LSOFPERSDCPATH"
+/* #define     HASSYSDC        "/your/choice/of/path" */
+
+/*
+ * HASCDRNODE is defined for those dialects that have CD-ROM nodes.
+ */
+
+#    define HASCDRNODE 1
+
+/*
+ * HASFIFONODE is defined for those dialects that have FIFO nodes.
+ */
+
+#    if AIXV >= 3200
+#        define HASFIFONODE 1
+#    endif /* AIXV>=3200 */
+
+/*
+ * 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->... */
+
+/*
+ * 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.  (AIX lsof doesn't use nlist, it uses knlist.)
+ */
+
+/* #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?       */
+
+/*
+ * 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.
+ */
+
+#    if AIXV >= 4140
+#        define HASPRIVFILETYPE process_shmt
+#        define PRIVFILETYPE 15
+#    endif /* AIXV>=4140 */
+
+/*
+ * 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.
+ */
+
+#    if AIXA < 1
+/* #define     HASPROCFS       "proc?" */
+/* #define     HASFSTYPE       1 */
+/* #define     HASPINODEN      1 */
+#    else /* AIXA>=1 */
+#        define HASPROCFS "proc"
+#        define HASFSTYPE 2
+#        define HASPINODEN 1
+#    endif /* AIXA<1 */
+
+/*
+ * HASRNODE is defined for those dialects that have rnodes.
+ *
+ * Note: while AIX has rnodes, they are processed privately, so this
+ *      definition should be disabled.
+ */
+
+/* #define     HASRNODE        1 */
+
+/*
+ * Define HASSECURITY to restrict the listing of all open files to the
+ * root user.  When HASSECURITY is defined, the non-root user may list
+ * only files whose processes have the same user ID as the real user ID
+ * (the one that its user logged on with) of the lsof process.
+ */
+
+/* #define     HASSECURITY     1       */
+
+/*
+ * If HASSECURITY is defined, define HASNOSOCKSECURITY to allow users
+ * restricted by HASSECURITY to list any open socket files, provide their
+ * listing is selected by the "-i" option.
+ */
+
+/* #define     HASNOSOCKSECURITY       1       */
+
+/*
+ * HASSETLOCALE is defined for those dialects that have <locale.h> and
+ * setlocale().
+ *
+ * If the dialect also has wide character support for language locales,
+ * HASWIDECHAR activates lsof's wide character support and WIDECHARINCL
+ * defines the header file (if any) that must be #include'd to use the
+ * mblen() and mbtowc() functions.
+ */
+
+#    define HASSETLOCALE 1
+
+#    if AIXV >= 4320
+#        define HASWIDECHAR 1
+#    endif /* AIXV>=4320 */
+
+/* #define     WIDECHARINCL    <wchar.h>       */
+
+/*
+ * HASSNODE is defined for those dialects that have snodes.
+ */
+
+/* #define     HASSNODE        1 */
+
+/*
+ * HASTASKS is defined for those dialects that have task reporting support.
+ */
+
+/* #define     HASTASKS        1 */
+
+/*
+ * HASSOOPT, HASSOSTATE and HASTCPOPT define the availability of information
+ * on socket options (SO_* symbols), socket states (SS_* symbols) and TCP
+ * options.
+ */
+
+#    define HASSOOPT 1   /* has socket option information */
+#    define HASSOSTATE 1 /* has socket state information */
+#    define HASTCPOPT 1  /* has TCP options or flags */
+
+/*
+ * Define HASSPECDEVD to be the name of a function that handles the results
+ * of a successful stat(2) of a file name argument.
+ *
+ * For example, HASSPECDEVD() for Darwin makes sure that st_dev is set to
+ * what stat("/dev") returns -- i.e., what's in DevDev.
+ *
+ * The function takes two arguments:
+ *
+ *     1: pointer to the full path name of file
+ *     2: pointer to the stat(2) result
+ *
+ * The function returns void.
+ */
+
+/* #define     HASSPECDEVD     process_dev_stat */
+
+/*
+ * HASSTREAMS is defined for those dialects that support streams.
+ */
+
+/* #define     HASSTREAMS      1 */
+
+/*
+ * HASTCPTPIQ is defined for dialects where it is possible to report the
+ * TCP/TPI Recv-Q and Send-Q values produced by netstat.
+ */
+
+#    define HASTCPTPIQ 1
+
+/*
+ * HASTCPTPIW is defined for dialects where it is possible to report the
+ * TCP/TPI send and receive window sizes produced by netstat.
+ */
+
+/* #define     HASTCPTPIW      1 */
+
+/*
+ * HASTCPUDPSTATE is defined for dialects that have TCP and UDP state
+ * support -- i.e., for the "-stcp|udp:state" option and its associated
+ * speed improvements.
+ */
+
+#    define HASTCPUDPSTATE 1
+
+/*
+ * HASTMPNODE is defined for those dialects that have tmpnodes.
+ */
+
+/* #define     HASTMPNODE      1 */
+
+/*
+ * HASVNODE is defined for those dialects that use the Sun virtual file
+ * system node, the vnode.  BSD derivatives usually do; System V derivatives
+ * prior to R4 usually don't.
+ */
+
+#    define HASVNODE 1
+
+/*
+ * HASXOPT is defined for those dialects that have an X option.  It
+ * defines the text for the usage display.  HASXOPT_VALUE defines the
+ * option's default binary value -- 0 or 1.
+ *
+ * AIX uses the X option to disable the use of the readx() kernel function
+ * on request.
+ *
+ * If you want to disable the use of readx() permanently, leave HASXOPT
+ * undefined and set HASXOPT_VALUE to 0.  To enable readx() permanently,
+ * leave HASXOPT undefined and set HASXOPT_VALUE to 1.
+ *
+ * Define HASXOPT_ROOT if you want to restrict the use of the X option to
+ * processes whose real UID is root.
+ */
+
+#    define HASXOPT "use readx() *RISKY*"
+/* #define     HASXOPT_ROOT    1 */
+#    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.
+ */
+
+#    if AIXV >= 4200
+#        define INODETYPE unsigned long long
+/* inode number internal storage type */
+#        define INODEPSPEC                                                     \
+            "ll" /* INODETYPE printf specification                             \
+                  * modifier */
+#    endif       /* AIXV>=4200 */
+
+/*
+ * UID_ARG defines the size of a User ID number when it is passed
+ * as a function argument.
+ */
+
+#    define UID_ARG uid_t
+
+/*
+ * 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_RNAM                    1          rnam.c */
+/* #define     USE_LIB_RNCH                    1          rnch.c */
+/* #define     USE_LIB_RNMH                    1          rnmh.c */
+/* #define     USE_LIB_SNPF                    1          snpf.c */
+#    define snpf snprintf /* use the system's snprintf() */
+
+/*
+ * WARNDEVACCESS is defined for those dialects that should issue a warning
+ * when lsof can't access /dev (or /device) or one of its sub-directories.
+ * The warning can be inhibited by the lsof caller with the -w option.
+ */
+
+#    define WARNDEVACCESS 1
+
+/*
+ * WARNINGSTATE is defined for those dialects that want to suppress all lsof
+ * warning messages.
+ */
+
+/* #define     WARNINGSTATE    1       warnings are enabled by default */
+
+/*
+ * WILLDROPGID is defined for those dialects whose lsof executable runs
+ * setgid(not_real_GID) and whose setgid power can be relinquished after
+ * the dialect's initialize() function has been executed.
+ */
+
+#    define WILLDROPGID 1
+
+/*
+ * zeromem is a macro that uses bzero or memset.
+ */
+
+#    define zeromem(a, l) bzero(a, l)
+
+#endif /* !defined(LSOF_MACHINE_H) */
diff --git a/lib/dialects/hpux/kmem/Makefile b/lib/dialects/hpux/kmem/Makefile
new file mode 100644 (file)
index 0000000..080063d
--- /dev/null
@@ -0,0 +1,160 @@
+
+# HP-UX /dev/kmem-based Makefile
+#
+# $Id: Makefile,v 1.15 2008/04/15 13:29:43 abe Exp $
+
+PROG=  lsof
+
+BIN=   ${DESTDIR}
+
+DOC=   ${DESTDIR}
+
+I=/usr/include
+S=/usr/include/sys
+L=/usr/include/local
+P=
+
+CDEF=
+CDEFS=  ${CDEF} ${CFGF}
+INCL=  ${DINC}
+CFLAGS=        ${CDEFS} ${INCL} ${DEBUG}
+
+GRP=
+
+HDR=    lsof.h lsof_fields.h dlsof.h machine.h proto.h dproto.h
+
+SRC=    dfile.c dmnt.c dnode.c dnode1.c dnode2.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 dnode1.o dnode2.o dproc.o dsock.o \
+       dstore.o \
+       arg.o main.o misc.o node.o print.o proc.o store.o usage.o util.o
+
+MAN=   lsof.8
+
+OTHER= 
+
+SHELL= /bin/sh
+
+SOURCE=        Makefile ${OTHER} ${MAN} ${HDR} ${SRC}
+
+all: ${PROG}
+
+${PROG}: ${LIB} ${P} ${OBJ}
+       ${CC} -o $@ ${CFLAGS} ${OBJ} ${CFGL}
+
+clean: FRC
+       rm -f Makefile.bak ${PROG} a.out core errs lint.out tags *.o version.h
+       rm -f machine.h.old new_machine.h
+       (cd lib; ${MAKE} -f Makefile.skel clean)
+
+install: all FRC
+       @echo ''
+       @echo 'Please write your own install rule.  Lsof should be installed'
+       @echo 'setgid to the group that can read /dev/kmem.  Normally that is'
+       @echo 'the sys group.  Your install rule actions might look something'
+       @echo 'like this:'
+       @echo ''
+       @echo '    install -i -g $${GRP} $${PROG} $${BIN}'
+       @echo '    chmod 2755 $${BIN}/$${PROG}'
+       @echo '    install -i $${MAN} $${DOC}'
+       @echo '    chmod 444 $${DOC}/$${MAN}'
+       @echo ''
+       @echo 'You will have to complete the skeletons for the BIN, DOC, and'
+       @echo 'GRP strings given at the 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_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
+
+dnode1.o:      ${HDR} dnode1.c
+
+dnode2.o:      ${HDR} dnode2.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/lib/dialects/hpux/kmem/Mksrc b/lib/dialects/hpux/kmem/Mksrc
new file mode 100755 (executable)
index 0000000..f94d164
--- /dev/null
@@ -0,0 +1,24 @@
+#!/bin/sh
+#
+# Mksrc - make /dev/kmem-based HP-UX source files
+#
+# WARNING: This script assumes it is running from the main directory
+#         of the lsof, version 4 distribution.
+#
+# One environment variable applies:
+#
+# LSOF_MKC     is the method for creating the source files.
+#              It defaults to "ln -s".  A common alternative is "cp".
+#
+# $Id: Mksrc,v 1.3 99/04/27 15:54:00 abe Exp $
+
+
+D=dialects/hpux/kmem
+L="dfile.c dlsof.h dmnt.c dnode.c dnode1.c dnode2.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/lib/dialects/hpux/kmem/dfile.c b/lib/dialects/hpux/kmem/dfile.c
new file mode 100644 (file)
index 0000000..fd9cf2b
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * dfile.c - /dev/kmem-based HP-UX file processing functions for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#ifndef lint
+static char copyright[] =
+    "@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
+#endif
+
+#if defined(HPUXKERNBITS) && HPUXKERNBITS >= 64
+#    define _TIME_T
+typedef int time_t;
+/*
+ * CAUTION!!! CAUTION!!! CAUTION!!! CAUTION!!! CAUTION!!! CAUTION!!!
+ *
+ * Do NOT:
+ *
+ *     #define INO_T
+ *     typedef int ino_t;
+ *
+ * in this source file for HP-UX >= 10.30.  Doing so will cause the kernel's
+ * ino_t type to be erroneously used instead of the application's.
+ *
+ * CAUTION!!! CAUTION!!! CAUTION!!! CAUTION!!! CAUTION!!! CAUTION!!!
+ */
+#endif /* defined(HPUXKERNBITS) && HPUXKERNBITS>=64 */
+
+#include "common.h"
+
+/*
+ * get_max_fd() - get maximum file descriptor plus one
+ */
+
+int get_max_fd() {
+    struct rlimit r;
+
+    if (getrlimit(RLIMIT_NOFILE, &r))
+        return (-1);
+    return (r.rlim_cur);
+}
+
+/*
+ * print_dev() - print device
+ */
+
+char *print_dev(struct lfile *lf, /* file whose device is to be printed */
+                dev_t *dev)       /* device to be printed */
+{
+    static char buf[128];
+
+    (void)snpf(buf, sizeof(buf), "%d,%#x", GET_MAJ_DEV(*dev),
+               GET_MIN_DEV(*dev));
+    return (buf);
+}
+
+/*
+ * process_file() - process file
+ */
+
+void process_file(fp) KA_T fp; /* kernel file structure address */
+{
+    struct file f;
+    int flag;
+
+    if (kread(ctx, (KA_T)fp, (char *)&f, sizeof(f))) {
+        (void)snpf(Namech, Namechl, "can't read file struct from %s",
+                   print_kptr(fp, (char *)NULL, 0));
+        enter_nm(Namech);
+        return;
+    }
+    Lf->off = (SZOFFTYPE)f.f_offset;
+    Lf->off_def = 1;
+
+    if (f.f_count) {
+
+#if defined(HASFSTRUCT)
+        /*
+         * Save file structure values.
+         */
+        Lf->fct = (long)f.f_count;
+        Lf->fsv |= FSV_CT;
+        Lf->fsa = fp;
+        Lf->fsv |= FSV_FA;
+        Lf->ffg = (long)f.f_flag;
+        Lf->fsv |= FSV_FG;
+        Lf->fna = (KA_T)f.f_data;
+        Lf->fsv |= FSV_NI;
+#endif /* defined(HASFSTRUCT) */
+
+        /*
+         * Construct access code.
+         */
+        if ((flag = (f.f_flag & (FREAD | FWRITE))) == FREAD)
+            Lf->access = LSOF_FILE_ACCESS_READ;
+        else if (flag == FWRITE)
+            Lf->access = LSOF_FILE_ACCESS_WRITE;
+        else if (flag == (FREAD | FWRITE))
+            Lf->access = LSOF_FILE_ACCESS_READ_WRITE;
+        /*
+         * Process structure by its type.
+         */
+        switch (f.f_type) {
+
+#if defined(DTYPE_LLA)
+        case DTYPE_LLA:
+            process_lla((KA_T)f.f_data);
+            return;
+#endif /* DTYPE_LLA */
+
+        case DTYPE_VNODE:
+            process_node((KA_T)f.f_data);
+            return;
+        case DTYPE_SOCKET:
+            process_socket((KA_T)f.f_data);
+            return;
+        default:
+            if (!f.f_type || (f.f_ops && (KA_T)f.f_ops != Vnfops)) {
+                (void)snpf(Namech, Namechl, "%s file struct, ty=%#x, op=%#x",
+                           print_kptr(fp, (char *)NULL, 0), f.f_type, f.f_ops);
+                enter_nm(Namech);
+                return;
+            }
+        }
+    }
+    enter_nm("no more information");
+}
+
+#if HPUXV >= 1030
+/*
+ * read_mi() - read stream's module information
+ *
+ * Note: this function is included in this module, because ino_t is not
+ *      redfined to the kernel's type, but is left at the application's type.
+ *      See the CAUTION statement inside the HPUXKERNBITS>=64 #if/#endif
+ *      block at the beginning of this file.
+ */
+
+int read_mi(sh, ip, pcb, pn)
+KA_T sh;   /* stream head address */
+KA_T *ip;  /* returned IP q_ptr */
+KA_T *pcb; /* returned TCP or UDP q_ptr */
+char **pn; /* returned protocol name */
+{
+    struct l_dev *dp;
+    char *ep = Namech;
+    struct sth_s hd;
+    int i;
+    size_t len, ml;
+    char mn[32];
+    KA_T ka, qa;
+    struct module_info mi;
+    struct queue q;
+    struct qinit qi;
+    size_t sz = Namechl;
+
+    if (!sh || kread(ctx, sh, (char *)&hd, sizeof(hd))) {
+        (void)snpf(Namech, Namechl, "can't read stream head: %s",
+                   print_kptr(sh, (char *)NULL, 0));
+        return (1);
+    }
+    if (!Lf->rdev_def)
+        dp = (struct l_dev *)NULL;
+    else
+        dp = lkupdev(&DevDev, &Lf->rdev, 1, 0);
+    if (dp)
+        (void)snpf(ep, sz, "%s", dp->name);
+    else
+        *ep = '\0';
+    /*
+     * Follow the stream head to each of its queue structures, retrieving the
+     * module names for each queue's q_info->qi_minfo->mi_idname chain of
+     * structures.  Separate each additional name from the previous one with
+     * "->".
+     *
+     * Ignore failures to read all but queue structure chain entries.
+     *
+     * Ignore module names that end in "head".
+     *
+     * Save the q_ptr value for "tcp" and "udp" modules.
+     */
+    ml = sizeof(mn) - 1;
+    mn[ml] = '\0';
+    *ip = *pcb = (KA_T)NULL;
+    qa = (KA_T)hd.sth_wq;
+    for (i = 0; i < 20; i++, qa = (KA_T)q.q_next) {
+        if (!qa || kread(ctx, qa, (char *)&q, sizeof(q)))
+            break;
+        if (!(ka = (KA_T)q.q_qinfo) || kread(ctx, ka, (char *)&qi, sizeof(qi)))
+            continue;
+        if (!(ka = (KA_T)qi.qi_minfo) ||
+            kread(ctx, ka, (char *)&mi, sizeof(mi)))
+            continue;
+        if (!(ka = (KA_T)mi.mi_idname) || kread(ctx, ka, mn, ml))
+            continue;
+        if ((len = strlen(mn)) < 1)
+            continue;
+        if (len >= 3 && !strcmp(&mn[len - 3], "sth"))
+            continue;
+        ep = endnm(&sz);
+        (void)snpf(ep, sz, "%s%s", (ep == Namech) ? "" : "->", mn);
+        if (!q.q_ptr)
+            continue;
+        if (!*ip && !strcmp(mn, "ip")) {
+            *ip = (KA_T)q.q_ptr;
+            continue;
+        }
+        if (!*pcb && !strcmp(mn, "tcpm")) {
+            *pcb = (KA_T)q.q_ptr;
+            *pn = "TCP";
+            continue;
+        }
+        if (!*pcb && !strcmp(mn, "udpm")) {
+            *pcb = (KA_T)q.q_ptr;
+            *pn = "UDP";
+        }
+    }
+    return (0);
+}
+#endif /* HPUXV>=1030 */
diff --git a/lib/dialects/hpux/kmem/dlsof.h b/lib/dialects/hpux/kmem/dlsof.h
new file mode 100644 (file)
index 0000000..9baed7b
--- /dev/null
@@ -0,0 +1,439 @@
+/*
+ * dlsof.h - /dev/kmem-based HP-UX header file for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+/*
+ * $Id: dlsof.h,v 1.19 2007/04/24 16:25:30 abe Exp $
+ */
+
+#if !defined(HPUX_LSOF_H)
+#    define HPUX_LSOF_H 1
+
+#    if HPUXV >= 1030
+#        include <fcntl.h>
+#    endif /* HPUXV>=1030 */
+
+#    include <stdlib.h>
+#    include <dirent.h>
+#    include <mntent.h>
+#    include <setjmp.h>
+#    include <string.h>
+#    include <nlist.h>
+#    include <unistd.h>
+
+#    if HPUXV < 1020
+#        include <sys/vnode.h>
+#    endif /* HPUXV<1020 */
+
+#    if HPUXV >= 1030
+/*
+ * Include header files for HP-UX 10.30 and up that have been
+ * manufactured with q4 and hand edited.
+ */
+
+#        include "lla.h"
+#        include "proc.h"
+#        include "rnode.h"
+#        include "nfs_clnt.h"
+#        include "vnode.h"
+#    endif /* HPUXV>=1030 */
+
+#    include <sys/domain.h>
+
+#    if HPUXV >= 1020
+#        define _INCLUDE_STRUCT_FILE
+#    endif /* HPUXV>=1020 */
+
+#    if HPUXV >= 1030
+struct uio { /* to satisfy function prototypes in <sys/file.h> */
+    int dummy;
+};
+#    endif /* HPUXV>=1030 */
+
+#    include <sys/file.h>
+
+#    if HPUXV >= 1020
+#        undef _INCLUDE_STRUCT_FILE
+#    endif /* HPUXV>=1020 */
+
+#    if HPUXV >= 1030
+#        include <sys/stream.h>
+#        include "sth.h"
+#    endif /* HPUXV>=1030 */
+
+#    include <sys/mbuf.h>
+
+#    if HPUXV >= 800
+#        undef _PROTOTYPES
+#        include <sys/pstat.h>
+#    endif /* HPUXV>=800 */
+
+#    include <sys/resource.h>
+
+#    if HPUXV < 1010
+#        include <sys/proc.h>
+#    endif /* HPUXV<1010 */
+
+#    include <sys/protosw.h>
+#    include <sys/socket.h>
+#    include <sys/socketvar.h>
+#    include <netinet/in.h>
+#    include <net/route.h>
+
+#    if HPUXV < 1030
+#        include <net/raw_cb.h>
+#        include <netinet/in_pcb.h>
+#    endif /* HPUXV<1030 */
+
+#    include <netinet/ip_var.h>
+#    include <netinet/tcp.h>
+#    include <netinet/tcpip.h>
+
+#    if HPUXV < 1030
+#        include <netinet/tcp_fsm.h>
+#        include <netinet/tcp_timer.h>
+#        include <netinet/tcp_var.h>
+#    else /* HPUXV>=1030 */
+#        include <sys/tihdr.h>
+/*
+ * Include header files for HP-UX 10.30 and up that have been
+ * manufactured with q4 and hand editing.
+ */
+
+#        include "ipc_s.h"
+#        include "tcp_s.h"
+#        include "udp_s.h"
+#    endif /* HPUXV<1030 */
+
+#    if HPUXV >= 1030
+#        undef TCP_NODELAY
+#        undef TCP_MAXSEG
+#    endif /* HPUXV>=1030 */
+
+#    include <rpc/types.h>
+#    include <rpc/rpc.h>
+#    include <rpc/pmap_prot.h>
+
+#    if HPUXV >= 1030
+#        include <rpc/clnt_soc.h>
+#    endif /* HPUXV>=1030 */
+
+#    if HPUXV >= 1000
+#        include <rpc/xdr.h>
+#        include <rpc/auth.h>
+#        include <rpc/clnt.h>
+#        include <sys/cdfsdir.h>
+#        include <sys/cdfs.h>
+#        include <sys/cdnode.h>
+#    endif /* HPUXV>=1000 */
+
+#    include <nfs/nfs.h>
+
+/*
+ * Structure for Atria's MVFS node (ancestry: lsof 3.61 or older)
+ */
+
+struct mvfsnode {
+    unsigned long d1[6];
+    unsigned long m_ino; /* node number */
+};
+
+#    if HPUXV < 1030
+#        include <nfs/nfs_clnt.h>
+#        if defined(HASRNODE3)
+/*
+ * This rnode structure definition should come from <nfs/rnode.h>, but HP-UX
+ * patched the kernel structures of NFS3 at PHNE_18173, PHNE_19426, PHNE_19937,
+ * and PHNE_20091 and didn't supply an updated <nfs/rnode.h>.
+ *
+ * This definition of rnode was derived via /usr/contrib/binq4.
+ */
+
+struct rnode {
+    struct rnode *r_next;
+    struct vnode r_vnode;
+    u_int r_fh3;
+    fhandle_t r_fh;
+    u_short r_flags;
+    short r_error;
+    daddr_t r_lastr;
+    k_off_t r_size;
+    k_off_t r_cachedsize;
+    struct ucred *r_rcred;
+    struct ucred *r_wcred;
+    struct ucred *r_unlcred;
+    int *r_unlname;
+    struct vnode *r_unldvp;
+    struct nfsfattr r_nfsattr;
+};
+#        else /* !defined(HASRNODE3) */
+#            include <nfs/rnode.h>
+#        endif /* defined(HASRNODE3) */
+#    endif     /* HPUXV<1030 */
+
+#    include <nfs/snode.h>
+
+#    if HPUXV >= 1000
+#        define _KERNEL
+#        include <nfs/fifonode.h>
+#        undef _KERNEL
+#    endif /* HPUXV>=1000 */
+
+#    if defined(DTYPE_LLA) && HPUXV < 1030
+#        define _KERNEL 1
+#        include <sio/lla.h>
+#        undef _KERNEL
+#    endif /* defined(DTYPE_LLA) && HPUXV<1030 */
+
+#    include <sys/un.h>
+#    include <sys/unpcb.h>
+#    include <sys/vfs.h>
+#    include <sys/vmmac.h>
+#    include <sys/user.h>
+
+/*
+ * The hpux_mount.h header file is manufactured from <sys/mount.h> by the
+ * Configure script to get the mount structure without needing to define
+ * _KERNEL when including <sys/mount.h>.  Defining _KERNEL causes unresolvable
+ * header file complications.
+ */
+
+#    include "hpux_mount.h"
+
+#    if HPUXV >= 800
+/*
+ * These definitions are from <sys/vfs.h>, defined under the _KERNEL symbol.
+ * Unfortunately, defining _KERNEL causes <sys/vfs.h> to include other
+ * header files not in <sys>.
+ */
+#        define MOUNT_UFS 0
+#        define MOUNT_NFS 1
+#        define MOUNT_CDFS 2
+#    endif /* HPUXV>=800 */
+
+#    if defined(HAS_CONST)
+#        define COMP_P const void
+#    else /* !defined(HAS_CONST) */
+#        define COMP_P void
+#    endif /* defined(HAS_CONST) */
+
+#    if HPUXV >= 800
+#        define CURDIR p->p_cdir
+#        define ROOTDIR p->p_rdir
+#    else /* HPUXV<800 */
+#        define CURDIR u->u_cdir
+#        define ROOTDIR u->u_rdir
+#    endif /* HPUXV>=800 */
+
+#    define DEVINCR 1024 /* device table malloc() increment */
+
+#    if HPUXV < 1030
+/*
+ * KA_T is defined in dialects/hpux/kmem/hpux11/kernbits.h for HP-UX 10.30
+ * and above.
+ */
+typedef off_t KA_T;
+#    endif /* HPUXV<1030 */
+
+#    define KMEM "/dev/kmem"
+#    define MALLOC_P void
+#    define FREE_P void
+#    define MALLOC_S unsigned
+#    define MOUNTED MNT_MNTTAB
+
+#    if HPUXV < 1000
+#        define N_UNIX "/hp-ux"
+#    else /* HPUXV>=1000 */
+#        define N_UNIX "/stand/vmunix"
+#    endif /* HPUXV<1000 */
+
+#    define QSORT_P void
+#    define READLEN_T int
+#    define STRNCPY_L size_t
+
+#    if HPUXV >= 1000
+#        define SZOFFTYPE unsigned long long
+/* type for size and offset */
+#        define SZOFFPSPEC "ll" /* SZOFFTYPE printf specification modifier */
+#    endif                      /* HPUXV>=1000 */
+
+#    define SWAP "/dev/swap"
+
+#    if HPUXV < 800
+#        define unp_addr unp_locaddr
+/*
+ * HP-UX <8 SWAP must be read in DEV_BSIZE chunks.
+ */
+#        define U_SIZE                                                         \
+            (((DEV_BSIZE + sizeof(struct user)) / DEV_BSIZE) * DEV_BSIZE)
+#    endif /* HPUXV<800 */
+
+#    if HPUXV >= 800
+#        define U_SIZE sizeof(struct user)
+#    endif /* HPUXV>=800 */
+
+#    if HPUXV >= 1030
+#        define XDR_PMAPLIST (xdrproc_t) xdr_pmaplist
+#        define XDR_VOID (xdrproc_t) xdr_void
+#    endif /* HPUXV>=1030 */
+
+#    if defined(HAS_AFS)
+/*
+ * AFS definitions
+ */
+
+#        define AFSAPATHDEF "/usr/adm/afs/kload"
+#        define AFSDEV 1 /* AFS "fake" device number */
+
+#        if defined(HASAOPT)
+extern char *AFSApath; /* alternate AFS name list path
+                        * (from -A) */
+#        endif         /* defined(HASAOPT) */
+
+extern struct vfs *AFSVfsp; /* AFS struct vfs kernel pointer */
+#    endif                  /* defined(HAS_AFS) */
+
+/*
+ * Global storage definitions (including their structure definitions)
+ */
+
+extern int CloneMaj;
+extern int HaveCloneMaj;
+extern int Kd;
+extern KA_T Kpa;
+
+#    if HPUXV >= 1010
+extern KA_T Ktp;
+#    endif /* HPUXV>=1010 */
+
+struct l_vfs {
+    KA_T addr;    /* kernel address */
+    dev_t dev;    /* device */
+    char *dir;    /* mounted directory */
+    char *fsname; /* file system name */
+
+#    if defined(HASFSINO)
+    INODETYPE fs_ino; /* file system inode number */
+#    endif            /* defined(HASFSINO) */
+
+    struct l_vfs *next; /* forward link */
+};
+extern struct l_vfs *Lvfs;
+
+#    if HPUXV < 800
+extern int Mem;
+#    endif /* HPUXV<800 */
+
+struct mounts {
+    char *dir;           /* directory (mounted on) */
+    char *fsname;        /* file system
+                          * (symbolic links unresolved) */
+    char *fsnmres;       /* file system
+                          * (symbolic links resolved) */
+    dev_t dev;           /* directory st_dev */
+    dev_t rdev;          /* directory st_rdev */
+    INODETYPE inode;     /* directory st_ino */
+    mode_t mode;         /* directory st_mode */
+    mode_t fs_mode;      /* file system st_mode */
+    struct mounts *next; /* forward link */
+};
+
+#    define X_NCACHE "ncache"
+#    define X_NCSIZE "ncsize"
+#    define NL_NAME n_name
+
+#    if HPUXV < 800 && defined(hp9000s800)
+extern int npids;
+extern struct proc *proc;
+#    endif /* HPUXV<800 && defined(hp9000s800) */
+
+struct sfile {
+    char *aname;        /* argument file name */
+    char *name;         /* file name (after readlink()) */
+    char *devnm;        /* device name (optional) */
+    dev_t dev;          /* device */
+    dev_t rdev;         /* raw device */
+    u_short mode;       /* S_IFMT mode bits from stat() */
+    int type;           /* file type: 0 = file system
+                         *           1 = regular file */
+    INODETYPE i;        /* inode number */
+    int f;              /* file found flag */
+    struct sfile *next; /* forward link */
+};
+
+#    if HPUXV < 800
+extern int Swap;
+#    endif /* HPUXV<800 */
+
+#    if HPUXV < 800 && defined(hp9000s800)
+extern struct user *ubase;
+#    endif /* HPUXV<800 && defined(hp9000s800) */
+
+#    if HPUXV < 800 && defined(hp9000s300)
+extern struct pte *Usrptmap;
+extern struct pte *usrpt;
+#    endif /* HPUXV<800 && defined(hp9000s300) */
+
+extern KA_T Vnfops;
+
+/*
+ * Definitions for dvch.c, isfn.c, and rdev.c
+ */
+
+#    define CLONEMAJ CloneMaj         /* clone major variable name */
+#    define DIRTYPE dirent            /* directory structure type */
+#    define HASDNAMLEN 1              /* DIRTYPE has d_namlen element */
+#    define HAS_STD_CLONE 1           /* uses standard clone structure */
+#    define HAVECLONEMAJ HaveCloneMaj /* clone major status variable name */
+#    define MAXSYSCMDL (PST_CLEN - 1)
+
+/*
+ * Definition for rmnt.c
+ */
+
+#    define MNTSKIP                                                            \
+        {                                                                      \
+            if (strcmp(mp->mnt_type, MNTTYPE_IGNORE) == 0)                     \
+                continue;                                                      \
+        }
+
+/*
+ * Definitions for rnch.c
+ */
+
+#    if defined(HASNCACHE)
+#        include <sys/dnlc.h>
+#        if HPUXV < 1000
+#            define ADDR_NCACHE 1
+#        endif /* HPUXV<1000 */
+#    endif     /* defined(HASNCACHE) */
+
+struct lsof_context_dialect {};
+
+#endif /* HPUX_LSOF_H */
diff --git a/lib/dialects/hpux/kmem/dmnt.c b/lib/dialects/hpux/kmem/dmnt.c
new file mode 100644 (file)
index 0000000..d24a7cc
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * dmnt.c - /dev/kmem-based HP-UX mount support functions for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#ifndef lint
+static char copyright[] =
+    "@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
+#endif
+
+#if defined(HPUXKERNBITS) && HPUXKERNBITS >= 64
+#    define _TIME_T
+typedef int time_t;
+#endif /* defined(HPUXKERNBITS) && HPUXKERNBITS>=64 */
+
+#include "common.h"
+
+/*
+ * Local static definitions
+ */
+
+/*
+ * completevfs() - complete local vfs structure
+ */
+void
+
+#if HPUXV >= 800
+    completevfs(vfs, dev,
+                v) struct l_vfs *vfs; /* local vfs structure pointer */
+dev_t *dev;                           /* device */
+struct vfs *v;                        /* kernel vfs structure */
+#else                                 /* HPUXV<800 */
+    completevfs(vfs, dev) struct l_vfs *vfs; /* local vfs structure pointer */
+dev_t *dev;                                  /* device */
+#endif                                /* HPUXV>=800 */
+
+{
+    struct mounts *mp;
+    /*
+     * If only Internet socket files are selected, don't bother completing the
+     * local vfs structure.
+     */
+    if (Selinet)
+        return;
+
+#if HPUXV >= 800
+    /*
+     * On HP-UX 8 and above, first search the local mount table for a match on
+     * the file system name from the vfs structure.
+     */
+    if (v) {
+        for (mp = readmnt(); mp; mp = mp->next) {
+            if (strcmp(mp->fsname, v->vfs_name) == 0) {
+                vfs->dev = mp->dev;
+                vfs->dir = mp->dir;
+                vfs->fsname = mp->fsname;
+
+#    if defined(HASFSINO)
+                vfs->fs_ino = mp->inode;
+#    endif /* defined(HASFSINO) */
+
+                return;
+            }
+        }
+    }
+#endif /* HPUXV>=800 */
+
+    /*
+     * Search for a match on device number.
+     */
+    for (mp = readmnt(); mp; mp = mp->next) {
+        if (mp->dev == *dev) {
+            vfs->dev = mp->dev;
+            vfs->dir = mp->dir;
+            vfs->fsname = mp->fsname;
+
+#if defined(HASFSINO)
+            vfs->fs_ino = mp->inode;
+#endif /* defined(HASFSINO) */
+
+            return;
+        }
+    }
+
+#if HPUXV >= 800
+    /*
+     * If the file system name and device number searches fail, use the
+     * vfs structure name, if there is one.  Determine the device number
+     * with statsafely().
+     */
+    if (v && v->vfs_name[0]) {
+
+        struct stat sb;
+
+        if (!(vfs->dir = mkstrcpy(v->vfs_name, (MALLOC_S *)NULL))) {
+            (void)fprintf(stderr, "%s: no space for vfs name: ", Pn);
+            safestrprt(v->vfs_name, stderr, 1);
+            Error(ctx);
+        }
+        if (statsafely(v->vfs_name, &sb) == 0)
+            vfs->dev = sb.st_dev;
+        else
+            vfs->dev = (dev_t)0;
+
+#    if defined(HASFSINO)
+        vfs->fs_ino = (INODETYPE)0;
+#    endif /* defined(HASFSINO) */
+    }
+#endif /* HPUXV>=800 */
+}
+
+/*
+ * readvfs() - read vfs structure
+ */
+
+struct l_vfs *readvfs(struct vnode *lv) /* local vnode */
+{
+    struct mount m;
+    struct mntinfo mi;
+    int ms;
+    dev_t td;
+    struct vfs v;
+    struct l_vfs *vp;
+
+    if (!lv->v_vfsp)
+        return ((struct l_vfs *)NULL);
+    for (vp = Lvfs; vp; vp = vp->next) {
+        if ((KA_T)lv->v_vfsp == vp->addr)
+            return (vp);
+    }
+    if ((vp = (struct l_vfs *)malloc(sizeof(struct l_vfs))) == NULL) {
+        (void)fprintf(stderr, "%s: PID %d, no space for vfs\n", Pn, Lp->pid);
+        Error(ctx);
+    }
+    vp->dev = 0;
+    vp->dir = (char *)NULL;
+    vp->fsname = (char *)NULL;
+
+#if defined(HASFSINO)
+    vp->fs_ino = 0;
+#endif /* defined(HASFSINO) */
+
+    if (lv->v_vfsp && kread(ctx, (KA_T)lv->v_vfsp, (char *)&v, sizeof(v))) {
+        (void)free((FREE_P *)vp);
+        return ((struct l_vfs *)NULL);
+    }
+    /*
+     * Complete the mount information.
+     */
+    if (Ntype == N_NFS) {
+
+        /*
+         * The device number for an NFS file is found by following the vfs
+         * private data pointer to an mntinfo structure.
+         */
+        if (v.vfs_data &&
+            kread(ctx, (KA_T)v.vfs_data, (char *)&mi, sizeof(mi)) == 0) {
+
+#if HPUXV < 1020
+            td = (dev_t)makedev(255, (int)mi.mi_mntno);
+#else  /* HPUXV>=1020 */
+            td = mi.mi_mntno;
+#endif /* HPUXV<1020 */
+
+#if HPUXV >= 800
+            (void)completevfs(vp, &td, (struct vfs *)NULL);
+#else  /* HPUXV<800 */
+            (void)completevfs(vp, &td);
+#endif /* HPUXV>=800 */
+        }
+    } else {
+        if (v.vfs_data) {
+            if (kread(ctx, (KA_T)v.vfs_data, (char *)&m, sizeof(m)) == 0)
+                ms = 1;
+            else
+                ms = 0;
+        }
+
+#if defined(HAS_AFS)
+        /*
+         * Fake the device number for an AFS device.
+         */
+        else if (Ntype == N_AFS) {
+            m.m_dev = AFSDEV;
+            ms = 1;
+        }
+#endif /* defined(HAS_AFS) */
+
+        else
+            ms = 0;
+        if (ms)
+
+#if HPUXV >= 800
+#    if HPUXV < 1000
+            (void)completevfs(vp, (dev_t *)&m.m_dev, &v);
+#    else  /* HPUXV>=1000 */
+            (void)completevfs(
+                vp, v.vfs_dev ? (dev_t *)&v.vfs_dev : (dev_t *)&m.m_dev, &v);
+#    endif /* HPUXV<1000 */
+#else      /* HPUXV<800 */
+            (void)completevfs(vp, (dev_t *)&m.m_dev);
+#endif     /* HPUXV>=800 */
+    }
+    /*
+     * Complete local vfs structure and link to the others.
+     */
+    vp->next = Lvfs;
+    vp->addr = (KA_T)lv->v_vfsp;
+    Lvfs = vp;
+    return (vp);
+}
diff --git a/lib/dialects/hpux/kmem/dnode.c b/lib/dialects/hpux/kmem/dnode.c
new file mode 100644 (file)
index 0000000..458d469
--- /dev/null
@@ -0,0 +1,1052 @@
+/*
+ * dnode.c - /dev/kmem-based HP-UX node functions for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#ifndef lint
+static char copyright[] =
+    "@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
+#endif
+
+#if defined(HPUXKERNBITS) && HPUXKERNBITS >= 64
+#    define _INO_T
+typedef int ino_t;
+#    define _TIME_T
+typedef int time_t;
+#endif /* defined(HPUXKERNBITS) && HPUXKERNBITS>=64 */
+
+#include "common.h"
+#include <sys/inode.h>
+
+#if HPUXV >= 900
+static void enter_nma(char *b);
+static enum lsof_lock_mode islocked(KA_T lp);
+#endif /* HPUXV>=900 */
+
+static int getnodety(struct vnode *v);
+static int readinode(KA_T ia, struct inode *i);
+static int read_nmn(KA_T na, KA_T ia, struct mvfsnode *m);
+
+#if HPUXV >= 900
+/*
+ * enter_nma() - enter NAME column addition
+ */
+
+static void enter_nma(b) char *b; /* addition buffer */
+{
+    if (Lf->nma)
+        return;
+    if (strlen(b) < 1)
+        return;
+    Lf->nma = mkstrcpy(b, (MALLOC_S *)NULL);
+}
+
+/*
+ * islocked() - is node locked?
+ */
+
+static enum lsof_lock_mode islocked(KA_T lp) /* local locklist struct pointer */
+{
+    static int ety = -1;
+    static unsigned int ei = 0;
+    static SZOFFTYPE el = 0;
+    int l;
+    struct locklist ll;
+    KA_T llf, llp;
+
+    if (!(llf = (KA_T)lp))
+        return LSOF_LOCK_NONE;
+    llp = llf;
+    /*
+     * Compute the end test value the first time through.
+     */
+
+    if (ety == -1) {
+
+#    if HPUXV < 1020
+        ety = 0;
+        ei = 0x7fffffff;
+#    else  /* HPUXV>=1020 */
+        if (sizeof(ll.ll_end) == 4) {
+            ety = 0;
+            ei = 0x80000000;
+        } else {
+            ety = 1;
+            el = 0x10000000000ll;
+        }
+#    endif /* HPUXV<1020 */
+    }
+
+    /*
+     * Search the locklist chain for this process.
+     */
+    do {
+        if (kread(ctx, llp, (char *)&ll, sizeof(ll)))
+            return LSOF_LOCK_NONE;
+
+#    if !defined(L_REMOTE)
+#        define L_REMOTE 0x1 /* from HP-UX 9.01 */
+#    endif                   /* !defined(L_REMOTE) */
+
+#    if HPUXV < 1010
+        if (ll.ll_flags & L_REMOTE || ll.ll_proc != (KA_T)Kpa)
+#    else  /* HPUXV>=1010 */
+        if (ll.ll_flags & L_REMOTE || (KA_T)ll.ll_kthreadp != Ktp)
+#    endif /* HPUXV<1010 */
+
+            continue;
+        l = 0;
+        if (ll.ll_start == 0) {
+            switch (ety) {
+            case 0:
+                if (ll.ll_end == ei)
+                    l = 1;
+                break;
+            case 1:
+                if (ll.ll_end == el)
+                    l = 1;
+                break;
+            }
+        }
+        if (ll.ll_type == F_WRLCK)
+            return l ? LSOF_LOCK_WRITE_FULL : LSOF_LOCK_WRITE_PARTIAL;
+        else if (ll.ll_type == F_RDLCK)
+            return l ? LSOF_LOCK_READ_FULL : LSOF_LOCK_READ_PARTIAL;
+        return LSOF_LOCK_NONE;
+    }
+
+#    if HPUXV < 1010
+    while ((llp = (KA_T)ll.ll_link) && llp != llf);
+#    else  /* HPUXV>=1010 */
+    while ((llp = (KA_T)ll.ll_fwd) && llp != llf);
+#    endif /* HPUXV<1010 */
+
+    return LSOF_LOCK_NONE;
+}
+#endif /* HPUXV>=900 */
+
+/*
+ * getnodety() - get node type
+ */
+
+static int getnodety(struct vnode *v) /* local vnode copy */
+{
+
+#if defined(HAS_AFS)
+    static int afs = 0; /* AFS test status: -1 = no AFS
+                         *                  0 = not tested
+                         *                  1 = AFS present */
+    struct afsnode an;
+#endif /* defined(HAS_AFS) */
+
+    static int ft = 1;
+    static KA_T avops;
+    static KA_T cvops;
+    static KA_T fvops;
+    static KA_T mvops;
+    static KA_T nvops;
+    static KA_T nvops3;
+    static KA_T nv3ops;
+    static KA_T pvops;
+    static KA_T svops;
+    static KA_T uvops;
+    static KA_T vvops;
+    /*
+     * Do first-time only operations.
+     */
+    if (ft) {
+        if (get_Nl_value("avops", Drive_Nl, &avops) < 0)
+            avops = (unsigned long)0;
+        if (get_Nl_value("cvops", Drive_Nl, &cvops) < 0)
+            cvops = (unsigned long)0;
+        if (get_Nl_value("fvops", Drive_Nl, &fvops) < 0)
+            fvops = (unsigned long)0;
+        if (get_Nl_value("mvops", Drive_Nl, &mvops) < 0)
+            mvops = (unsigned long)0;
+        if (get_Nl_value("nvops", Drive_Nl, &nvops) < 0)
+            nvops = (unsigned long)0;
+        if (get_Nl_value("nvops3", Drive_Nl, &nvops3) < 0)
+            nvops3 = (unsigned long)0;
+        if (get_Nl_value("nv3ops", Drive_Nl, &nv3ops) < 0)
+            nv3ops = (unsigned long)0;
+        if (get_Nl_value("pvops", Drive_Nl, &pvops) < 0)
+            pvops = (unsigned long)0;
+        if (get_Nl_value("svops", Drive_Nl, &svops) < 0)
+            svops = (unsigned long)0;
+        if (get_Nl_value("uvops", Drive_Nl, &uvops) < 0)
+            uvops = (unsigned long)0;
+        if (get_Nl_value("vvops", Drive_Nl, &vvops) < 0)
+            vvops = (unsigned long)0;
+        ft = 0;
+    }
+    /*
+     * Determine the vnode type.
+     */
+    if (uvops && uvops == (unsigned long)v->v_op)
+        return (N_REGLR);
+    else if (nvops && nvops == (unsigned long)v->v_op)
+        return (N_NFS);
+    else if (nvops3 && nvops3 == (unsigned long)v->v_op)
+        return (N_NFS);
+    else if (nv3ops && nv3ops == (unsigned long)v->v_op)
+        return (N_NFS);
+    else if (mvops && mvops == (unsigned long)v->v_op)
+        return (N_MVFS);
+
+#if defined(HASVXFS)
+    else if (vvops && vvops == (unsigned long)v->v_op)
+        return (N_VXFS);
+#endif /* defined(HASVXFS) */
+
+#if HPUXV >= 1000
+    else if (cvops && cvops == (unsigned long)v->v_op)
+        return (N_CDFS);
+    else if (fvops && fvops == (unsigned long)v->v_op)
+        return (N_FIFO);
+    else if (pvops && pvops == (unsigned long)v->v_op)
+        return (N_PIPE);
+    else if (svops && svops == (unsigned long)v->v_op)
+        return (N_SPEC);
+#else  /* HPUXV<1000 */
+    else if (v->v_type == VFIFO)
+        return (N_FIFO);
+#endif /* HPUXV<1000 */
+
+#if defined(HAS_AFS)
+    /*
+     * Caution: this AFS test should be the last one.
+     */
+
+    else if (avops) {
+        if (avops == (unsigned long)v->v_op)
+            return (N_AFS);
+        else {
+
+        unknown_v_op:
+            (void)snpf(Namech, Namechl, "unknown file system type; v_op: %s",
+                       print_kptr((KA_T)v->v_op, (char *)NULL, 0));
+            enter_nm(Namech);
+            return (-1);
+        }
+    } else if (v->v_data || !v->v_vfsp)
+        goto unknown_v_op;
+    else {
+        switch (afs) {
+        case -1:
+            goto unknown_v_op;
+        case 0:
+            if (!hasAFS(v)) {
+                afs = -1;
+                goto unknown_v_op;
+            }
+            afs = 1;
+            return (N_AFS);
+            break;
+        case 1:
+            if (v->v_vfsp == AFSVfsp)
+                return (N_AFS);
+            else
+                goto unknown_v_op;
+        }
+    }
+#else  /* !defined(HAS_AFS) */
+    else {
+        (void)snpf(Namech, Namechl, "unknown file system type; v_op: %s",
+                   print_kptr((KA_T)v->v_op, (char *)NULL, 0));
+        enter_nm(Namech);
+        return (-1);
+    }
+#endif /* defined(HAS_AFS) */
+}
+
+/*
+ * process_node() - process vnode
+ */
+
+void process_node(va) KA_T va; /* vnode kernel space address */
+
+{
+
+#if defined(HAS_AFS)
+    struct afsnode an;
+#endif /* defined(HAS_AFS) */
+
+    dev_t dev, rdev;
+    int devs = 0;
+    struct inode i;
+    int ins = 0;
+    struct mvfsnode m;
+    struct rnode r;
+    int rdevs = 0;
+    int rns = 0;
+    char tbuf[32];
+    enum vtype type;
+    static struct vnode *v = (struct vnode *)NULL;
+    struct l_vfs *vfs;
+    int vty;
+
+#if HPUXV >= 900
+    char fb[128];
+    int fns = 0;
+    int rp, sz, wp;
+    struct vnode rv;
+    struct snode s;
+#endif /* HPUXV>=900 */
+
+#if HPUXV >= 1000
+    struct cdnode c;
+    struct fifonode f;
+    struct vattr vat;
+    int vats = 0;
+#endif /* HPUXV>=1000 */
+
+    /*
+     * Read the vnode.
+     */
+    if (!va) {
+        enter_nm("no vnode address");
+        return;
+    }
+    if (!v) {
+
+        /*
+         * Allocate space for the vnode or AFS vcache structure.
+         */
+
+#if defined(HAS_AFS)
+        v = alloc_vcache();
+#else  /* !defined(HAS_AFS) */
+        v = (struct vnode *)malloc(sizeof(struct vnode));
+#endif /* defined(HAS_AFS) */
+
+        if (!v) {
+            (void)fprintf(stderr, "%s: can't allocate %s space\n", Pn,
+
+#if defined(HAS_AFS)
+                          "vcache"
+#else  /* !defined(HAS_AFS) */
+                          "vnode"
+#endif /* defined(HAS_AFS) */
+
+            );
+            Error(ctx);
+        }
+    }
+    if (readvnode(va, v)) {
+        enter_nm(Namech);
+        return;
+    }
+
+#if defined(HASNCACHE)
+    Lf->na = va;
+#endif /* defined(HASNCACHE) */
+
+#if defined(HASFSTRUCT)
+    Lf->fna = va;
+    Lf->fsv |= FSV_NI;
+#endif /* defined(HASFSTRUCT) */
+
+    /*
+     * Get the primary vnode type.
+     */
+    vty = getnodety(v);
+    if (vty == -1)
+        return;
+    Ntype = vty;
+    /*
+     * Determine lock type.
+     */
+
+#if HPUXV < 900
+    if (v->v_shlockc || v->v_exlockc) {
+        if (v->v_shlockc && v->v_exlockc)
+            Lf->lock = LSOF_LOCK_READ_WRITE;
+        else if (v->v_shlockc)
+            Lf->lock = LSOF_LOCK_READ_FULL;
+        else
+            Lf->lock = LSOF_LOCK_WRITE_FULL;
+    }
+#else /* HPUXV>900 */
+#    if HPUXV >= 1000
+    Lf->lock = islocked((KA_T)v->v_locklist);
+#    endif /* HPUXV>=1000 */
+#endif     /* HPUXV<900 */
+
+    /*
+     * Establish the local virtual file system structure.
+     */
+    if (!v->v_vfsp)
+        vfs = (struct l_vfs *)NULL;
+    else if (!(vfs = readvfs(v))) {
+        (void)snpf(Namech, Namechl, "can't read vfs for %s at %s",
+                   print_kptr(va, tbuf, sizeof(tbuf)),
+                   print_kptr((KA_T)v->v_vfsp, (char *)NULL, 0));
+        enter_nm(Namech);
+        return;
+    }
+    /*
+     * Read the cdnode, fifonode, inode, rnode, snode, or vache struct.
+     */
+    switch (Ntype) {
+
+#if defined(HAS_AFS)
+    case N_AFS:
+        if (readafsnode(va, v, &an))
+            return;
+        break;
+#endif /* defined(HAS_AFS) */
+
+#if defined(HASVXFS)
+    case N_VXFS:
+        if (!v->v_data || read_vxnode(v, vfs, &dev, &devs, &rdev, &rdevs)) {
+            (void)snpf(Namech, Namechl, "vnode at %s: can't read vx_inode (%s)",
+                       print_kptr(va, tbuf, sizeof(tbuf)),
+                       print_kptr((KA_T)v->v_data, (char *)NULL, 0));
+            enter_nm(Namech);
+            return;
+        }
+        break;
+#endif /* defined(HASVXFS) */
+
+#if HPUXV >= 1000
+    case N_CDFS:
+        if (!v->v_data || kread(ctx, (KA_T)v->v_data, (char *)&c, sizeof(c))) {
+            (void)snpf(Namech, Namechl, "vnode at %s: can't read cdnode (%s)",
+                       print_kptr(va, tbuf, sizeof(tbuf)),
+                       print_kptr((KA_T)v->v_data, (char *)NULL, 0));
+            enter_nm(Namech);
+            return;
+        }
+        break;
+    case N_FIFO:
+    case N_PIPE:
+        if (!v->v_data || kread(ctx, (KA_T)v->v_data, (char *)&f, sizeof(f))) {
+            (void)snpf(Namech, Namechl, "vnode at %s: can't read fifonode (%s)",
+                       print_kptr(va, tbuf, sizeof(tbuf)),
+                       print_kptr((KA_T)v->v_data, (char *)NULL, 0));
+            enter_nm(Namech);
+            return;
+        }
+        fns = 1;
+        if (f.fn_vap &&
+            kread(ctx, (KA_T)f.fn_vap, (char *)&vat, sizeof(vat)) == 0)
+            vats = 1;
+        break;
+#endif /* HPUXV>=1000 */
+
+    case N_MVFS:
+        if (read_nmn(va, (KA_T)v->v_data, &m))
+            return;
+        break;
+    case N_NFS:
+        if (!v->v_data || readrnode((KA_T)v->v_data, &r)) {
+            (void)snpf(Namech, Namechl, "vnode at %s: can't read rnode (%s)",
+                       print_kptr(va, tbuf, sizeof(tbuf)),
+                       print_kptr((KA_T)v->v_data, (char *)NULL, 0));
+            enter_nm(Namech);
+            return;
+        }
+        rns = 1;
+        break;
+
+#if HPUXV >= 1000
+    case N_SPEC:
+        if ((v->v_type == VBLK) || (v->v_type == VCHR)) {
+            if (!v->v_data || readsnode((KA_T)v->v_data, &s)) {
+                (void)snpf(Namech, Namechl, "vnode at %s: can't read snode(%s)",
+                           print_kptr(va, tbuf, sizeof(tbuf)),
+                           print_kptr((KA_T)v->v_data, (char *)NULL, 0));
+                enter_nm(Namech);
+                return;
+            }
+            if (!s.s_realvp || readvnode((KA_T)s.s_realvp, &rv)) {
+                (void)snpf(Namech, Namechl,
+                           "snode at %s: can't read real vnode (%s)",
+                           print_kptr((KA_T)v->v_data, tbuf, sizeof(tbuf)),
+                           print_kptr((KA_T)s.s_realvp, (char *)NULL, 0));
+                enter_nm(Namech);
+                return;
+            }
+
+#    if defined(HASVXFS)
+            if (getnodety(&rv) == N_VXFS) {
+                if (!rv.v_data ||
+                    read_vxnode(&rv, vfs, &dev, &devs, &rdev, &rdevs)) {
+                    (void)snpf(Namech, Namechl,
+                               "vnode at %s: can't read vx_inode (%s)",
+                               print_kptr(va, tbuf, sizeof(tbuf)),
+                               print_kptr((KA_T)rv.v_data, (char *)NULL, 0));
+                    enter_nm(Namech);
+                    return;
+                }
+                Ntype = N_VXFS;
+                break;
+            }
+#    endif /* defined(HASVXFS) */
+
+            if (!rv.v_data || readinode((KA_T)rv.v_data, &i)) {
+                (void)snpf(Namech, Namechl,
+                           "snode at %s: can't read inode (%s)",
+                           print_kptr((KA_T)v->v_data, tbuf, sizeof(tbuf)),
+                           print_kptr((KA_T)rv.v_data, (char *)NULL, 0));
+                enter_nm(Namech);
+                return;
+            }
+            ins = 1;
+            break;
+        }
+        if (!v->v_data || readinode((KA_T)v->v_data, &i)) {
+            (void)snpf(Namech, Namechl, "vnode at %s: can't read inode (%s)",
+                       print_kptr(va, tbuf, sizeof(tbuf)),
+                       print_kptr((KA_T)v->v_data, (char *)NULL, 0));
+            enter_nm(Namech);
+            return;
+        }
+        ins = 1;
+        break;
+#endif /* HPUXV>=1000 */
+
+#if HPUXV >= 900 && HPUXV < 1000
+    case N_FIFO:
+        if (v->v_fstype == VNFS_FIFO) {
+            if (!v->v_data || readsnode((KA_T)v->v_data, &s)) {
+                (void)snpf(Namech, Namechl,
+                           "vnode at %s: can't read snode (%s)",
+                           print_kptr(va, tbuf, sizeof(tbuf)),
+                           print_kptr((KA_T)v->v_data, (char *)NULL, 0));
+                enter_nm(Namech);
+                return;
+            }
+            if (!s.s_realvp || readvnode((KA_T)s.s_realvp, &rv)) {
+                (void)snpf(Namech, Namechl,
+                           "snode at %s: can't read real vnode (%s)",
+                           print_kptr((KA_T)v->v_data, tbuf, sizeof(tbuf)),
+                           print_kptr((KA_T)s.s_realvp, (char *)NULL, 0));
+                enter_nm(Namech);
+                return;
+            }
+            if (!rv.v_data || readrnode((KA_T)rv.v_data, &r)) {
+                (void)snpf(Namech, Namechl,
+                           "snode at %s: can't read real rnode (%s)",
+                           print_kptr((KA_T)v->v_data, tbuf, sizeof(tbuf)),
+                           print_kptr((KA_T)s.s_realvp, (char *)NULL, 0));
+                enter_nm(Namech);
+                return;
+            }
+            rns = 1;
+            break;
+        }
+        /* fall through */
+#endif /* HPUXV>=900 && HPUXV<1000 */
+
+    case N_REGLR:
+    default:
+        if (!v->v_data || readinode((KA_T)v->v_data, &i)) {
+            (void)snpf(Namech, Namechl, "vnode at %s: can't read inode (%s)",
+                       print_kptr(va, tbuf, sizeof(tbuf)),
+                       print_kptr((KA_T)v->v_data, (char *)NULL, 0));
+            enter_nm(Namech);
+            return;
+        }
+        ins = 1;
+
+#if HPUXV >= 900 && HPUXV < 1000
+        if (v->v_type == VFIFO)
+            Ntype = N_FIFO;
+#endif /* HPUXV>=900 && HPUXV<1000 */
+    }
+
+#if HPUXV >= 900 && HPUXV < 1000
+    Lf->lock = islocked((KA_T)i.i_locklist);
+#endif /* HPUXV>=900 && HPUXV<1000 */
+
+    /*
+     * Get device and type for printing.
+     */
+    switch (Ntype) {
+
+#if defined(HAS_AFS)
+    case N_AFS:
+        dev = an.dev;
+        devs = 1;
+        break;
+#endif /* defined(HAS_AFS) */
+
+    case N_MVFS:
+        if (vfs) {
+            dev = vfs->dev;
+            devs = 1;
+        }
+        break;
+    case N_NFS:
+        dev = vfs ? vfs->dev : 0;
+        devs = 1;
+        break;
+
+#if HPUXV >= 1000
+    case N_CDFS:
+        dev = c.cd_dev;
+        devs = 1;
+        break;
+    case N_FIFO:
+    case N_PIPE:
+        if (vfs && vfs->fsname) {
+            dev = vfs->dev;
+            devs = 1;
+        } else if (vats && (dev_t)vat.va_fsid != NODEV) {
+            dev = (dev_t)vat.va_fsid;
+            devs = 1;
+        } else
+            enter_dev_ch(print_kptr(va, (char *)NULL, 0));
+        break;
+#endif /* _HPUX>=1000 */
+
+#if defined(HASVXFS)
+    case N_VXFS:
+        /* obtained via read_vxnode */
+        break;
+#endif /* defined(HASVXFS) */
+
+    case N_SPEC:
+    default:
+
+#if HPUXV >= 800
+        if (vfs && vfs->fsname) {
+            dev = vfs->dev;
+            devs = 1;
+        } else if (ins) {
+            dev = i.i_dev;
+            devs = 1;
+        }
+        if ((v->v_type == VBLK) || (v->v_type == VCHR)) {
+            rdev = v->v_rdev;
+            rdevs = 1;
+        }
+#else  /* HPUXV<800 */
+        if (ins) {
+            dev = i.i_dev;
+            devs = 1;
+        }
+        if ((v->v_type == VCHR) || (v->v_type == VBLK)) {
+            rdev = v->v_rdev;
+            rdevs = 1;
+        }
+#endif /* HPUXV>=800 */
+    }
+    type = v->v_type;
+    /*
+     * Obtain the inode number.
+     */
+    switch (Ntype) {
+
+#if defined(HAS_AFS)
+    case N_AFS:
+        if (an.ino_st) {
+            Lf->inode = (INODETYPE)an.inode;
+            Lf->inp_ty = 1;
+        }
+        break;
+#endif /* defined(HAS_AFS) */
+
+    case N_MVFS:
+        Lf->inode = (INODETYPE)m.m_ino;
+        Lf->inp_ty = 1;
+        break;
+    case N_NFS:
+
+#if HPUXV < 1030
+        Lf->inode = (INODETYPE)r.r_nfsattr.na_nodeid;
+#else  /* HPUXV>=1030 */
+        Lf->inode = (INODETYPE)r.r_attr.va_nodeid;
+#endif /* HPUXV<1030 */
+
+        Lf->inp_ty = 1;
+        break;
+
+#if HPUXV >= 1000
+    case N_CDFS:
+        Lf->inode = (INODETYPE)c.cd_num;
+        Lf->inp_ty = 1;
+        break;
+    case N_FIFO:
+    case N_PIPE:
+        if (vats) {
+            Lf->inode = (INODETYPE)vat.va_nodeid;
+            Lf->inp_ty = 1;
+        } else {
+            Lf->inode = (INODETYPE)v->v_nodeid;
+            Lf->inp_ty = 1;
+        }
+        break;
+#endif /* HPUXV>=1000 */
+
+#if defined(HASVXFS)
+    case N_VXFS:
+        /* set in read_vxnode() */
+        break;
+#endif /* defined(HASVXFS) */
+
+#if HPUXV < 1000
+    case N_FIFO:
+
+#    if HPUXV >= 900
+        if (rns) {
+            Lf->inode = (INODETYPE)r.r_nfsattr.na_nodeid;
+            Lf->inp_ty = 1;
+            break;
+        }
+#    endif /* HPUXV>=900 */
+           /* fall through */
+
+#endif /* HPUXV<1000 */
+
+    case N_BLK:
+    case N_REGLR:
+    case N_SPEC:
+        if (ins) {
+            Lf->inode = (INODETYPE)i.i_number;
+            Lf->inp_ty = 1;
+        }
+    }
+
+#if HPUXV >= 1030
+    /*
+     * Check for an HP-UX 10.30 and above stream.
+     */
+    if (v->v_stream) {
+        KA_T ip, pcb;
+        char *pn = (char *)NULL;
+
+        Lf->dev = dev;
+        Lf->dev_def = devs;
+        Lf->rdev = rdev;
+        Lf->rdev_def = rdevs;
+        if (read_mi((KA_T)v->v_stream, &ip, &pcb, &pn))
+            return;
+        if (ip && pcb) {
+            process_stream_sock(ip, pcb, pn, type);
+            return;
+        }
+        Lf->is_stream = 1;
+    }
+#endif /* HPUXV>=1030 */
+
+    /*
+     * Obtain the file size.
+     */
+    switch (Ntype) {
+#if defined(HAS_AFS)
+    case N_AFS:
+        Lf->sz = (SZOFFTYPE)an.size;
+        Lf->sz_def = 1;
+        break;
+#endif /* defined(HAS_AFS) */
+
+#if HPUXV >= 1000
+    case N_CDFS:
+        Lf->sz = (SZOFFTYPE)c.cd_cdc.cdc_size;
+        Lf->sz_def = 1;
+        break;
+    case N_PIPE:
+        if (vats) {
+            Lf->sz = (SZOFFTYPE)vat.va_size;
+            Lf->sz_def = 1;
+        }
+        break;
+#endif /* HPUXV>=1000 */
+
+#if HPUXV >= 900
+    case N_FIFO:
+
+#    if HPUXV < 1000
+        if (ins) {
+            rp = i.i_frptr;
+            sz = (int)i.i_fifosize;
+            wp = i.i_fwptr;
+        } else if (rns)
+            Lf->sz = (SZOFFTYPE)r.r_nfsattr.na_size;
+#    else  /* HPUXV>=1000 */
+        if (fns) {
+            rp = f.fn_rptr;
+            sz = f.fn_size;
+            wp = f.fn_wptr;
+        }
+#    endif /* HPUXV<1000 */
+
+        if (Lf->access != LSOF_FILE_ACCESS_READ &&
+            Lf->access != LSOF_FILE_ACCESS_WRITE) {
+            if (fns || ins) {
+                (void)snpf(fb, sizeof(fb), "rd=%#x; wr=%#x", rp, wp);
+                (void)enter_nma(fb);
+            }
+            if (fns || ins || rns) {
+                Lf->sz = (SZOFFTYPE)sz;
+                Lf->sz_def = 1;
+            }
+            break;
+        }
+        if (fns || ins) {
+            Lf->off =
+                (unsigned long)((Lf->access == LSOF_FILE_ACCESS_READ) ? rp
+                                                                      : wp);
+            Lf->off_def = 1;
+            (void)snpf(fb, sizeof(fb), "%s=%#x",
+                       (Lf->access == LSOF_FILE_ACCESS_READ) ? "rd" : "wr",
+                       (Lf->access == LSOF_FILE_ACCESS_READ) ? rp : wp);
+            (void)enter_nma(fb);
+        }
+        break;
+#endif /* HPUXV>=900 */
+
+    case N_MVFS:
+        /* The location of the file size isn't known. */
+        break;
+    case N_NFS:
+
+#if HPUXV < 1030
+        Lf->sz = (SZOFFTYPE)r.r_nfsattr.na_size;
+#else  /* HPUXV>=1030 */
+        Lf->sz = (SZOFFTYPE)r.r_attr.va_size;
+#endif /* HPUXV<1030 */
+
+        Lf->sz_def = 1;
+        break;
+
+#if defined(HASVXFS)
+    case N_VXFS:
+        /* set in read_vxnode() */
+        break;
+#endif /* defined(HASVXFS) */
+
+    case N_SPEC:
+    case N_REGLR:
+        if (!(type == VCHR || type == VBLK) && ins) {
+            Lf->sz = (SZOFFTYPE)i.i_size;
+            Lf->sz_def = 1;
+        }
+        break;
+    }
+    /*
+     * Record link count.
+     */
+    switch (Ntype) {
+
+#if defined(HAS_AFS)
+    case N_AFS:
+        Lf->nlink = an.nlink;
+        Lf->nlink_def = an.nlink_st;
+        break;
+#endif /* defined(HAS_AFS) */
+
+    case N_MVFS:
+        /* The location of the link count isn't known. */
+        break;
+    case N_NFS:
+
+#if HPUXV < 1030
+        Lf->nlink = r.r_nfsattr.na_nlink;
+#else  /* HPUXV>=1030 */
+        Lf->nlink = r.r_attr.va_nlink;
+#endif /* HPUXV<1030 */
+
+        Lf->nlink_def = 1;
+        break;
+
+#if HPUXV >= 1000
+    case N_CDFS: /* no link count? */
+        break;
+#endif /* HPUXV>=1000 */
+
+    case N_FIFO:
+    case N_PIPE:
+
+#if HPUXV >= 1000
+        if (vats) {
+            Lf->nlink = (long)vat.va_nlink;
+            Lf->nlink_def = 1;
+        }
+#endif /* HPUXV>=1000 */
+
+        break;
+
+#if defined(HASVXFS)
+    case N_VXFS:
+        /* set in read_vxnode() */
+        break;
+#endif /* defined(HASVXFS) */
+
+    case N_SPEC:
+    default:
+        if (ins) {
+            Lf->nlink = (long)i.i_nlink;
+            Lf->nlink_def = 1;
+        }
+        break;
+    }
+    if (Nlink && Lf->nlink_def && (Lf->nlink < Nlink))
+        Lf->sf |= SELNLINK;
+    /*
+     * Record an NFS file selection.
+     */
+    if (Ntype == N_NFS && Fnfs)
+        Lf->sf |= SELNFS;
+    /*
+     * Save the file system names.
+     */
+    if (vfs) {
+        Lf->fsdir = vfs->dir;
+        Lf->fsdev = vfs->fsname;
+
+#if defined(HASFSINO)
+        Lf->fs_ino = vfs->fs_ino;
+#endif /* defined(HASFSINO) */
+    }
+    /*
+     * Save the device numbers and their states.
+     *
+     * Format the vnode type, and possibly the device name.
+     */
+    Lf->dev = dev;
+    Lf->dev_def = devs;
+    Lf->rdev = rdev;
+    Lf->rdev_def = rdevs;
+    switch (type) {
+    case VNON:
+        Lf->type = LSOF_FILE_VNODE_VNON;
+        break;
+    case VREG:
+    case VDIR:
+        Lf->type = (type == VREG) ? LSOF_FILE_VNODE_VREG : LSOF_FILE_VNODE_VDIR;
+        break;
+    case VBLK:
+        Lf->type = LSOF_FILE_VNODE_VBLK;
+        Ntype = N_BLK;
+        break;
+    case VCHR:
+        Lf->type = LSOF_FILE_VNODE_VCHR;
+        Ntype = N_CHR;
+        break;
+    case VLNK:
+        Lf->type = LSOF_FILE_VNODE_VLNK;
+        break;
+
+#if defined(VSOCK)
+    case VSOCK:
+        Lf->type = LSOF_FILE_VNODE_VSOCK;
+        break;
+#endif /* defined(VSOCK) */
+
+    case VBAD:
+        Lf->type = LSOF_FILE_VNODE_VBAD;
+        break;
+    case VFIFO:
+        switch (Ntype) {
+
+#if HPUXV >= 1000
+        case N_FIFO:
+            Lf->type = LSOF_FILE_VNODE_VFIFO;
+            break;
+        case N_PIPE:
+            Lf->type = LSOF_FILE_PIPE;
+            break;
+#endif /* HPUXV>=1000 */
+
+        default:
+            Lf->type = LSOF_FILE_FIFO;
+        }
+        break;
+    default:
+        Lf->type = LSOF_FILE_UNKNOWN_RAW;
+        Lf->unknown_file_type_number = type;
+    }
+    Lf->ntype = Ntype;
+
+#if defined(HASBLKDEV)
+    /*
+     * If this is a VBLK file and it's missing an inode number, try to
+     * supply one.
+     */
+    if ((Lf->inp_ty == 0) && (type == VBLK))
+        find_bl_ino();
+#endif /* defined(HASBLKDEV) */
+
+    /*
+     * If this is a VCHR file and it's missing an inode number, try to
+     * supply one.
+     */
+    if ((Lf->inp_ty == 0) && (type == VCHR))
+        find_ch_ino();
+    /*
+     * Test for specified file.
+     */
+    if (Sfile &&
+        is_file_named((char *)NULL, ((type == VCHR) || (type == VBLK) ? 1 : 0)))
+        Lf->sf |= SELNM;
+    /*
+     * Enter name characters.
+     */
+    if (Namech[0])
+        enter_nm(Namech);
+}
+
+/*
+ * readinode() - read inode
+ */
+
+static int readinode(ia, i)
+KA_T ia;         /* inode kernel address */
+struct inode *i; /* inode buffer */
+{
+    if (kread(ctx, (KA_T)ia, (char *)i, sizeof(struct inode))) {
+        (void)snpf(Namech, Namechl, "can't read inode at %s",
+                   print_kptr(ia, (char *)NULL, 0));
+        return (1);
+    }
+    return (0);
+}
+
+/*
+ * read_nmn() - read node's mvfsnode
+ */
+
+static int read_nmn(na, ma, m)
+KA_T na;            /* containing node's address */
+KA_T ma;            /* kernel mvfsnode address */
+struct mvfsnode *m; /* mvfsnode receiver */
+{
+    char tbuf[32];
+
+    if (!ma || kread(ctx, (KA_T)ma, (char *)m, sizeof(struct mvfsnode))) {
+        (void)snpf(Namech, Namechl, "node at %s: can't read mvfsnode: %s",
+                   print_kptr(na, tbuf, sizeof(tbuf)),
+                   print_kptr(ma, (char *)NULL, 0));
+        enter_nm(Namech);
+        return (1);
+    }
+    return (0);
+}
diff --git a/lib/dialects/hpux/kmem/dnode1.c b/lib/dialects/hpux/kmem/dnode1.c
new file mode 100644 (file)
index 0000000..e187c50
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * dnode1.c - /dev/kmem-based HP-UX node functions for lsof
+ *
+ * This module must be separate to keep separate the multiple kernel inode
+ * structure definitions.
+ */
+
+/*
+ * Copyright 1995 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#ifndef lint
+static char copyright[] =
+    "@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
+#endif
+
+#if defined(HASVXFS)
+
+#    if defined(HPUXKERNBITS) && HPUXKERNBITS >= 64
+#        define _INO_T
+typedef int ino_t;
+#        define _TIME_T
+typedef int time_t;
+#    endif /* defined(HPUXKERNBITS) && HPUXKERNBITS>=64 */
+
+#    include "lsof.h"
+
+/*
+ * HP-UX versions below 10.20:
+ *
+ *    The pool_id_t type does not seem to be defined in the header  files
+ *    distributed by HP.  However, <sys/fs/vx_hpux.h> requires  it when
+ *    _KERNEL is defined.  So we fake the pool_id_t definition.
+ *
+ *    <sys/fs/vx_hpux.h> also requires sv_sema_t.  It's defined in
+ *    <sys/sem_alpha.h> when _KERNEL is defined, but some other header file has
+ *    already included <sys/sem_alpha.h> with _KERNEL undefined.  So we fake the
+ *    sv_sema_t definition.
+ *
+ * HP-UX version 10.20 and above:
+ *
+ *    The pool_id_t type is used by other header files for other purposes.
+ *    Redefine it for VXFS.  Delete some other conflicting definitions.
+ *    Don't #define _KERNEL.  Include a different set of VXFS header files.
+ */
+
+#    if HPUXV >= 1020
+#        undef te_offset
+#        undef i_size
+#        undef di_size
+#        define pool_id_t vx_pool_id_t
+
+#        if HPUXV >= 1030
+#            define ulong vx_ulong /* avoid <sys/stream.h> conflict */
+#        endif                     /* HPUXV>=1030 */
+
+#        include <sys/fs/vx_hpux.h>
+#        include <sys/fs/vx_port.h>
+#        include <sys/fs/vx_inode.h>
+
+#        if HPUXV >= 1030
+#            undef ulong
+#        endif /* HPUXV>=1030 */
+
+#    else /* HPUXV<1020 */
+
+#        define pool_id_t caddr_t
+#        define sv_sema_t caddr_t
+#        define _KERNEL
+#        include <sys/fs/vx_hpux.h>
+#        include <sys/fs/vx_inode.h>
+#        undef _KERNEL
+#    endif /* HPUXV>=1020 */
+
+/*
+ * read_vxnode() - read Veritas file system inode information
+ */
+
+int read_vxnode(struct vnode *v,   /* local containing vnode */
+                struct l_vfs *vfs, /* local vfs structure */
+                dev_t *dev,        /* device number receiver */
+                int *devs,         /* device status receiver */
+                dev_t *rdev,       /* raw device number receiver */
+                int *rdevs)        /* raw device status receiver */
+{
+    struct vx_inode i;
+
+    if (!v->v_data || kread(ctx, (KA_T)v->v_data, (char *)&i, sizeof(i)))
+        return (1);
+    /*
+     * Return device numbers.
+     */
+    if (vfs && vfs->fsname)
+        *dev = vfs->dev;
+    else
+        *dev = i.i_dev;
+    *devs = 1;
+    if ((v->v_type == VCHR) || (v->v_type == VBLK)) {
+        *rdev = v->v_rdev;
+        *rdevs = 1;
+    }
+    /*
+     * Record inode number.
+     */
+    Lf->inode = (INODETYPE)i.i_number;
+    Lf->inp_ty = 1;
+    /*
+     * Record size.
+     */
+    if (!(v->v_type == VCHR || v->v_type == VBLK)) {
+        Lf->sz = (SZOFFTYPE)i.i_size;
+        Lf->sz_def = 1;
+    }
+    /*
+     * Record link count.
+     */
+    Lf->nlink = (long)i.i_nlink;
+    Lf->nlink_def = 1;
+    if (Nlink && (Lf->nlink < Nlink))
+        Lf->sf |= SELNLINK;
+    return (0);
+}
+#endif /* defined(HASVXFS) */
diff --git a/lib/dialects/hpux/kmem/dnode2.c b/lib/dialects/hpux/kmem/dnode2.c
new file mode 100644 (file)
index 0000000..240fabe
--- /dev/null
@@ -0,0 +1,346 @@
+/*
+ * dnode2.c - /dev/kmem-based HP-UX AFS support
+ */
+
+/*
+ * Copyright 1996 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 1996 Purdue Research Foundation.\nAll rights reserved.\n";
+#endif
+
+#if defined(HAS_AFS)
+
+#    if defined(HPUXKERNBITS) && HPUXKERNBITS >= 64
+#        define _INO_T
+typedef int ino_t;
+#        define _TIME_T
+typedef int time_t;
+#    endif /* defined(HPUXKERNBITS) && HPUXKERNBITS>=64 */
+
+#    include "lsof.h"
+#    include <afs/stds.h>
+#    include <afs/param.h>
+#    undef __dontcare__
+#    include <afs/afsint.h>
+#    include <afs/vldbint.h>
+
+/*
+ * This is an emulation of the afs_rwlock_t definition that appears in
+ * the AFS sources in afs/lock.h.
+ */
+
+struct afs_lock {
+
+#    if HAS_AFS < 304
+    unsigned long d1[1];
+#    else  /* HAS_AFS>=304 */
+    unsigned long d1[6];
+#    endif /* HAS_AFS<304 */
+};
+typedef struct afs_lock afs_lock_t;
+typedef struct afs_lock afs_rwlock_t;
+
+#    define KERNEL
+#    include <afs/afs.h>
+#    undef KERNEL
+
+/*
+ * Local function prototypes
+ */
+
+static struct volume *getvolume(struct VenusFid *f, int *vols);
+static int is_rootFid(struct vcache *vc, int *rfid);
+
+/*
+ * alloc_vcache() - allocate space for vcache structure
+ */
+
+struct vnode *alloc_vcache() {
+    return ((struct vnode *)malloc(sizeof(struct vcache)));
+}
+
+/*
+ * ckAFSsym() - check for missing X_AFS_* symbols in AFS name list file
+ */
+
+void ckAFSsym(nl) struct nlist *nl; /* copy of Nl[] when empty */
+{
+    char *path = AFSAPATHDEF;
+    int i;
+
+#    if defined(HASAOPT)
+    if (AFSApath)
+        path = AFSApath;
+#    endif /* defined(HASAOPT) */
+
+    /*
+     * See if the alternate AFS name list file can be read.
+     */
+    if (!is_readable(path, 0)) {
+        if (!Fwarn)
+            (void)fprintf(stderr,
+                          "%s: WARNING: can't access AFS name list file: %s\n",
+                          Pn, path);
+        return;
+    }
+
+    /*
+     * Read the AFS modload symbols and compare its non-zero values with
+     * the non-zero values in Nl[].  Quit if there is any mis-match.
+     */
+    if (nlist(path, nl) < 0)
+        return;
+    for (i = 0; Nl[i].n_name && Nl[i].n_name[0]; i++) {
+        if (!nl[i].n_value || !Nl[i].n_value)
+            continue;
+        if (nl[i].n_value != Nl[i].n_value)
+            return;
+    }
+    /*
+     * If any X_AFS_* symbol that doesn't have a value in Nl[] has one from
+     * the AFS modload file, copy its modload value to Nl[].
+     */
+    if (((i = get_Nl_value("arFid", Drive_Nl, NULL)) >= 0) && !Nl[i].n_value &&
+        nl[i].n_value)
+        Nl[i].n_value = nl[i].n_value;
+    if (((i = get_Nl_value("avops", Drive_Nl, NULL)) >= 0) && !Nl[i].n_value &&
+        nl[i].n_value)
+        Nl[i].n_value = nl[i].n_value;
+    if (((i = get_Nl_value("avol", Drive_Nl, NULL)) >= 0) && !Nl[i].n_value &&
+        nl[i].n_value)
+        Nl[i].n_value = nl[i].n_value;
+}
+
+/*
+ * getvolume() - get volume structure
+ */
+
+static struct volume *getvolume(struct VenusFid *f, /* file ID pointer */
+                                int *vols) /* afs_volumes status return */
+{
+    int i;
+    static KA_T ka = 0;
+    KA_T kh;
+    static struct volume v;
+    struct volume *vp;
+    static int w = 0;
+
+    if (!ka) {
+        if (get_Nl_value("avol", Drive_Nl, (unsigned long *)&ka) < 0 || !ka) {
+            if (!w && !Fwarn) {
+                (void)fprintf(
+                    stderr, "%s: WARNING: no afs_volumes kernel address\n", Pn);
+                (void)fprintf(
+                    stderr,
+                    "      This may hamper AFS node number reporting.\n");
+                w = 1;
+            }
+            *vols = 0;
+            return ((struct volume *)NULL);
+        }
+    }
+    *vols = 1;
+    i = (NVOLS - 1) & f->Fid.Volume;
+    kh = (KA_T)((char *)ka + (i * sizeof(struct volume *)));
+    if (kread(ctx, kh, (char *)&vp, sizeof(vp)))
+        return ((struct volume *)NULL);
+    while (vp) {
+        if (kread(ctx, (KA_T)vp, (char *)&v, sizeof(v)))
+            return ((struct volume *)NULL);
+        if (v.volume == f->Fid.Volume && v.cell == f->Cell)
+            return (&v);
+        vp = v.next;
+    }
+    return ((struct volume *)NULL);
+}
+
+/*
+ * hasAFS() - test for AFS presence via vfs structure
+ */
+
+int hasAFS(struct vnode *vp) /* vnode pointer */
+{
+    struct vfs v;
+    /*
+     * If this vnode has a v_data pointer, then it probably isn't an AFS vnode;
+     * return FALSE.
+     *
+     * If the vfs struct address of /afs is known and this vnode's v_vfsp
+     * matches it, return TRUE.
+     *
+     * Read this vnode's vfs structure and its mount structure.  See if the file
+     * system name is AFS.  If it isn't, return FALSE.  If it is, save the
+     * vnode's v_vfsp as AFSVfsp and return TRUE.
+     */
+    if (AFSVfsp && !vp->v_data && vp->v_vfsp == AFSVfsp)
+        return (1);
+    if (vp->v_data || !vp->v_vfsp ||
+        kread(ctx, (KA_T)vp->v_vfsp, (char *)&v, sizeof(v)) || v.vfs_data ||
+        strcmp(v.vfs_name, "AFS") != 0)
+        return (0);
+    AFSVfsp = vp->v_vfsp;
+    return (1);
+}
+
+/*
+ * is_rootFid() - is the file ID the root file ID
+ *
+ * return: 0   = is not root file ID
+ *        1    = is root file ID
+ *        rfid = 0 if root file ID structure address not available
+ *               1 if root file ID structure address available
+ */
+
+static int is_rootFid(struct vcache *vc, /* vcache structure */
+                      int *rfid) /* root file ID pointer status return */
+{
+    char *err;
+    static int f = 0; /* rootFID structure status:
+                       *     -1 = unavailable
+                       *       0 = not yet accessed
+                       *       1 = available */
+    static struct VenusFid r;
+    unsigned long v;
+    static int w = 0;
+
+    switch (f) {
+    case -1:
+        if (vc->v.v_flag & VROOT) {
+            *rfid = 1;
+            return (1);
+        }
+        *rfid = 0;
+        return (0);
+    case 0:
+        if (get_Nl_value("arFid", Drive_Nl, &v) < 0 || !v) {
+            err = "no kernel address";
+
+        rfid_unavailable:
+
+            if (!w && !Fwarn) {
+                (void)fprintf(stderr, "%s: WARNING: AFS root Fid: %s\n", Pn,
+                              err);
+                (void)fprintf(
+                    stderr,
+                    "      This may hamper AFS node number reporting.\n");
+                w = 1;
+            }
+            f = -1;
+            if (vc->v.v_flag & VROOT) {
+                *rfid = 1;
+                return (1);
+            }
+            *rfid = 0;
+            return (0);
+        }
+        if (kread(ctx, (KA_T)v, (char *)&r, sizeof(r))) {
+            err = "can't read from kernel";
+            goto rfid_unavailable;
+        }
+        f = 1;
+        /* fall through */
+    case 1:
+        *rfid = 1;
+        if (vc->fid.Fid.Unique == r.Fid.Unique &&
+            vc->fid.Fid.Vnode == r.Fid.Vnode &&
+            vc->fid.Fid.Volume == r.Fid.Volume && vc->fid.Cell == r.Cell)
+            return (1);
+    }
+    *rfid = 0;
+    return (0);
+}
+
+/*
+ * readafsnode() - read AFS node
+ */
+
+int readafsnode(va, v, an)
+KA_T va;            /* kernel vnode address */
+struct vnode *v;    /* vnode buffer pointer */
+struct afsnode *an; /* afsnode recipient */
+{
+    char *cp, tbuf[32];
+    KA_T ka;
+    int len, rfid, vols;
+    struct vcache *vc;
+    struct volume *vp;
+
+    cp = ((char *)v + sizeof(struct vnode));
+    ka = (KA_T)((char *)va + sizeof(struct vnode));
+    len = sizeof(struct vcache) - sizeof(struct vnode);
+    if (kread(ctx, ka, cp, len)) {
+        (void)snpf(Namech, Namechl,
+                   "vnode at %s: can't read vcache remainder from %s",
+                   print_kptr(va, tbuf, sizeof(tbuf)),
+                   print_kptr((KA_T)ka, (char *)NULL, 0));
+        enter_nm(Namech);
+        return (1);
+    }
+    vc = (struct vcache *)v;
+    an->dev = AFSDEV;
+    an->size = (unsigned long)vc->m.Length;
+    an->nlink = (long)vc->m.LinkCount;
+    an->nlink_st = 1;
+    /*
+     * Manufacture the "inode" number.
+     */
+    if (vc->mvstat == 2) {
+        if ((vp = getvolume(&vc->fid, &vols))) {
+            an->inode = (INODETYPE)(vp->mtpoint.Fid.Vnode +
+                                    (vp->mtpoint.Fid.Volume << 16));
+            if (an->inode == (INODETYPE)0) {
+                if (is_rootFid(vc, &rfid))
+                    an->ino_st = 1;
+                else if (rfid) {
+                    an->inode = (INODETYPE)2;
+                    an->ino_st = 1;
+                } else
+                    an->ino_st = 0;
+            } else
+                an->ino_st = 1;
+        } else {
+            if (vols) {
+                an->inode = (INODETYPE)2;
+                an->ino_st = 1;
+            } else {
+                if (v->v_flag & VROOT) {
+                    an->inode = (INODETYPE)0;
+                    an->ino_st = 1;
+                } else
+                    an->ino_st = 0;
+            }
+        }
+    } else {
+        an->inode =
+            (INODETYPE)((vc->fid.Fid.Vnode + (vc->fid.Fid.Volume << 16)) &
+                        0x7fffffff);
+        an->ino_st = 1;
+    }
+    return (0);
+}
+#endif /* defined(HAS_AFS) */
diff --git a/lib/dialects/hpux/kmem/dproc.c b/lib/dialects/hpux/kmem/dproc.c
new file mode 100644 (file)
index 0000000..2920151
--- /dev/null
@@ -0,0 +1,804 @@
+/*
+ * dproc.c - /dev/kmem-based HP-UX process access functions for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#ifndef lint
+static char copyright[] =
+    "@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
+#endif
+
+#if defined(HPUXKERNBITS)
+#    if HPUXKERNBITS >= 64
+#        define _INO_T
+typedef int ino_t;
+#        define _TIME_T
+typedef int time_t;
+#    else /* HPUXKERNBITS<64 */
+#        define _RLIM_T
+#        if !defined(__STDC_32_MODE__)
+typedef unsigned long long rlim_t;
+#        else  /* defined(__STDC_32_MODE__) */
+typedef unsigned long rlim_t;
+#        endif /* !defined(__STDC_32_MODE__) */
+#    endif     /* HPUXKERNBITS>=64 */
+#endif         /* defined(HPUXKERNBITS) */
+
+#include "common.h"
+
+#if defined(HASNCACHE)
+#    include <sys/dnlc.h>
+#endif /* defined(HASNCACHE) */
+
+#if HPUXV >= 1010
+/*
+ * HP doesn't include a definition for the proc structure in HP-UX 10.10
+ * or above in an attempt to force use of pstat(2).  Unfortunately, pstat(2)
+ * doesn't return the information lsof needs.  Hence, this private proc
+ * structure definition.
+ */
+
+#    include <sys/vas.h>
+
+#    define SZOMB 3
+
+#    if HPUXV < 1020
+struct proc {
+    caddr_t d1[2];             /* dummy to occupy space */
+    caddr_t p_firstthreadp;    /* thread pointer */
+    caddr_t d2[4];             /* dummy to occupy space */
+    int p_stat;                /* process status */
+    caddr_t d3[9];             /* dummy to occupy space */
+    uid_t p_uid;               /* UID */
+    caddr_t d4[2];             /* dummy to occupy space */
+    gid_t p_pgid;              /* process group ID */
+    pid_t p_pid;               /* PID */
+    pid_t p_ppid;              /* parent PID */
+    caddr_t d5[9];             /* dummy to occupy space */
+    vas_t *p_vas;              /* virtual address space */
+    caddr_t d6[16];            /* dummy to occupy space */
+    int p_maxof;               /* max open files allowed */
+    struct vnode *p_cdir;      /* current directory */
+    struct vnode *p_rdir;      /* root directory */
+    struct ofile_t **p_ofilep; /* file descriptor chunks */
+    caddr_t d7[43];            /* dummy to occupy space */
+};
+#    endif /* HPUXV<1020 */
+
+#    if HPUXV >= 1020 && HPUXV < 1030
+struct proc {
+    caddr_t d1[2];             /* dummy to occupy space */
+    caddr_t p_firstthreadp;    /* thread pointer */
+    caddr_t d2[6];             /* dummy to occupy space */
+    int p_stat;                /* process status */
+    caddr_t d3[14];            /* dummy to occupy space */
+    uid_t p_uid;               /* real UID */
+    uid_t p_suid;              /* effective UID */
+    caddr_t d4;                /* dummy to occupy space */
+    gid_t p_pgid;              /* process group ID */
+    pid_t p_pid;               /* PID */
+    pid_t p_ppid;              /* parent PID */
+    caddr_t d5[9];             /* dummy to occupy space */
+    vas_t *p_vas;              /* virtual address space */
+    caddr_t d6[16];            /* dummy to occupy space */
+    int p_maxof;               /* max open files allowed */
+    struct vnode *p_cdir;      /* current directory */
+    struct vnode *p_rdir;      /* root directory */
+    struct ofile_t **p_ofilep; /* file descriptor chunks */
+    caddr_t d7[84];            /* dummy to occupy space */
+};
+#    endif /* HPUXV>=1020 && HPUXV<1030 */
+#endif     /* HPUXV<1010 */
+
+/*
+ * Local static values
+ */
+
+static KA_T Kp; /* kernel's process table address */
+static int Np;  /* number of kernel processes */
+
+#if HPUXV >= 800
+static MALLOC_S Nva = 0;        /* number of entries allocated to
+                                 * vnode address cache */
+static KA_T *Vp = (KA_T *)NULL; /* vnode address cache */
+#endif                          /* HPUXV>=800 */
+
+static void get_kernel_access(void);
+
+#if HPUXV >= 800
+static void process_text(KA_T vasp);
+#endif /* HPUXV>=800 */
+
+/*
+ * gather_proc_info() -- gather process information
+ */
+
+void gather_proc_info() {
+    KA_T fp;
+    int err, i, j;
+
+#if HPUXV >= 1020 && HPUXV < 1100
+    struct ofile_t {
+        struct ofa {
+            KA_T ofile;
+            int d1;
+            int pofile;
+        } ofa[SFDCHUNK];
+    };
+    struct ofa *ofap;
+    int ofasz = (int)sizeof(struct ofa);
+    struct ofile_t oft;
+    char *oftp = (char *)&oft;
+    int oftsz = (int)sizeof(struct ofile_t);
+#else /* HPUXV<1020 || HPUXV>=1100 */
+#    if HPUXV >= 1100
+    struct ofa {
+        KA_T ofile;
+        int d1;
+        short d2;
+        char d3;
+        char pofile;
+    };
+    struct ofa *ofap;
+    int ofasz = (int)sizeof(struct ofa);
+    char *oftp = (char *)NULL;
+    int oftsz = (int)(sizeof(struct ofa) * SFDCHUNK);
+    KA_T v;
+#    endif /* HPUXV>=1100 */
+#endif     /* HPUXV>=1020 && HPUXV<1100 */
+
+#if HPUXV >= 800
+    char *c, *s;
+    KA_T pfp, ofp;
+
+#    if HPUXV < 1020
+    struct ofile_t oft;
+    char *oftp = (char *)&oft;
+    int oftsz = (int)sizeof(struct ofile_t);
+#    endif /* HPUXV<1020 */
+
+    struct pst_status ps;
+
+#    if HPUXV < 1010
+    struct user us;
+#    else  /* HPUXV>=1010 */
+    struct user {
+        char u_comm[PST_CLEN];
+    } us;
+#    endif /* HPUXV<1010 */
+#else      /* HPUXV<800 */
+    int k;
+    long sw;
+    char us[U_SIZE]; /* must read HP-UX SWAP in DEV_BSIZE chunks */
+
+#    if defined(hp9000s300)
+    struct pte pte1, pte2;
+    KA_T pte_off, pte_addr;
+#    endif /* defined(hp9000s300) */
+#endif     /* HPUXV>=800 */
+
+    struct proc *p;
+    struct proc pbuf;
+    short pss, sf;
+    int px;
+    struct user *u;
+
+#if defined(HASFSTRUCT)
+#    if HPUXV >= 1020 || (HPUXV >= 900 && HPUXV < 1000)
+#        define USESPOFILE 1
+    long pof;
+#    endif /* HPUXV>=1020 || (HPUXV>=900 && HPUXV<1000) */
+#endif     /* defined(HASFSTRUCT) */
+
+#if HPUXV >= 1100
+    /*
+     * Define FD chunk size and pointer for HP-UX >= 11.
+     */
+    if (!oftp) {
+        if ((get_Nl_value("chunksz", Drive_Nl, &v) >= 0) && v) {
+            if (kread(ctx, v, (char *)&oftsz, sizeof(oftsz))) {
+                (void)fprintf(stderr, "%s: can't get FD chunk size\n", Pn);
+                Error(ctx);
+            }
+            if (!oftsz) {
+                (void)fprintf(stderr, "%s: bad FD chunk size: %d\n", Pn, oftsz);
+                Error(ctx);
+            }
+        }
+        ofasz = (int)(oftsz / SFDCHUNK);
+        if (oftsz != (ofasz * SFDCHUNK)) {
+            (void)fprintf(stderr,
+                          "%s: FD chunk size (%d) not exact multiple of %d\n",
+                          Pn, oftsz, SFDCHUNK);
+            Error(ctx);
+        }
+        if (!(oftp = (char *)malloc((MALLOC_S)oftsz))) {
+            (void)fprintf(stderr, "%s: no space for %d FD bytes\n", Pn, oftsz);
+            Error(ctx);
+        }
+    }
+#endif /* HPUXV>=1100 */
+
+    /*
+     * Examine proc structures and their associated information.
+     */
+
+#if HPUXV >= 800
+    u = &us;
+    (void)zeromem((char *)u, U_SIZE);
+    for (p = &pbuf, px = 0; px < Np; px++)
+#else  /* HPUXV<800 */
+    for (p = &pbuf, px = 0, u = (struct user *)us; px < Np; px++)
+#endif /* HPUXV>=800 */
+
+    {
+        Kpa = Kp + (KA_T)(px * sizeof(struct proc));
+        if (kread(ctx, Kpa, (char *)&pbuf, sizeof(pbuf)))
+            continue;
+        if (p->p_stat == 0 || p->p_stat == SZOMB)
+            continue;
+        /*
+         * See if process is excluded.
+         */
+        if (is_proc_excl(p->p_pid, (int)p->p_pgid, (UID_ARG)p->p_uid, &pss,
+                         &sf))
+            continue;
+
+#if HPUXV >= 1010
+        /*
+         * Save the kernel thread pointer.
+         */
+        Ktp = (KA_T)p->p_firstthreadp;
+#endif /* HPUXV>=1010 */
+
+        /*
+         * Read the user area.
+         */
+
+#if HPUXV >= 800
+        /*
+         * Use the pstat() syscall to read process status.
+         */
+
+        if (pstat(PSTAT_PROC, &ps, sizeof(ps), 0, p->p_pid) != 1) {
+            if (!Fwarn)
+                (void)fprintf(stderr, "%s: can't pstat process %d: %s\n", Pn,
+                              p->p_pid, strerror(errno));
+            continue;
+        }
+        /*
+         * Use the pst_cmd command buffer.
+         */
+        c = ps.pst_cmd;
+        ps.pst_cmd[PST_CLEN - 1] = '\0'; /* paranoia */
+                                         /*
+                                          * Skip to the last component of the first path name.  Also skip any
+                                          * leading `-', signifying a login shell.  Copy the result to u_comm[].
+                                          */
+        if (*c == '-')
+            c++;
+        for (s = c; *c && (*c != ' '); c++) {
+            if (*c == '/')
+                s = c + 1;
+        }
+        for (i = 0; i < MAXCOMLEN; i++) {
+            if (*s == '\0' || *s == ' ' || *s == '/')
+                break;
+            u->u_comm[i] = *s++;
+        }
+        u->u_comm[i] = '\0';
+#else /* HPUXV<800 */
+        /*
+         * Read the user area from the swap file or memory.
+         */
+        if ((p->p_flag & SLOAD) == 0) {
+
+            /*
+             * If the process is not loaded, read the user area from the swap
+             * file.
+             */
+            if (Swap < 0)
+                continue;
+            sw = (long)p->p_swaddr;
+
+#    if defined(hp9000s800)
+            sw += (long)ctod(btoc(STACKSIZE * NBPG));
+#    endif /* defined(hp9000s800) */
+
+            if (lseek(Swap, (off_t)dtob(sw), L_SET) == (off_t)-1 ||
+                read(Swap, u, U_SIZE) != U_SIZE)
+                continue;
+        } else {
+
+            /*
+             * Read the user area via the page table.
+             */
+
+#    if defined(hp9000s300)
+            pte_off = (KA_T)&Usrptmap[btokmx(p->p_p0br) + p->p_szpt - 1];
+            if (kread(ctx, pte_off, (char *)&pte1, sizeof(pte1)))
+                continue;
+            pte_addr = (KA_T)(ctob(pte1.pg_pfnum + 1) -
+                              ((UPAGES + FLOAT) * sizeof(pte2)));
+            if (mread(pte_addr, (char *)&pte2, sizeof(pte2)))
+                continue;
+            if (mread((KA_T)ctob(pte2.pg_pfnum), (char *)u,
+                      sizeof(struct user)))
+                continue;
+#    endif /* defined(hp9000s300) */
+
+#    if defined(hp9000s800)
+            if (kread(ctx, (KA_T)uvadd((struct proc *)Kpa), (char *)u,
+                      sizeof(struct user)))
+                continue;
+        }
+#    endif /* defined(hp9000s800) */
+#endif     /* HPUXV>=800 */
+
+        /*
+         * Allocate a local process structure.
+         */
+        if (is_cmd_excl(u->u_comm, &pss, &sf))
+            continue;
+        alloc_lproc(p->p_pid, (int)p->p_pgid, (int)p->p_ppid, (UID_ARG)p->p_uid,
+                    u->u_comm, (int)pss, (int)sf);
+        Plf = (struct lfile *)NULL;
+        /*
+         * Save current working directory information.
+         */
+        if (CURDIR) {
+            alloc_lfile(ctx, LSOF_FD_CWD, -1);
+            process_node((KA_T)CURDIR);
+            if (Lf->sf)
+                link_lfile();
+        }
+        /*
+         * Save root directory information.
+         */
+        if (ROOTDIR) {
+            alloc_lfile(ctx, LSOF_FD_ROOT_DIR, -1);
+            process_node((KA_T)ROOTDIR);
+            if (Lf->sf)
+                link_lfile();
+        }
+
+#if HPUXV >= 800
+        /*
+         * Print information on the text file.
+         */
+        if (p->p_vas)
+            process_text((KA_T)p->p_vas);
+#endif /* HPUXV>=800 */
+
+            /*
+             * Loop through user's files.
+             */
+
+#if HPUXV >= 800
+        for (i = 0, j = SFDCHUNK, pfp = (KA_T)p->p_ofilep; i < p->p_maxof; i++)
+#else  /* HPUXV<800 */
+        for (i = j = k = 0;; i++)
+#endif /* HPUXV>=800 */
+
+        {
+
+#if HPUXV >= 800
+            if (j >= SFDCHUNK) {
+                if (!pfp || kread(ctx, (KA_T)pfp, (char *)&ofp, sizeof(ofp)) ||
+                    !ofp || kread(ctx, (KA_T)ofp, oftp, oftsz))
+                    break;
+                j = 0;
+                pfp += sizeof(KA_T);
+
+#    if HPUXV >= 1020
+                ofap = (struct ofa *)oftp;
+#    endif /* HPUXV>=1020 */
+            }
+            j++;
+
+#    if HPUXV >= 1020
+#        if defined(USESPOFILE)
+            pof = (long)ofap->pofile;
+#        endif /* defined(USESPOFILE) */
+
+            fp = (KA_T)ofap->ofile;
+            ofap = (struct ofa *)((char *)ofap + ofasz);
+            if (fp)
+#    else /* HPUXV<1020 */
+#        if defined(USESPOFILE)
+            pof = (long)oft.pofile[j - 1];
+#        endif /* defined(USESPOFILE) */
+
+            if ((fp = (KA_T)oft.ofile[j - 1]))
+#    endif     /* HPUXV>=1020 */
+#else          /* HPUXV<800 */
+            if (j >= SFDCHUNK) {
+
+                /*
+                 * Get next file pointer "chunk".
+                 */
+                while (++k < NFDCHUNKS && !u->u_ofilep[k])
+                    ;
+                if (k >= NFDCHUNKS)
+                    break;
+                if (kread(ctx, (KA_T)u->u_ofilep[k], (char *)&u->u_ofile,
+                          sizeof(struct ofile_t))) {
+                    break;
+                }
+                j = 0;
+            }
+            j++;
+            if ((fp = (KA_T)u->u_ofile.ofile[j - 1]))
+#endif         /* HPUXV>=800 */
+
+            /*
+             * Process the file pointer.
+             */
+
+            {
+                alloc_lfile(ctx, LSOF_FD_NUMERIC, i);
+                process_file(fp);
+                if (Lf->sf) {
+
+#if defined(USESPOFILE)
+                    Lf->pof = pof;
+#endif /* defined(USESPOFILE) */
+
+                    link_lfile();
+                }
+            }
+        }
+        /*
+         * Examine results.
+         */
+        if (examine_lproc())
+            return;
+    }
+}
+
+/*
+ * get_kernel_access() - access the required information in the kernel
+ */
+
+static void get_kernel_access() {
+    KA_T v;
+    /*
+     * Check the kernel version.
+     */
+    (void)ckkv("HP-UX", LSOF_VSTR, (char *)NULL, (char *)NULL);
+
+#if HPUXV >= 1030
+    /*
+     * See if build and run bit sizes match.  Exit if they don't.
+     */
+    {
+        long rv;
+
+        if ((rv = sysconf(_SC_KERNEL_BITS)) < 0) {
+            (void)fprintf(stderr, "%s: sysconf(_SC_KERNEL_BITS) returns: %s\n",
+                          Pn, strerror(errno));
+            Error(ctx);
+        }
+        if (rv != (long)HPUXKERNBITS) {
+            (void)fprintf(
+                stderr,
+                "%s: FATAL: %s was built for a %d bit kernel, but this\n", Pn,
+                Pn, HPUXKERNBITS);
+            (void)fprintf(stderr, "      is a %ld bit kernel.\n", rv);
+            Error(ctx);
+        }
+    }
+#endif /* HPUXV>=1030 */
+
+#if defined(HAS_AFS)
+    struct NLIST_TYPE *nl = (struct NLIST_TYPE *)NULL;
+#endif /* defined(HAS_AFS) */
+
+#if HPUXV < 800
+    /*
+     * Open access to /dev/mem and SWAP.
+     */
+    if ((Mem = open("/dev/mem", O_RDONLY, 0)) < 0) {
+        (void)fprintf(stderr, "%s: can't open /dev/mem: %s\n", Pn,
+                      strerror(errno));
+        err = 1;
+    }
+    if (!Memory || strcmp(Memory, KMEM) == 0) {
+        if ((Swap = open(SWAP, O_RDONLY, 0)) < 0) {
+            (void)fprintf(stderr, "%s: %s: %s\n", Pn, SWAP, strerror(errno));
+            err = 1;
+        }
+    }
+#endif /* HPUXV<800 */
+
+#if defined(WILLDROPGID)
+    /*
+     * If kernel memory isn't coming from KMEM, drop setgid permission
+     * before attempting to open the (Memory) file.
+     */
+    if (Memory)
+        (void)dropgid();
+#else  /* !defined(WILLDROPGID) */
+    /*
+     * See if the non-KMEM memory file is readable.
+     */
+    if (Memory && !is_readable(Memory, 1))
+        Error(ctx);
+#endif /* defined(WILLDROPGID) */
+
+    /*
+     * Open kernel memory access.
+     */
+    if ((Kd = open(Memory ? Memory : KMEM, O_RDONLY, 0)) < 0) {
+        int errno_save = errno;
+
+        (void)fprintf(stderr, "%s: can't open ", Pn);
+        safestrprt(Memory ? Memory : KMEM, stderr, 0);
+        (void)fprintf(stderr, ": %s\n", strerror(errno_save));
+        Error(ctx);
+    }
+
+#if defined(WILLDROPGID)
+    /*
+     * Drop setgid permission, if necessary.
+     */
+    if (!Memory)
+        (void)dropgid();
+#else  /* !defined(WILLDROPGID) */
+    /*
+     * See if the name list file is readable.
+     */
+    if (Nmlst && !is_readable(Nmlst, 1))
+        Error(ctx);
+#endif /* defined(WILLDROPGID) */
+
+    (void)build_Nl(Drive_Nl);
+
+#if defined(HAS_AFS)
+    if (!Nmlst) {
+
+        /*
+         * If AFS is defined and we're getting kernel symbol values from
+         * from N_UNIX, make a copy of Nl[] for possible use with the AFS
+         * module name list file.
+         */
+        if (!(nl = (struct NLIST_TYPE *)malloc(Nll))) {
+            (void)fprintf(stderr, "%s: no space (%d) for Nl[] copy\n", Pn, Nll);
+            Error(ctx);
+        }
+        (void)memcpy((void *)nl, (void *)Nl, (size_t)Nll);
+    }
+#endif /* defined(HAS_AFS) */
+
+    /*
+     * Access kernel symbols.
+     */
+    if (NLIST_TYPE(Nmlst ? Nmlst : N_UNIX, Nl) < 0) {
+        (void)fprintf(stderr, "%s: can't read namelist from: ", Pn);
+        safestrprt(Nmlst ? Nmlst : N_UNIX, stderr, 1);
+        Error(ctx);
+    }
+    if (get_Nl_value("proc", Drive_Nl, &v) < 0 || !v ||
+        kread(ctx, (KA_T)v, (char *)&Kp, sizeof(Kp)) ||
+        get_Nl_value("nproc", Drive_Nl, &v) < 0 || !v ||
+        kread(ctx, (KA_T)v, (char *)&Np, sizeof(Np)) || !Kp || Np < 1) {
+        (void)fprintf(stderr, "%s: can't read proc table info\n", Pn);
+        Error(ctx);
+    }
+    if (get_Nl_value("vfops", Drive_Nl, (KA_T *)&Vnfops) < 0)
+        Vnfops = (KA_T)NULL;
+
+#if HPUXV < 800 && defined(hp9000s300)
+    if (get_Nl_value("upmap", Drive_Nl, (unsigned long *)&Usrptmap) < 0) {
+        (void)fprintf(stderr, "%s: can't get kernel's Usrptmap\n", Pn);
+        Error(ctx);
+    }
+    if (get_Nl_value("upt", Drive_Nl, (unsigned long *)&usrpt) < 0) {
+        (void)fprintf(stderr, "%s: can't get kernel's usrpt\n", Pn);
+        Error(ctx);
+    }
+#endif /* HPUXV<800 && defined(hp9000s300) */
+
+#if HPUXV < 800 && defined(hp9000s800)
+    proc = (struct proc *)Kp;
+    if (get_Nl_value("ubase", Drive_Nl, (unsigned long *)&ubase) < 0) {
+        (void)fprintf(stderr, "%s: can't get kernel's ubase\n", Pn);
+        Error(ctx);
+    }
+    if (get_Nl_value("npids", Drive_Nl, &v) < 0 || !v ||
+        kread(ctx, (KA_T)v, (char *)&npids, sizeof(npids))) {
+        (void)fprintf(stderr, "%s: can't get kernel's npids\n", Pn);
+        Error(ctx);
+    }
+#endif /* HPUXV<800 && defined(hp9000s800) */
+
+#if HPUXV >= 1030
+    if (get_Nl_value("clmaj", Drive_Nl, &v) < 0 || !v ||
+        kread(ctx, (KA_T)v, (char *)&CloneMaj, sizeof(CloneMaj)))
+        HaveCloneMaj = 0;
+    else
+        HaveCloneMaj = 1;
+#endif /* HPUXV>=1030 */
+
+#if defined(HAS_AFS)
+    if (nl) {
+
+        /*
+         * If AFS is defined and we're getting kernel symbol values from
+         * N_UNIX, and if any X_AFS_* symbols isn't there, see if it is in the
+         * the AFS module name list file.  Make sure that other symbols that
+         * appear in both name list files have the same values.
+         */
+        if ((get_Nl_value("arFid", Drive_Nl, &v) >= 0 && !v) ||
+            (get_Nl_value("avops", Drive_Nl, &v) >= 0 && !v) ||
+            (get_Nl_value("avol", Drive_Nl, &v) >= 0 && !v))
+            (void)ckAFSsym(nl);
+        (void)free((FREE_P *)nl);
+    }
+#endif /* defined(HAS_AFS) */
+}
+
+/*
+ * initialize() - perform all initialization
+ */
+
+void initialize() { get_kernel_access(); }
+
+/*
+ * kread() - read from kernel memory
+ */
+
+int kread(struct lsof_context *ctx, /* context */
+          KA_T addr,                /* kernel memory address */
+          char *buf,                /* buffer to receive data */
+          READLEN_T len)            /* length to read */
+{
+    int br;
+
+    if (lseek(Kd, (off_t)addr, L_SET) == (off_t)-1L)
+        return (-1);
+    br = read(Kd, buf, len);
+    return ((br == len) ? 0 : 1);
+}
+
+#if HPUXV < 800
+/*
+ * mread() -- read from /dev/mem
+ */
+
+static int mread(addr, buf, len)
+KA_T addr;     /* /dev/mem address */
+char *buf;     /* buffer to receive data */
+READLEN_T len; /* length to read */
+{
+    int br;
+
+    if (lseek(Mem, addr, L_SET) == (off_t)-1L)
+        return (1);
+    br = read(Mem, buf, len);
+    return ((br == len) ? 0 : 1);
+}
+#endif /* HPUXV<800 */
+
+#if HPUXV >= 800
+/*
+ * process_text() - process text access information
+ */
+
+static void process_text(vasp) KA_T vasp; /* kernel's virtual address space
+                                           * pointer */
+{
+    char fd[FDLEN];
+    int i, j, lm;
+    MALLOC_S len;
+    struct pregion p;
+    KA_T prp;
+    struct region r;
+    struct vas v;
+    KA_T va;
+    /*
+     * Read virtual address space pointer.
+     */
+    if (kread(ctx, vasp, (char *)&v, sizeof(v)))
+        return;
+    /*
+     * Follow the virtual address space pregion structure chain.
+     */
+    for (i = lm = 0, prp = (KA_T)v.va_next; prp != vasp;
+         prp = (KA_T)p.p_next, lm++) {
+
+        /*
+         * Avoid infinite loop.
+         */
+        if (lm > 1000) {
+            if (!Fwarn)
+                (void)fprintf(
+                    stderr, "%s: too many virtual address regions for PID %d\n",
+                    Pn, Lp->pid);
+            return;
+        }
+        /*
+         * Read the pregion and region.
+         */
+        if (kread(ctx, prp, (char *)&p, sizeof(p)))
+            return;
+        if (kread(ctx, (KA_T)p.p_reg, (char *)&r, sizeof(r)))
+            return;
+        /*
+         * Skip file entries with no file pointers.
+         */
+        if (!(va = (KA_T)r.r_fstore))
+            continue;
+        /*
+         * Skip entries whose vnodes have already been displayed.
+         *
+         *  Record new, unique vnode pointers.
+         */
+        for (j = 0; j < i; j++) {
+            if (Vp[j] == va)
+                break;
+        }
+        if (j < i)
+            continue;
+        if (i >= Nva) {
+            Nva += 10;
+            len = (MALLOC_S)(Nva * sizeof(KA_T));
+            if (!Vp)
+                Vp = (KA_T *)malloc(len);
+            else
+                Vp = (KA_T *)realloc((MALLOC_P *)Vp, len);
+            if (!Vp) {
+                (void)fprintf(
+                    stderr, "%s: no more space for text vnode pointers\n", Pn);
+                Error(ctx);
+            }
+        }
+        Vp[i++] = va;
+        /*
+         * Allocate local file structure.
+         */
+        switch (p.p_type) {
+        case PT_DATA:
+        case PT_TEXT:
+            alloc_lfile(ctx, LSOF_FD_PROGRAM_TEXT, -1);
+            break;
+        case PT_MMAP:
+            alloc_lfile(ctx, LSOF_FD_MEMORY, -1);
+            break;
+        default:
+            alloc_lfile(ctx, LSOF_FD_PREGION_UNKNOWN, p.p_type);
+        }
+        /*
+         * Save vnode information.
+         */
+        process_node(va);
+        if (Lf->sf)
+            link_lfile();
+    }
+}
+#endif /* HPUXV>=800 */
diff --git a/lib/dialects/hpux/kmem/dproto.h b/lib/dialects/hpux/kmem/dproto.h
new file mode 100644 (file)
index 0000000..5dbff4f
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * dproto.h - /dev/kmem-based HP-UX function prototypes for lsof
+ *
+ * The _PROTOTYPE macro is defined in the common proto.h.
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+/*
+ * $Id: dproto.h,v 1.7 2000/12/04 14:26:14 abe Exp $
+ */
+
+#if HPUXV >= 800
+extern void completevfs(struct l_vfs *vfs, dev_t *dev, struct vfs *v);
+#else
+extern void completevfs(struct l_vfs *vfs, dev_t *dev);
+#endif /* HPUXV>=800 */
+
+extern int is_file_named(char *p, int cd);
+extern int get_max_fd(void);
+
+#if defined(DTYPE_LLA)
+extern void process_lla(KA_T la);
+#endif
+
+extern struct l_vfs *readvfs(struct vnode *lv);
+
+#if HPUXV >= 1030
+extern void process_stream_sock(KA_T ip, KA_T pcb, char *pn, enum vtype vt);
+extern int read_mi(KA_T sh, KA_T *ip, KA_T *pcb, char **pn);
+#endif /* HPUXV>=1030 */
+
+#if defined(HAS_AFS)
+extern struct vnode *alloc_vcache(void);
+extern void ckAFSsym(struct nlist *nl);
+extern int hasAFS(struct vnode *vp);
+extern int readafsnode(KA_T va, struct vnode *v, struct afsnode *an);
+#endif /* defined(HAS_AFS) */
+
+#if defined(HASVXFS)
+extern int read_vxnode(struct vnode *v, struct l_vfs *vfs, dev_t *dev,
+                       int *devs, dev_t *rdev, int *rdevs);
+#endif /* defined(HASVXFS) */
diff --git a/lib/dialects/hpux/kmem/dsock.c b/lib/dialects/hpux/kmem/dsock.c
new file mode 100644 (file)
index 0000000..9f57bd8
--- /dev/null
@@ -0,0 +1,1125 @@
+/*
+ * dsock.c - /dev/kmem-based HP-UX socket processing functions for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#ifndef lint
+static char copyright[] =
+    "@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
+#endif
+
+#if defined(HPUXKERNBITS) && HPUXKERNBITS >= 64
+#    define _INO_T
+typedef int ino_t;
+#    define _TIME_T
+typedef int time_t;
+#endif /* defined(HPUXKERNBITS) && HPUXKERNBITS>=64 */
+
+#include "common.h"
+
+#if HPUXV >= 800 && defined(HPUX_CCITT)
+#    include <x25/x25addrstr.h>
+#    include <x25/x25stat.h>
+#    include <x25/x25str.h>
+#    include <x25/x25config.h>
+#    include <x25/x25L3.h>
+#endif /* HPUXV>=800 && defined(HPUX_CCITT) */
+
+/*
+ * Local definitions
+ */
+
+#if defined(HASTCPOPT)
+#    define TF_NODELAY 0x1 /* TCP_NODELAY (Nagle algorithm) */
+#endif                     /* defined(HASTCPOPT) */
+
+#if HPUXV >= 1030
+/*
+ * print_tcptpi() - print TCP/TPI info
+ */
+
+void print_tcptpi(nl) int nl; /* 1 == '\n' required */
+{
+    char *cp = (char *)NULL;
+    char sbuf[128];
+    int i, t;
+    int ps = 0;
+    unsigned int u;
+
+    if (Ftcptpi & TCPTPI_STATE) {
+        switch ((t = Lf->lts.type)) {
+        case 0: /* TCP */
+            switch ((i = Lf->lts.state.i)) {
+            case TCPS_CLOSED:
+                cp = "CLOSED";
+                break;
+            case TCPS_IDLE:
+                cp = "IDLE";
+                break;
+            case TCPS_BOUND:
+                cp = "BOUND";
+                break;
+            case TCPS_LISTEN:
+                cp = "LISTEN";
+                break;
+            case TCPS_SYN_SENT:
+                cp = "SYN_SENT";
+                break;
+            case TCPS_SYN_RCVD:
+                cp = "SYN_RCVD";
+                break;
+            case TCPS_ESTABLISHED:
+                cp = "ESTABLISHED";
+                break;
+            case TCPS_CLOSE_WAIT:
+                cp = "CLOSE_WAIT";
+                break;
+            case TCPS_FIN_WAIT_1:
+                cp = "FIN_WAIT_1";
+                break;
+            case TCPS_CLOSING:
+                cp = "CLOSING";
+                break;
+            case TCPS_LAST_ACK:
+                cp = "LAST_ACK";
+                break;
+            case TCPS_FIN_WAIT_2:
+                cp = "FIN_WAIT_2";
+                break;
+            case TCPS_TIME_WAIT:
+                cp = "TIME_WAIT";
+                break;
+            default:
+                (void)snpf(sbuf, sizeof(sbuf), "UknownState_%d", i);
+                cp = sbuf;
+            }
+            break;
+        case 1: /* TPI */
+            switch ((u = Lf->lts.state.ui)) {
+            case TS_UNINIT:
+                cp = "Uninitialized";
+                break;
+            case TS_UNBND:
+                cp = "Unbound";
+                break;
+            case TS_WACK_BREQ:
+                cp = "Wait_BIND_REQ_Ack";
+                break;
+            case TS_WACK_UREQ:
+                cp = "Wait_UNBIND_REQ_Ack";
+                break;
+            case TS_IDLE:
+                cp = "Idle";
+                break;
+            case TS_WACK_OPTREQ:
+                cp = "Wait_OPT_REQ_Ack";
+                break;
+            case TS_WACK_CREQ:
+                cp = "Wait_CONN_REQ_Ack";
+                break;
+            case TS_WCON_CREQ:
+                cp = "Wait_CONN_REQ_Confirm";
+                break;
+            case TS_WRES_CIND:
+                cp = "Wait_CONN_IND_Response";
+                break;
+            case TS_WACK_CRES:
+                cp = "Wait_CONN_RES_Ack";
+                break;
+            case TS_DATA_XFER:
+                cp = "Wait_Data_Xfr";
+                break;
+            case TS_WIND_ORDREL:
+                cp = "Wait_Read_Release";
+                break;
+            case TS_WREQ_ORDREL:
+                cp = "Wait_Write_Release";
+                break;
+            case TS_WACK_DREQ6:
+            case TS_WACK_DREQ7:
+            case TS_WACK_DREQ9:
+            case TS_WACK_DREQ10:
+            case TS_WACK_DREQ11:
+                cp = "Wait_DISCON_REQ_Ack";
+                break;
+            case TS_WACK_ORDREL:
+                cp = "Internal";
+                break;
+            default:
+                (void)snpf(sbuf, sizeof(sbuf), "UNKNOWN_TPI_STATE_%u", u);
+                cp = sbuf;
+            }
+        }
+        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(HASSOOPT)
+    if (Ftcptpi & TCPTPI_FLAGS) {
+        int opt;
+
+        if ((opt = Lf->lts.opt) || Lf->lts.qlens || Lf->lts.qlims ||
+            Lf->lts.rbszs || Lf->lts.sbsz) {
+            char sep = ' ';
+
+            if (Ffield)
+                sep = LSOF_FID_TCPTPI;
+            else if (!ps)
+                sep = '(';
+            (void)printf("%cSO", sep);
+            ps++;
+            sep = '=';
+
+#        if defined(SO_BROADCAST)
+            if (opt & SO_BROADCAST) {
+                (void)printf("%cBROADCAST", sep);
+                opt &= ~SO_BROADCAST;
+                sep = ',';
+            }
+#        endif /* defined(SO_BROADCAST) */
+
+#        if defined(SO_DEBUG)
+            if (opt & SO_DEBUG) {
+                (void)printf("%cDEBUG", sep);
+                opt &= ~SO_DEBUG;
+                sep = ',';
+            }
+#        endif /* defined(SO_DEBUG) */
+
+#        if defined(SO_DONTROUTE)
+            if (opt & SO_DONTROUTE) {
+                (void)printf("%cDONTROUTE", sep);
+                opt &= ~SO_DONTROUTE;
+                sep = ',';
+            }
+#        endif /* defined(SO_DONTROUTE) */
+
+#        if defined(SO_KEEPALIVE)
+            if (opt & SO_KEEPALIVE) {
+                (void)printf("%cKEEPALIVE", sep);
+                if (Lf->lts.kai)
+                    (void)printf("=%d", Lf->lts.kai);
+                opt &= ~SO_KEEPALIVE;
+                sep = ',';
+            }
+#        endif /* defined(SO_KEEPALIVE) */
+
+#        if defined(SO_LINGER)
+            if (opt & SO_LINGER) {
+                (void)printf("%cLINGER", sep);
+                if (Lf->lts.ltm)
+                    (void)printf("=%d", Lf->lts.ltm);
+                opt &= ~SO_LINGER;
+                sep = ',';
+            }
+#        endif /* defined(SO_LINGER) */
+
+#        if defined(SO_OOBINLINE)
+            if (opt & SO_OOBINLINE) {
+                (void)printf("%cOOBINLINE", sep);
+                opt &= ~SO_OOBINLINE;
+                sep = ',';
+            }
+#        endif /* defined(SO_OOBINLINE) */
+
+            if (Lf->lts.qlens) {
+                (void)printf("%cQLEN=%u", sep, Lf->lts.qlen);
+                sep = ',';
+            }
+            if (Lf->lts.qlims) {
+                (void)printf("%cQLIM=%u", sep, Lf->lts.qlim);
+                sep = ',';
+            }
+
+#        if defined(SO_REUSEADDR)
+            if (opt & SO_REUSEADDR) {
+                (void)printf("%cREUSEADDR", sep);
+                opt &= ~SO_REUSEADDR;
+                sep = ',';
+            }
+#        endif /* defined(SO_REUSEADDR) */
+
+#        if defined(SO_REUSEPORT)
+            if (opt & SO_REUSEPORT) {
+                (void)printf("%cREUSEPORT", sep);
+                opt &= ~SO_REUSEPORT;
+                sep = ',';
+            }
+#        endif /* defined(SO_REUSEPORT) */
+
+#        if defined(SO_USELOOPBACK)
+            if (opt & SO_USELOOPBACK) {
+                (void)printf("%cUSELOOPBACK", sep);
+                opt &= ~SO_USELOOPBACK;
+                sep = ',';
+            }
+#        endif /* defined(SO_USELOOPBACK) */
+
+            if (opt)
+                (void)printf("%cUNKNOWN=%#x", sep, opt);
+            if (Ffield)
+                putchar(Terminator);
+        }
+    }
+#    endif /* defined(HASSOOPT) */
+
+#    if defined(HASTCPOPT)
+    if (Ftcptpi & TCPTPI_FLAGS) {
+        int topt;
+
+        if ((topt = Lf->lts.topt) || Lf->lts.msss) {
+            char sep = ' ';
+
+            if (Ffield)
+                sep = LSOF_FID_TCPTPI;
+            else if (!ps)
+                sep = '(';
+            (void)printf("%cTF", sep);
+            ps++;
+            sep = '=';
+
+            if (Lf->lts.msss) {
+                (void)printf("%cMSS=%lu", sep, Lf->lts.mss);
+                sep = ',';
+            }
+
+#        if defined(TF_NODELAY)
+            if (topt & TF_NODELAY) {
+                (void)printf("%cNODELAY", sep);
+                topt &= ~TF_NODELAY;
+                sep = ',';
+            }
+#        endif /* defined(TF_NODELAY) */
+
+            if (topt)
+                (void)printf("%cUNKNOWN=%#x", sep, topt);
+            if (Ffield)
+                putchar(Terminator);
+        }
+    }
+#    endif /* defined(HASTCPOPT) */
+
+#    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 (Ftcptpi && !Ffield && ps)
+        putchar(')');
+    if (nl)
+        putchar('\n');
+}
+#endif /* HPUXV>=1030 */
+
+#if defined(DTYPE_LLA)
+/*
+ * process_lla() - process link level access socket file
+ */
+
+void process_lla(la) KA_T la; /* link level CB address in kernel */
+{
+    char *ep;
+    struct lla_cb lcb;
+    size_t sz;
+
+    Lf->type = LSOF_FILE_LINK_LEVEL_ACCESS;
+    Lf->inp_ty = 2;
+    enter_dev_ch(print_kptr(la, (char *)NULL, 0));
+    /*
+     * Read link level access control block.
+     */
+    if (!la || kread(ctx, (KA_T)la, (char *)&lcb, sizeof(lcb))) {
+        (void)snpf(Namech, Namechl, "can't read LLA CB (%s)",
+                   print_kptr(la, (char *)NULL, 0));
+        enter_nm(Namech);
+        return;
+    }
+    /*
+     * Determine access mode.
+     */
+    if ((lcb.lla_flags & LLA_FWRITE | LLA_FREAD) == LLA_FWRITE)
+        Lf->access = LSOF_FILE_ACCESS_WRITE;
+    else if ((lcb.lla_flags & LLA_FWRITE | LLA_FREAD) == LLA_FREAD)
+        Lf->access = LSOF_FILE_ACCESS_READ;
+    else if (lcb.lla_flags & LLA_FWRITE | LLA_FREAD)
+        Lf->access = LSOF_FILE_ACCESS_READ_WRITE;
+    /*
+     * Determine the open mode, if possible.
+     */
+    if (lcb.lla_flags & LLA_IS_ETHER)
+        (void)snpf(Lf->iproto, sizeof(Lf->iproto), "Ether");
+    else if (lcb.lla_flags & (LLA_IS_8025 | LLA_IS_SNAP8025 | LLA_IS_FA8025)) {
+        (void)snpf(Lf->iproto, sizeof(Lf->iproto), "802.5");
+        if (lcb.lla_flags & LLA_IS_SNAP8025)
+            (void)snpf(Namech, Namechl, "SNAP");
+        else if (lcb.lla_flags & LLA_IS_FA8025)
+            (void)snpf(Namech, Namechl, "function address");
+    }
+    /*
+     * Add any significant flags.
+     */
+    if (lcb.lla_flags & ~(LLA_FWRITE | LLA_FREAD)) {
+        ep = endnm(&sz);
+        (void)snpf(ep, sz, "%s(flags = %#x)", (ep == Namech) ? "" : " ",
+                   lcb.lla_flags);
+    }
+    if (Namech[0])
+        enter_nm(Namech);
+}
+#endif /* DTYPE_LLA */
+
+/*
+ * process_socket() - process socket
+ */
+
+void process_socket(sa) KA_T sa; /* socket address in kernel */
+{
+    unsigned char *fa = (unsigned char *)NULL;
+    char *ep, tbuf[32];
+    int fam;
+    int fp, mbl, lp;
+    unsigned char *la = (unsigned char *)NULL;
+    struct protosw p;
+    struct socket s;
+    size_t sz;
+    struct unpcb uc, unp;
+    struct sockaddr_un *ua = (struct sockaddr_un *)NULL;
+    struct sockaddr_un un;
+
+#if HPUXV >= 800
+    struct domain d;
+
+#    if defined(HPUX_CCITT)
+    int i;
+    struct x25pcb xp;
+    struct x25pcb_extension xpe;
+#    endif /* defined(HPUX_CCITT) */
+
+#    if HPUXV < 1030
+    struct mbuf mb;
+    struct inpcb inp;
+    struct rawcb raw;
+    struct tcpcb t;
+#    else  /* HPUXV>=1030 */
+    struct datab db;
+    static char *dbf = (char *)NULL;
+    static int dbl = 0;
+    struct msgb mb;
+    struct sockbuf rb, sb;
+#    endif /* HPUXV<1030 */
+#endif     /* HPUXV>=800 */
+
+    Lf->type = LSOF_FILE_SOCKET;
+    Lf->inp_ty = 2;
+    /*
+     * Read socket structure.
+     */
+    if (!sa) {
+        enter_nm("no socket address");
+        return;
+    }
+    if (kread(ctx, (KA_T)sa, (char *)&s, sizeof(s))) {
+        (void)snpf(Namech, Namechl, "can't read socket struct from %s",
+                   print_kptr(sa, (char *)NULL, 0));
+        enter_nm(Namech);
+        return;
+    }
+    /*
+     * Read protocol switch and domain structure (HP-UX 8 and above).
+     */
+    if (!s.so_type) {
+        (void)snpf(Namech, Namechl, "no socket type");
+        enter_nm(Namech);
+        return;
+    }
+    if (!s.so_proto || kread(ctx, (KA_T)s.so_proto, (char *)&p, sizeof(p))) {
+        (void)snpf(Namech, Namechl, "no protocol switch");
+        enter_nm(Namech);
+        return;
+    }
+
+#if HPUXV >= 800
+    if (kread(ctx, (KA_T)p.pr_domain, (char *)&d, sizeof(d))) {
+        (void)snpf(Namech, Namechl, "can't read domain struct from %s",
+                   print_kptr((KA_T)p.pr_domain, (char *)NULL, 0));
+        enter_nm(Namech);
+        return;
+    }
+#endif /* HPUXV>=800 */
+
+#if HPUXV < 1030
+    /*
+     * Save size information for HP-UX < 10.30.
+     */
+    if (Lf->access == LSOF_FILE_ACCESS_READ)
+        Lf->sz = (SZOFFTYPE)s.so_rcv.sb_cc;
+    else if (Lf->access == LSOF_FILE_ACCESS_WRITE)
+        Lf->sz = (SZOFFTYPE)s.so_snd.sb_cc;
+    else
+        Lf->sz = (SZOFFTYPE)(s.so_rcv.sb_cc + s.so_snd.sb_cc);
+    Lf->sz_def = 1;
+
+#    if defined(HASTCPTPIQ)
+    Lf->lts.rq = s.so_rcv.sb_cc;
+    Lf->lts.sq = s.so_snd.sb_cc;
+    Lf->lts.rqs = Lf->lts.sqs = 1;
+#    endif /* defined(HASTCPTPIQ) */
+#endif     /* HPUXV<1030 */
+
+    /*
+     * Process socket by the associated domain family.
+     */
+
+#if HPUXV >= 800
+    switch ((fam = d.dom_family))
+#else  /* HPUXV<800 */
+    switch ((fam = p.pr_family))
+#endif /* HPUXV>=800 */
+
+    {
+
+#if HPUXV >= 800 && HPUXV < 1030 && defined(HPUX_CCITT)
+        /*
+         * Process an HP-UX [89].x CCITT X25 domain socket.
+         */
+    case AF_CCITT:
+        if (Fnet)
+            Lf->sf |= SELNET;
+        Lf->type = LSOF_FILE_X25;
+        (void)snpf(Lf->iproto, sizeof(Lf->iproto), "%.*s", IPROTOL, "CCITT");
+        /*
+         * Get the X25 PCB and its extension.
+         */
+        if (!s.so_pcb || kread(ctx, (KA_T)s.so_pcb, (char *)&xp, sizeof(xp))) {
+            (void)snpf(Namech, Namechl, "can't read x.25 pcb at %s",
+                       print_kptr((KA_T)s.so_pcb, (char *)NULL, 0));
+            enter_nm(Namech);
+            return;
+        }
+        enter_dev_ch(print_kptr((KA_T)s.so_pcb, (char *)NULL, 0));
+        if (!xp.x25pcb_extend ||
+            kread(ctx, (KA_T)xp.x25pcb_extend, (char *)&xpe, sizeof(xpe))) {
+            (void)snpf(Namech, Namechl,
+                       "can't read x.25 pcb (%s) extension at %s",
+                       print_kptr((KA_T)s.so_pcb, tbuf, sizeof(tbuf)),
+                       print_kptr((KA_T)xp.x25pcb_extend, (char *)NULL, 0));
+            enter_nm(Namech);
+            return;
+        }
+        /*
+         * Format local address.
+         */
+        for (i = 0; i < xpe.x25pcbx_local_addr.x25hostlen / 2; i++) {
+            ep = endnm(&sz);
+            (void)snpf(ep, sz, "%02x", xpe.x25pcbx_local_addr.x25_host[i]);
+        }
+        if (i * 2 != xpe.x25pcbx_local_addr.x25hostlen) {
+            ep = endnm(&sz);
+            (void)snpf(ep, sz, "%01x", xpe.x25pcbx_local_addr.x25_host[i] >> 4);
+        }
+        /*
+         * Display the virtual connection number, if it's defined.
+         */
+        if (xp.x25pcb_vcn >= 0) {
+            ep = endnm(&sz);
+            (void)snpf(ep, sz, ":%d", xp.x25pcb_vcn + 1);
+        }
+        /*
+         * Format peer address, if there is one.
+         */
+        if (xpe.x25pcbx_peer_addr.x25hostlen > 0) {
+            ep = endnm(&sz);
+            (void)snpf(ep, sz, "->");
+            for (i = 0; i < xpe.x25pcbx_peer_addr.x25hostlen / 2; i++) {
+                ep = endnm(&sz);
+                (void)snpf(ep, sz, "%02x", xpe.x25pcbx_peer_addr.x25_host[i]);
+            }
+            if (i * 2 != xpe.x25pcbx_peer_addr.x25hostlen) {
+                ep = endnm(&sz);
+                (void)snpf(ep, sz, "%01x",
+                           xpe.x25pcbx_peer_addr.x25_host[i] >> 4);
+            }
+        }
+        enter_nm(Namech);
+        break;
+#endif /* HPUXV>=800 && HPUXV<1030 && defined(HPUX_CCITT) */
+
+        /*
+         * Process an Internet domain socket.
+         */
+    case AF_INET:
+        if (Fnet)
+            Lf->sf |= SELNET;
+        Lf->type = LSOF_FILE_INET;
+        printiproto(ctx, p.pr_protocol);
+
+#if HPUXV >= 1030
+        /*
+         * Handle HP-UX 10.30 and above socket streams.
+         */
+        if (s.so_sth) {
+
+            KA_T ip, pcb;
+            char *pn = (char *)NULL;
+            /*
+             * Read module information.
+             */
+            if (read_mi((KA_T)s.so_sth, &ip, &pcb, &pn))
+                return;
+            if (ip && pcb) {
+
+                /*
+                 * If IP and TCP or UDP modules are present, process as a
+                 * stream socket.
+                 */
+                process_stream_sock(ip, pcb, pn, VNON);
+                return;
+            }
+            /*
+             * If an IP module's PCB address is present, print it as the
+             * device characters.
+             */
+
+            if (ip && !Lf->dev_def)
+                enter_dev_ch(print_kptr(ip, (char *)NULL, 0));
+            if (!strlen(Namech)) {
+
+                /*
+                 * If there are no NAME field characters, enter an error
+                 * message.
+                 */
+                if (!ip) {
+                    (void)snpf(Namech, Namechl,
+                               "no IP module for stream socket");
+                } else {
+                    (void)snpf(Namech, Namechl,
+                               "no TCP/UDP module for stream socket");
+                }
+            }
+            enter_nm(Namech);
+            return;
+        }
+#else  /* HPUXV<1030 */
+
+        /*
+         * Read protocol control block.
+         */
+        if (!s.so_pcb) {
+            enter_nm("no protocol control block");
+            return;
+        }
+        if (s.so_type == SOCK_RAW) {
+
+            /*
+             * Print raw socket information.
+             */
+            if (kread(ctx, (KA_T)s.so_pcb, (char *)&raw, sizeof(raw)) ||
+                (struct socket *)sa != (struct socket *)raw.rcb_socket) {
+                (void)snpf(Namech, Namechl, "can't read rawcb at %s",
+                           print_kptr((KA_T)s.so_pcb, (char *)NULL, 0));
+                enter_nm(Namech);
+                return;
+            }
+            enter_dev_ch(print_kptr(
+                (KA_T)(raw.rcb_pcb ? raw.rcb_pcb : s.so_pcb), (char *)NULL, 0));
+            if (raw.rcb_laddr.sa_family == AF_INET)
+                la = (unsigned char *)&raw.rcb_laddr.sa_data[2];
+            else if (raw.rcb_laddr.sa_family)
+                printrawaddr(&raw.rcb_laddr);
+            if (raw.rcb_faddr.sa_family == AF_INET)
+                fa = (unsigned char *)&raw.rcb_faddr.sa_data[2];
+            else if (raw.rcb_faddr.sa_family) {
+                ep = endnm(&sz);
+                (void)snpf(ep, sz, "->");
+                printrawaddr(&raw.rcb_faddr);
+            }
+            if (fa || la)
+                (void)ent_inaddr(la, -1, fa, -1, AF_INET);
+        } else {
+
+            /*
+             * Print Internet socket information.
+             */
+            if (kread(ctx, (KA_T)s.so_pcb, (char *)&inp, sizeof(inp))) {
+                (void)snpf(Namech, Namechl, "can't read inpcb at %s",
+                           print_kptr((KA_T)s.so_pcb, (char *)NULL, 0));
+                enter_nm(Namech);
+                return;
+            }
+            enter_dev_ch(
+                print_kptr((KA_T)(inp.inp_ppcb ? inp.inp_ppcb : s.so_pcb),
+                           (char *)NULL, 0));
+            la = (unsigned char *)&inp.inp_laddr;
+            lp = (int)ntohs(inp.inp_lport);
+            if (inp.inp_faddr.s_addr != INADDR_ANY || inp.inp_fport != 0) {
+                fa = (unsigned char *)&inp.inp_faddr;
+                fp = (int)ntohs(inp.inp_fport);
+            }
+            if (fa || la)
+                (void)ent_inaddr(la, lp, fa, fp, AF_INET);
+            if (p.pr_protocol == IPPROTO_TCP && inp.inp_ppcb &&
+                kread(ctx, (KA_T)inp.inp_ppcb, (char *)&t, sizeof(t)) == 0) {
+                Lf->lts.type = 0;
+                Lf->lts.state.i = (int)t.t_state;
+            }
+        }
+        break;
+#endif /* HPUXV>=1030 */
+
+        /*
+         * Process a Unix domain socket.
+         */
+    case AF_UNIX:
+        if (Funix)
+            Lf->sf |= SELUNX;
+        Lf->type = LSOF_FILE_UNIX;
+
+#if HPUXV >= 1030
+        /*
+         * Save size information for HP-UX 10.30 and above.
+         */
+        if (!s.so_rcv || kread(ctx, (KA_T)s.so_rcv, (char *)&rb, sizeof(rb)))
+            rb.sb_cc = 0;
+        if (!s.so_snd || kread(ctx, (KA_T)s.so_snd, (char *)&sb, sizeof(sb)))
+            sb.sb_cc = 0;
+        if (Lf->access == LSOF_FILE_ACCESS_READ)
+            Lf->sz = (SZOFFTYPE)rb.sb_cc;
+        else if (Lf->access == LSOF_FILE_ACCESS_WRITE)
+            Lf->sz = (SZOFFTYPE)sb.sb_cc;
+        else
+            Lf->sz = (SZOFFTYPE)(rb.sb_cc + sb.sb_cc);
+        Lf->sz_def = 1;
+#endif /* HPUXV>=1030 */
+
+        /*
+         * Read Unix protocol control block and the Unix address structure.
+         */
+        enter_dev_ch(print_kptr(sa, (char *)NULL, 0));
+        if (kread(ctx, (KA_T)s.so_pcb, (char *)&unp, sizeof(unp))) {
+            (void)snpf(Namech, Namechl, "can't read unpcb at %s",
+                       print_kptr((KA_T)s.so_pcb, (char *)NULL, 0));
+            break;
+        }
+        if ((struct socket *)sa != unp.unp_socket) {
+            (void)snpf(Namech, Namechl, "unp_socket (%s) mismatch",
+                       print_kptr((KA_T)unp.unp_socket, (char *)NULL, 0));
+            break;
+        }
+
+#if HPUXV < 1030
+        /*
+         * Read UNIX domain socket address information for HP-UX below 10.30.
+         */
+        if (unp.unp_addr) {
+            if (kread(ctx, (KA_T)unp.unp_addr, (char *)&mb, sizeof(mb))) {
+                (void)snpf(Namech, Namechl, "can't read unp_addr at %s",
+                           print_kptr((KA_T)unp.unp_addr, (char *)NULL, 0));
+                break;
+            }
+            ua = (struct sockaddr_un *)(((char *)&mb) + mb.m_off);
+            mbl = mb.m_len;
+        }
+#else  /* HPUXV>=1030 */
+        /*
+         * Obtain UNIX domain socket address information for HP-UX 10.30 and
+         * above.
+         */
+        if (unp.unp_ino) {
+            Lf->inode = (INODETYPE)unp.unp_ino;
+            Lf->inp_ty = 1;
+        }
+        ua = (struct sockaddr_un *)NULL;
+        mbl = 0;
+        if (unp.unp_addr &&
+            kread(ctx, (KA_T)unp.unp_addr, (char *)&mb, sizeof(mb)) == 0 &&
+            mb.b_datap &&
+            kread(ctx, (KA_T)mb.b_datap, (char *)&db, sizeof(db)) == 0) {
+            if (db.db_base) {
+                if (dbl < (db.db_size + 1)) {
+                    dbl = db.db_size + 1;
+                    if (dbf)
+                        dbf = (char *)realloc((MALLOC_P *)dbf, (MALLOC_S)dbl);
+                    else
+                        dbf = (char *)malloc((MALLOC_S)dbl);
+                    if (!dbf) {
+                        (void)fprintf(
+                            stderr,
+                            "%s: no space (%d) for UNIX socket address\n", Pn,
+                            dbl);
+                        Error(ctx);
+                    }
+                }
+                if (kread(ctx, (KA_T)db.db_base, dbf, db.db_size) == 0) {
+                    mbl = db.db_size;
+                    dbf[mbl] = '\0';
+                    ua = (struct sockaddr_un *)dbf;
+                }
+            }
+        }
+#endif /* HPUXV>=1030 */
+
+        if (!ua) {
+            ua = &un;
+            (void)bzero((char *)ua, sizeof(un));
+            ua->sun_family = AF_UNSPEC;
+        }
+        /*
+         * Print information on Unix socket that has no address bound
+         * to it, although it may be connected to another Unix domain
+         * socket as a pipe.
+         */
+        if (ua->sun_family != AF_UNIX) {
+            if (ua->sun_family == AF_UNSPEC) {
+                if (unp.unp_conn) {
+                    if (kread(ctx, (KA_T)unp.unp_conn, (char *)&uc, sizeof(uc)))
+                        (void)snpf(
+                            Namech, Namechl, "can't read unp_conn at %s",
+                            print_kptr((KA_T)unp.unp_conn, (char *)NULL, 0));
+                    else
+                        (void)snpf(
+                            Namech, Namechl, "->%s",
+                            print_kptr((KA_T)uc.unp_socket, (char *)NULL, 0));
+                } else
+                    (void)snpf(Namech, Namechl, "->(none)");
+            } else
+                (void)snpf(Namech, Namechl, "unknown sun_family (%d)",
+                           ua->sun_family);
+            break;
+        }
+        if (ua->sun_path[0]) {
+            if (mbl >= sizeof(struct sockaddr_un))
+                mbl = sizeof(struct sockaddr_un) - 1;
+            *((char *)ua + mbl) = '\0';
+            if (Sfile && is_file_named(ua->sun_path, 0))
+                Lf->sf |= SELNM;
+            if (!Namech[0])
+                (void)snpf(Namech, Namechl, "%s", ua->sun_path);
+        } else
+            (void)snpf(Namech, Namechl, "no address");
+        break;
+    default:
+        printunkaf(fam, 1);
+    }
+    if (Namech[0])
+        enter_nm(Namech);
+}
+
+#if HPUXV >= 1030
+/*
+ * process_stream_sock() - process stream socket
+ */
+
+void process_stream_sock(ip, pcb, pn, vt) KA_T ip; /* IP module's q_ptr */
+KA_T pcb;                                          /* protocol's q_ptr */
+char *pn;                                          /* protocol name */
+enum vtype vt;                                     /* vnode type */
+{
+    unsigned char *fa = (unsigned char *)NULL;
+    char *ep;
+    int fp, lp, rq, sq;
+    struct ipc_s ic;
+    unsigned char *la = (unsigned char *)NULL;
+    size_t sz;
+    u_short pt;
+    struct tcp_s tc;
+    tcph_t th;
+    struct udp_s ud;
+    /*
+     * Set file type and protocol.  If AF_INET selection is in effect, set its
+     * flag.
+     */
+    if (Fnet)
+        Lf->sf |= SELNET;
+    Lf->type = LSOF_FILE_INET;
+    if (pn) {
+        (void)snpf(Lf->iproto, sizeof(Lf->iproto), pn);
+        Lf->inp_ty = 2;
+    } else if (Sfile && (vt != VNON) && Lf->dev_def && (Lf->inp_ty == 1)) {
+
+        /*
+         * If the protocol name isn't known and this stream socket's vnode type
+         * isn't VNON, the stream socket will be handled mostly as a stream.
+         * Thus, a named file check is appropriate.
+         */
+        if (is_file_named((char *)NULL, (vt == VCHR) ? 1 : 0))
+            Lf->sf |= SELNM;
+    }
+    /*
+     * Get IP structure.
+     */
+    *Namech = '\0';
+    if (!ip || kread(ctx, ip, (char *)&ic, sizeof(ic))) {
+        ep = endnm(&sz);
+        (void)snpf(ep, sz, "%scan't read IP control structure from %s",
+                   sz ? " " : "", print_kptr(ip, (char *)NULL, 0));
+        enter_nm(Namech);
+        return;
+    }
+    if (!Lf->dev_def)
+        enter_dev_ch(print_kptr(ip, (char *)NULL, 0));
+    /*
+     * Check for protocol control block address.  Enter if non-NULL and clear
+     * device definition flag.
+     */
+    if (!pcb) {
+        ep = endnm(&sz);
+        (void)snpf(ep, sz, "%ssocket stream has no TCP or UDP module",
+                   sz ? " " : "");
+        enter_nm(Namech);
+        return;
+    }
+    /*
+     * Select processing by protocol name.
+     */
+    if (pn && !strcmp(pn, "TCP")) {
+
+        /*
+         * Process TCP socket.
+         */
+        if (kread(ctx, pcb, (char *)&tc, sizeof(tc))) {
+            ep = endnm(&sz);
+            (void)snpf(ep, sz, "%scan't read TCP PCB from %s", sz ? " " : "",
+                       print_kptr(pcb, (char *)NULL, 0));
+            enter_nm(Namech);
+            return;
+        }
+        /*
+         * Save TCP address.
+         */
+        la = (unsigned char *)&ic.ipc_tcp_laddr;
+        pt = (u_short)ic.ipc_tcp_lport;
+        if (((struct in_addr *)la)->s_addr == INADDR_ANY && pt == 0) {
+
+            /*
+             * If the ipc_s structure has no local address, use the local
+             * address in its tcp_iph structure, and the port number in its
+             * tcph structure.
+             */
+            la = (unsigned char *)&tc.tcp_u.tcp_u_iph.iph_src[0];
+            if (tc.tcp_hdr_len && tc.tcp_tcph &&
+                kread(ctx, (KA_T)tc.tcp_tcph, (char *)&th, sizeof(th)) == 0)
+                pt = (u_short)th.th_lport;
+        }
+        lp = (int)ntohs(pt);
+        if ((int)ic.ipc_tcp_faddr != INADDR_ANY ||
+            (u_short)ic.ipc_tcp_fport != 0) {
+            fa = (unsigned char *)&ic.ipc_tcp_faddr;
+            fp = (int)ntohs((u_short)ic.ipc_tcp_fport);
+        }
+        if (fa || la)
+            (void)ent_inaddr(la, lp, fa, fp, AF_INET);
+        /*
+         * Save TCP state and size information.
+         */
+        Lf->lts.type = 0;
+        Lf->lts.state.i = (int)tc.tcp_state;
+
+#    if defined(HASTCPTPIQ) || defined(HASTCPTPIW)
+#        if defined(HASTCPTPIW)
+        Lf->lts.rw = (int)tc.tcp_rwnd;
+        Lf->lts.ww = (int)tc.tcp_swnd;
+        Lf->lts.rws = Lf->lts.wws = 1;
+#        endif /* defined(HASTCPTPIW) */
+
+        if ((rq = (int)tc.tcp_rnxt - (int)tc.tcp_rack - 1) < 0)
+            rq = 0;
+        if ((sq = (int)tc.tcp_snxt - (int)tc.tcp_suna - 1) < 0)
+            sq = 0;
+
+#        if defined(HASTCPTPIQ)
+        Lf->lts.rq = (unsigned long)rq;
+        Lf->lts.sq = (unsigned long)sq;
+        Lf->lts.rqs = Lf->lts.sqs = 1;
+#        endif /* defined(HASTCPTPIQ) */
+
+        if (Lf->access == LSOF_FILE_ACCESS_READ)
+            Lf->sz = (SZOFFTYPE)rq;
+        else if (Lf->access == LSOF_FILE_ACCESS_WRITE)
+            Lf->sz = (SZOFFTYPE)sq;
+        else
+            Lf->sz = (SZOFFTYPE)(rq + sq);
+        Lf->sz_def = 1;
+
+#    endif /* defined(HASTCPTPIQ) || defined(HASTCPTPIW) */
+
+#    if defined(HASTCPOPT)
+
+        /*
+         * Save TCP options and values..
+         */
+        if (tc.tcp_naglim == (uint)1)
+            Lf->lts.topt |= TF_NODELAY;
+        Lf->lts.mss = (unsigned long)tc.tcp_mss;
+        Lf->lts.msss = (unsigned char)1;
+#    endif /* defined(HASTCPOPT) */
+
+#    if defined(HASSOOPT)
+
+        /*
+         * Save socket options.
+         */
+        if (tc.tcp_broadcast)
+            Lf->lts.opt |= SO_BROADCAST;
+        if (tc.tcp_so_debug)
+            Lf->lts.opt |= SO_DEBUG;
+        if (tc.tcp_dontroute)
+            Lf->lts.opt |= SO_DONTROUTE;
+        if (tc.tcp_keepalive_intrvl && (tc.tcp_keepalive_intrvl != 7200000)) {
+            Lf->lts.opt |= SO_KEEPALIVE;
+            Lf->lts.kai = (unsigned int)tc.tcp_keepalive_intrvl;
+        }
+        if (tc.tcp_lingering) {
+            Lf->lts.opt |= SO_LINGER;
+            Lf->lts.ltm = (unsigned int)tc.tcp_linger;
+        }
+        if (tc.tcp_oobinline)
+            Lf->lts.opt |= SO_OOBINLINE;
+        if (tc.tcp_reuseaddr)
+            Lf->lts.opt |= SO_REUSEADDR;
+        if (tc.tcp_reuseport)
+            Lf->lts.opt |= SO_REUSEPORT;
+        if (tc.tcp_useloopback)
+            Lf->lts.opt |= SO_USELOOPBACK;
+        Lf->lts.qlen = (unsigned int)tc.tcp_conn_ind_cnt;
+        Lf->lts.qlim = (unsigned int)tc.tcp_conn_ind_max;
+        if (Lf->lts.qlen || Lf->lts.qlim)
+            Lf->lts.qlens = Lf->lts.qlims = (unsigned char)1;
+#    endif /* defined(HASSOOPT) */
+
+        Namech[0] = '\0';
+        return;
+    } else if (pn && !strcmp(pn, "UDP")) {
+
+        /*
+         * Process UDP socket.
+         */
+        if (kread(ctx, pcb, (char *)&ud, sizeof(ud))) {
+            ep = endnm(&sz);
+            (void)snpf(ep, sz, "%scan't read UDP PCB from %s", sz ? " " : "",
+                       print_kptr(pcb, (char *)NULL, 0));
+            enter_nm(Namech);
+            return;
+        }
+        /*
+         * Save UDP address and TPI state.
+         */
+        la = (unsigned char *)&ic.ipc_udp_addr;
+        pt = (u_short)ic.ipc_udp_port;
+        if (((struct in_addr *)la)->s_addr == INADDR_ANY && pt == 0) {
+
+            /*
+             * If the ipc_s structure has no local address, use the one in the
+             * udp_s structure.
+             */
+            pt = (u_short)ud.udp_port[0];
+        }
+        (void)ent_inaddr(la, (int)ntohs(pt), (unsigned char *)NULL, -1,
+                         AF_INET);
+        Lf->lts.type = 1;
+        Lf->lts.state.ui = (unsigned int)ud.udp_state;
+        Namech[0] = '\0';
+        return;
+    } else {
+
+        /*
+         * Record an unknown protocol.
+         */
+        ep = endnm(&sz);
+        (void)snpf(ep, sz, "%sunknown stream protocol: %s", sz ? " " : "",
+                   pn ? pn : "NUll");
+    }
+    if (Namech[0])
+        enter_nm(Namech);
+}
+#endif /* HPUXV>=1030 */
diff --git a/lib/dialects/hpux/kmem/dstore.c b/lib/dialects/hpux/kmem/dstore.c
new file mode 100644 (file)
index 0000000..74415ee
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * dstore.c - /dev/kmem-based HP-UX global storage for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#ifndef lint
+static char copyright[] =
+    "@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
+#endif
+
+#include "common.h"
+
+/*
+ * Global storage definitions
+ */
+
+#if defined(HAS_AFS)
+
+#    if defined(HASAOPT)
+char *AFSApath = (char *)NULL; /* alternate AFS name list path
+                                * (from -A) */
+#    endif                     /* defined(HASAOPT) */
+
+struct vfs *AFSVfsp = (struct vfs *)NULL;
+/* AFS vfs struct kernel address */
+#endif /* defined(HAS_AFS) */
+
+int CloneMaj; /* clone major device number */
+
+/*
+ * Drive_Nl -- table to drive the building of Nl[] via build_Nl()
+ *             (See lsof.h and misc.c.)
+ */
+
+struct drive_Nl Drive_Nl[] = {
+
+#if defined(hp9000s300) || defined(__hp9000s300)
+    {"arFid", "_afs_rootFid"},
+    {"avops", "_afs_vnodeops"},
+    {"avol", "_afs_volumes"},
+    {X_NCACHE, "_ncache"},
+    {X_NCSIZE, "_ncsize"},
+    {"proc", "_proc"},
+    {"nvops", "_nfs_vnodeops"},
+    {"nvops3", "_nfs_vnodeops3"},
+    {"nv3ops", "_nfs3_vnodeops"},
+    {"nproc", "_nproc"},
+    {"uvops", "_ufs_vnodeops"},
+    {"vfops", "_vnodefops"},
+
+#    if HPUXV < 800
+    {"upmap", "_Usrptmap"},
+    {"upt", "_usrpt"},
+#    endif /* HPUXV<800 */
+#endif     /* defined(hp9000s300) || defined(__hp9000s300) */
+
+#if defined(hp9000s800) || defined(__hp9000s800)
+    {"arFid", "afs_rootFid"},
+    {"avops", "afs_vnodeops"},
+    {"avol", "afs_volumes"},
+    {X_NCACHE, "ncache"},
+    {X_NCSIZE, "ncsize"},
+    {"proc", "proc"},
+    {"nvops", "nfs_vnodeops"},
+    {"nvops3", "nfs_vnodeops3"},
+    {"nv3ops", "nfs3_vnodeops"},
+    {"nproc", "nproc"},
+    {"uvops", "ufs_vnodeops"},
+    {"vfops", "vnodefops"},
+
+#    if HPUXV < 800
+    {"ubase", "ubase"},
+    {"npids", "npids"},
+#    else /* HPUXV>=800 */
+#        if HPUXV >= 1000
+#            if HPUXV >= 1030
+    {"clmaj", "clonemajor"},
+#            endif /* HPUXV>=1030 */
+    {"cvops", "cdfs_vnodeops"},
+    {"fvops", "fifo_vnodeops"},
+    {"pvops", "pipe_vnodeops"},
+    {"svops", "spec_vnodeops"},
+    {"vvops", "vx_vnodeops"},
+#        endif     /* HPUXV>=1000 */
+#    endif         /* HPUXV<800 */
+#endif             /* defined(hp9000s800) || defined(__hp9000s800) */
+
+    {"mvops", "mvfs_vnodeops"},
+
+#if HPUXV >= 1100
+    {"chunksz", "sizeof_fd_chunk_t"},
+#endif /* HPUXV>=1100 */
+
+    {"", ""},
+    {NULL, NULL}};
+
+int HaveCloneMaj = 0; /* CloneMaj status */
+int Kd = -1;          /* /dev/kmem file descriptor */
+KA_T Kpa;             /* kernel proc structure address */
+
+#if HPUXV >= 1010
+KA_T Ktp; /* kernel thread pointer from proc
+           * struct */
+#endif    /* HPUXV>=1010 */
+
+struct l_vfs *Lvfs = NULL; /* local vfs structure table */
+
+#if HPUXV < 800
+int Mem = -1; /* /dev/mem file descriptor */
+#endif        /* HPUXV<800 */
+
+#if HPUXV < 800 && defined(hp9000s800)
+int npids;         /* number of PIDs (for uvadd()) */
+struct proc *proc; /* process table address (for uvadd()) */
+#endif             /* HPUXV<800 && defined(hp9000s300) */
+
+#if defined(HASFSTRUCT)
+/*
+ * Pff_tab[] - table for printing file flags
+ */
+
+struct pff_tab Pff_tab[] = {
+    {(long)FREAD, FF_READ},           {(long)FWRITE, FF_WRITE},
+    {(long)FNDELAY, FF_NDELAY},       {(long)FAPPEND, FF_APPEND},
+    {(long)FMARK, FF_MARK},           {(long)FDEFER, FF_DEFER},
+    {(long)FNBLOCK, FF_NBLOCK},       {(long)FNOCTTY, FF_NOCTTY},
+
+#    if defined(FSYNC)
+    {(long)FSYNC, FF_SYNC},
+#    else /* !defined(FSYNC) */
+#        if defined(O_SYNC)
+    {(long)O_SYNC, FF_SYNC},
+#        endif /* defined(O_SYNC) */
+#    endif     /* defined(FSYNC) */
+
+#    if defined(FCOPYAVOID)
+    {(long)FCOPYAVOID, FF_COPYAVOID},
+#    endif /* defined(FCOPYAVOID) */
+
+#    if defined(FPOSIX_AIO)
+    {(long)FPOSIX_AIO, FF_POSIX_AIO},
+#    endif /* defined(FPOSIX_AIO) */
+
+#    if defined(FLARGEFILE)
+    {(long)FLARGEFILE, FF_LARGEFILE},
+#    else /* !defined(FLARGEFILE) */
+#        if HPUXV >= 1100
+    {(long)0x800, FF_LARGEFILE},
+#        endif /* HPUXV>=1100 */
+#    endif     /* defined(FLARGEFILE) */
+
+    {(long)0x100, FF_KERNEL},         {(long)0, NULL}};
+
+/*
+ * Pof_tab[] - table for print process open file flags
+ */
+
+#    if HPUXV >= 1020
+#        define UF_EXCLOSE 0x1
+#        define UF_MAPPED 0x2
+#        define UF_FDLOCK 0x4
+#        define UF_INUSE 0x8
+#    endif /* HPUXV>=1020 */
+
+struct pff_tab Pof_tab[] = {
+
+#    if defined(UF_EXCLOSE)
+    {(long)UF_EXCLOSE, POF_CLOEXEC},
+#    endif /* defined(UF_EXCLOSE) */
+
+#    if defined(UF_MAPPED)
+    {(long)UF_MAPPED, POF_MAPPED},
+#    endif /* defined(UF_MAPPED) */
+
+#    if defined(UF_FDLOCK)
+    {(long)UF_FDLOCK, POF_FDLOCK},
+#    endif /* defined(UF_FDLOCK) */
+
+#    if defined(UF_INUSE)
+    {(long)UF_INUSE, POF_INUSE},
+#    endif /* defined(UF_INUSE) */
+
+    {(long)0, NULL}};
+#endif /* defined(HASFSTRUCT) */
+
+#if HPUXV < 800
+int Swap = -1; /* swap device file descriptor */
+#endif         /* HPUXV<800 */
+
+#if HPUXV < 800 && defined(hp9000s800)
+struct user *ubase; /* user area base (for uvadd()) */
+#endif              /* HPUXV<800 && defined(hp9000s800) */
+
+#if HPUXV < 800 && defined(hp9000s300)
+struct user *ubase;   /* user area base (for uvadd()) */
+struct pte *Usrptmap; /* user page table map pointer */
+struct pte *usrpt;    /* user page table pointer
+                       * (for bktomx from vmmac.h) */
+#endif                /* HPUXV<800 && defined(hp9000s300) */
+
+KA_T Vnfops; /* vnodefops switch address */
diff --git a/lib/dialects/hpux/kmem/hpux11/ipc_s.h b/lib/dialects/hpux/kmem/hpux11/ipc_s.h
new file mode 100644 (file)
index 0000000..d641295
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * ipc_s.h for HP-UX 10.30 and above
+ *
+ * This header file defines the ipc_s structure for lsof.  The ipc_s structure
+ * is the streams equivalent of a Berkeley-style inpcb (Internet Protocol
+ * Control Block).  The ipc_s holds the TCP/IP address for a stream.
+ *
+ * The original HP-UX 11 distribution has a flat ipc_s structure, with hash
+ * links to other ipc_s structures, and direct links to the the read and write
+ * sections of the stream.
+ *
+ * After patch bundle B11.00.43 the ipc_s structure definition requires
+ * two other Q4-derived structures, mirg_s and ipis_s.  The ipis_s structure
+ * contains the hash and stream links formerly contained in ipc_s.
+ *
+ * V. Abell <abe@purdue.edu>
+ * February, 1998
+ *
+ * Patch bundle update supplied by: Kevin Vajk <kvajk@cup.hp.com>
+ *                                 February, 1999
+ */
+
+#if !defined(LSOF_IPC_S_H)
+#    define LSOF_IPC_S_H
+
+#    include "kernbits.h"
+#    include <sys/types.h>
+
+typedef struct mirg_s {
+    uint mirg_gen;
+} mirg_t;
+
+#    if defined(HAS_IPC_S_PATCH)
+typedef struct ipis_s {
+    union {
+        KA_T u_ipc_hash_next;
+        KA_T u_ill_hash_next;
+        KA_T u_ipis_hash_next;
+    } ipis_hash_next_u;
+    union {
+        KA_T u_ipc_ptphn;
+        KA_T u_ill_ptphn;
+        KA_T u_ipis_ptphn;
+    } ipis_ptphn_u;
+    KA_T ipis_readers_next;
+    KA_T ipis_readers_ptpn;
+    KA_T ipis_ptr_hash_next;
+    KA_T ipis_ptr_ptphn;
+    KA_T ipis_rq;
+    KA_T ipis_wq;
+    mirg_t ipis_mirg;
+#        if HAS_IPC_S_PATCH == 2
+    uint ipis_msgsqueued;
+#        endif /* HAS_IPC_S_PATCH==2 */
+} ipis_t;
+#    endif /* defined(HAS_IPC_S_PATCH) */
+
+typedef struct ipc_s {
+
+#    if defined(HAS_IPC_S_PATCH)
+    ipis_t ipc_ipis;
+#    else  /* !defined(HAS_IPC_S_PATCH) */
+    KA_T ipc_hash_next; /* hash link -- ipc_s
+                         * structures are hashed in
+                         * ipc_tcp_conn[] and
+                         * ipc_udp_conn[] */
+    mirg_t ipc_mirg;
+    KA_T ipc_readers_next;
+    KA_T ipc_readers_ptpn;
+    KA_T ipc_ptphn;
+    KA_T ipc_rq; /* stream's read queue */
+    KA_T ipc_wq; /* stream's write queue */
+#    endif /* defined(HAS_IPC_S_PATCH) */
+
+    int ipc_ioctl_pended;
+    union {
+        struct {
+            uint32_t ipcu_lcl_addr; /* local IP address */
+            uint32_t ipcu_rem_addr; /* remote IP address */
+            uint16_t ipcu_rem_port; /* remote port */
+            uint16_t ipcu_lcl_port; /* local port */
+        } ipcu_addrs;
+        uint16_t ipcu_tcp_addr[6];
+    } ipc_ipcu;
+    /*
+     * The rest of the q4 elements are ignored.
+     */
+
+} ipc_s_t;
+
+#    define ipc_udp_port ipc_ipcu.ipcu_addrs.ipcu_lcl_port
+#    define ipc_udp_addr ipc_ipcu.ipcu_addrs.ipcu_lcl_addr
+#    define ipc_tcp_lport ipc_ipcu.ipcu_addrs.ipcu_lcl_port
+#    define ipc_tcp_laddr ipc_ipcu.ipcu_addrs.ipcu_lcl_addr
+#    define ipc_tcp_fport ipc_ipcu.ipcu_addrs.ipcu_rem_port
+#    define ipc_tcp_faddr ipc_ipcu.ipcu_addrs.ipcu_rem_addr
+
+#endif /* !defined(LSOF_IPC_S_H) */
diff --git a/lib/dialects/hpux/kmem/hpux11/kernbits.h b/lib/dialects/hpux/kmem/hpux11/kernbits.h
new file mode 100644 (file)
index 0000000..2abea80
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * kernbits.h for HP-UX 10.30 and above
+ *
+ * This header file defines the basic kernel word size type for lsof, using
+ * the Configure-generated -DHPUXKERNBITS=<32|64> definition.
+ *
+ * V. Abell
+ * February, 1998
+ */
+
+#if !defined(LSOF_KERNBITS_H)
+#    define LSOF_KERNBITS_H
+
+#    if !defined(HPUXKERNBITS) || HPUXKERNBITS < 64
+typedef uint32_t KA_T;
+#        define KA_T_FMT_X "%#lx"
+#    else /* defined(HPUXKERNBITS) && HPUXKERNBITS>=64 */
+typedef uint64_t KA_T;
+#        define KA_T_FMT_X "%#llx"
+#    endif /* !defined(HPUXKERNBITS) || HPUXKERNBITS<64 */
+
+#endif /* !defined(LSOF_KERNBITS_H) */
diff --git a/lib/dialects/hpux/kmem/hpux11/lla.h b/lib/dialects/hpux/kmem/hpux11/lla.h
new file mode 100644 (file)
index 0000000..a6fec9b
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * lla.h for HP-UX 10.30 and above
+ *
+ * This header file defines the lla_cb structure for lsof.  Lsof uses it to
+ * to read the Link Level Access (LLA) control block.  Link level access means
+ * access to the network link layer access protocol -- e.g., Ethernet 802.5.
+ *
+ * V. Abell <abe@purdue.edu>
+ * February, 1998
+ */
+
+#if !defined(LSOF_LLA_H)
+#    define LSOF_LLA_H
+
+#    include "kernbits.h"
+#    include <sys/types.h>
+
+#    define LLA_IS_ETHER 0x1
+#    define LLA_FWRITE 0x100
+#    define LLA_FREAD 0x200
+#    define LLA_IS_8025 0x800
+#    define LLA_IS_SNAP8025 0x1000
+#    define LLA_IS_FA8025 0x4000
+
+typedef struct lla_hdr {
+    union {
+        struct {
+            u_char destaddr[6];
+            u_char sourceaddr[6];
+            u_short length;
+            u_char dsap;
+            u_char ssap;
+            u_char ctrl;
+            u_char pad[3];
+            u_short dxsap;
+            u_short sxsap;
+        } ieee;
+        struct {
+            u_char destaddr[6];
+            u_char sourceaddr[6];
+            u_short log_type;
+            u_short dxsap;
+            u_short sxsap;
+        } ether;
+        struct {
+            u_char access_ctl;
+            u_char frame_ctl;
+            u_char destaddr[6];
+            u_char sourceaddr[6];
+            u_char rif_plus[26];
+            u_char dsap;
+            u_char ssap;
+            u_char ctrl;
+            u_char orgid[3];
+            u_short etype;
+        } snap8025;
+        struct {
+            u_char access_ctl;
+            u_char frame_ctl;
+            u_char destaddr[6];
+            u_char sourceaddr[6];
+            u_char rif_plus[26];
+            u_char dsap;
+            u_char ssap;
+            u_char ctrl;
+        } ieee8025;
+    } proto;
+} lla_hdr_t;
+
+typedef struct lla_cb {
+    KA_T so_pcb;
+    KA_T pktheader;
+    KA_T head_packet;
+    KA_T last_packet;
+    KA_T lla_ifp;
+    u_int lan_signal_mask;
+    u_int lan_signal_pid;
+    int lan_pkt_size;
+    int lla_timeo;
+    KA_T lla_rsel;
+    struct lla_hdr packet_header;
+    short lla_msgsqd;
+    short lla_maxmsgs;
+    u_short lla_flags; /* flags, including type  -- i.e.,
+                        * the LLA_* symbols defined above */
+    short hdr_size;
+    int func_addr;
+    KA_T lla_lock;
+} lla_cb_t;
+
+#endif
diff --git a/lib/dialects/hpux/kmem/hpux11/nfs_clnt.h b/lib/dialects/hpux/kmem/hpux11/nfs_clnt.h
new file mode 100644 (file)
index 0000000..5978855
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * nfs_clnt.h for HP-UX 10.30 and above
+ *
+ * This header file defines the mntinfo structure for lsof.  Lsof uses it to
+ * obtain the device number of an NFS mount point.
+ *
+ * V. Abell
+ * February, 1998
+ */
+
+#if !defined(LSOF_NFS_CLNT_H)
+#    define LSOF_NFS_CLNT_H
+
+#    include "kernbits.h"
+#    include "rnode.h"
+#    include <rpc/types.h>
+#    undef TCP_NODELAY
+#    undef TCP_MAXSEG
+#    include <rpc/rpc.h>
+#    include <rpc/clnt.h>
+#    include <sys/xti.h>
+#    undef TCP_NODELAY
+#    undef TCP_MAXSEG
+
+typedef struct kcondvar {
+    uint32_t _dummy1[6];
+} kcondvar_t;
+
+typedef struct mntinfo {
+    kmutex_t mi_lock;
+    KA_T mi_knetconfig;
+    struct netbuf mi_addr;
+    struct netbuf mi_syncaddr;
+    KA_T mi_rootvp;
+    uint32_t mi_flags;
+    int32_t mi_tsize;
+    int32_t mi_stsize;
+    int32_t mi_timeo;
+    int32_t mi_retrans;
+    char mi_hostname[32];
+    KA_T mi_netname;
+    int mi_netnamelen;
+    int mi_authflavor;
+    int32_t mi_acregmin;
+    int32_t mi_acregmax;
+    int32_t mi_acdirmin;
+    int32_t mi_acdirmax;
+    struct rpc_timers mi_timers[4];
+    int32_t mi_curread;
+    int32_t mi_curwrite;
+    KA_T mi_async_reqs;
+    KA_T mi_async_tail;
+    kcondvar_t mi_async_reqs_cv;
+    uint16_t mi_threads;
+    uint16_t mi_max_threads;
+    kcondvar_t mi_async_cv;
+    uint32_t mi_async_count;
+    kmutex_t mi_async_lock;
+    KA_T mi_pathconf;
+    u_long mi_prog;
+    u_long mi_vers;
+    KA_T mi_rfsnames;
+    KA_T mi_reqs;
+    KA_T mi_call_type;
+    KA_T mi_timer_type;
+    clock_t mi_printftime;
+    KA_T mi_aclnames;
+    KA_T mi_aclreqs;
+    KA_T mi_acl_call_type;
+    KA_T mi_acl_timer_type;
+    char mi_fsmnt[512];
+    uint64_t mi_maxfilesize;
+    dev_t mi_mntno; /* mounted device number */
+} mntinfo_t;
+
+#endif /* !defined(LSOF_NFS_CLNT_H) */
diff --git a/lib/dialects/hpux/kmem/hpux11/proc.h b/lib/dialects/hpux/kmem/hpux11/proc.h
new file mode 100644 (file)
index 0000000..a1be13f
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * proc.h for Hp-UX 10.30 and above
+ *
+ * This header file defines the proc structure for lsof.  Lsof uses it to
+ * get process information, including PGID, PID, PPID, UID, CWD, and open
+ * file pointers.
+ *
+ * V. Abell <abe@purdue.edu>
+ * February, 1998
+ */
+
+#if !defined(LSOF_PROC_H)
+#    define LSOF_PROC_H
+
+#    include "kernbits.h"
+#    include <sys/types.h>
+#    include <sys/resource.h>
+#    include <sys/user.h>
+
+struct pprof {
+    KA_T pr_base;
+    u_long pr_size;
+    u_long pr_off;
+    u_int pr_scale;
+};
+
+typedef enum proc_flag {
+    SLOAD = 0x1,
+    SSYS = 0x2,
+    SDONTTRC = 0x4,
+    STRC = 0x8,
+    SWTED_PARENT = 0x10,
+    SDEACTSELF = 0x20,
+    SPVFORK = 0x40,
+    SWEXIT = 0x80,
+    SPGID_EXIT_ADJUSTED = 0x100,
+    SVFORK = 0x200,
+    SWANTS_ALLCPU = 0x400,
+    SSERIAL = 0x800,
+    SDEACT = 0x1000,
+    SWAITIO = 0x2000,
+    SWTED_DEBUGGER = 0x4000,
+    SWCONT = 0x8000,
+    SDBG_CREATING = 0x10000,
+    SDBG_WAITING = 0x20000,
+    SDBG_ACTIVE = 0x40000,
+    SDBG_LIMBO = 0x80000,
+    SDBG_ATTACHING = 0x100000,
+    SDBG_EXITING = 0x200000,
+    SDBG_KILLED = 0x400000,
+    SDBG_INEXEC = 0x800000,
+    SDBG_TRACESELF = 0x1000000,
+    SDBG_STOPPED = 0x2000000,
+    SDBG_EXITREQ = 0x4000000,
+    SREAPING = 0x10000000
+} proc_flag_t;
+
+typedef enum proc_flag2 {
+    S2CLDSTOP = 0x1,
+    S2EXEC = 0x2,
+    SGRAPHICS = 0x4,
+    SADOPTIVE = 0x8,
+    SADOPTIVE_WAIT = 0x10,
+    SPMT = 0x40,
+    S2SENDDILSIG = 0x100,
+    SLKDONE = 0x200,
+    SISNFSLM = 0x400,
+    S2POSIX_NO_TRUNC = 0x800,
+    S2SYSCALL_BYPID = 0x1000,
+    S2ADOPTEE = 0x2000,
+    SCRITICAL = 0x4000,
+    SMULTITHREADED = 0x8000,
+    S2NOCLDWAIT = 0x10000,
+    S_USE_THRD_CACHE = 0x20000,
+    S2PASS_VIOREF = 0x40000,
+    S2VIOREF_NPROC = 0x80000,
+    SUSRMULTITHREADED = 0x100000
+} proc_flag2_t;
+
+typedef enum proc_state {
+    SUNUSED = 0,
+    SWAIT = 0x1,
+    SIDL = 0x2,
+    SZOMB = 0x3,
+    SSTOP = 0x4,
+    SINUSE = 0x5
+} proc_state_t;
+
+typedef enum proc_sync_flag {
+    P_OP_PENDING_READER = 0x1,
+    P_OP_PENDING_WRITER = 0x2
+} proc_sync_flag_t;
+
+typedef enum proc_sync_reason {
+    P_OP_NONE = 0,
+    P_OP_THREAD_MGMT = 0x1,
+    P_OP_EXIT = 0x2,
+    P_OP_EXEC = 0x3,
+    P_OP_SUSPEND = 0x4,
+    P_OP_CONTINUE = 0x5,
+    P_OP_SIGTRAP = 0x6,
+    P_OP_FORK = 0x7,
+    P_OP_VFORK = 0x8,
+    P_OP_CORE = 0x9,
+    KT_OP_SUSPEND = 0xa,
+    KT_OP_RESUME = 0xb,
+    KT_OP_CREATE = 0xc,
+    KT_OP_TERMINATE = 0xd,
+    KT_OP_LWPEXIT = 0xe,
+    KT_OP_ABORT_SYSCALL = 0xf
+} proc_sync_reason_t;
+
+typedef struct proc {
+    short p_fandx;
+    short p_pandx;
+    int p_created_threads;
+    KA_T p_firstthreadp; /* thread pointer (for locks) */
+    KA_T p_lastthreadp;
+    proc_flag_t p_flag;
+    KA_T thread_lock;
+    KA_T p_lock;
+    KA_T p_detached_zombie;
+    KA_T p_fss;
+    proc_state_t p_stat; /* process state */
+    char p_nice;
+    u_short p_pri;
+    int p_livethreads;
+    int p_cached_threads_count;
+    int p_cached_threads_max;
+    KA_T p_cached_threads;
+    KA_T p_cache_next;
+    KA_T p_cache_prev;
+    ksigset_t p_sig;
+    ksigset_t p_ksi_avail;
+    ksigset_t p_ksifl_alloced;
+    KA_T p_ksiactive;
+    KA_T p_ksifree;
+    KA_T p_sigcountp;
+    KA_T p_sigwaiters;
+    int p_cursig;
+    proc_flag2_t p_flag2;
+    int p_coreflags;
+    uid_t p_uid; /* user ID (UID) of process owner */
+    uid_t p_suid;
+    KA_T p_pgid_p;
+    gid_t p_pgid;
+    pid_t p_pid;  /* process ID (PID) */
+    pid_t p_ppid; /* parent process ID (PPID) */
+    size_t p_maxrss;
+    short p_idhash;
+    short p_ridhash;
+    short p_pgidhx;
+    short p_rpgidhx;
+    short p_uidhx;
+    short p_ruidhx;
+    KA_T p_pptr;
+    KA_T p_cptr;
+    KA_T p_osptr;
+    KA_T p_ysptr;
+    KA_T p_dptr;
+    KA_T p_vas; /* pointer to VM for process */
+    short p_memresv;
+    short p_swpresv;
+    short p_sysmemresv;
+    short p_sysswpresv;
+    u_short p_xstat;
+    time_t p_deactime;
+    short p_ndx;
+    sid_t p_sid;
+    short p_sidhx;
+    short p_rsidhx;
+    short p_idwrite;
+    KA_T p_semundo;
+    KA_T p_dbipcp;
+    u_char p_cookie;
+    u_char p_reglocks;
+    int p_no_swap_count;
+    dev_t p_ttyd;
+    KA_T p_ttyp;
+    KA_T p_nextdeact;
+    time_t p_start;
+    KA_T p_shadproc;
+    KA_T p_bor_lock;
+    int p_maxof;   /* maximum open files */
+    KA_T p_cdir;   /* pointer to CWD vnode */
+    KA_T p_rdir;   /* pointer to root directory vnode */
+    KA_T p_ofilep; /* pointer to ofile_t chain */
+    KA_T p_vforkbuf;
+    u_int p_schedpolicy;
+    u_short p_pindx;
+    KA_T p_krusagep;
+    KA_T p_timers;
+    KA_T p_clic;
+    proc_sync_reason_t p_sync_reason;
+    void (*p_wide_action_hdlr)();
+    proc_sync_flag_t p_sync_flag;
+    ushort p_sync_readers;
+    ushort p_sync_writers;
+    u_int p_sync_thread_cnt;
+    int p_suspended_threads;
+    int p_captr;
+    union {
+        struct {
+            u_int zombies_exist : 1, recalc_privgrps : 1, unused : 30;
+        } bits;
+        u_int all;
+    } p_pl_flags;
+    u_int p_seqnum;
+    spu_t p_spu_group;
+    u_char p_spu_mandatory;
+    KA_T p_cred;
+    caddr_t p_ki_bitmap;
+    KA_T p_aioqp;
+    KA_T p_shared;
+    KA_T p_nseminfop;
+    KA_T p_mqpinfop;
+    KA_T p_dbgctltp;
+    KA_T p_dbgp;
+    KA_T p_trcp;
+    KA_T p_p2p;
+    KA_T p_gang;
+    u_int p_pmon_timer_mask;
+    u_int p_pmon_inherit;
+    u_long p_pmon_state_flag;
+    u_long p_pmon_state_value;
+    KA_T p_cnx_features;
+    char p_comm[15];
+    aid_t p_aid;
+    short p_audproc;
+    short p_audsusp;
+    gid_t p_sgid;
+    u_int p_priv[2];
+    int p_highestfd;
+    short p_cmask;
+    time_t p_ticks;
+    short p_acflag;
+    struct rlimit p_rlimit[11];
+    KA_T p_auditperproc;
+    struct pprof p_prof;
+    char p_spare[48];
+} proc_t;
+
+#endif /* !defined(LSOF_PROC_H) */
diff --git a/lib/dialects/hpux/kmem/hpux11/rnode.h b/lib/dialects/hpux/kmem/hpux11/rnode.h
new file mode 100644 (file)
index 0000000..c32d809
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * rnode.h for HP-UX 10.30 and above
+ *
+ * This header file defines the rnode structure for lsof.  Lsof uses it to get
+ * infomation about remote (NFS) nodes -- e.g., node number and size.
+ *
+ * V. Abell <abe@purdue.edu>
+ * February, 1998
+ */
+
+#if !defined(LSOF_RNODE_H)
+#    define LSOF_RNODE_H
+
+#    include "kernbits.h"
+
+#    define _KERNEL
+#    include <sys/spinlock.h>
+#    undef _KERNEL
+
+#    include "vnode.h"
+
+typedef struct krwlock {
+    lock_t *interlock;
+    u_int delay;
+    int read_count;
+    char want_write;
+    char want_upgrade;
+    char waiting;
+    char no_swap;
+} krwlock_t;
+
+typedef struct kmutex {
+    lock_t *spin_lockp;
+    int lockp_type;
+} kmutex_t;
+
+typedef struct nfs_fhandle {
+    int fh_len;
+    char fh_buf[64];
+} nfs_fhandle_t;
+
+typedef struct rnode {
+    KA_T r_freef;
+    KA_T r_freeb;
+    KA_T r_hash;
+    vnode_t r_vnode; /* the vnode that contains this rnode */
+    krwlock_t r_rwlock;
+    kmutex_t r_statelock;
+    nfs_fhandle_t r_fh;
+    uint16_t r_flags;
+    int16_t r_error;
+    KA_T r_rcred;
+    KA_T r_wcred;
+    KA_T r_unlcred;
+    KA_T r_unlname;
+    KA_T r_unldvp;
+    int64_t r_size;      /* This should be an off_t, but there's an
+                          * unresolvable conflict between the kernel
+                          * and application off_t sizes. */
+    struct vattr r_attr; /* the vnode attributes -- e.g., node number,
+                          * size, etc.  (See ./vnode.h.) */
+
+    /*
+     * These q4 elements are ignored.
+
+        time_t r_attrtime;
+        time_t r_mtime;
+        int32_t r_mapcnt;
+        uint32_t r_count;
+        int32_t r_seq;
+        int *r_acc;
+        int *r_dir;
+        int *r_direof;
+        symlink_cache r_symlink;
+        u_char r_verf;
+        commit_t r_commit;
+        recover_t r_recover;
+        uint32_t r_truncaddr;
+        uint32_t r_iocnt;
+        kcondvar_t r_trunccv;
+        kmutex_t r_serialize;
+        u_char r_cookieverf;
+        int *r_lmpl;
+        daddr_t r_lastr;
+        kcondvar_t r_cv;
+        int *r_owner;
+        short r_ownercount;
+
+     * Those q4 elements were ignored.
+     */
+
+} rnode_t;
+
+#endif /* !defined(LSOF_RNODE_H) */
diff --git a/lib/dialects/hpux/kmem/hpux11/sth.h b/lib/dialects/hpux/kmem/hpux11/sth.h
new file mode 100644 (file)
index 0000000..f9de616
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * sth_h for HP-UX 10.30 and above
+ *
+ * This header file defines the stream head structure, sth_t, for lsof.  Lsof
+ * uses the stream head structure to obtain the stream's read and write queue
+ * structure pointers.
+ *
+ * V. Abell
+ * February, 1998
+ */
+
+#if !defined(LSOF_STH_H)
+#    define LSOF_STH_H
+
+#    include "kernbits.h"
+#    include <sys/types.h>
+
+typedef struct streams_queue {
+    KA_T q_qinfo; /* queue info pointer */
+    KA_T q_first;
+    KA_T q_last;
+    KA_T q_next;
+    KA_T q_link;
+    KA_T q_ptr; /* queue private data pointer */
+    ulong q_count;
+    ulong q_flag;
+    int q_minpsz;
+    int q_maxpsz;
+    ulong q_hiwat;
+    ulong q_lowat;
+    KA_T q_bandp;
+    u_char q_nband;
+    u_char q_pad1[3];
+    KA_T q_other;
+    KA_T queue_sth;
+} streams_queue_t;
+
+typedef struct sth_s {
+    streams_queue_t *sth_rq; /* pointer to stream's read queue
+                              * structure chain */
+    streams_queue_t *sth_wq; /* pointer to stream's write queue
+                              * structure chain */
+                             /*
+                              * These q4 elements are ignored.
+                         
+                                 dev_t sth_dev;
+                                 ulong sth_read_mode;
+                                 ulong sth_write_mode;
+                                 int sth_close_wait_timeout;
+                                 u_char sth_read_error;
+                                 u_char sth_write_error;
+                                 short sth_prim_ack;
+                                 short sth_prim_nak;
+                                 short sth_ext_flags;
+                                 ulong sth_flags;
+                                 int sth_ioc_id;
+                                 KA_T sth_ioc_mp;
+                                 OSRQ sth_ioctl_osrq;
+                                 OSRQ sth_read_osrq;
+                                 OSRQ sth_write_osrq;
+                                 ulong sth_wroff;
+                                 int sth_muxid;
+                                 KA_T sth_mux_link;
+                                 KA_T sth_mux_top;
+                                 gid_t sth_pgid;
+                                 KA_T sth_session;
+                                 KA_T sth_next;
+                                 POLLQ sth_pollq;
+                                 SIGSQ sth_sigsq;
+                                 KA_T sth_ttyp;
+                                 int sth_push_cnt;
+                                 OSR sth_osr;
+                                 KA_T sth_pipestatp;
+                                 KA_T sth_ext_flags_lock;
+                                 uint qlen;
+                                 struct sth_func_reg sth_f_reg;
+                                 spu_t sth_bindspu;
+                         
+                             * Those q4 elements were ignored.
+                             */
+
+} sth_s_t;
+
+#endif /* !defined(LSOF_STH_H) */
diff --git a/lib/dialects/hpux/kmem/hpux11/tcp_s.h b/lib/dialects/hpux/kmem/hpux11/tcp_s.h
new file mode 100644 (file)
index 0000000..7932ef1
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * tcp_s.h for HP-UX 10.30 and above
+ *
+ * This header file defines the TCP connection structure, tpc_s, for lsof.
+ * Lsof gets the parameters of a TCP connection from tcp_s.  Lsof locates a
+ * tcp_s structure by scanning the queue structure chain of a TCP stream,
+ * looking for a queue structure whose module name begins with TCP; that queue
+ * structure's private data pointer, q_ptr, addresses its associated tcp_s
+ * structure.
+ *
+ * V. Abell
+ * February, 1998
+ */
+
+#if !defined(LSOF_TCP_S_H)
+#    define LSOF_TCP_S_H
+
+#    include "kernbits.h"
+#    include <sys/types.h>
+
+#    define TCPS_CLOSED -6
+#    define TCPS_IDLE -5
+#    define TCPS_BOUND -4
+#    define TCPS_LISTEN -3
+#    define TCPS_SYN_SENT -2
+#    define TCPS_SYN_RCVD -1
+#    define TCPS_ESTABLISHED 0
+#    define TCPS_CLOSE_WAIT 1
+#    define TCPS_FIN_WAIT_1 2
+#    define TCPS_CLOSING 3
+#    define TCPS_LAST_ACK 4
+#    define TCPS_FIN_WAIT_2 5
+#    define TCPS_TIME_WAIT 6
+
+typedef struct iph_s { /* IP header */
+    u_char iph_version_and_hdr_length;
+    u_char iph_type_of_service;
+    u_char iph_length[2];
+    u_char iph_ident[2];
+    u_char iph_fragment_offset_and_flags[2];
+    u_char iph_ttl;
+    u_char iph_protocol;
+    u_char iph_hdr_checksum[2];
+    u_char iph_src[4]; /* source IP address */
+    u_char iph_dst[4]; /* destination IP address */
+} iph_t;
+
+typedef struct ipha_s {
+    u_char ipha_version_and_hdr_length;
+    u_char ipha_type_of_service;
+    uint16_t ipha_length;
+    uint16_t ipha_ident;
+    uint16_t ipha_fragment_offset_and_flags;
+    u_char ipha_ttl;
+    u_char ipha_protocol;
+    uint16_t ipha_hdr_checksum;
+    uint32_t ipha_src;
+    uint32_t ipha_dst;
+} ipha_t;
+
+typedef struct tcphdr_s {
+    uint16_t th_lport; /* local port */
+    uint16_t th_fport; /* foreign port */
+    u_char th_seq[4];
+    u_char th_ack[4];
+    u_char th_offset_and_rsrvd[1];
+    u_char th_flags[1];
+    u_char th_win[2];
+    u_char th_sum[2];
+    u_char th_urp[2];
+} tcph_t;
+
+typedef struct tcpsb {
+    uint32_t tcpsb_start;
+    uint32_t tcpsb_end;
+} tcpsb_t;
+
+typedef struct tcp_s {
+    int tcp_state; /* connection state */
+    KA_T tcp_rq;
+    KA_T tcp_wq;
+    KA_T tcp_xmit_head;
+    KA_T tcp_xmit_last;
+    uint tcp_unsent;
+    KA_T tcp_xmit_tail;
+    uint tcp_xmit_tail_unsent;
+    uint32_t tcp_snxt; /* send: next sequence number */
+    uint32_t tcp_suna; /* send: unacknowledged sequence nr */
+    uint tcp_swnd;     /* send: window size */
+    uint tcp_swnd_shift;
+    uint tcp_cwnd;
+    u_long tcp_ibsegs;
+    u_long tcp_obsegs;
+    uint tcp_mss;
+    uint tcp_naglim;
+    int tcp_hdr_len; /* TCP header length */
+    int tcp_wroff_extra;
+    KA_T tcp_tcph; /* pointer to TCP header structure */
+    int tcp_tcp_hdr_len;
+    uint tcp_valid_bits;
+    int tcp_xmit_hiwater;
+    KA_T tcp_flow_mp;
+    int tcp_ms_we_have_waited;
+    KA_T tcp_timer_mp;
+    uint tcp_timer_interval;
+    uint32_t tcp_urp_old : 1, tcp_urp_sig_sent : 1, tcp_hard_binding : 1,
+        tcp_hard_bound : 1, tcp_priv_stream : 1, tcp_fin_acked : 1,
+        tcp_fin_rcvd : 1, tcp_fin_sent : 1, tcp_ordrel_done : 1,
+        tcp_flow_stopped : 1, tcp_detached : 1, tcp_bind_pending : 1,
+        tcp_unbind_pending : 1, tcp_use_ts_opts : 1, tcp_reader_active : 1,
+        tcp_lingering : 1, /* SO_LINGER */
+        tcp_no_bind : 1, tcp_sack_permitted : 1, tcp_rexmitting : 1,
+        tcp_fast_rexmitting : 1, tcp_ooofin_seen : 1, tcp_smooth_rtt : 1,
+        tcp_main_flags_fill : 10;
+    uint32_t tcp_so_debug : 1, /* SO_DEBUG */
+        tcp_dontroute : 1,     /* SO_DONTROUTE */
+        tcp_broadcast : 1,     /* SO_BROADCAST */
+        tcp_useloopback : 1,   /* SO_USELOOPBACK */
+        tcp_reuseaddr : 1,     /* SO_REUSEADDR */
+        tcp_reuseport : 1,     /* SO_REUSEPORT */
+        tcp_oobinline : 1,     /* SO_OOBONLINE */
+        tcp_xmit_hiwater_set : 1, tcp_xmit_lowater_set : 1,
+        tcp_recv_hiwater_set : 1, tcp_no_window_shift : 1,
+        tcp_window_shift_set : 1, tcp_keepalive_kills : 1,
+        tcp_option_flags_fill : 19;
+    uint tcp_dupack_cnt;
+    uint32_t tcp_smax;
+    uint32_t tcp_rnxt;
+    uint tcp_rwnd; /* read: window size */
+    uint tcp_rwnd_shift;
+    uint tcp_rwnd_max;
+    int tcp_credit;
+    int tcp_credit_init;
+    KA_T tcp_reass_head;
+    KA_T tcp_reass_tail;
+    KA_T tcp_rcv_head;
+    KA_T tcp_rcv_tail;
+    uint tcp_rcv_cnt;
+    uint tcp_rcv_threshold;
+    uint tcp_cwnd_ssthresh;
+    uint tcp_cwnd_bytes_acked;
+    uint tcp_cwnd_max;
+    uint tcp_cwnd_init;
+    int tcp_rto;
+    int tcp_rtt_sa;
+    int tcp_rtt_sd;
+    uint tcp_swl1;
+    uint tcp_swl2;
+    uint32_t tcp_rack; /* read: acknowledged sequent number */
+    uint tcp_rack_cnt;
+    uint tcp_rack_cur_max;
+    uint tcp_rack_abs_max;
+    KA_T tcp_ts_ptr;
+    uint32_t tcp_ts_updated;
+    uint tcp_max_swnd;
+    uint tcp_sack_cnt;
+    tcpsb_t tcp_sack_blocks[4];
+    KA_T tcp_listener;
+    int tcp_xmit_lowater;
+    uint32_t tcp_irs;
+    uint32_t tcp_iss;
+    uint32_t tcp_fss;
+    uint32_t tcp_urg;
+    uint32_t tcp_ooofin_seq;
+    int tcp_ip_hdr_len;
+    int tcp_first_timer_threshold;
+    int tcp_second_timer_threshold;
+    uint32_t tcp_zero_win_suna;
+    int tcp_first_ctimer_threshold;
+    int tcp_second_ctimer_threshold;
+    int tcp_linger; /* SO_LINGER interval */
+    KA_T tcp_urp_mp;
+    KA_T tcp_eager_next;
+    KA_T tcp_eager_prev;
+    KA_T tcp_eager_data;
+    KA_T tcp_conn_ind_mp;
+    uint tcp_conn_ind_cnt;
+    uint tcp_conn_ind_max;
+    uint tcp_conn_ind_seqnum;
+    KA_T tcp_conn_ind_list;
+    KA_T tcp_pre_conn_ind_list;
+    int tcp_keepalive_intrvl; /* SO_KEEPALIVE interval */
+    int tcp_keepalive_detached_intrvl;
+    KA_T tcp_keepalive_mp;
+    int tcp_client_errno;
+    union {
+        iph_t tcp_u_iph; /* IP header */
+        ipha_t tcp_u_ipha;
+        char tcp_u_buf[128];
+        double tcp_u_aligner;
+    } tcp_u;
+    uint32_t tcp_sum;
+    uint32_t tcp_remote;
+    uint32_t tcp_bound_source;
+    uint tcp_last_sent_len;
+    KA_T tcp_cookie;
+    KA_T tcp_hnext_port;
+    KA_T tcp_ptphn_port;
+    KA_T tcp_hnext_listener;
+    KA_T tcp_ptphn_listener;
+    KA_T tcp_hnext_established;
+    KA_T tcp_ptphn_established;
+    uint tcp_mirg;
+    KA_T tcp_readers_next;
+    KA_T tcp_readers_ptpn;
+} tcp_s_t;
+
+#endif /* !defined(LSOF_TCP_S_H) */
diff --git a/lib/dialects/hpux/kmem/hpux11/udp_s.h b/lib/dialects/hpux/kmem/hpux11/udp_s.h
new file mode 100644 (file)
index 0000000..21234c4
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * udp_s.h for HP-UX 10.30 and above
+ *
+ * This header file defines the UDP connection structure, udp_s, for lsof.
+ * Lsof gets the parameters of a UDP connection from tcp_s.  Lsof locates a
+ * tcp_s structure by scanning the queue structure chain of a UDP stream,
+ * looking for a queue structure whose module name begins with UDP; that queue
+ * structure's private data pointer, q_ptr, addresses its associated tcp_s
+ * structure.
+ *
+ * V. Abell
+ * February, 1998
+ */
+
+#if !defined(LSOF_UDP_S_H)
+#    define LSOF_UDP_S_H
+
+#    include "kernbits.h"
+
+typedef struct udp_s {
+    int udp_state; /* connection state */
+    KA_T udp_hash_next;
+    KA_T udp_ptphn;
+    uint16_t udp_checksum;
+    uint16_t udp_port[2]; /* source and destination ports */
+    uint32_t udp_src;     /* source IP address */
+    uint32_t udp_dst;     /* destination IP address */
+
+    /*
+     * These q4 elements are ignored.
+
+        uint udp_hdr_length;
+        int udp_wroff_xtra;
+        uint udp_family;
+        uint udp_ip_snd_options_len;
+        KA_T udp_ip_snd_options;
+        int udp_linger;
+        union {
+            uchar udpu1_multicast_ttl;
+            u32 udpu1_pad;
+        } udp_u1;
+        NET32 udp_multicast_if_addr;
+        KA_T udp_udph;
+        uint udp_priv_stream;
+        uint udp_calc_checksum;
+        uint udp_debug;
+        uint udp_dontroute;
+        uint udp_broadcast;
+        uint udp_useloopback;
+        uint udp_reuseaddr;
+        uint udp_reuseport;
+        uint udp_multicast_loop;
+        uint udp_rx_icmp;
+        uint udp_rx_icmp_set;
+        uint udp_distribute;
+        uint udp_link_status;
+        uint udp_copyavoid;
+        uint udp_pad_to_bit_31;
+        union {
+            uint udpu2_wants_opts;
+           struct udpu2_flags_s udpu2_flags;
+        } udp_u2;
+        union {
+            char udpu3_iphc[72];
+            iph_t udpu3_iph;
+            u32 udpu3_ipharr[6];
+            uble udpu3_aligner;
+        } udp_u3;
+        u8 udp_pad2[2];
+        u8 udp_type_of_service;
+        u8 udp_ttl;
+        u8 udp_bound_ip[4];
+
+     * Those q4 elements were ignored.
+     */
+
+} udp_s_t;
+
+#endif /* !defined(LSOF_UDP_S_H) */
diff --git a/lib/dialects/hpux/kmem/hpux11/vnode.h b/lib/dialects/hpux/kmem/hpux11/vnode.h
new file mode 100644 (file)
index 0000000..5d4de4f
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * vnode.h for HP-UX 10.30 and above
+ *
+ * This header file defines the locklist, vnode and vattr structures for lsof
+ * in a manner that can be compiled at the application level.
+ *
+ * V. Abell <abe@purdue.edu>
+ * February, 1998
+ */
+
+#if !defined(LSOF_VNODE_H)
+#    define LSOF_VNODE_H
+#    define _SYS_VNODE_INCLUDED /* prevent inclusion of <sys/vnode.h> */
+
+#    include "kernbits.h"
+#    include <sys/types.h>
+#    include <sys/sem_beta.h>
+#    include <sys/time.h>
+
+#    define VROOT 0x01
+
+typedef struct locklist { /* lock list */
+    KA_T ll_link;
+    short ll_count;
+    short ll_flags;   /* flags */
+    KA_T ll_proc;     /* proc structure address (unused) */
+    KA_T ll_kthreadp; /* thread structure address */
+
+    /* ll_start and ll_end should be typed off_t, but there's an
+     * unresolvable conflict between the size of the kernel's off_t
+     * and the 32 and 64 bit application off_t sizes.
+     */
+
+    int64_t ll_start; /* lock start */
+    int64_t ll_end;   /* lock end */
+    short ll_type;    /* lock type -- e.g., F_RDLCK or
+                       * F_WRLCK */
+    KA_T ll_vp;
+    KA_T ll_waitq;
+    KA_T ll_fwd; /* forward link */
+    KA_T ll_rev;
+    KA_T ll_sib_fwd;
+    KA_T ll_sib_rev;
+} locklist_t;
+
+enum vtype {
+    VNON = 0,
+    VREG = 0x1,
+    VDIR = 0x2,
+    VBLK = 0x3,
+    VCHR = 0x4,
+    VLNK = 0x5,
+    VSOCK = 0x6,
+    VBAD = 0x7,
+    VFIFO = 0x8,
+    VFNWK = 0x9,
+    VEMPTYDIR = 0xa
+};
+
+enum vfstype {
+    VDUMMY = 0,
+    VNFS = 0x1,
+    VUFS = 0x2,
+    VDEV_VN = 0x3,
+    VNFS_SPEC = 0x4,
+    VNFS_BDEV = 0x5,
+    VNFS_FIFO = 0x6,
+    VCDFS = 0x7,
+    VVXFS = 0x8,
+    VDFS = 0x9,
+    VEFS = 0xa,
+    VLOFS = 0xb
+};
+
+typedef struct vnode {
+    u_short v_flag;    /* flags -- e.g., VROOT */
+    u_short v_shlockc; /* shared lock count */
+    u_short v_exlockc; /* exclusive lock count */
+    u_short v_tcount;
+    int v_count;
+    KA_T v_vfsmountedhere;
+    KA_T v_op; /* operations switch */
+    KA_T v_socket;
+    KA_T v_stream;     /* associated stream */
+    KA_T v_vfsp;       /* pointer to virtual file system
+                        * structure */
+    enum vtype v_type; /* vnode type */
+    dev_t v_rdev;      /* device -- for VCHR and VBLK
+                        * vnodes */
+    caddr_t v_data;    /* private data -- i.e., pointer to
+                        * successor node structure */
+    enum vfstype v_fstype;
+    KA_T v_vas;
+    vm_sema_t v_lock;
+    KA_T v_cleanblkhd;
+    KA_T v_dirtyblkhd;
+    int v_writecount;
+    KA_T v_locklist; /* locklist structure chain pointer */
+    int v_scount;
+    int32_t v_nodeid;
+    KA_T v_ncachedhd;
+    KA_T v_ncachevhd;
+    KA_T v_pfdathd;
+    u_int v_last_fsync;
+} vnode_t;
+
+typedef struct vattr {
+    enum vtype va_type;
+    u_short va_mode;
+    short va_nlink;
+    uid_t va_uid;
+    gid_t va_gid;
+    int32_t va_fsid;
+    int32_t va_nodeid; /* node ID number (e.g., inode
+                        * number) */
+    off64_t va_size;   /* file size */
+    int32_t va_blocksize;
+    struct timeval va_atime;
+    struct timeval va_mtime;
+    struct timeval va_ctime;
+    dev_t va_rdev;
+    blkcnt64_t va_blocks;
+    dev_t va_realdev;
+    u_short va_basemode;
+    u_short va_acl;
+    u_short va_sysVacl;
+    u_short va_dummy;
+    short va_fstype;
+} vattr_t;
+
+#endif /* !defined(LSOF_VNODE_H) */
diff --git a/lib/dialects/hpux/kmem/machine.h b/lib/dialects/hpux/kmem/machine.h
new file mode 100644 (file)
index 0000000..2fc875c
--- /dev/null
@@ -0,0 +1,608 @@
+/*
+ * machine.h - /dev/kmem-based HP-UX definitions for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+/*
+ * $Id: machine.h,v 1.42 2010/07/29 16:03:09 abe Exp $
+ */
+
+#if !defined(LSOF_MACHINE_H)
+#    define LSOF_MACHINE_H 1
+
+/*
+ * Do HP-UX 11 64 bit preparation.
+ */
+
+#    if defined(HPUXKERNBITS) && HPUXKERNBITS >= 64
+#        define NLIST_TYPE nlist64
+#    endif /* defined(HPUXKERNBITS) && HPUXKERNBITS>=64 */
+
+#    if HPUXV >= 1030
+#        include <sys/types.h>
+#        include "kernbits.h"
+#    else /* HPUXV<1030 */
+#        if HPUXV >= 1020
+/*
+ * Since we need kernel structures from the HP-UX 10.20 <sys/vnode.h>, and
+ * since defining _KERNEL before #include'ing it causes a conflict between
+ * its FILE enum and the FILE struct definition in <stdio.h>, redefine FILE,
+ * #include <stdio.h>, revoke the FILE redefinition, define _KERNEL,
+ * #include <sys/vnode.h>, revoke the _KERNEL definition, and restore the
+ * FILE redefinition.
+ */
+
+#            if defined(__GNUC__)
+/*
+ * Do gcc preparation.
+ */
+
+#                if !defined(__STDC_EXT__)
+#                    define __STDC_EXT__
+#                endif /* !defined(__STDC_EXT__) */
+#                include <sys/_inttypes.h>
+#            endif /* defined(__GNUC__) */
+
+#            define FILE STDIO_FILE
+#            include <stdio.h>
+#            undef FILE
+#            define _KERNEL 1
+#            include <sys/vnode.h>
+#            define FILE STDIO_FILE
+#            undef _KERNEL
+#        endif /* HPUXV>=1020 */
+#    endif     /* HPUXV>=1030 */
+
+/*
+ * 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().
+ */
+
+#    if HPUXV >= 1020
+#        define CAN_USE_CLNT_CREATE 1
+#    endif /* HPUXV>=1020 */
+
+/*
+ * 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 get_max_fd
+
+/*
+ * HASAOPT is defined for those dialects that have AFS support; it specifies
+ * that the default path to an alternate AFS kernel name list file may be
+ * supplied with the -A <path> option.
+ */
+
+#    define HASAOPT 1
+
+/*
+ * HASBLKDEV is defined for those dialects that want block device information
+ * recorded in BDevtp[].
+ */
+
+#    define HASBLKDEV 1
+
+/*
+ * HASDCACHE is defined for those dialects that support a device cache
+ * file.
+ *
+ * HASENVDC defined the name of an environment variable that contains the
+ * device cache file path.  The HASENVDC environment variable is ignored when
+ * the lsof process is setuid(root) or its real UID is 0.
+ *
+ * HASPERSDC defines the format for the last component of a personal device
+ * cache file path.  The first will be the home directory of the real UID that
+ * executes lsof.
+ *
+ * HASPERSDCPATH defines the environment variable whose value is the middle
+ * component of the personal device cache file path.  The middle component
+ * follows the home directory and precedes the results of applying HASPERSDC.
+ * The HASPERSDCPATH environment variable is ignored when the lsof process is
+ * setuid(root) or its real UID is 0.
+ *
+ * HASSYSDC defines a public device cache file path.  When it's defined, it's
+ * used as the path from which to read the device cache.
+ *
+ * Consult the 00DCACHE and 00FAQ files of the lsof distribution for more
+ * information on device cache file path construction.
+ */
+
+#    define HASDCACHE 1
+#    define HASENVDC "LSOFDEVCACHE"
+#    define HASPERSDC "%h/%p.lsof_%L"
+#    define HASPERSDCPATH "LSOFPERSDCPATH"
+/* #define     HASSYSDC        "/your/choice/of/path" */
+
+/*
+ * HASCDRNODE is defined for those dialects that have CD-ROM nodes.
+ */
+
+/* #define     HASCDRNODE      1 */
+
+/*
+ * HASFIFONODE is defined for those dialects that have FIFO nodes.
+ */
+
+/* #define     HASFIFONODE     1 */
+
+/*
+ * HASFSINO is defined for those dialects that have the file system
+ * inode element, fs_ino, in the lfile structure definition in lsof.h.
+ */
+
+#    define HASFSINO 1
+
+/*
+ * HASFSTRUCT is defined if the dialect has a file structure.
+ *
+ * FSV_DEFAULT defines the default set of file structure values to list.
+ * It defaults to zero (0), but may be made up of a combination of the
+ * FSV_* symbols from lsof.h.
+ *
+ *   HASNOFSADDR  -- has no file structure address
+ *   HASNOFSFLAGS -- has no file structure flags
+ *   HASNOFSCOUNT -- has no file structure count
+ *   HASNOFSNADDR -- has no file structure node address
+ */
+
+#    define HASFSTRUCT 1
+/* #define     FSV_DEFAULT     FSV_? | FSV_? | FSV_? */
+/* #define     HASNOFSADDR     1       has no file structure address */
+/* #define     HASNOFSFLAGS    1       has no file structure flags */
+/* #define     HASNOFSCOUNT    1       has no file structure count */
+/* #define     HASNOFSNADDR    1       has no file structure node address */
+
+/*
+ * HASGNODE is defined for those dialects that have gnodes.
+ */
+
+/* #define     HASGNODE        1 */
+
+/*
+ * HASHSNODE is defined for those dialects that have High Sierra nodes.
+ */
+
+/* #define     HASHSNODE       1 */
+
+/*
+ * HASINODE is defined for those dialects that have inodes and wish to
+ * use readinode() from node.c.
+ */
+
+/* #define     HASINODE        1 */
+
+/*
+ * HASINTSIGNAL is defined for those dialects whose signal function returns
+ * an int.
+ */
+
+/* #define     HASINTSIGNAL    1 */
+
+/*
+ * HASKERNIDCK is defined for those dialects that support the comparison of
+ * the build to running kernel identity.
+ */
+
+#    define HASKERNIDCK 1
+
+/*
+ * HASKOPT is defined for those dialects that support the -k option of
+ * reading the kernel's name list from an optional file.
+ */
+
+#    define HASKOPT 1
+
+/*
+ * HASLFILEADD is defined for those dialects that need additional elements
+ * in struct lfile.  The HASLFILEADD definition is a macro that defines
+ * them.  If any of the additional elements need to be preset in the
+ * alloc_lfile() function of proc.c, the SETLFILEADD macro may be defined
+ * to do that.
+ *
+ * If any additional elements need to be cleared in alloc_lfile() or in the
+ * free_proc() function of proc.c, the CLRLFILEADD macro may be defined to
+ * do that.  Note that CLRLFILEADD takes one argument, the pointer to the
+ * lfile struct.  The CLRLFILEADD macro is expected to expand to statements
+ * that are complete -- i.e., have terminating semi-colons -- so the macro is
+ * called without a terminating semicolon by proc.c.
+ *
+ * The HASXOPT definition may be used to select the conditions under which
+ * private lfile elements are used.
+ */
+
+/* #define HASLFILEADD int ... */
+/* #define CLRLFILEADD(lf)     (lf)->... = (type)NULL; */
+/* #define SETLFILEADD Lf->... */
+
+/*
+ * 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.
+ *
+ * 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     ??? */
+
+/*
+ * 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.
+ */
+
+#    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?       */
+
+/*
+ * 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
+
+#    if HPUXV >= 1100
+#        define HASWIDECHAR 1
+#    endif /* HPUXV>=1100 */
+
+/* #define     WIDECHARINCL    <wchar.h>       */
+
+/*
+ * HASSNODE is defined for those dialects that have snodes.
+ */
+
+#    if HPUXV >= 900
+#        define HASSNODE 1
+#    endif /* HPUXV>=900 */
+
+/*
+ * HASTASKS is defined for those dialects that have task reporting support.
+ */
+
+/* #define     HASTASKS        1 */
+
+/*
+ * HASSOOPT, HASSOSTATE and HASTCPOPT define the availability of information
+ * on socket options (SO_* symbols), socket states (SS_* symbols) and TCP
+ * options.
+ */
+
+#    if HPUXV >= 1030
+#        if HPUXV >= 1100
+#            define HASSOOPT 1 /* has socket option information */
+#        endif                 /* HPUXV>=1100 */
+/* #define     HASSOSTATE      1       has socket state information */
+#        define HASTCPOPT 1 /* has TCP options or flags */
+#    endif                  /* HPUXV>=1030 */
+
+/*
+ * Define HASSPECDEVD to be the name of a function that handles the results
+ * of a successful stat(2) of a file name argument.
+ *
+ * For example, HASSPECDEVD() for Darwin makes sure that st_dev is set to
+ * what stat("/dev") returns -- i.e., what's in DevDev.
+ *
+ * The function takes two arguments:
+ *
+ *     1: pointer to the full path name of file
+ *     2: pointer to the stat(2) result
+ *
+ * The function returns void.
+ */
+
+/* #define     HASSPECDEVD     process_dev_stat */
+
+/*
+ * HASSTREAMS is defined for those dialects that support streams.
+ */
+
+/* #define     HASSTREAMS      1 */
+
+/*
+ * HASTCPTPIQ is defined for dialects where it is possible to report the
+ * TCP/TPI Recv-Q and Send-Q values produced by netstat.
+ */
+
+#    define HASTCPTPIQ 1
+
+/*
+ * HASTCPTPIW is defined for dialects where it is possible to report the
+ * TCP/TPI send and receive window sizes produced by netstat.
+ */
+
+#    if HPUXV >= 1030
+#        define HASTCPTPIW 1
+#    endif /* HPUXV>=1030 */
+
+/*
+ * HASTMPNODE is defined for those dialects that have tmpnodes.
+ */
+
+/* #define     HASTMPNODE      1 */
+
+/*
+ * HASVNODE is defined for those dialects that use the Sun virtual file system
+ * node, the vnode.  BSD derivatives usually do; System V derivatives prior to
+ * R4 usually don't.
+ */
+
+#    define HASVNODE 1
+
+/*
+ * HASXOPT is defined for those dialects that have an X option.  It
+ * defines the text for the usage display.  HASXOPT_VALUE defines the
+ * option's default binary value -- 0 or 1.
+ */
+
+/* #define     HASXOPT         "help text for X option" */
+/* #define     HASXOPT_VALUE   1 */
+
+/*
+ * INODETYPE and INODEPSPEC define the internal node number type and its
+ * printf specification modifier.  These need not be defined and lsof.h
+ * can be allowed to define defaults.
+ *
+ * These are defined here, because they must be used in dlsof.h.
+ */
+
+#    if HPUXV >= 1000
+#        define INODETYPE unsigned long long
+/* inode number internal storage type */
+#        define INODEPSPEC                                                     \
+            "ll" /* INODETYPE printf specification                             \
+                  * modifier */
+#    endif       /* HPUXV>=1000 */
+
+/*
+ * UID_ARG defines the size of a User ID number when it is passed
+ * as a function argument.
+ */
+
+#    define UID_ARG uid_t
+
+/*
+ * 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 */
+
+#    if HPUXV < 1030
+#        define USE_LIB_PRINT_TCPTPI 1 /* ptti.c */
+#    else                              /* HPUXV>=1030 */
+/* #define     USE_LIB_PRINT_TCPTPI            1          ptti.c */
+#    endif                             /* HPUXV<1030 */
+
+#    define USE_LIB_READDEV 1 /* rdev.c */
+#    define USE_LIB_READMNT 1 /* rmnt.c */
+/* #define     USE_LIB_RNAM                    1          rnam.c */
+#    define USE_LIB_RNCH 1 /* rnch.c */
+/* #define     USE_LIB_RNMH                    1          rnmh.c */
+/* #define     USE_LIB_SNPF                    1          snpf.c */
+#    define snpf snprintf /* use the system's snprintf() */
+
+/*
+ * WARNDEVACCESS is defined for those dialects that should issue a warning
+ * when lsof can't access /dev (or /device) or one of its sub-directories.
+ * The warning can be inhibited by the lsof caller with the -w option.
+ */
+
+/* #define     WARNDEVACCESS   1 */
+
+/*
+ * WARNINGSTATE is defined for those dialects that want to suppress all lsof
+ * warning messages.
+ */
+
+/* #define     WARNINGSTATE    1       warnings are enabled by default */
+
+/*
+ * WILLDROPGID is defined for those dialects whose lsof executable runs
+ * setgid(not_real_GID) and whose setgid power can be relinquished after
+ * the dialect's initialize() function has been executed.
+ */
+
+#    define WILLDROPGID 1
+
+/*
+ * zeromem is a macro that uses bzero or memset.
+ */
+
+#    define zeromem(a, l) bzero(a, l)
+
+#endif /* !defined(LSOF_MACHINE_H) */
diff --git a/lib/dialects/hpux/pstat/Makefile b/lib/dialects/hpux/pstat/Makefile
new file mode 100644 (file)
index 0000000..9eace67
--- /dev/null
@@ -0,0 +1,149 @@
+
+# HP-UX PSTAT-based Makefile
+#
+# $Id: Makefile,v 1.6 2008/05/09 12:51:46 abe Exp $
+
+PROG=  lsof
+
+BIN=   ${DESTDIR}
+
+DOC=   ${DESTDIR}
+
+I=/usr/include
+S=/usr/include/sys
+L=/usr/include/local
+P=
+
+CDEF=
+CDEFS=  ${CDEF} ${CFGF}
+INCL=  ${DINC}
+CFLAGS=        ${CDEFS} ${INCL} ${DEBUG}
+
+GRP=
+
+HDR=    lsof.h lsof_fields.h dlsof.h machine.h proto.h dproto.h
+
+SRC=    dfile.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 dproc.o dsock.o dstore.o \
+       arg.o main.o misc.o node.o print.o proc.o store.o usage.o util.o
+
+MAN=   lsof.8
+
+OTHER= 
+
+SHELL= /bin/sh
+
+SOURCE=        Makefile ${OTHER} ${MAN} ${HDR} ${SRC}
+
+all: ${PROG}
+
+${PROG}: ${LIB} ${P} ${OBJ}
+       ${CC} -o $@ ${CFLAGS} ${OBJ} ${CFGL}
+
+clean: FRC
+       rm -f Makefile.bak ${PROG} a.out core errs lint.out tags *.o version.h
+       rm -f machine.h.old new_machine.h
+       (cd lib; ${MAKE} -f Makefile.skel clean)
+
+install: 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 <group> $${PROG} $${BIN}'
+       @echo '    install -m 444 $${MAN} $${DOC}'
+       @echo ''
+       @echo 'You will have to complete the 4xxx modes, the <group> value,'
+       @echo 'and 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_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
+
+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/lib/dialects/hpux/pstat/Mksrc b/lib/dialects/hpux/pstat/Mksrc
new file mode 100755 (executable)
index 0000000..0840e1a
--- /dev/null
@@ -0,0 +1,24 @@
+#!/bin/sh
+#
+# Mksrc - make pstat-based HP-UX source files
+#
+# WARNING: This script assumes it is running from the main directory
+#         of the lsof, version 4 distribution.
+#
+# One environment variable applies:
+#
+# LSOF_MKC     is the method for creating the source files.
+#              It defaults to "ln -s".  A common alternative is "cp".
+#
+# $Id: Mksrc,v 1.1 99/05/25 13:04:50 abe Exp $
+
+
+D=dialects/hpux/pstat
+L="dfile.c dlsof.h dfile.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/lib/dialects/hpux/pstat/dfile.c b/lib/dialects/hpux/pstat/dfile.c
new file mode 100644 (file)
index 0000000..f1e2d38
--- /dev/null
@@ -0,0 +1,753 @@
+/*
+ * dfile.c -- pstat-based HP-UX file functions for lsof
+ */
+
+/*
+ * Copyright 1999 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 1999 Purdue Research Foundation.\nAll rights reserved.\n";
+#endif
+
+#include "common.h"
+
+#if defined(HASNCACHE)
+/*
+ * Local definitions
+ */
+
+#    define DNLCINCR 2048 /* DNLC read increment */
+
+#    define NFSIDH                                                             \
+        256 /* file system ID hash count                                       \
+             * -- MUST BE A POWER OF TWO!!! */
+#    define NFSID sizeof(struct psfsid)
+/* size of psfsid structure */
+#    define NL_NC sizeof(struct l_nc)
+/* size of l_nc structure */
+#    define NPSTM sizeof(struct pst_mpathnode)
+/* size of pst_mpathnode */
+
+/*
+ * Local structure definitions
+ */
+
+struct l_nc {            /* local name cache */
+    struct psfileid id;  /* node's PSTAT ID */
+    struct psfileid par; /* parent's PSTAT ID */
+    struct l_nc *pl;     /* local parent name cache entry --
+                          * NULL if not found or not yet
+                          * accessed (see pls) */
+    int pls;             /* status of pl: 0 = not accessed
+                          *             1 = accessed */
+    int nl;              /* name length */
+    char *nm;            /* name */
+    struct l_nc *next;   /* next hash bucket link */
+};
+
+struct l_fic {          /* file system ID cache */
+    struct psfsid fsid; /* file system ID */
+    int nc;             /* files cached for file system */
+    struct l_fic *next; /* next hash bucket link */
+};
+
+/*
+ * Local static variables
+ */
+
+static int Nceh; /* number of Nchash entries allocated */
+static struct l_nc **Nchash = (struct l_nc **)NULL;
+/* the name cache hash buckets */
+static int Ncmask; /* power of two mask for the name
+                    * cache -- sized from Nc */
+static int Ndnlc;  /* number of DNLC entries via
+                    * pst_dynamic.psd_dnlc_size */
+static struct l_fic **Ncfsid = (struct l_fic **)NULL;
+/* the file system hash buckets */
+static struct pst_fid Nzpf;  /* zeroed pst_fid (for memcmp()) */
+static struct psfileid Nzps; /* zeroed psfilid (for memcmp()) */
+static int Nzpfs = 0;        /* Nzpf status: 1 = zeroed */
+static int Nzpss = 0;        /* Nzps status: 1 = zeroed */
+
+/*
+ * Local macros
+ */
+
+#    define HASHFSID(i)                                                        \
+        (Ncfsid +                                                              \
+         (((int)(((((struct psfsid *)i)->psfs_id * 31415) << 3) & 0xfffffff) + \
+           (int)((((((struct psfsid *)i)->psfs_type * 31415) << 5) &           \
+                  0xfffffff))) &                                               \
+          (NFSIDH - 1)))
+#    define HASHPSFILEID(p)                                                    \
+        (Nchash +                                                              \
+         (((int)(((int)((((struct psfileid *)p)->psf_fsid.psfs_id * 31415)     \
+                        << 3) &                                                \
+                  0xfffffff) +                                                 \
+                 (int)(((((struct psfileid *)p)->psf_fsid.psfs_type * 31415)   \
+                        << 5) &                                                \
+                       0xfffffff) +                                            \
+                 (int)(((((struct psfileid *)p)->psf_fileid * 31415) << 7) &   \
+                       0xfffffff))) &                                          \
+          Ncmask))
+
+/*
+ * Local function prototypes
+ */
+
+static struct l_nc *ncache_addr(struct psfileid *ps);
+static void ncache_free(void);
+static int ncache_isroot(struct psfileid *ps);
+static void ncache_size(void);
+#endif /* defined(HASNCACHE) */
+
+#if defined(HASIPv6)
+/*
+ * gethostbyname2() -- an RFC2133-compatible get-host-by-name-two function
+ *                     to get AF_INET and AF_INET6 addresses from host names,
+ *                     using the gethostbyname() and RFC2553-compatible
+ *                    getipnodebyname() functions
+ */
+
+extern struct hostent *
+gethostbyname2(char *nm, /* host name */
+               int prot) /* protocol -- AF_INET or AF_INET6 */
+{
+    int err;
+
+    if (prot == AF_INET) {
+
+        /*
+         * This shouldn't be necessary if /etc/nsswitch.conf is correct, but
+         * it's a good fail-safe in case /etc/nsswitch.conf is missing or
+         * incorrect.
+         */
+        return (gethostbyname(nm));
+    }
+    return (getipnodebyname(nm, prot, 0, &err));
+}
+#endif /* defined(HASIPv6) */
+
+/*
+ * get_max_fd() -- get maximum file descriptor plus one
+ */
+
+int get_max_fd() {
+    struct rlimit r;
+
+    if (getrlimit(RLIMIT_NOFILE, &r))
+        return (-1);
+    return (r.rlim_cur);
+}
+
+#if defined(HASNCACHE)
+
+/*
+ * ncache_addr() -- get ncache entry address
+ */
+
+static struct l_nc *ncache_addr(struct psfileid *ps) /* parent's psfileid */
+{
+    struct l_nc **hp, *lc;
+
+    for (hp = HASHPSFILEID(ps), lc = *hp; lc; lc = lc->next) {
+        if (!memcmp((void *)ps, (void *)&lc->id, sizeof(struct psfileid)))
+            return (lc);
+    }
+    return ((struct l_nc *)NULL);
+}
+
+/*
+ * ncache_alloc() -- allocate name cache space
+ */
+
+static void ncache_alloc() {
+    if (Nchash || Ncfsid)
+        ncache_free();
+    (void)ncache_size();
+    if (!(Nchash = (struct l_nc **)calloc(Nceh, sizeof(struct l_nc *)))) {
+        (void)fprintf(stderr,
+                      "%s: can't allocate %d local name cache entries\n", Pn,
+                      Nceh);
+        Error(ctx);
+    }
+    if (Ncfsid)
+        return;
+    if (!(Ncfsid = (struct l_fic **)calloc(NFSIDH, sizeof(struct l_fic *)))) {
+        (void)fprintf(stderr,
+                      "%s: can't allocate %d local file system cache entries\n",
+                      Pn, NFSIDH);
+        Error(ctx);
+    }
+}
+
+/*
+ * ncache_free() -- free previous ncache allocations
+ */
+
+static void ncache_free() {
+    int i;
+    struct l_fic **fh, *fp, *fx;
+    struct l_nc **nh, *np, *nx;
+
+    if (Ncfsid) {
+
+        /*
+         * Free file system ID hash bucket contents.
+         */
+        for (fh = Ncfsid, i = 0; i < NFSIDH; fh++, i++) {
+            for (fp = *fh; fp; fp = fx) {
+                fx = fp->next;
+                (void)free((MALLOC_P *)fp);
+            }
+            Ncfsid[i] = (struct l_fic *)NULL;
+        }
+    }
+    if (Nchash) {
+
+        /*
+         * Free name cache.
+         */
+        for (i = 0, nh = Nchash; i < Nceh; i++, nh++) {
+            for (np = *nh; np; np = nx) {
+                nx = np->next;
+                if (np->nm)
+                    (void)free((MALLOC_P *)np->nm);
+                (void)free((MALLOC_P *)np);
+            }
+        }
+        (void)free((MALLOC_P *)Nchash);
+        Nchash = (struct l_nc **)NULL;
+    }
+}
+
+/*
+ * ncache_isroot() -- does psfileid represent the root of a file system?
+ */
+
+static int ncache_isroot(struct psfileid *ps) /* psfileid */
+{
+    if (!ps->psf_fsid.psfs_id && !ps->psf_fsid.psfs_type &&
+        ps->psf_fileid == -1)
+        return (1);
+
+#    if defined(HASFSINO)
+    if (!Lf->fs_ino || (Lf->inp_ty != 1) || !Lf->dev_def)
+        return (0);
+    if ((Lf->dev == (dev_t)ps->psf_fsid.psfs_id) &&
+        (Lf->fs_ino == (unsigned long)ps->psf_fileid))
+        return (1);
+#    endif /* defined(HASFSINO) */
+
+    return (0);
+}
+
+/*
+ * ncache_load() -- load name cache
+ */
+
+void ncache_load() {
+    if (!Fncache)
+        return;
+    (void)ncache_alloc();
+    if (!Nzpfs) {
+        (void)memset((void *)&Nzpf, 0, sizeof(Nzpf));
+        Nzpfs = 1;
+    }
+    if (!Nzpss) {
+        (void)memset((void *)&Nzps, 0, sizeof(Nzps));
+        Nzpss = 1;
+    }
+}
+
+/*
+ * ncache_loadfs() -- load the name cache for a file system
+ */
+
+struct l_fic *ncache_loadfs(struct psfsid *fsid, /* ID of file system to add */
+                            struct l_fic **fh)   /* Ncfsid hash bucket */
+{
+    char *cp;
+    struct l_fic *f;
+    int i, nl, nr;
+    struct pst_mpathnode mp[DNLCINCR];
+    struct l_nc **nh, *nn, *nt, *ntp;
+    int x = 0;
+    /*
+     * Allocate a new file system pointer structure and link it to its bucket.
+     */
+    if (!(f = (struct l_fic *)malloc(sizeof(struct l_fic)))) {
+        (void)fprintf(stderr, "%s: no fsid structure space\n", Pn);
+        Error(ctx);
+    }
+    f->fsid = *fsid;
+    f->nc = 0;
+    f->next = *fh;
+    *fh = f;
+    while ((nr = pstat_getmpathname(&mp[0], NPSTM, DNLCINCR, x, fsid)) > 0) {
+        x = mp[nr - 1].psr_idx + 1;
+        for (i = 0; i < nr; i++) {
+
+            /*
+             * Ignore NUL names, ".", and "..".
+             */
+            if (!(nl = (int)strlen(mp[i].psr_name)))
+                continue;
+            if ((nl < 3) && (mp[i].psr_name[0] == '.')) {
+                if ((nl == 1) || (mp[i].psr_name[1] == '.'))
+                    continue;
+            }
+            /*
+             * Allocate name and name cache structure space.
+             */
+            if (!(cp = (char *)malloc((MALLOC_S)(nl + 1)))) {
+                (void)fprintf(stderr, "%s: no name entry space (%d) for:%s\n",
+                              Pn, nl + 1, mp[i].psr_name);
+                Error(ctx);
+            }
+            if (!(nn = (struct l_nc *)malloc(sizeof(struct l_nc)))) {
+                (void)fprintf(stderr,
+                              "%s: no name cache entry space (%d) for: %s\n",
+                              Pn, (int)sizeof(struct l_nc), mp[i].psr_name);
+                Error(ctx);
+            }
+            /*
+             * Fill in name cache entry, complete with name and name length.
+             */
+            (void)snpf(cp, nl + 1, "%s", mp[i].psr_name);
+            nn->id = mp[i].psr_file;
+            nn->par = mp[i].psr_parent;
+            nn->nm = cp;
+            nn->nl = nl;
+            nn->pl = nn->next = (struct l_nc *)NULL;
+            nn->pls = 0;
+            nh = HASHPSFILEID(&mp[i].psr_file);
+            /*
+             * Skip to the end of the hash bucket chain, looking for
+             * duplicates along the way.
+             */
+            for (nt = *nh, ntp = (struct l_nc *)NULL; nt;
+                 ntp = nt, nt = nt->next) {
+                if (memcmp((void *)&nt->id, (void *)&nn->id, NL_NC) == 0)
+                    break;
+            }
+            if (nt) {
+
+                /*
+                 * Remove a duplicate.
+                 */
+                if (ntp)
+                    ntp = nt->next;
+                else
+                    *nh = nt->next;
+                (void)free((MALLOC_P *)nt->nm);
+                (void)free((MALLOC_P *)nt);
+                (void)free((MALLOC_P *)nn->nm);
+                (void)free((MALLOC_P *)nn);
+            } else {
+
+                /*
+                 * Link a new entry.
+                 */
+                if (ntp)
+                    ntp->next = nn;
+                else
+                    *nh = nn;
+                f->nc++;
+            }
+        }
+        if (nr < DNLCINCR)
+            break;
+    }
+    return (f);
+}
+
+/*
+ * ncache_lookup() -- look up a node's name in the kernel's name cache
+ */
+
+char *ncache_lookup(char *buf, /* receiving name buffer */
+                    int blen,  /* receiving buffer length */
+                    int *fp)   /* full path reply */
+{
+    char *cp = buf;
+    int ef;
+    struct l_fic **fh, *fs;
+    struct l_nc *lc;
+    int nl, rlen;
+    char *pc;
+
+    *cp = '\0';
+    *fp = 0;
+
+#    if defined(HASFSINO)
+    /*
+     * If the entry has an inode number that matches the inode number of the
+     * file system mount point, return an empty path reply.  That tells the
+     * caller that the already-printed system mount point name is sufficient.
+     */
+    if (Lf->inp_ty == 1 && Lf->fs_ino && Lf->inode == Lf->fs_ino)
+        return (cp);
+#    endif /* defined(HASFSINO) */
+
+    /*
+     * See if cache has been loaded for this pfsid.  Don't try to load if cache
+     * loading has been inhibited with -C, or unless the real or effective UID
+     * of this process is root.
+     */
+    if ((!Myuid || Setuidroot) && Fncache) {
+        for (fh = HASHFSID(&Lf->psfid.psf_fsid), fs = *fh; fs; fs = fs->next) {
+            if (memcmp((void *)&fs->fsid, (void *)&Lf->psfid.psf_fsid, NFSID) ==
+                0)
+                break;
+        }
+        if (!fs)
+            fs = ncache_loadfs(&Lf->psfid.psf_fsid, fh);
+    } else
+        fs = (struct l_fic *)NULL;
+    /*
+     * Search the cache for an entry whose psfileid matches.
+     */
+    if (!fs || !fs->nc || !(lc = ncache_addr(&Lf->psfid))) {
+
+        /*
+         * If the node has no cache entry, see if it's the root of the file
+         * system.
+         */
+
+#    if defined(HASFSINO)
+        if (Lf->fs_ino && (Lf->inp_ty == 1) && (Lf->fs_ino == Lf->inode))
+            return (cp);
+#    endif /* defined(HASFSINO) */
+
+        /*
+         * If the file system's cache couldn't be loaded -- e.g., this lsof
+         * process lacks permission to load it or cache lookup is inhibited
+         * with -C -- but the UID of the file's process matches the UID of the
+         * lsof process, see if it's possible to read the single path name for
+         * this particular file.  (The file must have a non-zero opaque ID.)
+         */
+        if (!fs) {
+            if (Fncache && (Myuid == Lp->uid) &&
+                memcmp((void *)&Lf->opfid, (void *)&Nzpf, sizeof(Nzpf)) &&
+                (nl = pstat_getpathname(buf, (blen - 1), &Lf->opfid)) > 0) {
+                buf[nl] = '\0';
+                if (*buf == '/')
+                    *fp = 1;
+                return (buf);
+            }
+        }
+        return ((char *)NULL);
+    }
+    if (ncache_isroot(&lc->id)) {
+
+        /*
+         * If the node is the root of the file system, return a response
+         * that will cause the root directory to be displayed.
+         */
+        return (cp);
+    }
+    /*
+     * Start the path assembly.
+     */
+    if ((nl = lc->nl) > (blen - 1))
+        return ((char *)NULL);
+    cp = buf + blen - nl - 1;
+    rlen = blen - nl - 1;
+    (void)snpf(cp, nl + 1, "%s", lc->nm);
+    /*
+     * Look up the name cache entries that are parents of the node address.
+     * Quit when:
+     *
+     * there's no parent;
+     * the file system root is reached;
+     * the name length is too large to fit in the receiving buffer.
+     */
+    for (ef = 0; !ef;) {
+        if (!lc->pl) {
+            if (!lc->pls) {
+
+                /*
+                 * If there is a parent, look up its Ncache address;
+                 * otherwise quit on an incomplete path assembly.
+                 */
+                if (memcmp((void *)&lc->par, (void *)&Nzps, sizeof(Nzps))) {
+                    lc->pl = ncache_addr(&lc->par);
+                    lc->pls = 1;
+                } else
+                    break;
+            }
+        }
+        if (ncache_isroot(&lc->par)) {
+
+            /*
+             * If the parent entry is the file system root, enter the file
+             * system root directory, and indicate that the assembly should
+             * stop after this entry.
+             */
+            if (!(pc = Lf->fsdir))
+                break;
+            nl = (int)strlen(pc);
+            ef = 1;
+        } else {
+
+            /*
+             * Use the parent link if it exists; otherwise exit on an
+             * incomplete path assembly.
+             */
+            if (!(lc = lc->pl))
+                break;
+            pc = lc->nm;
+            nl = lc->nl;
+        }
+        /*
+         * Prefix the next path component.  Intersperse a '/' if the
+         * component doesn't end in one.
+         */
+        if (!nl)
+            break;
+        if (pc[nl - 1] != '/') {
+            if (1 > rlen)
+                break;
+            *(cp - 1) = '/';
+            cp--;
+            rlen--;
+        }
+        if (nl > rlen)
+            break;
+        (void)strncpy((cp - nl), pc, nl);
+        cp -= nl;
+        rlen -= nl;
+        if (ef) {
+
+            /*
+             * If the file system root directory was just prefixed, return
+             * a full-path indication.
+             */
+            *fp = 1;
+            break;
+        }
+    }
+    return (cp);
+}
+
+/*
+ * ncache_size() -- get DNLC size
+ */
+
+static void ncache_size() {
+    struct pst_dynamic pd;
+
+    if (pstat_getdynamic(&pd, sizeof(pd), 1, 0) != 1) {
+        (void)fprintf(stderr, "%s: can't get dynamic status\n", Pn);
+        Error(ctx);
+    }
+    Ndnlc = (int)pd.psd_dnlc_size;
+    for (Nceh = 1; Nceh < (Ndnlc + Ndnlc); Nceh <<= 1)
+        ;
+    Ncmask = Nceh - 1;
+}
+#endif /* defined(HASNCACHE) */
+
+/*
+ * print_dev() -- print device
+ */
+
+char *print_dev(struct lfile *lf, /* file whose device is to be printed */
+                dev_t *dev)       /* device to be printed */
+{
+    static char buf[128];
+
+    (void)snpf(buf, sizeof(buf), "%d,%#x", GET_MAJ_DEV(*dev),
+               GET_MIN_DEV(*dev));
+    return (buf);
+}
+
+/*
+ * process_finfo() -- process file information
+ */
+
+void process_finfo(pd, opfid, psfid,
+                   na) struct pst_filedetails *pd; /* file details */
+struct pst_fid *opfid;  /* opaque file ID for this file */
+struct psfileid *psfid; /* PSTAT file ID for this file */
+KA_T na;                /* node address */
+{
+    char *cp, buf[32];
+    enum lsof_file_type type;
+    uint32_t unknown_file_type_number = 0;
+    dev_t dev;
+    int devs = 0;
+    int32_t lk;
+    struct mounts *mp;
+    /*
+     * Save file IDs for later use in name lookup.
+     */
+    Lf->opfid = *opfid;
+    Lf->psfid = *psfid;
+
+#if defined(HASFSTRUCT)
+    /*
+     * Save node ID.
+     */
+    if (na) {
+        Lf->fna = na;
+        Lf->fsv |= FSV_NI;
+    }
+#endif /* defined(HASFSTRUCT) */
+
+    /*
+     * Construct lock code.
+     */
+    if ((lk = pd->psfd_lckflag) & PS_FPARTRDLCK)
+        Lf->lock = LSOF_LOCK_READ_PARTIAL;
+    else if (lk & PS_FPARTWRLCK)
+        Lf->lock = LSOF_LOCK_WRITE_PARTIAL;
+    else if (lk & PS_FFULLRDLCK)
+        Lf->lock = LSOF_LOCK_READ_FULL;
+    else if (lk & PS_FFULLWRLCK)
+        Lf->lock = LSOF_LOCK_WRITE_FULL;
+    else
+        Lf->lock = LSOF_LOCK_NONE;
+    /*
+     * Derive type from modes.
+     */
+    switch ((int)(pd->psfd_mode & PS_IFMT)) {
+    case PS_IFREG:
+        type = LSOF_FILE_REGULAR;
+        Ntype = N_REGLR;
+        break;
+    case PS_IFBLK:
+        type = LSOF_FILE_BLOCK;
+        Ntype = N_BLK;
+        break;
+    case PS_IFDIR:
+        type = LSOF_FILE_DIR;
+        Ntype = N_REGLR;
+        break;
+    case PS_IFCHR:
+        type = LSOF_FILE_CHAR;
+        Ntype = N_CHR;
+        break;
+    case PS_IFIFO:
+        type = LSOF_FILE_FIFO;
+        Ntype = N_FIFO;
+        break;
+    default:
+        type = LSOF_FILE_UNKNOWN_RAW;
+        unknown_file_type_number = (pd->psfd_mode & PS_IFMT) >> 12;
+        Ntype = N_REGLR;
+    }
+    if (Lf->type == LSOF_FILE_NONE) {
+        Lf->type = type;
+        Lf->unknown_file_type_number = unknown_file_type_number;
+    }
+    Lf->ntype = Ntype;
+    /*
+     * Save device number.
+     */
+    switch (Ntype) {
+    case N_FIFO:
+        (void)enter_dev_ch(print_kptr(na, (char *)NULL, 0));
+        break;
+    default:
+        dev = Lf->dev = (dev_t)pd->psfd_dev;
+        devs = Lf->dev_def = 1;
+        if ((Ntype == N_CHR) || (Ntype == N_BLK)) {
+            Lf->rdev = (dev_t)pd->psfd_rdev;
+            Lf->rdev_def = 1;
+        }
+    }
+    /*
+     * Save node number.
+     */
+    Lf->inode = (INODETYPE)pd->psfd_ino;
+    Lf->inp_ty = 1;
+    /*
+     * Save link count.
+     */
+
+    /*
+     * Ignore a zero link count only if the file is a FIFO.
+     */
+    if ((Lf->nlink = (long)pd->psfd_nlink) || (Ntype != N_FIFO))
+        Lf->nlink_def = 1;
+    if (Lf->nlink_def && Nlink && (Lf->nlink < Nlink))
+        Lf->sf |= SELNLINK;
+    /*
+     * Save file system identity.
+     */
+    if (devs) {
+        for (mp = readmnt(); mp; mp = mp->next) {
+            if (dev == mp->dev) {
+                Lf->fsdir = mp->dir;
+                Lf->fsdev = mp->fsname;
+
+#if defined(HASFSINO)
+                Lf->fs_ino = (unsigned long)mp->inode;
+#endif /* defined(HASFSINO) */
+
+                break;
+            }
+        }
+    } else
+        mp = (struct mounts *)NULL;
+    /*
+     * If no offset has been activated and no size saved, activate the offset or
+     * save the size.
+     */
+    if (!Lf->sz_def) {
+        switch (Ntype) {
+        case N_CHR:
+        case N_FIFO:
+            break;
+        default:
+            Lf->sz = (SZOFFTYPE)pd->psfd_size;
+            Lf->sz_def = 1;
+        }
+    }
+    /*
+     * See if this is an NFS file.
+     */
+    if (Fnfs) {
+        if (HasNFS < 0)
+            (void)scanmnttab();
+        if (HasNFS && mp && mp->is_nfs)
+            Lf->sf |= SELNFS;
+    }
+    /*
+     * Test for specified file.
+     */
+    if (Sfile &&
+        is_file_named(NULL, ((Ntype == N_CHR) || (Ntype == N_BLK) ? 1 : 0)))
+        Lf->sf |= SELNM;
+    /*
+     * Enter name characters.
+     */
+    if (!Lf->nm && Namech[0])
+        enter_nm(Namech);
+}
diff --git a/lib/dialects/hpux/pstat/dlsof.h b/lib/dialects/hpux/pstat/dlsof.h
new file mode 100644 (file)
index 0000000..2e123fd
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ * dlsof.h - pstat-based HP-UX header file for lsof
+ */
+
+/*
+ * Copyright 1999 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.8 2008/10/21 16:17:50 abe Exp $
+ */
+
+#if !defined(HPUX_LSOF_H)
+#    define HPUX_LSOF_H 1
+
+#    include <stddef.h>
+#    include <stdlib.h>
+#    include <dirent.h>
+#    include <mntent.h>
+#    include <setjmp.h>
+#    include <string.h>
+#    include <unistd.h>
+
+#    include <arpa/inet.h>
+#    include <netinet/in.h>
+
+#    if defined(HASIPv6)
+#        include <netinet/in6.h>
+#    endif /* defined(HASIPv6) */
+
+#    include <rpc/types.h>
+#    include <rpc/rpc.h>
+#    include <rpc/pmap_prot.h>
+
+#    include <sys/fstyp.h>
+#    include <sys/mount.h>
+#    include <sys/param.h>
+#    include <sys/pstat.h>
+
+#    if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 &&               \
+        defined(_APP32_64BIT_OFF_T)
+#        define TMP_APP32_64BIT_OFF_T _APP32_64BIT_OFF_T
+#        undef _APP32_64BIT_OFF_T
+#    endif
+
+#    if !defined(__LP64__) && defined(_LARGEFILE64_SOURCE) && HPUXV >= 1123
+/*
+ * Make sure a 32 bit lsof for HPUX>=1123 uses [l]stat64 when
+ * _LARGEFILE64_SOURCE is defined.
+ */
+
+#        define stat stat64
+#        define lstat lstat64
+#    endif /* !defined(__LP64__) && defined(_LARGEFILE64_SOURCE) &&            \
+            * HPUXV>=1123                                                      \
+            */
+
+#    include <sys/socket.h>
+
+#    if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 &&               \
+        defined(_APP32_64BIT_OFF_T)
+#        define _APP32_64BIT_OFF_T TMP_APP32_64BIT_OFF_T
+#        undef TMP_APP32_64BIT_OFF_T
+#    endif
+
+#    include <sys/tihdr.h>
+#    include <sys/un.h>
+
+/*
+ * This definition is needed for the common function prototype definitions
+ * in "proto.h".  The /proc-based lsof also uses it to make sure its
+ * manufactured node ID number has 64 bits.
+ */
+
+typedef unsigned long long KA_T;
+#    define KA_T_FMT_X "%#llx"
+
+/*
+ * Local definitions
+ */
+
+#    if defined(HAS_CONST)
+#        define COMP_P const void
+#    else /* !defined(HAS_CONST) */
+#        define COMP_P void
+#    endif /* defined(HAS_CONST) */
+
+#    define DEVINCR 1024 /* device table malloc() increment */
+#    define MALLOC_P void
+#    define FREE_P void
+#    define MALLOC_S unsigned
+#    define MOUNTED MNT_MNTTAB
+#    define QSORT_P void
+#    define READLEN_T int
+#    define STRNCPY_L size_t
+#    define SZOFFTYPE unsigned long long
+#    define SZOFFPSPEC "ll" /* SZOFFTYPE printf specification modifier */
+#    define XDR_PMAPLIST (xdrproc_t) xdr_pmaplist
+#    define XDR_VOID (xdrproc_t) xdr_void
+
+/*
+ * Local macros
+ */
+
+#    define IS_PSFILEID(p) ((p)->psf_fsid.psfs_id || (p)->psf_fsid.psfs_type)
+/* is psfiled active? */
+
+/*
+ * Global storage definitions (including their structure definitions)
+ */
+
+extern _T_LONG_T CloneMaj; /* clone major device number */
+extern int HaveCloneMaj;   /* clone major status */
+
+struct mounts {
+    char *dir;           /* directory (mounted on) */
+    char *fsname;        /* file system
+                          * (symbolic links unresolved) */
+    char *fsnmres;       /* file system
+                          * (symbolic links resolved) */
+    char *mnt_fstype;    /* file system type -- e.g.,
+                          * MNTTYPE_NFS */
+    int stat_fstype;     /* st_fstype */
+    dev_t dev;           /* directory st_dev */
+    dev_t rdev;          /* directory st_rdev */
+    INODETYPE inode;     /* directory st_ino */
+    mode_t mode;         /* directory st_mode */
+    mode_t fs_mode;      /* file system st_mode */
+    u_char is_nfs;       /* file system type is MNTTYPE_NFS or
+                          * MNTTYPE_NFS3 */
+    struct mounts *next; /* forward link */
+};
+
+struct sfile {
+    char *aname;        /* argument file name */
+    char *name;         /* file name (after readlink()) */
+    char *devnm;        /* device name (optional) */
+    dev_t dev;          /* device */
+    dev_t rdev;         /* raw device */
+    u_short mode;       /* S_IFMT mode bits from stat() */
+    int type;           /* file type: 0 = file system
+                         *           1 = regular file */
+    INODETYPE i;        /* inode number */
+    int f;              /* file found flag */
+    struct sfile *next; /* forward link */
+};
+
+extern char **Fsinfo;
+extern int Fsinfomax;
+extern int HasNFS;
+
+/*
+ * Definitions for dvch.c, isfn.c, and rdev.c
+ */
+
+#    define CLONEMAJ CloneMaj /* clone major variable name */
+#    define DIRTYPE dirent
+#    define HASDNAMLEN 1              /* DIRTYPE has d_namlen element */
+#    define HAS_STD_CLONE 1           /* uses standard clone structure */
+#    define HAVECLONEMAJ HaveCloneMaj /* clone major status variable name */
+#    define MAXSYSCMDL (PST_UCOMMLEN - 1)
+/* max system command name length */
+
+/*
+ * Definition for rmnt.c
+ */
+
+#    define MNTSKIP                                                            \
+        {                                                                      \
+            if (strcmp(mp->mnt_type, MNTTYPE_IGNORE) == 0)                     \
+                continue;                                                      \
+        }
+#    define RMNT_FSTYPE mnt_type
+#    define MOUNTS_FSTYPE mnt_fstype
+
+#    if defined(HASFSTYPE) && HASFSTYPE == 2
+#        define RMNT_STAT_FSTYPE st_fstype
+#        define MOUNTS_STAT_FSTYPE stat_fstype
+#    endif /* defined(HASFSTYPE) && HASFSTYPE==2 */
+
+struct lsof_context_dialect {};
+
+#endif /* HPUX_LSOF_H */
diff --git a/lib/dialects/hpux/pstat/dproc.c b/lib/dialects/hpux/pstat/dproc.c
new file mode 100644 (file)
index 0000000..aca6010
--- /dev/null
@@ -0,0 +1,845 @@
+/*
+ * dproc.c -- pstat-based HP-UX process access functions for lsof
+ */
+
+/*
+ * Copyright 1999 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 1999 Purdue Research Foundation.\nAll rights reserved.\n";
+#endif
+
+#include "common.h"
+
+/*
+ * Local definitions
+ */
+
+#define FDS_ALLOC_INCR 256 /* fds[] allocation increment */
+#define FDS_ALLOC_INIT 64  /* initial fds[] allocation */
+#define FINFOINCR                                                              \
+    128 /* pst_fileinfo2 table allocation                                      \
+         * increment */
+#define INCLMEM(s, m)                                                          \
+    ((size_t)(offsetof(struct s, m) + sizeof(((struct s *)0)->m)))
+/* size of struct s, including
+ * member m */
+#define PSTATINCR                                                              \
+    512 /* pst_status table allocation                                         \
+         * increment */
+#define TXTVMINCR                                                              \
+    64 /* text and vm info table table                                         \
+        * allocation increment */
+#define VMREGINCR                                                              \
+    64 /* VM region table table allocation                                     \
+        * increment */
+
+/*
+ * Local structures
+ */
+
+struct pstatck {
+    size_t moff; /* offset of size member in pst_static
+                  * -- from offsetof(...member) */
+    size_t msz;  /* structure's pst_static member
+                  * inclusion size -- from INCLMEM(s, m)
+                  * macro */
+    size_t ssz;  /* structure size -- from
+                  * sizeof(struct) */
+    char *sn;    /* structure name */
+} PstatCk[] = {
+    {(size_t)offsetof(struct pst_static, pst_status_size),
+     (size_t)INCLMEM(pst_static, pst_status_size), sizeof(struct pst_status),
+     "pst_status"},
+    {(size_t)offsetof(struct pst_static, pst_vminfo_size),
+     (size_t)INCLMEM(pst_static, pst_vminfo_size), sizeof(struct pst_vminfo),
+     "pst_vminfo"},
+    {(size_t)offsetof(struct pst_static, pst_filedetails_size),
+     (size_t)INCLMEM(pst_static, pst_filedetails_size),
+     sizeof(struct pst_filedetails), "pst_filedetails"},
+    {(size_t)offsetof(struct pst_static, pst_socket_size),
+     (size_t)INCLMEM(pst_static, pst_socket_size), sizeof(struct pst_socket),
+     "pst_socket"},
+    {(size_t)offsetof(struct pst_static, pst_stream_size),
+     (size_t)INCLMEM(pst_static, pst_stream_size), sizeof(struct pst_stream),
+     "pst_stream"},
+    {(size_t)offsetof(struct pst_static, pst_mpathnode_size),
+     (size_t)INCLMEM(pst_static, pst_mpathnode_size),
+     sizeof(struct pst_mpathnode), "pst_mpathnode"},
+    {(size_t)offsetof(struct pst_static, pst_fileinfo2_size),
+     (size_t)INCLMEM(pst_static, pst_fileinfo2_size),
+     sizeof(struct pst_fileinfo2), "pst_fileinfo2"},
+};
+#define NPSTATCK (sizeof(PstatCk) / sizeof(struct pstatck))
+
+/*
+ * Local static variables
+ */
+
+static int HvRtPsfid = -1;      /* "/" psfileid status:
+                                 *     -1: not yet tested;
+                                 *     0: tested and unknown;
+                                 *     1: tested and known */
+static struct psfileid RtPsfid; /* "/" psfileid */
+
+/*
+ * Local function prototypes
+ */
+
+static void get_kernel_access(void);
+static void process_text(struct pst_status *p);
+static struct pst_fileinfo2 *read_files(struct pst_status *p, int *n);
+static struct pst_status *read_proc(int *n);
+static struct pst_vm_status *read_vmreg(struct pst_status *p, int *n);
+
+/*
+ * gather_proc_info() -- gather process information
+ */
+
+void gather_proc_info() {
+    short cckreg; /* conditional status of regular file
+                   * checking:
+                   *     0 = unconditionally check
+                   *     1 = conditionally check */
+    short ckscko; /* socket file only checking status:
+                   *     0 = none
+                   *     1 = check only socket files,
+                   *      including TCP and UDP
+                   *      streams with eXPORT data,
+                   *      where supported */
+    int cwds, fd, *fds, fdsa, i, j, l, nf, np, rtds;
+    struct pst_fileinfo2 *f;
+    long flag;
+    KA_T ka, na;
+    MALLOC_S nb;
+    struct pst_status *p;
+    struct pst_filedetails pd;
+    struct pst_socket *s;
+    short pss, sf;
+    /*
+     * Compute current working and root directory statuses and the statuses of
+     * the first FDS_ALLOC_INIT FDs.
+     */
+    if (Fand && Fdl) {
+        cwds = (ck_fd_status(LSOF_FD_CWD, -1) != 2) ? 0 : 1;
+        rtds = (ck_fd_status(LSOF_FD_ROOT_DIR, -1) != 2) ? 0 : 1;
+        nb = (MALLOC_S)(sizeof(int) * FDS_ALLOC_INIT);
+        if (!(fds = (int *)malloc(nb))) {
+            (void)fprintf(stderr, "%s: can't allocate %d FD status entries\n",
+                          Pn, FDS_ALLOC_INIT);
+            Error(ctx);
+        }
+        for (fdsa = 0; fdsa < FDS_ALLOC_INIT; fdsa++) {
+            if (Fand && Fdl)
+                fds[fdsa] = (ck_fd_status(LSOF_FD_NUMERIC, fdsa) == 2) ? 1 : 0;
+            else
+                fds[fdsa] = 1;
+        }
+    } else {
+        cwds = rtds = 1;
+        fdsa = 0;
+        fds = (int *)NULL;
+    }
+    /*
+     * 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;
+    }
+    /*
+     * Examine proc structures and their associated information.
+     */
+    for (i = 0, p = read_proc(&np); i < np; i++, p++) {
+        if (!p->pst_stat || p->pst_stat == PS_ZOMBIE)
+            continue;
+        if (is_proc_excl((int)p->pst_pid, (int)p->pst_pgrp, (UID_ARG)p->pst_uid,
+                         &pss, &sf))
+            continue;
+        /*
+         * Make sure the command name is NUL-terminated.
+         */
+        p->pst_ucomm[PST_UCOMMLEN - 1] = '\0';
+        if (is_cmd_excl(p->pst_ucomm, &pss, &sf))
+            continue;
+        if (cckreg) {
+
+            /*
+             * If conditional checking of regular files is enabled, enable
+             * socket file only checking, based on the process' selection
+             * status.
+             */
+            ckscko = (sf & SelProc) ? 0 : 1;
+        }
+        alloc_lproc((int)p->pst_pid, (int)p->pst_pgrp, (int)p->pst_ppid,
+                    (UID_ARG)p->pst_uid, p->pst_ucomm, (int)pss, (int)sf);
+        Plf = (struct lfile *)NULL;
+        /*
+         * Save current working directory information.
+         */
+        if (!ckscko && cwds && IS_PSFILEID(&p->pst_cdir) &&
+            (p->pst_cdir.psf_fileid > 0)) {
+            alloc_lfile(ctx, LSOF_FD_CWD, -1);
+            if ((na = read_det(&p->pst_fid_cdir, p->pst_hi_fileid_cdir,
+                               p->pst_lo_fileid_cdir, p->pst_hi_nodeid_cdir,
+                               p->pst_lo_nodeid_cdir, &pd)))
+                (void)process_finfo(&pd, &p->pst_fid_cdir, &p->pst_cdir, na);
+            else {
+                (void)snpf(Namech, Namechl, "can't read %s pst_filedetails%s%s",
+                           CWD, errno ? ": " : "",
+                           errno ? strerror(errno) : "");
+                enter_nm(Namech);
+            }
+            if (Lf->sf)
+                link_lfile();
+        }
+        /*
+         * Save root directory information.
+         */
+        if (!ckscko && rtds && IS_PSFILEID(&p->pst_rdir) &&
+            (p->pst_rdir.psf_fileid > 0)) {
+            if (HvRtPsfid < 0)
+                (void)scanmnttab();
+            if (!HvRtPsfid || memcmp((void *)&RtPsfid, (void *)&p->pst_rdir,
+                                     sizeof(RtPsfid))) {
+                alloc_lfile(ctx, LSOF_FD_ROOT_DIR, -1);
+                if ((na = read_det(&p->pst_fid_rdir, p->pst_hi_fileid_rdir,
+                                   p->pst_lo_fileid_rdir, p->pst_hi_nodeid_rdir,
+                                   p->pst_lo_nodeid_rdir, &pd)))
+                    (void)process_finfo(&pd, &p->pst_fid_rdir, &p->pst_rdir,
+                                        na);
+                else {
+                    (void)snpf(Namech, Namechl,
+                               "can't read %s pst_filedetails%s%s", RTD,
+                               errno ? ": " : "", errno ? strerror(errno) : "");
+                    enter_nm(Namech);
+                }
+                if (Lf->sf)
+                    link_lfile();
+            }
+        }
+        /*
+         * Print information on the text files.
+         */
+        if (!ckscko)
+            (void)process_text(p);
+        /*
+         * Loop through user's files.
+         */
+        for (j = 0, f = read_files(p, &nf); j < nf; j++, f++) {
+            fd = (int)f->psf_fd;
+            /*
+             * Check FD status and allocate local file space, as required.
+             */
+            if (Fand && Fdl && fds) {
+
+                /*
+                 * Check and update the FD status array.
+                 */
+                if (fd >= fdsa) {
+                    for (l = fdsa; l <= fd; l += FDS_ALLOC_INCR)
+                        ;
+                    nb = (MALLOC_S)(l * sizeof(int));
+                    if (!(fds = (int *)realloc((MALLOC_P *)fds, nb))) {
+                        (void)fprintf(
+                            stderr,
+                            "%s: can't reallocate %d FD status entries\n", Pn,
+                            l);
+                        Error(ctx);
+                    }
+                    while (fdsa < l) {
+                        fds[fdsa] =
+                            (ck_fd_status(LSOF_FD_NUMERIC, fdsa) == 2) ? 1 : 0;
+                        fdsa++;
+                    }
+                }
+                if (!fds[fd])
+                    continue;
+            }
+            alloc_lfile(ctx, LSOF_FD_NUMERIC, (int)f->psf_fd);
+            /*
+             * Construct access code.
+             */
+            if ((flag = (long)(f->psf_flag & ~PS_FEXCLOS)) == (long)PS_FRDONLY)
+                Lf->access = LSOF_FILE_ACCESS_READ;
+            else if (flag == (long)PS_FWRONLY)
+                Lf->access = LSOF_FILE_ACCESS_WRITE;
+            else
+                Lf->access = LSOF_FILE_ACCESS_READ_WRITE;
+
+#if defined(HASFSTRUCT)
+            /*
+             * Save file structure values.
+             */
+            Lf->fct = (long)f->psf_count;
+            Lf->fsv |= FSV_CT;
+            ka = (((KA_T)(f->psf_hi_fileid & 0xffffffff) << 32) |
+                  (KA_T)(f->psf_lo_fileid & 0xffffffff));
+            if ((Lf->fsa = ka))
+                Lf->fsv |= FSV_FA;
+            Lf->ffg = flag;
+            Lf->fsv |= FSV_FG;
+            Lf->pof = (long)(f->psf_flag & PS_FEXCLOS);
+#endif /* defined(HASFSTRUCT) */
+
+            /*
+             * Save file offset.  _PSTAT64 should alwaus be defined, but just
+             * to be safe, check for it.
+             */
+
+#if defined(_PSTAT64)
+            Lf->off = (SZOFFTYPE)f->_PSF_OFFSET64;
+#else  /* !defined(_PSTAT64) */
+            Lf->off = (SZOFFTYPE)f->psf_offset;
+#endif /* defined(_PSTAT64) */
+            Lf->off_def = 1;
+
+            /*
+             * Process the file by its type.
+             */
+            switch (f->psf_ftype) {
+            case PS_TYPE_VNODE:
+                if (ckscko || Selinet)
+                    break;
+                if ((na = read_det(&f->psf_fid, f->psf_hi_fileid,
+                                   f->psf_lo_fileid, f->psf_hi_nodeid,
+                                   f->psf_lo_nodeid, &pd)))
+                    (void)process_finfo(&pd, &f->psf_fid, &f->psf_id, na);
+                else {
+                    (void)snpf(Namech, Namechl,
+                               "can't read pst_filedetails%s%s",
+                               errno ? ": " : "", errno ? strerror(errno) : "");
+                    enter_nm(Namech);
+                }
+                break;
+            case PS_TYPE_SOCKET:
+                switch (f->psf_subtype) {
+                case PS_SUBTYPE_SOCK:
+                    (void)process_socket(f, (struct pst_socket *)NULL);
+                    break;
+                case PS_SUBTYPE_SOCKSTR:
+                    if ((s = read_sock(f)))
+                        (void)process_socket(f, s);
+                    else
+                        (void)process_stream(f, (int)ckscko);
+                    break;
+                default:
+                    (void)snpf(Namech, Namechl, "unknown socket sub-type: %d",
+                               (int)f->psf_subtype);
+                    enter_nm(Namech);
+                }
+                break;
+            case PS_TYPE_STREAMS:
+                (void)process_stream(f, (int)ckscko);
+                break;
+            case PS_TYPE_UNKNOWN:
+                Lf->type = LSOF_FILE_UNKNOWN;
+                (void)enter_nm("no more information");
+                break;
+            case PS_TYPE_UNSP:
+                Lf->type = LSOF_FILE_UNSUPPORTED;
+                (void)enter_nm("no more information");
+                break;
+            case PS_TYPE_LLA:
+                Lf->type = LSOF_FILE_LINK_LEVEL_ACCESS;
+                (void)enter_nm("no more information");
+                break;
+            }
+            if (Lf->sf)
+                link_lfile();
+        }
+        /*
+         * Examine results.
+         */
+        if (examine_lproc())
+            return;
+    }
+}
+
+/*
+ * get_kernel_access() -- access the required information in the kernel
+ */
+
+static void get_kernel_access() {
+    int err = 0;
+    int i;
+    struct pst_static pst;
+    _T_LONG_T *szp;
+    /*
+     * Check the kernel version.
+     */
+    (void)ckkv("HP-UX", LSOF_VSTR, (char *)NULL, (char *)NULL);
+    /*
+     * Check PSTAT support.  First make sure we can read pst_static up through
+     * its pst_static_size member.  If not, quit.  If we can, read the full
+     * pst_static structure.
+     */
+    if (pstat_getstatic(&pst, (size_t)INCLMEM(pst_static, pst_static_size), 1,
+                        0) != 1) {
+        (void)fprintf(stderr,
+                      "%s: FATAL: can't determine PSTAT static size: %s\n", Pn,
+                      strerror(errno));
+        Error(ctx);
+    }
+    if (pstat_getstatic(&pst, (size_t)pst.pst_static_size, 1, 0) != 1) {
+        (void)fprintf(stderr, "%s: FATAL: can't read %ld bytes of pst_static\n",
+                      Pn, (long)pst.pst_static_size);
+        Error(ctx);
+    }
+    /*
+     * Check all the pst_static members defined in PstatCk[].
+     */
+    for (i = 0; i < NPSTATCK; i++) {
+        if (pst.pst_static_size < PstatCk[i].msz) {
+            (void)fprintf(stderr,
+                          "%s: FATAL: pst_static doesn't contain %s_size\n", Pn,
+                          PstatCk[i].sn);
+            err = 1;
+            continue;
+        }
+        szp = (_T_LONG_T *)(((char *)&pst) + PstatCk[i].moff);
+        if (*szp < PstatCk[i].ssz) {
+            (void)fprintf(stderr,
+                          "%s: FATAL: %s_size should be: %llu; is %llu\n", Pn,
+                          PstatCk[i].sn, (unsigned long long)PstatCk[i].ssz,
+                          (unsigned long long)*szp);
+            err = 1;
+        }
+    }
+    /*
+     * Save the clone major device number, if pst_static is big enough to hold
+     * it.
+     */
+    if (pst.pst_static_size >= (size_t)INCLMEM(pst_static, clonemajor)) {
+        CloneMaj = pst.clonemajor;
+        HaveCloneMaj = 1;
+    }
+    if (!err)
+        return;
+    Error(ctx);
+}
+
+/*
+ * initialize() -- perform all initialization
+ */
+
+void initialize() { get_kernel_access(); }
+
+/*
+ * process_text() -- process text access information
+ */
+
+static void process_text(p) struct pst_status *p; /* pst_status for process */
+{
+    int i, j, nr, ntvu;
+    int meme = 0;
+    static int mems = -1;
+    KA_T na;
+    MALLOC_S nb;
+    static int ntva;
+    struct pst_vm_status *rp;
+    static int txts = -1;
+    struct txtvm {
+        enum lsof_fd_type fd;
+        struct pst_fid opfid;
+        struct psfileid psfid;
+        KA_T na;
+        struct pst_filedetails pd;
+    };
+    static struct txtvm *tv = (struct txtvm *)NULL;
+    /*
+     * Get and remember "mem" and "txt" FD statuses.
+     */
+    if (mems < 0) {
+        if (Fand && Fdl)
+            mems = (ck_fd_status(LSOF_FD_MEMORY, -1) == 2) ? 1 : 0;
+        else
+            mems = 1;
+    }
+    if (txts < 0) {
+        if (Fand && Fdl)
+            txts = (ck_fd_status(LSOF_FD_PROGRAM_TEXT, -1) == 2) ? 1 : 0;
+        else
+            txts = 1;
+    }
+    if (!mems && !txts)
+        return;
+    /*
+     * Pre-allocate sufficient tv[] space for text file.
+     */
+    if (!tv) {
+        ntva = TXTVMINCR;
+        nb = (MALLOC_S)(ntva * sizeof(struct txtvm));
+        if (!(tv = (struct txtvm *)malloc(nb))) {
+
+        no_txtvm_space:
+
+            (void)fprintf(stderr,
+                          "%s: no memory for text and VM info array; PID: %d\n",
+                          Pn, (int)p->pst_pid);
+            Error(ctx);
+        }
+    }
+    /*
+     * Enter text file in tv[], if possible.
+     */
+    if (txts && IS_PSFILEID(&p->pst_text) && (p->pst_text.psf_fileid > 0)) {
+        if ((na = read_det(&p->pst_fid_text, p->pst_hi_fileid_text,
+                           p->pst_lo_fileid_text, p->pst_hi_nodeid_text,
+                           p->pst_lo_nodeid_text, &tv[0].pd))) {
+            tv[0].fd = LSOF_FD_PROGRAM_TEXT;
+            tv[0].na = na;
+            tv[0].opfid = p->pst_fid_text;
+            tv[0].psfid = p->pst_text;
+            ntvu = 1;
+        } else {
+            alloc_lfile(ctx, LSOF_FD_PROGRAM_TEXT, -1);
+            (void)snpf(Namech, Namechl, "can't read txt pst_filedetails%s%s",
+                       errno ? ": " : "", errno ? strerror(errno) : "");
+            enter_nm(Namech);
+            if (Lf->sf)
+                link_lfile();
+            ntvu = 0;
+        }
+    } else
+        ntvu = 0;
+    /*
+     * Get unique VM regions.
+     */
+    if (mems) {
+        for (i = 0, rp = read_vmreg(p, &nr); (i < nr); i++, rp++) {
+
+            /*
+             * Skip duplicate regions.
+             */
+            for (j = 0; j < ntvu; j++) {
+                if (memcmp((void *)&rp->pst_id, (void *)&tv[j].psfid,
+                           sizeof(struct psfileid)) == 0)
+                    break;
+            }
+            if (j < ntvu)
+                continue;
+            /*
+             * Make sure there's tv[] space for this region.
+             */
+            if (ntvu >= ntva) {
+                ntva += TXTVMINCR;
+                nb = (MALLOC_S)(ntva * sizeof(struct txtvm));
+                if (!(tv = (struct txtvm *)realloc((MALLOC_P *)tv, nb)))
+                    goto no_txtvm_space;
+            }
+            /*
+             * See if we can read the file details for this region.
+             */
+            if ((na = read_det(&rp->pst_fid, rp->pst_hi_fileid,
+                               rp->pst_lo_fileid, rp->pst_hi_nodeid,
+                               rp->pst_lo_nodeid, &tv[ntvu].pd))) {
+                tv[ntvu].fd = LSOF_FD_MEMORY;
+                tv[ntvu].na = na;
+                tv[ntvu].opfid = rp->pst_fid;
+                tv[ntvu].psfid = rp->pst_id;
+                ntvu++;
+            } else if (!meme) {
+                alloc_lfile(ctx, LSOF_FD_MEMORY, -1);
+                (void)snpf(Namech, Namechl,
+                           "can't read mem pst_filedetails%s%s",
+                           errno ? ": " : "", errno ? strerror(errno) : "");
+                enter_nm(Namech);
+                if (Lf->sf)
+                    link_lfile();
+                meme = 1;
+            }
+        }
+    }
+    /*
+     * Process information for unique regions.
+     */
+    for (i = 0; i < ntvu; i++) {
+        alloc_lfile(ctx, tv[i].fd, -1);
+        (void)process_finfo(&tv[i].pd, &tv[i].opfid, &tv[i].psfid, tv[i].na);
+        if (Lf->sf)
+            link_lfile();
+    }
+}
+
+/*
+ * read_det() -- read the pst_filedetails structure
+ */
+
+KA_T read_det(struct pst_fid *ki,         /* kernel file ID */
+              uint32_t hf,                /* high file ID bits */
+              uint32_t lf,                /* low file ID bits */
+              uint32_t hn,                /* high node ID bits */
+              uint32_t ln,                /* low node ID bits */
+              struct pst_filedetails *pd) /* details receiver */
+{
+    KA_T na;
+
+    errno = 0;
+    na = (KA_T)(((KA_T)(hn & 0xffffffff) << 32) | (KA_T)(ln & 0xffffffff));
+    if (pstat_getfiledetails(pd, sizeof(struct pst_filedetails), ki) <= 0 ||
+        hf != pd->psfd_hi_fileid || lf != pd->psfd_lo_fileid ||
+        hn != pd->psfd_hi_nodeid || ln != pd->psfd_lo_nodeid)
+        return ((KA_T)0);
+    return (na);
+}
+
+/*
+ * read_files() -- read the file descriptor information for a process
+ */
+
+static struct pst_fileinfo2 *
+read_files(struct pst_status *p, /* pst_status for the process */
+           int *n)               /* returned fi[] entry count */
+{
+    size_t ec;
+    static struct pst_fileinfo2 *fi = (struct pst_fileinfo2 *)NULL;
+    MALLOC_S nb;
+    int nf = 0;
+    static int nfa = 0;
+    int rc;
+    static size_t sz = sizeof(struct pst_fileinfo2);
+    /*
+     * Read the pst_fileinfo2 information for all files of the process
+     * into fi[].
+     */
+    do {
+        if (nf >= nfa) {
+
+            /*
+             * Increase the size of fi[].
+             */
+            nfa += FINFOINCR;
+            nb = (MALLOC_S)(nfa * sizeof(struct pst_fileinfo2));
+            if (!fi)
+                fi = (struct pst_fileinfo2 *)malloc(nb);
+            else
+                fi = (struct pst_fileinfo2 *)realloc((MALLOC_P *)fi, nb);
+            if (!fi) {
+                (void)fprintf(stderr,
+                              "%s: can't allocate %d bytes for pst_filinfo\n",
+                              Pn, nb);
+                Error(ctx);
+            }
+        }
+        /*
+         * Read the next block of pst_fileinfo2 structures.
+         */
+        ec = (size_t)(nfa - nf);
+        if ((rc = pstat_getfile2(fi + nf, sz, ec, nf, p->pst_pid)) > 0) {
+            nf += rc;
+            if (rc < (int)ec)
+                rc = 0;
+        }
+    } while (rc > 0);
+    *n = nf;
+    return (fi);
+}
+
+/*
+ * read_proc() -- read process table status information
+ */
+
+static struct pst_status *read_proc(int *n) /* returned ps[] entry count */
+{
+    size_t el;
+    int i = 0;
+    MALLOC_S nb;
+    int np = 0;
+    static int npa = 0;
+    static struct pst_status *ps = (struct pst_status *)NULL;
+    int rc;
+    size_t sz = sizeof(struct pst_status);
+    /*
+     * Read the pst_status information for all processes into ps[].
+     */
+    do {
+        if (np >= npa) {
+
+            /*
+             * Increase the size of ps[].
+             */
+            npa += PSTATINCR;
+            nb = (MALLOC_S)(npa * sizeof(struct pst_status));
+            if (!ps)
+                ps = (struct pst_status *)malloc(nb);
+            else
+                ps = (struct pst_status *)realloc((MALLOC_P *)ps, nb);
+            if (!ps) {
+
+            ps_alloc_error:
+                (void)fprintf(
+                    stderr,
+                    "%s: can't allocate %d bytes for pst_status table\n", Pn,
+                    nb);
+                Error(ctx);
+            }
+        }
+        /*
+         * Read the next block of pst_status structures.
+         */
+        el = (size_t)(npa - np);
+        if ((rc = pstat_getproc(ps + np, sz, el, i)) > 0) {
+            np += rc;
+            i = (ps + np - 1)->pst_idx + 1;
+            if (rc < el)
+                rc = 0;
+        }
+    } while (rc > 0);
+    /*
+     * Reduce ps[] to a minimum, unless repeat mode is in effect.
+     */
+    if (!RptTm && ps && np && (np < npa)) {
+        nb = (MALLOC_S)(np * sizeof(struct pst_status));
+        if (!(ps = (struct pst_status *)realloc((MALLOC_P *)ps, nb)))
+            goto ps_alloc_error;
+    }
+    *n = np;
+    return (ps);
+}
+
+/*
+ * read_vmreg() -- read info about the VM regions of a process
+ */
+
+static struct pst_vm_status *
+read_vmreg(struct pst_status *p, /* pst_status for process */
+           int *n)               /* returned region count */
+{
+    size_t ec = (size_t)p->pst_pid;
+    MALLOC_S nb;
+    int nr, rx;
+    static int nra = 0;
+    struct pst_vm_status *rp;
+    static struct pst_vm_status *reg = (struct pst_vm_status *)NULL;
+    size_t sz = sizeof(struct pst_vm_status);
+    /*
+     * Read all VM region information for the process.
+     */
+    for (nr = rx = 0;; rx++) {
+        if (nr >= nra) {
+
+            /*
+             * Increase the region table size.
+             */
+            nra += VMREGINCR;
+            nb = (MALLOC_S)(nra * sizeof(struct pst_vm_status));
+            if (!reg)
+                reg = (struct pst_vm_status *)malloc(nb);
+            else
+                reg = (struct pst_vm_status *)realloc((MALLOC_P *)reg, nb);
+            if (!reg) {
+                (void)fprintf(stderr,
+                              "%s: can't allocate %d bytes for pst_vm_status\n",
+                              Pn, nb);
+                Error(ctx);
+            }
+        }
+        /*
+         * Read the pst_vm_status structure for the next region.
+         */
+        rp = reg + nr;
+        if (pstat_getprocvm(rp, sz, ec, rx) != 1)
+            break;
+        if (IS_PSFILEID(&rp->pst_id) && (rp->pst_id.psf_fileid > 0))
+            nr++;
+    }
+    *n = nr;
+    return (reg);
+}
+
+/*
+ * scanmnttab() -- scan mount table
+ */
+
+extern void scanmnttab() {
+    struct mounts *mp;
+    /*
+     * Scan the mount table to identify NFS file systems and form the psfileid
+     * for "/".
+     *
+     * This function allows the mount table scan to be deferred until its
+     * information is needed.
+     */
+    if ((HvRtPsfid >= 0) && (HasNFS >= 0))
+        return;
+    (void)memset((void *)&RtPsfid, 0, sizeof(RtPsfid));
+    for (HasNFS = HvRtPsfid = 0, mp = readmnt(); mp; mp = mp->next) {
+        if (mp->MOUNTS_FSTYPE &&
+            (strcmp(mp->MOUNTS_FSTYPE, MNTTYPE_NFS) == 0 ||
+             strcmp(mp->MOUNTS_FSTYPE, MNTTYPE_NFS3) == 0)) {
+            HasNFS = 1;
+            mp->is_nfs = 1;
+        } else
+            mp->is_nfs = 0;
+        if (!HvRtPsfid && !strcmp(mp->dir, "/")) {
+            HvRtPsfid = 1;
+            RtPsfid.psf_fsid.psfs_id = mp->dev;
+            RtPsfid.psf_fsid.psfs_type = mp->MOUNTS_STAT_FSTYPE;
+            RtPsfid.psf_fileid = mp->inode;
+        }
+    }
+}
diff --git a/lib/dialects/hpux/pstat/dproto.h b/lib/dialects/hpux/pstat/dproto.h
new file mode 100644 (file)
index 0000000..6e17a1f
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * dproto.h - pstat-based HP-UX function prototypes for lsof
+ *
+ * The _PROTOTYPE macro is defined in the common proto.h.
+ */
+
+/*
+ * Copyright 1999 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.5 2008/10/21 16:17:50 abe Exp $
+ */
+
+extern int get_max_fd(void);
+extern int is_file_named(char *p, int cd);
+extern void process_finfo(struct pst_filedetails *pd, struct pst_fid *opfid,
+                          struct psfileid *psfid, KA_T na);
+extern void process_socket(struct pst_fileinfo2 *f, struct pst_socket *s);
+extern void process_stream(struct pst_fileinfo2 *f, int ckscko);
+extern KA_T read_det(struct pst_fid *ki, uint32_t hf, uint32_t lf, uint32_t hn,
+                     uint32_t ln, struct pst_filedetails *pd);
+extern struct pst_socket *read_sock(struct pst_fileinfo2 *f);
+
+#if defined(HASIPv6)
+extern struct hostent *gethostbyname2(char *nm, int proto);
+#endif /* defined(HASIPv6) */
+
+#if defined(HASVXFS)
+extern int read_vxnode(struct vnode *v, struct l_vfs *vfs, dev_t *dev);
+#endif /* defined(HASVXFS) */
+
+extern void scanmnttab(void);
diff --git a/lib/dialects/hpux/pstat/dsock.c b/lib/dialects/hpux/pstat/dsock.c
new file mode 100644 (file)
index 0000000..bc8b839
--- /dev/null
@@ -0,0 +1,1597 @@
+/*
+ * dsock.c -- pstat-based HP-UX socket and stream processing functions for lsof
+ */
+
+/*
+ * Copyright 1999 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 1999 Purdue Research Foundation.\nAll rights reserved.\n";
+#endif
+
+#include "common.h"
+
+/*
+ * Local function prototypes
+ */
+
+#if defined(PS_STR_XPORT_DATA)
+static void make_sock(struct pst_fileinfo2 *f, struct pst_stream *sh,
+                      struct pst_socket *s);
+#endif /* defined(PS_STR_XPORT_DATA) */
+
+static void printpsproto(uint32_t p);
+
+/*
+ * Local macros
+ */
+
+#if defined(HASIPv6)
+
+/*
+ * IPv6_2_IPv4()  -- macro to define the address of an IPv4 address contained
+ *                  in an IPv6 address
+ */
+
+#    define IPv6_2_IPv4(v6) (((uint8_t *)((struct in6_addr *)v6)->s6_addr) + 12)
+#endif /* defined(HASIPv6) */
+
+/*
+ * build_IPstates() -- build the TCP and UDP state tables
+ */
+
+void build_IPstates() {
+    if (!TcpSt) {
+        (void)enter_IPstate("TCP", "CLOSED", PS_TCPS_CLOSED);
+        (void)enter_IPstate("TCP", "IDLE", PS_TCPS_IDLE);
+        (void)enter_IPstate("TCP", "BOUND", PS_TCPS_BOUND);
+        (void)enter_IPstate("TCP", "LISTEN", PS_TCPS_LISTEN);
+        (void)enter_IPstate("TCP", "SYN_SENT", PS_TCPS_SYN_SENT);
+        (void)enter_IPstate("TCP", "SYN_RCVD", PS_TCPS_SYN_RCVD);
+        (void)enter_IPstate("TCP", "ESTABLISHED", PS_TCPS_ESTABLISHED);
+        (void)enter_IPstate("TCP", "CLOSE_WAIT", PS_TCPS_CLOSE_WAIT);
+        (void)enter_IPstate("TCP", "FIN_WAIT_1", PS_TCPS_FIN_WAIT_1);
+        (void)enter_IPstate("TCP", "CLOSING", PS_TCPS_CLOSING);
+        (void)enter_IPstate("TCP", "LAST_ACK", PS_TCPS_LAST_ACK);
+        (void)enter_IPstate("TCP", "FIN_WAIT_2", PS_TCPS_FIN_WAIT_2);
+        (void)enter_IPstate("TCP", "TIME_WAIT", PS_TCPS_TIME_WAIT);
+        (void)enter_IPstate("TCP", (char *)NULL, 0);
+    }
+    if (!UdpSt) {
+        (void)enter_IPstate("UDP", "Uninitialized", PS_TS_UNINIT);
+        (void)enter_IPstate("UDP", "Unbound", PS_TS_UNBND);
+        (void)enter_IPstate("UDP", "Wait_BIND_REQ_Ack", PS_TS_WACK_BREQ);
+        (void)enter_IPstate("UDP", "Wait_UNBIND_REQ_Ack", PS_TS_WACK_UREQ);
+        (void)enter_IPstate("UDP", "Idle", PS_TS_IDLE);
+        (void)enter_IPstate("UDP", "Wait_OPT_REQ_Ack", PS_TS_WACK_OPTREQ);
+        (void)enter_IPstate("UDP", "Wait_CONN_REQ_Ack", PS_TS_WACK_CREQ);
+        (void)enter_IPstate("UDP", "Wait_CONN_REQ_Confirm", PS_TS_WCON_CREQ);
+        (void)enter_IPstate("UDP", "Wait_CONN_IND_Response", PS_TS_WRES_CIND);
+        (void)enter_IPstate("UDP", "Wait_CONN_RES_Ack", PS_TS_WACK_CRES);
+        (void)enter_IPstate("UDP", "Wait_Data_Xfr", PS_TS_DATA_XFER);
+        (void)enter_IPstate("UDP", "Wait_Read_Release", PS_TS_WIND_ORDREL);
+        (void)enter_IPstate("UDP", "Wait_Write_Release", PS_TS_WREQ_ORDREL);
+        (void)enter_IPstate("UDP", "Wait_DISCON_REQ_Ack", PS_TS_WACK_DREQ6);
+        (void)enter_IPstate("UDP", "Wait_DISCON_REQ_Ack", PS_TS_WACK_DREQ7);
+        (void)enter_IPstate("UDP", "Wait_DISCON_REQ_Ack", PS_TS_WACK_DREQ9);
+        (void)enter_IPstate("UDP", "Wait_DISCON_REQ_Ack", PS_TS_WACK_DREQ10);
+        (void)enter_IPstate("UDP", "Wait_DISCON_REQ_Ack", PS_TS_WACK_DREQ11);
+        (void)enter_IPstate("UDP", "Internal", PS_TS_WACK_ORDREL);
+        (void)enter_IPstate("UDP", (char *)NULL, 0);
+    }
+}
+
+#if defined(PS_STR_XPORT_DATA)
+/*
+ * make_sock() -- make a socket from the eXPORT data in a stream's head
+ */
+
+static void make_sock(f, sh, s) struct pst_fileinfo2 *f; /* pst_fileinfo2 */
+struct pst_stream *sh;                                   /* stream head */
+struct pst_socket *s; /* constructed socket */
+{
+    size_t sz;
+    /*
+     * Zero the destination pst_socket structure  and propagate its file and
+     * node IDs from the stream head.  Also propagate the linger time.
+     */
+    (void)memset((void *)s, 0, sizeof(struct pst_socket));
+    s->pst_hi_fileid = sh->val.head.pst_hi_fileid;
+    s->pst_lo_fileid = sh->val.head.pst_lo_fileid;
+    s->pst_hi_nodeid = sh->val.head.pst_hi_nodeid;
+    s->pst_lo_nodeid = sh->val.head.pst_lo_nodeid;
+    s->pst_linger = sh->pst_str_xport_linger;
+    /*
+     * Convert stream family to socket family and stream protocol to socket
+     * protocol.
+     *
+     * This could be avoided if PSTAT were to use a common set of family and
+     * protocol symbols.
+     */
+    switch (sh->pst_str_xport_family) {
+    case PS_STR_XPORT_AFINET:
+        s->pst_family = PS_AF_INET;
+        break;
+    case PS_STR_XPORT_AFINET6:
+        s->pst_family = PS_AF_INET6;
+        break;
+    default:
+        s->pst_family = sh->pst_str_xport_family;
+    }
+    switch (sh->pst_str_xport_protocol) {
+    case PS_STR_XPORT_TCP_PROTO:
+        s->pst_protocol = PS_PROTO_TCP;
+        break;
+    case PS_STR_XPORT_UDP_PROTO:
+        s->pst_protocol = PS_PROTO_UDP;
+        break;
+    default:
+        s->pst_protocol = sh->pst_str_xport_protocol;
+    }
+    /*
+     * Copy stream size information.
+     */
+    s->pst_qlimit = sh->pst_str_xport_qlimit;
+    s->pst_qlen = sh->pst_str_xport_qlen;
+    s->pst_idata = sh->pst_str_xport_idata;
+    s->pst_ibufsz = sh->pst_str_xport_ibufsz;
+    s->pst_rwnd = sh->pst_str_xport_rwnd;
+    s->pst_swnd = sh->pst_str_xport_swnd;
+    s->pst_odata = sh->pst_str_xport_odata;
+    s->pst_obufsz = sh->pst_str_xport_obufsz;
+    /*
+     * Propagate protocol state from stream symbol values to socket ones.
+     *
+     * This could be avoided if PSTAT were to use a common set of protocol
+     * state symbols.
+     */
+    if (s->pst_protocol == PS_PROTO_TCP) {
+        switch (sh->pst_str_xport_pstate) {
+
+#    if defined(PS_STR_XPORT_TCPS_CLOSED) && defined(PS_TCPS_CLOSED) &&        \
+        (PS_STR_XPORT_TCPS_CLOSED != PS_TCPS_CLOSED)
+        case PS_STR_XPORT_TCPS_CLOSED:
+            s->pst_pstate = PS_TCPS_CLOSED;
+            break;
+#    endif
+
+#    if defined(PS_STR_XPORT_TCPS_IDLE) && defined(PS_TCPS_IDLE) &&            \
+        (PS_STR_XPORT_TCPS_IDLE != PS_TCPS_IDLE)
+        case PS_STR_XPORT_TCPS_IDLE:
+            s->pst_pstate = PS_TCPS_IDLE;
+            break;
+#    endif
+
+#    if defined(PS_STR_XPORT_TCPS_BOUND) && defined(PS_TCPS_BOUND) &&          \
+        (PS_STR_XPORT_TCPS_BOUND != PS_TCPS_BOUND)
+        case PS_STR_XPORT_TCPS_BOUND:
+            s->pst_pstate = PS_TCPS_BOUND;
+            break;
+#    endif
+
+#    if defined(PS_STR_XPORT_TCPS_LISTEN) && defined(PS_TCPS_LISTEN) &&        \
+        (PS_STR_XPORT_TCPS_LISTEN != PS_TCPS_LISTEN)
+        case PS_STR_XPORT_TCPS_LISTEN:
+            s->pst_pstate = PS_TCPS_LISTEN;
+            break;
+#    endif
+
+#    if defined(PS_STR_XPORT_TCPS_SYN_SENT) && defined(PS_TCPS_SYN_SENT) &&    \
+        (PS_STR_XPORT_TCPS_SYN_SENT != PS_TCPS_SYN_SENT)
+        case PS_STR_XPORT_TCPS_SYN_SENT:
+            s->pst_pstate = PS_TCPS_SYN_SENT;
+            break;
+#    endif
+
+#    if defined(PS_STR_XPORT_TCPS_SYN_RCVD) && defined(PS_TCPS_SYN_RCVD) &&    \
+        (PS_STR_XPORT_TCPS_SYN_RCVD != PS_TCPS_SYN_RCVD)
+        case PS_STR_XPORT_TCPS_SYN_RCVD:
+            s->pst_pstate = PS_TCPS_SYN_RCVD;
+            break;
+#    endif
+
+#    if defined(PS_STR_XPORT_TCPS_ESTABLISHED) &&                              \
+        defined(PS_TCPS_ESTABLISHED) &&                                        \
+        (PS_STR_XPORT_TCPS_ESTABLISHED != PS_TCPS_ESTABLISHED)
+        case PS_STR_XPORT_TCPS_ESTABLISHED:
+            s->pst_pstate = PS_TCPS_ESTABLISHED;
+            break;
+#    endif
+
+#    if defined(PS_STR_XPORT_TCPS_CLOSE_WAIT) &&                               \
+        defined(PS_TCPS_CLOSE_WAIT) &&                                         \
+        (PS_STR_XPORT_TCPS_CLOSE_WAIT != PS_TCPS_CLOSE_WAIT)
+        case PS_STR_XPORT_TCPS_CLOSE_WAIT:
+            s->pst_pstate = PS_TCPS_CLOSE_WAIT;
+            break;
+#    endif
+
+#    if defined(PS_STR_XPORT_TCPS_FIN_WAIT_1) &&                               \
+        defined(PS_TCPS_FIN_WAIT_1) &&                                         \
+        (PS_STR_XPORT_TCPS_FIN_WAIT_1 != PS_TCPS_FIN_WAIT_1)
+        case PS_STR_XPORT_TCPS_FIN_WAIT_1:
+            s->pst_pstate = PS_TCPS_FIN_WAIT_1;
+            break;
+#    endif
+
+#    if defined(PS_STR_XPORT_TCPS_CLOSING) && defined(PS_TCPS_CLOSING) &&      \
+        (PS_STR_XPORT_TCPS_CLOSING != PS_TCPS_CLOSING)
+        case PS_STR_XPORT_TCPS_CLOSING:
+            s->pst_pstate = PS_TCPS_CLOSING;
+            break;
+#    endif
+
+#    if defined(PS_STR_XPORT_TCPS_LAST_ACK) && defined(PS_TCPS_LAST_ACK) &&    \
+        (PS_STR_XPORT_TCPS_LAST_ACK != PS_TCPS_LAST_ACK)
+        case PS_STR_XPORT_TCPS_LAST_ACK:
+            s->pst_pstate = PS_TCPS_LAST_ACK;
+            break;
+#    endif
+
+#    if defined(PS_STR_XPORT_TCPS_FIN_WAIT_2) &&                               \
+        defined(PS_TCPS_FIN_WAIT_2) &&                                         \
+        (PS_STR_XPORT_TCPS_FIN_WAIT_2 != PS_TCPS_FIN_WAIT_2)
+        case PS_STR_XPORT_TCPS_FIN_WAIT_2:
+            s->pst_pstate = PS_TCPS_FIN_WAIT_2;
+            break;
+#    endif
+
+#    if defined(PS_STR_XPORT_TCPS_TIME_WAIT) && defined(PS_TCPS_TIME_WAIT) &&  \
+        (PS_STR_XPORT_TCPS_TIME_WAIT != PS_TCPS_TIME_WAIT)
+        case PS_STR_XPORT_TCPS_TIME_WAIT:
+            s->pst_pstate = PS_TCPS_TIME_WAIT;
+            break;
+#    endif
+
+        default:
+            s->pst_pstate = sh->pst_str_xport_pstate;
+        }
+    } else if (s->pst_protocol == PS_PROTO_UDP) {
+        switch (sh->pst_str_xport_pstate) {
+
+#    if defined(PS_STR_XPORT_TS_UNINIT) && defined(PS_TS_UNINIT) &&            \
+        (PS_STR_XPORT_TS_UNINIT != PS_TS_UNINIT)
+        case PS_STR_XPORT_TS_UNINIT:
+            s->pst_pstate = PS_TS_UNINIT;
+            break;
+#    endif
+
+#    if defined(PS_STR_XPORT_TS_UNBND) && defined(PS_TS_UNBND) &&              \
+        (PS_STR_XPORT_TS_UNBND != PS_TS_UNBND)
+        case PS_STR_XPORT_TS_UNBND:
+            s->pst_pstate = PS_TS_UNBND;
+            break;
+#    endif
+
+#    if defined(PS_STR_XPORT_TS_WACK_BREQ) && defined(PS_TS_WACK_BREQ) &&      \
+        (PS_STR_XPORT_TS_WACK_BREQ != PS_TS_WACK_BREQ)
+        case PS_STR_XPORT_TS_WACK_BREQ:
+            s->pst_pstate = PS_TS_WACK_BREQ;
+            break;
+#    endif
+
+#    if defined(PS_STR_XPORT_TS_WACK_UREQ) && defined(PS_TS_WACK_UREQ) &&      \
+        (PS_STR_XPORT_TS_WACK_UREQ != PS_TS_WACK_UREQ)
+        case PS_STR_XPORT_TS_WACK_UREQ:
+            s->pst_pstate = PS_TS_WACK_UREQ;
+            break;
+#    endif
+
+#    if defined(PS_STR_XPORT_TS_IDLE) && defined(PS_TS_IDLE) &&                \
+        (PS_STR_XPORT_TS_IDLE != PS_TS_IDLE)
+        case PS_STR_XPORT_TS_IDLE:
+            s->pst_pstate = PS_TS_IDLE;
+            break;
+#    endif
+
+#    if defined(PS_STR_XPORT_TS_WACK_OPTREQ) && defined(PS_TS_WACK_OPTREQ) &&  \
+        (PS_STR_XPORT_TS_WACK_OPTREQ != PS_TS_WACK_OPTREQ)
+        case PS_STR_XPORT_TS_WACK_OPTREQ:
+            s->pst_pstate = PS_TS_WACK_OPTREQ;
+            break;
+#    endif
+
+#    if defined(PS_STR_XPORT_TS_WACK_CREQ) && defined(PS_TS_WACK_CREQ) &&      \
+        (PS_STR_XPORT_TS_WACK_CREQ != PS_TS_WACK_CREQ)
+        case PS_STR_XPORT_TS_WACK_CREQ:
+            s->pst_pstate = PS_TS_WACK_CREQ;
+            break;
+#    endif
+
+#    if defined(PS_STR_XPORT_TS_WCON_CREQ) && defined(PS_TS_WCON_CREQ) &&      \
+        (PS_STR_XPORT_TS_WCON_CREQ != PS_TS_WCON_CREQ)
+        case PS_STR_XPORT_TS_WCON_CREQ:
+            s->pst_pstate = PS_TS_WCON_CREQ;
+            break;
+#    endif
+
+#    if defined(PS_STR_XPORT_TS_WRES_CIND) && defined(PS_TS_WRES_CIND) &&      \
+        (PS_STR_XPORT_TS_WRES_CIND != PS_TS_WRES_CIND)
+        case PS_STR_XPORT_TS_WRES_CIND:
+            s->pst_pstate = PS_TS_WRES_CIND;
+            break;
+#    endif
+
+#    if defined(PS_STR_XPORT_TS_WACK_CRES) && defined(PS_TS_WACK_CRES) &&      \
+        (PS_STR_XPORT_TS_WACK_CRES != PS_TS_WACK_CRES)
+        case PS_STR_XPORT_TS_WACK_CRES:
+            s->pst_pstate = PS_TS_WACK_CRES;
+            break;
+#    endif
+
+#    if defined(PS_STR_XPORT_TS_DATA_XFER) && defined(PS_TS_DATA_XFER) &&      \
+        (PS_STR_XPORT_TS_DATA_XFER != PS_TS_DATA_XFER)
+        case PS_STR_XPORT_TS_DATA_XFER:
+            s->pst_pstate = PS_TS_DATA_XFER;
+            break;
+#    endif
+
+#    if defined(PS_STR_XPORT_TS_WIND_ORDREL) && defined(PS_TS_WIND_ORDREL) &&  \
+        (PS_STR_XPORT_TS_WIND_ORDREL != PS_TS_WIND_ORDREL)
+        case PS_STR_XPORT_TS_WIND_ORDREL:
+            s->pst_pstate = PS_TS_WIND_ORDREL;
+            break;
+#    endif
+
+#    if defined(PS_STR_XPORT_TS_WREQ_ORDREL) && defined(PS_TS_WREQ_ORDREL) &&  \
+        (PS_STR_XPORT_TS_WREQ_ORDREL != PS_TS_WREQ_ORDREL)
+        case PS_STR_XPORT_TS_WREQ_ORDREL:
+            s->pst_pstate = PS_TS_WREQ_ORDREL;
+            break;
+#    endif
+
+#    if defined(PS_STR_XPORT_TS_WACK_DREQ6) && defined(PS_TS_WACK_DREQ6) &&    \
+        (PS_STR_XPORT_TS_WACK_DREQ6 != PS_TS_WACK_DREQ6)
+        case PS_STR_XPORT_TS_WACK_DREQ6:
+            s->pst_pstate = PS_TS_WACK_DREQ6;
+            break;
+#    endif
+
+#    if defined(PS_STR_XPORT_TS_WACK_DREQ7) && defined(PS_TS_WACK_DREQ7) &&    \
+        (PS_STR_XPORT_TS_WACK_DREQ7 != PS_TS_WACK_DREQ7)
+        case PS_STR_XPORT_TS_WACK_DREQ7:
+            s->pst_pstate = PS_TS_WACK_DREQ7;
+            break;
+#    endif
+
+#    if defined(PS_STR_XPORT_TS_WACK_DREQ9) && defined(PS_TS_WACK_DREQ9) &&    \
+        (PS_STR_XPORT_TS_WACK_DREQ9 != PS_TS_WACK_DREQ9)
+        case PS_STR_XPORT_TS_WACK_DREQ9:
+            s->pst_pstate = PS_TS_WACK_DREQ9;
+            break;
+#    endif
+
+#    if defined(PS_STR_XPORT_TS_WACK_DREQ10) && defined(PS_TS_WACK_DREQ10) &&  \
+        (PS_STR_XPORT_TS_WACK_DREQ10 != PS_TS_WACK_DREQ10)
+        case PS_STR_XPORT_TS_WACK_DREQ10:
+            s->pst_pstate = PS_TS_WACK_DREQ10;
+            break;
+#    endif
+
+#    if defined(PS_STR_XPORT_TS_WACK_DREQ11) && defined(PS_TS_WACK_DREQ11) &&  \
+        (PS_STR_XPORT_TS_WACK_DREQ11 != PS_TS_WACK_DREQ11)
+        case PS_STR_XPORT_TS_WACK_DREQ11:
+            s->pst_pstate = PS_TS_WACK_DREQ11;
+            break;
+#    endif
+
+#    if defined(PS_STR_XPORT_TS_WACK_ORDREL) && defined(PS_TS_WACK_ORDREL) &&  \
+        (PS_STR_XPORT_TS_WACK_ORDREL != PS_TS_WACK_ORDREL)
+        case PS_STR_XPORT_TS_WACK_ORDREL:
+            s->pst_pstate = PS_TS_WACK_ORDREL;
+            break;
+#    endif
+
+#    if defined(PS_STR_XPORT_TS_NOSTATES) && defined(PS_TS_NOSTATES) &&        \
+        (PS_STR_XPORT_TS_NOSTATES != PS_TS_NOSTATES)
+        case PS_STR_XPORT_TS_NOSTATES:
+            s->pst_pstate = PS_TS_NOSTATES;
+            break;
+#    endif
+
+        default:
+            s->pst_pstate = sh->pst_str_xport_pstate;
+        }
+    } else
+        s->pst_pstate = sh->pst_str_xport_pstate;
+    /*
+     * Now propagate the bound and remote address information from pst_stream
+     * to the pst_socket structure.  Validate the copy lengths.
+     */
+    sz = (size_t)sh->pst_str_xport_boundaddr_len;
+    if (sz > sizeof(s->pst_boundaddr))
+        sz = sizeof(s->pst_boundaddr);
+    if ((s->pst_boundaddr_len = sz)) {
+        (void)memcpy((void *)s->pst_boundaddr,
+                     (const void *)sh->pst_str_xport_boundaddr, sz);
+    }
+    sz = (size_t)sh->pst_str_xport_remaddr_len;
+    if (sz > sizeof(s->pst_remaddr))
+        sz = sizeof(s->pst_remaddr);
+    if ((s->pst_remaddr_len = sz)) {
+        (void)memcpy((void *)s->pst_remaddr,
+                     (const void *)sh->pst_str_xport_remaddr, sz);
+    }
+}
+#endif /* defined(PS_STR_XPORT_DATA) */
+
+/*
+ * printpsproto() -- print PSTAT protocol name
+ */
+
+static void printpsproto(p) uint32_t p; /* protocol number */
+{
+    int i;
+    static int m = -1;
+    char *s;
+
+    switch (p) {
+    case PS_PROTO_IP:
+        s = "IP";
+        break;
+    case PS_PROTO_ICMP:
+        s = "ICMP";
+        break;
+    case PS_PROTO_IGMP:
+        s = "IGMP";
+        break;
+    case PS_PROTO_GGP:
+        s = "GGP";
+        break;
+    case PS_PROTO_IPIP:
+        s = "IPIP";
+        break;
+    case PS_PROTO_TCP:
+        s = "TCP";
+        break;
+    case PS_PROTO_EGP:
+        s = "EGP";
+        break;
+    case PS_PROTO_IGP:
+        s = "IGP";
+        break;
+    case PS_PROTO_PUP:
+        s = "PUP";
+        break;
+    case PS_PROTO_UDP:
+        s = "UDP";
+        break;
+    case PS_PROTO_IDP:
+        s = "IDP";
+        break;
+    case PS_PROTO_XTP:
+        s = "XTP";
+        break;
+    case PS_PROTO_ESP:
+        s = "ESP";
+        break;
+    case PS_PROTO_AH:
+        s = "AH";
+        break;
+    case PS_PROTO_OSPF:
+        s = "OSPF";
+        break;
+    case PS_PROTO_IPENCAP:
+        s = "IPENCAP";
+        break;
+    case PS_PROTO_ENCAP:
+        s = "ENCAP";
+        break;
+    case PS_PROTO_PXP:
+        s = "PXP";
+        break;
+    case PS_PROTO_RAW:
+        s = "RAW";
+        break;
+    default:
+        s = (char *)NULL;
+    }
+    if (s)
+        (void)snpf(Lf->iproto, sizeof(Lf->iproto), "%.*s", IPROTOL - 1, s);
+    else {
+        if (m < 0) {
+            for (i = 0, m = 1; i < IPROTOL - 2; i++)
+                m *= 10;
+        }
+        if (m > p)
+            (void)snpf(Lf->iproto, sizeof(Lf->iproto), "%d?", p);
+        else
+            (void)snpf(Lf->iproto, sizeof(Lf->iproto), "*%d?", p % (m / 10));
+    }
+}
+
+/*
+ * print_tcptpi() -- print TCP/TPI info
+ */
+
+void print_tcptpi(nl) int nl; /* 1 == '\n' required */
+{
+    char *cp = (char *)NULL;
+    char sbuf[128];
+    int i;
+    int ps = 0;
+    unsigned int u;
+
+    if (Ftcptpi & TCPTPI_STATE) {
+        switch (Lf->lts.type) {
+        case 0: /* TCP */
+            if (!TcpSt)
+                (void)build_IPstates();
+            if ((i = Lf->lts.state.i + TcpStOff) < 0 || i >= TcpNstates) {
+                (void)snpf(sbuf, sizeof(sbuf), "UknownState_%d",
+                           Lf->lts.state.i);
+                cp = sbuf;
+            } else
+                cp = TcpSt[i];
+            break;
+        case 1: /* UDP */
+            if (!UdpSt)
+                (void)build_IPstates();
+            if ((u = Lf->lts.state.ui + UdpStOff) > UdpNstates) {
+                (void)snpf(sbuf, sizeof(sbuf), "UNKNOWN_TPI_STATE_%u",
+                           Lf->lts.state.ui);
+                cp = sbuf;
+            } else
+                cp = UdpSt[u];
+        }
+        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(HASSOOPT)
+    if (Ftcptpi & TCPTPI_FLAGS) {
+        int opt;
+
+        if ((opt = Lf->lts.opt) || Lf->lts.qlens || Lf->lts.qlims) {
+            char sep = ' ';
+
+            if (Ffield)
+                sep = LSOF_FID_TCPTPI;
+            else if (!ps)
+                sep = '(';
+            (void)printf("%cSO", sep);
+            ps++;
+            sep = '=';
+
+#    if defined(PS_SO_ACCEPTCONN)
+            if (opt & PS_SO_ACCEPTCONN) {
+                (void)printf("%cACCEPTCONN", sep);
+                opt &= ~PS_SO_ACCEPTCONN;
+                sep = ',';
+            }
+#    endif /* defined(PS_SO_ACCEPTCONN) */
+
+#    if defined(PS_SO_BROADCAST)
+            if (opt & PS_SO_BROADCAST) {
+                (void)printf("%cBROADCAST", sep);
+                opt &= ~PS_SO_BROADCAST;
+                sep = ',';
+            }
+#    endif /* defined(PS_SO_BROADCAST) */
+
+#    if defined(PS_SO_DEBUG)
+            if (opt & PS_SO_DEBUG) {
+                (void)printf("%cDEBUG", sep);
+                opt &= ~PS_SO_DEBUG;
+                sep = ',';
+            }
+#    endif /* defined(PS_SO_DEBUG) */
+
+#    if defined(PS_SO_DONTROUTE)
+            if (opt & PS_SO_DONTROUTE) {
+                (void)printf("%cDONTROUTE", sep);
+                opt &= ~PS_SO_DONTROUTE;
+                sep = ',';
+            }
+#    endif /* defined(PS_SO_DONTROUTE) */
+
+#    if defined(PS_SO_GETIFADDR)
+            if (opt & PS_SO_GETIFADDR) {
+                (void)printf("%cGETIFADDR", sep);
+                opt &= ~PS_SO_GETIFADDR;
+                sep = ',';
+            }
+#    endif /* defined(PS_SO_GETIFADDR) */
+
+#    if defined(PS_SO_INPCB_COPY)
+            if (opt & PS_SO_INPCB_COPY) {
+                (void)printf("%cINPCB_COPY", sep);
+                opt &= ~PS_SO_INPCB_COPY;
+                sep = ',';
+            }
+#    endif /* defined(PS_SO_INPCB_COPY) */
+
+#    if defined(PS_SO_KEEPALIVE)
+            if (opt & PS_SO_KEEPALIVE) {
+                (void)printf("%cKEEPALIVE", sep);
+                if (Lf->lts.kai)
+                    (void)printf("=%d", Lf->lts.kai);
+                opt &= ~PS_SO_KEEPALIVE;
+                sep = ',';
+            }
+#    endif /* defined(PS_SO_KEEPALIVE) */
+
+#    if defined(PS_SO_LINGER)
+            if (opt & PS_SO_LINGER) {
+                (void)printf("%cLINGER", sep);
+                if (Lf->lts.ltm)
+                    (void)printf("=%d", Lf->lts.ltm);
+                opt &= ~PS_SO_LINGER;
+                sep = ',';
+            }
+#    endif /* defined(PS_SO_LINGER) */
+
+#    if defined(PS_SO_OOBINLINE)
+            if (opt & PS_SO_OOBINLINE) {
+                (void)printf("%cOOBINLINE", sep);
+                opt &= ~PS_SO_OOBINLINE;
+                sep = ',';
+            }
+#    endif /* defined(PS_SO_OOBINLINE) */
+
+#    if defined(PS_SO_PMTU)
+            if (opt & PS_SO_PMTU) {
+                (void)printf("%cPMTU", sep);
+                opt &= ~PS_SO_PMTU;
+                sep = ',';
+            }
+#    endif /* defined(PS_SO_PMTU) */
+
+            if (Lf->lts.qlens) {
+                (void)printf("%cQLEN=%u", sep, Lf->lts.qlen);
+                sep = ',';
+            }
+            if (Lf->lts.qlims) {
+                (void)printf("%cQLIM=%u", sep, Lf->lts.qlim);
+                sep = ',';
+            }
+
+#    if defined(PS_SO_REUSEADDR)
+            if (opt & PS_SO_REUSEADDR) {
+                (void)printf("%cREUSEADDR", sep);
+                opt &= ~PS_SO_REUSEADDR;
+                sep = ',';
+            }
+#    endif /* defined(PS_SO_REUSEADDR) */
+
+#    if defined(PS_SO_REUSEPORT)
+            if (opt & PS_SO_REUSEPORT) {
+                (void)printf("%cREUSEPORT", sep);
+                opt &= ~PS_SO_REUSEPORT;
+                sep = ',';
+            }
+#    endif /* defined(PS_SO_REUSEPORT) */
+
+#    if defined(PS_SO_USELOOPBACK)
+            if (opt & PS_SO_USELOOPBACK) {
+                (void)printf("%cUSELOOPBACK", sep);
+                opt &= ~PS_SO_USELOOPBACK;
+                sep = ',';
+            }
+#    endif /* defined(PS_SO_USELOOPBACK) */
+
+            if (opt)
+                (void)printf("%cUNKNOWN=%#x", sep, opt);
+            if (Ffield)
+                putchar(Terminator);
+        }
+    }
+#endif /* defined(HASSOOPT) */
+
+#if defined(HASSOSTATE)
+    if (Ftcptpi & TCPTPI_FLAGS) {
+        int ss;
+
+        if ((ss = Lf->lts.ss)) {
+            char sep = ' ';
+
+            if (Ffield)
+                sep = LSOF_FID_TCPTPI;
+            else if (!ps)
+                sep = '(';
+            (void)printf("%cSS", sep);
+            ps++;
+            sep = '=';
+
+#    if defined(PS_SS_ASYNC)
+            if (ss & PS_SS_ASYNC) {
+                (void)printf("%cASYNC", sep);
+                ss &= ~PS_SS_ASYNC;
+                sep = ',';
+            }
+#    endif /* defined(PS_SS_ASYNC) */
+
+#    if defined(PS_SS_BOUND)
+            if (ss & PS_SS_BOUND) {
+                (void)printf("%cBOUND", sep);
+                ss &= ~PS_SS_BOUND;
+                sep = ',';
+            }
+#    endif /* defined(PS_SS_BOUND) */
+
+#    if defined(PS_SS_CANTRCVMORE)
+            if (ss & PS_SS_CANTRCVMORE) {
+                (void)printf("%cCANTRCVMORE", sep);
+                ss &= ~PS_SS_CANTRCVMORE;
+                sep = ',';
+            }
+#    endif /* defined(PS_SS_CANTRCVMORE) */
+
+#    if defined(PS_SS_CANTSENDMORE)
+            if (ss & PS_SS_CANTSENDMORE) {
+                (void)printf("%cCANTSENDMORE", sep);
+                ss &= ~PS_SS_CANTSENDMORE;
+                sep = ',';
+            }
+#    endif /* defined(PS_SS_CANTSENDMORE) */
+
+#    if defined(PS_SS_ISCONNECTED)
+            if (ss & PS_SS_ISCONNECTED) {
+                (void)printf("%cISCONNECTED", sep);
+                ss &= ~PS_SS_ISCONNECTED;
+                sep = ',';
+            }
+#    endif /* defined(PS_SS_ISCONNECTED) */
+
+#    if defined(PS_SS_ISCONNECTING)
+            if (ss & PS_SS_ISCONNECTING) {
+                (void)printf("%cISCONNECTING", sep);
+                ss &= ~PS_SS_ISCONNECTING;
+                sep = ',';
+            }
+#    endif /* defined(PS_SS_ISCONNECTING) */
+
+#    if defined(PS_SS_ISDISCONNECTI)
+            if (ss & PS_SS_ISDISCONNECTI) {
+                (void)printf("%cISDISCONNECTI", sep);
+                ss &= ~PS_SS_ISDISCONNECTI;
+                sep = ',';
+            }
+#    endif /* defined(PS_SS_ISDISCONNECTI) */
+
+#    if defined(PS_SS_INTERRUPTED)
+            if (ss & PS_SS_INTERRUPTED) {
+                (void)printf("%cINTERRUPTED", sep);
+                ss &= ~PS_SS_INTERRUPTED;
+                sep = ',';
+            }
+#    endif /* defined(PS_SS_INTERRUPTED) */
+
+#    if defined(PS_SS_NBIO)
+            if (ss & PS_SS_NBIO) {
+                (void)printf("%cNBIO", sep);
+                ss &= ~PS_SS_NBIO;
+                sep = ',';
+            }
+#    endif /* defined(PS_SS_NBIO) */
+
+#    if defined(PS_SS_NOFDREF)
+            if (ss & PS_SS_NOFDREF) {
+                (void)printf("%cNOFDREF", sep);
+                ss &= ~PS_SS_NOFDREF;
+                sep = ',';
+            }
+#    endif /* defined(PS_SS_NOFDREF) */
+
+#    if defined(PS_SS_NOUSER)
+            if (ss & PS_SS_NOUSER) {
+                (void)printf("%cNOUSER", sep);
+                ss &= ~PS_SS_NOUSER;
+                sep = ',';
+            }
+#    endif /* defined(PS_SS_NOUSER) */
+
+#    if defined(PS_SS_NOWAIT)
+            if (ss & PS_SS_NOWAIT) {
+                (void)printf("%cNOWAIT", sep);
+                ss &= ~PS_SS_NOWAIT;
+                sep = ',';
+            }
+#    endif /* defined(PS_SS_NOWAIT) */
+
+#    if defined(PS_SS_PRIV)
+            if (ss & PS_SS_PRIV) {
+                (void)printf("%cPRIV", sep);
+                ss &= ~PS_SS_PRIV;
+                sep = ',';
+            }
+#    endif /* defined(PS_SS_PRIV) */
+
+#    if defined(PS_SS_RCVATMARK)
+            if (ss & PS_SS_RCVATMARK) {
+                (void)printf("%cRCVATMARK", sep);
+                ss &= ~PS_SS_RCVATMARK;
+                sep = ',';
+            }
+#    endif /* defined(PS_SS_RCVATMARK) */
+
+#    if defined(PS_SS_XOPEN_EXT1)
+            if (ss & PS_SS_XOPEN_EXT1) {
+                (void)printf("%cXOPEN_EXT1", sep);
+                ss &= ~PS_SS_XOPEN_EXT1;
+                sep = ',';
+            }
+#    endif /* defined(PS_SS_XOPEN_EXT1) */
+
+            if (ss)
+                (void)printf("%cUNKNOWN=%#x", sep, ss);
+            if (Ffield)
+                putchar(Terminator);
+        }
+    }
+#endif /* defined(HASSOSTATE) */
+
+#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 (Ftcptpi && !Ffield && ps)
+        putchar(')');
+    if (nl)
+        putchar('\n');
+}
+
+/*
+ * process_socket() -- process socket
+ */
+
+void process_socket(struct pst_fileinfo2 *f, /* file information */
+                    struct pst_socket *s)    /* optional socket information
+                                              * NULL == none */
+{
+    int af, err, fp, lp, tx;
+    char buf[1024], tbuf[32];
+    unsigned char *fa = (unsigned char *)NULL;
+    unsigned char *la = (unsigned char *)NULL;
+    size_t len;
+    KA_T na, nau;
+    char *nma = (char *)NULL;
+    struct pst_filedetails pd;
+    struct sockaddr_in *sa;
+    int sx;
+    char fd[FDLEN];
+
+#if defined(HASIPv6)
+    struct sockaddr_in6 *sa6;
+#endif /* defined(HASIPv6) */
+
+    struct sockaddr_un *ua;
+    /*
+     * Read socket info, as required, so that the protocol state names can be
+     * tested as soon as possible.
+     */
+    if (!s) {
+        if (!(s = read_sock(f))) {
+            (void)snpf(Namech, Namechl, "can't read pst_socket%s%s",
+                       errno ? ": " : "", errno ? strerror(errno) : "");
+            (void)enter_nm(Namech);
+            return;
+        }
+    }
+    /*
+     * Collect protocol details so the protocol state name might be tested,
+     * as requested by options.
+     */
+    switch (s->pst_family) {
+    case PS_AF_INET:
+        af = 4;
+        break;
+
+#if defined(HASIPv6)
+    case PS_AF_INET6:
+        af = 6;
+        break;
+#endif /* defined(HASIPv6) */
+
+    default:
+        af = -1;
+    }
+    switch (s->pst_protocol) {
+    case PS_PROTO_TCP:
+        sx = (int)s->pst_pstate + TcpStOff;
+        tx = 0;
+        break;
+    case PS_PROTO_UDP:
+        sx = (unsigned int)s->pst_pstate + UdpStOff;
+        tx = 1;
+        break;
+    default:
+        sx = tx = -1;
+    }
+    /*
+     * Test the protocol state and name, setting the SELNET flag where possible.
+     */
+    switch (tx) {
+    case 0: /* TCP */
+        if (TcpStXn) {
+
+            /*
+             * Check for TCP state exclusion.
+             */
+            if (sx >= 0 && sx < TcpNstates) {
+                if (TcpStX[sx]) {
+                    Lf->sf |= SELEXCLF;
+                    return;
+                }
+            }
+        }
+        if (TcpStIn) {
+            if (sx >= 0 && sx < TcpNstates) {
+                if (TcpStI[sx])
+                    TcpStI[sx] = 2;
+                else {
+                    Lf->sf |= SELEXCLF;
+                    return;
+                }
+            }
+        }
+        break;
+    case 1: /* UDP */
+        if (UdpStXn) {
+
+            /*
+             * Check for UDP state exclusion.
+             */
+            if (sx >= 0 && sx < UdpNstates) {
+                if (UdpStX[sx]) {
+                    Lf->sf |= SELEXCLF;
+                    return;
+                }
+            }
+        }
+        if (UdpStIn) {
+            if (sx >= 0 && sx < UdpNstates) {
+                if (UdpStI[sx])
+                    UdpStI[sx] = 2;
+                else {
+                    Lf->sf |= SELEXCLF;
+                    return;
+                }
+            }
+        }
+        break;
+    }
+    /*
+     * Set default type.
+     */
+    Lf->type = LSOF_FILE_SOCKET;
+    Lf->inp_ty = 2;
+    /*
+     * Generate and save node ID.
+     */
+    na = (KA_T)(((KA_T)(f->psf_hi_nodeid & 0xffffffff) << 32) |
+                (KA_T)(f->psf_lo_nodeid & 0xffffffff));
+
+#if defined(HASFSTRUCT)
+    if (na) {
+        Lf->fna = na;
+        Lf->fsv |= FSV_NI;
+    }
+#endif /* defined(HASFSTRUCT) */
+
+    /*
+     * Save size information, as requested.
+     */
+    if (Lf->access == LSOF_FILE_ACCESS_READ)
+        Lf->sz = (SZOFFTYPE)s->pst_idata;
+    else if (Lf->access == LSOF_FILE_ACCESS_WRITE)
+        Lf->sz = (SZOFFTYPE)s->pst_odata;
+    else
+        Lf->sz = (SZOFFTYPE)(s->pst_idata + s->pst_odata);
+    Lf->sz_def = 1;
+
+#if defined(HASTCPTPIQ)
+    /*
+     * Enter queue sizes.
+     */
+    switch (s->pst_family) {
+    case PS_AF_INET:
+    case PS_AF_INET6:
+        Lf->lts.rq = (unsigned long)s->pst_idata;
+        Lf->lts.sq = (unsigned long)s->pst_odata;
+        Lf->lts.rqs = Lf->lts.sqs = (unsigned char)1;
+    }
+#endif /* defined(HASTCPTPIQ) */
+
+#if defined(HASSOOPT)
+    /*
+     * Enter socket options.
+     */
+    Lf->lts.opt = (unsigned int)s->pst_options;
+    Lf->lts.ltm = (unsigned int)s->pst_linger;
+    Lf->lts.qlen = (unsigned int)s->pst_qlen;
+    Lf->lts.qlim = (unsigned int)s->pst_qlimit;
+    Lf->lts.qlens = Lf->lts.qlims = (unsigned char)1;
+#endif /* defined(HASSOOPT) */
+
+#if defined(HASSOSTATE)
+    /*
+     * Enter socket state flags.
+     */
+    Lf->lts.ss = (unsigned int)s->pst_state;
+#endif /* defined(HASSOSTATE) */
+
+#if defined(HASTCPTPIW)
+    /*
+     * Enter window sizes.
+     */
+    switch (s->pst_family) {
+    case PS_AF_INET:
+    case PS_AF_INET6:
+        Lf->lts.rw = (unsigned long)s->pst_rwnd;
+        Lf->lts.ww = (unsigned long)s->pst_swnd;
+        Lf->lts.rws = Lf->lts.wws = (unsigned char)1;
+    }
+#endif /* defined(HASTCPTPIW) */
+
+    /*
+     * Process socket by the associated domain family.
+     */
+    switch (s->pst_family) {
+    case PS_AF_INET:
+        if (Fnet && (!FnetTy || (FnetTy != 6)))
+            Lf->sf |= SELNET;
+#if defined(HASIPv6)
+        Lf->type = LSOF_FILE_IPV4;
+#else  /* !defined(HASIPv6) */
+        Lf->type = LSOF_FILE_INET;
+#endif /* defined(HASIPv6) */
+        printpsproto(s->pst_protocol);
+        enter_dev_ch(print_kptr(na, (char *)NULL, 0));
+        switch (s->pst_protocol) {
+        case PS_PROTO_TCP:
+            Lf->lts.type = 0;
+            Lf->lts.state.i = (int)s->pst_pstate;
+            break;
+        case PS_PROTO_UDP:
+            Lf->lts.type = 1;
+            Lf->lts.state.ui = (unsigned int)s->pst_pstate;
+        }
+        /*
+         * Enter local and remote addresses, being careful to generate
+         * proper IPv4 address alignment by copying, since IPv4 addresses
+         * may not be properly aligned in pst_boundaddr[] and pst_remaddr[].
+         */
+        if ((size_t)s->pst_boundaddr_len == sizeof(struct sockaddr_in)) {
+            sa = (struct sockaddr_in *)s->pst_boundaddr;
+            la = (unsigned char *)&sa->sin_addr;
+            lp = (int)htons(sa->sin_port);
+        }
+        if ((size_t)s->pst_remaddr_len == sizeof(struct sockaddr_in)) {
+            sa = (struct sockaddr_in *)s->pst_remaddr;
+            fp = (int)htons(sa->sin_port);
+            if ((sa->sin_addr.s_addr != INADDR_ANY) || fp)
+                fa = (unsigned char *)&sa->sin_addr;
+        }
+        if (fa || la)
+            (void)ent_inaddr(la, lp, fa, fp, AF_INET);
+        break;
+
+#if defined(HASIPv6)
+    case PS_AF_INET6:
+        af = AF_INET6;
+        if (Fnet && (!FnetTy || (FnetTy != 4)))
+            Lf->sf |= SELNET;
+        Lf->type = LSOF_FILE_IPV6;
+        printpsproto(s->pst_protocol);
+        enter_dev_ch(print_kptr(na, (char *)NULL, 0));
+        switch (s->pst_protocol) {
+        case PS_PROTO_TCP:
+            Lf->lts.type = 0;
+            Lf->lts.state.i = (int)s->pst_pstate;
+            break;
+        case PS_PROTO_UDP:
+            Lf->lts.type = 1;
+            Lf->lts.state.ui = (unsigned int)s->pst_pstate;
+        }
+        /*
+         * Enter local and remote addresses, being careful to generate
+         * proper IPv6 address alignment by copying, since IPv6 addresses
+         * may not be properly aligned in pst_boundaddr[] and pst_remaddr[].
+         */
+        if ((size_t)s->pst_boundaddr_len == sizeof(struct sockaddr_in6)) {
+            sa6 = (struct sockaddr_in6 *)s->pst_boundaddr;
+            la = (unsigned char *)&sa6->sin6_addr;
+            lp = (int)htons(sa6->sin6_port);
+        }
+        if ((size_t)s->pst_remaddr_len == sizeof(struct sockaddr_in6)) {
+            sa6 = (struct sockaddr_in6 *)s->pst_remaddr;
+            if ((fp = (int)htons(sa6->sin6_port)) ||
+                !IN6_IS_ADDR_UNSPECIFIED(&sa6->sin6_addr))
+                fa = (unsigned char *)&sa6->sin6_addr;
+        }
+        if (la || fa) {
+            if ((la && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)la)) ||
+                (fa && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)fa))) {
+                if (la)
+                    la = (unsigned char *)IPv6_2_IPv4(la);
+                if (fa)
+                    fa = (unsigned char *)IPv6_2_IPv4(fa);
+                af = AF_INET;
+            }
+        }
+        if (fa || la)
+            (void)ent_inaddr(la, lp, fa, fp, af);
+        break;
+#endif /* defined(HASIPv6) */
+
+    case PS_AF_UNIX:
+        if (Funix)
+            Lf->sf |= SELUNX;
+        Lf->type = LSOF_FILE_UNIX;
+        if (((len = (size_t)s->pst_boundaddr_len) > 0) &&
+            (len <= sizeof(struct sockaddr_un))) {
+            ua = (struct sockaddr_un *)s->pst_boundaddr;
+            if (ua->sun_path[0]) {
+
+                /*
+                 * The AF_UNIX socket has a bound address (file path).
+                 *
+                 * Save it.  If there is a low nodeid, put that in
+                 * parentheses after the name.  If there is a low peer
+                 * nodeid, put that in the parentheses, too.
+                 */
+                s->pst_boundaddr[PS_ADDR_SZ - 1] = '\0';
+                if (s->pst_lo_nodeid) {
+                    (void)snpf(
+                        buf, sizeof(buf), "(%s%s%s)",
+                        print_kptr((KA_T)s->pst_lo_nodeid, tbuf, sizeof(tbuf)),
+                        s->pst_peer_lo_nodeid ? "->" : "",
+                        s->pst_peer_lo_nodeid
+                            ? print_kptr((KA_T)s->pst_peer_lo_nodeid,
+                                         (char *)NULL, 0)
+                            : "");
+                    len = strlen(buf) + 1;
+                    if (!(nma = (char *)malloc((MALLOC_S)len))) {
+                        fd_to_string(Lf->fd_type, Lf->fd_num, fd);
+                        (void)fprintf(
+                            stderr, "%s: no unix nma space(1): PID %ld, FD %s",
+                            Pn, (long)Lp->pid, fd);
+                    }
+                    (void)snpf(nma, len, "%s", buf);
+                    Lf->nma = nma;
+                }
+                /*
+                 * Read the pst_filedetails for the bound address and process
+                 * them as for a regular file.  The already-entered file type,
+                 * file name, size or offset, and name appendix will be
+                 * preserved.
+                 */
+                if ((nau = read_det(&f->psf_fid, f->psf_hi_fileid,
+                                    f->psf_lo_fileid, f->psf_hi_nodeid,
+                                    f->psf_lo_nodeid, &pd))) {
+                    enter_nm(ua->sun_path);
+                    (void)process_finfo(&pd, &f->psf_fid, &f->psf_id, nau);
+                    return;
+                } else {
+
+                    /*
+                     * Couldn't read file details.  Erase any name appendix.
+                     * Put the socket nodeid in the DEVICE column, put the
+                     * bound address (path) in the NAME column, and build
+                     * a new name appendix with the peer address.  Add an
+                     * error message if pstat_getfiledetails() set errno to
+                     * something other than ENOENT.
+                     */
+                    if ((err = errno) == ENOENT)
+                        err = 0;
+                    if (nma) {
+                        (void)free((MALLOC_P *)nma);
+                        Lf->nma = (char *)NULL;
+                    }
+                    if (s->pst_lo_nodeid) {
+                        enter_dev_ch(print_kptr((KA_T)s->pst_lo_nodeid,
+                                                (char *)NULL, 0));
+                    }
+                    (void)snpf(Namech, Namechl, "%s", ua->sun_path);
+                    if (err || s->pst_peer_lo_nodeid) {
+                        (void)snpf(buf, sizeof(buf), "%s%s%s%s%s%s%s",
+                                   err ? "(Error: " : "",
+                                   err ? strerror(err) : "", err ? ")" : "",
+                                   (err && s->pst_peer_lo_nodeid) ? " " : "",
+                                   s->pst_peer_lo_nodeid ? "(->" : "",
+                                   s->pst_peer_lo_nodeid
+                                       ? print_kptr((KA_T)s->pst_peer_lo_nodeid,
+                                                    (char *)NULL, 0)
+                                       : "",
+                                   s->pst_peer_lo_nodeid ? ")" : "");
+                        len = strlen(buf) + 1;
+                        if (!(nma = (char *)malloc((MALLOC_S)len))) {
+                            fd_to_string(Lf->fd_type, Lf->fd_num, fd);
+                            (void)fprintf(
+                                stderr,
+                                "%s: no unix nma space(2): PID %ld, FD %s", Pn,
+                                (long)Lp->pid, fd);
+                        }
+                        (void)snpf(nma, len, "%s", buf);
+                        Lf->nma = nma;
+                    }
+                    if (Sfile && is_file_named(ua->sun_path, 0))
+                        Lf->sf |= SELNM;
+                    break;
+                }
+            }
+        }
+        /*
+         * If the UNIX socket has no bound address (file path), display the
+         * low nodeid in the DEVICE column and the peer's low nodeid in the
+         * NAME column.
+         */
+        if (s->pst_peer_lo_nodeid) {
+            (void)snpf(
+                Namech, Namechl, "->%s",
+                print_kptr((KA_T)s->pst_peer_lo_nodeid, (char *)NULL, 0));
+        }
+        if (s->pst_lo_nodeid)
+            enter_dev_ch(print_kptr((KA_T)s->pst_lo_nodeid, (char *)NULL, 0));
+        break;
+    default:
+        (void)snpf(Namech, Namechl, "unsupported family: AF_%d", s->pst_family);
+    }
+    if (Namech[0])
+        enter_nm(Namech);
+}
+
+/*
+ * process_stream() -- process stream
+ */
+
+void process_stream(f, ckscko) struct pst_fileinfo2 *f; /* pst_fileinfo2 */
+int ckscko; /* socket file only checking
+             * if 1 */
+{
+    struct clone *cl;
+    enum lsof_file_type type;
+    struct l_dev *dp = (struct l_dev *)NULL;
+    int hx, i, ncx, nsn, nsr;
+    size_t nb, nl;
+    KA_T na;
+    static int nsa = 0;
+    dev_t rdev;
+    static struct pst_stream *s = (struct pst_stream *)NULL;
+    struct pst_socket sck;
+    static size_t sz = sizeof(struct pst_stream);
+
+#if !defined(PS_STR_XPORT_DATA)
+    /*
+     * If socket file only checking is enabled and this HP-UX PSTAT instance
+     * doesn't support TCP or UDP stream eXPORT data, return without further
+     * action.
+     */
+    if (ckscko == 1)
+        return;
+#endif /* !defined(PS_STR_XPORT_DATA) */
+
+    /*
+     * Generate and save node ID.
+     */
+    na = (KA_T)(((KA_T)(f->psf_hi_nodeid & 0xffffffff) << 32) |
+                (KA_T)(f->psf_lo_nodeid & 0xffffffff));
+
+#if defined(HASFSTRUCT)
+    if (na) {
+        Lf->fna = na;
+        Lf->fsv |= FSV_NI;
+    }
+#endif /* defined(HASFSTRUCT) */
+
+    /*
+     * Enter type.
+     */
+    switch (f->psf_ftype) {
+    case PS_TYPE_STREAMS:
+        Lf->type = LSOF_FILE_STREAM;
+        break;
+    case PS_TYPE_SOCKET:
+        if (f->psf_subtype == PS_SUBTYPE_SOCKSTR) {
+            Lf->type = LSOF_FILE_STREAM_SOCKET;
+            break;
+        }
+        /* fall through */
+    default:
+        Lf->type = LSOF_FILE_UNKNOWN_RAW;
+        Lf->unknown_file_type_number = f->psf_ftype;
+    }
+    /*
+     * Allocate sufficient space for stream structures, then read them.
+     */
+    if ((nsn = f->psf_nstrentt) && (nsn >= nsa)) {
+        nb = (size_t)(nsn * sizeof(struct pst_stream));
+        if (s)
+            s = (struct pst_stream *)realloc((MALLOC_P *)s, nb);
+        else
+            s = (struct pst_stream *)malloc(nb);
+        if (!s) {
+            (void)fprintf(stderr, "%s: no space for %ld pst_stream bytes\n", Pn,
+                          (long)nb);
+            Error(ctx);
+        }
+        nsa = nsn;
+    }
+    errno = 0;
+    if ((nsr = pstat_getstream(s, sz, (size_t)nsn, 0, &f->psf_fid)) < 1) {
+        if (nsn) {
+            (void)snpf(Namech, Namechl, "can't read %d stream structures%s%s",
+                       nsn, errno ? ": " : "", errno ? strerror(errno) : "");
+            enter_nm(Namech);
+        } else
+            enter_nm("no stream structures present");
+        return;
+    }
+    /*
+     * Find the stream head.
+     */
+    for (hx = 0; hx < nsn; hx++) {
+        if (s[hx].type == PS_STR_HEAD)
+            break;
+    }
+    if (hx >= nsn) {
+        enter_nm("no stream head located");
+        return;
+    }
+    /*
+     * Make sure the stream head's fileid and nodeid match the ones in the
+     * pst_fileino2 structure.
+     */
+    if ((f->psf_hi_fileid != s[hx].val.head.pst_hi_fileid) |
+        (f->psf_lo_fileid != s[hx].val.head.pst_lo_fileid) |
+        (f->psf_hi_nodeid != s[hx].val.head.pst_hi_nodeid) |
+        (f->psf_lo_nodeid != s[hx].val.head.pst_lo_nodeid)) {
+        enter_nm("no matching stream data available");
+        return;
+    }
+
+#if defined(PS_STR_XPORT_DATA)
+    /*
+     * See if this stream has eXPORT data available and is a TCP or
+     * UDP stream.
+     */
+    if ((s[hx].pst_extn_flags & PS_STR_XPORT_DATA) &&
+        ((s[hx].pst_str_xport_protocol == PS_STR_XPORT_TCP_PROTO) ||
+         (s[hx].pst_str_xport_protocol == PS_STR_XPORT_UDP_PROTO))) {
+
+        /*
+         * Make a socket from the eXPORT data and process it.
+         */
+        (void)make_sock(f, &s[hx], &sck);
+        (void)process_socket(f, &sck);
+        return;
+    } else if (ckscko || Selinet) {
+
+        /*
+         * If socket file or Internet file only processing is enabled, return.
+         */
+        return;
+    }
+#endif /* defined(PS_STR_XPORT_DATA) */
+
+    /*
+     * Enter size from stream head's structure, if requested.
+     */
+    if (Lf->access == LSOF_FILE_ACCESS_READ) {
+        Lf->sz = (SZOFFTYPE)s[hx].val.head.pst_rbytes;
+        Lf->sz_def = 1;
+    } else if (Lf->access == LSOF_FILE_ACCESS_WRITE) {
+        Lf->sz = (SZOFFTYPE)s[hx].val.head.pst_wbytes;
+        Lf->sz_def = 1;
+    } else if (Lf->access == LSOF_FILE_ACCESS_READ_WRITE) {
+        Lf->sz = (SZOFFTYPE)s[hx].val.head.pst_rbytes +
+                 (SZOFFTYPE)s[hx].val.head.pst_wbytes;
+        Lf->sz_def = 1;
+    }
+    /*
+     * Get the the device number from the stream head.
+     *
+     * If the stream is a clone:
+     *
+     * if there's a clone list, search it for the device, based on the stream
+     *     head's minor device number only;
+     * if there's no clone list, search Devtp[], using a device number made
+     *     from the stream head's major and minor device numbers;
+     * set the printable clone device number to one whose major device number
+     *     is the stream head's minor device number, and whose minor device
+     *     number is the stream head's device sequence number.
+     *
+     * If the stream isn't a clone, make the device number from the stream
+     *head's major and minor numbers, and look up the non-clone device number in
+     *Devtp[].
+     */
+    if (!Sdev)
+        readdev(0);
+    if (s[hx].val.head.pst_flag & PS_STR_ISACLONE) {
+        if (HaveCloneMaj && (CloneMaj == s[hx].val.head.pst_dev_major)) {
+            for (cl = Clone; cl; cl = cl->next) {
+                if (GET_MIN_DEV(Devtp[cl->dx].rdev) ==
+                    s[hx].val.head.pst_dev_minor) {
+                    dp = &Devtp[cl->dx];
+                    break;
+                }
+            }
+        } else {
+            rdev = makedev(s[hx].val.head.pst_dev_major,
+                           s[hx].val.head.pst_dev_minor);
+            dp = lkupdev(&DevDev, &rdev, 0, 1);
+        }
+        rdev =
+            makedev(s[hx].val.head.pst_dev_minor, s[hx].val.head.pst_dev_seq);
+    } else {
+        rdev =
+            makedev(s[hx].val.head.pst_dev_major, s[hx].val.head.pst_dev_minor);
+        dp = lkupdev(&DevDev, &rdev, 0, 1);
+    }
+    Lf->dev = DevDev;
+    Lf->rdev = rdev;
+    Lf->dev_def = Lf->rdev_def = 1;
+    /*
+     * If the device was located, enter the device name and save the node
+     * number.
+     *
+     * If the device wasn't located, save a positive file ID number from the
+     * pst_fileinfo as a node number.
+     */
+    if (dp) {
+        (void)snpf(Namech, Namechl, "%s", dp->name);
+        ncx = strlen(Namech);
+        Lf->inode = (INODETYPE)dp->inode;
+        Lf->inp_ty = 1;
+    } else {
+        ncx = (size_t)0;
+        if (f->psf_id.psf_fileid > 0) {
+            Lf->inode = (INODETYPE)f->psf_id.psf_fileid;
+            Lf->inp_ty = 1;
+        }
+    }
+    /*
+     * Enter stream module names.
+     */
+    for (i = 1; i < nsr; i++) {
+        if (!(nl = strlen(s[i].val.module.pst_name)))
+            continue;
+        if (ncx) {
+            if ((ncx + 2) > (Namechl - 1))
+                break;
+            (void)snpf(&Namech[ncx], Namechl - ncx, "->");
+            ncx += 2;
+        }
+        if ((ncx + nl) > (Namechl - 1))
+            break;
+        (void)snpf(Namech + ncx, Namechl - ncx, "%s", s[i].val.module.pst_name);
+        ncx += nl;
+    }
+    /*
+     * Set node type.
+     *
+     * Set offset defined if file size not requested or if no size was
+     * obtained from the stream head.
+     */
+    Lf->ntype = N_STREAM;
+    Lf->is_stream = 1;
+    /*
+     * Test for specified file.
+     */
+    if ((f->psf_subtype == PS_SUBTYPE_CHARDEV) ||
+        (f->psf_subtype == PS_SUBTYPE_BLKDEV))
+        i = 1;
+    else
+        i = 0;
+    if (Sfile && is_file_named((char *)NULL, i))
+        Lf->sf |= SELNM;
+    /*
+     * Enter any name characters.
+     */
+    if (Namech[0])
+        enter_nm(Namech);
+}
+
+/*
+ * read_sock() -- read pst_socket info for file
+ */
+
+struct pst_socket *read_sock(struct pst_fileinfo2 *f) /* file information */
+{
+    static struct pst_socket s;
+
+    errno = 0;
+    if (f) {
+        if (pstat_getsocket(&s, sizeof(s), &f->psf_fid) > 0 &&
+            f->psf_hi_fileid == s.pst_hi_fileid &&
+            f->psf_lo_fileid == s.pst_lo_fileid &&
+            f->psf_hi_nodeid == s.pst_hi_nodeid &&
+            f->psf_lo_nodeid == s.pst_lo_nodeid)
+            return (&s);
+    }
+    return ((struct pst_socket *)NULL);
+}
diff --git a/lib/dialects/hpux/pstat/dstore.c b/lib/dialects/hpux/pstat/dstore.c
new file mode 100644 (file)
index 0000000..0966506
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * dstore.c - pstat-based HP-UX global storage for lsof
+ */
+
+/*
+ * Copyright 1999 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 1999 Purdue Research Foundation.\nAll rights reserved.\n";
+#endif
+
+#include "common.h"
+
+/*
+ * Global storage definitions
+ */
+
+_T_LONG_T CloneMaj;   /* clone major device number */
+int HasNFS = -1;      /* NFS-mounted file system status:
+                       *    -1: not yet tested;
+                       *     0: tested and none mounted;
+                       *     1: tested and some mounted */
+int HaveCloneMaj = 0; /* CloneMaj status */
+
+#if defined(HASFSTRUCT)
+/*
+ * Pff_tab[] - table for printing file flags
+ */
+
+struct pff_tab Pff_tab[] = {
+    {(long)PS_FRDONLY, FF_READ},      {(long)PS_FWRONLY, FF_WRITE},
+    {(long)PS_FAPPEND, FF_APPEND},    {(long)PS_FNODELY, FF_NDELAY},
+    {(long)PS_FNBLOCK, FF_NBLOCK},    {(long)PS_FSYNC, FF_SYNC},
+    {(long)PS_FDSYNC, FF_DSYNC},      {(long)PS_FRSYNC, FF_RSYNC},
+    {(long)PS_FLGFILE, FF_LARGEFILE}, {(long)0, NULL}};
+
+/*
+ * Pof_tab[] - table for print process open file flags
+ */
+
+struct pff_tab Pof_tab[] = {{(long)PS_FEXCLOS, POF_CLOEXEC}, {(long)0, NULL}};
+#endif /* defined(HASFSTRUCT) */
diff --git a/lib/dialects/hpux/pstat/machine.h b/lib/dialects/hpux/pstat/machine.h
new file mode 100644 (file)
index 0000000..f132d1f
--- /dev/null
@@ -0,0 +1,590 @@
+/*
+ * machine.h - pstat-based HP-UX definitions for lsof
+ */
+
+/*
+ * Copyright 1999 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.22 2010/07/29 16:03:12 abe Exp $
+ */
+
+#if !defined(LSOF_MACHINE_H)
+#    define LSOF_MACHINE_H 1
+
+#    if defined(__GNUC__)
+/*
+ * Do gcc preparation.
+ */
+
+#        if !defined(__STDC_EXT__)
+#            define __STDC_EXT__
+#        endif /* !defined( __STDC_EXT__) */
+
+#        include <sys/_inttypes.h>
+
+#        if HPUXV >= 1123
+#            undef LSOF_XOPEN_SOURCE_EXTENDED
+#            if defined(_XOPEN_SOURCE_EXTENDED)
+#                define LSOF_XOPEN_SOURCE_EXTENDED _XOPEN_SOURCE_EXTENDED
+#                undef _XOPEN_SOURCE_EXTENDED
+#            endif /* defined(_XOPEN_SOURCE_EXTENDED) */
+#            include <netdb.h>
+#            if defined(LSOF_XOPEN_SOURCE_EXTENDED)
+#                define _XOPEN_SOURCE_EXTENDED LSOF_XOPEN_SOURCE_EXTENDED
+#                undef LSOF_XOPEN_SOURCE_EXTENDED
+#            endif /* defined(_XOPEN_SOURCE_EXTENDED) */
+#        endif     /* HPUXV>=1123 */
+#    endif         /* defined(__GNUC__) */
+
+/*
+ * Make sure a 32 bit lsof for HP-UX<1123 uses [l]stat64()
+ */
+
+#    if !defined(__LP64__) && HPUXV < 1123
+#        define lstat lstat64
+#        define stat stat64
+#    endif /* !defined(__LP64__) && HPUXV<1123 */
+
+/*
+ * 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 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
+
+/*
+ * HASCDRNODE is defined for those dialects that have CD-ROM nodes.
+ */
+
+/* #define     HASCDRNODE      1 */
+
+/*
+ * HASDCACHE is defined for those dialects that support a device cache
+ * file.
+ *
+ * HASENVDC defined the name of an environment variable that contains the
+ * device cache file path.  The HASENVDC environment variable is ignored when
+ * the lsof process is setuid(root) or its real UID is 0.
+ *
+ * HASPERSDC defines the format for the last component of a personal device
+ * cache file path.  The first will be the home directory of the real UID that
+ * executes lsof.
+ *
+ * HASPERSDCPATH defines the environment variable whose value is the middle
+ * component of the personal device cache file path.  The middle component
+ * follows the home directory and precedes the results of applying HASPERSDC.
+ * The HASPERSDCPATH environment variable is ignored when the lsof process is
+ * setuid(root) or its real UID is 0.
+ *
+ * HASSYSDC defines a public device cache file path.  When it's defined, it's
+ * used as the path from which to read the device cache.
+ *
+ * Consult the 00DCACHE and 00FAQ files of the lsof distribution for more
+ * information on device cache file path construction.
+ */
+
+#    define HASDCACHE 1
+#    define HASENVDC "LSOFDEVCACHE"
+#    define HASPERSDC "%h/%p.lsof_%L"
+#    define HASPERSDCPATH "LSOFPERSDCPATH"
+/* #define     HASSYSDC        "/your/choice/of/path" */
+
+/*
+ * HASFIFONODE is defined for those dialects that have FIFO nodes.
+ */
+
+/* #define     HASFIFONODE     1 */
+
+/*
+ * HASFSINO is defined for those dialects that have the file system
+ * inode element, fs_ino, in the lfile structure definition in lsof.h.
+ */
+
+#    define HASFSINO 1
+
+/*
+ * HASFSTRUCT is defined if the dialect has a file structure.
+ *
+ * FSV_DEFAULT defines the default set of file structure values to list.
+ * It defaults to zero (0), but may be made up of a combination of the
+ * FSV_* symbols from lsof.h.
+ *
+ *   HASNOFSADDR  -- has no file structure address
+ *   HASNOFSFLAGS -- has no file structure flags
+ *   HASNOFSCOUNT -- has no file structure count
+ *   HASNOFSNADDR -- has no file structure node address
+ */
+
+#    define HASFSTRUCT 1
+/* #define     FSV_DEFAULT     FSV_? | FSV_? | FSV_? */
+/* #define     HASNOFSADDR     1       has no file structure address */
+/* #define     HASNOFSFLAGS    1       has no file structure flags */
+/* #define     HASNOFSCOUNT    1       has no file structure count */
+/* #define     HASNOFSNADDR    1       has no file structure node address */
+
+/*
+ * HASGNODE is defined for those dialects that have gnodes.
+ */
+
+/* #define     HASGNODE        1 */
+
+/*
+ * HASHSNODE is defined for those dialects that have High Sierra nodes.
+ */
+
+/* #define     HASHSNODE       1 */
+
+/*
+ * HASINODE is defined for those dialects that have inodes and wish to
+ * use readinode() from node.c.
+ */
+
+/* #define     HASINODE        1 */
+
+/*
+ * HASINTSIGNAL is defined for those dialects whose signal function returns
+ * an int.
+ */
+
+/* #define     HASINTSIGNAL    1 */
+
+/*
+ * HASKERNIDCK is defined for those dialects that support the comparison of
+ * the build to running kernel identity.
+ */
+
+#    define HASKERNIDCK 1
+
+/*
+ * HASKOPT is defined for those dialects that support the -k option of
+ * reading the kernel's name list from an optional file.
+ */
+
+/* #define     HASKOPT 1 */
+
+/*
+ * HASLFILEADD is defined for those dialects that need additional elements
+ * in struct lfile.  The HASLFILEADD definition is a macro that defines
+ * them.  If any of the additional elements need to be preset in the
+ * alloc_lfile() function of proc.c, the SETLFILEADD macro may be defined
+ * to do that.
+ *
+ * If any additional elements need to be cleared in alloc_lfile() or in the
+ * free_proc() function of proc.c, the CLRLFILEADD macro may be defined to
+ * do that.  Note that CLRLFILEADD takes one argument, the pointer to the
+ * lfile struct.  The CLRLFILEADD macro is expected to expand to statements
+ * that are complete -- i.e., have terminating semi-colons -- so the macro is
+ * called without a terminating semicolon by proc.c.
+ *
+ * The HASXOPT definition may be used to select the conditions under which
+ * private lfile elements are used.
+ */
+
+#    define HASLFILEADD                                                        \
+        struct pst_fid opfid;                                                  \
+        struct psfileid psfid;
+/* #define CLRLFILEADD(lf)     (lf)->... = (type)NULL; */
+#    define SETLFILEADD                                                        \
+        memset((void *)&Lf->opfid, 0, sizeof(struct pst_fid));                 \
+        memset((void *)&Lf->psfid, 0, sizeof(struct psfileid));
+
+/*
+ * 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 2
+/* #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?       */
+
+/*
+ * 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 2 /* see also dlsof.h */
+/* #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       */
+
+/*
+ * HASTASKS is defined for those dialects that have task reporting support.
+ */
+
+/* #define     HASTASKS        1 */
+
+/*
+ * HASSOOPT, HASSOSTATE and HASTCPOPT define the availability of information
+ * on socket options (SO_* symbols), socket states (SS_* symbols) and TCP
+ * options.
+ */
+
+#    define HASSOOPT 1   /* has socket option information */
+#    define HASSOSTATE 1 /* has socket state information */
+/* #define     HASTCPOPT       1       has TCP options or flags */
+
+/*
+ * Define HASSPECDEVD to be the name of a function that handles the results
+ * of a successful stat(2) of a file name argument.
+ *
+ * For example, HASSPECDEVD() for Darwin makes sure that st_dev is set to
+ * what stat("/dev") returns -- i.e., what's in DevDev.
+ *
+ * The function takes two arguments:
+ *
+ *     1: pointer to the full path name of file
+ *     2: pointer to the stat(2) result
+ *
+ * The function returns void.
+ */
+
+/* #define     HASSPECDEVD     process_dev_stat */
+
+/*
+ * HASSTREAMS is defined for those dialects that support streams.
+ */
+
+/* #define     HASSTREAMS      1 */
+
+/*
+ * HASTCPTPIQ is defined for dialects where it is possible to report the
+ * TCP/TPI Recv-Q and Send-Q values produced by netstat.
+ */
+
+#    define HASTCPTPIQ 1
+
+/*
+ * HASTCPTPIW is defined for dialects where it is possible to report the
+ * TCP/TPI send and receive window sizes produced by netstat.
+ */
+
+#    define HASTCPTPIW 1
+
+/*
+ * HASTCPUDPSTATE is defined for dialects that have TCP and UDP state
+ * support -- i.e., for the "-stcp|udp:state" option and its associated
+ * speed improvements.
+ */
+
+#    define HASTCPUDPSTATE 1
+
+/*
+ * HASTMPNODE is defined for those dialects that have tmpnodes.
+ */
+
+/* #define     HASTMPNODE      1 */
+
+/*
+ * HASVNODE is defined for those dialects that use the Sun virtual file system
+ * node, the vnode.  BSD derivatives usually do; System V derivatives prior to
+ * R4 usually don't.
+ */
+
+/* #define     HASVNODE        1       */
+
+/*
+ * HASXOPT is defined for those dialects that have an X option.  It
+ * defines the text for the usage display.  HASXOPT_VALUE defines the
+ * option's default binary value -- 0 or 1.
+ */
+
+/* #define     HASXOPT         "help text for X option" */
+/* #define     HASXOPT_VALUE   1 */
+
+/*
+ * INODETYPE and INODEPSPEC define the internal node number type and its
+ * printf specification modifier.  These need not be defined and lsof.h
+ * can be allowed to define defaults.
+ *
+ * These are defined here, because they must be used in dlsof.h.
+ */
+
+#    define INODETYPE unsigned long long
+/* inode number internal storage type */
+#    define INODEPSPEC                                                         \
+        "ll" /* INODETYPE printf specification                                 \
+              * modifier */
+
+/*
+ * UID_ARG defines the size of a User ID number when it is passed
+ * as a function argument.
+ */
+
+#    define UID_ARG uid_t
+
+/*
+ * 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_PRINT_TCPTPI            1          ptti.c */
+#    define USE_LIB_READDEV 1 /* rdev.c */
+#    define USE_LIB_READMNT 1 /* rmnt.c */
+/* #define     USE_LIB_RNAM                    1          rnam.c */
+/* #define     USE_LIB_RNCH                    1          rnch.c */
+/* #define     USE_LIB_RNMH                    1          rnmh.c */
+/* #define     USE_LIB_SNPF                    1          snpf.c */
+#    define snpf snprintf /* use the system's snprintf() */
+
+/*
+ * WARNDEVACCESS is defined for those dialects that should issue a warning
+ * when lsof can't access /dev (or /device) or one of its sub-directories.
+ * The warning can be inhibited by the lsof caller with the -w option.
+ */
+
+/* #define     WARNDEVACCESS   1 */
+
+/*
+ * WARNINGSTATE is defined for those dialects that want to suppress all lsof
+ * warning messages.
+ */
+
+/* #define     WARNINGSTATE    1       warnings are enabled by default */
+
+/*
+ * WILLDROPGID is defined for those dialects whose lsof executable runs
+ * setgid(not_real_GID) and whose setgid power can be relinquished after
+ * the dialect's initialize() function has been executed.
+ */
+
+/* #define     WILLDROPGID     1       */
+
+/*
+ * zeromem is a macro that uses bzero or memset.
+ */
+
+#    define zeromem(a, l) memset((void *)a, 0, l)
+
+#endif /* !defined(LSOF_MACHINE_H) */
diff --git a/lib/dialects/linux/Makefile b/lib/dialects/linux/Makefile
new file mode 100644 (file)
index 0000000..f8adaa6
--- /dev/null
@@ -0,0 +1,180 @@
+
+# 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} -Iinclude -Ilib -Isrc -I.
+CFLAGS=        -Wall ${CDEFS} ${INCL} ${DEP} ${DEBUG}
+
+GRP=
+
+HDR=   lib/common.h include/lsof_fields.h dlsof.h machine.h lib/proto.h dproto.h
+
+SRC=    dfile.c dmnt.c dnode.c dprint.c dproc.c dsock.c dstore.c \
+       arg.c main.c print.c store.c usage.c \
+       util.c
+
+OBJ=   dfile.o dmnt.o dnode.o dprint.o dproc.o dsock.o dstore.o \
+       arg.o main.o print.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}
+
+check: all
+       bash ./check.bash linux
+
+dist: clean
+       test -d .git && bash support/GenericDistrib2 linux
+
+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)
+       (cd tests; ${MAKE} clean)
+       (cd lib/dialects/linux/tests; ${MAKE} 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_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 \
+         if [ "X${SOURCE_DATE_EPOCH}" = "X" ]; then \
+           echo '#define       LSOF_HOST       "'`uname -n`'"' >> version.h; \
+         else \
+           echo '#define       LSOF_HOST       ""' >> version.h; \
+         fi \
+       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 \
+         if [ "X${SOURCE_DATE_EPOCH}" = "X" ]; then \
+           echo '#define       LSOF_LOGNAME    "${LOGNAME}"' >> version.h; \
+         else \
+           echo '#define       LSOF_LOGNAME    ""' >> version.h; \
+         fi \
+       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 \
+         if [ "X${SOURCE_DATE_EPOCH}" = "X" ]; then \
+           echo '#define       LSOF_SYSINFO    "'`uname -a`'"' >> version.h; \
+         else \
+           echo '#define       LSOF_SYSINFO    ""' >> version.h; \
+         fi \
+       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 \
+         if [ "X${SOURCE_DATE_EPOCH}" = "X" ]; then \
+           echo '#define       LSOF_USER       "${USER}"' >> version.h; \
+         else \
+           echo '#define       LSOF_USER       ""' >> version.h; \
+         fi \
+       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/lib/dialects/linux/Mksrc b/lib/dialects/linux/Mksrc
new file mode 100755 (executable)
index 0000000..57a6f89
--- /dev/null
@@ -0,0 +1,37 @@
+#!/bin/bash
+#
+# 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 $
+
+mksrc() {
+  for i in $L
+  do
+    rm -f $i
+    $LSOF_MKC $D/$i $i
+    echo "$LSOF_MKC $D/$i $i"
+  done
+}
+
+D=lib/dialects/linux
+L="dfile.c dlsof.h dmnt.c dnode.c dproc.c dproto.h dsock.c dstore.c machine.h"
+
+mksrc
+
+D=src
+L="arg.c main.c print.c ptti.c store.c usage.c util.c"
+
+mksrc
+
+D=src/dialects/linux
+L="dprint.c"
+
+mksrc
diff --git a/lib/dialects/linux/dfile.c b/lib/dialects/linux/dfile.c
new file mode 100644 (file)
index 0000000..dbd6c00
--- /dev/null
@@ -0,0 +1,347 @@
+/*
+ * 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.
+ */
+
+#include "common.h"
+
+/*
+ * Local structures
+ */
+
+/*
+ * Local static variables
+ */
+
+
+/*
+ * 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!) */
+/* hash for Sfile by major device,
+ * minor device, and inode, modulo mod
+ * (mod must be a power of 2) */
+#define SFHASHDEVINO(maj, min, ino, mod)                                       \
+    ((int)(((int)((((int)(maj + 1)) * ((int)((min + 1)))) + ino) * 31415) &    \
+           (mod - 1)))
+#define SFRDHASH                                                               \
+    1024 /* Sfile hash by raw device number                                    \
+          * bucket count (power of 2!) */
+/* 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 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)))
+#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(struct lsof_context *ctx) {
+    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);
+        Error(ctx);
+    }
+    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);
+        Error(ctx);
+    }
+    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);
+        Error(ctx);
+    }
+    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);
+        Error(ctx);
+    }
+    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);
+                    Error(ctx);
+                }
+                sn->s = s;
+                sn->next = sh->next;
+                sh->next = sn;
+            }
+        }
+    }
+}
+
+/*
+ * is_file_named() - is this file named?
+ */
+int is_file_named(
+    /* context */
+    struct lsof_context *ctx,
+    /* 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
+     */
+    int search_type,
+    /* path name (device and inode are
+     * identified via *Lf) */
+    char *path,
+    /* NFS file system (NULL if not) */
+    struct mounts *nfs_mount,
+    /* character or block type file --
+     * VCHR or VBLK vnode, or S_IFCHR
+     * or S_IFBLK inode */
+    int cd) {
+    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 ((search_type == 2) && path && HbyNmCt) {
+        for (sh = &HbyNm[hashbyname(path, SFNMHASH)]; sh; sh = sh->next) {
+            if ((s = sh->s) && strcmp(path, s->aname) == 0) {
+                f = 2; /* Found match by path */
+                break;
+            }
+        }
+    }
+
+    /*
+     * Check for a regular file by device and inode number.
+     */
+    if (!f && (search_type < 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; /* Found match by inode and dev */
+                break;
+            }
+        }
+    }
+
+    /*
+     * Check for a file system match.
+     */
+    if (!f && (search_type == 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; /* Found match by fs */
+                        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 (path && nfs_mount && nfs_mount->dirl &&
+                        nfs_mount->dir && s->name &&
+                        !strncmp(nfs_mount->dir, s->name, nfs_mount->dirl)) {
+                        f = 1; /* Found match by fs */
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    /*
+     * Check for a character or block device match.
+     */
+    if (!f && !search_type && 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; /* Found match by inode and dev */
+                break;
+            }
+        }
+    }
+    /*
+     * Convert the name if a match occurred.
+     */
+    switch (f) {
+    case 0: /* Not found */
+        return (0);
+    case 1: /* Found match by inode and dev or fs */
+        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(ctx, &sz);
+                (void)snpf(ep, sz, " (%s)", s->devnm);
+            }
+        }
+        break;
+    case 2: /* Found match by path */
+        (void)strcpy(Namech, path);
+        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(struct lsof_context *ctx, /* context */
+                 dev_t *dev,               /* device */
+                 dev_t *rdev,              /* raw device */
+                 int newline,              /* 1 = follow with '\n' */
+                 int node_type)            /* node type: N_BLK or N_chr */
+{
+    char buf[128];
+
+    (void)snpf(buf, sizeof(buf), "%s device: %d,%d",
+               (node_type == N_BLK) ? "BLK" : "CHR", (int)GET_MAJ_DEV(*rdev),
+               (int)GET_MIN_DEV(*rdev));
+    safestrprt(buf, stdout, newline);
+    return (1);
+}
diff --git a/lib/dialects/linux/dlsof.h b/lib/dialects/linux/dlsof.h
new file mode 100644 (file)
index 0000000..f4504a6
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ * 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.23 2015/07/07 19:46:33 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__) || defined(NEEDS_NETINET_TCPH)
+#        include <netinet/tcp.h>
+#    else /* !defined(GLIBCV) && !defined(__UCLIBC__) &&                       \
+             !defined(NEEDS_NETINET_TCPH) */
+#        include <linux/tcp.h>
+#    endif /* defined(GLIBCV) || defined(__UCLIBC__) ||                        \
+              defined(NEEDS_NETINET_TCPH) */
+
+#    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>
+
+#    include <sys/syscall.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
+/* size and offset internal storage
+ * type */
+#        define SZOFFTYPE unsigned long long
+#        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 */
+};
+
+#    if defined(HASEPTOPTS)
+typedef struct pxinfo {  /* hashed pipe, UNIX socket or pseudo-
+                          * terminal inode information */
+    INODETYPE ino;       /* file's inode */
+    struct lfile *lf;    /* connected peer file */
+    int lpx;             /* connected process index */
+    struct pxinfo *next; /* next entry for hashed inode */
+} pxinfo_t;
+#    endif /* defined(HASEPTOPTS) */
+
+extern int HasNFS;
+extern dev_t MqueueDev;
+
+/* offset type:
+ *     0 == unknown
+ *     1 == lstat's st_size
+ *     2 == from /proc/<PID>/fdinfo
+ */
+#    define OFFSET_UNKNOWN 0
+#    define OFFSET_LSTAT 1
+#    define OFFSET_FDINFO 2
+extern int OffType;
+
+struct lsof_context_dialect {};
+
+#endif /* LINUX_LSOF_H */
diff --git a/lib/dialects/linux/dmnt.c b/lib/dialects/linux/dmnt.c
new file mode 100644 (file)
index 0000000..9d3fa21
--- /dev/null
@@ -0,0 +1,696 @@
+/*
+ * 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.
+ */
+
+#include "common.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
+ */
+
+static char *convert_octal_escaped(struct lsof_context *ctx, char *orig_str);
+
+#if defined(HASMNTSUP)
+static int getmntdev(struct lsof_context *ctx, char *dir_name,
+                     size_t dir_name_len, struct stat *s, int *ss);
+static int hash_mnt(char *dir_name);
+#endif /* defined(HASMNTSUP) */
+
+/*
+ * Local structure definitions.
+ */
+
+#if defined(HASMNTSUP)
+typedef struct mntsup {
+    char *dir_name;      /* mounted directory name */
+    size_t dir_name_len; /* strlen(dir_name) */
+    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 mntsup_t **MSHash = (mntsup_t **)NULL;      /* mount supplement
+                                                    * hash buckets */
+
+/*
+ * convert_octal_escaped() -- convert octal-escaped characters in string
+ */
+static char *convert_octal_escaped(struct lsof_context *ctx, /* context */
+                                   char *orig_str /* original string */) {
+    int cur_ch, cvt_len, cvt_idx, orig_len, orig_idx, temp_idx;
+    char *cvt_str;
+    int temp_ch;
+    /*
+     * 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 (!(orig_len = (int)strlen(orig_str)))
+        return ((char *)NULL);
+    if (!(cvt_str = (char *)malloc(orig_len + 1))) {
+        (void)fprintf(stderr,
+                      "%s: can't allocate %d bytes for octal-escaping.\n", Pn,
+                      orig_len + 1);
+        Error(ctx);
+    }
+    /*
+     * Copy the string, replacing octal-escaped characters as they are found.
+     */
+    for (cvt_idx = orig_idx = 0, cvt_len = orig_len; orig_idx < orig_len;
+         orig_idx++) {
+        if (((cur_ch = (int)orig_str[orig_idx]) == (int)'\\') &&
+            ((orig_idx + 3) < orig_len)) {
+
+            /*
+             * The beginning of an octal-escaped character has been found.
+             *
+             * Convert the octal value to a character value.
+             */
+            for (temp_ch = 0, temp_idx = 1;
+                 orig_str[orig_idx + temp_idx] && (temp_idx < 4); temp_idx++) {
+                if (((int)orig_str[orig_idx + temp_idx] < (int)'0') ||
+                    ((int)orig_str[orig_idx + temp_idx] > (int)'7')) {
+
+                    /*
+                     * The escape isn't followed by octets, so ignore the
+                     * escape and just copy it.
+                     */
+                    break;
+                }
+                temp_ch <<= 3;
+                temp_ch += (int)(orig_str[orig_idx + temp_idx] - '0');
+            }
+            if (temp_idx == 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.
+                 */
+                orig_idx += 3;
+                cur_ch = (temp_ch & 0xff);
+            }
+        }
+
+        if (cvt_idx >= cvt_len) {
+            /*
+             * Expand the copy string, as required.  Leave room for a '\0'
+             * terminator.
+             */
+            cvt_len += 64; /* (Make an arbitrary increase.) */
+            if (!(cvt_str = (char *)realloc(cvt_str, cvt_len + 1))) {
+                (void)fprintf(
+                    stderr, "%s: can't realloc %d bytes for octal-escaping.\n",
+                    Pn, cvt_len + 1);
+                Error(ctx);
+            }
+        }
+
+        /*
+         * Copy the character.
+         */
+        cvt_str[cvt_idx++] = (char)cur_ch;
+    }
+
+    /*
+     * Terminate the copy and return its pointer.
+     */
+    cvt_str[cvt_idx] = '\0';
+    return (cvt_str);
+}
+
+#if defined(HASMNTSUP)
+/*
+ * getmntdev() - get mount device from mount supplement
+ */
+static int
+getmntdev(struct lsof_context *ctx, /* context */
+      char *dir_name,               /* mounted directory name */
+      size_t dir_name_len,          /* strlen(dir_name) */
+      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(ctx, MntSupP, 1)) {
+
+            /*
+             * The mount supplement file isn't readable.
+             */
+            err = 1;
+            return (0);
+        }
+        if (!(fs = open_proc_stream(ctx, 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);
+                    Error(ctx);
+                }
+            }
+            h = hash_mnt(path);
+            for (mp = MSHash[h]; mp; mp = mp->next) {
+                if ((mp->dir_name_len == dir_name_len) &&
+                    !strcmp(mp->dir_name, 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);
+                Error(ctx);
+            }
+            if (!(mpn->dir_name = (char *)malloc(sz + 1))) {
+                (void)fprintf(
+                    stderr,
+                    "%s: no space for mount supplement path: %d \"%s\"\n", Pn,
+                    ln, buf);
+                Error(ctx);
+            }
+            (void)strcpy(mpn->dir_name, path);
+            mpn->dir_name_len = 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->dir_name)
+                            (void)free((MALLOC_P *)mp->dir_name);
+                        (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(dir_name);
+    for (mp = MSHash[h]; mp; mp = mp->next) {
+        if ((dir_name_len == mp->dir_name_len) &&
+            !strcmp(dir_name, mp->dir_name)) {
+            zeromem((char *)s, sizeof(struct stat));
+            s->st_dev = mp->dev;
+            *ss |= SB_DEV;
+            return (1);
+        }
+    }
+    return (0);
+}
+
+/*
+ * hash_mnt() - hash mount point
+ */
+static int hash_mnt(char *dir_name /* mount point directory name */) {
+    register int i, h;
+    size_t l;
+
+    if (!(l = strlen(dir_name)))
+        return (0);
+    if (l == 1)
+        return ((int)*dir_name & (HASHMNT - 1));
+    for (i = h = 0; i < (int)(l - 1); i++) {
+        h ^= ((int)dir_name[i] * (int)dir_name[i + 1]) << ((i * 3) % 13);
+    }
+    return (h & (HASHMNT - 1));
+}
+#endif /* defined(HASMNTSUP) */
+
+/*
+ * readmnt() - read mount table
+ */
+struct mounts *readmnt(struct lsof_context *ctx) {
+    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;
+    int mqueue;
+    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(ctx, buf, "r", &vbuf, &vsz, 1);
+    /*
+     * Read mount table entries.
+     */
+    while (fgets(buf, sizeof(buf), ms)) {
+        if (get_fields(ctx, 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 = convert_octal_escaped(ctx, fp[0])) ||
+            !(fp1 = convert_octal_escaped(ctx, 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(ctx, 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 Mqueue directory
+         */
+        mqueue = strcmp(fp[2], "mqueue");
+
+        /*
+         * 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 (!nfs && !HasNFS)
+            HasNFS = 1;
+        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(ctx, 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(ctx, 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);
+                Error(ctx);
+            }
+        }
+        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 if (!mqueue) {
+            mp->ty = N_MQUEUE;
+            MqueueDev = mp->dev;
+        } 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);
+                Error(ctx);
+            }
+            ignstat = 1;
+        } else
+            ln = Readlink(ctx, 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(ctx, ln, &sb))
+            sb.st_mode = 0;
+        mp->fsnmres = ln;
+        ln = NULL;
+        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/lib/dialects/linux/dnode.c b/lib/dialects/linux/dnode.c
new file mode 100644 (file)
index 0000000..725c52e
--- /dev/null
@@ -0,0 +1,901 @@
+/*
+ * 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.
+ */
+
+#include "common.h"
+
+#if defined(HASEPTOPTS) && defined(HASPTYEPT)
+#    include <linux/major.h>
+#endif /* defined(HASEPTOPTS) && defined(HASPTYEPT) */
+
+/*
+ * 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 PINFOBUCKS 512  /* pipe info hash buckets */
+#define HASHPID(pid) (((int)((pid * 31415) >> 3)) & (PIDBUCKS - 1))
+#define HASHPINFO(ino) (((int)((ino * 31415) >> 3)) & (PINFOBUCKS - 1))
+
+/*
+ * Local structure definitions
+ */
+
+struct llock {
+    int pid;
+    dev_t dev;
+    INODETYPE inode;
+    enum lsof_lock_mode type;
+    struct llock *next;
+};
+
+/*
+ * Local definitions
+ */
+
+struct llock **LckH = (struct llock **)NULL; /* PID-hashed locks */
+
+/*
+ * Local function prototypes
+ */
+
+static void check_lock(struct lsof_context *ctx);
+
+#if defined(HASEPTOPTS)
+static void enter_pinfo(struct lsof_context *ctx);
+#endif /* defined(HASEPTOPTS) */
+
+/*
+ * Local storage
+ */
+
+#if defined(HASEPTOPTS)
+static pxinfo_t **Pinfo = (pxinfo_t **)NULL; /* pipe endpoint hash buckets */
+#    if defined(HASPTYEPT)
+static pxinfo_t **PtyInfo = (pxinfo_t **)NULL; /* pseudoterminal endpoint hash
+                                                * buckets */
+#    endif                                     /* defined(HASPTYEPT) */
+static pxinfo_t **PSXMQinfo =
+    (pxinfo_t **)NULL; /* posix msg queue endpoint hash buckets */
+static pxinfo_t **EvtFDinfo =
+    (pxinfo_t **)NULL; /* envetfd endpoint hash buckets */
+#endif                 /* defined(HASEPTOPTS) */
+
+/*
+ * check_lock() - check lock for file *Lf, process *Lp
+ */
+
+static void check_lock(struct lsof_context *ctx) {
+    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;
+        }
+    }
+}
+
+#if defined(HASEPTOPTS)
+static void endpoint_pxinfo_hash(pxinfo_t **pinfo_hash, const size_t nbuckets,
+                                 void (*free_elt)(void *)) {
+    int h;             /* hash index */
+    pxinfo_t *pi, *pp; /* temporary pointers */
+
+    if (!pinfo_hash)
+        return;
+    for (h = 0; h < nbuckets; h++) {
+        if ((pi = pinfo_hash[h])) {
+            do {
+                pp = pi->next;
+                (void)(*free_elt)((FREE_P *)pi);
+                pi = pp;
+            } while (pi);
+            pinfo_hash[h] = (pxinfo_t *)NULL;
+        }
+    }
+}
+
+static void endpoint_enter(struct lsof_context *ctx, pxinfo_t **pinfo_hash,
+                           const char *table_name, int id) {
+    int h;
+    struct lfile *lf;       /* local file structure pointer */
+    struct lproc *lp;       /* local proc structure pointer */
+    pxinfo_t *np, *pi, *pe; /* inode hash pointers */
+    char fd[FDLEN];
+
+    /*
+     * Make sure this is a unique entry.
+     */
+    for (h = HASHPINFO(id), pi = pinfo_hash[h], pe = (pxinfo_t *)NULL; pi;
+         pe = pi, pi = pi->next) {
+        lf = pi->lf;
+        lp = &Lproc[pi->lpx];
+        if (pi->ino == id) {
+            if ((lp->pid == Lp->pid) && (lf->fd_type == Lf->fd_type) &&
+                (lf->fd_num == Lf->fd_num))
+                return;
+        }
+    }
+    /*
+     * Allocate, fill and link a new pipe info structure used for pty
+     * to the end of the pty device hash chain.
+     */
+    if (!(np = (pxinfo_t *)malloc(sizeof(pxinfo_t)))) {
+        fd_to_string(Lf->fd_type, Lf->fd_num, fd);
+        (void)fprintf(stderr,
+                      "%s: no space for pipeinfo for %s, PID %d, FD %s\n",
+                      table_name, Pn, Lp->pid, fd);
+        Error(ctx);
+    }
+    np->ino = id;
+    np->lf = Lf;
+    np->lpx = Lp - Lproc;
+    np->next = (pxinfo_t *)NULL;
+    if (pe)
+        pe->next = np;
+    else
+        pinfo_hash[h] = np;
+}
+
+static pxinfo_t *
+endpoint_find(struct lsof_context *ctx, pxinfo_t **pinfo_hash,
+              int (*is_acceptable)(struct lsof_context *, pxinfo_t *, int,
+                                   struct lfile *),
+              int pid, struct lfile *lf, int id, pxinfo_t *pp) {
+    int h;        /* hash result */
+    pxinfo_t *pi; /* pipe info pointer */
+
+    if (pinfo_hash) {
+        if (pp)
+            pi = pp;
+        else {
+            h = HASHPINFO(id);
+            pi = pinfo_hash[h];
+        }
+        while (pi) {
+            if (pi->ino == id && is_acceptable(ctx, pi, pid, lf))
+                return (pi);
+            pi = pi->next;
+        }
+    }
+    return ((pxinfo_t *)NULL);
+}
+
+/*
+ * endpoint_accept_other_than_self() -- a helper function return true if
+ * fd associated with pi is not the same as fd associated with lf.
+ */
+
+static int endpoint_accept_other_than_self(struct lsof_context *ctx,
+                                           pxinfo_t *pi, int pid,
+                                           struct lfile *lf) {
+    struct lfile *ef = pi->lf;
+    struct lproc *ep = &Lproc[pi->lpx];
+    return (lf->fd_type != ef->fd_type) || (lf->fd_num != ef->fd_num) ||
+           (pid != ep->pid);
+}
+
+/*
+ * clear_pinfo() -- clear allocated pipe info
+ */
+
+void clear_pinfo(struct lsof_context *ctx) {
+    endpoint_pxinfo_hash(Pinfo, PINFOBUCKS, free);
+}
+
+/*
+ * enter_pinfo() -- enter pipe info
+ *
+ *     entry   Lf = local file structure pointer
+ *             Lp = local process structure pointer
+ */
+
+static void enter_pinfo(struct lsof_context *ctx) {
+    if (!Pinfo) {
+        /*
+         * Allocate pipe info hash buckets.
+         */
+        if (!(Pinfo = (pxinfo_t **)calloc(PINFOBUCKS, sizeof(pxinfo_t *)))) {
+            (void)fprintf(stderr, "%s: no space for %d pipe info buckets\n", Pn,
+                          PINFOBUCKS);
+            Error(ctx);
+        }
+    }
+    endpoint_enter(ctx, Pinfo, "pipeinfo", Lf->inode);
+}
+
+/*
+ * find_pepti() -- find pipe end point info
+ */
+
+pxinfo_t *find_pepti(struct lsof_context *ctx, /* context */
+                     int pid,          /* pid of the process owning lf */
+                     struct lfile *lf, /* pipe's lfile */
+                     pxinfo_t *pp)     /* previous pipe info (NULL == none) */
+{
+    return endpoint_find(ctx, Pinfo, endpoint_accept_other_than_self, pid, lf,
+                         lf->inode, pp);
+}
+
+#    if defined(HASPTYEPT)
+
+/*
+ * clear_ptyinfo() -- clear allocated pseudoterminal info
+ */
+
+void clear_ptyinfo(struct lsof_context *ctx) {
+    endpoint_pxinfo_hash(PtyInfo, PINFOBUCKS, free);
+}
+
+/*
+ * enter_ptmxi() -- enter pty info
+ *
+ *     entry   Lf = local file structure pointer
+ *             Lp = local process structure pointer
+ */
+
+void enter_ptmxi(struct lsof_context *ctx, /* context */
+                 int mn)                   /* minor number of device */
+{
+    /*
+     * Allocate pipe info hash buckets (but used for pty).
+     */
+    if (!PtyInfo) {
+        if (!(PtyInfo = (pxinfo_t **)calloc(PINFOBUCKS, sizeof(pxinfo_t *)))) {
+            (void)fprintf(stderr, "%s: no space for %d pty info buckets\n", Pn,
+                          PINFOBUCKS);
+            Error(ctx);
+        }
+    }
+    endpoint_enter(ctx, PtyInfo, "pty", mn);
+}
+
+/*
+ * ptyepti_accept_ptmx() -- a helper function return whether lfile is pty ptmx
+ * or not
+ */
+
+static int ptyepti_accept_ptmx(struct lsof_context *ctx, pxinfo_t *pi, int pid,
+                               struct lfile *lf) {
+    struct lfile *ef = pi->lf;
+    return is_pty_ptmx(ef->rdev);
+}
+
+/*
+ * ptyepti_accept_slave() -- a helper function returns whether lfile is pty
+ * slave or not
+ */
+
+static int ptyepti_accept_slave(struct lsof_context *ctx, pxinfo_t *pi, int pid,
+                                struct lfile *lf) {
+    struct lfile *ef = pi->lf;
+    return is_pty_slave(GET_MAJ_DEV(ef->rdev));
+}
+
+/*
+ * find_ptyepti() -- find pseudoterminal end point info
+ */
+
+pxinfo_t *find_ptyepti(struct lsof_context *ctx, /* context */
+                       int pid,                  /* PID*/
+                       struct lfile *lf,         /* pseudoterminal's lfile */
+                       int m,                    /* minor number type:
+                                                  *     0 == use tty_index
+                                                  *     1 == use minor device */
+                       pxinfo_t *pp)             /* previous pseudoterminal info
+                                                  * (NULL == none) */
+{
+    return endpoint_find(ctx, PtyInfo,
+                         m ? ptyepti_accept_ptmx : ptyepti_accept_slave, pid,
+                         lf, m ? GET_MIN_DEV(lf->rdev) : lf->tty_index, pp);
+}
+
+/*
+ * is_pty_slave() -- is a pseudoterminal a slave device
+ */
+
+int is_pty_slave(int sm) /* slave major device number */
+{
+    /* linux/Documentation/admin-guide/devices.txt
+       -------------------------------------------
+       136-143 char    Unix98 PTY slaves
+       0 = /dev/pts/0  First Unix98 pseudo-TTY
+       1 = /dev/pts/1  Second Unix98 pseudo-TTY
+       ...
+
+       These device nodes are automatically generated with
+       the proper permissions and modes by mounting the
+       devpts filesystem onto /dev/pts with the appropriate
+       mount options (distribution dependent, however, on
+       *most* distributions the appropriate options are
+       "mode=0620,gid=<gid of the "tty" group>".) */
+    if ((UNIX98_PTY_SLAVE_MAJOR <= sm) &&
+        (sm < (UNIX98_PTY_SLAVE_MAJOR + UNIX98_PTY_MAJOR_COUNT))) {
+        return 1;
+    }
+    return 0;
+}
+
+/*
+ * is_pty_ptmx() -- is a pseudoterminal a master clone device
+ */
+
+int is_pty_ptmx(dev_t dev) /* device number */
+{
+    if ((GET_MAJ_DEV(dev) == TTYAUX_MAJOR) && (GET_MIN_DEV(dev) == 2))
+        return 1;
+    return 0;
+}
+#    endif /* defined(HASPTYEPT) */
+
+/*
+ * clear_psxmqinfo -- clear allocate posix mq info
+ */
+
+void clear_psxmqinfo(struct lsof_context *ctx) {
+    endpoint_pxinfo_hash(PSXMQinfo, PINFOBUCKS, free);
+}
+
+/*
+ * enter_psxmqinfo() -- enter posix mq info
+ *
+ *     entry   Lf = local file structure pointer
+ *             Lp = local process structure pointer
+ */
+
+void enter_psxmqinfo(struct lsof_context *ctx) {
+    if (!PSXMQinfo) {
+        /*
+         * Allocate posix mq info hash buckets.
+         */
+        if (!(PSXMQinfo =
+                  (pxinfo_t **)calloc(PINFOBUCKS, sizeof(pxinfo_t *)))) {
+            (void)fprintf(stderr, "%s: no space for %d posix mq info buckets\n",
+                          Pn, PINFOBUCKS);
+            Error(ctx);
+        }
+    }
+    endpoint_enter(ctx, PSXMQinfo, "psxmqinfo", Lf->inode);
+}
+
+/*
+ * find_psxmqinfo() -- find posix mq end point info
+ */
+
+pxinfo_t *
+find_psxmqinfo(struct lsof_context *ctx, /* context */
+               int pid,                  /* pid of the process owning lf */
+               struct lfile *lf,         /* posix mq's lfile */
+               pxinfo_t *pp) /* previous posix mq info (NULL == none) */
+{
+    return endpoint_find(ctx, PSXMQinfo, endpoint_accept_other_than_self, pid,
+                         lf, lf->inode, pp);
+}
+
+/*
+ * clear_evtfdinfo -- clear allocate eventfd info
+ */
+
+void clear_evtfdinfo(struct lsof_context *ctx) {
+    endpoint_pxinfo_hash(EvtFDinfo, PINFOBUCKS, free);
+}
+
+/*
+ * enter_evtfdinfo() -- enter eventfd info
+ *
+ *     entry   Lf = local file structure pointer
+ *             Lp = local process structure pointer
+ */
+
+void enter_evtfdinfo(struct lsof_context *ctx, int id) {
+    if (!EvtFDinfo) {
+        /*
+         * Allocate eventfd info hash buckets.
+         */
+        if (!(EvtFDinfo =
+                  (pxinfo_t **)calloc(PINFOBUCKS, sizeof(pxinfo_t *)))) {
+            (void)fprintf(stderr, "%s: no space for %d envet fd info buckets\n",
+                          Pn, PINFOBUCKS);
+            Error(ctx);
+        }
+    }
+    endpoint_enter(ctx, EvtFDinfo, "evtfdinfo", id);
+}
+
+/*
+ * find_evtfdinfo() -- find eventfd end point info
+ */
+
+pxinfo_t *
+find_evtfdinfo(struct lsof_context *ctx, /* context */
+               int pid,                  /* pid of the process owning lf */
+               struct lfile *lf,         /* eventfd's lfile */
+               pxinfo_t *pp) /* previous eventfd info (NULL == none) */
+{
+    void *r = endpoint_find(ctx, EvtFDinfo, endpoint_accept_other_than_self,
+                            pid, lf, lf->eventfd_id, pp);
+    return r;
+}
+#endif /* defined(HASEPTOPTS) */
+
+/*
+ * get_fields() - separate a line into fields
+ */
+
+int get_fields(struct lsof_context *ctx, /* context */
+               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);
+                Error(ctx);
+            }
+        }
+        fp[n++] = bp;
+    }
+    *fr = fp;
+    return (n);
+}
+
+/*
+ * get_locks() - get lock information from /proc/locks
+ */
+
+void get_locks(struct lsof_context *ctx, /* context */
+               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;
+    enum lsof_lock_mode 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));
+            Error(ctx);
+        }
+    }
+    /*
+     * Open the /proc lock file, assign a page size buffer to its stream,
+     * and read it.
+     */
+    if (!(ls = open_proc_stream(ctx, p, "r", &vbuf, &vsz, 0)))
+        return;
+    while (fgets(buf, sizeof(buf), ls)) {
+        if (get_fields(ctx, 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 ? LSOF_LOCK_WRITE_FULL : LSOF_LOCK_WRITE_PARTIAL;
+        else
+            type = ex ? LSOF_LOCK_READ_FULL : LSOF_LOCK_READ_PARTIAL;
+        /*
+         * 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), "%" INODEPSPEC "u", inode);
+            (void)fprintf(
+                stderr, "%s: can't allocate llock: PID %d; dev %x; inode %s\n",
+                Pn, pid, (int)dev, buf);
+            Error(ctx);
+        }
+        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(struct lsof_context *ctx, /* context */
+                       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 = LSOF_FILE_ACCESS_READ;
+        else if (access == S_IWUSR)
+            Lf->access = LSOF_FILE_ACCESS_WRITE;
+        else
+            Lf->access = LSOF_FILE_ACCESS_READ_WRITE;
+    }
+    /*
+     * 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(ctx, 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 defined(HASEPTOPTS) && defined(HASPTYEPT)
+            if (FeptE && (Ntype == N_CHR) &&
+                is_pty_slave(GET_MAJ_DEV(Lf->rdev))) {
+                enter_ptmxi(ctx, GET_MIN_DEV(Lf->rdev));
+                Lf->sf |= SELPTYINFO;
+            }
+#endif /* defined(HASEPTOPTS) && defined(HASPTYEPT) */
+        }
+    }
+    if (Ntype == N_REGLR && (HasNFS == 2)) {
+        for (mp = readmnt(ctx); 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;
+
+#if defined(HASEPTOPTS)
+        if ((Lf->ntype == N_FIFO) && FeptE) {
+            (void)enter_pinfo(ctx);
+            Lf->sf |= SELPINFO;
+        } else if ((Lf->dev == MqueueDev) && FeptE) {
+            (void)enter_psxmqinfo(ctx);
+            Lf->sf |= SELPSXMQINFO;
+        }
+#endif /* defined(HASEPTOPTS) */
+    }
+    /*
+     * Check for a lock.
+     */
+    if (Lf->dev_def && (Lf->inp_ty == 1))
+        (void)check_lock(ctx);
+    /*
+     * Save the file size.
+     */
+    switch (Ntype) {
+    case N_BLK:
+    case N_CHR:
+    case N_FIFO:
+        if (l && (ls & SB_SIZE) && OffType != OFFSET_UNKNOWN) {
+            Lf->off = (SZOFFTYPE)l->st_size;
+            Lf->off_def = 1;
+        }
+        break;
+    default:
+        if (l && (ls & SB_SIZE) && OffType != OFFSET_UNKNOWN) {
+            Lf->off = (SZOFFTYPE)l->st_size;
+            Lf->off_def = 1;
+        }
+        if (ss & SB_SIZE) {
+            Lf->sz = (SZOFFTYPE)s->st_size;
+            Lf->sz_def = 1;
+        }
+    }
+    /*
+     * Record the link count.
+     */
+    if (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:
+            Lf->type = LSOF_FILE_BLOCK;
+            break;
+        case S_IFCHR:
+            Lf->type = LSOF_FILE_CHAR;
+            break;
+        case S_IFDIR:
+            Lf->type = LSOF_FILE_DIR;
+            break;
+        case S_IFIFO:
+            Lf->type = LSOF_FILE_FIFO;
+            break;
+        case S_IFREG:
+            if (Lf->dev == MqueueDev)
+                Lf->type = LSOF_FILE_POSIX_MQ;
+            else
+                Lf->type = LSOF_FILE_REGULAR;
+            break;
+        case S_IFLNK:
+            Lf->type = LSOF_FILE_LINK;
+            break;
+        default:
+            if (Ntype == N_ANON_INODE)
+                Lf->type = LSOF_FILE_ANON_INODE;
+            else {
+                Lf->type = LSOF_FILE_UNKNOWN_RAW;
+                Lf->unknown_file_type_number = (type >> 12) & 0xf;
+            }
+        }
+    } else
+        Lf->type = LSOF_FILE_UNKNOWN_STAT;
+    /*
+     * Record an NFS file selection.
+     */
+    if (Ntype == N_NFS && Fnfs)
+        Lf->sf |= SELNFS;
+    /*
+     * Test for specified file.
+     */
+    if (Sfile &&
+        is_file_named(ctx, 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(ctx, &sz);
+            (void)snpf(cp, sz, " (%s)", mp->fsname);
+        }
+    }
+    if (Namech[0])
+        enter_nm(ctx, Namech);
+}
diff --git a/lib/dialects/linux/dproc.c b/lib/dialects/linux/dproc.c
new file mode 100644 (file)
index 0000000..cb6bb64
--- /dev/null
@@ -0,0 +1,1921 @@
+/*
+ * 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.
+ */
+
+#include "common.h"
+
+#include <inttypes.h>
+
+/*
+ * Local definitions
+ */
+
+#define FDINFO_FLAGS 0x1 /* fdinfo flags available */
+#define FDINFO_POS 0x2   /* fdinfo position available */
+
+#if defined(HASEPTOPTS)
+#    define FDINFO_EVENTFD_ID 0x4 /* fdinfo eventfd-id available */
+#    if defined(HASPTYEPT)
+#        define FDINFO_TTY_INDEX 0x8 /* fdinfo tty-index available */
+#    endif                           /* defined(HASPTYEPT) */
+#endif                               /* defined(HASEPTOPTS) */
+
+#define FDINFO_PID 0x10 /* pidfd pid available */
+#define FDINFO_TFD 0x20 /* fd monitored by eventpoll fd */
+
+#define FDINFO_BASE (FDINFO_FLAGS | FDINFO_POS)
+#if defined(HASEPTOPTS)
+#    if defined(HASPTYEPT)
+#        define FDINFO_ALL                                                     \
+            (FDINFO_BASE | FDINFO_TTY_INDEX | FDINFO_EVENTFD_ID | FDINFO_PID | \
+             FDINFO_TFD)
+#    else /* !defined(HASPTYEPT) */
+#        define FDINFO_ALL                                                     \
+            (FDINFO_BASE | FDINFO_EVENTFD_ID | FDINFO_PID | FDINFO_TFD)
+#    endif /* defined(HASPTYEPT) */
+#    define FDINFO_OPTIONAL (FDINFO_ALL & ~FDINFO_BASE)
+#else /* !defined(HASEPTOPTS) */
+#    define FDINFO_ALL (FDINFO_BASE | FDINFO_PID | FDINFO_TFD)
+#endif /* defined(HASEPTOPTS) */
+
+#define LSTAT_TEST_FILE "/"
+#define LSTAT_TEST_SEEK 1
+
+#if !defined(ULLONG_MAX)
+#    define ULLONG_MAX 18446744073709551615ULL
+#endif /* !defined(ULLONG_MAX) */
+
+#define NS_PATH_LENGTH 100  /* namespace path string length */
+#define MAP_PATH_LENGTH 100 /* map_files path length */
+#define ADDR_LENGTH 100     /* addr range of map_files length */
+
+/*
+ * Local structures
+ */
+
+struct l_fdinfo {
+    int flags; /* flags: line value */
+    off_t pos; /* pos: line value */
+
+#if defined(HASEPTOPTS)
+    int eventfd_id;
+#    if defined(HASPTYEPT)
+    int tty_index; /* pty line index */
+#    endif         /* defined(HASPTYEPT) */
+#endif             /* defined(HASEPTOPTS) */
+
+    int pid; /* for pidfd */
+
+#define EPOLL_MAX_TFDS 32
+    int tfds[EPOLL_MAX_TFDS];
+    size_t tfd_count;
+};
+
+/*
+ * 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
+ */
+
+static MALLOC_S alloc_cbf(struct lsof_context *ctx, MALLOC_S len, char **cbf,
+                          MALLOC_S cbfa);
+static int get_fdinfo(struct lsof_context *ctx, char *p, int msk,
+                      struct l_fdinfo *fi);
+static int getlinksrc(char *ln, char *src, int srcl, char **rest);
+static int isefsys(struct lsof_context *ctx, char *path,
+                   enum lsof_file_type type, int l, efsys_list_t **rep,
+                   struct lfile **lfr);
+static int nm2id(char *nm, int *id, int *idl);
+static int read_id_stat(struct lsof_context *ctx, char *p, int id, char **cmd,
+                        int *ppid, int *pgid);
+static void process_proc_map(struct lsof_context *ctx, char *p, struct stat *s,
+                             int ss);
+static int process_id(struct lsof_context *ctx, char *idp, int idpl, char *cmd,
+                      UID_ARG uid, int pid, int ppid, int pgid, int tid,
+                      char *tcmd);
+static int statEx(struct lsof_context *ctx, char *p, struct stat *s, int *ss);
+
+static void snp_eventpoll(char *p, int len, int *tfds, int tfd_count);
+
+#if defined(HASSELINUX)
+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(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(struct lsof_context *ctx, /* context */
+                   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);
+        Error(ctx);
+    }
+    cntxp->f = 0;
+    cntxp->cntx = cntx;
+    cntxp->next = CntxArg;
+    CntxArg = cntxp;
+    return (0);
+}
+#endif /* defined(HASSELINUX) */
+
+/*
+ * alloc_cbf() -- allocate a command buffer
+ */
+
+static MALLOC_S alloc_cbf(struct lsof_context *ctx, /* context */
+                          MALLOC_S len,             /* required length */
+                          char **cbf,               /* current buffer */
+                          MALLOC_S cbfa) /* current buffer allocation */
+{
+    if (*cbf)
+        *cbf = (char *)realloc((MALLOC_P *)*cbf, len);
+    else
+        *cbf = (char *)malloc(len);
+    if (!*cbf) {
+        (void)fprintf(stderr, "%s: can't allocate command %d bytes\n", Pn,
+                      (int)len);
+        Error(ctx);
+    }
+    return (len);
+}
+
+/*
+ * gather_proc_info() -- gather process information
+ */
+
+void gather_proc_info(struct lsof_context *ctx) {
+    char *cmd, *tcmd;
+    char cmdbuf[MAXPATHLEN];
+    struct dirent *dp;
+    unsigned char ht, pidts;
+    int n, nl, pgid, pid, ppid, prv, 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);
+            Error(ctx);
+        }
+        (void)snpf(pidpath, pidpathl, "%s/", PROCFS);
+    }
+    /*
+     * Get lock and net information.
+     */
+    (void)make_proc_path(ctx, pidpath, pidx, &path, &pathl, "locks");
+    (void)get_locks(ctx, path);
+    (void)make_proc_path(ctx, pidpath, pidx, &path, &pathl, "net/");
+    (void)set_net_paths(ctx, 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);
+            Error(ctx);
+        }
+    } 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);
+                Error(ctx);
+            }
+        }
+        (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;
+        /*
+         * Get the PID's command name.
+         */
+        (void)make_proc_path(ctx, pidpath, n, &path, &pathl, "stat");
+        if ((prv = read_id_stat(ctx, path, pid, &cmd, &ppid, &pgid)) < 0)
+            cmd = NULL; /* NULL means failure to get command name */
+
+#if defined(HASTASKS)
+        /*
+         * Task reporting has been selected, so save the process' command
+         * string, so that task processing won't change it in the buffer of
+         * read_id_stat().
+         *
+         * Check the tasks of the process first, so that the "-p<PID> -aK"
+         * options work properly.
+         */
+        else if (!IgnTasks && (Selflags & SELTASK)) {
+            /*
+             * Copy cmd before next call to read_id_stat due to static
+             * variables
+             */
+            if (cmd) {
+                strncpy(cmdbuf, cmd, sizeof(cmdbuf) - 1);
+                cmdbuf[sizeof(cmdbuf) - 1] = '\0';
+                cmd = cmdbuf;
+            }
+
+            (void)make_proc_path(ctx, 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);
+                            Error(ctx);
+                        }
+                    }
+                    (void)snpf(tidpath, tidpathl, "%s/%s/stat", taskpath,
+                               dp->d_name);
+                    /*
+                     * Check the task state.
+                     */
+                    rv = read_id_stat(ctx, tidpath, tid, &tcmd, &tppid, &tpgid);
+                    if ((rv < 0) || (rv == 1))
+                        continue;
+                    /*
+                     * Attempt to record the task.
+                     */
+                    if (!process_id(ctx, tidpath, (tx + 1 + nl + 1), cmd, uid,
+                                    pid, tppid, tpgid, tid, tcmd)) {
+                        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.
+         */
+        if ((prv >= 0) && (prv != 1)) {
+            tid = (Fand && ht && pidts && !IgnTasks && (Selflags & SELTASK))
+                      ? pid
+                      : 0;
+            if ((!process_id(ctx, pidpath, n, cmd, uid, pid, ppid, pgid, tid,
+                             (char *)NULL)) &&
+                tid) {
+                Lp->tid = 0;
+            }
+        }
+    }
+}
+
+/*
+ * get_fdinfo() - get values from /proc/<PID>fdinfo/FD
+ */
+
+static int get_fdinfo(struct lsof_context *ctx, /* context */
+                      char *p,                  /* path to fdinfo file */
+                      int msk,             /* mask for information type: e.g.,
+                                            * the FDINFO_* definition */
+                      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 defined(HASEPTOPTS)
+    fi->eventfd_id = -1;
+#    if defined(HASPTYEPT)
+    fi->tty_index = -1;
+#    endif /* defined(HASPTYEPT) */
+#endif     /* defined(HASEPTOPTS) */
+    fi->pid = -1;
+    fi->tfd_count = 0;
+
+    if (!p || !*p || !(fs = fopen(p, "r")))
+        return (0);
+    /*
+     * Read the fdinfo file.
+     */
+    while (fgets(buf, sizeof(buf), fs)) {
+        int opt_flg = 0;
+        if (get_fields(ctx, buf, (char *)NULL, &fp, (int *)NULL, 0) < 2)
+            continue;
+        if (!fp[0] || !*fp[0] || !fp[1] || !*fp[1])
+            continue;
+        if ((msk & FDINFO_FLAGS) && !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) == msk)
+                break;
+        } else if ((msk & FDINFO_POS) && !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) == msk)
+                break;
+
+        } else if (((msk & FDINFO_PID) && !strcmp(fp[0], "Pid:") &&
+                    ((opt_flg = FDINFO_PID))) ||
+                   ((msk & FDINFO_TFD) && !strcmp(fp[0], "tfd:") &&
+                    ((opt_flg = FDINFO_TFD)))
+#if defined(HASEPTOPTS)
+                   || ((msk & FDINFO_EVENTFD_ID) &&
+                       !strcmp(fp[0], "eventfd-id:") &&
+                       ((opt_flg = FDINFO_EVENTFD_ID)))
+#    if defined(HASPTYEPT)
+                   ||
+                   ((msk & FDINFO_TTY_INDEX) && !strcmp(fp[0], "tty-index:") &&
+                    ((opt_flg = FDINFO_TTY_INDEX)))
+#    endif /* defined(HASPTYEPT) */
+#endif     /* defined(HASEPTOPTS) */
+        ) {
+            int val;
+            /*
+             * Process a "tty-index:", "eventfd-id:", "Pid:", or "tfid:" line.
+             */
+            ep = (char *)NULL;
+            if ((ul = strtoul(fp[1], &ep, 0)) == ULONG_MAX || !ep || *ep)
+                continue;
+
+            val = (int)ul;
+            if (val < 0) {
+                /*
+                 * Oops! If integer overflow occurred, reset the field.
+                 */
+                val = -1;
+            }
+
+            rv |= opt_flg;
+            switch (opt_flg) {
+#if defined(HASEPTOPTS)
+            case FDINFO_EVENTFD_ID:
+                fi->eventfd_id = val;
+                break;
+#    if defined(HASPTYEPT)
+            case FDINFO_TTY_INDEX:
+                fi->tty_index = val;
+                break;
+#    endif /* defined(HASPTYEPT) */
+#endif     /* defined(HASEPTOPTS) */
+            case FDINFO_PID:
+                fi->pid = val;
+                break;
+            case FDINFO_TFD:
+                if (fi->tfd_count < EPOLL_MAX_TFDS) {
+                    fi->tfds[fi->tfd_count] = val;
+                    fi->tfd_count++;
+                }
+                break;
+            }
+
+            if ((
+                    /* There can be more than one tfd: lines.
+                   So even if we found one, we can not exit the loop.
+                   However, we can assume tfd lines are continuous. */
+                    opt_flg != FDINFO_TFD &&
+                    (rv == msk || (rv & FDINFO_TFD))) ||
+                (
+                    /* Too many tfds. */
+                    opt_flg == FDINFO_TFD && rv == msk &&
+                    fi->tfd_count == EPOLL_MAX_TFDS))
+                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(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(struct lsof_context *ctx) {
+    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(ctx, 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 = OFFSET_LSTAT;
+            }
+        }
+        if (OffType == OFFSET_UNKNOWN) {
+            (void)snpf(path, sizeof(path), "%s/%d/fdinfo/%d", PROCFS, Mypid,
+                       fd);
+            if (get_fdinfo(ctx, path, FDINFO_POS, &fi) & FDINFO_POS) {
+                if (fi.pos == (off_t)LSTAT_TEST_SEEK)
+                    OffType = OFFSET_FDINFO;
+            }
+        }
+        (void)close(fd);
+    }
+    if (OffType == OFFSET_UNKNOWN) {
+        if (Foffset && !Fwarn)
+            (void)fprintf(
+                stderr, "%s: WARNING: can't report offset; disregarding -o.\n",
+                Pn);
+        Foffset = 0;
+        Fsize = 1;
+    }
+    /*
+     * 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(ctx);
+}
+
+/*
+ * 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 = size of new file path buffer
+ *     sf = new path's suffix
+ *
+ * return: length of new path
+ *     np = updated with new path
+ *     nl = updated with new buffer size
+ */
+int make_proc_path(struct lsof_context *ctx, /* context */
+                   char *pp,  /* path prefix -- e.g., /proc/<pid>/ */
+                   int pl,    /* strlen(pp) */
+                   char **np, /* malloc'd receiving buffer */
+                   int *nl,   /* malloc'd size */
+                   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);
+            Error(ctx);
+        }
+        *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(struct lsof_context *ctx, /* context */
+                   char *path,               /* path to file */
+                   enum lsof_file_type 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(ctx, "UNKNOWN");
+        Lf->ntype = N_UNKN;
+        Lf->type = type != LSOF_FILE_NONE ? type : LSOF_FILE_UNKNOWN;
+        (void)enter_nm(ctx, path);
+        (void)snpf(nmabuf, sizeof(nmabuf), "(%ce %s)", ep->rdlnk ? '+' : '-',
+                   ep->path);
+        nmabuf[sizeof(nmabuf) - 1] = '\0';
+        (void)add_nma(ctx, nmabuf, strlen(nmabuf));
+        if (Lf->sf) {
+            if (lfr)
+                *lfr = Lf;
+            link_lfile(ctx);
+        } else if (lfr)
+            *lfr = (struct lfile *)NULL;
+        return (0);
+    }
+    return (1);
+}
+
+/*
+ * nm2id() - convert a name to an integer ID
+ */
+
+static int nm2id(char *nm, /* pointer to name */
+                 int *id,  /* pointer to ID receiver */
+                 int *idl) /* pointer to ID length receiver */
+{
+    int tid, tidl;
+    int invalid;
+
+    for (*id = *idl = tid = tidl = 0; *nm; nm++) {
+
+#if defined(__STDC__) /* { */
+        invalid = !isdigit((unsigned char)*nm);
+#else  /* !defined(__STDC__)      } { */
+        invalid = !isascii(*nm) || !isdigit((unsigned char)*cp);
+#endif /* defined(__STDC__)       } */
+        if (invalid) {
+            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(struct lsof_context *ctx, /* context */
+                       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 Error()
+                                    */
+{
+    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));
+        Error(ctx);
+    }
+    /*
+     * 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);
+            Error(ctx);
+        }
+        *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));
+        Error(ctx);
+    }
+    return (fs);
+}
+
+/*
+ * process_id - process ID: PID or LWP
+ *
+ * return:  0 == ID processed
+ *          1 == ID not processed
+ */
+
+static int process_id(struct lsof_context *ctx, /* context */
+                      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 */
+                      char *tcmd)  /* task command, if non-NULL) */
+{
+    int av = 0;
+    static char *dpath = (char *)NULL;
+    static int dpathl = 0;
+    short efs, enls, enss, lnk, oty, pn, pss, sf;
+    int fd, i, ls = 0, 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(ctx, pid, pgid, uid, &pss, &sf, tid) ||
+        is_cmd_excl(ctx, cmd, &pss, &sf)) {
+
+#if defined(HASEPTOPTS)
+        if (!FeptE)
+            return (1);
+#else  /* !defined(HASEPTOPTS) */
+        return (1);
+#endif /* defined(HASEPTOPTS) */
+    }
+    if (Cckreg && !FeptE) {
+
+        /*
+         * 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(ctx, pid, pgid, ppid, uid, cmd, (int)pss, (int)sf);
+    Plf = (struct lfile *)NULL;
+
+#if defined(HASTASKS)
+    /*
+     * Enter task information.
+     */
+    Lp->tid = tid;
+    if (tid && tcmd) {
+        if (!(Lp->tcmd = mkstrcpy(tcmd, (MALLOC_S *)NULL))) {
+            (void)fprintf(stderr,
+                          "%s: PID %d, TID %d, no space for task name: ", Pn,
+                          pid, tid);
+            safestrprt(tcmd, stderr, 1);
+            Error(ctx);
+        }
+    }
+#endif /* defined(HASTASKS) */
+
+    /*
+     * Process the ID's current working directory info.
+     */
+    efs = 0;
+    if (!Ckscko) {
+        (void)make_proc_path(ctx, idp, idpl, &path, &pathl, "cwd");
+        alloc_lfile(ctx, LSOF_FD_CWD, -1);
+        if (getlinksrc(path, pbuf, sizeof(pbuf), (char **)NULL) < 1) {
+            if (!Fwarn) {
+                zeromem((char *)&sb, sizeof(sb));
+                lnk = ss = 0;
+                (void)snpf(nmabuf, sizeof(nmabuf), "(readlink: %s)",
+                           strerror(errno));
+                nmabuf[sizeof(nmabuf) - 1] = '\0';
+                (void)add_nma(ctx, nmabuf, strlen(nmabuf));
+                pn = 1;
+            } else
+                pn = 0;
+        } else {
+            lnk = pn = 1;
+            if (Efsysl &&
+                !isefsys(ctx, pbuf, LSOF_FILE_UNKNOWN_CWD, 1, NULL, &lfr)) {
+                efs = 1;
+                pn = 0;
+            } else {
+                ss = SB_ALL;
+                if (HasNFS) {
+                    if ((sv = statsafely(ctx, path, &sb)))
+                        sv = statEx(ctx, 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(ctx, nmabuf, strlen(nmabuf));
+                    }
+                }
+            }
+        }
+        if (pn) {
+            (void)process_proc_node(ctx, lnk ? pbuf : path, path, &sb, ss,
+                                    (struct stat *)NULL, 0);
+            if (Lf->sf)
+                link_lfile(ctx);
+        }
+    }
+    /*
+     * Process the ID's root directory info.
+     */
+    lnk = ss = 0;
+    if (!Ckscko) {
+        (void)make_proc_path(ctx, idp, idpl, &path, &pathl, "root");
+        alloc_lfile(ctx, LSOF_FD_ROOT_DIR, -1);
+        if (getlinksrc(path, pbuf, sizeof(pbuf), (char **)NULL) < 1) {
+            if (!Fwarn) {
+                zeromem((char *)&sb, sizeof(sb));
+                (void)snpf(nmabuf, sizeof(nmabuf), "(readlink: %s)",
+                           strerror(errno));
+                nmabuf[sizeof(nmabuf) - 1] = '\0';
+                (void)add_nma(ctx, nmabuf, strlen(nmabuf));
+                pn = 1;
+            } else
+                pn = 0;
+        } else {
+            lnk = pn = 1;
+            if (Efsysl &&
+                !isefsys(ctx, pbuf, LSOF_FILE_UNKNOWN_ROOT_DIR, 1, NULL, NULL))
+                pn = 0;
+            else {
+                ss = SB_ALL;
+                if (HasNFS) {
+                    if ((sv = statsafely(ctx, path, &sb)))
+                        sv = statEx(ctx, 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(ctx, nmabuf, strlen(nmabuf));
+                    }
+                }
+            }
+        }
+        if (pn) {
+            (void)process_proc_node(ctx, lnk ? pbuf : path, path, &sb, ss,
+                                    (struct stat *)NULL, 0);
+            if (Lf->sf)
+                link_lfile(ctx);
+        }
+    }
+    /*
+     * Process the ID's execution info.
+     */
+    lnk = ss = txts = 0;
+    if (!Ckscko) {
+        (void)make_proc_path(ctx, idp, idpl, &path, &pathl, "exe");
+        alloc_lfile(ctx, LSOF_FD_PROGRAM_TEXT, -1);
+        if (getlinksrc(path, pbuf, sizeof(pbuf), (char **)NULL) < 1) {
+            zeromem((void *)&sb, sizeof(sb));
+            if (!Fwarn) {
+                if ((errno != ENOENT) || uid) {
+                    (void)snpf(nmabuf, sizeof(nmabuf), "(readlink: %s)",
+                               strerror(errno));
+                    nmabuf[sizeof(nmabuf) - 1] = '\0';
+                    (void)add_nma(ctx, nmabuf, strlen(nmabuf));
+                }
+                pn = 1;
+            } else
+                pn = 0;
+        } else {
+            lnk = pn = 1;
+            if (Efsysl && !isefsys(ctx, pbuf, LSOF_FILE_UNKNOWN_PROGRAM_TEXT, 1,
+                                   NULL, NULL))
+                pn = 0;
+            else {
+                ss = SB_ALL;
+                if (HasNFS) {
+                    if ((sv = statsafely(ctx, path, &sb))) {
+                        sv = statEx(ctx, 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(ctx, nmabuf, strlen(nmabuf));
+                    }
+                } else
+                    txts = 1;
+            }
+        }
+        if (pn) {
+            (void)process_proc_node(ctx, lnk ? pbuf : path, path, &sb, ss,
+                                    (struct stat *)NULL, 0);
+            if (Lf->sf)
+                link_lfile(ctx);
+        }
+    }
+    /*
+     * Process the ID's memory map info.
+     */
+    if (!Ckscko) {
+        (void)make_proc_path(ctx, idp, idpl, &path, &pathl, "maps");
+        (void)process_proc_map(ctx, path, txts ? &sb : (struct stat *)NULL,
+                               txts ? ss : 0);
+    }
+
+#if defined(HASSELINUX)
+    /*
+     * Process the PID's SELinux context.
+     */
+    /*
+     * 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);
+                Error(ctx);
+            }
+        }
+    } 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(ctx, idp, idpl, &dpath, &dpathl, "fd/")) < 3)
+        return (0);
+    dpath[i - 1] = '\0';
+    if ((OffType == OFFSET_FDINFO) &&
+        ((j = make_proc_path(ctx, 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(ctx, LSOF_FD_NOFD, -1);
+            nmabuf[sizeof(nmabuf) - 1] = '\0';
+            (void)add_nma(ctx, nmabuf, strlen(nmabuf));
+            link_lfile(ctx);
+        }
+        return (0);
+    }
+    dpath[i - 1] = '/';
+    while ((fp = readdir(fdp))) {
+        if (nm2id(fp->d_name, &fd, &n))
+            continue;
+        (void)make_proc_path(ctx, dpath, i, &path, &pathl, fp->d_name);
+        (void)alloc_lfile(ctx, LSOF_FD_NUMERIC, fd);
+        if (getlinksrc(path, pbuf, sizeof(pbuf), &rest) < 1) {
+            zeromem((char *)&sb, sizeof(sb));
+            lnk = ss = 0;
+            if (!Fwarn) {
+                ls = 0;
+                (void)snpf(nmabuf, sizeof(nmabuf), "(readlink: %s)",
+                           strerror(errno));
+                nmabuf[sizeof(nmabuf) - 1] = '\0';
+                (void)add_nma(ctx, nmabuf, strlen(nmabuf));
+                pn = 1;
+            } else
+                pn = 0;
+        } else {
+            lnk = 1;
+            if (Efsysl &&
+                !isefsys(ctx, pbuf, LSOF_FILE_UNKNOWN_FD, 1, NULL, &lfr)) {
+                efs = 1;
+                pn = 0;
+            } else {
+                if (HasNFS) {
+                    if (lstatsafely(ctx, path, &lsb)) {
+                        (void)statEx(ctx, pbuf, &lsb, &ls);
+                        enls = errno;
+                    } else {
+                        enls = 0;
+                        ls = SB_ALL;
+                    }
+                    if (statsafely(ctx, path, &sb)) {
+                        (void)statEx(ctx, 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(ctx, nmabuf, strlen(nmabuf));
+                }
+                if (!ss && !Fwarn) {
+                    (void)snpf(nmabuf, sizeof(nmabuf), "(stat: %s)",
+                               strerror(enss));
+                    nmabuf[sizeof(nmabuf) - 1] = '\0';
+                    (void)add_nma(ctx, 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)) {
+            /* Clear fi in case oty == 0 */
+            fi.eventfd_id = -1;
+            fi.pid = -1;
+            fi.tfd_count = -1;
+
+            if (oty) {
+                int fdinfo_mask = FDINFO_BASE;
+                (void)make_proc_path(ctx, ipath, j, &pathi, &pathil,
+                                     fp->d_name);
+
+                if (rest && rest[0] == '[' && rest[1] == 'e' &&
+                    rest[2] == 'v' && rest[3] == 'e' && rest[4] == 'n' &&
+                    rest[5] == 't') {
+#if defined(HASEPTOPTS)
+                    if (rest[6] == 'f')
+                        fdinfo_mask |= FDINFO_EVENTFD_ID;
+#endif /* defined(HASEPTOPTS) */
+                    else if (rest[6] == 'p')
+                        fdinfo_mask |= FDINFO_TFD;
+                }
+#if defined(HASEPTOPTS)
+#    if defined(HASPTYEPT)
+                fdinfo_mask |= FDINFO_TTY_INDEX;
+#    endif /* defined(HASPTYEPT) */
+#endif     /* defined(HASEPTOPTS) */
+                if (rest && rest[0] == '[' && rest[1] == 'p')
+                    fdinfo_mask |= FDINFO_PID;
+
+                if ((av = get_fdinfo(ctx, pathi, fdinfo_mask, &fi)) &
+                    FDINFO_POS) {
+                    if (efs) {
+                        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) {
+                    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(ctx, lnk ? pbuf : path, path, &sb, ss, &lsb,
+                                  ls);
+                if (Lf->ntype == N_ANON_INODE) {
+                    if (rest && *rest) {
+#if defined(HASEPTOPTS)
+                        if (fi.eventfd_id != -1 &&
+                            strcmp(rest, "[eventfd]") == 0) {
+                            (void)snpf(rest, sizeof(pbuf) - (rest - pbuf),
+                                       "[eventfd:%d]", fi.eventfd_id);
+                        }
+#endif /* defined(HASPTYEPT) */
+                        if (fi.pid != -1 && strcmp(rest, "[pidfd]") == 0) {
+                            (void)snpf(rest, sizeof(pbuf) - (rest - pbuf),
+                                       "[pidfd:%d]", fi.pid);
+                        }
+                        if (fi.tfd_count > 0 &&
+                            strcmp(rest, "[eventpoll]") == 0) {
+                            snp_eventpoll(rest, sizeof(pbuf) - (rest - pbuf),
+                                          fi.tfds, fi.tfd_count);
+                        }
+
+                        enter_nm(ctx, rest);
+                    }
+#if defined(HASEPTOPTS)
+                    if (FeptE && fi.eventfd_id != -1) {
+                        enter_evtfdinfo(ctx, fi.eventfd_id);
+                        Lf->eventfd_id = fi.eventfd_id;
+                        Lf->sf |= SELEVTFDINFO;
+                    }
+#endif /* defined(HASPTYEPT) */
+                }
+#if defined(HASEPTOPTS) && defined(HASPTYEPT)
+                else if (FeptE && Lf->rdev_def && is_pty_ptmx(Lf->rdev) &&
+                         (av & FDINFO_TTY_INDEX)) {
+                    enter_ptmxi(ctx, fi.tty_index);
+                    Lf->tty_index = fi.tty_index;
+                    Lf->sf |= SELPTYINFO;
+                }
+#endif /* defined(HASEPTOPTS) && defined(HASPTYEPT) */
+
+                if (Lf->sf)
+                    link_lfile(ctx);
+            }
+        }
+    }
+    (void)closedir(fdp);
+    return (0);
+}
+
+/* compare mount namespace of this lsof process and the target process */
+
+static int compare_mntns(int pid) /* pid of the target process */
+{
+    char nspath[NS_PATH_LENGTH];
+    struct stat sb_self, sb_target;
+    int ret;
+
+    if (stat("/proc/self/ns/mnt", &sb_self))
+        return -1;
+
+    ret = snprintf(nspath, sizeof(nspath), "/proc/%d/ns/mnt", pid);
+    if (ret >= sizeof(nspath) || ret <= 0)
+        return -1;
+
+    if (stat(nspath, &sb_target))
+        return -1;
+
+    if (sb_self.st_ino != sb_target.st_ino)
+        return -1;
+
+    return 0;
+}
+
+/*
+ * process_proc_map() - process the memory map of a process
+ */
+
+static void
+process_proc_map(struct lsof_context *ctx, /* context */
+                 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, 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;
+    int diff_mntns = 0;
+    /*
+     * Open the /proc/<pid>/maps file, assign a page size buffer to its stream,
+     * and read it/
+     */
+    if (!(ms = open_proc_stream(ctx, p, "r", &vbuf, &vsz, 0)))
+        return;
+
+    /* target process in a different mount namespace from lsof process. */
+    if (compare_mntns(Lp->pid))
+        diff_mntns = 1;
+
+    while (fgets(buf, sizeof(buf), ms)) {
+        if (get_fields(ctx, 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);
+                Error(ctx);
+            }
+        }
+        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(ctx, LSOF_FD_MEMORY, -1);
+        if (Efsysl && !isefsys(ctx, fp[6], LSOF_FILE_NONE, 0, &rep, NULL))
+            efs = sv = 1;
+        else
+            efs = 0;
+
+        /* For processes in different mount namespace from lsof process,
+         * stat corresponding files under /proc/[pid]/map_files would follow
+         * symlinks regardless of namespaces.
+         */
+        if (diff_mntns) {
+            char path[MAP_PATH_LENGTH];
+            char addr[ADDR_LENGTH];
+            uint64_t start, end;
+            int ret;
+
+            if (sscanf(fp[0], "%" SCNx64 "-%" SCNx64, &start, &end) != 2)
+                goto stat_directly;
+
+            ret = snprintf(addr, sizeof(addr), "%" PRIx64 "-%" PRIx64, start,
+                           end);
+            if (ret >= sizeof(addr) || ret <= 0)
+                goto stat_directly;
+
+            ret = snprintf(path, sizeof(path), "/proc/%d/map_files/%s", Lp->pid,
+                           addr);
+            if (ret >= sizeof(path) || ret <= 0)
+                goto stat_directly;
+
+            if (!efs) {
+                if (HasNFS)
+                    sv = statsafely(ctx, path, &sb);
+                else
+                    sv = stat(path, &sb);
+            }
+        } else {
+        stat_directly:
+            if (!efs) {
+                if (HasNFS)
+                    sv = statsafely(ctx, 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.
+             */
+            zeromem((char *)&sb, 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(ctx, LSOF_FD_DELETED, -1);
+            else if (!efs && !Fwarn) {
+                (void)snpf(nmabuf, sizeof(nmabuf), "(stat: %s)", strerror(en));
+                nmabuf[sizeof(nmabuf) - 1] = '\0';
+                (void)add_nma(ctx, nmabuf, strlen(nmabuf));
+            }
+        } else if (diff_mntns) {
+            mss = SB_ALL;
+        } 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(ctx, LSOF_FD_DELETED, -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(ctx, nmabuf, strlen(nmabuf));
+                    sep = "";
+                } else
+                    sep = "(path ";
+                if ((INODETYPE)sb.st_ino != inode) {
+                    (void)snpf(fmtbuf, sizeof(fmtbuf),
+                               "%%sinode=%%" INODEPSPEC "u)");
+                    (void)snpf(nmabuf, sizeof(nmabuf), fmtbuf, sep,
+                               (INODETYPE)sb.st_ino);
+                    nmabuf[sizeof(nmabuf) - 1] = '\0';
+                    (void)add_nma(ctx, nmabuf, strlen(nmabuf));
+                }
+            }
+            zeromem((char *)&sb, 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(ctx, 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(ctx, fp[6]);
+            Lf->type =
+                ds ? LSOF_FILE_UNKNOWN_DELETED : LSOF_FILE_UNKNOWN_MEMORY;
+            (void)snpf(nmabuf, sizeof(nmabuf), "(%ce %s)",
+                       rep->rdlnk ? '+' : '-', rep->path);
+            nmabuf[sizeof(nmabuf) - 1] = '\0';
+            (void)add_nma(ctx, nmabuf, strlen(nmabuf));
+        }
+        if (Lf->sf)
+            link_lfile(ctx);
+    }
+    (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(struct lsof_context *ctx, /* context */
+                        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;
+    int ch, cx, es, pc;
+    static char *cbf = (char *)NULL;
+    static MALLOC_S cbfa = 0;
+    FILE *fs;
+    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(ctx, p, "r", &vbuf, &vsz, 0)))
+        return (-1);
+    if (!(cp = fgets(buf, sizeof(buf), fs))) {
+
+    read_id_stat_exit:
+
+        (void)fclose(fs);
+        return (-1);
+    }
+    /*
+     * Skip to the first field, and make sure it is a matching ID.
+     */
+    cp1 = cp;
+    while (*cp && (*cp != ' ') && (*cp != '\t'))
+        cp++;
+    if (*cp)
+        *cp = '\0';
+    if (atoi(cp1) != id)
+        goto read_id_stat_exit;
+    /*
+     * The second field should contain the command, enclosed in parentheses.
+     * If it also has embedded '\n' characters, replace them with '?'
+     * characters, accumulating command characters until a closing parentheses
+     * appears.
+     *
+     */
+    for (++cp; *cp && (*cp == ' '); cp++)
+        ;
+    if (!cp || (*cp != '('))
+        goto read_id_stat_exit;
+    cp++;
+    pc = 1; /* start the parenthesis balance count at 1 */
+
+    /* empty process name to avoid leaking previous process name,
+     * see issue #246
+     */
+    if (cbf) {
+        cbf[0] = '\0';
+    }
+
+    /*
+     * Enter the command characters safely.  Supply them from the initial read
+     * of the stat file line, a '\n' if the initial read didn't yield a ')'
+     * command closure, or by reading the rest of the command a character at
+     * a time from the stat file.  Count embedded '(' characters and balance
+     * them with embedded ')' characters.  The opening '(' starts the balance
+     * count at one.
+     */
+    for (cx = es = 0;;) {
+        if (!es)
+            ch = *cp++;
+        else {
+            if ((ch = fgetc(fs)) == EOF)
+                goto read_id_stat_exit;
+        }
+        if (ch == '(') /* a '(' advances the balance count */
+            pc++;
+        if (ch == ')') {
+
+            /*
+             * Balance parentheses when a closure is encountered.  When
+             * they are balanced, this is the end of the command.
+             */
+            pc--;
+            if (!pc)
+                break;
+        }
+        if ((cx + 2) > cbfa)
+            cbfa = alloc_cbf(ctx, (cx + 2), &cbf, cbfa);
+        cbf[cx] = ch;
+        cx++;
+        cbf[cx] = '\0';
+        if (!es && !*cp)
+            es = 1; /* Switch to fgetc() when a '\0' appears. */
+    }
+    *cmd = cbf;
+    /*
+     * Read the remainder of the stat line if it was necessary to read command
+     * characters individually from the stat file.
+     *
+     * Separate the reminder into fields.
+     */
+    if (es)
+        cp = fgets(buf, sizeof(buf), fs);
+    (void)fclose(fs);
+    if (!cp || !*cp)
+        return (-1);
+    if (get_fields(ctx, cp, (char *)NULL, &fp, (int *)NULL, 0) < 3)
+        return (-1);
+    /*
+     * Convert and return parent process (fourth field) and process group (fifth
+     * field) IDs.
+     */
+    if (fp[1] && *fp[1])
+        *ppid = atoi(fp[1]);
+    else
+        return (-1);
+    if (fp[2] && *fp[2])
+        *pgid = atoi(fp[2]);
+    else
+        return (-1);
+    /*
+     * Check the state in the third field.  If it is 'Z', return that
+     * indication.
+     */
+    if (fp[0] && !strcmp(fp[0], "Z"))
+        return (1);
+    else if (fp[0] && !strcmp(fp[0], "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(struct lsof_context *ctx, /* context */
+                  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);
+            Error(ctx);
+        }
+        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(ctx, 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.
+     */
+    zeromem((char *)s, 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);
+}
+
+static int cal_order(int n) {
+    int i = 0;
+    do {
+        n /= 10;
+        i++;
+    } while (n);
+    return i;
+}
+
+static int snp_eventpoll_fds(char *p, int len, int *tfds, int count) {
+    int wl = 0;
+    int i;
+
+    if (len > 0)
+        p[0] = '\0';
+
+    for (i = 0; i < count; i++) {
+        int is_last_item = (i == count - 1);
+        int needs = cal_order(tfds[i]) + (is_last_item ? 0 : 3);
+
+        if ((len - wl + (wl ? 2 : 0)) <= needs) {
+            /* No space to print the tfd. */
+            break;
+        }
+
+        if (wl) {
+            /* Rewrite the last "..." to ",". */
+            wl -= 3;
+            p[wl++] = ',';
+        }
+        wl += snpf(p + wl, len - wl, (is_last_item ? "%d" : "%d..."), tfds[i]);
+    }
+
+    return wl;
+}
+
+static int fd_compare(const void *a, const void *b) {
+    int ia = *(int *)a, ib = *(int *)b;
+
+    return ia - ib;
+}
+
+static void snp_eventpoll(char *p, int len, int *tfds, int tfd_count) {
+    /* Reserve the area for prefix: "[eventpoll:" */
+    len -= 11;
+    /* Reserve the area for postfix */
+    len -= ((tfd_count == EPOLL_MAX_TFDS) ? 4 /* "...]" */
+                                          : 1 /* "]" */
+            ) +
+           1 /* for the last \0 */
+        ;
+
+    if (len > 1) {
+        qsort(tfds, tfd_count, sizeof(tfds[0]), fd_compare);
+
+        p[10] = ':'; /* "[eventpoll]" => "[eventpoll:" */
+        int wl = snp_eventpoll_fds(p + 11, len, tfds, tfd_count);
+
+        /* If the buffer doesn't have enough space, snp_eventpoll_fds puts
+         * "..." at the end of the buffer. In that case we don't
+         * have to "..." here.
+         */
+        const char *postfix =
+            ((wl > 3 && p[11 + wl - 1] == '.')
+                 ? "]"
+                 : ((tfd_count == EPOLL_MAX_TFDS)
+                        /* File descriptors more than EPOLL_MAX_TFDS are
+                         * associated to the eventpoll fd. */
+                        ? "...]"
+                        : "]"));
+        strcpy(p + 11 + wl, postfix);
+    }
+}
diff --git a/lib/dialects/linux/dproto.h b/lib/dialects/linux/dproto.h
new file mode 100644 (file)
index 0000000..defa7b8
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * 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)
+extern int enter_cntx_arg(struct lsof_context *ctx, char *cnxt);
+#endif /* defined(HASSELINUX) */
+
+extern int get_fields(struct lsof_context *ctx, char *ln, char *sep, char ***fr,
+                      int *eb, int en);
+extern void get_locks(struct lsof_context *ctx, char *p);
+extern void clean_locks(struct lsof_context *ctx);
+extern void clean_ax25(struct lsof_context *ctx);
+extern void clean_icmp(struct lsof_context *ctx);
+extern void clean_ipx(struct lsof_context *ctx);
+extern void clean_netlink(struct lsof_context *ctx);
+extern void clean_pack(struct lsof_context *ctx);
+extern void clean_raw(struct lsof_context *ctx);
+extern void clean_sctp(struct lsof_context *ctx);
+extern void clean_unix(struct lsof_context *ctx);
+extern void clean_tcpudp(struct lsof_context *ctx, int free_array);
+#if defined(HASIPv6)
+extern void clean_raw6(struct lsof_context *ctx);
+extern void clean_tcpudp6(struct lsof_context *ctx, int free_array);
+#endif
+extern int is_file_named(struct lsof_context *ctx, int ty, char *p,
+                         struct mounts *mp, int cd);
+extern int make_proc_path(struct lsof_context *ctx, char *pp, int lp, char **np,
+                          int *npl, char *sf);
+extern FILE *open_proc_stream(struct lsof_context *ctx, char *p, char *mode,
+                              char **buf, size_t *sz, int act);
+extern void process_proc_node(struct lsof_context *ctx, char *p, char *pbr,
+                              struct stat *s, int ss, struct stat *l, int ls);
+extern void process_proc_sock(struct lsof_context *ctx, char *p, char *pbr,
+                              struct stat *s, int ss, struct stat *l, int ls);
+extern void set_net_paths(struct lsof_context *ctx, char *p, int pl);
+extern void refresh_socket_info(struct lsof_context *ctx);
\ No newline at end of file
diff --git a/lib/dialects/linux/dsock.c b/lib/dialects/linux/dsock.c
new file mode 100644 (file)
index 0000000..297a22a
--- /dev/null
@@ -0,0 +1,5013 @@
+/*
+ * 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.
+ */
+
+#include "common.h"
+#include <sys/xattr.h>
+#include "hash.h"
+
+#if defined(HASEPTOPTS) && defined(HASUXSOCKEPT)
+/*
+ * UNIX endpoint definitions
+ */
+
+#    include <sys/socket.h>      /* for AF_NETLINK */
+#    include <linux/rtnetlink.h> /* for NETLINK_INET_DIAG */
+#    include <linux/sock_diag.h> /* for SOCK_DIAG_BY_FAMILY */
+#    include <linux/unix_diag.h> /* for unix_diag_req */
+#    include <string.h>          /* memset */
+#    include <stdint.h>          /* for unt8_t */
+#    include <unistd.h>          /* for getpagesize */
+#    define SOCKET_BUFFER_SIZE (getpagesize() < 8192L ? getpagesize() : 8192L)
+#endif /* defined(HASEPTOPTS) && defined(HASUXSOCKEPT) */
+
+#if defined(HASSOSTATE)
+#    include <linux/net.h> /* for SS_* */
+#endif                     /* defined(HASSOSTATE) */
+
+/*
+ * 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))
+
+#define IPCBUCKS                                                               \
+    4096 /* IPC hash bucket count -- must be                                   \
+          * a power of two */
+
+/* If a socket is used for IPC, we store both end points for the socket
+ * to the same hash bucket. This makes seaching the counter part of
+ * an end point easier. See get_netpeeri(). */
+#define TCPUDP_IPC_HASH(tp)                                                    \
+    ((int)(((((tp)->faddr * 0x109 + (tp)->laddr * 0x109 +                      \
+              (tp)->fport * 0x121 + (tp)->lport * 0x121 +                      \
+              (tp)->proto * 0x181) *                                           \
+             31415) >>                                                         \
+            3) &                                                               \
+           (IPCBUCKS - 1)))
+
+#define TCPUDP6_IPC_ADDR_INT32(a, n) (((a)->s6_addr32[n]))
+#define TCPUDP6_IPC_ADDR_MK_INT(a)                                             \
+    ((int)TCPUDP6_IPC_ADDR_INT32(a, 0x0) * 0x123 +                             \
+     (int)TCPUDP6_IPC_ADDR_INT32(a, 0x1) * 0x111 +                             \
+     (int)TCPUDP6_IPC_ADDR_INT32(a, 0x2) * 0x149 +                             \
+     (int)TCPUDP6_IPC_ADDR_INT32(a, 0x3) * 0x185)
+
+#define TCPUDP6_IPC_HASH(tp)                                                   \
+    ((int)((((TCPUDP6_IPC_ADDR_MK_INT(&(tp)->faddr) +                          \
+              TCPUDP6_IPC_ADDR_MK_INT(&(tp)->laddr) + (tp)->fport * 0x109 +    \
+              (tp)->lport * 0x109 + (tp)->proto * 0x141) *                     \
+             31415) >>                                                         \
+            3) &                                                               \
+           (IPCBUCKS - 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 IPv4 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;       /* in TcpUdp inode hash table */
+#if defined(HASEPTOPTS)
+    pxinfo_t *pxinfo;         /* inode information */
+    struct tcp_udp *ipc_next; /* in TcpUdp local ipc hash table */
+    struct tcp_udp *ipc_peer; /* locally connected peer(s) info */
+#endif                        /* defined(HASEPTOPTS) */
+};
+
+#if defined(HASIPv6)
+struct tcp_udp6 { /* IPv6 TCP and UDP socket
+                   * information */
+    INODETYPE inode;
+    struct in6_addr 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_udp6 *next;
+#    if defined(HASEPTOPTS)
+    pxinfo_t *pxinfo;          /* inode information */
+    struct tcp_udp6 *ipc_next; /* in TcpUdp6 local ipc hash table */
+    struct tcp_udp6 *ipc_peer; /* locally connected peer(s) info */
+#    endif                     /* defined(HASEPTOPTS) */
+};
+#endif /* defined(HASIPv6) */
+
+typedef 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 */
+    uint32_t ty;          /* socket type */
+    unsigned int opt;     /* socket options */
+    unsigned int ss;      /* socket state */
+
+#if defined(HASEPTOPTS) && defined(HASUXSOCKEPT)
+    struct uxsin *icons; /* incoming socket conections */
+    unsigned int icstat; /* incoming connection status
+                          * 0 == none */
+    pxinfo_t *pxinfo;    /* inode information */
+    struct uxsin *peer;  /* connected peer(s) info */
+#endif                   /* defined(HASEPTOPTS) && defined(HASUXSOCKEPT) */
+
+    struct uxsin *next;
+} uxsin_t;
+
+/*
+ * Local static values
+ */
+
+static char *AX25path = (char *)NULL; /* path to AX25 /proc information */
+/* AX25 socket info, hashed by inode */
+static struct ax25sin **AX25sin = (struct ax25sin **)NULL;
+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 */
+/* ICMP socket info, hashed by inode */
+static struct icmpin **Icmpin = (struct icmpin **)NULL;
+static char *Ipxpath = (char *)NULL; /* path to IPX /proc information */
+/* IPX socket info, hashed by inode */
+static struct ipxsin **Ipxsin = (struct ipxsin **)NULL;
+static char *Nlkpath = (char *)NULL; /* path to Netlink /proc information */
+/* Netlink socket info, hashed by
+ * inode */
+static struct nlksin **Nlksin = (struct nlksin **)NULL;
+/* packet info, hashed by inode */
+static struct packin **Packin = (struct packin **)NULL;
+static char *Packpath = (char *)NULL; /* path to packet /proc information */
+static char *Rawpath = (char *)NULL;  /* path to raw socket /proc
+                                       * information */
+/* raw socket info, hashed by inode */
+static struct rawsin **Rawsin = (struct rawsin **)NULL;
+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 */
+};
+/* SCTP info, hashed by inode */
+static struct sctpsin **SCTPsin = (struct sctpsin **)NULL;
+/* path to /proc/net socket status */
+static char *SockStatPath = (char *)NULL;
+static char *TCPpath = (char *)NULL; /* path to TCP /proc information */
+/* IPv4 TCP & UDP info, hashed by
+ * inode */
+static struct tcp_udp **TcpUdp = (struct tcp_udp **)NULL;
+static int TcpUdp_bucks = 0; /* dynamically sized hash bucket
+                              * count for TCP and UDP -- will
+                              * be a power of two */
+#if defined(HASEPTOPTS)
+/* IPv4 TCP & UDP info for socket used
+   for IPC, hashed by (addr, port paris
+   and protocol */
+static struct tcp_udp **TcpUdpIPC = (struct tcp_udp **)NULL;
+#endif /* defined(HASEPTOPTS) */
+
+#if defined(HASIPv6)
+static char *Raw6path = (char *)NULL; /* path to raw IPv6 /proc information */
+/* IPv6 raw socket info, hashed by
+ * inode */
+static struct rawsin **Rawsin6 = (struct rawsin **)NULL;
+/* path to /proc/net IPv6 socket
+ * status */
+static char *SockStatPath6 = (char *)NULL;
+static char *TCP6path = (char *)NULL; /* path to IPv6 TCP /proc information */
+/* IPv6 TCP & UDP info, hashed by
+ * inode */
+static struct tcp_udp6 **TcpUdp6 = (struct tcp_udp6 **)NULL;
+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 */
+/* path to IPv6 UDPLITE /proc
+ * information */
+static char *UDPLITE6path = (char *)NULL;
+#    if defined(HASEPTOPTS)
+/* IPv4 TCP & UDP info for socket used
+   for IPC, hashed by (addr, port paris
+   and protocol */
+static struct tcp_udp6 **TcpUdp6IPC = (struct tcp_udp6 **)NULL;
+#    endif /* defined(HASEPTOPTS) */
+#endif     /* defined(HASIPv6) */
+
+static char *UDPpath = (char *)NULL; /* path to UDP /proc information */
+/* path to UDPLITE /proc information */
+static char *UDPLITEpath = (char *)NULL;
+static char *UNIXpath = (char *)NULL; /* path to UNIX /proc information */
+/* UNIX socket info, hashed by inode */
+static uxsin_t **Uxsin = (uxsin_t **)NULL;
+
+/*
+ * Local function prototypes
+ */
+
+static struct ax25sin *check_ax25(struct lsof_context *ctx, INODETYPE i);
+
+#if defined(HASEPTOPTS) && defined(HASUXSOCKEPT)
+static void enter_uxsinfo(struct lsof_context *ctx, uxsin_t *up);
+static void fill_uxicino(struct lsof_context *ctx, INODETYPE si, INODETYPE sc);
+static void fill_uxpino(struct lsof_context *ctx, INODETYPE si, INODETYPE pi);
+static int get_diagmsg(int sockfd);
+static void get_uxpeeri(struct lsof_context *ctx);
+static void parse_diag(struct lsof_context *ctx, struct unix_diag_msg *dm,
+                       int len);
+static void prt_uxs(struct lsof_context *ctx, uxsin_t *p, int mk);
+#endif /* defined(HASEPTOPTS) && defined(HASUXSOCKEPT) */
+
+#if defined(HASEPTOPTS)
+static void enter_netsinfo(struct lsof_context *ctx, struct tcp_udp *tp);
+static void get_netpeeri(struct lsof_context *ctx);
+#endif /* defined(HASEPTOPTS) */
+
+#if defined(HASIPv6)
+#    if defined(HASEPTOPTS)
+static void enter_nets6info(struct lsof_context *ctx, struct tcp_udp6 *tp);
+static void get_net6peeri(struct lsof_context *ctx);
+#    endif /* defined(HASEPTOPTS) */
+#endif     /* defined(HASIPv6) */
+
+static struct icmpin *check_icmp(struct lsof_context *ctx, INODETYPE i);
+static struct ipxsin *check_ipx(struct lsof_context *ctx, INODETYPE i);
+static struct nlksin *check_netlink(struct lsof_context *ctx, INODETYPE i);
+static struct packin *check_pack(struct lsof_context *ctx, INODETYPE i);
+static struct rawsin *check_raw(struct lsof_context *ctx, INODETYPE i);
+static struct sctpsin *check_sctp(struct lsof_context *ctx, INODETYPE i);
+static struct tcp_udp *check_tcpudp(struct lsof_context *ctx, INODETYPE i,
+                                    char **p);
+static uxsin_t *check_unix(struct lsof_context *ctx, INODETYPE i);
+static void get_ax25(struct lsof_context *ctx, char *p);
+static void get_icmp(struct lsof_context *ctx, char *p);
+static void get_ipx(struct lsof_context *ctx, char *p);
+static void get_netlink(struct lsof_context *ctx, char *p);
+static void get_pack(struct lsof_context *ctx, char *p);
+static void get_raw(struct lsof_context *ctx, char *p);
+static void get_sctp(struct lsof_context *ctx);
+static char *get_sctpaddrs(char **fp, int i, int nf, int *x);
+static void get_tcpudp(struct lsof_context *ctx, char *p, int pr, int clr);
+static void get_unix(struct lsof_context *ctx, char *p);
+static int isainb(char *a, char *b);
+static void print_ax25info(struct lsof_context *ctx, struct ax25sin *ap);
+static void print_ipxinfo(struct lsof_context *ctx, struct ipxsin *ip);
+static char *socket_type_to_str(uint32_t ty, int *rf);
+static char *netlink_proto_to_str(unsigned int pr);
+#if defined(HASSOSTATE)
+static char *socket_state_to_str(struct lsof_context *ctx, unsigned int ss);
+#endif /* defined(HASSOSTATE) */
+static char *ethernet_proto_to_str(unsigned int pr);
+
+#if defined(HASIPv6)
+static struct rawsin *check_raw6(struct lsof_context *ctx, INODETYPE i);
+static struct tcp_udp6 *check_tcpudp6(struct lsof_context *ctx, INODETYPE i,
+                                      char **p);
+static void get_raw6(struct lsof_context *ctx, char *p);
+static void get_tcpudp6(struct lsof_context *ctx, char *p, int pr, int clr);
+static int hex_ipv6_to_in6(char *as, struct in6_addr *ad);
+#endif /* defined(HASIPv6) */
+
+/*
+ * build_IPstates() -- build the TCP and UDP state tables
+ */
+void build_IPstates(struct lsof_context *ctx) {
+    if (!TcpSt) {
+        (void)enter_IPstate(ctx, "TCP", "ESTABLISHED", TCP_ESTABLISHED);
+        (void)enter_IPstate(ctx, "TCP", "SYN_SENT", TCP_SYN_SENT);
+        (void)enter_IPstate(ctx, "TCP", "SYN_RECV", TCP_SYN_RECV);
+        (void)enter_IPstate(ctx, "TCP", "FIN_WAIT1", TCP_FIN_WAIT1);
+        (void)enter_IPstate(ctx, "TCP", "FIN_WAIT2", TCP_FIN_WAIT2);
+        (void)enter_IPstate(ctx, "TCP", "TIME_WAIT", TCP_TIME_WAIT);
+        (void)enter_IPstate(ctx, "TCP", "CLOSE", TCP_CLOSE);
+        (void)enter_IPstate(ctx, "TCP", "CLOSE_WAIT", TCP_CLOSE_WAIT);
+        (void)enter_IPstate(ctx, "TCP", "LAST_ACK", TCP_LAST_ACK);
+        (void)enter_IPstate(ctx, "TCP", "LISTEN", TCP_LISTEN);
+        (void)enter_IPstate(ctx, "TCP", "CLOSING", TCP_CLOSING);
+        (void)enter_IPstate(ctx, "TCP", "CLOSED", 0);
+        (void)enter_IPstate(ctx, "TCP", (char *)NULL, 0);
+    }
+}
+
+/*
+ * check_ax25() - check for AX25 socket file
+ */
+static struct ax25sin *check_ax25(struct lsof_context *ctx,
+                                  INODETYPE i) /* socket file's inode number */
+{
+    return HASH_FIND_ELEMENT(AX25sin, INOHASH, struct ax25sin, inode, i);
+}
+
+/*
+ * check_icmp() - check for ICMP socket
+ */
+static struct icmpin *check_icmp(struct lsof_context *ctx,
+                                 INODETYPE i) /* socket file's inode number */
+{
+    return HASH_FIND_ELEMENT(Icmpin, INOHASH, struct icmpin, inode, i);
+}
+
+/*
+ * check_ipx() - check for IPX socket file
+ */
+static struct ipxsin *check_ipx(struct lsof_context *ctx,
+                                INODETYPE i) /* socket file's inode number */
+{
+    return HASH_FIND_ELEMENT(Ipxsin, INOHASH, struct ipxsin, inode, i);
+}
+
+/*
+ * check_netlink() - check for Netlink socket file
+ */
+static struct nlksin *
+check_netlink(struct lsof_context *ctx,
+              INODETYPE i) /* socket file's inode number */
+{
+    return HASH_FIND_ELEMENT(Nlksin, INOHASH, struct nlksin, inode, i);
+}
+
+/*
+ * check_pack() - check for packet file
+ */
+static struct packin *check_pack(struct lsof_context *ctx,
+                                 INODETYPE i) /* packet file's inode number */
+{
+    return HASH_FIND_ELEMENT(Packin, INOHASH, struct packin, inode, i);
+}
+
+/*
+ * check_raw() - check for raw socket file
+ */
+
+static struct rawsin *check_raw(struct lsof_context *ctx,
+                                INODETYPE i) /* socket file's inode number */
+{
+    return HASH_FIND_ELEMENT(Rawsin, INOHASH, struct rawsin, inode, i);
+}
+
+/*
+ * check_sctp() - check for SCTP socket file
+ */
+static struct sctpsin *check_sctp(struct lsof_context *ctx,
+                                  INODETYPE i) /* socket file's inode number */
+{
+    return HASH_FIND_ELEMENT(SCTPsin, INOHASH, struct sctpsin, inode, i);
+}
+
+/*
+ * check_tcpudp() - check for IPv4 TCP or UDP socket file
+ */
+static struct tcp_udp *
+check_tcpudp(struct lsof_context *ctx,
+             INODETYPE i, /* socket file's inode number */
+             char **p)    /* protocol return */
+{
+    struct tcp_udp *tp;
+    tp = HASH_FIND_ELEMENT(TcpUdp, TCPUDPHASH, struct tcp_udp, inode, i);
+
+    if (tp) {
+        switch (tp->proto) {
+        case 0:
+            *p = "TCP";
+            break;
+        case 1:
+            *p = "UDP";
+            break;
+        case 2:
+            *p = "UDPLITE";
+            break;
+        default:
+            *p = "unknown";
+        }
+    }
+    return tp;
+}
+
+/*
+ * check_inet() - check for locally used INET domain socket
+ */
+static struct tcp_udp *check_inet(struct lsof_context *ctx,
+                                  INODETYPE i) /* socket file's inode number */
+{
+    return HASH_FIND_ELEMENT(TcpUdp, TCPUDPHASH, struct tcp_udp, inode, i);
+}
+
+/*
+ * clear_netsinfo -- clear allocated INET socket info
+ */
+void clear_netsinfo(struct lsof_context *ctx) {
+    int h;                   /* hash index */
+    struct tcp_udp *ti, *tp; /* temporary pointers */
+
+#if defined(HASEPTOPTS)
+    pxinfo_t *pp, *pnp;
+#endif /* defined(HASEPTOPTS) */
+
+    if (TcpUdp) {
+        for (h = 0; h < TcpUdp_bucks; h++) {
+            if ((ti = TcpUdp[h])) {
+                do {
+                    tp = ti->next;
+
+#if defined(HASEPTOPTS)
+                    for (pp = ti->pxinfo; pp; pp = pnp) {
+                        pnp = pp->next;
+                        (void)free((FREE_P *)pp);
+                    }
+#endif /* defined(HASEPTOPTS) */
+
+                    (void)free((FREE_P *)ti);
+                    ti = tp;
+                } while (ti);
+                TcpUdp[h] = (struct tcp_udp *)NULL;
+            }
+        }
+    }
+    if (TcpUdpIPC) {
+        for (h = 0; h < IPCBUCKS; h++)
+            TcpUdpIPC[h] = (struct tcp_udp *)NULL;
+    }
+}
+
+#if defined(HASIPv6)
+/*
+ * check_raw6() - check for raw IPv6 socket file
+ */
+static struct rawsin *check_raw6(struct lsof_context *ctx,
+                                 INODETYPE i) /* socket file's inode number */
+{
+    return HASH_FIND_ELEMENT(Rawsin6, INOHASH, struct rawsin, inode, i);
+}
+
+/*
+ * check_tcpudp6() - check for IPv6 TCP or UDP socket file
+ */
+static struct tcp_udp6 *
+check_tcpudp6(struct lsof_context *ctx,
+              INODETYPE i, /* socket file's inode number */
+              char **p)    /* protocol return */
+{
+    struct tcp_udp6 *tp6;
+    tp6 = HASH_FIND_ELEMENT(TcpUdp6, TCPUDP6HASH, struct tcp_udp6, inode, i);
+
+    if (tp6) {
+        switch (tp6->proto) {
+        case 0:
+            *p = "TCP";
+            break;
+        case 1:
+            *p = "UDP";
+            break;
+        case 2:
+            *p = "UDPLITE";
+            break;
+        default:
+            *p = "unknown";
+        }
+    }
+    return tp6;
+}
+
+/*
+ * check_inet6() - check for locally used INET6 domain socket
+ */
+static struct tcp_udp6 *
+check_inet6(struct lsof_context *ctx,
+            INODETYPE i) /* socket file's inode number */
+{
+    return HASH_FIND_ELEMENT(TcpUdp6, TCPUDP6HASH, struct tcp_udp6, inode, i);
+}
+
+/*
+ * clear_nets6info -- clear allocated INET6 socket info
+ */
+void clear_nets6info(struct lsof_context *ctx) {
+    int h;                    /* hash index */
+    struct tcp_udp6 *ti, *tp; /* temporary pointers */
+
+#    if defined(HASEPTOPTS)
+    pxinfo_t *pp, *pnp;
+#    endif /* defined(HASEPTOPTS) */
+
+    if (TcpUdp6) {
+        for (h = 0; h < TcpUdp6_bucks; h++) {
+            if ((ti = TcpUdp6[h])) {
+                do {
+                    tp = ti->next;
+
+#    if defined(HASEPTOPTS)
+                    for (pp = ti->pxinfo; pp; pp = pnp) {
+                        pnp = pp->next;
+                        (void)free((FREE_P *)pp);
+                    }
+#    endif /* defined(HASEPTOPTS) */
+
+                    (void)free((FREE_P *)ti);
+                    ti = tp;
+                } while (ti);
+                TcpUdp6[h] = (struct tcp_udp6 *)NULL;
+            }
+        }
+    }
+    if (TcpUdp6IPC) {
+        for (h = 0; h < IPCBUCKS; h++)
+            TcpUdp6IPC[h] = (struct tcp_udp6 *)NULL;
+    }
+}
+
+#endif /* defined(HASIPv6) */
+
+/*
+ * check_unix() - check for UNIX domain socket
+ */
+static uxsin_t *check_unix(struct lsof_context *ctx,
+                           INODETYPE i) /* socket file's inode number */
+{
+    return HASH_FIND_ELEMENT(Uxsin, INOHASH, uxsin_t, inode, i);
+}
+
+/*
+ * clear_uxsinfo -- clear allocated UNIX socket info
+ */
+void clear_uxsinfo(struct lsof_context *ctx) {
+    int h;            /* hash index */
+    uxsin_t *ui, *up; /* remporary pointers */
+
+#if defined(HASEPTOPTS) && defined(HASUXSOCKEPT)
+    pxinfo_t *pp, *pnp;
+#endif /* defined(HASEPTOPTS) && defined(HASUXSOCKEPT) */
+
+    if (!Uxsin)
+        return;
+    for (h = 0; h < INOBUCKS; h++) {
+        if ((ui = Uxsin[h])) {
+            do {
+                up = ui->next;
+
+#if defined(HASEPTOPTS) && defined(HASUXSOCKEPT)
+                for (pp = ui->pxinfo; pp; pp = pnp) {
+                    pnp = pp->next;
+                    (void)free((FREE_P *)pp);
+                }
+#endif /* defined(HASEPTOPTS) && defined(HASUXSOCKEPT) */
+
+                if (ui->path)
+                    (void)free((FREE_P *)ui->path);
+                if (ui->pcb)
+                    (void)free((FREE_P *)ui->pcb);
+                (void)free((FREE_P *)ui);
+                ui = up;
+            } while (ui);
+            Uxsin[h] = (uxsin_t *)NULL;
+        }
+    }
+}
+
+/*
+ * get_ax25() - get /proc/net/ax25 info
+ */
+static void get_ax25(struct lsof_context *ctx,
+                     char *p) /* /proc/net/ax25 path */
+{
+    struct ax25sin *ap, *np;
+    FILE *as;
+    char buf[MAXPATHLEN], *da, *dev_ch, *ep, **fp, *sa;
+    int h;
+    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 *)));
+            Error(ctx);
+        }
+    }
+    /*
+     * 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(ctx, p, "r", &vbuf, &vsz, 0)))
+        return;
+    while (fgets(buf, sizeof(buf) - 1, as)) {
+        if (get_fields(ctx, 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_info_show() 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;
+        /* Skip if already exists in hash table */
+        if (HASH_FIND_ELEMENT(AX25sin, INOHASH, struct ax25sin, inode, inode))
+            continue;
+        /*
+         * Assemble the send and receive queue values and the state.
+         */
+        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]);
+                Error(ctx);
+            }
+            (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]);
+                Error(ctx);
+            }
+            (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]);
+                Error(ctx);
+            }
+            (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));
+            Error(ctx);
+        }
+        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;
+        HASH_INSERT_ELEMENT(AX25sin, INOHASH, ap, inode);
+    }
+    (void)fclose(as);
+}
+
+#if defined(HASEPTOPTS) && defined(HASUXSOCKEPT)
+/*
+ * enter_uxsinfo() -- enter unix socket info
+ *     entry   Lf = local file structure pointer
+ *             Lp = local process structure pointer
+ */
+static void enter_uxsinfo(struct lsof_context *ctx, uxsin_t *up) {
+    pxinfo_t *pi;     /* pxinfo_t structure pointer */
+    struct lfile *lf; /* local file structure pointer */
+    struct lproc *lp; /* local proc structure pointer */
+    pxinfo_t *np;     /* new pxinfo_t structure pointer */
+
+    for (pi = up->pxinfo; pi; pi = pi->next) {
+        lf = pi->lf;
+        lp = &Lproc[pi->lpx];
+        if (pi->ino == Lf->inode) {
+            if ((lp->pid == Lp->pid) && (lf->fd_type == Lf->fd_type) &&
+                (lf->fd_num == Lf->fd_num))
+                return;
+        }
+    }
+    if (!(np = (pxinfo_t *)malloc(sizeof(pxinfo_t)))) {
+        (void)fprintf(stderr, "%s: no space for pipeinfo in uxsinfo, PID %d\n",
+                      Pn, Lp->pid);
+        Error(ctx);
+    }
+    np->ino = Lf->inode;
+    np->lf = Lf;
+    np->lpx = Lp - Lproc;
+    np->next = up->pxinfo;
+    up->pxinfo = np;
+}
+
+/*
+ * fill_uxicino() -- fill incoming connection inode number
+ */
+static void fill_uxicino(struct lsof_context *ctx,
+                         INODETYPE si, /* UNIX socket inode number */
+                         INODETYPE ic) /* incoming UNIX socket connection
+                                        * inode number */
+{
+    uxsin_t *psi; /* pointer to socket's information */
+    uxsin_t *pic; /* pointer to incoming connection's
+                   * information */
+
+    if ((psi = check_unix(ctx, si))) {
+        if (psi->icstat || psi->icons)
+            return;
+        if ((pic = check_unix(ctx, ic))) {
+            psi->icstat = 1;
+            psi->icons = pic;
+        }
+    }
+}
+
+/*
+ * fill_uxpino() -- fill in UNIX socket's peer inode number
+ */
+static void fill_uxpino(struct lsof_context *ctx,
+                        INODETYPE si, /* UNIX socket inode number */
+                        INODETYPE pi) /* UNIX socket peer's inode number */
+{
+    uxsin_t *pp, *up;
+
+    if ((up = check_unix(ctx, si))) {
+        if (!up->peer) {
+            if ((pp = check_unix(ctx, pi)))
+                up->peer = pp;
+        }
+    }
+}
+
+/*
+ * find_uxepti(lf) -- find UNIX socket endpoint info
+ */
+uxsin_t *find_uxepti(struct lsof_context *ctx,
+                     struct lfile *lf) /* pipe's lfile */
+{
+    uxsin_t *up;
+
+    up = check_unix(ctx, lf->inode);
+    return (up ? up->peer : (uxsin_t *)NULL);
+}
+
+/*
+ * get_diagmsg() -- get UNIX socket's diag message
+ */
+
+static int get_diagmsg(int sockfd) /* socket's file descriptor */
+{
+    struct msghdr msg;         /* message header */
+    struct nlmsghdr nlh;       /* header length */
+    struct unix_diag_req creq; /* connection request */
+    struct sockaddr_nl sa;     /* netlink socket address */
+    struct iovec iov[2];       /* I/O vector */
+    /*
+     * Build and send message to socket's file descriptor, asking for its
+     * diagnostic message.
+     */
+    zeromem((char *)&msg, sizeof(msg));
+    zeromem((char *)&sa, sizeof(sa));
+    zeromem((char *)&nlh, sizeof(nlh));
+    zeromem((char *)&creq, sizeof(creq));
+    sa.nl_family = AF_NETLINK;
+    creq.sdiag_family = AF_UNIX;
+    creq.sdiag_protocol = 0;
+    memset((void *)&creq.udiag_states, -1, sizeof(creq.udiag_states));
+    creq.udiag_ino = (INODETYPE)0;
+    creq.udiag_show = UDIAG_SHOW_PEER | UDIAG_SHOW_ICONS;
+    nlh.nlmsg_len = NLMSG_LENGTH(sizeof(creq));
+    nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
+    nlh.nlmsg_type = SOCK_DIAG_BY_FAMILY;
+    iov[0].iov_base = (void *)&nlh;
+    iov[0].iov_len = sizeof(nlh);
+    iov[1].iov_base = (void *)&creq;
+    iov[1].iov_len = sizeof(creq);
+    msg.msg_name = (void *)&sa;
+    msg.msg_namelen = sizeof(sa);
+    msg.msg_iov = iov;
+    msg.msg_iovlen = 2;
+    return (sendmsg(sockfd, &msg, 0));
+}
+
+/*
+ * get_uxpeeri() - get UNIX socket peer inode information
+ */
+static void get_uxpeeri(struct lsof_context *ctx) {
+    struct unix_diag_msg *dm;       /* pointer to diag message */
+    struct nlmsghdr *hp;            /* netlink structure header pointer */
+    int nb = 0;                     /* number of bytes */
+    int ns = 0;                     /* netlink socket */
+    uint8_t rb[SOCKET_BUFFER_SIZE]; /* receive buffer */
+    int rl = 0;                     /* route info length */
+    /*
+     * Get a netlink socket.
+     */
+    if ((ns = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_SOCK_DIAG)) == -1) {
+        (void)fprintf(stderr, "%s: netlink socket error: %s\n", Pn,
+                      strerror(errno));
+        Error(ctx);
+    }
+    /*
+     * Request peer information.
+     */
+    if (get_diagmsg(ns) < 0) {
+        (void)fprintf(stderr, "%s: netlink peer request error: %s\n", Pn,
+                      strerror(errno));
+        goto get_uxpeeri_exit;
+    }
+    /*
+     * Receive peer information.
+     */
+    while (1) {
+        if ((nb = recv(ns, rb, sizeof(rb), 0)) <= 0)
+            goto get_uxpeeri_exit;
+        hp = (struct nlmsghdr *)rb;
+        while (NLMSG_OK(hp, nb)) {
+            if (hp->nlmsg_type == NLMSG_DONE)
+                goto get_uxpeeri_exit;
+            if (hp->nlmsg_type == NLMSG_ERROR) {
+                (void)fprintf(stderr,
+                              "%s: netlink UNIX socket msg peer info error\n",
+                              Pn);
+                goto get_uxpeeri_exit;
+            }
+            dm = (struct unix_diag_msg *)NLMSG_DATA(hp);
+            rl = hp->nlmsg_len - NLMSG_LENGTH(sizeof(*dm));
+            parse_diag(ctx, dm, rl);
+            hp = NLMSG_NEXT(hp, nb);
+        }
+    }
+
+get_uxpeeri_exit:
+
+    (void)close(ns);
+}
+
+/*
+ * parse_diag() -- parse UNIX diag message
+ */
+static void parse_diag(struct lsof_context *ctx,
+                       struct unix_diag_msg *dm, /* pointer to diag message */
+                       int len)                  /* message length */
+{
+    struct rtattr *rp;   /* route info pointer */
+    int i;               /* tmporary index */
+    int icct;            /* incoming connection count */
+    uint32_t *icp;       /* incoming connection pointer */
+    uint32_t inoc, inop; /* inode numbers */
+
+    if (!dm || (dm->udiag_family != AF_UNIX) || !(inop = dm->udiag_ino) ||
+        (len <= 0)) {
+        return;
+    }
+    rp = (struct rtattr *)(dm + 1);
+    /*
+     * Process route information.
+     */
+    while (RTA_OK(rp, len)) {
+        switch (rp->rta_type) {
+        case UNIX_DIAG_PEER:
+            if (len < 4) {
+                (void)fprintf(stderr, "%s: unix_diag: msg length (%d) < 4)\n",
+                              Pn, len);
+                return;
+            }
+            if ((inoc = *(uint32_t *)RTA_DATA(rp))) {
+                fill_uxpino(ctx, (INODETYPE)inop, (INODETYPE)inoc);
+                fill_uxpino(ctx, (INODETYPE)inoc, (INODETYPE)inop);
+            }
+            break;
+        case UNIX_DIAG_ICONS:
+            icct = RTA_PAYLOAD(rp), icp = (uint32_t *)RTA_DATA(rp);
+
+            for (i = 0; i < icct; i += sizeof(uint32_t), icp++) {
+                fill_uxicino(ctx, (INODETYPE)inop, (INODETYPE)*icp);
+            }
+        }
+        rp = RTA_NEXT(rp, len);
+    }
+}
+
+/*
+ * prt_uxs() -- print UNIX socket information
+ */
+static void prt_uxs(struct lsof_context *ctx, uxsin_t *p, /* peer info */
+                    int mk) /* 1 == mark for later processing */
+{
+    struct lproc *ep; /* socket endpoint process */
+    struct lfile *ef; /* socket endpoint file */
+    int i;            /* temporary index */
+    int len;          /* string length */
+    char nma[1024];   /* character buffer */
+    pxinfo_t *pp;     /* previous pipe info of socket */
+    char fd[FDLEN];
+
+    (void)strcpy(nma, "->INO=");
+    len = (int)strlen(nma);
+    (void)snpf(&nma[len], sizeof(nma) - len - 1, "%" INODEPSPEC "u", p->inode);
+    (void)add_nma(ctx, nma, strlen(nma));
+    for (pp = p->pxinfo; pp; pp = pp->next) {
+
+        /*
+         * Add a linked socket's PID, command name and FD to the name column
+         * addition.
+         */
+        ep = &Lproc[pp->lpx];
+        ef = pp->lf;
+        fd_to_string(ef->fd_type, ef->fd_num, fd);
+        (void)snpf(nma, sizeof(nma) - 1, "%d,%.*s,%s%c", ep->pid, CmdLim,
+                   ep->cmd, fd, access_to_char(ef->access));
+        (void)add_nma(ctx, nma, strlen(nma));
+        if (mk && FeptE == 2) {
+
+            /*
+             * Endpoint files have been selected, so mark this
+             * one for selection later.
+             */
+            ef->chend = CHEND_UXS;
+            ep->ept |= EPT_UXS_END;
+        }
+    }
+}
+
+/*
+ * process_uxsinfo() -- process UNIX socket information, adding it to selected
+ *                     UNIX socket files and selecting UNIX socket end point
+ *                     files (if requested)
+ */
+void process_uxsinfo(struct lsof_context *ctx,
+                     int f) /* function:
+                             *     0 == process selected socket
+                             *     1 == process socket end point
+                             */
+{
+    uxsin_t *p;  /* peer UNIX socket info pointer */
+    uxsin_t *tp; /* temporary UNIX socket info pointer */
+
+    if (!FeptE)
+        return;
+    for (Lf = Lp->file; Lf; Lf = Lf->next) {
+        if (Lf->type != LSOF_FILE_UNIX)
+            continue;
+        switch (f) {
+        case 0:
+
+            /*
+             * Process already selected socket.
+             */
+            if (is_file_sel(ctx, Lp, Lf)) {
+
+                /*
+                 * This file has been selected by some criterion other than its
+                 * being a socket.  Look up the socket's endpoints.
+                 */
+                p = find_uxepti(ctx, Lf);
+                if (p && p->inode)
+                    prt_uxs(ctx, p, 1);
+                if ((tp = check_unix(ctx, Lf->inode))) {
+                    if (tp->icons) {
+                        if (tp->icstat) {
+                            p = tp->icons;
+                            while (p && p != tp) {
+                                if (p->inode)
+                                    prt_uxs(ctx, p, 1);
+                                p = p->icons;
+                            }
+                        } else {
+                            for (p = tp->icons; p && !p->icstat; p = p->icons)
+                                ; /* DO NOTHING */
+                            if (p && p->inode)
+                                prt_uxs(ctx, p, 1);
+                        }
+                    }
+                }
+            }
+            break;
+        case 1:
+            if (!is_file_sel(ctx, Lp, Lf) && (Lf->chend & CHEND_UXS)) {
+
+                /*
+                 * This is an unselected end point UNIX socket file.  Select it
+                 * and add its end point information to peer's name column
+                 * addition.
+                 */
+                Lf->sf = Selflags;
+                Lp->pss |= PS_SEC;
+                p = find_uxepti(ctx, Lf);
+                if (p && p->inode)
+                    prt_uxs(ctx, p, 0);
+                else if ((tp = check_unix(ctx, Lf->inode))) {
+                    if (tp->icons) {
+                        if (tp->icstat) {
+                            p = tp->icons;
+                            while (p && p != tp) {
+                                if (p->inode)
+                                    prt_uxs(ctx, p, 0);
+                                p = p->icons;
+                            }
+                        } else {
+                            for (p = tp->icons; p && !p->icstat; p = p->icons)
+                                ; /* DO NOTHING */
+                            if (p && p->inode)
+                                prt_uxs(ctx, p, 0);
+                        }
+                    }
+                }
+            }
+            break;
+        }
+    }
+}
+#endif /* defined(HASEPTOPTS) && defined(HASUXSOCKEPT) */
+
+#if defined(HASEPTOPTS)
+/*
+ * enter_netsinfo_common() -- enter inet or inet6 socket info
+ *     tp = tcp/udp on ipv4 or ipv4 socket pointer
+ */
+static void enter_netsinfo_common(struct lsof_context *ctx, void *tp,
+                                  pxinfo_t *(*get_pxinfo)(void *),
+                                  void (*set_pxinfo)(void *, pxinfo_t *)) {
+    pxinfo_t *pi;     /* pxinfo_t structure pointer */
+    struct lfile *lf; /* local file structure pointer */
+    struct lproc *lp; /* local proc structure pointer */
+    pxinfo_t *np;     /* new pxinfo_t structure pointer */
+
+    for (pi = (*get_pxinfo)(tp); pi; pi = pi->next) {
+        lf = pi->lf;
+        lp = &Lproc[pi->lpx];
+        if (pi->ino == Lf->inode) {
+            if ((lp->pid == Lp->pid) && (lf->fd_type == Lf->fd_type) &&
+                (lf->fd_num == Lf->fd_num))
+                return;
+        }
+    }
+    if (!(np = (pxinfo_t *)malloc(sizeof(pxinfo_t)))) {
+        (void)fprintf(stderr, "%s: no space for pipeinfo in netsinfo, PID %d\n",
+                      Pn, Lp->pid);
+        Error(ctx);
+    }
+    np->ino = Lf->inode;
+    np->lf = Lf;
+    np->lpx = Lp - Lproc;
+    np->next = (*get_pxinfo)(tp);
+    (*set_pxinfo)(tp, np);
+}
+
+/*
+ * prt_nets_common() -- print locally used INET or INET6 socket information
+ */
+static void prt_nets_common(struct lsof_context *ctx, void *p, /* peer info */
+                            int mk, /* 1 == mark for later
+                                     * processing */
+                            pxinfo_t *(*get_pxinfo)(void *),
+                            unsigned char chend, short ept_flag) {
+    struct lproc *ep; /* socket endpoint process */
+    struct lfile *ef; /* socket endpoint file */
+    int i;            /* temporary index */
+    char nma[1024];   /* character buffer */
+    pxinfo_t *pp;     /* previous pipe info of socket */
+    char fd[FDLEN];
+
+    for (pp = (*get_pxinfo)(p); pp; pp = pp->next) {
+
+        /*
+         * Add a linked socket's PID, command name and FD to the name column
+         * addition.
+         */
+        ep = &Lproc[pp->lpx];
+        ef = pp->lf;
+        fd_to_string(ef->fd_type, ef->fd_num, fd);
+        (void)snpf(nma, sizeof(nma) - 1, "%d,%.*s,%s%c", ep->pid, CmdLim,
+                   ep->cmd, fd, access_to_char(ef->access));
+        (void)add_nma(ctx, nma, strlen(nma));
+        if (mk && FeptE == 2) {
+
+            /*
+             * Endpoint files have been selected, so mark this
+             * one for selection later.
+             */
+            ef->chend = chend;
+            ep->ept |= ept_flag;
+        }
+    }
+}
+
+/*
+ * enter_netsinfo() -- enter inet socket info
+ *     tp = tcp/udp on ipv4 socket pointer
+ */
+static pxinfo_t *tcp_udp_get_pxinfo(void *vp) {
+    struct tcp_udp *tp = vp;
+    return tp->pxinfo;
+}
+
+static void tcp_udp_set_pxinfo(void *vp, pxinfo_t *np) {
+    struct tcp_udp *tp = vp;
+    tp->pxinfo = np;
+}
+
+static void enter_netsinfo(struct lsof_context *ctx, struct tcp_udp *tp) {
+    enter_netsinfo_common(ctx, tp, tcp_udp_get_pxinfo, tcp_udp_set_pxinfo);
+}
+
+/*
+ * find_netsepti(lf) -- find locally used INET socket endpoint info
+ */
+static struct tcp_udp *find_netsepti(struct lsof_context *ctx, /* context */
+                                     struct lfile *lf) /* socket's lfile */
+{
+    struct tcp_udp *tp;
+
+    tp = check_inet(ctx, lf->inode);
+    return (tp ? tp->ipc_peer : (struct tcp_udp *)NULL);
+}
+
+/*
+ * get_netpeeri() - get INET socket peer inode information
+ */
+static void get_netpeeri(struct lsof_context *ctx) {
+    int h;
+    struct tcp_udp *np, *tp;
+
+    for (h = 0; h < IPCBUCKS; h++) {
+        for (tp = TcpUdpIPC[h]; tp; tp = tp->ipc_next) {
+            if (tp->ipc_peer)
+                continue;
+            for (np = TcpUdpIPC[h]; np; np = np->ipc_next) {
+                if (np->ipc_peer)
+                    continue;
+                if (tp->faddr == np->laddr && tp->laddr == np->faddr &&
+                    tp->fport == np->lport && tp->lport == np->fport &&
+                    tp->proto == np->proto) {
+                    tp->ipc_peer = np;
+                    np->ipc_peer = tp;
+                    break;
+                }
+            }
+        }
+    }
+}
+
+/*
+ * prt_nets() -- print locally used INET socket information
+ */
+static void prt_nets(struct lsof_context *ctx, /* context */
+                     struct tcp_udp *p,        /* peer info */
+                     int mk) /* 1 == mark for later processing */
+{
+    prt_nets_common(ctx, p, mk, tcp_udp_get_pxinfo, CHEND_NETS, EPT_NETS_END);
+}
+
+/*
+ * process_netsinfo() -- process locally used INET socket information, adding
+ *                     it to selected INET socket files and selecting INET
+ *                     socket end point files (if requested)
+ */
+void process_netsinfo(struct lsof_context *ctx, /* context */
+                      int f)                    /* function:
+                                                 *     0 == process selected socket
+                                                 *     1 == process socket end point
+                                                 */
+{
+    struct tcp_udp *p; /* peer INET socket info pointer */
+
+    if (!FeptE)
+        return;
+    for (Lf = Lp->file; Lf; Lf = Lf->next) {
+#    if defined(HASIPv6)
+        enum lsof_file_type type = LSOF_FILE_IPV4;
+#    else  /* !defined(HASIPv6) */
+        enum lsof_file_type type = LSOF_FILE_INET;
+#    endif /* defined(HASIPv6) */
+        if (Lf->type != type)
+            continue;
+        switch (f) {
+        case 0:
+
+            /*
+             * Process already selected socket.
+             */
+            if (is_file_sel(ctx, Lp, Lf)) {
+
+                /*
+                 * This file has been selected by some criterion other than its
+                 * being a socket.  Look up the socket's endpoints.
+                 */
+                p = find_netsepti(ctx, Lf);
+                if (p && p->inode)
+                    prt_nets(ctx, p, 1);
+            }
+            break;
+        case 1:
+            if (!is_file_sel(ctx, Lp, Lf) && (Lf->chend & CHEND_NETS)) {
+
+                /*
+                 * This is an unselected end point INET socket file.  Select it
+                 * and add its end point information to peer's name column
+                 * addition.
+                 */
+                Lf->sf = Selflags;
+                Lp->pss |= PS_SEC;
+                p = find_netsepti(ctx, Lf);
+                if (p && p->inode)
+                    prt_nets(ctx, p, 0);
+            }
+            break;
+        }
+    }
+}
+#endif /* defined(HASEPTOPTS) */
+
+#if defined(HASIPv6)
+#    if defined(HASEPTOPTS)
+/*
+ * enter_nets6info() -- enter inet socket info
+ *     tp = tcp/udp on ipv6 socket pointer
+ */
+static pxinfo_t *tcp_udp6_get_pxinfo(void *vp) {
+    struct tcp_udp6 *tp = vp;
+    return tp->pxinfo;
+}
+
+static void tcp_udp6_set_pxinfo(void *vp, pxinfo_t *np) {
+    struct tcp_udp6 *tp = vp;
+    tp->pxinfo = np;
+}
+
+static void enter_nets6info(struct lsof_context *ctx, struct tcp_udp6 *tp) {
+    enter_netsinfo_common(ctx, tp, tcp_udp6_get_pxinfo, tcp_udp6_set_pxinfo);
+}
+
+/*
+ * find_nets6epti(lf) -- find locally used INET6 socket endpoint info
+ */
+static struct tcp_udp6 *find_nets6epti(struct lsof_context *ctx, /* context */
+                                       struct lfile *lf) /* socket's lfile */
+{
+    struct tcp_udp6 *tp;
+
+    tp = check_inet6(ctx, lf->inode);
+    return (tp ? tp->ipc_peer : (struct tcp_udp6 *)NULL);
+}
+
+/*
+ * get_net6peeri() - get INET6 socket peer inode information
+ */
+static void get_net6peeri(struct lsof_context *ctx) {
+    int h;
+    struct tcp_udp6 *np, *tp;
+
+    for (h = 0; h < IPCBUCKS; h++) {
+        for (tp = TcpUdp6IPC[h]; tp; tp = tp->ipc_next) {
+            if (tp->ipc_peer)
+                continue;
+            for (np = TcpUdp6IPC[h]; np; np = np->ipc_next) {
+                if (np->ipc_peer)
+                    continue;
+                if (IN6_ARE_ADDR_EQUAL(&tp->faddr, &np->laddr) &&
+                    IN6_ARE_ADDR_EQUAL(&tp->laddr, &np->faddr) &&
+                    tp->fport == np->lport && tp->lport == np->fport &&
+                    tp->proto == np->proto) {
+                    tp->ipc_peer = np;
+                    np->ipc_peer = tp;
+                    break;
+                }
+            }
+        }
+    }
+}
+
+/*
+ * prt_nets6() -- print locally used INET6 socket information
+ */
+static void prt_nets6(struct lsof_context *ctx, /* context */
+                      struct tcp_udp6 *p,       /* peer info */
+                      int mk) /* 1 == mark for later processing */
+{
+    prt_nets_common(ctx, p, mk, tcp_udp6_get_pxinfo, CHEND_NETS6,
+                    EPT_NETS6_END);
+}
+
+/*
+ * process_nets6info() -- process locally used INET6 socket information, adding
+ *                     it to selected INET6 socket files and selecting INET6
+ *                     socket end point files (if requested)
+ */
+void process_nets6info(struct lsof_context *ctx, /* context */
+                       int f)                    /* function:
+                                                  *     0 == process selected socket
+                                                  *     1 == process socket end point
+                                                  */
+{
+    struct tcp_udp6 *p; /* peer INET6 socket info pointer */
+
+    if (!FeptE)
+        return;
+    for (Lf = Lp->file; Lf; Lf = Lf->next) {
+        if (Lf->type != LSOF_FILE_IPV6)
+            continue;
+        switch (f) {
+        case 0:
+
+            /*
+             * Process already selected socket.
+             */
+            if (is_file_sel(ctx, Lp, Lf)) {
+                /*
+                 * This file has been selected by some criterion other than its
+                 * being a socket.  Look up the socket's endpoints.
+                 */
+                p = find_nets6epti(ctx, Lf);
+                if (p && p->inode)
+                    prt_nets6(ctx, p, 1);
+            }
+            break;
+        case 1:
+            if (!is_file_sel(ctx, Lp, Lf) && (Lf->chend & CHEND_NETS6)) {
+
+                /*
+                 * This is an unselected end point INET6 socket file.  Select it
+                 * and add its end point information to peer's name column
+                 * addition.
+                 */
+                Lf->sf = Selflags;
+                Lp->pss |= PS_SEC;
+                p = find_nets6epti(ctx, Lf);
+                if (p && p->inode)
+                    prt_nets6(ctx, p, 0);
+            }
+            break;
+        }
+    }
+}
+#    endif /* defined(HASEPTOPTS) */
+#endif     /* defined(HASIPv6) */
+
+/*
+ * get_icmp() - get ICMP net info
+ */
+static void get_icmp(struct lsof_context *ctx, /* context */
+                     char *p)                  /* /proc/net/icmp path */
+{
+    char buf[MAXPATHLEN], *ep, **fp, *la, *ra;
+    int fl = 1;
+    int h;
+    INODETYPE inode;
+    struct icmpin *np, *icmpp;
+    MALLOC_S lal, ral;
+    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 *)));
+            Error(ctx);
+        }
+    }
+    /*
+     * 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(ctx, p, "r", &vbuf, &vsz, 0)))
+        return;
+    while (fgets(buf, sizeof(buf) - 1, xs)) {
+        if (get_fields(ctx, 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;
+        /* Skip if already exists in hash table */
+        if (HASH_FIND_ELEMENT(Icmpin, INOHASH, struct icmpin, inode, inode))
+            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]);
+                Error(ctx);
+            }
+            (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]);
+                Error(ctx);
+            }
+            (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));
+            Error(ctx);
+        }
+        icmpp->inode = inode;
+        icmpp->la = la;
+        icmpp->lal = lal;
+        icmpp->ra = ra;
+        icmpp->ral = ral;
+        HASH_INSERT_ELEMENT(Icmpin, INOHASH, icmpp, inode);
+    }
+    (void)fclose(xs);
+}
+
+/*
+ * get_ipx() - get /proc/net/ipx info
+ */
+static void get_ipx(struct lsof_context *ctx, /* context */
+                    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 *)));
+            Error(ctx);
+        }
+    }
+    /*
+     * 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(ctx, p, "r", &vbuf, &vsz, 0)))
+        return;
+    while (fgets(buf, sizeof(buf) - 1, xs)) {
+        if (get_fields(ctx, 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;
+        /* Skip if already exists in hash table */
+        if (HASH_FIND_ELEMENT(Ipxsin, INOHASH, struct ipxsin, inode, inode))
+            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]);
+                Error(ctx);
+            }
+            (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]);
+                Error(ctx);
+            }
+            (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));
+            Error(ctx);
+        }
+        ip->inode = inode;
+        ip->la = la;
+        ip->ra = ra;
+        ip->txq = txq;
+        ip->rxq = rxq;
+        ip->state = (int)state;
+        HASH_INSERT_ELEMENT(Ipxsin, INOHASH, ip, inode);
+    }
+    (void)fclose(xs);
+}
+
+/*
+ * get_netlink() - get /proc/net/netlink info
+ */
+static void get_netlink(struct lsof_context *ctx, /* context */
+                        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 *)));
+            Error(ctx);
+        }
+    }
+    /*
+     * 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(ctx, p, "r", &vbuf, &vsz, 0)))
+        return;
+    while (fgets(buf, sizeof(buf) - 1, xs)) {
+        if (get_fields(ctx, 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;
+        /* Skip if already exists in hash table */
+        if (HASH_FIND_ELEMENT(Nlksin, INOHASH, struct nlksin, inode, inode))
+            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));
+            Error(ctx);
+        }
+        lp->inode = inode;
+        lp->pr = pr;
+        HASH_INSERT_ELEMENT(Nlksin, INOHASH, lp, inode);
+    }
+    (void)fclose(xs);
+}
+
+/*
+ * get_pack() - get /proc/net/packet info
+ */
+static void get_pack(struct lsof_context *ctx, /* context */
+                     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 *)));
+            Error(ctx);
+        }
+    }
+    /*
+     * 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(ctx, p, "r", &vbuf, &vsz, 0)))
+        return;
+    while (fgets(buf, sizeof(buf) - 1, xs)) {
+        if (get_fields(ctx, 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;
+        /* Skip if already exists in hash table */
+        if (HASH_FIND_ELEMENT(Packin, INOHASH, struct packin, inode, inode))
+            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));
+            Error(ctx);
+        }
+        pp->inode = inode;
+        pp->pr = (int)pr;
+        pp->ty = ty;
+        HASH_INSERT_ELEMENT(Packin, INOHASH, pp, inode);
+    }
+    (void)fclose(xs);
+}
+
+/*
+ * get_raw() - get /proc/net/raw info
+ */
+static void get_raw(struct lsof_context *ctx, /* context */
+                    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 *)));
+            Error(ctx);
+        }
+    }
+    /*
+     * 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(ctx, p, "r", &vbuf, &vsz, 0)))
+        return;
+    while (fgets(buf, sizeof(buf) - 1, xs)) {
+        if (get_fields(ctx, 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;
+        /* Skip if already exists in hash table */
+        if (HASH_FIND_ELEMENT(Rawsin, INOHASH, struct rawsin, inode, inode))
+            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]);
+                Error(ctx);
+            }
+            (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]);
+                Error(ctx);
+            }
+            (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]);
+                Error(ctx);
+            }
+            (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));
+            Error(ctx);
+        }
+        rp->inode = inode;
+        rp->la = la;
+        rp->lal = lal;
+        rp->ra = ra;
+        rp->ral = ral;
+        rp->sp = sp;
+        rp->spl = spl;
+        HASH_INSERT_ELEMENT(Rawsin, INOHASH, rp, inode);
+    }
+    (void)fclose(xs);
+}
+
+/*
+ * get_sctp() - get /proc/net/sctp/assocs info
+ */
+static void get_sctp(struct lsof_context *ctx) {
+    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 *)));
+            Error(ctx);
+        }
+    }
+    /*
+     * 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(ctx, SCTPPath[i], "r", &vbuf, &vsz, 0)))
+            continue;
+        fl = 1;
+        while (fgets(buf, sizeof(buf) - 1, ss)) {
+            if ((nf = get_fields(ctx, 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;
+            sp = HASH_FIND_ELEMENT(SCTPsin, INOHASH, struct sctpsin, inode,
+                                   inode);
+            /*
+             * 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]);
+                    Error(ctx);
+                }
+                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]);
+                    Error(ctx);
+                }
+                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]);
+                    Error(ctx);
+                }
+                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]);
+                    Error(ctx);
+                }
+                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;
+            x = 0;
+            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);
+                    Error(ctx);
+                }
+                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);
+                            Error(ctx);
+                        }
+                        (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);
+                    Error(ctx);
+                }
+                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);
+                            Error(ctx);
+                        }
+                        (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));
+                    Error(ctx);
+                }
+                sp->inode = inode;
+                HASH_INSERT_ELEMENT(SCTPsin, INOHASH, sp, inode);
+            }
+            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(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(struct lsof_context *ctx, /* context */
+                       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;
+
+#if defined(HASEPTOPTS)
+    pxinfo_t *pp, *pnp;
+#endif /* defined(HASEPTOPTS) */
+
+    /*
+     * 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;
+
+#if defined(HASEPTOPTS)
+                    for (pp = tp->pxinfo; pp; pp = pnp) {
+                        pnp = pp->next;
+                        (void)free((FREE_P *)pp);
+                    }
+#endif /* defined(HASEPTOPTS) */
+
+                    (void)free((FREE_P *)tp);
+                }
+                TcpUdp[h] = (struct tcp_udp *)NULL;
+            }
+#if defined(HASEPTOPTS)
+            if (FeptE)
+                for (h = 0; h < IPCBUCKS; h++)
+                    TcpUdpIPC[h] = (struct tcp_udp *)NULL;
+#endif /* defined(HASEPTOPTS) */
+        }
+        /*
+         * 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(ctx, 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 *)));
+            Error(ctx);
+        }
+#if defined(HASEPTOPTS)
+        if (FeptE && (!(TcpUdpIPC = (struct tcp_udp **)calloc(
+                            IPCBUCKS, sizeof(struct tcp_udp *))))) {
+            (void)fprintf(stderr,
+                          "%s: can't allocate %d bytes for TCP&UDP local IPC "
+                          "hash buckets\n",
+                          Pn, (int)(IPCBUCKS * sizeof(struct tcp_udp *)));
+            Error(ctx);
+        }
+#endif /* defined(HASEPTOPTS) */
+    }
+    /*
+     * Open the /proc/net file, assign a page size buffer to the stream, and
+     * read it.
+     */
+    if (!(fs = open_proc_stream(ctx, p, "r", &vbuf, &vsz, 0)))
+        return;
+    nf = 12;
+    while (fgets(buf, sizeof(buf) - 1, fs)) {
+        if (get_fields(ctx, 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;
+        if (HASH_FIND_ELEMENT(TcpUdp, TCPUDPHASH, struct tcp_udp, inode, inode))
+            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));
+            Error(ctx);
+        }
+        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;
+        HASH_INSERT_ELEMENT(TcpUdp, TCPUDPHASH, tp, inode);
+#if defined(HASEPTOPTS)
+        tp->pxinfo = (pxinfo_t *)NULL;
+        if (FeptE) {
+            tp->ipc_peer = (struct tcp_udp *)NULL;
+            if (tp->state == TCP_ESTABLISHED) {
+                int i = TCPUDP_IPC_HASH(tp);
+                tp->ipc_next = TcpUdpIPC[i];
+                TcpUdpIPC[i] = tp;
+            }
+        }
+#endif /* defined(HASEPTOPTS) */
+    }
+
+#if defined(HASEPTOPTS)
+    /*
+     * If endpoint info has been requested, link INET socket peer info.
+     */
+    if (FeptE)
+        get_netpeeri(ctx);
+#endif /* defined(HASEPTOPTS) */
+
+    (void)fclose(fs);
+}
+
+#if defined(HASIPv6)
+/*
+ * get_raw6() - get /proc/net/raw6 info
+ */
+static void get_raw6(struct lsof_context *ctx, /* context */
+                     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);
+                if (rp->sp)
+                    (void)free((FREE_P *)rp->sp);
+                (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 *)));
+            Error(ctx);
+        }
+    }
+    /*
+     * 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(ctx, p, "r", &vbuf, &vsz, 0)))
+        return;
+    while (fgets(buf, sizeof(buf) - 1, xs)) {
+        if (get_fields(ctx, 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;
+        /* Skip if already exists in hash table */
+        if (HASH_FIND_ELEMENT(Rawsin6, INOHASH, struct rawsin, inode, inode))
+            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]);
+                Error(ctx);
+            }
+            (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]);
+                Error(ctx);
+            }
+            (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]);
+                Error(ctx);
+            }
+            (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));
+            Error(ctx);
+        }
+        rp->inode = inode;
+        rp->la = la;
+        rp->lal = lal;
+        rp->ra = ra;
+        rp->ral = ral;
+        rp->sp = sp;
+        rp->spl = spl;
+        HASH_INSERT_ELEMENT(Rawsin6, INOHASH, rp, inode);
+    }
+    (void)fclose(xs);
+}
+
+/*
+ * get_tcpudp6() - get IPv6 TCP, UDP or UDPLITE net info
+ */
+static void get_tcpudp6(struct lsof_context *ctx, /* context */
+                        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;
+
+#    if defined(HASEPTOPTS)
+    pxinfo_t *pp, *pnp;
+#    endif /* defined(HASEPTOPTS) */
+
+    /*
+     * 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;
+
+#    if defined(HASEPTOPTS)
+                    for (pp = tp6->pxinfo; pp; pp = pnp) {
+                        pnp = pp->next;
+                        (void)free((FREE_P *)pp);
+                    }
+#    endif /* defined(HASEPTOPTS) */
+
+                    (void)free((FREE_P *)tp6);
+                }
+                TcpUdp6[h] = (struct tcp_udp6 *)NULL;
+            }
+#    if defined(HASEPTOPTS)
+            if (FeptE)
+                for (h = 0; h < IPCBUCKS; h++)
+                    TcpUdp6IPC[h] = (struct tcp_udp6 *)NULL;
+#    endif /* defined(HASEPTOPTS) */
+        }
+    } else {
+
+        /*
+         * Open the /proc/net/sockstat6 file and establish the hash bucket
+         * count from its "TCP6: inuse" and "UDP6: inuse" lines.
+         */
+        TcpUdp6_bucks = INOBUCKS;
+        i = nf = 0;
+        if ((fs = fopen(SockStatPath6, "r"))) {
+            while (fgets(buf, sizeof(buf) - 1, fs)) {
+                if (get_fields(ctx, 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 *)));
+            Error(ctx);
+        }
+#    if defined(HASEPTOPTS)
+        if (FeptE && (!(TcpUdp6IPC = (struct tcp_udp6 **)calloc(
+                            IPCBUCKS, sizeof(struct tcp_udp6 *))))) {
+            (void)fprintf(stderr,
+                          "%s: can't allocate %d bytes for TCP6&UDP6 local IPC "
+                          "hash buckets\n",
+                          Pn, (int)(IPCBUCKS * sizeof(struct tcp_udp6 *)));
+            Error(ctx);
+        }
+#    endif /* defined(HASEPTOPTS) */
+    }
+    /*
+     * Open the /proc/net file, assign a page size buffer to the stream,
+     * and read it.
+     */
+    if (!(fs = open_proc_stream(ctx, p, "r", &vbuf, &vsz, 0)))
+        return;
+    nf = 12;
+    while (fgets(buf, sizeof(buf) - 1, fs)) {
+        if (get_fields(ctx, 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] || hex_ipv6_to_in6(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] || hex_ipv6_to_in6(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;
+        if (HASH_FIND_ELEMENT(TcpUdp6, TCPUDP6HASH, struct tcp_udp6, inode,
+                              inode))
+            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));
+            Error(ctx);
+        }
+        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;
+        HASH_INSERT_ELEMENT(TcpUdp6, TCPUDP6HASH, tp6, inode);
+#    if defined(HASEPTOPTS)
+        tp6->pxinfo = (pxinfo_t *)NULL;
+        if (FeptE) {
+            tp6->ipc_peer = (struct tcp_udp6 *)NULL;
+            if (tp6->state == TCP_ESTABLISHED) {
+                int i = TCPUDP6_IPC_HASH(tp6);
+                tp6->ipc_next = TcpUdp6IPC[i];
+                TcpUdp6IPC[i] = tp6;
+            }
+        }
+#    endif /* defined(HASEPTOPTS) */
+    }
+#    if defined(HASEPTOPTS)
+    /*
+     * If endpoint info has been requested, link INET6 socket peer info.
+     */
+    if (FeptE)
+        get_net6peeri(ctx);
+#    endif /* defined(HASEPTOPTS) */
+
+    (void)fclose(fs);
+}
+#endif /* defined(HASIPv6) */
+
+/*
+ * get_unix() - get UNIX net info
+ */
+static void get_unix(struct lsof_context *ctx, /* context */
+                     char *p)                  /* /proc/net/unix path */
+{
+    char buf[MAXPATHLEN], *ep, **fp, *path, *pcb;
+    int fl = 1; /* First line */
+    int h, nf;
+    INODETYPE inode;
+    MALLOC_S len;
+    uxsin_t *np, *up;
+    FILE *us;
+    uint32_t ty;
+    static char *vbuf = (char *)NULL;
+    static size_t vsz = (size_t)0;
+
+#if defined(HASEPTOPTS) && defined(HASUXSOCKEPT)
+    pxinfo_t *pp, *pnp;
+#endif /* defined(HASEPTOPTS) && defined(HASUXSOCKEPT) */
+
+    /*
+     * 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 defined(HASEPTOPTS) && defined(HASUXSOCKEPT)
+                for (pp = up->pxinfo; pp; pp = pnp) {
+                    pnp = pp->next;
+                    (void)free((FREE_P *)pp);
+                }
+#endif /* defined(HASEPTOPTS) && defined(HASUXSOCKEPT) */
+
+                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] = (uxsin_t *)NULL;
+        }
+    } else {
+        Uxsin = (uxsin_t **)calloc(INOBUCKS, sizeof(uxsin_t *));
+        if (!Uxsin) {
+            (void)fprintf(stderr,
+                          "%s: can't allocate %d bytes for Unix socket info\n",
+                          Pn, (int)(INOBUCKS * sizeof(uxsin_t *)));
+            Error(ctx);
+        }
+    }
+    /*
+     * 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(ctx, p, "r", &vbuf, &vsz, 0)))
+        return;
+    while (fgets(buf, sizeof(buf) - 1, us)) {
+        if ((nf = get_fields(ctx, 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;
+        /* Skip if already exists in hash table */
+        if (HASH_FIND_ELEMENT(Uxsin, INOHASH, uxsin_t, inode, inode))
+            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]);
+                Error(ctx);
+            }
+            (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]);
+                Error(ctx);
+            }
+            (void)snpf(path, len + 1, "%s", fp[7]);
+        } else
+            path = (char *)NULL;
+        /*
+         * Assemble socket type.
+         */
+        ep = (char *)NULL;
+        if (!fp[4] || !*fp[4] ||
+            (ty = (uint32_t)strtoul(fp[4], &ep, 16)) == (uint32_t)UINT32_MAX ||
+            !ep || *ep) {
+            ty = (uint32_t)UINT_MAX;
+        }
+        /*
+         * Record socket state.
+         */
+        unsigned long proc_flags = 0UL;
+        ep = (char *)NULL;
+        if (fp[3] && *fp[3] &&
+            (proc_flags = strtoul(fp[3], &ep, 16)) == ULONG_MAX)
+            proc_flags = 0UL;
+
+        unsigned long proc_st = 0UL;
+        ep = (char *)NULL;
+        if (fp[5] && *fp[5] &&
+            ((proc_st = strtoul(fp[5], &ep, 16)) == ULONG_MAX))
+            proc_st = 0UL;
+
+        /*
+         * Allocate and fill a Unix socket info structure; link it to its
+         * hash bucket.
+         */
+        if (!(up = (uxsin_t *)malloc(sizeof(uxsin_t)))) {
+            (void)fprintf(stderr,
+                          "%s: can't allocate %d bytes for uxsin struct\n", Pn,
+                          (int)sizeof(uxsin_t));
+            Error(ctx);
+        }
+        up->inode = inode;
+        up->next = (uxsin_t *)NULL;
+        up->pcb = pcb;
+        up->sb_def = 0;
+        up->ty = ty;
+        up->opt = (unsigned int)proc_flags;
+        up->ss = (unsigned int)proc_st;
+        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(ctx, path, &sb);
+            else
+                sr = stat(path, &sb);
+            if (sr == 0 && ((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;
+            }
+        }
+
+#if defined(HASEPTOPTS) && defined(HASUXSOCKEPT)
+        /*
+         * Clean UNIX socket endpoint values.
+         */
+        up->icstat = 0;
+        up->pxinfo = (pxinfo_t *)NULL;
+        up->peer = up->icons = (uxsin_t *)NULL;
+#endif /* defined(HASEPTOPTS) && defined(HASUXSOCKEPT) */
+
+        HASH_INSERT_ELEMENT(Uxsin, INOHASH, up, inode);
+    }
+
+#if defined(HASEPTOPTS) && defined(HASUXSOCKEPT)
+    /*
+     * If endpoint info has been requested, get UNIX socket peer info.
+     */
+    if (FeptE)
+        get_uxpeeri(ctx);
+#endif /* defined(HASEPTOPTS) && defined(HASUXSOCKEPT) */
+
+    (void)fclose(us);
+}
+
+#if defined(HASIPv6)
+/*
+ * hex_ipv6_to_in6() - convert ASCII IPv6 address in /proc/net/{tcp,udp}6 form
+ *to an in6_addr
+ */
+static int hex_ipv6_to_in6(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;
+
+        errno = 0;
+        unsigned long ul_addr = strtoul(buf, &ep, 16);
+        if (!ep || *ep)
+            break;
+        else if (ul_addr == ULONG_MAX && errno == ERANGE) {
+            /* Quoted from strtoul(3)
+               ---------------------------------------------------
+               The strtoul() function returns either the result of
+               the conversion or, if there was a leading minus
+               sign, the negation of the result of the conversion
+               represented as an unsigned value, unless the
+               original (nonnegated) value would overflow; in the
+               latter case, strtoul() returns ULONG_MAX and sets
+               errno to ERANGE.
+               ---------------------------------------------------
+               NOTE: even if the value doesn't overflow, a
+               negative is not acceptable. */
+            break;
+        } else if (ul_addr > (unsigned long)UINT32_MAX) {
+            /* This will never happen:
+               The maximum length of BUF is 8 characters.
+               The possible maximum value represented by BUF is
+               "FFFFFFFF". This is UINT32_MAX.
+               If you agree with what I write here, make a pull
+               request for removing this block. */
+            break;
+        }
+        ad->s6_addr32[i] = (uint32_t)ul_addr;
+    }
+    return ((*as || (i != 4) || len) ? 1 : 0);
+}
+#endif /* defined(HASIPv6) */
+
+/*
+ * isainb(a,b) check if string a is included in b, where b is a comma-separated
+ * string
+ */
+static int isainb(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(struct lsof_context *ctx, /* context */
+                           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);
+        Error(ctx);
+    }
+    (void)snpf(cp, pl + 1, "%s", pbuf);
+    Lf->nma = cp;
+}
+
+/*
+ * print_ipxinfo() - print IPX socket info
+ */
+static void print_ipxinfo(struct lsof_context *ctx, /* context */
+                          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);
+        Error(ctx);
+    }
+    (void)snpf(cp, pl + 1, "%s", pbuf);
+    Lf->nma = cp;
+}
+
+/*
+ * process_proc_sock() - process /proc-based socket
+ */
+void process_proc_sock(struct lsof_context *ctx, /* context */
+                       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 = (char *)NULL, tbuf[64];
+    unsigned char *fa, *la;
+    struct in_addr fs, ls;
+    struct icmpin *icmpp;
+    struct ipxsin *ip;
+    int i, len, nl, rf;
+    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;
+    uxsin_t *up;
+
+#if defined(HASIPv6)
+    int af;
+    struct tcp_udp6 *tp6;
+#endif /* defined(HASIPv6) */
+
+    /*
+     * Enter offset, if possible.
+     */
+    if (l && (lss & SB_SIZE) && OffType != OFFSET_UNKNOWN) {
+        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(ctx, AX25path);
+        (void)free((FREE_P *)AX25path);
+        AX25path = (char *)NULL;
+    }
+    if ((ss & SB_INO) && (ap = check_ax25(ctx, (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.
+         */
+        Lf->type = LSOF_FILE_AX25;
+        if (ap->dev_ch)
+            (void)enter_dev_ch(ctx, ap->dev_ch);
+        Lf->inode = ap->inode;
+        Lf->inp_ty = 1;
+        print_ax25info(ctx, ap);
+        return;
+    }
+
+    if (Ipxpath) {
+        (void)get_ipx(ctx, Ipxpath);
+        (void)free((FREE_P *)Ipxpath);
+        Ipxpath = (char *)NULL;
+    }
+    if ((ss & SB_INO) && (ip = check_ipx(ctx, (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.
+         */
+        Lf->type = LSOF_FILE_IPX;
+        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 - 1)
+                len = nl - 1;
+            (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);
+                len = strlen(ip->ra);
+                cp += len;
+                nl -= len;
+            }
+        }
+        (void)print_ipxinfo(ctx, ip);
+        if (Namech[0])
+            enter_nm(ctx, Namech);
+        return;
+    }
+
+    if (Rawpath) {
+        (void)get_raw(ctx, Rawpath);
+        (void)free((FREE_P *)Rawpath);
+        Rawpath = (char *)NULL;
+    }
+    if ((ss & SB_INO) && (rp = check_raw(ctx, (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.
+         */
+        Lf->type = LSOF_FILE_RAW;
+        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(ctx, Namech);
+        return;
+    }
+
+    if (Nlkpath) {
+        (void)get_netlink(ctx, Nlkpath);
+        (void)free((FREE_P *)Nlkpath);
+        Nlkpath = (char *)NULL;
+    }
+    if ((ss & SB_INO) && (np = check_netlink(ctx, (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.
+         */
+
+        Lf->type = LSOF_FILE_NETLINK;
+        cp = netlink_proto_to_str(np->pr);
+        if (cp)
+            (void)snpf(Namech, Namechl, "%s", cp);
+        else
+            (void)snpf(Namech, Namechl, "unknown protocol: %d", np->pr);
+
+        Lf->inode = (INODETYPE)s->st_ino;
+        Lf->inp_ty = 1;
+        if (Namech[0])
+            enter_nm(ctx, Namech);
+        return;
+    }
+
+    if (Packpath) {
+        (void)get_pack(ctx, Packpath);
+        (void)free((FREE_P *)Packpath);
+        Packpath = (char *)NULL;
+    }
+    if ((ss & SB_INO) && (pp = check_pack(ctx, (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.
+         */
+        Lf->type = LSOF_FILE_PACKET;
+        cp = socket_type_to_str(pp->ty, &rf);
+        (void)snpf(Namech, Namechl, "type=%s%s", rf ? "" : "SOCK_", cp);
+        cp = ethernet_proto_to_str(pp->pr);
+        if (!cp) {
+            /* Unknown ethernet proto */
+            (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), "%" INODEPSPEC "u",
+                       (INODETYPE)s->st_ino);
+            tbuf[sizeof(tbuf) - 1] = '\0';
+            enter_dev_ch(ctx, tbuf);
+        }
+        if (Namech[0])
+            enter_nm(ctx, Namech);
+        return;
+    }
+
+    if (UNIXpath) {
+        (void)get_unix(ctx, UNIXpath);
+        (void)free((FREE_P *)UNIXpath);
+        UNIXpath = (char *)NULL;
+    }
+    if ((ss & SB_INO) && (up = check_unix(ctx, (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;
+        Lf->type = LSOF_FILE_UNIX;
+        if (up->pcb)
+            enter_dev_ch(ctx, up->pcb);
+        Lf->inode = (INODETYPE)s->st_ino;
+        Lf->inp_ty = 1;
+
+        Lf->lts.type = up->ty;
+#if defined(HASSOOPT)
+        Lf->lts.opt = up->opt;
+#endif /* defined(HASSOOPT) */
+#if defined(HASSOSTATE)
+        Lf->lts.ss = up->ss;
+#endif /* defined(HASSOSTATE) */
+#if defined(HASEPTOPTS) && defined(HASUXSOCKEPT)
+        if (FeptE) {
+            (void)enter_uxsinfo(ctx, up);
+            Lf->sf |= SELUXSINFO;
+        }
+#endif /* defined(HASEPTOPTS) && defined(HASUXSOCKEPT) */
+
+        cp = socket_type_to_str(up->ty, &rf);
+        (void)snpf(Namech, Namechl - 1, "%s%stype=%s", up->path ? up->path : "",
+                   up->path ? " " : "", cp);
+        Namech[Namechl - 1] = '\0';
+        (void)enter_nm(ctx, Namech);
+        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(ctx, 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(ctx, 2, up->path ? up->path : p,
+                                  (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(ctx, Raw6path);
+        (void)free((FREE_P *)Raw6path);
+        Raw6path = (char *)NULL;
+    }
+    if (!Fxopt && (ss & SB_INO) &&
+        (rp = check_raw6(ctx, (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.
+         */
+        Lf->type = LSOF_FILE_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(ctx, Namech);
+        return;
+    }
+
+    if (TCP6path) {
+        if (!Fxopt)
+            (void)get_tcpudp6(ctx, TCP6path, 0, 1);
+        (void)free((FREE_P *)TCP6path);
+        TCP6path = (char *)NULL;
+    }
+
+    if (UDP6path) {
+        if (!Fxopt)
+            (void)get_tcpudp6(ctx, UDP6path, 1, 0);
+        (void)free((FREE_P *)UDP6path);
+        UDP6path = (char *)NULL;
+    }
+
+    if (UDPLITE6path) {
+        if (!Fxopt)
+            (void)get_tcpudp6(ctx, UDPLITE6path, 2, 0);
+        (void)free((FREE_P *)UDPLITE6path);
+        UDPLITE6path = (char *)NULL;
+    }
+
+    if (!Fxopt && (ss & SB_INO) &&
+        (tp6 = check_tcpudp6(ctx, (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;
+        Lf->type = LSOF_FILE_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), "%" INODEPSPEC "u",
+                       (INODETYPE)s->st_ino);
+            tbuf[sizeof(tbuf) - 1] = '\0';
+            enter_dev_ch(ctx, tbuf);
+            Lf->inode = (INODETYPE)s->st_ino;
+        }
+        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(ctx, 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) */
+
+#    if defined(HASEPTOPTS)
+        if (FeptE && tp6->ipc_peer) {
+            (void)enter_nets6info(ctx, tp6);
+            Lf->sf |= SELNETS6INFO;
+        }
+#    endif /* defined(HASEPTOPTS) */
+        return;
+    }
+#endif /* defined(HASIPv6) */
+
+    if (TCPpath) {
+        if (!Fxopt)
+            (void)get_tcpudp(ctx, TCPpath, 0, 1);
+        (void)free((FREE_P *)TCPpath);
+        TCPpath = (char *)NULL;
+    }
+
+    if (UDPpath) {
+        if (!Fxopt)
+            (void)get_tcpudp(ctx, UDPpath, 1, 0);
+        (void)free((FREE_P *)UDPpath);
+        UDPpath = (char *)NULL;
+    }
+
+    if (UDPLITEpath) {
+        if (!Fxopt)
+            (void)get_tcpudp(ctx, UDPLITEpath, 2, 0);
+        (void)free((FREE_P *)UDPLITEpath);
+        UDPLITEpath = (char *)NULL;
+    }
+
+    if (!Fxopt && (ss & SB_INO) &&
+        (tp = check_tcpudp(ctx, (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)
+        Lf->type = LSOF_FILE_IPV4;
+#else  /* !defined(HASIPv6) */
+        Lf->type = LSOF_FILE_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), "%" INODEPSPEC "u",
+                       (INODETYPE)s->st_ino);
+            tbuf[sizeof(tbuf) - 1] = '\0';
+            enter_dev_ch(ctx, tbuf);
+            Lf->inode = (INODETYPE)s->st_ino;
+        }
+        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(ctx, 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) */
+
+#if defined(HASEPTOPTS)
+        if (FeptE && tp->ipc_peer) {
+            (void)enter_netsinfo(ctx, tp);
+            Lf->sf |= SELNETSINFO;
+        }
+#endif /* defined(HASEPTOPTS) */
+
+        return;
+    }
+
+    if (SCTPPath[0]) {
+        (void)get_sctp(ctx);
+        for (i = 0; i < NSCTPPATHS; i++) {
+            (void)free((FREE_P *)SCTPPath[i]);
+            SCTPPath[i] = (char *)NULL;
+        }
+    }
+    if ((ss & SB_INO) && (sp = check_sctp(ctx, (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.
+         */
+        Lf->type = LSOF_FILE_SOCKET;
+        (void)snpf(Lf->iproto, sizeof(Lf->iproto), "%.*s", IPROTOL - 1, "SCTP");
+        Lf->inp_ty = 2;
+        (void)snpf(tbuf, sizeof(tbuf), "%" INODEPSPEC "u", (INODETYPE)s->st_ino);
+        tbuf[sizeof(tbuf) - 1] = '\0';
+        enter_dev_ch(ctx, 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(ctx, Namech);
+        return;
+    }
+
+    if (ICMPpath) {
+        (void)get_icmp(ctx, ICMPpath);
+        (void)free((FREE_P *)ICMPpath);
+        ICMPpath = (char *)NULL;
+    }
+    if ((ss & SB_INO) && (icmpp = check_icmp(ctx, (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.
+         */
+        Lf->type = LSOF_FILE_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(ctx, Namech);
+        return;
+    }
+
+    /*
+     * The socket's protocol can't be identified.
+     */
+    Lf->type = LSOF_FILE_SOCKET;
+    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(ctx, "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(ctx, "can't identify protocol");
+        else
+            enter_nm(ctx, Namech);
+    }
+}
+
+/*
+ * set_net_paths() - set /proc/net paths
+ */
+void set_net_paths(struct lsof_context *ctx, /* context */
+                   char *p,                  /* path to /proc/net/ */
+                   int pl)                   /* strlen(p) */
+{
+    int i;
+    int pathl;
+
+    pathl = 0;
+    (void)make_proc_path(ctx, p, pl, &AX25path, &pathl, "ax25");
+    pathl = 0;
+    (void)make_proc_path(ctx, p, pl, &ICMPpath, &pathl, "icmp");
+    pathl = 0;
+    (void)make_proc_path(ctx, p, pl, &Ipxpath, &pathl, "ipx");
+    pathl = 0;
+    (void)make_proc_path(ctx, p, pl, &Nlkpath, &pathl, "netlink");
+    pathl = 0;
+    (void)make_proc_path(ctx, p, pl, &Packpath, &pathl, "packet");
+    pathl = 0;
+    (void)make_proc_path(ctx, p, pl, &Rawpath, &pathl, "raw");
+    for (i = 0; i < NSCTPPATHS; i++) {
+        pathl = 0;
+        (void)make_proc_path(ctx, p, pl, &SCTPPath[i], &pathl, SCTPSfx[i]);
+    }
+    pathl = 0;
+    (void)make_proc_path(ctx, p, pl, &SockStatPath, &pathl, "sockstat");
+    pathl = 0;
+    (void)make_proc_path(ctx, p, pl, &TCPpath, &pathl, "tcp");
+    pathl = 0;
+    (void)make_proc_path(ctx, p, pl, &UDPpath, &pathl, "udp");
+    pathl = 0;
+    (void)make_proc_path(ctx, p, pl, &UDPLITEpath, &pathl, "udplite");
+
+#if defined(HASIPv6)
+    pathl = 0;
+    (void)make_proc_path(ctx, p, pl, &Raw6path, &pathl, "raw6");
+    pathl = 0;
+    (void)make_proc_path(ctx, p, pl, &SockStatPath6, &pathl, "sockstat6");
+    pathl = 0;
+    (void)make_proc_path(ctx, p, pl, &TCP6path, &pathl, "tcp6");
+    pathl = 0;
+    (void)make_proc_path(ctx, p, pl, &UDP6path, &pathl, "udp6");
+    pathl = 0;
+    (void)make_proc_path(ctx, p, pl, &UDPLITE6path, &pathl, "udplite6");
+#endif /* defined(HASIPv6) */
+
+    pathl = 0;
+    (void)make_proc_path(ctx, p, pl, &UNIXpath, &pathl, "unix");
+}
+
+/*
+ * socket_type_to_str() -- convert socket type number to a string
+ */
+
+static char *socket_type_to_str(uint32_t ty, /* socket type number */
+                                int *rf)     /* result flag: 0 == known
+                                              *                1 = unknown */
+{
+    int f = 0; /* result flag */
+    char *sr;  /* string result */
+
+    switch (ty) {
+
+#if defined(SOCK_STREAM)
+    case SOCK_STREAM:
+        sr = "STREAM";
+        break;
+#endif /* defined(SOCK_STREAM) */
+
+#if defined(SOCK_DGRAM)
+    case SOCK_DGRAM:
+        sr = "DGRAM";
+        break;
+#endif /* defined(SOCK_DGRAM) */
+
+#if defined(SOCK_RAW)
+    case SOCK_RAW:
+        sr = "RAW";
+        break;
+#endif /* defined(SOCK_RAW) */
+
+#if defined(SOCK_RDM)
+    case SOCK_RDM:
+        sr = "RDM";
+        break;
+#endif /* defined(SOCK_RDM) */
+
+#if defined(SOCK_SEQPACKET)
+    case SOCK_SEQPACKET:
+        sr = "SEQPACKET";
+        break;
+#endif /* defined(SOCK_SEQPACKET) */
+
+#if defined(SOCK_DCCP)
+    case SOCK_DCCP:
+        sr = "DCCP";
+        break;
+#endif /* defined(SOCK_DCCP) */
+
+#if defined(SOCK_PACKET)
+    case SOCK_PACKET:
+        sr = "PACKET";
+        break;
+#endif /* defined(SOCK_PACKET) */
+
+    default:
+        f = 1;
+        sr = "unknown";
+    }
+    *rf = f;
+    return (sr);
+}
+
+/*
+ * netlink_proto_to_str() -- convert netlink protocol number to a string
+ *
+ * return NULL if the number is unknown.
+ */
+static char *netlink_proto_to_str(unsigned int pr) {
+    char *cp = NULL;
+    switch (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) */
+
+#if defined(NETLINK_RDMA)
+    case NETLINK_RDMA:
+        cp = "RDMA";
+        break;
+#endif /* defined(NETLINK_RDMA) */
+
+#if defined(NETLINK_CRYPTO)
+    case NETLINK_CRYPTO:
+        cp = "CRYPTO";
+        break;
+#endif /* defined(NETLINK_CRYPTO) */
+
+#if defined(NETLINK_SMC)
+    case NETLINK_SMC:
+        cp = "SMC";
+        break;
+#endif /* defined(NETLINK_SMC) */
+    }
+
+    return cp;
+}
+
+/*
+ * ethernet_proto_to_str() -- convert ethernet protocol number to a string
+ *
+ * The string should not exceed 7 characters.
+ *
+ * return NULL if the number is unknown.
+ */
+static char *ethernet_proto_to_str(unsigned int pr) {
+    char *cp = NULL;
+    switch (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_TSN)
+    case ETH_P_TSN:
+        cp = "TSN";
+        break;
+#endif /* defined(ETH_P_TSN) */
+
+#if defined(ETH_P_ERSPAN2)
+    case ETH_P_ERSPAN2:
+        cp = "ERSPAN2";
+        break;
+#endif /* defined(ETH_P_ERSPAN2) */
+
+#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_BATMAN)
+    case ETH_P_BATMAN:
+        cp = "BATMAN";
+        break;
+#endif /* defined(ETH_P_BATMAN) */
+
+#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_TEB)
+    case ETH_P_TEB:
+        cp = "TEB";
+        break;
+#endif /* defined(ETH_P_TEB) */
+
+#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_ERSPAN)
+    case ETH_P_ERSPAN:
+        cp = "ERSPAN";
+        break;
+#endif /* defined(ETH_P_ERSPAN) */
+
+#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_PAUSE)
+    case ETH_P_PAUSE:
+        cp = "PAUSE";
+        break;
+#endif /* defined(ETH_P_PAUSE) */
+
+#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_MPLS_UC)
+    case ETH_P_MPLS_UC:
+        cp = "MPLS_UC";
+        break;
+#endif /* defined(ETH_P_MPLS_UC) */
+
+#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_ATMMPOA)
+    case ETH_P_ATMMPOA:
+        cp = "ATMMPOA";
+        break;
+#endif /* defined(ETH_P_ATMMPOA) */
+
+#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_LINK_CTL)
+    case ETH_P_LINK_CTL:
+        cp = "LINKCTL";
+        break;
+#endif /* defined(ETH_P_LINK_CTL) */
+
+#if defined(ETH_P_ATMFATE)
+    case ETH_P_ATMFATE:
+        cp = "ATMFATE";
+        break;
+#endif /* defined(ETH_P_ATMFATE) */
+
+#if defined(ETH_P_PAE)
+    case ETH_P_PAE:
+        cp = "PAE";
+        break;
+#endif /* defined(ETH_P_PAE) */
+
+#if defined(ETH_P_AOE)
+    case ETH_P_AOE:
+        cp = "AOE";
+        break;
+#endif /* defined(ETH_P_AOE) */
+
+#if defined(ETH_P_8021AD)
+    case ETH_P_8021AD:
+        cp = "8021AD";
+        break;
+#endif /* defined(ETH_P_8021AD) */
+
+#if defined(ETH_P_802_EX1)
+    case ETH_P_802_EX1:
+        cp = "802_EX1";
+        break;
+#endif /* defined(ETH_P_802_EX1) */
+
+#if defined(ETH_P_PREAUTH)
+    case ETH_P_PREAUTH:
+        cp = "PREAUTH";
+        break;
+#endif /* defined(ETH_P_PREAUTH) */
+
+#if defined(ETH_P_TIPC)
+    case ETH_P_TIPC:
+        cp = "TIPC";
+        break;
+#endif /* defined(ETH_P_TIPC) */
+
+#if defined(ETH_P_LLDP)
+    case ETH_P_LLDP:
+        cp = "LLDP";
+        break;
+#endif /* defined(ETH_P_LLDP) */
+
+#if defined(ETH_P_MRP)
+    case ETH_P_MRP:
+        cp = "MRP";
+        break;
+#endif /* defined(ETH_P_MRP) */
+
+#if defined(ETH_P_MACSEC)
+    case ETH_P_MACSEC:
+        cp = "MACSEC";
+        break;
+#endif /* defined(ETH_P_MACSEC) */
+
+#if defined(ETH_P_8021AH)
+    case ETH_P_8021AH:
+        cp = "8021AH";
+        break;
+#endif /* defined(ETH_P_8021AH) */
+
+#if defined(ETH_P_MVRP)
+    case ETH_P_MVRP:
+        cp = "MVRP";
+        break;
+#endif /* defined(ETH_P_MVRP) */
+
+#if defined(ETH_P_1588)
+    case ETH_P_1588:
+        cp = "1588";
+        break;
+#endif /* defined(ETH_P_1588) */
+
+#if defined(ETH_P_NCSI)
+    case ETH_P_NCSI:
+        cp = "NCSI";
+        break;
+#endif /* defined(ETH_P_NCSI) */
+
+#if defined(ETH_P_PRP)
+    case ETH_P_PRP:
+        cp = "PRP";
+        break;
+#endif /* defined(ETH_P_PRP) */
+
+#if defined(ETH_P_FCOE)
+    case ETH_P_FCOE:
+        cp = "FCOE";
+        break;
+#endif /* defined(ETH_P_FCOE) */
+
+#if defined(ETH_P_IBOE)
+    case ETH_P_IBOE:
+        cp = "IBOE";
+        break;
+#endif /* defined(ETH_P_IBOE) */
+
+#if defined(ETH_P_TDLS)
+    case ETH_P_TDLS:
+        cp = "TDLS";
+        break;
+#endif /* defined(ETH_P_TDLS) */
+
+#if defined(ETH_P_FIP)
+    case ETH_P_FIP:
+        cp = "FIP";
+        break;
+#endif /* defined(ETH_P_FIP) */
+
+#if defined(ETH_P_80221)
+    case ETH_P_80221:
+        cp = "802.21";
+        break;
+#endif /* defined(ETH_P_80221) */
+
+#if defined(ETH_P_HSR)
+    case ETH_P_HSR:
+        cp = "HSR";
+        break;
+#endif /* defined(ETH_P_HSR) */
+
+#if defined(ETH_P_NSH)
+    case ETH_P_NSH:
+        cp = "NSH";
+        break;
+#endif /* defined(ETH_P_NSH) */
+
+#if defined(ETH_P_LOOPBACK)
+    case ETH_P_LOOPBACK:
+        cp = "LOOPBACK";
+        break;
+#endif /* defined(ETH_P_LOOPBACK) */
+
+#if defined(ETH_P_QINQ1)
+    case ETH_P_QINQ1:
+        cp = "QINQ1";
+        break;
+#endif /* defined(ETH_P_QINQ1) */
+
+#if defined(ETH_P_QINQ2)
+    case ETH_P_QINQ2:
+        cp = "QINQ2";
+        break;
+#endif /* defined(ETH_P_QINQ2) */
+
+#if defined(ETH_P_QINQ3)
+    case ETH_P_QINQ3:
+        cp = "QINQ3";
+        break;
+#endif /* defined(ETH_P_QINQ3) */
+
+#if defined(ETH_P_EDSA)
+    case ETH_P_EDSA:
+        cp = "EDSA";
+        break;
+#endif /* defined(ETH_P_EDSA) */
+
+#if defined(ETH_P_DSA_8021Q)
+    case ETH_P_DSA_8021Q:
+        cp = "DSAD1Q";
+        break;
+#endif /* defined(ETH_P_DSA_8021Q) */
+
+#if defined(ETH_P_IFE)
+    case ETH_P_IFE:
+        cp = "IFE";
+        break;
+#endif /* defined(ETH_P_IFE) */
+
+#if defined(ETH_P_AF_IUCV)
+    case ETH_P_AF_IUCV:
+        cp = "AF_IUCV";
+        break;
+#endif /* defined(ETH_P_AF_IUCV) */
+
+#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_CAN)
+    case ETH_P_CAN:
+        cp = "CAN";
+        break;
+#endif /* defined(ETH_P_CAN) */
+
+#if defined(ETH_P_CANFD)
+    case ETH_P_CANFD:
+        cp = "CANFD";
+        break;
+#endif /* defined(ETH_P_CANFD) */
+
+#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) */
+
+#if defined(ETH_P_DSA)
+    case ETH_P_DSA:
+        cp = "DSA";
+        break;
+#endif /* defined(ETH_P_DSA) */
+
+#if defined(ETH_P_TRAILER)
+    case ETH_P_TRAILER:
+        cp = "TRAILER";
+        break;
+#endif /* defined(ETH_P_TRAILER) */
+
+#if defined(ETH_P_PHONET)
+    case ETH_P_PHONET:
+        cp = "PHONET";
+        break;
+#endif /* defined(ETH_P_PHONET) */
+
+#if defined(ETH_P_IEEE802154)
+    case ETH_P_IEEE802154:
+        cp = "802154";
+        break;
+#endif /* defined(ETH_P_IEEE802154) */
+
+#if defined(ETH_P_CAIF)
+    case ETH_P_CAIF:
+        cp = "CAIF";
+        break;
+#endif /* defined(ETH_P_CAIF) */
+
+#if defined(ETH_P_XDSA)
+    case ETH_P_XDSA:
+        cp = "XDSA";
+        break;
+#endif /* defined(ETH_P_XDSA) */
+
+#if defined(ETH_P_MAP)
+    case ETH_P_MAP:
+        cp = "MAP";
+        break;
+#endif /* defined(ETH_P_MAP) */
+
+    default:
+        cp = NULL;
+        break;
+    }
+    return cp;
+}
diff --git a/lib/dialects/linux/dstore.c b/lib/dialects/linux/dstore.c
new file mode 100644 (file)
index 0000000..9cea7d4
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * 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.
+ */
+
+#include "common.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
+                       */
+dev_t MqueueDev = -1; /* The number for the device behind
+                       * mqueue mount point */
+/* offset type:
+ *     0 == unknown
+ *     1 == lstat's st_size
+ *     2 == from /proc/<PID>/fdinfo
+ */
+int OffType = OFFSET_UNKNOWN;
+
+/*
+ * 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) */
+
+#if defined(O_CLOEXEC)
+                            {(long)O_CLOEXEC, POF_CLOEXEC},
+#endif /* defined(O_CLOEXEC) */
+
+#if defined(O_PATH)
+                            {(long)O_PATH, FF_PATH},
+#endif /* defined(O_PATH) */
+
+#if defined(O_TMPFILE)
+                            {(long)O_TMPFILE, FF_TMPFILE},
+#endif /* defined(O_TMPFILE) */
+
+                            {(long)0, NULL}};
+
+/*
+ * Pof_tab[] - table for print process open file flags
+ */
+
+struct pff_tab Pof_tab[] = {{(long)0, NULL}};
diff --git a/lib/dialects/linux/machine.h b/lib/dialects/linux/machine.h
new file mode 100644 (file)
index 0000000..fd9793b
--- /dev/null
@@ -0,0 +1,589 @@
+/*
+ * 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.37 2014/10/13 22:25:58 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 */
+
+/*
+ * HASEPTOPTS is defined for dialects that support the +|-E options.
+ */
+
+#    define HASEPTOPTS 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?       */
+
+/*
+ * 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_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) memset(a, 0, l)
+
+#endif /* !defined(LSOF_MACHINE_H) */
diff --git a/lib/dialects/linux/tests/Makefile b/lib/dialects/linux/tests/Makefile
new file mode 100644 (file)
index 0000000..1532cbe
--- /dev/null
@@ -0,0 +1,33 @@
+HELPERS = \
+       epoll \
+       eventfd \
+       mq_fork \
+       mq_open \
+       pidfd \
+       pipe \
+       pty \
+       ux \
+       mmap \
+       \
+       open_with_flags \
+       \
+       $(NULL)
+
+CFLAGS  = -g -Wall -std=c99
+
+.PHONY: clean all
+
+all: $(HELPERS)
+clean:
+       rm -f $(HELPERS) *.o
+
+# See
+# https://stackoverflow.com/questions/19964206/weird-posix-message-queue-linking-issue-sometimes-it-doesnt-link-correctly
+#
+# We cannot use LDFLAGS here.
+# -lrt must be at the end of the command line.
+#
+mq_open: mq_open.o
+       $(CC) $(CFLAGS) -o $@ $< -lrt
+mq_fork: mq_fork.o
+       $(CC) $(CFLAGS) -o $@ $< -lrt
diff --git a/lib/dialects/linux/tests/case-00-linux-hello.bash b/lib/dialects/linux/tests/case-00-linux-hello.bash
new file mode 100755 (executable)
index 0000000..5b66503
--- /dev/null
@@ -0,0 +1,10 @@
+report=$2
+tdir=$3
+
+{
+    # This make invocaiton is needed to
+    # run test cases locally, not CI environment.
+    make -C $tdir || exit 1
+} > $report
+
+exit 0
diff --git a/lib/dialects/linux/tests/case-10-mqueue.bash b/lib/dialects/linux/tests/case-10-mqueue.bash
new file mode 100755 (executable)
index 0000000..b3212b5
--- /dev/null
@@ -0,0 +1,69 @@
+#!/bin/bash
+source tests/common.bash
+
+MQUEUE_MNTPOINT=/tmp/$$
+
+TARGET=$tcasedir/mq_open
+if ! [ -x $TARGET ]; then
+    echo "target executable ( $TARGET ) is not found" >> $report
+    exit 1
+fi
+
+if grep -q mqueue /proc/mounts; then
+    :
+elif ! [ $(id -u) = 0 ]; then
+    echo "root privileged is needed to run $(basename $0 .sh), skipping" >> $report
+    exit 77
+else
+    mkdir -p ${MQUEUE_MNTPOINT}
+    if ! mount -t mqueue none ${MQUEUE_MNTPOINT}; then
+       echo "failed to mount mqeueu file system, skipping"
+       exit 77
+    fi
+fi
+
+umount_mqueue()
+{
+    if [ -d ${MQUEUE_MNTPOINT} ]; then
+       umount ${MQUEUE_MNTPOINT}
+       rmdir ${MQUEUE_MNTPOINT}
+    fi
+}
+
+cleanup()
+{
+    local status=$1
+    local pid=$2
+
+    umount_mqueue
+    while kill -0 $pid 2> /dev/null; do
+       kill -CONT $pid
+       sleep 1
+    done
+    exit $status
+}
+
+$TARGET | {
+    if read label0 pid sep label1 fd; then
+       if line=`$lsof -p $pid -a -d $fd -Ft`; then
+           if echo "$line" | grep -q PSXMQ; then
+               cleanup 0 $pid
+           else
+               echo "unexpected output: $line" >> $report
+               cleanup 1 $pid
+           fi
+       else
+           echo "lsof rejects following command line: $lsof -p $pid -a -d $fd" >> $report
+           cleanup 1 $pid
+       fi
+    else
+       echo "$TARGET prints an unexpected line: $label0 $pid $sep $label1 $fd" >> $report
+       umount_mqueue
+       case "$pid" in
+           [0-9]*)
+               kill $pid
+               ;;
+       esac
+       exit 1
+    fi
+}
diff --git a/lib/dialects/linux/tests/case-10-ux-socket-state.bash b/lib/dialects/linux/tests/case-10-ux-socket-state.bash
new file mode 100755 (executable)
index 0000000..d47e53a
--- /dev/null
@@ -0,0 +1,81 @@
+#!/bin/bash
+source tests/common.bash
+
+if ! [ -r "/proc/self/stack" ]; then
+    echo "this platform doesn't allow to access /proc/\$PID/stack, skipping" >> $report
+    exit 77
+fi
+
+if [ -z "$(nc -h 2>&1 | grep '\-U')" ]; then
+    echo "nc does not support unix socket, skipping" >> $report
+    exit 77
+fi
+
+ux=/tmp/$name-$$.sock
+nc -l -U $ux > /dev/null < /dev/zero &
+server=$!
+
+killBoth()
+{
+    kill -9 $1
+    sleep 1
+    kill -9 $2
+} 2> /dev/null > /dev/null
+
+waitForSyscall()
+{
+    local pid=$1
+    local pat=$2
+    local niterations=$3
+    local i
+
+    for i in $(seq 0 $niterations); do
+       sleep 1
+       if grep -q "$pat" /proc/$pid/stack; then
+           break
+       fi
+    done
+}
+
+waitForSyscall $server 'select\|poll' 10
+
+fserver=/tmp/${name}-server-$$-before
+$lsof -n -Ts -P -U -a -p $server > $fserver
+# nc        22512 yamato    3u  unix 0x000000008f6993b8      0t0     470697 /tmp/a type=STREAM (LISTEN)
+if ! cat $fserver | grep -q "^.* unix 0x[0-9a-f]\+ \+0t0 \+[0-9]\+ $ux type=STREAM (LISTEN)"; then
+    echo "failed in server side (before connecting)" >> $report
+    cat $fserver >> $report
+    kill -9 $server
+    rm $ux
+    exit 1
+fi
+
+nc -U $ux < /dev/zero  > /dev/null &
+client=$!
+sleep 1
+fserver=/tmp/${name}-server-$$-after
+$lsof -n -Ts -P -U -a -p $server > $fserver
+# nc      22512 yamato    4u  unix 0x00000000deffde05      0t0 472699 /tmp/a type=STREAM (CONNECTED)
+if ! cat $fserver | grep -q "^.* unix 0x[0-9a-f]\+ \+0t0 \+[0-9]\+ $ux type=STREAM (CONNECTED)"; then
+    echo "failed in server side (after connecting)" >> $report
+    cat $fserver >> $report
+    killBoth $client $server
+    rm $ux
+    exit 1
+fi
+
+fclient=/tmp/${name}-client-$$
+$lsof -n -Ts -P -U -a -p $client -FT | grep ^TST > $fclient
+# TST=CONNECTED
+if ! cat $fclient | grep -q "^TST=CONNECTED"; then
+    echo "failed in client side" >> $report
+    cat $fclient >> $report
+    killBoth $client $server
+    rm $ux
+    exit 1
+fi
+
+killBoth $client $server
+rm $ux
+
+exit 0
diff --git a/lib/dialects/linux/tests/case-20-epoll.bash b/lib/dialects/linux/tests/case-20-epoll.bash
new file mode 100755 (executable)
index 0000000..770a1d7
--- /dev/null
@@ -0,0 +1,35 @@
+#!/bin/bash
+source tests/common.bash
+
+TARGET=$tcasedir/epoll
+if ! [ -x $TARGET ]; then
+    echo "target executable ( $TARGET ) is not found" >> $report
+    exit 1
+fi
+
+$TARGET 2>> $report | {
+    read pid epfd evfd0 evfd1
+    if [[ -z "$pid" || -z "$epfd" || -z "$evfd0" || -z "$evfd1" ]]; then
+       echo "unexpected output form target ( $TARGET )" >> $report
+       exit 1
+    fi
+    if ! [ -e "/proc/$pid" ]; then
+       echo "the target process dead unexpectedly" >> $report
+       exit 1
+    fi
+    {
+       echo pid: $pid
+       echo epfd: $epfd
+       echo cmdline: "$lsof -p $pid -a -d $epfd"
+       $lsof -p $pid -a -d $epfd
+       echo done
+    } >> $report
+    if $lsof -p $pid -a -d $epfd |
+           grep -q "epoll *[0-9]* *.* *${epfd}u *a_inode *[0-9]*,[0-9]* *[0-9]* *[0-9]* *\[eventpoll:${evfd0},${evfd1}\]"; then
+       kill $pid
+       exit 0
+    else
+       kill $pid
+       exit 1
+    fi
+}
diff --git a/lib/dialects/linux/tests/case-20-eventfd-endpoint.bash b/lib/dialects/linux/tests/case-20-eventfd-endpoint.bash
new file mode 100755 (executable)
index 0000000..d7d0113
--- /dev/null
@@ -0,0 +1,81 @@
+#!/bin/bash
+source tests/common.bash
+
+uname -r >> $report
+uname -r | sed -ne 's/^\([0-9]\+\)\.\([0-9]\+\)\.\([0-9]\+\).*/\1 \2/p' | {
+    read major minor
+    if [ "$major" -lt 5 ]; then
+       echo "eventfd endpoint features doesn't work on Linux $major, skipping"
+       exit 77
+    fi
+    if [ "$major" -eq 5 -a "$minor" -lt 2 ]; then
+       echo "event endpoint features doesn't work on Linux $major.$minor, skipping"
+       exit 77
+    fi
+} >> $report
+s=$?
+if ! [ $s = 0 ]; then
+    exit $s
+fi
+
+TARGET=$tcasedir/eventfd
+if ! [ -x $TARGET ]; then
+    echo "target executable ( $TARGET ) is not found" >> $report
+    exit 1
+fi
+
+{ $TARGET & } | {
+    read parent child fd
+    if [ -z "$parent" ] || [ -z "$child" ] || [ -z "$fd" ]; then
+       echo "unexpected output form target ( $TARGET )" >> $report
+       exit 1
+    fi
+    {
+       echo parent: $parent
+       echo child: $child
+       echo fd: $fd
+       echo cmdline: "$lsof +E -p "$parent""
+       echo
+       echo PARENT
+       echo
+       $lsof +E -p "$parent"
+       echo
+       echo CHILD
+       echo
+       $lsof +E -p "$child"
+    } >> $report
+    {
+       {
+           echo From the parent side
+           # eventfd 23685 yamato    3u  a_inode   0,13        0    11217 [eventfd:29] 23686,eventfd,3u
+           echo expected pattern: "eventfd *${parent} .* ${fd}u *a_inode .* \[eventfd:[0-9]*\] *${child},eventfd,${fd}u"
+           $lsof +E -p "$parent" |
+               grep -q "eventfd *${parent} .* ${fd}u *a_inode .* \[eventfd:[0-9]*\] *${child},eventfd,${fd}u"
+       } && {
+           echo From the parent side
+           # eventfd 23686 yamato    3u  a_inode   0,13        0    11217 [eventfd:29] 23685,eventfd,3u
+           echo expected pattern: "eventfd *${child} .* ${fd}u *a_inode .* \[eventfd:[0-9]*\] *${parent},eventfd,${fd}u"
+           $lsof +E -p "$parent" |
+               grep -q "eventfd *${child} .* ${fd}u *a_inode .* \[eventfd:[0-9]*\] *${parent},eventfd,${fd}u"
+
+       } && {
+           echo From the child side
+           # eventfd 23685 yamato    3u  a_inode   0,13        0    11217 [eventfd:29] 23686,eventfd,3u
+           echo expected pattern: "eventfd *${parent} .* ${fd}u *a_inode .* \[eventfd:[0-9]*\] *${child},eventfd,${fd}u"
+           $lsof +E -p "$parent" |
+               grep -q  "eventfd *${parent} .* ${fd}u *a_inode .* \[eventfd:[0-9]*\] *${child},eventfd,${fd}u"
+       } && {
+           echo From the child side
+           # eventfd 23686 yamato    3u  a_inode   0,13        0    11217 [eventfd:29] 23685,eventfd,3u
+           echo expected pattern: "eventfd *${child} .* ${fd}u *a_inode .* \[eventfd:[0-9]*\] *${parent},eventfd,${fd}u"
+           $lsof +E -p "$parent" |
+               grep -q  "eventfd *${child} .* ${fd}u *a_inode .* \[eventfd:[0-9]*\] *${parent},eventfd,${fd}u"
+
+       } && {
+           kill "$child"
+           exit 0
+       }
+    } >> $report
+    kill "$child"
+    exit 1
+}
diff --git a/lib/dialects/linux/tests/case-20-inet-socket-endpoint.bash b/lib/dialects/linux/tests/case-20-inet-socket-endpoint.bash
new file mode 100755 (executable)
index 0000000..a0a652f
--- /dev/null
@@ -0,0 +1,44 @@
+#!/bin/bash
+source tests/common.bash
+
+if [ -z "$(nc -h 2>&1 | grep '\s\-4')" ]; then
+    echo "nc does not support -4 option, skipping" >> $report
+    exit 77
+fi
+
+nc -l -4 127.0.0.1 10000 > /dev/null < /dev/zero &
+server=$!
+sleep 1
+nc -4 -s 127.0.0.2 -p 9999 127.0.0.1 10000 < /dev/zero  > /dev/null &
+client=$!
+
+sleep 1
+
+killBoth()
+{
+    kill -9 $1
+    sleep 1
+    kill -9 $2
+} 2> /dev/null > /dev/null
+
+fclient=/tmp/${name}-client-$$
+$lsof -n -E -P -p $client > $fclient
+if ! cat $fclient | grep -q "TCP 127.0.0.2:9999->127.0.0.1:10000 $server,nc,[0-9]\+u (ESTABLISHED)"; then
+    echo "failed in client side" >> $report
+    cat $fclient >> $report
+    killBoth $client $server
+    exit 1
+fi
+
+fserver=/tmp/${name}-server-$$
+$lsof -n -E -P -p $server > $fserver
+if ! cat $fserver | grep -q "TCP 127.0.0.1:10000->127.0.0.2:9999\+ $client,nc,[0-9]\+u (ESTABLISHED)"; then
+    echo "failed in server side" >> $report
+    cat $fserver >> $report
+    killBoth $client $server
+    exit 1
+fi
+
+killBoth $client $server
+
+exit 0
diff --git a/lib/dialects/linux/tests/case-20-inet6-ffffffff-handling.bash b/lib/dialects/linux/tests/case-20-inet6-ffffffff-handling.bash
new file mode 100755 (executable)
index 0000000..9677b6a
--- /dev/null
@@ -0,0 +1,46 @@
+#!/bin/bash
+source tests/common.bash
+
+if [[ $(id -u) != 0 ]]; then
+    echo "root privileged is needed to run $(basename $0. sh)" >> "${report}"
+    exit 77
+fi
+
+#
+# Derrived from the issue #102 opened by @zhrf2020.
+#
+
+v6addr=abcd:ef10:ffff:ffff:ffff:ffff:ffff:ff62
+port=9999
+dev=lo
+
+if ! ip -6 address add "${v6addr}" dev "${dev}" 2>> "${report}"; then
+    echo "failed to add ipv6 address "${v6addr}" to ${dev}, skipping" >> "${report}"
+    exit 77
+fi
+
+ip -6 address show >> "${report}"
+
+nc -6 -l "${v6addr}" "${port}" 2>> "${report}" &
+pid=$!
+
+sleep 1
+
+expectation="n[${v6addr}]:$port"
+result=1
+if "${lsof}" -p "${pid}" -a -d fd -P -n -F n \
+    | tee -a "${report}" \
+    | fgrep -q "$expectation"; then
+    result=0
+fi
+
+nc -6 "${v6addr}" "${port}" < /dev/null > /dev/null 2>> "${report}"
+sleep 1
+
+ip -6 address delete "${v6addr}" dev "${dev}" 2>> "${report}"
+
+if [[ "${result}" != 0 ]]; then
+    echo "failed to find \"$expectation\" in the outpuf of lsof" >> "${report}"
+fi
+
+exit "${result}"
diff --git a/lib/dialects/linux/tests/case-20-inet6-socket-endpoint.bash b/lib/dialects/linux/tests/case-20-inet6-socket-endpoint.bash
new file mode 100755 (executable)
index 0000000..fbf5cd1
--- /dev/null
@@ -0,0 +1,45 @@
+#!/bin/bash
+source tests/common.bash
+
+nc -l -6 ::1 10000 > /dev/null < /dev/zero 2>> $report &
+server=$!
+sleep 1
+nc -6 -s ::1 -p 9999 ::1 10000 < /dev/zero  > /dev/null 2>> $report &
+client=$!
+sleep 1
+
+if ! kill -0 $server 2>/dev/null; then
+    echo "Maybe ipv6 stack is not available on this system, skipping" >> $report
+    exit 77
+fi
+
+sleep 1
+
+killBoth()
+{
+    kill -9 $1
+    sleep 1
+    kill -9 $2
+} 2> /dev/null > /dev/null
+
+fclient=/tmp/${name}-client-$$
+$lsof -n -E -P -p $client > $fclient
+if ! cat $fclient | grep -q "TCP \[::1\]:9999->\[::1\]:10000 $server,nc,[0-9]\+u (ESTABLISHED)"; then
+    echo "failed in client side" >> $report
+    cat $fclient >> $report
+    killBoth $client $server
+    exit 1
+fi
+
+fserver=/tmp/${name}-server-$$
+$lsof -n -E -P -p $server > $fserver
+if ! cat $fserver | grep -q "TCP \[::1\]:10000->\[::1\]:9999\+ $client,nc,[0-9]\+u (ESTABLISHED)"; then
+    echo "failed in server side" >> $report
+    cat $fserver >> $report
+    killBoth $client $server
+    exit 1
+fi
+
+killBoth $client $server
+
+exit 0
diff --git a/lib/dialects/linux/tests/case-20-mmap.bash b/lib/dialects/linux/tests/case-20-mmap.bash
new file mode 100755 (executable)
index 0000000..99a7f0c
--- /dev/null
@@ -0,0 +1,59 @@
+#!/bin/bash
+source tests/common.bash
+
+cleanup()
+{
+    if [ -n "$(mount | grep "tmp\/ext4.img" | grep -v grep)" ]
+    then
+        umount /tmp/ext4.img
+    fi
+    
+    if [ -f /tmp/ext4.img ]
+    then
+        rm -f /tmp/ext4.img
+    fi
+    
+    if [ -d /tmp/TEST ]
+    then
+        rm -rf /tmp/TEST
+    fi
+    
+    pidlist=`ps aux | grep "TEST\/MMAP" | grep -v grep | awk '{print $2}'`
+    for pid in $pidlist
+    do
+        kill -9 $pid
+    done
+}
+
+# cleanup the environment
+cleanup
+
+# create a new namespace and mmap
+output=$(unshare --mount --propagation private $3/mount-and-mmap.bash $@ 2>&1)
+echo "$output" >> $report
+if echo "$output" | grep -q 'Operation not permitted'; then
+    echo "unshare is not supported on this platform, skipping" >> $report
+    exit 77
+fi
+
+# get pid of the mmap process
+pid=`ps aux | grep "TEST\/MMAP" | grep -v grep | awk '{print $2}'`
+if [ -z "$pid" ]
+then
+    echo "mmap process does not exist" >> $report
+    cleanup
+    exit 1
+fi
+
+# lsof -p pid and obtain the output
+output=`$lsof -p $pid | grep "TEST\/MMAP" | grep "stat: No such file or directory"`
+
+if [ -z "$output" ]
+then
+    cleanup
+    exit 0
+else
+    echo "unexpected output: $output" >> $report
+    cleanup
+    exit 1
+fi
diff --git a/lib/dialects/linux/tests/case-20-mqueue-endpoint.bash b/lib/dialects/linux/tests/case-20-mqueue-endpoint.bash
new file mode 100755 (executable)
index 0000000..a5613c5
--- /dev/null
@@ -0,0 +1,90 @@
+#!/bin/bash
+source tests/common.bash
+
+MQUEUE_MNTPOINT=/tmp/$$
+
+TARGET=$tcasedir/mq_fork
+if ! [ -x $TARGET ]; then
+    echo "target executable ( $TARGET ) is not found" >> $report
+    exit 1
+fi
+
+if grep -q mqueue /proc/mounts; then
+    :
+elif ! [ $(id -u) = 0 ]; then
+    echo "root privileged is needed to run $(basename $0 .sh), skipping" >> $report
+    exit 77
+else
+    mkdir -p ${MQUEUE_MNTPOINT}
+    if ! mount -t mqueue none ${MQUEUE_MNTPOINT}; then
+       echo "failed to mount mqueue file system, skipping"
+       exit 77
+    fi
+fi
+
+umount_mqueue()
+{
+    if [ -d ${MQUEUE_MNTPOINT} ]; then
+       umount ${MQUEUE_MNTPOINT}
+       rmdir ${MQUEUE_MNTPOINT}
+    fi
+}
+
+mqname=/lsof-$name-$$
+{ $TARGET $mqname & } | {
+    read parent child fd
+    if [ -z "$parent" ] || [ -z "$child" ] || [ -z "$fd" ]; then
+       echo "unexpected output form target ( $TARGET )" >> $report
+       umount_mqueue
+       exit 1
+    fi
+    {
+       echo mqname: $mqname
+       echo parent: $parent
+       echo child:  $child
+       echo fd:    $fd
+       echo cmdline: "$lsof +E -p "$parent""
+       echo
+       echo PARENT
+       echo
+       $lsof +E -p "$parent"
+       echo
+       echo CHILD
+       echo
+       $lsof +E -p "$child"
+    } >> $report
+    {
+       {
+           echo From the parent side
+           # mq_fork 18020 yamato    3u  PSXMQ   0,18       80     622461 /xxx 18021,mq_fork,3u
+           echo expected pattern: "mq_fork *$parent .* ${fd}u *PSXMQ .* $mqname $child,mq_fork,${fd}u"
+           $lsof +E -p "$parent" |
+               grep -q "mq_fork *${parent} .* ${fd}u *PSXMQ .* ${mqname} ${child},mq_fork,${fd}u"
+       } && {
+           echo From the parent side
+           # mq_fork 18021 yamato    3u  PSXMQ   0,18       80     622461 /xxx 18020,mq_fork,3u
+           echo expected pattern: "mq_fork *$child .* ${fd}u *PSXMQ .* $mqname $parent,mq_fork,${fd}u"
+           $lsof +E -p "$parent" |
+               grep -q "mq_fork *${child} .* ${fd}u *PSXMQ .* ${mqname} ${parent},mq_fork,${fd}u"
+       } && {
+           echo From the child side
+           # mq_fork 18021 yamato    3u  PSXMQ   0,18       80     622461 /xxx 18020,mq_fork,3u
+           echo expected pattern: "mq_fork *$child .* ${fd}u *PSXMQ .* $mqname $parent,mq_fork,${fd}u"
+           $lsof +E -p "$child" |
+               grep -q "mq_fork *${child} .* ${fd}u *PSXMQ .* ${mqname} ${parent},mq_fork,${fd}u"
+       } && {
+           echo From the child side
+           # mq_fork 18020 yamato    3u  PSXMQ   0,18       80     622461 /xxx 18021,mq_fork,3u
+           echo expected pattern: "mq_fork *$parent .* ${fd}u *PSXMQ .* $mqname $child,mq_fork,${fd}u"
+           $lsof +E -p "$child" |
+               grep -q "mq_fork *${parent} .* ${fd}u *PSXMQ .* ${mqname} ${child},mq_fork,${fd}u"
+       } && {
+           kill "$child"
+           umount_mqueue
+           exit 0
+       }
+    } >> $report
+    kill "$child"
+    umount_mqueue
+    exit 1
+}
diff --git a/lib/dialects/linux/tests/case-20-open-flags-cx.bash b/lib/dialects/linux/tests/case-20-open-flags-cx.bash
new file mode 100755 (executable)
index 0000000..26cf413
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/bash
+source tests/common.bash
+
+pat=".*DIR[ \t]\+.*CX.*[ \t]\+.*/tmp$"
+source $tcasedir/util-open-flags.bash "$lsof" "$report" "$tcasedir" "$dialect" "$pat" /tmp cx
diff --git a/lib/dialects/linux/tests/case-20-open-flags-path.bash b/lib/dialects/linux/tests/case-20-open-flags-path.bash
new file mode 100755 (executable)
index 0000000..4bc6c2d
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/bash
+source tests/common.bash
+
+pat=".*DIR[ \t]\+.*PATH.*[ \t]\+.*/tmp$"
+source $tcasedir/util-open-flags.bash "$lsof" "$report" "$tcasedir" "$dialect" "$pat" /tmp path
diff --git a/lib/dialects/linux/tests/case-20-open-flags-tmpf.bash b/lib/dialects/linux/tests/case-20-open-flags-tmpf.bash
new file mode 100755 (executable)
index 0000000..7e17e07
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/bash
+source tests/common.bash
+
+pat=".*REG[ \t]\+.*TMPF.*/tmp/.*$"
+source $tcasedir/util-open-flags.bash "$lsof" "$report" "$tcasedir" "$dialect" "$pat" /tmp tmpf rdwr
diff --git a/lib/dialects/linux/tests/case-20-pidfd-pid.bash b/lib/dialects/linux/tests/case-20-pidfd-pid.bash
new file mode 100755 (executable)
index 0000000..fe439e5
--- /dev/null
@@ -0,0 +1,24 @@
+#!/bin/bash
+source tests/common.bash
+
+TARGET=$tcasedir/pidfd
+
+{
+$TARGET | (
+    read pid fd
+    if [[ $pid = -1 && $fd = -1 ]]; then
+        echo "pidfd is not available on this platform, skipping"
+        exit 77
+    fi
+    line=$($lsof -p $pid -a -d $fd -F pfn| tr '\n' ' ')
+    if ! fgrep -q "p${pid} f${fd} n[pidfd:$pid]" <<<"$line"; then
+       $lsof -p $pid -a -d $fd -F pfn
+       echo
+       echo $line
+       echo
+       r=1
+    fi
+    kill $pid
+    exit $r
+)
+} >> $report 2>&1
diff --git a/lib/dialects/linux/tests/case-20-pipe-endpoint.bash b/lib/dialects/linux/tests/case-20-pipe-endpoint.bash
new file mode 100755 (executable)
index 0000000..77d3ddc
--- /dev/null
@@ -0,0 +1,39 @@
+#!/bin/bash
+source tests/common.bash
+
+TARGET=$tcasedir/pipe
+if ! [ -x $TARGET ]; then
+    echo "target executable ( $TARGET ) is not found" >> $report
+    exit 1
+fi
+
+{ $TARGET & } | {
+    read parent child fdr fdw;
+    if [ -z "$parent" ] || [ -z "$child" ] || [ -z "$fdr" ] || [ -z "$fdw" ]; then
+       echo "unexpected output form target ( $TARGET )" >> $report
+       exit 1
+    fi
+    echo parent: $parent >> $report
+    echo child:  $child >> $report
+    echo fdr:    $fdr >> $report
+    echo fdw:    $fdw >> $report
+    echo cmdline: "$lsof +E -p "$parent"" >> $report
+    $lsof +E -p "$parent" >> $report
+
+    {
+       {
+           echo expected pattern: ".* $parent .* ${fdr}r *FIFO .* pipe ${child},p[-a-z]*,${fdw}w"
+           $lsof +E -p "$parent" |
+               grep -q ".* $parent .* ${fdr}r *FIFO .* pipe ${child},p[-a-z]*,${fdw}w"
+       } && {
+           echo expected parent: ".* $child .* ${fdw}w *FIFO .* pipe ${parent},p[-a-z]*,${fdr}r"
+           $lsof +E -p "$parent" |
+               grep -q ".* $child .* ${fdw}w *FIFO .* pipe ${parent},p[-a-z]*,${fdr}r"
+       } && {
+           kill "$child"
+           exit 0
+       }
+    } >> $report
+    kill "$child"
+    exit 1
+}
diff --git a/lib/dialects/linux/tests/case-20-pipe-no-close-endpoint.bash b/lib/dialects/linux/tests/case-20-pipe-no-close-endpoint.bash
new file mode 100755 (executable)
index 0000000..7529300
--- /dev/null
@@ -0,0 +1,51 @@
+#!/bin/bash
+source tests/common.bash
+
+TARGET=$tcasedir/pipe
+if ! [ -x $TARGET ]; then
+    echo "target executable ( $TARGET ) is not found" >> $report
+    exit 1
+fi
+
+{ $TARGET no-close & } | {
+    read parent child fdr fdw;
+    if [ -z "$parent" ] || [ -z "$child" ] || [ -z "$fdr" ] || [ -z "$fdw" ]; then
+       echo "unexpected output form target ( $TARGET )" >> $report
+       exit 1
+    fi
+    echo parent: $parent >> $report
+    echo child:  $child >> $report
+    echo fdr:    $fdr >> $report
+    echo fdw:    $fdw >> $report
+    echo cmdline: "$lsof +E -p "$parent"" >> $report
+    $lsof +E -p "$parent" >> $report
+
+    {
+       {
+           # pipe-no-c 25113 yamato    3r  FIFO   0,12      0t0     616532 pipe 25113,pipe-no-c,4w 25114,pipe-no-c,3r 25114,pipe-no-c,4w
+           echo expected pattern: ".* $parent .* ${fdr}r *FIFO .* pipe ${parent},p[-a-z]*,${fdw}w ${child},p[-a-z]*,${fdr}r ${child},p[-a-z]*,${fdw}w"
+           $lsof +E -p "$parent" |
+               grep -q ".* $parent .* ${fdr}r *FIFO .* pipe ${parent},p[-a-z]*,${fdw}w ${child},p[-a-z]*,${fdr}r ${child},p[-a-z]*,${fdw}w"
+       } && {
+           # pipe-no-c 25113 yamato    4w  FIFO   0,12      0t0     616532 pipe 25113,pipe-no-c,3r 25114,pipe-no-c,3r 25114,pipe-no-c,4w
+           echo expected pattern: ".* $parent .* ${fdw}w *FIFO .* pipe ${parent},p[-a-z]*,${fdr}r ${child},p[-a-z]*,${fdr}r ${child},p[-a-z]*,${fdw}w"
+           $lsof +E -p "$parent" |
+               grep -q ".* $parent .* ${fdw}w *FIFO .* pipe ${parent},p[-a-z]*,${fdr}r ${child},p[-a-z]*,${fdr}r ${child},p[-a-z]*,${fdw}w"
+       } && {
+           # pipe-no-c 25114 yamato    3r  FIFO   0,12      0t0     616532 pipe 25113,pipe-no-c,3r 25113,pipe-no-c,4w 25114,pipe-no-c,4w
+           echo expected pattern: ".* $child .* ${fdr}r *FIFO .* pipe ${parent},p[-a-z]*,${fdr}r ${parent},p[-a-z]*,${fdw}w ${child},p[-a-z]*,${fdw}w"
+           $lsof +E -p "$parent" |
+               grep -q ".* $child .* ${fdr}r *FIFO .* pipe ${parent},p[-a-z]*,${fdr}r ${parent},p[-a-z]*,${fdw}w ${child},p[-a-z]*,${fdw}w"
+       } && {
+           # pipe-no-c 25114 yamato    4w  FIFO   0,12      0t0     616532 pipe 25113,pipe-no-c,3r 25113,pipe-no-c,4w 25114,pipe-no-c,3r
+           echo expected parent: ".* $child .* ${fdw}w *FIFO .* pipe ${parent},p[-a-z]*,${fdr}r ${parent},p[-a-z]*,${fdw}w ${child},p[-a-z]*,${fdr}r"
+           $lsof +E -p "$parent" |
+               grep -q ".* $child .* ${fdw}w *FIFO .* pipe ${parent},p[-a-z]*,${fdr}r ${parent},p[-a-z]*,${fdw}w ${child},p[-a-z]*,${fdr}r"
+       } && {
+           kill $child
+           exit 0
+       }
+    } >> $report
+    kill $child
+    exit 1
+}
diff --git a/lib/dialects/linux/tests/case-20-pty-endpoint.bash b/lib/dialects/linux/tests/case-20-pty-endpoint.bash
new file mode 100755 (executable)
index 0000000..21e2660
--- /dev/null
@@ -0,0 +1,75 @@
+#!/bin/bash
+source tests/common.bash
+
+uname -r >> $report
+uname -r | sed -ne 's/^\([0-9]\+\)\.\([0-9]\+\)\.\([0-9]\+\).*/\1 \2/p' | {
+    read major minor
+    if [ "$major" -lt 4 ]; then
+       echo "pty endpoint features doesn't work on Linux $major, skipping"
+       exit 77
+    fi
+    if [ "$major" -eq 4 -a "$minor" -lt 13 ]; then
+       echo "pty endpoint features doesn't work on Linux $major.$minor, skipping"
+       exit 77
+    fi
+} >> $report
+s=$?
+if ! [ $s = 0 ]; then
+    exit $s
+fi
+
+TARGET=$tcasedir/pty
+if ! [ -x $TARGET ]; then
+    echo "target executable ( $TARGET ) is not found" >> $report
+    exit 1
+fi
+
+{ $TARGET & } | {
+    read parent child fdm fds names;
+    if [ -z "$parent" ] || [ -z "$child" ] || [ -z "$fdm" ] || [ -z "$fds" ] || [ -z "$names" ]; then
+       echo "unexpected output form target ( $TARGET )" >> $report
+       exit 1
+    fi
+    {
+       echo parent: $parent
+       echo child:  $child
+       echo fdm:    $fdm
+       echo fds:    $fds
+       echo nams:   $names
+       echo cmdline: "$lsof +E -p $parent"
+    } >> $report
+    $lsof +E -p "$parent" >> $report
+    {
+       {
+           # pty     17592 yamato    3r   CHR    5,2      0t0       1129 /dev/ptmx ->/dev/pts/16 17592,pty,4r 17593,pty,3r
+           echo expected pattern: "pty *$parent .* ${fdm}r *CHR .* /dev/(pts/)?ptmx ->/dev/pts/$names ($parent,pty,${fds}r $child,pty,${fdm}r)|($child,pty,${fdm}r $parent,pty,${fds}r)"
+           $lsof +E -p "$parent" |
+               grep -E -q "pty *$parent .* ${fdm}r *CHR .* /dev/(pts/)?ptmx ->/dev/pts/$names ($parent,pty,${fds}r $child,pty,${fdm}r)|($child,pty,${fdm}r $parent,pty,${fds}r)"
+       } && {
+           # pty     17592 yamato    4r   CHR 136,16      0t0         19 /dev/pts/16 17592,pty,3r
+           echo expected pattern: "pty *$parent .* ${fds}r *CHR .* /dev/pts/$names $parent,pty,${fdm}r"
+           $lsof +E -p "$parent" |
+               grep -E -q "pty *$parent .* ${fds}r *CHR .* /dev/pts/$names $parent,pty,${fdm}r"
+       } && {
+           # pty     17593 yamato    3r   CHR 136,16      0t0         19 /dev/pts/16 17592,pty,3r
+           echo expected pattern: "pty *$child .* ${fdm}r *CHR .* /dev/pts/$names $parent,pty,${fdm}r"
+           $lsof +E -p "$parent" |
+               grep -E -q "pty *$child .* ${fdm}r *CHR .* /dev/pts/$names $parent,pty,${fdm}r"
+       } && {
+           # pty     17592 yamato    3r   CHR    5,2      0t0       1129 /dev/ptmx ->/dev/pts/16 17592,pty,4r 17593,pty,3r
+           echo expected pattern: "pty *$parent .* ${fdm}r *CHR .* /dev/(pts/)?ptmx ->/dev/pts/$names ($parent,pty,${fds}r $child,pty,${fdm}r)|($child,pty,${fdm}r $parent,pty,${fds}r)"
+           $lsof +E -p "$child" |
+               grep -E -q "pty *$parent .* ${fdm}r *CHR .* /dev/(pts/)?ptmx ->/dev/pts/$names ($parent,pty,${fds}r $child,pty,${fdm}r)|($child,pty,${fdm}r $parent,pty,${fds}r)"
+       } && {
+           # pty     17593 yamato    3r   CHR 136,16      0t0         19 /dev/pts/16 17592,pty,3r
+           echo expected pattern: "pty *$child .* ${fdm}r *CHR .* /dev/pts/$names $parent,pty,${fdm}r"
+           $lsof +E -p "$child" |
+               grep -E -q "pty *$child .* ${fdm}r *CHR .* /dev/pts/$names $parent,pty,${fdm}r"
+       } && {
+           kill "$child"
+           exit 0
+       }
+    } >> $report
+    kill "$child"
+    exit 1
+}
diff --git a/lib/dialects/linux/tests/case-20-ux-socket-endpoint-unaccepted.bash b/lib/dialects/linux/tests/case-20-ux-socket-endpoint-unaccepted.bash
new file mode 100755 (executable)
index 0000000..35ba967
--- /dev/null
@@ -0,0 +1,80 @@
+#!/bin/bash
+source tests/common.bash
+
+TARGET=$tcasedir/ux
+
+$TARGET | {
+    #
+    # An example of expect output:
+    #
+    # pid=1451661
+    # connect=4
+    # connect2=5
+    # ppid=1451659
+    # listen=3
+    # accept=5
+    # path=/tmp/lsof-test-ux-1451659.s
+    # end
+    echo "target output:" >> $report
+    while read k v; do
+       if [[ $k = end ]]; then
+           break;
+       fi
+       echo "$k=$v" >> $report
+       eval "$k=$v"
+    done
+    #
+    # An exapmle of lsof output:
+    #
+    # COMMAND     PID USER   FD   TYPE             DEVICE SIZE/OFF     NODE NAME
+    # ux      1445917  jet    3u  unix 0x000000002d21092b      0t0 75849115 /tmp/lsof-test-ux-1445917.s type=STREAM ->INO=75843930 1445919,ux,5u
+    listen_sock_pat="^ux \+${ppid} \+.* \+${listen}u \+unix \+0x[0-9a-f]\+ \+0t0 \+[0-9]\+ \+${path} \+type=STREAM ->INO=[0-9]\+ \+${pid},ux,${connect2}u"'$'
+    # ux      1445917  jet    5u  unix 0x00000000335230a5      0t0 75849117 /tmp/lsof-test-ux-1445917.s type=STREAM ->INO=75843929 1445919,ux,4u
+    accepted_sock_pat="^ux \+${ppid} \+.* \+${accept}u \+unix \+0x[0-9a-f]\+ \+0t0 \+[0-9]\+ \+${path} \+type=STREAM ->INO=[0-9]\+ \+${pid},ux,${connect}u"'$'
+    # ux      1445919  jet    4u  unix 0x00000000627d8ccc      0t0 75843929 type=STREAM ->INO=75849117 1445917,ux,5u
+    client_sock_pat="^ux \+${pid} \+.* \+${connect}u \+unix \+0x[0-9a-f]\+ \+0t0 \+[0-9]\+ \+type=STREAM ->INO=[0-9]\+ \+${ppid},ux,${accept}u"'$'
+    # ux      1445919  jet    5u  unix 0x00000000cc000ead      0t0 75843930 type=STREAM
+    client2_sock_pat="^ux \+${pid} \+.* \+${connect2}u \+unix \+0x[0-9a-f]\+ \+0t0 \+[0-9]\+ \+type=STREAM"'$'
+    # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    # The last line reflects what unix-diagnose netlink socket reports. The counter part just queued in the listen socket,
+    # and is not accepted yet.
+    #
+    out=/tmp/${name}-$$
+    if $lsof +E $path > $out; then
+       kill -CONT $ppid
+       if [[ $(wc -l < $out) != $(( 1 + 4 )) ]]; then
+           echo "Too many file descriptors are found (the expection is 4 but got $(wc -l < $out)):" >> $report
+           cat $out >> $report
+           rm $out
+           exit 1
+       elif ! grep -q "$listen_sock_pat" < $out; then
+           echo "don't match the pattern for listen socket" >> $report
+           echo "expected pattern: $listen_sock_pat" >> $report
+           cat $out >> $report
+           rm $out
+           exit 1
+       elif ! grep -q "$accepted_sock_pat" < $out; then
+           echo "don't match the pattern for accepted socket" >> $report
+           echo "expected pattern: $accepted_sock_pat" >> $report
+           cat $out >> $report
+           rm $out
+           exit 1
+       elif ! grep -q "$client_sock_pat" < $out; then
+           echo "don't match the pattern for the 1st client socket" >> $report
+           echo "expected pattern: $client_sock_pat" >> $report
+           cat $out >> $report
+           rm $out
+           exit 1
+       elif ! grep -q "$client2_sock_pat" < $out; then
+           echo "don't match the pattern for the 2nd client socket" >> $report
+           echo "expected pattern: $client2_sock_pat" >> $report
+           cat $out >> $report
+           rm $out
+           exit 1
+       fi
+    else
+       echo "failed to run lsof: $?" >> $report
+       exit 1
+    fi
+}
+exit 0
diff --git a/lib/dialects/linux/tests/case-20-ux-socket-endpoint.bash b/lib/dialects/linux/tests/case-20-ux-socket-endpoint.bash
new file mode 100755 (executable)
index 0000000..50acf13
--- /dev/null
@@ -0,0 +1,45 @@
+#!/bin/bash
+source tests/common.bash
+
+if [ -z "$(nc -h 2>&1 | grep '\-U')" ]; then
+    echo "nc does not support unix socket, skipping" >> $report
+    exit 77
+fi
+
+ux=/tmp/$name-$$.sock
+nc -l -U $ux > /dev/null < /dev/zero &
+server=$!
+sleep 1
+nc -U $ux < /dev/zero  > /dev/null &
+client=$!
+
+sleep 1
+
+killBoth()
+{
+    kill -9 $1
+    sleep 1
+    kill -9 $2
+} 2> /dev/null > /dev/null
+
+fclient=/tmp/${name}-client-$$
+$lsof -n -E -P -p $client > $fclient
+if ! cat $fclient | grep -q "^.* unix 0x[0-9a-f]\+ \+0t0 \+[0-9]\+ type=STREAM ->INO=[0-9]\+ $server,nc,[0-9]\+u"; then
+    echo "failed in client side" >> $report
+    cat $fclient >> $report
+    killBoth $client $server
+    exit 1
+fi
+
+fserver=/tmp/${name}-server-$$
+$lsof -n -E -P -p $server > $fserver
+if ! cat $fserver | grep -q "^.* unix 0x[0-9a-f]\+ \+0t0 \+[0-9]\+ $ux type=STREAM ->INO=[0-9]\+ $client,nc,[0-9]\+u"; then
+    echo "failed in server side" >> $report
+    cat $fserver >> $report
+    killBoth $client $server
+    exit 1
+fi
+
+killBoth $client $server
+
+exit 0
diff --git a/lib/dialects/linux/tests/epoll.c b/lib/dialects/linux/tests/epoll.c
new file mode 100644 (file)
index 0000000..4f68e73
--- /dev/null
@@ -0,0 +1,49 @@
+#include <stdio.h>
+#include <sys/epoll.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+int main(int argc, char **argv) {
+    int epfd = epoll_create(1);
+    if (epfd < 0) {
+        perror("epoll_create");
+        return 1;
+    }
+
+    int pipefd[2];
+    if (pipe(pipefd) < 0) {
+        perror("pipe");
+        return 1;
+    }
+
+    int evfd[2];
+    if ((evfd[0] = dup(pipefd[0])) < 0) {
+        perror("dup(pipefd[0])");
+        return 1;
+    }
+    if ((evfd[1] = dup(pipefd[1])) < 0) {
+        perror("dup(pipefd[1])");
+        return 1;
+    }
+
+    struct epoll_event ev;
+    ev.events = EPOLLOUT;
+    ev.data.fd = evfd[1];
+    if (epoll_ctl(epfd, EPOLL_CTL_ADD, ev.data.fd, &ev) < 0) {
+        perror("epoll_ctl<evfd[1]>");
+        return 1;
+    }
+
+    ev.events = EPOLLIN;
+    ev.data.fd = evfd[0];
+    if (epoll_ctl(epfd, EPOLL_CTL_ADD, ev.data.fd, &ev) < 0) {
+        perror("epoll_ctl<evfd[0]>");
+        return 1;
+    }
+
+    printf("%d %d %d %d\n", getpid(), epfd, evfd[0], evfd[1]);
+    fflush(stdout);
+    pause();
+    return 0;
+}
diff --git a/lib/dialects/linux/tests/eventfd.c b/lib/dialects/linux/tests/eventfd.c
new file mode 100644 (file)
index 0000000..12a5c11
--- /dev/null
@@ -0,0 +1,29 @@
+#include <sys/eventfd.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+
+static int fd = -1;
+
+int main(int argc, char **argv) {
+    fd = eventfd(0, 0);
+    if (fd < 0) {
+        perror("eventfd");
+        return -1;
+    }
+
+    pid_t pid = fork();
+    if (pid < 0) {
+        perror("fork");
+        return -1;
+    } else if (pid == 0) {
+        pause();
+    } else {
+        printf("%d %d %d\n", getpid(), pid, fd);
+        fflush(stdout);
+        wait(NULL);
+    }
+    return 0;
+}
diff --git a/lib/dialects/linux/tests/mmap.c b/lib/dialects/linux/tests/mmap.c
new file mode 100644 (file)
index 0000000..b7e47e5
--- /dev/null
@@ -0,0 +1,35 @@
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define handle_error(msg)                                                      \
+    do {                                                                       \
+        perror(msg);                                                           \
+        exit(EXIT_FAILURE);                                                    \
+    } while (0)
+
+int main(int argc, char *argv[]) {
+    char *addr;
+    int fd;
+    struct stat sb;
+
+    if (argc != 2)
+        exit(EXIT_FAILURE);
+
+    fd = open(argv[1], O_RDONLY);
+    if (fd == -1)
+        handle_error("open");
+
+    if (fstat(fd, &sb) == -1)
+        handle_error("fstat");
+
+    addr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+    if (addr == MAP_FAILED)
+        handle_error("mmap");
+
+    pause();
+    return 0;
+}
diff --git a/lib/dialects/linux/tests/mount-and-mmap.bash b/lib/dialects/linux/tests/mount-and-mmap.bash
new file mode 100755 (executable)
index 0000000..2eebacc
--- /dev/null
@@ -0,0 +1,20 @@
+#!/bin/sh
+set -e
+
+lsof=$1
+report=$2
+tdir=$3
+
+TARGET=$tdir/mmap
+if ! [ -x $TARGET ]; then
+    echo "target executable ( $TARGET ) is not found" >> $report
+    exit 1
+fi
+
+mkdir /tmp/TEST
+dd if=/dev/zero of=/tmp/ext4.img bs=40MB count=1
+mkfs.ext4 /tmp/ext4.img
+mount --make-private /tmp/ext4.img /tmp/TEST
+
+dd if=/dev/zero of=/tmp/TEST/MMAP bs=2MB count=1
+$TARGET /tmp/TEST/MMAP &
diff --git a/lib/dialects/linux/tests/mq_fork.c b/lib/dialects/linux/tests/mq_fork.c
new file mode 100644 (file)
index 0000000..2bcb991
--- /dev/null
@@ -0,0 +1,43 @@
+#include <fcntl.h>    /* For O_* constants */
+#include <sys/stat.h> /* For mode constants */
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <mqueue.h>
+#include <unistd.h>
+#include <stdio.h>
+
+int main(int argc, char **argv) {
+    int pid;
+    char *fname;
+
+    if (argc != 2) {
+        fprintf(stderr, "wrong number of arguments: %d\n", argc);
+        return 1;
+    } else if (argv[1][0] != '/') {
+        fprintf(stderr, "name must starts with '/': %c\n", argv[1][0]);
+        return 1;
+    }
+
+    fname = argv[1];
+    mqd_t t = mq_open(fname, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR, NULL);
+    ;
+
+    if (t == -1) {
+        perror("mq_open");
+        return 1;
+    }
+
+    pid = fork();
+    if (pid == 0)
+        pause();
+    else if (pid > 0) {
+        printf("%d %d %d\n", getpid(), pid, t);
+        fflush(stdout);
+        wait(NULL);
+        mq_unlink(fname);
+    } else {
+        perror("fork");
+        return 1;
+    }
+    return 0;
+}
diff --git a/lib/dialects/linux/tests/mq_open.c b/lib/dialects/linux/tests/mq_open.c
new file mode 100644 (file)
index 0000000..c818fce
--- /dev/null
@@ -0,0 +1,24 @@
+#include <fcntl.h>    /* For O_* constants */
+#include <sys/stat.h> /* For mode constants */
+#include <mqueue.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <signal.h>
+
+#define NAME "/xxx"
+
+static void do_nothing(int n) { signal(SIGCONT, do_nothing); }
+
+int main(void) {
+    mqd_t t = mq_open(NAME, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR, NULL);
+    if ((mqd_t)t == -1) {
+        perror("open[" NAME "]");
+        return 1;
+    }
+
+    printf("pid: %d / fd: %d\n", getpid(), t);
+    fflush(stdout);
+    signal(SIGCONT, do_nothing);
+    pause();
+    return 0;
+}
diff --git a/lib/dialects/linux/tests/open_with_flags.c b/lib/dialects/linux/tests/open_with_flags.c
new file mode 100644 (file)
index 0000000..01d6316
--- /dev/null
@@ -0,0 +1,63 @@
+#define _GNU_SOURCE
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdio.h>
+
+struct {
+    const char *name;
+    int flag;
+} table[] = {
+    {"path", O_PATH},
+    {"cx", O_CLOEXEC},
+    {"tmpf", O_TMPFILE},
+    {"rdwr", O_RDWR},
+};
+
+#define TABLELEN sizeof(table) / sizeof(table[0])
+
+static int encode(const char *const s) {
+    for (int i = 0; i < TABLELEN; i++)
+        if (!strcmp(s, table[i].name))
+            return table[i].flag;
+    return 0;
+}
+
+static void print_usage(FILE *fp, const char *const prog) {
+    fprintf(fp, "Usage:\n");
+    fprintf(fp, "      %s FILENAME FLAG ...\n", prog);
+    fprintf(fp, "Flags:\n");
+    for (int i = 0; i < TABLELEN; i++)
+        fprintf(fp, "  %s\n", table[i].name);
+}
+
+int main(int argc, char **argv) {
+
+    if (argc < 3) {
+        fprintf(stderr, "Too few argument\n");
+        print_usage(stderr, argv[0]);
+        return 1;
+    }
+
+    char *fname = argv[1];
+    int flags = 0;
+
+    for (int i = 2; i < argc; i++)
+        flags |= encode(argv[i]);
+
+    int fd = open(fname, flags, 0644);
+    if (fd < 0) {
+        perror("open");
+        return 1;
+    }
+
+    printf("%d\n", getpid());
+    fflush(stdout);
+    pause();
+    return 0;
+}
diff --git a/lib/dialects/linux/tests/pidfd.c b/lib/dialects/linux/tests/pidfd.c
new file mode 100644 (file)
index 0000000..b5660c3
--- /dev/null
@@ -0,0 +1,26 @@
+#define _GNU_SOURCE
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+
+#ifndef __NR_pidfd_open
+#    define __NR_pidfd_open 434 /* System call # on most architectures */
+#endif
+
+int main(void) {
+    pid_t self = getpid();
+    int pidfd = syscall(__NR_pidfd_open, self, 0);
+    if (pidfd < 0) {
+        if (errno == ENOSYS) {
+            printf("%d %d\n", -1, -1);
+        }
+        perror("pidfd_open");
+        return 1;
+    }
+    printf("%d %d\n\n\n", self, pidfd);
+    fclose(stdout);
+    pause();
+    return 0;
+}
diff --git a/lib/dialects/linux/tests/pipe.c b/lib/dialects/linux/tests/pipe.c
new file mode 100644 (file)
index 0000000..7ec1726
--- /dev/null
@@ -0,0 +1,41 @@
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+
+int main(int argc, char **argv) {
+    int no_close = 0;
+
+    if (argc > 1 && strcmp(argv[1], "no-close") == 0)
+        no_close = 1;
+
+    int pd[2];
+
+    if (pipe(pd) < 0) {
+        perror("pipe");
+        return 1;
+    }
+
+    pid_t self, child;
+
+    self = getpid();
+    child = fork();
+
+    if (child == 0) {
+        if (!no_close)
+            close(pd[0]);
+        pause();
+        return 0;
+    } else if (child < 0) {
+        perror("fork");
+        return 1;
+    }
+
+    if (!no_close)
+        close(pd[1]);
+    printf("%d %d %d %d\n", self, child, pd[0], pd[1]);
+    fflush(stdout);
+    wait(NULL);
+    return 0;
+}
diff --git a/lib/dialects/linux/tests/pty.c b/lib/dialects/linux/tests/pty.c
new file mode 100644 (file)
index 0000000..42eb88a
--- /dev/null
@@ -0,0 +1,48 @@
+#include <fcntl.h>
+#include <stdio.h>
+#include <err.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+int main(void) {
+    int tfd[2];
+    int s;
+
+    if ((tfd[0] = open("/dev/ptmx", O_RDONLY)) < 0)
+        err(1, "failed to open ptmx");
+
+    int unlock = 0;
+    if (ioctl(tfd[0], TIOCSPTLCK, &unlock) < 0)
+        err(1, "failed to do ioctl TIOCSPTLCK");
+
+    if (ioctl(tfd[0], TIOCGPTN, &s) < 0)
+        err(1, "failed to do ioctl TIOCGPTN");
+
+    char slave_name[128];
+    snprintf(slave_name, 128, "/dev/pts/%d", s);
+    if ((tfd[1] = open(slave_name, O_RDONLY)) < 0)
+        err(1, "failed to open %s", slave_name);
+
+    pid_t self, child;
+    self = getpid();
+    child = fork();
+
+    if (child == 0) {
+        if (dup2(tfd[1], tfd[0]) < 0)
+            err(1, "failed to dup2(%d, %d)", tfd[1], tfd[0]);
+        close(tfd[1]);
+        pause();
+        return 0;
+    } else if (child < 0) {
+        perror("fork");
+        return 1;
+    }
+
+    printf("%d %d %d %d %d\n", self, child, tfd[0], tfd[1], s);
+    fflush(stdout);
+    wait(NULL);
+    return 0;
+}
diff --git a/lib/dialects/linux/tests/util-open-flags.bash b/lib/dialects/linux/tests/util-open-flags.bash
new file mode 100644 (file)
index 0000000..5e06399
--- /dev/null
@@ -0,0 +1,44 @@
+source tests/common.bash
+
+pat=$5
+tfile=$6
+
+shift 6
+
+TARGET=$tcasedir/open_with_flags
+if ! [ -x $TARGET ]; then
+    echo "target executable ( $TARGET ) is not found" >> $report
+    exit 1
+fi
+
+export LC_ALL=C
+
+log=/tmp/$name-$$.log
+$TARGET $tfile "$@" 2>> $log | {
+    read pid
+
+    if  [[ -z "$pid" ]]; then
+        cat $log >> $report
+        # musl prints "Not supported" instead of "Operation not supported"
+        if grep -E -q 'open: (Operation not supported|Not supported)' $log; then
+            echo "a flag passed to open is not supported on this platform, skipping" >> $report
+            exit 77
+        fi
+        echo "unexpected output from target ( $TARGET )" >> $report
+       exit 1
+    fi
+    if ! [ -e "/proc/$pid" ]; then
+        echo "the target process dead unexpectedly" >> $report
+        exit 1
+    fi
+
+    echo "expected: $pat" >> $report
+    echo "lsof output:" >> $report
+    output=$($lsof +fg -p $pid)
+    echo "$output" >> $report
+    echo "$output" | grep -q "$pat"
+    result=$?
+
+    kill $pid
+    exit $result
+}
diff --git a/lib/dialects/linux/tests/ux.c b/lib/dialects/linux/tests/ux.c
new file mode 100644 (file)
index 0000000..bab986d
--- /dev/null
@@ -0,0 +1,133 @@
+#define _POSIX_SOURCE
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <signal.h>
+
+#define TEMPLATE "/tmp/lsof-test-ux-%ld.s"
+
+static void do_nothing(int n) {}
+
+int main(void) {
+    int rendezvous[2];
+    if (pipe(rendezvous) < 0) {
+        perror("pipe");
+        return 1;
+    }
+
+    pid_t pid = fork();
+    if (pid > 0) {
+        close(rendezvous[0]);
+        /* parent: server */
+        int server = socket(AF_UNIX, SOCK_STREAM, 0);
+        if (server < 0) {
+            perror("socket (server)");
+            return 1;
+        }
+        struct sockaddr_un un = {
+            .sun_family = AF_UNIX,
+        };
+        snprintf(un.sun_path, 108, TEMPLATE, (long int)getpid());
+        unlink(un.sun_path);
+
+        if (bind(server, (void *)&un, sizeof(un)) < 0) {
+            perror("bind (server)");
+            return 1;
+        }
+        if (listen(server, 0) < 0) {
+            perror("listen (server)");
+            return 1;
+        }
+
+        char b = 1;
+        if (write(rendezvous[1], &b, 1) < 0) {
+            perror("write rendezvous pipe (server)");
+            return 1;
+        }
+        b++;
+
+        int client;
+        if ((client = accept(server, NULL, 0)) < 0) {
+            perror("listen (server)");
+            return 1;
+        }
+
+        char buf[1024];
+        if (read(client, buf, 1024) < 0) {
+            perror("read (server)");
+            return 1;
+        }
+
+        fputs(buf, stdout);
+        printf("ppid %ld\nlisten %d\naccept %d\npath %s\n", (long int)getpid(),
+               server, client, un.sun_path);
+        fputs("end\n", stdout);
+        fflush(stdout);
+        signal(SIGCONT, do_nothing);
+        pause();
+
+        unlink(un.sun_path);
+        (void)write(rendezvous[1], &b, 1);
+        b++;
+
+        return 0;
+    } else if (pid == 0) {
+        char b;
+        /* child: client */
+        close(rendezvous[1]);
+        if (read(rendezvous[0], &b, 1) < 0) {
+            perror("read rendezvous pipe (client)");
+            /* TODO: kill the parent process. */
+            return 1;
+        }
+
+        int server = socket(AF_UNIX, SOCK_STREAM, 0);
+        if (server < 0) {
+            perror("socket (client)");
+            return 1;
+        }
+
+        struct sockaddr_un un = {
+            .sun_family = AF_UNIX,
+        };
+        snprintf(un.sun_path, 108, TEMPLATE, (long int)getppid());
+        if (connect(server, (void *)&un, sizeof(un)) < 0) {
+            perror("connect (client)");
+            return 1;
+        }
+
+        FILE *serverf = fdopen(server, "w");
+        if (!serverf) {
+            perror("fdopen (client)");
+            return 1;
+        }
+
+        int server2 = socket(AF_UNIX, SOCK_STREAM, 0);
+        if (server2 < 0) {
+            perror("socket (client)");
+            return 1;
+        }
+        if (connect(server2, (void *)&un, sizeof(un)) < 0) {
+            perror("connect (client (server2))");
+            return 1;
+        }
+
+        fprintf(serverf, "pid %ld\nconnect %d\nconnect2 %d\n",
+                (long int)getpid(), server, server2);
+        putc('\0', serverf);
+        fflush(serverf);
+
+        if (read(rendezvous[0], &b, 1) < 0) {
+            perror("read rendezvous pipe (client)");
+            return 1;
+        }
+        return 0;
+    }
+
+    perror("fork");
+    return 1;
+}
diff --git a/lib/dialects/netbsd/Makefile b/lib/dialects/netbsd/Makefile
new file mode 100644 (file)
index 0000000..602673f
--- /dev/null
@@ -0,0 +1,158 @@
+
+# NetBSD Makefile
+#
+# $Id: Makefile,v 1.12 2008/04/15 13:30:14 abe Exp $
+
+PROG=  lsof
+
+BIN=   ${DESTDIR}
+
+DOC=   ${DESTDIR}
+
+I=/usr/include
+S=/usr/include/sys
+L=/usr/include/local
+P=
+
+CDEF=
+CDEFS=  ${CDEF} ${CFGF}
+INCL=  ${DINC} -Iinclude -Ilib -Isrc -I.
+CFLAGS=        ${CDEFS} ${INCL} ${DEBUG}
+
+GRP=
+
+HDR=   lib/common.h include/lsof_fields.h dlsof.h machine.h lib/proto.h dproto.h
+
+SRC=    dmnt.c dnode.c dnode1.c dproc.c dsock.c dstore.c \
+       arg.c main.c node.c print.c ptti.c store.c usage.c \
+       util.c
+
+OBJ=   dmnt.o dnode.o dnode1.o dproc.o dsock.o dstore.o \
+       arg.o main.o node.o print.o ptti.o store.o usage.o \
+       util.o
+
+MAN=   lsof.8
+MANLCL=        lsof.0
+
+OTHER= 
+
+SHELL= /bin/sh
+
+SOURCE=        Makefile ${OTHER} ${MAN} ${HDR} ${SRC}
+
+all: ${PROG}
+
+${MANLCL}: ${MAN}
+       rm -f ${MANLCL}
+       nroff -mandoc -Tlp ${MAN} > ${MANLCL}
+
+${PROG}: ${LIB} ${P} ${OBJ}
+       ${CC} -o $@ ${CFLAGS} ${OBJ} ${CFGL}
+
+clean: FRC
+       rm -f Makefile.bak ${PROG} a.out core *.core errs lint.out tags *.o
+       rm -f machine.h.old new_machine.h version.h
+       (cd lib; ${MAKE} -f Makefile.skel clean)
+
+install: all ${MANLCL} FRC
+       @echo ''
+       @echo 'Please write your own install rule.  Lsof should be installed'
+       @echo 'setgid to the group that can can read /dev/kmem.  Normally'
+       @echo 'that is the kmem group.  Your install rule actions might look'
+       @echo 'something like this:'
+       @echo ''
+       @echo '    install -cs -m 2755 -g $${GRP} $${PROG} $${BIN}/$${PROG}'
+       @echo '    install -c -m 444 $${MANLCL} $${DOC}/$${MANLCL}'
+       @echo ''
+       @echo 'You will have to complete the skeletons for the BIN, DOC, and'
+       @echo 'GRP strings given at the beginning of this Makefile, e.g.,'
+       @echo ''
+       @echo '    BIN= $${DESTDIR}/usr/local/etc'
+       @echo '    DOC= $${DESTDIR}/usr/local/man/man8'
+       @echo '    GRP= kmem'
+       @echo ''
+
+${LIB}: FRC
+       (cd lib; ${MAKE} DEBUG="${DEBUG}" CFGF="${CFGF}")
+
+version.h:     FRC
+       @echo Constructing version.h
+       @rm -f version.h
+       @echo '#define  LSOF_BLDCMT     "${LSOF_BLDCMT}"' > version.h;
+       @echo '#define  LSOF_CC         "${CC}"' >> version.h
+       @echo '#define  LSOF_CCV        "${CCV}"' >> version.h
+       @echo '#define  LSOF_CCFLAGS    "'`echo ${CFLAGS} | sed 's/\\\\(/\\(/g' | sed 's/\\\\)/\\)/g' | sed 's/"/\\\\"/g'`'"' >> 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
+
+dmnt.o:                ${HDR} dmnt.c
+
+dnode.o:       ${HDR} dnode.c
+
+dnode1.o:      ${HDR} dnode1.c
+
+dproc.o:       ${HDR} dproc.c
+
+dsock.o:       ${HDR} dsock.c
+
+dstore.o:      ${HDR} dstore.c
+
+arg.o:         ${HDR} arg.c
+
+main.o:                ${HDR} main.c
+
+misc.o:                ${HDR} misc.c
+
+node.o:                ${HDR} node.c
+
+print.o:       ${HDR} print.c
+
+proc.o:                ${HDR} proc.c
+
+store.o:       ${HDR} store.c
+
+usage.o:       ${HDR} version.h usage.c
+
+util.o:                ${HDR} util.c
+
+# *** Do not add anything here - It will go away. ***
diff --git a/lib/dialects/netbsd/Mksrc b/lib/dialects/netbsd/Mksrc
new file mode 100755 (executable)
index 0000000..0f86dab
--- /dev/null
@@ -0,0 +1,32 @@
+#!/bin/sh
+#
+# Mksrc - make NetBSD source files
+#
+# WARNING: This script assumes it is running from the main directory
+#         of the lsof, version 4 distribution.
+#
+# One environment variable applies:
+#
+# LSOF_MKC     is the method for creating the source files.
+#              It defaults to "ln -s".  A common alternative is "cp".
+#
+# $Id: Mksrc,v 1.5 99/04/15 06:40:37 abe Exp $
+
+mksrc() {
+  for i in $L
+  do
+    rm -f $i
+    $LSOF_MKC $D/$i $i
+    echo "$LSOF_MKC $D/$i $i"
+  done
+}
+
+D=lib/dialects/netbsd
+L="dlsof.h dmnt.c dnode.c dnode1.c dproc.c dproto.h dsock.c dstore.c machine.h"
+
+mksrc
+
+D=src
+L="arg.c main.c node.c print.c ptti.c store.c usage.c util.c"
+
+mksrc
diff --git a/lib/dialects/netbsd/dlsof.h b/lib/dialects/netbsd/dlsof.h
new file mode 100644 (file)
index 0000000..41dd7f2
--- /dev/null
@@ -0,0 +1,573 @@
+/*
+ * dlsof.h - NetBSD header file for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+/*
+ * $Id: dlsof.h,v 1.38 2006/03/28 21:54:08 abe Exp $
+ */
+
+#if !defined(NETBSD_LSOF_H)
+#    define NETBSD_LSOF_H 1
+
+#    include <stdlib.h>
+#    include <dirent.h>
+#    include <nlist.h>
+#    include <paths.h>
+#    include <setjmp.h>
+#    include <signal.h>
+#    include <string.h>
+#    include <unistd.h>
+#    if (!defined(NETBSDV) || __NetBSD_Version__ >= 999001900)
+#        include <sys/ptrace.h> /* pulled in by procfs.h, but needs to be pulled in before _KERNEL is defined */
+#    endif
+
+#    if defined(HASGETBOOTFILE)
+#        include <util.h>
+#    endif /* defined(HASGETBOOTFILE) */
+
+#    include <sys/filedesc.h>
+#    include <sys/mbuf.h>
+
+#    if defined(HAS_LWP_H)
+#        include <sys/lwp.h>
+#    endif /* defined(HAS_LWP_H) */
+
+#    if defined(NETBSDV) && __NetBSD_Version__ >= 106060000
+
+#        if __NetBSD_Version__ < 399001100
+#            define _KERNEL
+#        endif /* __NetBSD_Version__<399001100 */
+
+#        if defined(NETBSDV) && __NetBSD_Version__ < 399001100
+struct buf;    /* dummy for function prototype in <sys/buf.h> */
+struct uio;    /* dummy for function prototype in <sys/buf.h> */
+#        endif /* defined(NETBSDV && __NetBSD_Version__<399001100) */
+
+#        include <sys/ucred.h>
+#    endif /* defined(NETBSDV) && __NetBSD_Version__>=106060000 */
+
+#    if defined(NETBSDV) && __NetBSD_Version__ < 399001100
+#        include <sys/buf.h>
+#    endif /* defined(NETBSDV) && __NetBSD_Version__<399001100 */
+
+#    if defined(NETBSDV) && __NetBSD_Version__ >= 106060000 &&                 \
+        __NetBSD_Version__ < 399001100
+#        undef _KERNEL
+#    endif /* defined(NETBSDV) && __NetBSD_Version__>=106060000                \
+          &&  __NetBSD_Version__<399001100 */
+
+#    define NFS
+#    define m_stat mnt_stat
+
+#    if defined(NETBSDV) && __NetBSD_Version__ >= 106060000
+#        define _KERNEL
+#    endif /* defined(NETBSDV) && __NetBSD_Version__>=106060000 */
+
+#    if defined(NETBSDV) && NETBSDV >= 1003000
+#        define sockproto NETBSD_sockproto
+#    endif /* defined(NETBSDV) && NETBSDV>=1003000 */
+
+#    include <sys/mount.h>
+
+#    if defined(NETBSDV) && __NetBSD_Version__ >= 106060000
+#        undef _KERNEL
+#    endif /* defined(NETBSDV) && __NetBSD_Version__>=106060000 */
+
+#    include <rpc/types.h>
+#    include <sys/protosw.h>
+
+#    include <sys/socket.h>
+
+#    if defined(HASMSDOSFS)
+#        if HASMSDOSFS == 1
+#            include <msdosfs/bpb.h>
+#            include <msdosfs/fat.h>
+#        else /* HASMSDOSFS!=1 */
+#            include <fs/msdosfs/bpb.h>
+#            include <fs/msdosfs/fat.h>
+#        endif /* HASMSDOSFS==1 */
+
+#        if defined(NETBSDV) && __NetBSD_Version__ < 106060000
+/*
+ * The netcred and netexport structures may be needed in the msdosfsmount
+ * structure, defined in <msdosfs/msdosfsmount.h>.  So as a terrible hack,
+ * the lsof Configure script extracts the netcred and netexport structure
+ * definitions from <sys/mount.h> and places them in "netexport.h".
+ *
+ * When needed, the netcred and netexport structures netcred should really
+ * be obtained from <sys/mount.h>.  However they are hidden in <sys/mount.h>
+ * under _KERNEL, and that sometimes can't be defined when including
+ * <sys/mount.h> without causing other seemingly insurmountable #include
+ * problems.
+ *
+ * THIS IS A TERRIBLE AND FRAGILE HACK!!!  It might break if the netexport or
+ * netcred definitions change radically in <sys/mount.h>.
+ *
+ * It is no longer needed for NetBSD Versions 1.6F and above, or for OpenBSD
+ * versions 3.3 and above.
+ */
+
+#            include "netexport.h"
+#        endif /* defined(NETBSDV) && __NetBSD_Version__<106060000 */
+
+#        define _KERNEL
+#        ifndef VFS_PROTOS
+#            define VFS_PROTOS(x)
+#        endif
+struct nameidata; /* to satisfy a function prototype in msdosfsmount.h */
+#        include <msdosfs/msdosfsmount.h>
+#        undef _KERNEL
+#        include <msdosfs/direntry.h>
+#        include <msdosfs/denode.h>
+#    endif /* defined(HASMSDOSFS) */
+
+#    if defined(NETBSDV) && NETBSDV >= 1003000
+#        undef sockproto
+#    endif /* defined(NETBSDV) && NETBSDV>=1003000 */
+
+#    include <sys/socketvar.h>
+#    include <sys/un.h>
+#    include <sys/unpcb.h>
+#    include <net/route.h>
+#    include <netinet/in.h>
+#    include <netinet/in_systm.h>
+#    include <netinet/ip.h>
+
+#    if defined(HASIPv6) && defined(NETBSDV) && !defined(HASINRIAIPv6)
+#        include <netinet/ip6.h>
+#        include <netinet6/in6_pcb.h>
+#    endif /* defined(HASIPv6) && defined(NETBSDV) && !defined(HASINRIAIPv6)   \
+            */
+
+#    include <netinet/in_pcb.h>
+#    include <netinet/ip_var.h>
+#    include <netinet/tcp.h>
+#    include <netinet/tcpip.h>
+#    include <netinet/tcp_fsm.h>
+#    include <netinet/tcp_timer.h>
+#    include <netinet/tcp_var.h>
+
+#    include <sys/ucred.h>
+
+#    if defined(UVM)
+/*
+ * Avoid conflicts with definitions in <vm/vm_param.h>.
+ */
+
+#        undef FALSE
+#        undef TRUE
+#    endif /* defined(UVM) */
+
+#    include <sys/vnode.h>
+
+#    if defined(NETBSDV) && NETBSDV >= 1003000
+/*
+ * Because late in the 1.3I NetBSD development cycle the sockproto structure
+ * was placed under _KERNEL in <sys/socket.h>, and because defining _KERNEL
+ * before #include'ing <sys/socket.h> causes other #include problems, the
+ * sockproto structure definition that might have been in <sys/socket.h> is
+ * renamed NETBSD_sockproto, and the following definition is used instead.
+ *
+ * Ugly, isn't it?
+ */
+
+struct sockproto {
+    u_short sp_family;
+    u_short sp_protocol;
+};
+#    endif /* defined(NETBSDV) && NETBSDV>=1003000 */
+
+#    include <net/raw_cb.h>
+#    include <sys/domain.h>
+#    define pmap RPC_pmap
+#    include <rpc/rpc.h>
+#    include <rpc/pmap_prot.h>
+#    undef pmap
+#    define KERNEL
+#    include <ufs/ufs/quota.h>
+#    if defined(DIRBLKSIZ)
+#        define DIRENT_DIRBLKSIZ DIRBLKSIZ
+#        undef DIRBLKSIZ
+#    endif /* defined(DIRBLKSIZ) */
+
+#    if defined(HASI_FFS1)
+#        define _KERNEL
+#        include <ufs/ufs/ufsmount.h>
+#        undef _KERNEL
+#    endif /* defined(HASI_FFS1) */
+
+#    include <ufs/ufs/inode.h>
+
+#    if defined(DIRENT_BLKSIZ)
+#        define DIRBLKSIZ DIRENT_DIRBLKSIZ
+#        undef DIRENT_DIRBLKSIZ
+#    endif /*defined(DIRENT_BLKSIZ) */
+
+#    if defined(HASBUFQ_H)
+#        if defined(NETBSDV) && NETBSDV >= 2099010
+#            define _KERNEL
+#            include <sys/bufq.h>
+#            undef _KERNEL
+#        endif /* defined(NETBSDV) && NETBSDV>=2099010 */
+#    endif     /* defined(HASBUFQ_H) */
+
+#    undef KERNEL
+#    include <ufs/mfs/mfsnode.h>
+#    if defined(HASTMPFS)
+#        include <fs/tmpfs/tmpfs.h>
+#    endif /* defined(HASTMPFS) */
+
+#    if defined(HASNFSPROTO)
+#        include <nfs/rpcv2.h>
+#        include <nfs/nfsproto.h>
+#    else /* !defined(HASNFSPROTO) */
+#        include <nfs/nfsv2.h>
+#    endif /* defined(HASNFSPROTO) */
+
+#    include <nfs/nfs.h>
+#    include <nfs/nfsnode.h>
+#    include <sys/proc.h>
+#    include <kvm.h>
+#    include <sys/sysctl.h>
+#    if defined(HASKVMGETPROC2)
+#        define P_ADDR p_paddr
+#        define P_COMM p_comm
+#        define P_CWDI p_cwdi
+#        define P_FD p_fd
+#        define P_PID p_pid
+#        define P_PGID p__pgid
+#        define P_PPID p_ppid
+#        define P_STAT p_stat
+#        define P_TRACEP p_tracep
+#        define P_UID p_uid
+#        define P_VMSPACE p_vmspace
+#    else /* !defined(HASKVMGETPROC2) */
+#        define P_ADDR kp_eproc.e_paddr
+#        define P_COMM kp_proc.p_comm
+#        define P_CWDI kp_proc.p_cwdi
+#        define P_FD kp_proc.p_fd
+#        define P_PID kp_proc.p_pid
+#        define P_PGID kp_eproc.e_pgid
+#        define P_PPID kp_eproc.e_ppid
+#        define P_STAT kp_proc.p_stat
+#        define P_TRACEP kp_proc.p_tracep
+#        define P_UID kp_eproc.e_ucred.cr_uid
+#        define P_VMSPACE kp_proc.p_vmspace
+#    endif /* defined(HASKVMGETPROC2) */
+
+#    if defined(HASFDESCFS)
+#        define _KERNEL
+#        include <miscfs/fdesc/fdesc.h>
+#        undef _KERNEL
+#    endif /* defined(HASFDESCFS) */
+
+#    if defined(HASKERNFS)
+#        define _KERNEL
+#        define Pkern __Pkern
+#        define Proot __Proot
+#        define Pnull __Pnull
+#        define Ptime __Ptime
+#        define Pint __Pint
+#        define Pstring __Pstring
+#        define Phostname __Phostname
+#        define Pavenrun __Pavenrun
+#        define Pdevice __Pdevice
+#        define Pmsgbuf __Pmsgbuf
+#        define Pipsecsadir __Pipsecsadir
+#        define Pipsecspdir __Pipsecspdir
+#        define Pipsecsa __Pipseca
+#        define Pipsecsp __Pipsecsp
+#        include <miscfs/kernfs/kernfs.h>
+#        undef _KERNEL
+#        undef Pkern
+#        undef Proot
+#        undef Pnull
+#        undef Ptime
+#        undef Pint
+#        undef Pstring
+#        undef Phostname
+#        undef Pavenrun
+#        undef Pdevice
+#        undef Pmsgbuf
+#        undef Pipsecsadir
+#        undef Pipsecspdir
+#        undef Pipseca
+#        undef Pipsecsp
+#        if defined(HASKERNFS_KFS_KT)
+#            define kf_kt kfs_kt
+#        endif /* defined(HASKERNFS_KFS_KT) */
+#    endif     /* defined(HASKERNFS) */
+
+#    if defined(HASNULLFS)
+#        define _KERNEL
+#        if defined(NETBSDV) && NETBSDV >= 1005000 &&                          \
+            __NetBSD_Version__ < 106060000
+#            include "netexport.h"
+#        endif /* defined(NETBSDV) && NETBSDV>=1005000                         \
+              && __NetBSD_Version__<106060000 */
+#        include <miscfs/nullfs/null.h>
+#        undef _KERNEL
+#    endif /* defined(HASNULLFS) */
+
+#    if defined(HASPROCFS)
+#        if defined(HASPROCFS_PFSROOT)
+#            define _KERNEL
+#        endif /* defined(HASPROCFS_PFSROOT) */
+#        if (defined(NETBSDV) && __NetBSD_Version__ >= 900000000)
+#            include <sys/ptrace.h>
+#        endif
+/*
+ * Needed for definition of curlwp, which isn't used by this code base,
+ * but is exposed in procfs.h in an inline function declaration.
+ */
+#        if (defined(NETBSDV) && __NetBSD_Version__ >= 999009300)
+extern struct lwp *curlwp;
+#        endif
+#        include <miscfs/procfs/procfs.h>
+#        if defined(HASPROCFS_PFSROOT)
+#            undef _KERNEL
+#            define Proot PFSroot
+#            define Pproc PFSproc
+#            define Pcurproc PFScurproc
+#            define Pmem PFSmem
+#            define Pregs PFSregs
+#            define Pfile PFSfile
+#            define Pfpregs PFSfpregs
+#            define Pstatus PFSstatus
+#            define Pnote PFSnote
+#            define Pnotepg PFSnotepg
+#            if defined(NetBSDV)
+#                if NETBSDV >= 2000000
+#                    define Pfd PFSfd
+#                endif /* NETBSDV>=2000000 */
+#                if NETBSDV >= 1006000
+#                    define Pmap PFSmap
+#                    define Pmaps PFSmaps
+#                endif /* NETBSDV>=1006000 */
+#                if NETBSDV < 8099000
+#                    define Pctl PFSctl
+#                endif /* NETBSDV<8099000 */
+#            endif     /* defined(NetBSDV) */
+#        endif         /* defined(HASPROCFS_PFSROOT) */
+#        include <machine/reg.h>
+#    endif /* defined(HASPROCFS) */
+
+#    if defined(HASPTYFS)
+#        define _KERNEL
+#        include <fs/ptyfs/ptyfs.h>
+#        include <miscfs/specfs/specdev.h>
+#        undef _KERNEL
+#    endif /* defined(HASPTYFS) */
+
+#    define KERNEL
+#    define _KERNEL
+#    include <sys/file.h>
+#    include <sys/fcntl.h>
+
+#    if defined(HAS_ADVLOCK_ARGS)
+struct vop_advlock_args;
+#    endif /* defined(HAS_ADVLOCK_ARGS) */
+
+#    if defined(DTYPE_KQUEUE)
+#        define HASKQUEUE /* has the kqueue file type */
+#    endif                /* defined(DTYPE_KQUEUE) */
+
+#    include <sys/lockf.h>
+#    undef KERNEL
+#    undef _KERNEL
+
+#    if defined(UVM)
+#        define FALSE 0
+#        define TRUE 1
+#        include <uvm/uvm.h>
+#    endif /* defined(UVM) */
+
+#    if defined(HAS_UVM_INCL)
+#        include <uvm/uvm.h>
+#        include <uvm/uvm_map.h>
+#        include <uvm/uvm_object.h>
+#        include <uvm/uvm_pager.h>
+#    else /* !defined(HAS_UVM_INCL) */
+#        include <vm/vm.h>
+#        include <vm/vm_map.h>
+#        include <vm/vm_object.h>
+#        include <vm/vm_pager.h>
+#    endif /* defined(HAS_UVM_INCL) */
+
+#    if defined(HAS_SYS_PIPEH)
+#        include <sys/pipe.h>
+#    endif /* defined(HAS_SYS_PIPEH) */
+
+#    define COMP_P const void
+#    define DEVINCR 1024 /* device table malloc() increment */
+typedef u_long KA_T;
+#    define KMEM "/dev/kmem"
+#    define MALLOC_P void
+#    define FREE_P MALLOC_P
+#    define MALLOC_S size_t
+
+#    if !defined(MAXSYSCMDL)
+#        define MAXSYSCMDL MAXCOMLEN /* max system command name length */
+#    endif                           /* !defined(MAXSYSCMDL) */
+
+#    if defined(N_UNIXV)
+#        define N_UNIX_TMP(x) #        x
+#        define N_UNIX_STR(x) N_UNIX_TMP(x)
+#        define N_UNIX N_UNIX_STR(N_UNIXV)
+#    endif /* defined(N_UNIXV) */
+
+#    define QSORT_P void
+#    define READLEN_T int
+#    define STRNCPY_L size_t
+#    define SWAP "/dev/drum"
+#    define SZOFFTYPE unsigned long long
+/* size and offset internal storage
+ * type */
+#    define SZOFFPSPEC                                                         \
+        "ll" /* SZOFFTYPE print specification                                  \
+              * modifier */
+
+/*
+ * Global storage definitions (including their structure definitions)
+ */
+
+extern struct file *Cfp;
+extern kvm_t *Kd;
+extern KA_T Kpa;
+
+struct l_vfs {
+    KA_T addr;   /* kernel address */
+    fsid_t fsid; /* file system ID */
+#    if defined(NETBSDV) && __NetBSD_Version__ >= 499002500
+    /* MFSNAMELEN was removed from the kernel source after 4.99.24 */
+    char type[sizeof(
+        ((struct statvfs *)NULL)->f_fstypename)]; /* type of file system */
+#    else
+    char type[MFSNAMELEN]; /* type of file system */
+#    endif
+    char *dir;          /* mounted directory */
+    char *fsname;       /* file system name */
+    struct l_vfs *next; /* forward link */
+};
+extern struct l_vfs *Lvfs;
+
+struct mounts {
+    char *dir;           /* directory (mounted on) */
+    char *fsname;        /* file system
+                          * (symbolic links unresolved) */
+    char *fsnmres;       /* file system
+                          * (symbolic links resolved) */
+    dev_t dev;           /* directory st_dev */
+    dev_t rdev;          /* directory st_rdev */
+    INODETYPE inode;     /* directory st_ino */
+    mode_t mode;         /* directory st_mode */
+    mode_t fs_mode;      /* file_system st_mode */
+    struct mounts *next; /* forward link */
+};
+
+#    define X_NCACHE "ncache"
+#    define X_NCSIZE "ncsize"
+#    define NL_NAME n_name
+
+extern int Np; /* number of kernel processes */
+
+#    if defined(HASKVMGETPROC2)
+struct kinfo_proc2 *P; /* local process table copy */
+#    else              /* ! defined(HASKVMGETPROC2) */
+struct kinfo_proc *P;      /* local process table copy */
+#    endif             /* defined(HASKVMGETPROC2) */
+
+extern int pgshift; /* kernel's page shift */
+
+struct sfile {
+    char *aname;        /* argument file name */
+    char *name;         /* file name (after readlink()) */
+    char *devnm;        /* device name (optional) */
+    dev_t dev;          /* device */
+    dev_t rdev;         /* raw device */
+    u_short mode;       /* S_IFMT mode bits from stat() */
+    int type;           /* file type: 0 = file system
+                         *           1 = regular file */
+    INODETYPE i;        /* inode number */
+    int f;              /* file found flag */
+    struct sfile *next; /* forward link */
+};
+
+/*
+ * Definitions for rdev.c
+ */
+
+#    define DIRTYPE dirent
+#    define HASDNAMLEN 1 /* struct DIRTYPE has d_namlen element */
+
+/*
+ * Definitions for rnam.c and rnmh.c
+ */
+
+#    if defined(HASNCACHE)
+#        if defined(NETBSDV) && NETBSDV >= 1002000
+#            include <stddef.h>
+#        endif /* defined(NETBSDV) && NETBSDV>=1002000 */
+
+#        include <sys/uio.h>
+#        include <sys/namei.h>
+#        define NCACHE namecache      /* kernel's structure name */
+#        define NCACHE_NM nc_name     /* name in NCACHE */
+#        define NCACHE_NMLEN nc_nlen  /* name length in NCACHE */
+#        define NCACHE_NODEADDR nc_vp /* node address in NCACHE */
+#        define NCACHE_PARADDR nc_dvp /* parent node address in NCACHE */
+
+#        if defined(NETBSDV) && NETBSDV >= 1002000 &&                          \
+            __NetBSD_Version__ < 999005400
+#            define NCACHE_NXT nc_hash.le_next /* link in NCACHE */
+#        else /* defined(NETBSDV) && NETBSDV>=1002000 */
+#            if defined(NetBSD1_0) && NetBSD < 1994101
+#                define NCACHE_NXT nc_nxt /* link in NCACHE */
+#            else /* !defined(NetBSD1_0) || NetBSD>=1994101 */
+#                define NCACHE_NXT nc_lru.tqe_next /* link in NCACHE */
+#            endif /* defined(NetBSD1_0) && NetBSD<1994101 */
+#        endif     /* defined(NETBSDV) && NETBSDV>=1002000 */
+
+#        if defined(HASNCVPID)
+#            define NCACHE_PARID nc_dvpid /* parent node ID in NCACHE */
+#            define NCACHE_NODEID nc_vpid /* node ID in NCACHE */
+#        endif                            /* defined(HASNCVPID) */
+#    endif                                /* defined(HASNCACHE) */
+
+#    if defined(VV_ROOT) /* NetBSD >= 4.99.33 */
+#        define VNODE_VFLAG v_vflag
+#        define NCACHE_VROOT VV_ROOT
+#    else
+#        define VNODE_VFLAG v_flag
+#        define NCACHE_VROOT VROOT
+#    endif /* VV_ROOT */
+
+struct lsof_context_dialect {};
+
+#endif /* NETBSD_LSOF_H */
diff --git a/lib/dialects/netbsd/dmnt.c b/lib/dialects/netbsd/dmnt.c
new file mode 100644 (file)
index 0000000..efb6b73
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ * dmnt.c - NetBSD mount support functions for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#ifndef lint
+static char copyright[] =
+    "@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
+#endif
+
+#if defined(NETBSDV) && defined(HASSTATVFS)
+/*
+ * NetBSD needs the statvfs structure to be defined without the
+ * pre-definition of _KERNEL.
+ */
+
+#    include <sys/statvfs.h>
+#endif /* defined(NETBSDV) && defined(HASSTATVFS) */
+
+#if defined(NETBSDV)
+#    include <sys/param.h>
+
+#    if __NetBSD_Version__ >= 899000100
+#        define __EXPOSE_MOUNT
+#    endif
+#    if __NetBSD_Version__ >= 399002400
+#        include <sys/types.h>
+#        include <sys/mount.h>
+#    endif
+#endif
+
+#include "common.h"
+
+/*
+ * Local static definitions
+ */
+
+/*
+ * readmnt() - read mount table
+ */
+
+struct mounts *readmnt(struct lsof_context *ctx) {
+    char *dn = (char *)NULL;
+    char *ln;
+    struct mounts *mtp;
+    int n;
+    struct stat sb;
+
+#if defined(HASPROCFS)
+    unsigned char procfs = 0;
+#endif /* defined(HASPROCFS) */
+
+#if defined(HASSTATVFS)
+    struct statvfs *mb = (struct statvfs *)NULL;
+#else  /* !defined(HASSTATVFS) */
+    struct statfs *mb = (struct statfs *)NULL;
+#endif /* defined(HASSTATVFS) */
+
+    if (Lmi || Lmist)
+        return (Lmi);
+    /*
+     * Access mount information.
+     */
+    if ((n = getmntinfo(&mb, MNT_NOWAIT)) <= 0) {
+        (void)fprintf(stderr, "%s: no mount information\n", Pn);
+        return (0);
+    }
+    /*
+     * Read mount information.
+     */
+    for (; n; n--, mb++) {
+        if (mb->f_fstypename[0] == '\0')
+            continue;
+#if defined(NETBSDV) && __NetBSD_Version__ >= 499002500
+        /* MFSNAMELEN was removed from the kernel source after 4.99.24 */
+        mb->f_fstypename[sizeof(mb->f_fstypename) - 1] = '\0';
+#else
+        mb->f_fstypename[MFSNAMELEN - 1] = '\0';
+#endif
+        /*
+         * Interpolate a possible symbolic directory link.
+         */
+        if (dn)
+            (void)free((FREE_P *)dn);
+        if (!(dn = mkstrcpy(mb->f_mntonname, (MALLOC_S *)NULL))) {
+
+        no_space_for_mount:
+
+            (void)fprintf(stderr, "%s: no space for mount at ", Pn);
+            safestrprt(mb->f_mntonname, stderr, 0);
+            (void)fprintf(stderr, " (");
+            safestrprt(mb->f_mntfromname, stderr, 0);
+            (void)fprintf(stderr, ")\n");
+            Error(ctx);
+        }
+        if ((ln = Readlink(ctx, dn)) == NULL) {
+            if (!Fwarn) {
+                (void)fprintf(stderr,
+                              "      Output information may be incomplete.\n");
+            }
+            continue;
+        }
+        if (ln != dn) {
+            (void)free((FREE_P *)dn);
+            dn = ln;
+        }
+        if (*dn != '/')
+            continue;
+        /*
+         * Stat() the directory.
+         */
+        if (statsafely(ctx, dn, &sb)) {
+            if (!Fwarn) {
+                (void)fprintf(stderr, "%s: WARNING: can't stat() ", Pn);
+                safestrprt(mb->f_fstypename, stderr, 0);
+                (void)fprintf(stderr, " file system ");
+                safestrprt(mb->f_mntonname, stderr, 1);
+                (void)fprintf(stderr,
+                              "      Output information may be incomplete.\n");
+            }
+            (void)bzero((char *)&sb, sizeof(sb));
+
+#if defined(HASSTATVFS)
+            sb.st_dev = (dev_t)mb->f_fsid;
+#else  /* !defined(HASSTATVFS) */
+            sb.st_dev = (dev_t)mb->f_fsid.val[0];
+#endif /* defined(HASSTATVFS) */
+
+            sb.st_mode = S_IFDIR | 0777;
+            if (!Fwarn) {
+                (void)fprintf(stderr,
+                              "      assuming \"dev=%x\" from mount table\n",
+                              sb.st_dev);
+            }
+        }
+        /*
+         * Allocate and fill a local mount structure.
+         */
+        if (!(mtp = (struct mounts *)malloc(sizeof(struct mounts))))
+            goto no_space_for_mount;
+        mtp->dir = dn;
+        dn = (char *)NULL;
+
+#if defined(HASPROCFS)
+        if (strcmp(mb->f_fstypename, MOUNT_PROCFS) == 0) {
+
+            /*
+             * Save information on exactly one procfs file system.
+             */
+            if (procfs)
+                Mtprocfs = (struct mounts *)NULL;
+            else {
+                procfs = 1;
+                Mtprocfs = mtp;
+            }
+        }
+#endif /* defined(HASPROCFS) */
+
+        mtp->next = Lmi;
+        mtp->dev = sb.st_dev;
+        mtp->rdev = sb.st_rdev;
+        mtp->inode = (INODETYPE)sb.st_ino;
+        mtp->mode = sb.st_mode;
+        /*
+         * Interpolate a possible file system (mounted-on) device name link.
+         */
+        if (!(dn = mkstrcpy(mb->f_mntfromname, (MALLOC_S *)NULL)))
+            goto no_space_for_mount;
+        mtp->fsname = dn;
+        ln = Readlink(ctx, dn);
+        dn = (char *)NULL;
+        /*
+         * Stat() the file system (mounted-on) name and add file system
+         * information to the local mount table entry.
+         */
+        if (!ln || statsafely(ctx, ln, &sb))
+            sb.st_mode = 0;
+        mtp->fsnmres = ln;
+        mtp->fs_mode = sb.st_mode;
+        Lmi = mtp;
+    }
+    /*
+     * Clean up and return local mount info table address.
+     */
+    if (dn)
+        (void)free((FREE_P *)dn);
+    Lmist = 1;
+    return (Lmi);
+}
+
+/*
+ * readvfs() - read vfs structure
+ */
+
+struct l_vfs *readvfs(struct lsof_context *ctx, /* context */
+                      KA_T vm) /* kernel mount address from vnode */
+{
+    struct mount m;
+    struct l_vfs *vp;
+    /*
+     * Search for match on existing entry.
+     */
+    for (vp = Lvfs; vp; vp = vp->next) {
+        if (vm == vp->addr)
+            return (vp);
+    }
+    /*
+     * Read the (new) mount structure, allocate a local entry, and fill it.
+     */
+    if (kread(ctx, vm, (char *)&m, sizeof(m)) != 0)
+        return ((struct l_vfs *)NULL);
+    if (!(vp = (struct l_vfs *)malloc(sizeof(struct l_vfs)))) {
+        (void)fprintf(stderr, "%s: PID %d, no space for vfs\n", Pn, Lp->pid);
+        Error(ctx);
+    }
+    if (!(vp->dir = mkstrcpy(m.m_stat.f_mntonname, (MALLOC_S *)NULL)) ||
+        !(vp->fsname = mkstrcpy(m.m_stat.f_mntfromname, (MALLOC_S *)NULL))) {
+        (void)fprintf(stderr, "%s: PID %d, no space for mount names\n", Pn,
+                      Lp->pid);
+        Error(ctx);
+    }
+    vp->addr = vm;
+
+#if defined(HASSTATVFS)
+    vp->fsid = m.m_stat.f_fsidx;
+#else  /* !defined(HASSTATVFS) */
+    vp->fsid = m.m_stat.f_fsid;
+#endif /* defined(HASSTATVFS) */
+
+    (void)snpf(vp->type, sizeof(vp->type), "%s", m.m_stat.f_fstypename);
+    vp->next = Lvfs;
+    Lvfs = vp;
+    return (vp);
+}
diff --git a/lib/dialects/netbsd/dnode.c b/lib/dialects/netbsd/dnode.c
new file mode 100644 (file)
index 0000000..6a7b941
--- /dev/null
@@ -0,0 +1,1449 @@
+/*
+ * dnode.c - NetBSD node functions for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#ifndef lint
+static char copyright[] =
+    "@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
+#endif
+
+#include "common.h"
+
+#if defined(HAS_LOCKF_H)
+#    include "lockf.h"
+#endif
+
+#if defined(HAS_DINODE_U)
+#    define DINODE_U dinode_u
+#else /* !defined(HAS_DINODE_U) */
+#    define DINODE_U i_din
+#endif /* defined(HAS_DINODE_U) */
+
+#if defined(HASFDESCFS) && HASFDESCFS == 1
+static int lkup_dev_tty(struct lsof_context *ctx, dev_t *dr, INODETYPE *ir);
+#endif /* defined(HASFDESCFS) && HASFDESCFS==1 */
+
+#if defined(HAS_UM_UFS)
+#    define UFS1 UM_UFS1
+#    define UFS2 UM_UFS2
+#endif /* defined(HAS_UM_UFS) */
+
+#if defined(HASPROCFS)
+static void getmemsz(struct lsof_context *ctx, pid_t pid);
+
+#    if !defined(PGSHIFT)
+#        define PGSHIFT pgshift
+#    endif /* !defined(PGSHIFT) */
+
+/*
+ * getmemsz() - get memory size of a /proc/<n>/mem entry
+ */
+
+static void getmemsz(struct lsof_context *ctx, pid_t pid) {
+    int n;
+    struct vmspace vm;
+
+#    if defined(HASKVMGETPROC2)
+    struct kinfo_proc2 *p;
+#    else  /* !defined(HASKVMGETPROC2) */
+    struct kinfo_proc *p;
+#    endif /* defined(HASKVMGETPROC2) */
+
+    for (n = 0, p = P; n < Np; n++, p++) {
+        if (p->P_PID == pid) {
+            if (!p->P_VMSPACE ||
+                kread(ctx, (KA_T)p->P_VMSPACE, (char *)&vm, sizeof(vm)))
+                return;
+            Lf->sz = (SZOFFTYPE)ctob(vm.vm_tsize + vm.vm_dsize + vm.vm_ssize);
+            Lf->sz_def = 1;
+            return;
+        }
+    }
+}
+#    undef PGSHIFT
+#endif /* defined(HASPROCFS) */
+
+#if defined(HASFDESCFS) && HASFDESCFS == 1
+/*
+ * lkup_dev_tty() - look up /dev/tty
+ */
+
+static int lkup_dev_tty(struct lsof_context *ctx, /* context */
+                        dev_t *dr,     /* place to return device number */
+                        INODETYPE *ir) /* place to return inode number */
+{
+    int i;
+
+    readdev(ctx, 0);
+
+#    if defined(HASDCACHE)
+
+lkup_dev_tty_again:
+
+#    endif /* defined(HASDCACHE) */
+
+    for (i = 0; i < Ndev; i++) {
+        if (strcmp(Devtp[i].name, "/dev/tty") == 0) {
+
+#    if defined(HASDCACHE)
+            if (DCunsafe && !Devtp[i].v && !vfy_dev(ctx, &Devtp[i]))
+                goto lkup_dev_tty_again;
+#    endif /* defined(HASDCACHE) */
+
+            *dr = Devtp[i].rdev;
+            *ir = Devtp[i].inode;
+            return (1);
+        }
+    }
+
+#    if defined(HASDCACHE)
+    if (DCunsafe) {
+        (void)rereaddev(ctx);
+        goto lkup_dev_tty_again;
+    }
+#    endif /* defined(HASDCACHE) */
+
+    return (-1);
+}
+#endif /* defined(HASFDESCFS) && HASFDESCFS==1 */
+
+#if defined(HASKQUEUE)
+/*
+ * process_kqueue() -- process kqueue file
+ *
+ * Strictly speaking this function should appear in dfile.c, because it is
+ * a file processing function.  However, the Net and Open BSD sources don't
+ * require a dfile.c, so this is the next best location for the function.
+ */
+
+void process_kqueue(struct lsof_context *ctx, /* context */
+                    KA_T ka) /* kqueue file structure address */
+{
+    Lf->type = LSOF_FILE_KQUEUE;
+    enter_dev_ch(ctx, print_kptr(ka, (char *)NULL, 0));
+}
+#endif /* defined(HASKQUEUE) */
+
+/*
+ * process_node() - process vnode
+ */
+
+void process_node(struct lsof_context *ctx, /* context */
+                  KA_T va)                  /* vnode kernel space address */
+{
+    dev_t dev, rdev;
+    unsigned char devs;
+    unsigned char lt;
+    unsigned char ns;
+    unsigned char rdevs;
+    char *ep;
+#if defined(HAS_LOCKF_H)
+    struct lockf lf, *lff, *lfp;
+#endif
+    struct inode i;
+    struct mfsnode m;
+#if defined(HASTMPFS)
+    struct tmpfs_node tmp;
+#endif /* defined(HASTMPFS) */
+    struct nfsnode n;
+    enum nodetype {
+        NONODE,
+        CDFSNODE,
+        DOSNODE,
+        EXT2NODE,
+        FDESCNODE,
+        INODE,
+        KERNFSNODE,
+        MFSNODE,
+        NFSNODE,
+        PFSNODE,
+        PTYFSNODE,
+        TMPFSNODE
+    } nty;
+    enum vtype type;
+    struct vnode *v, vb;
+    struct l_vfs *vfs;
+
+#if defined(HAS9660FS)
+    dev_t iso_dev;
+    INODETYPE iso_ino;
+    long iso_nlink;
+    int iso_stat;
+    SZOFFTYPE iso_sz;
+#endif /* defined(HAS9660FS) */
+
+#if defined(HASFDESCFS)
+    struct fdescnode f;
+
+#    if HASFDESCFS == 1
+    static dev_t f_tty_dev;
+    static INODETYPE f_tty_ino;
+    static int f_tty_s = 0;
+#    endif /* HASFDESCFS==1 */
+
+#endif /* defined(HASFDESCFS) */
+
+#if defined(HASEXT2FS)
+#    if defined(HASI_E2FS_PTR)
+    struct ext2fs_dinode ed;
+#    endif /* defined(HASI_E2FS_PTR) */
+    struct ext2fs_dinode *edp = (struct ext2fs_dinode *)NULL;
+#endif /* defined(HASEXT2FS) */
+
+#if defined(HASI_FFS1)
+    unsigned char ffs = 0;
+    unsigned char u1s = 0;
+    unsigned char u2s = 0;
+    struct ufs1_dinode u1;
+    struct ufs2_dinode u2;
+    struct ufsmount um;
+#endif /* defined(HASI_FFS1) */
+
+#if defined(HASKERNFS)
+    struct kernfs_node kn;
+    struct stat ksb;
+    int ksbs;
+    struct kern_target kt;
+    int ktnl;
+    char ktnm[MAXPATHLEN + 1];
+#endif /* defined(HASKERNFS) */
+
+#if defined(HASMSDOSFS)
+    struct denode d;
+    u_long dpb;
+    INODETYPE nn;
+    struct msdosfsmount pm;
+#endif /* defined(HASMSDOSFS) */
+
+#if defined(HASNFSVATTRP)
+    struct vattr nv;
+#    define NVATTR nv
+#else /* !defined(HASNFSVATTRP) */
+#    define NVATTR n.n_vattr
+#endif /* defined(HASNFSVATTRP) */
+
+#if defined(HASNULLFS)
+    struct null_node nu;
+    int sc = 0;
+    struct l_vfs *nvfs = (struct l_vfs *)NULL;
+#endif /* defined(HASNULLFS) */
+
+#if defined(HASPROCFS)
+    struct pfsnode p;
+    struct procfsid *pfi;
+    size_t sz;
+#endif /* defined(HASPROCFS) */
+
+#if defined(HASPTYFS)
+    struct ptyfsnode pt;
+#    if __NetBSD_Version__ >= 499006200
+#        define specinfo specnode
+#        define vu_specinfo vu_specnode
+#        define si_rdev sn_rdev
+#    endif
+    struct specinfo si;
+#endif /* defined(HASPTYFS) */
+
+#if defined(HASNULLFS)
+
+process_overlaid_node:
+
+    if (++sc > 1024) {
+        (void)snpf(Namech, Namechl, "too many overlaid nodes");
+        enter_nm(ctx, Namech);
+        return;
+    }
+#endif /* defined(HASNULLFS) */
+
+    /*
+     * Initialize miscellaneous variables.  This is done so that processing an
+     * overlaid node will be a fresh start.
+     */
+    devs = rdevs = 0;
+    nty = NONODE;
+    Namech[0] = '\0';
+
+#if defined(HAS9660FS)
+    iso_stat = 0;
+#endif /* defined(HAS9660FS) */
+
+#if defined(HASKERNFS)
+    ksbs = 0;
+#endif /* defined(HASKERNFS) */
+
+#if defined(HASEXT2FS)
+    edp = (struct ext2fs_dinode *)NULL;
+#endif /* defined(HASEXT2FS) */
+
+#if defined(HASI_FFS1)
+    ffs = u1s = u2s = 0;
+#endif /* defined(HASI_FFS1) */
+
+    /*
+     * Read the vnode.
+     */
+    if (!va) {
+        enter_nm(ctx, "no vnode address");
+        return;
+    }
+    v = &vb;
+    if (readvnode(ctx, va, v)) {
+        enter_nm(ctx, Namech);
+        return;
+    }
+
+#if defined(HASNCACHE)
+    Lf->na = va;
+#    if defined(HASNCVPID)
+    Lf->id = v->v_id;
+#    endif /* defined(HASNCVPID) */
+#endif     /* defined(HASNCACHE) */
+
+#if defined(HASFSTRUCT)
+    Lf->fna = va;
+    Lf->fsv |= FSV_NI;
+#endif /* defined(HASFSTRUCT) */
+
+    /*
+     * Get the vnode type.
+     */
+    if (!v->v_mount)
+        vfs = (struct l_vfs *)NULL;
+    else {
+        vfs = readvfs(ctx, (KA_T)v->v_mount);
+        if (vfs) {
+            if (strcmp(vfs->type, MOUNT_NFS) == 0)
+                Ntype = N_NFS;
+
+#if defined(HASKERNFS)
+            else if (strcmp(vfs->type, MOUNT_KERNFS) == 0)
+                Ntype = N_KERN;
+#endif /* defined(HASKERNFS) */
+
+#if defined(HASPROCFS)
+            else if (strcmp(vfs->type, MOUNT_PROCFS) == 0)
+                Ntype = N_PROC;
+#endif /* defined(HASPROCFS) */
+
+#if defined(HAS9660FS)
+            else if (strcmp(vfs->type, MOUNT_CD9660) == 0)
+                Ntype = N_CDFS;
+#endif /* defined(HAS9660FS) */
+        }
+    }
+    if (Ntype == N_REGLR) {
+        switch (v->v_type) {
+        case VFIFO:
+            Ntype = N_FIFO;
+            break;
+        }
+    }
+    /*
+     * Read the successor node.
+     */
+    switch (v->v_tag) {
+
+#if defined(HAS9660FS)
+    case VT_ISOFS:
+        if (read_iso_node(ctx, v, &iso_dev, &iso_ino, &iso_nlink, &iso_sz)) {
+            (void)snpf(Namech, Namechl, "can't read iso_node at: %s",
+                       print_kptr((KA_T)v->v_data, (char *)NULL, 0));
+            enter_nm(ctx, Namech);
+            return;
+        }
+        iso_stat = 1;
+        nty = CDFSNODE;
+        break;
+#endif /* defined(HAS9660FS) */
+
+#if defined(HASFDESCFS)
+    case VT_FDESC:
+        if (!v->v_data || kread(ctx, (KA_T)v->v_data, (char *)&f, sizeof(f))) {
+            (void)snpf(Namech, Namechl, "can't read fdescnode at: %x",
+                       print_kptr((KA_T)v->v_data, (char *)NULL, 0));
+            enter_nm(ctx, Namech);
+            return;
+        }
+        nty = FDESCNODE;
+        break;
+#endif /* defined(HASFDESCFS) */
+
+#if defined(HASKERNFS)
+    case VT_KERNFS:
+
+        /*
+         * Read the kernfs_node.
+         */
+        if (!v->v_data ||
+            kread(ctx, (KA_T)v->v_data, (char *)&kn, sizeof(kn))) {
+            if (v->v_type != VDIR || !(v->VNODE_VFLAG && NCACHE_VROOT)) {
+                (void)snpf(Namech, Namechl, "can't read kernfs_node at: %s",
+                           print_kptr((KA_T)v->v_data, (char *)NULL, 0));
+                enter_nm(ctx, Namech);
+                return;
+            } else
+                kn.kf_kt = (struct kern_target *)NULL;
+        }
+        /*
+         * Generate the /kern file name by reading the kern_target to which
+         * the kernfs_node points.
+         */
+        if (kn.kf_kt &&
+            kread(ctx, (KA_T)kn.kf_kt, (char *)&kt, sizeof(kt)) == 0 &&
+            (ktnl = (int)kt.kt_namlen) > 0 && kt.kt_name) {
+            if (ktnl > (sizeof(ktnm) - 1))
+                ktnl = sizeof(ktnm) - 1;
+            if (!kread(ctx, (KA_T)kt.kt_name, ktnm, ktnl)) {
+                ktnm[ktnl] = 0;
+                ktnl = strlen(ktnm);
+                if (ktnl > (MAXPATHLEN - strlen(_PATH_KERNFS) - 2)) {
+                    ktnl = MAXPATHLEN - strlen(_PATH_KERNFS) - 2;
+                    ktnm[ktnl] = '\0';
+                }
+                (void)snpf(Namech, Namechl, "%s/%s", _PATH_KERNFS, ktnm);
+            }
+        }
+        /*
+         * If this is the /kern root directory, its name, inode number and
+         * size are fixed; otherwise, safely stat() the file to get the
+         * inode number and size.
+         */
+        if (v->v_type == VDIR && (v->VNODE_VFLAG & NCACHE_VROOT)) {
+            (void)snpf(Namech, Namechl, "%s", _PATH_KERNFS);
+            ksb.st_ino = (ino_t)2;
+            ksb.st_size = DEV_BSIZE;
+            ksbs = 1;
+        } else if (Namech[0] && statsafely(Namech, &ksb) == 0)
+            ksbs = 1;
+        nty = KERNFSNODE;
+        break;
+#endif /* defined(HASKERNFS) */
+
+    case VT_MFS:
+        if (!v->v_data || kread(ctx, (KA_T)v->v_data, (char *)&m, sizeof(m))) {
+            (void)snpf(Namech, Namechl, "can't read mfsnode at: %s",
+                       print_kptr((KA_T)v->v_data, (char *)NULL, 0));
+            enter_nm(ctx, Namech);
+            return;
+        }
+        nty = MFSNODE;
+        break;
+
+#if defined(HASTMPFS)
+    case VT_TMPFS:
+        if (!v->v_data ||
+            kread(ctx, (KA_T)v->v_data, (char *)&tmp, sizeof(tmp))) {
+            (void)snpf(Namech, Namechl, "can't read tmpfs_node at: %s",
+                       print_kptr((KA_T)v->v_data, (char *)NULL, 0));
+            enter_nm(ctx, Namech);
+            return;
+        }
+        nty = TMPFSNODE;
+        break;
+#endif /* defined(HASTMPFS) */
+
+#if defined(HASMSDOSFS)
+    case VT_MSDOSFS:
+        if (!v->v_data || kread(ctx, (KA_T)v->v_data, (char *)&d, sizeof(d))) {
+            (void)snpf(Namech, Namechl, "can't read denode at: %s",
+                       print_kptr((KA_T)v->v_data, (char *)NULL, 0));
+            enter_nm(ctx, Namech);
+            return;
+        }
+        nty = DOSNODE;
+        break;
+#endif /* defined(HASMSDOSFS) */
+
+    case VT_NFS:
+        if (!v->v_data || kread(ctx, (KA_T)v->v_data, (char *)&n, sizeof(n))) {
+            (void)snpf(Namech, Namechl, "can't read nfsnode at: %s",
+                       print_kptr((KA_T)v->v_data, (char *)NULL, 0));
+            enter_nm(ctx, Namech);
+            return;
+        }
+
+#if defined(HASNFSVATTRP)
+        if (!n.n_vattr ||
+            kread(ctx, (KA_T)n.n_vattr, (char *)&nv, sizeof(nv))) {
+            (void)snpf(Namech, Namechl, "can't read n_vattr at: %x",
+                       print_kptr((KA_T)n.n_vattr, (char *)NULL, 0));
+            enter_nm(ctx, Namech);
+            return;
+        }
+#endif /* defined(HASNFSVATTRP) */
+
+        nty = NFSNODE;
+        break;
+
+#if defined(HASNULLFS)
+    case VT_NULL:
+        if ((sc == 1) && vfs)
+            nvfs = vfs;
+        if (!v->v_data ||
+            kread(ctx, (KA_T)v->v_data, (char *)&nu, sizeof(nu))) {
+            (void)snpf(Namech, Namechl, "can't read null_node at: %s",
+                       print_kptr((KA_T)v->v_data, (char *)NULL, 0));
+            enter_nm(ctx, Namech);
+            return;
+        }
+        if (!nu.null_lowervp) {
+            (void)snpf(Namech, Namechl, "null_node overlays nothing");
+            enter_nm(ctx, Namech);
+            return;
+        }
+        va = (KA_T)nu.null_lowervp;
+        goto process_overlaid_node;
+#endif /* defined(HASNULLFS) */
+
+#if defined(HASPROCFS)
+    case VT_PROCFS:
+        if (!v->v_data || kread(ctx, (KA_T)v->v_data, (char *)&p, sizeof(p))) {
+            (void)snpf(Namech, Namechl, "can't read pfsnode at: %s",
+                       print_kptr((KA_T)v->v_data, (char *)NULL, 0));
+            enter_nm(ctx, Namech);
+            return;
+        }
+        nty = PFSNODE;
+        break;
+#endif /* defined(HASPROCFS) */
+
+#if defined(HASPTYFS)
+    case VT_PTYFS:
+        if (!v->v_data ||
+            kread(ctx, (KA_T)v->v_data, (char *)&pt, sizeof(pt))) {
+            (void)snpf(Namech, Namechl, "can't read ptyfsnode at: %s",
+                       print_kptr((KA_T)v->v_data, (char *)NULL, 0));
+            enter_nm(ctx, Namech);
+            return;
+        }
+        nty = PTYFSNODE;
+        break;
+#endif /* defined(HASPTYFS) */
+
+#if defined(HASEXT2FS)
+    case VT_EXT2FS:
+#endif /* defined(HASEXT2FS) */
+
+#if defined(HASLFS)
+    case VT_LFS:
+#endif /* defined(HASLFS) */
+
+    case VT_UFS:
+        if (!v->v_data || kread(ctx, (KA_T)v->v_data, (char *)&i, sizeof(i))) {
+            (void)snpf(Namech, Namechl, "can't read inode at: %s",
+                       print_kptr((KA_T)v->v_data, (char *)NULL, 0));
+            enter_nm(ctx, Namech);
+            return;
+        }
+
+#if defined(HASEXT2FS)
+        if (v->v_tag == VT_EXT2FS) {
+            nty = EXT2NODE;
+
+#    if defined(HASI_E2FS_PTR)
+            if (i.DINODE_U.e2fs_din &&
+                !kread(ctx, (KA_T)i.DINODE_U.e2fs_din, (char *)&ed, sizeof(ed)))
+                edp = &ed;
+#    else /* !defined(HASI_E2FS_PTR) */
+#        if HASEXT2FS < 2
+            edp = &i.DINODE_U.e2fs_din;
+#        else  /* HASEXT2FS>=2 */
+            edp = &i.i_e2din;
+#        endif /* HASEXT2FS>=2 */
+#    endif     /* defined(HASI_E2FS_PTR) */
+
+        } else
+#endif /* defined(HASEXT2FS) */
+
+        {
+            nty = INODE;
+
+#if defined(HASI_FFS1)
+            /*
+             * If there are multiple FFS's, read the relevant structures.
+             */
+            if (i.i_ump &&
+                !kread(ctx, (KA_T)i.i_ump, (char *)&um, sizeof(um))) {
+                if (um.um_fstype == UFS1) {
+                    ffs = 1;
+                    if (i.DINODE_U.ffs1_din &&
+                        !kread(ctx, (KA_T)i.DINODE_U.ffs1_din, (char *)&u1,
+                               sizeof(u1))) {
+                        u1s = 1;
+                    }
+                } else if (um.um_fstype == UFS2) {
+                    ffs = 2;
+                    if (i.DINODE_U.ffs2_din &&
+                        !kread(ctx, (KA_T)i.DINODE_U.ffs2_din, (char *)&u2,
+                               sizeof(u2))) {
+                        u2s = 1;
+                    }
+                }
+            }
+#endif /* defined(HASI_FFS1) */
+        }
+
+#if defined(HAS_LOCKF_H)
+        if ((lff = i.i_lockf)) {
+
+            /*
+             * Determine the lock state.
+             */
+            lfp = lff;
+            do {
+                if (kread(ctx, (KA_T)lfp, (char *)&lf, sizeof(lf)))
+                    break;
+                lt = 0;
+                switch (lf.lf_flags & (F_FLOCK | F_POSIX)) {
+                case F_FLOCK:
+                    if (Cfp && (struct file *)lf.lf_id == Cfp)
+                        lt = 1;
+                    break;
+                case F_POSIX:
+                    if ((KA_T)lf.lf_id == Kpa)
+                        lt = 1;
+
+#    if defined(HAS_LWP_H) && !defined(HAS_LF_LWP)
+                    else {
+
+                        struct lwp lw;
+
+                        if (!kread(ctx, (KA_T)lf.lf_id, (char *)&lw,
+                                   sizeof(lw)) &&
+                            (KA_T)lw.l_proc == Kpa)
+                            lt = 1;
+                    }
+#    endif /* defined(HAS_LWP_H) && !defined(HAS_LF_LWP) */
+
+                    break;
+                }
+                if (!lt)
+                    continue;
+                if (lf.lf_start == (off_t)0 &&
+                    lf.lf_end == 0xffffffffffffffffLL)
+                    lt = 1;
+                else
+                    lt = 0;
+                if (lf.lf_type == F_RDLCK)
+                    Lf->lock =
+                        lt ? LSOF_LOCK_READ_FULL : LSOF_LOCK_READ_PARTIAL;
+                else if (lf.lf_type == F_WRLCK)
+                    Lf->lock =
+                        lt ? LSOF_LOCK_WRITE_FULL : LSOF_LOCK_WRITE_PARTIAL;
+                else if (lf.lf_type == (F_RDLCK | F_WRLCK))
+                    Lf->lock = LSOF_LOCK_READ_WRITE;
+                break;
+            } while ((lfp = lf.lf_next) && lfp != lff);
+        }
+#endif
+        break;
+    default:
+        if (v->v_type == VBAD || v->v_type == VNON)
+            break;
+        (void)snpf(Namech, Namechl, "unknown file system type: %d", v->v_tag);
+        enter_nm(ctx, Namech);
+        return;
+    }
+    /*
+     * Get device and type for printing.
+     */
+    type = v->v_type;
+    switch (nty) {
+
+#if defined(HASMSDOSFS)
+    case DOSNODE:
+        dev = d.de_dev;
+        devs = 1;
+        break;
+#endif /* defined(HASMSDOSFS) */
+
+#if defined(HASFDESCFS)
+    case FDESCNODE:
+
+#    if defined(HASFDLINK)
+        if (f.fd_link && !kread(ctx, (KA_T)f.fd_link, Namech, Namechl - 1)) {
+            Namech[Namechl - 1] = '\0';
+            break;
+        }
+#    endif /* defined(HASFDLINK) */
+
+#    if HASFDESCFS == 1
+        if (f.fd_type == Fctty) {
+            if (f_tty_s == 0)
+                f_tty_s = lkup_dev_tty(ctx, &f_tty_dev, &f_tty_ino);
+            if (f_tty_s == 1) {
+                dev = DevDev;
+                rdev = f_tty_dev;
+                Lf->inode = f_tty_ino;
+                devs = Lf->inp_ty = rdevs = 1;
+            }
+        }
+        break;
+#    endif /* HASFDESCFS==1 */
+#endif     /* defined(HASFDESCFS) */
+
+#if defined(HASEXT2FS)
+    case EXT2NODE:
+
+        dev = i.i_dev;
+        devs = 1;
+        if ((type == VCHR) || (type == VBLK)) {
+
+#    if defined(HASI_E2FS_PTR)
+            if (edp) {
+                rdev = edp->e2di_rdev;
+                rdevs = 1;
+            }
+#    else /* !defined(HASI_E2FS_PTR) */
+#        if HASEXT2FS < 2
+            rdev = i.DINODE_U.e2fs_din.e2di_rdev;
+#        else  /* HASEXT2FS>=2 */
+            rdev = i.i_e2din.e2di_rdev;
+#        endif /* HASEXT2FS>=2 */
+            rdevs = 1;
+#    endif     /* defined(HASI_E2FS_PTR) */
+        }
+        break;
+#endif /* defined(HASEXT2FS) */
+
+    case INODE:
+        dev = i.i_dev;
+        devs = 1;
+        if ((type == VCHR) || (type == VBLK)) {
+
+#if defined(HASI_FFS)
+            rdev = i.i_ffs_rdev;
+            rdevs = 1;
+#else /* !defined(HASI_FFS) */
+#    if defined(HASI_FFS1)
+            if (ffs == 1) {
+                if (u1s) {
+                    rdev = u1.di_rdev;
+                    rdevs = 1;
+                }
+            } else if (ffs == 2) {
+                if (u2s) {
+                    rdev = u2.di_rdev;
+                    rdevs = 1;
+                }
+            }
+#    else  /* !defined(HASI_FFS1) */
+            rdev = i.i_rdev;
+            rdevs = 1;
+#    endif /* defined(HASI_FFS1) */
+#endif     /* defined(HASI_FFS) */
+        }
+        break;
+
+#if defined(HASKERNFS)
+    case KERNFSNODE:
+        if (vfs) {
+
+#    if defined(HASSTATVFS)
+            dev = (dev_t)vfs->fsid.__fsid_val[0];
+#    else  /* !defined(HASSTATVFS) */
+            dev = (dev_t)vfs->fsid.val[0];
+#    endif /* defined(HASSTATVFS) */
+
+            devs = 1;
+        }
+        break;
+#endif /* defined(HASKERNFS) */
+
+#if defined(HAS9660FS)
+    case CDFSNODE:
+        if (iso_stat) {
+            dev = iso_dev;
+            devs = 1;
+        }
+        break;
+#endif /* defined(HAS9660FS) */
+
+    case NFSNODE:
+        dev = NVATTR.va_fsid;
+        devs = 1;
+        break;
+
+#if defined(HASPTYFS)
+    case PTYFSNODE:
+        if (v->v_un.vu_specinfo &&
+            !kread(ctx, (KA_T)v->v_un.vu_specinfo, (char *)&si, sizeof(si))) {
+            rdev = si.si_rdev;
+            rdevs = 1;
+        }
+        if (vfs) {
+
+#    if defined(HASSTATVFS)
+            dev = (dev_t)vfs->fsid.__fsid_val[0];
+#    else  /* !defined(HASSTATVFS) */
+            dev = (dev_t)vfs->fsid.val[0];
+#    endif /* defined(HASSTATVFS) */
+
+            devs = 1;
+        }
+        break;
+#endif /* defined(HASPTYFS) */
+
+#if defined(HASTMPFS)
+    case TMPFSNODE:
+        if (vfs) {
+
+#    if defined(HASSTATVFS)
+            dev = (dev_t)vfs->fsid.__fsid_val[0];
+#    else  /* !defined(HASSTATVFS) */
+            dev = (dev_t)vfs->fsid.val[0];
+#    endif /* defined(HASSTATVFS) */
+
+            devs = 1;
+        }
+        break;
+#endif /* defined(HASTMPFS) */
+    }
+    /*
+     * Obtain the inode number.
+     */
+    switch (nty) {
+
+#if defined(HASMSDOSFS)
+    case DOSNODE:
+        if (d.de_pmp && !kread(ctx, (KA_T)d.de_pmp, (char *)&pm, sizeof(pm))) {
+            dpb = (u_long)(pm.pm_BytesPerSec / sizeof(struct direntry));
+            if (d.de_Attributes & ATTR_DIRECTORY) {
+                if (d.de_StartCluster == MSDOSFSROOT)
+                    nn = (INODETYPE)1;
+                else
+                    nn = (INODETYPE)(cntobn(&pm, d.de_StartCluster) * dpb);
+            } else {
+                if (d.de_dirclust == MSDOSFSROOT)
+                    nn = (INODETYPE)(roottobn(&pm, 0) * dpb);
+                else
+                    nn = (INODETYPE)(cntobn(&pm, d.de_dirclust) * dpb);
+                nn += (INODETYPE)(d.de_diroffset / sizeof(struct direntry));
+            }
+            Lf->inode = nn;
+            Lf->inp_ty = 1;
+        }
+        break;
+#endif /* defined(HASMSDOSFS) */
+
+#if defined(HASEXT2FS)
+    case EXT2NODE:
+#endif /* defined(HASEXT2FS) */
+
+    case INODE:
+        Lf->inode = (INODETYPE)i.i_number;
+        Lf->inp_ty = 1;
+        break;
+
+#if defined(HASKERNFS)
+    case KERNFSNODE:
+        if (ksbs) {
+            Lf->inode = (INODETYPE)ksb.st_ino;
+            Lf->inp_ty = 1;
+        }
+        break;
+#endif /* defined(HASKERNFS) */
+
+#if defined(HAS9660FS)
+    case CDFSNODE:
+        if (iso_stat) {
+            Lf->inode = iso_ino;
+            Lf->inp_ty = 1;
+        }
+        break;
+#endif /* defined(HAS9660FS) */
+
+    case NFSNODE:
+        Lf->inode = (INODETYPE)NVATTR.va_fileid;
+        Lf->inp_ty = 1;
+        break;
+
+#if defined(HASPROCFS)
+    case PFSNODE:
+        Lf->inode = (INODETYPE)p.pfs_fileno;
+        Lf->inp_ty = 1;
+        break;
+#endif /* defined(HASPROCFS) */
+
+#if defined(HASPTYFS)
+    case PTYFSNODE:
+        if (pt.ptyfs_type == PTYFSptc) {
+            if (pt.ptyfs_fileno > 0x3fffffff)
+                Lf->inode = (INODETYPE)(pt.ptyfs_fileno & 0x3fffffff);
+            else
+                Lf->inode = (INODETYPE)(pt.ptyfs_fileno - 1);
+        } else
+            Lf->inode = (INODETYPE)pt.ptyfs_fileno;
+        Lf->inp_ty = 1;
+        break;
+#endif /* defined(HASPTYFS) */
+
+#if defined(HASTMPFS)
+    case TMPFSNODE:
+        Lf->inode = (INODETYPE)tmp.tn_id;
+        Lf->inp_ty = 1;
+        break;
+#endif /* defined(HASTMPFS) */
+    }
+
+    /*
+     * Obtain the file size.
+     */
+    switch (Ntype) {
+#if defined(HAS9660FS)
+    case N_CDFS:
+        if (iso_stat) {
+            Lf->sz = (SZOFFTYPE)iso_sz;
+            Lf->sz_def = 1;
+        }
+        break;
+#endif /* defined(HAS9660FS) */
+
+    case N_FIFO:
+        break;
+
+#if defined(HASKERNFS)
+    case N_KERN:
+        if (ksbs) {
+            Lf->sz = (SZOFFTYPE)ksb.st_size;
+            Lf->sz_def = 1;
+        }
+        break;
+#endif /* defined(HASKERNFS) */
+
+    case N_NFS:
+        if (nty == NFSNODE) {
+            Lf->sz = (SZOFFTYPE)NVATTR.va_size;
+            Lf->sz_def = 1;
+        }
+        break;
+
+#if defined(HASPROCFS)
+    case N_PROC:
+        if (nty == PFSNODE) {
+            switch (p.pfs_type) {
+            case Proot:
+            case Pproc:
+                Lf->sz = (SZOFFTYPE)DEV_BSIZE;
+                Lf->sz_def = 1;
+                break;
+            case Pcurproc:
+                Lf->sz = (SZOFFTYPE)DEV_BSIZE;
+                Lf->sz_def = 1;
+                break;
+            case Pmem:
+                (void)getmemsz(ctx, p.pfs_pid);
+                break;
+            case Pregs:
+                Lf->sz = (SZOFFTYPE)sizeof(struct reg);
+                Lf->sz_def = 1;
+                break;
+
+#    if defined(FP_QSIZE)
+            case Pfpregs:
+                Lf->sz = (SZOFFTYPE)sizeof(struct fpreg);
+                Lf->sz_def = 1;
+                break;
+#    endif /* defined(FP_QSIZE) */
+            }
+        }
+        break;
+#endif /* defined(HASPROCFS) */
+
+    case N_REGLR:
+        if (type == VREG || type == VDIR) {
+            switch (nty) {
+            case INODE:
+
+#if defined(HASI_FFS)
+
+                Lf->sz = (SZOFFTYPE)i.i_ffs_size;
+                Lf->sz_def = 1;
+                break;
+#else /* !defined(HASI_FFS) */
+#    if defined(HASI_FFS1)
+
+                if (ffs == 1) {
+                    if (u1s) {
+                        Lf->sz = (SZOFFTYPE)u1.di_size;
+                        Lf->sz_def = 1;
+                    }
+                } else if (ffs == 2) {
+                    if (u2s) {
+                        Lf->sz = (SZOFFTYPE)u2.di_size;
+                        Lf->sz_def = 1;
+                    }
+                }
+                break;
+#    else  /* !defined(HASI_FFS1) */
+                Lf->sz = (SZOFFTYPE)i.i_size;
+                Lf->sz_def = 1;
+#    endif /* defined(HASI_FFS1) */
+#endif     /* defined(HASI_FFS) */
+
+                break;
+
+#if defined(HASMSDOSFS)
+            case DOSNODE:
+                Lf->sz = (SZOFFTYPE)d.de_FileSize;
+                Lf->sz_def = 1;
+                break;
+#endif /* defined(HASMSDOSFS) */
+
+            case MFSNODE:
+                Lf->sz = (SZOFFTYPE)m.mfs_size;
+                Lf->sz_def = 1;
+                break;
+
+#if defined(HASTMPFS)
+            case TMPFSNODE:
+                Lf->sz = (SZOFFTYPE)tmp.tn_size;
+                Lf->sz_def = 1;
+                break;
+#endif /* defined(HASTMPFS) */
+
+#if defined(HASEXT2FS)
+            case EXT2NODE:
+#    if defined(HASI_E2FS_PTR)
+                if (edp) {
+                    Lf->sz = (SZOFFTYPE)edp->e2di_size;
+                    Lf->sz_def = 1;
+                }
+#    else  /* !defined(HASI_E2FS_PTR) */
+                Lf->sz = (SZOFFTYPE)i.i_e2fs_size;
+                Lf->sz_def = 1;
+#    endif /* defined(HASI_E2FS_PTR) */
+                break;
+#endif /* defined(HASEXT2FS) */
+            }
+        }
+        break;
+    }
+    /*
+     * Record the link count.
+     */
+    switch (Ntype) {
+
+#if defined(HAS9660FS)
+    case N_CDFS:
+        if (iso_stat) {
+            Lf->nlink = iso_nlink;
+            Lf->nlink_def = 1;
+        }
+        break;
+#endif /* defined(HAS9660FS) */
+
+#if defined(HASKERNFS)
+    case N_KERN:
+        if (ksbs) {
+            Lf->nlink = (long)ksb.st_nlink;
+            Lf->nlink_def = 1;
+        }
+        break;
+#endif /* defined(HASKERNFS) */
+
+    case N_NFS:
+        if (nty == NFSNODE) {
+            Lf->nlink = (long)NVATTR.va_nlink;
+            Lf->nlink_def = 1;
+        }
+        break;
+    case N_REGLR:
+        switch (nty) {
+        case INODE:
+
+#if defined(HASEFFNLINK)
+            Lf->nlink = (long)i.HASEFFNLINK;
+#else /* !defined(HASEFFNLINK) */
+#    if defined(HASI_FFS)
+            Lf->nlink = (long)i.i_ffs_nlink;
+#    else /* !defined(HASI_FFS) */
+#        if defined(HASI_FFS1)
+            if (ffs == 1) {
+                if (u1s)
+                    Lf->nlink = (long)u1.di_nlink;
+            } else if (ffs == 2) {
+                if (u2s)
+                    Lf->nlink = (long)u2.di_nlink;
+            }
+#        else  /* !defined(HASI_FFS1) */
+
+            Lf->nlink = (long)i.i_nlink;
+#        endif /* defined(HASI_FFS1) */
+#    endif     /* defined(HASI_FFS) */
+#endif         /* defined(HASEFFNLINK) */
+
+            Lf->nlink_def = 1;
+            break;
+
+#if defined(HASMSDOSFS)
+        case DOSNODE:
+            Lf->nlink = (long)d.de_refcnt;
+            Lf->nlink_def = 1;
+            break;
+#endif /* defined(HASMSDOSFS) */
+
+#if defined(HASEXT2FS)
+        case EXT2NODE:
+#    if defined(HASI_E2FS_PTR)
+            if (edp) {
+                Lf->nlink = (long)edp->e2di_nlink;
+                Lf->nlink_def = 1;
+            }
+#    else  /* !defined(HASI_E2FS_PTR) */
+            Lf->nlink = (long)i.i_e2fs_nlink;
+            Lf->nlink_def = 1;
+#    endif /* defined(HASI_E2FS_PTR) */
+
+            break;
+
+#endif /* defined(HASEXT2FS) */
+        }
+        break;
+    }
+    if (Lf->nlink_def && Nlink && (Lf->nlink < Nlink))
+        Lf->sf |= SELNLINK;
+    /*
+     * Record an NFS file selection.
+     */
+    if (Ntype == N_NFS && Fnfs)
+        Lf->sf |= SELNFS;
+
+#if defined(HASNULLFS)
+    /*
+     * If there is a saved nullfs vfs pointer, propagate its device number.
+     */
+    if (nvfs) {
+
+#    if defined(HASSTATVFS)
+        dev = nvfs->fsid.__fsid_val[0];
+#    else  /* !defined(HASSTATVFS) */
+        dev = nvfs->fsid.val[0];
+#    endif /* defined(HASSTATVFS) */
+
+        devs = 1;
+    }
+#endif /* defined(HASNULLFS) */
+
+    /*
+     * Save the file system names.
+     */
+    if (vfs) {
+        Lf->fsdir = vfs->dir;
+        Lf->fsdev = vfs->fsname;
+    }
+    /*
+     * Save the device numbers and their states.
+     *
+     * Format the vnode type, and possibly the device name.
+     */
+    Lf->dev = dev;
+    Lf->dev_def = devs;
+    Lf->rdev = rdev;
+    Lf->rdev_def = rdevs;
+    switch (type) {
+    case VNON:
+        Lf->type = LSOF_FILE_VNODE_VNON;
+        break;
+    case VREG:
+        Lf->type = LSOF_FILE_VNODE_VREG;
+        break;
+    case VDIR:
+        Lf->type = LSOF_FILE_VNODE_VDIR;
+        break;
+    case VBLK:
+        Lf->type = LSOF_FILE_VNODE_VBLK;
+        Ntype = N_BLK;
+        break;
+    case VCHR:
+        Lf->type = LSOF_FILE_VNODE_VCHR;
+        Ntype = N_CHR;
+        break;
+    case VLNK:
+        Lf->type = LSOF_FILE_VNODE_VLNK;
+        break;
+
+#if defined(VSOCK)
+    case VSOCK:
+        Lf->type = LSOF_FILE_VNODE_VSOCK;
+        break;
+#endif /* defined(VSOCK) */
+
+    case VBAD:
+        Lf->type = LSOF_FILE_VNODE_VBAD;
+        break;
+    case VFIFO:
+        Lf->type = LSOF_FILE_VNODE_VFIFO;
+        break;
+    default:
+        Lf->type = LSOF_FILE_UNKNOWN_RAW;
+        Lf->unknown_file_type_number = type;
+    }
+    Lf->ntype = Ntype;
+    /*
+     * Handle some special cases:
+     *
+     *         ioctl(fd, TIOCNOTTY) files;
+     * /kern files
+     * memory node files;
+     * /proc files;
+     * ptyfs files.
+     */
+
+    if (type == VBAD)
+        (void)snpf(Namech, Namechl, "(revoked)");
+    else if (nty == MFSNODE) {
+        Lf->dev_def = Lf->rdev_def = 0;
+        (void)snpf(Namech, Namechl, "%#x", m.mfs_baseoff);
+        enter_dev_ch(ctx, "memory");
+    }
+
+#if defined(HASPROCFS)
+    else if (nty == PFSNODE) {
+        Lf->dev_def = Lf->rdev_def = 0;
+        (void)snpf(Namech, Namechl, "/%s", HASPROCFS);
+        switch (p.pfs_type) {
+        case Proot:
+            Lf->type = LSOF_FILE_PROC_DIR;
+            break;
+        case Pcurproc:
+            ep = endnm(ctx, &sz);
+            (void)snpf(ep, sz, "/curproc");
+            Lf->type = LSOF_FILE_PROC_CUR_PROC;
+            break;
+        case Pproc:
+            ep = endnm(ctx, &sz);
+            (void)snpf(ep, sz, "/%d", p.pfs_pid);
+            Lf->type = LSOF_FILE_PROC_DIR;
+            break;
+        case Pfile:
+            ep = endnm(ctx, &sz);
+            (void)snpf(ep, sz, "/%d/file", p.pfs_pid);
+            Lf->type = LSOF_FILE_PROC_FILE;
+            break;
+        case Pmem:
+            ep = endnm(ctx, &sz);
+            (void)snpf(ep, sz, "/%d/mem", p.pfs_pid);
+            Lf->type = LSOF_FILE_PROC_MEMORY;
+            break;
+        case Pregs:
+            ep = endnm(ctx, &sz);
+            (void)snpf(ep, sz, "/%d/regs", p.pfs_pid);
+            Lf->type = LSOF_FILE_PROC_REGS;
+            break;
+        case Pfpregs:
+            ep = endnm(ctx, &sz);
+            (void)snpf(ep, sz, "/%d/fpregs", p.pfs_pid);
+            Lf->type = LSOF_FILE_PROC_FP_REGS;
+            break;
+
+#    if defined(Pctl)
+        case Pctl:
+            ep = endnm(ctx, &sz);
+            (void)snpf(ep, sz, "/%d/ctl", p.pfs_pid);
+            Lf->type = LSOF_FILE_PROC_CTRL;
+            break;
+#    endif /* defined(Pctl) */
+
+        case Pstatus:
+            ep = endnm(ctx, &sz);
+            (void)snpf(ep, sz, "/%d/status", p.pfs_pid);
+            Lf->type = LSOF_FILE_PROC_STATUS;
+            break;
+        case Pnote:
+            ep = endnm(ctx, &sz);
+            (void)snpf(ep, sz, "/%d/note", p.pfs_pid);
+            Lf->type = LSOF_FILE_PROC_PROC_NOTIFIER;
+            break;
+        case Pnotepg:
+            ep = endnm(ctx, &sz);
+            (void)snpf(ep, sz, "/%d/notepg", p.pfs_pid);
+            Lf->type = LSOF_FILE_PROC_GROUP_NOTIFIER;
+            break;
+
+#    if defined(Pfd)
+        case Pfd:
+            ep = endnm(ctx, &sz);
+            (void)snpf(ep, sz, "/%d/fd", p.pfs_pid);
+            Lf->type = LSOF_FILE_PROC_FD;
+            break;
+#    endif /* defined(Pfd) */
+
+#    if defined(Pmap)
+        case Pmap:
+            ep = endnm(ctx, &sz);
+            (void)snpf(ep, sz, "/%d/map", p.pfs_pid);
+            Lf->type = LSOF_FILE_PROC_MAP;
+            break;
+#    endif /* defined(Pmap) */
+
+#    if defined(Pmaps)
+        case Pmaps:
+            ep = endnm(ctx, &sz);
+            (void)snpf(ep, sz, "/%d/maps", p.pfs_pid);
+            Lf->type = LSOF_FILE_PROC_MAPS;
+            break;
+#    endif /* defined(Pmaps) */
+        }
+    }
+#endif /* defined(HASPROCFS) */
+
+#if defined(HASPTYFS)
+    else if (nty == PTYFSNODE) {
+        (void)snpf(Namech, Namechl, "%s", Lf->fsdir);
+        Lf->nlink = 1;
+        Lf->nlink_def = 1;
+        switch (pt.ptyfs_type) {
+        case PTYFSpts:
+            ep = endnm(ctx, &sz);
+            (void)snpf(ep, sz, "/%lu", (unsigned long)pt.ptyfs_pty);
+            break;
+        case PTYFSptc:
+            ep = endnm(ctx, &sz);
+            (void)snpf(ep, sz, "/%lu (master)", (unsigned long)pt.ptyfs_pty);
+            break;
+        case PTYFSroot:
+            Lf->sz = 512;
+            Lf->sz_def = 1;
+            break;
+        }
+    }
+#endif /* defined(HASPTYFS) */
+
+#if defined(HASBLKDEV)
+    /*
+     * If this is a VBLK file and it's missing an inode number, try to
+     * supply one.
+     */
+    if ((Lf->inp_ty == 0) && (type == VBLK))
+        find_bl_ino(ctx);
+#endif /* defined(HASBLKDEV) */
+
+    /*
+     * If this is a VCHR file and it's missing an inode number, try to
+     * supply one.
+     */
+    if ((Lf->inp_ty == 0) && (type == VCHR))
+        find_ch_ino(ctx);
+        /*
+         * Test for specified file.
+         */
+
+#if defined(HASPROCFS)
+    if (Ntype == N_PROC) {
+        if (Procsrch) {
+            Procfind = 1;
+            Lf->sf |= SELNM;
+        } else if (nty == PFSNODE) {
+            for (pfi = Procfsid; pfi; pfi = pfi->next) {
+                if ((pfi->pid && pfi->pid == p.pfs_pid)
+
+#    if defined(HASPINODEN)
+                    || ((Lf->inp_ty == 1) && (pfi->inode == Lf->inode))
+#    endif /* defined(HASPINODEN) */
+
+                ) {
+                    pfi->f = 1;
+                    if (Namech[0] && pfi->nm)
+                        (void)snpf(Namech, Namechl, "%s", pfi->nm);
+                    Lf->sf |= SELNM;
+                    break;
+                }
+            }
+        }
+    } else
+#endif /* defined(HASPROCFS) */
+
+    {
+        if (Namech[0]) {
+            enter_nm(ctx, Namech);
+            ns = 1;
+        } else
+            ns = 0;
+        if (Sfile &&
+            is_file_named(ctx, (char *)NULL,
+                          ((type == VCHR) || (type == VBLK)) ? 1 : 0)) {
+            Lf->sf |= SELNM;
+        }
+        if (ns)
+            Namech[0] = '\0';
+    }
+    /*
+     * Enter name characters.
+     */
+    if (Namech[0])
+        enter_nm(ctx, Namech);
+}
+
+#if defined(HAS_SYS_PIPEH)
+/*
+ * process_pipe() - process a file structure whose type is DTYPE_PIPE
+ */
+
+void process_pipe(struct lsof_context *ctx, /* context */
+                  KA_T pa)                  /* pipe structure kernel address */
+{
+    char *ep;
+    struct pipe p;
+    size_t sz;
+
+    if (!pa || kread(ctx, (KA_T)pa, (char *)&p, sizeof(p))) {
+        (void)snpf(Namech, Namechl, "can't read DTYPE_PIPE pipe struct: %#s",
+                   print_kptr(pa, (char *)NULL, 0));
+        enter_nm(ctx, Namech);
+        return;
+    }
+    Lf->type = LSOF_FILE_PIPE;
+    enter_dev_ch(ctx, print_kptr(pa, (char *)NULL, 0));
+    Lf->sz = (SZOFFTYPE)p.pipe_buffer.size;
+    Lf->sz_def = 1;
+    if (p.pipe_peer)
+        (void)snpf(Namech, Namechl, "->%s",
+                   print_kptr((KA_T)p.pipe_peer, (char *)NULL, 0));
+    else
+        Namech[0] = '\0';
+    if (p.pipe_buffer.cnt) {
+        ep = endnm(ctx, &sz);
+        (void)snpf(ep, sz, ", cnt=%d", p.pipe_buffer.cnt);
+    }
+    if (p.pipe_buffer.in) {
+        ep = endnm(ctx, &sz);
+        (void)snpf(ep, sz, ", in=%d", p.pipe_buffer.in);
+    }
+    if (p.pipe_buffer.out) {
+        ep = endnm(ctx, &sz);
+        (void)snpf(ep, sz, ", out=%d", p.pipe_buffer.out);
+    }
+    /*
+     * Enter name characters.
+     */
+    if (Namech[0])
+        enter_nm(ctx, Namech);
+}
+#endif /* defined(HAS_SYS_PIPEH) */
diff --git a/lib/dialects/netbsd/dnode1.c b/lib/dialects/netbsd/dnode1.c
new file mode 100644 (file)
index 0000000..7182530
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * dnode1.c - NetBSD node functions for lsof
+ *
+ * This module must be separate to keep separate the multiple kernel inode
+ * structure definitions.
+ */
+
+/*
+ * Copyright 1995 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#ifndef lint
+static char copyright[] =
+    "@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
+#endif
+
+#include "common.h"
+
+#if defined(HAS9660FS)
+/*
+ * Undo some conflicting node header file definitions.
+ */
+
+#    undef doff_t
+#    undef i_dev
+#    undef i_devvp
+#    undef i_number
+#    undef IN_ACCESS
+#    undef IN_LOCKED
+#    undef i_size
+#    undef IN_WANTED
+#    undef i_endoff
+#    undef i_diroff
+#    undef i_offset
+
+/*
+ * At last, #include the desired header files.
+ */
+
+#    if HAS9660FS == 1
+#        include <isofs/cd9660/iso.h>
+#        include <isofs/cd9660/cd9660_node.h>
+#    else /* HAS9660FS!=1 */
+#        include <fs/cd9660/iso.h>
+#        include <fs/cd9660/cd9660_node.h>
+#    endif /* HAS9660FS==1 */
+
+/*
+ * read_iso_node() -- read CD 9660 iso_node
+ */
+
+int read_iso_node(struct lsof_context *ctx, /* context */
+                  struct vnode *v,          /* containing vnode */
+                  dev_t *d,                 /* returned device number */
+                  INODETYPE *ino,           /* returned inode number */
+                  long *nl,                 /* returned link count */
+                  SZOFFTYPE *sz)            /* returned size */
+{
+    struct iso_node i;
+
+    if (!v->v_data || kread(ctx, (KA_T)v->v_data, (char *)&i, sizeof(i)))
+        return (1);
+    *d = i.i_dev;
+    *ino = (INODETYPE)i.i_number;
+    *nl = i.inode.iso_links;
+    *sz = (SZOFFTYPE)i.i_size;
+    return (0);
+}
+#endif /* defined(HAS9660FS) */
diff --git a/lib/dialects/netbsd/dproc.c b/lib/dialects/netbsd/dproc.c
new file mode 100644 (file)
index 0000000..dc9254f
--- /dev/null
@@ -0,0 +1,576 @@
+/*
+ * dproc.c - NetBSD process access functions for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#ifndef lint
+static char copyright[] =
+    "@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
+#endif
+
+#include "common.h"
+
+#if __NetBSD_Version__ >= 499006200
+/*
+ * In NetBSD-4.99.62, struct fdfile was added, struct filedesc::fd_ofiles
+ * changed type from struct file ** to struct fdfile **, and
+ * fd_ofileflags disappeared from struct filedesc, being
+ * replaced by fields in struct fdfile.
+ */
+#    define HAVE_STRUCT_FDFILE 1
+#    define FILESTRUCT struct fdfile
+#else
+#    undef HAVE_STRUCT_FDFILE
+#    define FILESTRUCT struct file
+#endif
+#if __NetBSD_Version__ >= 599001400
+/*
+ * Between NetBSD-5.99.13 and 5.99.14, struct fdtab was added, and
+ * struct filedesc::fd_ofiles and fd_nfiles were replaced by
+ * struct filedesc::fd_dt (a pointer to struct fdtab).
+ */
+#    define HAVE_STRUCT_FDTAB 1
+#    define NFILES(fd, dt) ((dt).dt_nfiles)
+#    define OFILES(fd, dt) ((fd).fd_dt->dt_ff)
+#else
+#    undef HAVE_STRUCT_FDTAB
+#    define NFILES(fd, dt) ((fd).fd_nfiles)
+#    define OFILES(fd, dt) ((fd).fd_ofiles)
+#endif
+
+static void enter_vn_text(struct lsof_context *ctx, KA_T va, int *n);
+static void get_kernel_access(struct lsof_context *ctx);
+static void process_text(struct lsof_context *ctx, KA_T vm);
+
+/*
+ * Local static values
+ */
+
+static MALLOC_S Nv = 0; /* allocated Vp[] entries */
+static KA_T *Vp = NULL; /* vnode address cache */
+
+/*
+ * ckkv - check kernel version
+ */
+
+void ckkv(struct lsof_context *ctx, /* context */
+          char *d,                  /* dialect */
+          char *er,                 /* expected release */
+          char *ev,                 /* expected version */
+          char *ea)                 /* expected architecture */
+{
+
+#if defined(HASKERNIDCK)
+    size_t l;
+    int m[2];
+    char v[64];
+
+    if (Fwarn)
+        return;
+    /*
+     * Read kernel version.
+     */
+    m[0] = CTL_KERN;
+    m[1] = KERN_OSRELEASE;
+    l = sizeof(v);
+    if (sysctl(m, 2, v, &l, NULL, 0) < 0) {
+        (void)fprintf(stderr, "%s: CTL_KERN, KERN_OSRELEASE: %s\n", Pn,
+                      strerror(errno));
+        Error(ctx);
+    }
+    /*
+     * Warn if the actual and expected releases don't match.
+     */
+    if (!er || strcmp(v, er))
+        (void)fprintf(stderr,
+                      "%s: WARNING: compiled for %s release %s; this is %s.\n",
+                      Pn, d, er ? er : "UNKNOWN", v);
+#endif /* defined(HASKERNIDCK) */
+}
+
+/*
+ * enter_vn_text() - enter a vnode text reference
+ */
+
+static void enter_vn_text(struct lsof_context *ctx, /* context */
+                          KA_T va,                  /* vnode address */
+                          int *n)                   /* Vp[] entries in use */
+{
+    int i;
+    /*
+     * Ignore the request if the vnode has already been entered.
+     */
+    for (i = 0; i < *n; i++) {
+        if (va == Vp[i])
+            return;
+    }
+    /*
+     * Save the text file information.
+     */
+    alloc_lfile(ctx, LSOF_FD_PROGRAM_TEXT, -1);
+    Cfp = (struct file *)NULL;
+    process_node(ctx, (KA_T)va);
+    if (Lf->sf)
+        link_lfile(ctx);
+    if (i >= Nv) {
+
+        /*
+         * Allocate space for remembering the vnode.
+         */
+        Nv += 10;
+        if (!Vp)
+            Vp = (KA_T *)malloc((MALLOC_S)(sizeof(struct vnode *) * 10));
+        else
+            Vp = (KA_T *)realloc((MALLOC_P *)Vp, (MALLOC_S)(Nv * sizeof(KA_T)));
+        if (!Vp) {
+            (void)fprintf(stderr, "%s: no txt ptr space, PID %d\n", Pn,
+                          Lp->pid);
+            Error(ctx);
+        }
+    }
+    /*
+     * Remember the vnode.
+     */
+    Vp[*n] = va;
+    (*n)++;
+}
+
+/*
+ * gather_proc_info() -- gather process information
+ */
+
+void gather_proc_info(struct lsof_context *ctx) {
+    struct filedesc fd;
+    int i, nf;
+    MALLOC_S nb;
+    static FILESTRUCT **ofb = NULL;
+    static int ofbb = 0;
+    short pss, sf;
+    int px;
+    uid_t uid;
+
+#if defined(HASCWDINFO)
+    struct cwdinfo cw;
+#    define CDIR cw.cwdi_cdir
+#    define RDIR cw.cwdi_rdir
+#else /* !defined(HASCWDINFO) */
+#    define CDIR fd.fd_cdir
+#    define RDIR fd.fd_rdir
+#endif /* defined(HASCWDINFO) */
+
+#if defined(HASFSTRUCT)
+    static char *pof = (char *)NULL;
+    static int pofb = 0;
+#endif /* defined(HASFSTRUCT) */
+
+#if defined(HASKVMGETPROC2)
+    struct kinfo_proc2 *p;
+#    define KVMPROCSZ2 sizeof(struct kinfo_proc2)
+#else  /* !defined(HASKVMGETPROC2) */
+    struct kinfo_proc *p;
+#endif /* defined(HASKVMGETPROC2) */
+
+#if HAVE_STRUCT_FDTAB
+    struct fdtab dt;
+#endif /* HAVE_STRUCT_FDTAB */
+
+    /*
+     * Read the process table.
+     */
+
+#if defined(HASKVMGETPROC2)
+    P = kvm_getproc2(Kd, KERN_PROC_ALL, 0, KVMPROCSZ2, &Np);
+#else  /* !defined(HASKVMGETPROC2) */
+    P = kvm_getprocs(Kd, KERN_PROC_ALL, 0, &Np);
+#endif /* defined(HASKVMGETPROC2) */
+
+    if (!P) {
+        (void)fprintf(stderr, "%s: can't read process table: %s\n", Pn,
+                      kvm_geterr(Kd));
+        Error(ctx);
+    }
+    /*
+     * Examine proc structures and their associated information.
+     */
+
+    for (p = P, px = 0; px < Np; px++, p++) {
+        if (p->P_STAT == 0 || p->P_STAT == SZOMB)
+            continue;
+        /*
+         * Read process information, process group structure (if
+         * necessary), and User ID (if necessary).
+         *
+         * See if process is excluded.
+         *
+         * Read file structure pointers.
+         */
+        uid = p->P_UID;
+        if (is_proc_excl(ctx, (int)p->P_PID, (int)p->P_PGID, (UID_ARG)uid, &pss,
+                         &sf)) {
+            continue;
+        }
+        if (!p->P_FD || kread(ctx, (KA_T)p->P_FD, (char *)&fd, sizeof(fd)))
+            continue;
+        if (!fd.fd_refcnt)
+            continue;
+#if HAVE_STRUCT_FDTAB
+        if (!fd.fd_dt || kread(ctx, (KA_T)fd.fd_dt, (char *)&dt, sizeof(dt)))
+            continue;
+#endif /* ! HAVE_STRUCT_FDTAB */
+        if (fd.fd_lastfile > NFILES(fd, dt))
+            continue;
+
+#if defined(HASCWDINFO)
+        if (!p->P_CWDI || kread(ctx, (KA_T)p->P_CWDI, (char *)&cw, sizeof(cw)))
+            CDIR = RDIR = (struct vnode *)NULL;
+#endif /* defined(HASCWDINFO) */
+
+        /*
+         * Allocate a local process structure.
+         */
+        if (is_cmd_excl(ctx, p->P_COMM, &pss, &sf))
+            continue;
+        alloc_lproc(ctx, (int)p->P_PID, (int)p->P_PGID, (int)p->P_PPID,
+                    (UID_ARG)uid, p->P_COMM, (int)pss, (int)sf);
+        Plf = (struct lfile *)NULL;
+        Kpa = (KA_T)p->P_ADDR;
+        /*
+         * Save current working directory information.
+         */
+        if (CDIR) {
+            alloc_lfile(ctx, LSOF_FD_CWD, -1);
+            Cfp = (struct file *)NULL;
+            process_node(ctx, (KA_T)CDIR);
+            if (Lf->sf)
+                link_lfile(ctx);
+        }
+        /*
+         * Save root directory information.
+         */
+        if (RDIR) {
+            alloc_lfile(ctx, LSOF_FD_ROOT_DIR, -1);
+            Cfp = (struct file *)NULL;
+            process_node(ctx, (KA_T)RDIR);
+            if (Lf->sf)
+                link_lfile(ctx);
+        }
+
+        /*
+         * Save information on the text file.
+         */
+        if (p->P_VMSPACE)
+            process_text(ctx, (KA_T)p->P_VMSPACE);
+        /*
+         * Read open file structure pointers.
+         */
+        if (!OFILES(fd, dt) || (nf = NFILES(fd, dt)) <= 0)
+            continue;
+        nb = (MALLOC_S)(sizeof(FILESTRUCT *) * nf);
+        if (nb > ofbb) {
+            if (!ofb)
+                ofb = (FILESTRUCT **)malloc(nb);
+            else
+                ofb = (FILESTRUCT **)realloc((MALLOC_P *)ofb, nb);
+            if (!ofb) {
+                (void)fprintf(stderr, "%s: PID %d, no file * space\n", Pn,
+                              p->P_PID);
+                Error(ctx);
+            }
+            ofbb = nb;
+        }
+        if (kread(ctx, (KA_T)OFILES(fd, dt), (char *)ofb, nb))
+            continue;
+
+#if defined(HASFSTRUCT)
+        nb = (MALLOC_S)(sizeof(char) * nf);
+        if (nb > pofb) {
+            if (!pof)
+                pof = (char *)malloc(nb);
+            else
+                pof = (char *)realloc((MALLOC_P *)pof, nb);
+            if (!pof) {
+                (void)fprintf(stderr, "%s: PID %d, no file flag space\n", Pn,
+                              p->P_PID);
+                Error(ctx);
+            }
+            pofb = nb;
+        }
+#    if !HAVE_STRUCT_FDFILE
+        if (!fd.fd_ofileflags || kread(ctx, (KA_T)fd.fd_ofileflags, pof, nb))
+            zeromem(pof, nb);
+#    endif /* ! HAVE_STRUCT_FDFILE */
+#endif     /* defined(HASFSTRUCT) */
+
+        /*
+         * Save information on file descriptors.
+         */
+        for (i = 0; i < nf; i++) {
+            if (ofb[i]) {
+#if HAVE_STRUCT_FDFILE
+                struct fdfile fdf;
+                if (kread(ctx, (KA_T)ofb[i], (char *)&fdf, sizeof(fdf)))
+                    continue;
+                Cfp = fdf.ff_file;
+                if (Cfp == NULL)
+                    continue;
+                if (pof)
+                    pof[i] = fdf.ff_exclose;
+#else  /* ! HAVE_STRUCT_FDFILE */
+                Cfp = ofb[i];
+#endif /* ! HAVE_STRUCT_FDFILE */
+                alloc_lfile(ctx, LSOF_FD_NUMERIC, i);
+                process_file(ctx, (KA_T)Cfp);
+                if (Lf->sf) {
+
+#if defined(HASFSTRUCT)
+                    Lf->pof = (long)pof[i];
+#endif /* defined(HASFSTRUCT) */
+
+                    link_lfile(ctx);
+                }
+            }
+        }
+        /*
+         * Examine results.
+         */
+        if (examine_lproc(ctx))
+            return;
+    }
+}
+
+/*
+ * get_kernel_access() - get access to kernel memory
+ */
+
+static void get_kernel_access(struct lsof_context *ctx) {
+    KA_T v;
+    /*
+     * Check kernel version.
+     */
+    (void)ckkv(ctx, "NetBSD", LSOF_VSTR, (char *)NULL, (char *)NULL);
+    /*
+     * Set name list file path.
+     */
+    if (!Nmlst)
+
+#if defined(N_UNIX)
+        Nmlst = N_UNIX;
+#else  /* !defined(N_UNIX) */
+    {
+        if (!(Nmlst = get_nlist_path(ctx, 1))) {
+            (void)fprintf(stderr, "%s: can't get kernel name list path\n", Pn);
+            Error(ctx);
+        }
+    }
+#endif /* defined(N_UNIX) */
+
+#if defined(WILLDROPGID)
+    /*
+     * If kernel memory isn't coming from KMEM, drop setgid permission
+     * before attempting to open the (Memory) file.
+     */
+    if (Memory)
+        (void)dropgid(ctx);
+#else  /* !defined(WILLDROPGID) */
+    /*
+     * See if the non-KMEM memory and name list files are readable.
+     */
+    if ((Memory && !is_readable(Memory, 1)) ||
+        (Nmlst && !is_readable(Nmlst, 1)))
+        Error(ctx);
+#endif /* defined(WILLDROPGID) */
+
+    /*
+     * Open kernel memory access.
+     */
+    if ((Kd = kvm_openfiles(Nmlst, Memory, NULL, O_RDONLY, NULL)) == NULL) {
+        (void)fprintf(stderr,
+                      "%s: kvm_openfiles(execfile=%s, corefile=%s): %s\n", Pn,
+                      Nmlst,
+                      Memory ? Memory :
+
+#if defined(_PATH_MEM)
+                             _PATH_MEM,
+#else  /* !defined(_PATH_MEM) */
+                             "default",
+#endif /* defined(_PATH_MEM) */
+
+                      strerror(errno));
+        Error(ctx);
+    }
+    (void)build_Nl(ctx, Drive_Nl);
+    if (kvm_nlist(Kd, Nl) < 0) {
+        (void)fprintf(stderr, "%s: can't read namelist from %s\n", Pn, Nmlst);
+        Error(ctx);
+    }
+
+#if defined(WILLDROPGID)
+    /*
+     * Drop setgid permission, if necessary.
+     */
+    if (!Memory)
+        (void)dropgid(ctx);
+#endif /* defined(WILLDROPGID) */
+
+    /*
+     * Read the kernel's page shift amount, if possible.
+     */
+    if (get_Nl_value(ctx, "pgshift", Drive_Nl, &v) < 0 || !v ||
+        kread(ctx, (KA_T)v, (char *)&pgshift, sizeof(pgshift)))
+        pgshift = 0;
+}
+
+#if !defined(N_UNIX)
+/*
+ * get_nlist_path() - get kernel name list path
+ */
+
+char *get_nlist_path(struct lsof_context *ctx, /* context */
+                     int ap) /* on success, return an allocated path
+                              * string pointer if 1; return a
+                              * constant character pointer if 0;
+                              * return NULL if failure */
+{
+    const char *bf;
+    static char *bfc;
+    MALLOC_S bfl;
+    /*
+     * Get bootfile name.
+     */
+    if ((bf = getbootfile())) {
+        if (!ap)
+            return ("");
+        bfl = (MALLOC_S)(strlen(bf) + 1);
+        if (!(bfc = (char *)malloc(bfl))) {
+            (void)fprintf(
+                stderr, "%s: can't allocate %d bytes for boot file path: %s\n",
+                Pn, bfl, bf);
+            Error(ctx);
+        }
+        (void)snpf(bfc, bfl, "%s", bf);
+        return (bfc);
+    }
+    return ((char *)NULL);
+}
+#endif /* !defined(N_UNIX) */
+
+/*
+ * initialize() - perform all initialization
+ */
+
+void initialize(struct lsof_context *ctx) { get_kernel_access(ctx); }
+
+/*
+ * kread() - read from kernel memory
+ */
+
+int kread(struct lsof_context *ctx, /* context */
+          KA_T addr,                /* kernel memory address */
+          char *buf,                /* buffer to receive data */
+          READLEN_T len)            /* length to read */
+{
+    int br;
+
+    br = kvm_read(Kd, (u_long)addr, buf, len);
+    return ((br == len) ? 0 : 1);
+}
+
+/*
+ * process_text() - process text information
+ */
+void process_text(struct lsof_context *ctx, /* context */
+                  KA_T vm)                  /* kernel vm space pointer */
+{
+    int i, j;
+    KA_T ka;
+    int n = 0;
+    struct vm_map_entry vmme, *e;
+    struct vmspace vmsp;
+
+#if !defined(UVM)
+    struct pager_struct pg;
+    struct vm_object vmo;
+#endif /* !defined(UVM) */
+
+    /*
+     * Read the vmspace structure for the process.
+     */
+    if (kread(ctx, vm, (char *)&vmsp, sizeof(vmsp)))
+        return;
+        /*
+         * Read the vm_map structure.  Search its vm_map_entry structure list.
+         */
+
+#if !defined(UVM)
+    if (!vmsp.vm_map.is_main_map)
+        return;
+#endif /* !defined(UVM) */
+
+    for (i = 0; i < vmsp.vm_map.nentries; i++) {
+
+        /*
+         * Read the next vm_map_entry.
+         */
+        if (!i)
+            e = &vmsp.vm_map.header;
+        else {
+            if (!(ka = (KA_T)e->next))
+                return;
+            e = &vmme;
+            if (kread(ctx, ka, (char *)e, sizeof(vmme)))
+                return;
+        }
+
+#if defined(UVM)
+        /*
+         * Process the uvm_obj pointer of a UVM map entry with a UVM_ET_OBJ
+         * type as a vnode pointer.
+         */
+        if ((e->etype > UVM_ET_OBJ) && e->object.uvm_obj)
+            (void)enter_vn_text(ctx, (KA_T)e->object.uvm_obj, &n);
+#else  /* !defined(UVM) */
+        /*
+         * Read the map entry's object and the object's shadow.
+         * Look for a PG_VNODE pager handle.
+         */
+        if (e->is_a_map || e->is_sub_map)
+            continue;
+        for (j = 0, ka = (KA_T)e->object.vm_object; j < 2 && ka;
+             j++, ka = (KA_T)vmo.shadow) {
+            if (kread(ctx, ka, (char *)&vmo, sizeof(vmo)))
+                break;
+            if (!(ka = (KA_T)vmo.pager) ||
+                kread(ctx, ka, (char *)&pg, sizeof(pg)))
+                continue;
+            if (!pg.pg_handle || pg.pg_type != PG_VNODE)
+                continue;
+            (void)enter_vn_text((KA_T)pg.pg_handle, &n);
+        }
+#endif /* defined(UVM) */
+    }
+}
diff --git a/lib/dialects/netbsd/dproto.h b/lib/dialects/netbsd/dproto.h
new file mode 100644 (file)
index 0000000..897b155
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * dproto.h - NetBSD function prototypes for lsof
+ *
+ * The _PROTOTYPE macro is defined in the common proto.h.
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+/*
+ * $Id: dproto.h,v 1.11 2005/08/08 19:53:24 abe Exp $
+ */
+
+#if !defined(N_UNIX)
+extern char *get_nlist_path(struct lsof_context *ctx, int ap);
+#endif /* !defined(N_UNIX) */
+
+extern int is_file_named(struct lsof_context *ctx, char *p, int cd);
+extern struct l_vfs *readvfs(struct lsof_context *ctx, KA_T vm);
+
+#if defined(HAS_SYS_PIPEH)
+extern void process_pipe(struct lsof_context *ctx, KA_T pa);
+#endif /* defined(HAS_SYS_PIPEH) */
+
+#if defined(HAS9660FS)
+extern int read_iso_node(struct lsof_context *ctx, struct vnode *v, dev_t *d,
+                         INODETYPE *ino, long *nl, SZOFFTYPE *sz);
+#endif /* defined(HAS9660FS) */
+
+extern void process_socket(struct lsof_context *ctx, KA_T sa);
diff --git a/lib/dialects/netbsd/dsock.c b/lib/dialects/netbsd/dsock.c
new file mode 100644 (file)
index 0000000..2c1aacb
--- /dev/null
@@ -0,0 +1,438 @@
+/*
+ * dsock.c - NetBSD socket processing functions for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#ifndef lint
+static char copyright[] =
+    "@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
+#endif
+
+#include "common.h"
+
+#if defined(HASIPv6)
+
+/*
+ * IPv6_2_IPv4()  -- macro to define the address of an IPv4 address contained
+ *                  in an IPv6 address
+ */
+
+#    define IPv6_2_IPv4(v6) (((uint8_t *)((struct in6_addr *)v6)->s6_addr) + 12)
+#endif /* defined(HASIPv6) */
+
+/*
+ * process_socket() - process socket
+ */
+
+void process_socket(struct lsof_context *ctx, /* context */
+                    KA_T sa)                  /* socket address in kernel */
+{
+#if NETBSDV >= 9099104
+#    define NETBSD_MERGED_INPCB
+#endif
+    struct domain d;
+    unsigned char *fa = (unsigned char *)NULL;
+    int fam;
+    int fp, lp;
+#ifdef NETBSD_MERGED_INPCB
+    struct in4pcb inp;
+#else
+    struct inpcb inp;
+#endif
+    unsigned char *la = (unsigned char *)NULL;
+    struct protosw p;
+    struct socket s;
+    struct tcpcb t;
+    KA_T ta = (KA_T)NULL;
+    struct unpcb uc, unp;
+    struct sockaddr_un *ua = NULL;
+    struct sockaddr_un un;
+
+#if defined(HASIPv6) && defined(NETBSDV) && !defined(HASINRIAIPv6)
+#    ifdef NETBSD_MERGED_INPCB
+#        define in6p_ppcb in6p_pcb.inp_ppcb
+#    endif
+    struct in6pcb in6p;
+#endif /* defined(HASIPv6) && defined(NETBSDV) && !defined(HASINRIAIPv6) */
+
+#define UNPADDR_IN_MBUF
+
+#if defined(NETBSDV)
+#    if NETBSDV >= 1004000
+#        undef UNPADDR_IN_MBUF
+#    endif /* NETBSDV>=1004000 */
+#endif     /* defined(NETBSDV) */
+
+#if defined(UNPADDR_IN_MBUF)
+    struct mbuf mb;
+#endif /* defined(UNPADDR_IN_MBUF) */
+
+    Lf->type = LSOF_FILE_SOCKET;
+    Lf->inp_ty = 2;
+    /*
+     * Read the socket, protocol, and domain structures.
+     */
+    if (!sa) {
+        enter_nm(ctx, "no socket address");
+        return;
+    }
+    if (kread(ctx, sa, (char *)&s, sizeof(s))) {
+        (void)snpf(Namech, Namechl, "can't read socket struct from %s",
+                   print_kptr(sa, (char *)NULL, 0));
+        enter_nm(ctx, Namech);
+        return;
+    }
+    if (!s.so_type) {
+        enter_nm(ctx, "no socket type");
+        return;
+    }
+    if (!s.so_proto || kread(ctx, (KA_T)s.so_proto, (char *)&p, sizeof(p))) {
+        (void)snpf(Namech, Namechl, "can't read protocol switch from %s",
+                   print_kptr((KA_T)s.so_proto, (char *)NULL, 0));
+        enter_nm(ctx, Namech);
+        return;
+    }
+    if (!p.pr_domain || kread(ctx, (KA_T)p.pr_domain, (char *)&d, sizeof(d))) {
+        (void)snpf(Namech, Namechl, "can't read domain struct from %s",
+                   print_kptr((KA_T)p.pr_domain, (char *)NULL, 0));
+        enter_nm(ctx, Namech);
+        return;
+    }
+    /*
+     * Save size information.
+     */
+    if (Lf->access == LSOF_FILE_ACCESS_READ)
+        Lf->sz = (SZOFFTYPE)s.so_rcv.sb_cc;
+    else if (Lf->access == LSOF_FILE_ACCESS_WRITE)
+        Lf->sz = (SZOFFTYPE)s.so_snd.sb_cc;
+    else
+        Lf->sz = (SZOFFTYPE)(s.so_rcv.sb_cc + s.so_snd.sb_cc);
+    Lf->sz_def = 1;
+
+#if defined(HASTCPTPIQ)
+    Lf->lts.rq = s.so_rcv.sb_cc;
+    Lf->lts.sq = s.so_snd.sb_cc;
+    Lf->lts.rqs = Lf->lts.sqs = 1;
+#endif /* defined(HASTCPTPIQ) */
+
+#if defined(HASSOOPT)
+    Lf->lts.ltm = (unsigned int)s.so_linger;
+    Lf->lts.opt = (unsigned int)s.so_options;
+    Lf->lts.pqlen = (unsigned int)s.so_q0len;
+    Lf->lts.qlen = (unsigned int)s.so_qlen;
+    Lf->lts.qlim = (unsigned int)s.so_qlimit;
+    Lf->lts.rbsz = (unsigned long)s.so_rcv.sb_mbmax;
+    Lf->lts.sbsz = (unsigned long)s.so_snd.sb_mbmax;
+    Lf->lts.pqlens = Lf->lts.qlens = Lf->lts.qlims = Lf->lts.rbszs =
+        Lf->lts.sbszs = (unsigned char)1;
+#endif /* defined(HASSOOPT) */
+
+#if defined(HASSOSTATE)
+    Lf->lts.ss = (unsigned int)s.so_state;
+#endif /* defined(HASSOSTATE) */
+
+    /*
+     * Process socket by the associated domain family.
+     */
+    switch ((fam = d.dom_family)) {
+        /*
+         * Process an Internet domain socket.
+         */
+    case AF_INET:
+
+#if defined(HASIPv6)
+    case AF_INET6:
+#endif /* defined(HASIPv6) */
+
+        if (Fnet) {
+            if (!FnetTy || ((FnetTy == 4) && (fam == AF_INET))
+
+#if defined(HASIPv6)
+                || ((FnetTy == 6) && (fam == AF_INET6))
+#endif /* defined(HASIPv6) */
+            )
+
+                Lf->sf |= SELNET;
+        }
+        printiproto(ctx, p.pr_protocol);
+
+#if defined(HASIPv6)
+        Lf->type = (fam == AF_INET) ? LSOF_FILE_IPV4 : LSOF_FILE_IPV6;
+#else  /* !defined(HASIPv6) */
+        Lf->type = LSOF_FILE_INET;
+#endif /* defined(HASIPv6) */
+
+#if defined(HASIPv6) && defined(NETBSDV) && !defined(HASINRIAIPv6)
+        if (fam == AF_INET6) {
+
+            /*
+             * Read IPv6 protocol control block.
+             */
+            if (!s.so_pcb ||
+                kread(ctx, (KA_T)s.so_pcb, (char *)&in6p, sizeof(in6p))) {
+                (void)snpf(Namech, Namechl, "can't read in6pcb at %s",
+                           print_kptr((KA_T)s.so_pcb, (char *)NULL, 0));
+                enter_nm(ctx, Namech);
+                return;
+            }
+            /*
+             * Save IPv6 address information.
+             */
+            enter_dev_ch(ctx, print_kptr((KA_T)(in6p.in6p_ppcb ? in6p.in6p_ppcb
+                                                               : s.so_pcb),
+                                         (char *)NULL, 0));
+            if (p.pr_protocol == IPPROTO_TCP)
+                ta = (KA_T)in6p.in6p_ppcb;
+#    ifdef NETBSD_MERGED_INPCB
+            la = (unsigned char *)&in6p_laddr(&in6p);
+            lp = (int)ntohs(in6p.in6p_pcb.inp_lport);
+            if (!IN6_IS_ADDR_UNSPECIFIED(&in6p_faddr(&in6p)) ||
+                (in6p.in6p_pcb.inp_fport)) {
+                fa = (unsigned char *)&in6p_faddr(&in6p);
+                fp = (int)ntohs(in6p.in6p_pcb.inp_fport);
+            }
+#    else
+            la = (unsigned char *)&in6p.in6p_laddr;
+            lp = (int)ntohs(in6p.in6p_lport);
+            if (!IN6_IS_ADDR_UNSPECIFIED(&in6p.in6p_faddr) || in6p.in6p_fport) {
+                fa = (unsigned char *)&in6p.in6p_faddr;
+                fp = (int)ntohs(in6p.in6p_fport);
+            }
+#    endif
+        } else
+#endif /* defined(HASIPv6) && defined(NETBSDV) && !defined(HASINRIAIPv6) */
+
+        {
+
+            /*
+             * Read IPv4 or IPv6 (NetBSD) protocol control block.
+             */
+            if (!s.so_pcb ||
+                kread(ctx, (KA_T)s.so_pcb, (char *)&inp, sizeof(inp))) {
+                if (!s.so_pcb) {
+                    (void)snpf(
+                        Namech, Namechl, "no PCB%s%s",
+                        (s.so_state & SS_CANTSENDMORE) ? ", CANTSENDMORE" : "",
+                        (s.so_state & SS_CANTRCVMORE) ? ", CANTRCVMORE" : "");
+                } else {
+                    (void)snpf(Namech, Namechl, "can't read inpcb at %s",
+                               print_kptr((KA_T)s.so_pcb, (char *)NULL, 0));
+                }
+                enter_nm(ctx, Namech);
+                return;
+            }
+#ifdef NETBSD_MERGED_INPCB
+#    define inp_ppcb in4p_pcb.inp_ppcb
+#    define inp_lport in4p_pcb.inp_lport
+#endif
+            enter_dev_ch(
+                ctx, print_kptr((KA_T)(inp.inp_ppcb ? inp.inp_ppcb : s.so_pcb),
+                                (char *)NULL, 0));
+            if (p.pr_protocol == IPPROTO_TCP)
+                ta = (KA_T)inp.inp_ppcb;
+            lp = (int)ntohs(inp.inp_lport);
+#ifdef NETBSD_MERGED_INPCB
+#    undef inp_ppcb
+#    undef inp_lport
+#endif
+            if (fam == AF_INET) {
+
+                /*
+                 * Save IPv4 address information.
+                 */
+#ifdef NETBSD_MERGED_INPCB
+                la = (unsigned char *)&in4p_laddr(&inp);
+                if (in4p_faddr(&inp).s_addr != INADDR_ANY ||
+                    inp.in4p_pcb.inp_fport) {
+                    fa = (unsigned char *)&in4p_faddr(&inp);
+                    fp = (int)ntohs(inp.in4p_pcb.inp_fport);
+                }
+#else
+                la = (unsigned char *)&inp.inp_laddr;
+                if (inp.inp_faddr.s_addr != INADDR_ANY || inp.inp_fport) {
+                    fa = (unsigned char *)&inp.inp_faddr;
+                    fp = (int)ntohs(inp.inp_fport);
+                }
+#endif
+            }
+
+#if defined(HASIPv6) && defined(HASINRIAIPv6)
+            else {
+                la = (unsigned char *)&inp.inp_laddr6;
+                if (!IN6_IS_ADDR_UNSPECIFIED(&inp.inp_faddr6) ||
+                    inp.inp_fport) {
+                    fa = (unsigned char *)&inp.inp_faddr6;
+                    fp = (int)ntohs(inp.inp_fport);
+                }
+            }
+#endif /* defined(HASIPv6) && defined(HASINRIAIPv6) */
+        }
+
+#if defined(HASIPv6)
+        if ((fam == AF_INET6) &&
+            ((la && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)la)) ||
+             ((fa && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)fa))))) {
+
+            /*
+             * Adjust for IPv4 addresses mapped in IPv6 addresses.
+             */
+            if (la)
+                la = (unsigned char *)IPv6_2_IPv4(la);
+            if (fa)
+                fa = (unsigned char *)IPv6_2_IPv4(fa);
+            fam = AF_INET;
+        }
+#endif /* defined(HASIPv6) */
+
+        /*
+         * Enter local and remote addresses by address family.
+         */
+        if (fa || la)
+            (void)ent_inaddr(ctx, la, lp, fa, fp, fam);
+        /*
+         * If the protocol is TCP, and its address is available, read the
+         * TCP protocol control block and save its state.
+         */
+        if (ta && !kread(ctx, ta, (char *)&t, sizeof(t))) {
+            Lf->lts.type = 0;
+            Lf->lts.state.i = (int)t.t_state;
+
+#if defined(HASTCPOPT)
+            Lf->lts.mss = (unsigned long)t.t_ourmss;
+
+            Lf->lts.msss = (unsigned char)1;
+            Lf->lts.topt = (unsigned int)t.t_flags;
+#endif /* defined(HASTCPOPT) */
+        }
+        break;
+        /*
+         * Process a ROUTE domain socket.
+         */
+    case AF_ROUTE:
+        Lf->type = LSOF_FILE_ROUTE;
+        if (s.so_pcb)
+            enter_dev_ch(ctx, print_kptr((KA_T)(s.so_pcb), (char *)NULL, 0));
+        else
+            (void)snpf(Namech, Namechl, "no protocol control block");
+        break;
+        /*
+         * Process a Unix domain socket.
+         */
+    case AF_UNIX:
+        if (Funix)
+            Lf->sf |= SELUNX;
+        Lf->type = LSOF_FILE_UNIX;
+        /*
+         * Read Unix protocol control block and the Unix address structure.
+         */
+
+        enter_dev_ch(ctx, print_kptr(sa, (char *)NULL, 0));
+        if (kread(ctx, (KA_T)s.so_pcb, (char *)&unp, sizeof(unp))) {
+            (void)snpf(Namech, Namechl, "can't read unpcb at %s",
+                       print_kptr((KA_T)s.so_pcb, (char *)NULL, 0));
+            break;
+        }
+        if ((struct socket *)sa != unp.unp_socket) {
+            (void)snpf(Namech, Namechl, "unp_socket (%s) mismatch",
+                       print_kptr((KA_T)unp.unp_socket, (char *)NULL, 0));
+            break;
+        }
+        if (unp.unp_addr) {
+
+#if defined(UNPADDR_IN_MBUF)
+            if (kread(ctx, (KA_T)unp.unp_addr, (char *)&mb, sizeof(mb)))
+#else  /* !defined(UNPADDR_IN_MBUF) */
+            if (kread(ctx, (KA_T)unp.unp_addr, (char *)&un, sizeof(un)))
+#endif /* defined(UNPADDR_IN_MBUF) */
+
+            {
+                (void)snpf(Namech, Namechl, "can't read unp_addr at %s",
+                           print_kptr((KA_T)unp.unp_addr, (char *)NULL, 0));
+                break;
+            }
+
+#if defined(UNPADDR_IN_MBUF)
+            if (mb.m_hdr.mh_len == sizeof(struct sockaddr_un))
+                ua = (struct sockaddr_un *)((char *)&mb +
+                                            (mb.m_hdr.mh_data -
+                                             (caddr_t)unp.unp_addr));
+#else  /* !defined(UNPADDR_IN_MBUF) */
+            ua = &un;
+#endif /* defined(UNPADDR_IN_MBUF) */
+        }
+        if (!ua) {
+            ua = &un;
+            (void)bzero((char *)ua, sizeof(un));
+            ua->sun_family = AF_UNSPEC;
+        }
+        /*
+         * Print information on Unix socket that has no address bound
+         * to it, although it may be connected to another Unix domain
+         * socket as a pipe.
+         */
+        if (ua->sun_family != AF_UNIX) {
+            if (ua->sun_family == AF_UNSPEC) {
+                if (unp.unp_conn) {
+                    if (kread(ctx, (KA_T)unp.unp_conn, (char *)&uc, sizeof(uc)))
+                        (void)snpf(
+                            Namech, Namechl, "can't read unp_conn at %s",
+                            print_kptr((KA_T)unp.unp_conn, (char *)NULL, 0));
+                    else
+                        (void)snpf(
+                            Namech, Namechl, "->%s",
+                            print_kptr((KA_T)uc.unp_socket, (char *)NULL, 0));
+                } else
+                    (void)snpf(Namech, Namechl, "->(none)");
+            } else
+                (void)snpf(Namech, Namechl, "unknown sun_family (%d)",
+                           ua->sun_family);
+            break;
+        }
+        if (ua->sun_path[0]) {
+
+#if defined(UNPADDR_IN_MBUF)
+            if (mb.m_len >= sizeof(struct sockaddr_un))
+                mb.m_len = sizeof(struct sockaddr_un) - 1;
+            *((char *)ua + mb.m_len) = '\0';
+#else  /* !defined(UNPADDR_IN_MBUF) */
+            ua->sun_path[sizeof(ua->sun_path) - 1] = '\0';
+#endif /* defined(UNPADDR_IN_MBUF) */
+
+            if (Sfile && is_file_named(ctx, ua->sun_path, 0))
+                Lf->sf |= SELNM;
+            if (!Namech[0])
+                (void)snpf(Namech, Namechl, "%s", ua->sun_path);
+        } else
+            (void)snpf(Namech, Namechl, "no address");
+        break;
+    default:
+        printunkaf(ctx, fam, 1);
+    }
+    if (Namech[0])
+        enter_nm(ctx, Namech);
+}
diff --git a/lib/dialects/netbsd/dstore.c b/lib/dialects/netbsd/dstore.c
new file mode 100644 (file)
index 0000000..1a46015
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * dstore.c - NetBSD and global storage for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#ifndef lint
+static char copyright[] =
+    "@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
+#endif
+
+#include "common.h"
+
+struct file *Cfp; /* current file's file struct pointer */
+
+/*
+ * Drive_Nl -- table to drive the building of Nl[] via build_Nl()
+ *             (See lsof.h and misc.c.)
+ */
+
+struct drive_Nl Drive_Nl[] = {
+#if (defined(NETBSDV) && NETBSDV >= 9099000)
+    {
+        "rootvnode",
+        "rootvnode",
+    },
+#endif
+#if defined(NETBSDV) && NETBSDV >= 1002000
+    {
+        X_NCACHE,
+        "_nchashtbl",
+    },
+    {X_NCSIZE, "_nchash"},
+#else /* defined(NETBSDV) && NETBSDV>=1002000 */
+#    if defined(NetBSD1_0) && NetBSD < 1994101
+    {
+        X_NCACHE,
+        "_nchhead",
+    },
+#    else  /* !defined(NetBSD1_0) || NetBSD>=1994101 */
+    {X_NCACHE, "_nclruhead"},
+#    endif /* defined(NetBSD1_0) && NetBSD<1994101 */
+
+    {X_NCSIZE, "_numcache"},
+#endif     /* defined(NETBSDV) && NETBSDV>=1002000 */
+
+    {"pgshift", "_pgshift"},
+    {"", ""},
+    {NULL, NULL}};
+
+kvm_t *Kd; /* kvm descriptor */
+KA_T Kpa;  /* kernel proc struct address */
+
+struct l_vfs *Lvfs = NULL; /* local vfs structure table */
+
+int Np = 0; /* number of kernel processes */
+
+#if defined(HASKVMGETPROC2)
+struct kinfo_proc2 *P = NULL; /* local process table copy */
+#else                         /* !defined(HASKVMGETPROC2) */
+struct kinfo_proc *P = NULL; /* local process table copy */
+#endif                        /* defined(HASKVMGETPROC2) */
+
+#if defined(HASFSTRUCT)
+/*
+ * Pff_tab[] - table for printing file flags
+ */
+
+struct pff_tab Pff_tab[] = {{(long)FREAD, FF_READ},
+                            {(long)FWRITE, FF_WRITE},
+                            {(long)FNONBLOCK, FF_NBLOCK},
+                            {(long)FNDELAY, FF_NDELAY},
+                            {(long)FAPPEND, FF_APPEND},
+                            {(long)FASYNC, FF_ASYNC},
+
+#    if defined(FDSYNC)
+                            {(long)FDSYNC, FF_DSYNC},
+#    endif /* defined*FDSYNC) */
+
+                            {(long)FFSYNC, FF_FSYNC},
+
+#    if defined(FRSYNC)
+                            {(long)FRSYNC, FF_RSYNC},
+#    endif /* defined(FRSYNC( */
+
+                            {(long)FMARK, FF_MARK},
+                            {(long)FDEFER, FF_DEFER},
+                            {(long)FHASLOCK, FF_HASLOCK},
+                            {(long)O_NOCTTY, FF_NOCTTY},
+                            {(long)0, NULL}};
+
+/*
+ * Pof_tab[] - table for print process open file flags
+ */
+
+struct pff_tab Pof_tab[] = {
+
+#    if defined(UF_EXCLOSE)
+    {(long)UF_EXCLOSE, POF_CLOEXEC},
+#    else
+    {(long)1, POF_CLOEXEC},
+#    endif /* defined(UF_EXCLOSE) */
+
+#    if defined(UF_MAPPED)
+    {(long)UF_MAPPED, POF_MAPPED},
+#    endif /* defined(UF_MAPPED) */
+
+    {(long)0, NULL}};
+#endif /* defined(HASFSTRUCT) */
+
+int pgshift = 0; /* kernel's page shift */
diff --git a/lib/dialects/netbsd/machine.h b/lib/dialects/netbsd/machine.h
new file mode 100644 (file)
index 0000000..18400ca
--- /dev/null
@@ -0,0 +1,575 @@
+/*
+ * machine.h - NetBSD definitions for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+/*
+ * $Id: machine.h,v 1.39 2010/07/29 16:02:52 abe Exp $
+ */
+
+#if !defined(LSOF_MACHINE_H)
+#    define LSOF_MACHINE_H 1
+
+#    ifdef AUTOTOOLS
+#        include "autotools.h"
+#    endif
+
+#    include <sys/types.h>
+#    include <sys/param.h>
+#    include <stdbool.h>
+#    if __NetBSD_Version__ >= 499006200
+#        define HASCWDINFO
+#    endif
+
+/*
+ * CAN_USE_CLNT_CREATE is defined for those dialects where RPC clnt_create()
+ * can be used to obtain a CLIENT handle in lieu of clnttcp_create().
+ */
+
+#    define CAN_USE_CLNT_CREATE 1
+
+/*
+ * DEVDEV_PATH defines the path to the directory that contains device
+ * nodes.
+ */
+
+#    define DEVDEV_PATH "/dev"
+
+/*
+ * GET_MAX_FD is defined for those dialects that provide a function other than
+ * getdtablesize() to obtain the maximum file descriptor number plus one.
+ */
+
+/* #define     GET_MAX_FD      ?       */
+
+/*
+ * HASAOPT is defined for those dialects that have AFS support; it specifies
+ * that the default path to an alternate AFS kernel name list file may be
+ * supplied with the -A <path> option.
+ */
+
+/* #define     HASAOPT         1 */
+
+/*
+ * HASBLKDEV is defined for those dialects that want block device information
+ * recorded in BDevtp[].
+ */
+
+#    define HASBLKDEV 1
+
+/*
+ * HASDCACHE is defined for those dialects that support a device cache
+ * file.
+ *
+ * HASENVDC defined the name of an environment variable that contains the
+ * device cache file path.  The HASENVDC environment variable is ignored when
+ * the lsof process is setuid(root) or its real UID is 0.
+ *
+ * HASPERSDC defines the format for the last component of a personal device
+ * cache file path.  The first will be the home directory of the real UID that
+ * executes lsof.
+ *
+ * HASPERSDCPATH defines the environment variable whose value is the middle
+ * component of the personal device cache file path.  The middle component
+ * follows the home directory and precedes the results of applying HASPERSDC.
+ * The HASPERSDCPATH environment variable is ignored when the lsof process is
+ * setuid(root) or its real UID is 0.
+ *
+ * HASSYSDC defines a public device cache file path.  When it's defined, it's
+ * used as the path from which to read the device cache.
+ *
+ * Consult the 00DCACHE and 00FAQ files of the lsof distribution for more
+ * information on device cache file path construction.
+ */
+
+#    define HASDCACHE 1
+#    define HASENVDC "LSOFDEVCACHE"
+#    define HASPERSDC "%h/%p.lsof_%L"
+#    define HASPERSDCPATH "LSOFPERSDCPATH"
+/* #define     HASSYSDC        "/your/choice/of/path" */
+
+/*
+ * HASCDRNODE is defined for those dialects that have CD-ROM nodes.
+ */
+
+/* #define     HASCDRNODE      1 */
+
+/*
+ * HASFIFONODE is defined for those dialects that have FIFO nodes.
+ */
+
+/* #define     HASFIFONODE     1 */
+
+/*
+ * HASFSINO is defined for those dialects that have the file system
+ * inode element, fs_ino, in the lfile structure definition in lsof.h.
+ */
+
+/* #define     HASFSINO        1 */
+
+/*
+ * HASFSTRUCT is defined if the dialect has a file structure.
+ *
+ * FSV_DEFAULT defines the default set of file structure values to list.
+ * It defaults to zero (0), but may be made up of a combination of the
+ * FSV_* symbols from lsof.h.
+ *
+ *   HASNOFSADDR  -- has no file structure address
+ *   HASNOFSFLAGS -- has no file structure flags
+ *   HASNOFSCOUNT -- has no file structure count
+ *   HASNOFSNADDR -- has no file structure node address
+ */
+
+#    define HASFSTRUCT 1
+/* #define     FSV_DEFAULT     FSV_? | FSV_? | FSV_? */
+/* #define     HASNOFSADDR     1       has no file structure address */
+/* #define     HASNOFSFLAGS    1       has no file structure flags */
+/* #define     HASNOFSCOUNT    1       has no file structure count */
+/* #define     HASNOFSNADDR    1       has no file structure node address */
+
+/*
+ * HASGNODE is defined for those dialects that have gnodes.
+ */
+
+/* #define     HASGNODE        1 */
+
+/*
+ * HASHSNODE is defined for those dialects that have High Sierra nodes.
+ */
+
+/* #define     HASHSNODE       1 */
+
+/*
+ * HASINODE is defined for those dialects that have inodes and wish to
+ * use readinode() from node.c.
+ */
+
+#    define HASINODE 1
+
+/*
+ * HASINTSIGNAL is defined for those dialects whose signal function returns
+ * an int.
+ */
+
+/* #define     HASINTSIGNAL    1 */
+
+/*
+ * HASKERNIDCK is defined for those dialects that support the comparison of
+ * the build to running kernel identity.
+ */
+
+#    define HASKERNIDCK 1
+
+/*
+ * HASKOPT is defined for those dialects that support the -k option of
+ * reading the kernel's name list from an optional file.
+ */
+
+#    define HASKOPT 1
+
+/*
+ * HASLFILEADD is defined for those dialects that need additional elements
+ * in struct lfile.  The HASLFILEADD definition is a macro that defines
+ * them.  If any of the additional elements need to be preset in the
+ * alloc_lfile() function of proc.c, the SETLFILEADD macro may be defined
+ * to do that.
+ *
+ * If any additional elements need to be cleared in alloc_lfile() or in the
+ * free_proc() function of proc.c, the CLRLFILEADD macro may be defined to
+ * do that.  Note that CLRLFILEADD takes one argument, the pointer to the
+ * lfile struct.  The CLRLFILEADD macro is expected to expand to statements
+ * that are complete -- i.e., have terminating semi-colons -- so the macro is
+ * called without a terminating semicolon by proc.c.
+ *
+ * The HASXOPT definition may be used to select the conditions under which
+ * private lfile elements are used.
+ */
+
+/* #define HASLFILEADD int ... */
+/* #define CLRLFILEADD(lf)     (lf)->... = (type)NULL; */
+/* #define SETLFILEADD Lf->... */
+
+/*
+ * 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.
+ */
+
+#    if defined(HAS_SYS_PIPEH)
+#        define HASPIPEFN process_pipe
+#    endif /* defined(HAS_SYS_PIPEH) */
+
+/*
+ * 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?       */
+
+/*
+ * 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.  For FreeBSD, NetBSD,
+ * and OpenBSD the lsof Configure script defines HASPROCFS, based on the
+ * presence of /usr/src/sys/miscfs/procfs/procfs.h header file.
+ *
+ * HASFSTYPE is defined as 1 for those systems that have a file system type
+ * string, st_fstype, in the stat() buffer; 2, for those systems that have a
+ * file system type integer in the stat() buffer, named MOUNTS_STAT_FSTYPE;
+ * 0, for systems whose stat(2) structure has no file system type member.  The
+ * additional symbols MOUNTS_FSTYPE, RMNT_FSTYPE, and RMNT_STAT_FSTYPE may be
+ * defined in dlsof.h to direct how the readmnt() function in lib/rmnt.c
+ * preserves these stat(2) and getmntent(3) buffer values in the local mounts
+ * structure.
+ *
+ * The defined value is the string that names the file system type.
+ *
+ * The HASPROCFS definition usually must be accompanied by the HASFSTYPE
+ * definition and the providing of an fstype element in the local mounts
+ * structure (defined in dlsof.h).
+ *
+ * The HASPROCFS definition may be accompanied by the HASPINODEN definition.
+ * HASPINODEN specifies that searching for files in HASPROCFS is to be done
+ * by inode number.
+ */
+
+#    if defined(HASPROCFS)
+#        undef HASPROCFS
+#        define HASPROCFS "proc"
+#    endif /* defined(HASPROCFS) */
+
+/* #define HASPROCFS   "proc?" */
+/* #define             HASFSTYPE       1 */
+#    define HASPINODEN 1
+
+/*
+ * HASRNODE is defined for those dialects that have rnodes.
+ */
+
+/* #define     HASRNODE        1 */
+
+/*
+ * Define HASSECURITY to restrict the listing of all open files to the
+ * root user.  When HASSECURITY is defined, the non-root user may list
+ * only files whose processes have the same user ID as the real user ID
+ * (the one that its user logged on with) of the lsof process.
+ */
+
+/* #define     HASSECURITY     1 */
+
+/*
+ * If HASSECURITY is defined, define HASNOSOCKSECURITY to allow users
+ * restricted by HASSECURITY to list any open socket files, provide their
+ * listing is selected by the "-i" option.
+ */
+
+/* #define     HASNOSOCKSECURITY       1       */
+
+/*
+ * HASSETLOCALE is defined for those dialects that have <locale.h> and
+ * setlocale().
+ *
+ * If the dialect also has wide character support for language locales,
+ * HASWIDECHAR activates lsof's wide character support and WIDECHARINCL
+ * defines the header file (if any) that must be #include'd to use the
+ * mblen() and mbtowc() functions.
+ */
+
+#    define HASSETLOCALE 1
+
+#    if defined(NETBSDV) && NETBSDV >= 1006000
+#        define HASWIDECHAR 1
+#    endif /* defined(NETBSDV) && NETBSDV>=1006000 */
+
+/* #define     WIDECHARINCL    <wchar.h>       */
+
+/*
+ * HASSNODE is defined for those dialects that have snodes.
+ */
+
+/* #define     HASSNODE        1 */
+
+/*
+ * HASTASKS is defined for those dialects that have task reporting support.
+ */
+
+/* #define     HASTASKS        1 */
+
+/*
+ * HASSOOPT, HASSOSTATE and HASTCPOPT define the availability of information
+ * on socket options (SO_* symbols), socket states (SS_* symbols) and TCP
+ * options.
+ */
+
+#    define HASSOOPT 1   /* has socket option information */
+#    define HASSOSTATE 1 /* has socket state information */
+#    define HASTCPOPT 1  /* has TCP options or flags */
+
+/*
+ * Define HASSPECDEVD to be the name of a function that handles the results
+ * of a successful stat(2) of a file name argument.
+ *
+ * For example, HASSPECDEVD() for Darwin makes sure that st_dev is set to
+ * what stat("/dev") returns -- i.e., what's in DevDev.
+ *
+ * The function takes two arguments:
+ *
+ *     1: pointer to the full path name of file
+ *     2: pointer to the stat(2) result
+ *
+ * The function returns void.
+ */
+
+/* #define     HASSPECDEVD     process_dev_stat */
+
+/*
+ * HASSTREAMS is defined for those dialects that support streams.
+ */
+
+/* #define     HASSTREAMS      1 */
+
+/*
+ * HASTCPTPIQ is defined for dialects where it is possible to report the
+ * TCP/TPI Recv-Q and Send-Q values produced by netstat.
+ */
+
+#    define HASTCPTPIQ 1
+
+/*
+ * HASTCPTPIW is defined for dialects where it is possible to report the
+ * TCP/TPI send and receive window sizes produced by netstat.
+ */
+
+/* #define     HASTCPTPIW      1 */
+
+/*
+ * HASTMPNODE is defined for those dialects that have tmpnodes.
+ */
+
+/* #define     HASTMPNODE      1 */
+
+/*
+ * HASVNODE is defined for those dialects that use the Sun virtual file system
+ * node, the vnode.  BSD derivatives usually do; System V derivatives prior
+ * to R4 usually don't.
+ * doesn't.
+ */
+
+#    define HASVNODE 1
+
+/*
+ * HASXOPT is defined for those dialects that have an X option.  It
+ * defines the text for the usage display.  HASXOPT_VALUE defines the
+ * option's default binary value -- 0 or 1.
+ */
+
+/* #define     HASXOPT         "help text for X option" */
+/* #define     HASXOPT_VALUE   1 */
+
+/*
+ * INODETYPE and INODEPSPEC define the internal node number type and its
+ * printf specification modifier.  These need not be defined and lsof.h
+ * can be allowed to define defaults.
+ *
+ * These are defined here, because they must be used in dlsof.h.
+ */
+
+#    define INODETYPE unsigned long long
+/* inode number internal storage type */
+#    define INODEPSPEC                                                         \
+        "ll" /* INODETYPE printf specification                                 \
+              * modifier */
+
+/*
+ * UID_ARG defines the size of a User ID number when it is passed
+ * as a function argument.
+ */
+
+#    define UID_ARG int
+
+/*
+ * Each USE_LIB_<function_name> is defined for dialects that use the
+ * <function_name> in the lsof library.
+ *
+ * Note: other definitions and operations may be required to condition the
+ * library function source code.  They may be found in the dialect dlsof.h
+ * header files.
+ */
+
+/* #define     USE_LIB_CKKV                    1          ckkv.c */
+/* #define     USE_LIB_COMPLETEVFS             1          cvfs.c */
+#    define USE_LIB_FIND_CH_INO 1   /* fino.c */
+#    define USE_LIB_IS_FILE_NAMED 1 /* isfn.c */
+#    define USE_LIB_LKUPDEV 1       /* lkud.c */
+#    define USE_LIB_PRINTDEVNAME 1  /* pdvn.c */
+#    define USE_LIB_PROCESS_FILE 1  /* prfp.c */
+#    define USE_LIB_PRINT_TCPTPI 1  /* ptti.c */
+#    define USE_LIB_READDEV 1       /* rdev.c */
+/* #define     USE_LIB_READMNT                 1          rmnt.c */
+
+#    if defined(NETBSDV) && NETBSDV >= 9099000
+#        define USE_LIB_RNMT 1 /* rnmt.c */
+#    elif defined(NETBSDV) && NETBSDV >= 1002000
+#        define USE_LIB_RNMH 1 /* rnmh.c */
+#    else                      /* defined(NETBSDV) && NETBSDV<1002000 */
+#        define USE_LIB_RNAM 1 /* rnam.c */
+#    endif                     /* defined(NETBSDV) && NETBSDV>=1002000 */
+
+/* #define     USE_LIB_RNCH                    1          rnch.c */
+/* #define     USE_LIB_SNPF                    1          snpf.c */
+#    define snpf snprintf /* use the system's snprintf() */
+
+/*
+ * WARNDEVACCESS is defined for those dialects that should issue a warning
+ * when lsof can't access /dev (or /device) or one of its sub-directories.
+ * The warning can be inhibited by the lsof caller with the -w option.
+ */
+
+/* #define     WARNDEVACCESS   1 */
+
+/*
+ * WARNINGSTATE is defined for those dialects that want to suppress all lsof
+ * warning messages.
+ */
+
+/* #define     WARNINGSTATE    1       warnings are enabled by default */
+
+/*
+ * WILLDROPGID is defined for those dialects whose lsof executable runs
+ * setgid(not_real_GID) and whose setgid power can be relinquished after
+ * the dialect's initialize() function has been executed.
+ */
+
+#    define WILLDROPGID 1
+
+/*
+ * zeromem is a macro that uses bzero or memset.
+ */
+
+#    define zeromem(a, l) memset(a, 0, l)
+
+#endif /* !defined(LSOF_MACHINE_H) */
diff --git a/lib/dialects/openbsd/Makefile b/lib/dialects/openbsd/Makefile
new file mode 100644 (file)
index 0000000..5b566fc
--- /dev/null
@@ -0,0 +1,158 @@
+
+# OpenBSD Makefile
+#
+# $Id: Makefile,v 1.12 2008/04/15 13:30:14 abe Exp $
+
+PROG=  lsof
+
+BIN=   ${DESTDIR}
+
+DOC=   ${DESTDIR}
+
+I=/usr/include
+S=/usr/include/sys
+L=/usr/include/local
+P=
+
+CDEF=
+CDEFS=  ${CDEF} ${CFGF}
+INCL=  ${DINC} -Iinclude -Ilib -Isrc -I.
+CFLAGS=        ${CDEFS} ${INCL} ${DEBUG}
+
+GRP=
+
+HDR=    lib/common.h include/lsof_fields.h dlsof.h machine.h lib/proto.h dproto.h
+
+SRC=    dfile.c dmnt.c dnode.c dproc.c dsock.c dstore.c \
+       arg.c main.c print.c ptti.c store.c usage.c \
+       util.c
+
+OBJ=   dfile.o dmnt.o dnode.o dproc.o dsock.o dstore.o \
+       arg.o main.o print.o ptti.o store.o usage.o \
+       util.o
+
+MAN=   lsof.8
+MANLCL=        lsof.0
+
+OTHER= 
+
+SHELL= /bin/sh
+
+SOURCE=        Makefile ${OTHER} ${MAN} ${HDR} ${SRC}
+
+all: ${PROG}
+
+${MANLCL}: ${MAN}
+       rm -f ${MANLCL}
+       nroff -mandoc -Tlp ${MAN} > ${MANLCL}
+
+${PROG}: ${LIB} ${P} ${OBJ}
+       ${CC} -o $@ ${CFLAGS} ${OBJ} ${CFGL}
+
+clean: FRC
+       rm -f Makefile.bak ${PROG} a.out core *.core errs lint.out tags *.o
+       rm -f machine.h.old new_machine.h version.h
+       (cd lib; ${MAKE} -f Makefile.skel clean)
+
+install: all ${MANLCL} FRC
+       @echo ''
+       @echo 'Please write your own install rule.  Lsof should be installed'
+       @echo 'setgid to the group that can can read /dev/kmem.  Normally'
+       @echo 'that is the kmem group.  Your install rule actions might look'
+       @echo 'something like this:'
+       @echo ''
+       @echo '    install -cs -m 2755 -g $${GRP} $${PROG} $${BIN}/$${PROG}'
+       @echo '    install -c -m 444 $${MANLCL} $${DOC}/$${MANLCL}'
+       @echo ''
+       @echo 'You will have to complete the skeletons for the BIN, DOC, and'
+       @echo 'GRP strings given at the beginning of this Makefile, e.g.,'
+       @echo ''
+       @echo '    BIN= $${DESTDIR}/usr/local/etc'
+       @echo '    DOC= $${DESTDIR}/usr/local/man/man8'
+       @echo '    GRP= kmem'
+       @echo ''
+
+${LIB}: FRC
+       (cd lib; ${MAKE} DEBUG="${DEBUG}" CFGF="${CFGF}")
+
+version.h:     FRC
+       @echo Constructing version.h
+       @rm -f version.h
+       @echo '#define  LSOF_BLDCMT     "${LSOF_BLDCMT}"' > version.h;
+       @echo '#define  LSOF_CC         "${CC}"' >> version.h
+       @echo '#define  LSOF_CCV        "${CCV}"' >> version.h
+       @echo '#define  LSOF_CCFLAGS    "'`echo ${CFLAGS} | sed 's/\\\\(/\\(/g' | sed 's/\\\\)/\\)/g' | sed 's/"/\\\\"/g'`'"' >> 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/lib/dialects/openbsd/Mksrc b/lib/dialects/openbsd/Mksrc
new file mode 100755 (executable)
index 0000000..f12e8e8
--- /dev/null
@@ -0,0 +1,32 @@
+#!/bin/sh
+#
+# Mksrc - make OpenBSD source files
+#
+# WARNING: This script assumes it is running from the main directory
+#         of the lsof, version 4 distribution.
+#
+# One environment variable applies:
+#
+# LSOF_MKC     is the method for creating the source files.
+#              It defaults to "ln -s".  A common alternative is "cp".
+#
+# $Id: Mksrc,v 1.5 99/04/15 06:40:37 abe Exp $
+
+mksrc() {
+  for i in $L
+  do
+    rm -f $i
+    $LSOF_MKC $D/$i $i
+    echo "$LSOF_MKC $D/$i $i"
+  done
+}
+
+D=lib/dialects/openbsd
+L="dfile.c dlsof.h dmnt.c dnode.c dproc.c dproto.h dsock.c dstore.c machine.h"
+
+mksrc
+
+D=src
+L="arg.c main.c node.c print.c ptti.c store.c usage.c util.c"
+
+mksrc
diff --git a/lib/dialects/openbsd/dfile.c b/lib/dialects/openbsd/dfile.c
new file mode 100644 (file)
index 0000000..5234b0b
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * dnode.c - OpenBSD node functions for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#ifndef lint
+static char copyright[] =
+    "@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
+#endif
+
+#include "common.h"
+
+/*
+ * process_kqueue() -- process kqueue file
+ */
+void process_kqueue_file(struct lsof_context *ctx, struct kinfo_file *file) {
+    char buf[64];
+    int flag;
+
+    /* Alloc Lf and set fd */
+    alloc_lfile(ctx, LSOF_FD_NUMERIC, file->fd_fd);
+
+    /* Fill type name*/
+    Lf->type = LSOF_FILE_KQUEUE;
+
+    /* Fill dev with f_data if available */
+    if (file->f_data) {
+        (void)snpf(buf, sizeof(buf), "0x%" PRIx64, file->f_data);
+        enter_dev_ch(ctx, buf);
+    }
+
+    /*
+     * Construct access code.
+     */
+    if ((flag = (file->f_flag & (FREAD | FWRITE))) == FREAD)
+        Lf->access = LSOF_FILE_ACCESS_READ;
+    else if (flag == FWRITE)
+        Lf->access = LSOF_FILE_ACCESS_WRITE;
+    else if (flag == (FREAD | FWRITE))
+        Lf->access = LSOF_FILE_ACCESS_READ_WRITE;
+
+    /* Finish */
+    if (Lf->sf)
+        link_lfile(ctx);
+}
+
+/*
+ * process_pipe() - process a file structure whose type is DTYPE_PIPE
+ */
+void process_pipe(struct lsof_context *ctx, struct kinfo_file *file) {}
\ No newline at end of file
diff --git a/lib/dialects/openbsd/dlsof.h b/lib/dialects/openbsd/dlsof.h
new file mode 100644 (file)
index 0000000..77346c1
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * dlsof.h - OpenBSD header file for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+/*
+ * $Id: dlsof.h,v 1.38 2006/03/28 21:54:08 abe Exp $
+ */
+
+#if !defined(OPENBSD_LSOF_H)
+#    define OPENBSD_LSOF_H 1
+
+#    include <stdlib.h>
+#    include <inttypes.h>
+#    include <dirent.h>
+#    include <nlist.h>
+#    include <paths.h>
+#    include <setjmp.h>
+#    include <signal.h>
+#    include <string.h>
+#    include <unistd.h>
+#    include <fcntl.h>
+
+#    include <arpa/inet.h>
+#    include <sys/queue.h>
+#    include <sys/filedesc.h>
+#    include <sys/mbuf.h>
+#    include <sys/mount.h>
+#    include <rpc/types.h>
+#    include <sys/protosw.h>
+#    include <sys/socket.h>
+#    include <sys/socketvar.h>
+#    include <sys/un.h>
+#    include <sys/unpcb.h>
+#    include <net/route.h>
+#    include <netinet/in.h>
+#    include <netinet/in_systm.h>
+#    include <netinet/ip.h>
+
+#    include <netinet/in_pcb.h>
+#    include <netinet/ip_var.h>
+#    include <netinet/tcp.h>
+#    include <netinet/tcp_fsm.h>
+#    include <netinet/tcp_timer.h>
+#    include <netinet/tcp_var.h>
+
+#    include <sys/ucred.h>
+
+#    include <sys/vnode.h>
+#    include <sys/domain.h>
+
+#    define pmap RPC_pmap
+#    include <rpc/rpc.h>
+#    include <rpc/pmap_prot.h>
+#    undef pmap
+
+#    include <sys/proc.h>
+#    include <kvm.h>
+#    include <sys/sysctl.h>
+
+#    include <sys/file.h>
+#    include <sys/fcntl.h>
+#    include <sys/lockf.h>
+
+#    define COMP_P const void
+#    define DEVINCR 1024 /* device table malloc() increment */
+typedef u_long KA_T;
+#    define KMEM "/dev/kmem"
+#    define MALLOC_P void
+#    define FREE_P MALLOC_P
+#    define MALLOC_S size_t
+
+#    if !defined(MAXSYSCMDL)
+#        define MAXSYSCMDL MAXCOMLEN /* max system command name length */
+#    endif                           /* !defined(MAXSYSCMDL) */
+
+#    define QSORT_P void
+#    define READLEN_T int
+#    define STRNCPY_L size_t
+#    define SWAP "/dev/drum"
+#    define SZOFFTYPE unsigned long long
+/* size and offset internal storage
+ * type */
+#    define SZOFFPSPEC                                                         \
+        "ll" /* SZOFFTYPE print specification                                  \
+              * modifier */
+
+/*
+ * Global storage definitions (including their structure definitions)
+ */
+
+struct mounts {
+    char *dir;           /* directory (mounted on) */
+    char *fsname;        /* file system
+                          * (symbolic links unresolved) */
+    char *fsnmres;       /* file system
+                          * (symbolic links resolved) */
+    dev_t dev;           /* directory st_dev */
+    dev_t rdev;          /* directory st_rdev */
+    INODETYPE inode;     /* directory st_ino */
+    mode_t mode;         /* directory st_mode */
+    mode_t fs_mode;      /* file_system st_mode */
+    struct mounts *next; /* forward link */
+};
+
+#    define X_NCACHE "ncache"
+#    define X_NCSIZE "ncsize"
+#    define NL_NAME n_name
+
+struct sfile {
+    char *aname;        /* argument file name */
+    char *name;         /* file name (after readlink()) */
+    char *devnm;        /* device name (optional) */
+    dev_t dev;          /* device */
+    dev_t rdev;         /* raw device */
+    u_short mode;       /* S_IFMT mode bits from stat() */
+    int type;           /* file type: 0 = file system
+                         *           1 = regular file */
+    INODETYPE i;        /* inode number */
+    int f;              /* file found flag */
+    struct sfile *next; /* forward link */
+};
+
+/*
+ * Definitions for rdev.c
+ */
+
+#    define DIRTYPE dirent
+#    define HASDNAMLEN 1 /* struct DIRTYPE has d_namlen element */
+
+struct lsof_context_dialect {};
+
+#endif /* OPENBSD_LSOF_H */
diff --git a/lib/dialects/openbsd/dmnt.c b/lib/dialects/openbsd/dmnt.c
new file mode 100644 (file)
index 0000000..2210b60
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * dmnt.c - OpenBSD mount support functions for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#ifndef lint
+static char copyright[] =
+    "@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
+#endif
+
+#include "common.h"
+
+/*
+ * Local static definitions
+ */
+
+/*
+ * readmnt() - read mount table
+ */
+struct mounts *readmnt(struct lsof_context *ctx) {
+    char *dn = (char *)NULL;
+    char *ln;
+    struct mounts *mtp;
+    int n;
+    struct stat sb;
+
+    struct statfs *mb = (struct statfs *)NULL;
+
+    if (Lmi || Lmist)
+        return (Lmi);
+    /*
+     * Access mount information.
+     */
+    if ((n = getmntinfo(&mb, MNT_NOWAIT)) <= 0) {
+        (void)fprintf(stderr, "%s: no mount information\n", Pn);
+        return (0);
+    }
+    /*
+     * Read mount information.
+     */
+    for (; n; n--, mb++) {
+        if (mb->f_fstypename[0] == '\0')
+            continue;
+        mb->f_fstypename[MFSNAMELEN - 1] = '\0';
+        /*
+         * Interpolate a possible symbolic directory link.
+         */
+        if (dn)
+            (void)free((FREE_P *)dn);
+        if (!(dn = mkstrcpy(mb->f_mntonname, (MALLOC_S *)NULL))) {
+
+        no_space_for_mount:
+
+            (void)fprintf(stderr, "%s: no space for mount at ", Pn);
+            safestrprt(mb->f_mntonname, stderr, 0);
+            (void)fprintf(stderr, " (");
+            safestrprt(mb->f_mntfromname, stderr, 0);
+            (void)fprintf(stderr, ")\n");
+            Error(ctx);
+        }
+        if ((ln = Readlink(ctx, dn)) == NULL) {
+            if (!Fwarn) {
+                (void)fprintf(stderr,
+                              "      Output information may be incomplete.\n");
+            }
+            continue;
+        }
+        if (ln != dn) {
+            (void)free((FREE_P *)dn);
+            dn = ln;
+        }
+        if (*dn != '/')
+            continue;
+        /*
+         * Stat() the directory.
+         */
+        if (statsafely(ctx, dn, &sb)) {
+            if (!Fwarn) {
+                (void)fprintf(stderr, "%s: WARNING: can't stat() ", Pn);
+                safestrprt(mb->f_fstypename, stderr, 0);
+                (void)fprintf(stderr, " file system ");
+                safestrprt(mb->f_mntonname, stderr, 1);
+                (void)fprintf(stderr,
+                              "      Output information may be incomplete.\n");
+            }
+            (void)bzero((char *)&sb, sizeof(sb));
+
+            sb.st_dev = (dev_t)mb->f_fsid.val[0];
+
+            sb.st_mode = S_IFDIR | 0777;
+            if (!Fwarn) {
+                (void)fprintf(stderr,
+                              "      assuming \"dev=%x\" from mount table\n",
+                              sb.st_dev);
+            }
+        }
+        /*
+         * Allocate and fill a local mount structure.
+         */
+        if (!(mtp = (struct mounts *)malloc(sizeof(struct mounts))))
+            goto no_space_for_mount;
+        mtp->dir = dn;
+        dn = (char *)NULL;
+
+        mtp->next = Lmi;
+        mtp->dev = sb.st_dev;
+        mtp->rdev = sb.st_rdev;
+        mtp->inode = (INODETYPE)sb.st_ino;
+        mtp->mode = sb.st_mode;
+        /*
+         * Interpolate a possible file system (mounted-on) device name link.
+         */
+        if (!(dn = mkstrcpy(mb->f_mntfromname, (MALLOC_S *)NULL)))
+            goto no_space_for_mount;
+        mtp->fsname = dn;
+        ln = Readlink(ctx, dn);
+        dn = (char *)NULL;
+        /*
+         * Stat() the file system (mounted-on) name and add file system
+         * information to the local mount table entry.
+         */
+        if (!ln || statsafely(ctx, ln, &sb))
+            sb.st_mode = 0;
+        mtp->fsnmres = ln;
+        mtp->fs_mode = sb.st_mode;
+        Lmi = mtp;
+    }
+    /*
+     * Clean up and return local mount info table address.
+     */
+    if (dn)
+        (void)free((FREE_P *)dn);
+    Lmist = 1;
+    return (Lmi);
+}
diff --git a/lib/dialects/openbsd/dnode.c b/lib/dialects/openbsd/dnode.c
new file mode 100644 (file)
index 0000000..4b10651
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * dnode.c - OpenBSD node functions for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#ifndef lint
+static char copyright[] =
+    "@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
+#endif
+
+#include "common.h"
+
+/*
+ * process_vnode() - process vnode
+ */
+void process_vnode(struct lsof_context *ctx, struct kinfo_file *file) {
+    enum lsof_fd_type fd_type;
+    int num = -1;
+    uint32_t flag;
+    int mib[3];
+    size_t size;
+    char path[PATH_MAX];
+
+    /* Alloc Lf and set fd */
+    switch (file->fd_fd) {
+    case KERN_FILE_TEXT:
+        fd_type = LSOF_FD_PROGRAM_TEXT;
+        break;
+    case KERN_FILE_CDIR:
+        fd_type = LSOF_FD_CWD;
+        break;
+    case KERN_FILE_RDIR:
+        fd_type = LSOF_FD_ROOT_DIR;
+        break;
+    default:
+        fd_type = LSOF_FD_NUMERIC;
+        num = file->fd_fd;
+        break;
+    }
+    alloc_lfile(ctx, fd_type, num);
+
+    if (file->fd_fd == KERN_FILE_CDIR) {
+        /*
+         * Save current working directory information if available
+         * sysctl(CTL_KERN, KERN_PROC_CWD, pid)
+         */
+        mib[0] = CTL_KERN;
+        mib[1] = KERN_PROC_CWD;
+        mib[2] = file->p_pid;
+        size = sizeof(path);
+        if (sysctl(mib, 3, path, &size, NULL, 0) >= 0) {
+            (void)snpf(Namech, Namechl, "%s", path);
+            enter_nm(ctx, Namech);
+        }
+    }
+
+    /*
+     * Construct access code.
+     */
+    if (file->fd_fd >= 0) {
+        if ((flag = (file->f_flag & (FREAD | FWRITE))) == FREAD)
+            Lf->access = LSOF_FILE_ACCESS_READ;
+        else if (flag == FWRITE)
+            Lf->access = LSOF_FILE_ACCESS_WRITE;
+        else if (flag == (FREAD | FWRITE))
+            Lf->access = LSOF_FILE_ACCESS_READ_WRITE;
+    }
+
+    /* Fill file size/offset */
+    if (file->v_type == VBLK || file->v_type == VCHR) {
+        /* blk/char devices have no size, only offset */
+        if (file->f_offset != (uint64_t)(-1)) {
+            Lf->off = file->f_offset;
+            Lf->off_def = 1;
+        }
+    } else {
+        Lf->off = file->f_offset;
+        Lf->off_def = 1;
+        Lf->sz = file->va_size;
+        Lf->sz_def = 1;
+    }
+
+    /* Fill inode */
+    Lf->inode = file->va_fileid;
+    Lf->inp_ty = 1;
+
+    /* Fill dev && rdef */
+    Lf->dev = file->va_fsid;
+    Lf->dev_def = 1;
+    if (file->v_type == VBLK || file->v_type == VCHR) {
+        Lf->rdev = file->va_rdev;
+        Lf->rdev_def = 1;
+    }
+
+    /* Fill type */
+    switch (file->v_type) {
+    case VREG:
+        Lf->ntype = N_REGLR;
+        Lf->type = LSOF_FILE_VNODE_VREG;
+        break;
+    case VDIR:
+        Lf->type = LSOF_FILE_VNODE_VDIR;
+        break;
+    case VCHR:
+        Lf->ntype = N_CHR;
+        Lf->type = LSOF_FILE_VNODE_VCHR;
+        break;
+    case VFIFO:
+        Lf->ntype = N_FIFO;
+        Lf->type = LSOF_FILE_VNODE_VFIFO;
+        break;
+    }
+
+    /* No way to read file path, request mount info  */
+    Lf->lmi_srch = 1;
+
+    /* Fill number of links */
+    Lf->nlink = file->va_nlink;
+    Lf->nlink_def = 1;
+
+    /* Handle link count filter */
+    if (Nlink && (Lf->nlink < Nlink))
+        Lf->sf |= SELNLINK;
+
+    /* Handle name match, must be done late, because if_file_named checks
+     * Lf->dev etc. */
+    if (is_file_named(ctx, NULL, 0)) {
+        Lf->sf |= SELNM;
+    }
+
+    /* Finish */
+    if (Lf->sf)
+        link_lfile(ctx);
+}
diff --git a/lib/dialects/openbsd/dproc.c b/lib/dialects/openbsd/dproc.c
new file mode 100644 (file)
index 0000000..5038f79
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * dproc.c - OpenBSD process access functions for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#ifndef lint
+static char copyright[] =
+    "@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
+#endif
+
+#include "common.h"
+
+static void process_kinfo_file(struct lsof_context *ctx,
+                               struct kinfo_file *file);
+
+/*
+ * Local static values
+ */
+
+/*
+ * gather_proc_info() -- gather process information
+ */
+void gather_proc_info(struct lsof_context *ctx) {
+    short pss, sf;
+    uid_t uid;
+    struct stat st;
+    int mib[6];
+    size_t size = 0;
+    int res;
+
+    struct kinfo_proc *procs = NULL;
+    struct kinfo_proc *proc;
+    int num_procs;
+    int px; /* process loop index */
+
+    struct kinfo_file *files = NULL;
+    struct kinfo_file *file;
+    int num_files;
+    int fx; /* file loop index */
+
+    char path[PATH_MAX];
+
+    /*
+     * Read the process table.
+     */
+
+    /* See OpenSBD kernel sys/kern/kern_sysctl.c sysctl_doproc */
+    /* sysctl(CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc),
+     * count) */
+    mib[0] = CTL_KERN;
+    mib[1] = KERN_PROC;
+    mib[2] = KERN_PROC_ALL;             /* op */
+    mib[3] = 0;                         /* arg */
+    mib[4] = sizeof(struct kinfo_proc); /* elem_size */
+
+    /* Loop to probe size, learned from libkvm */
+    while (1) {
+        mib[5] = 0; /* elem_count */
+
+        /* Probe number of entries */
+        if (sysctl(mib, 6, NULL, &size, NULL, 0) < 0) {
+            (void)fprintf(stderr, "%s: can't read process table: %d\n", Pn,
+                          errno);
+            Error(ctx);
+        }
+
+        /* Alloc more to handle new processes in the meantime */
+        size = (size_t)(size / sizeof(struct kinfo_proc) * 1.1) *
+               sizeof(struct kinfo_proc);
+
+        if (!procs) {
+            procs = (struct kinfo_proc *)malloc(size);
+        } else {
+            procs = (struct kinfo_proc *)realloc(procs, size);
+        }
+        if (!procs) {
+            (void)fprintf(stderr, "%s: no kinfo_proc * space\n", Pn);
+            Error(ctx);
+        }
+
+        mib[5] = size / sizeof(struct kinfo_proc); /* elem_count */
+        res = sysctl(mib, 6, procs, &size, NULL, 0);
+        if (res >= 0) {
+            num_procs = size / sizeof(struct kinfo_proc);
+            break;
+        } else if (res < 0 && errno != ENOMEM) {
+            (void)fprintf(stderr, "%s: can't read process table: %d\n", Pn,
+                          errno);
+            Error(ctx);
+        }
+    };
+
+    /*
+     * Examine proc structures and their associated information.
+     */
+
+    for (proc = procs, px = 0; px < num_procs; px++, proc++) {
+        if (proc->p_stat == 0 || proc->p_stat == SZOMB)
+            continue;
+        /*
+         * Read process information, process group structure (if
+         * necessary), and User ID (if necessary).
+         *
+         * See if process is excluded.
+         *
+         * Read file structure pointers.
+         */
+        uid = proc->p_uid;
+        if (is_proc_excl(ctx, (int)proc->p_pid, (int)proc->p__pgid,
+                         (UID_ARG)uid, &pss, &sf)) {
+            continue;
+        }
+
+        /*
+         * Allocate a local process structure.
+         */
+        if (is_cmd_excl(ctx, proc->p_comm, &pss, &sf))
+            continue;
+        alloc_lproc(ctx, (int)proc->p_pid, (int)proc->p__pgid,
+                    (int)proc->p_ppid, (UID_ARG)uid, proc->p_comm, (int)pss,
+                    (int)sf);
+        Plf = (struct lfile *)NULL; /* Empty list head */
+
+        /*
+         * Read open file structure pointers.
+         * sysctl(CTL_KERN, KERN_FILE, KERN_FILE_BYPID, pid, sizeof(struct
+         * kinfo_file), count)
+         */
+        mib[0] = CTL_KERN;
+        mib[1] = KERN_FILE;
+        mib[2] = KERN_FILE_BYPID;
+        mib[3] = proc->p_pid;
+        mib[4] = sizeof(struct kinfo_file);
+        size = 0;
+
+        /* Loop to probe size, learned from libkvm */
+        while (1) {
+            mib[5] = 0; /* elem_count */
+
+            /* Probe number of entries */
+            if (sysctl(mib, 6, NULL, &size, NULL, 0) < 0) {
+                (void)fprintf(stderr, "%s: can't read file table: %d\n", Pn,
+                              errno);
+                Error(ctx);
+            }
+
+            /* Alloc more to handle new processes in the meantime */
+            size = (size_t)(size / sizeof(struct kinfo_file) * 1.1) *
+                   sizeof(struct kinfo_file);
+
+            if (!files) {
+                files = (struct kinfo_file *)malloc(size);
+            } else {
+                files = (struct kinfo_file *)realloc(files, size);
+            }
+            if (!files) {
+                (void)fprintf(stderr, "%s: no kinfo_file * space\n", Pn);
+                Error(ctx);
+            }
+
+            mib[5] = size / sizeof(struct kinfo_file); /* elem_count */
+            res = sysctl(mib, 6, files, &size, NULL, 0);
+            if (res >= 0) {
+                num_files = size / sizeof(struct kinfo_file);
+                break;
+            } else if (res < 0 && errno != ENOMEM) {
+                (void)fprintf(stderr, "%s: can't read file table: %d\n", Pn,
+                              errno);
+                Error(ctx);
+            }
+        };
+
+        for (file = files, fx = 0; fx < num_files; fx++, file++) {
+            process_kinfo_file(ctx, file);
+        }
+
+        /*
+         * Examine results.
+         */
+        if (examine_lproc(ctx))
+            return;
+    }
+}
+
+/*
+ * initialize() - perform all initialization
+ */
+void initialize(struct lsof_context *ctx) {}
+
+/*
+ * process_kinfo_file() - process kinfo_file
+ */
+void process_kinfo_file(struct lsof_context *ctx, struct kinfo_file *file) {
+    switch (file->f_type) {
+    case DTYPE_VNODE: /* file */
+        process_vnode(ctx, file);
+        break;
+    case DTYPE_SOCKET:
+        process_socket(ctx, file);
+        break;
+    case DTYPE_PIPE:
+        process_pipe(ctx, file);
+        break;
+    case DTYPE_KQUEUE:
+        process_kqueue_file(ctx, file);
+        break;
+    }
+}
\ No newline at end of file
diff --git a/lib/dialects/openbsd/dproto.h b/lib/dialects/openbsd/dproto.h
new file mode 100644 (file)
index 0000000..138ca13
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * dproto.h - OpenBSD function prototypes for lsof
+ *
+ * The _PROTOTYPE macro is defined in the common proto.h.
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+/*
+ * $Id: dproto.h,v 1.11 2005/08/08 19:53:24 abe Exp $
+ */
+
+extern int is_file_named(struct lsof_context *ctx, char *p, int cd);
+
+extern void process_vnode(struct lsof_context *ctx, struct kinfo_file *file);
+extern void process_socket(struct lsof_context *ctx, struct kinfo_file *file);
+extern void process_pipe(struct lsof_context *ctx, struct kinfo_file *file);
+extern void process_kqueue_file(struct lsof_context *ctx,
+                                struct kinfo_file *file);
diff --git a/lib/dialects/openbsd/dsock.c b/lib/dialects/openbsd/dsock.c
new file mode 100644 (file)
index 0000000..c492c12
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * dsock.c - OpenBSD socket processing functions for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#ifndef lint
+static char copyright[] =
+    "@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
+#endif
+
+#include "common.h"
+
+/*
+ * process_socket() - process socket
+ */
+void process_socket(struct lsof_context *ctx, struct kinfo_file *file) {
+    char *proto = NULL;
+    char *type = NULL;
+    char buf[64];
+    int flag;
+    uint32_t lport, fport;
+
+    /* Alloc Lf and set fd */
+    alloc_lfile(ctx, LSOF_FD_NUMERIC, file->fd_fd);
+
+    /* Type name */
+    switch (file->so_family) {
+    case AF_INET:
+        Lf->type = LSOF_FILE_IPV4;
+        break;
+    case AF_INET6:
+        Lf->type = LSOF_FILE_IPV6;
+        break;
+    case AF_UNIX:
+        Lf->type = LSOF_FILE_UNIX;
+        break;
+    case AF_ROUTE:
+        Lf->type = LSOF_FILE_ROUTE;
+        break;
+    }
+
+    /*
+     * Construct access code.
+     */
+    if (file->fd_fd >= 0) {
+        if ((flag = (file->f_flag & (FREAD | FWRITE))) == FREAD)
+            Lf->access = LSOF_FILE_ACCESS_READ;
+        else if (flag == FWRITE)
+            Lf->access = LSOF_FILE_ACCESS_WRITE;
+        else if (flag == (FREAD | FWRITE))
+            Lf->access = LSOF_FILE_ACCESS_READ_WRITE;
+    }
+
+    /* Fill iproto */
+    switch (file->so_type) {
+    case SOCK_STREAM:
+        proto = "TCP";
+        break;
+    case SOCK_DGRAM:
+        proto = "UDP";
+        break;
+    case SOCK_RAW:
+        proto = "RAW";
+        break;
+    }
+    if (proto) {
+        (void)snpf(Lf->iproto, sizeof(Lf->iproto), "%s", proto);
+        Lf->inp_ty = 2;
+    }
+
+    if (file->so_family == AF_INET || file->so_family == AF_INET6) {
+        /* Show this entry if -i */
+        if (Fnet) {
+            /* Handle v4/v6 only */
+            if (FnetTy == 4 && file->so_family == AF_INET) {
+                Lf->sf |= SELNET;
+            } else if (FnetTy == 6 && file->so_family == AF_INET6) {
+                Lf->sf |= SELNET;
+            } else if (FnetTy == 0) {
+                Lf->sf |= SELNET;
+            }
+        }
+
+        /* Fill internet address info */
+        lport = ntohs(file->inp_lport);
+        fport = ntohs(file->inp_fport);
+        if (file->inp_fport) {
+            ent_inaddr(ctx, (unsigned char *)file->inp_laddru, lport,
+                       (unsigned char *)file->inp_faddru, fport,
+                       file->so_family);
+        } else {
+            /* No foreign address on LISTEN sockets */
+            ent_inaddr(ctx, (unsigned char *)file->inp_laddru, lport, NULL, 0,
+                       file->so_family);
+        }
+
+        /* Fill TCP state */
+        if (file->so_type == SOCK_STREAM) {
+            Lf->lts.type = 0;
+            Lf->lts.state.i = file->t_state;
+        }
+
+        /* Fill dev with pcb if available */
+        if (file->inp_ppcb) {
+            (void)snpf(buf, sizeof(buf), "0x%" PRIx64, file->inp_ppcb);
+            enter_dev_ch(ctx, buf);
+        } else if (file->so_pcb && file->so_pcb != (uint64_t)(-1)) {
+            /* when running as non-root, -1 means not NULL */
+            (void)snpf(buf, sizeof(buf), "0x%" PRIx64, file->so_pcb);
+            enter_dev_ch(ctx, buf);
+        }
+    } else if (file->so_family == AF_UNIX) {
+        /* Show this entry if requested */
+        /* Via -U */
+        if (Funix)
+            Lf->sf |= SELUNX;
+        /* Name matches */
+        if (is_file_named(ctx, file->unp_path, 0)) {
+            Lf->sf |= SELNM;
+        }
+
+        /* Fill name */
+        switch (file->so_type) {
+        case SOCK_STREAM:
+            type = "STREAM";
+            break;
+        case SOCK_DGRAM:
+            type = "DGRAM";
+            break;
+        default:
+            type = "UNKNOWN";
+            break;
+        }
+
+        (void)snpf(Namech, Namechl, "%s%stype=%s",
+                   file->unp_path[0] ? file->unp_path : "",
+                   file->unp_path[0] ? " " : "", type);
+        (void)enter_nm(ctx, Namech);
+
+        /* Fill TCP state */
+        if (file->so_type == SOCK_STREAM) {
+            Lf->lts.type = 0;
+            Lf->lts.state.i = file->t_state;
+        }
+
+        /* Fill dev with so_pcb if available */
+        if (file->so_pcb && file->so_pcb != (uint64_t)(-1)) {
+            (void)snpf(buf, sizeof(buf), "0x%" PRIx64, file->so_pcb);
+            enter_dev_ch(ctx, buf);
+        }
+    } else if (file->so_family == AF_ROUTE) {
+        /* Fill dev with f_data if available */
+        if (file->f_data) {
+            (void)snpf(buf, sizeof(buf), "0x%" PRIx64, file->f_data);
+            enter_dev_ch(ctx, buf);
+        }
+    }
+
+    /* Finish */
+    if (Lf->sf)
+        link_lfile(ctx);
+}
diff --git a/lib/dialects/openbsd/dstore.c b/lib/dialects/openbsd/dstore.c
new file mode 100644 (file)
index 0000000..d3ecc50
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * dstore.c - OpenBSD global storage for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#ifndef lint
+static char copyright[] =
+    "@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
+#endif
+
+#include "common.h"
+
+#if defined(HASFSTRUCT)
+/*
+ * Pff_tab[] - table for printing file flags
+ */
+
+struct pff_tab Pff_tab[] = {
+    {(long)FREAD, FF_READ},       {(long)FWRITE, FF_WRITE},
+    {(long)FNONBLOCK, FF_NBLOCK}, {(long)FNDELAY, FF_NDELAY},
+    {(long)FAPPEND, FF_APPEND},   {(long)FASYNC, FF_ASYNC},
+
+#    if defined(FDSYNC)
+    {(long)FDSYNC, FF_DSYNC},
+#    endif /* defined*FDSYNC) */
+
+    {(long)FFSYNC, FF_FSYNC},
+
+#    if defined(FRSYNC)
+    {(long)FRSYNC, FF_RSYNC},
+#    endif /* defined(FRSYNC) */
+
+#    if defined(FMARK)
+    {(long)FMARK, FF_MARK},
+#    endif /* defined(FMARK) */
+
+#    if defined(FDEFER)
+    {(long)FDEFER, FF_DEFER},
+#    endif /* defined(FDEFER) */
+
+#    if defined(FHASLOCK)
+    {(long)FHASLOCK, FF_HASLOCK},
+#    endif /* defined(FHASLOCK) */
+    {(long)O_NOCTTY, FF_NOCTTY},  {(long)0, NULL}};
+
+/*
+ * Pof_tab[] - table for print process open file flags
+ */
+
+struct pff_tab Pof_tab[] = {
+
+#    if defined(UF_EXCLOSE)
+    {(long)UF_EXCLOSE, POF_CLOEXEC},
+#    else
+    {(long)1, POF_CLOEXEC},
+#    endif /* defined(UF_EXCLOSE) */
+
+#    if defined(UF_MAPPED)
+    {(long)UF_MAPPED, POF_MAPPED},
+#    endif /* defined(UF_MAPPED) */
+
+    {(long)0, NULL}};
+#endif /* defined(HASFSTRUCT) */
+
+int pgshift = 0; /* kernel's page shift */
diff --git a/lib/dialects/openbsd/machine.h b/lib/dialects/openbsd/machine.h
new file mode 100644 (file)
index 0000000..ac2e98c
--- /dev/null
@@ -0,0 +1,564 @@
+/*
+ * machine.h - OpenBSD definitions for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+/*
+ * $Id: machine.h,v 1.39 2010/07/29 16:02:52 abe Exp $
+ */
+
+#if !defined(LSOF_MACHINE_H)
+#    define LSOF_MACHINE_H 1
+
+#    ifdef AUTOTOOLS
+#        include "autotools.h"
+#    endif
+
+#    include <sys/types.h>
+#    include <sys/param.h>
+#    include <stdbool.h>
+
+/*
+ * CAN_USE_CLNT_CREATE is defined for those dialects where RPC clnt_create()
+ * can be used to obtain a CLIENT handle in lieu of clnttcp_create().
+ */
+
+#    define CAN_USE_CLNT_CREATE 1
+
+/*
+ * DEVDEV_PATH defines the path to the directory that contains device
+ * nodes.
+ */
+
+#    define DEVDEV_PATH "/dev"
+
+/*
+ * GET_MAX_FD is defined for those dialects that provide a function other than
+ * getdtablesize() to obtain the maximum file descriptor number plus one.
+ */
+
+/* #define     GET_MAX_FD      ?       */
+
+/*
+ * HASAOPT is defined for those dialects that have AFS support; it specifies
+ * that the default path to an alternate AFS kernel name list file may be
+ * supplied with the -A <path> option.
+ */
+
+/* #define     HASAOPT         1 */
+
+/*
+ * HASBLKDEV is defined for those dialects that want block device information
+ * recorded in BDevtp[].
+ */
+
+#    define HASBLKDEV 1
+
+/*
+ * HASDCACHE is defined for those dialects that support a device cache
+ * file.
+ *
+ * HASENVDC defined the name of an environment variable that contains the
+ * device cache file path.  The HASENVDC environment variable is ignored when
+ * the lsof process is setuid(root) or its real UID is 0.
+ *
+ * HASPERSDC defines the format for the last component of a personal device
+ * cache file path.  The first will be the home directory of the real UID that
+ * executes lsof.
+ *
+ * HASPERSDCPATH defines the environment variable whose value is the middle
+ * component of the personal device cache file path.  The middle component
+ * follows the home directory and precedes the results of applying HASPERSDC.
+ * The HASPERSDCPATH environment variable is ignored when the lsof process is
+ * setuid(root) or its real UID is 0.
+ *
+ * HASSYSDC defines a public device cache file path.  When it's defined, it's
+ * used as the path from which to read the device cache.
+ *
+ * Consult the 00DCACHE and 00FAQ files of the lsof distribution for more
+ * information on device cache file path construction.
+ */
+
+#    define HASDCACHE 1
+#    define HASENVDC "LSOFDEVCACHE"
+#    define HASPERSDC "%h/%p.lsof_%L"
+#    define HASPERSDCPATH "LSOFPERSDCPATH"
+/* #define     HASSYSDC        "/your/choice/of/path" */
+
+/*
+ * HASCDRNODE is defined for those dialects that have CD-ROM nodes.
+ */
+
+/* #define     HASCDRNODE      1 */
+
+/*
+ * HASFIFONODE is defined for those dialects that have FIFO nodes.
+ */
+
+/* #define     HASFIFONODE     1 */
+
+/*
+ * HASFSINO is defined for those dialects that have the file system
+ * inode element, fs_ino, in the lfile structure definition in lsof.h.
+ */
+
+/* #define     HASFSINO        1 */
+
+/*
+ * HASFSTRUCT is defined if the dialect has a file structure.
+ *
+ * FSV_DEFAULT defines the default set of file structure values to list.
+ * It defaults to zero (0), but may be made up of a combination of the
+ * FSV_* symbols from lsof.h.
+ *
+ *   HASNOFSADDR  -- has no file structure address
+ *   HASNOFSFLAGS -- has no file structure flags
+ *   HASNOFSCOUNT -- has no file structure count
+ *   HASNOFSNADDR -- has no file structure node address
+ */
+
+#    define HASFSTRUCT 1
+/* #define     FSV_DEFAULT     FSV_? | FSV_? | FSV_? */
+/* #define     HASNOFSADDR     1       has no file structure address */
+/* #define     HASNOFSFLAGS    1       has no file structure flags */
+/* #define     HASNOFSCOUNT    1       has no file structure count */
+/* #define     HASNOFSNADDR    1       has no file structure node address */
+
+/*
+ * HASGNODE is defined for those dialects that have gnodes.
+ */
+
+/* #define     HASGNODE        1 */
+
+/*
+ * HASHSNODE is defined for those dialects that have High Sierra nodes.
+ */
+
+/* #define     HASHSNODE       1 */
+
+/*
+ * HASINODE is defined for those dialects that have inodes and wish to
+ * use readinode() from node.c.
+ */
+
+/* #define     HASINODE        1 */
+
+/*
+ * HASINTSIGNAL is defined for those dialects whose signal function returns
+ * an int.
+ */
+
+/* #define     HASINTSIGNAL    1 */
+
+/*
+ * HASKERNIDCK is defined for those dialects that support the comparison of
+ * the build to running kernel identity.
+ */
+
+#    define HASKERNIDCK 1
+
+/*
+ * HASKOPT is defined for those dialects that support the -k option of
+ * reading the kernel's name list from an optional file.
+ */
+
+/* #define     HASKOPT 1 */
+
+/*
+ * HASLFILEADD is defined for those dialects that need additional elements
+ * in struct lfile.  The HASLFILEADD definition is a macro that defines
+ * them.  If any of the additional elements need to be preset in the
+ * alloc_lfile() function of proc.c, the SETLFILEADD macro may be defined
+ * to do that.
+ *
+ * If any additional elements need to be cleared in alloc_lfile() or in the
+ * free_proc() function of proc.c, the CLRLFILEADD macro may be defined to
+ * do that.  Note that CLRLFILEADD takes one argument, the pointer to the
+ * lfile struct.  The CLRLFILEADD macro is expected to expand to statements
+ * that are complete -- i.e., have terminating semi-colons -- so the macro is
+ * called without a terminating semicolon by proc.c.
+ *
+ * The HASXOPT definition may be used to select the conditions under which
+ * private lfile elements are used.
+ */
+
+/* #define HASLFILEADD int ... */
+/* #define CLRLFILEADD(lf)     (lf)->... = (type)NULL; */
+/* #define SETLFILEADD Lf->... */
+
+/*
+ * 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       ??? */
+/* #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.
+ */
+
+#    if defined(HAS_SYS_PIPEH)
+#        define HASPIPEFN process_pipe
+#    endif /* defined(HAS_SYS_PIPEH) */
+
+/*
+ * 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?       */
+
+/*
+ * 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.  For FreeBSD, NetBSD,
+ * and OpenBSD the lsof Configure script defines HASPROCFS, based on the
+ * presence of /usr/src/sys/miscfs/procfs/procfs.h header file.
+ *
+ * HASFSTYPE is defined as 1 for those systems that have a file system type
+ * string, st_fstype, in the stat() buffer; 2, for those systems that have a
+ * file system type integer in the stat() buffer, named MOUNTS_STAT_FSTYPE;
+ * 0, for systems whose stat(2) structure has no file system type member.  The
+ * additional symbols MOUNTS_FSTYPE, RMNT_FSTYPE, and RMNT_STAT_FSTYPE may be
+ * defined in dlsof.h to direct how the readmnt() function in lib/rmnt.c
+ * preserves these stat(2) and getmntent(3) buffer values in the local mounts
+ * structure.
+ *
+ * The defined value is the string that names the file system type.
+ *
+ * The HASPROCFS definition usually must be accompanied by the HASFSTYPE
+ * definition and the providing of an fstype element in the local mounts
+ * structure (defined in dlsof.h).
+ *
+ * The HASPROCFS definition may be accompanied by the HASPINODEN definition.
+ * HASPINODEN specifies that searching for files in HASPROCFS is to be done
+ * by inode number.
+ */
+
+#    if defined(HASPROCFS)
+#        undef HASPROCFS
+#        define HASPROCFS "proc"
+#    endif /* defined(HASPROCFS) */
+
+/* #define HASPROCFS   "proc?" */
+/* #define             HASFSTYPE       1 */
+#    define HASPINODEN 1
+
+/*
+ * HASRNODE is defined for those dialects that have rnodes.
+ */
+
+/* #define     HASRNODE        1 */
+
+/*
+ * Define HASSECURITY to restrict the listing of all open files to the
+ * root user.  When HASSECURITY is defined, the non-root user may list
+ * only files whose processes have the same user ID as the real user ID
+ * (the one that its user logged on with) of the lsof process.
+ */
+
+/* #define     HASSECURITY     1 */
+
+/*
+ * If HASSECURITY is defined, define HASNOSOCKSECURITY to allow users
+ * restricted by HASSECURITY to list any open socket files, provide their
+ * listing is selected by the "-i" option.
+ */
+
+/* #define     HASNOSOCKSECURITY       1       */
+
+/*
+ * HASSETLOCALE is defined for those dialects that have <locale.h> and
+ * setlocale().
+ *
+ * If the dialect also has wide character support for language locales,
+ * HASWIDECHAR activates lsof's wide character support and WIDECHARINCL
+ * defines the header file (if any) that must be #include'd to use the
+ * mblen() and mbtowc() functions.
+ */
+
+#    define HASSETLOCALE 1
+
+/* #define     WIDECHARINCL    <wchar.h>       */
+
+/*
+ * HASSNODE is defined for those dialects that have snodes.
+ */
+
+/* #define     HASSNODE        1 */
+
+/*
+ * HASTASKS is defined for those dialects that have task reporting support.
+ */
+
+/* #define     HASTASKS        1 */
+
+/*
+ * HASSOOPT, HASSOSTATE and HASTCPOPT define the availability of information
+ * on socket options (SO_* symbols), socket states (SS_* symbols) and TCP
+ * options.
+ */
+
+#    define HASSOOPT 1   /* has socket option information */
+#    define HASSOSTATE 1 /* has socket state information */
+#    define HASTCPOPT 1  /* has TCP options or flags */
+
+/*
+ * Define HASSPECDEVD to be the name of a function that handles the results
+ * of a successful stat(2) of a file name argument.
+ *
+ * For example, HASSPECDEVD() for Darwin makes sure that st_dev is set to
+ * what stat("/dev") returns -- i.e., what's in DevDev.
+ *
+ * The function takes two arguments:
+ *
+ *     1: pointer to the full path name of file
+ *     2: pointer to the stat(2) result
+ *
+ * The function returns void.
+ */
+
+/* #define     HASSPECDEVD     process_dev_stat */
+
+/*
+ * HASSTREAMS is defined for those dialects that support streams.
+ */
+
+/* #define     HASSTREAMS      1 */
+
+/*
+ * HASTCPTPIQ is defined for dialects where it is possible to report the
+ * TCP/TPI Recv-Q and Send-Q values produced by netstat.
+ */
+
+#    define HASTCPTPIQ 1
+
+/*
+ * HASTCPTPIW is defined for dialects where it is possible to report the
+ * TCP/TPI send and receive window sizes produced by netstat.
+ */
+
+/* #define     HASTCPTPIW      1 */
+
+/*
+ * HASTMPNODE is defined for those dialects that have tmpnodes.
+ */
+
+/* #define     HASTMPNODE      1 */
+
+/*
+ * HASVNODE is defined for those dialects that use the Sun virtual file system
+ * node, the vnode.  BSD derivatives usually do; System V derivatives prior
+ * to R4 usually don't.
+ * doesn't.
+ */
+
+/* #define     HASVNODE        1 */
+
+/*
+ * HASXOPT is defined for those dialects that have an X option.  It
+ * defines the text for the usage display.  HASXOPT_VALUE defines the
+ * option's default binary value -- 0 or 1.
+ */
+
+/* #define     HASXOPT         "help text for X option" */
+/* #define     HASXOPT_VALUE   1 */
+
+/*
+ * INODETYPE and INODEPSPEC define the internal node number type and its
+ * printf specification modifier.  These need not be defined and lsof.h
+ * can be allowed to define defaults.
+ *
+ * These are defined here, because they must be used in dlsof.h.
+ */
+
+#    define INODETYPE unsigned long long
+/* inode number internal storage type */
+#    define INODEPSPEC                                                         \
+        "ll" /* INODETYPE printf specification                                 \
+              * modifier */
+
+/*
+ * UID_ARG defines the size of a User ID number when it is passed
+ * as a function argument.
+ */
+
+#    define UID_ARG int
+
+/*
+ * Each USE_LIB_<function_name> is defined for dialects that use the
+ * <function_name> in the lsof library.
+ *
+ * Note: other definitions and operations may be required to condition the
+ * library function source code.  They may be found in the dialect dlsof.h
+ * header files.
+ */
+
+/* #define     USE_LIB_CKKV                    1          ckkv.c */
+/* #define     USE_LIB_COMPLETEVFS             1          cvfs.c */
+#    define USE_LIB_FIND_CH_INO 1   /* fino.c */
+#    define USE_LIB_IS_FILE_NAMED 1 /* isfn.c */
+#    define USE_LIB_LKUPDEV 1       /* lkud.c */
+#    define USE_LIB_PRINTDEVNAME 1  /* pdvn.c */
+/* #define     USE_LIB_PROCESS_FILE            1          prfp.c */
+#    define USE_LIB_PRINT_TCPTPI 1 /* ptti.c */
+#    define USE_LIB_READDEV 1      /* rdev.c */
+/* #define     USE_LIB_READMNT                 1          rmnt.c */
+
+/* #define     USE_LIB_RNMT                    1          rnmt.c */
+/* #define     USE_LIB_RNMH                    1          rnmh.c */
+/* #define     USE_LIB_RNAM                    1          rnam.c */
+
+/* #define     USE_LIB_RNCH                    1          rnch.c */
+/* #define     USE_LIB_SNPF                    1          snpf.c */
+#    define snpf snprintf /* use the system's snprintf() */
+
+/*
+ * WARNDEVACCESS is defined for those dialects that should issue a warning
+ * when lsof can't access /dev (or /device) or one of its sub-directories.
+ * The warning can be inhibited by the lsof caller with the -w option.
+ */
+
+/* #define     WARNDEVACCESS   1 */
+
+/*
+ * WARNINGSTATE is defined for those dialects that want to suppress all lsof
+ * warning messages.
+ */
+
+/* #define     WARNINGSTATE    1       warnings are enabled by default */
+
+/*
+ * WILLDROPGID is defined for those dialects whose lsof executable runs
+ * setgid(not_real_GID) and whose setgid power can be relinquished after
+ * the dialect's initialize() function has been executed.
+ */
+
+#    define WILLDROPGID 1
+
+/*
+ * zeromem is a macro that uses bzero or memset.
+ */
+
+#    define zeromem(a, l) memset(a, 0, l)
+
+#endif /* !defined(LSOF_MACHINE_H) */
diff --git a/lib/dialects/openbsd/tests/case-00-openbsd-hello.bash b/lib/dialects/openbsd/tests/case-00-openbsd-hello.bash
new file mode 100755 (executable)
index 0000000..ca916d0
--- /dev/null
@@ -0,0 +1 @@
+exit 0
diff --git a/lib/dialects/sun/Makefile b/lib/dialects/sun/Makefile
new file mode 100644 (file)
index 0000000..c3e0cd4
--- /dev/null
@@ -0,0 +1,159 @@
+
+# Sun Makefile
+#
+# $Id: Makefile,v 1.13 2008/04/15 13:30:50 abe Exp $
+
+PROG=  lsof
+
+I=/usr/include
+S=/usr/include/sys
+L=/usr/include/local
+P=
+
+CDEF=
+CDEFS=  ${CDEF} ${CFGF}
+INCL=  ${DINC}
+CFLAGS=        ${CDEFS} ${INCL} ${DEBUG}
+
+HDR=    lsof.h lsof_fields.h dlsof.h machine.h proto.h dproto.h
+
+SRC=    ddev.c dfile.c dmnt.c dnode.c dnode1.c dnode2.c dproc.c dsock.c \
+       dstore.c \
+       arg.c main.c misc.c node.c print.c proc.c store.c usage.c util.c
+
+OBJ=   ddev.o dfile.o dmnt.o dnode.o dnode1.o dnode2.o dproc.o dsock.o \
+       dstore.o \
+       arg.o main.o misc.o node.o print.o proc.o store.o usage.o util.o
+
+MAN=   lsof.8
+
+OTHER= 
+
+SHELL= /bin/sh
+
+SOURCE=        Makefile ${OTHER} ${MAN} ${HDR} ${SRC}
+
+all: ${PROG}
+
+${PROG}: ${LIB} ${P} ${OBJ}
+       ${CC} -o $@ ${CFLAGS} ${OBJ} ${CFGL}
+
+clean: FRC
+       rm -f Makefile.bak ${PROG} a.out core errs lint.out tags *.o version.h
+       rm -f machine.h.old new_machine.h
+       (cd lib; ${MAKE} -f Makefile.skel clean)
+
+install: all FRC
+       @echo ''
+       @echo 'Please write your own install rule.  Lsof should be installed'
+       @echo 'setgid to the group that can can read /dev/kmem.  Normally'
+       @echo 'that is the kmem (SunOS) or sys (Solaris) group.  Your SunOS'
+       @echo 'install rule actions might look something like this:'
+       @echo ''
+       @echo '  install <options> -m 2755 -g kmem ${PROG} <bin_dest>'
+       @echo '  install <options> -m 444 ${MAN} <man_dest>'
+       @echo ''
+       @echo 'Your Solaris install rule actions might look something like
+       @echo 'this:'
+       @echo ''
+       @echo '  install -[cf] <bin_dest> <options> -m 2755 -g sys ${PROG}'
+       @echo '  install -[cf] <man_dest> <options> -m 444 ${MAN}'
+       @echo ''
+       @echo 'You may have to put additional values in <options>, as required'
+       @echo 'by the install application in your version of SunOS or Solaris.'
+       @echo 'You will have to set the appropriate destination for the lsof'
+       @echo 'executable in <bin_dest>; the appropriate destination for the'
+       @echo 'man page in <man_dest>.'
+       @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_CCFLAGS    "'`echo ${CFLAGS} | sed 's/\\\\(/\\(/g' | sed 's/\\\\)/\\)/g' | sed 's/"/\\\\"/g'`'"' >> version.h
+       @echo '#define  LSOF_CINFO      "${CINFO}"' >> version.h
+       @if [ "X${LSOF_HOST}" = "X" ]; then \
+         echo '#define LSOF_HOST       "'`uname -n`'"' >> version.h; \
+       else \
+         if [ "${LSOF_HOST}" = "none" ]; then \
+           echo '#define       LSOF_HOST       ""' >> version.h; \
+         else \
+           echo '#define       LSOF_HOST       "${LSOF_HOST}"' >> version.h; \
+         fi \
+       fi
+       @echo '#define  LSOF_LDFLAGS    "${CFGL}"' >> version.h
+       @if [ "X${LSOF_LOGNAME}" = "X" ]; then \
+         echo '#define LSOF_LOGNAME    "${LOGNAME}"' >> version.h; \
+       else \
+         if [ "${LSOF_LOGNAME}" = "none" ]; then \
+           echo '#define       LSOF_LOGNAME    ""' >> version.h; \
+         else \
+           echo '#define       LSOF_LOGNAME    "${LSOF_LOGNAME}"' >> version.h; \
+         fi; \
+       fi
+       @if [ "X${LSOF_SYSINFO}" = "X" ]; then \
+           echo '#define       LSOF_SYSINFO    "'`uname -a`'"' >> version.h; \
+       else \
+         if [ "${LSOF_SYSINFO}" = "none" ]; then \
+           echo '#define       LSOF_SYSINFO    ""' >> version.h; \
+         else \
+           echo '#define       LSOF_SYSINFO    "${LSOF_SYSINFO}"' >> version.h; \
+         fi \
+       fi
+       @if [ "X${LSOF_USER}" = "X" ]; then \
+         echo '#define LSOF_USER       "${USER}"' >> version.h; \
+       else \
+         if [ "${LSOF_USER}" = "none" ]; then \
+           echo '#define       LSOF_USER       ""' >> version.h; \
+         else \
+           echo '#define       LSOF_USER       "${LSOF_USER}"' >> version.h; \
+         fi \
+       fi
+       @sed '/VN/s/.ds VN \(.*\)/#define       LSOF_VERSION    "\1"/' < version >> version.h
+
+FRC:
+
+# DO NOT DELETE THIS LINE - make depend DEPENDS ON IT
+
+ddev.o:                ${HDR} ddev.c
+
+dfile.o:       ${HDR} dfile.c
+
+dmnt.o:                ${HDR} dmnt.c
+
+dnode.o:       ${HDR} dnode.c
+
+dnode1.o:      ${HDR} dnode1.c
+
+dnode2.o:      ${HDR} dnode2.c
+
+dproc.o:       ${HDR} kernelbase.h 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/lib/dialects/sun/Mksrc b/lib/dialects/sun/Mksrc
new file mode 100755 (executable)
index 0000000..78ad256
--- /dev/null
@@ -0,0 +1,27 @@
+#!/bin/bash
+#
+# Mksrc - make Solaris source files
+#
+# WARNING: This script assumes it is running from the main directory
+#         of the lsof, version 4 distribution.
+#
+# One environment variable applies:
+#
+# LSOF_MKC     is the method for creating the source files.
+#              It defaults to "ln -s".  A common alternative is "cp".
+#
+# $Id: Mksrc,v 1.4 2000/12/04 14:35:13 abe Exp $
+
+mksrc() {
+  for i in $L
+  do
+    rm -f $i
+    $LSOF_MKC $D/$i $i
+    echo "$LSOF_MKC $D/$i $i"
+  done
+}
+
+D=lib/dialects/sun
+L="ddev.c dfile.c dlsof.h dmnt.c dnode.c dnode1.c dnode2.c dproc.c dproto.h dsock.c dstore.c machine.h"
+
+mksrc
diff --git a/lib/dialects/sun/ddev.c b/lib/dialects/sun/ddev.c
new file mode 100644 (file)
index 0000000..53265a0
--- /dev/null
@@ -0,0 +1,1086 @@
+/*
+ * ddev.c - Solaris device support functions for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#ifndef lint
+static char copyright[] =
+    "@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
+#endif
+
+#include "common.h"
+
+/*
+ * Local definitions
+ */
+
+#define LIKE_BLK_SPEC "like block special"
+#define LIKE_CHR_SPEC "like character special"
+
+/*
+ * Local static values
+ */
+
+static int Devx = 0; /* current Devtp[] index */
+
+/*
+ * Local function prototypes
+ */
+
+static void make_devtp(struct lsof_context *ctx, struct stat *s, char *p);
+static int rmdupdev(struct lsof_context *ctx, struct l_dev ***dp, int n,
+                    int ty);
+
+/*
+ * make_devtp() - make Devtp[] entry
+ */
+
+static void make_devtp(struct lsof_context *ctx, /* context */
+                       struct stat *s,           /* device lstat() buffer */
+                       char *p)                  /* device path name */
+{
+
+    /*
+     * Make room for another Devtp[] entry.
+     */
+    if (Devx >= Ndev) {
+        Ndev += DEVINCR;
+        if (!Devtp)
+            Devtp =
+                (struct l_dev *)malloc((MALLOC_S)(sizeof(struct l_dev) * Ndev));
+        else
+            Devtp = (struct l_dev *)realloc(
+                (MALLOC_P *)Devtp, (MALLOC_S)(sizeof(struct l_dev) * Ndev));
+        if (!Devtp) {
+            (void)fprintf(stderr, "%s: no space for character device\n", Pn);
+            Error(ctx);
+        }
+    }
+    /*
+     * Store the device number, inode number, and name in the Devtp[] entry.
+     */
+    Devtp[Devx].inode = (INODETYPE)s->st_ino;
+    if (!(Devtp[Devx].name = mkstrcpy(p, (MALLOC_S *)NULL))) {
+        (void)fprintf(stderr, "%s: no space for /dev/", Pn);
+        safestrprt(p, stderr, 1);
+        Error(ctx);
+    }
+    Devtp[Devx].rdev = s->st_rdev;
+    Devtp[Devx].v = 0;
+    Devx++;
+}
+
+/*
+ * printdevname() - print block or character device name
+ */
+
+int printdevname(struct lsof_context *ctx, /* context */
+                 dev_t *dev,               /* device */
+                 dev_t *rdev,              /* raw device */
+                 int f,                    /* 1 = print trailing '\n' */
+                 int nty)                  /* node type: N_BLK or N_CHR */
+{
+    struct clone *c;
+    struct l_dev *dp;
+    struct pseudo *p;
+
+    readdev(ctx, 0);
+    /*
+     * Search device table for a full match.
+     */
+
+#if defined(HASDCACHE)
+
+printchdevname_again:
+
+#endif /* defined(HASDCACHE) */
+
+#if defined(HASBLKDEV)
+    if (nty == N_BLK)
+        dp = lkupbdev(ctx, dev, rdev, 1, 0);
+    else
+#endif /* defined(HASBLKDEV) */
+
+        dp = lkupdev(ctx, dev, rdev, 1, 0);
+    if (dp) {
+        safestrprt(dp->name, stdout, f);
+        return (1);
+    }
+    /*
+     * Search device table for a match without inode number and dev.
+     */
+
+#if defined(HASBLKDEV)
+    if (nty == N_BLK)
+        dp = lkupbdev(ctx, &DevDev, rdev, 0, 0);
+    else
+#endif /* defined(HASBLKDEV) */
+
+        dp = lkupdev(ctx, &DevDev, rdev, 0, 0);
+    if (dp) {
+
+        /*
+         * A match was found.  Record it as a name column addition.
+         */
+        char *cp, *ttl;
+        int len;
+
+        ttl = (nty == N_BLK) ? LIKE_BLK_SPEC : LIKE_CHR_SPEC;
+        len = (int)(1 + strlen(ttl) + 1 + strlen(dp->name) + 1);
+        if (!(cp = (char *)malloc((MALLOC_S)(len + 1)))) {
+            (void)fprintf(stderr, "%s: no nma space for: (%s %s)\n", Pn, ttl,
+                          dp->name);
+            Error(ctx);
+        }
+        (void)snpf(cp, len + 1, "(%s %s)", ttl, dp->name);
+        (void)add_nma(ctx, cp, len);
+        (void)free((MALLOC_P *)cp);
+        return (0);
+    }
+    /*
+     * Search for clone parent.
+     */
+    if ((nty == N_CHR) && Lf->is_stream && Clone && (*dev == DevDev)) {
+        for (c = Clone; c; c = c->next) {
+            if (GET_MAJ_DEV(*rdev) == GET_MIN_DEV(c->cd.rdev)) {
+
+#if defined(HASDCACHE)
+                if (DCunsafe && !c->cd.v && !vfy_dev(ctx, &c->cd))
+                    goto printchdevname_again;
+#endif /* defined(HASDCACHE) */
+
+                safestrprt(c->cd.name, stdout, f);
+                return (1);
+            }
+        }
+    }
+    /*
+     * Search for pseudo device match on major device only.
+     */
+    if ((nty == N_CHR) && *dev == DevDev) {
+        for (p = Pseudo; p; p = p->next) {
+            if (GET_MAJ_DEV(*rdev) == GET_MAJ_DEV(p->pd.rdev)) {
+
+#if defined(HASDCACHE)
+                if (DCunsafe && !p->pd.v && vfy_dev(ctx, &p->pd))
+                    goto printchdevname_again;
+#endif /* defined(HASDCACHE) */
+
+                safestrprt(p->pd.name, stdout, f);
+                return (1);
+            }
+        }
+    }
+
+#if defined(HASDCACHE)
+    /*
+     * If the device cache is "unsafe" and we haven't found any match, reload
+     * the device cache.
+     */
+    if (DCunsafe) {
+        (void)rereaddev(ctx);
+        goto printchdevname_again;
+    }
+#endif /* defined(HASDCACHE) */
+
+    return (0);
+}
+
+/*
+ * read_clone() - read Solaris clone device information
+ */
+
+void read_clone(struct lsof_context *ctx) {
+    struct clone *c;
+    char *cn;
+    DIR *dfp;
+    struct DIRTYPE *dp;
+    char *fp = (char *)NULL;
+    MALLOC_S fpl;
+    char *path;
+    MALLOC_S pl;
+    struct pseudo *p;
+    struct stat sb;
+
+    if (Clone || Pseudo)
+        return;
+    /*
+     * Open the /DVCH_DEVPATH/pseudo directory.
+     */
+    if (!(path = mkstrcat(DVCH_DEVPATH, -1, "/", 1, "pseudo ", -1, &pl))) {
+        (void)fprintf(stderr, "%s: no space for %s/pseudo\n", DVCH_DEVPATH, Pn);
+        Error(ctx);
+    }
+    path[pl - 1] = '\0';
+    if (!(dfp = OpenDir(path))) {
+
+#if defined(WARNDEVACCESS)
+        if (!Fwarn) {
+            (void)fprintf(stderr, "%s: WARNING: can't open: ", Pn);
+            safestrprt(path, stderr, 1);
+        }
+#endif /* defined(WARNDEVACCESS) */
+
+        (void)free((FREE_P *)path);
+        return;
+    }
+    path[pl - 1] = '/';
+    /*
+     * Scan the directory.
+     */
+    for (dp = ReadDir(dfp); dp; dp = ReadDir(dfp)) {
+        if (dp->d_ino == 0 || dp->d_name[0] == '.')
+            continue;
+        /*
+         * Form the full path name and stat() it.
+         */
+        if (fp) {
+            (void)free((FREE_P *)fp);
+            fp = (char *)NULL;
+        }
+        if (!(fp =
+                  mkstrcat(path, pl, dp->d_name, -1, (char *)NULL, -1, &fpl))) {
+            (void)fprintf(stderr, "%s: no space for: ", Pn);
+            safestrprt(path, stderr, 0);
+            safestrprt(dp->d_name, stderr, 1);
+            Error(ctx);
+        }
+
+#if defined(USE_STAT)
+        if (stat(fp, &sb) != 0)
+#else  /* !defined(USE_STAT) */
+        if (lstat(fp, &sb) != 0)
+#endif /* defined(USE_STAT) */
+
+        {
+            if (!Fwarn) {
+                int errno_save = errno;
+
+                (void)fprintf(stderr, "%s: can't stat: ", Pn);
+                safestrprt(fp, stderr, 0);
+                (void)fprintf(stderr, ": %s\n", strerror(errno_save));
+            }
+            continue;
+        }
+        /*
+         * Skip subdirectories and all but character devices.
+         */
+        if ((sb.st_mode & S_IFMT) == S_IFDIR ||
+            (sb.st_mode & S_IFMT) != S_IFCHR)
+            continue;
+        /*
+         * Make Devtp[] entry.
+         */
+        make_devtp(ctx, &sb, fp);
+        /*
+         * Create a clone structure entry for "clone*:" devices.
+         *
+         * Make special note of network clones -- tcp, and udp.
+         */
+        if (strncmp(&fp[pl], "clone", 5) == 0) {
+            if (!(cn = strrchr(&fp[pl], ':')))
+                continue;
+            /*
+             * Allocate a clone structure.
+             */
+            if (!(c = (struct clone *)malloc(sizeof(struct clone)))) {
+                (void)fprintf(stderr,
+                              "%s: no space for network clone device: ", Pn);
+                safestrprt(fp, stderr, 1);
+                Error(ctx);
+            }
+            /*
+             * Allocate space for the path name.
+             */
+            if (!(c->cd.name = mkstrcpy(fp, (MALLOC_S *)NULL))) {
+                (void)fprintf(stderr, "%s: no space for clone name: ", Pn);
+                safestrprt(fp, stderr, 1);
+                Error(ctx);
+            }
+            /*
+             * Save the inode and device numbers.  Clear the verify flag.
+             */
+            c->cd.inode = (INODETYPE)sb.st_ino;
+            c->cd.rdev = sb.st_rdev;
+            c->cd.v = 0;
+            /*
+             * Make special note of a network clone device.
+             */
+            if (!strcmp(++cn, "tcp") || !strcmp(cn, "udp"))
+                c->n = cn - fp;
+            else
+                c->n = 0;
+            /*
+             * Link the new clone entry to the rest.
+             */
+            c->next = Clone;
+            Clone = c;
+            continue;
+        }
+        /*
+         * Save pseudo device information.
+         */
+        if (GET_MIN_DEV(sb.st_rdev) == 0) {
+
+            /*
+             * Allocate space for the pseduo device entry.
+             */
+            if (!(p = (struct pseudo *)malloc(sizeof(struct pseudo)))) {
+                (void)fprintf(stderr, "%s: no space for pseudo device: ", Pn);
+                safestrprt(fp, stderr, 1);
+                Error(ctx);
+            }
+            /*
+             * Save the path name, and inode and device numbers.  Clear the
+             * verify flag.  Link the entry to the pseudo chain.
+             */
+            p->pd.inode = (INODETYPE)sb.st_ino;
+            p->pd.name = fp;
+            fp = (char *)NULL;
+            p->pd.rdev = sb.st_rdev;
+            p->pd.v = 0;
+            p->next = Pseudo;
+            Pseudo = p;
+        }
+    }
+    (void)CloseDir(dfp);
+    if (fp)
+        (void)free((FREE_P *)fp);
+    if (path)
+        (void)free((FREE_P *)path);
+}
+
+/*
+ * readdev() - read names, modes and device types of everything in /dev
+ *            or /device (Solaris)
+ */
+
+void readdev(struct lsof_context *ctx, /* context */
+             int skip)                 /* skip device cache read if 1 */
+{
+
+#if defined(HASDCACHE)
+    int dcrd = 0;
+#endif /* defined(HASDCACHE) */
+
+    DIR *dfp;
+    struct DIRTYPE *dp;
+    char *fp = (char *)NULL;
+    MALLOC_S fpl;
+    int i;
+
+#if defined(HASBLKDEV)
+    int j = 0;
+#endif /* defined(HASBLKDEV) */
+
+    char *path = (char *)NULL;
+    char *ppath = (char *)NULL;
+    MALLOC_S pl;
+    struct stat sb;
+
+    if (Sdev)
+        return;
+
+#if defined(HASDCACHE)
+    /*
+     * Read device cache, as directed.
+     */
+    if (!skip) {
+        if (DCstate == 2 || DCstate == 3) {
+            if ((dcrd = read_dcache(ctx)) == 0)
+                return;
+        }
+    } else
+        dcrd = 1;
+#endif /* defined(HASDCACHE) */
+
+    if (!(ppath = mkstrcat(DVCH_DEVPATH, -1, "/", 1, "pseudo", -1,
+                           (MALLOC_S *)NULL))) {
+        (void)fprintf(stderr, "%s: no space for: %s/pseudo\n", Pn,
+                      DVCH_DEVPATH);
+        Error(ctx);
+    }
+    read_clone(ctx);
+    Dstk = (char **)NULL;
+    Dstkn = Dstkx = 0;
+    (void)stkdir(ctx, DVCH_DEVPATH);
+    /*
+     * Unstack the next directory.
+     */
+    while (--Dstkx >= 0) {
+        if (!(dfp = OpenDir(Dstk[Dstkx]))) {
+
+#if defined(WARNDEVACCESS)
+            if (!Fwarn) {
+                (void)fprintf(stderr, "%s: WARNING: can't open: ", Pn);
+                safestrprt(Dstk[Dstkx], stderr, 1);
+            }
+#endif /* defined(WARNDEVACCESS) */
+
+            (void)free((FREE_P *)Dstk[Dstkx]);
+            Dstk[Dstkx] = (char *)NULL;
+            continue;
+        }
+        /*
+         * Create a directory name buffer with a trailing slash.
+         */
+        if (path) {
+            (void)free((FREE_P *)path);
+            path = (char *)NULL;
+        }
+        if (!(path =
+                  mkstrcat(Dstk[Dstkx], -1, "/", 1, (char *)NULL, -1, &pl))) {
+            (void)fprintf(stderr, "%s: no space for: ", Pn);
+            safestrprt(Dstk[Dstkx], stderr, 1);
+            Error(ctx);
+        }
+        (void)free((FREE_P *)Dstk[Dstkx]);
+        Dstk[Dstkx] = (char *)NULL;
+        /*
+         * Scan the directory.
+         */
+        for (dp = ReadDir(dfp); dp; dp = ReadDir(dfp)) {
+            if (dp->d_ino == 0 || dp->d_name[0] == '.')
+                continue;
+            /*
+             * Form the full path name and get its status.
+             */
+            if (fp) {
+                (void)free((FREE_P *)fp);
+                fp = (char *)NULL;
+            }
+            if (!(fp = mkstrcat(path, pl, dp->d_name, -1, (char *)NULL, -1,
+                                &fpl))) {
+                (void)fprintf(stderr, "%s: no space for: ", Pn);
+                safestrprt(path, stderr, 0);
+                safestrprt(dp->d_name, stderr, 1);
+                Error(ctx);
+            }
+
+#if defined(USE_STAT)
+            if (stat(fp, &sb) != 0)
+#else  /* !defined(USE_STAT) */
+            if (lstat(fp, &sb) != 0)
+#endif /* defined(USE_STAT) */
+
+            {
+                if (errno == ENOENT) /* symbolic link to nowhere? */
+                    continue;
+
+#if defined(WARNDEVACCESS)
+                if (!Fwarn) {
+                    int errno_save = errno;
+
+                    (void)fprintf(stderr, "%s: can't stat ", Pn);
+                    safestrprt(fp, stderr, 0);
+                    (void)fprintf(stderr, ": %s\n", strerror(errno_save));
+                }
+#endif /* defined(WARNDEVACCESS) */
+
+                continue;
+            }
+            /*
+             * If it's a subdirectory, stack its name for later processing.
+             */
+            if ((sb.st_mode & S_IFMT) == S_IFDIR) {
+
+                /*
+                 * Skip Solaris /DVCH_DEV_PATH/pseudo sub-directory;
+                 * it has been examined in read_clone().
+                 */
+                if (strcmp(fp, ppath) == 0)
+                    continue;
+                (void)stkdir(ctx, fp);
+                continue;
+            }
+            if ((sb.st_mode & S_IFMT) == S_IFCHR) {
+
+                /*
+                 * Make Devtp[] entry.
+                 */
+                make_devtp(ctx, &sb, fp);
+            }
+
+#if defined(HASBLKDEV)
+            if ((sb.st_mode & S_IFMT) == S_IFBLK) {
+
+                /*
+                 * Save block device information in BDevtp[].
+                 */
+                if (j >= BNdev) {
+                    BNdev += DEVINCR;
+                    if (!BDevtp)
+                        BDevtp = (struct l_dev *)malloc(
+                            (MALLOC_S)(sizeof(struct l_dev) * BNdev));
+                    else
+                        BDevtp = (struct l_dev *)realloc(
+                            (MALLOC_P *)BDevtp,
+                            (MALLOC_S)(sizeof(struct l_dev) * BNdev));
+                    if (!BDevtp) {
+                        (void)fprintf(stderr, "%s: no space for block device\n",
+                                      Pn);
+                        Error(ctx);
+                    }
+                }
+                BDevtp[j].rdev = sb.st_rdev;
+                BDevtp[j].inode = (INODETYPE)sb.st_ino;
+                BDevtp[j].name = fp;
+                fp = (char *)NULL;
+                BDevtp[j].v = 0;
+                j++;
+            }
+#endif /* defined(HASBLKDEV) */
+        }
+        (void)CloseDir(dfp);
+    }
+    /*
+     * Free any allocated space.
+     */
+    if (Dstk) {
+        (void)free((FREE_P *)Dstk);
+        Dstk = (char **)NULL;
+        Dstkn = Dstkx = 0;
+    }
+    if (fp)
+        (void)free((FREE_P *)fp);
+    if (path)
+        (void)free((FREE_P *)path);
+    if (ppath)
+        (void)free((FREE_P *)ppath);
+        /*
+         * Reduce the BDevtp[] (optional) and Devtp[] tables to their minimum
+         * sizes; allocate and build sort pointer lists; and sort the tables by
+         * device number.
+         */
+
+#if defined(HASBLKDEV)
+    if (BNdev) {
+        if (BNdev > j) {
+            BNdev = j;
+            BDevtp = (struct l_dev *)realloc(
+                (MALLOC_P *)BDevtp, (MALLOC_S)(sizeof(struct l_dev) * BNdev));
+        }
+        if (!(BSdev = (struct l_dev **)malloc(
+                  (MALLOC_S)(sizeof(struct l_dev *) * BNdev)))) {
+            (void)fprintf(stderr,
+                          "%s: no space for block device sort pointers\n", Pn);
+            Error(ctx);
+        }
+        for (j = 0; j < BNdev; j++) {
+            BSdev[j] = &BDevtp[j];
+        }
+        (void)qsort((QSORT_P *)BSdev, (size_t)BNdev,
+                    (size_t)sizeof(struct l_dev *), compdev);
+        BNdev = rmdupdev(ctx, &BSdev, BNdev, 0);
+    } else {
+        if (!Fwarn)
+            (void)fprintf(stderr, "%s: WARNING: no block devices found\n", Pn);
+    }
+#endif /* defined(HASBLKDEV) */
+
+    if (Ndev) {
+        if (Ndev > Devx) {
+            Ndev = Devx;
+            Devtp = (struct l_dev *)realloc(
+                (MALLOC_P *)Devtp, (MALLOC_S)(sizeof(struct l_dev) * Ndev));
+        }
+        if (!(Sdev = (struct l_dev **)malloc(
+                  (MALLOC_S)(sizeof(struct l_dev *) * Ndev)))) {
+            (void)fprintf(stderr,
+                          "%s: no space for character device sort pointers\n",
+                          Pn);
+            Error(ctx);
+        }
+        for (i = 0; i < Ndev; i++) {
+            Sdev[i] = &Devtp[i];
+        }
+        (void)qsort((QSORT_P *)Sdev, (size_t)Ndev,
+                    (size_t)sizeof(struct l_dev *), compdev);
+        Ndev = rmdupdev(ctx, &Sdev, Ndev, 1);
+    } else {
+        (void)fprintf(stderr, "%s: no character devices found\n", Pn);
+        Error(ctx);
+    }
+
+#if defined(HASDCACHE)
+    /*
+     * Write device cache file, as required.
+     */
+    if (DCstate == 1 || (DCstate == 3 && dcrd))
+        write_dcache(ctx);
+#endif /* defined(HASDCACHE) */
+}
+
+/*
+ * clr_sect() - clear cached clone and pseudo sections
+ */
+
+void clr_sect(struct lsof_context *ctx) {
+    if (Clone) {
+        struct clone *c, *c1;
+
+        for (c = Clone; c; c = c1) {
+            c1 = c->next;
+            if (c->cd.name)
+                (void)free((FREE_P *)c->cd.name);
+            (void)free((FREE_P *)c);
+        }
+        Clone = (struct clone *)NULL;
+    }
+    if (Pseudo) {
+        struct pseudo *p, *p1;
+
+        for (p = Pseudo; p; p = p1) {
+            p1 = p->next;
+            if (p->pd.name)
+                (void)free((FREE_P *)p->pd.name);
+            (void)free((FREE_P *)p);
+        }
+        Pseudo = (struct pseudo *)NULL;
+    }
+}
+
+#if defined(HASDCACHE)
+/*
+ * rw_clone_sect() - read/write the device cache file clone section
+ */
+
+int rw_clone_sect(struct lsof_context *ctx,
+                  int m) /* mode: 1 = read; 2 = write */
+{
+    char buf[MAXPATHLEN * 2], *cp;
+    struct clone *c;
+    int i, len, n;
+
+    if (m == 1) {
+
+        /*
+         * Read the clone section header and validate it.
+         */
+        if (!fgets(buf, sizeof(buf), DCfs)) {
+
+        bad_clone_sect:
+
+            if (!Fwarn) {
+                (void)fprintf(stderr,
+                              "%s: bad clone section header in %s: ", Pn,
+                              DCpath[DCpathX]);
+                safestrprt(buf, stderr, 1);
+            }
+            return (1);
+        }
+        (void)crc(buf, strlen(buf), &DCcksum);
+        len = strlen("clone section: ");
+        if (strncmp(buf, "clone section: ", len) != 0)
+            goto bad_clone_sect;
+        if ((n = atoi(&buf[len])) < 0)
+            goto bad_clone_sect;
+        /*
+         * Read the clone section lines and create the Clone list.
+         */
+        for (i = 0; i < n; i++) {
+            if (!fgets(buf, sizeof(buf), DCfs)) {
+                if (!Fwarn) {
+                    (void)fprintf(stderr, "%s: bad clone line in %s: ", Pn,
+                                  DCpath[DCpathX]);
+                    safestrprt(buf, stderr, 1);
+                }
+                return (1);
+            }
+            (void)crc(buf, strlen(buf), &DCcksum);
+            /*
+             * Allocate a clone structure.
+             */
+            if (!(c = (struct clone *)calloc(1, sizeof(struct clone)))) {
+                (void)fprintf(stderr, "%s: no space for cached clone: ", Pn);
+                safestrprt(buf, stderr, 1);
+                Error(ctx);
+            }
+            /*
+             * Enter the clone device number.
+             *
+             * New format clone lines (with an inode number) have a leading
+             * space, so that older lsof versions, not expecting them, will
+             * not use the new format lines.
+             */
+            if (buf[0] != ' ' || !(cp = x2dev(&buf[1], &c->cd.rdev)) ||
+                *cp++ != ' ') {
+                if (!Fwarn) {
+                    (void)fprintf(stderr, "%s: bad cached clone device: ", Pn);
+                    safestrprt(buf, stderr, 1);
+                }
+                return (1);
+            }
+            /*
+             * Enter the clone network value.
+             */
+            for (c->n = 0; *cp != ' '; cp++) {
+                if (*cp < '0' || *cp > '9') {
+                    if (!Fwarn) {
+                        (void)fprintf(
+                            stderr, "%s: bad cached clone network flag: ", Pn);
+                        safestrprt(buf, stderr, 1);
+                    }
+                    return (1);
+                }
+                c->n = (c->n * 10) + (int)(*cp - '0');
+            }
+            /*
+             * Enter the clone device inode number.
+             */
+            for (c->cd.inode = (INODETYPE)0, ++cp; *cp != ' '; cp++) {
+                if (*cp < '0' || *cp > '9') {
+                    if (!Fwarn) {
+                        (void)fprintf(
+                            stderr, "%s: bad cached clone inode number: ", Pn);
+                        safestrprt(buf, stderr, 1);
+                    }
+                    return (1);
+                }
+                c->cd.inode =
+                    (INODETYPE)((c->cd.inode * 10) + (int)(*cp - '0'));
+            }
+            /*
+             * Enter the clone path name.
+             */
+            if ((len = strlen(++cp)) < 2 || *(cp + len - 1) != '\n') {
+                if (!Fwarn) {
+                    (void)fprintf(stderr, "%s: bad cached clone path: ", Pn);
+                    safestrprt(buf, stderr, 1);
+                }
+                return (1);
+            }
+            *(cp + len - 1) = '\0';
+            if (!(c->cd.name = mkstrcpy(cp, (MALLOC_S *)NULL))) {
+                (void)fprintf(stderr,
+                              "%s: no space for cached clone path: ", Pn);
+                safestrprt(buf, stderr, 1);
+                Error(ctx);
+            }
+            c->cd.v = 0;
+            c->next = Clone;
+            Clone = c;
+        }
+        return (0);
+    } else if (m == 2) {
+
+        /*
+         * Write the clone section header.
+         */
+        for (c = Clone, n = 0; c; c = c->next, n++)
+            ;
+        (void)snpf(buf, sizeof(buf), "clone section: %d\n", n);
+        if (wr2DCfd(ctx, buf, &DCcksum))
+            return (1);
+        /*
+         * Write the clone section lines.
+         *
+         *
+         * New format clone lines (with an inode number) have a leading
+         * space, so that older lsof versions, not expecting them, will
+         * not use the new format lines.
+         */
+        for (c = Clone; c; c = c->next) {
+            (void)snpf(buf, sizeof(buf), " %lx %d %ld %s\n", (long)c->cd.rdev,
+                       c->n, (long)c->cd.inode, c->cd.name);
+            if (wr2DCfd(ctx, buf, &DCcksum))
+                return (1);
+        }
+        return (0);
+    }
+    /*
+     * A shouldn't-happen case: mode neither 1 nor 2.
+     */
+    (void)fprintf(stderr, "%s: internal rw_clone_sect error: %d\n", Pn, m);
+    Error(ctx);
+    return (1); /* to make code analyzers happy */
+}
+
+/*
+ * rereaddev() - reread device names, modes and types
+ */
+
+void rereaddev(struct lsof_context *ctx) {
+    (void)clr_devtab(ctx);
+    (void)clr_sect(ctx);
+    Devx = 0;
+
+#    if defined(DCACHE_CLR)
+    (void)DCACHE_CLR(ctx);
+#    endif /* defined(DCACHE_CLR) */
+
+    readdev(ctx, 1);
+    DCunsafe = 0;
+}
+
+/*
+ * rw_pseudo_sect() - read/write the device cache pseudo section
+ */
+
+int rw_pseudo_sect(struct lsof_context *ctx,
+                   int m) /* mode: 1 = read; 2 = write */
+{
+    char buf[MAXPATHLEN * 2], *cp;
+    struct pseudo *p;
+    int i, len, n;
+
+    if (m == 1) {
+
+        /*
+         * Read the pseudo section header and validate it.
+         */
+        if (!fgets(buf, sizeof(buf), DCfs)) {
+
+        bad_pseudo_sect:
+
+            if (!Fwarn) {
+                (void)fprintf(stderr,
+                              "%s: bad pseudo section header in %s: ", Pn,
+                              DCpath[DCpathX]);
+                safestrprt(buf, stderr, 1);
+            }
+            return (1);
+        }
+        (void)crc(buf, strlen(buf), &DCcksum);
+        len = strlen("pseudo section: ");
+        if (strncmp(buf, "pseudo section: ", len) != 0)
+            goto bad_pseudo_sect;
+        if ((n = atoi(&buf[len])) < 0)
+            goto bad_pseudo_sect;
+        /*
+         * Read the pseudo section lines and create the Pseudo list.
+         */
+        for (i = 0; i < n; i++) {
+            if (!fgets(buf, sizeof(buf), DCfs)) {
+                if (!Fwarn) {
+                    (void)fprintf(stderr, "%s: bad pseudo line in %s: ", Pn,
+                                  DCpath[DCpathX]);
+                    safestrprt(buf, stderr, 1);
+                }
+                return (1);
+            }
+            (void)crc(buf, strlen(buf), &DCcksum);
+            /*
+             * Allocate a pseudo structure.
+             */
+            if (!(p = (struct pseudo *)calloc(1, sizeof(struct pseudo)))) {
+                (void)fprintf(stderr, "%s: no space for cached pseudo: ", Pn);
+                safestrprt(buf, stderr, 1);
+                Error(ctx);
+            }
+            /*
+             * Enter the pseudo device number.
+             *
+             * New format pseudo lines (with an inode number) have a leading
+             * space, so that older lsof versions, not expecting them, will
+             * not use the new format lines.
+             */
+            if (buf[0] != ' ' || !(cp = x2dev(&buf[1], &p->pd.rdev)) ||
+                *cp++ != ' ') {
+                if (!Fwarn) {
+                    (void)fprintf(stderr, "%s: bad cached pseudo device: ", Pn);
+                    safestrprt(buf, stderr, 1);
+                }
+                return (1);
+            }
+            /*
+             * Enter the pseudo inode number.
+             */
+            for (p->pd.inode = (INODETYPE)0; *cp != ' '; cp++) {
+                if (*cp < '0' || *cp > '9') {
+                    if (!Fwarn) {
+                        (void)fprintf(
+                            stderr, "%s: bad cached pseudo inode number: ", Pn);
+                        safestrprt(buf, stderr, 1);
+                    }
+                    return (1);
+                }
+                p->pd.inode =
+                    (INODETYPE)((p->pd.inode * 10) + (int)(*cp - '0'));
+            }
+            /*
+             * Enter the pseudo path name.
+             *
+             *
+             * New format clone lines (with an inode number) have a leading
+             * space, so that older lsof versions, not expecting them, will
+             * not use the new format lines.
+             */
+            if ((len = strlen(++cp)) < 2 || *(cp + len - 1) != '\n') {
+                if (!Fwarn) {
+                    (void)fprintf(stderr, "%s: bad cached pseudo path: ", Pn);
+                    safestrprt(buf, stderr, 1);
+                }
+                return (1);
+            }
+            if (!(p->pd.name = (char *)malloc(len))) {
+                (void)fprintf(stderr,
+                              "%s: no space for cached pseudo path: ", Pn);
+                safestrprt(buf, stderr, 1);
+                Error(ctx);
+            }
+            *(cp + len - 1) = '\0';
+            (void)snpf(p->pd.name, len, "%s", cp);
+            p->pd.v = 0;
+            p->next = Pseudo;
+            Pseudo = p;
+        }
+        return (0);
+    } else if (m == 2) {
+
+        /*
+         * Write the pseudo section header.
+         */
+        for (p = Pseudo, n = 0; p; p = p->next, n++)
+            ;
+        (void)snpf(buf, sizeof(buf), "pseudo section: %d\n", n);
+        if (wr2DCfd(ctx, buf, &DCcksum))
+            return (1);
+        /*
+         * Write the pseudo section lines.
+         *
+         *
+         * New format pseudo lines (with an inode number) have a leading
+         * space, so that older lsof versions, not expecting them, will
+         * not use the new format lines.
+         */
+        for (p = Pseudo; p; p = p->next) {
+            (void)snpf(buf, sizeof(buf), " %lx %ld %s\n", (long)p->pd.rdev,
+                       (long)p->pd.inode, p->pd.name);
+            if (wr2DCfd(ctx, buf, &DCcksum))
+                return (1);
+        }
+        return (0);
+    }
+    /*
+     * A shouldn't-happen case: mode neither 1 nor 2.
+     */
+    (void)fprintf(stderr, "%s: internal rw_pseudo_sect error: %d\n", Pn, m);
+    return (1);
+}
+
+/*
+ * vfy_dev() - verify a device table entry (usually when DCunsafe == 1)
+ *
+ * Note: rereads entire device table when an entry can't be verified.
+ */
+
+int vfy_dev(struct lsof_context *ctx, /* context */
+            struct l_dev *dp)         /* device table pointer */
+{
+    struct stat sb;
+
+    if (!DCunsafe || dp->v)
+        return (1);
+
+#    if defined(USE_STAT)
+    if (stat(dp->name, &sb) != 0
+#    else  /* !defined(USE_STAT) */
+    if (lstat(dp->name, &sb) != 0
+#    endif /* defined(USE_STAT) */
+
+        || dp->rdev != sb.st_rdev || dp->inode != (INODETYPE)sb.st_ino) {
+        (void)rereaddev(ctx);
+        return (0);
+    }
+    dp->v = 1;
+    return (1);
+}
+#endif /* defined(HASDCACHE) */
+
+/*
+ * rmdupdev() - remove duplicate (major/minor/inode) devices
+ */
+
+static int rmdupdev(struct lsof_context *ctx, /* context */
+                    struct l_dev ***dp, /* device table pointers address */
+                    int n,              /* number of pointers */
+                    int ty)             /* type: 0 = block, 1 = char */
+{
+    struct clone *c, *cp;
+    struct l_dev **d;
+    int i, j, k;
+    struct pseudo *p, *pp;
+
+    for (i = j = 0, d = *dp; i < n;) {
+        for (k = i + 1; k < n; k++) {
+            if (d[i]->rdev != d[k]->rdev || d[i]->inode != d[k]->inode)
+                break;
+            if (ty == 0)
+                continue;
+            /*
+             * See if we're deleting a duplicate clone device.  If so,
+             * delete its clone table entry.
+             */
+            for (c = Clone, cp = (struct clone *)NULL; c; cp = c, c = c->next) {
+                if (c->cd.rdev != d[k]->rdev || c->cd.inode != d[k]->inode ||
+                    strcmp(c->cd.name, d[k]->name))
+                    continue;
+                if (!cp)
+                    Clone = c->next;
+                else
+                    cp->next = c->next;
+                if (c->cd.name)
+                    (void)free((FREE_P *)c->cd.name);
+                (void)free((FREE_P *)c);
+                break;
+            }
+            /*
+             * See if we're deleting a duplicate pseudo device.  If so,
+             * delete its pseudo table entry.
+             */
+            for (p = Pseudo, pp = (struct pseudo *)NULL; p;
+                 pp = p, p = p->next) {
+                if (p->pd.rdev != d[k]->rdev || p->pd.inode != d[k]->inode ||
+                    strcmp(p->pd.name, d[k]->name))
+                    continue;
+                if (!pp)
+                    Pseudo = p->next;
+                else
+                    pp->next = p->next;
+                if (p->pd.name)
+                    (void)free((FREE_P *)p->pd.name);
+                (void)free((FREE_P *)p);
+                break;
+            }
+        }
+        if (i != j)
+            d[j] = d[i];
+        j++;
+        i = k;
+    }
+    if (n == j)
+        return (n);
+    if (!(*dp = (struct l_dev **)realloc(
+              (MALLOC_P *)*dp, (MALLOC_S)(j * sizeof(struct l_dev *))))) {
+        (void)fprintf(stderr, "%s: can't realloc %s device pointers\n", Pn,
+                      ty ? "char" : "block");
+        Error(ctx);
+    }
+    return (j);
+}
diff --git a/lib/dialects/sun/dfile.c b/lib/dialects/sun/dfile.c
new file mode 100644 (file)
index 0000000..c047bb6
--- /dev/null
@@ -0,0 +1,590 @@
+/*
+ * dfile.c - Solaris file processing functions for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#ifndef lint
+static char copyright[] =
+    "@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
+#endif
+
+#include "common.h"
+
+/*
+ * Local structures
+ */
+
+/*
+ * Local static variables
+ */
+
+/*
+ * Local definitions
+ */
+
+#define SFCDHASH 1024 /* Sfile hash by clone device */
+#define SFDIHASH                                                               \
+    4094 /* Sfile hash by (device,inode) number                                \
+          * pair bucket count (power of 2!) */
+#define SFFSHASH                                                               \
+    128 /* 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 m
+ * (m must be a power of 2) */
+#define SFNMHASH                                                               \
+    4096 /* Sfile hash by name bucket count                                    \
+  (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) */
+
+#if solaris < 20500
+/*
+ * get_max_fd() - get maximum file descriptor plus one
+ */
+
+int get_max_fd() {
+    struct rlimit r;
+
+    if (getrlimit(RLIMIT_NOFILE, &r))
+        return (-1);
+    return (r.rlim_cur);
+}
+#endif /* solaris<20500 */
+
+/*
+ * hashSfile() - hash Sfile entries for use in is_file_named() searches
+ */
+
+void hashSfile(struct lsof_context *ctx) {
+    int cmaj, hvc, i;
+    static int hs = 0;
+    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;
+    /*
+     * Preset the clone major device for Solaris.
+     */
+    if (HaveCloneMaj) {
+        cmaj = CloneMaj;
+        hvc = 1;
+    } else
+        hvc = 0;
+    /*
+     * Allocate hash buckets by clone device, (device,inode), file system
+     * device, and file name.
+     */
+    if (hvc) {
+        if (!(HbyCd = (struct hsfile *)calloc((MALLOC_S)SFCDHASH,
+                                              sizeof(struct hsfile)))) {
+            (void)fprintf(
+                stderr, "%s: can't allocate space for %d clone hash buckets\n",
+                Pn, SFCDHASH);
+            Error(ctx);
+        }
+    }
+    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);
+        Error(ctx);
+    }
+    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);
+        Error(ctx);
+    }
+    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);
+        Error(ctx);
+    }
+    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);
+        Error(ctx);
+    }
+    hs++;
+    /*
+     * Scan the Sfile chain, building file, file system, and file name hash
+     * bucket chains.
+     */
+    for (s = Sfile; s; s = s->next) {
+        for (i = 0; i < 4; i++) {
+            if (i == 0) {
+                if (!s->aname)
+                    continue;
+                sh = &HbyNm[hashbyname(s->aname, SFNMHASH)];
+                HbyNmCt++;
+            } else if (i == 1) {
+                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++;
+                }
+            } else if (i == 2) {
+                if (s->type && ((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;
+            } else {
+                if (!hvc || (GET_MAJ_DEV(s->rdev) != cmaj))
+                    continue;
+                sh = &HbyCd[SFHASHDEVINO(0, GET_MIN_DEV(s->rdev), 0, SFCDHASH)];
+                HbyCdCt++;
+            }
+            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);
+                    Error(ctx);
+                }
+                sn->s = s;
+                sn->next = sh->next;
+                sh->next = sn;
+            }
+        }
+    }
+}
+
+/*
+ * is_file_named() - is this file named?
+ */
+
+int is_file_named(struct lsof_context *ctx, /* context */
+                  char *p,       /* path name; NULL = search by device
+                                  * and inode (from *Lf) */
+                  int nt,        /* node type -- e.g., N_* */
+                  enum vtype vt, /* vnode type */
+                  int ps)        /* print status: 0 = don't copy name
+                                  * to Namech */
+{
+    char *ep;
+    int f = 0;
+    struct sfile *s;
+    struct hsfile *sh;
+    size_t sz;
+    /*
+     * Check for a path name match, as requested.
+     */
+    if (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 Solaris clone file.
+     */
+    if (!f && HbyCdCt && nt == N_STREAM && Lf->dev_def && Lf->rdev_def &&
+        (Lf->dev == DevDev)) {
+        for (sh = &HbyCd[SFHASHDEVINO(0, GET_MAJ_DEV(Lf->rdev), 0, SFCDHASH)];
+             sh; sh = sh->next) {
+            if ((s = sh->s) &&
+                (GET_MAJ_DEV(Lf->rdev) == GET_MIN_DEV(s->rdev))) {
+                f = 1;
+                break;
+            }
+        }
+    }
+    /*
+     * Check for a regular file.
+     */
+    if (!f && 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 && 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) && Lf->dev == s->dev) {
+                f = 1;
+                break;
+            }
+        }
+    }
+    /*
+     * Check for a character or block device match.
+     */
+    if (!f && HbyFrdCt && ((vt = VCHR) || (vt = VBLK)) && 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.
+     */
+    if (f) {
+        if (f == 2) {
+            if (ps)
+                (void)snpf(Namech, Namechl, "%s", p);
+        } else {
+            if (ps && 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(ctx, &sz);
+                    (void)snpf(ep, sz, " (%s)", s->devnm);
+                }
+            }
+        }
+        s->f = 1;
+        return (1);
+    }
+    return (0);
+}
+
+#if defined(HASPRINTDEV)
+/*
+ * print_dev() - print device
+ */
+
+char *print_dev(struct lfile *lf, /* file whose device is to be printed */
+                dev_t *dev)       /* device to be printed */
+{
+    static char buf[128];
+    /*
+     * Avoid the Solaris major() and minor() functions from makedev(3C) to get
+     * printable major/minor numbers.
+     *
+     * We would like to use the L_MAXMAJ definition from <sys/sysmacros.h> all
+     * the time, but it's not always correct in all versions of Solaris.
+     */
+    (void)snpf(buf, sizeof(buf), "%d,%d",
+               (int)((*dev >> L_BITSMINOR) &
+
+#    if solaris >= 20501
+                     L_MAXMAJ
+#    else  /* solaris<20501 */
+                     0x3fff
+#    endif /* solaris>=20501 */
+
+                     ),
+               (int)(*dev & L_MAXMIN));
+    return (buf);
+}
+#endif /* defined(HASPRINTDEV) */
+
+#if defined(HAS_V_PATH)
+
+/*
+ * Local definitions
+ */
+
+#    define VPRDLEN ((MAXPATHLEN + 7) / 8) /* v_path read length increment */
+
+/*
+ * print_v_path() - print path name from vnode's v_path pointer
+ */
+
+extern int print_v_path(struct lsof_context *ctx,
+                        struct lfile *lf) /* local file structure */
+{
+    char buf[MAXPATHLEN + 1];
+    unsigned char del = 0;
+    unsigned char aperr = 0;
+
+#    if defined(HASMNTSTAT)
+    struct stat sb;
+#    endif /* defined(HASMNTSTAT) */
+
+#    if defined(HASVXFS) && defined(HASVXFSRNL)
+    if (lf->is_vxfs && (lf->inp_ty == 1) && lf->fsdir) {
+        if (print_vxfs_rnl_path(lf))
+            return (1);
+    }
+#    endif /* defined(HASVXFS) && defined(HASVXFSRNL) */
+
+    (void)read_v_path(ctx, (KA_T)lf->V_path, buf, (size_t)sizeof(buf));
+    if (buf[0]) {
+
+#    if defined(HASMNTSTAT)
+        if (!lf->mnt_stat && lf->dev_def && (lf->inp_ty == 1)) {
+
+            /*
+             * No problem was detected in applying stat(2) to this mount point.
+             * If the device and inode for the file are known, it is probably
+             * safe and worthwhile to apply stat(2) to the v_path.
+             */
+            if (!statsafely(ctx, buf, &sb)) {
+
+                /*
+                 * The stat(2) succeeded.  See if the device and inode match.
+                 * If they both don't match, ignore the v_path.
+                 */
+                if ((lf->dev != sb.st_dev) ||
+                    (lf->inode != (INODETYPE)sb.st_ino)) {
+                    return (0);
+                }
+            } else {
+
+                /*
+                 * The stat(2) failed.
+                 *
+                 * If the error reply is ENOENT and the -X option hasn't been
+                 * specified, ignore the v_path.
+                 *
+                 * If the error reply is ENOENT, the -X option has been
+                 * specified and the file's link count is zero, report the
+                 * v_path with the "(deleted)" notation.
+                 *
+                 * If the error reply is EACCES or EPERM, report the v_path,
+                 * followed by "(?)", because lsof probably lacks permission
+                 * to apply stat(2) to v_path.
+                 */
+                switch (errno) {
+                case EACCES:
+                case EPERM:
+                    aperr = 1;
+                    break;
+                case ENOENT:
+
+#        if defined(HASXOPT)
+                    if (Fxopt && lf->nlink_def && !lf->nlink) {
+                        del = 1;
+                        break;
+                    }
+#        endif /* defined(HASXOPT) */
+
+                    return (0);
+                default:
+                    return (0);
+                }
+            }
+        }
+#    endif /* defined(HASMNTSTAT) */
+
+        /*
+         * Print the v_path.
+         */
+        safestrprt(buf, stdout, 0);
+        if (del)
+            safestrprt(" (deleted)", stdout, 0);
+        else if (aperr)
+            safestrprt(" (?)", stdout, 0);
+        return (1);
+    }
+    return (0);
+}
+
+/*
+ * read_v_path() - read path name from vnode's v_path pointer
+ */
+
+extern void read_v_path(struct lsof_context *ctx,
+                        KA_T ka,    /* kernel path address */
+                        char *rb,   /* receiving buffer */
+                        size_t rbl) /* receiving buffer length */
+{
+    char *ba;
+    size_t rl, tl;
+
+    *rb = '\0';
+    if (!ka)
+        return;
+    for (ba = rb, tl = 0; tl < (rbl - 1);
+         ba += rl, ka += (KA_T)((char *)ka + rl), tl += rl) {
+
+        /*
+         * Read v_path VPRDLEN bytes at a time until the local buffer is full
+         * or a NUL byte is reached.
+         */
+        if ((rl = rbl - 1 - tl) > VPRDLEN)
+            rl = VPRDLEN;
+        else if (rl < 1) {
+            *(rb + rbl - 1) = '\0';
+            break;
+        }
+        if (!kread(ctx, ka, ba, rl)) {
+            *(ba + rl) = '\0';
+            if (strchr(ba, '\0') < (ba + rl))
+                break;
+        } else {
+
+            /*
+             * Can't read a full buffer load; try reducing the length one
+             * byte at a time until it reaches zero.  Stop here, since it
+             * has been established that no more bytes can be read.
+             */
+            for (rl--; rl > 0; rl--) {
+                if (!kread(ctx, ka, ba, rl)) {
+                    *(ba + rl) = '\0';
+                    break;
+                }
+            }
+            if (rl <= 0)
+                *ba = '\0';
+            break;
+        }
+    }
+}
+#endif /* defined(HAS_V_PATH) */
+
+/*
+ * process_file() - process file
+ */
+
+void process_file(struct lsof_context *ctx, /* context */
+                  KA_T fp)                  /* kernel file structure address */
+{
+    struct file f;
+    int flag;
+
+#if defined(FILEPTR)
+    FILEPTR = &f;
+#endif /* defined(FILEPTR) */
+
+    if (kread(ctx, fp, (char *)&f, sizeof(f))) {
+        (void)snpf(Namech, Namechl, "can't read file struct from %s",
+                   print_kptr(fp, (char *)NULL, 0));
+        enter_nm(ctx, Namech);
+        return;
+    }
+    Lf->off = (SZOFFTYPE)f.f_offset;
+    Lf->off_def = 1;
+
+    if (f.f_count) {
+
+        /*
+         * Construct access code.
+         */
+        if ((flag = (f.f_flag & (FREAD | FWRITE))) == FREAD)
+            Lf->access = LSOF_FILE_ACCESS_READ;
+        else if (flag == FWRITE)
+            Lf->access = LSOF_FILE_ACCESS_WRITE;
+        else if (flag == (FREAD | FWRITE))
+            Lf->access = LSOF_FILE_ACCESS_READ_WRITE;
+
+#if defined(HASFSTRUCT)
+        /*
+         * Save file structure values.
+         */
+        Lf->fct = (long)f.f_count;
+        Lf->fsv |= FSV_CT;
+        Lf->fsa = fp;
+        Lf->fsv |= FSV_FA;
+        Lf->ffg = (long)f.f_flag;
+        Lf->fsv |= FSV_FG;
+        Lf->fna = (KA_T)f.f_vnode;
+        Lf->fsv |= FSV_NI;
+#endif /* defined(HASFSTRUCT) */
+
+        /*
+         * Solaris file structures contain a vnode pointer.  Process it.
+         */
+        process_node(ctx, (KA_T)f.f_vnode);
+        return;
+    }
+    enter_nm(ctx, "no more information");
+}
+
+#if defined(HASIPv6)
+/*
+ * gethostbyname2() -- an RFC2133-compatible get-host-by-name-two function
+ *                     to get AF_INET and AF_INET6 addresses from host names,
+ *                     using the RFC2553-compatible getipnodebyname() function
+ */
+
+extern struct hostent *gethostbyname2(nm, prot) const char *nm; /* host name */
+int prot; /* protocol -- AF_INET or AF_INET6 */
+{
+    int err;
+    static struct hostent *hep = (struct hostent *)NULL;
+
+    if (hep)
+        (void)freehostent(hep);
+    return ((hep = getipnodebyname(nm, prot, 0, &err)));
+}
+#endif /* defined(HASIPv6) */
diff --git a/lib/dialects/sun/distfile.kvm b/lib/dialects/sun/distfile.kvm
new file mode 100644 (file)
index 0000000..9559172
--- /dev/null
@@ -0,0 +1,14 @@
+# $Id: distfile.kvm,v 1.1 94/05/03 16:04:00 abe Exp $
+#
+# distfile.kvm -- an assist to distributing SunOS objects that use -lkvm
+#
+# This distfile allows Sun4 systems to limit distribution of object files
+# to systems of like architecture, using the source architecture definition
+# in SKVM and the destination architecture definition in KVM.
+#
+# The path of the object to be distributed is defined in OBJPATH.
+
+ifelse(SKVM,KVM,
+`( OBJPATH ) -> ( HOST )
+       install -b ;
+')dnl
diff --git a/lib/dialects/sun/dlsof.h b/lib/dialects/sun/dlsof.h
new file mode 100644 (file)
index 0000000..17725a7
--- /dev/null
@@ -0,0 +1,697 @@
+/*
+ * dlsof.h - Solaris header file for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+/*
+ * $Id: dlsof.h,v 1.48 2012/04/10 16:40:23 abe Exp $
+ */
+
+#if !defined(SOLARIS_LSOF_H)
+#    define SOLARIS_LSOF_H 1
+
+#    include <fcntl.h>
+#    include <sys/mntent.h>
+#    include <sys/mnttab.h>
+
+#    if solaris < 20600
+#        define _KMEMUSER 1
+#    else /* solaris>=20600 */
+#        include <stddef.h>
+#    endif /* solaris<20600 */
+
+#    include <stdlib.h>
+#    include <dirent.h>
+
+#    if defined(HASZONES)
+#        define _KERNEL
+#        include <sys/zone.h>
+#        undef _KERNEL
+#    endif /* defined(HASZONES) */
+
+#    include <kvm.h>
+#    include <nlist.h>
+#    include <signal.h>
+#    include <setjmp.h>
+#    include <string.h>
+#    include <unistd.h>
+#    include <arpa/inet.h>
+#    include <rpc/types.h>
+#    include <sys/protosw.h>
+#    include <sys/socket.h>
+#    include <sys/un.h>
+#    include <sys/wait.h>
+
+#    if solaris >= 110000
+#        define _KERNEL
+#    endif /* solaris>=110000 */
+
+#    include <netinet/in.h>
+
+#    if solaris >= 110000
+#        undef _KERNEL
+#    endif /* solaris>=110000 */
+
+#    if solaris >= 70000
+#        include <sys/conf.h>
+#        include <sys/systeminfo.h>
+#    endif /* solaris>=70000 */
+
+#    define _KERNEL
+#    define MI_HRTIMING
+#    include <inet/led.h>
+
+#    if solaris < 20600
+#        undef staticf
+#    endif /* solaris<20600 */
+
+#    include <inet/common.h>
+
+#    if solaris >= 70000
+#        include <sys/stropts.h>
+#    endif /* solaris>=70000 */
+
+#    if solaris < 20600
+#        include <inet/mi.h>
+#    endif /* solaris<20600 */
+
+#    if solaris >= 80000
+#        include <netinet/igmp.h>
+#        include <netinet/ip6.h>
+#    endif /* solaris>=80000 */
+
+#    if defined(HAS_IPCLASSIFIER_H)
+#        define ffs __kernel_ffs
+#        define inet_ntop __inet_ntop
+#        define inet_pton __inet_pton
+#        define longjmp __kernel_longjmp
+#        define setjmp __kernel_setjmp
+#        if solaris >= 110000
+#            define printf __kernel_printf
+#            define snprintf __kernel_snprintf
+#            define sprintf __kernel_sprintf
+#            define strsignal __kernel_strsignal
+#            define swab __kernel_swab
+#            define vprintf __kernel_vprintf
+#            define vsprintf __kernel_vsprintf
+#            define vsnprintf __kernel_vsnprintf
+#            define fls __kernel_fls
+#            define exit __kernel_exit
+#        endif /* solaris>=110000 */
+#        include <inet/ipclassifier.h>
+#        undef ffs
+#        undef inet_ntop
+#        undef inet_pton
+#        undef longjmp
+#        undef setjmp
+#        if solaris >= 110000
+#            undef printf
+#            undef snprintf
+#            undef sprintf
+#            undef strsignal
+#            undef swab
+#            undef vprintf
+#            undef vsprintf
+#            undef vsnprintf
+#            undef fls
+#            undef exit
+#        endif /* solaris>=110000 */
+#    endif     /* defined(HAS_IPCLASSIFIER_H) */
+
+#    include <inet/ip.h>
+#    undef _KERNEL
+#    undef MI_HRTIMING
+#    define exit kernel_exit
+#    define rval_t char
+#    define strsignal kernel_strsignal
+#    include <sys/strsubr.h>
+
+#    if defined(HAS_SOCKET_PROTO_H)
+#        define _KERNEL 1 /* DEBUG */
+#    endif                /* HAS_SOCKET_PROTO_H */
+
+#    include <sys/socketvar.h>
+
+#    if defined(HAS_SOCKET_PROTO_H)
+#        undef _KERNEL /* DEBUG */
+#    endif             /* HAS_SOCKET_PROTO_H */
+
+#    undef exit
+#    undef rval_t
+#    undef strsignal
+
+#    if solaris >= 80000
+#        define _KERNEL 1
+#    endif /* solaris>=80000 */
+
+#    include <inet/tcp.h>
+
+#    if solaris >= 80000
+#        undef _KERNEL
+#    endif /* solaris>=80000 */
+
+#    include <net/route.h>
+#    include <netinet/in_pcb.h>
+#    include <sys/stream.h>
+
+#    if solaris < 20600
+#        undef MAX
+#        undef MIN
+#    endif /* solaris<20600 */
+
+#    include <sys/sysmacros.h>
+#    include <sys/vfs.h>
+#    include <sys/vnode.h>
+#    include <sys/fs/hsfs_spec.h>
+#    include <sys/fs/hsfs_node.h>
+#    include <sys/fs/lofs_node.h>
+
+#    if solaris >= 20600
+#        define _KERNEL
+#    endif /* solaris>=20600 */
+
+#    include <sys/fs/namenode.h>
+
+#    if solaris >= 20600
+#        undef _KERNEL
+#    endif /* solaris>=20600 */
+
+#    include <sys/tihdr.h>
+
+#    if solaris >= 20500
+#        include <sys/tiuser.h>
+#        if solaris >= 110000
+#            define _KERNEL
+#            if defined(HAS_SYS_RGM_H)
+#                include <sys/rgm.h>
+#            endif /* defined(HAS_SYS_RGM_H) */
+#            if defined(HAS_RPC_RPC_TAGS_H)
+#                include <rpc/rpc_tags.h>
+#            endif /* defined(HAS_RPC_RPC_TAGS_H) */
+#            undef _KERNEL
+#        endif /* solaris>=110000 */
+#        include <rpc/auth.h>
+#        include <rpc/clnt.h>
+
+#        if solaris >= 110000
+#            define _KERNEL
+#            include <rpc/rpc.h>
+#            undef _KERNEL
+#        endif /* solaris>=110000 */
+
+#        include <rpc/clnt_soc.h>
+#        include <rpc/pmap_prot.h>
+#        define _KERNEL
+#        include <sys/fs/autofs.h>
+
+#        if solaris >= 100000
+#            define printf lsof_printf
+#            define snprintf lsof_snprintf
+#            define sprintf lsof_sprintf
+#            define swab lsof_swab
+#            define vprintf lsof_vprintf
+#            define vsnprintf lsof_vsnprintf
+#            define vsprintf lsof_vsprintf
+#            include <sys/fs/dv_node.h>
+#            undef printf
+#            undef snprintf
+#            undef sprintf
+#            undef swab
+#            undef vprintf
+#            undef vsnprintf
+#            undef vsprintf
+#            include <sys/contract_impl.h>
+#            include <sys/ctfs_impl.h>
+#            include <sys/port_impl.h>
+#        endif /* solaris>=100000 */
+
+#        include <sys/door.h>
+#        undef _KERNEL
+#    endif /* solaris>=20500 */
+
+#    if !defined(_NETDB_H_)
+#        include <rpc/rpcent.h>
+#    endif /* !defined(_NETDB_H_) */
+
+#    include <sys/t_lock.h>
+#    include <sys/flock.h>
+
+#    if solaris >= 20300
+#        if solaris < 20400
+/*
+ * The lock_descriptor structure definition is missing from Solaris 2.3.
+ */
+
+struct lock_descriptor {
+    struct lock_descriptor *prev;
+    struct lock_descriptor *next;
+    struct vnode *vnode;
+    struct owner {
+        pid_t pid;
+        long sysid;
+    } owner;
+    int flags;
+    short type;
+    off_t start;
+    off_t end;
+    struct lock_info {
+        struct active_lock_info {
+            struct lock_descriptor *ali_stack;
+        } li_active;
+        struct sleep_lock_info {
+            struct flock sli_flock;
+            /* Ignore the rest. */
+        } li_sleep;
+    } info;
+};
+#            define ACTIVE_LOCK 0x008 /* lock is active */
+#        else                         /* solaris>=20400 */
+#            include <sys/flock_impl.h>
+#        endif /* solaris<20400 */
+#    endif     /* solaris>=20300 */
+
+#    include <sys/fstyp.h>
+#    include <sys/dditypes.h>
+#    include <sys/ddidmareq.h>
+#    include <sys/ddi_impldefs.h>
+#    include <sys/mkdev.h>
+
+#    if defined(HASCACHEFS)
+#        include <sys/fs/cachefs_fs.h>
+#    endif /* defined(HACACHEFS) */
+
+#    include <sys/fs/fifonode.h>
+#    include <sys/fs/pc_fs.h>
+#    include <sys/fs/pc_dir.h>
+#    include <sys/fs/pc_label.h>
+#    include <sys/fs/pc_node.h>
+
+#    if solaris >= 20600
+#        undef SLOCKED
+#    endif /* solaris>=20600 */
+
+#    include <sys/fs/snode.h>
+#    include <sys/fs/tmpnode.h>
+
+#    if solaris >= 110000
+#        define _KERNEL
+#    endif /* solaris>=110000 */
+
+#    include <nfs/nfs.h>
+
+#    if solaris >= 110000
+#        undef _KERNEL
+#    endif /* solaris>=110000 */
+
+#    if solaris >= 100000
+#        define _KERNEL
+#    endif /* solaris >= 100000 */
+
+#    include <nfs/rnode.h>
+
+#    if solaris >= 100000
+#        include <nfs/mount.h>
+#        include <nfs/nfs4.h>
+#        include <nfs/rnode4.h>
+#    endif /* solaris>=100000 */
+
+#    if solaris >= 100000
+#        undef _KERNEL
+#    endif /* solaris >= 100000 */
+
+#    include <sys/proc.h>
+#    include <sys/user.h>
+
+#    if defined(HASPROCFS)
+#        include <sys/proc/prdata.h>
+#    endif /* defined(HASPROCFS) */
+
+#    include <sys/file.h>
+#    include <vm/hat.h>
+#    include <vm/as.h>
+#    include <vm/seg.h>
+#    include <vm/seg_dev.h>
+#    include <vm/seg_map.h>
+#    include <vm/seg_vn.h>
+#    include <sys/tiuser.h>
+#    include <sys/t_kuser.h>
+
+#    if solaris < 100000
+#        include <sys/sockmod.h>
+#    endif /* solaris<100000 */
+
+/*
+ * Structure for Atria's MVFS nodes
+ */
+
+struct mvfsnode {
+    unsigned long d1[6];
+    unsigned long m_ino; /* node number */
+};
+
+extern int nlist();
+
+#    if defined(HAS_AFS) && !defined(AFSAPATHDEF)
+#        define AFSAPATHDEF "/usr/vice/etc/modload/libafs"
+#    endif /* defined(HAS_AFS) && !defined(AFSAPATHDEF) */
+
+#    define ALLKMEM "/dev/allkmem"
+#    define COMP_P const void
+#    define CWDLEN (MAXPATHLEN + 1)
+#    define DEVINCR 1024 /* device table malloc() increment */
+#    define DINAMEL 32
+#    define DIRTYPE dirent
+
+#    if solaris >= 100000
+#        define GET_MAJ_DEV(d) ((major_t)(d >> L_BITSMINOR & L_MAXMAJ))
+#        define GET_MIN_DEV(d) ((minor_t)(d & L_MAXMIN))
+#    endif /* solaris >= 100000 */
+
+#    if solaris >= 70000
+typedef uintptr_t KA_T;
+#    else  /* solaris<70000 */
+typedef void *KA_T;
+#    endif /* solaris>=70000 */
+
+#    if solaris >= 70000
+#        define KA_T_FMT_X "0x%p"
+#    endif /* solaris>=70000 */
+
+#    if solaris >= 20501
+#        define KMEM "/dev/mem"
+#    else /* solaris<20501 */
+#        define KMEM "/dev/kmem"
+#    endif /* solaris>=20501 */
+
+#    define MALLOC_P char
+#    define FREE_P MALLOC_P
+#    define MALLOC_S unsigned
+
+#    if !defined(MAXEND)
+#        define MAXEND 0x7fffffff
+#    endif /* !defined(MAXEND) */
+
+#    define MAXSEGS 100          /* maximum text segments */
+#    define MAXSYSCMDL MAXCOMLEN /* max system command name length */
+#    define NETCLNML 8
+#    define N_UNIX "/dev/ksyms"
+#    define PROCMIN 5 /* processes that make a "good" scan */
+
+#    if defined(HASPROCFS)
+#        define PR_ROOTINO 2 /* root inode for proc file system */
+#    endif                   /* defined(HASPROCFS) */
+
+#    define PROCDFLT                                                           \
+        256 /* default size for local proc table --                            \
+             * MUST BE > 4!!!  */
+#    define PROCSIZE sizeof(struct proc)
+#    define PROCTRYLM 5 /* times to try to read proc table */
+#    define QSORT_P char
+#    define READLEN_T int
+#    define STRNCPY_L int
+#    define STRNML 32 /* stream name length (maximum) */
+
+#    if solaris >= 20501
+/*
+ * Enable large file support.
+ */
+
+#        if solaris >= 20600
+#            define fstat fstat64
+#            define lstat lstat64
+#            define stat stat64
+#        endif /* solaris>=20600 */
+
+#        define SZOFFTYPE unsigned long long
+/* size and offset internal storage
+ * type */
+#        define SZOFFPSPEC                                                     \
+            "ll" /* SZOFFTYPE printf specification                             \
+                  * modifier */
+#    endif       /* solaris>=20501 */
+
+#    define U_SIZE sizeof(struct user)
+
+/*
+ * Global storage definitions (including their structure definitions)
+ */
+
+#    if defined(HAS_AFS)
+
+#        if defined(HASAOPT)
+extern char *AFSApath; /* alternate AFS name list path
+                        * (from -a) */
+#        endif         /* defined(HASAOPT) */
+
+extern dev_t AFSdev;   /* AFS file system device number */
+extern int AFSdevStat; /* AFS file system device number
+                        * status: 0 = unknown; 1 = known */
+extern int AFSfstype;  /* AFS file system type index */
+extern KA_T AFSVfsp;   /* AFS struct vfs kernel pointer */
+#    endif             /* defined(HAS_AFS) */
+
+struct clone {
+    struct l_dev cd;    /* device, inode, name, and verify */
+    int n;              /* network flag */
+    struct clone *next; /* forward link */
+};
+extern struct clone *Clone;
+
+extern major_t CloneMaj;
+
+#    if defined(HAS_LIBCTF)
+/*
+ * Definitions for using the CTF library, libctf.
+ */
+
+#        include <libctf.h>
+
+#        define CTF_MEMBER_UNDEF ~0UL /* undefined member type */
+                                      /* CTF_member_t element definition */
+
+/*
+ * Member structure definition, initialized by CTF_MEMBER() macro calls
+ */
+
+typedef struct CTF_member {
+    char *m_name;     /* Member name. */
+    ulong_t m_offset; /* Member offset, initially in bits,
+                       * later bytes */
+} CTF_member_t;
+
+/*
+ * CTF request structure
+ */
+
+typedef struct CTF_request {
+    char *name;        /* structure name */
+    CTF_member_t *mem; /* member table */
+} CTF_request_t;
+
+/*
+ * CTF macroes
+ */
+
+#        define CTF_MEMBER(name)                                               \
+            { #name, CTF_MEMBER_UNDEF }
+#        define CTF_MEMBER_READ(ka, s, members, member)                        \
+            kread(ctx, (KA_T)(ka) + members[MX_##member].m_offset,                  \
+                  (char *)&s->member, sizeof(s->member))
+#    endif /* defined(HAS_LIBCTF) */
+
+extern char **Fsinfo;
+extern int Fsinfomax;
+extern int HasALLKMEM;
+extern int HaveCloneMaj;
+extern kvm_t *Kd;
+
+struct l_ino {
+    unsigned char dev_def;  /* dev member is defined */
+    unsigned char ino_def;  /* ino member is defined */
+    unsigned char nl_def;   /* nl member is defined */
+    unsigned char rdev_def; /* rdev member is defined */
+    unsigned char sz_def;   /* sz member is defined */
+    dev_t dev;              /* device */
+    long ino;               /* node number */
+    long nl;                /* link count */
+    dev_t rdev;             /* "raw" device */
+    SZOFFTYPE sz;           /* size */
+};
+
+struct l_vfs {
+    KA_T addr;    /* kernel address */
+    char *dir;    /* mounted directory */
+    char *fsname; /* file system name */
+    dev_t dev;    /* device */
+
+#    if defined(HASFSINO)
+    INODETYPE fs_ino; /* file system inode number */
+#    endif            /* defined(HASFSINO) */
+
+#    if defined(HASMNTSTAT)
+    unsigned char mnt_stat; /* mount point stat() status:
+                             *     0 = succeeded
+                             *     1 = failed */
+#    endif                  /* defined(HASMNTSTAT) */
+
+#    if solaris >= 80000
+    nlink_t nlink; /* directory link count */
+    off_t size;    /* directory size */
+#    endif         /* solaris>=80000 */
+
+    struct l_vfs *next; /* forward link */
+};
+extern struct l_vfs *Lvfs;
+
+struct mounts {
+    char *dir;           /* directory (mounted on) */
+    char *fsname;        /* file system
+                          * (symbolic links unresolved) */
+    char *fsnmres;       /* file system
+                          * (symbolic links resolved) */
+    dev_t dev;           /* directory st_dev */
+    dev_t rdev;          /* directory st_rdev */
+    INODETYPE inode;     /* directory st_ino */
+    mode_t mode;         /* directory st_mode */
+    mode_t fs_mode;      /* file system st_mode */
+    struct mounts *next; /* forward link */
+
+#    if defined(HASFSTYPE)
+    char *fstype; /* file system type */
+#    endif        /* defined(HASFSTYPE) */
+
+#    if solaris >= 80000
+    nlink_t nlink; /* directory st_nlink */
+    off_t size;    /* directory st_size */
+#    endif         /* solaris>=80000 */
+
+#    if defined(HASMNTSTAT)
+    unsigned char stat; /* mount point stat() status:
+                         *     0 = succeeded
+                         *     1 = failed */
+#    endif              /* defined(HASMNTSTAT) */
+};
+
+struct pseudo {
+    struct l_dev pd;     /* device, inode, path, verify */
+    struct pseudo *next; /* forward link */
+};
+extern struct pseudo *Pseudo;
+
+/*
+ * Solaris 11 sdev definitions
+ */
+
+#    define SDVOP_IP 0  /* Sdev[] devipnet_vnodeops index */
+#    define SDVOP_NET 1 /* Sdev[] devnet_vnodeops index */
+#    define SDVOP_PTS 2 /* Sdev[] devpts_vnodeops index */
+#    define SDVOP_VT 3  /* Sdev[] devvt_vnodeops index */
+#    define SDVOP_NUM 4 /* number of Sdev[] entries */
+
+struct sfile {
+    char *aname;        /* file name argument */
+    char *name;         /* file name (after readlink()) */
+    char *devnm;        /* device name (optional) */
+    dev_t dev;          /* device */
+    dev_t rdev;         /* raw device */
+    u_short mode;       /* S_IFMT mode bits from stat() */
+    int type;           /* file type: 0 = file system
+                         *           1 = regular file */
+    INODETYPE i;        /* inode number */
+    int f;              /* file found flag */
+    struct sfile *next; /* forward link */
+};
+extern int Unof; /* u_nofiles value */
+
+/*
+ * VxFS definitions
+ */
+
+#    define VXVOP_FCL 0   /* Vvops[] vx_fcl_vnodeops_p index */
+#    define VXVOP_FDD 1   /* Vvops[] fdd_vnops index */
+#    define VXVOP_FDDCH 2 /* Vvops[] fdd_chain_vnops index */
+#    define VXVOP_REG 3   /* Vvops[] vx_vnodeops index */
+#    define VXVOP_REG_P 4 /* Vvops[] vx_vnodeops_p index */
+#    define VXVOP_NUM 5   /* number of Vvops[] entries */
+
+/*
+ * Kernel name list definitions
+ */
+
+#    define NL_NAME n_name
+#    define X_NCACHE "ncache"
+#    define X_NCSIZE "ncsize"
+
+/*
+ * Definitions for dvch.c
+ */
+
+#    if defined(HASDCACHE)
+#        define DCACHE_CLONE                                                   \
+            rw_clone_sect /* clone function for read_dcache                    \
+                           */
+#        define DCACHE_CLR                                                     \
+            clr_sect /* function to clear clone and                            \
+                      * pseudo caches when reading the                         \
+                      * device cache file fails */
+#        define DCACHE_PSEUDO                                                  \
+            rw_pseudo_sect /* pseudo function for read_dcache */
+#    endif                 /* defined(HASDCACHE) */
+
+#    define DVCH_DEVPATH "/devices"
+
+/*
+ * Definition for cvfs.c
+ */
+
+#    define CVFS_DEVSAVE 1
+
+#    if solaris >= 80000
+#        define CVFS_NLKSAVE 1
+#        define CVFS_SZSAVE 1
+#    endif /* solaris>=80000 */
+
+/*
+ * Definitions for rnch.c
+ */
+
+#    if defined(HASNCACHE)
+#        include <sys/dnlc.h>
+
+#        if !defined(NC_NAMLEN)
+#            define HASDNLCPTR 1
+#        endif /* !defined(NC_NAMLEN) */
+
+#        if solaris >= 80000
+#            define NCACHE_NEGVN "negative_cache_vnode"
+#        endif /* solaris>=80000 */
+#    endif     /* defined(HASNCACHE) */
+
+struct lsof_context_dialect {};
+
+#endif /* SOLARIS_LSOF_H */
diff --git a/lib/dialects/sun/dmnt.c b/lib/dialects/sun/dmnt.c
new file mode 100644 (file)
index 0000000..de1128b
--- /dev/null
@@ -0,0 +1,396 @@
+/*
+ * dmnt.c - Solaris mount support functions for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#ifndef lint
+static char copyright[] =
+    "@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
+#endif
+
+#include "common.h"
+
+/*
+ * Local static definitions
+ */
+
+static char *getmntdev(struct lsof_context *ctx, char *o, int l, struct stat *s,
+                       char *f);
+
+/*
+ * getmntdev() - get mount entry's device number
+ */
+
+static char *getmntdev(struct lsof_context *ctx, /* context */
+                       char *o,                  /* start of device option */
+                       int l,          /* length of device keyword (not
+                                        * including `=') */
+                       struct stat *s, /* pointer to stat buffer to create */
+                       char *f)        /* file system type */
+{
+    char *opte;
+
+    memset((char *)s, 0, sizeof(struct stat));
+    if (!(opte = x2dev(o + l + 1, &s->st_dev)))
+        return ((char *)NULL);
+
+#if solaris >= 70000 && L_BITSMAJOR != L_BITSMAJOR32
+    /*
+     * If this is a Solaris 7 system with a 64 bit kernel, convert the 32 bit
+     * device number to a 64 bit device number.
+     */
+    s->st_dev = (((s->st_dev >> L_BITSMINOR32) & L_MAXMAJ32) << L_BITSMINOR) |
+                (s->st_dev & L_MAXMIN32);
+#endif /* solaris>=70000 && L_BITSMAJOR!=L_BITSMAJOR32 */
+
+    s->st_mode = S_IFDIR | 0777;
+
+#if defined(HASFSTYPE)
+    if (f) {
+        (void)strncpy(s->st_fstype, f, sizeof(s->st_fstype));
+        s->st_fstype[sizeof(s->st_fstype) - 1] = '\0';
+    }
+#endif /* defined(HASFSTYPE) */
+
+    return (opte);
+}
+
+/*
+ * readmnt() - read mount table
+ */
+
+struct mounts *readmnt(struct lsof_context *ctx) {
+    int devl, ignore;
+    char *cp, *dir, *fs;
+    char *dn = (char *)NULL;
+    char *ln;
+    FILE *mfp;
+    struct mounts *mtp;
+    char *dopt, *dopte;
+    struct stat sb;
+    struct mnttab me;
+    struct mnttab *mp;
+
+#if defined(HASPROCFS)
+    int procfs = 0;
+#endif /* defined(HASPROCFS) */
+
+    unsigned char stat;
+    char *zopt;
+
+#if defined(HASZONES)
+    int zwarn = 0;
+#endif /* definesd(HASZONES) */
+
+    if (Lmi || Lmist)
+        return (Lmi);
+    devl = strlen(MNTOPT_DEV);
+    /*
+     * Open access to the mount table and read mount table entries.
+     */
+    if (!(mfp = fopen(MNTTAB, "r"))) {
+        (void)fprintf(stderr, "%s: can't access %s\n", Pn, MNTTAB);
+        return (0);
+    }
+    for (mp = &me; getmntent(mfp, mp) == 0;) {
+
+        /*
+         * Skip loop-back mounts, since they are aliases for legitimate file
+         * systems and there is no way to determine that a vnode refers to a
+         * loop-back alias.
+         */
+        if (strcmp(mp->mnt_fstype, MNTTYPE_LO) == 0)
+            continue;
+        /*
+         * Save pointers to the directory and file system names for later use.
+         *
+         * Check the file system name.  If it doesn't begin with a `/'
+         * but contains a `:' not followed by a '/', ignore this entry.
+         */
+        dir = mp->mnt_mountp;
+        fs = mp->mnt_special;
+        if (*fs != '/' && (cp = strchr(fs, ':')) && *(cp + 1) != '/')
+            continue;
+        /*
+         * Check for a "ignore" type (SunOS) or "ignore" option (Solaris).
+         */
+        if (hasmntopt(mp, MNTOPT_IGNORE))
+            ignore = 1;
+        else
+            ignore = 0;
+        /*
+         * Interpolate a possible symbolic directory link.
+         */
+        if (dn)
+            (void)free((FREE_P *)dn);
+        if (!(dn = mkstrcpy(dir, (MALLOC_S *)NULL))) {
+
+        no_space_for_mount:
+
+            (void)fprintf(stderr, "%s: no space for mount ", Pn);
+            safestrprt(fs, stderr, 0);
+            (void)fprintf(stderr, " (");
+            safestrprt(dir, stderr, 0);
+            (void)fprintf(stderr, ")\n");
+            Error(ctx);
+        }
+        if (!(ln = Readlink(ctx, dn))) {
+            if (!Fwarn) {
+                (void)fprintf(stderr,
+                              "      Output information may be incomplete.\n");
+            }
+            continue;
+        }
+        if (ln != dn) {
+            (void)free((FREE_P *)dn);
+            dn = ln;
+        }
+        if (*dn != '/')
+            continue;
+        /*
+         * Stat() the directory.
+         *
+         * Avoid the stat() if the mount entry has an "ignore" option and
+         * try to use the mount entry's device number instead.
+         */
+        dopt = hasmntopt(mp, MNTOPT_DEV);
+        if (ignore) {
+            if (!dopt || !(dopte = getmntdev(ctx, dopt, devl, &sb,
+
+#if defined(HASFSTYPE)
+                                             mp->mnt_fstype
+#else  /* !defined(HASFSTYPE) */
+                                             (char *)NULL
+#endif /* defined(HASFSTYPE) */
+
+                                             )))
+                continue;
+            stat = 1;
+        } else if (statsafely(ctx, dn, &sb)) {
+            if (dopt) {
+                if (!(dopte = getmntdev(ctx, dopt, devl, &sb,
+
+#if defined(HASFSTYPE)
+                                        mp->mnt_fstype
+#else  /* !defined(HASFSTYPE) */
+                                        (char *)NULL
+#endif /* defined(HASFSTYPE) */
+
+                                        )))
+                    dopt = (char *)NULL;
+            } else
+                dopte = (char *)NULL;
+            if (!Fwarn) {
+
+#if defined(HASZONES)
+                if ((zopt = hasmntopt(mp, "zone")) && dopte)
+                    zwarn++;
+#else  /* !defined(HASZONES) */
+                zopt = (char *)NULL;
+#endif /* defined(HASZONES) */
+
+                if (!zopt || !dopte) {
+                    (void)fprintf(stderr, "%s: WARNING: can't stat() ", Pn);
+                    safestrprt(mp->mnt_fstype, stderr, 0);
+                    (void)fprintf(stderr, " file system ");
+                    safestrprt(dir, stderr, 1);
+                    (void)fprintf(
+                        stderr,
+                        "      Output information may be incomplete.\n");
+                    if (dopte) {
+                        (void)fprintf(stderr,
+                                      "      assuming \"%.*s\" from %s\n",
+                                      (int)(dopte - dopt), dopt, MNTTAB);
+                    }
+                }
+            }
+            if (!dopt)
+                continue;
+            stat = 1;
+        } else
+            stat = 0;
+        /*
+         * Allocate and fill a local mount structure.
+         */
+        if (!(mtp = (struct mounts *)malloc(sizeof(struct mounts))))
+            goto no_space_for_mount;
+
+#if defined(HASFSTYPE)
+        if (!(mtp->fstype = mkstrcpy(sb.st_fstype, (MALLOC_S *)NULL)))
+            goto no_space_for_mount;
+#endif /* defined(HASFSTYPE) */
+
+        mtp->dir = dn;
+        dn = (char *)NULL;
+        mtp->next = Lmi;
+        mtp->dev = sb.st_dev;
+        mtp->rdev = sb.st_rdev;
+        mtp->inode = (INODETYPE)sb.st_ino;
+        mtp->mode = sb.st_mode;
+
+#if solaris >= 80000
+        mtp->nlink = sb.st_nlink;
+        mtp->size = sb.st_size;
+#endif /* solaris>=80000 */
+
+#if defined(HASMNTSTAT)
+        mtp->stat = stat;
+#endif /* defined(HASMNTSTAT) */
+
+#if defined(HASPROCFS)
+        if (strcmp(sb.st_fstype, HASPROCFS) == 0) {
+
+            /*
+             * Save information on exactly one proc file system.
+             */
+            if (procfs)
+                Mtprocfs = (struct mounts *)NULL;
+            else {
+                procfs = 1;
+                Mtprocfs = mtp;
+            }
+        }
+#endif /* defined(HASPROCFS) */
+
+        /*
+         * Interpolate a possible file system (mounted-on) device name link.
+         */
+        if (!(dn = mkstrcpy(fs, (MALLOC_S *)NULL)))
+            goto no_space_for_mount;
+        mtp->fsname = dn;
+        ln = Readlink(ctx, dn);
+        dn = (char *)NULL;
+        /*
+         * Stat() the file system (mounted-on) name and add file system
+         * information to the local mount table entry.
+         */
+        if (!ln || statsafely(ctx, ln, &sb))
+            sb.st_mode = 0;
+        mtp->fsnmres = ln;
+        mtp->fs_mode = sb.st_mode;
+        Lmi = mtp;
+
+#if defined(HAS_AFS)
+        /*
+         * If an AFS device number hasn't yet been defined, look for it.
+         */
+        if (!AFSdevStat && mtp->dir && strcmp(mtp->dir, "/afs") == 0 &&
+            mtp->fsname && strcmp(mtp->fsname, "AFS") == 0) {
+            AFSdev = mtp->dev;
+            AFSdevStat = 1;
+        }
+#endif /* defined(HAS_AFS) && solaris>=20600 */
+    }
+    (void)fclose(mfp);
+
+#if defined(HASZONES)
+    /*
+     * If some zone file systems were encountered, issue a warning.
+     */
+    if (!Fwarn && zwarn) {
+        (void)fprintf(stderr, "%s: WARNING: can't stat() %d zone file system%s",
+                      Pn, zwarn, (zwarn == 1) ? "" : "s");
+        (void)fprintf(stderr, "; using dev= option%s\n",
+                      (zwarn == 1) ? "" : "s");
+    }
+#endif /* defined(HASZONES) */
+
+    /*
+     * Clean up and return local mount info table address.
+     */
+    if (dn)
+        (void)free((FREE_P *)dn);
+    Lmist = 1;
+    return (Lmi);
+}
+
+/*
+ * readvfs() - read vfs structure
+ */
+
+struct l_vfs *readvfs(struct lsof_context *ctx, /* context */
+                      KA_T ka,          /* vfs structure kernel address, if
+                                         * must be read from kernel */
+                      struct vfs *la,   /* local vfs structure address, non-
+                                         * NULL if already read from kernel */
+                      struct vnode *lv) /* local vnode */
+{
+    struct vfs *v, tv;
+    struct l_vfs *vp;
+
+    if (!ka && !la)
+        return ((struct l_vfs *)NULL);
+    for (vp = Lvfs; vp; vp = vp->next) {
+        if (ka == vp->addr)
+            return (vp);
+    }
+    if (!(vp = (struct l_vfs *)malloc(sizeof(struct l_vfs)))) {
+        (void)fprintf(stderr, "%s: PID %d, no space for vfs\n", Pn, Lp->pid);
+        Error(ctx);
+    }
+    vp->dir = (char *)NULL;
+    vp->fsname = (char *)NULL;
+
+#if defined(HASFSINO)
+    vp->fs_ino = 0;
+#endif /* defined(HASFSINO) */
+
+    /*
+     * Read vfs structure from kernel, if necessary.
+     */
+    if (la)
+        v = la;
+    else {
+        v = &tv;
+        if (kread(ctx, (KA_T)ka, (char *)v, sizeof(tv))) {
+            (void)free((FREE_P *)vp);
+            return ((struct l_vfs *)NULL);
+        }
+    }
+
+#if defined(HAS_AFS)
+    /*
+     * Fake the device number for an AFS device.
+     */
+    if (v->vfs_fstype == AFSfstype) {
+        if (!AFSdevStat)
+            (void)readmnt(ctx);
+        v->vfs_dev = AFSdevStat ? AFSdev : 0;
+    }
+#endif /* defined(HAS_AFS) */
+
+    /*
+     * Complete mount information.
+     */
+
+    (void)completevfs(ctx, vp, (dev_t *)&v->vfs_dev);
+    vp->next = Lvfs;
+    vp->addr = ka;
+    Lvfs = vp;
+    return (vp);
+}
diff --git a/lib/dialects/sun/dnode.c b/lib/dialects/sun/dnode.c
new file mode 100644 (file)
index 0000000..2696571
--- /dev/null
@@ -0,0 +1,5268 @@
+/*
+ * dnode.c - Solaris node reading functions for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#ifndef lint
+static char copyright[] =
+    "@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
+#endif
+
+#include "common.h"
+
+#if solaris >= 110000
+#    include <sys/fs/sdev_impl.h>
+#endif /* solaris>=110000 */
+
+#undef fs_bsize
+#include <sys/fs/ufs_inode.h>
+
+#if solaris >= 110000 && defined(HAS_LIBCTF)
+/*
+ * Sockfs support for Solaris 11 via libctf
+ */
+
+/*
+ * Sockfs internal structure definitions
+ *
+ * The structure definitions may look like kernel structures, but they are
+ * not.  They have been defined to have member names that duplicate those
+ * used by the kernel that are of interest to lsof.  Member values are
+ * obtained via the CTF library, libctf.
+ *
+ * Robert Byrnes developed the CTF library access code and contributed it
+ * to lsof.
+ */
+
+struct soaddr {              /* sadly, CTF doesn't grok this
+                              * structure */
+    struct sockaddr *soa_sa; /* address */
+    t_uscalar_t soa_len;     /* length in bytes */
+    t_uscalar_t soa_maxlen;  /* maximum length */
+};
+
+typedef struct sotpi_info {
+    dev_t sti_dev;                  /* sonode device */
+    struct soaddr sti_laddr;        /* local address */
+    struct soaddr sti_faddr;        /* peer address */
+    struct so_ux_addr sti_ux_laddr; /* bound local address */
+    struct so_ux_addr sti_ux_faddr; /* bound peer address */
+    t_scalar_t sti_serv_type;       /* service type */
+} sotpi_info_t;
+
+/*
+ * CTF definitions for sockfs
+ */
+
+static int Sockfs_ctfs = 0; /* CTF initialization status for
+                             * sockfs */
+
+#    if defined(_LP64)
+#        define SOCKFS_MOD_FORMAT "/kernel/%s/genunix"
+#    else /* !defined(_LP64) */
+#        define SOCKFS_MOD_FORMAT "/kernel/fs/sockfs"
+#    endif /* defined(_LP64) */
+
+/* sockfs module pathname template to
+ * which the kernel's instruction type
+ * set is added for CTF access */
+
+/*
+ * Sockfs access definitions and structures
+ */
+
+#    define SOADDR_TYPE_NAME "soaddr"
+
+static CTF_member_t soaddr_members[] = {CTF_MEMBER(soa_sa),
+#    define MX_soa_sa 0
+
+                                        CTF_MEMBER(soa_len),
+#    define MX_soa_len 1
+
+                                        CTF_MEMBER(soa_maxlen),
+#    define MX_soa_maxlen 2
+
+                                        {NULL, 0}};
+
+#    define SOTPI_INFO_TYPE_NAME "sotpi_info_t"
+
+static CTF_member_t sotpi_info_members[] = {CTF_MEMBER(sti_dev),
+#    define MX_sti_dev 0
+
+                                            CTF_MEMBER(sti_laddr),
+#    define MX_sti_laddr 1
+
+                                            CTF_MEMBER(sti_faddr),
+#    define MX_sti_faddr 2
+
+                                            CTF_MEMBER(sti_ux_laddr),
+#    define MX_sti_ux_laddr 3
+
+                                            CTF_MEMBER(sti_ux_faddr),
+#    define MX_sti_ux_faddr 4
+
+                                            CTF_MEMBER(sti_serv_type),
+#    define MX_sti_serv_type 5
+
+                                            {NULL, 0}};
+
+/*
+ * CTF sockfs request table
+ */
+
+static CTF_request_t Sockfs_requests[] = {
+    {SOTPI_INFO_TYPE_NAME, sotpi_info_members}, {NULL, NULL}};
+
+/*
+ * Sockfs function prototypes
+ */
+
+static int read_nsti(struct lsof_context *ctx, struct sonode *so,
+                     sotpi_info_t *stpi);
+#endif /* solaris>=110000 && defined(HAS_LIBCTF) */
+
+#if defined(HAS_ZFS) && defined(HAS_LIBCTF)
+/*
+ * ZFS support via libctf
+ */
+
+/*
+ * ZFS internal structure definitions
+ *
+ * The structure definitions may look like kernel structures, but they are
+ * not.  They have been defined to have member names that duplicate those
+ * used by the kernel that are of interest to lsof.  Member values are
+ * obtained via the CTF library, libctf.
+ *
+ * Robert Byrnes developed the CTF library access code and contributed it
+ * to lsof.
+ */
+
+typedef struct zfsvfs {
+    vfs_t *z_vfs; /* pointer to VFS */
+} zfsvfs_t;
+
+typedef struct znode_phys {
+    uint64_t zp_size;  /* file size (ZFS below 5) */
+    uint64_t zp_links; /* links (ZFS below 5) */
+} znode_phys_t;
+
+typedef struct znode {
+    zfsvfs_t *z_zfsvfs;   /* pointer to associated vfs */
+    vnode_t *z_vnode;     /* pointer to associated vnode */
+    uint64_t z_id;        /* node ID */
+    znode_phys_t *z_phys; /* pointer to persistent znode (ZFS
+                           * below 5) */
+    uint64_t z_links;     /* links (ZFS 5 and above) */
+    uint64_t z_size;      /* file size (ZFS 5 and above) */
+} znode_t;
+
+/*
+ * CTF definitions for ZFS
+ */
+
+static int ZFS_ctfs = 0; /* CTF initialization status for ZFS */
+
+#    if defined(_LP64)
+#        define ZFS_MOD_FORMAT "/kernel/fs/%s/zfs"
+#    else /* !defined(_LP64) */
+#        define ZFS_MOD_FORMAT "/kernel/fs/zfs"
+#    endif /* defined(_LP64) */
+
+/* ZFS module pathname template to
+ * which the kernel's instruction type
+ * set is added for CTF access */
+
+/*
+ * ZFS access definitions and structures
+ */
+
+#    define ZNODE_TYPE_NAME "znode_t"
+
+static CTF_member_t znode_members[] = {CTF_MEMBER(z_zfsvfs),
+#    define MX_z_zfsvfs 0
+
+                                       CTF_MEMBER(z_vnode),
+#    define MX_z_vnode 1
+
+                                       CTF_MEMBER(z_id),
+#    define MX_z_id 2
+
+                                       CTF_MEMBER(z_link_node),
+#    define MX_z_link_node 3
+
+                                       CTF_MEMBER(z_phys),
+#    define MX_z_phys 4
+
+                                       CTF_MEMBER(z_links),
+#    define MX_z_links 5
+
+                                       CTF_MEMBER(z_size),
+#    define MX_z_size 6
+
+                                       {NULL, 0}};
+
+#    define ZNODE_PHYS_TYPE_NAME "znode_phys_t"
+
+static CTF_member_t znode_phys_members[] = {CTF_MEMBER(zp_size),
+#    define MX_zp_size 0
+
+                                            CTF_MEMBER(zp_links),
+#    define MX_zp_links 1
+
+                                            {NULL, 0}};
+
+#    define ZFSVFS_TYPE_NAME "zfsvfs_t"
+
+static CTF_member_t zfsvfs_members[] = {CTF_MEMBER(z_vfs),
+#    define MX_z_vfs 0
+
+                                        {NULL, 0}};
+
+/*
+ * CTF ZFS request table
+ */
+
+static CTF_request_t ZFS_requests[] = {
+    {ZNODE_TYPE_NAME, znode_members},
+    {ZNODE_PHYS_TYPE_NAME, znode_phys_members},
+    {ZFSVFS_TYPE_NAME, zfsvfs_members},
+    {NULL, NULL}};
+
+/*
+ * Missing members exceptions -- i.e., CTF_getmem won't consider it
+ * an error if any of these members are undefined.
+ */
+
+typedef struct CTF_exception {
+    char *tynm;  /* type name */
+    char *memnm; /* member name */
+} CTF_exception_t;
+
+static CTF_exception_t CTF_exceptions[] = {{ZNODE_TYPE_NAME, "z_phys"},
+                                           {ZNODE_TYPE_NAME, "z_links"},
+                                           {ZNODE_TYPE_NAME, "z_size"},
+                                           {NULL, NULL}};
+
+/*
+ * ZFS function prototypes
+ */
+
+static int read_nzn(struct lsof_context *ctx, KA_T na, KA_T nza, znode_t *z);
+static int read_nznp(struct lsof_context *ctx, KA_T nza, KA_T nzpa,
+                     znode_phys_t *zp);
+static int read_nzvfs(struct lsof_context *ctx, KA_T nza, KA_T nzva,
+                      zfsvfs_t *zv);
+#endif /* defined(HAS_ZFS) && defined(HAS_LIBCTF) */
+
+static struct l_dev *finddev(struct lsof_context *ctx, dev_t *dev, dev_t *rdev,
+                             int flags);
+
+/*
+ * Finddev() "look-in " flags
+ */
+
+#define LOOKDEV_TAB 0x01    /* look in device table */
+#define LOOKDEV_CLONE 0x02  /* look in Clone table */
+#define LOOKDEV_PSEUDO 0x04 /* look in Pseudo table */
+#define LOOKDEV_ALL (LOOKDEV_TAB | LOOKDEV_CLONE | LOOKDEV_PSEUDO)
+/* look all places */
+
+/*
+ * SAM-FS definitions
+ */
+
+#define SAMFS_NMA_MSG "(limited SAM-FS info)"
+
+/*
+ * Voptab definitions
+ */
+
+typedef struct build_v_optab {
+    char *dnm;  /* drive_NL name */
+    char *fsys; /* file system type name */
+    int nty;    /* node type index (i.e., N_*) */
+} build_v_optab_t;
+
+static build_v_optab_t Build_v_optab[] = {
+    {"auvops", "autofs", N_AUTO},
+    {"avops", "afs", N_AFS},
+    {"afsops", "afs", N_AFS},
+    {"ctfsadir", NULL, N_CTFSADIR},
+    {"ctfsbund", NULL, N_CTFSBUND},
+    {"ctfscdir", NULL, N_CTFSCDIR},
+    {"ctfsctl", NULL, N_CTFSCTL},
+    {"ctfsevt", NULL, N_CTFSEVT},
+    {"ctfslate", NULL, N_CTFSLATE},
+    {"ctfsroot", NULL, N_CTFSROOT},
+    {"ctfsstat", NULL, N_CTFSSTAT},
+    {"ctfssym", NULL, N_CTFSSYM},
+    {"ctfstdir", NULL, N_CTFSTDIR},
+    {"ctfstmpl", NULL, N_CTFSTMPL},
+
+#if defined(HASCACHEFS)
+    {"cvops", NULL, N_CACHE},
+#endif /* defined(HASCACHEFS) */
+
+    {"devops", "devfs", N_DEV},
+    {"doorops", NULL, N_DOOR},
+    {"fdops", "fd", N_FD},
+    {"fd_ops", "fd", N_FD},
+    {"fvops", "fifofs", N_FIFO},
+    {"hvops", "hsfs", N_HSFS},
+    {"lvops", "lofs", N_LOFS},
+    {"mntops", "mntfs", N_MNT},
+    {"mvops", "mvfs", N_MVFS},
+    {"n3vops", NULL, N_NFS},
+
+#if solaris >= 100000
+    {"n4vops", NULL, N_NFS4},
+#else  /* solaris<100000 */
+    {"n4vops", NULL, N_NFS},
+#endif /* solaris>=100000 */
+
+    {"nmvops", "namefs", N_NM},
+    {"nvops", NULL, N_NFS},
+    {"pdvops", "pcfs", N_PCFS},
+    {"pfvops", "pcfs", N_PCFS},
+    {"portvops", NULL, N_PORT},
+    {"prvops", "proc", N_PROC},
+    {"sam1vops", NULL, N_SAMFS},
+    {"sam2vops", NULL, N_SAMFS},
+    {"sam3vops", NULL, N_SAMFS},
+    {"sam4vops", NULL, N_SAMFS},
+    {"sckvops", "sockfs", N_SOCK},
+    {"devipnetops", "sdevfs", N_SDEV},
+    {"devnetops", "sdevfs", N_SDEV},
+    {"devptsops", "sdevfs", N_SDEV},
+    {"devvtops", "sdevfs", N_SDEV},
+    {"socketvops", "sockfs", N_SOCK},
+    {"sdevops", "sdevfs", N_SDEV},
+    {"shvops", "sharedfs", N_SHARED},
+    {"sncavops", "sockfs", N_SOCK},
+    {"stpivops", "sockfs", N_SOCK},
+    {"spvops", "specfs", N_REGLR},
+    {"tvops", "tmpfs", N_TMP},
+    {"uvops", "ufs", N_REGLR},
+    {"vvfclops", "vxfs", N_VXFS},
+    {"vvfops", "vxfs", N_VXFS},
+    {"vvfcops", "vxfs", N_VXFS},
+    {"vvops", "vxfs", N_VXFS},
+    {"vvops_p", "vxfs", N_VXFS},
+    {"zfsdops", "zfs", N_ZFS},
+    {"zfseops", "zfs", N_ZFS},
+    {"zfsfops", "zfs", N_ZFS},
+    {"zfsshops", "zfs", N_ZFS},
+    {"zfssymops", "zfs", N_ZFS},
+    {"zfsxdops", "zfs", N_ZFS},
+    {NULL, NULL, 0} /* table end */
+};
+
+typedef struct v_optab {
+    char *fsys;           /* file system type name */
+    int fx;               /* Fsinfo[] index (-1 if none) */
+    int nty;              /* node type index (i.e., N_*) */
+    KA_T v_op;            /* vnodeops address */
+    struct v_optab *next; /* next entry */
+} v_optab_t;
+
+static v_optab_t **FxToVoptab = (v_optab_t **)NULL;
+/* table to convert file system index
+ * to Voptab address[] -- built by
+ * build_Voptab() */
+static v_optab_t **Voptab = (v_optab_t **)NULL;
+/* table to convert vnode v_op
+ * addresses to file system name and
+ * node type -- built by build_Voptab()
+ * and addressed through the HASHVOP()
+ * macro */
+
+#define VOPHASHBINS                                                            \
+    256 /* number of Voptab[] hash bins --                                     \
+         * MUST BE A POWER OF TWO! */
+
+/*
+ * Local function prototypes
+ */
+
+static void build_Voptab(struct lsof_context *ctx);
+static enum lsof_lock_mode isvlocked(struct lsof_context *ctx,
+                                     struct vnode *va);
+static int readinode(struct lsof_context *ctx, KA_T ia, struct inode *i);
+static void read_mi(struct lsof_context *ctx, KA_T s, dev_t *dev, caddr_t so,
+                    int *so_st, KA_T *so_ad, struct l_dev **sdp);
+
+#if solaris >= 20500
+#    if solaris >= 20600
+static int read_nan(struct lsof_context *ctx, KA_T na, KA_T aa,
+                    struct fnnode *rn);
+static int read_nson(struct lsof_context *ctx, KA_T na, KA_T sa,
+                     struct sonode *sn);
+static int read_nusa(struct lsof_context *ctx, struct soaddr *so,
+                     struct sockaddr_un *ua);
+#    else  /* solaris<20600 */
+static int read_nan(struct lsof_context *ctx, KA_T na, KA_T aa,
+                    struct autonode *a);
+#    endif /* solaris>=20600 */
+static int idoorkeep(struct lsof_context *ctx, struct door_node *d);
+static int read_ndn(struct lsof_context *ctx, KA_T na, KA_T da,
+                    struct door_node *d);
+#endif /* solaris>=20500 */
+
+#if solaris >= 110000
+static int read_nsdn(struct lsof_context *ctx, KA_T na, KA_T sa,
+                     struct sdev_node *sdn, struct vattr *sdva);
+#endif /* solaris>=110000 */
+
+static int read_nfn(struct lsof_context *ctx, KA_T na, KA_T fa,
+                    struct fifonode *f);
+static int read_nhn(struct lsof_context *ctx, KA_T na, KA_T ha,
+                    struct hsnode *h);
+static int read_nin(struct lsof_context *ctx, KA_T na, KA_T ia,
+                    struct inode *i);
+static int read_nmn(struct lsof_context *ctx, KA_T na, KA_T ia,
+                    struct mvfsnode *m);
+static int read_npn(struct lsof_context *ctx, KA_T na, KA_T pa,
+                    struct pcnode *p);
+static int read_nrn(struct lsof_context *ctx, KA_T na, KA_T ra,
+                    struct rnode *r);
+
+#if solaris >= 100000
+static int read_nctfsn(struct lsof_context *ctx, int ty, KA_T na, KA_T ca,
+                       char *cn);
+static int read_nprtn(struct lsof_context *ctx, KA_T na, KA_T ra, port_t *p);
+static int read_nrn4(struct lsof_context *ctx, KA_T na, KA_T ra,
+                     struct rnode4 *r);
+#endif /* solaris>=100000 */
+
+static int read_nsn(struct lsof_context *ctx, KA_T na, KA_T sa,
+                    struct snode *s);
+static int read_ntn(struct lsof_context *ctx, KA_T na, KA_T ta,
+                    struct tmpnode *t);
+static int read_nvn(struct lsof_context *ctx, KA_T na, KA_T va,
+                    struct vnode *v);
+
+#if defined(HASPROCFS)
+static int read_npi(struct lsof_context *ctx, KA_T na, struct vnode *v,
+                    struct pid *pids);
+#endif /* defined(HASPROCFS) */
+
+static char *ent_fa(KA_T *a1, KA_T *a2, char *d, int *len);
+static int is_socket(struct lsof_context *ctx, struct vnode *v);
+static int read_cni(struct lsof_context *ctx, struct snode *s, struct vnode *rv,
+                    struct vnode *v, struct snode *rs, struct dev_info *di,
+                    char *din, int dinl);
+
+#if defined(HASCACHEFS)
+static int read_ncn(struct lsof_context *ctx, KA_T na, KA_T ca,
+                    struct cnode *cn);
+#endif /* defined(HASCACHEFS) */
+
+static int read_nln(struct lsof_context *ctx, KA_T na, KA_T la,
+                    struct lnode *ln);
+static int read_nnn(struct lsof_context *ctx, KA_T na, KA_T nna,
+                    struct namenode *n);
+
+#if solaris < 100000
+static void savesockmod(struct so_so *so, struct so_so *sop, int *so_st);
+#else  /* solaris>=100000 */
+static int read_ndvn(struct lsof_context *ctx, KA_T na, KA_T da,
+                     struct dv_node *dv, dev_t *dev, unsigned char *devs);
+#endif /* solaris<100000 */
+
+/*
+ * Local static values
+ */
+
+static KA_T Spvops = (KA_T)0; /* specfs vnodeops address -- saved
+                               * by build_Voptab() */
+static KA_T Vvops[VXVOP_NUM]; /* addresses of:
+                               *   vx_fcl_dnodeops_p (VXVOP_FCL)
+                               *   fdd_vnops (VXVOP_FDD)
+                               *   fdd_chain_vnops (VXVOP_FDDCH),
+                               *   vx_vnodeops (VXVOP_REG)
+                               *   vx_vnodeops_p (VXVOP_REG_P)
+                               *   -- saved by build_Voptab() */
+
+/*
+ * Local macros
+ *
+ * GETVOPS() -- get direct or indirect *vnodeops address
+ *
+ * HASHVOP() -- hash the vnode's v_op address
+ */
+
+#if defined(VOPNAME_OPEN) && solaris >= 100000
+#    define GETVOPS(name, nl, ops)                                             \
+        if (get_Nl_value(ctx, name, nl, &ops) < 0)                                  \
+            ops = (KA_T)0;                                                     \
+        else if (kread(ctx, ops, (char *)&ops, sizeof(ops)))                   \
+        ops = (KA_T)0
+#else /* !defined(VOPNAME_OPEN) || solaris<100000 */
+#    define GETVOPS(name, nl, ops)                                             \
+        if (get_Nl_value(ctx, name, nl, &ops) < 0)                                  \
+        ops = (KA_T)0
+#endif /* defined(VOPNAME_OPEN) && solaris>=100000 */
+
+#define HASHVOP(ka)                                                            \
+    ((int)((((ka & 0x1fffffff) * 31415) >> 3) & (VOPHASHBINS - 1)))
+
+/*
+ * build_Voptab() -- build Voptab[]
+ */
+
+static void build_Voptab(struct lsof_context *ctx) {
+    build_v_optab_t *bp;      /* Build_v_optab[] pointer */
+    int fx;                   /* temporary file system type index */
+    int h;                    /* hash index */
+    int i, j;                 /* temporary indexes */
+    KA_T ka;                  /* temporary kernel address */
+    v_optab_t *nv, *vp, *vpp; /* Voptab[] working pointers */
+    int vv = 0;               /* number of Vvops[] addresses that
+                               * have been located */
+                              /*
+                               * If Voptab[] is allocated, return; otherwise allocate space for Voptab[]
+                               * and FxToVoptab[] amd fill them.
+                               */
+    if (Voptab)
+        return;
+    /*
+     * During first call, allocate space for Voptab[] and FxToVoptab[].
+     */
+
+    if (!(Voptab =
+              (v_optab_t **)calloc((MALLOC_S)VOPHASHBINS, sizeof(v_optab_t)))) {
+        (void)fprintf(stderr, "%s: no space for Voptab\n", Pn);
+        Error(ctx);
+    }
+    if (!(FxToVoptab =
+              (v_optab_t **)calloc((MALLOC_S)Fsinfomax, sizeof(v_optab_t *)))) {
+        (void)fprintf(stderr, "%s: no space for FxToVoptab\n", Pn);
+        Error(ctx);
+    }
+    for (i = 0; i < VXVOP_NUM; i++) {
+        Vvops[i] = (KA_T)NULL;
+    }
+    /*
+     * Use Build_v_optab[] to build Voptab[].
+     */
+    for (bp = Build_v_optab; bp->dnm; bp++) {
+
+        /*
+         * Get the kernel address for the symbol.  Do nothing if it can't
+         * be determined.
+         */
+        GETVOPS(bp->dnm, Drive_Nl, ka);
+        if (!ka)
+            continue;
+        /*
+         * Check the Voptab[] for the address.
+         */
+        h = HASHVOP(ka);
+        for (vp = Voptab[h], vpp = (v_optab_t *)NULL; vp; vp = vp->next) {
+            if (vp->v_op == ka)
+                break;
+            vpp = vp;
+        }
+        if (vp) {
+
+            /*
+             * Ignore duplicates.
+             */
+            continue;
+        }
+        /*
+         * No Voptab[] entry was found, so allocate space for a new
+         * v_optab_t structure, determine its file system type index,
+         * fill it and link it to the Voptab[].
+         */
+        if (!(nv = (v_optab_t *)malloc((MALLOC_S)sizeof(v_optab_t)))) {
+            (void)fprintf(stderr, "%s: out of Voptab space at: %s\n", Pn,
+                          bp->dnm);
+            Error(ctx);
+        }
+        nv->fsys = bp->fsys;
+        nv->fx = -1;
+        nv->nty = bp->nty;
+        nv->next = (v_optab_t *)NULL;
+        nv->v_op = ka;
+        if (bp->fsys) {
+            for (i = 0; i < Fsinfomax; i++) {
+                if (!strcmp(bp->fsys, Fsinfo[i])) {
+                    nv->fx = i;
+                    break;
+                }
+            }
+        }
+        if (!Voptab[h])
+            Voptab[h] = nv;
+        else
+            vpp->next = nv;
+        /*
+         * Handle special v_op addresses:
+         *
+         *   special vnode ops;
+         *   VxFS ops.
+         */
+        if (!Spvops) {
+            if (!strcmp(bp->dnm, "spvops"))
+                Spvops = ka;
+        }
+        for (i = 0; (i < VXVOP_NUM) && (vv < VXVOP_NUM); i++) {
+            if (Vvops[i])
+                continue;
+            switch (i) {
+            case VXVOP_FCL:
+                if (!strcmp(bp->dnm, "vvfclops")) {
+                    Vvops[i] = ka;
+                    vv++;
+                }
+                break;
+            case VXVOP_FDD:
+                if (!strcmp(bp->dnm, "vvfops")) {
+                    Vvops[i] = ka;
+                    vv++;
+                }
+                break;
+            case VXVOP_FDDCH:
+                if (!strcmp(bp->dnm, "vvfcops")) {
+                    Vvops[i] = ka;
+                    vv++;
+                }
+                break;
+            case VXVOP_REG:
+                if (!strcmp(bp->dnm, "vvops")) {
+                    Vvops[i] = ka;
+                    vv++;
+                }
+                break;
+            case VXVOP_REG_P:
+                if (!strcmp(bp->dnm, "vvops_p")) {
+                    Vvops[i] = ka;
+                    vv++;
+                }
+                break;
+            }
+        }
+    }
+    /*
+     * Link Voptab[] entries to FxToVoptab[] entries.
+     */
+    for (h = 0; h < VOPHASHBINS; h++) {
+        for (vp = Voptab[h]; vp; vp = vp->next) {
+            if (!vp->fsys)
+                continue;
+            if (((fx = vp->fx) >= 0) && (fx < Fsinfomax)) {
+                if (!FxToVoptab[fx])
+                    FxToVoptab[fx] = vp;
+                continue;
+            }
+            for (i = 0; i < Fsinfomax; i++) {
+                if (!strcmp(Fsinfo[i], vp->fsys)) {
+                    vp->fx = i;
+                    if (!FxToVoptab[i])
+                        FxToVoptab[i] = vp;
+                    break;
+                }
+            }
+        }
+    }
+}
+
+#if defined(HAS_LIBCTF)
+/*
+ * CTF_getmem() -- get CTF members
+ */
+
+int CTF_getmem(struct lsof_context *ctx, /* context*/
+               ctf_file_t *f,            /* CTF file handle */
+               const char *mod,          /* module name */
+               const char *ty,           /* type */
+               CTF_member_t *mem)        /* member table */
+{
+    int err;             /* error flag */
+    ctf_id_t id;         /* CTF ID */
+    CTF_member_t *mp;    /* member pointer */
+    CTF_exception_t *xp; /* exception table pointer */
+    int xs;              /* exception status */
+                         /*
+                          * Look up the type.
+                          */
+    if ((id = ctf_lookup_by_name(f, ty)) == CTF_ERR) {
+        (void)fprintf(stderr, "%s: ctf_lookup_by_name: %s: %s: %s\n", Pn, mod,
+                      ty, ctf_errmsg(ctf_errno(f)));
+        return (1);
+    }
+    /*
+     * Get member offsets.
+     */
+    if (ctf_member_iter(f, id, CTF_memCB, mem) == CTF_ERR) {
+        (void)fprintf(stderr, "%s: ctf_member_iter: %s: %s: %s\n", Pn, mod, ty,
+                      ctf_errmsg(ctf_errno(f)));
+        return (1);
+    }
+    /*
+     * Examine members.
+     */
+    for (err = 0, mp = mem; mp->m_name; mp++) {
+        if (mp->m_offset == CTF_MEMBER_UNDEF) {
+
+            /*
+             * Check for an undefined member exception.  Report an error if
+             * no exception is found.
+             */
+            for (xp = CTF_exceptions, xs = 0; xp->tynm; xp++) {
+                if (!strcmp(xp->tynm, ty) && !strcmp(xp->memnm, mp->m_name)) {
+                    xs = 1;
+                    break;
+                }
+            }
+            if (!xs) {
+                (void)fprintf(
+                    stderr,
+                    "%s: getmembers: %s: %s: %s: struct member undefined\n", Pn,
+                    mod, ty, mp->m_name);
+                err = 1;
+            }
+        } else {
+
+            /*
+             * Convert bit offsets to byte offsets.
+             */
+            if ((mp->m_offset % NBBY) != 0) {
+                (void)fprintf(
+                    stderr,
+                    "%s: getmembers: %s: %s: %s: struct member is bit field\n",
+                    Pn, mod, ty, mp->m_name);
+                err = 1;
+            } else
+                mp->m_offset /= NBBY;
+        }
+    }
+    return (err);
+}
+
+/*
+ * CTF_init - initialize CTF library access
+ */
+
+void CTF_init(struct lsof_context *ctx, /* context */
+              int *i,                   /* initialization status */
+              char *t,                  /* kernel module template */
+              CTF_request_t *r)         /* CTF requests */
+{
+    int err;       /* error status */
+    ctf_file_t *f; /* CTF file info handle */
+
+#    if defined(_LP64)
+    static char isa[256 + 1]; /* kernel instruction set name */
+    static int isas = 0;      /* isa[] status */
+#    endif                    /* defined(_LP64) */
+
+    char kernmod[MAXPATHLEN];    /* kernel module pathname */
+    char *kmp;                   /* kernel module path name pointer */
+    static char pfn[256 + 1];    /* system platform name */
+    static int pfns = 0;         /* pfn[] status: -1 = request failed
+                                  *              0 = none requested
+                                  *             >0 = available */
+    char pfxkernmod[MAXPATHLEN]; /* prefixed kernel module name */
+    struct stat sb;              /* stat(2) buffer */
+
+    if (*i)
+        return;
+
+#    if defined(_LP64)
+    /*
+     * If CTF access hasn't been initialized and a 64 bit kernel is in use,
+     * determine the name of the kernel's instruction set, and construct the
+     * pathname of the kernel module, using the supplied template.
+     */
+    if (!isas) {
+        if (sysinfo(SI_ARCHITECTURE_K, isa, sizeof(isa) - 1) == -1) {
+            (void)fprintf(stderr, "%s: sysinfo: %s\n", Pn, strerror(errno));
+            Error(ctx);
+        }
+        isas = 1;
+        isa[sizeof(isa) - 1] = '\0';
+    }
+    (void)snprintf(kernmod, sizeof(kernmod) - 1, t, isa);
+    kernmod[sizeof(kernmod) - 1] = '\0';
+#    else  /* !defined(_LP64) */
+    /*
+     * If CTF access hasn't been initialized and a 32 bit kernel is in use, the
+     * supplied template is the module path name.
+     */
+    (void)strncpy(kernmod, t, sizeof(kernmod) - 1);
+#    endif /* defined(_LP64) */
+
+    kernmod[sizeof(kernmod) - 1] = '\0';
+    kmp = kernmod;
+    if (statsafely(ctx, kmp, &sb)) {
+
+        /*
+         * The module at the specified path does not exist or is inaccessible.
+         *
+         * Get the platform name and construct a prefix from it for module path
+         * name and see if that exists and is accessible.
+         *
+         * If it is, let CTF_init() use it; otherwise let CTF_init() fail on
+         * the specified path.
+         */
+        if (pfns >= 0) {
+            if (!pfns)
+                pfns = sysinfo(SI_MACHINE, pfn, sizeof(pfn) - 1);
+            if (pfns > 0) {
+                pfn[sizeof(pfn) - 1] = '\0';
+                (void)snprintf(pfxkernmod, sizeof(pfxkernmod) - 1,
+                               "/platform/%s/%s", pfn,
+                               (kernmod[0] == '/') ? &kernmod[1] : kernmod);
+                pfxkernmod[sizeof(pfxkernmod) - 1] = '\0';
+                if (!stat(pfxkernmod, &sb))
+                    kmp = pfxkernmod;
+            }
+        }
+    }
+    /*
+     * Open the module file and read its CTF info.
+     */
+    if ((f = ctf_open(kmp, &err)) == NULL) {
+        (void)fprintf(stderr, "%s: ctf_open: %s: %s\n", Pn, kmp,
+                      ctf_errmsg(err));
+        Error(ctx);
+    }
+    for (err = 0; r->name; r++) {
+        if (CTF_getmem(ctx, f, kmp, r->name, r->mem))
+            err = 1;
+    }
+    (void)ctf_close(f);
+    if (err)
+        Error(ctx);
+    *i = 1;
+}
+
+/*
+ * CTF_memCB() - Callback function for ctf_member_iter()
+ */
+
+int CTF_memCB(const char *name, /* structure member name */
+              ctf_id_t id,      /* CTF ID */
+              ulong_t offset,   /* member offset */
+              void *arg)        /* member table */
+{
+    CTF_member_t *mp;
+    /*
+     * Check for members of interest and record their offsets.
+     */
+    for (mp = (CTF_member_t *)arg; mp->m_name; mp++) {
+        if (!strcmp(name, mp->m_name)) {
+            mp->m_offset = offset;
+            break;
+        }
+    }
+    return (0);
+}
+#endif /* defined(HAS_LIBCTF) */
+
+/*
+ * ent_fa() - enter fattach addresses in NAME column addition
+ */
+
+static char *ent_fa(KA_T *a1, /* first fattach address (NULL OK) */
+                    KA_T *a2, /* second fattach address */
+                    char *d,  /* direction ("->" or "<-") */
+                    int *len) /* returned description length */
+{
+    static char buf[1024];
+    size_t bufl = sizeof(buf);
+    char tbuf[32];
+    /*
+     * Form the fattach description.
+     */
+    if (!a1)
+
+#if solaris < 20600
+        (void)snpf(buf, bufl, "(FA:%s%s)", d, print_kptr(*a2, (char *)NULL, 0));
+#else  /* solaris>=20600 */
+        (void)snpf(buf, bufl, "(FA:%s%s)", d, print_kptr(*a2, (char *)NULL, 0));
+#endif /* solaris<20600 */
+
+    else
+
+#if solaris < 20600
+        (void)snpf(buf, bufl, "(FA:%s%s%s)",
+                   print_kptr(*a1, tbuf, sizeof(tbuf)), d,
+                   print_kptr(*a2, (char *)NULL, 0));
+#else  /* solaris>=20600 */
+        (void)snpf(buf, bufl, "(FA:%s%s%s)",
+                   print_kptr(*a1, tbuf, sizeof(tbuf)), d,
+                   print_kptr(*a2, (char *)NULL, 0));
+#endif /* solaris<20600 */
+
+    *len = (int)strlen(buf);
+    return (buf);
+}
+
+/*
+ * is_socket() - is the stream a socket?
+ */
+
+static int is_socket(struct lsof_context *ctx, /* context */
+                     struct vnode *v)          /* vnode pointer */
+{
+    char *cp, *ep, *pf;
+    int i, j, len, n, pfl;
+    major_t maj;
+    minor_t min;
+    static struct tcpudp {
+        int ds;
+        major_t maj;
+        minor_t min;
+        char *proto;
+    } tcpudp[] = {
+        {0, 0, 0, "tcp"},
+        {0, 0, 0, "udp"},
+
+#if defined(HASIPv6)
+        {0, 0, 0, "tcp6"},
+        {0, 0, 0, "udp6"},
+#endif /* defined(HASIPv6) */
+
+    };
+#define NTCPUDP (sizeof(tcpudp) / sizeof(struct tcpudp))
+
+    static int tcpudps = 0;
+
+    if (!v->v_stream)
+        return (0);
+    maj = (major_t)GET_MAJ_DEV(v->v_rdev);
+    min = (minor_t)GET_MIN_DEV(v->v_rdev);
+    /*
+     * Fill in tcpudp[], as required.
+     */
+    if (!tcpudps) {
+
+#if solaris < 80000
+        pf = "/devices/pseudo/clone";
+#else  /* solaris>=80000 */
+        pf = "/devices/pseudo/";
+#endif /* solaris<80000 */
+
+        for (i = n = 0, pfl = (int)strlen(pf); (i < Ndev) && (n < NTCPUDP);
+             i++) {
+            if (strncmp(Devtp[i].name, pf, pfl) ||
+                !(ep = strrchr((cp = &Devtp[i].name[pfl]), ':')) ||
+                (strncmp(++ep, "tcp", 3) && strncmp(ep, "udp", 3)))
+                continue;
+
+#if solaris < 80000
+            if (*(ep + 3))
+#else  /* solaris>=80000 */
+            len = (*(ep + 3) == '6') ? 4 : 3;
+            if (*(ep + len) || ((cp + len) >= ep) || strncmp(cp, ep, len))
+#endif /* solaris<80000 */
+
+                continue;
+            for (j = 0; j < NTCPUDP; j++) {
+                if (!tcpudp[j].ds && !strcmp(ep, tcpudp[j].proto)) {
+                    tcpudp[j].ds = 1;
+                    tcpudp[j].maj = (major_t)GET_MAJ_DEV(Devtp[i].rdev);
+                    tcpudp[j].min = (minor_t)GET_MIN_DEV(Devtp[i].rdev);
+                    n++;
+                    break;
+                }
+            }
+        }
+        tcpudps = n ? 1 : -1;
+    }
+    /*
+     * Check for known IPv[46] TCP or UDP device.
+     */
+    for (i = 0; (i < NTCPUDP) && (tcpudps > 0); i++) {
+        if (tcpudp[i].ds
+
+#if solaris < 80000
+            && (maj == tcpudp[i].min)
+#else  /* solaris>=80000 */
+            && (maj == tcpudp[i].maj)
+#endif /* solaris<80000 */
+
+        ) {
+            process_socket(ctx, (KA_T)v->v_stream, tcpudp[i].proto);
+            return (1);
+        }
+    }
+    return (0);
+}
+
+/*
+ * isvlocked() - is Solaris vnode locked?
+ */
+
+static enum lsof_lock_mode isvlocked(struct lsof_context *ctx, /* context */
+                                     struct vnode *va) /* local vnode address */
+{
+
+#if solaris < 20500
+    struct filock f;
+    KA_T ff;
+    KA_T fp;
+#endif /* solaris<20500 */
+
+    int i, l;
+
+#if solaris >= 20300
+    struct lock_descriptor ld;
+    KA_T lf;
+    KA_T lp;
+#    if solaris < 20500
+#        define LOCK_END ld.info.li_sleep.sli_flock.l_len
+#        define LOCK_FLAGS ld.flags
+#        define LOCK_NEXT ld.next
+#        define LOCK_OWNER ld.owner.pid
+#        define LOCK_START ld.start
+#        define LOCK_TYPE ld.type
+#    else /* solaris>=20500 */
+#        define LOCK_END ld.l_flock.l_len
+#        define LOCK_FLAGS ld.l_state
+#        define LOCK_NEXT ld.l_next
+#        define LOCK_OWNER ld.l_flock.l_pid
+#        define LOCK_START ld.l_start
+#        define LOCK_TYPE ld.l_type
+#    endif /* solaris<20500 */
+#endif     /* solaris>=20300 */
+
+    if (va->v_filocks == NULL)
+        return LSOF_LOCK_NONE;
+
+#if solaris < 20500
+#    if solaris > 20300 ||                                                     \
+        (solaris == 20300 && defined(P101318) && P101318 >= 45)
+    if (Ntype == N_NFS)
+#    endif /* solaris>20300 || (solaris==20300 && defined(P101318) &&          \
+              P101318>=45) */
+
+    {
+        ff = fp = (KA_T)va->v_filocks;
+        i = 0;
+        do {
+            if (kread(ctx, fp, (char *)&f, sizeof(f)))
+                return LSOF_LOCK_NONE;
+            i++;
+            if (f.set.l_pid != (pid_t)Lp->pid)
+                continue;
+            if (f.set.l_whence == 0 && f.set.l_start == 0 &&
+                f.set.l_len == MAXEND)
+                l = 1;
+            else
+                l = 0;
+            switch (f.set.l_type & (F_RDLCK | F_WRLCK)) {
+            case F_RDLCK:
+                return l ? LSOF_LOCK_READ_FULL : LSOF_LOCK_READ_PARTIAL;
+            case F_WRLCK:
+                return l ? LSOF_LOCK_WRITE_FULL : LSOF_LOCK_WRITE_PARTIAL;
+            case F_RDLCK | F_WRLCK:
+                return LSOF_LOCK_READ_WRITE;
+            default:
+                return LSOF_LOCK_SOLARIS_NFS;
+            }
+        } while ((fp = (KA_T)f.next) && (fp != ff) && (i < 10000));
+    }
+#endif /* solaris<20500 */
+
+#if solaris >= 20300
+    lf = lp = (KA_T)va->v_filocks;
+    i = 0;
+    do {
+        if (kread(ctx, lp, (char *)&ld, sizeof(ld)))
+            return LSOF_LOCK_NONE;
+        i++;
+        if (!(LOCK_FLAGS & ACTIVE_LOCK) || LOCK_OWNER != (pid_t)Lp->pid)
+            continue;
+        if (LOCK_START == 0 && (LOCK_END == 0
+
+#    if solaris < 20500
+                                || LOCK_END == MAXEND
+#    else  /* solaris>=20500 */
+                                || LOCK_END == MAXEND
+#    endif /* solaris<20500 */
+
+                                ))
+            l = 1;
+        else
+            l = 0;
+        switch (LOCK_TYPE) {
+        case F_RDLCK:
+            return l ? LSOF_LOCK_READ_FULL : LSOF_LOCK_READ_PARTIAL;
+        case F_WRLCK:
+            return l ? LSOF_LOCK_WRITE_FULL : LSOF_LOCK_WRITE_PARTIAL;
+        case (F_RDLCK | F_WRLCK):
+            return LSOF_LOCK_READ_WRITE;
+        default:
+            /* It was 'L' since 1997, dunno what is it */
+            return LSOF_LOCK_UNKNOWN;
+        }
+    } while ((lp = (KA_T)LOCK_NEXT) && (lp != lf) && (i < 10000));
+    return LSOF_LOCK_NONE;
+#endif /* solaris>=20300 */
+}
+
+/*
+ * finddev() - look up device by device number
+ */
+
+static struct l_dev *finddev(struct lsof_context *ctx, /* context */
+                             dev_t *dev,               /* device */
+                             dev_t *rdev,              /* raw device */
+                             int flags) /* look flags -- see LOOKDEV_* symbol
+                                         * definitions */
+{
+    struct clone *c;
+    struct l_dev *dp;
+    struct pseudo *p;
+
+    if (!Sdev)
+        readdev(ctx, 0);
+        /*
+         * Search device table for match.
+         */
+
+#if defined(HASDCACHE)
+
+finddev_again:
+
+#endif /* defined(HASDCACHE) */
+
+    if (flags & LOOKDEV_TAB) {
+        if ((dp = lkupdev(ctx, dev, rdev, 0, 0)))
+            return (dp);
+    }
+    /*
+     * Search for clone.
+     */
+    if ((flags & LOOKDEV_CLONE) && Clone) {
+        for (c = Clone; c; c = c->next) {
+            if (GET_MAJ_DEV(*rdev) == GET_MIN_DEV(c->cd.rdev)) {
+
+#if defined(HASDCACHE)
+                if (DCunsafe && !c->cd.v && !vfy_dev(ctx, &c->cd))
+                    goto finddev_again;
+#endif /* defined(HASDCACHE) */
+
+                return (&c->cd);
+            }
+        }
+    }
+    /*
+     * Search for pseudo device match on major device only.
+     */
+    if ((flags & LOOKDEV_PSEUDO) && Pseudo) {
+        for (p = Pseudo; p; p = p->next) {
+            if (GET_MAJ_DEV(*rdev) == GET_MAJ_DEV(p->pd.rdev)) {
+
+#if defined(HASDCACHE)
+                if (DCunsafe && !p->pd.v && !vfy_dev(ctx, &p->pd))
+                    goto finddev_again;
+#endif /* defined(HASDCACHE) */
+
+                return (&p->pd);
+            }
+        }
+    }
+    return ((struct l_dev *)NULL);
+}
+
+#if solaris >= 20500
+/*
+ * idoorkeep() -- identify door keeper process
+ */
+
+static int idoorkeep(struct lsof_context *ctx, /* context */
+                     struct door_node *d)      /* door's node */
+{
+    char buf[1024];
+    size_t bufl = sizeof(buf);
+    struct proc dp;
+    struct pid dpid;
+    /*
+     * Get the proc structure and its pid structure for the door target.
+     */
+    if (!d->door_target ||
+        kread(ctx, (KA_T)d->door_target, (char *)&dp, sizeof(dp)))
+        return (0);
+    if (!dp.p_pidp || kread(ctx, (KA_T)dp.p_pidp, (char *)&dpid, sizeof(dpid)))
+        return (0);
+    /*
+     * Form a description of the door.
+     *
+     * Put the description in the NAME column addition field.  If there's
+     * already something there, allocate more space and add the door description
+     * to it.
+     */
+    if (Lp->pid == (int)dpid.pid_id)
+        (void)snpf(buf, bufl, "(this PID's door)");
+    else {
+        (void)snpf(buf, bufl, "(door to %.64s[%ld])", dp.p_user.u_comm,
+                   (long)dpid.pid_id);
+    }
+    (void)add_nma(ctx, buf, (int)strlen(buf));
+    return (1);
+}
+#endif /* solaris>=20500 */
+
+/*
+ * process_node() - process vnode
+ */
+
+void process_node(struct lsof_context *ctx, /* context */
+                  KA_T va)                  /* vnode kernel space address */
+{
+
+#if defined(HASCACHEFS)
+    struct cnode cn;
+#endif /* defined(HASCACHEFS) */
+
+    dev_t dev, rdev, trdev;
+    unsigned char devs = 0;
+    unsigned char fxs = 0;
+    unsigned char ins = 0;
+    unsigned char kvs = 0;
+    unsigned char nns = 0;
+    unsigned char pnl = 0;
+    unsigned char rdevs = 0;
+    unsigned char rvs = 0;
+    unsigned char rfxs = 0;
+    unsigned char sdns = 0;
+    unsigned char tdef;
+    unsigned char trdevs = 0;
+    unsigned char unix_sock = 0;
+    struct dev_info di;
+    char din[DINAMEL];
+    char *ep;
+    struct fifonode f;
+    char *fa = (char *)NULL;
+    int fal;
+    static int ft = 1;
+    struct vnode fv, rv;
+    int fx, rfx;
+    struct hsnode h;
+    struct inode i;
+    int j;
+    KA_T ka, vka;
+    struct lnode lo;
+    struct vfs kv, rkv;
+    int len, llc, nl, snl, sepl;
+    struct mvfsnode m;
+    struct namenode nn;
+    struct l_vfs *nvfs, *vfs;
+    struct pcnode pc;
+    struct pcfs pcfs;
+    struct rnode r;
+    KA_T realvp = (KA_T)NULL;
+    struct snode rs;
+    struct snode s;
+    char fd[FDLEN];
+
+#if solaris >= 110000
+    char *nm, *sep;
+    size_t nmrl, tl;
+    struct sdev_node sdn;
+    struct vattr sdva;
+    sotpi_info_t sti;
+    int stis = 0;
+#endif /* solaris>=110000 */
+
+    struct l_dev *sdp = (struct l_dev *)NULL;
+    size_t sz;
+    struct tmpnode t;
+    char tbuf[128], *ty, ubuf[128];
+    int tbufx;
+    enum vtype type;
+    struct sockaddr_un ua;
+    static struct vnode *v = (struct vnode *)NULL;
+    KA_T vs;
+    int vty = 0;
+    int vty_tmp;
+
+#if solaris >= 20500
+#    if solaris >= 20600
+    struct fnnode fnn;
+    struct pairaddr {
+        short f;
+        unsigned short p;
+    } * pa;
+    KA_T peer;
+    struct sonode so;
+    KA_T soa, sona;
+#    else  /* solaris<20600 */
+    struct autonode au;
+#    endif /* solaris>=20600 */
+
+    struct door_node dn;
+    int dns = 0;
+#endif /* solaris >=20500 */
+
+#if solaris < 100000
+    KA_T so_ad[2];
+    struct so_so soso;
+    int so_st = 0;
+#else  /* solaris>=100000 */
+    union {
+        ctfs_adirnode_t adir;
+        ctfs_bunode_t bun;
+        ctfs_cdirnode_t cdir;
+        ctfs_ctlnode_t ctl;
+        ctfs_evnode_t ev;
+        ctfs_latenode_t late;
+        ctfs_rootnode_t root;
+        ctfs_symnode_t sym;
+        ctfs_tdirnode_t tdir;
+        ctfs_tmplnode_t tmpl;
+    } ctfs;
+    dev_t dv_dev;
+    struct dv_node dv;
+    unsigned char dv_devs = 0;
+    unsigned char dvs = 0;
+    port_t pn;
+    struct rnode4 r4;
+#endif /* solaris<100000 */
+
+#if defined(HASPROCFS)
+    struct procfsid *pfi;
+    struct pid pids;
+#endif /* defined(HASPROCFS) */
+
+#if defined(HAS_AFS)
+    struct afsnode an;
+#endif /* defined(HAS_AFS) */
+
+#if defined(HASVXFS)
+    struct l_ino vx;
+#endif /* defined(HASVXFS) */
+
+#if defined(HAS_ZFS)
+    vfs_t zgvfs;
+    unsigned char zns = 0;
+    znode_t zn;
+    zfsvfs_t zvfs;
+#endif /* defined(HAS_ZFS) */
+
+    /*
+     * Do first-time only operations.
+     */
+
+#if solaris < 100000
+    so_ad[0] = so_ad[1] = (KA_T)0;
+#endif /* solaris<100000 */
+
+    if (ft) {
+        (void)build_Voptab(ctx);
+        ft = 0;
+    }
+    /*
+     * Read the vnode.
+     */
+    if (!va) {
+        enter_nm(ctx, "no vnode address");
+        return;
+    }
+    if (!v) {
+
+        /*
+         * Allocate space for the vnode or AFS vcache structure.
+         */
+
+#if defined(HAS_AFS)
+        v = alloc_vcache();
+#else  /* !defined(HAS_AFS) */
+        v = (struct vnode *)malloc(sizeof(struct vnode));
+#endif /* defined(HAS_AFS) */
+
+        if (!v) {
+            (void)fprintf(stderr, "%s: can't allocate %s space\n", Pn,
+
+#if defined(HAS_AFS)
+                          "vcache"
+#else  /* !defined(HAS_AFS) */
+                          "vnode"
+#endif /* defined(HAS_AFS) */
+
+            );
+            Error(ctx);
+        }
+    }
+    if (readvnode(ctx, va, v)) {
+        enter_nm(ctx, Namech);
+        return;
+    }
+
+#if defined(HASNCACHE)
+    Lf->na = va;
+#endif /* defined(HASNCACHE) */
+
+#if defined(HASFSTRUCT)
+    Lf->fna = va;
+    Lf->fsv |= FSV_NI;
+#endif /* defined(HASFSTRUCT) */
+
+#if defined(HASLFILEADD) && defined(HAS_V_PATH)
+    Lf->V_path = (KA_T)v->v_path;
+#endif /* defined(HASLFILEADD) && defined(HAS_V_PATH) */
+
+    vs = (KA_T)v->v_stream;
+    /*
+     * Check for a Solaris socket.
+     */
+    if (is_socket(ctx, v))
+        return;
+    /*
+     * Obtain the Solaris virtual file system structure.
+     */
+    if ((ka = (KA_T)v->v_vfsp)) {
+        if (kread(ctx, ka, (char *)&kv, sizeof(kv))) {
+            vka = va;
+
+        vfs_read_error:
+
+            (void)snpf(Namech, Namechl - 1, "vnode at %s: can't read vfs: %s",
+                       print_kptr(vka, tbuf, sizeof(tbuf)),
+                       print_kptr(ka, (char *)NULL, 0));
+            Namech[Namechl - 1] = '\0';
+            enter_nm(ctx, Namech);
+            return;
+        }
+        kvs = 1;
+    } else
+        kvs = 0;
+    /*
+     * Derive the virtual file system structure's device number from
+     * its file system ID for NFS and High Sierra file systems.
+     */
+    if (kvs && ((fx = kv.vfs_fstype - 1) >= 0) && (fx < Fsinfomax)) {
+        fxs = 1;
+        if (strcmp(Fsinfo[fx], "nfs") == 0 || strcmp(Fsinfo[fx], "nfs3") == 0 ||
+            strcmp(Fsinfo[fx], "hsfs") == 0)
+            kv.vfs_dev = (dev_t)kv.vfs_fsid.val[0];
+    } else {
+        fx = -1;
+        fxs = 0;
+    }
+    /*
+     * Determine the Solaris vnode type.
+     */
+    if ((Ntype = vop2ty(ctx, v, fx)) < 0) {
+        if (v->v_type == VFIFO) {
+            vty = N_REGLR;
+            Ntype = N_FIFO;
+        } else if (vs) {
+            Ntype = vty = N_STREAM;
+            Lf->is_stream = 1;
+        }
+        if (Ntype < 0) {
+            (void)snpf(Namech, Namechl - 1,
+                       "unknown file system type%s%s%s, v_op: %s",
+                       fxs ? " (" : "", fxs ? Fsinfo[fx] : "", fxs ? ")" : "",
+                       print_kptr((KA_T)v->v_op, (char *)NULL, 0));
+            Namech[Namechl - 1] = '\0';
+            enter_nm(ctx, Namech);
+            return;
+        }
+    } else {
+        vty = Ntype;
+        if (v->v_type == VFIFO)
+            Ntype = N_FIFO;
+        else if (vs && Ntype != N_SOCK) {
+            Ntype = vty = N_STREAM;
+            Lf->is_stream = 1;
+        }
+    }
+    /*
+     * See if this Solaris node has been fattach'ed to another node.
+     * If it has, read the namenode, and enter the node addresses in
+     * the NAME column addition.
+     *
+     * See if it's covering a socket as well and process accordingly.
+     */
+    if (vty == N_NM) {
+        if (read_nnn(ctx, va, (KA_T)v->v_data, &nn))
+            return;
+        nns = 1;
+        if (nn.nm_mountpt)
+
+#if solaris >= 20500
+            fa = ent_fa(
+                (KA_T *)((Ntype == N_FIFO || v->v_type == VDOOR) ? NULL : &va),
+                (KA_T *)&nn.nm_mountpt, "->", &fal);
+#else  /* solaris<20500 */
+            fa = ent_fa((KA_T *)((Ntype == N_FIFO) ? NULL : &va),
+                        (KA_T *)&nn.nm_mountpt, "->", &fal);
+#endif /* solaris>=20500 */
+
+        if (Ntype != N_FIFO && nn.nm_filevp &&
+            !kread(ctx, (KA_T)nn.nm_filevp, (char *)&rv, sizeof(rv))) {
+            rvs = 1;
+            if ((ka = (KA_T)rv.v_vfsp) &&
+                !kread(ctx, ka, (char *)&rkv, sizeof(rkv)) &&
+                ((rfx = rkv.vfs_fstype - 1) >= 0) && (rfx < Fsinfomax)) {
+                rfxs = 1;
+            } else {
+                rfx = fx;
+                rfxs = fxs;
+            }
+
+#if defined(HASNCACHE)
+            Lf->na = (KA_T)nn.nm_filevp;
+#endif /* defined(HASNCACHE) */
+
+            if (is_socket(ctx, &rv))
+                return;
+        }
+    }
+    if (Selinet && Ntype != N_SOCK)
+        return;
+    /*
+     * See if this Solaris node is served by spec_vnodeops.
+     */
+    if (Spvops && Spvops == (KA_T)v->v_op)
+        Ntype = N_SPEC;
+    /*
+     * Determine the Solaris lock state.
+     */
+    Lf->lock = isvlocked(ctx, v);
+    /*
+     * Establish the Solaris local virtual file system structure.
+     */
+    if (!(ka = (KA_T)v->v_vfsp) || !kvs)
+        vfs = (struct l_vfs *)NULL;
+    else if (!(vfs = readvfs(ctx, ka, &kv, v))) {
+        vka = va;
+        goto vfs_read_error;
+    }
+    /*
+     * Read the afsnode, autonode, cnode, door_node, fifonode, fnnode, lnode,
+     * inode, pcnode, rnode, snode, tmpnode, znode, etc.
+     */
+    switch (Ntype) {
+    case N_SPEC:
+
+        /*
+         * A N_SPEC node is a node that resides in in an underlying file system
+         * type -- e.g. NFS, HSFS.  Its vnode points to an snode.  Subsequent
+         * node structures are implied by the underlying node type.
+         */
+        if (read_nsn(ctx, va, (KA_T)v->v_data, &s))
+            return;
+        realvp = (KA_T)s.s_realvp;
+        if (!realvp && s.s_commonvp) {
+            if (read_cni(ctx, &s, &rv, v, &rs, &di, din, sizeof(din)) == 1)
+                return;
+            if (!rv.v_stream) {
+                if (din[0]) {
+                    (void)snpf(Namech, Namechl, "COMMON: %s", din);
+                    Namech[Namechl - 1] = '\0';
+                    Lf->is_com = 1;
+                }
+                break;
+            }
+        }
+        if (!realvp) {
+
+            /*
+             * If the snode lacks a real vnode (and also lacks a common vnode),
+             * it's original type is N_STREAM or N_REGLR, and it has a stream
+             * pointer, get the module names.
+             */
+            if ((vty == N_STREAM || vty == N_REGLR) && vs) {
+                Lf->is_stream = 1;
+                vty = N_STREAM;
+
+#if solaris < 100000
+                read_mi(ctx, vs, (dev_t *)&s.s_dev, (caddr_t)&soso, &so_st,
+                        so_ad, &sdp);
+#else  /* solaris>=100000 */
+                read_mi(ctx, vs, (dev_t *)&s.s_dev, NULL, NULL, NULL, &sdp);
+#endif /* solaris<100000 */
+
+                vs = (KA_T)NULL;
+            }
+        }
+        break;
+
+#if defined(HAS_AFS)
+    case N_AFS:
+        if (readafsnode(ctx, va, v, &an))
+            return;
+        break;
+#endif /* defined(HAS_AFS) */
+
+#if solaris >= 20500
+    case N_AUTO:
+
+#    if solaris < 20600
+        if (read_nan(ctx, va, (KA_T)v->v_data, &au))
+#    else  /* solaris>=20600 */
+        if (read_nan(ctx, va, (KA_T)v->v_data, &fnn))
+#    endif /* solaris<20600 */
+
+            return;
+        break;
+
+#    if solaris >= 100000
+    case N_DEV:
+        if (read_ndvn(ctx, va, (KA_T)v->v_data, &dv, &dv_dev, &dv_devs))
+            return;
+        dvs = 1;
+        break;
+#    endif /* solaris>=100000 */
+
+    case N_DOOR:
+        if (read_ndn(ctx, va, (KA_T)v->v_data, &dn))
+            return;
+        dns = 1;
+        break;
+#endif /* solaris>=20500 */
+
+#if defined(HASCACHEFS)
+    case N_CACHE:
+        if (read_ncn(ctx, va, (KA_T)v->v_data, &cn))
+            return;
+        break;
+#endif /* defined(HASCACHEFS) */
+
+#if solaris >= 100000
+    case N_CTFSADIR:
+    case N_CTFSBUND:
+    case N_CTFSCDIR:
+    case N_CTFSCTL:
+    case N_CTFSEVT:
+    case N_CTFSLATE:
+    case N_CTFSROOT:
+    case N_CTFSSTAT:
+    case N_CTFSSYM:
+    case N_CTFSTDIR:
+    case N_CTFSTMPL:
+        if (read_nctfsn(ctx, Ntype, va, (KA_T)v->v_data, (char *)&ctfs))
+            return;
+        break;
+#endif /* solaris>=100000 */
+
+#if solaris >= 20600
+    case N_SOCK:
+        sona = (KA_T)v->v_data;
+        if (read_nson(ctx, va, sona, &so))
+            return;
+        break;
+#endif /* solaris>=20600 */
+
+    case N_MNT:
+        /* Information comes from the l_vfs structure. */
+        break;
+    case N_MVFS:
+        if (read_nmn(ctx, va, (KA_T)v->v_data, &m))
+            return;
+        break;
+    case N_NFS:
+        if (read_nrn(ctx, va, (KA_T)v->v_data, &r))
+            return;
+        break;
+
+#if solaris >= 100000
+    case N_NFS4:
+        if (read_nrn4(ctx, va, (KA_T)v->v_data, &r4))
+            return;
+        break;
+#endif /* solaris>=100000 */
+
+    case N_NM:
+        if (nns)
+            realvp = (KA_T)nn.nm_filevp;
+
+#if defined(HASNCACHE)
+        Lf->na = (KA_T)nn.nm_filevp;
+#endif /* defined(HASNCACHE) */
+
+        break;
+    case N_FD:
+        break; /* no successor node */
+    case N_FIFO:
+
+        /*
+         * Solaris FIFO vnodes are usually linked to a fifonode.  One
+         * exception is a FIFO vnode served by nm_vnodeops; it is linked
+         * to a namenode, and the namenode points to the fifonode.
+         *
+         * Non-pipe fifonodes are linked to a vnode thorough fn_realvp.
+         */
+        if (vty == N_NM && nns) {
+            if (nn.nm_filevp) {
+                if (read_nfn(ctx, va, (KA_T)nn.nm_filevp, &f))
+                    return;
+                realvp = (KA_T)NULL;
+                vty = N_FIFO;
+            } else {
+                (void)snpf(Namech, Namechl - 1,
+                           "FIFO namenode at %s: no fifonode pointer",
+                           print_kptr((KA_T)v->v_data, (char *)NULL, 0));
+                Namech[Namechl - 1] = '\0';
+                return;
+            }
+        } else {
+            if (read_nfn(ctx, va, (KA_T)v->v_data, &f))
+                return;
+            realvp = (KA_T)f.fn_realvp;
+        }
+        if (!realvp) {
+            Lf->inode = (INODETYPE)(nns ? nn.nm_vattr.va_nodeid : f.fn_ino);
+
+#if solaris >= 80000 /* Solaris 8 and above hack! */
+#    if defined(_LP64)
+            if (Lf->inode >= (unsigned long)0xbaddcafebaddcafe)
+#    else  /* !defined(_LP64) */
+            if (Lf->inode >= (unsigned long)0xbaddcafe)
+#    endif /* defined(_LP64) */
+
+                Lf->inp_ty = 0;
+            else
+#endif /* solaris>=80000 Solaris 8 and above hack! */
+
+                Lf->inp_ty = 1;
+            enter_dev_ch(ctx, print_kptr((KA_T)v->v_data, (char *)NULL, 0));
+            if (f.fn_flag & ISPIPE) {
+                (void)snpf(tbuf, sizeof(tbuf), "PIPE");
+                tbufx = (int)strlen(tbuf);
+            } else
+                tbufx = 0;
+
+#if solaris < 20500
+            if (f.fn_mate) {
+                (void)snpf(&tbuf[tbufx], sizeof(tbuf) - tbufx, "->%s",
+                           print_kptr((KA_T)f.fn_mate, (char *)NULL, 0));
+                tbufx = (int)strlen(tbuf);
+            }
+#else  /* solaris>=20500 */
+            if (f.fn_dest) {
+                (void)snpf(&tbuf[tbufx], sizeof(tbuf) - tbufx, "->%s",
+                           print_kptr((KA_T)f.fn_dest, (char *)NULL, 0));
+                tbufx = (int)strlen(tbuf);
+            }
+#endif /* solaris<20500 */
+
+            if (tbufx)
+                (void)add_nma(ctx, tbuf, tbufx);
+            break;
+        }
+        break;
+
+    case N_HSFS:
+        if (read_nhn(ctx, va, (KA_T)v->v_data, &h))
+            return;
+        break;
+    case N_LOFS:
+        llc = 0;
+        do {
+            rvs = 0;
+            if (read_nln(ctx, va, llc ? (KA_T)rv.v_data : (KA_T)v->v_data,
+                         &lo)) {
+                return;
+            }
+            if (!(realvp = (KA_T)lo.lo_vp)) {
+                (void)snpf(Namech, Namechl - 1, "lnode at %s: no real vnode",
+                           print_kptr((KA_T)v->v_data, (char *)NULL, 0));
+                Namech[Namechl - 1] = '\0';
+                enter_nm(ctx, Namech);
+                return;
+            }
+            if (read_nvn(ctx, (KA_T)v->v_data, (KA_T)realvp, &rv))
+                return;
+            rvs = 1;
+            llc++;
+            if ((ka = (KA_T)rv.v_vfsp) &&
+                !kread(ctx, ka, (char *)&rkv, sizeof(rkv)) &&
+                ((rfx = rkv.vfs_fstype - 1) >= 0) && (rfx < Fsinfomax)) {
+                rfxs = 1;
+            } else {
+                rfx = fx;
+                rfxs = fxs;
+            }
+            if (((vty_tmp = vop2ty(ctx, &rv, rfx)) == N_LOFS) && (llc > 1000)) {
+                (void)snpf(Namech, Namechl - 1, "lnode at %s: loop > 1000",
+                           print_kptr((KA_T)v->v_data, (char *)NULL, 0));
+                Namech[Namechl - 1] = '\0';
+                enter_nm(ctx, Namech);
+                return;
+            }
+        } while (vty_tmp == N_LOFS);
+        break;
+    case N_PCFS:
+        if (read_npn(ctx, va, (KA_T)v->v_data, &pc))
+            return;
+        break;
+
+#if solaris >= 100000
+    case N_PORT:
+        if (read_nprtn(ctx, va, (KA_T)v->v_data, &pn))
+            return;
+        break;
+#endif /* solaris>=100000 */
+
+#if defined(HASPROCFS)
+    case N_PROC:
+        if (read_npi(ctx, va, v, &pids))
+            return;
+        break;
+#endif /* defined(HASPROCFS) */
+
+#if solaris >= 110000
+    case N_SDEV:
+        if (read_nsdn(ctx, va, (KA_T)v->v_data, &sdn, &sdva))
+            return;
+        sdns = 1;
+        break;
+#endif /* solaris>=110000 */
+
+    case N_SAMFS:
+        (void)add_nma(ctx, SAMFS_NMA_MSG, (int)strlen(SAMFS_NMA_MSG));
+        break;
+    case N_SHARED:
+        break; /* No more sharedfs information is available. */
+    case N_STREAM:
+        if (read_nsn(ctx, va, (KA_T)v->v_data, &s))
+            return;
+        if (vs) {
+            Lf->is_stream = 1;
+
+#if solaris < 100000
+            read_mi(ctx, vs, (dev_t *)&s.s_dev, (caddr_t)&soso, &so_st, so_ad,
+                    &sdp);
+#else  /* solaris>=100000 */
+            read_mi(ctx, vs, (dev_t *)&s.s_dev, NULL, NULL, NULL, &sdp);
+#endif /* solaris<100000 */
+
+            vs = (KA_T)NULL;
+        }
+        break;
+    case N_TMP:
+        if (read_ntn(ctx, va, (KA_T)v->v_data, &t))
+            return;
+        break;
+
+#if defined(HASVXFS)
+    case N_VXFS:
+        if (read_vxnode(ctx, va, v, vfs, fx, &vx, Vvops))
+            return;
+        break;
+#endif /* defined(HASVXFS) */
+
+#if defined(HAS_ZFS)
+    case N_ZFS:
+        if (read_nzn(ctx, va, (KA_T)v->v_data, &zn))
+            return;
+        zns = 1;
+        break;
+#endif /* defined(HAS_ZFS) */
+
+    case N_REGLR:
+    default:
+        if (read_nin(ctx, va, (KA_T)v->v_data, &i))
+            return;
+        ins = 1;
+    }
+    /*
+     * If the node has a real vnode pointer, follow it.
+     */
+    if (realvp) {
+        if (rvs) {
+            *v = rv;
+            fx = rfx;
+            fxs = rfxs;
+        } else {
+            if (read_nvn(ctx, (KA_T)v->v_data, (KA_T)realvp, v))
+                return;
+            else {
+
+#if defined(HASNCACHE)
+                Lf->na = (KA_T)realvp;
+#endif /* defined(HASNCACHE) */
+
+                if ((ka = (KA_T)v->v_vfsp) &&
+                    !kread(ctx, ka, (char *)&kv, sizeof(kv))) {
+                    kvs = 1;
+                }
+                if (kvs && ((fx = kv.vfs_fstype - 1) >= 0) &&
+                    (fx < Fsinfomax)) {
+                    fxs = 1;
+                }
+            }
+        }
+        /*
+         * If the original vnode type is N_STREAM, if there is a stream
+         * pointer and if there is no sdev_node, get the module names.
+         */
+        if (vty == N_STREAM && vs && !sdns) {
+            Lf->is_stream = 1;
+
+#if solaris < 100000
+            read_mi(ctx, vs, (dev_t *)&s.s_dev, (caddr_t)&soso, &so_st, so_ad,
+                    &sdp);
+#else  /* solaris>=100000 */
+            read_mi(ctx, vs, (dev_t *)&s.s_dev, NULL, NULL, NULL, &sdp);
+#endif /* solaris<100000 */
+
+            vs = (KA_T)NULL;
+        }
+        /*
+         * Get the real vnode's type.
+         */
+        if ((vty = vop2ty(ctx, v, fx)) < 0) {
+            if (Ntype != N_FIFO && vs)
+                vty = N_STREAM;
+            else {
+
+#if solaris < 100000
+                (void)snpf(Namech, Namechl - 1,
+                           "unknown file system type, v_op: %s",
+                           print_kptr((KA_T)v->v_op, (char *)NULL, 0));
+#else  /* solaris>=100000 */
+                (void)snpf(Namech, Namechl - 1,
+                           "unknown file system type (%s), v_op: %s",
+                           fxs ? Fsinfo[fx] : "unknown",
+                           print_kptr((KA_T)v->v_op, (char *)NULL, 0));
+#endif /* solaris<100000 */
+
+                Namech[Namechl - 1] = '\0';
+            }
+        }
+        if (Ntype == N_NM || Ntype == N_AFS)
+            Ntype = vty;
+        /*
+         * Base further processing on the "real" vnode.
+         */
+        Lf->lock = isvlocked(ctx, v);
+        switch (vty) {
+
+#if defined(HAS_AFS)
+        case N_AFS:
+            if (readafsnode(ctx, va, v, &an))
+                return;
+            break;
+#endif /* defined(HAS_AFS) */
+
+#if solaris >= 20500
+        case N_AUTO:
+
+#    if solaris < 20600
+            if (read_nan(ctx, va, (KA_T)v->v_data, &au))
+#    else  /* solaris>=20600 */
+            if (read_nan(ctx, va, (KA_T)v->v_data, &fnn))
+#    endif /* solaris<20600 */
+
+                return;
+            break;
+
+#    if solaris >= 100000
+        case N_DEV:
+            if (read_ndvn(ctx, va, (KA_T)v->v_data, &dv, &dv_dev, &dv_devs))
+                return;
+            dvs = 1;
+            break;
+#    endif /* solaris>=100000 */
+
+        case N_DOOR:
+
+#    if solaris < 20600
+            if (read_ndn(ctx, realvp, (KA_T)v->v_data, &dn))
+#    else  /* solaris>=20600 */
+            if (read_ndn(ctx, va, (KA_T)v->v_data, &dn))
+#    endif /* solaris<20500 */
+
+                return;
+            dns = 1;
+            break;
+#endif /* solaris>=20500 */
+
+#if defined(HASCACHEFS)
+        case N_CACHE:
+            if (read_ncn(ctx, va, (KA_T)v->v_data, &cn))
+                return;
+            break;
+#endif /* defined(HASCACHEFS) */
+
+#if solaris >= 100000
+        case N_CTFSADIR:
+        case N_CTFSBUND:
+        case N_CTFSCDIR:
+        case N_CTFSCTL:
+        case N_CTFSEVT:
+        case N_CTFSLATE:
+        case N_CTFSROOT:
+        case N_CTFSSTAT:
+        case N_CTFSSYM:
+        case N_CTFSTDIR:
+        case N_CTFSTMPL:
+            if (read_nctfsn(ctx, vty, va, (KA_T)v->v_data, (char *)&ctfs))
+                return;
+            break;
+#endif /* solaris>=100000 */
+
+        case N_HSFS:
+            if (read_nhn(ctx, va, (KA_T)v->v_data, &h))
+                return;
+            break;
+        case N_MNT:
+            /* Information comes from the l_vfs structure. */
+            break;
+        case N_MVFS:
+            if (read_nmn(ctx, va, (KA_T)v->v_data, &m))
+                return;
+            break;
+        case N_NFS:
+            if (read_nrn(ctx, va, (KA_T)v->v_data, &r))
+                return;
+            break;
+
+#if solaris >= 100000
+        case N_NFS4:
+            if (read_nrn4(ctx, va, (KA_T)v->v_data, &r4))
+                return;
+            break;
+#endif /* solaris>=100000 */
+
+        case N_NM:
+            if (read_nnn(ctx, va, (KA_T)v->v_data, &nn))
+                return;
+            nns = 1;
+            break;
+
+#if solaris >= 100000
+        case N_PORT:
+            if (read_nprtn(ctx, va, (KA_T)v->v_data, &pn))
+                return;
+            break;
+#endif /* solaris>=100000 */
+
+        case N_PCFS:
+            if (read_npn(ctx, va, (KA_T)v->v_data, &pc))
+                return;
+            break;
+        case N_SAMFS:
+            (void)add_nma(ctx, SAMFS_NMA_MSG, (int)strlen(SAMFS_NMA_MSG));
+
+#if solaris >= 110000
+        case N_SDEV:
+            if (read_nsdn(ctx, va, (KA_T)v->v_data, &sdn, &sdva))
+                return;
+            if (Lf->is_stream) {
+
+                /*
+                 * This stream's real node is an sdev_node, so it's not really
+                 * a stream.  Reverse prior stream settings.
+                 */
+                Lf->is_stream = 0;
+                Namech[0] = '\0';
+            }
+            sdns = 1;
+            break;
+#endif /* solaris>=110000 */
+
+            break;
+
+#if solaris >= 20600
+        case N_SOCK:
+            sona = (KA_T)v->v_data;
+            if (read_nson(ctx, va, sona, &so))
+                return;
+            break;
+#endif /* solaris>=20600 */
+
+        case N_STREAM:
+            if (vs) {
+                Lf->is_stream = 1;
+
+#if solaris < 100000
+                read_mi(ctx, vs, (dev_t *)&s.s_dev, (caddr_t)&soso, &so_st,
+                        so_ad, &sdp);
+#else  /* solaris>=100000 */
+                read_mi(ctx, vs, (dev_t *)&s.s_dev, NULL, NULL, NULL, &sdp);
+#endif /* solaris<100000 */
+
+                vs = (KA_T)NULL;
+            }
+            break;
+        case N_TMP:
+            if (read_ntn(ctx, va, (KA_T)v->v_data, &t))
+                return;
+            break;
+
+#if defined(HASVXFS)
+        case N_VXFS:
+            if (read_vxnode(ctx, va, v, vfs, fx, &vx, Vvops))
+                return;
+            break;
+#endif /* defined(HASVXFS) */
+
+#if defined(HAS_ZFS)
+        case N_ZFS:
+            if (read_nzn(ctx, va, (KA_T)v->v_data, &zn))
+                return;
+            zns = 1;
+            break;
+#endif /* defined(HAS_ZFS) */
+
+        case N_REGLR:
+        default:
+            if (read_nin(ctx, va, (KA_T)v->v_data, &i))
+                return;
+            ins = 1;
+        }
+        /*
+         * If this is a Solaris loopback node, use the "real" node type.
+         */
+        if (Ntype == N_LOFS)
+            Ntype = vty;
+    }
+    /*
+     * Get device and type for printing.
+     */
+    switch (((Ntype == N_FIFO) || (vty == N_SDEV)) ? vty : Ntype) {
+
+#if defined(HAS_AFS)
+    case N_AFS:
+        dev = an.dev;
+        devs = 1;
+        break;
+#endif /* defined(HAS_AFS) */
+
+#if solaris >= 20500
+    case N_AUTO:
+        if (kvs) {
+            dev = (dev_t)kv.vfs_fsid.val[0];
+            devs = 1;
+        }
+        break;
+
+#    if solaris >= 100000
+    case N_DEV:
+        if (dv_devs) {
+            dev = dv_dev;
+            devs = 1;
+        } else if (vfs) {
+            dev = vfs->dev;
+            devs = 1;
+        }
+        rdev = v->v_rdev;
+        rdevs = 1;
+        break;
+#    endif /* solaris>=100000 */
+
+    case N_DOOR:
+
+#    if solaris < 20600
+        if (kvs) {
+            dev = (dev_t)kv.vfs_fsid.val[0];
+            devs = 1;
+        }
+#    else  /* solaris>=20600 */
+        if (nns) {
+            dev = (dev_t)nn.nm_vattr.va_fsid;
+            devs = 1;
+        } else if (dns) {
+            dev = (dev_t)dn.door_index;
+            devs = 1;
+        }
+#    endif /* solaris<20600 */
+
+        break;
+#endif /* solaris>=20500 */
+
+#if defined(HASCACHEFS)
+    case N_CACHE:
+#endif /* defined(HASCACHEFS) */
+
+    case N_HSFS:
+    case N_PCFS:
+        if (kvs) {
+            dev = kv.vfs_dev;
+            devs = 1;
+        }
+        break;
+
+#if solaris >= 100000
+    case N_CTFSADIR:
+    case N_CTFSBUND:
+    case N_CTFSCDIR:
+    case N_CTFSCTL:
+    case N_CTFSEVT:
+    case N_CTFSLATE:
+    case N_CTFSROOT:
+    case N_CTFSSTAT:
+    case N_CTFSSYM:
+    case N_CTFSTDIR:
+    case N_CTFSTMPL:
+        if (kvs) {
+            dev = kv.vfs_dev;
+            devs = 1;
+        }
+        break;
+#endif /* solaris>=100000 */
+
+    case N_FD:
+        if (kvs) {
+            dev = kv.vfs_dev;
+            devs = 1;
+        }
+        if ((v->v_type == VCHR) || (v->v_type == VBLK)) {
+            rdev = v->v_rdev;
+            rdevs = 1;
+        }
+        break;
+
+    case N_MNT:
+
+#if defined(CVFS_DEVSAVE)
+        if (vfs) {
+            dev = vfs->dev;
+            devs = 1;
+        }
+#endif /* defined(CVFS_DEVSAVE) */
+
+        break;
+    case N_MVFS:
+
+#if defined(CVFS_DEVSAVE)
+        if (vfs) {
+            dev = vfs->dev;
+            devs = 1;
+        }
+#endif /* defined(CVFS_DEVSAVE) */
+
+        break;
+    case N_NFS:
+        dev = r.r_attr.va_fsid;
+        devs = 1;
+        break;
+
+#if solaris >= 100000
+    case N_NFS4:
+        dev = r4.r_attr.va_fsid;
+        devs = 1;
+        break;
+#endif /* solaris>=100000 */
+
+    case N_NM:
+        if (nns) {
+            dev = (dev_t)nn.nm_vattr.va_fsid;
+            devs = 1;
+        } else
+            enter_dev_ch(ctx, "    NMFS");
+        break;
+
+#if solaris >= 100000
+    case N_PORT:
+        if (kvs) {
+            dev = kv.vfs_dev;
+            devs = 1;
+        }
+        break;
+#endif /* solaris>=100000 */
+
+#if defined(HASPROCFS)
+    case N_PROC:
+        if (kvs) {
+            dev = kv.vfs_dev;
+            devs = 1;
+        }
+        break;
+#endif /* defined(HASPROCFS) */
+
+    case N_SAMFS:
+        if ((v->v_type == VCHR) || (v->v_type == VBLK)) {
+            rdev = v->v_rdev;
+            rdevs = 1;
+        } else if (vfs) {
+            dev = vfs->dev;
+            devs = 1;
+        }
+        break;
+
+#if solaris >= 110000
+    case N_SDEV:
+        if (sdns) {
+            if (v->v_type == VDIR) {
+                dev = v->v_rdev;
+                devs = 1;
+            } else {
+                rdev = v->v_rdev;
+                rdevs = 1;
+            }
+        }
+        break;
+#endif /* solaris>=110000 */
+
+    case N_SHARED:
+        if (vfs) {
+            dev = vfs->dev;
+            devs = 1;
+        }
+        break;
+
+#if solaris >= 20600
+    case N_SOCK:
+        if (so.so_family == AF_UNIX)
+
+        /*
+         * Process an AF_UNIX socket node.
+         */
+
+#    if solaris >= 110000
+        {
+
+            /*
+             * Process a Solaris >= 11 AF_UNIX socket node:
+             *
+             * Get its sotpi_info_t structure;
+             */
+            if (read_nsti(ctx, &so, &sti))
+                return;
+            /*
+             * Get its device numbers.  If they are located, start the NAME
+             * column with the device name, followed by "->".
+             */
+            nm = Namech;
+            nmrl = Namechl - 1;
+            Namech[Namechl - 1] = '\0';
+            if (!sdp)
+                sdp = finddev(ctx, &DevDev, &sti.sti_dev, LOOKDEV_ALL);
+            if (sdp) {
+                dev = DevDev;
+                rdev = v->v_rdev;
+                trdev = sdp->rdev;
+                devs = rdevs = trdevs = 1;
+                Lf->inode = (INODETYPE)sdp->inode;
+                Lf->inp_ty = 1;
+                (void)snpf(nm, nmrl, "%s", sdp->name);
+                tl = strlen(nm);
+                nm += tl;
+                nmrl -= tl;
+                sep = "->";
+            } else {
+                devs = rdevs = trdevs = 0;
+                sep = "";
+            }
+            /*
+             * Add the socket node's address to the NAME column.
+             */
+            sepl = strlen(sep);
+            if (sona && ((nmrl - sepl) > 0)) {
+                (void)snpf(nm, nmrl, "%s%s", sep,
+                           print_kptr(sona, (char *)NULL, 0));
+                tl = strlen(nm);
+                nm += tl;
+                nmrl -= tl;
+            }
+            /*
+             * Add the service type to the NAME column.
+             */
+            switch (sti.sti_serv_type) {
+            case T_CLTS:
+                ty = "dgram";
+                break;
+            case T_COTS:
+                ty = "stream";
+                break;
+            case T_COTS_ORD:
+                ty = "stream-ord";
+                break;
+            default:
+                ty = (char *)NULL;
+            }
+            if (ty && (nmrl > 1)) {
+                (void)snpf(nm, nmrl, " %s", ty);
+                tl = strlen(nm);
+                nm += tl;
+                nmrl -= tl;
+            }
+            /*
+             * Add the vnode and connected addresses to the NAME column,
+             * as indicated by the socket node state.
+             */
+            if ((so.so_state & SS_ISBOUND) && (nmrl > 36) &&
+                (sti.sti_ux_laddr.soua_magic == SOU_MAGIC_EXPLICIT)) {
+                (void)snpf(nm, nmrl, " Vn=%s",
+                           print_kptr((KA_T)sti.sti_ux_laddr.soua_vp,
+                                      (char *)NULL, 0));
+                tl = strlen(nm);
+                nm += tl;
+                nmrl -= tl;
+            }
+            if ((so.so_state & SS_ISCONNECTED) && (nmrl > 38) &&
+                (sti.sti_ux_faddr.soua_magic == SOU_MAGIC_EXPLICIT)) {
+                (void)snpf(nm, nmrl, " Conn=%s ",
+                           print_kptr((KA_T)sti.sti_ux_faddr.soua_vp,
+                                      (char *)NULL, 0));
+                tl = strlen(nm);
+                nm += tl;
+                nmrl -= tl;
+            }
+            /*
+             * Put local and connected UNIX addresses in the NAME column, if
+             * they exist and as indicated by the socket node's state.
+             */
+            if ((so.so_state & SS_ISBOUND) &&
+                ((len = read_nusa(ctx, &sti.sti_laddr, &ua)) > 0) &&
+                (nmrl > (len + 5))) {
+                if (Sfile && is_file_named(ctx, ua.sun_path, Ntype, VSOCK, 0))
+                    Lf->sf |= SELNM;
+                if (len > nmrl)
+                    len = nmrl;
+                if (len > 0) {
+                    ua.sun_path[len] = '\0';
+                    (void)snpf(nm, nmrl, " Lcl=%s", ua.sun_path);
+                    tl = strlen(nm);
+                    nm += tl;
+                    nmrl -= tl;
+                }
+            }
+            if ((so.so_state & SS_ISCONNECTED) &&
+                ((len = read_nusa(ctx, &sti.sti_faddr, &ua)) > 0) &&
+                (nmrl > (len + 5))) {
+                if (Sfile && is_file_named(ctx, ua.sun_path, Ntype, VSOCK, 0))
+                    Lf->sf |= SELNM;
+                if (len > nmrl)
+                    len = nmrl;
+                if (len > 0) {
+                    ua.sun_path[len] = '\0';
+                    (void)snpf(nm, nmrl, " Rem=%s", ua.sun_path);
+                    tl = strlen(nm);
+                    nm += tl;
+                    nmrl -= tl;
+                }
+            }
+        } else {
+
+            /*
+             * Process Solaris >= 11 AF_INET, AF_INET6 and AF_ROUTE VSOCK
+             * nodes.
+             */
+            switch (so.so_family) {
+            case AF_INET:
+            case AF_INET6:
+            case AF_ROUTE:
+                if (process_VSOCK(ctx, (KA_T)va, v, &so))
+                    return;
+            }
+        }
+#    else /* solaris<110000 */
+        {
+
+            /*
+             * Process an AF_UNIX socket node for Solaris < 11:
+             *   Locate its device numbers;
+             *    Enter the sonode address as the device (netstat's local
+             *   address);
+             *    Get a non-NULL local sockaddr_un and enter it in Namech;
+             *    Get a non-NULL foreign sockaddr_un and enter it in Namech;
+             *    Check for matches on sockaddr_un.sun_path names.
+             */
+
+            if (!sdp)
+                sdp = finddev(&DevDev,
+
+#        if solaris < 100000
+                              &so.so_vnode.v_rdev,
+#        else  /* solaris>=100000 */
+                              &so.so_dev,
+#        endif /* solaris<100000 */
+
+                              LOOKDEV_ALL);
+
+            if (sdp) {
+                dev = DevDev;
+
+#        if solaris < 100000
+                rdev = so.so_vnode.v_rdev;
+#        else  /* solaris>=100000 */
+                rdev = so.so_dev;
+#        endif /* solaris<100000 */
+
+                trdev = sdp->rdev;
+                devs = rdevs = trdevs = 1;
+                Lf->inode = (INODETYPE)sdp->inode;
+                Lf->inp_ty = 1;
+                (void)snpf(Namech, Namechl - 1, "%s", sdp->name);
+                Namech[Namechl - 1] = '\0';
+            } else
+                devs = 0;
+            nl = snl = (int)strlen(Namech);
+
+            if ((len = read_nusa(&so.so_laddr, &ua))) {
+                if (Sfile && is_file_named(ctx, ua.sun_path, Ntype, VSOCK, 0))
+                    Lf->sf |= SELNM;
+                sepl = Namech[0] ? 2 : 0;
+                if (len > (Namechl - nl - sepl - 1))
+                    len = Namechl - nl - sepl - 1;
+                if (len > 0) {
+                    ua.sun_path[len] = '\0';
+                    (void)snpf(&Namech[nl], Namechl - nl, "%s%s",
+                               sepl ? "->" : "", ua.sun_path);
+                    nl += (len + sepl);
+                }
+            }
+            if ((len = read_nusa(&so.so_faddr, &ua))) {
+                if (Sfile && is_file_named(ctx, ua.sun_path, Ntype, VSOCK, 0))
+                    Lf->sf |= SELNM;
+                sepl = Namech[0] ? 2 : 0;
+                if (len > (Namechl - nl - sepl - 1))
+                    len = Namechl - nl - sepl - 1;
+                if (len > 0) {
+                    ua.sun_path[len] = 0;
+                    (void)snpf(&Namech[nl], Namechl - nl, "%s%s",
+                               sepl ? "->" : "", ua.sun_path);
+                    nl += (len + sepl);
+                }
+            }
+            if ((nl == snl)
+
+#        if defined(HASSOUXSOUA)
+                && so.so_ux_laddr.soua_magic == SOU_MAGIC_IMPLICIT
+#        else  /* !defined(HASSOUXSOUA) */
+                && so.so_ux_laddr.sou_magic == SOU_MAGIC_IMPLICIT
+#        endif /* defined(HASSOUXSOUA) */
+
+            ) {
+
+                /*
+                 * There are no addresses; this must be a socket pair.
+                 * Print its identity.
+                 */
+                pa = (struct pairaddr *)&ua;
+                if (!(peer = (KA_T)((int)pa->p)))
+
+#        if defined(HASSOUXSOUA)
+                    peer = (KA_T)so.so_ux_laddr.soua_vp;
+#        else  /* !defined(HASSOUXSOUA) */
+                    peer = (KA_T)so.so_ux_laddr.sou_vp;
+#        endif /* defined(HASSOUXSOUA) */
+
+                if (peer)
+                    (void)snpf(ubuf, sizeof(ubuf), "(socketpair: %s)",
+                               print_kptr(peer, (char *)NULL, 0));
+                else
+                    (void)snpf(ubuf, sizeof(ubuf), "(socketpair)");
+                len = (int)strlen(ubuf);
+                sepl = Namech[0] ? 2 : 0;
+                if (len > (Namechl - nl - sepl - 1))
+                    len = Namechl - nl - sepl - 1;
+                if (len > 0) {
+                    (void)snpf(&Namech[nl], Namechl - nl, "%s%s",
+                               sepl ? "->" : "", ubuf);
+                    nl += (len + sepl);
+                }
+            }
+            /*
+             * Add the local and foreign addresses, ala `netstat -f unix` to
+             * the name.
+             */
+
+#        if defined(HASSOUXSOUA)
+            soa = (KA_T)so.so_ux_faddr.soua_vp;
+#        else  /* !defined(HASSOUXSOUA) */
+            soa = (KA_T)so.so_ux_faddr.sou_vp;
+#        endif /* defined(HASSOUXSOUA) */
+
+            (void)snpf(ubuf, sizeof(ubuf), "%s(%s%s%s)", Namech[0] ? " " : "",
+                       print_kptr((KA_T)v->v_data, (char *)NULL, 0),
+                       soa ? "->" : "",
+                       soa ? print_kptr(soa, tbuf, sizeof(tbuf)) : "");
+            len = (int)strlen(ubuf);
+            if (len <= (Namechl - nl - 1)) {
+                (void)snpf(&Namech[nl], Namechl - nl, "%s", ubuf);
+                nl += len;
+            }
+            /*
+             * If there is a bound vnode, add its address to the name.
+             */
+
+            if (so.so_ux_bound_vp) {
+                (void)snpf(
+                    ubuf, sizeof(ubuf), "%s(Vnode=%s)", Namech[0] ? " " : "",
+                    print_kptr((KA_T)so.so_ux_bound_vp, (char *)NULL, 0));
+                len = (int)strlen(ubuf);
+                if (len <= (Namechl - nl - 1)) {
+                    (void)snpf(&Namech[nl], Namechl - nl, "%s", ubuf);
+                    nl += len;
+                }
+            }
+        }
+#    endif     /* solaris>=110000 */
+
+        break;
+
+#endif /* solaris>=20600 */
+
+    case N_SPEC:
+
+#if solaris < 100000
+        if (((Ntype = vty) == N_STREAM) && so_st) {
+            if (Funix)
+                Lf->sf |= SELUNX;
+            unix_sock = 1;
+            if (so_ad[0]) {
+                if (sdp) {
+                    if (vfs) {
+                        dev = vfs->dev;
+                        devs = 1;
+                    }
+                    rdev = sdp->rdev;
+                    rdevs = 1;
+                    Lf->inode = (INODETYPE)sdp->inode;
+                    Lf->inp_ty = 1;
+                    (void)snpf(ubuf, sizeof(ubuf), "(%s%s%s)",
+                               print_kptr(so_ad[0], (char *)NULL, 0),
+                               so_ad[1] ? "->" : "",
+                               so_ad[1]
+                                   ? print_kptr(so_ad[1], tbuf, sizeof(tbuf))
+                                   : "");
+                } else {
+                    enter_dev_ch(print_kptr(so_ad[0], (char *)NULL, 0));
+                    if (so_ad[1])
+                        (void)snpf(ubuf, sizeof(ubuf), "(->%s)",
+                                   print_kptr(so_ad[1], (char *)NULL, 0));
+                }
+                if (!Lf->nma &&
+                    (Lf->nma = (char *)malloc((int)strlen(ubuf) + 1))) {
+                    (void)snpf(Lf->nma, (int)strlen(ubuf) + 1, "%s", ubuf);
+                }
+            } else if (soso.lux_dev.addr.tu_addr.ino) {
+                if (vfs) {
+                    dev = vfs->dev;
+                    devs = 1;
+                }
+                rdev = soso.lux_dev.addr.tu_addr.dev;
+                rdevs = 1;
+            } else {
+                int dc, dl, dr;
+
+#    if solaris < 20400
+                dl = (soso.lux_dev.addr.tu_addr.dev >> 16) & 0xffff;
+                dr = (soso.rux_dev.addr.tu_addr.dev >> 16) & 0xffff;
+#    else  /* solaris>=20400 */
+                dl = soso.lux_dev.addr.tu_addr.dev & 0xffff;
+                dr = soso.rux_dev.addr.tu_addr.dev & 0xffff;
+#    endif /* solaris<20400 */
+
+                dc = (dl << 16) | dr;
+                enter_dev_ch(print_kptr((KA_T)dc, (char *)NULL, 0));
+                devs = 0;
+            }
+            if (soso.laddr.buf && soso.laddr.len == sizeof(ua)) {
+                if (kread(ctx, (KA_T)soso.laddr.buf, (char *)&ua, sizeof(ua)) ==
+                    0) {
+                    ua.sun_path[sizeof(ua.sun_path) - 1] = '\0';
+                    if (ua.sun_path[0]) {
+                        if (Sfile &&
+                            is_file_named(ctx, ua.sun_path, Ntype, type, 0))
+                            Lf->sf |= SELNM;
+                        len = (int)strlen(ua.sun_path);
+                        nl = (int)strlen(Namech);
+                        sepl = Namech[0] ? 2 : 0;
+                        if (len > (Namechl - nl - sepl - 1))
+                            len = Namechl - nl - sepl - 1;
+                        if (len > 0) {
+                            ua.sun_path[len] = '\0';
+                            (void)snpf(&Namech[nl], Namechl - nl, "%s%s",
+                                       sepl ? "->" : "", ua.sun_path);
+                        }
+                    }
+                }
+            }
+        } else
+#endif /* solaris<100000 */
+
+        {
+            if (vfs) {
+                dev = vfs->dev;
+                devs = 1;
+            }
+            rdev = s.s_dev;
+            rdevs = 1;
+        }
+        break;
+    case N_STREAM:
+        if (vfs) {
+            dev = vfs->dev;
+            devs = 1;
+        }
+        rdev = s.s_dev;
+        rdevs = 1;
+        break;
+    case N_TMP:
+        dev = t.tn_attr.va_fsid;
+        devs = 1;
+        break;
+
+#if defined(HASVXFS)
+    case N_VXFS:
+        dev = vx.dev;
+        devs = vx.dev_def;
+        if ((v->v_type == VCHR) || (v->v_type == VBLK)) {
+            rdev = vx.rdev;
+            rdevs = vx.rdev_def;
+        }
+        break;
+#endif /* defined(HASVXFS) */
+
+#if defined(HAS_ZFS)
+    case N_ZFS:
+        if (zns) {
+            if (!read_nzvfs(ctx, (KA_T)v->v_data, (KA_T)zn.z_zfsvfs, &zvfs) &&
+                zvfs.z_vfs &&
+                !kread(ctx, (KA_T)zvfs.z_vfs, (char *)&zgvfs, sizeof(zgvfs))) {
+                dev = zgvfs.vfs_dev;
+                devs = 1;
+            }
+        }
+        if ((v->v_type == VCHR) || (v->v_type == VBLK)) {
+            rdev = v->v_rdev;
+            rdevs = 1;
+        }
+        break;
+#endif /* defined(HAS_ZFS) */
+
+    default:
+        if (ins) {
+            dev = i.i_dev;
+            devs = 1;
+        } else if (nns) {
+            dev = nn.nm_vattr.va_fsid;
+            devs = 1;
+        } else if (vfs) {
+            dev = vfs->dev;
+            devs = 1;
+        }
+        if ((v->v_type == VCHR) || (v->v_type == VBLK)) {
+            rdev = v->v_rdev;
+            rdevs = 1;
+        }
+    }
+    type = v->v_type;
+    if (devs && vfs && !vfs->dir) {
+        (void)completevfs(ctx, vfs, &dev);
+
+#if defined(HAS_AFS)
+        if (vfs->dir && (Ntype == N_AFS || vty == N_AFS) && !AFSVfsp)
+            AFSVfsp = (KA_T)v->v_vfsp;
+#endif /* defined(HAS_AFS) */
+    }
+    /*
+     * Obtain the inode number.
+     */
+    switch (vty) {
+
+#if defined(HAS_AFS)
+    case N_AFS:
+        if (an.ino_st) {
+            Lf->inode = (INODETYPE)an.inode;
+            Lf->inp_ty = 1;
+        }
+        break;
+#endif /* defined(HAS_AFS) */
+
+#if solaris >= 20500
+    case N_AUTO:
+
+#    if solaris < 20600
+        Lf->inode = (INODETYPE)au.an_nodeid;
+#    else  /* solaris>=20600 */
+        Lf->inode = (INODETYPE)fnn.fn_nodeid;
+#    endif /* solaris<20600 */
+
+        Lf->inp_ty = 1;
+        break;
+
+#    if solaris >= 100000
+    case N_DEV:
+        if (dvs) {
+            Lf->inode = (INODETYPE)dv.dv_ino;
+            Lf->inp_ty = 1;
+        }
+        break;
+#    endif /* solaris>=100000 */
+
+    case N_DOOR:
+        if (nns && (Lf->inode = (INODETYPE)nn.nm_vattr.va_nodeid)) {
+            Lf->inp_ty = 1;
+            break;
+        }
+        if (dns) {
+            if ((Lf->inode = (INODETYPE)dn.door_index))
+                Lf->inp_ty = 1;
+        }
+        break;
+#endif /* solaris>=20500 */
+
+#if defined(HASCACHEFS)
+    case N_CACHE:
+        Lf->inode = (INODETYPE)cn.c_fileno;
+        Lf->inp_ty = 1;
+        break;
+#endif /* defined(HASCACHEFS) */
+
+#if solaris >= 100000
+    case N_CTFSADIR:
+    case N_CTFSBUND:
+    case N_CTFSCDIR:
+    case N_CTFSCTL:
+    case N_CTFSEVT:
+    case N_CTFSLATE:
+    case N_CTFSROOT:
+    case N_CTFSSTAT:
+    case N_CTFSSYM:
+    case N_CTFSTDIR:
+    case N_CTFSTMPL:
+        /* Method of computing CTFS inode not known. */
+        break;
+#endif /* solaris>=10000 */
+
+    case N_FD:
+        if (v->v_type == VDIR)
+            Lf->inode = (INODETYPE)2;
+        else
+            Lf->inode = (INODETYPE)(GET_MIN_DEV(v->v_rdev) * 100);
+        Lf->inp_ty = 1;
+        break;
+    case N_HSFS:
+        Lf->inode = (INODETYPE)h.hs_nodeid;
+        Lf->inp_ty = 1;
+        break;
+
+    case N_MNT:
+
+#if defined(HASFSINO)
+        if (vfs) {
+            Lf->inode = vfs->fs_ino;
+            Lf->inp_ty = 1;
+        }
+#endif /* defined(HASFSINO) */
+
+        break;
+    case N_MVFS:
+        Lf->inode = (INODETYPE)m.m_ino;
+        Lf->inp_ty = 1;
+        break;
+    case N_NFS:
+        Lf->inode = (INODETYPE)r.r_attr.va_nodeid;
+        Lf->inp_ty = 1;
+        break;
+
+#if solaris >= 100000
+    case N_NFS4:
+        Lf->inode = (INODETYPE)r4.r_attr.va_nodeid;
+        Lf->inp_ty = 1;
+        break;
+#endif /* solaris>=100000 */
+
+    case N_NM:
+        Lf->inode = (INODETYPE)nn.nm_vattr.va_nodeid;
+        Lf->inp_ty = 1;
+        break;
+
+#if defined(HASPROCFS)
+    case N_PROC:
+
+        /*
+         * The proc file system inode number is defined when the
+         * prnode is read.
+         */
+        break;
+#endif /* defined(HASPROCFS) */
+
+    case N_PCFS:
+        if (kvs && kv.vfs_data &&
+            !kread(ctx, (KA_T)kv.vfs_data, (char *)&pcfs, sizeof(pcfs))) {
+
+#if solaris >= 70000
+#    if defined(HAS_PC_DIRENTPERSEC)
+            Lf->inode = (INODETYPE)pc_makenodeid(
+                pc.pc_eblkno, pc.pc_eoffset, pc.pc_entry.pcd_attr,
+                IS_FAT32(&pcfs)
+                    ? ltohs(pc.pc_entry.pcd_scluster_lo) |
+                          (ltohs(pc.pc_entry.un.pcd_scluster_hi) << 16)
+                    : ltohs(pc.pc_entry.pcd_scluster_lo),
+                pc_direntpersec(&pcfs));
+#    else  /* !defined(HAS_PC_DIRENTPERSEC) */
+            Lf->inode = (INODETYPE)pc_makenodeid(
+                pc.pc_eblkno, pc.pc_eoffset, pc.pc_entry.pcd_attr,
+                IS_FAT32(&pcfs)
+                    ? ltohs(pc.pc_entry.pcd_scluster_lo) |
+                          (ltohs(pc.pc_entry.un.pcd_scluster_hi) << 16)
+                    : ltohs(pc.pc_entry.pcd_scluster_lo),
+                pcfs.pcfs_entps);
+#    endif /* defined(HAS_PC_DIRENTPERSEC) */
+#else      /* solaris<70000 */
+            Lf->inode = (INODETYPE)pc_makenodeid(pc.pc_eblkno, pc.pc_eoffset,
+                                                 &pc.pc_entry, pcfs.pcfs_entps);
+#endif     /* solaris>=70000 */
+
+            Lf->inp_ty = 1;
+        }
+        break;
+
+    case N_REGLR:
+        if (nns) {
+            if ((Lf->inode = (INODETYPE)nn.nm_vattr.va_nodeid))
+                Lf->inp_ty = 1;
+        } else if (ins) {
+            if ((Lf->inode = (INODETYPE)i.i_number))
+                Lf->inp_ty = 1;
+        }
+        break;
+    case N_SAMFS:
+        break; /* No more SAM-FS information is available. */
+
+#if solaris >= 110000
+    case N_SDEV:
+        if (sdns) {
+            Lf->inode = (INODETYPE)sdva.va_nodeid;
+            Lf->inp_ty = 1;
+        }
+        break;
+#endif /* solaris>=110000 */
+
+    case N_SHARED:
+        (void)snpf(Lf->iproto, sizeof(Lf->iproto), "SHARED");
+        Lf->inp_ty = 2;
+        break;
+    case N_STREAM:
+
+#if solaris < 100000
+        if (so_st && soso.lux_dev.addr.tu_addr.ino) {
+            if (Lf->inp_ty) {
+                nl = Lf->nma ? (int)strlen(Lf->nma) : 0;
+                (void)snpf(ubuf, sizeof(ubuf), "%s(Inode=%lu)", nl ? " " : "",
+                           (unsigned long)soso.lux_dev.addr.tu_addr.ino);
+                len = nl + (int)strlen(ubuf) + 1;
+                if (Lf->nma)
+                    Lf->nma = (char *)realloc(Lf->nma, len);
+                else
+                    Lf->nma = (char *)malloc(len);
+                if (Lf->nma)
+                    (void)snpf(&Lf->nma[nl], len - nl, "%s", ubuf);
+            } else {
+                Lf->inode = (INODETYPE)soso.lux_dev.addr.tu_addr.ino;
+                Lf->inp_ty = 1;
+            }
+        }
+#endif /* solaris<100000 */
+
+        break;
+    case N_TMP:
+        Lf->inode = (INODETYPE)t.tn_attr.va_nodeid;
+        Lf->inp_ty = 1;
+        break;
+
+#if defined(HASVXFS)
+    case N_VXFS:
+        if (vx.ino_def) {
+            Lf->inode = (INODETYPE)vx.ino;
+            Lf->inp_ty = 1;
+        } else if (type == VCHR)
+            pnl = 1;
+        break;
+#endif /* defined(HASVXFS) */
+
+#if defined(HAS_ZFS)
+    case N_ZFS:
+        if (zns) {
+            Lf->inode = (INODETYPE)zn.z_id;
+            Lf->inp_ty = 1;
+        }
+        break;
+#endif /* defined(HAS_ZFS) */
+    }
+    /*
+     * Obtain the file size.
+     */
+    switch (Ntype) {
+
+#if defined(HAS_AFS)
+    case N_AFS:
+        Lf->sz = (SZOFFTYPE)an.size;
+        Lf->sz_def = 1;
+        break;
+#endif /* defined(HAS_AFS) */
+
+#if solaris >= 20500
+    case N_AUTO:
+
+#    if solaris < 20600
+        Lf->sz = (SZOFFTYPE)au.an_size;
+#    else  /* solaris >=20600 */
+        Lf->sz = (SZOFFTYPE)fnn.fn_size;
+#    endif /* solaris < 20600 */
+
+        Lf->sz_def = 1;
+        break;
+#endif /* solaris>=20500 */
+
+#if defined(HASCACHEFS)
+    case N_CACHE:
+        Lf->sz = (SZOFFTYPE)cn.c_size;
+        Lf->sz_def = 1;
+        break;
+#endif /* defined(HASCACHEFS) */
+
+#if solaris >= 100000
+    case N_CTFSADIR:
+    case N_CTFSBUND:
+    case N_CTFSCDIR:
+    case N_CTFSCTL:
+    case N_CTFSEVT:
+    case N_CTFSLATE:
+    case N_CTFSROOT:
+    case N_CTFSSTAT:
+    case N_CTFSSYM:
+    case N_CTFSTDIR:
+    case N_CTFSTMPL:
+        /* Method of computing CTFS size not known. */
+        break;
+#endif /* solaris>=100000 */
+
+    case N_FD:
+        if (v->v_type == VDIR)
+            Lf->sz = (Unof + 2) * 16;
+        else
+            Lf->sz = (unsigned long)0;
+        Lf->sz_def = 1;
+        break;
+
+#if solaris >= 20600
+    case N_SOCK:
+        break;
+#endif /* solaris>=20600 */
+
+    case N_HSFS:
+        Lf->sz = (SZOFFTYPE)h.hs_dirent.ext_size;
+        Lf->sz_def = 1;
+        break;
+    case N_NM:
+        Lf->sz = (SZOFFTYPE)nn.nm_vattr.va_size;
+        Lf->sz_def = 1;
+        break;
+
+#if solaris >= 100000
+    case N_DEV:
+        break;
+#endif /* solaris>=100000 */
+
+    case N_DOOR:
+    case N_FIFO:
+        break;
+    case N_MNT:
+
+#if defined(CVFS_SZSAVE)
+        if (vfs) {
+            Lf->sz = (SZOFFTYPE)vfs->size;
+            Lf->sz_def = 1;
+        } else
+#endif /* defined(CVFS_SZSAVE) */
+
+            break;
+    case N_MVFS:
+        /* The location of file size isn't known. */
+        break;
+    case N_NFS:
+        if (!(type == VCHR || type == VBLK)) {
+            Lf->sz = (SZOFFTYPE)r.r_size;
+            Lf->sz_def = 1;
+        }
+        break;
+
+#if solaris >= 100000
+    case N_NFS4:
+        if (!(type == VCHR || type == VBLK)) {
+            Lf->sz = (SZOFFTYPE)r4.r_size;
+            Lf->sz_def = 1;
+        }
+        break;
+#endif /* solaris>=100000 */
+
+    case N_PCFS:
+        Lf->sz = (SZOFFTYPE)pc.pc_size;
+        Lf->sz_def = 1;
+        break;
+
+#if solaris >= 100000
+    case N_PORT:
+        Lf->sz = (SZOFFTYPE)pn.port_curr;
+        Lf->sz_def = 1;
+        break;
+#endif /* solaris>=100000 */
+
+#if defined(HASPROCFS)
+    case N_PROC:
+
+        /*
+         * The proc file system size is defined when the
+         * prnode is read.
+         */
+        break;
+#endif /* defined(HASPROCFS) */
+
+    case N_REGLR:
+        if (type == VREG || type == VDIR) {
+            if (ins | nns) {
+                Lf->sz = (SZOFFTYPE)(nns ? nn.nm_vattr.va_size : i.i_size);
+                Lf->sz_def = 1;
+            }
+        }
+        break;
+
+#if solaris >= 110000
+    case N_SDEV:
+        if (sdns) {
+            if (type == VREG || type == VDIR) {
+                Lf->sz = (SZOFFTYPE)sdva.va_size;
+                Lf->sz_def = 1;
+            }
+        }
+        break;
+#endif /* solaris>=110000 */
+
+    case N_SAMFS:
+        break; /* No more SAM-FS information is available. */
+    case N_SHARED:
+        break; /* No more sharedfs information is available. */
+    case N_STREAM:
+        break;
+    case N_TMP:
+        Lf->sz = (SZOFFTYPE)t.tn_attr.va_size;
+        Lf->sz_def = 1;
+        break;
+
+#if defined(HASVXFS)
+    case N_VXFS:
+        if (type == VREG || type == VDIR) {
+            Lf->sz = (SZOFFTYPE)vx.sz;
+            Lf->sz_def = vx.sz_def;
+        }
+        break;
+#endif /* defined(HASVXFS) */
+
+#if defined(HAS_ZFS)
+    case N_ZFS:
+        if (zns) {
+            if (type == VREG || type == VDIR) {
+                Lf->sz = (SZOFFTYPE)zn.z_size;
+                Lf->sz_def = 1;
+            }
+        }
+        break;
+#endif /* defined(HAS_ZFS) */
+    }
+    /*
+     * Record link count.
+     */
+
+    switch (Ntype) {
+
+#if defined(HAS_AFS)
+    case N_AFS:
+        Lf->nlink = an.nlink;
+        Lf->nlink_def = an.nlink_st;
+        break;
+#endif /* defined(HAS_AFS) */
+
+#if solaris >= 20500
+    case N_AUTO:
+        break;
+
+#    if defined(HASCACHEFS)
+    case N_CACHE:
+        Lf->nlink = (long)cn.c_attr.va_nlink;
+        Lf->nlink_def = 1;
+        break;
+#    endif /* defined(HASCACHEFS) */
+
+#endif /* solaris>=20500 */
+
+#if solaris >= 100000
+    case N_CTFSADIR:
+    case N_CTFSBUND:
+    case N_CTFSCDIR:
+    case N_CTFSCTL:
+    case N_CTFSEVT:
+    case N_CTFSLATE:
+    case N_CTFSROOT:
+    case N_CTFSSTAT:
+    case N_CTFSSYM:
+    case N_CTFSTDIR:
+    case N_CTFSTMPL:
+        /* Method of computing CTFS link count not known. */
+        break;
+#endif /* solaris>=100000 */
+
+    case N_FD:
+        Lf->nlink = (v->v_type == VDIR) ? 2 : 1;
+        Lf->nlink_def = 1;
+        break;
+
+#if solaris >= 20600
+    case N_SOCK: /* no link count */
+        break;
+#endif /* solaris>=20600 */
+
+    case N_HSFS:
+        Lf->nlink = (long)h.hs_dirent.nlink;
+        Lf->nlink_def = 1;
+        break;
+    case N_NM:
+        Lf->nlink = (long)nn.nm_vattr.va_nlink;
+        Lf->nlink_def = 1;
+        break;
+
+#if solaris >= 100000
+    case N_DEV:
+        if (dvs) {
+            Lf->nlink = (long)dv.dv_nlink;
+            Lf->nlink_def = 1;
+        }
+        break;
+#endif /* solaris>=100000 */
+
+    case N_DOOR:
+        Lf->nlink = (long)v->v_count;
+        Lf->nlink_def = 1;
+        break;
+    case N_FIFO:
+        break;
+    case N_MNT:
+
+#if defined(CVFS_NLKSAVE)
+        if (vfs) {
+            Lf->nlink = (long)vfs->nlink;
+            Lf->nlink_def = 1;
+        }
+#endif /* defined(CVFS_NLKSAVE) */
+
+        break;
+    case N_MVFS: /* no link count */
+        break;
+    case N_NFS:
+        Lf->nlink = (long)r.r_attr.va_nlink;
+        Lf->nlink_def = 1;
+        break;
+
+#if solaris >= 100000
+    case N_NFS4:
+        Lf->nlink = (long)r4.r_attr.va_nlink;
+        Lf->nlink_def = 1;
+        break;
+#endif /* solaris>=100000 */
+
+    case N_PCFS:
+        break;
+
+#if defined(HASPROCFS)
+    case N_PROC:
+        break;
+#endif /* defined(HASPROCFS) */
+
+    case N_REGLR:
+        if (ins) {
+            Lf->nlink = (long)i.i_nlink;
+            Lf->nlink_def = 1;
+        }
+        break;
+    case N_SAMFS:
+        break; /* No more SAM-FS information is available. */
+
+#if solaris >= 110000
+    case N_SDEV:
+        if (sdns) {
+            Lf->nlink = (long)sdva.va_nlink;
+            Lf->nlink_def = 1;
+        }
+        break;
+#endif /* solaris>=110000 */
+
+    case N_SHARED:
+        break; /* No more sharedfs information is available. */
+    case N_STREAM:
+        break;
+    case N_TMP:
+        Lf->nlink = (long)t.tn_attr.va_nlink;
+        Lf->nlink_def = 1;
+        break;
+
+#if defined(HASVXFS)
+    case N_VXFS:
+        Lf->nlink = vx.nl;
+        Lf->nlink_def = vx.nl_def;
+        break;
+#endif /* defined(HASVXFS) */
+
+#if defined(HAS_ZFS)
+    case N_ZFS:
+        if (zns) {
+            Lf->nlink = (long)MIN(zn.z_links, UINT32_MAX);
+            Lf->nlink_def = 1;
+        }
+        break;
+#endif /* defined(HAS_ZFS) */
+    }
+    if (Nlink && Lf->nlink_def && (Lf->nlink < Nlink))
+        Lf->sf |= SELNLINK;
+
+#if defined(HASVXFS)
+        /*
+         * Record a VxFS file.
+         */
+
+#    if defined(HASVXFSDNLC)
+    Lf->is_vxfs = (Ntype == N_VXFS) ? 1 : 0;
+#    endif /* defined(HASVXFSDNLC) */
+#endif     /* defined(HASVXFS) */
+
+    /*
+     * Record an NFS selection.
+     */
+    if (Fnfs) {
+        if ((Ntype == N_NFS) || (Ntype == N_NFS4))
+            Lf->sf |= SELNFS;
+    }
+
+#if solaris >= 20500
+    /*
+     * If this is a Solaris 2.5 and greater autofs entry, save the autonode name
+     * (less than Solaris 2.6) or fnnode name (Solaris 2.6 and greater).
+     */
+    if (Ntype == N_AUTO && !Namech[0]) {
+
+#    if solaris < 20600
+        if (au.an_name[0])
+            (void)snpf(Namech, Namechl - 1, "%s", au.an_name);
+        Namech[Namechl - 1] = '\0';
+#    else  /* solaris>=20600 */
+        if (fnn.fn_name && (len = fnn.fn_namelen) > 0 && len < (Namechl - 1)) {
+            if (kread(ctx, (KA_T)fnn.fn_name, Namech, len))
+                Namech[0] = '\0';
+            else
+                Namech[len] = '\0';
+        }
+#    endif /* solaris<20600 */
+    }
+    /*
+     * If there is no local virtual file system pointer, or if its directory and
+     * file system names are NULL, and if there is a namenode, and if we're
+     * using the device number from it, see if its nm_mountpt vnode pointer
+     * leads to a local virtual file system structure with non-NULL directory
+     * and file system names.  If it does, switch to that local virtual file
+     * system pointer.
+     */
+    if (nns && (!vfs || (!vfs->dir && !vfs->fsname)) && devs &&
+        (dev == nn.nm_vattr.va_fsid) && nn.nm_mountpt) {
+        if (!readvnode(ctx, (KA_T)nn.nm_mountpt, &fv) && fv.v_vfsp) {
+            if ((nvfs = readvfs(ctx, (KA_T)fv.v_vfsp, (struct vfs *)NULL,
+                                nn.nm_filevp)) &&
+                !nvfs->dir) {
+                (void)completevfs(ctx, nvfs, &dev);
+            }
+
+#    if defined(HASNCACHE)
+            if (nvfs && nvfs->dir && nvfs->fsname) {
+                fa = (char *)NULL;
+                vfs = nvfs;
+            }
+#    endif /* defined(HASNCACHE) */
+        }
+    }
+
+#    if defined(HASNCACHE)
+    /*
+     * If there's a namenode and its device and node number match this one,
+     * use the nm_mountpt's address for name cache lookups.
+     */
+    if (nns && devs && (dev == nn.nm_vattr.va_fsid) && (Lf->inp_ty == 1) &&
+        (Lf->inode == (INODETYPE)nn.nm_vattr.va_nodeid))
+        Lf->na = (KA_T)nn.nm_mountpt;
+#    endif /* defined(HASNCACHE) */
+#endif     /* solaris>=20500 */
+
+    /*
+     * Save the file system names.
+     */
+    if (vfs) {
+        Lf->fsdir = vfs->dir;
+        Lf->fsdev = vfs->fsname;
+
+#if defined(HASMNTSTAT)
+        Lf->mnt_stat = vfs->mnt_stat;
+#endif /* defined(HASMNTSTAT) */
+
+        if (!Lf->fsdir && !Lf->fsdev && kvs && fxs) {
+
+            /*
+             * The file system names are unknown.
+             *
+             * Set the file system device to the file system type and clear
+             * the doubtful device numbers.
+             */
+            Lf->fsdev = Fsinfo[fx];
+            devs = 0;
+            rdevs = 0;
+        }
+
+#if defined(HASFSINO)
+        else
+            Lf->fs_ino = vfs->fs_ino;
+#endif /* defined(HASFSINO) */
+    }
+    /*
+     * Save the device numbers, and their states.
+     *
+     * Format the vnode type, and possibly the device name.
+     */
+    switch (type) {
+
+    case VNON:
+        Lf->type = LSOF_FILE_VNODE_VNON;
+        Lf->dev = dev;
+        Lf->dev_def = devs;
+        Lf->rdev = rdev;
+        Lf->rdev_def = rdevs;
+        break;
+    case VREG:
+    case VDIR:
+        Lf->type = (type == VREG) ? LSOF_FILE_VNODE_VREG : LSOF_FILE_VNODE_VDIR;
+        Lf->dev = dev;
+        Lf->dev_def = devs;
+        Lf->rdev = rdev;
+        Lf->rdev_def = rdevs;
+        break;
+    case VBLK:
+        Lf->type = LSOF_FILE_VNODE_VBLK;
+        Lf->dev = dev;
+        Lf->dev_def = devs;
+        Lf->rdev = rdev;
+        Lf->rdev_def = rdevs;
+        Ntype = N_BLK;
+        break;
+    case VCHR:
+        Lf->dev = dev;
+        Lf->dev_def = devs;
+        Lf->rdev = rdev;
+        Lf->rdev_def = rdevs;
+        if (unix_sock) {
+            Lf->type = LSOF_FILE_UNIX;
+            break;
+        }
+        Lf->type = LSOF_FILE_VNODE_VCHR;
+        if (Lf->is_stream == 0 && Lf->is_com == 0)
+            Ntype = N_CHR;
+        break;
+
+#if solaris >= 20500
+    case VDOOR:
+        Lf->dev = dev;
+        Lf->dev_def = devs;
+        Lf->rdev = rdev;
+        Lf->rdev_def = rdevs;
+        Lf->type = LSOF_FILE_VNODE_VDOOR;
+        if (dns)
+            (void)idoorkeep(ctx, &dn);
+        break;
+#endif /* solaris>=20500 */
+
+    case VLNK:
+        Lf->type = LSOF_FILE_VNODE_VLNK;
+        Lf->dev = dev;
+        Lf->dev_def = devs;
+        Lf->rdev = rdev;
+        Lf->rdev_def = rdevs;
+        break;
+
+#if solaris >= 100000
+    case VPORT:
+        Lf->type = LSOF_FILE_VNODE_VPORT;
+        Lf->dev = dev;
+        Lf->dev_def = devs;
+        Lf->rdev = rdev;
+        Lf->rdev_def = rdevs;
+        break;
+#endif /* solaris>=100000 */
+
+#if solaris >= 20600
+    case VPROC:
+
+        /*
+         * The proc file system type is defined when the prnode is read.
+         */
+        Lf->dev = dev;
+        Lf->dev_def = devs;
+        Lf->rdev = rdev;
+        Lf->rdev_def = rdevs;
+        Lf->type = LSOF_FILE_NONE;
+        break;
+#endif /* solaris>=20600 */
+
+#if defined(HAS_VSOCK)
+    case VSOCK:
+
+#    if solaris >= 20600
+        if (so.so_family == AF_UNIX) {
+            Lf->type = LSOF_FILE_UNIX;
+            if (Funix)
+                Lf->sf |= SELUNX;
+        } else {
+            if (so.so_family == AF_INET) {
+
+#        if defined(HASIPv6)
+                Lf->type = LSOF_FILE_IPV4;
+#        else  /* !defined(HASIPv6) */
+                Lf->type = LSOF_FILE_INET;
+#        endif /* defined(HASIPv6) */
+
+                (void)snpf(Namech, Namechl - 1, printsockty(so.so_type));
+                Namech[Namechl - 1] = '\0';
+                if (TcpStIn || UdpStIn || TcpStXn || UdpStXn)
+                    Lf->sf |= SELEXCLF;
+                else if (Fnet && (FnetTy != 6))
+                    Lf->sf |= SELNET;
+            }
+
+#        if defined(HASIPv6)
+            else if (so.so_family == AF_INET6) {
+                Lf->type = LSOF_FILE_IPV6;
+                (void)snpf(Namech, Namechl - 1, printsockty(so.so_type));
+                Namech[Namechl - 1] = '\0';
+                if (TcpStIn || UdpStIn || TcpStXn || UdpStXn)
+                    Lf->sf |= SELEXCLF;
+                else if (Fnet && (FnetTy != 4))
+                    Lf->sf |= SELNET;
+            }
+#        endif /* defined(HASIPv6) */
+
+            else {
+                Lf->type = LSOF_FILE_SOCKET;
+                (void)printunkaf(ctx, so.so_family, 0);
+                ep = endnm(ctx, &sz);
+                (void)snpf(ep, sz, ", %s", printsockty(so.so_type));
+            }
+        }
+#    endif /* solaris>=20600 */
+
+        Lf->dev = dev;
+        Lf->dev_def = devs;
+        Lf->rdev = rdev;
+        Lf->rdev_def = rdevs;
+        break;
+#endif /* defined(HAS_VSOCK) */
+
+    case VBAD:
+        Lf->type = LSOF_FILE_VNODE_VBAD;
+        Lf->dev = dev;
+        Lf->dev_def = devs;
+        Lf->rdev = rdev;
+        Lf->rdev_def = rdevs;
+        break;
+    case VFIFO:
+        Lf->type = LSOF_FILE_VNODE_VFIFO;
+        if (!Lf->dev_ch || Lf->dev_ch[0] == '\0') {
+            Lf->dev = dev;
+            Lf->dev_def = devs;
+            Lf->rdev = rdev;
+            Lf->rdev_def = rdevs;
+        }
+        break;
+    default:
+        Lf->dev = dev;
+        Lf->dev_def = devs;
+        Lf->rdev = rdev;
+        Lf->rdev_def = rdevs;
+        Lf->type = LSOF_FILE_UNKNOWN_RAW;
+        Lf->unknown_file_type_number = type;
+    }
+    Lf->ntype = Ntype;
+    /*
+     * If this a Solaris common vnode/snode void some information.
+     */
+    if (Lf->is_com)
+        Lf->sz_def = Lf->inp_ty = 0;
+    /*
+     * If a file attach description remains, put it in the NAME column addition.
+     */
+    if (fa)
+        (void)add_nma(ctx, fa, fal);
+
+#if defined(HASBLKDEV)
+    /*
+     * If this is a VBLK file and it's missing an inode number, try to
+     * supply one.
+     */
+    if ((Lf->inp_ty == 0) && (type == VBLK))
+        find_bl_ino(ctx);
+#endif /* defined(HASBLKDEV) */
+
+    /*
+     * If this is a VCHR file and it's missing an inode number, try to
+     * supply one.
+     */
+    if ((Lf->inp_ty == 0) && (type == VCHR)) {
+        find_ch_ino(ctx);
+        /*
+         * If the VCHR inode number still isn't known and this is a COMMON
+         * vnode file or a stream, or if a pseudo node ID lookup has been
+         * requested, see if an inode number can be derived from a pseudo
+         * or clone device node.
+         *
+         * If it can, save the pseudo or clone device for temporary
+         * use when searching for a match with a named file argument.
+         */
+        if ((Lf->inp_ty == 0) && (Lf->is_com || Lf->is_stream || pnl) &&
+            (Clone || Pseudo)) {
+            if (!sdp) {
+                if (rdevs || devs) {
+                    if (Lf->is_stream && !pnl)
+                        sdp = finddev(ctx, devs ? &dev : &DevDev,
+                                      rdevs ? &rdev : &Lf->dev, LOOKDEV_CLONE);
+                    else
+                        sdp = finddev(ctx, devs ? &dev : &DevDev,
+                                      rdevs ? &rdev : &Lf->dev, LOOKDEV_PSEUDO);
+                    if (!sdp)
+                        sdp = finddev(ctx, devs ? &dev : &DevDev,
+                                      rdevs ? &rdev : &Lf->dev, LOOKDEV_ALL);
+                    if (sdp) {
+                        if (!rdevs) {
+                            Lf->rdev = Lf->dev;
+                            Lf->rdev_def = rdevs = 1;
+                        }
+                        if (!devs) {
+                            Lf->dev = DevDev;
+                            devs = Lf->dev_def = 1;
+                        }
+                    }
+                }
+            } else {
+
+                /*
+                 * A local device structure has been located.  Make sure
+                 * that it's accompanied by device settings.
+                 */
+                if (!devs && vfs) {
+                    dev = Lf->dev = vfs->dev;
+                    devs = Lf->dev_def = 1;
+                }
+                if (!rdevs) {
+                    Lf->rdev = rdev = sdp->rdev;
+                    Lf->rdev_def = rdevs = 1;
+                }
+            }
+            if (sdp) {
+
+                /*
+                 * Process the local device information.
+                 */
+                trdev = sdp->rdev;
+                Lf->inode = sdp->inode;
+                Lf->inp_ty = trdevs = 1;
+                if (!Namech[0] || Lf->is_com) {
+                    (void)snpf(Namech, Namechl - 1, "%s", sdp->name);
+                    Namech[Namechl - 1] = '\0';
+                }
+                if (Lf->is_com && !Lf->nma) {
+                    len = (int)strlen("(COMMON)") + 1;
+                    if (!(Lf->nma = (char *)malloc(len))) {
+                        fd_to_string(Lf->fd_type, Lf->fd_num, fd);
+                        (void)fprintf(
+                            stderr,
+                            "%s: no space for (COMMON): PID %d; FD %s\n", Pn,
+                            Lp->pid, fd);
+                        Error(ctx);
+                    }
+                    (void)snpf(Lf->nma, len, "(COMMON)");
+                }
+            }
+        }
+    }
+    /*
+     * Record stream status.
+     */
+    if (Lf->inp_ty == 0 && Lf->is_stream && strcmp(Lf->iproto, "STR") == 0)
+        Lf->inp_ty = 2;
+        /*
+         * Test for specified file.
+         */
+
+#if defined(HASPROCFS)
+    if (Ntype == N_PROC) {
+        if (Procsrch) {
+            Procfind = 1;
+            Lf->sf |= SELNM;
+        } else {
+            for (pfi = Procfsid; pfi; pfi = pfi->next) {
+                if ((pfi->pid && pfi->pid == pids.pid_id)
+
+#    if defined(HASPINODEN)
+                    || (Lf->inp_ty == 1 && Lf->inode == pfi->inode)
+#    endif /* defined(HASPINODEN) */
+
+                ) {
+                    pfi->f = 1;
+                    if (!Namech[0]) {
+                        (void)snpf(Namech, Namechl - 1, "%s", pfi->nm);
+                        Namech[Namechl - 1] = '\0';
+                    }
+                    Lf->sf |= SELNM;
+                    break;
+                }
+            }
+        }
+    } else
+#endif /* defined(HASPROCFS) */
+
+    {
+        if (Sfile) {
+            if (trdevs) {
+                rdev = Lf->rdev;
+                Lf->rdev = trdev;
+                tdef = Lf->rdev_def;
+                Lf->rdev_def = 1;
+            }
+            if (is_file_named(ctx, NULL, Ntype, type, 1))
+                Lf->sf |= SELNM;
+            if (trdevs) {
+                Lf->rdev = rdev;
+                Lf->rdev_def = tdef;
+            }
+        }
+    }
+    /*
+     * Enter name characters.
+     */
+    if (Namech[0])
+        enter_nm(ctx, Namech);
+}
+
+/*
+ * read_cni() - read common snode information
+ */
+
+static int read_cni(struct lsof_context *ctx, /* context */
+                    struct snode *s,          /* starting snode */
+                    struct vnode *rv,         /* "real" vnode receiver */
+                    struct vnode *v,          /* starting vnode */
+                    struct snode *rs,         /* "real" snode receiver */
+                    struct dev_info *di,      /* dev_info structure receiver */
+                    char *din,                /* device info name receiver */
+                    int dinl)                 /* sizeof(*din) */
+{
+    char tbuf[32];
+
+    if (read_nvn(ctx, (KA_T)v->v_data, (KA_T)s->s_commonvp, rv))
+        return (1);
+    if (read_nsn(ctx, (KA_T)s->s_commonvp, (KA_T)rv->v_data, rs))
+        return (1);
+    *din = '\0';
+    if (rs->s_dip) {
+        if (kread(ctx, (KA_T)rs->s_dip, (char *)di, sizeof(struct dev_info))) {
+            (void)snpf(Namech, Namechl - 1,
+                       "common snode at %s: no dev info: %s",
+                       print_kptr((KA_T)rv->v_data, tbuf, sizeof(tbuf)),
+                       print_kptr((KA_T)rs->s_dip, (char *)NULL, 0));
+            Namech[Namechl - 1] = '\0';
+            enter_nm(ctx, Namech);
+            return (1);
+        }
+        if (di->devi_name &&
+            kread(ctx, (KA_T)di->devi_name, din, dinl - 1) == 0)
+            din[dinl - 1] = '\0';
+    }
+    return (0);
+}
+
+/*
+ * readinode() - read inode
+ */
+
+static int readinode(struct lsof_context *ctx, /* context */
+                     KA_T ia,                  /* inode kernel address */
+                     struct inode *i)          /* inode buffer */
+{
+    if (kread(ctx, (KA_T)ia, (char *)i, sizeof(struct inode))) {
+        (void)snpf(Namech, Namechl - 1, "can't read inode at %s",
+                   print_kptr((KA_T)ia, (char *)NULL, 0));
+        Namech[Namechl - 1] = '\0';
+        enter_nm(ctx, Namech);
+        return (1);
+    }
+    return (0);
+}
+
+#if solaris >= 20500
+/*
+ * read_ndn() - read node's door node
+ */
+
+static int read_ndn(struct lsof_context *ctx, /* context */
+                    KA_T na,                  /* containing vnode's address */
+                    KA_T da,                  /* door node's address */
+                    struct door_node *dn)     /* door node receiver */
+{
+    char tbuf[32];
+
+    if (!da || kread(ctx, (KA_T)da, (char *)dn, sizeof(struct door_node))) {
+        (void)snpf(Namech, Namechl - 1, "vnode at %s: can't read door_node: %s",
+                   print_kptr(na, tbuf, sizeof(tbuf)),
+                   print_kptr(da, (char *)NULL, 0));
+        Namech[Namechl - 1] = '\0';
+        enter_nm(ctx, Namech);
+        return (1);
+    }
+    return (0);
+}
+#endif /* solaris>=20500 */
+
+/*
+ * read_mi() - read stream's module information
+ */
+
+static void read_mi(struct lsof_context *ctx, /* context */
+                    KA_T s,             /* kernel stream pointer address */
+                    dev_t *rdev,        /* raw device pointer */
+                    caddr_t so,         /* so_so return (Solaris) */
+                    int *so_st,         /* so_so status */
+                    KA_T *so_ad,        /* so_so addresses */
+                    struct l_dev **sdp) /* returned device pointer */
+{
+    struct l_dev *dp;
+    int i, j, k, nl;
+    KA_T ka;
+    struct module_info mi;
+    char mn[STRNML];
+    struct stdata sd;
+    struct queue q;
+    struct qinit qi;
+    KA_T qp;
+    /*
+     * If there is no stream pointer, or we can't read the stream head,
+     * return.
+     */
+    if (!s)
+        return;
+    if (kread(ctx, (KA_T)s, (char *)&sd, sizeof(sd))) {
+        (void)snpf(Namech, Namechl - 1, "can't read stream head: %s",
+                   print_kptr(s, (char *)NULL, 0));
+        Namech[Namechl - 1] = '\0';
+        enter_nm(ctx, Namech);
+        return;
+    }
+    /*
+     * Follow the stream head to each of its queue structures, retrieving the
+     * module names from each queue's q_info->qi_minfo->mi_idname chain of
+     * structures.  Separate each additional name from the previous one with
+     * "->".
+     *
+     * Ignore failures to read all but queue structure chain entries.
+     *
+     * Ignore module names that end in "head".
+     */
+    k = 0;
+    Namech[0] = '\0';
+    if (!(dp = finddev(ctx, &DevDev, rdev, LOOKDEV_CLONE)))
+        dp = finddev(ctx, &DevDev, rdev, LOOKDEV_ALL);
+    if (dp) {
+        (void)snpf(Namech, Namechl - 1, "%s", dp->name);
+        Namech[Namechl - 1] = '\0';
+        k = (int)strlen(Namech);
+        *sdp = dp;
+    } else
+        (void)snpf(Lf->iproto, sizeof(Lf->iproto), "STR");
+    nl = sizeof(mn) - 1;
+    mn[nl] = '\0';
+    qp = (KA_T)sd.sd_wrq;
+    for (i = 0; qp && i < 20; i++, qp = (KA_T)q.q_next) {
+        if (!qp || kread(ctx, qp, (char *)&q, sizeof(q)))
+            break;
+        if ((ka = (KA_T)q.q_qinfo) == (KA_T)NULL ||
+            kread(ctx, ka, (char *)&qi, sizeof(qi)))
+            continue;
+        if ((ka = (KA_T)qi.qi_minfo) == (KA_T)NULL ||
+            kread(ctx, ka, (char *)&mi, sizeof(mi)))
+            continue;
+        if ((ka = (KA_T)mi.mi_idname) == (KA_T)NULL || kread(ctx, ka, mn, nl))
+            continue;
+        if ((j = (int)strlen(mn)) < 1)
+            continue;
+        if (j >= 4 && strcmp(&mn[j - 4], "head") == 0)
+            continue;
+
+#if solaris < 100000
+        if (strcmp(mn, "sockmod") == 0) {
+
+            /*
+             * Save the Solaris sockmod device and inode numbers.
+             */
+            if (so) {
+
+                struct so_so s;
+
+                if (!kread(ctx, (KA_T)q.q_ptr, (char *)&s, sizeof(s))) {
+                    if (!(*so_st))
+                        so_ad[0] = (KA_T)q.q_ptr;
+                    else
+                        so_ad[1] = (KA_T)q.q_ptr;
+                    (void)savesockmod(&s, (struct so_so *)so, so_st);
+                }
+            }
+        }
+#endif /* solaris<100000 */
+
+        if (k) {
+            if ((k + 2) > (Namechl - 1))
+                break;
+            (void)snpf(&Namech[k], Namechl - k, "->");
+            k += 2;
+        }
+        if ((k + j) > (Namechl - 1))
+            break;
+        (void)snpf(&Namech[k], Namechl - k, "%s", mn);
+        k += j;
+    }
+}
+
+#if solaris >= 20500
+
+/*
+ * read_nan(na, ca, cn) - read node's autofs node
+ */
+
+static int read_nan(struct lsof_context *ctx, /* context */
+                    KA_T na,                  /* containing node's address */
+                    KA_T aa,                  /* autofs node address */
+
+#    if solaris < 20600
+                    struct autonode *rn) /* autofs node receiver */
+#    else                                /* solaris>=20600 */
+                    struct fnnode *rn) /* autofs node receiver */
+#    endif                               /* solaris<20600 */
+
+{
+    char tbuf[32];
+
+#    if solaris < 20600
+    if (!aa || kread(ctx, (KA_T)aa, (char *)rn, sizeof(struct autonode)))
+#    else  /* solaris>=20600 */
+    if (!aa || kread(ctx, (KA_T)aa, (char *)rn, sizeof(struct fnnode)))
+#    endif /* solaris<20600 */
+
+    {
+        (void)snpf(Namech, Namechl - 1,
+
+#    if solaris < 20600
+                   "node at %s: can't read autonode: %s",
+#    else  /* solaris>=20600 */
+                   "node at %s: can't read fnnode: %s",
+#    endif /* solaris<20600 */
+
+                   print_kptr(na, tbuf, sizeof(tbuf)),
+                   print_kptr(aa, (char *)NULL, 0));
+        Namech[Namechl - 1] = '\0';
+        enter_nm(ctx, Namech);
+        return (1);
+    }
+    return (0);
+}
+#endif /* solaris>=20500 */
+
+#if defined(HASCACHEFS)
+/*
+ * read_ncn(na, ca, cn) - read node's cache node
+ */
+
+static int read_ncn(struct lsof_context *ctx, /* context */
+                    KA_T na,                  /* containing node's address */
+                    KA_T ca,                  /* cache node address */
+                    struct cnode *cn)         /* cache node receiver */
+{
+    char tbuf[32];
+
+    if (!ca || kread(ctx, (KA_T)ca, (char *)cn, sizeof(struct cnode))) {
+        (void)snpf(Namech, Namechl - 1, "node at %s: can't read cnode: %s",
+                   print_kptr(na, tbuf, sizeof(tbuf)),
+                   print_kptr(ca, (char *)NULL, 0));
+        Namech[Namechl - 1] = '\0';
+        enter_nm(ctx, Namech);
+        return (1);
+    }
+    return (0);
+}
+#endif /* defined(HASCACHEFS) */
+
+#if solaris >= 100000
+/*
+ * read_nctfsn(ty, na, ca, cn) - read node's cache node
+ */
+
+static int read_nctfsn(struct lsof_context *ctx, /* context */
+                       int ty,   /* node type -- i.e., N_CTFS* */
+                       KA_T na,  /* containing node's address */
+                       KA_T ca,  /* cache node address */
+                       char *cn) /* CTFS node receiver */
+{
+    char *cp, *nm, tbuf[32];
+    READLEN_T sz;
+
+    switch (ty) {
+    case N_CTFSADIR:
+        nm = "ADIR";
+        sz = (READLEN_T)sizeof(ctfs_adirnode_t);
+        break;
+    case N_CTFSBUND:
+        nm = "BUND";
+        sz = (READLEN_T)sizeof(ctfs_bunode_t);
+        break;
+    case N_CTFSCDIR:
+        nm = "CDIR";
+        sz = (READLEN_T)sizeof(ctfs_cdirnode_t);
+        break;
+    case N_CTFSCTL:
+        nm = "CTL";
+        sz = (READLEN_T)sizeof(ctfs_ctlnode_t);
+        break;
+    case N_CTFSEVT:
+        nm = "EVT";
+        sz = (READLEN_T)sizeof(ctfs_evnode_t);
+        break;
+    case N_CTFSLATE:
+        nm = "LATE";
+        sz = (READLEN_T)sizeof(ctfs_latenode_t);
+        break;
+    case N_CTFSROOT:
+        nm = "ROOT";
+        sz = (READLEN_T)sizeof(ctfs_rootnode_t);
+        break;
+    case N_CTFSSTAT:
+        nm = "STAT";
+        sz = (READLEN_T)sizeof(ctfs_ctlnode_t);
+        break;
+    case N_CTFSSYM:
+        nm = "SYM";
+        sz = (READLEN_T)sizeof(ctfs_symnode_t);
+        break;
+    case N_CTFSTDIR:
+        nm = "TDIR";
+        sz = (READLEN_T)sizeof(ctfs_tdirnode_t);
+        break;
+    case N_CTFSTMPL:
+        nm = "TMPL";
+        sz = (READLEN_T)sizeof(ctfs_tmplnode_t);
+        break;
+    default:
+        (void)snpf(Namech, Namechl - 1, "unknown CTFS node type: %d", ty);
+        Namech[Namechl - 1] = '\0';
+        enter_nm(ctx, Namech);
+        return (1);
+    }
+    if (!ca || kread(ctx, (KA_T)ca, cn, sz)) {
+        (void)snpf(Namech, Namechl - 1,
+                   "node at %s: can't read CTFS %s node: %s",
+                   print_kptr(na, tbuf, sizeof(tbuf)), nm,
+                   print_kptr(ca, (char *)NULL, 0));
+        Namech[Namechl - 1] = '\0';
+        enter_nm(ctx, Namech);
+        return (1);
+    }
+    return (0);
+}
+#endif /* solaris>=100000 */
+
+/*
+ * read_nfn() - read node's fifonode
+ */
+
+static int read_nfn(struct lsof_context *ctx, /* context */
+                    KA_T na,                  /* containing node's address */
+                    KA_T fa,                  /* fifonode address */
+                    struct fifonode *f)       /* fifonode receiver */
+{
+    char tbuf[32];
+
+    if (!fa || readfifonode(ctx, fa, f)) {
+        (void)snpf(Namech, Namechl - 1, "node at %s: can't read fifonode: %s",
+                   print_kptr(na, tbuf, sizeof(tbuf)),
+                   print_kptr(fa, (char *)NULL, 0));
+        Namech[Namechl - 1] = '\0';
+        enter_nm(ctx, Namech);
+        return (1);
+    }
+    return (0);
+}
+
+/*
+ * read_nhn() - read node's High Sierra node
+ */
+
+static int read_nhn(struct lsof_context *ctx, /* context */
+                    KA_T na,                  /* containing node's address */
+                    KA_T ha,                  /* hsnode address */
+                    struct hsnode *h)         /* hsnode receiver */
+{
+    char tbuf[32];
+
+    if (!ha || readhsnode(ctx, ha, h)) {
+        (void)snpf(Namech, Namechl - 1, "node at %s: can't read hsnode: %s",
+                   print_kptr(na, tbuf, sizeof(tbuf)),
+                   print_kptr(ha, (char *)NULL, 0));
+        Namech[Namechl - 1] = '\0';
+        enter_nm(ctx, Namech);
+        return (1);
+    }
+    return (0);
+}
+
+/*
+ * read_nin() - read node's inode
+ */
+
+static int read_nin(struct lsof_context *ctx, /* context */
+                    KA_T na,                  /* containing node's address */
+                    KA_T ia,                  /* kernel inode address */
+                    struct inode *i)          /* inode receiver */
+{
+    char tbuf[32];
+
+    if (!ia || readinode(ctx, ia, i)) {
+        (void)snpf(Namech, Namechl - 1, "node at %s: can't read inode: %s",
+                   print_kptr(na, tbuf, sizeof(tbuf)),
+                   print_kptr(ia, (char *)NULL, 0));
+        Namech[Namechl - 1] = '\0';
+        enter_nm(ctx, Namech);
+        return (1);
+    }
+    return (0);
+}
+
+/*
+ * read_nln(na, la, ln) - read node's loopback node
+ */
+
+static int read_nln(struct lsof_context *ctx, /* context */
+                    KA_T na,                  /* containing node's address */
+                    KA_T la,                  /* loopback node address */
+                    struct lnode *ln)         /* loopback node receiver */
+{
+    char tbuf[32];
+
+    if (!la || kread(ctx, (KA_T)la, (char *)ln, sizeof(struct lnode))) {
+        (void)snpf(Namech, Namechl - 1, "node at %s: can't read lnode: %s",
+                   print_kptr(na, tbuf, sizeof(tbuf)),
+                   print_kptr(la, (char *)NULL, 0));
+        Namech[Namechl - 1] = '\0';
+        enter_nm(ctx, Namech);
+        return (1);
+    }
+    return (0);
+}
+
+/*
+ * read_nnn() - read node's namenode
+ */
+
+static int read_nnn(struct lsof_context *ctx, /* context */
+                    KA_T na,                  /* containing node's address */
+                    KA_T nna,                 /* namenode address */
+                    struct namenode *nn)      /* namenode receiver */
+{
+    char tbuf[32];
+
+    if (!nna || kread(ctx, (KA_T)nna, (char *)nn, sizeof(struct namenode))) {
+        (void)snpf(Namech, Namechl - 1, "node at %s: can't read namenode: %s",
+                   print_kptr(na, tbuf, sizeof(tbuf)),
+                   print_kptr(nna, (char *)NULL, 0));
+        Namech[Namechl - 1] = '\0';
+        enter_nm(ctx, Namech);
+        return (1);
+    }
+    return (0);
+}
+
+/*
+ * read_nmn() - read node's mvfsnode
+ */
+
+static int read_nmn(struct lsof_context *ctx, /* context */
+                    KA_T na,                  /* containing node's address */
+                    KA_T ma,                  /* kernel mvfsnode address */
+                    struct mvfsnode *m)       /* mvfsnode receiver */
+{
+    char tbuf[32];
+
+    if (!ma || kread(ctx, (KA_T)ma, (char *)m, sizeof(struct mvfsnode))) {
+        (void)snpf(Namech, Namechl - 1, "node at %s: can't read mvfsnode: %s",
+                   print_kptr(na, tbuf, sizeof(tbuf)),
+                   print_kptr(ma, (char *)NULL, 0));
+        Namech[Namechl - 1] = '\0';
+        enter_nm(ctx, Namech);
+        return (1);
+    }
+    return (0);
+}
+
+#if defined(HASPROCFS)
+/*
+ * read_npi() - read node's /proc file system information
+ */
+
+static int read_npi(struct lsof_context *ctx, /* context */
+                    KA_T na,                  /* containing node's address */
+                    struct vnode *v,          /* containing vnode */
+                    struct pid *pids)         /* pid structure receiver */
+{
+    struct as as;
+    struct proc p;
+    struct prnode pr;
+    char tbuf[32];
+
+#    if solaris >= 20600
+    prcommon_t pc, ppc;
+    int pcs, ppcs, prpcs, prppcs;
+    struct proc pp;
+    kthread_t thread;
+    pid_t prpid;
+    id_t prtid;
+    char *ty = (char *)NULL;
+#    endif /* solaris>=20600 */
+
+    if (!v->v_data || kread(ctx, (KA_T)v->v_data, (char *)&pr, sizeof(pr))) {
+        (void)snpf(Namech, Namechl - 1, "node at %s: can't read prnode: %s",
+                   print_kptr(na, tbuf, sizeof(tbuf)),
+                   print_kptr((KA_T)v->v_data, (char *)NULL, 0));
+        Namech[Namechl - 1] = '\0';
+        enter_nm(ctx, Namech);
+        return (1);
+    }
+
+#    if solaris < 20600
+    /*
+     * For Solaris < 2.6:
+     * * Read the proc structure, get the process size and PID;
+     * * Return the PID;
+     * * Enter a name, constructed from the file system and PID;
+     * * Enter an inode number, constructed from the PID.
+     */
+    if (!pr.pr_proc) {
+        if (v->v_type == VDIR) {
+            (void)snpf(Namech, Namechl - 1, "/%s", HASPROCFS);
+            Namech[Namechl - 1] = '\0';
+            enter_nm(ctx, Namech);
+            Lf->inode = (INODETYPE)PR_ROOTINO;
+            Lf->inp_ty = 1;
+        } else {
+            (void)snpf(Namech, Namechl - 1, "/%s/", HASPROCFS);
+            Namech[Namechl - 1] = '\0';
+            enter_nm(ctx, Namech);
+            Lf->inp_ty = 0;
+        }
+        return (0);
+    }
+    if (kread(ctx, (KA_T)pr.pr_proc, (char *)&p, sizeof(p))) {
+        (void)snpf(Namech, Namechl - 1, "prnode at %s: can't read proc: %s",
+                   print_kptr((KA_T)v->v_data, tbuf, sizeof(tbuf)),
+                   print_kptr((KA_T)pr.pr_proc, (char *)NULL, 0));
+        Namech[Namechl - 1] = '\0';
+        enter_nm(ctx, Namech);
+        return (1);
+    }
+    if (p.p_as && !kread(ctx, (KA_T)p.p_as, (char *)&as, sizeof(as))) {
+        Lf->sz = (SZOFFTYPE)as.a_size;
+        Lf->sz_def = 1;
+    }
+    if (!p.p_pidp ||
+        kread(ctx, (KA_T)p.p_pidp, (char *)pids, sizeof(struct pid))) {
+        (void)snpf(Namech, Namechl - 1, "proc struct at %s: can't read pid: %s",
+                   print_kptr((KA_T)pr.pr_proc, tbuf, sizeof(tbuf)),
+                   print_kptr((KA_T)p.p_pidp, (char *)NULL, 0));
+        Namech[Namechl - 1] = '\0';
+        enter_nm(ctx, Namech);
+        return (1);
+    }
+    (void)snpf(Namech, Namechl, "/%s/%d", HASPROCFS, (int)pids->pid_id);
+    Namech[Namechl - 1] = '\0';
+    Lf->inode = (INODETYPE)ptoi(pids->pid_id);
+    Lf->inp_ty = 1;
+#    else /* solaris>=20600 */
+    /*
+     * Enter the >= Solaris 2.6 inode number.
+     */
+    Lf->inode = (INODETYPE)pr.pr_ino;
+    Lf->inp_ty = 1;
+    /*
+     * Read the >= Solaris 2.6 prnode common structures.
+     *
+     * Return the PID number.
+     *
+     * Identify the lwp PID (the thread ID).
+     */
+    if (pr.pr_common &&
+        kread(ctx, (KA_T)pr.pr_common, (char *)&pc, sizeof(pc)) == 0) {
+        pcs = 1;
+        if (pc.prc_proc &&
+            kread(ctx, (KA_T)pc.prc_proc, (char *)&p, sizeof(p)) == 0)
+            prpcs = 1;
+        else
+            prpcs = 0;
+    } else
+        pcs = prpcs = 0;
+    if (pr.pr_pcommon &&
+        kread(ctx, (KA_T)pr.pr_pcommon, (char *)&ppc, sizeof(ppc)) == 0) {
+        ppcs = 1;
+        if (ppc.prc_proc &&
+            kread(ctx, (KA_T)ppc.prc_proc, (char *)&pp, sizeof(pp)) == 0)
+            prppcs = 1;
+        else
+            prppcs = 0;
+    } else
+        ppcs = prppcs = 0;
+    if (prpcs && p.p_pidp &&
+        kread(ctx, (KA_T)p.p_pidp, (char *)pids, sizeof(struct pid)) == 0)
+        prpid = pids->pid_id;
+    else if (prppcs && pp.p_pidp &&
+             kread(ctx, (KA_T)pp.p_pidp, (char *)pids, sizeof(struct pid)) == 0)
+        prpid = pids->pid_id;
+    else
+        pids->pid_id = prpid = (pid_t)0;
+    if (pcs && pc.prc_thread &&
+        kread(ctx, (KA_T)pc.prc_thread, (char *)&thread, sizeof(kthread_t)) ==
+            0)
+        prtid = thread.t_tid;
+    else if (ppcs && ppc.prc_thread &&
+             kread(ctx, (KA_T)ppc.prc_thread, (char *)&thread,
+                   sizeof(kthread_t)) == 0)
+        prtid = thread.t_tid;
+    else
+        prtid = (id_t)0;
+    /*
+     * Identify the Solaris 2.6 /proc file system name, file size, and file
+     * type.
+     */
+    switch (pr.pr_type) {
+    case PR_PROCDIR:
+        (void)snpf(Namech, Namechl - 1, "/%s", HASPROCFS);
+        Lf->type = LSOF_FILE_PROC_DIR;
+        break;
+    case PR_PIDDIR:
+        (void)snpf(Namech, Namechl - 1, "/%s/%d", HASPROCFS, (int)prpid);
+        Lf->type = LSOF_FILE_PROC_DIR;
+        break;
+    case PR_AS:
+        (void)snpf(Namech, Namechl - 1, "/%s/%d/as", HASPROCFS, (int)prpid);
+        Lf->type = LSOF_FILE_PROC_AS;
+        if (prpcs &&
+            kread(ctx, (KA_T)pc.prc_proc, (char *)&p, sizeof(p)) == 0 &&
+            p.p_as && kread(ctx, (KA_T)p.p_as, (char *)&as, sizeof(as)) == 0) {
+            Lf->sz = (SZOFFTYPE)as.a_size;
+            Lf->sz_def = 1;
+        }
+        break;
+    case PR_CTL:
+        (void)snpf(Namech, Namechl - 1, "/%s/%d/ctl", HASPROCFS, (int)prpid);
+        Lf->type = LSOF_FILE_PROC_CTRL;
+        break;
+    case PR_STATUS:
+        (void)snpf(Namech, Namechl - 1, "/%s/%d/status", HASPROCFS, (int)prpid);
+        Lf->type = LSOF_FILE_PROC_STATUS;
+        break;
+    case PR_LSTATUS:
+        (void)snpf(Namech, Namechl - 1, "/%s/%d/lstatus", HASPROCFS,
+                   (int)prpid);
+        Lf->type = LSOF_FILE_PROC_LSTATUS;
+        break;
+    case PR_PSINFO:
+        (void)snpf(Namech, Namechl - 1, "/%s/%d/psinfo", HASPROCFS, (int)prpid);
+        Lf->type = LSOF_FILE_PROC_PSINFO;
+        break;
+    case PR_LPSINFO:
+        (void)snpf(Namech, Namechl - 1, "/%s/%d/lpsinfo", HASPROCFS,
+                   (int)prpid);
+        Lf->type = LSOF_FILE_PROC_LPS_INFO;
+        break;
+    case PR_MAP:
+        (void)snpf(Namech, Namechl - 1, "/%s/%d/map", HASPROCFS, (int)prpid);
+        Lf->type = LSOF_FILE_PROC_MAP;
+        break;
+    case PR_RMAP:
+        (void)snpf(Namech, Namechl - 1, "/%s/%d/rmap", HASPROCFS, (int)prpid);
+        Lf->type = LSOF_FILE_PROC_RMAP;
+        break;
+    case PR_XMAP:
+        (void)snpf(Namech, Namechl - 1, "/%s/%d/xmap", HASPROCFS, (int)prpid);
+        Lf->type = LSOF_FILE_PROC_XMAP;
+        break;
+    case PR_CRED:
+        (void)snpf(Namech, Namechl - 1, "/%s/%d/cred", HASPROCFS, (int)prpid);
+        Lf->type = LSOF_FILE_PROC_CRED;
+        break;
+    case PR_SIGACT:
+        (void)snpf(Namech, Namechl - 1, "/%s/%d/sigact", HASPROCFS, (int)prpid);
+        Lf->type = LSOF_FILE_PROC_SIGACT;
+        break;
+    case PR_AUXV:
+        (void)snpf(Namech, Namechl - 1, "/%s/%d/auxv", HASPROCFS, (int)prpid);
+        Lf->type = LSOF_FILE_PROC_AUXV;
+        break;
+
+#        if defined(HASPR_LDT)
+    case PR_LDT:
+        (void)snpf(Namech, Namechl - 1, "/%s/%d/ldt", HASPROCFS, (int)prpid);
+        Lf->type = LSOF_FILE_PROC_LDT;
+        break;
+#        endif /* defined(HASPR_LDT) */
+
+    case PR_USAGE:
+        (void)snpf(Namech, Namechl - 1, "/%s/%d/usage", HASPROCFS, (int)prpid);
+        Lf->type = LSOF_FILE_PROC_USAGE;
+        break;
+    case PR_LUSAGE:
+        (void)snpf(Namech, Namechl - 1, "/%s/%d/lusage", HASPROCFS, (int)prpid);
+        Lf->type = LSOF_FILE_PROC_LUSAGE;
+        break;
+    case PR_PAGEDATA:
+        (void)snpf(Namech, Namechl - 1, "/%s/%d/pagedata", HASPROCFS,
+                   (int)prpid);
+        Lf->type = LSOF_FILE_PROC_PAGE_DATA;
+        break;
+    case PR_WATCH:
+        (void)snpf(Namech, Namechl - 1, "/%s/%d/watch", HASPROCFS, (int)prpid);
+        Lf->type = LSOF_FILE_PROC_WATCH;
+        break;
+    case PR_CURDIR:
+        (void)snpf(Namech, Namechl - 1, "/%s/%d/cwd", HASPROCFS, (int)prpid);
+        Lf->type = LSOF_FILE_PROC_CWD;
+        break;
+    case PR_ROOTDIR:
+        (void)snpf(Namech, Namechl - 1, "/%s/%d/root", HASPROCFS, (int)prpid);
+        Lf->type = LSOF_FILE_PROC_ROOT;
+        break;
+    case PR_FDDIR:
+        (void)snpf(Namech, Namechl - 1, "/%s/%d/fd", HASPROCFS, (int)prpid);
+        Lf->type = LSOF_FILE_PROC_FD_DIR;
+        break;
+    case PR_FD:
+        (void)snpf(Namech, Namechl - 1, "/%s/%d/fd/%d", HASPROCFS, (int)prpid,
+                   pr.pr_index);
+        Lf->type = LSOF_FILE_PROC_FD;
+        break;
+    case PR_OBJECTDIR:
+        (void)snpf(Namech, Namechl - 1, "/%s/%d/object", HASPROCFS, (int)prpid);
+        Lf->type = LSOF_FILE_PROC_OBJ_DIR;
+        break;
+    case PR_OBJECT:
+        (void)snpf(Namech, Namechl - 1, "/%s/%d/object/", HASPROCFS,
+                   (int)prpid);
+        Lf->type = LSOF_FILE_PROC_OBJ;
+        break;
+    case PR_LWPDIR:
+        (void)snpf(Namech, Namechl - 1, "/%s/%d/lpw", HASPROCFS, (int)prpid);
+        Lf->type = LSOF_FILE_PROC_LWP_DIR;
+        break;
+    case PR_LWPIDDIR:
+        (void)snpf(Namech, Namechl, "/%s/%d/lwp/%d", HASPROCFS, (int)prpid,
+                   (int)prtid);
+        Lf->type = LSOF_FILE_PROC_LWP_DIR;
+        break;
+    case PR_LWPCTL:
+        (void)snpf(Namech, Namechl - 1, "/%s/%d/lwp/%d/lwpctl", HASPROCFS,
+                   (int)prpid, (int)prtid);
+        Lf->type = LSOF_FILE_PROC_LWP_CTL;
+        break;
+    case PR_LWPSTATUS:
+        (void)snpf(Namech, Namechl - 1, "/%s/%d/lwp/%d/lwpstatus", HASPROCFS,
+                   (int)prpid, (int)prtid);
+        Lf->type = LSOF_FILE_PROC_LWP_STATUS;
+        break;
+    case PR_LWPSINFO:
+        (void)snpf(Namech, Namechl - 1, "/%s/%d/lwp/%d/lwpsinfo", HASPROCFS,
+                   (int)prpid, (int)prtid);
+        Lf->type = LSOF_FILE_PROC_LWP_SINFO;
+        break;
+    case PR_LWPUSAGE:
+        (void)snpf(Namech, Namechl - 1, "/%s/%d/lwp/%d/lwpusage", HASPROCFS,
+                   (int)prpid, (int)prtid);
+        Lf->type = LSOF_FILE_PROC_LWP_USAGE;
+        break;
+    case PR_XREGS:
+        (void)snpf(Namech, Namechl - 1, "/%s/%d/lwp/%d/xregs", HASPROCFS,
+                   (int)prpid, (int)prtid);
+        Lf->type = LSOF_FILE_PROC_LWP_XREGS;
+        break;
+
+#        if defined(HASPR_GWINDOWS)
+    case PR_GWINDOWS:
+        (void)snpf(Namech, Namechl - 1, "/%s/%d/lwp/%d/gwindows", HASPROCFS,
+                   (int)prpid, (int)prtid);
+        Lf->type = LSOF_FILE_PROC_LWP_GWINDOWS;
+        break;
+#        endif /* defined(HASPR_GWINDOWS) */
+
+#        if defined(PR_PIDFILE)
+    case PR_PIDFILE:
+        (void)snpf(Namech, Namechl - 1, "/%s/%d", HASPROCFS, (int)prpid);
+        Lf->type = LSOF_FILE_PROC_OLD_PID;
+        break;
+#        endif /* defined(PR_PIDFILE) */
+
+#        if defined(PR_LWPIDFILE)
+    case PR_LWPIDFILE:
+        (void)snpf(Namech, Namechl - 1, "/%s/%d", HASPROCFS, (int)prpid);
+        Lf->type = LSOF_FILE_PROC_OLD_LWP;
+        break;
+#        endif /* defined(PR_LWPIDFILE) */
+
+    case PR_OPAGEDATA:
+        (void)snpf(Namech, Namechl - 1, "/%s/%d", HASPROCFS, (int)prpid);
+        Lf->type = LSOF_FILE_PROC_OLD_PAGE;
+        break;
+    default:
+        Lf->type = LSOF_FILE_UNKNOWN_RAW;
+        Lf->unknown_file_type_number = pr.pr_type;
+    }
+    /*
+     * Record the Solaris 2.6 /proc file system inode number.
+     */
+    Lf->inode = (INODETYPE)pr.pr_ino;
+    Lf->inp_ty = 1;
+#    endif     /* solaris<20600 */
+
+    Namech[Namechl - 1] = '\0';
+    enter_nm(ctx, Namech);
+    return (0);
+}
+#endif /* defined(HASPROCFS) */
+
+/*
+ * read_npn() - read node's pcnode
+ */
+
+static int read_npn(struct lsof_context *ctx, /* context */
+                    KA_T na,                  /* containing node's address */
+                    KA_T pa,                  /* pcnode address */
+                    struct pcnode *p)         /* pcnode receiver */
+{
+    char tbuf[32];
+
+    if (!pa || kread(ctx, pa, (char *)p, sizeof(struct pcnode))) {
+        (void)snpf(Namech, Namechl - 1, "node at %s: can't read pcnode: %s",
+                   print_kptr(na, tbuf, sizeof(tbuf)),
+                   print_kptr(pa, (char *)NULL, 0));
+        Namech[Namechl - 1] = '\0';
+        enter_nm(ctx, Namech);
+        return (1);
+    }
+    return (0);
+}
+
+#if solaris >= 100000
+/*
+ * read_nprtn() - read node's port node
+ */
+
+static int read_nprtn(struct lsof_context *ctx, /* context */
+                      KA_T na,                  /* containing node's address */
+                      KA_T pa,                  /* port node address */
+                      port_t *p)                /* port node receiver */
+{
+    char tbuf[32];
+
+    if (!pa || kread(ctx, pa, (char *)p, sizeof(port_t))) {
+        (void)snpf(Namech, Namechl - 1, "node at %s: can't read port node: %s",
+                   print_kptr(na, tbuf, sizeof(tbuf)),
+                   print_kptr(pa, (char *)NULL, 0));
+        Namech[Namechl - 1] = '\0';
+        enter_nm(ctx, Namech);
+        return (1);
+    }
+    return (0);
+}
+#endif /* solaris>=100000 */
+
+/*
+ * read_nrn() - read node's rnode
+ */
+
+static int read_nrn(struct lsof_context *ctx, /* context */
+                    KA_T na,                  /* containing node's address */
+                    KA_T ra,                  /* rnode address */
+                    struct rnode *r)          /* rnode receiver */
+{
+    char tbuf[32];
+
+    if (!ra || readrnode(ctx, ra, r)) {
+        (void)snpf(Namech, Namechl - 1, "node at %s: can't read rnode: %s",
+                   print_kptr(na, tbuf, sizeof(tbuf)),
+                   print_kptr(ra, (char *)NULL, 0));
+        Namech[Namechl - 1] = '\0';
+        enter_nm(ctx, Namech);
+        return (1);
+    }
+    return (0);
+}
+
+#if solaris >= 100000
+/*
+ * read_nrn4() - read node's rnode4
+ */
+
+static int read_nrn4(struct lsof_context *ctx, /* context */
+                     KA_T na,                  /* containing node's address */
+                     KA_T ra,                  /* rnode address */
+                     struct rnode4 *r)         /* rnode receiver */
+{
+    char tbuf[32];
+
+    if (!ra || kread(ctx, (KA_T)ra, (char *)r, sizeof(struct rnode4))) {
+        (void)snpf(Namech, Namechl - 1, "node at %s: can't read rnode4: %s",
+                   print_kptr(na, tbuf, sizeof(tbuf)),
+                   print_kptr(ra, (char *)NULL, 0));
+        Namech[Namechl - 1] = '\0';
+        enter_nm(ctx, Namech);
+        return (1);
+    }
+    return (0);
+}
+#endif /* solaris>=100000 */
+
+#if solaris >= 110000
+/*
+ * read_nsdn() - read node's sdev_node
+ */
+
+static int read_nsdn(struct lsof_context *ctx, /* context */
+                     KA_T na,                  /* containing node's address */
+                     KA_T sa,                  /* sdev_node address */
+                     struct sdev_node *sdn,    /* sdev_node receiver */
+                     struct vattr *sdva)       /* sdev_node's vattr receiver */
+{
+    KA_T va;
+    char tbuf[32], tbuf1[32];
+
+    if (!sa || kread(ctx, (KA_T)sa, (char *)sdn, sizeof(struct sdev_node))) {
+        (void)snpf(Namech, Namechl - 1, "node at %s: can't read sdev_node: %s",
+                   print_kptr(na, tbuf, sizeof(tbuf)),
+                   print_kptr(sa, (char *)NULL, 0));
+        Namech[Namechl - 1] = '\0';
+        enter_nm(ctx, Namech);
+        return (1);
+    }
+    if (!(va = (KA_T)sdn->sdev_attr) ||
+        kread(ctx, va, (char *)sdva, sizeof(struct vattr))) {
+        (void)snpf(Namech, Namechl - 1,
+                   "node at %s; sdev_node at %s: can't read vattr: %s",
+                   print_kptr(na, tbuf, sizeof(tbuf)),
+                   print_kptr(sa, tbuf1, sizeof(tbuf1)),
+                   print_kptr(va, (char *)NULL, 0));
+        Namech[Namechl - 1] = '\0';
+        enter_nm(ctx, Namech);
+        return (1);
+    }
+    return (0);
+}
+#endif /* solaris>=110000 */
+
+#if solaris >= 20600
+/*
+ * read_nson() - read node's sonode
+ */
+
+static int read_nson(struct lsof_context *ctx, /* context */
+                     KA_T na,                  /* containing node's address */
+                     KA_T sa,                  /* sonode address */
+                     struct sonode *sn)        /* sonode receiver */
+
+{
+    char tbuf[32];
+
+    if (!sa || kread(ctx, (KA_T)sa, (char *)sn, sizeof(struct sonode))) {
+        (void)snpf(Namech, Namechl - 1, "node at %s: can't read sonode: %s",
+                   print_kptr(na, tbuf, sizeof(tbuf)),
+                   print_kptr(sa, (char *)NULL, 0));
+        Namech[Namechl - 1] = '\0';
+        enter_nm(ctx, Namech);
+        return (1);
+    }
+    return (0);
+}
+#endif /* solaris>=20600 */
+
+/*
+ * read_nsn() - read node's snode
+ */
+
+static int read_nsn(struct lsof_context *ctx, /* context */
+                    KA_T na,                  /* containing node's address */
+                    KA_T sa,                  /* snode address */
+                    struct snode *s)          /* snode receiver */
+{
+    char tbuf[32];
+
+    if (!sa || readsnode(ctx, sa, s)) {
+        (void)snpf(Namech, Namechl - 1, "node at %s: can't read snode: %s",
+                   print_kptr(na, tbuf, sizeof(tbuf)),
+                   print_kptr(sa, (char *)NULL, 0));
+        Namech[Namechl - 1] = '\0';
+        enter_nm(ctx, Namech);
+        return (1);
+    }
+    return (0);
+}
+
+#if solaris >= 110000
+/*
+ * read_nsti() - read socket node's info
+ */
+
+static int read_nsti(struct lsof_context *ctx, /* context */
+                     struct sonode *so,        /* socket's sonode */
+                     sotpi_info_t *stpi)       /* local socket info receiver */
+{
+    char tbuf[32];
+
+    (void)CTF_init(ctx, &Sockfs_ctfs, SOCKFS_MOD_FORMAT, Sockfs_requests);
+    if (!so || !so->so_priv ||
+        CTF_MEMBER_READ(so->so_priv, stpi, sotpi_info_members, sti_dev) ||
+        CTF_MEMBER_READ(so->so_priv, stpi, sotpi_info_members, sti_laddr) ||
+        CTF_MEMBER_READ(so->so_priv, stpi, sotpi_info_members, sti_faddr) ||
+        CTF_MEMBER_READ(so->so_priv, stpi, sotpi_info_members, sti_ux_laddr) ||
+        CTF_MEMBER_READ(so->so_priv, stpi, sotpi_info_members, sti_ux_faddr) ||
+        CTF_MEMBER_READ(so->so_priv, stpi, sotpi_info_members, sti_serv_type)) {
+        (void)snpf(Namech, Namechl - 1, "sonode at %s: can't read so_priv: %s",
+                   print_kptr((KA_T)so, tbuf, sizeof(tbuf)),
+                   print_kptr((KA_T)so->so_priv, (char *)NULL, 0));
+        Namech[Namechl - 1] = '\0';
+        enter_nm(ctx, Namech);
+        return (1);
+    }
+    return (0);
+}
+#endif /* solaris>=110000 */
+
+/*
+ * read_ntn() - read node's tmpnode
+ */
+
+static int read_ntn(struct lsof_context *ctx, /* context */
+                    KA_T na,                  /* containing node's address */
+                    KA_T ta,                  /* tmpnode address */
+                    struct tmpnode *t)        /* tmpnode receiver */
+{
+    char tbuf[32];
+
+    if (!ta || readtnode(ctx, ta, t)) {
+        (void)snpf(Namech, Namechl - 1, "node at %s: can't read tnode: %s",
+                   print_kptr(na, tbuf, sizeof(tbuf)),
+                   print_kptr(ta, (char *)NULL, 0));
+        Namech[Namechl - 1] = '\0';
+        enter_nm(ctx, Namech);
+        return (1);
+    }
+    return (0);
+}
+
+#if solaris >= 20600
+/*
+ * read_nusa() - read sondode's UNIX socket address
+ */
+
+static int read_nusa(struct lsof_context *ctx, /* context */
+                     struct soaddr *so,      /* kernel socket info structure */
+                     struct sockaddr_un *ua) /* local sockaddr_un address */
+{
+    KA_T a;
+    int len;
+    int min = offsetof(struct sockaddr_un, sun_path);
+
+    ua->sun_path[0] = '\0';
+
+    if (!(a = (KA_T)so->soa_sa) || (len = so->soa_len) < (min + 2) ||
+        len > (int)sizeof(struct sockaddr_un) ||
+        kread(ctx, a, (char *)ua, len) || ua->sun_family != AF_UNIX)
+        return (0);
+    len -= min;
+    if (len >= sizeof(ua->sun_path))
+        len = sizeof(ua->sun_path) - 1;
+    ua->sun_path[len] = '\0';
+    return ((int)strlen(ua->sun_path));
+}
+#endif /* solaris>=20600 */
+
+/*
+ * read_nvn() - read node's vnode
+ */
+
+static int read_nvn(struct lsof_context *ctx, /* context */
+                    KA_T na,                  /* node's address */
+                    KA_T va,                  /* vnode address */
+                    struct vnode *v)          /* vnode receiver */
+{
+    char tbuf[32];
+
+    if (readvnode(ctx, va, v)) {
+        (void)snpf(Namech, Namechl - 1, "node at %s: can't read real vnode: %s",
+                   print_kptr(na, tbuf, sizeof(tbuf)),
+                   print_kptr(va, (char *)NULL, 0));
+        Namech[Namechl - 1] = '\0';
+        enter_nm(ctx, Namech);
+        return (1);
+    }
+    return (0);
+}
+
+#if defined(HAS_ZFS)
+/*
+ * read_nzn() - read node's ZFS node
+ */
+
+static int read_nzn(struct lsof_context *ctx, /* context */
+                    KA_T na,                  /* containing node's address */
+                    KA_T nza,                 /* znode address */
+                    znode_t *zn)              /* znode receiver */
+{
+    int err = 0;      /* error flag */
+    CTF_member_t *mp; /* member pointer */
+    char tbuf[32];    /* temporary buffer */
+    znode_phys_t zp;  /* physical znode */
+
+    (void)CTF_init(ctx, &ZFS_ctfs, ZFS_MOD_FORMAT, ZFS_requests);
+    if (!nza || CTF_MEMBER_READ(nza, zn, znode_members, z_zfsvfs) ||
+        CTF_MEMBER_READ(nza, zn, znode_members, z_vnode) ||
+        CTF_MEMBER_READ(nza, zn, znode_members, z_id) ||
+        CTF_MEMBER_READ(nza, zn, znode_members, z_phys) ||
+        CTF_MEMBER_READ(nza, zn, znode_members, z_links) ||
+        CTF_MEMBER_READ(nza, zn, znode_members, z_size)) {
+        (void)snpf(Namech, Namechl - 1, "node at %s: can't read znode: %s",
+                   print_kptr(na, tbuf, sizeof(tbuf)),
+                   print_kptr(nza, (char *)NULL, 0));
+        Namech[Namechl - 1] = '\0';
+        enter_nm(ctx, Namech);
+        return (1);
+    }
+    /*
+     * If the physical znode pointer is defined, read the physizal znode
+     * and propagate its values to the znode.
+     */
+    if (znode_members[MX_z_phys].m_offset != CTF_MEMBER_UNDEF) {
+        err = read_nznp(ctx, nza, (KA_T)zn->z_phys, &zp);
+        if (!err) {
+            zn->z_links = zp.zp_links;
+            zn->z_size = zp.zp_size;
+        }
+    } else {
+
+        /*
+         * Make sure z_link and z_size are defined when z_phys isn't.
+         */
+        if (znode_members[MX_z_links].m_offset == CTF_MEMBER_UNDEF) {
+            (void)snpf(Namech, Namechl - 1,
+                       "node at %s: can't read z_links: %s",
+                       print_kptr(na, tbuf, sizeof(tbuf)),
+                       print_kptr(nza, (char *)NULL, 0));
+            Namech[Namechl - 1] = '\0';
+            enter_nm(ctx, Namech);
+            err = 1;
+        }
+        if (znode_members[MX_z_size].m_offset == CTF_MEMBER_UNDEF) {
+            (void)snpf(Namech, Namechl - 1, "node at %s: can't read z_size: %s",
+                       print_kptr(na, tbuf, sizeof(tbuf)),
+                       print_kptr(nza, (char *)NULL, 0));
+            Namech[Namechl - 1] = '\0';
+            enter_nm(ctx, Namech);
+            err = 1;
+        }
+    }
+    return (err);
+}
+
+/*
+ * read_nznp() - read znode's persistent znode
+ */
+
+static int read_nznp(struct lsof_context *ctx, /* context */
+                     KA_T nza,                 /* containing znode's address */
+                     KA_T nzpa,                /* persistent znode address */
+                     znode_phys_t *zp)         /* persistent znode receiver */
+{
+    char tbuf[32];
+
+    (void)CTF_init(ctx, &ZFS_ctfs, ZFS_MOD_FORMAT, ZFS_requests);
+    if (!nzpa || CTF_MEMBER_READ(nzpa, zp, znode_phys_members, zp_size) ||
+        CTF_MEMBER_READ(nzpa, zp, znode_phys_members, zp_links)) {
+        (void)snpf(Namech, Namechl - 1,
+                   "znode at %s: "
+                   "can't read znode_phys: %s",
+                   print_kptr(nza, tbuf, sizeof(tbuf)),
+                   print_kptr(nzpa, (char *)NULL, 0));
+        Namech[Namechl - 1] = '\0';
+        enter_nm(ctx, Namech);
+        return (1);
+    }
+    return (0);
+}
+
+/*
+ * read_nzvfs() - read znode's associated vfs
+ */
+
+static int read_nzvfs(struct lsof_context *ctx, /* context */
+                      KA_T nza,                 /* containing znode's address */
+                      KA_T nzva,                /* associated vfs address */
+                      zfsvfs_t *zv)             /* associated vfs receiver */
+{
+    char tbuf[32];
+
+    (void)CTF_init(ctx, &ZFS_ctfs, ZFS_MOD_FORMAT, ZFS_requests);
+    if (!nzva || CTF_MEMBER_READ(nzva, zv, zfsvfs_members, z_vfs)) {
+        (void)snpf(Namech, Namechl - 1, "znode at %s: can't read zfsvfs: %s",
+                   print_kptr(nza, tbuf, sizeof(tbuf)),
+                   print_kptr(nzva, (char *)NULL, 0));
+        Namech[Namechl - 1] = '\0';
+        enter_nm(ctx, Namech);
+        return (1);
+    }
+    return (0);
+}
+#endif /* defined(HAS_ZFS) */
+
+#if solaris < 100000
+/*
+ * savesockmod() - save addresses from sockmod so_so structure
+ */
+
+static void
+savesockmod(struct so_so *so,  /* new so_so structure pointer */
+            struct so_so *sop, /* previous so_so structure pointer */
+            int *so_st)        /* status of *sop (0 if not loaded) */
+{
+
+#    if solaris < 20500
+    dev_t d1, d2, d3;
+#    endif /* solaris<20500 */
+
+#    define luxadr lux_dev.addr.tu_addr
+#    define luxdev lux_dev.addr.tu_addr.dev
+#    define luxino lux_dev.addr.tu_addr.ino
+#    define ruxadr rux_dev.addr.tu_addr
+#    define ruxdev rux_dev.addr.tu_addr.dev
+#    define ruxino rux_dev.addr.tu_addr.ino
+
+#    if solaris < 20500
+    /*
+     * If either address in the new structure is missing a device number, clear
+     * its corresponding inode number.  Then sort the inode-less device numbers.
+     */
+    if (!so->luxdev)
+        so->luxino = (ino_t)0;
+    if (!so->ruxdev)
+        so->ruxino = (ino_t)0;
+    if (!so->luxino && !so->ruxino) {
+        if (so->luxdev > so->ruxdev) {
+            d2 = so->luxdev;
+            d1 = so->luxdev = so->ruxdev;
+            so->ruxdev = d2;
+        } else {
+            d1 = so->luxdev;
+            d2 = so->ruxdev;
+        }
+    } else
+        d1 = d2 = (dev_t)0;
+    /*
+     * If the previous structure hasn't been loaded, save the new one in it with
+     * adjusted or sorted addresses.
+     */
+    if (!*so_st) {
+        if (so->luxdev && so->luxino) {
+            *sop = *so;
+            sop->ruxdev = (dev_t)0;
+            sop->ruxino = (ino_t)0;
+            *so_st = 1;
+            return;
+        }
+        if (so->ruxdev && so->ruxino) {
+            *sop = *so;
+            sop->luxadr = sop->ruxadr;
+            sop->ruxdev = (dev_t)0;
+            sop->ruxino = (ino_t)0;
+            *so_st = 1;
+            return;
+        }
+        *sop = *so;
+        *so_st = 1;
+        return;
+    }
+    /*
+     * See if the new sockmod addresses need to be merged with the previous
+     * ones:
+     *
+     * *  Don't merge if the previous so_so structure's lux_dev has a non-
+     *    zero device and a non-zero inode number.
+     *
+     * *  If either of the device/inode pairs in the new structure is non-
+     *    zero, propagate them to the previous so_so structure.
+     *
+     * *  Don't merge if the both device numbers in the new structure are
+     *    zero.
+     */
+    if (sop->luxdev && sop->luxino)
+        return;
+    if (so->luxdev && so->luxino) {
+        sop->luxadr = so->luxadr;
+        sop->ruxdev = (dev_t)0;
+        sop->ruxino = (ino_t)0;
+        return;
+    }
+    if (so->ruxdev && so->ruxino) {
+        sop->luxadr = so->ruxadr;
+        sop->ruxdev = (dev_t)0;
+        sop->ruxino = (ino_t)0;
+        return;
+    }
+    if (!so->luxdev && !so->ruxdev)
+        return;
+    /*
+     * Check the previous structure's device numbers:
+     *
+     * *  If both are zero, replace the previous structure with the new one.
+     *
+     * *  Choose the minimum and maximum non-zero device numbers contained in
+     *    either structure.
+     */
+    if (!sop->luxdev && !sop->ruxdev) {
+        *sop = *so;
+        return;
+    }
+    if (!sop->luxdev && (d1 || d2)) {
+        if (d1) {
+            sop->luxdev = d1;
+            d1 = (dev_t)0;
+        } else {
+            sop->luxdev = d2;
+            d2 = (dev_t)0;
+        }
+        if (sop->luxdev > sop->ruxdev) {
+            d3 = sop->luxdev;
+            sop->luxdev = sop->ruxdev;
+            sop->ruxdev = d3;
+        }
+    }
+    if (!sop->ruxdev && (d1 || d2)) {
+        if (d1) {
+            sop->ruxdev = d1;
+            d1 = (dev_t)0;
+        } else {
+            sop->ruxdev = d2;
+            d2 = (dev_t)0;
+        }
+        if (sop->luxdev > sop->ruxdev) {
+            d3 = sop->luxdev;
+            sop->luxdev = sop->ruxdev;
+            sop->ruxdev = d3;
+        }
+    }
+    if (sop->luxdev && sop->ruxdev) {
+        if (d1) {
+            if (d1 < sop->luxdev)
+                sop->luxdev = d1;
+            else if (d1 > sop->ruxdev)
+                sop->ruxdev = d1;
+        }
+        if (d2) {
+            if (d2 < sop->luxdev)
+                sop->luxdev = d2;
+            else if (d2 > sop->ruxdev)
+                sop->ruxdev = d2;
+        }
+    }
+#    else  /* solaris>=20500 */
+    /*
+     * Save the first sockmod structure.
+     */
+    if (!*so_st) {
+        *so_st = 1;
+        *sop = *so;
+    }
+#    endif /* solaris<20500 */
+}
+#endif /* solaris<100000 */
+
+/*
+ * vop2ty() - convert vnode operation switch address to internal type
+ */
+
+int vop2ty(struct lsof_context *ctx, /* context */
+           struct vnode *vp,         /* local vnode pointer */
+           int fx)                   /* file system index (-1 if none) */
+{
+    int h;
+    register int i;
+    KA_T ka;
+    int nty;
+    v_optab_t *nv, *v, *vt;
+
+#if defined(HAS_AFS)
+    static int afs = 0; /* afs test status: -1 = no AFS
+                         *                  0 = not tested
+                         *                  1 = AFS */
+#endif                  /* defined(HAS_AFS) */
+
+    /*
+     * Locate the node type by hashing the vnode's v_op address into the
+     * Voptab[].
+     */
+    if (!(ka = (KA_T)vp->v_op))
+        return (-1);
+    h = HASHVOP(ka);
+    for (v = Voptab[h]; v; v = v->next) {
+        if (ka == v->v_op)
+            break;
+    }
+    if (!v) {
+
+        /*
+         * If there's no entry in the Voptab[] for the v_op address, see if
+         * an entry can be found via the file system type and FxToVoptab[].
+         */
+        if ((fx >= 0) && (fx < Fsinfomax) && (v = FxToVoptab[fx])) {
+
+            /*
+             * There's an FxToVoptab[] mapping, so add an entry to Voptab[]
+             * for the v_op address.
+             */
+            if (!(nv = (v_optab_t *)malloc((MALLOC_S)sizeof(v_optab_t)))) {
+                (void)fprintf(stderr, "%s: can't add \"%s\" to Voptab\n", Pn,
+                              Fsinfo[fx]);
+                Error(ctx);
+            }
+            *nv = *v;
+            nv->v_op = ka;
+            h = HASHVOP(ka);
+            nv->next = Voptab[h];
+            Voptab[h] = v = nv;
+        }
+    }
+    if (!v)
+        return (-1);
+
+#if defined(HAS_AFS)
+    /*
+     * Do special AFS checks.
+     */
+    if (v->nty == N_AFS) {
+        if (vp->v_data || !vp->v_vfsp)
+            return (-1);
+        switch (afs) {
+        case -1:
+            return (-1);
+        case 0:
+            if (!hasAFS(vp)) {
+                afs = -1;
+                return (-1);
+            }
+            afs = 1;
+            return (N_AFS);
+        case 1:
+            if ((KA_T)vp->v_vfsp == AFSVfsp)
+                return (N_AFS);
+        }
+        return (-1);
+    }
+#endif /* defined(HAS_AFS) */
+
+    return (v->nty);
+}
+
+#if solaris >= 100000
+/*
+ * read_ndvn() -- read node's dv_node
+ */
+
+static int read_ndvn(struct lsof_context *ctx, /* context */
+                     KA_T na,                  /* containing vnode's address */
+                     KA_T da,                  /* containing vnode's v_data */
+                     struct dv_node *dv,       /* dv_node receiver */
+                     dev_t *dev,               /* underlying file system device
+                                                * number receptor */
+                     unsigned char *devs)      /* status of *dev */
+{
+    struct vnode rv;
+    struct snode s;
+    char tbuf[32];
+    struct vfs v;
+    /*
+     * Read the snode.
+     */
+    if (!da || kread(ctx, (KA_T)da, (char *)&s, sizeof(s))) {
+        (void)snpf(Namech, Namechl - 1,
+                   "dv_node vnode at %s: can't read snode: %s",
+                   print_kptr(na, tbuf, sizeof(tbuf)),
+                   print_kptr(da, (char *)NULL, 0));
+        Namech[Namechl - 1] = '\0';
+        enter_nm(ctx, Namech);
+        return (1);
+    }
+    /*
+     * Read the snode's real vnode.
+     */
+    if (!s.s_realvp ||
+        kread(ctx, (KA_T)s.s_realvp, (char *)&rv, sizeof(struct dv_node))) {
+        (void)snpf(Namech, Namechl - 1,
+                   "dv_node snode at %s: can't read real vnode: %s",
+                   print_kptr(da, tbuf, sizeof(tbuf)),
+                   print_kptr((KA_T)s.s_realvp, (char *)NULL, 0));
+        Namech[Namechl - 1] = '\0';
+        enter_nm(ctx, Namech);
+        return (1);
+    }
+    /*
+     * Read the real vnode's dv_node.
+     */
+    if (!rv.v_data || kread(ctx, (KA_T)rv.v_data, (char *)dv, sizeof(rv))) {
+        (void)snpf(Namech, Namechl - 1,
+                   "dv_node real vnode at %s: can't read dv_node: %s",
+                   print_kptr((KA_T)s.s_realvp, tbuf, sizeof(tbuf)),
+                   print_kptr((KA_T)rv.v_data, (char *)NULL, 0));
+        Namech[Namechl - 1] = '\0';
+        enter_nm(ctx, Namech);
+        return (1);
+    }
+    /*
+     * Return the device number of the underlying file system, if possible.
+     */
+    if (rv.v_vfsp && !kread(ctx, (KA_T)rv.v_vfsp, (char *)&v, sizeof(v))) {
+        *dev = v.vfs_dev;
+        *devs = 1;
+    }
+    return (0);
+}
+#endif /* solaris<100000 */
diff --git a/lib/dialects/sun/dnode1.c b/lib/dialects/sun/dnode1.c
new file mode 100644 (file)
index 0000000..58785dc
--- /dev/null
@@ -0,0 +1,414 @@
+/*
+ * dnode1.h - Solaris AFS support
+ */
+
+/*
+ * Copyright 1996 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 1996 Purdue Research Foundation.\nAll rights reserved.\n";
+#endif
+
+#if defined(HAS_AFS)
+#    include "lsof.h"
+
+#    include <rpc/xdr.h>
+#    define __XDR_INCLUDE__
+#    define int32 old_solaris_int32
+
+#    if solaris >= 20600
+#        undef SHARED
+#        undef PRIVATE
+#    endif /* solaris>=20600 */
+
+#    include <afs/param.h>
+#    include <afs/afsint.h>
+#    include <afs/vldbint.h>
+
+/*
+ * This is an emulation of the afs_rwlock_t definition that appears in
+ * the AFS sources in afs/lock.h.
+ */
+
+#    if defined(AFS_SUN5_ENV)
+#        define AFS_NOBOZO_LOCK
+#    endif /* defined(AFS_SUN5_ENV) */
+
+#    define INSTRUMENT_LOCKS
+
+#    if defined(AFS_FINEGR_SUNLOCK)
+typedef kmutex_ afs_lock_t;
+typedef krwlock_t afs_rwlock_t;
+#    endif /* !defined(AFS_FINEGR_SUNLOCK) */
+
+struct afs_lock {
+
+#    if solaris >= 20500
+    unsigned char d1[2];
+    unsigned short d1_5[3];
+#    else  /* solaris < 20500 */
+    unsigned char d1[4];
+#    endif /* solaris>=20500 */
+
+    struct timeval d2;
+
+#    if defined(INSTRUMENT_LOCKS)
+    unsigned int d3[3];
+#    endif /* defined(INSTRUMENT_LOCKS) */
+};
+typedef struct afs_lock afs_lock_t;
+typedef struct afs_lock afs_rwlock_t;
+
+/*
+ * This is an emulation of the afs_bozoLock_t definition that appears in
+ * the AFS sources in afs/lock.h.
+ */
+
+struct afs_bozoLock {
+    short d1;
+    char d2[2];
+    char *d3;
+};
+
+#    if !defined(AFS_NOBOZO_LOCK)
+typedef struct afs_bozoLock afs_bozoLock_t;
+#    else /* defined(AFS_NOBOZO_LOCK) */
+#        if defined(AFS_SUN5_ENV)
+typedef kmutex_t afs_bozoLock_t;
+#        else  /* !defined(AFS_SUN5_ENV) */
+typedef struct afs_bozoLock afs_bozoLock_t;
+#        endif /* defined(AFS_SUN5_ENV) */
+#    endif     /* !defined(AFS_NOBOZO_LOCK) */
+
+#    define KERNEL
+#    include <afs/afs.h>
+#    undef KERNEL
+
+/*
+ * Local function prototypes
+ */
+
+static struct volume *getvolume(struct VenusFid *f, int *vols);
+static int is_rootFid(struct vcache *vc, int *rfid);
+
+/*
+ * alloc_vcache() - allocate space for vcache structure
+ */
+
+struct vnode *alloc_vcache() {
+    return ((struct vnode *)malloc(sizeof(struct vcache)));
+}
+
+/*
+ * ckAFSsym() - check for missing X_AFS_* symbols in AFS name list file
+ */
+
+void ckAFSsym(struct nlist *nl) /* copy of Nl[] when empty */
+{
+    char *path = AFSAPATHDEF;
+    int i;
+    KA_T v;
+
+#    if defined(HASAOPT)
+    if (AFSApath)
+        path = AFSApath;
+#    endif /* defined(HASAOPT) */
+
+    /*
+     * If an alternate AFS name list file was specified, see if it can be read.
+     */
+    if (!is_readable(path, 0)) {
+        if (!Fwarn)
+            (void)fprintf(stderr,
+                          "%s: WARNING: can't access AFS name list file: %s\n",
+                          Pn, path);
+        return;
+    }
+    /*
+     * Read the AFS modload symbols and compare its non-zero values with
+     * the non-zero values in Nl[].  Quit if there is any mis-match.
+     */
+    if (nlist(path, nl) < 0)
+        return;
+    for (i = 0; Nl[i].n_name && Nl[i].n_name[0]; i++) {
+        if (!nl[i].n_value || !Nl[i].n_value)
+            continue;
+        if (nl[i].n_value != Nl[i].n_value)
+            return;
+    }
+    /*
+     * If any AFS symbol that doesn't have a value in Nl[] has one from
+     * the AFS modload file, copy its modload value to Nl[].
+     */
+    if ((i = get_Nl_value("arFid", Drive_Nl, &v)) >= 0 && !Nl[i].n_value &&
+        nl[i].n_value)
+        Nl[i].n_value = nl[i].n_value;
+    if ((i = get_Nl_value("avops", Drive_Nl, &v)) >= 0 && !Nl[i].n_value &&
+        nl[i].n_value)
+        Nl[i].n_value = nl[i].n_value;
+    if ((i = get_Nl_value("avol", Drive_Nl, &v)) >= 0 && !Nl[i].n_value &&
+        nl[i].n_value)
+        Nl[i].n_value = nl[i].n_value;
+}
+
+/*
+ * getvolume() - get volume structure
+ */
+
+static struct volume *getvolume(struct VenusFid *f, /* file ID pointer */
+                                int *vols) /* afs_volumes status return */
+{
+    int i;
+    static KA_T ka = 0;
+    KA_T kh;
+    static struct volume v;
+    KA_T vp;
+    static int w = 0;
+
+    if (!ka) {
+        if (get_Nl_value("avol", Drive_Nl, &ka) < 0 || !ka) {
+            if (!w && !Fwarn) {
+                (void)fprintf(
+                    stderr, "%s: WARNING: no kernel address for afs_volumes\n",
+                    Pn);
+                (void)fprintf(
+                    stderr,
+                    "      This may hamper AFS node number reporting.\n");
+                w = 1;
+            }
+            *vols = 0;
+            return ((struct volume *)NULL);
+        }
+    }
+    *vols = 1;
+    i = (NVOLS - 1) & f->Fid.Volume;
+    kh = (KA_T)((char *)ka + (i * sizeof(struct volume *)));
+    if (kread(ctx, kh, (char *)&vp, sizeof(vp)))
+        return ((struct volume *)NULL);
+    while (vp) {
+        if (kread(ctx, (KA_T)vp, (char *)&v, sizeof(v)))
+            return ((struct volume *)NULL);
+        if (v.volume == f->Fid.Volume && v.cell == f->Cell)
+            return (&v);
+        vp = (KA_T)v.next;
+    }
+    return ((struct volume *)NULL);
+}
+
+/*
+ * hasAFS() - test for AFS presence via vfs structure
+ */
+
+int hasAFS(struct vnode *vp) /* vnode pointer */
+{
+    struct mounts *mp;
+    int n;
+    struct vfs v;
+    /*
+     * If this vnode has a v_data pointer, then it probably isn't an AFS vnode;
+     * return FALSE.
+     *
+     * If the vfs struct address of /afs is known and this vnode's v_vfsp
+     * matches it, return TRUE.
+     *
+     * Read this vnode's vfs structure and see if it's device (fsid.val[0]) is
+     * AFSdev.  If it is, record the AFS vfs struct address and return TRUE.
+     */
+    if (AFSVfsp && !vp->v_data && (KA_T)vp->v_vfsp == AFSVfsp)
+        return (1);
+    if (!AFSdevStat)
+        (void)readmnt();
+    if (!AFSdevStat || vp->v_data || !vp->v_vfsp ||
+        kread(ctx, (KA_T)vp->v_vfsp, (char *)&v, sizeof(v)) || v.vfs_data)
+        return (0);
+    if ((dev_t)v.vfs_fsid.val[0] == AFSdev) {
+        AFSVfsp = (KA_T)vp->v_vfsp;
+        return (1);
+    }
+    /*
+     * Search the local mount table for /afs devices.  Count /afs devices,
+     * and skip a device number test for them.  A match on device number for
+     * non-AFS devices produces a FALSE return.
+     */
+    for (mp = readmnt(), n = 0; mp; mp = mp->next) {
+        if (AFSdevStat && mp->dev == AFSdev && mp->dir &&
+            strcmp(mp->dir, "/afs") == 0 && mp->fsname &&
+            strcmp(mp->fsname, "AFS") == 0)
+            n++;
+        else if (mp->dev == (dev_t)v.vfs_fsid.val[0])
+            return (0);
+    }
+    /*
+     * If there is exactly one /afs device, assume its vfs struct address is
+     * the one for this vnode, record it, and return TRUE.
+     */
+    if (n == 1) {
+        AFSVfsp = (KA_T)vp->v_vfsp;
+        return (1);
+    }
+    return (0);
+}
+
+/*
+ * is_rootFid() - is the file ID the root file ID
+ *
+ * return: 0   = is not root file ID
+ *        1    = is root file ID
+ *        rfid = 0 if root file ID structure address not available
+ *               1 if root file ID structure address available
+ */
+
+static int is_rootFid(struct vcache *vc, /* vcache structure */
+                      int *rfid) /* root file ID pointer status return */
+{
+    KA_T arFid;
+    char *err;
+    static int f = 0; /* rootFid structure status:
+                       *     -1 = unavailable
+                       *       0 = not yet accessed
+                       *       1 = available */
+    static struct VenusFid r;
+    static int w = 0;
+
+    switch (f) {
+    case -1:
+        if (vc->v.v_flag & VROOT) {
+            *rfid = 1;
+            return (1);
+        }
+        *rfid = 0;
+        return (0);
+    case 0:
+        if (get_Nl_value("arFid", Drive_Nl, &arFid) < 0 || !arFid) {
+            err = "no afs_rootFid kernel address";
+
+        rfid_unavailable:
+
+            if (!w && !Fwarn) {
+                (void)fprintf(stderr, "%s: WARNING: AFS root Fid error: %s\n",
+                              Pn, err);
+                (void)fprintf(
+                    stderr,
+                    "      This may hamper AFS node number reporting.\n");
+                w = 1;
+            }
+            f = -1;
+            if (vc->v.v_flag & VROOT) {
+                *rfid = 1;
+                return (1);
+            }
+            *rfid = 0;
+            return (0);
+        }
+        if (kread(ctx, arFid, (char *)&r, sizeof(r))) {
+            err = "can't read afs_rootFid from kernel";
+            goto rfid_unavailable;
+        }
+        f = 1;
+        /* fall through */
+    case 1:
+        *rfid = 1;
+        if (vc->fid.Fid.Unique == r.Fid.Unique &&
+            vc->fid.Fid.Vnode == r.Fid.Vnode &&
+            vc->fid.Fid.Volume == r.Fid.Volume && vc->fid.Cell == r.Cell)
+            return (1);
+    }
+    *rfid = 0;
+    return (0);
+}
+
+/*
+ * readafsnode() - read AFS node
+ */
+
+int readafsnode(KA_T va,            /* kernel vnode address */
+                struct vnode *v,    /* vnode buffer pointer */
+                struct afsnode *an) /* afsnode recipient */
+{
+    char *cp, tbuf[32];
+    KA_T ka;
+    int len, rfid, vols;
+    struct vcache *vc;
+    struct volume *vp;
+
+    cp = ((char *)v + sizeof(struct vnode));
+    ka = (KA_T)((char *)va + sizeof(struct vnode));
+    len = sizeof(struct vcache) - sizeof(struct vnode);
+    if (kread(ctx, ka, cp, len)) {
+        (void)snpf(Namech, Namechl,
+                   "vnode at %s: can't read vcache remainder from %s",
+                   print_kptr(va, tbuf, sizeof(tbuf)),
+                   print_kptr(ka, (char *)NULL, 0));
+        enter_nm(ctx, Namech);
+        return (1);
+    }
+    vc = (struct vcache *)v;
+    if (!AFSdevStat)
+        (void)readmnt();
+    an->dev = AFSdevStat ? AFSdev : 0;
+    an->size = (unsigned long)vc->m.Length;
+    an->nlink = (long)vc->m.LinkCount;
+    an->nlink_st = 1;
+    /*
+     * Manufacture the "inode" number.
+     */
+    if (vc->mvstat == 2) {
+        if ((vp = getvolume(&vc->fid, &vols))) {
+            an->inode = (INODETYPE)((vp->mtpoint.Fid.Vnode +
+                                     (vp->mtpoint.Fid.Volume << 16)) &
+                                    0x7fffffff);
+            if (an->inode == (INODETYPE)0) {
+                if (is_rootFid(vc, &rfid))
+                    an->ino_st = 1;
+                else if (rfid) {
+                    an->inode = (INODETYPE)2;
+                    an->ino_st = 1;
+                } else
+                    an->ino_st = 0;
+            } else
+                an->ino_st = 1;
+        } else {
+            if (vols) {
+                an->inode = (INODETYPE)2;
+                an->ino_st = 1;
+            } else {
+                if (v->v_flag & VROOT) {
+                    an->inode = (INODETYPE)0;
+                    an->ino_st = 1;
+                } else
+                    an->ino_st = 0;
+            }
+        }
+    } else {
+        an->inode =
+            (INODETYPE)((vc->fid.Fid.Vnode + (vc->fid.Fid.Volume << 16)) &
+                        0x7fffffff);
+        an->ino_st = 1;
+    }
+    return (0);
+}
+#endif /* defined(HAS_AFS) */
diff --git a/lib/dialects/sun/dnode2.c b/lib/dialects/sun/dnode2.c
new file mode 100644 (file)
index 0000000..8ecbde2
--- /dev/null
@@ -0,0 +1,483 @@
+/*
+ * dnode2.c - Solaris node functions for lsof
+ *
+ * This module must be separate to keep separate the multiple kernel inode
+ * structure definitions.
+ */
+
+/*
+ * 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 1994 Purdue Research Foundation.\nAll rights reserved.\n";
+#endif
+
+#include "common.h"
+
+#if defined(HASVXFS)
+
+#    if defined(HASVXFSUTIL)
+#        include <vxfsutil.h>
+#        define EMSGPFX "vx_inode: "
+
+static char *add2em(char *em, char *fmt, char *arg);
+static char *ckptr(char *em, char *ptr, int len, int slen, char *nm);
+static char *getioffs(char **vx, int *vxl, char **dev, int *devl, char **ino,
+                      int *inol, char **nl, int *nll, char **sz, int *szl);
+#    else /* !defined(HASVXFSUTIL) */
+#        if defined(HASVXFS_FS_H) && !defined(HASVXFS_VX_INODE)
+#            undef fs_bsize
+#            include <sys/fs/vx_fs.h>
+#        endif /* defined(HASVXFS_FS_H) && !defined(HASVXFS_VX_INODE) */
+
+#        if HASVXFS_SOL_H
+#            include <sys/fs/vx_sol.h>
+#        endif /* defined(HSVXFS_SOL_H) */
+
+#        if defined(HASVXFS_SOLARIS_H) && defined(HASVXFS_U64_T)
+#            include <sys/fs/vx_solaris.h>
+#        endif /* defined(HASVXFS_SOLARIS_H) && defined(HASVXFS_U64_T) */
+
+#        if defined(HASVXFS_MACHDEP_H)
+#            if defined(HASVXFS_OFF32_T) && solaris >= 70000
+#                define off32_t VXFS_off32_t
+#            endif /* defined(HASVXFS_OFF32_T) && solaris>=70000 */
+#            include <sys/fs/vx_machdep.h>
+#        endif /* defined(HASVXFS_MACHDEP_H) */
+
+#        if defined(HASVXFS_SOLARIS_H)
+struct kdm_vnode { /* dummy for <sys/fs/vx_inode.h> */
+    int d1;
+};
+#            undef fs_bsize
+#            define uint16_t VXFS_uint16_t
+
+#            if defined(HASVXFS_OFF64_T)
+#                define off64_t VXFS_off64_t
+#            endif /* defined(HASVXFS_OFF64_T) */
+
+#            if defined(HASVXFS_SOLARIS_H) && !defined(HASVXFS_U64_T)
+#                include <sys/fs/vx_solaris.h>
+#            endif /* defined(HASVXFS_SOLARIS_H) && !defined(HASVXFS_U64_T) */
+
+#            include <sys/fs/vx_layout.h>
+#            include <sys/fs/vx_const.h>
+#            include <sys/fs/vx_mlink.h>
+#        endif /* defined(HASVXFS_SOLARIS_H) */
+
+#        include <sys/fs/vx_inode.h>
+#    endif /* defined(HASVXFSUTIL) */
+
+#    if defined(HASVXFSUTIL)
+static struct vx_ioffsets Ioffsets; /* VXFS inode offsets */
+static int Ioffs_state = -1;        /* Ioffsets state:
+                                     *   -1 = uninitialized
+                                     *    0 = initialized
+                                     *   >0 = initialization error */
+
+/*
+ * access_vxfs_ioffsets() - access the VXFS inode offsets
+ */
+
+extern int access_vxfs_ioffsets() {
+
+    /*
+     * This operation is done in an external function, so it can be done before
+     * GID permission has been surrendered.
+     */
+    Ioffs_state = vxfsu_get_ioffsets(&Ioffsets, sizeof(Ioffsets));
+    return (Ioffs_state);
+}
+
+/*
+ * add2em() - add to error message
+ */
+
+static char *add2em(char *em,  /* current error message */
+                    char *fmt, /* message format */
+                    char *arg) /* format's single string argument */
+{
+    MALLOC_S al, eml, nl;
+    char msg[1024];
+    MALLOC_S msgl = (MALLOC_S)sizeof(msg);
+
+    (void)snpf(msg, msgl, fmt, arg);
+    msg[msgl - 1] = '\0';
+    nl = (MALLOC_S)strlen(msg);
+    if (!em) {
+        al = (MALLOC_S)strlen(EMSGPFX) + nl + 1;
+        em = (char *)malloc((MALLOC_S)al);
+        eml = (MALLOC_S)0;
+    } else {
+        if (!(eml = (MALLOC_S)strlen(em))) {
+            (void)fprintf(stderr, "%s: add2em: previous message empty\n", Pn);
+            Error(ctx);
+        }
+        al = eml + nl + 3;
+        em = (char *)realloc((MALLOC_P *)em, al);
+    }
+    if (!em) {
+        (void)fprintf(stderr, "%s: no VxFS error message space\n", Pn);
+        Error(ctx);
+    }
+    (void)snpf(em + eml, al - eml, "%s%s%s", eml ? "" : EMSGPFX,
+               eml ? "; " : "", msg);
+    return (em);
+}
+
+/*
+ * ckptr() - check pointer and length
+ */
+
+static char *ckptr(char *em,  /* pointer to previous error message */
+                   char *ptr, /* pointer to check */
+                   int len,   /* pointer's value length */
+                   int slen,  /* value's storage length */
+                   char *nm)  /* element name */
+{
+
+#        if defined(_LP64)
+#            define PTR_CAST unsigned long long
+#        else /* !defined(_LP64) */
+#            define PTR_CAST unsigned long
+#        endif /* defined(_LP64) */
+
+    PTR_CAST m;
+    char tbuf[1024];
+
+    if (!ptr)
+        return (add2em(em, "no %s pointer", nm ? nm : "(null)"));
+    if (len > slen) {
+        (void)snpf(tbuf, sizeof(tbuf) - 1, "%s size, %d, > %d",
+                   nm ? nm : "(null)", len, slen);
+        tbuf[sizeof(tbuf) - 1] = '\0';
+        return (add2em(em, "%s", tbuf));
+    }
+    if ((m = (PTR_CAST)(len - 1)) < (PTR_CAST)1)
+        return (em);
+    if ((PTR_CAST)ptr & m)
+        return (add2em(em, "%s misaligned", nm ? nm : "(null)"));
+    return (em);
+}
+
+/*
+ * getioffs() - get the vx_inode offsets
+ */
+
+static char *getioffs(char **vx,  /* pointer to allocated vx_inode space */
+                      int *vxl,   /* sizeof(*vx) */
+                      char **dev, /* pointer to device number element of *vx */
+                      int *devl,  /* sizeof(*dev) */
+                      char **ino, /* pointer to node number element of *vx */
+                      int *inol,  /* sizeof(*ino) */
+                      char **nl,  /* pointer to nlink element of *vx */
+                      int *nll,   /* sizeof(*nl) */
+                      char **sz,  /* pointer to size element of *vx */
+                      int *szl)   /* sizeof(*sz) */
+{
+    char *tv;
+    int tvl;
+
+    if (Ioffs_state)
+        return (add2em((char *)NULL, "%s error", "vxfsu_get_ioffsets"));
+    tvl = (int)(Ioffsets.ioff_dev + Ioffsets.ioff_dev_sz);
+    if ((Ioffsets.ioff_nlink + Ioffsets.ioff_nlink_sz) > tvl)
+        tvl = (int)(Ioffsets.ioff_nlink + Ioffsets.ioff_nlink_sz);
+    if ((Ioffsets.ioff_number + Ioffsets.ioff_number_sz) > tvl)
+        tvl = (int)(Ioffsets.ioff_number + Ioffsets.ioff_number_sz);
+    if ((Ioffsets.ioff_size + Ioffsets.ioff_size_sz) > tvl)
+        tvl = (int)(Ioffsets.ioff_size + Ioffsets.ioff_size_sz);
+    if (!tvl)
+        return (add2em((char *)NULL, "zero length %s", "vx_inode"));
+    if (!(tv = (char *)malloc((MALLOC_S)tvl))) {
+        (void)fprintf(stderr, "%s: no vx_inode space\n", Pn);
+        Error(ctx);
+    }
+    *vx = tv;
+    *vxl = tvl;
+    *dev = tv + Ioffsets.ioff_dev;
+    *devl = (int)Ioffsets.ioff_dev_sz;
+    *ino = tv + Ioffsets.ioff_number;
+    *inol = (int)Ioffsets.ioff_number_sz;
+    *nl = tv + Ioffsets.ioff_nlink;
+    *nll = (int)Ioffsets.ioff_nlink_sz;
+    *sz = tv + Ioffsets.ioff_size;
+    *szl = (int)Ioffsets.ioff_size_sz;
+    return ((char *)NULL);
+}
+
+#        if defined(HASVXFSRNL)
+
+#            define RNLCINIT 64 /* inital RNL cache size */
+#            define RNLCINCR 32 /* RNL cache increment */
+
+/*
+ * print_vxfs_rnl_path() -- print VxFS RNL path
+ */
+
+int print_vxfs_rnl_path(struct lfile *lf) /* file whose name is to be printed */
+{
+    char **bp = (char **)NULL;
+    int i, j, n, p;
+    typedef struct rmc { /* RNL mount point cache */
+        char *mp;        /* mount point */
+        unsigned char s; /* RNL status: 0 = supported
+                          *           1 = not supported */
+    } rmc_t;
+    static rmc_t *rm = (rmc_t *)NULL;
+    /* RNL mount point cache */
+    static int rma = 0; /* allocated cache entries */
+    static int rmu = 0; /* used cache entries */
+    size_t sz;
+    /*
+     * This must be a VxFS file, it must have an inode and its mount point must
+     * be known.
+     */
+    if (!lf->is_vxfs || (lf->inp_ty != 1) || !lf->fsdir)
+        return (0);
+    /*
+     * Locate or create an RNL mount point cache entry.
+     */
+    for (i = 0; i < rmu; i++) {
+        if (rm[i].mp == lf->fsdir)
+            break;
+    }
+    if (i >= rmu) {
+
+        /*
+         * A new entry must be created.
+         */
+        if (i >= rma) {
+
+            /*
+             * RNL mount point cache space must be allocated.
+             */
+            rma += rm ? RNLCINCR : RNLCINIT;
+            sz = (size_t)(rma * sizeof(rmc_t));
+            if (rm)
+                rm = (rmc_t *)realloc((MALLOC_P *)rm, (MALLOC_S)sz);
+            else
+                rm = (rmc_t *)malloc((MALLOC_S)sz);
+            if (!rm) {
+                (void)fprintf(stderr, "%s: no RNL mount point cache space\n",
+                              Pn);
+                Error(ctx);
+            }
+        }
+        i = rmu;
+        rm[rmu].mp = lf->fsdir;
+        rm[rmu++].s = 0;
+    }
+    if (rm[i].s)
+        return (0);
+    /*
+     * Get the RNL path for this mount point and inode.
+     */
+    if (vxfs_inotopath(lf->fsdir, (uint64_t)lf->inode, 0, &bp, &n)) {
+        if (errno == ENOTSUP)
+            rm[i].s = 1;
+        return (0);
+    }
+    /*
+     * Print the first RNL path, then free the allocated function reply space.
+     */
+    if (bp) {
+        for (j = 0; j < n; j++) {
+            if (bp[j] && *bp[j]) {
+                safestrprt(bp[j], stdout, 0);
+                p = 1;
+                break;
+            }
+        }
+        for (j = 0; j < n; j++) {
+            if (bp[j])
+                (void)free((FREE_P *)bp[j]);
+        }
+        (void)free((FREE_P *)bp);
+    } else
+        p = 0;
+    return (p);
+}
+#        endif /* defined(HASVXFSRNL) */
+#    endif     /* defined(HASVXFSUTIL) */
+
+/*
+ * read_vxnode() - read Veritas file system inode information
+ */
+
+int read_vxnode(KA_T va,           /* containing vnode's address */
+                struct vnode *v,   /* containing vnode */
+                struct l_vfs *vfs, /* local vfs structure */
+                int fx,            /* file system index (-1 if none) */
+                struct l_ino *li,  /* local inode value receiver */
+                KA_T *vnops)       /* table of VxFS v_op values */
+{
+    struct vnode cv;
+    char tbuf[32];
+
+#    if defined(HASVXFS_VX_INODE)
+    struct vx_inode vx;
+    int vxl = (int)sizeof(vx);
+    dev_t *vxn_dev = (dev_t *)&vx.i_dev;
+    int *vxn_nlink = (int *)&vx.i_nlink;
+    unsigned int *vxn_ino = (unsigned int *)&vx.i_number;
+    SZOFFTYPE *vxn_sz = (SZOFFTYPE *)&vx.i_size;
+    char *vxp = (char *)&vx;
+#    else /* !defined(HASVXFS_VX_INODE) */
+#        if defined(HASVXFSUTIL)
+    static char *em = (char *)NULL;
+    int devl, nll, szl;
+    static int inol;
+    static char *vxp = (char *)NULL;
+    static int vxl = 0;
+    static dev_t *vxn_dev = (dev_t *)NULL;
+    static int *vxn_nlink = (int *)NULL;
+    static char *vxn_ino = (char *)NULL;
+    static SZOFFTYPE *vxn_sz = (SZOFFTYPE *)NULL;
+#        else  /* !defined(HASVXFSUTIL) */
+    struct inode vx;
+    int vxl = sizeof(vx);
+    dev_t *vxn_dev = (dev_t *)&vx.i_dev;
+    int *vxn_nlink = (int *)&vx.i_nlink;
+    long *vxn_ino = (long *)&vx.i_number;
+    SZOFFTYPE *vxn_sz = (SZOFFTYPE *)&vx.i_size;
+    char *vxp = (char &)&vx;
+#        endif /* defined(HASVXFSUTIL) */
+#    endif     /* defined(HASVXFS_VX_INODE) */
+
+    li->dev_def = li->ino_def = li->nl_def = li->rdev_def = li->sz_def = 0;
+    /*
+     * See if this is vnode is served by fdd_chain_vnops.  If it is, its
+     * v_data pointer leads to the "real" vnode.
+     */
+    if (v->v_data && v->v_op && (VXVOP_FDDCH < VXVOP_NUM) &&
+        vnops[VXVOP_FDDCH] && ((KA_T)v->v_op == vnops[VXVOP_FDDCH])) {
+        if (kread(ctx, (KA_T)v->v_data, (char *)&cv, sizeof(cv))) {
+            (void)snpf(Namech, Namechl,
+                       "node at %s: can't read real vx vnode: %s",
+                       print_kptr(va, tbuf, sizeof(tbuf)),
+                       print_kptr((KA_T)v->v_data, (char *)NULL, 0));
+            enter_nm(ctx, Namech);
+            return (1);
+        }
+
+#    if defined(HASNCACHE)
+        Lf->na = (KA_T)v->v_data;
+#    endif /* defined(HASNCACHE) */
+
+        *v = cv;
+        Ntype = vop2ty(v, fx);
+    }
+
+#    if defined(HASVXFSUTIL)
+    /*
+     * If libvxfsutil[64].a is in use, establish the vx_inode size and the
+     * locations and sizes of its device, link count, node number, and size
+     * elements.
+     *
+     * If an error was detected while determining the vx_inode values, repeat
+     * the error explanation in the NAME column.
+     */
+    if (!vxp && !em) {
+        em = getioffs(&vxp, &vxl, (char **)&vxn_dev, &devl, &vxn_ino, &inol,
+                      (char **)&vxn_nlink, &nll, (char **)&vxn_sz, &szl);
+        if (!em) {
+
+            /*
+             * Check the returned pointers and their sizes.
+             */
+            em = ckptr(em, (char *)vxn_dev, devl, sizeof(dev_t), "dev");
+            em = ckptr(em, (char *)vxn_ino, inol, sizeof(INODETYPE), "ino");
+            em = ckptr(em, (char *)vxn_nlink, nll, sizeof(int), "nlink");
+            em = ckptr(em, (char *)vxn_sz, szl, sizeof(SZOFFTYPE), "sz");
+        }
+    }
+    if (em) {
+        (void)snpf(Namech, Namechl, "%s", em);
+        (void)enter_nm(ctx, Namech);
+        return (1);
+    }
+#    endif /* !defined(HASVXFSUTIL) */
+
+    /*
+     * Read vnode's vx_inode.
+     */
+    if (!v->v_data || kread(ctx, (KA_T)v->v_data, vxp, vxl)) {
+        (void)snpf(Namech, Namechl, "node at %s: can't read vx_inode: %s",
+                   print_kptr(va, tbuf, sizeof(tbuf)),
+                   print_kptr((KA_T)v->v_data, (char *)NULL, 0));
+        (void)enter_nm(ctx, Namech);
+        return (1);
+    }
+    /*
+     * Return device number, inode number, link count, raw device number, and
+     * size.
+     */
+    if (vfs && vfs->fsname) {
+        li->dev = (dev_t)vfs->dev;
+        li->dev_def = 1;
+    } else if (vxn_dev) {
+        li->dev = (dev_t)*vxn_dev;
+        li->dev_def = 1;
+    }
+    if (vxn_ino) {
+
+#    if defined(HASVXFSUTIL)
+        switch (inol) {
+        case sizeof(short):
+            li->ino = (INODETYPE) * ((short *)vxn_ino);
+            li->ino_def = 1;
+            break;
+        case sizeof(unsigned int):
+            li->ino = (INODETYPE) * ((unsigned int *)vxn_ino);
+            li->ino_def = 1;
+            break;
+        case sizeof(unsigned long long):
+            li->ino = (INODETYPE) * ((unsigned long long *)vxn_ino);
+            li->ino_def = 1;
+            break;
+        default:
+            break;
+        }
+#    else  /* !defined(HASVXFSUTIL) */
+        li->ino = (INODETYPE)*vxn_ino;
+        li->ino_def = 1;
+#    endif /* defined(HASVXFSUTIL) */
+    }
+    if (vxn_nlink) {
+        li->nl = (long)*vxn_nlink;
+        li->nl_def = 1;
+    }
+    li->rdev = v->v_rdev;
+    li->rdev_def = 1;
+    if (vxn_sz) {
+        li->sz = (SZOFFTYPE)*vxn_sz;
+        li->sz_def = 1;
+    }
+    return (0);
+}
+#endif /* defined(HASVXFS) */
diff --git a/lib/dialects/sun/dproc.c b/lib/dialects/sun/dproc.c
new file mode 100644 (file)
index 0000000..21f91f8
--- /dev/null
@@ -0,0 +1,2138 @@
+/*
+ * dproc.c - Solaris lsof functions for accessing process information
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#ifndef lint
+static char copyright[] =
+    "@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
+#endif
+
+#include "common.h"
+
+#if solaris < 20500
+#    include "kernelbase.h"
+#endif /* solaris<20500 */
+
+#if defined(HAS_CRED_IMPL_H)
+#    if solaris >= 110000
+#        define _KERNEL
+#    endif /* solaris>=110000 */
+
+#    include <sys/cred_impl.h>
+
+#    if solaris >= 110000
+#        undef _KERNEL
+#    endif /* solaris>=110000 */
+#endif     /* defined(HAS_CRED_IMPL_H) */
+
+/*
+ * Local definitions
+ */
+
+#if defined(__sparc) || defined(__sparcv9)
+#    define ARCH64B "sparcv9"
+#else /* !defined(__sparc) && !defined(__sparcv9) */
+#    if defined(__i386) || defined(__amd64)
+#        define ARCH64B "amd64"
+#    endif /* defined(__i386) || defined(__amd64) */
+#endif     /* defined(__sparc) || defined(__sparcv9) */
+
+#if solaris >= 20501
+#    define KVMHASHBN                                                          \
+        8192 /* KVM hash bucket count -- MUST BE                               \
+              * A POWER OF 2!!! */
+#    define HASHKVM(va) ((int)((va * 31415) >> 3) & (KVMHASHBN - 1))
+/* virtual address hash function */
+
+#    if solaris < 70000
+#        define KAERR (u_longlong_t) - 1 /* kvm_physaddr() error return */
+#        define KBUFT char               /* kernel read buffer type */
+#        define KPHYS u_longlong_t       /* kernel physical address type */
+#        define KVIRT u_int              /* kernel virtual address type */
+#    else                                /* solaris>=70000 */
+#        define KAERR (uint64_t) - 1     /* kvm_physaddr() error return */
+#        define KBUFT void               /* kernel read buffer type */
+#        define KPHYS uint64_t           /* kernel physical address type */
+#        define KVIRT uintptr_t          /* kernel virtual address type */
+#    endif                               /* solaris<70000 */
+#endif                                   /* solaris>=20501 */
+
+/*
+ * Local structures
+ */
+
+#if solaris >= 20501
+typedef struct kvmhash {
+    KVIRT vpa;           /* virtual page address */
+    KPHYS pa;            /* physical address */
+    struct kvmhash *nxt; /* next virtual address */
+} kvmhash_t;
+#endif /* solaris>=20501 */
+
+/*
+ * Local variables
+ */
+
+#if solaris >= 20501
+static struct as *Kas = (struct as *)NULL;
+/* pointer to kernel's address space
+ * map in kernel virtual memory */
+static kvmhash_t **KVMhb = (kvmhash_t **)NULL;
+/* KVM hash buckets */
+static int PageSz = 0; /* page size */
+static int PSMask = 0; /* page size mask */
+static int PSShft = 0; /* page size shift */
+
+#    if solaris < 70000
+static struct as Kam; /* kernel's address space map */
+static int Kmd = -1;  /* memory device file descriptor */
+#    endif            /* solaris<70000 */
+#endif                /* solaris>=20501 */
+
+#if solaris >= 20500
+static KA_T Kb = (KA_T)NULL; /* KERNELBASE for Solaris 2.5 */
+#endif                       /* solaris>=20500 */
+
+static int Np;                  /* number of P[], Pgid[] and Pid[]
+                                 * entries  */
+static int Npa = 0;             /* number of P[], Pgid[] and Pid[]
+                                 * entries for which space has been
+                                 * allocated */
+static struct proc *P = NULL;   /* local proc structure table */
+static int *Pgid = NULL;        /* process group IDs for P[] entries */
+static int *Pid = NULL;         /* PIDs for P[] entries */
+static KA_T PrAct = (KA_T)NULL; /* kernel's *practive address */
+static gid_t Savedgid;          /* saved (effective) GID */
+static KA_T Sgvops;             /* [_]segvn_ops address */
+static int Switchgid = 0;       /* must switch GIDs for kvm_open() */
+
+#if defined(HASZONES)
+static znhash_t **ZoneNm = (znhash_t **)NULL;
+/* zone names hash buckets */
+#endif /* defined(HASZONES) */
+
+/*
+ * Local function prototypes
+ */
+
+static void get_kernel_access(struct lsof_context *ctx);
+static void process_text(struct lsof_context *ctx, KA_T pa);
+static void read_proc(struct lsof_context *ctx);
+static void readfsinfo(struct lsof_context *ctx);
+
+#if solaris >= 20501
+static void readkam(struct lsof_context *ctx, KA_T addr);
+#endif /* solaris>=20501 */
+
+#if solaris >= 20501 && solaris < 70000
+extern u_longlong_t kvm_physaddr(kvm_t *, struct as *, u_int);
+#endif /* solaris>=20501 && solaris<70000 */
+
+#if defined(HASZONES)
+static int hash_zn(char *zn);
+#endif /* defined(HASZONES) */
+
+/*
+ * close_kvm() - close kernel virtual memory access
+ */
+
+void close_kvm(struct lsof_context *ctx) {
+    if (!Kd)
+        return;
+    if (Kd) {
+        if (kvm_close(Kd) != 0) {
+            (void)fprintf(stderr, "%s: kvm_close failed\n", Pn);
+            Error(ctx);
+        }
+        Kd = (kvm_t *)NULL;
+    }
+
+#if solaris >= 20501 && solaris < 70000
+    if (Kmd >= 0) {
+        (void)close(Kmd);
+        Kmd = -1;
+    }
+#endif /* solaris>=20501 && solaris<70000 */
+}
+
+/*
+ * gather_proc_info() - gather process information
+ */
+
+void gather_proc_info(struct lsof_context *ctx) {
+    short cckreg; /* conditional status of regular file
+                   * checking:
+                   *     0 = unconditionally check
+                   *     1 = conditionally check */
+    short ckscko; /* socket file only checking status:
+                   *     0 = none
+                   *     1 = check only socket files,
+                   *      including TCP and UDP
+                   *      streams with eXPORT data,
+                   *      where supported */
+    static int ft = 1;
+    int i, j;
+    struct proc *p;
+    int pgid, pid, px;
+    long pofv;
+    short pss, sf;
+    struct user *u;
+    uid_t uid;
+
+#if solaris >= 20400
+    int k;
+
+#    if !defined(NFPCHUNK)
+#        define uf_ofile uf_file
+#        define uf_pofile uf_flag
+#        define u_flist u_finfo.fi_list
+#        define u_nofiles u_finfo.fi_nfiles
+#        define NFPREAD 64
+#    else /* defined(NFPCHUNK) */
+#        define NFPREAD NFPCHUNK
+#    endif /* !defined(NFPCHUNK) */
+    uf_entry_t uf[NFPREAD];
+#endif /* solaris>=20400 */
+#if solaris >= 20500
+    struct cred pc;
+#endif /* solaris>=20500 */
+
+#if defined(HASZONES)
+    struct zone z;
+    int zh;
+    char zn[ZONENAME_MAX + 1];
+    znhash_t *zp, *zpn;
+#endif /* defined(HASZONES) */
+
+    if (ft) {
+        /*
+         * Do first-time only operations.
+         */
+        /*
+         * Get the segment vnodeops address.
+         */
+        if (get_Nl_value(ctx, "sgvops", Drive_Nl, &Sgvops) < 0)
+            Sgvops = (KA_T)NULL;
+        ft = 0;
+    } else if (!HasALLKMEM) {
+
+        /*
+         * If not the first time and the ALLKMEM device isn't available, it is
+         * necessary to close and reopen the KVM device, so that kvm_open()
+         * will acquire a fresh address for the head of the linked list process
+         * table.
+         */
+        close_kvm(ctx);
+        open_kvm(ctx);
+
+#if solaris >= 20501
+        /*
+         * If not the first time and the ALLKMEM device isn't available,
+         * re-read the kernel's address space map.
+         */
+        readkam(ctx, (KA_T)NULL);
+#endif /* solaris>=20501 */
+    }
+    /*
+     * Define socket and regular file conditional processing flags.
+     *
+     * If only socket files have been selected, or socket files have been
+     * selected, ANDed with other selection options, enable the skipping of
+     * regular files.
+     *
+     * If socket files and some process options have been selected, enable
+     * conditional skipping of regular file; i.e., regular files will be skipped
+     * unless they belong to a process selected by one of the specified options.
+     */
+    if (Selflags & SELNW) {
+
+        /*
+         * Some network files selection options have been specified.
+         */
+        if (Fand || !(Selflags & ~SELNW)) {
+
+            /*
+             * Selection ANDing or only network file options have been
+             * specified, so set unconditional skipping of regular files
+             * and socket file only checking.
+             */
+            cckreg = 0;
+            ckscko = 1;
+        } else {
+
+            /*
+             * If ORed file selection options have been specified, or no
+             * ORed process selection options have been specified, enable
+             * unconditional file checking and clear socket file only
+             * checking.
+             *
+             * If only ORed process selection options have been specified,
+             * enable conditional file skipping and socket file only checking.
+             */
+            if ((Selflags & SELFILE) || !(Selflags & SELPROC))
+                cckreg = ckscko = 0;
+            else
+                cckreg = ckscko = 1;
+        }
+    } else {
+
+        /*
+         * No network file selection options were specified.  Enable
+         * unconditional file checking and clear socket file only checking.
+         */
+        cckreg = ckscko = 0;
+    }
+    /*
+     * Read the process table.
+     */
+    read_proc(ctx);
+    /*
+     * Loop through processes.
+     */
+    for (p = P, px = 0; px < Np; p++, px++) {
+
+        /*
+         * Get the process ID.
+         */
+
+        if (Fpgid)
+            pgid = Pgid[px];
+        else
+            pgid = 0;
+        pid = Pid[px];
+
+#if solaris < 20500
+        uid = p->p_uid;
+#else  /* solaris >=20500 */
+        /*
+         * Read credentials for Solaris 2.5 and above process.
+         */
+        if (kread(ctx, (KA_T)p->p_cred, (char *)&pc, sizeof(pc)))
+            continue;
+        uid = pc.cr_uid;
+#endif /* solaris<20500 */
+
+        /*
+         * See if the process is excluded.
+         */
+        if (is_proc_excl(ctx, pid, pgid, (UID_ARG)uid, &pss, &sf))
+            continue;
+
+#if defined(HASZONES)
+        /*
+         * If the -z (zone) option was specified, get the zone name.
+         */
+        if (Fzone) {
+            zn[0] = zn[sizeof(zn) - 1] = '\0';
+            if (p->p_zone &&
+                !kread(ctx, (KA_T)p->p_zone, (char *)&z, sizeof(z))) {
+                if (!z.zone_name ||
+                    kread(ctx, (KA_T)z.zone_name, (char *)&zn, sizeof(zn) - 1))
+                    zn[0] = '\0';
+            }
+        }
+#endif /* defined(HASZONES) */
+
+        /*
+         * Get the user area associated with the process.
+         */
+        u = &p->p_user;
+        /*
+         * Allocate a local process structure and start filling it.
+         */
+        if (is_cmd_excl(ctx, u->u_comm, &pss, &sf))
+            continue;
+        if (cckreg) {
+
+            /*
+             * If conditional checking of regular files is enabled, enable
+             * socket file only checking, based on the process' selection
+             * status.
+             */
+            ckscko = (sf & SELPROC) ? 0 : 1;
+        }
+        alloc_lproc(ctx, pid, pgid, (int)p->p_ppid, (UID_ARG)uid, u->u_comm,
+                    (int)pss, (int)sf);
+        Plf = (struct lfile *)NULL;
+
+#if defined(HASZONES)
+        /*
+         * If zone processing is enabled and requested, and if there is a zone
+         * name:
+         *
+         *     o Skip processes excluded by zone name.
+         *     o Save zone name.
+         */
+        if (Fzone && zn[0]) {
+            zh = hash_zn(zn);
+            if (ZoneArg) {
+
+                /*
+                 * See if zone name excludes the process.
+                 */
+                for (zp = ZoneArg[zh]; zp; zp = zp->next) {
+                    if (!strcmp(zn, zp->zn))
+                        break;
+                }
+                if (!zp)
+                    continue;
+                zp->f = 1;
+                Lp->pss |= PS_PRI;
+                Lp->sf |= SELZONE;
+            }
+            /*
+             * Make sure the zone name is cached, then save a pointer to it in
+             * the local proc structure.
+             */
+            if (!ZoneNm) {
+                if (!(ZoneNm =
+                          (znhash_t **)calloc(HASHZONE, sizeof(znhash_t *)))) {
+                    (void)fprintf(stderr, "%s: no space for zone name hash\n",
+                                  Pn);
+                    Error(ctx);
+                }
+            }
+            for (zp = ZoneNm[zh]; zp; zp = zp->next) {
+                if (!strcmp(zn, zp->zn))
+                    break;
+            }
+            if (!zp) {
+
+                /*
+                 * The zone name isn't cached, so cache it.
+                 */
+                if (!(zp = (znhash_t *)malloc((MALLOC_S)sizeof(znhash_t)))) {
+                    (void)fprintf(stderr, "%s: no zone name cache space: %s\n",
+                                  Pn, zn);
+                    Error(ctx);
+                }
+                if (!(zp->zn = mkstrcpy(zn, (MALLOC_S *)NULL))) {
+                    (void)fprintf(stderr,
+                                  "%s: no zone name space at PID %d: %s\n", Pn,
+                                  (int)Lp->pid, zn);
+                    Error(ctx);
+                }
+                zp->next = ZoneNm[zh];
+                ZoneNm[zh] = zp;
+            }
+            Lp->zn = zp->zn;
+        }
+#endif /* defined(HASZONES) */
+
+        /*
+         * Save file count.
+         */
+        Unof = u->u_nofiles;
+        /*
+         * Save current working directory information.
+         */
+        if (!ckscko && u->u_cdir) {
+            alloc_lfile(ctx, LSOF_FD_CWD, -1);
+
+#if defined(FILEPTR)
+            FILEPTR = (struct file *)NULL;
+#endif /* defined(FILEPTR) */
+
+            process_node(ctx, (KA_T)u->u_cdir);
+            if (Lf->sf)
+                link_lfile(ctx);
+        }
+        /*
+         * Save root directory information.
+         */
+        if (!ckscko && u->u_rdir) {
+            alloc_lfile(ctx, LSOF_FD_ROOT_DIR, -1);
+
+#if defined(FILEPTR)
+            FILEPTR = (struct file *)NULL;
+#endif /* defined(FILEPTR) */
+
+            process_node(ctx, (KA_T)u->u_rdir);
+            if (Lf->sf)
+                link_lfile(ctx);
+        }
+        /*
+         * Save information on text files.
+         */
+        if (!ckscko && p->p_as && Sgvops) {
+
+#if defined(FILEPTR)
+            FILEPTR = (struct file *)NULL;
+#endif /* defined(FILEPTR) */
+
+            process_text(ctx, (KA_T)p->p_as);
+        }
+        /*
+         * Save information on file descriptors.
+         *
+         * Under Solaris the file pointers are stored in dynamically-linked
+         * ufchunk structures, each containing NFPREAD file pointers.  The
+         * first ufchunk structure is in the user area.
+         *
+         * Under Solaris 2.4 the file pointers are in a dynamically allocated,
+         * contiguous memory block.
+         */
+
+#if solaris < 20400
+        for (i = 0, j = 0; i < u->u_nofiles; i++) {
+            if (++j > NFPCHUNK) {
+                if (!u->u_flist.uf_next)
+                    break;
+                if (kread(ctx, (KA_T)u->u_flist.uf_next, (char *)&u->u_flist,
+                          sizeof(struct ufchunk)))
+                    break;
+                j = 1;
+            }
+            if (!u->u_flist.uf_ofile[j - 1])
+#else  /* solaris>=20400 */
+        for (i = 0, j = NFPREAD; i < u->u_nofiles; i++) {
+            if (++j > NFPREAD) {
+                k = u->u_nofiles - i;
+                if (k > NFPREAD)
+                    k = NFPREAD;
+                if (kread(ctx,
+                          (KA_T)((unsigned long)u->u_flist +
+                                 i * sizeof(uf_entry_t)),
+                          (char *)&uf, k * sizeof(uf_entry_t))) {
+                    break;
+                }
+                j = 1;
+            }
+            if (!uf[j - 1].uf_ofile)
+#endif /* solaris<20400 */
+
+                continue;
+            alloc_lfile(ctx, LSOF_FD_NUMERIC, i);
+
+#if solaris < 20400
+            pofv = (long)u->u_flist.uf_pofile[j - 1];
+            process_file(ctx, (KA_T)u->u_flist.uf_ofile[j - 1]);
+#else  /* solaris>=20400 */
+            pofv = uf[j - 1].uf_pofile;
+            process_file(ctx, (KA_T)uf[j - 1].uf_ofile);
+#endif /* solaris <20400 */
+
+            if (Lf->sf) {
+
+#if defined(HASFSTRUCT)
+                Lf->pof = pofv;
+#endif /* defined(HASFSTRUCT) */
+
+                link_lfile(ctx);
+            }
+        }
+        /*
+         * Examine results.
+         */
+        if (examine_lproc(ctx))
+            return;
+    }
+}
+
+/*
+ * get_kernel_access() - access the required information in the kernel
+ */
+
+static void get_kernel_access(struct lsof_context *ctx) {
+    int i;
+    struct stat sb;
+    KA_T v;
+
+#if defined(HAS_AFS)
+    struct nlist *nl = (struct nlist *)NULL;
+#endif /* defined(HAS_AFS) */
+
+    /*
+     * Check the Solaris or SunOS version number; check the SunOS architecture.
+     */
+    (void)ckkv(ctx, "Solaris", LSOF_VSTR, (char *)NULL, (char *)NULL);
+
+#if solaris >= 70000
+    /*
+     * Compare the Solaris 7 and above lsof compilation bit size with the kernel
+     * bit size.
+     *
+     * Quit on a mismatch.
+     */
+    {
+        char *cp, isa[1024];
+        short kbits = 32;
+
+#    if defined(_LP64)
+        short xkbits = 64;
+#    else  /* !defined(_LP64) */
+        short xkbits = 32;
+#    endif /* defined(_LP64) */
+
+        if (sysinfo(SI_ISALIST, isa, (long)sizeof(isa)) < 0) {
+            (void)fprintf(stderr, "%s: can't get ISA list: %s\n", Pn,
+                          strerror(errno));
+            Error(ctx);
+        }
+        for (cp = isa; *cp;) {
+            if (strncmp(cp, ARCH64B, strlen(ARCH64B)) == 0) {
+                kbits = 64;
+                break;
+            }
+            if (!(cp = strchr(cp, ' ')))
+                break;
+            cp++;
+        }
+        if (kbits != xkbits) {
+            (void)fprintf(stderr,
+                          "%s: FATAL: lsof was compiled for a %d bit kernel,\n",
+                          Pn, (int)xkbits);
+            (void)fprintf(
+                stderr, "      but this machine has booted a %d bit kernel.\n",
+                (int)kbits);
+            Error(ctx);
+        }
+    }
+#endif /* solaris>=70000 */
+
+    /*
+     * Get kernel symbols.
+     */
+    if (Nmlst && !is_readable(ctx, Nmlst, 1))
+        Error(ctx);
+    (void)build_Nl(ctx, Drive_Nl);
+
+#if defined(HAS_AFS)
+    if (!Nmlst) {
+
+        /*
+         * If AFS is defined and we're getting kernel symbol values from
+         * from N_UNIX, make a copy of Nl[] for possible use with the AFS
+         * modload file.
+         */
+        if (!(nl = (struct nlist *)malloc(Nll))) {
+            (void)fprintf(stderr, "%s: no space (%d) for Nl[] copy\n", Pn, Nll);
+            Error(ctx);
+        }
+        (void)memcpy((void *)nl, (void *)Nl, (size_t)Nll);
+    }
+#endif /* defined(HAS_AFS) */
+
+    if (nlist(Nmlst ? Nmlst : N_UNIX, Nl) < 0) {
+        (void)fprintf(stderr, "%s: can't read namelist from %s\n", Pn,
+                      Nmlst ? Nmlst : N_UNIX);
+        Error(ctx);
+    }
+
+#if defined(HAS_AFS)
+    if (nl) {
+
+        /*
+         * If AFS is defined and we're getting kernel symbol values from
+         * N_UNIX, and if any X_AFS_* symbols isn't there, see if it is in the
+         * the AFS modload file.  Make sure that other symbols that appear in
+         * both name list files have the same values.
+         */
+        if ((get_Nl_value(ctx, "arFID", Drive_Nl, &v) >= 0 && !v) ||
+            (get_Nl_value(ctx, "avops", Drive_Nl, &v) >= 0 && !v) ||
+            (get_Nl_value(ctx, "avol", Drive_Nl, &v) >= 0 && !v))
+            (void)ckAFSsym(nl);
+        (void)free((MALLOC_P *)nl);
+    }
+#endif /* defined(HAS_AFS) */
+
+    /*
+     * Determine the availability of the ALLKMEM device.  If it is available,
+     * the active processes will be gathered directly from the active process
+     * chain.
+     *
+     * If ALLKMEM isn't available, the active processes will be gathered via the
+     * kvm_*proc() functions.
+     */
+    if (statsafely(ctx, ALLKMEM, &sb) == 0)
+        HasALLKMEM = 1;
+
+#if defined(HASVXFSUTIL)
+    /*
+     * If the VXFS utility library is being used, attempt to get the VXFS inode
+     * offsets before setgid permission is surrendered.
+     */
+    if (access_vxfs_ioffsets() && !Fwarn) {
+
+        /*
+         * Warn that the VxFS offsets are unavailable.
+         */
+        (void)fprintf(stderr,
+                      "%s: WARNING: vxfsu_get_ioffsets() returned an error.\n",
+                      Pn);
+        (void)fprintf(
+            stderr, "%s: WARNING: Thus, no vx_inode information is available\n",
+            Pn);
+        (void)fprintf(stderr,
+                      "%s: WARNING: for display or selection of VxFS files.\n",
+                      Pn);
+    }
+#endif /* defined(HASVXFSUTIL) */
+
+#if defined(WILLDROPGID)
+    /*
+     * If Solaris kernel memory is coming from KMEM, the process is willing to
+     * surrender GID permission, and the ALLKMEM device is not available, set up
+     * for GID switching after the first call to open_kvm().
+     */
+    if (!Memory && !HasALLKMEM) {
+        Savedgid = getegid();
+        if (Setgid)
+            Switchgid = 1;
+    }
+    /*
+     * If kernel memory isn't coming from KMEM, drop setgid permission
+     * before attempting to open the (Memory) file.
+     */
+    if (Memory)
+        (void)dropgid(ctx);
+#else  /* !defined(WILLDROPGID) */
+    /*
+     * See if the non-KMEM memory file is readable.
+     */
+    if (Memory && !is_readable(ctx, Memory, 1))
+        Error(ctx);
+#endif /* defined(WILLDROPGID) */
+
+    /*
+     * Open access to kernel memory.
+     */
+    open_kvm(ctx);
+
+#if solaris >= 20500
+    /*
+     * Get the kernel's KERNELBASE value for Solaris 2.5 and above.
+     */
+    v = (KA_T)0;
+    if (get_Nl_value(ctx, "kbase", Drive_Nl, &v) < 0 || !v ||
+        kread(ctx, (KA_T)v, (char *)&Kb, sizeof(Kb))) {
+        (void)fprintf(stderr, "%s: can't read kernel base address from %s\n",
+                      Pn, print_kptr(v, (char *)NULL, 0));
+        Error(ctx);
+    }
+#endif /* solaris>=20500 */
+
+    /*
+     * Get the Solaris clone major device number, if possible.
+     */
+    v = (KA_T)0;
+    if ((get_Nl_value(ctx, "clmaj", Drive_Nl, &v) < 0) || !v) {
+        if (get_Nl_value(ctx, "clmaj_alt", Drive_Nl, &v) < 0)
+            v = (KA_T)0;
+    }
+    if (v && kread(ctx, (KA_T)v, (char *)&CloneMaj, sizeof(CloneMaj)) == 0)
+        HaveCloneMaj = 1;
+    /*
+     * If the ALLKMEM device is available, check for the address of the kernel's
+     * active process chain.  If it's not available, clear the ALLKMEM status.
+     */
+    if (HasALLKMEM) {
+        if ((get_Nl_value(ctx, "pract", Drive_Nl, &PrAct) < 0) || !PrAct)
+            HasALLKMEM = 0;
+    }
+
+#if solaris >= 20501
+    /*
+     * If the ALLKMEM device isn't available, get the kernel's virtual to
+     * physical map structure for Solaris 2.5.1 and above.
+     */
+    if (!HasALLKMEM) {
+        if (get_Nl_value(ctx, "kasp", Drive_Nl, &v) >= 0 && v) {
+            PageSz = getpagesize();
+            PSMask = PageSz - 1;
+            for (i = 1, PSShft = 0; i < PageSz; i <<= 1, PSShft++)
+                ;
+            (void)readkam(ctx, v);
+        }
+    }
+#endif /* solaris>=20501 */
+
+#if defined(WILLDROPGID)
+    /*
+     * If the ALLKMEM device is available -- i.e., we're not using the
+     * kvm_*proc() functions to read proc structures -- and if we're willing to
+     * drop setgid permission, do so.
+     */
+    if (HasALLKMEM)
+        (void)dropgid(ctx);
+#endif /* defined(WILLDROPGID) */
+}
+
+#if defined(HASZONES)
+/*
+ * enter_zone_arg() - enter zone name argument
+ */
+
+int enter_zone_arg(struct lsof_context *ctx, /* context */
+                   char *zn)                 /* zone name */
+{
+    int zh;
+    znhash_t *zp, *zpn;
+    /*
+     * Allocate zone argument hash space, as required.
+     */
+    if (!ZoneArg) {
+        if (!(ZoneArg = (znhash_t **)calloc(HASHZONE, sizeof(znhash_t *)))) {
+            (void)fprintf(stderr, "%s: no space for zone arg hash\n", Pn);
+            Error(ctx);
+        }
+    }
+    /*
+     * Hash the zone name and search the argument hash.
+     */
+    zh = hash_zn(zn);
+    for (zp = ZoneArg[zh]; zp; zp = zp->next) {
+        if (!strcmp(zp->zn, zn))
+            break;
+    }
+    if (zp) {
+
+        /*
+         * Process a duplicate.
+         */
+        if (!Fwarn)
+            (void)fprintf(stderr, "%s: duplicate zone name: %s\n", Pn, zn);
+        return (1);
+    }
+    /*
+     * Create a new hash entry and link it to its bucket.
+     */
+    if (!(zpn = (znhash_t *)malloc((MALLOC_S)sizeof(znhash_t)))) {
+        (void)fprintf(stderr, "%s no hash space for zone: %s\n", Pn, zn);
+        Error(ctx);
+    }
+    zpn->f = 0;
+    zpn->zn = zn;
+    zpn->next = ZoneArg[zh];
+    ZoneArg[zh] = zpn;
+    return (0);
+}
+
+/*
+ * hash_zn() - hash zone name
+ */
+
+static int hash_zn(char *zn) /* zone name */
+{
+    register int i, h;
+    size_t l;
+
+    if (!(l = strlen(zn)))
+        return (0);
+    if (l == 1)
+        return ((int)*zn & (HASHZONE - 1));
+    for (i = h = 0; i < (int)(l - 1); i++) {
+        h ^= ((int)zn[i] * (int)zn[i + 1]) << ((i * 3) % 13);
+    }
+    return (h & (HASHZONE - 1));
+}
+#endif /* defined(HASZONES) */
+
+/*
+ * initialize() - perform all initialization
+ */
+
+void initialize(struct lsof_context *ctx) {
+    get_kernel_access(ctx);
+    /*
+     * Read Solaris file system information and construct the clone table.
+     *
+     * The clone table is needed to identify sockets.
+     */
+    readfsinfo(ctx);
+
+#if defined(HASDCACHE)
+    readdev(ctx, 0);
+#else  /* !defined(HASDCACHE) */
+    read_clone();
+#endif /*defined(HASDCACHE) */
+}
+
+/*
+ * kread() - read from kernel memory
+ */
+
+int kread(struct lsof_context *ctx, /* context */
+          KA_T addr,                /* kernel memory address */
+          char *buf,                /* buffer to receive data */
+          READLEN_T len)            /* length to read */
+{
+    register int br;
+    /*
+     * Because lsof reads kernel data and follows pointers found there at a
+     * rate considerably slower than the kernel, lsof sometimes acquires
+     * invalid pointers.  If the invalid pointers are fed to kvm_[k]read(),
+     * a segmentation violation may result, so legal kernel addresses are
+     * limited by the value of the KERNELBASE symbol (Kb value from the
+     * kernel's _kernelbase variable for Solaris 2.5 and above).
+     */
+
+#if solaris >= 20500
+#    define KVMREAD kvm_kread
+    if (addr < Kb)
+#else /* solaris<20500 */
+#    define KVMREAD kvm_read
+    if (addr < (KA_T)KERNELBASE)
+#endif /* solaris>=20500 */
+
+        return (1);
+
+#if solaris >= 20501
+
+    /*
+     * Do extra address checking for Solaris above 2.5 when the ALLKMEM device
+     * isn't available.
+     *
+     * Make sure the virtual address represents real physical memory by testing
+     * it with kvm_physaddr().
+     *
+     * For Solaris below 7 read the kernel data with llseek() and read().  For
+     * Solaris 7 and above use kvm_pread().
+     */
+    if (Kas && !HasALLKMEM) {
+
+#    if solaris > 20501
+        register int b2r;
+        register char *bp;
+#    endif /* solaris>20501 */
+
+        register int h, ip, tb;
+        register kvmhash_t *kp;
+        KPHYS pa;
+        register KVIRT va, vpa;
+
+#    if solaris < 20600
+        for (tb = 0, va = (KVIRT)addr; tb < len; tb += br, va += (KVIRT)br)
+#    else  /* solaris>=20600 */
+        for (bp = buf, tb = 0, va = (KVIRT)addr; tb < len;
+             bp += br, tb += br, va += (KVIRT)br)
+#    endif /* solaris<20600 */
+
+        {
+            vpa = (va & (KVIRT)~PSMask) >> PSShft;
+            ip = (int)(va & (KVIRT)PSMask);
+            h = HASHKVM(vpa);
+            for (kp = KVMhb[h]; kp; kp = kp->nxt) {
+                if (kp->vpa == vpa) {
+                    pa = kp->pa;
+                    break;
+                }
+            }
+            if (!kp) {
+                if ((pa = kvm_physaddr(Kd, Kas, va)) == KAERR)
+                    return (1);
+                if (!(kp = (kvmhash_t *)malloc(sizeof(kvmhash_t)))) {
+                    (void)fprintf(stderr, "%s: no kvmhash_t space\n", Pn);
+                    Error(ctx);
+                }
+                kp->nxt = KVMhb[h];
+                pa = kp->pa = (pa & ~(KPHYS)PSMask);
+                kp->vpa = vpa;
+                KVMhb[h] = kp;
+            }
+
+#    if solaris < 20600
+            br = (int)(len - tb);
+            if ((ip + br) > PageSz)
+                br = PageSz - ip;
+#    else /* solaris>=20600 */
+            b2r = (int)(len - tb);
+            if ((ip + b2r) > PageSz)
+                b2r = PageSz - ip;
+            pa |= (KPHYS)ip;
+
+#        if solaris < 70000
+            if (llseek(Kmd, (offset_t)pa, SEEK_SET) == (offset_t)-1)
+                return (1);
+            if ((br = (int)read(Kmd, (void *)bp, (size_t)b2r)) <= 0)
+                return (1);
+#        else  /* solaris>=70000 */
+            if ((br = kvm_pread(Kd, pa, (void *)bp, (size_t)b2r)) <= 0)
+                return (1);
+#        endif /* solaris<70000 */
+#    endif     /* solaris<20600 */
+        }
+
+#    if solaris >= 20600
+        return (0);
+#    endif /* solaris>=20600 */
+    }
+#endif /* solaris>=20501 */
+
+    /*
+     * Use kvm_read for Solaris < 2.5; use kvm_kread() Solaris >= 2.5.
+     */
+    br = KVMREAD(Kd, (u_long)addr, buf, len);
+    return (((READLEN_T)br == len) ? 0 : 1);
+}
+
+/*
+ * open_kvm() - open kernel virtual memory access
+ */
+
+void open_kvm(struct lsof_context *ctx) {
+    if (Kd)
+        return;
+
+#if defined(WILLDROPGID)
+    /*
+     * If this Solaris process began with setgid permission and its been
+     * surrendered, regain it.
+     */
+    (void)restoregid(ctx);
+#endif /* defined(WILLDROPGID) */
+
+    if (!(Kd = kvm_open(Nmlst, Memory, NULL, O_RDONLY, Pn))) {
+        (void)fprintf(stderr, "%s: kvm_open(namelist=%s, corefile=%s): %s\n",
+                      Pn, Nmlst ? Nmlst : "default",
+                      Memory ? Memory : "default", strerror(errno));
+        Error(ctx);
+    }
+
+#if solaris >= 20501 && solaris < 70000
+    if ((Kmd = open((Memory ? Memory : KMEM), O_RDONLY)) < 0) {
+        (void)fprintf(stderr, "%s: open(\"/dev/mem\"): %s\n", Pn,
+                      strerror(errno));
+        Error(ctx);
+    }
+#endif /* solaris>=20501 && solaris<70000 */
+
+#if defined(WILLDROPGID)
+    /*
+     * If this process has setgid permission, and is willing to surrender it,
+     * do so.
+     */
+    (void)dropgid(ctx);
+    /*
+     * If this Solaris process must switch GIDs, enable switching after the
+     * first call to this function.
+     */
+    if (Switchgid == 1)
+        Switchgid = 2;
+#endif /* define(WILLDROPGID) */
+}
+
+/*
+ * process_text() - process text access information
+ */
+
+#if solaris >= 90000
+#    include <sys/avl.h>
+
+/*
+ * Avl trees are implemented as follows: types in AVL trees contain an
+ * avl_node_t.  These avl_nodes connect to other avl nodes embedded in
+ * objects of the same type.  The avl_tree contains knowledge about the
+ * size of the structure and the offset of the AVL node in the object
+ * so we can convert between AVL nodes and (in this case) struct seg.
+ *
+ * This code was provided by Casper Dik <Casper.Dik@holland.sun.com>.
+ */
+
+#    define READ_AVL_NODE(n, o, s)                                             \
+        if (kread(ctx, (KA_T)AVL_NODE2DATA(n, o), (char *)s, sizeof(*s)))      \
+        return -1
+
+static int get_first_seg(struct lsof_context *ctx, avl_tree_t *av,
+                         struct seg *s) {
+    avl_node_t *node = av->avl_root;
+    size_t off = av->avl_offset;
+    int count = 0;
+
+    while (node != NULL && ++count < MAXSEGS * 2) {
+        READ_AVL_NODE(node, off, s);
+        node = s->s_tree.avl_child[0];
+        if (node == NULL)
+            return 0;
+    }
+    return -1;
+}
+
+static int get_next_seg(struct lsof_context *ctx, avl_tree_t *av,
+                        struct seg *s) {
+    avl_node_t *node = &s->s_tree;
+    size_t off = av->avl_offset;
+    int count = 0;
+
+    if (node->avl_child[1]) {
+        /*
+         * Has right child, go all the way to the leftmost child of
+         * the right child.
+         */
+        READ_AVL_NODE(node->avl_child[1], off, s);
+        while (node->avl_child[0] != NULL && ++count < 2 * MAXSEGS)
+            READ_AVL_NODE(node->avl_child[0], off, s);
+        if (count < 2 * MAXSEGS)
+            return 0;
+    } else {
+        /*
+         * No right child, go up until we find a node we're not a right
+         * child of.
+         */
+        for (; count < 2 * MAXSEGS; count++) {
+            int index = AVL_XCHILD(node);
+            avl_node_t *parent = AVL_XPARENT(node);
+
+            if (parent == NULL)
+                return -1;
+
+            READ_AVL_NODE(parent, off, s);
+
+            if (index == 0)
+                return 0;
+        }
+    }
+    return -1;
+}
+
+static void process_text(struct lsof_context *ctx, /* context */
+                         KA_T pa) /* address space description pointer */
+{
+    struct as as;
+    int i, j, k;
+    struct seg s;
+    struct segvn_data vn;
+    avl_tree_t *avtp;
+    KA_T v[MAXSEGS];
+    /*
+     * Get address space description.
+     */
+    if (kread(ctx, (KA_T)pa, (char *)&as, sizeof(as))) {
+        alloc_lfile(ctx, LSOF_FD_PROGRAM_TEXT, -1);
+        (void)snpf(Namech, Namechl, "can't read text segment list (%s)",
+                   print_kptr(pa, (char *)NULL, 0));
+        enter_nm(ctx, Namech);
+        if (Lf->sf)
+            link_lfile(ctx);
+        return;
+    }
+    /*
+     * Loop through the segments.  The loop should stop when the segment
+     * pointer returns to its starting point, but just in case, it's stopped
+     * when MAXSEGS unique segments have been recorded or 2*MAXSEGS segments
+     * have been examined.
+     */
+    for (avtp = &as.a_segtree, i = j = 0; (i < MAXSEGS) && (j < 2 * MAXSEGS);
+         j++) {
+        if (j ? get_next_seg(ctx, avtp, &s) : get_first_seg(ctx, avtp, &s))
+            break;
+        if ((KA_T)s.s_ops == Sgvops && s.s_data) {
+            if (kread(ctx, (KA_T)s.s_data, (char *)&vn, sizeof(vn)))
+                break;
+            if (vn.vp) {
+
+                /*
+                 * This is a virtual node segment.
+                 *
+                 * If its vnode pointer has not been seen already, record the
+                 * vnode pointer and process the vnode.
+                 */
+                for (k = 0; k < i; k++) {
+                    if (v[k] == (KA_T)vn.vp)
+                        break;
+                }
+                if (k >= i) {
+                    v[i++] = (KA_T)vn.vp;
+                    alloc_lfile(ctx, LSOF_FD_PROGRAM_TEXT, -1);
+
+#    if defined(FILEPTR)
+                    FILEPTR = (struct file *)NULL;
+#    endif /* defined(FILEPTR) */
+
+                    process_node(ctx, (KA_T)vn.vp);
+                    if (Lf->sf)
+                        link_lfile(ctx);
+                }
+            }
+        }
+    }
+}
+
+#else /* solaris<90000 */
+
+#    if solaris >= 20400
+#        define S_NEXT s_next.list
+#    else /* solaris<20400 */
+#        define S_NEXT s_next
+#    endif /* solaris>=20400 */
+
+static void process_text(struct lsof_context *ctx, /* context */
+                         KA_T pa) /* address space description pointer */
+{
+    struct as as;
+    int i, j, k;
+    struct seg s;
+    struct segvn_data vn;
+    KA_T v[MAXSEGS];
+    /*
+     * Get address space description.
+     */
+    if (kread(ctx, (KA_T)pa, (char *)&as, sizeof(as))) {
+        alloc_lfile(ctx, LSOF_FD_PROGRAM_TEXT, -1);
+        (void)snpf(Namech, Namechl, "can't read text segment list (%s)",
+                   print_kptr(pa, (char *)NULL, 0));
+        enter_nm(ctx, Namech);
+        if (Lf->sf)
+            link_lfile();
+        return;
+    }
+    /*
+     * Loop through the segments.  The loop should stop when the segment
+     * pointer returns to its starting point, but just in case, it's stopped
+     * when MAXSEGS unique segments have been recorded or 2*MAXSEGS segments
+     * have been examined.
+     */
+    for (s.s_next = as.a_segs, i = j = 0; i < MAXSEGS && j < 2 * MAXSEGS; j++) {
+        if (!s.S_NEXT || kread(ctx, (KA_T)s.S_NEXT, (char *)&s, sizeof(s)))
+            break;
+        if ((KA_T)s.s_ops == Sgvops && s.s_data) {
+            if (kread(ctx, (KA_T)s.s_data, (char *)&vn, sizeof(vn)))
+                break;
+            if (vn.vp) {
+
+                /*
+                 * This is a virtual node segment.
+                 *
+                 * If its vnode pointer has not been seen already, record the
+                 * vnode pointer and process the vnode.
+                 */
+                for (k = 0; k < i; k++) {
+                    if (v[k] == (KA_T)vn.vp)
+                        break;
+                }
+                if (k >= i) {
+                    v[i++] = (KA_T)vn.vp;
+                    alloc_lfile(ctx, LSOF_FD_PROGRAM_TEXT, -1);
+
+#    if defined(FILEPTR)
+                    FILEPTR = (struct file *)NULL;
+#    endif /* defined(FILEPTR) */
+
+                    process_node(ctx, (KA_T)vn.vp);
+                    if (Lf->sf)
+                        link_lfile();
+                }
+            }
+        }
+        /*
+         * Follow the segment link to the starting point in the address
+         * space description.  (The i and j counters place an absolute
+         * limit on the loop.)
+         */
+
+#    if solaris < 20400
+        if (s.s_next == as.a_segs)
+#    else  /* solaris>=20400 */
+        if (s.s_next.list == as.a_segs.list)
+#    endif /* solaris<20400 */
+
+            break;
+    }
+}
+#endif     /* solaris>=90000 */
+
+/*
+ * readfsinfo() - read file system information
+ */
+
+static void readfsinfo(struct lsof_context *ctx) {
+    char buf[FSTYPSZ + 1];
+    int i, len;
+
+    if ((Fsinfomax = sysfs(GETNFSTYP)) == -1) {
+        (void)fprintf(stderr, "%s: sysfs(GETNFSTYP) error: %s\n", Pn,
+                      strerror(errno));
+        Error(ctx);
+    }
+    if (Fsinfomax == 0)
+        return;
+    if (!(Fsinfo = (char **)malloc((MALLOC_S)(Fsinfomax * sizeof(char *))))) {
+        (void)fprintf(stderr, "%s: no space for sysfs info\n", Pn);
+        Error(ctx);
+    }
+    for (i = 1; i <= Fsinfomax; i++) {
+        if (sysfs(GETFSTYP, i, buf) == -1) {
+            (void)fprintf(stderr, "%s: sysfs(GETFSTYP) error: %s\n", Pn,
+                          strerror(errno));
+            Error(ctx);
+        }
+        if (buf[0] == '\0') {
+            Fsinfo[i - 1] = "";
+            continue;
+        }
+        buf[FSTYPSZ] = '\0';
+        len = strlen(buf) + 1;
+        if (!(Fsinfo[i - 1] = (char *)malloc((MALLOC_S)len))) {
+            (void)fprintf(stderr, "%s: no space for file system entry %s\n", Pn,
+                          buf);
+            Error(ctx);
+        }
+        (void)snpf(Fsinfo[i - 1], len, "%s", buf);
+
+#if defined(HAS_AFS)
+        if (strcasecmp(buf, "afs") == 0)
+            AFSfstype = i;
+#endif /* defined(HAS_AFS) */
+    }
+}
+
+#if solaris >= 20501
+/*
+ * readkam() - read kernel's address map structure
+ */
+
+static void readkam(struct lsof_context *ctx, /* context */
+                    KA_T addr)                /* kernel virtual address */
+{
+    register int i;
+    register kvmhash_t *kp, *kpp;
+    static KA_T kas = (KA_T)NULL;
+
+    if (addr)
+        kas = addr;
+    Kas = (struct as *)NULL;
+
+#    if solaris < 70000
+    if (kas && !kread(ctx, kas, (char *)&Kam, sizeof(Kam)))
+        Kas = (KA_T)&Kam;
+#    else  /* solaris>=70000 */
+    Kas = (struct as *)kas;
+#    endif /* solaris<70000 */
+
+    if (Kas) {
+        if (!KVMhb) {
+            if (!(KVMhb =
+                      (kvmhash_t **)calloc(KVMHASHBN, sizeof(kvmhash_t *)))) {
+                (void)fprintf(stderr,
+                              "%s: no space (%d) for KVM hash buckets\n", Pn,
+                              (int)(KVMHASHBN * sizeof(kvmhash_t *)));
+                Error(ctx);
+            }
+        } else if (!addr) {
+            for (i = 0; i < KVMHASHBN; i++) {
+                if ((kp = KVMhb[i])) {
+                    while (kp) {
+                        kpp = kp->nxt;
+                        (void)free((void *)kp);
+                        kp = kpp;
+                    }
+                    KVMhb[i] = (kvmhash_t *)NULL;
+                }
+            }
+        }
+    }
+}
+#endif /* solaris>=20501 */
+
+/*
+ * read_proc() - read proc structures
+ *
+ * As a side-effect, Kd is set by a call to kvm_open().
+ */
+
+static void read_proc(struct lsof_context *ctx) {
+    int ct, ctl, knp, n, try;
+    MALLOC_S len;
+    struct proc *p;
+    KA_T pa, paf, pan;
+    struct pid pg, pids;
+    /*
+     * Try PROCTRYLM times to read a valid proc table.
+     */
+    for (try = 0; try < PROCTRYLM; try++) {
+
+        /*
+         * Get a proc structure count estimate.
+         */
+        if (get_Nl_value(ctx, "nproc", Drive_Nl, &pa) < 0 || !pa ||
+            kread(ctx, pa, (char *)&knp, sizeof(knp)) || knp < 1)
+            knp = PROCDFLT;
+        /*
+         * Pre-allocate space, as required.
+         */
+        n = knp + PROCDFLT / 4;
+        if (n > Npa) {
+
+            /*
+             * Allocate proc structure space.
+             */
+            len = (n * sizeof(struct proc));
+            if (P)
+                P = (struct proc *)realloc((MALLOC_P *)P, len);
+            else
+                P = (struct proc *)malloc(len);
+            if (!P) {
+                (void)fprintf(stderr, "%s: no proc table space\n", Pn);
+                Error(ctx);
+            }
+            /*
+             * Pre-allocate PGID and PID number space.
+             */
+            len = (MALLOC_S)(n * sizeof(int));
+            if (Fpgid) {
+                if (Pgid)
+                    Pgid = (int *)realloc((MALLOC_P *)Pgid, len);
+                else
+                    Pgid = (int *)malloc(len);
+                if (!Pgid) {
+                    (void)fprintf(stderr, "%s: no PGID table space\n", Pn);
+                    Error(ctx);
+                }
+            }
+            if (Pid)
+                Pid = (int *)realloc((MALLOC_P *)Pid, len);
+            else
+                Pid = (int *)malloc(len);
+            if (!Pid) {
+                (void)fprintf(stderr, "%s: no PID table space\n", Pn);
+                Error(ctx);
+            }
+            Npa = n;
+        }
+        if (HasALLKMEM) {
+
+            /*
+             * Prepare for a proc table scan via direct reading of the active
+             * chain.
+             */
+            if (!PrAct || kread(ctx, PrAct, (char *)&paf, sizeof(pa))) {
+                (void)fprintf(stderr, "%s: can't read practive from %s\n", Pn,
+                              print_kptr(PrAct, (char *)NULL, 0));
+                Error(ctx);
+            }
+            ct = 1;
+            ctl = knp << 3;
+            pan = paf;
+            pa = (KA_T)NULL;
+        } else {
+
+            /*
+             * Prepare for a proc table scan via the kvm_*proc() functions.
+             */
+            if (kvm_setproc(Kd) != 0) {
+                (void)fprintf(stderr, "%s: kvm_setproc: %s\n", Pn,
+                              strerror(errno));
+                Error(ctx);
+            }
+        }
+        /*
+         * Accumulate proc structures.
+         */
+        Np = 0;
+        for (;;) {
+            if (Np >= Npa) {
+
+                /*
+                 * Expand the local proc table.
+                 */
+                Npa += PROCDFLT / 2;
+                len = (MALLOC_S)(Npa * sizeof(struct proc));
+                if (!(P = (struct proc *)realloc((MALLOC_P *)P, len))) {
+                    (void)fprintf(stderr, "%s: no more (%d) proc space\n", Pn,
+                                  Npa);
+                    Error(ctx);
+                }
+                /*
+                 * Expand the PGID and PID tables.
+                 */
+                len = (MALLOC_S)(Npa * sizeof(int));
+                if (Fpgid) {
+                    if (!(Pgid = (int *)realloc((MALLOC_P *)Pgid, len))) {
+                        (void)fprintf(stderr, "%s: no more (%d) PGID space\n",
+                                      Pn, Npa);
+                        Error(ctx);
+                    }
+                }
+                if (!(Pid = (int *)realloc((MALLOC_P *)Pid, len))) {
+                    (void)fprintf(stderr, "%s: no more (%d) PID space\n", Pn,
+                                  Npa);
+                    Error(ctx);
+                }
+            }
+            /*
+             * Read the next proc structure.
+             */
+            if (HasALLKMEM) {
+
+                /*
+                 * If the ALLKMEM device exists, read proc structures directly
+                 * from the active chain.
+                 */
+                if (!pa)
+                    pa = paf;
+                else {
+                    pa = pan;
+                    if ((pan == paf) || (++ct > ctl))
+                        break;
+                }
+                if (!pa)
+                    break;
+                p = (struct proc *)&P[Np];
+                if (kread(ctx, pa, (char *)p, sizeof(struct proc)))
+                    break;
+                pan = (KA_T)p->p_next;
+            } else {
+
+                /*
+                 * If the ALLKMEM device doesn't exist, read proc structures
+                 * via kbm_getproc().
+                 */
+                if (!(p = kvm_nextproc(Kd)))
+                    break;
+            }
+            /*
+             * Check process status.
+             */
+            if (p->p_stat == 0 || p->p_stat == SZOMB)
+                continue;
+
+#if solaris >= 20500
+            /*
+             * Check Solaris 2.5 and above p_cred pointer.
+             */
+            if (!p->p_cred)
+                continue;
+#endif /* solaris >=20500 */
+
+            /*
+             * Read Solaris PGID and PID numbers.
+             */
+            if (Fpgid) {
+                if (!p->p_pgidp ||
+                    kread(ctx, (KA_T)p->p_pgidp, (char *)&pg, sizeof(pg)))
+                    continue;
+            }
+            if (!p->p_pidp ||
+                kread(ctx, (KA_T)p->p_pidp, (char *)&pids, sizeof(pids)))
+                continue;
+            /*
+             * Save the PGID and PID numbers in local tables.
+             */
+            if (Fpgid)
+                Pgid[Np] = (int)pg.pid_id;
+            Pid[Np] = (int)pids.pid_id;
+            /*
+             * If the proc structure came from kvm_getproc(), save it in the
+             * local table.
+             */
+            if (!HasALLKMEM)
+                P[Np] = *p;
+            Np++;
+        }
+        /*
+         * If not enough processes were saved in the local table, try again.
+         *
+         * If the ALLKMEM device isn't available, it is necessary to close and
+         * reopen the KVM device, so that kvm_open() will acquire a fresh
+         * address for the head of the linked list process table.
+         */
+        if (Np >= PROCMIN)
+            break;
+        if (!HasALLKMEM) {
+            close_kvm(ctx);
+            open_kvm(ctx);
+        }
+    }
+    /*
+     * Quit if no proc structures were stored in the local table.
+     */
+    if (try >= PROCTRYLM) {
+        (void)fprintf(stderr, "%s: can't read proc table\n", Pn);
+        Error(ctx);
+    }
+    if (Np < Npa && !RptTm) {
+
+        /*
+         * Reduce the local proc structure table size to its minimum if
+         * not in repeat mode.
+         */
+        len = (MALLOC_S)(Np * sizeof(struct proc));
+        if (!(P = (struct proc *)realloc((MALLOC_P *)P, len))) {
+            (void)fprintf(stderr, "%s: can't reduce proc table to %d\n", Pn,
+                          Np);
+            Error(ctx);
+        }
+        /*
+         * Reduce the Solaris PGID and PID tables to their minimum if
+         * not in repeat mode.
+         */
+        len = (MALLOC_S)(Np * sizeof(int));
+        if (Fpgid) {
+            if (!(Pgid = (int *)realloc((MALLOC_P *)Pgid, len))) {
+                (void)fprintf(stderr, "%s: can't reduce PGID table to %d\n", Pn,
+                              Np);
+                Error(ctx);
+            }
+        }
+        if (!(Pid = (int *)realloc((MALLOC_P *)Pid, len))) {
+            (void)fprintf(stderr, "%s: can't reduce PID table to %d\n", Pn, Np);
+            Error(ctx);
+        }
+        Npa = Np;
+    }
+}
+
+#if defined(WILLDROPGID)
+/*
+ * restoregid() -- restore setgid permission, as required
+ */
+
+void restoregid(struct lsof_context *ctx) {
+    if (Switchgid == 2 && !Setgid) {
+        if (setgid(Savedgid) != 0) {
+            (void)fprintf(stderr, "%s: can't set effective GID to %d: %s\n", Pn,
+                          (int)Savedgid, strerror(errno));
+            Error(ctx);
+        }
+        Setgid = 1;
+    }
+}
+#endif /* defined(WILLDROPGID) */
+
+#if defined(HASNCACHE) && solaris >= 90000
+
+/*
+ * Local static values
+ */
+
+static int Mhl;     /* local name cache hash mask */
+static int Nhl = 0; /* size of local name cache hash
+                     * pointer table */
+struct l_nch {
+    KA_T vp;          /* vnode address */
+    KA_T dp;          /* parent vnode address */
+    struct l_nch *pa; /* parent Ncache address */
+    char *nm;         /* name */
+    int nl;           /* name length */
+};
+
+static struct l_nch *Ncache = (struct l_nch *)NULL;
+/* the local name cache */
+static struct l_nch **Nchash = (struct l_nch **)NULL;
+/* Ncache hash pointers */
+static int Ncfirst = 1;         /* first-call status */
+static KA_T NegVN = (KA_T)NULL; /* negative vnode address */
+static int Nla = 0;             /* entries allocated to Ncache[] */
+static int Nlu = 0;             /* entries used in Ncache[] */
+
+static struct l_nch *ncache_addr(KA_T v);
+
+#    define ncachehash(v) Nchash + ((((int)(v) >> 2) * 31415) & Mhl)
+
+static int ncache_isroot(KA_T va, char *cp);
+
+#    define LNCHINCRSZ 64 /* local size increment */
+#    define XNC                                                                \
+        15 /* extra name characters to read beyond those                       \
+            * in name[] of the ncache_t structure -- this                      \
+            * is an efficiency hint and MUST BE AT LEAST                       \
+            * ONE. */
+
+/*
+ * ncache_addr() - look up a node's local ncache address
+ */
+
+static struct l_nch *
+
+ncache_addr(KA_T v) /* vnode's address */
+{
+    struct l_nch **hp;
+
+    for (hp = ncachehash(v); *hp; hp++) {
+        if ((*hp)->vp == v)
+            return (*hp);
+    }
+    return ((struct l_nch *)NULL);
+}
+
+/*
+ * ncache_isroot() - is head of name cache path a file system root?
+ */
+
+static int ncache_isroot(KA_T va,  /* kernel vnode address */
+                         char *cp) /* partial path */
+{
+    char buf[MAXPATHLEN];
+    int i;
+    MALLOC_S len;
+    struct mounts *mtp;
+    struct stat sb;
+    struct vnode v;
+    static int vca = 0;
+    static int vcn = 0;
+    static KA_T *vc = (KA_T *)NULL;
+
+    if (!va)
+        return (0);
+    /*
+     * Search the root vnode cache.
+     */
+    for (i = 0; i < vcn; i++) {
+        if (va == vc[i])
+            return (1);
+    }
+    /*
+     * Read the vnode and see if it's a VDIR node with the VROOT flag set.  If
+     * it is, then the path is complete.
+     *
+     * If it isn't, and if the file has an inode number, search the mount table
+     * and see if the file system's inode number is known.  If it is, form the
+     * possible full path, safely stat() it, and see if it's inode number
+     * matches the one we have for this file.  If it does, then the path is
+     * complete.
+     */
+    if (kread(ctx, (KA_T)va, (char *)&v, sizeof(v)) || v.v_type != VDIR ||
+        !(v.v_flag & VROOT)) {
+
+        /*
+         * The vnode tests failed.  Try the inode tests.
+         */
+        if (Lf->inp_ty != 1 || !Lf->inode || !Lf->fsdir ||
+            (len = strlen(Lf->fsdir)) < 1)
+            return (0);
+        if ((len + 1 + strlen(cp) + 1) > sizeof(buf))
+            return (0);
+        for (mtp = readmnt(); mtp; mtp = mtp->next) {
+            if (!mtp->dir || !mtp->inode)
+                continue;
+            if (strcmp(Lf->fsdir, mtp->dir) == 0)
+                break;
+        }
+        if (!mtp)
+            return (0);
+        (void)strcpy(buf, Lf->fsdir);
+        if (buf[len - 1] != '/')
+            buf[len++] = '/';
+        (void)strcpy(&buf[len], cp);
+        if (statsafely(buf, &sb) != 0 || (INODETYPE)sb.st_ino != Lf->inode)
+            return (0);
+    }
+    /*
+     * Add the vnode address to the root vnode cache.
+     */
+    if (vcn >= vca) {
+        vca += 10;
+        len = (MALLOC_S)(vca * sizeof(KA_T));
+        if (!vc)
+            vc = (KA_T *)malloc(len);
+        else
+            vc = (KA_T *)realloc(vc, len);
+        if (!vc) {
+            (void)fprintf(stderr, "%s: no space for root vnode table\n", Pn);
+            Error(ctx);
+        }
+    }
+    vc[vcn++] = va;
+    return (1);
+}
+
+/*
+ * ncache_load() - load the kernel's name cache
+ */
+
+void ncache_load() {
+    char *cp;
+    struct l_nch **hp, *lc;
+    int h, i, len, n, xl;
+    static int iNch = 0;
+    nc_hash_t *kh;
+    static KA_T kha = (KA_T)NULL;
+    static nc_hash_t *khl = (nc_hash_t *)NULL;
+    KA_T kn;
+    static ncache_t *nc = (ncache_t *)NULL;
+    static int Nch = 0;
+    static int nmo = 0;
+    KA_T v;
+    static int xn = 0;
+
+    if (!Fncache)
+        return;
+    if (Ncfirst) {
+
+        /*
+         * Do startup (first-time) functions.
+         */
+        Ncfirst = 0;
+        /*
+         * Establish DNLC hash size.
+         */
+        v = (KA_T)0;
+        if (get_Nl_value(ctx, X_NCSIZE, (struct drive_Nl *)NULL, &v) < 0 || !v ||
+            kread(ctx, (KA_T)v, (char *)&Nch, sizeof(Nch))) {
+            if (!Fwarn)
+                (void)fprintf(stderr,
+                              "%s: WARNING: can't read DNLC hash size: %s\n",
+                              Pn, print_kptr(v, (char *)NULL, 0));
+            iNch = Nch = 0;
+            return;
+        }
+        if ((iNch = Nch) < 1) {
+            if (!Fwarn)
+                (void)fprintf(stderr, "%s: WARNING: DNLC hash size: %d\n", Pn,
+                              Nch);
+            iNch = Nch = 0;
+            return;
+        }
+        /*
+         * Get negative vnode address.
+         */
+        if (get_Nl_value(ctx, NCACHE_NEGVN, (struct drive_Nl *)NULL, &NegVN) < 0)
+            NegVN = (KA_T)NULL;
+        /*
+         * Establish DNLC hash address.
+         */
+        v = (KA_T)0;
+        if (get_Nl_value(ctx, X_NCACHE, (struct drive_Nl *)NULL, (KA_T *)&v) < 0 ||
+            !v || kread(ctx, v, (char *)&kha, sizeof(kha)) || !kha) {
+            if (!Fwarn)
+                (void)fprintf(stderr, "%s: WARNING: no DNLC hash address\n",
+                              Pn);
+            iNch = Nch = 0;
+            return;
+        }
+        /*
+         * Allocate space for a local copy of the kernel's hash table.
+         */
+        len = Nch * sizeof(nc_hash_t);
+        if (!(khl = (nc_hash_t *)malloc((MALLOC_S)len))) {
+            (void)fprintf(stderr, "%s: can't allocate DNLC hash space: %d\n",
+                          Pn, len);
+            Error(ctx);
+        }
+        /*
+         * Allocate space for a kernel DNLC entry, plus additional name space
+         * for efficiency.
+         */
+        xn = XNC;
+        if (!(nc = (ncache_t *)malloc((MALLOC_S)(sizeof(ncache_t) + XNC)))) {
+            (void)fprintf(stderr, "%s: can't allocate DNLC ncache_t space\n",
+                          Pn);
+            Error(ctx);
+        }
+        nmo = offsetof(struct ncache, name);
+        /*
+         * Allocate estimated space for the local cache, based on the
+         * hash table count and the current average hash length.
+         */
+        v = (KA_T)0;
+        if ((get_Nl_value(ctx, "hshav", (struct drive_Nl *)NULL, (KA_T *)&v) < 0) ||
+            !v || kread(ctx, v, (char *)&i, sizeof(i)) || (i < 1)) {
+            i = 16;
+            if (!Fwarn) {
+                (void)fprintf(stderr,
+                              "%s: can't read DNLC average hash bucket size,",
+                              Pn);
+                (void)fprintf(stderr, " using %d\n", i);
+            }
+        }
+        Nla = Nch * i;
+        if (!(Ncache = (struct l_nch *)calloc(Nla, sizeof(struct l_nch)))) {
+
+        no_local_space:
+
+            (void)fprintf(stderr, "%s: no space for %d byte local name cache\n",
+                          Pn, len);
+            Error(ctx);
+        }
+    } else {
+
+        /*
+         * Do setup for repeat calls.
+         */
+        if (!iNch || !Nla || !Ncache)
+            return;
+        if (Nchash) {
+            (void)free((FREE_P *)Nchash);
+            Nchash = (struct l_nch **)NULL;
+        }
+        if (Ncache && Nlu) {
+
+            /*
+             * Free space malloc'd to names in local name cache.
+             */
+            for (i = 0, lc = Ncache; i < Nlu; i++, lc++) {
+                if (lc->nm) {
+                    (void)free((FREE_P *)lc->nm);
+                    lc->nm = (char *)NULL;
+                }
+            }
+        }
+        Nch = iNch;
+        Nlu = 0;
+    }
+    /*
+     * Read the kernel's DNLC hash.
+     */
+    if (kread(ctx, kha, (char *)khl, (Nch * sizeof(nc_hash_t)))) {
+        if (!Fwarn)
+            (void)fprintf(stderr, "%s: WARNING: can't read DNLC hash: %s\n", Pn,
+                          print_kptr(kha, (char *)NULL, 0));
+        iNch = Nch = 0;
+        return;
+    }
+    /*
+     * Build a local copy of the kernel name cache.
+     */
+    for (i = n = 0, kh = khl, lc = Ncache; i < Nch; i++, kh++) {
+
+        /*
+         * Skip empty hash buckets.
+         */
+        if (!kh->hash_next || ((KA_T)kh->hash_next == kha))
+            continue;
+        /*
+         * Process a hash bucket.
+         */
+        for (kn = (KA_T)kh->hash_next, h = 0;
+             kn && (h < Nch) && (!h || (h && kn != (KA_T)kh->hash_next));
+             kn = (KA_T)nc->hash_next, h++) {
+            if (kread(ctx, kn, (char *)nc, sizeof(ncache_t) + XNC))
+                break;
+            if (!nc->vp || (len = (int)nc->namlen) < 1)
+                continue;
+            if (NegVN && ((KA_T)nc->vp == NegVN))
+                continue;
+            if ((len < 3) && (nc->name[0] == '.')) {
+                if ((len < 2) || (nc->name[1] == '.'))
+                    continue;
+            }
+            /*
+             * If not all the name has been read, read the rest of it,
+             * allocating more space at the end of the ncache structure as
+             * required.
+             */
+            if (len > (XNC + 1)) {
+                if (len > (xn + 1)) {
+                    while (len > (xn + 1))
+                        xn = xn + xn;
+                    xn = ((xn + 7) & ~7) - 1;
+                    if (!(nc = (ncache_t *)realloc((MALLOC_P *)nc,
+                                                   (sizeof(ncache_t) + xn)))) {
+                        (void)fprintf(stderr,
+                                      "%s: can't extend DNLC ncache_t buffer\n",
+                                      Pn);
+                        Error(ctx);
+                    }
+                }
+                cp = &nc->name[XNC + 1];
+                v = (KA_T)((char *)kn + nmo + XNC + 1);
+                xl = len - XNC - 1;
+                if (kread(ctx, v, cp, xl))
+                    continue;
+            }
+            /*
+             * Allocate space for the name in the local name cache entry.
+             */
+            if (!(cp = (char *)malloc(len + 1))) {
+                (void)fprintf(
+                    stderr, "%s: can't allocate %d bytes for name cache name\n",
+                    Pn, len + 1);
+                Error(ctx);
+            }
+            (void)strncpy(cp, nc->name, len);
+            cp[len] = '\0';
+            /*
+             * Make sure there is space for another local name cache entry.
+             * If not, allocate twice as many entries.
+             */
+            if (n >= Nla) {
+                Nla = Nla + Nla;
+                if (!(Ncache = (struct l_nch *)realloc(
+                          Ncache, (MALLOC_S)(Nla * sizeof(struct l_nch))))) {
+                    (void)fprintf(stderr,
+                                  "%s: can't enlarge local name cache\n", Pn);
+                    Error(ctx);
+                }
+                lc = &Ncache[n];
+            }
+            /*
+             * Complete the local cache entry.
+             */
+            lc->vp = (KA_T)nc->vp;
+            lc->dp = (KA_T)nc->dp;
+            lc->pa = (struct l_nch *)NULL;
+            lc->nm = cp;
+            lc->nl = len;
+            lc++;
+            n++;
+        }
+    }
+    /*
+     * Reduce memory usage, as required.
+     */
+    if ((Nlu = n) < 1) {
+
+        /*
+         * No DNLC entries were located, an unexpected result.
+         */
+        if (!RptTm && Ncache) {
+
+            /*
+             * If not in repeat mode, free the space that has been malloc'd
+             * to the local name cache.
+             */
+            (void)free((FREE_P *)Ncache);
+            Ncache = (struct l_nch *)NULL;
+            Nla = Nlu = 0;
+        }
+        /*
+         * Issue a warning and disable furthe DNLC processing.
+         */
+        if (!Fwarn)
+            (void)fprintf(stderr,
+                          "%s: WARNING: unusable local name cache size: %d\n",
+                          Pn, n);
+        iNch = Nch = 0;
+        return;
+    }
+    if ((Nlu < Nla) && !RptTm) {
+        len = Nlu * sizeof(struct l_nch);
+        if (!(Ncache = (struct l_nch *)realloc(Ncache, len)))
+            goto no_local_space;
+        Nla = Nlu;
+    }
+    /*
+     * Build a hash table to locate Ncache entries.
+     */
+    for (Nhl = 1; Nhl < Nlu; Nhl <<= 1)
+        ;
+    Nhl <<= 1;
+    Mhl = Nhl - 1;
+    if (!(Nchash =
+              (struct l_nch **)calloc(Nhl + Nlu, sizeof(struct l_nch *)))) {
+        (void)fprintf(stderr, "%s: no space for %d name cache hash pointers\n",
+                      Pn, Nhl + Nlu);
+        Error(ctx);
+    }
+    for (i = 0, lc = Ncache; i < Nlu; i++, lc++) {
+        for (hp = ncachehash(lc->vp), h = 1; *hp; hp++) {
+            if ((*hp)->vp == lc->vp && strcmp((*hp)->nm, lc->nm) == 0 &&
+                (*hp)->dp == lc->dp) {
+                h = 0;
+                break;
+            }
+        }
+        if (h)
+            *hp = lc;
+    }
+    /*
+     * Make a final pass through the local cache and convert parent vnode
+     * addresses to local name cache pointers.
+     */
+    for (i = 0, lc = Ncache; i < Nlu; i++, lc++) {
+        if (!lc->dp)
+            continue;
+        if (NegVN && (lc->dp == NegVN)) {
+            lc->pa = (struct l_nch *)NULL;
+            continue;
+        }
+        lc->pa = ncache_addr(lc->dp);
+    }
+}
+
+/*
+ * ncache_lookup() - look up a node's name in the kernel's name cache
+ */
+
+char *ncache_lookup(char *buf, /* receiving name buffer */
+                    int blen,  /* receiving buffer length */
+                    int *fp)   /* full path reply */
+{
+    char *cp = buf;
+    struct l_nch *lc;
+    struct mounts *mtp;
+    int nl, rlen;
+
+    *cp = '\0';
+    *fp = 0;
+
+#    if defined(HASFSINO)
+    /*
+     * If the entry has an inode number that matches the inode number of the
+     * file system mount point, return an empty path reply.  That tells the
+     * caller to print the file system mount point name only.
+     */
+    if (Lf->inp_ty == 1 && Lf->fs_ino && Lf->inode == Lf->fs_ino)
+        return (cp);
+#    endif /* defined(HASFSINO) */
+
+    /*
+     * Look up the name cache entry for the node address.
+     */
+    if (!Nlu || !(lc = ncache_addr(Lf->na))) {
+
+        /*
+         * If the node has no cache entry, see if it's the mount
+         * point of a known file system.
+         */
+        if (!Lf->fsdir || !Lf->dev_def || Lf->inp_ty != 1)
+            return ((char *)NULL);
+        for (mtp = readmnt(); mtp; mtp = mtp->next) {
+            if (!mtp->dir || !mtp->inode)
+                continue;
+            if (Lf->dev == mtp->dev && mtp->inode == Lf->inode &&
+                strcmp(mtp->dir, Lf->fsdir) == 0)
+                return (cp);
+        }
+        return ((char *)NULL);
+    }
+    /*
+     * Begin the path assembly.
+     */
+    if ((nl = lc->nl) > (blen - 1))
+        return ((char *)NULL);
+    cp = buf + blen - nl - 1;
+    rlen = blen - nl - 1;
+    (void)strcpy(cp, lc->nm);
+    /*
+     * Look up the name cache entries that are parents of the node address.
+     * Quit when:
+     *
+     * there's no parent;
+     * the name is too large to fit in the receiving buffer.
+     */
+    for (;;) {
+        if (!lc->pa) {
+            if (ncache_isroot(lc->dp, cp))
+                *fp = 1;
+            break;
+        }
+        lc = lc->pa;
+        if (((nl = lc->nl) + 1) > rlen)
+            break;
+        *(cp - 1) = '/';
+        cp--;
+        rlen--;
+        (void)strncpy((cp - nl), lc->nm, nl);
+        cp -= nl;
+        rlen -= nl;
+    }
+    return (cp);
+}
+#endif /* defined(HASNCACHE) && solaris>=90000 */
diff --git a/lib/dialects/sun/dproto.h b/lib/dialects/sun/dproto.h
new file mode 100644 (file)
index 0000000..014c28f
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * dproto.h - Solaris function prototypes for lsof
+ *
+ * The _PROTOTYPE macro is defined in the common proto.h.
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+/*
+ * $Id: dproto.h,v 1.21 2010/01/18 19:03:54 abe Exp $
+ */
+
+#if defined(HASVXFSUTIL)
+extern int access_vxfs_ioffsets(void);
+#endif /* defined(HASVXFSUTIL) */
+
+extern void completevfs(struct lsof_context *ctx, struct l_vfs *vfs,
+                        dev_t *dev);
+
+#if defined(HAS_LIBCTF)
+extern int CTF_getmem(struct lsof_context *ctx, ctf_file_t *f, const char *mod,
+                      const char *ty, CTF_member_t *mem);
+extern void CTF_init(struct lsof_context *ctx, int *i, char *t,
+                     CTF_request_t *r);
+extern int CTF_memCB(const char *name, ctf_id_t id, ulong_t offset, void *arg);
+#endif /* defined(HAS_LIBCTF) */
+
+extern int is_file_named(struct lsof_context *ctx, char *p, int nt,
+                         enum vtype vt, int ps);
+extern struct l_vfs *readvfs(struct lsof_context *ctx, KA_T ka, struct vfs *la,
+                             struct vnode *lv);
+extern int vop2ty(struct lsof_context *ctx, struct vnode *vp, int fx);
+
+#if defined(HAS_AFS)
+extern struct vnode *alloc_vcache(void);
+extern void ckAFSsym(struct nlist *nl);
+extern int hasAFS(struct vnode *vp);
+extern int readafsnode(KA_T va, struct vnode *v, struct afsnode *an);
+#endif /* defined(HAS_AFS) */
+
+#if defined(HASDCACHE)
+extern int rw_clone_sect(struct lsof_context *ctx, int m);
+extern void clr_sect(struct lsof_context *ctx);
+extern int rw_pseudo_sect(struct lsof_context *ctx, int m);
+#endif /* defined(HASDCACHE) */
+
+#if defined(HASIPv6)
+extern struct hostent *gethostbyname2(const char *nm, int proto);
+#endif /* defined(HASIPv6) */
+
+#if defined(HAS_V_PATH)
+extern int print_v_path(struct lsof_context *ctx, struct lfile *lf);
+extern void read_v_path(struct lsof_context *ctx, KA_T ka, char *rb,
+                        size_t rbl);
+#endif /* defined(HAS_V_PATH) */
+
+#if defined(HASVXFS)
+extern int read_vxnode(struct lsof_context *ctx, KA_T va, struct vnode *v,
+                       struct l_vfs *vfs, int fx, struct l_ino *li,
+                       KA_T *vnops);
+#    if defined(HASVXFSRNL)
+extern int print_vxfs_rnl_path(struct lfile *lf);
+#    endif /* defined(HASVXFSRNL) */
+#endif     /* defined(HASVXFS) */
+
+#if defined(HASZONES)
+extern int enter_zone_arg(struct lsof_context *ctx, char *zn);
+#endif /* defined(HASZONES) */
+
+extern void close_kvm(struct lsof_context *ctx);
+extern void open_kvm(struct lsof_context *ctx);
+extern void process_socket(struct lsof_context *ctx, KA_T sa, char *ty);
+
+#if solaris >= 110000
+extern int process_VSOCK(struct lsof_context *ctx, KA_T va, struct vnode *v,
+                         struct sonode *so);
+#endif /* solaris>=11000 */
+
+extern void read_clone(struct lsof_context *ctx);
+
+#if solaris < 20500
+extern int get_max_fd(void);
+#endif /* solaris<20500 */
+
+#if defined(WILLDROPGID)
+extern void restoregid(struct lsof_context *ctx);
+#endif /* defined(WILLDROPGID) */
diff --git a/lib/dialects/sun/dsock.c b/lib/dialects/sun/dsock.c
new file mode 100644 (file)
index 0000000..3f9ae62
--- /dev/null
@@ -0,0 +1,1996 @@
+/*
+ * dsock.c - Solaris socket processing functions for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#ifndef lint
+static char copyright[] =
+    "@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
+#endif
+
+#include "common.h"
+
+#if solaris >= 110000
+#    include <inet/ipclassifier.h>
+#endif /* solaris>=110000 */
+
+#if defined(HAS_LIBCTF) && solaris >= 110000
+/*
+ * Icmp_t, rts_t and udp_t structure support for Solaris >=11 via libctf
+ *
+ * These structure definitions may look like kernel structures, but they
+ * are not.  They have been defined to have member names that duplicate
+ * those used by the kernel that are of interest to lsof.  Member valuess
+ * are obtained via the CTF library, libctf.
+ *
+ * Robert Byrnes developed the CTF library access code and contributed it
+ * to lsof.
+ */
+
+/*
+ * Icmp_t internal structure definition
+ */
+
+typedef struct icmp_s {
+    uint_t icmp_state;           /* TPI state */
+    KA_T *icmp_connp;            /* connection structure pointer */
+    in6_addr_t icmp_bound_v6src; /* Explicitely bound to address */
+    in6_addr_t icmp_v6src;       /* Source address of this stream */
+    union {
+        uint_t icmp_dummy;
+        uint_t icmp_Debug : 1,     /* SO_DEBUG option */
+            icmp_dontroute : 1,    /* SO_DONTROUTE option */
+            icmp_broadcast : 1,    /* SO_BROADCAST option */
+            icmp_reuseaddr : 1,    /* SO_REUSEADDR option */
+            icmp_useloopback : 1,  /* SO_USELOOPBACK option */
+            icmp_hdrincl : 1,      /* IP_HDRINCL option, etc. */
+            icmp_dgram_errind : 1, /* SO_DGRAM_ERRIND option */
+            icmp_pad : 25;         /* pad to bit 31 */
+    } icmp_debug;                  /* This name identifies a single bit
+                                    * variable of the kernel's union, but
+                                    * CTF won't read individual bit
+                                    * variables, so for CTF's purposes
+                                    * it is declared as a uint_t union,
+                                    * named by the first bit variable of
+                                    * the kernel union, whose address CTF
+                                    * groks. */
+} icmp_t;
+
+/*
+ * Rts_t internal structure definition
+ */
+
+typedef struct rts_s {
+    uint_t rts_state; /* Provider interface state */
+
+#    if defined(HAS_CONN_NEW)
+    KA_T *rts_connp; /* connection structure pointer */
+#    endif           /* defined(HAS_CONN_NEW) */
+
+    union {
+        uint_t rts_dummy;
+        uint_t rts_Debug : 1,    /* SO_DEBUG option */
+            rts_dontroute : 1,   /* SO_DONTROUTE option */
+            rts_broadcast : 1,   /* SO_BROADCAST option */
+            rts_reuseaddr : 1,   /* SO_REUSEADDR option */
+            rts_useloopback : 1, /* SO_USELOOPBACK option */
+            icmp_pad : 27;       /* padding to bit 31 */
+    } rts_debug;                 /* This name identifies a single bit
+                                  * variable, but CTF won't read
+                                  * individual bit variables, so for
+                                  * CTF's purposes it is declared as a
+                                  * uint_t union, named by its first
+                                  * bit variable, whose address CTF
+                                  * groks. */
+} rts_t;
+
+/*
+ * Udp_t internal structure definition
+ */
+
+typedef struct udp {
+    uint_t udp_state;       /* TPI state */
+    in_port_t udp_port;     /* port bound to this stream */
+    in_port_t udp_dstport;  /* connected port */
+    in6_addr_t udp_v6src;   /* source address of this stream */
+    in6_addr_t udp_v6dst;   /* connected destination */
+    ushort_t udp_ipversion; /* version -- IPV[46]_VERSION */
+    KA_T *udp_connp;        /* connection structure pointer */
+    uint_t udp_bits;        /* socket option bits */
+} udp_t;
+
+/*
+ * CTF definitions for icmp_t, rts_t and udp_t
+ */
+
+static int IRU_ctfs = 0; /* CTF initialization status for
+                          * icmp_t, rts_t and udp_t */
+
+#    if defined(_LP64)
+#        define IRU_MOD_FORMAT "/kernel/%s/genunix"
+#    else /* !defined(_LP64) */
+#        define IRU_MOD_FORMAT "/kernel/genunix"
+#    endif /* defined(_LP64) */
+
+/* genunix pathname template to which
+ * the kernel's instruction type set
+ * is added for CTF access to icmp_t,
+ * rts_t and udp_t */
+
+/*
+ * Icmp_t, rts_t and udp_t access definitions and structures
+ */
+
+#    define ICMP_T_TYPE_NAME "icmp_t"
+
+static CTF_member_t icmp_t_members[] = {CTF_MEMBER(icmp_state),
+#    define MX_icmp_state 0
+
+#    if defined(HAS_CONN_NEW)
+
+                                        CTF_MEMBER(icmp_connp),
+#        define MX_icmp_connp 1
+#    else /* !defined(HAS_CONN_NEW) */
+                                        CTF_MEMBER(icmp_bound_v6src),
+#        define MX_icmp_bound_v6src 1
+
+                                        CTF_MEMBER(icmp_v6src),
+#        define MX_icmp_v6src 2
+
+                                        CTF_MEMBER(icmp_debug),
+#        define MX_icmp_debug 3
+#    endif /* defined(HAS_CONN_NEW) */
+
+                                        {NULL, 0}};
+
+#    define RTS_T_TYPE_NAME "rts_t"
+
+static CTF_member_t rts_t_members[] = {CTF_MEMBER(rts_state),
+#    define MX_rts_state 0
+
+#    if defined(HAS_CONN_NEW)
+                                       CTF_MEMBER(rts_connp),
+#        define MX_rts_connp 1
+#    else /* !defined(HAS_CONN_NEW) */
+
+                                       CTF_MEMBER(rts_debug),
+#        define MX_rts_debug 1
+#    endif /* defined(HAS_CONN_NEW) */
+
+                                       {NULL, 0}};
+
+#    define UDP_T_TYPE_NAME "udp_t"
+
+static CTF_member_t udp_t_members[] = {CTF_MEMBER(udp_state),
+#    define MX_udp_state 0
+
+                                       CTF_MEMBER(udp_connp),
+#    define MX_udp_connp 1
+
+#    if !defined(HAS_CONN_NEW)
+                                       CTF_MEMBER(udp_port),
+#        define MX_udp_port 2
+
+                                       CTF_MEMBER(udp_dstport),
+#        define MX_udp_dstport 3
+
+                                       CTF_MEMBER(udp_v6src),
+#        define MX_udp_v6src 4
+
+                                       CTF_MEMBER(udp_v6dst),
+#        define MX_udp_v6dst 5
+
+                                       CTF_MEMBER(udp_ipversion),
+#        define MX_udp_ipversion 6
+
+                                       CTF_MEMBER(udp_bits),
+#        define MX_udp_bits 7
+#    endif /* !defined(HAS_CONN_NEW) */
+
+                                       {NULL, 0}};
+
+/*
+ * CTF icmp_t, rts_t and udp_t request table
+ */
+
+static CTF_request_t IRU_requests[] = {{ICMP_T_TYPE_NAME, icmp_t_members},
+                                       {RTS_T_TYPE_NAME, rts_t_members},
+                                       {UDP_T_TYPE_NAME, udp_t_members},
+                                       {NULL, NULL}};
+
+/*
+ * Icmp_t, rts_t and udp_t function prototypes
+ */
+
+static int read_icmp_t(struct lsof_context *ctx, KA_T va, KA_T ph, KA_T ia,
+                       icmp_t *ic);
+static int read_rts_t(struct lsof_context *ctx, KA_T va, KA_T ph, KA_T ra,
+                      rts_t *rt);
+static int read_udp_t(struct lsof_context *ctx, KA_T ua, udp_t *uc);
+#endif /* defined(HAS_LIBCTF) && solaris>=110000 */
+
+#if solaris < 80000 || defined(HAS_IPCLASSIFIER_H)
+/*
+ * Make sure the tcpb structure is always defined.
+ */
+
+typedef struct tcpb {
+    int dummy;
+} tcpb_t;
+#endif /* solaris<80000 || defined(HAS_IPCLASSIFIER_H) */
+
+#if defined(HASIPv6)
+
+/*
+ * IPv6_2_IPv4()  -- macro to define the address of an IPv4 address contained
+ *                  in an IPv6 address
+ */
+
+#    define IPv6_2_IPv4(v6) (((uint8_t *)((struct in6_addr *)v6)->s6_addr) + 12)
+
+/*
+ * IPv_ADDR_UNSPEC() -- macro to test an IP[46] address for an unspecified
+ *                     address value
+ */
+
+#    define IPv_ADDR_UNSPEC(af, p)                                             \
+        (((af) == AF_INET6) ? (IN6_IS_ADDR_UNSPECIFIED((struct in6_addr *)p))  \
+                            : (((struct in_addr *)(p))->s_addr == INADDR_ANY))
+#else /* !defined(HASIPv6) */
+
+/*
+ * IPv_ADDR_UNSPEC() -- IPv4-only form of macro to test for an unspecified
+ *                     address value
+ */
+
+#    define IPv_ADDR_UNSPEC(af, p)                                             \
+        (((struct in_addr *)(p))->s_addr == INADDR_ANY)
+
+#endif /* !defined(HASIPv6) */
+
+#if defined(HASTCPOPT)
+#    if solaris == 20600
+#        include <netinet/tcp.h>
+#    endif /* solaris==20600 */
+#    include <netinet/tcp_timer.h>
+#    include <netinet/tcp_var.h>
+
+#    if defined(TH_TIMER_NEEDED)
+#        define ACK_TIMER TH_TIMER_NEEDED
+#    else
+#        if defined(TH_ACK_TIMER_NEEDED)
+#            define ACK_TIMER TH_ACK_TIMER_NEEDED
+#        endif /* defined(TH_ACK_TIMER_NEEDED) */
+#    endif     /* defined(TH_TIMER_NEEDED */
+#endif         /* defined(HASTCPOPT) */
+
+#if defined(HASSOOPT)
+#    if solaris < 100000
+#        define KEEPALIVE_INTERVAL tcp_keepalive_intrvl
+#    else /* solaris>=100000 */
+#        define KEEPALIVE_INTERVAL tcp_ka_last_intrvl
+#    endif /* solaris<100000 */
+#endif     /* defined(HASSOOPT) */
+
+/*
+ * Local function prototypes
+ */
+
+static void save_TCP_size(struct lsof_context *ctx, tcp_t *tc);
+static void save_TCP_states(struct lsof_context *ctx, tcp_t *tc, caddr_t *fa, tcpb_t *tb, caddr_t *xp);
+
+/*
+ * build_IPstates() -- build the TCP and UDP state tables
+ */
+
+void build_IPstates(struct lsof_context *ctx) {
+    if (!TcpSt) {
+        (void)enter_IPstate(ctx, "TCP", "CLOSED", TCPS_CLOSED);
+        (void)enter_IPstate(ctx, "TCP", "IDLE", TCPS_IDLE);
+        (void)enter_IPstate(ctx, "TCP", "BOUND", TCPS_BOUND);
+        (void)enter_IPstate(ctx, "TCP", "LISTEN", TCPS_LISTEN);
+        (void)enter_IPstate(ctx, "TCP", "SYN_SENT", TCPS_SYN_SENT);
+        (void)enter_IPstate(ctx, "TCP", "SYN_RCVD", TCPS_SYN_RCVD);
+        (void)enter_IPstate(ctx, "TCP", "ESTABLISHED", TCPS_ESTABLISHED);
+        (void)enter_IPstate(ctx, "TCP", "CLOSE_WAIT", TCPS_CLOSE_WAIT);
+        (void)enter_IPstate(ctx, "TCP", "FIN_WAIT_1", TCPS_FIN_WAIT_1);
+        (void)enter_IPstate(ctx, "TCP", "CLOSING", TCPS_CLOSING);
+        (void)enter_IPstate(ctx, "TCP", "LAST_ACK", TCPS_LAST_ACK);
+        (void)enter_IPstate(ctx, "TCP", "FIN_WAIT_2", TCPS_FIN_WAIT_2);
+        (void)enter_IPstate(ctx, "TCP", "TIME_WAIT", TCPS_TIME_WAIT);
+        (void)enter_IPstate(ctx, "TCP", (char *)NULL, 0);
+    }
+    if (!UdpSt) {
+        (void)enter_IPstate(ctx, "UDP", "Unbound", TS_UNBND);
+        (void)enter_IPstate(ctx, "UDP", "Wait_BIND_REQ_Ack", TS_WACK_BREQ);
+        (void)enter_IPstate(ctx, "UDP", "Wait_UNBIND_REQ_Ack", TS_WACK_UREQ);
+        (void)enter_IPstate(ctx, "UDP", "Idle", TS_IDLE);
+        (void)enter_IPstate(ctx, "UDP", "Wait_OPT_REQ_Ack", TS_WACK_OPTREQ);
+        (void)enter_IPstate(ctx, "UDP", "Wait_CONN_REQ_Ack", TS_WACK_CREQ);
+        (void)enter_IPstate(ctx, "UDP", "Wait_CONN_REQ_Confirm", TS_WCON_CREQ);
+        (void)enter_IPstate(ctx, "UDP", "Wait_CONN_IND_Response", TS_WRES_CIND);
+        (void)enter_IPstate(ctx, "UDP", "Wait_CONN_RES_Ack", TS_WACK_CRES);
+        (void)enter_IPstate(ctx, "UDP", "Wait_Data_Xfr", TS_DATA_XFER);
+        (void)enter_IPstate(ctx, "UDP", "Wait_Read_Release", TS_WIND_ORDREL);
+        (void)enter_IPstate(ctx, "UDP", "Wait_Write_Release", TS_WREQ_ORDREL);
+        (void)enter_IPstate(ctx, "UDP", "Wait_DISCON_REQ_Ack", TS_WACK_DREQ6);
+        (void)enter_IPstate(ctx, "UDP", "Wait_DISCON_REQ_Ack", TS_WACK_DREQ7);
+        (void)enter_IPstate(ctx, "UDP", "Wait_DISCON_REQ_Ack", TS_WACK_DREQ9);
+        (void)enter_IPstate(ctx, "UDP", "Wait_DISCON_REQ_Ack", TS_WACK_DREQ10);
+        (void)enter_IPstate(ctx, "UDP", "Wait_DISCON_REQ_Ack", TS_WACK_DREQ11);
+        (void)enter_IPstate(ctx, "UDP", (char *)NULL, 0);
+    }
+}
+
+/*
+ * print_tcptpi() - print TCP/TPI info
+ */
+
+void print_tcptpi(struct lsof_context *ctx, /* context */
+                  int nl)                   /* 1 == '\n' required */
+{
+    char *cp = (char *)NULL;
+    char sbuf[128];
+    int i;
+    int ps = 0;
+    unsigned int u;
+
+    if (Ftcptpi & TCPTPI_STATE) {
+        switch (Lf->lts.type) {
+        case 0: /* TCP */
+            if (!TcpSt)
+                (void)build_IPstates(ctx);
+            if ((i = Lf->lts.state.i + TcpStOff) < 0 || i >= TcpNstates) {
+                (void)snpf(sbuf, sizeof(sbuf), "UNKNOWN_TCP_STATE_%d",
+                           Lf->lts.state.i);
+                cp = sbuf;
+            } else
+                cp = TcpSt[i];
+            break;
+        case 1: /* TPI */
+            if (!UdpSt)
+                (void)build_IPstates(ctx);
+            if ((u = Lf->lts.state.ui + UdpStOff) < 0 || u >= UdpNstates) {
+                (void)snpf(sbuf, sizeof(sbuf), "UNKNOWN_UDP_STATE_%u",
+                           Lf->lts.state.ui);
+                cp = sbuf;
+            } else
+                cp = UdpSt[u];
+        }
+        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(HASSOOPT)
+    if (Ftcptpi & TCPTPI_FLAGS) {
+        int opt;
+
+        if ((opt = Lf->lts.opt) || Lf->lts.pqlens || Lf->lts.qlens ||
+            Lf->lts.qlims || Lf->lts.rbszs || Lf->lts.sbsz) {
+            char sep = ' ';
+
+            if (Ffield)
+                sep = LSOF_FID_TCPTPI;
+            else if (!ps)
+                sep = '(';
+            (void)printf("%cSO", sep);
+            ps++;
+            sep = '=';
+
+#    if defined(SO_BROADCAST)
+            if (opt & SO_BROADCAST) {
+                (void)printf("%cBROADCAST", sep);
+                opt &= ~SO_BROADCAST;
+                sep = ',';
+            }
+#    endif /* defined(SO_BROADCAST) */
+
+#    if defined(SO_DEBUG)
+            if (opt & SO_DEBUG) {
+                (void)printf("%cDEBUG", sep);
+                opt &= ~SO_DEBUG;
+                sep = ',';
+            }
+#    endif /* defined(SO_DEBUG) */
+
+#    if defined(SO_DGRAM_ERRIND)
+            if (opt & SO_DGRAM_ERRIND) {
+                (void)printf("%cDGRAM_ERRIND", sep);
+                opt &= ~SO_DGRAM_ERRIND;
+                sep = ',';
+            }
+#    endif /* defined(SO_DGRAM_ERRIND) */
+
+#    if defined(SO_DONTROUTE)
+            if (opt & SO_DONTROUTE) {
+                (void)printf("%cDONTROUTE", sep);
+                opt &= ~SO_DONTROUTE;
+                sep = ',';
+            }
+#    endif /* defined(SO_DONTROUTE) */
+
+#    if defined(SO_KEEPALIVE)
+            if (opt & SO_KEEPALIVE) {
+                (void)printf("%cKEEPALIVE", sep);
+                if (Lf->lts.kai)
+                    (void)printf("=%d", Lf->lts.kai);
+                opt &= ~SO_KEEPALIVE;
+                sep = ',';
+            }
+#    endif /* defined(SO_KEEPALIVE) */
+
+#    if defined(SO_LINGER)
+            if (opt & SO_LINGER) {
+                (void)printf("%cLINGER", sep);
+                if (Lf->lts.ltm)
+                    (void)printf("=%d", Lf->lts.ltm);
+                opt &= ~SO_LINGER;
+                sep = ',';
+            }
+#    endif /* defined(SO_LINGER) */
+
+#    if defined(SO_OOBINLINE)
+            if (opt & SO_OOBINLINE) {
+                (void)printf("%cOOBINLINE", sep);
+                opt &= ~SO_OOBINLINE;
+                sep = ',';
+            }
+#    endif /* defined(SO_OOBINLINE) */
+
+            if (Lf->lts.pqlens) {
+                (void)printf("%cPQLEN=%u", sep, Lf->lts.pqlen);
+                sep = ',';
+            }
+            if (Lf->lts.qlens) {
+                (void)printf("%cQLEN=%u", sep, Lf->lts.qlen);
+                sep = ',';
+            }
+            if (Lf->lts.qlims) {
+                (void)printf("%cQLIM=%u", sep, Lf->lts.qlim);
+                sep = ',';
+            }
+            if (Lf->lts.rbszs) {
+                (void)printf("%cRCVBUF=%lu", sep, Lf->lts.rbsz);
+                sep = ',';
+            }
+
+#    if defined(SO_REUSEADDR)
+            if (opt & SO_REUSEADDR) {
+                (void)printf("%cREUSEADDR", sep);
+                opt &= ~SO_REUSEADDR;
+                sep = ',';
+            }
+#    endif /* defined(SO_REUSEADDR) */
+
+            if (Lf->lts.sbszs) {
+                (void)printf("%cSNDBUF=%lu", sep, Lf->lts.sbsz);
+                sep = ',';
+            }
+
+#    if defined(SO_TIMESTAMP)
+            if (opt & SO_TIMESTAMP) {
+                (void)printf("%cTIMESTAMP", sep);
+                opt &= ~SO_TIMESTAMP;
+                sep = ',';
+            }
+#    endif /* defined(SO_TIMESTAMP) */
+
+#    if defined(SO_USELOOPBACK)
+            if (opt & SO_USELOOPBACK) {
+                (void)printf("%cUSELOOPBACK", sep);
+                opt &= ~SO_USELOOPBACK;
+                sep = ',';
+            }
+#    endif /* defined(SO_USELOOPBACK) */
+
+            if (opt)
+                (void)printf("%cUNKNOWN=%#x", sep, opt);
+            if (Ffield)
+                putchar(Terminator);
+        }
+    }
+#endif /* defined(HASSOOPT) */
+
+#if defined(HASTCPOPT)
+    if (Ftcptpi & TCPTPI_FLAGS) {
+        int topt;
+
+        if ((topt = Lf->lts.topt) || Lf->lts.msss) {
+            char sep = ' ';
+
+            if (Ffield)
+                sep = LSOF_FID_TCPTPI;
+            else if (!ps)
+                sep = '(';
+            (void)printf("%cTF", sep);
+            ps++;
+            sep = '=';
+
+#    if defined(TF_ACKNOW)
+            if (topt & TF_ACKNOW) {
+                (void)printf("%cACKNOW", sep);
+                topt &= ~TF_ACKNOW;
+                sep = ',';
+            }
+#    endif /* defined(TF_ACKNOW) */
+
+#    if defined(TF_DELACK)
+            if (topt & TF_DELACK) {
+                (void)printf("%cDELACK", sep);
+                topt &= ~TF_DELACK;
+                sep = ',';
+            }
+#    endif /* defined(TF_DELACK) */
+
+            if (Lf->lts.msss) {
+                (void)printf("%cMSS=%lu", sep, Lf->lts.mss);
+                sep = ',';
+            }
+
+#    if defined(TF_NODELAY)
+            if (topt & TF_NODELAY) {
+                (void)printf("%cNODELAY", sep);
+                topt &= ~TF_NODELAY;
+                sep = ',';
+            }
+#    endif /* defined(TF_NODELAY) */
+
+#    if defined(TF_NOOPT)
+            if (topt & TF_NOOPT) {
+                (void)printf("%cNOOPT", sep);
+                topt &= ~TF_NOOPT;
+                sep = ',';
+            }
+#    endif /* defined(TF_NOOPT) */
+
+#    if defined(TF_SENTFIN)
+            if (topt & TF_SENTFIN) {
+                (void)printf("%cSENTFIN", sep);
+                topt &= ~TF_SENTFIN;
+                sep = ',';
+            }
+#    endif /* defined(TF_SENTFIN) */
+
+            if (topt)
+                (void)printf("%cUNKNOWN=%#x", sep, topt);
+            if (Ffield)
+                putchar(Terminator);
+        }
+    }
+#endif /* defined(HASTCPOPT) */
+
+#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 (Ftcptpi && !Ffield && ps)
+        putchar(')');
+    if (nl)
+        putchar('\n');
+}
+
+#if solaris >= 110000
+/*
+ * procss_VSOCK() -- process a VSOCK socket
+ */
+
+#    if defined(HAS_CONN_NEW)
+/*
+ * Adjust for changes in the conn_s structure, introduced at OpenSolaris
+ * level b134.
+ */
+
+#        define conn_ulp conn_proto
+#        define conn_rem V4_PART_OF_V6(connua_v6addr.connua_faddr)
+#        define conn_src V4_PART_OF_V6(connua_v6addr.connua_laddr)
+#    endif /* defined(HAS_CONN_NEW) */
+
+int process_VSOCK(struct lsof_context *ctx, /* context */
+                  KA_T va,                  /* containing vnode address */
+                  struct vnode *v,          /* pointer to containing vnode */
+                  struct sonode *so)        /* pointer to socket's sonode */
+{
+    int af;           /* address family */
+    struct conn_s cs; /* connection info */
+    unsigned char *fa = (unsigned char *)NULL;
+    /* foreign address */
+    u_short fp = (u_short)0; /* foreign port */
+    u_short lp;              /* local port */
+    icmp_t ic;               /* ICMP control structure */
+    KA_T ka;                 /* temporary kernel address */
+    unsigned char *la = (unsigned char *)NULL;
+    /* local address */
+    KA_T pha; /* protocol handle address */
+    rts_t rt; /* AF_ROUTE control structure */
+    int s;    /* state */
+    unsigned char *ta = (unsigned char *)NULL;
+    /* temporary address */
+    char tbuf[32], tbuf1[32]; /* temporary buffers */
+    tcp_t tc;                 /* TCP control structure */
+    tcph_t th;                /* TCP header structure */
+
+#    if defined(HAS_CONN_NEW)
+    struct ip_xmit_attr_s xa;
+    caddr_t *xp = (caddr_t *)NULL;
+#    else  /* !defined(HAS_CONN_NEW) */
+    tcph_t *tha = (tcph_t *)NULL; /* TCP header structure address */
+#    endif /* defined(HAS_CONN_NEW) */
+
+    char *ty; /* TCP type */
+    udp_t uc; /* local UDP control structure */
+              /*
+               * Read VSOCK's connection information.  Enter its address as the protocol
+               * control block device address.
+               */
+    if (!(pha = (KA_T)so->so_proto_handle))
+        return (0);
+    if (kread(ctx, pha, (char *)&cs, sizeof(cs))) {
+        (void)snpf(Namech, Namechl,
+                   "vnode at %s; snode at %s; can't read proto handle at: %s",
+                   print_kptr(va, tbuf, sizeof(tbuf)),
+                   print_kptr((KA_T)v->v_data, tbuf1, sizeof(tbuf1)),
+                   print_kptr(pha, (char *)NULL, 0));
+        Namech[Namechl - 1] = '\0';
+        enter_nm(ctx, Namech);
+        return (1);
+    }
+    enter_dev_ch(ctx, print_kptr(pha, (char *)NULL, 0));
+    /*
+     * Process connection info by protocol.
+     */
+    switch ((af = so->so_family)) {
+    case AF_INET:
+    case AF_INET6:
+
+        /*
+         * Set INET type -- IPv4 or IPv6.
+         */
+        if (af == AF_INET)
+            Lf->type = LSOF_FILE_IPV4;
+        else
+            Lf->type = LSOF_FILE_IPV6;
+
+        switch (cs.conn_ulp) {
+        case IPPROTO_TCP:
+
+            /*
+             * Process TCP socket; read its control structure.
+             */
+            if (!(ka = (KA_T)cs.conn_proto_priv.cp_tcp) ||
+                kread(ctx, ka, (char *)&tc, sizeof(tc))) {
+                (void)snpf(Namech, Namechl - 1,
+                           "can't read TCP socket's control structure: %s",
+                           print_kptr((KA_T)ka, (char *)NULL, 0));
+                Namech[Namechl - 1] = '\0';
+                enter_nm(ctx, Namech);
+                return (1);
+            }
+            /*
+             * Set TCP protcol name in Lf->iproto[].
+             */
+            (void)snpf(Lf->iproto, IPROTOL - 1, "%s", "TCP");
+            Lf->iproto[IPROTOL - 1] = '\0';
+            Lf->inp_ty = 2;
+            /*
+             * Check for TCP state inclusion or exclusion.
+             */
+            if (TcpNstates) {
+                if ((s = (int)tc.tcp_state + TcpStOff) < TcpNstates) {
+                    if (TcpStXn) {
+                        if (TcpStX[s]) {
+                            Lf->sf |= SELEXCLF;
+                            return (1);
+                        }
+                    }
+                    if (TcpStIn) {
+                        if (TcpStI[s]) {
+                            TcpStI[s] = 2;
+                            Lf->sf |= SELNET;
+                        } else {
+                            Lf->sf |= SELEXCLF;
+                            return (1);
+                        }
+                    }
+                }
+            }
+            /*
+             * Set network file selection status.
+             */
+            if (Fnet) {
+                if (!FnetTy || ((FnetTy == 4) && (af == AF_INET)) ||
+                    ((FnetTy == 6) && (af == AF_INET6))) {
+                    Lf->sf |= SELNET;
+                }
+            }
+            /*
+             * Save local and remote (foreign) TCP address.
+             */
+            if (af == AF_INET6) {
+                ta = (unsigned char *)&cs.connua_v6addr.connua_faddr;
+                la = (unsigned char *)&cs.connua_v6addr.connua_laddr;
+            } else {
+                ta = (unsigned char *)&cs.conn_rem;
+                la = (unsigned char *)&cs.conn_src;
+            }
+            if (!IPv_ADDR_UNSPEC(af, ta) || (u_short)cs.conn_fport) {
+                fa = ta;
+                fp = (u_short)cs.conn_fport;
+            }
+            if ((af == AF_INET6) &&
+                ((la && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)la)) ||
+                 ((fa && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)fa))))) {
+
+                /*
+                 * Convert IPv4 addresses in IPv6 structures to IPv4 addresses
+                 * in IPv4 structures.  Change the address family to AF_INET.
+                 */
+                if (la)
+                    la = (unsigned char *)IPv6_2_IPv4(la);
+                if (fa)
+                    fa = (unsigned char *)IPv6_2_IPv4(fa);
+                af = AF_INET;
+            }
+            lp = (u_short)cs.conn_lport;
+            (void)ent_inaddr(ctx, la, (int)ntohs(lp), fa, (int)ntohs(fp), af);
+            /*
+             * Save TCP state information.
+             */
+
+#    if defined(HAS_CONN_NEW)
+            if ((ka = (KA_T)cs.conn_ixa) &&
+                !kread(ctx, ka, (char *)&xa, sizeof(xa))) {
+                xp = (caddr_t *)&xa;
+            }
+            (void)save_TCP_states(ctx, &tc, (caddr_t *)&cs, (tcpb_t *)NULL, xp);
+#    else  /* !defined(HAS_CONN_NEW) */
+            if (tc.tcp_tcp_hdr_len && (ka = (KA_T)tc.tcp_tcph) &&
+                !kread(ctx, ka, (char *)&th, sizeof(th))) {
+                tha = &th;
+            }
+            (void)save_TCP_states(ctx, &tc, (caddr_t *)tha, (tcpb_t *)NULL,
+                                  (caddr_t *)NULL);
+#    endif /* defined(HAS_CONN_NEW) */
+
+            Lf->lts.type = 0;
+            Lf->lts.state.i = (int)tc.tcp_state;
+            /*
+             * Save TCP size information.
+             */
+            (void)save_TCP_size(ctx, &tc);
+            break;
+        case IPPROTO_UDP:
+
+            /*
+             * Process UDP socket; read its control structure.
+             */
+            if (!(ka = (KA_T)cs.conn_proto_priv.cp_udp) ||
+                kread(ctx, ka, (char *)&uc, sizeof(uc))) {
+                (void)snpf(Namech, Namechl - 1,
+                           "can't read UDP socket's control structure: %s",
+                           print_kptr((KA_T)ka, (char *)NULL, 0));
+                Namech[Namechl - 1] = '\0';
+                enter_nm(ctx, Namech);
+                return (1);
+            }
+            /*
+             * Set UDP protcol name in Lf->iproto[].
+             */
+            (void)snpf(Lf->iproto, IPROTOL - 1, "%s", "UDP");
+            Lf->iproto[IPROTOL - 1] = '\0';
+            Lf->inp_ty = 2;
+            /*
+             * Check for UDP state inclusion or exclusion.
+             */
+            if (UdpNstates) {
+                if ((s = (int)uc.udp_state + TcpStOff) < UdpNstates) {
+                    if (UdpStXn) {
+                        if (UdpStX[s]) {
+                            Lf->sf |= SELEXCLF;
+                            return (1);
+                        }
+                    }
+                    if (UdpStIn) {
+                        if (UdpStI[s]) {
+                            UdpStI[s] = 2;
+                            Lf->sf |= SELNET;
+                        } else {
+                            Lf->sf |= SELEXCLF;
+                            return (1);
+                        }
+                    }
+                }
+            }
+            /*
+             * Set network file selection status.
+             */
+            if (Fnet) {
+                if (!FnetTy || ((FnetTy == 4) && (af == AF_INET)) ||
+                    ((FnetTy == 6) && (af == AF_INET6))) {
+                    Lf->sf |= SELNET;
+                }
+            }
+            /*
+             * Save local and remote (foreign) UDP address.
+             */
+            if (af == AF_INET6) {
+                ta = (unsigned char *)&cs.connua_v6addr.connua_faddr;
+                la = (unsigned char *)&cs.connua_v6addr.connua_laddr;
+            } else {
+                ta = (unsigned char *)&cs.conn_rem;
+                la = (unsigned char *)&cs.conn_src;
+            }
+            if (!IPv_ADDR_UNSPEC(af, ta) || (u_short)cs.conn_fport) {
+                fa = ta;
+                fp = (u_short)cs.conn_fport;
+            }
+            lp = (u_short)cs.conn_lport;
+            (void)ent_inaddr(ctx, la, (int)ntohs(lp), fa, (int)ntohs(fp), af);
+            /*
+             * Save UDP state and size information.
+             */
+            Lf->lts.type = 1;
+            Lf->lts.state.ui = (unsigned int)uc.udp_state;
+
+#    if defined(HASSOOPT)
+            /*
+             * Save UDP flags.
+             */
+            union {
+                uint_t flags;
+                uint_t udpb_debug : 1,     /* SO_DEBUG option */
+                    udpb_dontroute : 1,    /* SO_DONTROUTE option */
+                    udpb_broadcast : 1,    /* SO_BROADCAST option */
+                    udpb_reuseaddr : 1,    /* SO_REUSEADDR option */
+                    udpb_useloopback : 1,  /* SO_USELOOPBACK option */
+                    udpb_dgram_errind : 1, /* SO_DGRAM_ERRIND option */
+                    udpb_pad : 26;         /* pad to bit 31 */
+            } ucf;
+
+            ucf.flags = uc.udp_bits;
+            if (ucf.udpb_debug)
+                Lf->lts.opt |= SO_DEBUG;
+            if (ucf.udpb_dontroute)
+                Lf->lts.opt |= SO_DONTROUTE;
+            if (ucf.udpb_broadcast)
+                Lf->lts.opt |= SO_BROADCAST;
+            if (ucf.udpb_reuseaddr)
+                Lf->lts.opt |= SO_REUSEADDR;
+            if (ucf.udpb_useloopback)
+                Lf->lts.opt |= SO_USELOOPBACK;
+            if (ucf.udpb_dgram_errind)
+                Lf->lts.opt |= SO_DGRAM_ERRIND;
+#    endif /* defined(HASSOOPT) */
+
+            break;
+        case IPPROTO_ICMP:
+        case IPPROTO_ICMPV6:
+
+            /*
+             * Process ICMP or ICMP6 socket.
+             *
+             * Set protocol name.
+             */
+            if (cs.conn_ulp == IPPROTO_ICMP)
+                ty = "ICMP";
+            else
+                ty = "ICMP6";
+            (void)snpf(Lf->iproto, IPROTOL - 1, "%s", ty);
+            Lf->iproto[IPROTOL - 1] = '\0';
+            Lf->inp_ty = 2;
+            /*
+             * Read the ICMP control structure.
+             */
+            if (read_icmp_t(ctx, va, pha, (KA_T)cs.conn_proto_priv.cp_icmp,
+                            &ic))
+                return (1);
+            /*
+             * Save ICMP size and state information.
+             */
+            Lf->lts.type = 1;
+            Lf->lts.state.ui = (unsigned int)ic.icmp_state;
+            /*
+             * Set network file selection status.
+             */
+            if (Fnet) {
+                if (!FnetTy || ((FnetTy == 4) && (af == AF_INET)) ||
+                    ((FnetTy == 6) && (af == AF_INET6))) {
+                    Lf->sf |= SELNET;
+                }
+            }
+            /*
+             * Save addresses.
+             */
+            ta = (af == AF_INET6)
+                     ? (unsigned char *)&ic.icmp_bound_v6src
+                     : (unsigned char *)&V4_PART_OF_V6(ic.icmp_bound_v6src);
+            if (!IPv_ADDR_UNSPEC(af, ta))
+                la = ta;
+            ta = (af == AF_INET6)
+                     ? (unsigned char *)&ic.icmp_v6src
+                     : (unsigned char *)&V4_PART_OF_V6(ic.icmp_v6src);
+            if (!IPv_ADDR_UNSPEC(af, ta))
+                fa = ta;
+            if (la || fa)
+                (void)ent_inaddr(ctx, la, 0, fa, 0, af);
+
+#    if defined(HASSOOPT)
+            /*
+             * Save ICMP flags.
+             */
+            if (ic.icmp_debug.icmp_Debug)
+                Lf->lts.opt |= SO_DEBUG;
+            if (ic.icmp_debug.icmp_dontroute)
+                Lf->lts.opt |= SO_DONTROUTE;
+            if (ic.icmp_debug.icmp_broadcast)
+                Lf->lts.opt |= SO_BROADCAST;
+            if (ic.icmp_debug.icmp_reuseaddr)
+                Lf->lts.opt |= SO_REUSEADDR;
+            if (ic.icmp_debug.icmp_useloopback)
+                Lf->lts.opt |= SO_USELOOPBACK;
+            if (ic.icmp_debug.icmp_dgram_errind)
+                Lf->lts.opt |= SO_DGRAM_ERRIND;
+#    endif /* defined(HASSOOPT) */
+
+            break;
+        default:
+            (void)snpf(Namech, Namechl - 1,
+                       "unsupported conn_s AF_INET%s protocol: %u",
+                       (af == AF_INET6) ? "6" : "", (unsigned int)cs.conn_ulp);
+            Namech[Namechl - 1] = '\0';
+            enter_nm(ctx, Namech);
+            return (1);
+        }
+        break;
+    case AF_ROUTE:
+
+        /*
+         * Set INET type -- IPv4 or IPv6.
+         */
+        if (af == AF_INET)
+            Lf->type = LSOF_FILE_IPV4;
+        else
+            Lf->type = LSOF_FILE_IPV6;
+        /*
+         * Set protocol name.
+         */
+        (void)strncpy(Lf->iproto, "ROUTE", IPROTOL - 1);
+        Lf->iproto[IPROTOL - 1] = '\0';
+        Lf->inp_ty = 2;
+
+        /*
+         * Read routing control structure.
+         */
+        if (read_rts_t(ctx, va, pha, (KA_T)cs.conn_proto_priv.cp_rts, &rt))
+            return (1);
+        /*
+        /*
+         * Save AF_ROUTE size and state information.
+         */
+        Lf->lts.type = 1;
+        Lf->lts.state.i = (int)rt.rts_state;
+        /*
+         * Set network file selection status.
+         */
+        if (Fnet) {
+            if (!FnetTy || ((FnetTy == 4) && (af == AF_INET)) ||
+                ((FnetTy == 6) && (af == AF_INET6))) {
+                Lf->sf |= SELNET;
+            }
+        }
+
+#    if defined(HASSOOPT)
+        /*
+         * Save ROUTE flags.
+         */
+        if (rt.rts_debug.rts_Debug)
+            Lf->lts.opt |= SO_DEBUG;
+        if (rt.rts_debug.rts_dontroute)
+            Lf->lts.opt |= SO_DONTROUTE;
+        if (rt.rts_debug.rts_broadcast)
+            Lf->lts.opt |= SO_BROADCAST;
+        if (rt.rts_debug.rts_reuseaddr)
+            Lf->lts.opt |= SO_REUSEADDR;
+        if (rt.rts_debug.rts_useloopback)
+            Lf->lts.opt |= SO_USELOOPBACK;
+#    endif /* defined(HASSOOPT) */
+
+        break;
+    default:
+        (void)printiproto(ctx, (int)cs.conn_ulp);
+        (void)snpf(Namech, Namechl - 1, "unsupported socket family: %u",
+                   so->so_family);
+        Namech[Namechl - 1] = '\0';
+        enter_nm(ctx, Namech);
+        Lf->inp_ty = 2;
+    }
+    return (1);
+}
+#endif /* solaris>=110000*/
+
+/*
+ * process_socket() - process Solaris socket
+ */
+
+void process_socket(struct lsof_context *ctx, /* context */
+                    KA_T sa,  /* stream's data address in kernel */
+                    char *ty) /* socket type name */
+{
+    int af;
+    unsigned char *fa = (unsigned char *)NULL;
+    int fp = 0;
+    int i, lp;
+
+#if solaris < 110000
+#    if solaris >= 100000 && defined(HAS_IPCLASSIFIER_H)
+    struct conn_s ic;
+#        define ipc_v6laddr conn_srcv6
+#        define ipc_v6faddr conn_remv6
+#        define ipc_fport conn_fport
+#        define ipc_lport conn_lport
+#    else  /* solaris<100000 || !defined(HAS_IPCLASSIFIER_H) */
+    struct ipc_s ic;
+#    endif /* solaris>=100000 && defined(HAS_IPCLASSIFIER_H) */
+#else      /* solaris>=110000 */
+    struct conn_s cs;
+#endif     /* solaris<110000 */
+
+    int ics = 0;
+    unsigned char *la = (unsigned char *)NULL;
+    struct module_info mi;
+    KA_T ka;
+    u_short p;
+    KA_T pcb = (KA_T)NULL;
+    struct queue q;
+    struct qinit qi;
+    KA_T qp;
+    u_short *s;
+    struct stdata sd;
+    unsigned char *ta;
+    char tbuf[32];
+
+#if solaris < 20600
+    struct tcp_s { /* should come from kernel source
+                    * file ../uts/common/inet/tcp.c */
+
+#    if solaris >= 20400
+        struct tcp_s *d1[8];
+#    endif /* solaris>=20400 */
+
+#    if defined(P101318) && P101318 >= 32
+        struct tcp_s *d1[6];
+#    endif /* defined(P101318) && P101318>=32 */
+
+        int tcp_state;
+        queue_t *d3[2];
+        mblk_t *d4[2];
+        u_long d5;
+        mblk_t *d6;
+        u_long d7;
+        u_long tcp_snxt; /* Senders next seq num */
+        u_long tcp_suna; /* Sender unacknowledged */
+        u_long tcp_swnd; /* Senders window (relative to suna) */
+        u_long d8[5];
+        int tcp_hdr_len;  /* combined TCP/IP header length */
+        tcph_t *tcp_tcph; /* pointer to combined header */
+        int d9;
+        unsigned int d10;
+        int d11;
+        mblk_t *d12;
+        long d13;
+        mblk_t *d14;
+        u_long d15;
+
+#    if solaris < 20400 && (!defined(P101318) || P101318 < 32)
+        mblk_t *d16;
+#    endif /* solaris<20400 && (!defined(P101318) || P101318<32) */
+
+        unsigned int d17;
+        u_long tcp_rnxt; /* Seq we expect to recv next */
+        u_long tcp_rwnd; /* Current receive window */
+        u_long d18;
+        long d19[2];
+        mblk_t *d20[4];
+        u_long d21[5];
+        long d22[3];
+
+#    if solaris < 20500
+        u_long d23[2];
+        u_long tcp_rack; /* Seq # we have acked */
+#    else                /* solaris>=20500 */
+        u_long d23[3];
+#    endif               /* solaris<20500 */
+
+#    if solaris < 20400
+        u_long d24[28];
+#    else /* solaris>=20400 */
+#        if solaris < 20500
+        u_long d24[67];
+#        else /* solaris>=20500 */
+#            if solaris < 20501
+        u_long d25[6];
+#            else  /* solaris>=20501 */
+        u_long d25[8];
+#            endif /* solaris<20501 */
+        u_long tcp_rack; /* Seq # we have acked */
+#            if solaris < 20501
+        u_long d26[29];
+#            else  /* solaris>=20501 */
+        u_long d26[33];
+#            endif /* solaris>=20501 */
+#        endif     /* solaris<20500 */
+#    endif         /* solaris<20400 */
+
+        iph_t tcp_iph;
+    } tc;
+#else  /* solaris>=20600 */
+    struct tcp_s tc;
+#endif /* solaris<20600 */
+
+#if solaris >= 80000 && !defined(HAS_IPCLASSIFIER_H)
+    tcpb_t tcb;
+#endif /* solaris>=80000 && !defined(HAS_IPCLASSIFIER_H) */
+
+    tcpb_t *tcbp = (tcpb_t *)NULL;
+    int tcs = 0;
+    tcph_t th;
+    tcph_t *tha = (tcph_t *)NULL;
+
+#if solaris < 110000
+    struct ud_s {       /* should come from kernel source
+                         * file ../uts/common/inet/udp.c */
+        uint udp_state; /* TPI state */
+        unsigned char d1[2];
+        unsigned char udp_port[2]; /* port bound to this stream */
+        unsigned char udp_src[4];  /* source address of this stream */
+    } uc;
+#else  /* solaris>=110000 */
+    udp_t uc; /* UDP control structure */
+#endif /* solaris<110000 */
+    int ucs = 0;
+
+#if defined(HASIPv6)
+    if (strrchr(ty, '6')) {
+        Lf->type = LSOF_FILE_IPV6;
+        af = AF_INET6;
+    } else {
+        Lf->type = LSOF_FILE_IPV4;
+        af = AF_INET;
+    }
+#else  /* !defined(HASIPv6) */
+    Lf->type = LSOF_FILE_INET;
+    af = AF_INET;
+#endif /* defined(HASIPv6) */
+
+    /*
+     * Set network file selection status.
+     */
+    if (Fnet) {
+        if (!FnetTy || ((FnetTy == 4) && (af == AF_INET))
+
+#if defined(HASIPv6)
+            || ((FnetTy == 6) && (af == AF_INET6))
+#endif /* defined(HASIPv6) */
+
+        ) {
+            if (!TcpStIn && !UdpStIn)
+                Lf->sf |= SELNET;
+        }
+    }
+    Lf->inp_ty = 2;
+    /*
+     * Convert type to upper case protocol name.
+     */
+    if (ty) {
+        for (i = 0; (ty[i] != '\0') && (i < IPROTOL) && (i < 3); i++) {
+            if (islower((unsigned char)ty[i]))
+                Lf->iproto[i] = toupper((unsigned char)ty[i]);
+            else
+                Lf->iproto[i] = ty[i];
+        }
+    } else
+        i = 0;
+    Lf->iproto[i] = '\0';
+    /*
+     * Read stream queue entries to obtain private IP, TCP, and UDP structures.
+     */
+    if (!sa || readstdata(ctx, sa, &sd))
+        qp = (KA_T)NULL;
+    else
+        qp = (KA_T)sd.sd_wrq;
+    for (i = 0; qp && i < 20; i++, qp = (KA_T)q.q_next) {
+        if (kread(ctx, qp, (char *)&q, sizeof(q)))
+            break;
+        if ((ka = (KA_T)q.q_qinfo) == (KA_T)NULL ||
+            kread(ctx, ka, (char *)&qi, sizeof(qi)))
+            continue;
+        if ((ka = (KA_T)qi.qi_minfo) == (KA_T)NULL ||
+            kread(ctx, ka, (char *)&mi, sizeof(mi)) ||
+            (ka = (KA_T)mi.mi_idname) == (KA_T)NULL)
+            continue;
+        if (kread(ctx, ka, (char *)&tbuf, sizeof(tbuf) - 1))
+            continue;
+        if ((pcb = (KA_T)q.q_ptr) == (KA_T)NULL)
+            continue;
+
+#if solaris < 110000
+        if (strncasecmp(tbuf, "IP", 2) == 0) {
+            if (kread(ctx, pcb, (char *)&ic, sizeof(ic)) == 0)
+                ics = 1;
+            continue;
+        }
+#endif /* solaris<110000 */
+
+        if (strncasecmp(tbuf, "TCP", 3) == 0) {
+
+#if solaris <= 90000 || !defined(HAS_IPCLASSIFIER_H)
+            if (!kread(ctx, (KA_T)pcb, (char *)&tc, sizeof(tc)))
+
+#    if solaris >= 80000
+            {
+                if (tc.tcp_base &&
+                    !kread(ctx, (KA_T)tc.tcp_base, (char *)&tcb, sizeof(tcb))) {
+                    tcs = 1;
+                    tcbp = &tcb;
+                }
+                tc.tcp_base = &tcb; /* support for macros */
+                tcb.tcpb_tcp = &tc; /* support for macros */
+            }
+#    else  /* solaris<80000 */
+                tcs = 1;
+#    endif /* solaris>=80000 */
+#else      /* solaris>90000 && defined(HAS_IPCLASSIFIER_H) */
+#    if solaris >= 110000
+            if (!kread(ctx, pcb, (char *)&cs, sizeof(cs)) &&
+                (cs.conn_ulp == IPPROTO_TCP)) {
+                ics = 1;
+                if ((ka = (KA_T)cs.conn_proto_priv.cp_tcp) &&
+                    !kread(ctx, ka, (char *)&tc, sizeof(tc))) {
+                    tcs = 1;
+                }
+            }
+#    else  /* solaris<110000 */
+            if (!kread(ctx, (KA_T)pcb, (char *)&ic, sizeof(ic)) &&
+                ic.conn_tcp &&
+                !kread(ctx, (KA_T)ic.conn_tcp, (char *)&tc, sizeof(tc))) {
+                ics = tcs = 1;
+            }
+#    endif /* solaris>=110000 */
+#endif     /* solaris<=90000 || !defined(HAS_IPCLASSIFIER_H) */
+
+            if (tcs && TcpNstates) {
+                int s = (int)tc.tcp_state + TcpStOff;
+                /*
+                 * Check for TCP state inclusion or exclusion.
+                 */
+
+                if (s < TcpNstates) {
+                    if (TcpStXn) {
+                        if (TcpStX[s]) {
+                            Lf->sf &= ~SELNET;
+                            Lf->sf |= SELEXCLF;
+                            return;
+                        }
+                    }
+                    if (TcpStIn) {
+                        if (TcpStI[s]) {
+                            TcpStI[s] = 2;
+                            Lf->sf |= SELNET;
+                        } else {
+                            Lf->sf &= ~SELNET;
+                            Lf->sf |= SELEXCLF;
+                            return;
+                        }
+                    }
+                }
+            }
+            if (!(Lf->sf & SELNET) && !TcpStIn && UdpStIn) {
+                if (Fnet) {
+                    if (!FnetTy || (FnetTy == 4) && (af == AF_INET)
+
+#if defined(HASIPv6)
+                        || (FnetTy == 6) && (af == AF_INET6)
+#endif /* defined(HASIPv6) */
+
+                    ) {
+                        Lf->sf |= SELNET;
+                    }
+                }
+            }
+            continue;
+        }
+        if (strncasecmp(tbuf, "UDP", 3) == 0) {
+
+#if solaris < 110000
+            if (kread(ctx, pcb, (char *)&uc, sizeof(uc)) == 0)
+                ucs = 1;
+#else  /* solaris>=110000 */
+            if (!kread(ctx, pcb, (char *)&cs, sizeof(cs)) &&
+                (cs.conn_ulp == IPPROTO_UDP)) {
+                ics = 1;
+                if ((ka = (KA_T)cs.conn_proto_priv.cp_udp) &&
+                    !read_udp_t(ctx, ka, &uc)) {
+                    ucs = 1;
+                }
+            }
+#endif /* solaris<110000 */
+
+            if (ucs && UdpNstates) {
+                unsigned int s = (unsigned int)uc.udp_state + UdpStOff;
+                /*
+                 * Check for UDP state inclusion or exclusion.
+                 */
+
+                if (s < UdpNstates) {
+                    if (UdpStXn) {
+                        if (UdpStX[s]) {
+                            Lf->sf &= ~SELNET;
+                            Lf->sf |= SELEXCLF;
+                            return;
+                        }
+                    }
+                    if (UdpStIn) {
+                        if (UdpStI[s]) {
+                            UdpStI[s] = 2;
+                            Lf->sf |= SELNET;
+                        } else {
+                            Lf->sf |= SELEXCLF;
+                            return;
+                        }
+                    }
+                }
+            }
+            if (!(Lf->sf & SELNET) && TcpStIn && !UdpStIn) {
+                if (Fnet) {
+                    if (!FnetTy || (FnetTy == 4) && (af == AF_INET)
+
+#if defined(HASIPv6)
+                        || (FnetTy == 6) && (af == AF_INET6)
+#endif /* defined(HASIPv6) */
+
+                    ) {
+                        Lf->sf |= SELNET;
+                    }
+                }
+            }
+            continue;
+        }
+    }
+    if (ics) {
+
+        /*
+         * Print stream head's q_ptr address as protocol control block address.
+         */
+        if (pcb)
+            enter_dev_ch(ctx, print_kptr(pcb, (char *)NULL, 0));
+        if (strncmp(Lf->iproto, "UDP", 3) == 0) {
+
+            /*
+             * Save UDP address and TPI state.
+             */
+
+#if solaris < 20600
+            la = (unsigned char *)&ic.ipc_udp_addr;
+            p = (u_short)ic.ipc_udp_port;
+#else /* solaris>=20600 */
+#    if solaris >= 110000
+            af = (uc.udp_ipversion == IPV6_VERSION) ? AF_INET6 : AF_INET;
+            la = (af == AF_INET6)
+                     ? (unsigned char *)&uc.udp_v6src
+                     : (unsigned char *)&V4_PART_OF_V6(uc.udp_v6src);
+            p = (u_short)uc.udp_port;
+#    else /* solaris<110000 */
+#        if defined(HASIPv6)
+            la = (af == AF_INET6)
+                     ? (unsigned char *)&ic.ipc_v6laddr
+                     : (unsigned char *)IPv6_2_IPv4(&ic.ipc_v6laddr);
+#        else  /* !defined(HASIPv6 */
+            la = (unsigned char *)&ic.ipc_laddr;
+#        endif /* defined(HASIPv6) */
+
+            p = (u_short)ic.ipc_lport;
+#    endif     /* solaris>=110000 */
+#endif         /* solaris<20600 */
+
+#if solaris < 110000
+            if (IPv_ADDR_UNSPEC(af, la) && !p && ucs) {
+
+                /*
+                 * If the ipc_s structure has no local address, use
+                 * the port in the ud_s structure.
+                 */
+                s = (u_short *)&uc.udp_port[0];
+                p = *s;
+            }
+
+#    if defined(HASIPv6)
+            if ((af == AF_INET6) && la &&
+                IN6_IS_ADDR_V4MAPPED((struct in6_addr *)la)) {
+
+                /*
+                 * Convert a local IPv4 address in an IPv6 structure to an IPv4
+                 * address in an IPv4 structure.  Change the address family to
+                 * AF_INET.
+                 */
+                la = (unsigned char *)IPv6_2_IPv4(la);
+                af = AF_INET;
+            }
+#    endif /* defined(HASIPv6) */
+#endif     /* solaris<110000 */
+
+            (void)ent_inaddr(ctx, la, (int)ntohs(p), (unsigned char *)NULL, -1,
+                             af);
+            if (ucs) {
+                Lf->lts.type = 1;
+                Lf->lts.state.ui = (unsigned int)uc.udp_state;
+            }
+        } else if (strncmp(Lf->iproto, "TCP", 3) == 0) {
+            if (ics) {
+
+                /*
+                 * Save TCP address.
+                 */
+
+#if solaris < 20400
+                la = (unsigned char *)&ic.ipc_tcp_addr[0];
+                p = (u_short)ic.ipc_tcp_addr[5];
+#else /* solaris>=20400 */
+#    if solaris < 20600
+                la = (unsigned char *)&ic.ipc_tcp_laddr;
+                p = (u_short)((short *)&ic.ipc_tcp_ports)[1];
+#    else /* solaris>=20600 */
+#        if solaris >= 110000
+                la = (af == AF_INET6)
+                         ? (unsigned char *)&cs.connua_v6addr.connua_laddr
+                         : (unsigned char *)&cs.conn_src;
+                lp = cs.conn_lport;
+#        else /* solaris<110000 */
+#            if defined(HASIPv6)
+                la = (af == AF_INET6)
+                         ? (unsigned char *)&ic.ipc_v6laddr
+                         : (unsigned char *)IPv6_2_IPv4(&ic.ipc_v6laddr);
+#            else  /* !defined(HASIPv6 */
+                la = (unsigned char *)&ic.ipc_laddr;
+#            endif /* defined(HASIPv6) */
+
+                p = (u_short)ic.ipc_lport;
+#        endif     /* solaris>=110000 */
+#    endif         /* solaris<20600 */
+#endif             /* solaris<20400 */
+
+#if solaris < 110000
+                if (IPv_ADDR_UNSPEC(af, la) && !p && tcs) {
+
+                    /*
+                     * If the ipc_s structure has no local address, use the
+                     * local address in the stream's tcp_iph structure (except
+                     * for Solaris 2.4), and the port number in the stream's
+                     * tcph structure.
+                     */
+
+#    if solaris != 20400 && solaris < 80000
+                    la = (unsigned char *)&tc.tcp_iph.iph_src[0];
+#    else /* solaris==20400 || solaris<80000 */
+#        if solaris >= 100000 && defined(HAS_IPCLASSIFIER_H)
+                    la = (af == AF_INET6)
+                             ? (unsigned char *)&ic.conn_srcv6
+                             : (unsigned char *)IPv6_2_IPv4(&ic.conn_srcv6);
+#        else /* solaris<100000 || !defined(HAS_IPCLASSIFIER_H) */
+#            if solaris >= 80000
+#                if defined(HASIPv6)
+                    la =
+                        (af == AF_INET6)
+                            ? (unsigned char *)&tcb.tcpb_ip_src_v6
+                            : (unsigned char *)IPv6_2_IPv4(&tcb.tcpb_ip_src_v6);
+#                else  /* !defined(HASIPv6) */
+                    la = (unsigned char *)&tcb.tcpb_ip_src;
+#                endif /* defined(HASIPv6) */
+#            endif     /* solaris>=80000 */
+#        endif         /* solaris>=100000 && defined(HAS_IPCLASSIFIER_H) */
+#    endif             /* solaris!=20400 && !defined(HASIPv6) */
+
+                    if (tc.tcp_hdr_len && tc.tcp_tcph &&
+                        !kread(ctx, (KA_T)tc.tcp_tcph, (char *)&th,
+                               sizeof(th))) {
+                        tha = &th;
+                        s = (u_short *)&th.th_lport[0];
+                        p = *s;
+                    }
+                }
+#endif /* solaris<110000 */
+
+                lp = (int)ntohs(p);
+
+#if solaris < 20400
+                if ((int)ic.ipc_tcp_addr[2] != INADDR_ANY ||
+                    ic.ipc_tcp_addr[4] != 0) {
+                    fa = (unsigned char *)&ic.ipc_tcp_addr[2];
+                    fp = (int)ntohs(ic.ipc_tcp_addr[4]);
+                }
+#else /* solaris>=20400 */
+#    if solaris < 20600
+                if ((int)ic.ipc_tcp_faddr != INADDR_ANY ||
+                    ((u_short *)&ic.ipc_tcp_ports)[0] != 0) {
+                    fa = (unsigned char *)&ic.ipc_tcp_faddr;
+                    fp = (int)ntohs(((u_short *)&ic.ipc_tcp_ports)[0]);
+                }
+#    else /* solaris>=20600 */
+
+#        if solaris >= 110000
+                ta = (af == AF_INET6)
+                         ? (unsigned char *)&cs.connua_v6addr.connua_faddr
+                         : (unsigned char *)&cs.conn_rem;
+                if (!IPv_ADDR_UNSPEC(af, ta) || ((u_short)cs.conn_fport)) {
+                    fa = ta;
+                    fp = (u_short)cs.conn_fport;
+                }
+#        else /* solaris<110000 */
+#            if defined(HASIPv6)
+                ta = (af == AF_INET6)
+                         ? (unsigned char *)&ic.ipc_v6faddr
+                         : (unsigned char *)IPv6_2_IPv4(&ic.ipc_v6faddr);
+#            else  /* !defined(HASIPv6) */
+                ta = (unsigned char *)&ic.ipc_faddr;
+#            endif /* defined(HASIPv6) */
+
+                if (!IPv_ADDR_UNSPEC(af, ta) || ((u_short)ic.ipc_fport)) {
+                    fa = ta;
+                    fp = (int)ntohs(((u_short)ic.ipc_fport));
+                }
+#        endif     /* solaris>=110000 */
+#    endif         /* solaris<20600 */
+#endif             /* solaris <20400 */
+
+#if defined(HASIPv6)
+                if ((af == AF_INET6) &&
+                    ((la && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)la)) ||
+                     ((fa && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)fa))))) {
+
+                    /*
+                     * Convert IPv4 addresses in IPv6 structures to IPv4
+                     * addresses in IPv4 structures.  Change the address
+                     * family to AF_INET.
+                     */
+                    if (la)
+                        la = (unsigned char *)IPv6_2_IPv4(la);
+                    if (fa)
+                        fa = (unsigned char *)IPv6_2_IPv4(fa);
+                    af = AF_INET;
+                }
+#endif /* defined(HASIPv6) */
+
+                if (fa || la)
+                    (void)ent_inaddr(ctx, la, lp, fa, fp, af);
+            }
+            /*
+             * Save TCP state information.
+             */
+            if (tcs) {
+                (void)save_TCP_states(ctx, &tc, (caddr_t *)tha, tcbp,
+                                      (caddr_t *)NULL);
+                Lf->lts.type = 0;
+                Lf->lts.state.i = (int)tc.tcp_state;
+            }
+            /*
+             * Save TCP size information.
+             */
+
+            if (tcs)
+                (void)save_TCP_size(ctx, &tc);
+        }
+    } else
+        (void)strcat(Namech, "no TCP/UDP/IP information available");
+    /*
+     * Enter name characters if there are some.
+     */
+    if (Namech[0])
+        enter_nm(ctx, Namech);
+}
+
+#if solaris >= 110000
+/*
+ * read_icmp_t() - read connections icmp_t info
+ */
+
+static int read_icmp_t(struct lsof_context *ctx, /* context */
+                       KA_T va,    /* containing vnode kernel address */
+                       KA_T ph,    /* containing protocol handle kernel
+                                    * address */
+                       KA_T ia,    /* icmp_t structure's kernel address */
+                       icmp_t *ic) /* local icmp_t receiver */
+{
+    char tbuf[32], tbuf1[32]; /* print_kptr() temporary buffers */
+
+#    if defined(HAS_CONN_NEW)
+    struct conn_s cs; /* connection structure */
+    KA_T ka;          /* kernel address */
+
+    zeromem((char *)ic, sizeof(icmp_t));
+#    endif /* defined(HAS_CONN_NEW) */
+
+    (void)CTF_init(ctx, &IRU_ctfs, IRU_MOD_FORMAT, IRU_requests);
+    if (!ia || CTF_MEMBER_READ(ia, ic, icmp_t_members, icmp_state)
+
+#    if defined(HAS_CONN_NEW)
+        || CTF_MEMBER_READ(ia, ic, icmp_t_members, icmp_connp)
+#    else  /* !defined(HAS_CONN_NEW) */
+        || CTF_MEMBER_READ(ia, ic, icmp_t_members, icmp_bound_v6src) ||
+        CTF_MEMBER_READ(ia, ic, icmp_t_members, icmp_v6src) ||
+        CTF_MEMBER_READ(ia, ic, icmp_t_members, icmp_debug)
+#    endif /* defined(HAS_CONN_NEW) */
+
+    ) {
+        (void)snpf(Namech, Namechl - 1,
+                   "vnode at %s; proto handle at %s; can't read icmp_t at %s",
+                   print_kptr(va, tbuf, sizeof(tbuf)),
+                   print_kptr(ph, tbuf1, sizeof(tbuf1)),
+                   print_kptr(ia, (char *)NULL, 0));
+        Namech[Namechl - 1] = '\0';
+        enter_nm(ctx, Namech);
+        return (1);
+    }
+
+#    if defined(HAS_CONN_NEW)
+    if ((ka = (KA_T)ic->icmp_connp) &&
+        !kread(ctx, ka, (char *)&cs, sizeof(cs))) {
+        struct ip_xmit_attr_s xa;
+
+        /*
+         * Complete the icmp_t structure from the conn_s structure.
+         */
+        ic->icmp_bound_v6src = cs.conn_bound_addr_v6;
+        ic->icmp_v6src = cs.conn_saddr_v6;
+        ic->icmp_debug.icmp_Debug = cs.conn_debug;
+        ic->icmp_debug.icmp_broadcast = cs.conn_broadcast;
+        ic->icmp_debug.icmp_reuseaddr = cs.conn_reuseaddr;
+        ic->icmp_debug.icmp_useloopback = cs.conn_useloopback;
+        ic->icmp_debug.icmp_dgram_errind = cs.conn_dgram_errind;
+        if ((ka = (KA_T)cs.conn_ixa) &&
+            !kread(ctx, ka, (char *)&xa, sizeof(xa))) {
+            ic->icmp_debug.icmp_dontroute =
+                (xa.ixa_flags & IXAF_DONTROUTE) ? 1 : 0;
+        }
+    }
+#    endif /* defined(HAS_CONN_NEW) */
+
+    return (0);
+}
+
+/*
+ * read_rts_t() - read connections rts_t info
+ */
+
+static int read_rts_t(struct lsof_context *ctx, /* context */
+                      KA_T va,   /* containing vnode kernel address */
+                      KA_T ph,   /* containing protocol handle kernel
+                                  * address */
+                      KA_T ra,   /* rts_t structure's kernel address */
+                      rts_t *rt) /* local rts_t receiver */
+{
+    char tbuf[32], tbuf1[32]; /* print_kptr() temporary buffers */
+
+#    if defined(HAS_CONN_NEW)
+    struct conn_s cs; /* connextion structure */
+    KA_T ka;          /* kernal address */
+
+    zeromem((char *)rt, sizeof(rts_t));
+#    endif /* defined(HAS_CONN_NEW) */
+
+    (void)CTF_init(ctx, &IRU_ctfs, IRU_MOD_FORMAT, IRU_requests);
+    if (!ra || CTF_MEMBER_READ(ra, rt, rts_t_members, rts_state)
+
+#    if defined(HAS_CONN_NEW)
+        || CTF_MEMBER_READ(ra, rt, rts_t_members, rts_connp)
+#    else  /* !defined(HAS_CONN_NEW) */
+        || CTF_MEMBER_READ(ra, rt, rts_t_members, rts_debug)
+#    endif /* defined(HAS_CONN_NEW) */
+
+    ) {
+        (void)snpf(Namech, Namechl - 1,
+                   "vnode at %s; proto handle at %s; can't read rts_t at %s",
+                   print_kptr(va, tbuf, sizeof(tbuf)),
+                   print_kptr(ph, tbuf1, sizeof(tbuf1)),
+                   print_kptr(ra, (char *)NULL, 0));
+        Namech[Namechl - 1] = '\0';
+        enter_nm(ctx, Namech);
+        return (1);
+    }
+
+#    if defined(HAS_CONN_NEW)
+    if ((ka = (KA_T)rt->rts_connp) &&
+        !kread(ctx, ka, (char *)&cs, sizeof(struct conn_s))) {
+        struct ip_xmit_attr_s xa;
+
+        /*
+         * Fill in rts_debug from the connection structure.
+         */
+        rt->rts_debug.rts_Debug = cs.conn_debug;
+        rt->rts_debug.rts_broadcast = cs.conn_broadcast;
+        rt->rts_debug.rts_reuseaddr = cs.conn_reuseaddr;
+        rt->rts_debug.rts_useloopback = cs.conn_useloopback;
+        if ((ka = (KA_T)cs.conn_ixa) &&
+            !kread(ctx, ka, (char *)&xa, sizeof(xa))) {
+            rt->rts_debug.rts_dontroute =
+                (xa.ixa_flags & IXAF_DONTROUTE) ? 1 : 0;
+        }
+    }
+
+#    endif /* defined(HAS_CONN_NEW) */
+
+    return (0);
+}
+
+/*
+ * read_udp_t() - read UDP control structure
+ */
+
+static int read_udp_t(struct lsof_context *ctx, /* context */
+                      KA_T ua,                  /* ucp_t kernel address */
+                      udp_t *uc)                /* receiving udp_t structure */
+{
+    (void)CTF_init(ctx, &IRU_ctfs, IRU_MOD_FORMAT, IRU_requests);
+    if (!ua || CTF_MEMBER_READ(ua, uc, udp_t_members, udp_state)
+
+#    if defined(HAS_CONN_NEW)
+        || CTF_MEMBER_READ(ua, uc, udp_t_members, udp_connp)
+#    else  /* !defined(HAS_CONN_NEW) */
+        || CTF_MEMBER_READ(ua, uc, udp_t_members, udp_port) ||
+        CTF_MEMBER_READ(ua, uc, udp_t_members, udp_dstport) ||
+        CTF_MEMBER_READ(ua, uc, udp_t_members, udp_v6src) ||
+        CTF_MEMBER_READ(ua, uc, udp_t_members, udp_v6dst) ||
+        CTF_MEMBER_READ(ua, uc, udp_t_members, udp_ipversion) ||
+        CTF_MEMBER_READ(ua, uc, udp_t_members, udp_bits)
+#    endif /* defined(HAS_CONN_NEW) */
+
+    ) {
+        (void)snpf(Namech, Namechl, "can't read udp_t: %s",
+                   print_kptr(ua, (char *)NULL, 0));
+        Namech[Namechl - 1] = '\0';
+        enter_nm(ctx, Namech);
+        return (1);
+    }
+    return (0);
+}
+#endif /* solaris>=110000 */
+
+/*
+ * save_TCP_size() -- save TCP size information
+ */
+
+static void save_TCP_size(struct lsof_context *ctx, tcp_t *tc) /* pointer to TCP control structure */
+{
+    int rq, sq;
+
+#if defined(HASTCPTPIQ) || defined(HASTCPTPIW)
+#    if defined(HASTCPTPIW)
+    Lf->lts.rw = (int)tc->tcp_rwnd;
+    Lf->lts.ww = (int)tc->tcp_swnd;
+    Lf->lts.rws = Lf->lts.wws = 1;
+#    endif /* defined(HASTCPTPIW) */
+
+    if ((rq = (int)tc->tcp_rnxt - (int)tc->tcp_rack) < 0)
+        rq = 0;
+    if ((sq = (int)tc->tcp_snxt - (int)tc->tcp_suna - 1) < 0)
+        sq = 0;
+
+#    if defined(HASTCPTPIQ)
+    Lf->lts.rq = (unsigned long)rq;
+    Lf->lts.sq = (unsigned long)sq;
+    Lf->lts.rqs = Lf->lts.sqs = 1;
+#    endif /* defined(HASTCPTPIQ) */
+
+    if (Lf->access == LSOF_FILE_ACCESS_READ)
+        Lf->sz = (SZOFFTYPE)rq;
+    else if (Lf->access == LSOF_FILE_ACCESS_WRITE)
+        Lf->sz = (SZOFFTYPE)sq;
+    else
+        Lf->sz = (SZOFFTYPE)(rq + sq);
+    Lf->sz_def = 1;
+#endif /* defined(HASTCPTPIQ) || defined(HASTCPTPIW) */
+}
+
+/*
+ * save_TCP_states() - save TCP states
+ */
+
+static void save_TCP_states(struct lsof_context *ctx, /* context */
+                            tcp_t *tc,   /* pointer to TCP control structure */
+                            caddr_t *fa, /* flags address (may be NULL):
+                                          *   if HAS_CONN_NEW: conn_s *
+                                          *   if !CONN_HAS_NEW: tcph_t *
+                                          */
+                            tcpb_t *tb,  /* pointer to TCP base structure (may
+                                          * be NULL) */
+                            caddr_t *xp) /* pointer to struct ip_xmit_attr_s if
+                                          * HAS_CONN_NEW (may be NULL) */
+{
+    if (!tc)
+        return;
+
+#if defined(HASSOOPT)
+#    if defined(HAS_CONN_NEW)
+    if (fa) {
+        struct conn_s *cs = (struct conn_s *)fa;
+
+        if (cs->conn_broadcast)
+            Lf->lts.opt |= SO_BROADCAST;
+        if (cs->conn_debug)
+            Lf->lts.opt |= SO_DEBUG;
+        if (cs->conn_dgram_errind)
+            Lf->lts.opt |= SO_DGRAM_ERRIND;
+        if (xp && (((ip_xmit_attr_t *)xp)->ixa_flags & IXAF_DONTROUTE))
+            Lf->lts.opt |= SO_DONTROUTE;
+        if (cs->conn_keepalive) {
+            Lf->lts.opt |= SO_KEEPALIVE;
+            Lf->lts.kai = (unsigned int)tc->tcp_ka_interval;
+        }
+        if (cs->conn_linger) {
+            Lf->lts.opt |= SO_LINGER;
+            Lf->lts.ltm = (unsigned int)cs->conn_lingertime;
+        }
+        if (cs->conn_oobinline)
+            Lf->lts.opt |= SO_OOBINLINE;
+        Lf->lts.pqlen = (unsigned int)tc->tcp_conn_req_cnt_q0;
+        Lf->lts.qlen = (unsigned int)tc->tcp_conn_req_cnt_q;
+        Lf->lts.qlim = (unsigned int)tc->tcp_conn_req_max;
+        Lf->lts.pqlens = Lf->lts.qlens = Lf->lts.qlims = (unsigned char)1;
+        if (cs->conn_reuseaddr)
+            Lf->lts.opt |= SO_REUSEADDR;
+        if (cs->conn_useloopback)
+            Lf->lts.opt |= SO_USELOOPBACK;
+#    else /* !defined(HAS_CONN_NEW) */
+    if (1) {
+        if (tc->tcp_broadcast)
+            Lf->lts.opt |= SO_BROADCAST;
+        if (tc->tcp_debug)
+            Lf->lts.opt |= SO_DEBUG;
+        if (tc->tcp_dgram_errind)
+            Lf->lts.opt |= SO_DGRAM_ERRIND;
+        if (tc->tcp_dontroute)
+            Lf->lts.opt |= SO_DONTROUTE;
+        if (tc->KEEPALIVE_INTERVAL) {
+            Lf->lts.opt |= SO_KEEPALIVE;
+            Lf->lts.kai = (unsigned int)tc->KEEPALIVE_INTERVAL;
+        }
+        if (tc->tcp_linger) {
+            Lf->lts.opt |= SO_LINGER;
+            Lf->lts.ltm = (unsigned int)tc->tcp_lingertime;
+        }
+        if (tc->tcp_oobinline)
+            Lf->lts.opt |= SO_OOBINLINE;
+        Lf->lts.pqlen = (unsigned int)tc->tcp_conn_req_cnt_q0;
+        Lf->lts.qlen = (unsigned int)tc->tcp_conn_req_cnt_q;
+        Lf->lts.qlim = (unsigned int)tc->tcp_conn_req_max;
+        Lf->lts.pqlens = Lf->lts.qlens = Lf->lts.qlims = (unsigned char)1;
+
+#        if solaris >= 80000
+#            if defined(HAS_IPCLASSIFIER_H)
+        if (tc->tcp_reuseaddr)
+#            else  /* !defined(HAS_IPCLASSIFIER_H) */
+        if (tb && tb->tcpb_reuseaddr)
+#            endif /* !defined(HAS_IPCLASSIFIER_H) */
+
+            Lf->lts.opt |= SO_REUSEADDR;
+#        endif     /* solaris>=80000 */
+
+        if (tc->tcp_useloopback)
+            Lf->lts.opt |= SO_USELOOPBACK;
+#    endif         /* defined(HAS_CONN_NEW) */
+#endif             /* defined(HASSOOPT) */
+
+#if defined(HASTCPOPT)
+#    if defined(ACK_TIMER)
+#        if !defined(HAS_CONN_NEW)
+        if (fa && (((tcph_t *)fa)->th_flags[0] & ACK_TIMER))
+            Lf->lts.topt |= TF_DELACK;
+#        endif /* !defined(HAS_CONN_NEW) */
+#    endif     /* defined(ACK_TIMER) */
+
+#    if solaris < 80000 || defined(HAS_IPCLASSIFIER_H)
+        Lf->lts.mss = (unsigned long)tc->tcp_mss;
+#    else  /* solaris>=80000 && !defined(HAS_IPCLASSIFIER_H) */
+        if (tb)
+            Lf->lts.mss = (unsigned long)tb->tcpb_mss;
+#    endif /* solaris<80000 || defined(HAS_IPCLASSIFIER_H) */
+
+        Lf->lts.msss = (unsigned char)1;
+        if (tc->tcp_naglim == 1L)
+            Lf->lts.topt |= TF_NODELAY;
+        if (tc->tcp_fin_sent)
+            Lf->lts.topt |= TF_SENTFIN;
+    }
+#endif /* defined(HASTCPOPT) */
+}
diff --git a/lib/dialects/sun/dstore.c b/lib/dialects/sun/dstore.c
new file mode 100644 (file)
index 0000000..9e600ca
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * dstore.c - Solaris global storage for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#ifndef lint
+static char copyright[] =
+    "@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
+#endif
+
+#include "common.h"
+
+/*
+ * Global storage definitions
+ */
+
+#if defined(HAS_AFS)
+
+#    if defined(HASAOPT)
+char *AFSApath = (char *)NULL; /* alternate AFS name list path
+                                * (from -a) */
+#    endif                     /* defined(HASAOPT) */
+
+dev_t AFSdev;              /* AFS file system device number */
+int AFSdevStat = 0;        /* AFSdev status: 0 = unknown;
+                            *            1 = known */
+int AFSfstype = -1;        /* AFS file system type index */
+KA_T AFSVfsp = (KA_T)NULL; /* AFS vfs struct kernel address */
+#endif                     /* defined(HAS_AFS) */
+
+struct clone *Clone = NULL; /* clone list */
+major_t CloneMaj;           /* clone major device number */
+
+/*
+ * Drive_Nl -- table to drive the building of Nl[] via build_Nl()
+ *            (See lsof.h and misc.c.)
+ */
+
+struct drive_Nl Drive_Nl[] = {{"afsops", "afs_ops"},
+                              {"arFid", "afs_rootFid"},
+                              {"avops", "afs_vnodeops"},
+                              {"Avops", "Afs_vnodeops"},
+                              {"avol", "afs_volumes"},
+                              {"auvops", "auto_vnodeops"},
+                              {"ctfsadir", "ctfs_ops_adir"},
+                              {"ctfsbund", "ctfs_ops_bundle"},
+                              {"ctfscdir", "ctfs_ops_cdir"},
+                              {
+                                  "ctfsctl",
+                                  "ctfs_ops_ctl",
+                              },
+                              {
+                                  "ctfsevt",
+                                  "ctfs_ops_event",
+                              },
+                              {
+                                  "ctfslate",
+                                  "ctfs_ops_latest",
+                              },
+                              {
+                                  "ctfsroot",
+                                  "ctfs_ops_root",
+                              },
+                              {
+                                  "ctfsstat",
+                                  "ctfs_ops_stat",
+                              },
+                              {
+                                  "ctfssym",
+                                  "ctfs_ops_sym",
+                              },
+                              {
+                                  "ctfstdir",
+                                  "ctfs_ops_tdir",
+                              },
+                              {
+                                  "ctfstmpl",
+                                  "ctfs_ops_tmpl",
+                              },
+                              {"cvops", "cachefs_vnodeops"},
+                              {"clmaj", "clonemaj"},
+                              {"clmaj_alt", "clone_major"},
+                              {"fdops", "fdvnodeops"},
+                              {"fd_ops", "fd_vnodeops"},
+                              {"fvops", "fifo_vnodeops"},
+                              {"hvops", "hsfs_vnodeops"},
+                              {"lvops", "lo_vnodeops"},
+                              {"mntops", "mntvnodeops"},
+                              {"mvops", "mvfs_vnodeops"},
+
+#if solaris < 90000
+                              {X_NCACHE, "ncache"},
+                              {X_NCSIZE, "ncsize"},
+#else  /* solaris>=90000 */
+                              {X_NCACHE, "nc_hash"},
+                              {X_NCSIZE, "nc_hashsz"},
+                              {"hshav", "nc_hashavelen"},
+#endif /* solaris<90000 */
+
+#if defined(NCACHE_NEGVN)
+                              {NCACHE_NEGVN, NCACHE_NEGVN},
+#endif /* defined(NCACHE_NEGVN) */
+
+                              {"nvops", "nfs_vnodeops"},
+                              {"n3vops", "nfs3_vnodeops"},
+                              {"n4vops", "nfs4_vnodeops"},
+                              {"nmvops", "nm_vnodeops"},
+                              {"nproc", "nproc"},
+                              {"pdvops", "pcfs_dvnodeops"},
+                              {"pfvops", "pcfs_fvnodeops"},
+                              {"portvops", "port_vnodeops"},
+                              {"pract", "practive"},
+                              {"prvops", "prvnodeops"},
+                              {"sam1vops", "samfs_vnodeops"},
+                              {"sam2vops", "samfs_client_vnodeops"},
+                              {"sam3vops", "samfs_vnodeopsp"},
+                              {"sam4vops", "samfs_client_vnodeopsp"},
+                              {"sdevops", "sdev_vnodeops"},
+                              {"sgvops", "segvn_ops"},
+                              {"shvops", "sharefs_ops_data"},
+                              {"sckvops", "sock_vnodeops"},
+                              {"socketvops", "socket_vnodeops"},
+                              {"spvops", "spec_vnodeops"},
+                              {"sncavops", "socknca_vnodeops"},
+                              {"stpivops", "socktpi_vnodeops"},
+                              {"tvops", "tmp_vnodeops"},
+                              {"uvops", "ufs_vnodeops"},
+                              {"vvfops", "fdd_vnops"},
+                              {"vvfcops", "fdd_chain_vnops"},
+                              {"vvfclops", "vx_fcl_vnodeops_p"},
+                              {"vvops", "vx_vnodeops"},
+                              {"vvops_p", "vx_vnodeops_p"},
+
+#if solaris >= 20500
+                              {"devops", "dv_vnodeops"},
+                              {"doorops", "door_vnodeops"},
+                              {"kbase", "_kernelbase"},
+#endif /* solaris>=20500 */
+
+#if solaris >= 20501
+                              {"kasp", "kas"},
+#endif /* solaris>=20501 */
+
+#if solaris >= 110000
+                              {"devipnetops", "devipnet_vnodeops"},
+                              {"devnetops", "devnet_vnodeops"},
+                              {"devptsops", "devpts_vnodeops"},
+                              {"devvtops", "devvt_vnodeops"},
+#endif /* solaris>=110000 */
+
+                              {"zfsdops", "zfs_dvnodeops"},
+                              {"zfseops", "zfs_evnodeops"},
+                              {"zfsfops", "zfs_fvnodeops"},
+                              {"zfsshops", "zfs_sharevnodeops"},
+                              {"zfssymops", "zfs_symvnodeops"},
+                              {"zfsxdops", "zfs_xdvnodeops"},
+                              {"", ""},
+                              {NULL, NULL}};
+
+char **Fsinfo = NULL;             /* file system information */
+int Fsinfomax = 0;                /* maximum file system type */
+int HasALLKMEM = 0;               /* has ALLKMEM device */
+int HaveCloneMaj = 0;             /* clone major device number has
+                                   * been identified and is in
+                                   * CloneMaj */
+kvm_t *Kd = NULL;                 /* kvm descriptor */
+struct l_vfs *Lvfs = NULL;        /* local vfs structure table */
+struct netclone *Netclone = NULL; /* net clone devices from
+                                   * /devices/pseudo */
+
+#if defined(HASFSTRUCT)
+/*
+ * Pff_tab[] - table for printing file flags
+ */
+
+struct pff_tab Pff_tab[] = {{(long)FREAD, FF_READ},
+                            {(long)FWRITE, FF_WRITE},
+                            {(long)FNDELAY, FF_NDELAY},
+                            {(long)FAPPEND, FF_APPEND},
+                            {(long)FSYNC, FF_SYNC},
+
+#    if defined(FREVOKED)
+                            {(long)FREVOKED, FF_REVOKED},
+#    endif /* defined(FREVOKED) */
+
+                            {(long)FDSYNC, FF_DSYNC},
+                            {(long)FRSYNC, FF_RSYNC},
+
+#    if defined(FOFFMAX)
+                            {(long)FOFFMAX, FF_LARGEFILE},
+#    endif /* defined(FFOFFMAX) */
+
+                            {(long)FNONBLOCK, FF_NBLOCK},
+                            {(long)FNOCTTY, FF_NOCTTY},
+                            {(long)FASYNC, FF_ASYNC},
+                            {(long)FNODSYNC, FF_NODSYNC},
+                            {(long)0, NULL}};
+
+/*
+ * Pof_tab[] - table for print process open file flags
+ */
+
+struct pff_tab Pof_tab[] = {
+
+#    if defined(UF_EXCLOSE)
+    {(long)UF_EXCLOSE, POF_CLOEXEC},
+#    endif /* defined(UF_EXCLOSE) */
+
+#    if defined(FD_CLOEXEC)
+    {(long)FD_CLOEXEC, POF_CLOEXEC},
+#    endif /* defined(FD_CLOEXEC) */
+
+#    if defined(UF_FDLOCK)
+    {(long)UF_FDLOCK, POF_FDLOCK},
+#    endif /* defined(UF_FDLOCK) */
+
+    {(long)0, NULL}};
+#endif /* defined(HASFSTRUCT) */
+
+struct pseudo *Pseudo = NULL; /* non-clone devices from
+                               * /devices/pseudo */
+int Unof;                     /* u_nofiles value */
diff --git a/lib/dialects/sun/machine.h b/lib/dialects/sun/machine.h
new file mode 100644 (file)
index 0000000..b385241
--- /dev/null
@@ -0,0 +1,696 @@
+/*
+ * machine.h - Solaris definitions for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+/*
+ * $Id: machine.h,v 1.48 2018/02/14 14:24:07 abe Exp $
+ */
+
+#if !defined(LSOF_MACHINE_H)
+#    define LSOF_MACHINE_H 1
+
+#    if defined(HAS_LGRP_ROOT_CONFLICT)
+/*
+ * <sys/lgrp.h> must be #include'd early on some older Solaris systems at
+ * version 9 and Solaris 10 before _KMEMUSER or _KERNEL are defined to avoid
+ * a conflict with the use of lgrp_root as an external symbol in <sys/lgrp.h>
+ * and a macro in <sys/lgrp_user.h>.
+ */
+
+#        include <sys/lgrp.h>
+#    endif /* defined(HAS_LGRP_ROOT_CONFLICT) */
+
+#    if solaris >= 100000
+#        if !defined(HAS_AIO_REQ_STRUCT)
+/*
+ * When <sys.aio_req.h> lacks one, define a dummy aio_req structure for
+ * Solaris >= 10 systems.
+ *
+ * If this definition causes compilation errors for <sys/vnode.h>, especially
+ * with Solaris 11, it may be necessary to comment out the following structure
+ * definition.  I don't know a test that will determine the possibility of
+ * compilation errors.
+ */
+
+typedef struct aio_req {
+    int dummy;
+} aio_req_t;
+
+#        endif /* !defined(HAS_AIO_REQ_STRUCT) */
+
+/*
+ * Include <sys/utsname.h> so it won't be corrupted for 32 bit compilations
+ * when _KERNEL is defined for some include files in dlsof.h.
+ *
+ * Daniel Trinkle identified this requirement.
+ */
+
+#        include <sys/utsname.h>
+#    endif /* solaris>=100000 */
+
+#    if solaris >= 20600
+/*
+ * <sys/poll.h> must be #include'd for Solaris >= 2.6 while _KMEMUSER is
+ * defined.  Since <netdb.h> also #include's <sys/poll.h> and <netdb.h>
+ * is #include'd from lsof.h, we must perform some early #include magic
+ * here to set things up properly.
+ */
+
+#        define _KMEMUSER 1
+#        define __BIT_TYPES_DEFINED__                                          \
+            1 /* work around to keep the BIND                                  \
+               * <sys/bitypes.h> from colliding with                           \
+               * the Solaris <sys/int_types.h> */
+
+#        if defined(HAS_PAD_MUTEX)
+/*
+ * Some versions of Solaris 11 need to have the pad_mutex_t typedef defined.
+ * However, it is only defined by <sys/mutex.h> when _KERNEL is defined, and
+ * doing that causes other difficulties.
+ *
+ * So <sys/mutex.h> is included here, followed by a copy of its pad_mutex_t
+ * typedef, all outside the _KERNEL definition.
+ *
+ * This brute force work-around was supplied by Carson Gaspar.
+ */
+
+#            include <sys/mutex.h>
+typedef struct pad_mutex {
+    kmutex_t pad_mutex;
+#            if defined(_LP64)
+    char pad_pad[64 - sizeof(kmutex_t)];
+#            endif /* defined(_LP64) */
+} pad_mutex_t;
+#        endif /* defined(HAS_PAD_MUTEX) */
+
+#        include <sys/poll.h>
+
+#        if solaris >= 80000
+#            include <sys/wait.h>
+#            include <sys/types32.h>
+#            define _KERNEL 1
+#            include <netinet/in.h>
+#            undef _KERNEL
+#            define ipa_32 s6_ipaddr.ipa_32
+#        endif /* solaris>=80000 */
+
+#    endif /* solaris>=20600 */
+
+/*
+ * 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().
+ */
+
+#    if solaris >= 20501
+#        define CAN_USE_CLNT_CREATE 1
+#    endif /* solaris>=20501 */
+
+/*
+ * DEVDEV_PATH defines the path to the directory that contains device
+ * nodes.
+ */
+
+#    if solaris < 100000
+#        define DEVDEV_PATH "/dev"
+#    else /* solaris>=100000 */
+#        define DEVDEV_PATH "/devices"
+#    endif /* solaris<100000 */
+
+/*
+ * GET_MAX_FD is defined for those dialects that provide a function other than
+ * getdtablesize() to obtain the maximum file descriptor number plus one.
+ */
+
+#    if solaris < 20500
+#        define GET_MAX_FD get_max_fd
+#    endif /* solaris<20500 */
+
+/*
+ * HASAOPT is defined for those dialects that have AFS support; it specifies
+ * that the default path to an alternate AFS kernel name list file may be
+ * supplied with the -A <path> option.
+ */
+
+#    define HASAOPT 1
+
+/*
+ * HASBLKDEV is defined for those dialects that want block device information
+ * recorded in BDevtp[].
+ */
+
+#    define HASBLKDEV 1
+
+/*
+ * HASDCACHE is defined for those dialects that support a device cache
+ * file.
+ *
+ * HASENVDC defined the name of an environment variable that contains the
+ * device cache file path.  The HASENVDC environment variable is ignored when
+ * the lsof process is setuid(root) or its real UID is 0.
+ *
+ * HASPERSDC defines the format for the last component of a personal device
+ * cache file path.  The first will be the home directory of the real UID that
+ * executes lsof.
+ *
+ * HASPERSDCPATH defines the environment variable whose value is the middle
+ * component of the personal device cache file path.  The middle component
+ * follows the home directory and precedes the results of applying HASPERSDC.
+ * The HASPERSDCPATH environment variable is ignored when the lsof process is
+ * setuid(root) or its real UID is 0.
+ *
+ * HASSYSDC defines a public device cache file path.  When it's defined, it's
+ * used as the path from which to read the device cache.
+ *
+ * Consult the 00DCACHE and 00FAQ files of the lsof distribution for more
+ * information on device cache file path construction.
+ */
+
+#    define HASDCACHE 1
+#    define HASENVDC "LSOFDEVCACHE"
+#    define HASPERSDC "%h/%p.lsof_%L"
+#    define HASPERSDCPATH "LSOFPERSDCPATH"
+/* #define     HASSYSDC        "/your/choice/of/path" */
+
+/*
+ * HASCDRNODE is defined for those dialects that have CD-ROM nodes.
+ */
+
+/* #define     HASCDRNODE      1 */
+
+/*
+ * HASEOPT is defined for dialects that support the +|-e option.
+ */
+
+/* #define     HASEOPT 1 */
+
+/*
+ * HASFIFONODE is defined for those dialects that have FIFO nodes.
+ */
+
+#    define HASFIFONODE 1
+
+/*
+ * HASFSINO is defined for those dialects that have the file system
+ * inode element, fs_ino, in the lfile structure definition in lsof.h.
+ */
+
+#    define HASFSINO 1
+
+/*
+ * HASFSTRUCT is defined if the dialect has a file structure.
+ *
+ * FSV_DEFAULT defines the default set of file structure values to list.
+ * It defaults to zero (0), but may be made up of a combination of the
+ * FSV_* symbols from lsof.h.
+ *
+ * If any file structure value is unavailable, its use may be suppressed
+ * with any of the following definitions:
+ *
+ *   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 additional elements need to be preset in the alloc_lfile() function
+ * of proc.c, the SETLFILEADD macro may be defined to do that.
+ *
+ * If any additional elements need to be cleared in alloc_lfile() or in the
+ * free_proc() function of proc.c, the CLRLFILEADD macro may be defined to
+ * do that.  Note that CLRLFILEADD takes one argument, the pointer to the
+ * lfile struct.  The CLRLFILEADD macro is expected to expand to statements
+ * that are complete -- i.e., have terminating semi-colons -- so the macro is
+ * called without a terminating semicolon by proc.c.
+ *
+ * The HASXOPT definition may be used to select the conditions under which
+ * private lfile elements are used.
+ */
+
+#    if solaris >= 10000 && defined(HAS_V_PATH)
+#        define HASLFILEADD KA_T V_path;
+#        define CLRLFILEADD(lf) (lf)->V_path = (KA_T)NULL;
+#        define SETLFILEADD Lf->V_path = (KA_T)NULL;
+#    endif /* solaris>=10000 && defined(HAS_V_PATH) */
+
+/*
+ * HASMNTSTAT indicates the dialect supports the mount stat(2) result option
+ * in its l_vfs and mounts structures.
+ */
+
+#    if solaris >= 10000 && defined(HAS_V_PATH)
+#        define HASMNTSTAT 1
+#    endif /* solaris>=10000 && defined(HAS_V_PATH) */
+
+/*
+ * HASMNTSUP is defined for those dialects that support the mount supplement
+ * option.
+ */
+
+/* #define     HASMNTSUP       1       */
+
+/*
+ * HASMOPT is defined for those dialects that support the reading of
+ * kernel memory from an alternate file.
+ */
+
+#    define HASMOPT 1
+
+/*
+ * HASNCACHE is defined for those dialects that have a kernel name cache
+ * that lsof can search.  A value of 1 directs printname() to prefix the
+ * cache value with the file system directory name; 2, avoid the prefix.
+ *
+ * NCACHELDPFX is a set of C commands to execute before calling ncache_load().
+ *
+ * NCACHELDSFX is a set of C commands to execute after calling ncache_load().
+ */
+
+#    if solaris >= 10000 && defined(HAS_V_PATH)
+/* #define     HASNCACHE       1       */
+#    else /* solaris<10 || !defined(HAS_V_PATH) */
+#        define HASNCACHE 1
+#    endif /* solaris>=10000 && defined(HAS_V_PATH) */
+
+#    define NCACHELDPFX open_kvm(); /* do before calling ncache_load() */
+
+/* #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().
+ */
+
+#    if solaris < 100000
+#        define HASPRINTDEV print_dev
+#    endif /* solaris<100000 */
+
+/* #define     HASPRINTINO     print_ino?      */
+/* #define     HASPRINTNM      print_nm?       */
+
+/*
+ * HASPRIVFILETYPE and PRIVFILETYPE are defined for dialects that have a
+ * file structure type that isn't defined by a DTYPE_* symbol.  They are
+ * used in lib/prfp.c to select the type's processing.
+ *
+ * PRIVFILETYPE is the definition of the f_type value in the file struct.
+ *
+ * HASPRIVFILETYPE is the name of the processing function.
+ */
+
+/* #define     HASPRIVFILETYPE process_shmf?   */
+/* #define     PRIVFILETYPE    ??      */
+
+/*
+ * HASPRIVNMCACHE is defined for dialects that have a private method for
+ * printing cached NAME column values for some files.  HASPRIVNAMECACHE
+ * is defined to be the name of the function.
+ *
+ * The function takes one argument, a struct lfile pointer to the file, and
+ * returns non-zero if it prints a name to stdout.
+ */
+
+#    if solaris >= 10000 && defined(HAS_V_PATH)
+#        define HASPRIVNMCACHE print_v_path
+#    else /* solaris<10 || !defined(HAS_V_PATH) */
+#        if defined(HASVXFSRNL)
+#            define HASPRIVNMCACHE print_vxfs_rnl_path
+#        else  /* !defined(HASVXFSRNL) */
+/* #define     HASPRIVNMCACHE  <function name> */
+#        endif /* defined(HASVXFSRNL) */
+#    endif     /* solaris>=10000 && defined(HAS_V_PATH) */
+
+/*
+ * HASPRIVPRIPP is defined for dialects that have a private function for
+ * printing IP protocol names.  When HASPRIVPRIPP isn't defined, the
+ * IP protocol name printing function defaults to printiprto().
+ */
+
+/* #define     HASPRIVPRIPP    1       */
+
+/*
+ * HASPROCFS is defined for those dialects that have a proc file system --
+ * usually /proc and usually in SYSV4 derivatives.
+ *
+ * HASFSTYPE is defined as 1 for those systems that have a file system type
+ * string, st_fstype, in the stat() buffer; 2, for those systems that have a
+ * file system type integer in the stat() buffer, named MOUNTS_STAT_FSTYPE;
+ * 0, for systems whose stat(2) structure has no file system type member.  The
+ * additional symbols MOUNTS_FSTYPE, RMNT_FSTYPE, and RMNT_STAT_FSTYPE may be
+ * defined in dlsof.h to direct how the readmnt() function in lib/rmnt.c
+ * preserves these stat(2) and getmntent(3) buffer values in the local mounts
+ * structure.
+ *
+ * The defined value is the string that names the file system type.
+ *
+ * The HASPROCFS definition usually must be accompanied by the HASFSTYPE
+ * definition and the providing of an fstype element in the local mounts
+ * structure (defined in dlsof.h).
+ *
+ * The HASPROCFS definition may be accompanied by the HASPINODEN definition.
+ * HASPINODEN specifies that searching for files in HASPROCFS is to be done
+ * by inode number.
+ */
+
+#    define HASPROCFS "proc"
+#    define HASFSTYPE 1
+#    define HASPINODEN 1
+
+/*
+ * HASRNODE is defined for those dialects that have rnodes.
+ */
+
+#    define HASRNODE 1
+
+/*
+ * Define HASSECURITY to restrict the listing of all open files to the
+ * root user.  When HASSECURITY is defined, the non-root user may list
+ * only files whose processes have the same user ID as the real user ID
+ * (the one that its user logged on with) of the lsof process.
+ */
+
+/* #define     HASSECURITY     1       */
+
+/*
+ * If HASSECURITY is defined, define HASNOSOCKSECURITY to allow users
+ * restricted by HASSECURITY to list any open socket files, provide their
+ * listing is selected by the "-i" option.
+ */
+
+/* #define     HASNOSOCKSECURITY       1       */
+
+/*
+ * HASSETLOCALE is defined for those dialects that have <locale.h> and
+ * setlocale().
+ *
+ * If the dialect also has wide character support for language locales,
+ * HASWIDECHAR activates lsof's wide character support and WIDECHARINCL
+ * defines the header file (if any) that must be #include'd to use the
+ * mblen() and mbtowc() functions.
+ *
+ * If a special definition is required (e.g., for Solaris) before #include'ing
+ * <ctype.h>, do that here.
+ */
+
+#    define HASSETLOCALE 1
+#    define HASWIDECHAR 1
+#    define WIDECHARINCL <wchar.h>
+#    define __XPG4_CHAR_CLASS__
+#    include <ctype.h>
+#    undef __XPG4_CHAR_CLASS__
+
+/*
+ * HASSNODE is defined for those dialects that have snodes.
+ */
+
+#    define HASSNODE 1
+
+/*
+ * HASTASKS is defined for those dialects that have task reporting support.
+ */
+
+/* #define     HASTASKS        1 */
+
+/*
+ * HASSOOPT, HASSOSTATE and HASTCPOPT define the availability of information
+ * on socket options (SO_* symbols), socket states (SS_* symbols) and TCP
+ * options.
+ */
+
+#    if solaris >= 20600
+#        define HASSOOPT 1 /* has socket option information */
+/* #define     HASSOSTATE      1       has socket state information */
+#        define HASTCPOPT 1 /* has TCP options or flags */
+#    endif                  /* solaris>=20600 */
+
+/*
+ * Define HASSPECDEVD to be the name of a function that handles the results
+ * of a successful stat(2) of a file name argument.
+ *
+ * For example, HASSPECDEVD() for Darwin makes sure that st_dev is set to
+ * what stat("/dev") returns -- i.e., what's in DevDev.
+ *
+ * The function takes two arguments:
+ *
+ *     1: pointer to the full path name of file
+ *     2: pointer to the stat(2) result
+ *
+ * The function returns void.
+ */
+
+/* #define     HASSPECDEVD     process_dev_stat */
+
+/*
+ * HASSTREAMS is defined for those dialects that support streams.
+ */
+
+#    define HASSTREAMS 1
+
+/*
+ * HASTCPTPIQ is defined for dialects where it is possible to report the
+ * TCP/TPI Recv-Q and Send-Q values produced by netstat.
+ */
+
+#    if solaris == 20300 || solaris >= 20500
+#        define HASTCPTPIQ 1
+#    endif /* solaris==20300 || solaris>=20500 */
+
+/*
+ * HASTCPTPIW is defined for dialects where it is possible to report the
+ * TCP/TPI send and receive window sizes produced by netstat.
+ */
+
+#    if solaris == 20300 || solaris >= 20500
+#        define HASTCPTPIW 1
+#    endif /* solaris==20300 || solaris>=20500 */
+
+/*
+ * HASTCPUDPSTATE is defined for dialects that have TCP and UDP state
+ * support -- i.e., for the "-stcp|udp:state" option and its associated
+ * speed improvements.
+ */
+
+#    define HASTCPUDPSTATE 1
+
+/*
+ * HASTMPNODE is defined for those dialects that have tmpnodes.
+ */
+
+#    define HASTMPNODE 1
+
+/*
+ * HASVNODE is defined for those dialects that use the Sun virtual file system
+ * node, the vnode.  BSD derivatives usually do; System V derivatives prior to
+ * R4 usually don't.
+ */
+
+#    define HASVNODE 1
+
+/*
+ * HASXOPT is defined for those dialects that have an X option.  It
+ * defines the text for the usage display.  HASXOPT_VALUE defines the
+ * option's default binary value -- 0 or 1.
+ */
+
+#    if solaris >= 10000 && defined(HAS_V_PATH)
+#        define HASXOPT "report deleted paths"
+#        define HASXOPT_VALUE 0
+#    endif /* solaris>=10000 && defined(HAS_V_PATH) */
+
+/*
+ * INODETYPE and INODEPSPEC define the internal node number type and its
+ * printf specification modifier.  These need not be defined and lsof.h
+ * can be allowed to define defaults.
+ *
+ * These are defined here, because they must be used in dlsof.h.
+ */
+
+#    if solaris >= 20501
+#        define INODETYPE unsigned long long
+/* inode number internal storage type */
+#        define INODEPSPEC                                                     \
+            "ll" /* INODETYPE printf specification                             \
+                  * modifier */
+#    endif       /* solaris>=20501 */
+
+/*
+ * UID_ARG defines the size of a User ID number when it is passed
+ * as a function argument.
+ */
+
+#    define UID_ARG long
+
+/*
+ * 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_RNAM                    1          rnam.c */
+
+#    if solaris < 90000
+#        define USE_LIB_RNCH 1 /* rnch.c */
+#    endif                     /* solaris<90000 */
+
+/* #define     USE_LIB_RNMH                    1          rnmh.c */
+/* #define     USE_LIB_SNPF                    1          snpf.c */
+#    define snpf snprintf /* use the system's snprintf() */
+
+/*
+ * WARNDEVACCESS is defined for those dialects that should issue a warning
+ * when lsof can't access /dev (or /device) or one of its sub-directories.
+ * The warning can be inhibited by the lsof caller with the -w option.
+ */
+
+#    define WARNDEVACCESS 1
+
+/*
+ * WARNINGSTATE is defined for those dialects that want to suppress all lsof
+ * warning messages.
+ */
+
+/* #define     WARNINGSTATE    1       warnings are enabled by default */
+
+/*
+ * WILLDROPGID is defined for those dialects whose lsof executable runs
+ * setgid(not_real_GID) and whose setgid power can be relinquished after
+ * the dialect's initialize() function has been executed.
+ */
+
+#    define WILLDROPGID 1
+
+/*
+ * zeromem is a macro that uses bzero or memset.
+ */
+
+#    define zeromem(a, l) memset((void *)a, 0, l)
+
+#endif /* !defined(LSOF_MACHINE_H) */
diff --git a/lib/dialects/sun/solaris_kaddr_filters b/lib/dialects/sun/solaris_kaddr_filters
new file mode 100644 (file)
index 0000000..7fcd692
--- /dev/null
@@ -0,0 +1,239 @@
+       Solaris Kernel Address Filtering in lsof 4.50 and Above
+
+Current Filter
+==============
+
+Lsof revisions 4.49 and below, have exactly one filter:  the kernel
+virtual address is checked against the kernel's virtual address
+base -- e.g., what's found in the kernel variable kernelbase.  For
+sun4m that's 0xf0000000, for sun4u, 0x10000000.
+
+This filter keeps lsof from handing some bad addresses to the
+kernel, but not all bad addresses.  For example, the virtual address
+0x657a682e passes this test on a sun4u machine, but on at least
+one sun4u that virtual address translates to the physical address
+0x1cf08c30000, which is the address of a register of a qfe interface
+on the machine.  There is some evidence that a kvm_kread() call for
+the 0x657a682e address may crash that sun4u.
+
+Lsof 4.71 and above use no filter if they detect that /dev/allkmem
+exists.  That is done because, when /dev/allkmem exists, /dev/kmem has
+address filtering in its device driver.
+
+
+======================
+!!!IMPORTANT UPDATE!!!
+======================
+
+In late May 2002 I learned that Sun had reports of other kernel
+crashes, caused by adb, lsof, and mdb, related to incorrect addresses
+being supplied to /dev/kmem.  (This report was written originally
+on July 18, 2000.)
+
+The problem is described in and fixed or patched:
+
+    Solaris 7: SPARC kernel patch 106541-20
+              Intel kernel patch 106542-20
+
+    Solaris 8: SPARC kernel patch 108528-14
+              Intel kernel patch 108529-14
+
+    Solaris 9: bug 4344513
+
+So, if you want to be comfortable using lsof (or adb or mdb) with
+Solaris, install the appropriate Solaris 7 or 8 patches, or upgrade
+to Solaris 9.
+
+Note that these patches provide the /dev/allkmem device, whose presence
+causes lsof to rely on the address filtering of the /dev/kmem device.
+
+
+New Filters
+===========
+
+Lsof 4.50 adds additional filters to the kernelbase check.  The
+filters differ, based on the Solaris version:
+
+       Solaris
+       Version         New Filters
+       =======         ===========
+
+       2.5 and below   none
+       2.5.1           kvm_physaddr() (-lkvm), caching, llseek(),
+                           and /dev/mem
+       2.6             kvm_physaddr() (-lkvm), caching, llseek(),
+                           and /dev/mem
+       7, 8, and 9     kvm_physaddr() (ioctl()), caching, and
+                           kvm_pread()
+
+                       See !!!IMPORTANT NOTICE!! above for
+                       information on a Solaris 9 bug report about,
+                       or Solaris 7 and 8 kernel patches to the
+                       kernel /dev/kmem driver.  Those fixes
+                       obviate the need for the kernel address
+                       filtering described in this report.
+
+                       !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+                       !!! I STRONGLY RECOMMEND YOU INSTALL  !!!
+                       !!! THE PATCHES OR UPGRADE TO SOLARIS !!!
+                       !!! 9.                                !!!
+                       !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+kvm_physaddr() (-lkvm)
+======================
+
+Solaris has an undocumented function called kvm_physaddr() that
+will convert a kernel virtual address to a kernel physical address.
+(Until Solaris 7 this function doesn't even have a prototype
+definition in <kvm.h>.)
+
+I have been assured repeatedly by Casper Dik of Sun that this
+function, when given a kernel virtual address, will produce addresses
+of physical memory only; it will not produce physical addresses of
+interface registers, such as the one for the qfe interface.
+
+In Solaris 2.5.1 this function runs in application space from within
+the KVM library.  Since it needs to know the components of the
+kernel's address space map, it must read those from kernel memory
+each time it is called.  That can be time consuming.
+
+I'm not sure about kvm_physaddr() for Solaris 2.6.  It may still
+run in application space from within the KVM library, but if so,
+it is much faster than its 2.5.1 ancestor.
+
+kvm_physaddr() (ioctl())
+========================
+
+I'm sure that at Solaris 7 and above kvm_physaddr() has moved inside
+the kernel and is called with an ioctl().  That makes it much faster
+than its ancestors.
+
+kvm_physaddr() Use
+==================
+
+Lsof 4.50 for Solaris will use one or the other version of
+kvm_physaddr() for Solaris 2.5.1, 2.6, 7, and 8.
+
+Using it for Solaris 2.5.1 causes lsof to take four times as much
+real time as it formerly did with only the kernelbase filtering.
+
+Caching
+=======
+
+To recover the performance lost by kvm_physaddr() on Solaris 2.5.1,
+I added virtual-to-physical address caching to lsof's kernel read
+function, kread().  This improves Solaris 2.6, 7, and 8 performance,
+too, but by a smaller amount.
+
+It turns out that a typical lsof run may require reading from 16,000
+or more different kernel virtual addresses.  However, it also turns
+out that those addresses are contained within about 600 distinct
+kernel memory pages.
+
+To exploit this condition lsof caches each virtual page address
+that has a corresponding legitimate physical page address for use
+in checking later addresses.  This caching regains all but a bit
+of the performance loss on Solaris 2.5.1.
+
+Caching can provide some performance gain on Solaris 2.6, 7, and
+8, but it's not nearly as large as the gain for 2.5.1, and may
+depend on the machine architecture type.
+
+/dev/mem
+========
+
+Once lsof has kernel physical addresses, on Solaris 2.5.1 and 2.6
+it seeks to those addresses with llseek() and reads from them via
+the /dev/mem device.  This contrasts with lsof's pre-4.50 behavior
+where it fed kernel virtual addresses to kvm_kread(), letting it
+and the kernel do the virtual to physical translations -- and
+letting that combined process crash that one unlucky sun4u via its
+qfe interface.
+
+Using /dev/mem requires no more permission for lsof, but it does
+require an additional open file descriptor and use of the 64 bit
+llseek() function.
+
+The additional file descriptor is an unfortunate consequence of
+the KVM library's opacity.  The library usually has /dev/kmem open
+to a file descriptor, but lsof can't easily get at that descriptor,
+so it opens one of its own.
+
+On Solaris 2.6 for one test system, a 4 CPU E4000 sun4u, doing
+physical kernel address reads from /dev/mem turned out to be faster
+than using kvm_kread().  It was marginally faster on a sun4d, and
+marginally slower on two sun4m's.
+
+kvm_pread()
+===========
+
+Even though it is still undocumented, the kvm_physaddr() function
+is represented by a prototype in the Solaris 7 and 8 <kvm.h>.
+Additionally useful is another undocumented function, kvm_pread()
+(for physical read), that also is represented by a <kvm.h> prototype
+in Solaris 7 and 8.
+
+Lsof 4.50 for Solaris 7 and 8 uses kvm_pread() instead of opening
+a descriptor to /dev/mem, llseek()-ing to physical addresses in
+it, and using read(2) to obtain physical address contents.  The
+bonus of kvm_pread() is two-fold: 1) it does positioning as well
+as reading, so there's one less function call; and 2) its combined
+operation appears to be faster than llseek() plus read() -- or even
+kvm_kread().
+
+Combined with the virtual-to-physical address caching, the performance
+boost of kvm_pread() makes lsof faster on Solaris 7 and 8 than
+previous revisions, using only kernelbase filtering and kvm_kread().
+
+Remaining Risks
+===============
+
+There may remain some extremely small likelihood that lsof will
+transmit a bad physical address to the kernel.  Here are some
+possible failure scenarios:
+
+       *  The physical address filters haven't been tested on
+          the machine whose qfe interface was affected.  That's
+          because the machine's memory configuration was changed
+          before the test could be run.
+
+       *  The kvm_physaddr() function, especially in Solaris
+          2.5.1, might fail to map an address correctly.  Only
+          Sun can correct this problem.
+
+       *  Because lsof must read the kernel address map from
+          kernel virtual memory to pass it to the Solaris 2.5.1
+          and 2.6 kvm_physaddr() functions, lsof must use kvm_kread()
+          to read the map.
+
+          There's also the chance that lsof could pass a stale
+          kernel address map to kvm_physaddr(), because re-reading
+          it for each call to kvm_physaddr() would lead to
+          unacceptable performance.  When in repeat mode lsof
+          re-reads the map between each cycle.
+
+          On Solaris 7 and 8, since kvm_physaddr() is inside the
+          kernel, there's no chance of its having a stale address
+          map.
+
+       *  There's an extremely small chance that a cached
+          virtual+physical page address could become invalid.
+          This is so small I think it can be ignored, since the
+          kernel memory map rarely changes.
+
+          When in repeat mode, lsof clears its virtual+physical
+          address map between cycles.
+
+       *  Lsof still uses Sun's kvm_getproc() (from -lkvm), and
+          I have no idea what kernel address filtering it does,
+          if any.
+
+I wish to acknowledge: Casper Dik of Sun, who provided information
+about kvm_physaddr() and helped test the lsof changes; Jim Mewes
+of Phone.com, who reported the initial problem and helped test the
+lsof changes; and several readers of the lsof-l listserv, who
+volunteered to run test programs.
+
+
+Vic Abell
+March 16, 2004
diff --git a/lib/dvch.c b/lib/dvch.c
new file mode 100644 (file)
index 0000000..5097882
--- /dev/null
@@ -0,0 +1,1352 @@
+/*
+ * dvch.c -- device cache functions for lsof library
+ */
+
+/*
+ * 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.
+ */
+
+#include "common.h"
+#include "machine.h"
+
+#if defined(HASDCACHE)
+
+/*
+ * dvch.c - module that contains common device cache functions
+ *
+ * The caller may define the following:
+ *
+ *     DCACHE_CLONE    is the name of the function that reads and writes the
+ *                     clone section of the device cache file.  The clone
+ *                     section follows the device section.  If DCACHE_CLONE
+ *                     isn't defined, but HAS_STD_CLONE is defined to be 1,
+ *                     DCACHE_CLONE defaults to the local static function
+ *                     rw_clone_sect() that reads and writes a standard
+ *                     clone cache.
+ *
+ *     DCACHE_CLR      is the name of the function that clears the clone and
+ *                     pseudo caches when reading the device cache fails.   If
+ *                     DCACHE_CLR isn't defined, but HAS_STD_CLONE is defined
+ *                     to be 1, DCACHE_CLR defaults to the local static
+ *                     function clr_sect() that clears a standard clone cache.
+ *
+ *     DCACHE_PSEUDO   is the name of the function that reads and writes
+ *                     the pseudo section of the device cache file.  The
+ *                     pseudo section follows the device section and the
+ *                     clone section, if there is one.
+ *
+ *     DVCH_CHOWN      if the dialect has no fchown() function, so
+ *                     chown() must be used instead.
+ *
+ *     DVCH_DEVPATH    if the path to the device directory isn't "/dev".
+ *
+ *     DVCH_EXPDEV     if st_rdev must be expanded with the expdev()
+ *                     macro before use.  (This is an EP/IX artifact.)
+ *
+ *     HASBLKDEV       if block device information is stored in BDevtp[].
+ */
+
+/*
+ * Local definitions
+ */
+
+#    if !defined(DVCH_DEVPATH)
+#        define DVCH_DEVPATH "/dev"
+#    endif /* !defined(DVCH_DEVPATH) */
+
+/*
+ * Local storage
+ */
+
+static int crctbl[CRC_TBLL]; /* crc partial results table */
+
+/*
+ * Local function prototypes
+ */
+
+#    undef DCACHE_CLR_LOCAL
+#    if !defined(DCACHE_CLR)
+#        if defined(HAS_STD_CLONE) && HAS_STD_CLONE == 1
+#            define DCACHE_CLR clr_sect
+#            define DCACHE_CLR_LOCAL 1
+static void clr_sect(void);
+#        endif /* defined(HAS_STD_CLONE) && HAS_STD_CLONE==1 */
+#    endif     /* !defined(DCACHE_CLR) */
+
+#    undef DCACHE_CLONE_LOCAL
+#    if !defined(DCACHE_CLONE)
+#        if defined(HAS_STD_CLONE) && HAS_STD_CLONE == 1
+#            define DCACHE_CLONE rw_clone_sect
+#            define DCACHE_CLONE_LOCAL 1
+static int rw_clone_sect(int m);
+#        endif /* defined(HAS_STD_CLONE) && HAS_STD_CLONE==1 */
+#    endif     /*!defined(DCACHE_CLONE) */
+
+#    if defined(HASBLKDEV)
+/*
+ * alloc_bdcache() - allocate block device cache
+ */
+
+void alloc_bdcache(struct lsof_context *ctx) {
+    if (!(BDevtp =
+              (struct l_dev *)calloc((MALLOC_S)BNdev, sizeof(struct l_dev)))) {
+        (void)fprintf(stderr, "%s: no space for block devices\n", Pn);
+        Error(ctx);
+    }
+    if (!(BSdev = (struct l_dev **)malloc(
+              (MALLOC_S)(sizeof(struct l_dev *) * BNdev)))) {
+        (void)fprintf(stderr, "%s: no space for block device pointers\n", Pn);
+        Error(ctx);
+    }
+}
+#    endif /* defined(HASBLKDEV) */
+
+/*
+ * alloc_dcache() - allocate device cache
+ */
+
+void alloc_dcache(struct lsof_context *ctx) {
+    if (!(Devtp =
+              (struct l_dev *)calloc((MALLOC_S)Ndev, sizeof(struct l_dev)))) {
+        (void)fprintf(stderr, "%s: no space for devices\n", Pn);
+        Error(ctx);
+    }
+    if (!(Sdev = (struct l_dev **)malloc(
+              (MALLOC_S)(sizeof(struct l_dev *) * Ndev)))) {
+        (void)fprintf(stderr, "%s: no space for device pointers\n", Pn);
+        Error(ctx);
+    }
+}
+
+/*
+ * clr_devtab() - clear the device tables and free their space
+ */
+
+void clr_devtab(struct lsof_context *ctx) {
+    int i;
+
+    if (Devtp) {
+        for (i = 0; i < Ndev; i++) {
+            if (Devtp[i].name) {
+                (void)free((FREE_P *)Devtp[i].name);
+                Devtp[i].name = (char *)NULL;
+            }
+        }
+        (void)free((FREE_P *)Devtp);
+        Devtp = (struct l_dev *)NULL;
+    }
+    if (Sdev) {
+        (void)free((FREE_P *)Sdev);
+        Sdev = (struct l_dev **)NULL;
+    }
+    Ndev = 0;
+
+#    if defined(HASBLKDEV)
+    if (BDevtp) {
+        for (i = 0; i < BNdev; i++) {
+            if (BDevtp[i].name) {
+                (void)free((FREE_P *)BDevtp[i].name);
+                BDevtp[i].name = (char *)NULL;
+            }
+        }
+        (void)free((FREE_P *)BDevtp);
+        BDevtp = (struct l_dev *)NULL;
+    }
+    if (BSdev) {
+        (void)free((FREE_P *)BSdev);
+        BSdev = (struct l_dev **)NULL;
+    }
+    BNdev = 0;
+#    endif /* defined(HASBLKDEV) */
+}
+
+#    if defined(DCACHE_CLR_LOCAL)
+/*
+ * clr_sect() - clear cached standard clone sections
+ */
+
+static void clr_sect() {
+    struct clone *c, *c1;
+
+    if (Clone) {
+        for (c = Clone; c; c = c1) {
+            c1 = c->next;
+            (void)free((FREE_P *)c);
+        }
+        Clone = (struct clone *)NULL;
+    }
+}
+#    endif /* defined(DCACHE_CLR_LOCAL) */
+
+/*
+ * crc(b, l, s) - compute a crc for a block of bytes
+ */
+
+void crc(char *b,     /* block address */
+         int l,       /* length */
+         unsigned *s) /* sum */
+{
+    char *cp;     /* character pointer */
+    char *lm;     /* character limit pointer */
+    unsigned sum; /* check sum */
+
+    cp = b;
+    lm = cp + l;
+    sum = *s;
+    do {
+        sum ^= ((int)*cp++) & 0xff;
+        sum = (sum >> 8) ^ crctbl[sum & 0xff];
+    } while (cp < lm);
+    *s = sum;
+}
+
+/*
+ * crcbld - build the CRC-16 partial results table
+ */
+
+void crcbld() {
+    int bit;        /* temporary bit value */
+    unsigned entry; /* entry under construction */
+    int i;          /* polynomial table index */
+    int j;          /* bit shift count */
+
+    for (i = 0; i < CRC_TBLL; i++) {
+        entry = i;
+        for (j = 1; j <= CRC_BITS; j++) {
+            bit = entry & 1;
+            entry >>= 1;
+            if (bit)
+                entry ^= CRC_POLY;
+        }
+        crctbl[i] = entry;
+    }
+}
+
+/*
+ * dcpath() - define device cache file paths
+ */
+
+int dcpath(struct lsof_context *ctx, int rw, /* read (1) or write (2) mode */
+           int npw)                          /* inhibit (0) or enable (1) no
+                                              * path warning message */
+{
+    char buf[MAXPATHLEN + 1], *cp1, *cp2, hn[MAXPATHLEN + 1];
+    int endf;
+    int i, j;
+    int l = 0;
+    int ierr = 0; /* intermediate error state */
+    int merr = 0; /* malloc error state */
+    struct passwd *p = (struct passwd *)NULL;
+    static short wenv = 1; /* HASENVDC warning state */
+    static short wpp = 1;  /* HASPERSDCPATH warning state */
+                           /*
+                            * Release any space reserved by previous path calls to dcpath().
+                            */
+    if (DCpath[1]) {
+        (void)free((FREE_P *)DCpath[1]);
+        DCpath[1] = (char *)NULL;
+    }
+    if (DCpath[3]) {
+        (void)free((FREE_P *)DCpath[3]);
+        DCpath[3] = (char *)NULL;
+    }
+    /*
+     * If a path was specified via -D, it's character address will have been
+     * stored in DCpathArg by ctrl_dcache().  Use that address if the real UID
+     * of this process is root, or the mode is read, or the process is neither
+     * setuid-root nor setgid.
+     */
+    if (Myuid == 0 || rw == 1 || (!Setuidroot && !Setgid))
+        DCpath[0] = DCpathArg;
+    else
+        DCpath[0] = (char *)NULL;
+
+#    if defined(HASENVDC)
+    /*
+     * If HASENVDC is defined, get its value from the environment, unless this
+     * is a setuid-root process, or the real UID of the process is 0, or the
+     * mode is write and the process is setgid.
+     */
+    if ((cp1 = getenv(HASENVDC)) && (l = strlen(cp1)) > 0 && !Setuidroot &&
+        Myuid && (rw == 1 || !Setgid)) {
+        if (!(cp2 = mkstrcpy(cp1, (MALLOC_S *)NULL))) {
+            (void)fprintf(stderr, "%s: no space for device cache path: %s=", Pn,
+                          HASENVDC);
+            safestrprt(cp1, stderr, 1);
+            merr = 1;
+        } else
+            DCpath[1] = cp2;
+    } else if (cp1 && l > 0) {
+        if (!Fwarn && wenv) {
+            (void)fprintf(stderr, "%s: WARNING: ignoring environment: %s=", Pn,
+                          HASENVDC);
+            safestrprt(cp1, stderr, 1);
+        }
+        wenv = 0;
+    }
+#    endif /* defined(HASENVDC) */
+
+#    if defined(HASSYSDC)
+    /*
+     * If HASSYSDC is defined, record the path of the system-wide device
+     * cache file, unless the mode is write.
+     */
+    if (rw != 2)
+        DCpath[2] = HASSYSDC;
+    else
+        DCpath[2] = (char *)NULL;
+#    endif /* defined(HASSYSDC) */
+
+#    if defined(HASPERSDC)
+    /*
+     * If HASPERSDC is defined, form a personal device cache path by
+     * interpreting the conversions specified in it.
+     *
+     * Get (HASPERSDCPATH) from the environment and add it to the home directory
+     * path, if possible.
+     */
+    for (cp1 = HASPERSDC, endf = i = 0; *cp1 && !endf; cp1++) {
+        if (*cp1 != '%') {
+
+            /*
+             * If the format character isn't a `%', copy it.
+             */
+            if (i < (int)sizeof(buf)) {
+                buf[i++] = *cp1;
+                continue;
+            } else {
+                ierr = 2;
+                break;
+            }
+        }
+        /*
+         * `%' starts a conversion; the next character specifies
+         * the conversion type.
+         */
+        cp1++;
+        switch (*cp1) {
+
+            /*
+             * Two consecutive `%' characters convert to one `%'
+             * character in the output.
+             */
+
+        case '%':
+            if (i < (int)sizeof(buf))
+                buf[i++] = '%';
+            else
+                ierr = 2;
+            break;
+
+            /*
+             * ``%0'' defines a root boundary.  If the effective
+             * (setuid-root) or real UID of the process is root, any
+             * path formed to this point is discarded and path formation
+             * begins with the next character.
+             *
+             * If neither the effective nor the real UID is root, path
+             * formation ends.
+             *
+             * This allows HASPERSDC to specify one path for non-root
+             * UIDs and another for the root (effective or real) UID.
+             */
+
+        case '0':
+            if (Setuidroot || !Myuid)
+                i = 0;
+            else
+                endf = 1;
+            break;
+
+            /*
+             * ``%h'' converts to the home directory.
+             */
+
+        case 'h':
+            if (!p && !(p = getpwuid(Myuid))) {
+                if (!Fwarn)
+                    (void)fprintf(
+                        stderr, "%s: WARNING: can't get home dir for UID: %d\n",
+                        Pn, (int)Myuid);
+                ierr = 1;
+                break;
+            }
+            if ((i + (l = strlen(p->pw_dir))) >= (int)sizeof(buf)) {
+                ierr = 2;
+                break;
+            }
+            (void)strcpy(&buf[i], p->pw_dir);
+            i += l;
+            if (i > 0 && buf[i - 1] == '/' && *(cp1 + 1)) {
+
+                /*
+                 * If the home directory ends in a '/' and the next format
+                 * character is a '/', delete the '/' at the end of the home
+                 * directory.
+                 */
+                i--;
+                buf[i] = '\0';
+            }
+            break;
+
+            /*
+             * ``%l'' converts to the full host name.
+             *
+             * ``%L'' converts to the first component (characters up
+             * to the first `.') of the host name.
+             */
+
+        case 'l':
+        case 'L':
+            if (gethostname(hn, sizeof(hn) - 1) < 0) {
+                if (!Fwarn)
+                    (void)fprintf(
+                        stderr,
+                        "%s: WARNING: no gethostname for %%l or %%L: %s\n", Pn,
+                        strerror(errno));
+                ierr = 1;
+                break;
+            }
+            hn[sizeof(hn) - 1] = '\0';
+            if (*cp1 == 'L' && (cp2 = strchr(hn, '.')) && cp2 > hn)
+                *cp2 = '\0';
+            j = strlen(hn);
+            if ((j + i) < (int)sizeof(buf)) {
+                (void)strcpy(&buf[i], hn);
+                i += j;
+            } else
+                ierr = 2;
+            break;
+
+            /*
+             * ``%p'' converts to the contents of LSOFPERSDCPATH, followed
+             * by a '/'.
+             *
+             * It is ignored when:
+             *
+             *    The lsof process is setuid-root;
+             *    The real UID of the lsof process is 0;
+             *    The mode is write and the process is setgid.
+             */
+
+        case 'p':
+
+#        if defined(HASPERSDCPATH)
+            if ((cp2 = getenv(HASPERSDCPATH)) && (l = strlen(cp2)) > 0 &&
+                !Setuidroot && Myuid && (rw == 1 || !Setgid)) {
+                if (i && buf[i - 1] == '/' && *cp2 == '/') {
+                    cp2++;
+                    l--;
+                }
+                if ((i + l) < ((int)sizeof(buf) - 1)) {
+                    (void)strcpy(&buf[i], cp2);
+                    i += l;
+                    if (buf[i - 1] != '/') {
+                        if (i < ((int)sizeof(buf) - 2)) {
+                            buf[i++] = '/';
+                            buf[i] = '\0';
+                        } else
+                            ierr = 2;
+                    }
+                } else
+                    ierr = 2;
+            } else {
+                if (cp2 && l > 0) {
+                    if (!Fwarn && wpp) {
+                        (void)fprintf(stderr,
+                                      "%s: WARNING: ignoring environment: %s",
+                                      Pn, HASPERSDCPATH);
+                        safestrprt(cp2, stderr, 1);
+                    }
+                    wpp = 0;
+                }
+            }
+#        else  /* !defined(HASPERSDCPATH) */
+            if (!Fwarn && wpp)
+                (void)fprintf(stderr,
+                              "%s: WARNING: HASPERSDCPATH disabled: %s\n", Pn,
+                              HASPERSDC);
+            ierr = 1;
+            wpp = 0;
+#        endif /* defined(HASPERSDCPATH) */
+
+            break;
+
+            /*
+             * ``%u'' converts to the login name of the real UID of the
+             * lsof process.
+             */
+
+        case 'u':
+            if (!p && !(p = getpwuid(Myuid))) {
+                if (!Fwarn)
+                    (void)fprintf(
+                        stderr,
+                        "%s: WARNING: can't get login name for UID: %d\n", Pn,
+                        (int)Myuid);
+                ierr = 1;
+                break;
+            }
+            if ((i + (l = strlen(p->pw_name))) >= (int)sizeof(buf)) {
+                ierr = 2;
+                break;
+            }
+            (void)strcpy(&buf[i], p->pw_name);
+            i += l;
+            break;
+
+            /*
+             * ``%U'' converts to the real UID of the lsof process.
+             */
+
+        case 'U':
+            (void)snpf(hn, sizeof(hn), "%d", (int)Myuid);
+            if ((i + (l = strlen(hn))) >= (int)sizeof(buf))
+                ierr = 2;
+            else {
+                (void)strcpy(&buf[i], hn);
+                i += l;
+            }
+            break;
+        default:
+            if (!Fwarn)
+                (void)fprintf(stderr,
+                              "%s: WARNING: bad conversion (%%%c): %s\n", Pn,
+                              *cp1, HASPERSDC);
+            ierr = 1;
+        }
+        if (endf || ierr > 1)
+            break;
+    }
+    if (ierr) {
+
+        /*
+         * If there was an intermediate error of some type, handle it.
+         * A type 1 intermediate error has already been noted with a
+         * warning message.  A type 2 intermediate error requires the
+         * issuing of a buffer overlow warning message.
+         */
+        if (ierr == 2 && !Fwarn)
+            (void)fprintf(stderr,
+                          "%s: WARNING: device cache path too large: %s\n", Pn,
+                          HASPERSDC);
+        i = 0;
+    }
+    buf[i] = '\0';
+    /*
+     * If there is one, allocate space for the personal device cache path,
+     * copy buf[] to it, and store its pointer in DCpath[3].
+     */
+    if (i) {
+        if (!(cp1 = mkstrcpy(buf, (MALLOC_S *)NULL))) {
+            (void)fprintf(stderr, "%s: no space for device cache path: ", Pn);
+            safestrprt(buf, stderr, 1);
+            merr = 1;
+        } else
+            DCpath[3] = cp1;
+    }
+#    endif /* defined(HASPERSDC) */
+
+    /*
+     * Quit if there was a malloc() error.  The appropriate error message
+     * will have been issued to stderr.
+     */
+    if (merr)
+        Error(ctx);
+    /*
+     * Return the index of the first defined path.  Since DCpath[] is arranged
+     * in priority order, searching it beginning to end follows priority.
+     * Return an error indication if the search discloses no path name.
+     */
+    for (i = 0; i < MAXDCPATH; i++) {
+        if (DCpath[i])
+            return (i);
+    }
+    if (!Fwarn && npw)
+        (void)fprintf(stderr, "%s: WARNING: can't form any device cache path\n",
+                      Pn);
+    return (-1);
+}
+
+/*
+ * open_dcache() - open device cache file
+ */
+
+int open_dcache(struct lsof_context *ctx, int m, /* mode: 1 = read; 2 = write */
+                int r,          /* create DCpath[] if 0, reuse if 1 */
+                struct stat *s) /* stat() receiver */
+{
+    char buf[128];
+    char *w = (char *)NULL;
+    /*
+     * Get the device cache file paths.
+     */
+    if (!r) {
+        if ((DCpathX = dcpath(ctx, m, 1)) < 0)
+            return (1);
+    }
+    /*
+     * Switch to the requested open() action.
+     */
+    switch (m) {
+    case 1:
+
+        /*
+         * Check for access permission.
+         */
+        if (!is_readable(ctx, DCpath[DCpathX], 0)) {
+            if (DCpathX == 2 && errno == ENOENT)
+                return (2);
+            if (!Fwarn)
+                (void)fprintf(stderr, ACCESSERRFMT, Pn, DCpath[DCpathX],
+                              strerror(errno));
+            return (1);
+        }
+        /*
+         * Open for reading.
+         */
+        if ((DCfd = open(DCpath[DCpathX], O_RDONLY, 0)) < 0) {
+            if (DCstate == 3 && errno == ENOENT)
+                return (1);
+
+        cant_open:
+            (void)fprintf(stderr, "%s: WARNING: can't open %s: %s\n", Pn,
+                          DCpath[DCpathX], strerror(errno));
+            return (1);
+        }
+        if (stat(DCpath[DCpathX], s) != 0) {
+
+        cant_stat:
+            if (!Fwarn)
+                (void)fprintf(stderr, "%s: WARNING: can't stat(%s): %s\n", Pn,
+                              DCpath[DCpathX], strerror(errno));
+        close_exit:
+            (void)close(DCfd);
+            DCfd = -1;
+            return (1);
+        }
+        if ((int)(s->st_mode & 07777) != ((DCpathX == 2) ? 0644 : 0600)) {
+            (void)snpf(buf, sizeof(buf), "doesn't have %04o modes",
+                       (DCpathX == 2) ? 0644 : 0600);
+            w = buf;
+        } else if ((s->st_mode & S_IFMT) != S_IFREG)
+            w = "isn't a regular file";
+        else if (!s->st_size)
+            w = "is empty";
+        if (w) {
+            if (!Fwarn)
+                (void)fprintf(stderr, "%s: WARNING: %s %s.\n", Pn,
+                              DCpath[DCpathX], w);
+            goto close_exit;
+        }
+        return (0);
+    case 2:
+
+        /*
+         * Open for writing: first unlink any previous version; then
+         * open exclusively, specifying it's an error if the file exists.
+         */
+        if (unlink(DCpath[DCpathX]) < 0) {
+            if (errno != ENOENT) {
+                if (!Fwarn)
+                    (void)fprintf(stderr, "%s: WARNING: can't unlink %s: %s\n",
+                                  Pn, DCpath[DCpathX], strerror(errno));
+                return (1);
+            }
+        }
+        if ((DCfd = open(DCpath[DCpathX], O_RDWR | O_CREAT | O_EXCL, 0600)) < 0)
+            goto cant_open;
+        /*
+         * If the real user is not root, but the process is setuid-root,
+         * change the ownerships of the file to the real ones.
+         */
+        if (Myuid && Setuidroot) {
+
+#    if defined(DVCH_CHOWN)
+            if (chown(DCpath[DCpathX], Myuid, getgid()) < 0)
+#    else  /* !defined(DVCH_CHOWN) */
+            if (fchown(DCfd, Myuid, getgid()) < 0)
+#    endif /* defined(DVCH_CHOWN) */
+
+            {
+                if (!Fwarn)
+                    (void)fprintf(
+                        stderr,
+                        "%s: WARNING: can't change ownerships of %s: %s\n", Pn,
+                        DCpath[DCpathX], strerror(errno));
+            }
+        }
+        if (!Fwarn && DCstate != 1 && !DCunsafe)
+            (void)fprintf(stderr,
+                          "%s: WARNING: created device cache file: %s\n", Pn,
+                          DCpath[DCpathX]);
+        if (stat(DCpath[DCpathX], s) != 0) {
+            (void)unlink(DCpath[DCpathX]);
+            goto cant_stat;
+        }
+        return (0);
+    default:
+
+        /*
+         * Oops!
+         */
+        (void)fprintf(stderr, "%s: internal error: open_dcache=%d\n", Pn, m);
+        Error(ctx);
+    }
+    return (1);
+}
+
+/*
+ * read_dcache() - read device cache file
+ */
+
+int read_dcache(struct lsof_context *ctx) {
+    char buf[MAXPATHLEN * 2], cbuf[64], *cp;
+    int i, len, ov;
+    struct stat sb, devsb;
+    /*
+     * Open the device cache file.
+     *
+     * If the open at HASSYSDC fails because the file doesn't exist, and
+     * the real UID of this process is not zero, try to open a device cache
+     * file at HASPERSDC.
+     */
+    if ((ov = open_dcache(ctx, 1, 0, &sb)) != 0) {
+        if (DCpathX == 2) {
+            if (ov == 2 && DCpath[3]) {
+                DCpathX = 3;
+                if (open_dcache(ctx, 1, 1, &sb) != 0)
+                    return (1);
+            } else
+                return (1);
+        } else
+            return (1);
+    }
+    /*
+     * If the open device cache file's last mtime/ctime isn't greater than
+     * DVCH_DEVPATH's mtime/ctime, ignore it, unless -Dr was specified.
+     */
+    if (stat(DVCH_DEVPATH, &devsb) != 0) {
+        if (!Fwarn)
+            (void)fprintf(stderr, "%s: WARNING: can't stat(%s): %s\n", Pn,
+                          DVCH_DEVPATH, strerror(errno));
+    } else {
+        if (sb.st_mtime <= devsb.st_mtime || sb.st_ctime <= devsb.st_ctime)
+            DCunsafe = 1;
+    }
+    if (!(DCfs = fdopen(DCfd, "r"))) {
+        if (!Fwarn)
+            (void)fprintf(stderr, "%s: WARNING: can't fdopen(%s)\n", Pn,
+                          DCpath[DCpathX]);
+        (void)close(DCfd);
+        DCfd = -1;
+        return (1);
+    }
+    /*
+     * Read the section count line; initialize the CRC table;
+     * validate the section count line.
+     */
+    if (!fgets(buf, sizeof(buf), DCfs)) {
+
+    cant_read:
+        if (!Fwarn)
+            (void)fprintf(stderr, "%s: WARNING: can't fread %s: %s\n", Pn,
+                          DCpath[DCpathX], strerror(errno));
+    read_close:
+        (void)fclose(DCfs);
+        DCfd = -1;
+        DCfs = (FILE *)NULL;
+        (void)clr_devtab(ctx);
+
+#    if defined(DCACHE_CLR)
+        (void)DCACHE_CLR(ctx);
+#    endif /* defined(DCACHE_CLR) */
+
+        return (1);
+    }
+    (void)crcbld();
+    DCcksum = 0;
+    (void)crc(buf, strlen(buf), &DCcksum);
+    i = 1;
+    cp = "";
+
+#    if defined(HASBLKDEV)
+    i++;
+    cp = "s";
+#    endif /* defined(HASBLKDEV) */
+
+#    if defined(DCACHE_CLONE)
+    i++;
+    cp = "s";
+#    endif /* defined(DCACHE_CLONE) */
+
+#    if defined(DCACHE_PSEUDO)
+    i++;
+    cp = "s";
+#    endif /* defined(DCACHE_PSEUDO) */
+
+    (void)snpf(cbuf, sizeof(cbuf), "%d section%s", i, cp);
+    len = strlen(cbuf);
+    (void)snpf(&cbuf[len], sizeof(cbuf) - len, ", dev=%lx\n", (long)DevDev);
+    if (!strncmp(buf, cbuf, len) && (buf[len] == '\n')) {
+        if (!Fwarn) {
+            (void)fprintf(stderr, "%s: WARNING: no /dev device in %s: line ",
+                          Pn, DCpath[DCpathX]);
+            safestrprt(buf, stderr, 1 + 4 + 8);
+        }
+        goto read_close;
+    }
+    if (strcmp(buf, cbuf)) {
+        if (!Fwarn) {
+            (void)fprintf(stderr,
+                          "%s: WARNING: bad section count line in %s: line ",
+                          Pn, DCpath[DCpathX]);
+            safestrprt(buf, stderr, 1 + 4 + 8);
+        }
+        goto read_close;
+    }
+    /*
+     * Read device section header and validate it.
+     */
+    if (!fgets(buf, sizeof(buf), DCfs))
+        goto cant_read;
+    (void)crc(buf, strlen(buf), &DCcksum);
+    len = strlen("device section: ");
+    if (strncmp(buf, "device section: ", len) != 0) {
+
+    read_dhdr:
+        if (!Fwarn) {
+            (void)fprintf(stderr,
+                          "%s: WARNING: bad device section header in %s: line ",
+                          Pn, DCpath[DCpathX]);
+            safestrprt(buf, stderr, 1 + 4 + 8);
+        }
+        goto read_close;
+    }
+    /*
+     * Compute the device count; allocate Sdev[] and Devtp[] space.
+     */
+    if ((Ndev = atoi(&buf[len])) < 1)
+        goto read_dhdr;
+    alloc_dcache(ctx);
+    /*
+     * Read the device lines and store their information in Devtp[].
+     * Construct the Sdev[] pointers to Devtp[].
+     */
+    for (i = 0; i < Ndev; i++) {
+        if (!fgets(buf, sizeof(buf), DCfs)) {
+            if (!Fwarn)
+                (void)fprintf(stderr,
+                              "%s: WARNING: can't read device %d from %s\n", Pn,
+                              i + 1, DCpath[DCpathX]);
+            goto read_close;
+        }
+        (void)crc(buf, strlen(buf), &DCcksum);
+        /*
+         * Convert hexadecimal device number.
+         */
+        if (!(cp = x2dev(buf, &Devtp[i].rdev)) || *cp != ' ') {
+            if (!Fwarn) {
+                (void)fprintf(stderr, "%s: device %d: bad device in %s: line ",
+                              Pn, i + 1, DCpath[DCpathX]);
+                safestrprt(buf, stderr, 1 + 4 + 8);
+            }
+            goto read_close;
+        }
+        /*
+         * Convert inode number.
+         */
+        for (cp++, Devtp[i].inode = (INODETYPE)0; *cp != ' '; cp++) {
+            if (*cp < '0' || *cp > '9') {
+                if (!Fwarn) {
+                    (void)fprintf(
+                        stderr,
+                        "%s: WARNING: device %d: bad inode # in %s: line ", Pn,
+                        i + 1, DCpath[DCpathX]);
+                    safestrprt(buf, stderr, 1 + 4 + 8);
+                }
+                goto read_close;
+            }
+            Devtp[i].inode =
+                (INODETYPE)((Devtp[i].inode * 10) + (int)(*cp - '0'));
+        }
+        /*
+         * Get path name; allocate space for it; copy it; store the
+         * pointer in Devtp[]; clear verify status; construct the Sdev[]
+         * pointer to Devtp[].
+         */
+        if ((len = strlen(++cp)) < 2 || *(cp + len - 1) != '\n') {
+            if (!Fwarn) {
+                (void)fprintf(stderr,
+                              "%s: WARNING: device %d: bad path in %s: line ",
+                              Pn, i + 1, DCpath[DCpathX]);
+                safestrprt(buf, stderr, 1 + 4 + 8);
+            }
+            goto read_close;
+        }
+        *(cp + len - 1) = '\0';
+        if (!(Devtp[i].name = mkstrcpy(cp, (MALLOC_S *)NULL))) {
+            (void)fprintf(stderr, "%s: device %d: no space for path: line ", Pn,
+                          i + 1);
+            safestrprt(buf, stderr, 1 + 4 + 8);
+            Error(ctx);
+        }
+        Devtp[i].v = 0;
+        Sdev[i] = &Devtp[i];
+    }
+
+#    if defined(HASBLKDEV)
+    /*
+     * Read block device section header and validate it.
+     */
+    if (!fgets(buf, sizeof(buf), DCfs))
+        goto cant_read;
+    (void)crc(buf, strlen(buf), &DCcksum);
+    len = strlen("block device section: ");
+    if (strncmp(buf, "block device section: ", len) != 0) {
+        if (!Fwarn) {
+            (void)fprintf(
+                stderr,
+                "%s: WARNING: bad block device section header in %s: line ", Pn,
+                DCpath[DCpathX]);
+            safestrprt(buf, stderr, 1 + 4 + 8);
+        }
+        goto read_close;
+    }
+    /*
+     * Compute the block device count; allocate BSdev[] and BDevtp[] space.
+     */
+    if ((BNdev = atoi(&buf[len])) > 0) {
+        alloc_bdcache(ctx);
+        /*
+         * Read the block device lines and store their information in BDevtp[].
+         * Construct the BSdev[] pointers to BDevtp[].
+         */
+        for (i = 0; i < BNdev; i++) {
+            if (!fgets(buf, sizeof(buf), DCfs)) {
+                if (!Fwarn)
+                    (void)fprintf(
+                        stderr,
+                        "%s: WARNING: can't read block device %d from %s\n", Pn,
+                        i + 1, DCpath[DCpathX]);
+                goto read_close;
+            }
+            (void)crc(buf, strlen(buf), &DCcksum);
+            /*
+             * Convert hexadecimal device number.
+             */
+            if (!(cp = x2dev(buf, &BDevtp[i].rdev)) || *cp != ' ') {
+                if (!Fwarn) {
+                    (void)fprintf(stderr,
+                                  "%s: block dev %d: bad device in %s: line ",
+                                  Pn, i + 1, DCpath[DCpathX]);
+                    safestrprt(buf, stderr, 1 + 4 + 8);
+                }
+                goto read_close;
+            }
+            /*
+             * Convert inode number.
+             */
+            for (cp++, BDevtp[i].inode = (INODETYPE)0; *cp != ' '; cp++) {
+                if (*cp < '0' || *cp > '9') {
+                    if (!Fwarn) {
+                        (void)fprintf(stderr,
+                                      "%s: WARNING: block dev %d: bad inode # "
+                                      "in %s: line ",
+                                      Pn, i + 1, DCpath[DCpathX]);
+                        safestrprt(buf, stderr, 1 + 4 + 8);
+                    }
+                    goto read_close;
+                }
+                BDevtp[i].inode =
+                    (INODETYPE)((BDevtp[i].inode * 10) + (int)(*cp - '0'));
+            }
+            /*
+             * Get path name; allocate space for it; copy it; store the
+             * pointer in BDevtp[]; clear verify status; construct the BSdev[]
+             * pointer to BDevtp[].
+             */
+            if ((len = strlen(++cp)) < 2 || *(cp + len - 1) != '\n') {
+                if (!Fwarn) {
+                    (void)fprintf(
+                        stderr,
+                        "%s: WARNING: block dev %d: bad path in %s: line", Pn,
+                        i + 1, DCpath[DCpathX]);
+                    safestrprt(buf, stderr, 1 + 4 + 8);
+                }
+                goto read_close;
+            }
+            *(cp + len - 1) = '\0';
+            if (!(BDevtp[i].name = mkstrcpy(cp, (MALLOC_S *)NULL))) {
+                (void)fprintf(stderr,
+                              "%s: block dev %d: no space for path: line", Pn,
+                              i + 1);
+                safestrprt(buf, stderr, 1 + 4 + 8);
+                Error(ctx);
+            }
+            BDevtp[i].v = 0;
+            BSdev[i] = &BDevtp[i];
+        }
+    }
+#    endif /* defined(HASBLKDEV) */
+
+#    if defined(DCACHE_CLONE)
+    /*
+     * Read the clone section.
+     */
+    if (DCACHE_CLONE(ctx, 1))
+        goto read_close;
+#    endif /* defined(DCACHE_CLONE) */
+
+#    if defined(DCACHE_PSEUDO)
+    /*
+     * Read the pseudo section.
+     */
+    if (DCACHE_PSEUDO(ctx, 1))
+        goto read_close;
+#    endif /* defined(DCACHE_PSEUDO) */
+
+    /*
+     * Read and check the CRC section; it must be the last thing in the file.
+     */
+    (void)snpf(cbuf, sizeof(cbuf), "CRC section: %x\n", DCcksum);
+    if (!fgets(buf, sizeof(buf), DCfs) || strcmp(buf, cbuf) != 0) {
+        if (!Fwarn) {
+            (void)fprintf(stderr, "%s: WARNING: bad CRC section in %s: line ",
+                          Pn, DCpath[DCpathX]);
+            safestrprt(buf, stderr, 1 + 4 + 8);
+        }
+        goto read_close;
+    }
+    if (fgets(buf, sizeof(buf), DCfs)) {
+        if (!Fwarn) {
+            (void)fprintf(stderr,
+                          "%s: WARNING: data follows CRC section in %s: line ",
+                          Pn, DCpath[DCpathX]);
+            safestrprt(buf, stderr, 1 + 4 + 8);
+        }
+        goto read_close;
+    }
+    /*
+     * Check one device entry at random -- the randomness based on our
+     * PID.
+     */
+    i = (int)(Mypid % Ndev);
+    if (stat(Devtp[i].name, &sb) != 0
+
+#    if defined(DVCH_EXPDEV)
+        || expdev(sb.st_rdev) != Devtp[i].rdev
+#    else  /* !defined(DVCH_EXPDEV) */
+        || sb.st_rdev != Devtp[i].rdev
+#    endif /* defined(DVCH_EXPDEV) */
+
+        || sb.st_ino != Devtp[i].inode) {
+        if (!Fwarn)
+            (void)fprintf(stderr, "%s: WARNING: device cache mismatch: %s\n",
+                          Pn, Devtp[i].name);
+        goto read_close;
+    }
+    /*
+     * Close the device cache file and return OK.
+     */
+    (void)fclose(DCfs);
+    DCfd = -1;
+    DCfs = (FILE *)NULL;
+    return (0);
+}
+
+#    if defined(DCACHE_CLONE_LOCAL)
+/*
+ * rw_clone_sect() - read/write the device cache file clone section
+ */
+
+static int rw_clone_sect(struct lsof_context *ctx,
+                         int m) /* mode: 1 = read; 2 = write */
+{
+    char buf[MAXPATHLEN * 2], *cp, *cp1;
+    struct clone *c;
+    struct l_dev *dp;
+    int i, j, len, n;
+
+    if (m == 1) {
+
+        /*
+         * Read the clone section header and validate it.
+         */
+        if (!fgets(buf, sizeof(buf), DCfs)) {
+
+        bad_clone_sect:
+            if (!Fwarn) {
+                (void)fprintf(stderr,
+                              "%s: bad clone section header in %s: line ", Pn,
+                              DCpath[DCpathX]);
+                safestrprt(buf, stderr, 1 + 4 + 8);
+            }
+            return (1);
+        }
+        (void)crc(buf, strlen(buf), &DCcksum);
+        len = strlen("clone section: ");
+        if (strncmp(buf, "clone section: ", len) != 0)
+            goto bad_clone_sect;
+        if ((n = atoi(&buf[len])) < 0)
+            goto bad_clone_sect;
+        /*
+         * Read the clone section lines and create the Clone list.
+         */
+        for (i = 0; i < n; i++) {
+            if (fgets(buf, sizeof(buf), DCfs) == NULL) {
+                if (!Fwarn) {
+                    (void)fprintf(stderr, "%s: no %d clone line in %s: line ",
+                                  Pn, i + 1, DCpath[DCpathX]);
+                    safestrprt(buf, stderr, 1 + 4 + 8);
+                }
+                return (1);
+            }
+            (void)crc(buf, strlen(buf), &DCcksum);
+            /*
+             * Assemble Devtp[] index and make sure it's correct.
+             */
+            for (cp = buf, j = 0; *cp != ' '; cp++) {
+                if (*cp < '0' || *cp > '9') {
+
+                bad_clone_index:
+                    if (!Fwarn) {
+                        (void)fprintf(
+                            stderr,
+                            "%s: clone %d: bad cached device index: line ", Pn,
+                            i + 1);
+                        safestrprt(buf, stderr, 1 + 4 + 8);
+                    }
+                    return (1);
+                }
+                j = (j * 10) + (int)(*cp - '0');
+            }
+            if (j < 0 || j >= Ndev || (cp1 = strchr(++cp, '\n')) == NULL)
+                goto bad_clone_index;
+            if (strncmp(cp, Devtp[j].name, (cp1 - cp)) != 0)
+                goto bad_clone_index;
+            /*
+             * Allocate and complete a clone structure.
+             */
+            if (!(c = (struct clone *)malloc(sizeof(struct clone)))) {
+                (void)fprintf(stderr,
+                              "%s: clone %d: no space for cached clone: line ",
+                              Pn, i + 1);
+                safestrprt(buf, stderr, 1 + 4 + 8);
+                Error(ctx);
+            }
+            c->dx = j;
+            c->next = Clone;
+            Clone = c;
+        }
+        return (0);
+    } else if (m == 2) {
+
+        /*
+         * Write the clone section header.
+         */
+        for (c = Clone, n = 0; c; c = c->next, n++)
+            ;
+        (void)snpf(buf, sizeof(buf), "clone section: %d\n", n);
+        if (wr2DCfd(ctx, buf, &DCcksum))
+            return (1);
+        /*
+         * Write the clone section lines.
+         */
+        for (c = Clone; c; c = c->next) {
+            for (dp = &Devtp[c->dx], j = 0; j < Ndev; j++) {
+                if (dp == Sdev[j])
+                    break;
+            }
+            if (j >= Ndev) {
+                if (!Fwarn) {
+                    (void)fprintf(stderr,
+                                  "%s: can't make index for clone: ", Pn);
+                    safestrprt(dp->name, stderr, 1);
+                }
+                (void)unlink(DCpath[DCpathX]);
+                (void)close(DCfd);
+                DCfd = -1;
+                return (1);
+            }
+            (void)snpf(buf, sizeof(buf), "%d %s\n", j, dp->name);
+            if (wr2DCfd(ctx, buf, &DCcksum))
+                return (1);
+        }
+        return (0);
+    }
+    /*
+     * A shouldn't-happen case: mode neither 1 nor 2.
+     */
+    (void)fprintf(stderr, "%s: internal rw_clone_sect error: %d\n", Pn, m);
+    Error(ctx);
+    return (1); /* This useless return(1) keeps some
+                 * compilers happy. */
+}
+#    endif /* defined(DCACHE_CLONE_LOCAL) */
+
+/*
+ * write_dcache() - write device cache file
+ */
+
+void write_dcache(struct lsof_context *ctx) {
+    char buf[MAXPATHLEN * 2], *cp;
+    struct l_dev *dp;
+    int i;
+    struct stat sb;
+    /*
+     * Open the cache file; set up the CRC table; write the section count.
+     */
+    if (open_dcache(ctx, 2, 0, &sb))
+        return;
+    i = 1;
+    cp = "";
+
+#    if defined(HASBLKDEV)
+    i++;
+    cp = "s";
+#    endif /* defined(HASBLKDEV) */
+
+#    if defined(DCACHE_CLONE)
+    i++;
+    cp = "s";
+#    endif /* defined(DCACHE_CLONE) */
+
+#    if defined(DCACHE_PSEUDO)
+    i++;
+    cp = "s";
+#    endif /* defined(DCACHE_PSEUDO) */
+
+    (void)snpf(buf, sizeof(buf), "%d section%s, dev=%lx\n", i, cp,
+               (long)DevDev);
+    (void)crcbld();
+    DCcksum = 0;
+    if (wr2DCfd(ctx, buf, &DCcksum))
+        return;
+    /*
+     * Write the device section from the contents of Sdev[] and Devtp[].
+     */
+    (void)snpf(buf, sizeof(buf), "device section: %d\n", Ndev);
+    if (wr2DCfd(ctx, buf, &DCcksum))
+        return;
+    for (i = 0; i < Ndev; i++) {
+        dp = Sdev[i];
+        (void)snpf(buf, sizeof(buf), "%lx %ld %s\n", (long)dp->rdev,
+                   (long)dp->inode, dp->name);
+        if (wr2DCfd(ctx, buf, &DCcksum))
+            return;
+    }
+
+#    if defined(HASBLKDEV)
+    /*
+     * Write the block device section from the contents of BSdev[] and BDevtp[].
+     */
+    (void)snpf(buf, sizeof(buf), "block device section: %d\n", BNdev);
+    if (wr2DCfd(ctx, buf, &DCcksum))
+        return;
+    if (BNdev) {
+        for (i = 0; i < BNdev; i++) {
+            dp = BSdev[i];
+            (void)snpf(buf, sizeof(buf), "%lx %ld %s\n", (long)dp->rdev,
+                       (long)dp->inode, dp->name);
+            if (wr2DCfd(ctx, buf, &DCcksum))
+                return;
+        }
+    }
+#    endif /* defined(HASBLKDEV) */
+
+#    if defined(DCACHE_CLONE)
+    /*
+     * Write the clone section.
+     */
+    if (DCACHE_CLONE(ctx, 2))
+        return;
+#    endif /* defined(DCACHE_CLONE) */
+
+#    if defined(DCACHE_PSEUDO)
+    /*
+     * Write the pseudo section.
+     */
+    if (DCACHE_PSEUDO(ctx, 2))
+        return;
+#    endif /* defined(DCACHE_PSEUDO) */
+
+    /*
+     * Write the CRC section and close the file.
+     */
+    (void)snpf(buf, sizeof(buf), "CRC section: %x\n", DCcksum);
+    if (wr2DCfd(ctx, buf, (unsigned *)NULL))
+        return;
+    if (close(DCfd) != 0) {
+        if (!Fwarn)
+            (void)fprintf(stderr, "%s: WARNING: can't close %s: %s\n", Pn,
+                          DCpath[DCpathX], strerror(errno));
+        (void)unlink(DCpath[DCpathX]);
+        DCfd = -1;
+    }
+    DCfd = -1;
+    /*
+     * If the previous reading of the previous device cache file marked it
+     * "unsafe," drop that marking and record that the device cache file was
+     * rebuilt.
+     */
+    if (DCunsafe) {
+        DCunsafe = 0;
+        DCrebuilt = 1;
+    }
+}
+
+/*
+ * wr2DCfd() - write to the DCfd file descriptor
+ */
+
+int wr2DCfd(struct lsof_context *ctx, /* context */
+            char *b,                  /* buffer */
+            unsigned *c)              /* checksum receiver */
+{
+    int bl, bw;
+
+    bl = strlen(b);
+    if (c)
+        (void)crc(b, bl, c);
+    while (bl > 0) {
+        if ((bw = write(DCfd, b, bl)) < 0) {
+            if (!Fwarn)
+                (void)fprintf(stderr, "%s: WARNING: can't write to %s: %s\n",
+                              Pn, DCpath[DCpathX], strerror(errno));
+            (void)unlink(DCpath[DCpathX]);
+            (void)close(DCfd);
+            DCfd = -1;
+            return (1);
+        }
+        b += bw;
+        bl -= bw;
+    }
+    return (0);
+}
+#else  /* !defined(HASDCACHE) */
+char dvch_d1[] = "d";
+char *dvch_d2 = dvch_d1;
+#endif /* defined(HASDCACHE) */
diff --git a/lib/fino.c b/lib/fino.c
new file mode 100644 (file)
index 0000000..693fba3
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * fino.c -- find inode functions for lsof library
+ */
+
+/*
+ * 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.
+ */
+
+/*
+ * fino.c -- find block (optional) and character device file inode numbers
+ *
+ * The caller must define:
+ *
+ *     HASBLKDEV       to activate the block device inode lookup
+ */
+
+#include "common.h"
+#include "machine.h"
+
+#if defined(HASBLKDEV) || defined(USE_LIB_FIND_CH_INO)
+
+#else  /* !defined(HASBLKDEV) && !defined(USE_LIB_FIND_CH_INO) */
+char fino_d1[] = "d";
+char *fino_d2 = fino_d1;
+#endif /* defined(HASBLKDEV) || defined(USE_LIB_FIND_CH_INO) */
+
+#if defined(HASBLKDEV)
+/*
+ * find_bl_ino() - find the inode number for a block device file
+ */
+
+void find_bl_ino(struct lsof_context *ctx) {
+    dev_t ldev, tdev;
+    int low, hi, mid;
+
+    readdev(ctx, 0);
+
+#    if defined(HASDCACHE)
+find_bl_ino_again:
+#    endif /* defined(HASDCACHE) */
+
+    low = mid = 0;
+    hi = BNdev - 1;
+    if (!Lf->dev_def || (Lf->dev != DevDev) || !Lf->rdev_def)
+        return;
+    ldev = Lf->rdev;
+    while (low <= hi) {
+        mid = (low + hi) / 2;
+        tdev = BSdev[mid]->rdev;
+        if (ldev < tdev)
+            hi = mid - 1;
+        else if (ldev > tdev)
+            low = mid + 1;
+        else {
+
+#    if defined(HASDCACHE)
+            if (DCunsafe && !BSdev[mid]->v && !vfy_dev(ctx, BSdev[mid]))
+                goto find_bl_ino_again;
+#    endif /* defined(HASDCACHE) */
+
+            Lf->inode = BSdev[mid]->inode;
+            if (Lf->inp_ty == 0)
+                Lf->inp_ty = 1;
+            return;
+        }
+    }
+}
+#endif /* defined(HASBLKDEV) */
+
+#if defined(USE_LIB_FIND_CH_INO)
+/*
+ * find_ch_ino() - find the inode number for a character device file
+ */
+
+void find_ch_ino(struct lsof_context *ctx) {
+    dev_t ldev, tdev;
+    int low, hi, mid;
+
+    readdev(ctx, 0);
+
+#    if defined(HASDCACHE)
+find_ch_ino_again:
+#    endif /* defined(HASDCACHE) */
+
+    low = mid = 0;
+    hi = Ndev - 1;
+    if (!Lf->dev_def || (Lf->dev != DevDev) || !Lf->rdev_def)
+        return;
+    ldev = Lf->rdev;
+    while (low <= hi) {
+        mid = (low + hi) / 2;
+        tdev = Sdev[mid]->rdev;
+        if (ldev < tdev)
+            hi = mid - 1;
+        else if (ldev > tdev)
+            low = mid + 1;
+        else {
+
+#    if defined(HASDCACHE)
+            if (DCunsafe && !Sdev[mid]->v && !vfy_dev(ctx, Sdev[mid]))
+                goto find_ch_ino_again;
+#    endif /* defined(HASDCACHE) */
+
+            Lf->inode = Sdev[mid]->inode;
+            if (Lf->inp_ty == 0)
+                Lf->inp_ty = 1;
+            return;
+        }
+    }
+}
+#endif /* defined(USE_LIB_FIND_CH_INO) */
diff --git a/lib/hash.h b/lib/hash.h
new file mode 100644 (file)
index 0000000..7667a53
--- /dev/null
@@ -0,0 +1,75 @@
+
+/*
+ * hash.sh - utilty functions for hash tables
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#if !defined(LSOF_HASH_H)
+#    define LSOF_HASH_H 1
+
+/* Find element in hash table by key, return NULL if not found
+ *
+ * table: hash table
+ * hash: hash function/macro
+ * type: struct type
+ * member: member to match key
+ * key: key
+ *
+ * the struct type should have a member called next
+ **/
+#    define HASH_FIND_ELEMENT(table, hash, type, member, key)                  \
+        ({                                                                     \
+            type *__value = NULL;                                              \
+            int __h = hash(key);                                               \
+            if ((table)) {                                                     \
+                for (__value = (table)[__h]; __value;                          \
+                     __value = __value->next) {                                \
+                    if ((key) == __value->member)                              \
+                        break;                                                 \
+                };                                                             \
+            };                                                                 \
+            __value;                                                           \
+        })
+
+/* Insert element into hash table
+ *
+ * table: hash table
+ * hash: hash function/macro
+ * element: element
+ * member: member name containing key
+ *
+ * the type of element should have a member called next
+ **/
+#    define HASH_INSERT_ELEMENT(table, hash, element, member)                  \
+        ({                                                                     \
+            int __h = hash((element)->member);                                 \
+            (element)->next = (table)[__h];                                    \
+            (table)[__h] = (element);                                          \
+        })
+
+#endif
diff --git a/lib/isfn.c b/lib/isfn.c
new file mode 100644 (file)
index 0000000..b73f293
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+ * isfn.c -- is_file_named() function for lsof library
+ */
+
+/*
+ * 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.
+ */
+
+/*
+ * To use this source file:
+ *
+ * 1. Define USE_LIB_IS_FILE_NAMED.
+ *
+ * 2. If clone support is required:
+ *
+ *    a.  Define HAVECLONEMAJ to be the name of the variable that
+ *       contains the status of the clone major device -- e.g.,
+ *
+ *             #define HAVECLONEMAJ HaveCloneMaj
+ *
+ *    b.  Define CLONEMAJ to be the name of the constant or
+ *       variable that defines the clone major device -- e.g.,
+ *
+ *             #define CLONEMAJ CloneMaj
+ *
+ *    c.  Make sure that clone devices are identified by an lfile
+ *       element is_stream value of 1.
+ *
+ *    d.  Accept clone searching by device number only.
+ */
+
+#include "common.h"
+#include "machine.h"
+
+#if defined(USE_LIB_IS_FILE_NAMED)
+
+/*
+ * Local structures
+ */
+
+/*
+ * Local static variables
+ */
+
+/*
+ * Local definitions
+ */
+
+#    if defined(HAVECLONEMAJ)
+#        define SFCDHASH                                                       \
+            1024 /* Sfile hash by clone device (power                          \
+                  * of 2!) */
+#    endif       /* defined(HAVECLONEMAJ) */
+
+#    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(struct lsof_context *ctx) {
+    static int hs = 0;
+    int i;
+    int sfplm = 3;
+    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 defined(HAVECLONEMAJ)
+    if (HAVECLONEMAJ) {
+        if (!(HbyCd = (struct hsfile *)calloc((MALLOC_S)SFCDHASH,
+                                              sizeof(struct hsfile)))) {
+            (void)fprintf(
+                stderr, "%s: can't allocate space for %d clone hash buckets\n",
+                Pn, SFCDHASH);
+            Error(ctx);
+        }
+        sfplm++;
+    }
+#    endif /* defined(HAVECLONEMAJ) */
+
+    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);
+        Error(ctx);
+    }
+    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);
+        Error(ctx);
+    }
+    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);
+        Error(ctx);
+    }
+    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);
+        Error(ctx);
+    }
+    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 < sfplm; i++) {
+            if (i == 0) {
+                if (!s->aname)
+                    continue;
+                sh = &HbyNm[hashbyname(s->aname, SFNMHASH)];
+                HbyNmCt++;
+            } else if (i == 1) {
+                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++;
+                }
+            } else if (i == 2) {
+                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;
+            }
+
+#    if defined(HAVECLONEMAJ)
+            else {
+                if (!HAVECLONEMAJ || (GET_MAJ_DEV(s->rdev) != CLONEMAJ))
+                    continue;
+                sh = &HbyCd[SFHASHDEVINO(0, GET_MIN_DEV(s->rdev), 0, SFCDHASH)];
+                HbyCdCt++;
+            }
+#    else  /* ! defined(HAVECLONEMAJ) */
+            else
+                continue;
+#    endif /* defined(HAVECLONEMAJ) */
+
+            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);
+                    Error(ctx);
+                }
+                sn->s = s;
+                sn->next = sh->next;
+                sh->next = sn;
+            }
+        }
+    }
+}
+
+/*
+ * is_file_named() - is this file named?
+ */
+
+int is_file_named(struct lsof_context *ctx,
+                  char *p, /* path name; NULL = search by device
+                            * and inode (from *Lf) */
+                  int cd)  /* character or block type file --
+                            * VCHR or VBLK vnode, or S_IFCHR
+                            * or S_IFBLK inode */
+{
+    char *ep;
+    int f = 0;
+    struct sfile *s = (struct sfile *)NULL;
+    struct hsfile *sh;
+    size_t sz;
+    /*
+     * Check for a path name match, as requested.
+     */
+    if (p && HbyNmCt) {
+        for (sh = &HbyNm[hashbyname(p, SFNMHASH)]; sh; sh = sh->next) {
+            if ((s = sh->s) && strcmp(p, s->aname) == 0) {
+                f = 2;
+                break;
+            }
+        }
+    }
+
+#    if defined(HAVECLONEMAJ)
+    /*
+     * If this is a stream, check for a clone device match.
+     */
+    if (!f && HbyCdCt && Lf->is_stream && Lf->dev_def && Lf->rdev_def &&
+        (Lf->dev == DevDev)) {
+        for (sh = &HbyCd[SFHASHDEVINO(0, GET_MAJ_DEV(Lf->rdev), 0, SFCDHASH)];
+             sh; sh = sh->next) {
+            if ((s = sh->s) &&
+                (GET_MAJ_DEV(Lf->rdev) == GET_MIN_DEV(s->rdev))) {
+                f = 3;
+                break;
+            }
+        }
+    }
+#    endif /* defined(HAVECLONEMAJ) */
+
+    /*
+     * Check for a regular file.
+     */
+    if (!f && 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 && 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)) {
+                f = 1;
+                break;
+            }
+        }
+    }
+    /*
+     * Check for a character or block device match.
+     */
+    if (!f && 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(ctx, &sz);
+                (void)snpf(ep, sz, " (%s)", s->devnm);
+            }
+        }
+        break;
+    case 2:
+        (void)strcpy(Namech, p);
+        break;
+
+#    if defined(HAVECLONEMAJ)
+        /* case 3:             do nothing for stream clone matches */
+#    endif /* defined(HAVECLONEMAJ) */
+    }
+    if (s)
+        s->f = 1;
+    return (1);
+}
+#else  /* !defined(USE_LIB_IS_FILE_NAMED) */
+char isfn_d1[] = "d";
+char *isfn_d2 = isfn_d1;
+#endif /* defined(USE_LIB_IS_FILE_NAMED) */
diff --git a/lib/lkud.c b/lib/lkud.c
new file mode 100644 (file)
index 0000000..221b704
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * lkud.c -- device lookup functions for lsof library
+ */
+
+/*
+ * 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.
+ */
+
+/*
+ * lkud.c -- lookup device
+ *
+ * The caller may define:
+ *
+ *     HASBLKDEV       to activate block device lookup
+ */
+
+#include "common.h"
+#include "machine.h"
+
+#if defined(HASBLKDEV) || defined(USE_LIB_LKUPDEV)
+
+#else  /* !defined(HASBLKDEV) && !defined(USE_LIB_LKUPDEV) */
+char lkud_d1[] = "d";
+char *lkud_d2 = lkud_d1;
+#endif /* defined(HASBLKDEV) || defined(USE_LIB_LKUPDEV) */
+
+#if defined(HASBLKDEV)
+/*
+ * lkupbdev() - look up a block device
+ */
+
+struct l_dev *lkupbdev(struct lsof_context *ctx,
+                       dev_t *dev,  /* pointer to device number */
+                       dev_t *rdev, /* pointer to raw device number */
+                       int i,       /* inode match status */
+                       int r)       /* if 1, rebuild the device cache with
+                                     * rereaddev() when no match is found
+                                     * and HASDCACHE is defined and
+                                     * DCunsafe is one */
+{
+    INODETYPE inode = (INODETYPE)0;
+    int low, hi, mid;
+    struct l_dev *dp;
+    int ty = 0;
+
+    if (*dev != DevDev)
+        return ((struct l_dev *)NULL);
+    readdev(ctx, 0);
+    if (i) {
+        inode = Lf->inode;
+        ty = Lf->inp_ty;
+    }
+    /*
+     * Search block device table for match.
+     */
+
+#    if defined(HASDCACHE)
+
+lkupbdev_again:
+
+#    endif /* defined(HASDCACHE) */
+
+    low = mid = 0;
+    hi = BNdev - 1;
+    while (low <= hi) {
+        mid = (low + hi) / 2;
+        dp = BSdev[mid];
+        if (*rdev < dp->rdev)
+            hi = mid - 1;
+        else if (*rdev > dp->rdev)
+            low = mid + 1;
+        else {
+            if ((i == 0) || (ty != 1) || (inode == dp->inode)) {
+
+#    if defined(HASDCACHE)
+                if (DCunsafe && !dp->v && !vfy_dev(ctx, dp))
+                    goto lkupbdev_again;
+#    endif /* defined(HASDCACHE) */
+
+                return (dp);
+            }
+            if (inode < dp->inode)
+                hi = mid - 1;
+            else
+                low = mid + 1;
+        }
+    }
+
+#    if defined(HASDCACHE)
+    if (DCunsafe && r) {
+        (void)rereaddev(ctx);
+        goto lkupbdev_again;
+    }
+#    endif /* defined(HASDCACHE) */
+
+    return ((struct l_dev *)NULL);
+}
+#endif /* defined(HASBLKDEV) */
+
+#if defined(USE_LIB_LKUPDEV)
+/*
+ * lkupdev() - look up a character device
+ */
+
+struct l_dev *lkupdev(struct lsof_context *ctx,
+                      dev_t *dev,  /* pointer to device number */
+                      dev_t *rdev, /* pointer to raw device number */
+                      int i,       /* inode match status */
+                      int r)       /* if 1, rebuild the device cache with
+                                    * rereaddev() when no match is found
+                                    * and HASDCACHE is defined and
+                                    * DCunsafe is one */
+{
+    INODETYPE inode = (INODETYPE)0;
+    int low, hi, mid;
+    struct l_dev *dp;
+    int ty = 0;
+
+    if (*dev != DevDev)
+        return ((struct l_dev *)NULL);
+    readdev(ctx, 0);
+    if (i) {
+        inode = Lf->inode;
+        ty = Lf->inp_ty;
+    }
+    /*
+     * Search device table for match.
+     */
+
+#    if defined(HASDCACHE)
+
+lkupdev_again:
+
+#    endif /* defined(HASDCACHE) */
+
+    low = mid = 0;
+    hi = Ndev - 1;
+    while (low <= hi) {
+        mid = (low + hi) / 2;
+        dp = Sdev[mid];
+        if (*rdev < dp->rdev)
+            hi = mid - 1;
+        else if (*rdev > dp->rdev)
+            low = mid + 1;
+        else {
+            if ((i == 0) || (ty != 1) || (inode == dp->inode)) {
+
+#    if defined(HASDCACHE)
+                if (DCunsafe && !dp->v && !vfy_dev(ctx, dp))
+                    goto lkupdev_again;
+#    endif /* defined(HASDCACHE) */
+
+                return (dp);
+            }
+            if (inode < dp->inode)
+                hi = mid - 1;
+            else
+                low = mid + 1;
+        }
+    }
+
+#    if defined(HASDCACHE)
+    if (DCunsafe && r) {
+        (void)rereaddev(ctx);
+        goto lkupdev_again;
+    }
+#    endif /* defined(HASDCACHE) */
+
+    return ((struct l_dev *)NULL);
+}
+#endif /* defined(USE_LIB_LKUPDEV) */
diff --git a/lib/lsof.c b/lib/lsof.c
new file mode 100644 (file)
index 0000000..e15bab1
--- /dev/null
@@ -0,0 +1,1113 @@
+/*
+ * lsof.c -- implement lsof_* functions() for liblsof
+ */
+
+/*
+ * 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.
+ */
+
+#ifdef AUTOTOOLS
+#    include "config.h"
+#endif
+#include "common.h"
+#include "lsof.h"
+#include <unistd.h>
+
+#ifndef API_EXPORT
+#    define API_EXPORT
+#endif
+
+API_EXPORT
+int lsof_get_api_version() { return LSOF_API_VERSION; }
+
+#ifdef AUTOTOOLS
+API_EXPORT
+char *lsof_get_library_version() { return PACKAGE_VERSION; }
+#endif
+
+API_EXPORT
+struct lsof_context *lsof_new() {
+    struct lsof_context *ctx =
+        (struct lsof_context *)malloc(sizeof(struct lsof_context));
+    if (ctx) {
+        /* Initialization */
+        memset(ctx, 0, sizeof(struct lsof_context));
+
+        if (!(Namech = (char *)malloc(MAXPATHLEN + 1))) {
+            free(ctx);
+            return NULL;
+        }
+        Namechl = (size_t)(MAXPATHLEN + 1);
+
+#if defined(WARNINGSTATE)
+        /* suppress warnings */
+        Fwarn = 1;
+#else  /* !defined(WARNINGSTATE) */
+        /* display warnings */
+        Fwarn = 0;
+#endif /* defined(WARNINGSTATE) */
+
+#if defined(HASXOPT_VALUE)
+        /* -X option status */
+        Fxopt = HASXOPT_VALUE;
+#endif /* defined(HASXOPT_VALUE) */
+
+        /* -1 == none */
+        FdlTy = -1;
+
+        /* Readlink() and stat() timeout (seconds) */
+        TmLimit = TMLIMIT;
+
+        /* default */
+        AllProc = 1;
+
+        /* -1 == none */
+        FdlTy = -1;
+
+        /* device cache file descriptor */
+        DCfd = -1;
+
+        /* device cache path index: -1 = path not defined */
+        DCpathX = -1;
+
+        /* device cache state: 3 = update; read and rebuild if necessary */
+        DCstate = 3;
+
+        /* COMMAND column width limit */
+        CmdLim = CMDL;
+    }
+    return ctx;
+}
+
+API_EXPORT
+enum lsof_error lsof_avoid_blocking(struct lsof_context *ctx, int avoid) {
+    if (!ctx || ctx->frozen) {
+        return LSOF_ERROR_INVALID_ARGUMENT;
+    }
+    Fblock = avoid;
+    return LSOF_EXIT_SUCCESS;
+}
+
+API_EXPORT
+enum lsof_error lsof_avoid_forking(struct lsof_context *ctx, int avoid) {
+    if (!ctx || ctx->frozen) {
+        return LSOF_ERROR_INVALID_ARGUMENT;
+    }
+    Fovhd = avoid;
+    return LSOF_SUCCESS;
+}
+
+API_EXPORT
+enum lsof_error lsof_logic_and(struct lsof_context *ctx) {
+    if (!ctx || ctx->frozen) {
+        return LSOF_ERROR_INVALID_ARGUMENT;
+    }
+    Fand = 1;
+    return LSOF_SUCCESS;
+}
+
+API_EXPORT
+enum lsof_error lsof_select_process(struct lsof_context *ctx, char *command,
+                                    int exclude) {
+    char *cp; /* command copy */
+    MALLOC_S len;
+    struct str_lst *lpt, *str;
+    if (!ctx || ctx->frozen) {
+        return LSOF_ERROR_INVALID_ARGUMENT;
+    }
+
+    /*
+     * Check for command inclusion/exclusion conflicts.
+     */
+    for (str = Cmdl; str; str = str->next) {
+        if (str->x != exclude) {
+            if (!strcmp(str->str, command)) {
+                if (ctx->err) {
+                    (void)fprintf(ctx->err, "%s: -c^%s and -c%s conflict.\n",
+                                  Pn, str->str, command);
+                }
+                return LSOF_ERROR_INVALID_ARGUMENT;
+            }
+        }
+    }
+
+    if (!(cp = mkstrcpy(command, &len))) {
+        if (ctx->err) {
+            (void)fprintf(ctx->err, "%s: no string copy space: ", Pn);
+            safestrprt(command, ctx->err, 1);
+        }
+        return LSOF_ERROR_NO_MEMORY;
+    }
+
+#if defined(MAXSYSCMDL)
+    if (len > MAXSYSCMDL) {
+        /* Impossible to match */
+        if (ctx->err) {
+            (void)fprintf(ctx->err, "%s: \"-c ", Pn);
+            (void)safestrprt(command, ctx->err, 2);
+            (void)fprintf(ctx->err, "\" length (%zu) > what system", len);
+            (void)fprintf(ctx->err, " provides (%d)\n", MAXSYSCMDL);
+        }
+        CLEAN(cp);
+        return LSOF_ERROR_INVALID_ARGUMENT;
+    }
+#endif
+
+    if ((lpt = (struct str_lst *)malloc(sizeof(struct str_lst))) == NULL) {
+        if (ctx->err) {
+            safestrprt(command, ctx->err, 1);
+            (void)fprintf(ctx->err, "%s: no list space: ", Pn);
+            safestrprt(command, ctx->err, 1);
+        }
+        CLEAN(cp);
+        return LSOF_ERROR_NO_MEMORY;
+    }
+
+    /* Insert into list */
+    lpt->f = 0;
+    lpt->str = cp;
+    lpt->len = (int)len;
+    lpt->x = exclude;
+    if (exclude) {
+        Cmdnx++;
+    } else {
+        Cmdni++;
+        /* Update selection flag for inclusions */
+        Selflags |= SELCMD;
+    }
+    lpt->next = Cmdl;
+    Cmdl = lpt;
+
+    return LSOF_SUCCESS;
+}
+
+API_EXPORT
+enum lsof_error lsof_set_output_stream(struct lsof_context *ctx, FILE *fp,
+                                       char *program_name, int warn) {
+    if (!ctx) {
+        return LSOF_ERROR_INVALID_ARGUMENT;
+    }
+    ctx->err = fp;
+    ctx->program_name = mkstrcpy(program_name, NULL);
+    ctx->warn = warn;
+    return LSOF_SUCCESS;
+}
+
+API_EXPORT
+enum lsof_error lsof_freeze(struct lsof_context *ctx) {
+    if (ctx->frozen) {
+        return LSOF_ERROR_INVALID_ARGUMENT;
+    }
+
+    if (Selflags == 0) {
+        Selflags = SelAll;
+    } else {
+        if ((Selflags & (SELNA | SELNET)) != 0 &&
+            (Selflags & ~(SELNA | SELNET)) == 0)
+            Selinet = 1;
+        AllProc = 0;
+    }
+
+    initialize(ctx);
+    hashSfile(ctx);
+    ctx->frozen = 1;
+    return LSOF_SUCCESS;
+}
+
+API_EXPORT
+enum lsof_error lsof_gather(struct lsof_context *ctx,
+                            struct lsof_result **result) {
+    enum lsof_error ret = LSOF_SUCCESS;
+    int pi = 0;  /* proc index */
+    int upi = 0; /* user proc index */
+    struct lsof_process *p;
+    struct lproc *lp;
+    int fi = 0; /* file index */
+    size_t num_files;
+    struct lsof_file *f;
+    struct lfile *lf;
+    struct lfile *lf_next;
+    size_t sel_procs = 0;
+    char *cp;
+    char buf[64];
+    int s;
+    struct str_lst *str;
+    struct sfile *sfp;
+    struct nwad *np, *npn;
+#if defined(HASPROCFS)
+    struct procfsid *pfi;
+#endif /* defined(HASPROCFS) */
+#if defined(HASZONES)
+    znhash_t *zp;
+#endif /* defined(HASZONES) */
+#if defined(HASSELINUX)
+    cntxlist_t *cntxp;
+#endif /* defined(HASSELINUX) */
+    int pass;
+    int i;
+    struct lsof_selection *selections;
+    size_t num_selections = 0;
+
+    if (!result) {
+        ret = LSOF_ERROR_INVALID_ARGUMENT;
+        return ret;
+    } else if (!ctx->frozen) {
+        ret = lsof_freeze(ctx);
+        if (ret != LSOF_SUCCESS)
+            return ret;
+    }
+
+    gather_proc_info(ctx);
+
+    /* Cleanup orphaned cur_file, if any*/
+    if (ctx->cur_file) {
+        CLEAN(ctx->cur_file->dev_ch);
+        CLEAN(ctx->cur_file->nm);
+        CLEAN(ctx->cur_file->nma);
+        CLEAN(ctx->cur_file);
+    }
+
+    /* Count selected procs */
+    for (pi = 0; pi < ctx->procs_size; pi++) {
+        lp = &ctx->procs[pi];
+        if (lp->pss) {
+            sel_procs++;
+        }
+    }
+
+    /* Fill result */
+    struct lsof_result *res =
+        (struct lsof_result *)malloc(sizeof(struct lsof_result));
+    struct lsof_process *user_procs =
+        (struct lsof_process *)malloc(sizeof(struct lsof_process) * sel_procs);
+    memset(user_procs, 0, sizeof(struct lsof_process) * sel_procs);
+
+    for (pi = 0, upi = 0; pi < ctx->procs_size; pi++) {
+        /* Copy fields from lproc */
+        lp = &ctx->procs[pi];
+        if (lp->pss) {
+            /* selected process */
+            p = &user_procs[upi++];
+
+            p->command = lp->cmd;
+            lp->cmd = NULL;
+            p->pid = lp->pid;
+
+#if defined(HASTASKS)
+            p->tid = lp->tid;
+            p->task_cmd = lp->tcmd;
+            lp->tcmd = NULL;
+#endif
+#if defined(HASZONES)
+            p->solaris_zone = lp->zn;
+            lp->zn = NULL;
+#endif
+#if defined(HASSELINUX)
+            p->selinux_context = lp->cntx;
+            lp->cntx = NULL;
+#endif
+
+            p->pgid = lp->pgid;
+            p->ppid = lp->ppid;
+            p->uid = lp->uid;
+
+            /* Compute number of files in the linked list */
+            num_files = 0;
+            for (lf = lp->file; lf; lf = lf->next) {
+                if (!is_file_sel(ctx, lp, lf))
+                    continue;
+                num_files++;
+            }
+
+            p->files = (struct lsof_file *)malloc(sizeof(struct lsof_file) *
+                                                  num_files);
+            memset(p->files, 0, sizeof(struct lsof_file) * num_files);
+            p->num_files = num_files;
+            for (fi = 0, lf = lp->file; lf; lf = lf_next) {
+                if (is_file_sel(ctx, lp, lf)) {
+                    /* Copy fields from lfile */
+                    f = &p->files[fi++];
+                    f->flags = 0;
+
+                    /* FD column */
+                    f->fd_type = lf->fd_type;
+                    f->fd_num = lf->fd_num;
+                    f->access = lf->access;
+                    f->lock = lf->lock;
+
+                    /* TYPE column */
+                    f->file_type = lf->type;
+                    f->unknown_file_type_number = lf->unknown_file_type_number;
+
+                    /* DEVICE column */
+                    f->dev = lf->dev;
+                    if (lf->dev_def) {
+                        f->flags |= LSOF_FILE_FLAG_DEV_VALID;
+                    }
+                    f->rdev = lf->rdev;
+                    if (lf->rdev_def) {
+                        f->flags |= LSOF_FILE_FLAG_RDEV_VALID;
+                    }
+
+                    /* SIZE, SIZE/OFF, OFFSET column */
+                    f->size = lf->sz;
+                    if (lf->sz_def) {
+                        f->flags |= LSOF_FILE_FLAG_SIZE_VALID;
+                    }
+                    f->offset = lf->off;
+                    if (lf->off_def) {
+                        f->flags |= LSOF_FILE_FLAG_OFFSET_VALID;
+                    }
+
+                    /* NLINK column */
+                    f->num_links = lf->nlink;
+                    if (lf->nlink_def) {
+                        f->flags |= LSOF_FILE_FLAG_NUM_LINKS_VALID;
+                    }
+
+                    /* NODE column */
+                    f->inode = lf->inode;
+                    if (lf->inp_ty == 1 || lf->inp_ty == 3) {
+                        f->flags |= LSOF_FILE_FLAG_INODE_VALID;
+                    }
+
+                    /* NAME column */
+                    f->name = lf->nm;
+                    lf->nm = NULL;
+                }
+                lf_next = lf->next;
+            }
+        }
+
+        for (lf = lp->file; lf; lf = lf_next) {
+            /* free lf */
+            lf_next = lf->next;
+            CLEAN(lf->nma);
+            CLEAN(lf->dev_ch);
+#if defined(CLRLFILEADD)
+            CLRLFILEADD(lf)
+#endif /* defined(CLRLFILEADD) */
+            CLEAN(lf);
+        }
+        lp->file = NULL;
+
+        /* skip and free */
+        CLEAN(lp->cmd);
+#if defined(HASTASKS)
+        CLEAN(lp->tcmd);
+#endif
+#if defined(HASSELINUX)
+        CLEAN(lp->cntx);
+#endif /* defined(HASSELINUX) */
+        continue;
+    }
+
+    /* Cleanup */
+    CLEAN(ctx->procs);
+    ctx->cur_proc = NULL;
+
+    res->processes = user_procs;
+    res->num_processes = sel_procs;
+
+    ctx->procs_size = ctx->procs_cap = 0;
+    ctx->cur_file = ctx->prev_file = NULL;
+
+    /* Collect selection result */
+    for (pass = 0; pass < 2; pass++) {
+        num_selections = 0;
+
+        /* command */
+        for (str = Cmdl; str; str = str->next) {
+            if (pass) {
+                selections[num_selections].type = LSOF_SELECTION_COMMAND;
+                selections[num_selections].found = str->f;
+                selections[num_selections].string = str->str;
+            }
+            num_selections++;
+        }
+
+        /* command regex */
+        for (i = 0; i < NCmdRxU; i++) {
+            if (pass) {
+                selections[num_selections].type = LSOF_SELECTION_COMMAND_REGEX;
+                selections[num_selections].found = CmdRx[i].mc > 0;
+                selections[num_selections].string = CmdRx[i].exp;
+            }
+            num_selections++;
+        }
+
+        /* select file or file system */
+        for (sfp = Sfile; sfp; sfp = sfp->next) {
+            if (pass) {
+                selections[num_selections].type =
+                    sfp->type ? LSOF_SELECTION_PATH
+                              : LSOF_SELECTION_FILE_SYSTEM;
+                selections[num_selections].found = sfp->f;
+                selections[num_selections].string = sfp->aname;
+            }
+            num_selections++;
+        }
+
+#if defined(HASPROCFS)
+        /* procfs */
+        if (Procsrch) {
+            if (pass) {
+                selections[num_selections].type = LSOF_SELECTION_FILE_SYSTEM;
+                selections[num_selections].found = Procfind;
+                selections[num_selections].string =
+                    Mtprocfs ? Mtprocfs->dir : HASPROCFS;
+            }
+            num_selections++;
+        }
+
+        for (pfi = Procfsid; pfi; pfi = pfi->next) {
+            if (pass) {
+                selections[num_selections].type = LSOF_SELECTION_PATH;
+                selections[num_selections].found = pfi->f;
+                selections[num_selections].string = pfi->nm;
+            }
+            num_selections++;
+        }
+#endif /* defined(HASPROCFS) */
+
+        /* network address */
+        for (np = Nwad; np;) {
+            int found = np->f;
+            if (!(cp = np->arg)) {
+                np = np->next;
+                continue;
+            }
+            for (npn = np->next; npn; npn = npn->next) {
+                if (!npn->arg)
+                    continue;
+                if (!strcmp(cp, npn->arg)) {
+                    /* Found duplicate specification */
+                    found |= npn->f;
+                } else {
+                    break;
+                }
+            }
+
+            if (pass) {
+                selections[num_selections].type =
+                    LSOF_SELECTION_NETWORK_ADDRESS;
+                selections[num_selections].found = found;
+                selections[num_selections].string = np->arg;
+            }
+            num_selections++;
+            np = npn;
+        }
+
+        /* ip protocol */
+        if (Fnet) {
+            if (pass) {
+                selections[num_selections].type = LSOF_SELECTION_INTERNET;
+                selections[num_selections].found = Fnet == 2;
+            }
+            num_selections++;
+        }
+
+#if defined(HASTCPUDPSTATE)
+        /* tcp/tpi protocol state */
+        if (TcpStIn) {
+            for (i = 0; i < TcpNstates; i++) {
+                if (TcpStI[i]) {
+                    if (pass) {
+                        selections[num_selections].type =
+                            LSOF_SELECTION_PROTOCOL_STATE;
+                        selections[num_selections].found = TcpStI[i] == 2;
+                        selections[num_selections].string = TcpSt[i];
+                    }
+                    num_selections++;
+                }
+            }
+        }
+        if (UdpStIn) {
+            for (i = 0; i < UdpNstates; i++) {
+                if (UdpStI[i]) {
+                    if (pass) {
+                        selections[num_selections].type =
+                            LSOF_SELECTION_PROTOCOL_STATE;
+                        selections[num_selections].found = UdpStI[i] == 2;
+                        selections[num_selections].string = UdpSt[i];
+                    }
+                    num_selections++;
+                }
+            }
+        }
+#endif /* defined(HASTCPUDPSTATE) */
+
+        /* nfs */
+        if (Fnfs) {
+            if (pass) {
+                selections[num_selections].type = LSOF_SELECTION_NFS;
+                selections[num_selections].found = Fnfs == 2;
+            }
+            num_selections++;
+        }
+
+        /* pid */
+        for (i = 0; i < Npid; i++) {
+            if (Spid[i].x)
+                continue;
+            if (pass) {
+                selections[num_selections].type = LSOF_SELECTION_PID;
+                selections[num_selections].found = Spid[i].f;
+                selections[num_selections].integer = Spid[i].i;
+            }
+            num_selections++;
+        }
+
+        /* pgid */
+        for (i = 0; i < Npgid; i++) {
+            if (Spgid[i].x)
+                continue;
+            if (pass) {
+                selections[num_selections].type = LSOF_SELECTION_PGID;
+                selections[num_selections].found = Spgid[i].f;
+                selections[num_selections].integer = Spgid[i].i;
+            }
+            num_selections++;
+        }
+
+        /* uid */
+        for (i = 0; i < Nuid; i++) {
+            if (Suid[i].excl)
+                continue;
+            if (pass) {
+                selections[num_selections].type = LSOF_SELECTION_UID;
+                selections[num_selections].found = Suid[i].f;
+                selections[num_selections].string = Suid[i].lnm;
+                selections[num_selections].integer = Suid[i].uid;
+            }
+            num_selections++;
+        }
+
+#if defined(HASTASKS)
+        /* tasks */
+        if (Ftask) {
+            if (pass) {
+                selections[num_selections].type = LSOF_SELECTION_TASK;
+                selections[num_selections].found = Ftask == 2;
+            }
+            num_selections++;
+        }
+#endif /* defined(HASTASKS) */
+
+#if defined(HASZONES)
+        /* solaris zones */
+        if (ZoneArg) {
+            for (i = 0; i < HASHZONE; i++) {
+                for (zp = ZoneArg[i]; zp; zp = zp->next) {
+                    if (pass) {
+                        selections[num_selections].type =
+                            LSOF_SELECTION_SOLARIS_ZONE;
+                        selections[num_selections].found = zp->f;
+                        selections[num_selections].string = zp->zn;
+                    }
+                    num_selections++;
+                }
+            }
+        }
+#endif /* defined(HASZONES) */
+
+#if defined(HASSELINUX)
+        /* SELinux context */
+        if (CntxArg) {
+            for (cntxp = CntxArg; cntxp; cntxp = cntxp->next) {
+                if (pass) {
+                    selections[num_selections].type =
+                        LSOF_SELECTION_SELINUX_CONTEXT;
+                    selections[num_selections].found = cntxp->f;
+                    selections[num_selections].string = cntxp->cntx;
+                }
+                num_selections++;
+            }
+        }
+#endif /* defined(HASSELINUX) */
+
+        /* allocation selections array */
+        if (pass == 0) {
+            selections = (struct lsof_selection *)malloc(
+                sizeof(struct lsof_selection) * num_selections);
+            memset(selections, 0,
+                   sizeof(struct lsof_selection) * num_selections);
+            res->selections = selections;
+            res->num_selections = num_selections;
+        }
+    }
+
+    /* Params */
+    *result = res;
+
+    return ret;
+}
+
+API_EXPORT
+void lsof_destroy(struct lsof_context *ctx) {
+    int i;
+    struct str_lst *str_lst, *str_lst_next;
+    struct int_lst *int_lst, *int_lst_next;
+    struct mounts *mnt, *mnt_next;
+    if (!ctx) {
+        return;
+    }
+    /* Free parameters */
+    for (str_lst = Cmdl; str_lst; str_lst = str_lst_next) {
+        str_lst_next = str_lst->next;
+        CLEAN(str_lst->str);
+        CLEAN(str_lst);
+    }
+    CLEAN(Spid);
+    CLEAN(Spgid);
+    for (i = 0; i < Nuid; i++) {
+        CLEAN(Suid[i].lnm);
+    }
+    CLEAN(Suid);
+    CLEAN(Nmlst);
+
+    /* Free temporary */
+    CLEAN(Namech);
+#if defined(HASNLIST)
+    CLEAN(Nl);
+    Nll = 0;
+#endif /* defined(HASNLIST) */
+
+    /* Free local mount info */
+    if (Lmist) {
+        for (mnt = Lmi; mnt; mnt = mnt_next) {
+            mnt_next = mnt->next;
+            CLEAN(mnt->dir);
+            CLEAN(mnt->fsname);
+            CLEAN(mnt->fsnmres);
+#if defined(HASFSTYPE)
+            CLEAN(mnt->fstype);
+#endif
+            CLEAN(mnt);
+        }
+        Lmi = NULL;
+        Lmist = 0;
+    }
+
+    /* state table */
+#if !defined(USE_LIB_PRINT_TCPTPI)
+    for (i = 0; i < TcpNstates; i++) {
+        CLEAN(TcpSt[i]);
+    }
+    CLEAN(TcpSt);
+#endif /* !defined(USE_LIB_PRINT_TCPTPI) */
+    for (i = 0; i < UdpNstates; i++) {
+        CLEAN(UdpSt[i]);
+    }
+    CLEAN(UdpSt);
+    CLEAN(Pn);
+
+    CLEAN(ctx);
+}
+
+API_EXPORT
+void lsof_free_result(struct lsof_result *result) {
+    int pi, fi;
+    struct lsof_process *p;
+    struct lsof_file *f;
+    for (pi = 0; pi < result->num_processes; pi++) {
+        p = &result->processes[pi];
+        /* Free files */
+        for (fi = 0; fi < p->num_files; fi++) {
+            f = &p->files[fi];
+            CLEAN(f->name);
+        }
+        CLEAN(p->files);
+
+        /* Free process fields */
+        CLEAN(p->command);
+        CLEAN(p->task_cmd);
+        CLEAN(p->solaris_zone);
+        CLEAN(p->selinux_context);
+    }
+    CLEAN(result->processes);
+    CLEAN(result->selections);
+    CLEAN(result);
+}
+
+API_EXPORT
+enum lsof_error lsof_select_process_regex(struct lsof_context *ctx, char *x) {
+    int bmod = 0;
+    int bxmod = 0;
+    int i, re;
+    int imod = 0;
+    int xmod = 0;
+    int co = REG_NOSUB | REG_EXTENDED;
+    char reb[256], *xb, *xe, *xm;
+    MALLOC_S xl;
+    char *xp = (char *)NULL;
+    enum lsof_error ret = LSOF_SUCCESS;
+
+    if (!ctx || ctx->frozen) {
+        return LSOF_ERROR_INVALID_ARGUMENT;
+    }
+
+    /*
+     * Make sure the supplied string starts a regular expression.
+     */
+    if (!*x || (*x != '/')) {
+        if (ctx->err) {
+            (void)fprintf(ctx->err, "%s: regexp doesn't begin with '/': ", Pn);
+            if (x)
+                safestrprt(x, ctx->err, 1);
+        }
+        ret = LSOF_ERROR_INVALID_ARGUMENT;
+        goto cleanup;
+    }
+
+    /*
+     * Skip to the end ('/') of the regular expression.
+     */
+    xb = x + 1;
+    for (xe = xb; *xe; xe++) {
+        if (*xe == '/')
+            break;
+    }
+    if (*xe != '/') {
+        if (ctx->err) {
+            (void)fprintf(ctx->err, "%s: regexp doesn't end with '/': ", Pn);
+            safestrprt(x, ctx->err, 1);
+        }
+        ret = LSOF_ERROR_INVALID_ARGUMENT;
+        goto cleanup;
+    }
+
+    /*
+     * Decode any regular expression modifiers.
+     */
+    for (i = 0, xm = xe + 1; *xm; xm++) {
+        switch (*xm) {
+        case 'b': /* This is a basic expression. */
+            if (++bmod > 1) {
+                if (bmod == 2 && ctx->err) {
+                    (void)fprintf(ctx->err,
+                                  "%s: b regexp modifier already used: ", Pn);
+                    safestrprt(x, ctx->err, 1);
+                }
+                i = 1;
+            } else if (xmod) {
+                if (++bxmod == 1 && ctx->err) {
+                    (void)fprintf(
+                        ctx->err,
+                        "%s: b and x regexp modifiers conflict: ", Pn);
+                    safestrprt(x, ctx->err, 1);
+                }
+                i = 1;
+            } else
+                co &= ~REG_EXTENDED;
+            break;
+        case 'i': /* Ignore case. */
+            if (++imod > 1) {
+                if (imod == 2 && ctx->err) {
+                    (void)fprintf(ctx->err,
+                                  "%s: i regexp modifier already used: ", Pn);
+                    safestrprt(x, ctx->err, 1);
+                }
+                i = 1;
+            } else
+                co |= REG_ICASE;
+            break;
+        case 'x': /* This is an extended expression. */
+            if (++xmod > 1) {
+                if (xmod == 2 && ctx->err) {
+                    (void)fprintf(ctx->err,
+                                  "%s: x regexp modifier already used: ", Pn);
+                    safestrprt(x, ctx->err, 1);
+                }
+                i = 1;
+            } else if (bmod) {
+                if (++bxmod == 1 && ctx->err) {
+                    (void)fprintf(
+                        ctx->err,
+                        "%s: b and x regexp modifiers conflict: ", Pn);
+                    safestrprt(x, ctx->err, 1);
+                }
+                i = 1;
+            } else
+                co |= REG_EXTENDED;
+            break;
+        default:
+            if (ctx->err)
+                (void)fprintf(ctx->err, "%s: invalid regexp modifier: %c\n", Pn,
+                              (int)*xm);
+            i = 1;
+        }
+    }
+    if (i) {
+        ret = LSOF_ERROR_INVALID_ARGUMENT;
+        goto cleanup;
+    }
+
+    /*
+     * Allocate space to hold expression and copy it there.
+     */
+    xl = (MALLOC_S)(xe - xb);
+    if (!(xp = (char *)malloc(xl + 1))) {
+        if (ctx->err) {
+            (void)fprintf(ctx->err, "%s: no regexp space for: ", Pn);
+            safestrprt(x, ctx->err, 1);
+        }
+        Error(ctx);
+        ret = LSOF_ERROR_NO_MEMORY;
+        goto cleanup;
+    }
+    (void)strncpy(xp, xb, xl);
+    xp[(int)xl] = '\0';
+    /*
+     * Assign a new CmdRx[] slot for this expression.
+     */
+    if (NCmdRxA <= NCmdRxU) {
+        /*
+         * More CmdRx[] space must be assigned.
+         */
+        NCmdRxA += 32;
+        xl = (MALLOC_S)(ctx->cmd_regex_cap * sizeof(lsof_rx_t));
+        if (CmdRx)
+            CmdRx = (lsof_rx_t *)realloc((MALLOC_P *)CmdRx, xl);
+        else
+            CmdRx = (lsof_rx_t *)malloc(xl);
+        if (!CmdRx) {
+            if (ctx->err) {
+                (void)fprintf(ctx->err, "%s: no space for regexp: ", Pn);
+                safestrprt(x, ctx->err, 1);
+            }
+            Error(ctx);
+            ret = LSOF_ERROR_NO_MEMORY;
+            goto cleanup;
+        }
+    }
+    i = NCmdRxU;
+    CmdRx[i].exp = xp;
+    /*
+     * Compile the expression.
+     */
+    if ((re = regcomp(&CmdRx[i].cx, xp, co))) {
+        if (ctx->err) {
+            (void)fprintf(ctx->err, "%s: regexp error: ", Pn);
+            safestrprt(x, ctx->err, 0);
+            (void)regerror(re, &CmdRx[i].cx, &reb[0], sizeof(reb));
+            (void)fprintf(ctx->err, ": %s\n", reb);
+        }
+        ret = LSOF_ERROR_INVALID_ARGUMENT;
+        goto cleanup;
+    }
+    /*
+     * Complete the CmdRx[] table entry.
+     */
+    CmdRx[i].mc = 0;
+    CmdRx[i].exp = xp;
+    NCmdRxU++;
+
+    /** Update selection flags for inclusion */
+    if (CmdRx)
+        Selflags |= SELCMD;
+    ret = LSOF_SUCCESS;
+cleanup:
+    CLEAN(xp);
+    return ret;
+}
+
+/* Internel helper for lsof_select_pid/pgid */
+enum lsof_error lsof_select_pid_pgid(struct lsof_context *ctx, int32_t id,
+                                     struct int_lst **sel, int *cap, int *size,
+                                     int *incl_num, int *excl_num, int exclude,
+                                     int is_pid) {
+    int i, j;
+    if (!ctx || ctx->frozen) {
+        return LSOF_ERROR_INVALID_ARGUMENT;
+    }
+
+    /*
+     * Avoid entering duplicates and conflicts.
+     */
+    for (i = 0; i < *size; i++) {
+        if (id == (*sel)[i].i) {
+            if (exclude == (*sel)[i].x) {
+                return LSOF_SUCCESS;
+            }
+            if (ctx->err) {
+                (void)fprintf(ctx->err,
+                              "%s: P%sID %d has been included and excluded.\n",
+                              Pn, is_pid ? "" : "G", id);
+            }
+            return LSOF_ERROR_INVALID_ARGUMENT;
+        }
+    }
+
+    /*
+     * Allocate table table space.
+     */
+    if (*size >= *cap) {
+        *cap += 10;
+        if (!(*sel))
+            *sel = (struct int_lst *)malloc(
+                (MALLOC_S)(sizeof(struct int_lst) * (*cap)));
+        else
+            *sel = (struct int_lst *)realloc(
+                (MALLOC_P *)(*sel),
+                (MALLOC_S)(sizeof(struct int_lst) * (*cap)));
+        if (!(*sel)) {
+            if (ctx->err) {
+                (void)fprintf(ctx->err, "%s: no space for %d process%s IDs", Pn,
+                              *cap, is_pid ? "" : " group");
+            }
+            Error(ctx);
+            return LSOF_ERROR_NO_MEMORY;
+        }
+    }
+
+    /* Insert selection into sel_pid/sel_pgid*/
+    (*sel)[*size].f = 0;
+    (*sel)[*size].i = id;
+    (*sel)[(*size)++].x = exclude;
+    if (exclude)
+        (*excl_num)++;
+    else {
+        (*incl_num)++;
+        /* Update selection flags */
+        Selflags |= is_pid ? SELPID : SELPGID;
+    }
+    return LSOF_SUCCESS;
+}
+
+API_EXPORT
+enum lsof_error lsof_select_pid(struct lsof_context *ctx, uint32_t pid,
+                                int exclude) {
+    enum lsof_error res = lsof_select_pid_pgid(ctx, pid, &Spid, &Mxpid, &Npid,
+                                               &Npidi, &Npidx, exclude, 1);
+    /* Record number of unselected PIDs for optimization */
+    Npuns = Npid;
+    return res;
+}
+
+API_EXPORT
+enum lsof_error lsof_select_pgid(struct lsof_context *ctx, uint32_t pgid,
+                                 int exclude) {
+    return lsof_select_pid_pgid(ctx, pgid, &Spgid, &Mxpgid, &Npgid, &Npgidi,
+                                &Npgidx, exclude, 0);
+}
+
+/* Internal helper for lsof_select_uid/lsof_select_login*/
+enum lsof_error lsof_select_uid_login(struct lsof_context *ctx, uint32_t uid,
+                                      char *login, int exclude) {
+    int i, j;
+    MALLOC_S len;
+    char *lp;
+
+    if (!ctx || ctx->frozen) {
+        return LSOF_ERROR_INVALID_ARGUMENT;
+    }
+
+    /*
+     * Avoid entering duplicates.
+     */
+    for (i = 0; i < Nuid; i++) {
+        if (uid != Suid[i].uid)
+            continue;
+        /* Duplicate */
+        if (Suid[i].excl == exclude) {
+            return LSOF_SUCCESS;
+        }
+
+        /* Conflict */
+        if (ctx->err) {
+            (void)fprintf(ctx->err,
+                          "%s: UID %d has been included and excluded.\n", Pn,
+                          (int)uid);
+        }
+        return LSOF_ERROR_INVALID_ARGUMENT;
+    }
+
+    /*
+     * Allocate space for User IDentifier.
+     */
+    if (Nuid >= Mxuid) {
+        Mxuid += 10;
+        len = (MALLOC_S)(Mxuid * sizeof(struct seluid));
+        if (!Suid)
+            Suid = (struct seluid *)malloc(len);
+        else
+            Suid = (struct seluid *)realloc((MALLOC_P *)Suid, len);
+        if (!Suid) {
+            if (ctx->err) {
+                (void)fprintf(ctx->err, "%s: no space for UIDs", Pn);
+            }
+            Error(ctx);
+            return LSOF_ERROR_NO_MEMORY;
+        }
+    }
+    if (login) {
+        if (!(lp = mkstrcpy(login, (MALLOC_S *)NULL))) {
+            if (ctx->err) {
+                (void)fprintf(ctx->err, "%s: no space for login: ", Pn);
+                safestrprt(login, ctx->err, 1);
+            }
+            Error(ctx);
+            return LSOF_ERROR_NO_MEMORY;
+        }
+        Suid[Nuid].lnm = lp;
+    } else
+        Suid[Nuid].lnm = (char *)NULL;
+    Suid[Nuid].f = 0;
+    Suid[Nuid].uid = uid;
+    Suid[Nuid++].excl = exclude;
+    if (exclude)
+        Nuidexcl++;
+    else {
+        Nuidincl++;
+        Selflags |= SELUID;
+    }
+    return LSOF_SUCCESS;
+}
+
+API_EXPORT
+enum lsof_error lsof_select_uid(struct lsof_context *ctx, uint32_t uid,
+                                int exclude) {
+    return lsof_select_uid_login(ctx, uid, NULL, exclude);
+}
+
+API_EXPORT
+enum lsof_error lsof_select_login(struct lsof_context *ctx, char *login,
+                                  int exclude) {
+    struct passwd *pw;
+    if (!ctx || ctx->frozen) {
+        return LSOF_ERROR_INVALID_ARGUMENT;
+    }
+
+    /* Convert login to uid, then call lsof_select_uid_login */
+    if ((pw = getpwnam(login)) == NULL) {
+        if (ctx->err) {
+            (void)fprintf(ctx->err, "%s: can't get UID for ", Pn);
+            safestrprt(login, ctx->err, 1);
+        }
+        return LSOF_ERROR_INVALID_ARGUMENT;
+    }
+    return lsof_select_uid_login(ctx, pw->pw_uid, login, exclude);
+}
\ No newline at end of file
diff --git a/lib/misc.c b/lib/misc.c
new file mode 100644 (file)
index 0000000..3bf7187
--- /dev/null
@@ -0,0 +1,1606 @@
+/*
+ * misc.c - common miscellaneous functions for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#include "common.h"
+#include "dlsof.h"
+
+#if defined(HASWIDECHAR)
+#    if defined(WIDECHARINCL)
+#        include WIDECHARINCL
+#    endif /* defined(WIDECHARINCL) */
+#    if defined(HASWCTYPE_H)
+#        include <wctype.h>
+#    endif /* defined(HASWCTYPE_H) */
+#endif     /* defined(HASWIDECHAR) */
+
+/*
+ * Local definitions
+ */
+
+#if !defined(MAXSYMLINKS)
+#    define MAXSYMLINKS 32
+#endif /* !defined(MAXSYMLINKS) */
+
+/*
+ * Local function prototypes
+ */
+
+static void closePipes(void);
+static int dolstat(char *path, char *buf, int len);
+static int dostat(char *path, char *buf, int len);
+static int doreadlink(char *path, char *buf, int len);
+static int doinchild(struct lsof_context *ctx, int (*fn)(), char *fp,
+                     char *rbuf, int rbln);
+
+#if defined(HASINTSIGNAL)
+static int handleint(int sig);
+#else  /* !defined(HASINTSIGNAL) */
+static void handleint(int sig);
+#endif /* defined(HASINTSIGNAL) */
+
+/*
+ * Local variables
+ */
+
+static pid_t Cpid = 0;  /* child PID */
+static jmp_buf Jmp_buf; /* jump buffer */
+static int Pipes[] =    /* pipes for child process */
+    {-1, -1, -1, -1};
+static int CtSigs[] = {0, SIGINT, SIGKILL};
+/* child termination signals (in order
+ * of application) -- the first is a
+ * dummy to allow pipe closure to
+ * cause the child to exit */
+#define NCTSIGS (sizeof(CtSigs) / sizeof(int))
+
+#if defined(HASNLIST)
+/*
+ * build-Nl() - build kernel name list table
+ */
+
+static struct drive_Nl *Build_Nl = (struct drive_Nl *)NULL;
+/* the default Drive_Nl address */
+
+void build_Nl(struct lsof_context *ctx,
+              struct drive_Nl *d) /* data to drive the construction */
+{
+    struct drive_Nl *dp;
+    int i, n;
+
+    for (dp = d, n = 0; dp->nn; dp++, n++)
+        ;
+    if (n < 1) {
+        (void)fprintf(stderr, "%s: can't calculate kernel name list length\n",
+                      Pn);
+        Error(ctx);
+    }
+    if (!(Nl = (struct NLIST_TYPE *)calloc((n + 1),
+                                           sizeof(struct NLIST_TYPE)))) {
+        (void)fprintf(
+            stderr,
+            "%s: can't allocate %d bytes to kernel name list structure\n", Pn,
+            (int)((n + 1) * sizeof(struct NLIST_TYPE)));
+        Error(ctx);
+    }
+    for (dp = d, i = 0; i < n; dp++, i++) {
+        Nl[i].NL_NAME = dp->knm;
+    }
+    Nll = (int)((n + 1) * sizeof(struct NLIST_TYPE));
+    Build_Nl = d;
+}
+#endif /* defined(HASNLIST) */
+
+/*
+ * childx() - make child process exit (if possible)
+ */
+
+void childx(struct lsof_context *ctx) {
+    static int at, sx;
+    pid_t wpid;
+
+    if (Cpid > 1) {
+
+        /*
+         * First close the pipes to and from the child.  That should cause the
+         * child to exit.  Compute alarm time shares.
+         */
+        (void)closePipes();
+        if ((at = TmLimit / NCTSIGS) < TMLIMMIN)
+            at = TMLIMMIN;
+        /*
+         * Loop, waiting for the child to exit.  After the first pass, help
+         * the child exit by sending it signals.
+         */
+        for (sx = 0; sx < NCTSIGS; sx++) {
+            if (setjmp(Jmp_buf)) {
+
+                /*
+                 * An alarm has rung.  Disable further alarms.
+                 *
+                 * If there are more signals to send, continue the signal loop.
+                 *
+                 * If the last signal has been sent, issue a warning (unless
+                 * warninge have been suppressed) and exit the signal loop.
+                 */
+                (void)alarm(0);
+                (void)signal(SIGALRM, SIG_DFL);
+                if (sx < (NCTSIGS - 1))
+                    continue;
+                if (!Fwarn)
+                    (void)fprintf(
+                        stderr,
+                        "%s: WARNING -- child process %d may be hung.\n", Pn,
+                        (int)Cpid);
+                break;
+            }
+            /*
+             * Send the next signal to the child process, after the first pass
+             * through the loop.
+             *
+             * Wrap the wait() with an alarm.
+             */
+            if (sx)
+                (void)kill(Cpid, CtSigs[sx]);
+            (void)signal(SIGALRM, handleint);
+            (void)alarm(at);
+            wpid = (pid_t)wait(NULL);
+            (void)alarm(0);
+            (void)signal(SIGALRM, SIG_DFL);
+            if (wpid == Cpid)
+                break;
+        }
+        Cpid = 0;
+    }
+}
+
+/*
+ * closePipes() - close open pipe file descriptors
+ */
+
+static void closePipes() {
+    int i;
+
+    for (i = 0; i < 4; i++) {
+        if (Pipes[i] >= 0) {
+            (void)close(Pipes[i]);
+            Pipes[i] = -1;
+        }
+    }
+}
+
+/*
+ * compdev() - compare Devtp[] entries
+ */
+
+int compdev(COMP_P *a1, COMP_P *a2) {
+    struct l_dev **p1 = (struct l_dev **)a1;
+    struct l_dev **p2 = (struct l_dev **)a2;
+
+    if ((dev_t)((*p1)->rdev) < (dev_t)((*p2)->rdev))
+        return (-1);
+    if ((dev_t)((*p1)->rdev) > (dev_t)((*p2)->rdev))
+        return (1);
+    if ((INODETYPE)((*p1)->inode) < (INODETYPE)((*p2)->inode))
+        return (-1);
+    if ((INODETYPE)((*p1)->inode) > (INODETYPE)((*p2)->inode))
+        return (1);
+    return (strcmp((*p1)->name, (*p2)->name));
+}
+
+/*
+ * closefrom_shim() -- provide closefrom() when unavailable
+ */
+void closefrom_shim(struct lsof_context *ctx, int low) {
+    int i;
+#if defined(HAS_CLOSEFROM)
+    (void)closefrom(low);
+#else /* !defined(HAS_CLOSEFROM) */
+    /* fallback to SYS_close_range */
+#    if defined(SYS_close_range)
+    if (MaxFd > low && syscall(SYS_close_range, low, MaxFd - 1, 0) == 0)
+        return;
+#    endif
+    /* slow fallback */
+    for (i = low; i < MaxFd; i++)
+        (void)close(i);
+#endif /* !defined(HAS_CLOSEFROM) */
+}
+
+/*
+ * doinchild() -- do a function in a child process
+ */
+
+static int doinchild(struct lsof_context *ctx,
+                     int (*fn)(), /* function to perform */
+                     char *fp,    /* function parameter */
+                     char *rbuf,  /* response buffer */
+                     int rbln)    /* response buffer length */
+{
+    int en, rv;
+
+    /*
+     * Check reply buffer size.
+     */
+    if (!Fovhd && rbln > MAXPATHLEN) {
+        (void)fprintf(stderr,
+                      "%s: doinchild error; response buffer too large: %d\n",
+                      Pn, rbln);
+        Error(ctx);
+    }
+    /*
+     * Set up to handle an alarm signal; handle an alarm signal; build
+     * pipes for exchanging information with a child process; start the
+     * child process; and perform functions in the child process.
+     */
+    if (!Fovhd) {
+        if (setjmp(Jmp_buf)) {
+
+            /*
+             * Process an alarm that has rung.
+             */
+            (void)alarm(0);
+            (void)signal(SIGALRM, SIG_DFL);
+            (void)childx(ctx);
+            errno = ETIMEDOUT;
+            return (1);
+        } else if (!Cpid) {
+
+            /*
+             * Create pipes to exchange function information with a child
+             * process.
+             */
+            if (pipe(Pipes) < 0 || pipe(&Pipes[2]) < 0) {
+                (void)fprintf(stderr, "%s: can't open pipes: %s\n", Pn,
+                              strerror(errno));
+                Error(ctx);
+            }
+            /*
+             * Fork a child to execute functions.
+             */
+            if ((Cpid = fork()) == 0) {
+
+                /*
+                 * Begin the child process.
+                 */
+
+                int r_al, r_rbln;
+                char r_arg[MAXPATHLEN + 1];
+                union {
+                    char r_rbuf[MAXPATHLEN + 1];
+                    /*
+                     * This field is only for adjusting the alignment of r_rbuf
+                     * that can be used as an argument for stat().
+                     */
+                    struct stat _;
+                } r;
+                int (*r_fn)();
+                /*
+                 * Close sufficient open file descriptors except Pipes[0] and
+                 * Pipes[3].
+                 */
+
+#if defined(HAS_DUP2)
+                int rc;
+
+                rc = dup2(Pipes[0], 0);
+                if (rc < 0) {
+                    (void)fprintf(stderr,
+                                  "%s: can't dup Pipes[0] to fd 0: %s\n", Pn,
+                                  strerror(errno));
+                    Error(ctx);
+                }
+                Pipes[0] = 0;
+                rc = dup2(Pipes[3], 1);
+                if (rc < 0) {
+                    (void)fprintf(stderr,
+                                  "%s: can't dup Pipes.[3] to fd 1: %s\n", Pn,
+                                  strerror(errno));
+                    Error(ctx);
+                }
+                Pipes[3] = 1;
+                (void)closefrom_shim(ctx, 2);
+                Pipes[1] = -1;
+                Pipes[2] = -1;
+
+#else  /* !defined(HAS_DUP2) */
+                int fd;
+
+                for (fd = 0; fd < MaxFd; fd++) {
+                    if (fd == Pipes[0] || fd == Pipes[3])
+                        continue;
+                    (void)close(fd);
+                    if (fd == Pipes[1])
+                        Pipes[1] = -1;
+                    else if (fd == Pipes[2])
+                        Pipes[2] = -1;
+                }
+                if (Pipes[1] >= 0) {
+                    (void)close(Pipes[1]);
+                    Pipes[1] = -1;
+                }
+                if (Pipes[2] >= 0) {
+                    (void)close(Pipes[2]);
+                    Pipes[2] = -1;
+                }
+#endif /* defined(HAS_DUP2) */
+
+                /*
+                 * Read function requests, process them, and return replies.
+                 */
+                for (;;) {
+                    if (read(Pipes[0], (char *)&r_fn, sizeof(r_fn)) !=
+                            (int)sizeof(r_fn) ||
+                        read(Pipes[0], (char *)&r_al, sizeof(int)) !=
+                            (int)sizeof(int) ||
+                        r_al < 1 || r_al > (int)sizeof(r_arg) ||
+                        read(Pipes[0], r_arg, r_al) != r_al ||
+                        read(Pipes[0], (char *)&r_rbln, sizeof(r_rbln)) !=
+                            (int)sizeof(r_rbln) ||
+                        r_rbln < 1 || r_rbln > (int)sizeof(r.r_rbuf))
+                        break;
+                    zeromem(r.r_rbuf, r_rbln);
+                    rv = r_fn(r_arg, r.r_rbuf, r_rbln);
+                    en = errno;
+                    if (write(Pipes[3], (char *)&rv, sizeof(rv)) !=
+                            sizeof(rv) ||
+                        write(Pipes[3], (char *)&en, sizeof(en)) !=
+                            sizeof(en) ||
+                        write(Pipes[3], r.r_rbuf, r_rbln) != r_rbln)
+                        break;
+                }
+                (void)_exit(0);
+            }
+            /*
+             * Continue in the parent process to finish the setup.
+             */
+            if (Cpid < 0) {
+                (void)fprintf(stderr, "%s: can't fork: %s\n", Pn,
+                              strerror(errno));
+                Error(ctx);
+            }
+            (void)close(Pipes[0]);
+            (void)close(Pipes[3]);
+            Pipes[0] = Pipes[3] = -1;
+        }
+    }
+    if (!Fovhd) {
+        int len;
+
+        /*
+         * Send a function to the child and wait for the response.
+         */
+        len = strlen(fp) + 1;
+        (void)signal(SIGALRM, handleint);
+        (void)alarm(TmLimit);
+        if (write(Pipes[1], (char *)&fn, sizeof(fn)) != sizeof(fn) ||
+            write(Pipes[1], (char *)&len, sizeof(len)) != sizeof(len) ||
+            write(Pipes[1], fp, len) != len ||
+            write(Pipes[1], (char *)&rbln, sizeof(rbln)) != sizeof(rbln) ||
+            read(Pipes[2], (char *)&rv, sizeof(rv)) != sizeof(rv) ||
+            read(Pipes[2], (char *)&en, sizeof(en)) != sizeof(en) ||
+            read(Pipes[2], rbuf, rbln) != rbln) {
+            (void)alarm(0);
+            (void)signal(SIGALRM, SIG_DFL);
+            (void)childx(ctx);
+            errno = ECHILD;
+            return (-1);
+        }
+    } else {
+
+        /*
+         * Do the operation directly -- not in a child.
+         */
+        (void)signal(SIGALRM, handleint);
+        (void)alarm(TmLimit);
+        rv = fn(fp, rbuf, rbln);
+        en = errno;
+    }
+    /*
+     * Function completed, response collected -- complete the operation.
+     */
+    (void)alarm(0);
+    (void)signal(SIGALRM, SIG_DFL);
+    errno = en;
+    return (rv);
+}
+
+/*
+ * dolstat() - do an lstat() function
+ */
+
+static int dolstat(char *path, /* path */
+                   char *rbuf, /* response buffer */
+                   int rbln)   /* response buffer length */
+
+/* ARGSUSED */
+
+{
+    return (lstat(path, (struct stat *)rbuf));
+}
+
+/*
+ * doreadlink() -- do a readlink() function
+ */
+
+static int doreadlink(char *path, /* path */
+                      char *rbuf, /* response buffer */
+                      int rbln)   /* response buffer length */
+{
+    return (readlink(path, rbuf, rbln));
+}
+
+/*
+ * dostat() - do a stat() function
+ */
+
+static int dostat(char *path, /* path */
+                  char *rbuf, /* response buffer */
+                  int rbln)   /* response buffer length */
+
+/* ARGSUSED */
+
+{
+    return (stat(path, (struct stat *)rbuf));
+}
+
+#if defined(WILLDROPGID)
+/*
+ * dropgid() - drop setgid permission
+ */
+
+void dropgid(struct lsof_context *ctx) {
+    if (!Setuidroot && Setgid) {
+        if (setgid(Mygid) < 0) {
+            (void)fprintf(stderr, "%s: can't setgid(%d): %s\n", Pn, (int)Mygid,
+                          strerror(errno));
+            Error(ctx);
+        }
+        Setgid = 0;
+    }
+}
+#endif /* defined(WILLDROPGID) */
+
+/*
+ * enter_dev_ch() - enter device characters in file structure
+ */
+
+void enter_dev_ch(struct lsof_context *ctx, char *m) {
+    char *mp;
+
+    if (!m || *m == '\0')
+        return;
+    if (!(mp = mkstrcpy(m, (MALLOC_S *)NULL))) {
+        (void)fprintf(stderr, "%s: no more dev_ch space at PID %d: \n", Pn,
+                      Lp->pid);
+        safestrprt(m, stderr, 1);
+        Error(ctx);
+    }
+    if (Lf->dev_ch)
+        (void)free((FREE_P *)Lf->dev_ch);
+    Lf->dev_ch = mp;
+}
+
+/*
+ * enter_IPstate() -- enter a TCP or UDP state
+ */
+
+void enter_IPstate(struct lsof_context *ctx, char *ty, /* type -- TCP or UDP */
+                   char *nm, /* state name (may be NULL) */
+                   int nr)   /* state number */
+{
+
+#if defined(USE_LIB_PRINT_TCPTPI)
+    TcpNstates = nr;
+#else  /* !defined(USE_LIB_PRINT_TCPTPI) */
+
+    int al, i, j, oc, nn, ns, off, tx;
+    char *cp;
+    MALLOC_S len;
+    /*
+     * Check the type name and set the type index.
+     */
+    if (!ty) {
+        (void)fprintf(stderr, "%s: no type specified to enter_IPstate()\n", Pn);
+        Error(ctx);
+    }
+    if (!strcmp(ty, "TCP"))
+        tx = 0;
+    else if (!strcmp(ty, "UDP"))
+        tx = 1;
+    else {
+        (void)fprintf(stderr, "%s: unknown type for enter_IPstate: %s\n", Pn,
+                      ty);
+        Error(ctx);
+    }
+    /*
+     * If the name argument is NULL, reduce the allocated table to its minimum
+     * size.
+     */
+    if (!nm) {
+        if (tx) {
+            if (UdpSt) {
+                if (!UdpNstates) {
+                    (void)free((MALLOC_P *)UdpSt);
+                    UdpSt = (char **)NULL;
+                }
+                if (UdpNstates < UdpStAlloc) {
+                    len = (MALLOC_S)(UdpNstates * sizeof(char *));
+                    if (!(UdpSt = (char **)realloc((MALLOC_P *)UdpSt, len))) {
+                        (void)fprintf(stderr, "%s: can't reduce UdpSt[]\n", Pn);
+                        Error(ctx);
+                    }
+                }
+                UdpStAlloc = UdpNstates;
+            }
+        } else {
+            if (TcpSt) {
+                if (!TcpNstates) {
+                    (void)free((MALLOC_P *)TcpSt);
+                    TcpSt = (char **)NULL;
+                }
+                if (TcpNstates < TcpStAlloc) {
+                    len = (MALLOC_S)(TcpNstates * sizeof(char *));
+                    if (!(TcpSt = (char **)realloc((MALLOC_P *)TcpSt, len))) {
+                        (void)fprintf(stderr, "%s: can't reduce TcpSt[]\n", Pn);
+                        Error(ctx);
+                    }
+                }
+                TcpStAlloc = TcpNstates;
+            }
+        }
+        return;
+    }
+    /*
+     * Check the name and number.
+     */
+    if (strlen(nm) < 1) {
+        (void)fprintf(stderr, "%s: bad %s name (\"%s\"), number=%d\n", Pn, ty,
+                      nm, nr);
+        Error(ctx);
+    }
+    /*
+     * Make a copy of the name.
+     */
+    if (!(cp = mkstrcpy(nm, (MALLOC_S *)NULL))) {
+        (void)fprintf(stderr, "%s: enter_IPstate(): no %s space for %s\n", Pn,
+                      ty, nm);
+        Error(ctx);
+    }
+    /*
+     * Set the necessary offset for using nr as an index.  If it is
+     * a new offset, adjust previous entries.
+     */
+    if ((nr < 0) && ((off = -nr) > (tx ? UdpStOff : TcpStOff))) {
+        if (tx ? UdpSt : TcpSt) {
+
+            /*
+             * A new, larger offset (smaller negative state number) could mean
+             * a previously allocated state table must be enlarged and its
+             * previous entries moved.
+             */
+            oc = off - (tx ? UdpStOff : TcpStOff);
+            al = tx ? UdpStAlloc : TcpStAlloc;
+            ns = tx ? UdpNstates : TcpNstates;
+            if ((nn = ns + oc) >= al) {
+                while ((nn + 5) > al) {
+                    al += TCPUDPALLOC;
+                }
+                len = (MALLOC_S)(al * sizeof(char *));
+                if (tx) {
+                    if (!(UdpSt = (char **)realloc((MALLOC_P *)UdpSt, len)))
+                        goto no_IP_space;
+                    UdpStAlloc = al;
+                } else {
+                    if (!(TcpSt = (char **)realloc((MALLOC_P *)TcpSt, len)))
+                        goto no_IP_space;
+                    TcpStAlloc = al;
+                }
+                for (i = 0, j = oc; i < oc; i++, j++) {
+                    if (tx) {
+                        if (i < UdpNstates)
+                            UdpSt[j] = UdpSt[i];
+                        UdpSt[i] = (char *)NULL;
+                    } else {
+                        if (i < TcpNstates)
+                            TcpSt[j] = TcpSt[i];
+                        TcpSt[i] = (char *)NULL;
+                    }
+                }
+                if (tx)
+                    UdpNstates += oc;
+                else
+                    TcpNstates += oc;
+            }
+        }
+        if (tx)
+            UdpStOff = off;
+        else
+            TcpStOff = off;
+    }
+    /*
+     * Enter name as {Tc|Ud}pSt[nr + {Tc|Ud}pStOff].
+     *
+     * Allocate space, as required.
+     */
+    al = tx ? UdpStAlloc : TcpStAlloc;
+    off = tx ? UdpStOff : TcpStOff;
+    nn = nr + off + 1;
+    if (nn > al) {
+        i = tx ? UdpNstates : TcpNstates;
+        while ((nn + 5) > al) {
+            al += TCPUDPALLOC;
+        }
+        len = (MALLOC_S)(al * sizeof(char *));
+        if (tx) {
+            if (UdpSt)
+                UdpSt = (char **)realloc((MALLOC_P *)UdpSt, len);
+            else
+                UdpSt = (char **)malloc(len);
+            if (!UdpSt) {
+
+            no_IP_space:
+
+                (void)fprintf(stderr, "%s: no %s state space\n", Pn, ty);
+                Error(ctx);
+            }
+            UdpNstates = nn;
+            UdpStAlloc = al;
+        } else {
+            if (TcpSt)
+                TcpSt = (char **)realloc((MALLOC_P *)TcpSt, len);
+            else
+                TcpSt = (char **)malloc(len);
+            if (!TcpSt)
+                goto no_IP_space;
+            TcpNstates = nn;
+            TcpStAlloc = al;
+        }
+        while (i < al) {
+            if (tx)
+                UdpSt[i] = (char *)NULL;
+            else
+                TcpSt[i] = (char *)NULL;
+            i++;
+        }
+    } else {
+        if (tx) {
+            if (nn > UdpNstates)
+                UdpNstates = nn;
+        } else {
+            if (nn > TcpNstates)
+                TcpNstates = nn;
+        }
+    }
+    if (tx) {
+        if (UdpSt[nr + UdpStOff]) {
+
+        dup_IP_state:
+
+            (void)fprintf(
+                stderr, "%s: duplicate %s state %d (already %s): %s\n", Pn, ty,
+                nr, tx ? UdpSt[nr + UdpStOff] : TcpSt[nr + TcpStOff], nm);
+            Error(ctx);
+        }
+        UdpSt[nr + UdpStOff] = cp;
+    } else {
+        if (TcpSt[nr + TcpStOff])
+            goto dup_IP_state;
+        TcpSt[nr + TcpStOff] = cp;
+    }
+#endif /* defined(USE_LIB_PRINT_TCPTPI) */
+}
+
+/*
+ * enter_nm() - enter name in local file structure
+ */
+
+void enter_nm(struct lsof_context *ctx, char *m) {
+    char *mp;
+
+    if (!m || *m == '\0')
+        return;
+    if (!(mp = mkstrcpy(m, (MALLOC_S *)NULL))) {
+        (void)fprintf(stderr, "%s: no more nm space at PID %d for: ", Pn,
+                      Lp->pid);
+        safestrprt(m, stderr, 1);
+        Error(ctx);
+    }
+    if (Lf->nm)
+        (void)free((FREE_P *)Lf->nm);
+    Lf->nm = mp;
+}
+
+/*
+ * Exit() - do a clean exit()
+ */
+
+void Exit(struct lsof_context *ctx, enum ExitStatus xv) /* exit() value */
+{
+    (void)childx(ctx);
+
+#if defined(HASDCACHE)
+    if (DCrebuilt && !Fwarn)
+        (void)fprintf(stderr, "%s: WARNING: %s was updated.\n", Pn,
+                      DCpath[DCpathX]);
+#endif /* defined(HASDCACHE) */
+
+    exit(xv);
+}
+
+/*
+ * Error() - exit with an error status
+ */
+void Error(struct lsof_context *ctx) { Exit(ctx, LSOF_EXIT_ERROR); }
+
+#if defined(HASNLIST)
+/*
+ * get_Nl_value() - get Nl value for nickname
+ */
+
+int get_Nl_value(struct lsof_context *ctx, /* context */
+                 char *nn,                 /* nickname of requested entry */
+                 struct drive_Nl *d,       /* drive_Nl table that built Nl
+                                            * (if NULL, use Build_Nl) */
+                 KA_T *v)                  /* returned value (if NULL,
+                                            * return nothing) */
+{
+    int i;
+
+    if (!Nl || !Nll)
+        return (-1);
+    if (!d)
+        d = Build_Nl;
+    for (i = 0; d->nn; d++, i++) {
+        if (strcmp(d->nn, nn) == 0) {
+            if (v)
+                *v = (KA_T)Nl[i].n_value;
+            return (i);
+        }
+    }
+    return (-1);
+}
+#endif /* defined(HASNLIST) */
+
+/*
+ * handleint() - handle an interrupt
+ */
+
+#if defined(HASINTSIGNAL)
+static int
+#else
+static void
+#endif
+
+/* ARGSUSED */
+
+handleint(int sig) {
+    longjmp(Jmp_buf, 1);
+}
+
+/*
+ * hashbyname() - hash by name
+ */
+
+int hashbyname(char *nm, /* pointer to NUL-terminated name */
+               int mod)  /* hash modulus */
+{
+    int i, j;
+
+    for (i = j = 0; *nm; nm++) {
+        i ^= (int)*nm << j;
+        if (++j > 7)
+            j = 0;
+    }
+    return (((int)(i * 31415)) & (mod - 1));
+}
+
+/*
+ * is_nw_addr() - is this network address selected?
+ */
+
+int is_nw_addr(struct lsof_context *ctx, /* context */
+               unsigned char *ia,        /* Internet address */
+               int p,                    /* port */
+               int af)                   /* address family -- e.g., AF_INET,
+                                          * AF_INET6 */
+{
+    struct nwad *n;
+
+    if (!(n = Nwad))
+        return (0);
+    for (; n; n = n->next) {
+        if (n->proto) {
+            if (strcasecmp(n->proto, Lf->iproto) != 0)
+                continue;
+        }
+        if (af && n->af && af != n->af)
+            continue;
+
+#if defined(HASIPv6)
+        if (af == AF_INET6) {
+            if (n->a[15] || n->a[14] || n->a[13] || n->a[12] || n->a[11] ||
+                n->a[10] || n->a[9] || n->a[8] || n->a[7] || n->a[6] ||
+                n->a[5] || n->a[4] || n->a[3] || n->a[2] || n->a[1] ||
+                n->a[0]) {
+                if (ia[15] != n->a[15] || ia[14] != n->a[14] ||
+                    ia[13] != n->a[13] || ia[12] != n->a[12] ||
+                    ia[11] != n->a[11] || ia[10] != n->a[10] ||
+                    ia[9] != n->a[9] || ia[8] != n->a[8] || ia[7] != n->a[7] ||
+                    ia[6] != n->a[6] || ia[5] != n->a[5] || ia[4] != n->a[4] ||
+                    ia[3] != n->a[3] || ia[2] != n->a[2] || ia[1] != n->a[1] ||
+                    ia[0] != n->a[0])
+                    continue;
+            }
+        } else if (af == AF_INET)
+#endif /* defined(HASIPv6) */
+
+        {
+            if (n->a[3] || n->a[2] || n->a[1] || n->a[0]) {
+                if (ia[3] != n->a[3] || ia[2] != n->a[2] || ia[1] != n->a[1] ||
+                    ia[0] != n->a[0])
+                    continue;
+            }
+        }
+
+#if defined(HASIPv6)
+        else
+            continue;
+#endif /* defined(HASIPv6) */
+
+        if (n->sport == -1 || (p >= n->sport && p <= n->eport)) {
+            n->f = 1;
+            return (1);
+        }
+    }
+    return (0);
+}
+
+/*
+ * mkstrcpy() - make a string copy in malloc()'d space
+ *
+ * return: copy pointer
+ *        copy length (optional)
+ */
+
+char *mkstrcpy(char *src,     /* source */
+               MALLOC_S *rlp) /* returned length pointer (optional)
+                               * The returned length is an strlen()
+                               * equivalent */
+{
+    MALLOC_S len;
+    char *ns;
+
+    len = (MALLOC_S)(src ? strlen(src) : 0);
+    ns = (char *)malloc(len + 1);
+    if (ns) {
+        if (src)
+            (void)snpf(ns, len + 1, "%s", src);
+        else
+            *ns = '\0';
+    }
+    if (rlp)
+        *rlp = len;
+    return (ns);
+}
+
+/*
+ * mkstrcat() - make a catenated copy of up to three strings under optional
+ *             string-by-string count control
+ *
+ * return: copy pointer
+ *        copy string length (optional)
+ */
+
+char *mkstrcat(char *s1,      /* source string 1 */
+               int l1,        /* length of string 1 (-1 if none) */
+               char *s2,      /* source string 2 */
+               int l2,        /* length of string 2 (-1 if none) */
+               char *s3,      /* source string 3 (optional) */
+               int l3,        /* length of string 3 (-1 if none) */
+               MALLOC_S *clp) /* pointer to return of copy length
+                               * (optional) */
+{
+    MALLOC_S cl, len1, len2, len3;
+    char *cp;
+
+    if (s1)
+        len1 = (MALLOC_S)((l1 >= 0) ? l1 : strlen(s1));
+    else
+        len1 = (MALLOC_S)0;
+    if (s2)
+        len2 = (MALLOC_S)((l2 >= 0) ? l2 : strlen(s2));
+    else
+        len2 = (MALLOC_S)0;
+    if (s3)
+        len3 = (MALLOC_S)((l3 >= 0) ? l3 : strlen(s3));
+    else
+        len3 = (MALLOC_S)0;
+    cl = len1 + len2 + len3;
+    if ((cp = (char *)malloc(cl + 1))) {
+        char *tp = cp;
+
+        if (s1 && len1) {
+            (void)strncpy(tp, s1, len1);
+            tp += len1;
+        }
+        if (s2 && len2) {
+            (void)strncpy(tp, s2, len2);
+            tp += len2;
+        }
+        if (s3 && len3) {
+            (void)strncpy(tp, s3, len3);
+            tp += len3;
+        }
+        *tp = '\0';
+    }
+    if (clp)
+        *clp = cl;
+    return (cp);
+}
+
+/*
+ * is_readable() -- is file readable
+ */
+
+int is_readable(struct lsof_context *ctx, /* context */
+                char *path,               /* file path */
+                int msg)                  /* issue warning message if 1 */
+{
+    if (access(path, R_OK) < 0) {
+        if (!Fwarn && msg == 1)
+            (void)fprintf(stderr, ACCESSERRFMT, Pn, path, strerror(errno));
+        return (0);
+    }
+    return (1);
+}
+
+/*
+ * lstatsafely() - lstat path safely (i. e., with timeout)
+ */
+
+int lstatsafely(struct lsof_context *ctx, char *path, /* file path */
+                struct stat *buf)                     /* stat buffer address */
+{
+    if (Fblock) {
+        if (!Fwarn)
+            (void)fprintf(stderr, "%s: avoiding stat(%s): -b was specified.\n",
+                          Pn, path);
+        errno = EWOULDBLOCK;
+        return (1);
+    }
+    return (doinchild(ctx, dolstat, path, (char *)buf, sizeof(struct stat)));
+}
+
+/*
+ * Readlink() - read and interpret file system symbolic links
+ */
+
+char *Readlink(struct lsof_context *ctx,
+               char *arg) /* argument to be interpreted */
+{
+    char abuf[MAXPATHLEN + 1];
+    int alen;
+    char *ap;
+    char *argp1, *argp2;
+    int i, len, llen, slen;
+    char lbuf[MAXPATHLEN + 1];
+    static char *op = (char *)NULL;
+    static int ss = 0;
+    char *s1;
+    static char **stk = (char **)NULL;
+    static int sx = 0;
+    char tbuf[MAXPATHLEN + 1];
+    /*
+     * See if avoiding kernel blocks.
+     */
+    if (Fblock) {
+        if (!Fwarn) {
+            (void)fprintf(stderr, "%s: avoiding readlink(", Pn);
+            safestrprt(arg, stderr, 0);
+            (void)fprintf(stderr, "): -b was specified.\n");
+        }
+        op = (char *)NULL;
+        return mkstrcpy(arg, NULL);
+    }
+    /*
+     * Save the original path.
+     */
+    if (!op)
+        op = arg;
+    /*
+     * Evaluate each component of the argument for a symbolic link.
+     */
+    for (alen = 0, ap = abuf, argp1 = argp2 = arg; *argp2; argp1 = argp2) {
+        for (argp2 = argp1 + 1; *argp2 && *argp2 != '/'; argp2++)
+            ;
+        if ((len = argp2 - arg) >= (int)sizeof(tbuf)) {
+
+        path_too_long:
+            if (!Fwarn) {
+                (void)fprintf(stderr, "%s: readlink() path too long: ", Pn);
+                safestrprt(op ? op : arg, stderr, 1);
+            }
+            op = (char *)NULL;
+            return ((char *)NULL);
+        }
+        (void)strncpy(tbuf, arg, len);
+        tbuf[len] = '\0';
+        /*
+         * Dereference a symbolic link.
+         */
+        if ((llen = doinchild(ctx, doreadlink, tbuf, lbuf, sizeof(lbuf) - 1)) >=
+            0) {
+
+            /*
+             * If the link is a new absolute path, replace
+             * the previous assembly with it.
+             */
+            if (lbuf[0] == '/') {
+                (void)strncpy(abuf, lbuf, llen);
+                ap = &abuf[llen];
+                *ap = '\0';
+                alen = llen;
+                continue;
+            }
+            lbuf[llen] = '\0';
+            s1 = lbuf;
+        } else {
+            llen = argp2 - argp1;
+            s1 = argp1;
+        }
+        /*
+         * Make sure two components are separated by a `/'.
+         *
+         * If the first component is not a link, don't force
+         * a leading '/'.
+         *
+         * If the first component is a link and the source of
+         * the link has a leading '/', force a leading '/'.
+         */
+        if (*s1 == '/')
+            slen = 1;
+        else {
+            if (alen > 0) {
+
+                /*
+                 * This is not the first component.
+                 */
+                if (abuf[alen - 1] == '/')
+                    slen = 1;
+                else
+                    slen = 2;
+            } else {
+
+                /*
+                 * This is the first component.
+                 */
+                if (s1 == lbuf && tbuf[0] == '/')
+                    slen = 2;
+                else
+                    slen = 1;
+            }
+        }
+        /*
+         * Add to the path assembly.
+         */
+        if ((alen + llen + slen) >= (int)sizeof(abuf))
+            goto path_too_long;
+        if (slen == 2)
+            *ap++ = '/';
+        (void)strncpy(ap, s1, llen);
+        ap += llen;
+        *ap = '\0';
+        alen += (llen + slen - 1);
+    }
+    /*
+     * If the assembled path and argument are the same, free all but the
+     * last string in the stack, and return the argument.
+     */
+    if (strcmp(arg, abuf) == 0) {
+        for (i = 0; i < sx; i++) {
+            if (i < (sx - 1))
+                (void)free((FREE_P *)stk[i]);
+            stk[i] = (char *)NULL;
+        }
+        sx = 0;
+        op = (char *)NULL;
+        return mkstrcpy(arg, NULL);
+    }
+    /*
+     * If the assembled path and argument are different, add it to the
+     * string stack, then Readlink() it.
+     */
+    if (!(s1 = mkstrcpy(abuf, (MALLOC_S *)NULL))) {
+
+    no_readlink_space:
+
+        (void)fprintf(stderr, "%s: no Readlink string space for ", Pn);
+        safestrprt(abuf, stderr, 1);
+        Error(ctx);
+    }
+    if (sx >= MAXSYMLINKS) {
+
+        /*
+         * If there are too many symbolic links, report an error, clear
+         * the stack, and return no path.
+         */
+        if (!Fwarn) {
+            (void)fprintf(
+                stderr,
+                "%s: too many (> %d) symbolic links in readlink() path: ", Pn,
+                MAXSYMLINKS);
+            safestrprt(op ? op : arg, stderr, 1);
+        }
+        for (i = 0; i < sx; i++) {
+            (void)free((FREE_P *)stk[i]);
+            stk[i] = (char *)NULL;
+        }
+        (void)free((FREE_P *)stk);
+        (void)free((FREE_P *)s1);
+        stk = (char **)NULL;
+        ss = sx = 0;
+        s1 = (char *)NULL;
+        op = (char *)NULL;
+        return ((char *)NULL);
+    }
+    if (++sx > ss) {
+        if (!stk)
+            stk = (char **)malloc((MALLOC_S)(sizeof(char *) * sx));
+        else
+            stk = (char **)realloc((MALLOC_P *)stk,
+                                   (MALLOC_S)(sizeof(char *) * sx));
+        if (!stk)
+            goto no_readlink_space;
+        ss = sx;
+    }
+    stk[sx - 1] = s1;
+    return (Readlink(ctx, s1));
+}
+
+#if defined(HASSTREAMS)
+/*
+ * readstdata() - read stream's stdata structure
+ */
+
+int readstdata(struct lsof_context *ctx, /* context */
+               KA_T addr,                /* stdata address in kernel*/
+               struct stdata *buf)       /* buffer addess */
+{
+    if (!addr || kread(ctx, addr, (char *)buf, sizeof(struct stdata))) {
+        (void)snpf(Namech, Namechl, "no stream data in %s",
+                   print_kptr(addr, (char *)NULL, 0));
+        return (1);
+    }
+    return (0);
+}
+
+/*
+ * readsthead() - read stream head
+ */
+
+int readsthead(struct lsof_context *ctx, /* context */
+               KA_T addr,                /* starting queue pointer in kernel */
+               struct queue *buf)        /* buffer for queue head */
+{
+    KA_T qp;
+
+    if (!addr) {
+        (void)snpf(Namech, Namechl, "no stream queue head");
+        return (1);
+    }
+    for (qp = addr; qp; qp = (KA_T)buf->q_next) {
+        if (kread(ctx, qp, (char *)buf, sizeof(struct queue))) {
+            (void)snpf(Namech, Namechl, "bad stream queue link at %s",
+                       print_kptr(qp, (char *)NULL, 0));
+            return (1);
+        }
+    }
+    return (0);
+}
+
+/*
+ * readstidnm() - read stream module ID name
+ */
+
+int readstidnm(struct lsof_context *ctx, /* context */
+               KA_T addr,                /* module ID name address in kernel */
+               char *buf,                /* receiving buffer address */
+               READLEN_T len)            /* buffer length */
+{
+    if (!addr || kread(ctx, addr, buf, len)) {
+        (void)snpf(Namech, Namechl, "can't read module ID name from %s",
+                   print_kptr(addr, (char *)NULL, 0));
+        return (1);
+    }
+    return (0);
+}
+
+/*
+ * readstmin() - read stream's module info
+ */
+
+int readstmin(struct lsof_context *ctx, /* context */
+              KA_T addr,                /* module info address in kernel */
+              struct module_info *buf)  /* receiving buffer address */
+{
+    if (!addr || kread(ctx, addr, (char *)buf, sizeof(struct module_info))) {
+        (void)snpf(Namech, Namechl, "can't read module info from %s",
+                   print_kptr(addr, (char *)NULL, 0));
+        return (1);
+    }
+    return (0);
+}
+
+/*
+ * readstqinit() - read stream's queue information structure
+ */
+
+int readstqinit(struct lsof_context *ctx, /* context */
+                KA_T addr,                /* queue info address in kernel */
+                struct qinit *buf)        /* receiving buffer address */
+{
+    if (!addr || kread(ctx, addr, (char *)buf, sizeof(struct qinit))) {
+        (void)snpf(Namech, Namechl, "can't read queue info from %s",
+                   print_kptr(addr, (char *)NULL, 0));
+        return (1);
+    }
+    return (0);
+}
+#endif /* HASSTREAMS */
+
+/*
+ * safepup() - safely print an unprintable character -- i.e., print it in a
+ *            printable form
+ *
+ * return: char * to printable equivalent
+ *        cl = strlen(printable equivalent)
+ */
+
+char *safepup(unsigned int c, /* unprintable (i.e., !isprint())
+                               * character  and '\\' */
+              int *cl)        /* returned printable strlen -- NULL if
+                               * no return needed */
+{
+    int len;
+    char *rp;
+    static char up[8];
+
+    if (c < 0x20) {
+        switch (c) {
+        case '\b':
+            rp = "\\b";
+            break;
+        case '\f':
+            rp = "\\f";
+            break;
+        case '\n':
+            rp = "\\n";
+            break;
+        case '\r':
+            rp = "\\r";
+            break;
+        case '\t':
+            rp = "\\t";
+            break;
+        default:
+            (void)snpf(up, sizeof(up), "^%c", c + 0x40);
+            rp = up;
+        }
+        len = 2;
+    } else if (c == 0xff) {
+        rp = "^?";
+        len = 2;
+    } else if (c == '\\') {
+        rp = "\\\\";
+        len = 2;
+    } else {
+        (void)snpf(up, sizeof(up), "\\x%02x", (int)(c & 0xff));
+        rp = up;
+        len = 4;
+    }
+    if (cl)
+        *cl = len;
+    return (rp);
+}
+
+/*
+ * safestrlen() - calculate a "safe" string length -- i.e., compute space for
+ *               non-printable characters when printed in a printable form
+ */
+
+int safestrlen(char *sp,  /* string pointer */
+               int flags) /* flags:
+                           *   bit 0: 0 (0) = no NL
+                           *       1 (1) = add trailing NL
+                           *    1: 0 (0) = ' ' printable
+                           *       1 (2) = ' ' not printable
+                           */
+{
+    char c;
+    int len = 0;
+
+    c = (flags & 2) ? ' ' : '\0';
+    if (sp) {
+        for (; *sp; sp++) {
+            if (!isprint((unsigned char)*sp) || (*sp == '\\') || (*sp == c)) {
+                if ((*sp < 0x20) || ((unsigned char)*sp == 0xff) ||
+                    (*sp == '\\'))
+                    len += 2; /* length of \. or ^. form */
+                else
+                    len += 4; /* length of "\x%02x" printf */
+            } else
+                len++;
+        }
+    }
+    return (len);
+}
+
+/*
+ * safestrprt() - print a string "safely" to the indicated stream -- i.e.,
+ *               print unprintable characters in a printable form
+ */
+void safestrprt(char *sp,  /* string to print pointer pointer */
+                FILE *fs,  /* destination stream -- e.g., stderr
+                            * or stdout */
+                int flags) /* flags:
+                            *   bit 0: 0 (0) = no NL
+                            *      1 (1) = add trailing NL
+                            *   1: 0 (0) = ' ' printable
+                            *      1 (2) = ' ' not printable
+                            *   2: 0 (0) = print string as is
+                            *      1 (4) = surround string
+                            *              with '"'
+                            *   4: 0 (0) = print ending '\n'
+                            *      1 (8) = don't print ending
+                            *              '\n'
+                            */
+{
+    char c;
+    int lnc, lnt, sl;
+
+#if defined(HASWIDECHAR)
+    wchar_t w;
+    int wcmx = MB_CUR_MAX;
+#else  /* !defined(HASWIDECHAR) */
+    static int wcmx = 1;
+#endif /* defined(HASWIDECHAR) */
+
+    c = (flags & 2) ? ' ' : '\0';
+    if (flags & 4)
+        putc('"', fs);
+    if (sp) {
+        for (sl = strlen(sp); *sp; sl -= lnc, sp += lnc) {
+
+#if defined(HASWIDECHAR)
+            if (wcmx > 1) {
+                lnc = mblen(sp, sl);
+                if (lnc > 1) {
+                    if ((mbtowc(&w, sp, sl) == lnc) && iswprint(w)) {
+                        for (lnt = 0; lnt < lnc; lnt++) {
+                            putc((int)*(sp + lnt), fs);
+                        }
+                    } else {
+                        for (lnt = 0; lnt < lnc; lnt++) {
+                            fputs(
+                                safepup((unsigned int)*(sp + lnt), (int *)NULL),
+                                fs);
+                        }
+                    }
+                    continue;
+                } else
+                    lnc = 1;
+            } else
+                lnc = 1;
+#else  /* !defined(HASWIDECHAR) */
+            lnc = 1;
+#endif /* defined(HASWIDECHAR) */
+
+            if ((*sp != '\\') && isprint((unsigned char)*sp) && *sp != c)
+                putc((int)(*sp & 0xff), fs);
+            else {
+                if ((flags & 8) && (*sp == '\n') && !*(sp + 1))
+                    break;
+                fputs(safepup((unsigned int)*sp, (int *)NULL), fs);
+            }
+        }
+    }
+    if (flags & 4)
+        putc('"', fs);
+    if (flags & 1)
+        putc('\n', fs);
+}
+
+/*
+ * safestrprtn() - print a specified number of characters from a string
+ *                "safely" to the indicated stream
+ */
+
+void safestrprtn(char *sp,  /* string to print pointer pointer */
+                 int len,   /* safe number of characters to
+                             * print */
+                 FILE *fs,  /* destination stream -- e.g., stderr
+                             * or stdout */
+                 int flags) /* flags:
+                             *   bit 0: 0 (0) = no NL
+                             *     1 (1) = add trailing NL
+                             *  1: 0 (0) = ' ' printable
+                             *     1 (2) = ' ' not printable
+                             *  2: 0 (0) = print string as is
+                             *     1 (4) = surround string
+                             *             with '"'
+                             *  4: 0 (0) = print ending '\n'
+                             *     1 (8) = don't print ending
+                             *             '\n'
+                             */
+{
+    char c, *up;
+    int cl, i;
+
+    if (flags & 4)
+        putc('"', fs);
+    if (sp) {
+        c = (flags & 2) ? ' ' : '\0';
+        for (i = 0; i < len && *sp; sp++) {
+            if ((*sp != '\\') && isprint((unsigned char)*sp) && *sp != c) {
+                putc((int)(*sp & 0xff), fs);
+                i++;
+            } else {
+                if ((flags & 8) && (*sp == '\n') && !*(sp + 1))
+                    break;
+                up = safepup((unsigned int)*sp, &cl);
+                if ((i + cl) > len)
+                    break;
+                fputs(up, fs);
+                i += cl;
+            }
+        }
+    } else
+        i = 0;
+    for (; i < len; i++)
+        putc(' ', fs);
+    if (flags & 4)
+        putc('"', fs);
+    if (flags & 1)
+        putc('\n', fs);
+}
+
+/*
+ * statsafely() - stat path safely (i. e., with timeout)
+ */
+
+int statsafely(struct lsof_context *ctx, char *path, /* file path */
+               struct stat *buf)                     /* stat buffer address */
+{
+    if (Fblock) {
+        if (!Fwarn)
+            (void)fprintf(stderr, "%s: avoiding stat(%s): -b was specified.\n",
+                          Pn, path);
+        errno = EWOULDBLOCK;
+        return (1);
+    }
+    return (doinchild(ctx, dostat, path, (char *)buf, sizeof(struct stat)));
+}
+
+/*
+ * stkdir() - stack directory name
+ */
+
+void stkdir(struct lsof_context *ctx, char *p) /* directory path */
+{
+    MALLOC_S len;
+    /*
+     * Provide adequate space for directory stack pointers.
+     */
+    if (Dstkx >= Dstkn) {
+        Dstkn += 128;
+        len = (MALLOC_S)(Dstkn * sizeof(char *));
+        if (!Dstk)
+            Dstk = (char **)malloc(len);
+        else
+            Dstk = (char **)realloc((MALLOC_P *)Dstk, len);
+        if (!Dstk) {
+            (void)fprintf(stderr, "%s: no space for directory stack at: ", Pn);
+            safestrprt(p, stderr, 1);
+            Error(ctx);
+        }
+    }
+    /*
+     * Allocate space for the name, copy it there and put its pointer on the
+     * stack.
+     */
+    if (!(Dstk[Dstkx] = mkstrcpy(p, (MALLOC_S *)NULL))) {
+        (void)fprintf(stderr, "%s: no space for: ", Pn);
+        safestrprt(p, stderr, 1);
+        Error(ctx);
+    }
+    Dstkx++;
+}
+
+/*
+ * x2dev() - convert hexadecimal ASCII string to device number
+ */
+
+char *x2dev(char *s,  /* ASCII string */
+            dev_t *d) /* device receptacle */
+{
+    char *cp, *cp1;
+    int n;
+    dev_t r;
+
+    /*
+     * Skip an optional leading 0x.  Count the number of hex digits up to the
+     * end of the string, or to a space, or to a comma.  Return an error if an
+     * unknown character is encountered.  If the count is larger than (2 *
+     * sizeof(dev_t))
+     * -- e.g., because of sign extension -- ignore excess leading hex 0xf
+     * digits, but return an error if an excess leading digit isn't 0xf.
+     */
+    if (strncasecmp(s, "0x", 2) == 0)
+        s += 2;
+    for (cp = s, n = 0; *cp; cp++, n++) {
+        if (isdigit((unsigned char)*cp))
+            continue;
+        if ((unsigned char)*cp >= 'a' && (unsigned char)*cp <= 'f')
+            continue;
+        if ((unsigned char)*cp >= 'A' && (unsigned char)*cp <= 'F')
+            continue;
+        if (*cp == ' ' || *cp == ',')
+            break;
+        return ((char *)NULL);
+    }
+    if (!n)
+        return ((char *)NULL);
+    if (n > (2 * (int)sizeof(dev_t))) {
+        cp1 = s;
+        s += (n - (2 * sizeof(dev_t)));
+        while (cp1 < s) {
+            if (*cp1 != 'f' && *cp1 != 'F')
+                return ((char *)NULL);
+            cp1++;
+        }
+    }
+    /*
+     * Assemble the validated hex digits of the device number, starting at a
+     * point in the string relevant to sizeof(dev_t).
+     */
+    for (r = 0; s < cp; s++) {
+        r = r << 4;
+        if (isdigit((unsigned char)*s))
+            r |= (unsigned char)(*s - '0') & 0xf;
+        else {
+            if (isupper((unsigned char)*s))
+                r |= ((unsigned char)(*s - 'A') + 10) & 0xf;
+            else
+                r |= ((unsigned char)(*s - 'a') + 10) & 0xf;
+        }
+    }
+    *d = r;
+    return (s);
+}
diff --git a/lib/node.c b/lib/node.c
new file mode 100644 (file)
index 0000000..4da6c67
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * node.c - common node reading functions for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#include "common.h"
+
+/*
+ * print_kptr() - print kernel pointer
+ */
+
+char *print_kptr(KA_T kp,     /* kernel pointer address */
+                 char *buf,   /* optional destination buffer */
+                 size_t bufl) /* size of buf[] */
+{
+    static char dbuf[32];
+
+    (void)snpf(buf ? buf : dbuf, buf ? bufl : sizeof(dbuf), KA_T_FMT_X, kp);
+    return (buf ? buf : dbuf);
+}
+
+#if defined(HASCDRNODE)
+/*
+ * readcdrnode() - read CD-ROM node
+ */
+
+int readcdrnode(struct lsof_context *ctx, /* context */
+                KA_T ca,                  /* cdrnode kernel address */
+                struct cdrnode *c)        /* cdrnode buffer */
+{
+    if (kread(ctx, (KA_T)ca, (char *)c, sizeof(struct cdrnode))) {
+        (void)snpf(Namech, Namechl, "can't read cdrnode at %s",
+                   print_kptr(ca, (char *)NULL, 0));
+        return (1);
+    }
+    return (0);
+}
+#endif /* defined(HASCDRNODE) */
+
+#if defined(HASFIFONODE)
+/*
+ * readfifonode() - read fifonode
+ */
+
+int readfifonode(struct lsof_context *ctx, /* context */
+                 KA_T fa,                  /* fifonode kernel address */
+                 struct fifonode *f)       /* fifonode buffer */
+{
+    if (kread(ctx, (KA_T)fa, (char *)f, sizeof(struct fifonode))) {
+        (void)snpf(Namech, Namechl, "can't read fifonode at %s",
+                   print_kptr(fa, (char *)NULL, 0));
+        return (1);
+    }
+    return (0);
+}
+#endif /* defined(HASFIFONODE) */
+
+#if defined(HASGNODE)
+/*
+ * readgnode() - read gnode
+ */
+
+int readgnode(struct lsof_context *ctx, /* context */
+              KA_T ga,                  /* gnode kernel address */
+              struct gnode *g)          /* gnode buffer */
+{
+    if (kread(ctx, (KA_T)ga, (char *)g, sizeof(struct gnode))) {
+        (void)snpf(Namech, Namechl, "can't read gnode at %s",
+                   print_kptr(ga, (char *)NULL, 0));
+        return (1);
+    }
+    return (0);
+}
+#endif /* defined(HASGNODE) */
+
+#if defined(HASHSNODE)
+/*
+ * readhsnode() - read High Sierra file system node
+ */
+
+int readhsnode(struct lsof_context *ctx, /* context */
+               KA_T ha,                  /* hsnode kernel address */
+               struct hsnode *h)         /* hsnode buffer */
+{
+    if (kread(ctx, (KA_T)ha, (char *)h, sizeof(struct hsnode))) {
+        (void)snpf(Namech, Namechl, "can't read hsnode at %s",
+                   print_kptr(ha, (char *)NULL, 0));
+        return (1);
+    }
+    return (0);
+}
+#endif /* defined(HASHSNODE) */
+
+#if defined(HASINODE)
+/*
+ * readinode() - read inode
+ */
+
+int readinode(struct lsof_context *ctx, /* context */
+              KA_T ia,                  /* inode kernel address */
+              struct inode *i)          /* inode buffer */
+{
+    if (kread(ctx, (KA_T)ia, (char *)i, sizeof(struct inode))) {
+        (void)snpf(Namech, Namechl, "can't read inode at %s",
+                   print_kptr(ia, (char *)NULL, 0));
+        return (1);
+    }
+    return (0);
+}
+#endif /* defined(HASINODE) */
+
+#if defined(HASPIPENODE)
+/*
+ * readpipenode() - read pipe node
+ */
+
+int readpipenode(struct lsof_context *ctx, /* context */
+                 KA_T pa,                  /* pipe node kernel address */
+                 struct pipenode *p)       /* pipe node buffer */
+{
+    if (kread(ctx, (KA_T)pa, (char *)p, sizeof(struct pipenode))) {
+        (void)snpf(Namech, Namechl, "can't read pipenode at %s",
+                   print_kptr(pa, (char *)NULL, 0));
+        return (1);
+    }
+    return (0);
+}
+#endif /* defined(HASPIPENODE) */
+
+#if defined(HASRNODE)
+/*
+ * readrnode() - read rnode
+ */
+
+int readrnode(struct lsof_context *ctx, /* context */
+              KA_T ra,                  /* rnode kernel space address */
+              struct rnode *r)          /* rnode buffer pointer */
+{
+    if (kread(ctx, (KA_T)ra, (char *)r, sizeof(struct rnode))) {
+        (void)snpf(Namech, Namechl, "can't read rnode at %s",
+                   print_kptr(ra, (char *)NULL, 0));
+        return (1);
+    }
+    return (0);
+}
+#endif /* defined(HASRNODE) */
+
+#if defined(HASSNODE)
+/*
+ * readsnode() - read snode
+ */
+
+int readsnode(struct lsof_context *ctx, /* context */
+              KA_T sa,                  /* snode kernel space address */
+              struct snode *s)          /* snode buffer pointer */
+{
+    if (kread(ctx, (KA_T)sa, (char *)s, sizeof(struct snode))) {
+        (void)snpf(Namech, Namechl, "can't read snode at %s",
+                   print_kptr(sa, (char *)NULL, 0));
+        return (1);
+    }
+    return (0);
+}
+#endif /* defined(HASSNODE) */
+
+#if defined(HASTMPNODE)
+/*
+ * readtnode() - read tmpnode
+ */
+
+int readtnode(struct lsof_context *ctx, /* context */
+              KA_T ta,                  /* tmpnode kernel space address */
+              struct tmpnode *t)        /* tmpnode buffer pointer */
+{
+    if (kread(ctx, (KA_T)ta, (char *)t, sizeof(struct tmpnode))) {
+        (void)snpf(Namech, Namechl, "can't read tmpnode at %s",
+                   print_kptr(ta, (char *)NULL, 0));
+        return (1);
+    }
+    return (0);
+}
+#endif /* defined(HASTMPNODE) */
+
+#if defined(HASVNODE)
+/*
+ * readvnode() - read vnode
+ */
+
+int readvnode(struct lsof_context *ctx, /* context */
+              KA_T va,                  /* vnode kernel space address */
+              struct vnode *v)          /* vnode buffer pointer */
+{
+    if (kread(ctx, (KA_T)va, (char *)v, sizeof(struct vnode))) {
+        (void)snpf(Namech, Namechl, "can't read vnode at %s",
+                   print_kptr(va, (char *)NULL, 0));
+        return (1);
+    }
+    return (0);
+}
+#endif /* defined(HASVNODE) */
diff --git a/lib/pdvn.c b/lib/pdvn.c
new file mode 100644 (file)
index 0000000..d553f67
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * pdvn.c -- print device name functions for lsof library
+ */
+
+/*
+ * 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.
+ */
+
+#include "common.h"
+#include "machine.h"
+
+#if defined(USE_LIB_PRINTDEVNAME)
+
+#else  /* !defined(USE_LIB_PRINTDEVNAME) */
+char pdvn_d1[] = "d";
+char *pdvn_d2 = pdvn_d1;
+#endif /* defined(USE_LIB_PRINTDEVNAME) */
+
+/*
+ * To use this source file:
+ *
+ * 1. Define USE_LIB_PRINTDEVNAME, or both.
+ *
+ * 2. Define HAS_STD_CLONE to enable standard clone searches in
+ *    printdevname().
+ *
+ * 3. Define HASBLDKDEV to enable block device processing.
+ */
+
+/*
+ * Local definitions
+ */
+
+#define LIKE_BLK_SPEC "like block special"
+#define LIKE_CHR_SPEC "like character special"
+
+#if defined(USE_LIB_PRINTDEVNAME)
+/*
+ * printdevname() - print block or character device name
+ */
+
+int printdevname(struct lsof_context *ctx, dev_t *dev, /* device */
+                 dev_t *rdev,                          /* raw device */
+                 int f,   /* 1 = print trailing '\n' */
+                 int nty) /* node type: N_BLK or N_CHR */
+{
+
+#    if defined(HAS_STD_CLONE)
+    struct clone *c;
+#    endif /* defined(HAS_STD_CLONE) */
+
+    struct l_dev *dp;
+    int r = 1;
+
+#    if defined(HASDCACHE)
+
+printdevname_again:
+
+#    endif /* defined(HASDCACHE) */
+
+#    if defined(HAS_STD_CLONE)
+    /*
+     * Search for clone if this is a character device on the same device as
+     * /dev (or /devices).
+     */
+    if ((nty == N_CHR) && Lf->is_stream && Clone && (*dev == DevDev)) {
+        r = 0; /* Don't let lkupdev() rebuild the device cache,
+                * because when it has been rebuilt we want to
+                * search again for clones. */
+        readdev(0);
+        for (c = Clone; c; c = c->next) {
+            if (GET_MAJ_DEV(*rdev) == GET_MIN_DEV(Devtp[c->dx].rdev)) {
+
+#        if defined(HASDCACHE)
+                if (DCunsafe && !Devtp[c->dx].v && !vfy_dev(&Devtp[c->dx]))
+                    goto printdevname_again;
+#        endif /* defined(HASDCACHE) */
+
+                safestrprt(Devtp[c->dx].name, stdout, f);
+                return (1);
+            }
+        }
+    }
+#    endif /* defined(HAS_STD_CLONE) */
+
+    /*
+     * Search appropriate device table for a full match.
+     */
+
+#    if defined(HASBLKDEV)
+    if (nty == N_BLK)
+        dp = lkupbdev(ctx, dev, rdev, 1, r);
+    else
+#    endif /* defined(HASBLKDEV) */
+
+        dp = lkupdev(ctx, dev, rdev, 1, r);
+    if (dp) {
+        safestrprt(dp->name, stdout, f);
+        return (1);
+    }
+    /*
+     * Search device table for a match without inode number and dev.
+     */
+
+#    if defined(HASBLKDEV)
+    if (nty == N_BLK)
+        dp = lkupbdev(ctx, &DevDev, rdev, 0, r);
+    else
+#    endif /* defined(HASBLKDEV) */
+
+        dp = lkupdev(ctx, &DevDev, rdev, 0, r);
+    if (dp) {
+        /*
+         * A match was found.  Record it as a name column addition.
+         */
+        char *cp, *ttl;
+        int len;
+
+        ttl = (nty == N_BLK) ? LIKE_BLK_SPEC : LIKE_CHR_SPEC;
+        len = (int)(1 + strlen(ttl) + 1 + strlen(dp->name) + 1);
+        if (!(cp = (char *)malloc((MALLOC_S)(len + 1)))) {
+            (void)fprintf(stderr, "%s: no nma space for: (%s %s)\n", Pn, ttl,
+                          dp->name);
+            Error(ctx);
+        }
+        (void)snpf(cp, len + 1, "(%s %s)", ttl, dp->name);
+        (void)add_nma(ctx, cp, len);
+        (void)free((MALLOC_P *)cp);
+        return (0);
+    }
+
+#    if defined(HASDCACHE)
+    /*
+     * We haven't found a match.
+     *
+     * If rebuilding the device cache was suppressed and the device cache is
+     * "unsafe," rebuild it.
+     */
+    if (!r && DCunsafe) {
+        (void)rereaddev(ctx);
+        goto printdevname_again;
+    }
+#    endif /* defined(HASDCACHE) */
+
+    return (0);
+}
+#endif /* defined(USE_LIB_PRINTDEVNAME) */
diff --git a/lib/prfp.c b/lib/prfp.c
new file mode 100644 (file)
index 0000000..6e57391
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * prfp.c -- process_file() function for lsof library
+ */
+
+/*
+ * 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.
+ */
+
+#include "common.h"
+#include "machine.h"
+
+#if defined(USE_LIB_PROCESS_FILE)
+
+/*
+ * process_file() - process file
+ */
+
+/*
+ * The caller may define:
+ *
+ *     FILEPTR as the name of the location to store a pointer
+ *                     to the current file struct -- e.g.,
+ *
+ *                     struct file *foobar;
+ *                     #define FILEPTR foobar
+ */
+
+void process_file(struct lsof_context *ctx,
+                  KA_T fp) /* kernel file structure address */
+{
+    struct file f;
+    int flag;
+    char tbuf[32];
+
+#    if defined(FILEPTR)
+    /*
+     * Save file structure address for process_node().
+     */
+    FILEPTR = &f;
+#    endif /* defined(FILEPTR) */
+
+    /*
+     * Read file structure.
+     */
+    if (kread(ctx, (KA_T)fp, (char *)&f, sizeof(f))) {
+        (void)snpf(Namech, Namechl, "can't read file struct from %s",
+                   print_kptr(fp, (char *)NULL, 0));
+        enter_nm(ctx, Namech);
+        return;
+    }
+    Lf->off = (SZOFFTYPE)f.f_offset;
+    Lf->off_def = 1;
+    if (f.f_count) {
+
+        /*
+         * Construct access code.
+         */
+        if ((flag = (f.f_flag & (FREAD | FWRITE))) == FREAD)
+            Lf->access = LSOF_FILE_ACCESS_READ;
+        else if (flag == FWRITE)
+            Lf->access = LSOF_FILE_ACCESS_WRITE;
+        else if (flag == (FREAD | FWRITE))
+            Lf->access = LSOF_FILE_ACCESS_READ_WRITE;
+
+#    if defined(HASFSTRUCT)
+            /*
+             * Save file structure values.
+             */
+
+#        if !defined(HASNOFSCOUNT)
+        Lf->fct = (long)f.f_count;
+        Lf->fsv |= FSV_CT;
+#        endif /* !defined(HASNOFSCOUNT) */
+
+#        if !defined(HASNOFSADDR)
+        Lf->fsa = fp;
+        Lf->fsv |= FSV_FA;
+#        endif /* !defined(HASNOFSADDR) */
+
+#        if !defined(HASNOFSFLAGS)
+        Lf->ffg = (long)f.f_flag;
+        Lf->fsv |= FSV_FG;
+#        endif /* !defined(HASNOFSFLAGS) */
+
+#        if !defined(HASNOFSNADDR)
+        Lf->fna = (KA_T)f.f_data;
+        Lf->fsv |= FSV_NI;
+#        endif /* !defined(HASNOFSNADDR) */
+#    endif     /* defined(HASFSTRUCT) */
+
+        /*
+         * Process structure by its type.
+         */
+        switch (f.f_type) {
+
+#    if defined(DTYPE_PIPE)
+        case DTYPE_PIPE:
+#        if defined(HASPIPEFN)
+            if (!Selinet)
+                HASPIPEFN(ctx, (KA_T)f.f_data);
+#        endif /* defined(HASPIPEFN) */
+            return;
+#    endif /* defined(DTYPE_PIPE) */
+
+#    if defined(DTYPE_PTS)
+        case DTYPE_PTS:
+#        if defined(HASPTSFN)
+            HASPTSFN(ctx, (KA_T)f.f_data);
+#        endif /* defined(HASPTSFN) */
+            return;
+#    endif /* defined(DTYPE_PIPE) */
+
+#    if defined(DTYPE_FIFO)
+        case DTYPE_FIFO:
+#    endif /* defined(DTYPE_FIFO) */
+
+#    if defined(DTYPE_GNODE)
+        case DTYPE_GNODE:
+#    endif /* defined(DTYPE_GNODE) */
+
+#    if defined(DTYPE_INODE)
+        case DTYPE_INODE:
+#    endif /* defined(DTYPE_INODE) */
+
+#    if defined(DTYPE_PORT)
+        case DTYPE_PORT:
+#    endif /* defined(DTYPE_PORT) */
+
+#    if defined(DTYPE_VNODE)
+        case DTYPE_VNODE:
+#    endif /* defined(DTYPE_VNODE) */
+
+#    if defined(HASF_VNODE)
+            process_node(ctx, (KA_T)f.f_vnode);
+#    else  /* !defined(HASF_VNODE) */
+            process_node(ctx, (KA_T)f.f_data);
+#    endif /* defined(HASF_VNODE) */
+
+            return;
+        case DTYPE_SOCKET:
+            process_socket(ctx, (KA_T)f.f_data);
+            return;
+
+#    if defined(HASKQUEUE)
+        case DTYPE_KQUEUE:
+            process_kqueue(ctx, (KA_T)f.f_data);
+            return;
+#    endif /* defined(HASKQUEUE) */
+
+#    if defined(HASPSXSEM)
+        case DTYPE_PSXSEM:
+            process_psxsem(ctx, (KA_T)f.f_data);
+            return;
+#    endif /* defined(HASPSXSEM) */
+
+#    if defined(HASPSXSHM)
+        case DTYPE_PSXSHM:
+            process_psxshm(ctx, (KA_T)f.f_data);
+            return;
+#    endif /* defined(HASPSXSHM) */
+
+#    if defined(HASPRIVFILETYPE)
+        case PRIVFILETYPE:
+            HASPRIVFILETYPE(ctx, (KA_T)f.f_data);
+            return;
+#    endif /* defined(HASPRIVFILETYPE) */
+
+        default:
+
+#    if defined(X_BADFILEOPS)
+            if (X_bfopsa && f.f_ops && (X_bfopsa == (KA_T)f.f_ops)) {
+                (void)snpf(Namech, Namechl,
+                           "no more information; ty=%d file may be closing",
+                           (int)f.f_type);
+                enter_nm(ctx, Namech);
+                return;
+            }
+#    endif /* defined(X_BADFILEOPS) */
+
+            if (f.f_type || f.f_ops) {
+                (void)snpf(Namech, Namechl, "%s file struct, ty=%d, op=%s",
+                           print_kptr(fp, tbuf, sizeof(tbuf)), (int)f.f_type,
+                           print_kptr((KA_T)f.f_ops, (char *)NULL, 0));
+                enter_nm(ctx, Namech);
+                return;
+            }
+        }
+    }
+    enter_nm(ctx, "no more information");
+}
+#else  /* !defined(USE_LIB_PROCESS_FILE) */
+char prfp_d1[] = "d";
+char *prfp_d2 = prfp_d1;
+#endif /* defined(USE_LIB_PROCESS_FILE) */
diff --git a/lib/print.c b/lib/print.c
new file mode 100644 (file)
index 0000000..f9feef0
--- /dev/null
@@ -0,0 +1,1483 @@
+/*
+ * print.c - common print support functions for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#include "common.h"
+#include "lsof.h"
+
+/*
+ * Local definitions, structures and function prototypes
+ */
+
+/*
+ * access_to_char() - convert enum lsof_file_access_mode to char
+ */
+char access_to_char(enum lsof_file_access_mode access) {
+    switch (access) {
+    default:
+    case LSOF_FILE_ACCESS_NONE:
+        return ' ';
+    case LSOF_FILE_ACCESS_READ:
+        return 'r';
+    case LSOF_FILE_ACCESS_WRITE:
+        return 'w';
+    case LSOF_FILE_ACCESS_READ_WRITE:
+        return 'u';
+    }
+}
+
+/*
+ * lock_to_char() - convert enum lsof_lock_mode to char
+ */
+char lock_to_char(enum lsof_lock_mode lock) {
+    switch (lock) {
+    default:
+    case LSOF_LOCK_NONE:
+        return ' ';
+    case LSOF_LOCK_UNKNOWN:
+        return 'U';
+    case LSOF_LOCK_READ_PARTIAL:
+        return 'r';
+    case LSOF_LOCK_READ_FULL:
+        return 'R';
+    case LSOF_LOCK_WRITE_PARTIAL:
+        return 'w';
+    case LSOF_LOCK_WRITE_FULL:
+        return 'W';
+    case LSOF_LOCK_READ_WRITE:
+        return 'u';
+    case LSOF_LOCK_SOLARIS_NFS:
+        return 'N';
+    case LSOF_LOCK_SCO_PARTIAL:
+        return 'x';
+    case LSOF_LOCK_SCO_FULL:
+        return 'X';
+    }
+}
+
+/*
+ * file_type_to_string() - convert enum lsof_file_type to string
+ */
+void file_type_to_string(enum lsof_file_type type,
+                         uint32_t unknown_file_type_number, char *buf,
+                         size_t buf_len) {
+    switch (type) {
+    default:
+    case LSOF_FILE_UNKNOWN_RAW:
+        (void)snpf(buf, buf_len, "%04o", (unknown_file_type_number & 0xfff));
+        break;
+    case LSOF_FILE_FIFO:
+        (void)snpf(buf, buf_len, "FIFO");
+        break;
+    case LSOF_FILE_CHAR:
+        (void)snpf(buf, buf_len, "CHR");
+        break;
+    case LSOF_FILE_DIR:
+        (void)snpf(buf, buf_len, "DIR");
+        break;
+    case LSOF_FILE_BLOCK:
+        (void)snpf(buf, buf_len, "BLK");
+        break;
+    case LSOF_FILE_REGULAR:
+        (void)snpf(buf, buf_len, "REG");
+        break;
+    case LSOF_FILE_LINK:
+        (void)snpf(buf, buf_len, "LINK");
+        break;
+    /* Use lower case for network-related files except IPv4/IPv6/ATALK for
+     * compatibility */
+    case LSOF_FILE_SOCKET:
+        (void)snpf(buf, buf_len, "sock");
+        break;
+    case LSOF_FILE_IPV4:
+        (void)snpf(buf, buf_len, "IPv4");
+        break;
+    case LSOF_FILE_IPV6:
+        (void)snpf(buf, buf_len, "IPv6");
+        break;
+    case LSOF_FILE_AX25:
+        (void)snpf(buf, buf_len, "ax25");
+        break;
+    case LSOF_FILE_INET:
+        (void)snpf(buf, buf_len, "inet");
+        break;
+    case LSOF_FILE_LINK_LEVEL_ACCESS:
+        (void)snpf(buf, buf_len, "lla");
+        break;
+    case LSOF_FILE_ROUTE:
+        (void)snpf(buf, buf_len, "rte");
+        break;
+    case LSOF_FILE_UNIX:
+        (void)snpf(buf, buf_len, "unix");
+        break;
+    case LSOF_FILE_X25:
+        (void)snpf(buf, buf_len, "x.25");
+        break;
+    case LSOF_FILE_APPLETALK:
+        (void)snpf(buf, buf_len, "ATALK");
+        break;
+    case LSOF_FILE_NET_DRIVER:
+        (void)snpf(buf, buf_len, "ndrv");
+        break;
+    case LSOF_FILE_INTERNAL_KEY:
+        (void)snpf(buf, buf_len, "key");
+        break;
+    case LSOF_FILE_SYSTEM:
+        (void)snpf(buf, buf_len, "systm");
+        break;
+    case LSOF_FILE_PPP:
+        (void)snpf(buf, buf_len, "ppp");
+        break;
+    case LSOF_FILE_IPX:
+        (void)snpf(buf, buf_len, "ipx");
+        break;
+    case LSOF_FILE_RAW:
+        (void)snpf(buf, buf_len, "raw");
+        break;
+    case LSOF_FILE_RAW6:
+        (void)snpf(buf, buf_len, "raw6");
+        break;
+    case LSOF_FILE_NETLINK:
+        (void)snpf(buf, buf_len, "netlink");
+        break;
+    case LSOF_FILE_PACKET:
+        (void)snpf(buf, buf_len, "pack");
+        break;
+    case LSOF_FILE_ICMP:
+        (void)snpf(buf, buf_len, "icmp");
+        break;
+
+    case LSOF_FILE_PROC_AS:
+        (void)snpf(buf, buf_len, "PAS");
+        break;
+    case LSOF_FILE_PROC_AUXV:
+        (void)snpf(buf, buf_len, "PAXV");
+        break;
+    case LSOF_FILE_PROC_CRED:
+        (void)snpf(buf, buf_len, "PCRE");
+        break;
+    case LSOF_FILE_PROC_CTRL:
+        (void)snpf(buf, buf_len, "PCTL");
+        break;
+    case LSOF_FILE_PROC_CUR_PROC:
+        (void)snpf(buf, buf_len, "PCUR");
+        break;
+    case LSOF_FILE_PROC_CWD:
+        (void)snpf(buf, buf_len, "PCWD");
+        break;
+    case LSOF_FILE_PROC_DIR:
+        (void)snpf(buf, buf_len, "PDIR");
+        break;
+    case LSOF_FILE_PROC_EXEC_TYPE:
+        (void)snpf(buf, buf_len, "PETY");
+        break;
+    case LSOF_FILE_PROC_FD:
+        (void)snpf(buf, buf_len, "PFD");
+        break;
+    case LSOF_FILE_PROC_FD_DIR:
+        (void)snpf(buf, buf_len, "PFDR");
+        break;
+    case LSOF_FILE_PROC_FILE:
+        (void)snpf(buf, buf_len, "PFIL");
+        break;
+    case LSOF_FILE_PROC_FP_REGS:
+        (void)snpf(buf, buf_len, "PFPR");
+        break;
+    case LSOF_FILE_PROC_PAGE_DATA:
+        (void)snpf(buf, buf_len, "PGD");
+        break;
+    case LSOF_FILE_PROC_GROUP_NOTIFIER:
+        (void)snpf(buf, buf_len, "PGID");
+        break;
+    case LSOF_FILE_PROC_LWP_CTL:
+        (void)snpf(buf, buf_len, "PLC");
+        break;
+    case LSOF_FILE_PROC_LWP_DIR:
+        (void)snpf(buf, buf_len, "PLDR");
+        break;
+    case LSOF_FILE_PROC_LDT:
+        (void)snpf(buf, buf_len, "PLDT");
+        break;
+    case LSOF_FILE_PROC_LPS_INFO:
+        (void)snpf(buf, buf_len, "PLPI");
+        break;
+    case LSOF_FILE_PROC_LSTATUS:
+        (void)snpf(buf, buf_len, "PLST");
+        break;
+    case LSOF_FILE_PROC_LUSAGE:
+        (void)snpf(buf, buf_len, "PLU");
+        break;
+    case LSOF_FILE_PROC_LWP_GWINDOWS:
+        (void)snpf(buf, buf_len, "PLWG");
+        break;
+    case LSOF_FILE_PROC_LWP_SINFO:
+        (void)snpf(buf, buf_len, "PLWI");
+        break;
+    case LSOF_FILE_PROC_LWP_STATUS:
+        (void)snpf(buf, buf_len, "PLWS");
+        break;
+    case LSOF_FILE_PROC_LWP_USAGE:
+        (void)snpf(buf, buf_len, "PLWU");
+        break;
+    case LSOF_FILE_PROC_LWP_XREGS:
+        (void)snpf(buf, buf_len, "PLWX");
+        break;
+    case LSOF_FILE_PROC_MAP:
+        (void)snpf(buf, buf_len, "PMAP");
+        break;
+    case LSOF_FILE_PROC_MAPS:
+        (void)snpf(buf, buf_len, "PMPS");
+        break;
+    case LSOF_FILE_PROC_MEMORY:
+        (void)snpf(buf, buf_len, "PMEM");
+        break;
+    case LSOF_FILE_PROC_PROC_NOTIFIER:
+        (void)snpf(buf, buf_len, "PNTF");
+        break;
+    case LSOF_FILE_PROC_OBJ:
+        (void)snpf(buf, buf_len, "POBJ");
+        break;
+    case LSOF_FILE_PROC_OBJ_DIR:
+        (void)snpf(buf, buf_len, "PODR");
+        break;
+    case LSOF_FILE_PROC_OLD_LWP:
+        (void)snpf(buf, buf_len, "POLP");
+        break;
+    case LSOF_FILE_PROC_OLD_PID:
+        (void)snpf(buf, buf_len, "POPF");
+        break;
+    case LSOF_FILE_PROC_OLD_PAGE:
+        (void)snpf(buf, buf_len, "POPG");
+        break;
+    case LSOF_FILE_PROC_REGS:
+        (void)snpf(buf, buf_len, "PREG");
+        break;
+    case LSOF_FILE_PROC_RMAP:
+        (void)snpf(buf, buf_len, "PRMP");
+        break;
+    case LSOF_FILE_PROC_ROOT:
+        (void)snpf(buf, buf_len, "PRTD");
+        break;
+    case LSOF_FILE_PROC_SIGACT:
+        (void)snpf(buf, buf_len, "PSGA");
+        break;
+    case LSOF_FILE_PROC_PSINFO:
+        (void)snpf(buf, buf_len, "PSIN");
+        break;
+    case LSOF_FILE_PROC_STATUS:
+        (void)snpf(buf, buf_len, "PSTA");
+        break;
+    case LSOF_FILE_PROC_USAGE:
+        (void)snpf(buf, buf_len, "PUSG");
+        break;
+    case LSOF_FILE_PROC_WATCH:
+        (void)snpf(buf, buf_len, "PW");
+        break;
+    case LSOF_FILE_PROC_XMAP:
+        (void)snpf(buf, buf_len, "PXMP");
+        break;
+
+    /* Others */
+    case LSOF_FILE_ANON_INODE:
+        (void)snpf(buf, buf_len, "a_inode");
+        break;
+    case LSOF_FILE_DEL:
+        (void)snpf(buf, buf_len, "DEL");
+        break;
+    case LSOF_FILE_DOOR:
+        (void)snpf(buf, buf_len, "DOOR");
+        break;
+    case LSOF_FILE_KQUEUE:
+        (void)snpf(buf, buf_len, "KQUEUE");
+        break;
+    case LSOF_FILE_FSEVENTS:
+        (void)snpf(buf, buf_len, "FSEVENTS");
+        break;
+    case LSOF_FILE_EVENTFD:
+        (void)snpf(buf, buf_len, "EVENTFD");
+        break;
+    case LSOF_FILE_PROCDESC:
+        (void)snpf(buf, buf_len, "PROCDSC");
+        break;
+    case LSOF_FILE_MULTIPLEXED_BLOCK:
+        (void)snpf(buf, buf_len, "MPB");
+        break;
+    case LSOF_FILE_MULTIPLEXED_CHAR:
+        (void)snpf(buf, buf_len, "MPC");
+        break;
+    case LSOF_FILE_UNKNOWN_DELETED:
+        (void)snpf(buf, buf_len, "UNKNdel");
+        break;
+    case LSOF_FILE_UNKNOWN_MEMORY:
+        (void)snpf(buf, buf_len, "UNKNmem");
+        break;
+    case LSOF_FILE_UNKNOWN_FD:
+        (void)snpf(buf, buf_len, "UNKNfd");
+        break;
+    case LSOF_FILE_UNKNOWN_CWD:
+        (void)snpf(buf, buf_len, "UNKNcwd");
+        break;
+    case LSOF_FILE_UNKNOWN_ROOT_DIR:
+        (void)snpf(buf, buf_len, "UNKNrtd");
+        break;
+    case LSOF_FILE_UNKNOWN_PROGRAM_TEXT:
+        (void)snpf(buf, buf_len, "UNKNtxt");
+        break;
+    case LSOF_FILE_UNKNOWN:
+        (void)snpf(buf, buf_len, "UNKN");
+        break;
+    case LSOF_FILE_UNKNOWN_STAT:
+        (void)snpf(buf, buf_len, "unknown");
+        break;
+    case LSOF_FILE_PIPE:
+        (void)snpf(buf, buf_len, "PIPE");
+        break;
+    case LSOF_FILE_PORT:
+        (void)snpf(buf, buf_len, "PORT");
+        break;
+    case LSOF_FILE_POSIX_MQ:
+        (void)snpf(buf, buf_len, "PSXMQ");
+        break;
+    case LSOF_FILE_POSIX_SEMA:
+        (void)snpf(buf, buf_len, "PSXSEM");
+        break;
+    case LSOF_FILE_POSIX_SHM:
+        (void)snpf(buf, buf_len, "PSXSHM");
+        break;
+    case LSOF_FILE_SHM:
+        (void)snpf(buf, buf_len, "SHM");
+        break;
+    case LSOF_FILE_PTS:
+        (void)snpf(buf, buf_len, "PTS");
+        break;
+    case LSOF_FILE_SHARED_MEM_TRANSPORT:
+        (void)snpf(buf, buf_len, "SMT");
+        break;
+    case LSOF_FILE_STREAM:
+        (void)snpf(buf, buf_len, "STR");
+        break;
+    case LSOF_FILE_STREAM_SOCKET:
+        (void)snpf(buf, buf_len, "STSO");
+        break;
+    case LSOF_FILE_SCO_UNKNOWN:
+        (void)snpf(buf, buf_len, "XNAM");
+        break;
+    case LSOF_FILE_SCO_SEMA:
+        (void)snpf(buf, buf_len, "XSEM");
+        break;
+    case LSOF_FILE_SCO_SHARED:
+        (void)snpf(buf, buf_len, "XSD");
+        break;
+    case LSOF_FILE_UNSUPPORTED:
+        (void)snpf(buf, buf_len, "UNSP");
+        break;
+
+    /* vnode */
+    case LSOF_FILE_VNODE_VNON:
+        (void)snpf(buf, buf_len, "VNON");
+        break;
+    case LSOF_FILE_VNODE_VREG:
+        (void)snpf(buf, buf_len, "VREG");
+        break;
+    case LSOF_FILE_VNODE_VDIR:
+        (void)snpf(buf, buf_len, "VDIR");
+        break;
+    case LSOF_FILE_VNODE_VBLK:
+        (void)snpf(buf, buf_len, "VBLK");
+        break;
+    case LSOF_FILE_VNODE_VCHR:
+        (void)snpf(buf, buf_len, "VCHR");
+        break;
+    case LSOF_FILE_VNODE_VLNK:
+        (void)snpf(buf, buf_len, "VLNK");
+        break;
+    case LSOF_FILE_VNODE_VSOCK:
+        (void)snpf(buf, buf_len, "SOCK");
+        break;
+    case LSOF_FILE_VNODE_VBAD:
+        (void)snpf(buf, buf_len, "VBAD");
+        break;
+    case LSOF_FILE_VNODE_VMPC:
+        (void)snpf(buf, buf_len, "VMPC");
+        break;
+    case LSOF_FILE_VNODE_VFIFO:
+        (void)snpf(buf, buf_len, "FIFO");
+        break;
+    case LSOF_FILE_VNODE_VDOOR:
+        (void)snpf(buf, buf_len, "DOOR");
+        break;
+    case LSOF_FILE_VNODE_VPORT:
+        (void)snpf(buf, buf_len, "PORT");
+        break;
+    case LSOF_FILE_VNODE_VUNNAMED:
+        (void)snpf(buf, buf_len, "UNNM");
+        break;
+    }
+}
+
+/*
+ * endnm() - locate end of Namech
+ */
+char *endnm(struct lsof_context *ctx, size_t *sz) /* returned remaining size */
+{
+    register char *s;
+    register size_t tsz;
+
+    for (s = Namech, tsz = Namechl; *s; s++, tsz--)
+        ;
+    *sz = tsz;
+    return (s);
+}
+
+void __attribute__((weak))
+usage(struct lsof_context *ctx, /* context */
+      int err,                  /* it is called as part of error handlng? */
+      int fh,                   /* ``-F ?'' status */
+      int version)              /* ``-v'' status */
+{
+    // do nothing in liblsof
+}
+
+#if !defined(HASPRIVPRIPP)
+/*
+ * printiproto() - print Internet protocol name
+ */
+
+void printiproto(struct lsof_context *ctx, /* context */
+                 int p)                    /* protocol number */
+{
+    int i;
+    static int m = -1;
+    char *s;
+
+    switch (p) {
+
+#    if defined(IPPROTO_TCP)
+    case IPPROTO_TCP:
+        s = "TCP";
+        break;
+#    endif /* defined(IPPROTO_TCP) */
+
+#    if defined(IPPROTO_UDP)
+    case IPPROTO_UDP:
+        s = "UDP";
+        break;
+#    endif /* defined(IPPROTO_UDP) */
+
+#    if defined(IPPROTO_IP)
+#        if !defined(IPPROTO_HOPOPTS) || IPPROTO_IP != IPPROTO_HOPOPTS
+    case IPPROTO_IP:
+        s = "IP";
+        break;
+#        endif /* !defined(IPPROTO_HOPOPTS) || IPPROTO_IP!=IPPROTO_HOPOPTS */
+#    endif     /* defined(IPPROTO_IP) */
+
+#    if defined(IPPROTO_ICMP)
+    case IPPROTO_ICMP:
+        s = "ICMP";
+        break;
+#    endif /* defined(IPPROTO_ICMP) */
+
+#    if defined(IPPROTO_ICMPV6)
+    case IPPROTO_ICMPV6:
+        s = "ICMPV6";
+        break;
+#    endif /* defined(IPPROTO_ICMPV6) */
+
+#    if defined(IPPROTO_IGMP)
+    case IPPROTO_IGMP:
+        s = "IGMP";
+        break;
+#    endif /* defined(IPPROTO_IGMP) */
+
+#    if defined(IPPROTO_GGP)
+    case IPPROTO_GGP:
+        s = "GGP";
+        break;
+#    endif /* defined(IPPROTO_GGP) */
+
+#    if defined(IPPROTO_EGP)
+    case IPPROTO_EGP:
+        s = "EGP";
+        break;
+#    endif /* defined(IPPROTO_EGP) */
+
+#    if defined(IPPROTO_PUP)
+    case IPPROTO_PUP:
+        s = "PUP";
+        break;
+#    endif /* defined(IPPROTO_PUP) */
+
+#    if defined(IPPROTO_IDP)
+    case IPPROTO_IDP:
+        s = "IDP";
+        break;
+#    endif /* defined(IPPROTO_IDP) */
+
+#    if defined(IPPROTO_ND)
+    case IPPROTO_ND:
+        s = "ND";
+        break;
+#    endif /* defined(IPPROTO_ND) */
+
+#    if defined(IPPROTO_RAW)
+    case IPPROTO_RAW:
+        s = "RAW";
+        break;
+#    endif /* defined(IPPROTO_RAW) */
+
+#    if defined(IPPROTO_HELLO)
+    case IPPROTO_HELLO:
+        s = "HELLO";
+        break;
+#    endif /* defined(IPPROTO_HELLO) */
+
+#    if defined(IPPROTO_PXP)
+    case IPPROTO_PXP:
+        s = "PXP";
+        break;
+#    endif /* defined(IPPROTO_PXP) */
+
+#    if defined(IPPROTO_RAWIP)
+    case IPPROTO_RAWIP:
+        s = "RAWIP";
+        break;
+#    endif /* defined(IPPROTO_RAWIP) */
+
+#    if defined(IPPROTO_RAWIF)
+    case IPPROTO_RAWIF:
+        s = "RAWIF";
+        break;
+#    endif /* defined(IPPROTO_RAWIF) */
+
+#    if defined(IPPROTO_HOPOPTS)
+    case IPPROTO_HOPOPTS:
+        s = "HOPOPTS";
+        break;
+#    endif /* defined(IPPROTO_HOPOPTS) */
+
+#    if defined(IPPROTO_IPIP)
+    case IPPROTO_IPIP:
+        s = "IPIP";
+        break;
+#    endif /* defined(IPPROTO_IPIP) */
+
+#    if defined(IPPROTO_ST)
+    case IPPROTO_ST:
+        s = "ST";
+        break;
+#    endif /* defined(IPPROTO_ST) */
+
+#    if defined(IPPROTO_PIGP)
+    case IPPROTO_PIGP:
+        s = "PIGP";
+        break;
+#    endif /* defined(IPPROTO_PIGP) */
+
+#    if defined(IPPROTO_RCCMON)
+    case IPPROTO_RCCMON:
+        s = "RCCMON";
+        break;
+#    endif /* defined(IPPROTO_RCCMON) */
+
+#    if defined(IPPROTO_NVPII)
+    case IPPROTO_NVPII:
+        s = "NVPII";
+        break;
+#    endif /* defined(IPPROTO_NVPII) */
+
+#    if defined(IPPROTO_ARGUS)
+    case IPPROTO_ARGUS:
+        s = "ARGUS";
+        break;
+#    endif /* defined(IPPROTO_ARGUS) */
+
+#    if defined(IPPROTO_EMCON)
+    case IPPROTO_EMCON:
+        s = "EMCON";
+        break;
+#    endif /* defined(IPPROTO_EMCON) */
+
+#    if defined(IPPROTO_XNET)
+    case IPPROTO_XNET:
+        s = "XNET";
+        break;
+#    endif /* defined(IPPROTO_XNET) */
+
+#    if defined(IPPROTO_CHAOS)
+    case IPPROTO_CHAOS:
+        s = "CHAOS";
+        break;
+#    endif /* defined(IPPROTO_CHAOS) */
+
+#    if defined(IPPROTO_MUX)
+    case IPPROTO_MUX:
+        s = "MUX";
+        break;
+#    endif /* defined(IPPROTO_MUX) */
+
+#    if defined(IPPROTO_MEAS)
+    case IPPROTO_MEAS:
+        s = "MEAS";
+        break;
+#    endif /* defined(IPPROTO_MEAS) */
+
+#    if defined(IPPROTO_HMP)
+    case IPPROTO_HMP:
+        s = "HMP";
+        break;
+#    endif /* defined(IPPROTO_HMP) */
+
+#    if defined(IPPROTO_PRM)
+    case IPPROTO_PRM:
+        s = "PRM";
+        break;
+#    endif /* defined(IPPROTO_PRM) */
+
+#    if defined(IPPROTO_TRUNK1)
+    case IPPROTO_TRUNK1:
+        s = "TRUNK1";
+        break;
+#    endif /* defined(IPPROTO_TRUNK1) */
+
+#    if defined(IPPROTO_TRUNK2)
+    case IPPROTO_TRUNK2:
+        s = "TRUNK2";
+        break;
+#    endif /* defined(IPPROTO_TRUNK2) */
+
+#    if defined(IPPROTO_LEAF1)
+    case IPPROTO_LEAF1:
+        s = "LEAF1";
+        break;
+#    endif /* defined(IPPROTO_LEAF1) */
+
+#    if defined(IPPROTO_LEAF2)
+    case IPPROTO_LEAF2:
+        s = "LEAF2";
+        break;
+#    endif /* defined(IPPROTO_LEAF2) */
+
+#    if defined(IPPROTO_RDP)
+    case IPPROTO_RDP:
+        s = "RDP";
+        break;
+#    endif /* defined(IPPROTO_RDP) */
+
+#    if defined(IPPROTO_IRTP)
+    case IPPROTO_IRTP:
+        s = "IRTP";
+        break;
+#    endif /* defined(IPPROTO_IRTP) */
+
+#    if defined(IPPROTO_TP)
+    case IPPROTO_TP:
+        s = "TP";
+        break;
+#    endif /* defined(IPPROTO_TP) */
+
+#    if defined(IPPROTO_BLT)
+    case IPPROTO_BLT:
+        s = "BLT";
+        break;
+#    endif /* defined(IPPROTO_BLT) */
+
+#    if defined(IPPROTO_NSP)
+    case IPPROTO_NSP:
+        s = "NSP";
+        break;
+#    endif /* defined(IPPROTO_NSP) */
+
+#    if defined(IPPROTO_INP)
+    case IPPROTO_INP:
+        s = "INP";
+        break;
+#    endif /* defined(IPPROTO_INP) */
+
+#    if defined(IPPROTO_SEP)
+    case IPPROTO_SEP:
+        s = "SEP";
+        break;
+#    endif /* defined(IPPROTO_SEP) */
+
+#    if defined(IPPROTO_3PC)
+    case IPPROTO_3PC:
+        s = "3PC";
+        break;
+#    endif /* defined(IPPROTO_3PC) */
+
+#    if defined(IPPROTO_IDPR)
+    case IPPROTO_IDPR:
+        s = "IDPR";
+        break;
+#    endif /* defined(IPPROTO_IDPR) */
+
+#    if defined(IPPROTO_XTP)
+    case IPPROTO_XTP:
+        s = "XTP";
+        break;
+#    endif /* defined(IPPROTO_XTP) */
+
+#    if defined(IPPROTO_DDP)
+    case IPPROTO_DDP:
+        s = "DDP";
+        break;
+#    endif /* defined(IPPROTO_DDP) */
+
+#    if defined(IPPROTO_CMTP)
+    case IPPROTO_CMTP:
+        s = "CMTP";
+        break;
+#    endif /* defined(IPPROTO_CMTP) */
+
+#    if defined(IPPROTO_TPXX)
+    case IPPROTO_TPXX:
+        s = "TPXX";
+        break;
+#    endif /* defined(IPPROTO_TPXX) */
+
+#    if defined(IPPROTO_IL)
+    case IPPROTO_IL:
+        s = "IL";
+        break;
+#    endif /* defined(IPPROTO_IL) */
+
+#    if defined(IPPROTO_IPV6)
+    case IPPROTO_IPV6:
+        s = "IPV6";
+        break;
+#    endif /* defined(IPPROTO_IPV6) */
+
+#    if defined(IPPROTO_SDRP)
+    case IPPROTO_SDRP:
+        s = "SDRP";
+        break;
+#    endif /* defined(IPPROTO_SDRP) */
+
+#    if defined(IPPROTO_ROUTING)
+    case IPPROTO_ROUTING:
+        s = "ROUTING";
+        break;
+#    endif /* defined(IPPROTO_ROUTING) */
+
+#    if defined(IPPROTO_FRAGMENT)
+    case IPPROTO_FRAGMENT:
+        s = "FRAGMNT";
+        break;
+#    endif /* defined(IPPROTO_FRAGMENT) */
+
+#    if defined(IPPROTO_IDRP)
+    case IPPROTO_IDRP:
+        s = "IDRP";
+        break;
+#    endif /* defined(IPPROTO_IDRP) */
+
+#    if defined(IPPROTO_RSVP)
+    case IPPROTO_RSVP:
+        s = "RSVP";
+        break;
+#    endif /* defined(IPPROTO_RSVP) */
+
+#    if defined(IPPROTO_GRE)
+    case IPPROTO_GRE:
+        s = "GRE";
+        break;
+#    endif /* defined(IPPROTO_GRE) */
+
+#    if defined(IPPROTO_MHRP)
+    case IPPROTO_MHRP:
+        s = "MHRP";
+        break;
+#    endif /* defined(IPPROTO_MHRP) */
+
+#    if defined(IPPROTO_BHA)
+    case IPPROTO_BHA:
+        s = "BHA";
+        break;
+#    endif /* defined(IPPROTO_BHA) */
+
+#    if defined(IPPROTO_ESP)
+    case IPPROTO_ESP:
+        s = "ESP";
+        break;
+#    endif /* defined(IPPROTO_ESP) */
+
+#    if defined(IPPROTO_AH)
+    case IPPROTO_AH:
+        s = "AH";
+        break;
+#    endif /* defined(IPPROTO_AH) */
+
+#    if defined(IPPROTO_INLSP)
+    case IPPROTO_INLSP:
+        s = "INLSP";
+        break;
+#    endif /* defined(IPPROTO_INLSP) */
+
+#    if defined(IPPROTO_SWIPE)
+    case IPPROTO_SWIPE:
+        s = "SWIPE";
+        break;
+#    endif /* defined(IPPROTO_SWIPE) */
+
+#    if defined(IPPROTO_NHRP)
+    case IPPROTO_NHRP:
+        s = "NHRP";
+        break;
+#    endif /* defined(IPPROTO_NHRP) */
+
+#    if defined(IPPROTO_NONE)
+    case IPPROTO_NONE:
+        s = "NONE";
+        break;
+#    endif /* defined(IPPROTO_NONE) */
+
+#    if defined(IPPROTO_DSTOPTS)
+    case IPPROTO_DSTOPTS:
+        s = "DSTOPTS";
+        break;
+#    endif /* defined(IPPROTO_DSTOPTS) */
+
+#    if defined(IPPROTO_AHIP)
+    case IPPROTO_AHIP:
+        s = "AHIP";
+        break;
+#    endif /* defined(IPPROTO_AHIP) */
+
+#    if defined(IPPROTO_CFTP)
+    case IPPROTO_CFTP:
+        s = "CFTP";
+        break;
+#    endif /* defined(IPPROTO_CFTP) */
+
+#    if defined(IPPROTO_SATEXPAK)
+    case IPPROTO_SATEXPAK:
+        s = "SATEXPK";
+        break;
+#    endif /* defined(IPPROTO_SATEXPAK) */
+
+#    if defined(IPPROTO_KRYPTOLAN)
+    case IPPROTO_KRYPTOLAN:
+        s = "KRYPTOL";
+        break;
+#    endif /* defined(IPPROTO_KRYPTOLAN) */
+
+#    if defined(IPPROTO_RVD)
+    case IPPROTO_RVD:
+        s = "RVD";
+        break;
+#    endif /* defined(IPPROTO_RVD) */
+
+#    if defined(IPPROTO_IPPC)
+    case IPPROTO_IPPC:
+        s = "IPPC";
+        break;
+#    endif /* defined(IPPROTO_IPPC) */
+
+#    if defined(IPPROTO_ADFS)
+    case IPPROTO_ADFS:
+        s = "ADFS";
+        break;
+#    endif /* defined(IPPROTO_ADFS) */
+
+#    if defined(IPPROTO_SATMON)
+    case IPPROTO_SATMON:
+        s = "SATMON";
+        break;
+#    endif /* defined(IPPROTO_SATMON) */
+
+#    if defined(IPPROTO_VISA)
+    case IPPROTO_VISA:
+        s = "VISA";
+        break;
+#    endif /* defined(IPPROTO_VISA) */
+
+#    if defined(IPPROTO_IPCV)
+    case IPPROTO_IPCV:
+        s = "IPCV";
+        break;
+#    endif /* defined(IPPROTO_IPCV) */
+
+#    if defined(IPPROTO_CPNX)
+    case IPPROTO_CPNX:
+        s = "CPNX";
+        break;
+#    endif /* defined(IPPROTO_CPNX) */
+
+#    if defined(IPPROTO_CPHB)
+    case IPPROTO_CPHB:
+        s = "CPHB";
+        break;
+#    endif /* defined(IPPROTO_CPHB) */
+
+#    if defined(IPPROTO_WSN)
+    case IPPROTO_WSN:
+        s = "WSN";
+        break;
+#    endif /* defined(IPPROTO_WSN) */
+
+#    if defined(IPPROTO_PVP)
+    case IPPROTO_PVP:
+        s = "PVP";
+        break;
+#    endif /* defined(IPPROTO_PVP) */
+
+#    if defined(IPPROTO_BRSATMON)
+    case IPPROTO_BRSATMON:
+        s = "BRSATMN";
+        break;
+#    endif /* defined(IPPROTO_BRSATMON) */
+
+#    if defined(IPPROTO_WBMON)
+    case IPPROTO_WBMON:
+        s = "WBMON";
+        break;
+#    endif /* defined(IPPROTO_WBMON) */
+
+#    if defined(IPPROTO_WBEXPAK)
+    case IPPROTO_WBEXPAK:
+        s = "WBEXPAK";
+        break;
+#    endif /* defined(IPPROTO_WBEXPAK) */
+
+#    if defined(IPPROTO_EON)
+    case IPPROTO_EON:
+        s = "EON";
+        break;
+#    endif /* defined(IPPROTO_EON) */
+
+#    if defined(IPPROTO_VMTP)
+    case IPPROTO_VMTP:
+        s = "VMTP";
+        break;
+#    endif /* defined(IPPROTO_VMTP) */
+
+#    if defined(IPPROTO_SVMTP)
+    case IPPROTO_SVMTP:
+        s = "SVMTP";
+        break;
+#    endif /* defined(IPPROTO_SVMTP) */
+
+#    if defined(IPPROTO_VINES)
+    case IPPROTO_VINES:
+        s = "VINES";
+        break;
+#    endif /* defined(IPPROTO_VINES) */
+
+#    if defined(IPPROTO_TTP)
+    case IPPROTO_TTP:
+        s = "TTP";
+        break;
+#    endif /* defined(IPPROTO_TTP) */
+
+#    if defined(IPPROTO_IGP)
+    case IPPROTO_IGP:
+        s = "IGP";
+        break;
+#    endif /* defined(IPPROTO_IGP) */
+
+#    if defined(IPPROTO_DGP)
+    case IPPROTO_DGP:
+        s = "DGP";
+        break;
+#    endif /* defined(IPPROTO_DGP) */
+
+#    if defined(IPPROTO_TCF)
+    case IPPROTO_TCF:
+        s = "TCF";
+        break;
+#    endif /* defined(IPPROTO_TCF) */
+
+#    if defined(IPPROTO_IGRP)
+    case IPPROTO_IGRP:
+        s = "IGRP";
+        break;
+#    endif /* defined(IPPROTO_IGRP) */
+
+#    if defined(IPPROTO_OSPFIGP)
+    case IPPROTO_OSPFIGP:
+        s = "OSPFIGP";
+        break;
+#    endif /* defined(IPPROTO_OSPFIGP) */
+
+#    if defined(IPPROTO_SRPC)
+    case IPPROTO_SRPC:
+        s = "SRPC";
+        break;
+#    endif /* defined(IPPROTO_SRPC) */
+
+#    if defined(IPPROTO_LARP)
+    case IPPROTO_LARP:
+        s = "LARP";
+        break;
+#    endif /* defined(IPPROTO_LARP) */
+
+#    if defined(IPPROTO_MTP)
+    case IPPROTO_MTP:
+        s = "MTP";
+        break;
+#    endif /* defined(IPPROTO_MTP) */
+
+#    if defined(IPPROTO_AX25)
+    case IPPROTO_AX25:
+        s = "AX25";
+        break;
+#    endif /* defined(IPPROTO_AX25) */
+
+#    if defined(IPPROTO_IPEIP)
+    case IPPROTO_IPEIP:
+        s = "IPEIP";
+        break;
+#    endif /* defined(IPPROTO_IPEIP) */
+
+#    if defined(IPPROTO_MICP)
+    case IPPROTO_MICP:
+        s = "MICP";
+        break;
+#    endif /* defined(IPPROTO_MICP) */
+
+#    if defined(IPPROTO_SCCSP)
+    case IPPROTO_SCCSP:
+        s = "SCCSP";
+        break;
+#    endif /* defined(IPPROTO_SCCSP) */
+
+#    if defined(IPPROTO_ETHERIP)
+    case IPPROTO_ETHERIP:
+        s = "ETHERIP";
+        break;
+#    endif /* defined(IPPROTO_ETHERIP) */
+
+#    if defined(IPPROTO_ENCAP)
+#        if !defined(IPPROTO_IPIP) || IPPROTO_IPIP != IPPROTO_ENCAP
+    case IPPROTO_ENCAP:
+        s = "ENCAP";
+        break;
+#        endif /* !defined(IPPROTO_IPIP) || IPPROTO_IPIP!=IPPROTO_ENCAP */
+#    endif     /* defined(IPPROTO_ENCAP) */
+
+#    if defined(IPPROTO_APES)
+    case IPPROTO_APES:
+        s = "APES";
+        break;
+#    endif /* defined(IPPROTO_APES) */
+
+#    if defined(IPPROTO_GMTP)
+    case IPPROTO_GMTP:
+        s = "GMTP";
+        break;
+#    endif /* defined(IPPROTO_GMTP) */
+
+#    if defined(IPPROTO_DIVERT)
+    case IPPROTO_DIVERT:
+        s = "DIVERT";
+        break;
+#    endif /* defined(IPPROTO_DIVERT) */
+
+    default:
+        s = (char *)NULL;
+    }
+    if (s)
+        (void)snpf(Lf->iproto, sizeof(Lf->iproto), "%.*s", IPROTOL - 1, s);
+    else {
+        if (m < 0) {
+            for (i = 0, m = 1; i < IPROTOL - 2; i++)
+                m *= 10;
+        }
+        if (m > p)
+            (void)snpf(Lf->iproto, sizeof(Lf->iproto), "%d?", p);
+        else
+            (void)snpf(Lf->iproto, sizeof(Lf->iproto), "*%d?", p % (m / 10));
+    }
+}
+#endif /* !defined(HASPRIVPRIPP) */
+
+/*
+ * printunkaf() - print unknown address family
+ */
+
+void printunkaf(struct lsof_context *ctx, int fam, /* unknown address family */
+                int ty) /* output type: 0 = terse; 1 = full */
+{
+    char *p, *s;
+
+    p = "";
+    switch (fam) {
+
+#if defined(AF_UNSPEC)
+    case AF_UNSPEC:
+        s = "UNSPEC";
+        break;
+#endif /* defined(AF_UNSPEC) */
+
+#if defined(AF_UNIX)
+    case AF_UNIX:
+        s = "UNIX";
+        break;
+#endif /* defined(AF_UNIX) */
+
+#if defined(AF_INET)
+    case AF_INET:
+        s = "INET";
+        break;
+#endif /* defined(AF_INET) */
+
+#if defined(AF_INET6)
+    case AF_INET6:
+        s = "INET6";
+        break;
+#endif /* defined(AF_INET6) */
+
+#if defined(AF_IMPLINK)
+    case AF_IMPLINK:
+        s = "IMPLINK";
+        break;
+#endif /* defined(AF_IMPLINK) */
+
+#if defined(AF_PUP)
+    case AF_PUP:
+        s = "PUP";
+        break;
+#endif /* defined(AF_PUP) */
+
+#if defined(AF_CHAOS)
+    case AF_CHAOS:
+        s = "CHAOS";
+        break;
+#endif /* defined(AF_CHAOS) */
+
+#if defined(AF_NS)
+    case AF_NS:
+        s = "NS";
+        break;
+#endif /* defined(AF_NS) */
+
+#if defined(AF_ISO)
+    case AF_ISO:
+        s = "ISO";
+        break;
+#endif /* defined(AF_ISO) */
+
+#if defined(AF_NBS)
+#    if !defined(AF_ISO) || AF_NBS != AF_ISO
+    case AF_NBS:
+        s = "NBS";
+        break;
+#    endif /* !defined(AF_ISO) || AF_NBS!=AF_ISO */
+#endif     /* defined(AF_NBS) */
+
+#if defined(AF_ECMA)
+    case AF_ECMA:
+        s = "ECMA";
+        break;
+#endif /* defined(AF_ECMA) */
+
+#if defined(AF_DATAKIT)
+    case AF_DATAKIT:
+        s = "DATAKIT";
+        break;
+#endif /* defined(AF_DATAKIT) */
+
+#if defined(AF_CCITT)
+    case AF_CCITT:
+        s = "CCITT";
+        break;
+#endif /* defined(AF_CCITT) */
+
+#if defined(AF_SNA)
+    case AF_SNA:
+        s = "SNA";
+        break;
+#endif /* defined(AF_SNA) */
+
+#if defined(AF_DECnet)
+    case AF_DECnet:
+        s = "DECnet";
+        break;
+#endif /* defined(AF_DECnet) */
+
+#if defined(AF_DLI)
+    case AF_DLI:
+        s = "DLI";
+        break;
+#endif /* defined(AF_DLI) */
+
+#if defined(AF_LAT)
+    case AF_LAT:
+        s = "LAT";
+        break;
+#endif /* defined(AF_LAT) */
+
+#if defined(AF_HYLINK)
+    case AF_HYLINK:
+        s = "HYLINK";
+        break;
+#endif /* defined(AF_HYLINK) */
+
+#if defined(AF_APPLETALK)
+    case AF_APPLETALK:
+        s = "APPLETALK";
+        break;
+#endif /* defined(AF_APPLETALK) */
+
+#if defined(AF_BSC)
+    case AF_BSC:
+        s = "BSC";
+        break;
+#endif /* defined(AF_BSC) */
+
+#if defined(AF_DSS)
+    case AF_DSS:
+        s = "DSS";
+        break;
+#endif /* defined(AF_DSS) */
+
+#if defined(AF_ROUTE)
+    case AF_ROUTE:
+        s = "ROUTE";
+        break;
+#endif /* defined(AF_ROUTE) */
+
+#if defined(AF_RAW)
+    case AF_RAW:
+        s = "RAW";
+        break;
+#endif /* defined(AF_RAW) */
+
+#if defined(AF_LINK)
+    case AF_LINK:
+        s = "LINK";
+        break;
+#endif /* defined(AF_LINK) */
+
+#if defined(pseudo_AF_XTP)
+    case pseudo_AF_XTP:
+        p = "pseudo_";
+        s = "XTP";
+        break;
+#endif /* defined(pseudo_AF_XTP) */
+
+#if defined(AF_RMP)
+    case AF_RMP:
+        s = "RMP";
+        break;
+#endif /* defined(AF_RMP) */
+
+#if defined(AF_COIP)
+    case AF_COIP:
+        s = "COIP";
+        break;
+#endif /* defined(AF_COIP) */
+
+#if defined(AF_CNT)
+    case AF_CNT:
+        s = "CNT";
+        break;
+#endif /* defined(AF_CNT) */
+
+#if defined(pseudo_AF_RTIP)
+    case pseudo_AF_RTIP:
+        p = "pseudo_";
+        s = "RTIP";
+        break;
+#endif /* defined(pseudo_AF_RTIP) */
+
+#if defined(AF_NETMAN)
+    case AF_NETMAN:
+        s = "NETMAN";
+        break;
+#endif /* defined(AF_NETMAN) */
+
+#if defined(AF_INTF)
+    case AF_INTF:
+        s = "INTF";
+        break;
+#endif /* defined(AF_INTF) */
+
+#if defined(AF_NETWARE)
+    case AF_NETWARE:
+        s = "NETWARE";
+        break;
+#endif /* defined(AF_NETWARE) */
+
+#if defined(AF_NDD)
+    case AF_NDD:
+        s = "NDD";
+        break;
+#endif /* defined(AF_NDD) */
+
+#if defined(AF_NIT)
+#    if !defined(AF_ROUTE) || AF_ROUTE != AF_NIT
+    case AF_NIT:
+        s = "NIT";
+        break;
+#    endif /* !defined(AF_ROUTE) || AF_ROUTE!=AF_NIT */
+#endif     /* defined(AF_NIT) */
+
+#if defined(AF_802)
+#    if !defined(AF_RAW) || AF_RAW != AF_802
+    case AF_802:
+        s = "802";
+        break;
+#    endif /* !defined(AF_RAW) || AF_RAW!=AF_802 */
+#endif     /* defined(AF_802) */
+
+#if defined(AF_X25)
+    case AF_X25:
+        s = "X25";
+        break;
+#endif /* defined(AF_X25) */
+
+#if defined(AF_CTF)
+    case AF_CTF:
+        s = "CTF";
+        break;
+#endif /* defined(AF_CTF) */
+
+#if defined(AF_WAN)
+    case AF_WAN:
+        s = "WAN";
+        break;
+#endif /* defined(AF_WAN) */
+
+#if defined(AF_OSINET)
+#    if defined(AF_INET) && AF_INET != AF_OSINET
+    case AF_OSINET:
+        s = "OSINET";
+        break;
+#    endif /* defined(AF_INET) && AF_INET!=AF_OSINET */
+#endif     /* defined(AF_OSINET) */
+
+#if defined(AF_GOSIP)
+    case AF_GOSIP:
+        s = "GOSIP";
+        break;
+#endif /* defined(AF_GOSIP) */
+
+#if defined(AF_SDL)
+    case AF_SDL:
+        s = "SDL";
+        break;
+#endif /* defined(AF_SDL) */
+
+#if defined(AF_IPX)
+    case AF_IPX:
+        s = "IPX";
+        break;
+#endif /* defined(AF_IPX) */
+
+#if defined(AF_SIP)
+    case AF_SIP:
+        s = "SIP";
+        break;
+#endif /* defined(AF_SIP) */
+
+#if defined(psuedo_AF_PIP)
+    case psuedo_AF_PIP:
+        p = "pseudo_";
+        s = "PIP";
+        break;
+#endif /* defined(psuedo_AF_PIP) */
+
+#if defined(AF_OTS)
+    case AF_OTS:
+        s = "OTS";
+        break;
+#endif /* defined(AF_OTS) */
+
+#if defined(pseudo_AF_BLUE)
+    case pseudo_AF_BLUE: /* packets for Blue box */
+        p = "pseudo_";
+        s = "BLUE";
+        break;
+#endif /* defined(pseudo_AF_BLUE) */
+
+#if defined(AF_NDRV) /* network driver raw access */
+    case AF_NDRV:
+        s = "NDRV";
+        break;
+#endif /* defined(AF_NDRV) */
+
+#if defined(AF_SYSTEM) /* kernel event messages */
+    case AF_SYSTEM:
+        s = "SYSTEM";
+        break;
+#endif /* defined(AF_SYSTEM) */
+
+#if defined(AF_USER)
+    case AF_USER:
+        s = "USER";
+        break;
+#endif /* defined(AF_USER) */
+
+#if defined(pseudo_AF_KEY)
+    case pseudo_AF_KEY:
+        p = "pseudo_";
+        s = "KEY";
+        break;
+#endif /* defined(pseudo_AF_KEY) */
+
+#if defined(AF_KEY) /* Security Association DB socket */
+    case AF_KEY:
+        s = "KEY";
+        break;
+#endif /* defined(AF_KEY) */
+
+#if defined(AF_NCA) /* NCA socket */
+    case AF_NCA:
+        s = "NCA";
+        break;
+#endif /* defined(AF_NCA) */
+
+#if defined(AF_POLICY) /* Security Policy DB socket */
+    case AF_POLICY:
+        s = "POLICY";
+        break;
+#endif /* defined(AF_POLICY) */
+
+#if defined(AF_PPP) /* PPP socket */
+    case AF_PPP:
+        s = "PPP";
+        break;
+#endif /* defined(AF_PPP) */
+
+    default:
+        if (!ty)
+            (void)snpf(Namech, Namechl, "%#x", fam);
+        else
+            (void)snpf(Namech, Namechl, "no further information on family %#x",
+                       fam);
+        return;
+    }
+    if (!ty)
+        (void)snpf(Namech, Namechl, "%sAF_%s", p, s);
+    else
+        (void)snpf(Namech, Namechl, "no further information on %sAF_%s", p, s);
+    return;
+}
diff --git a/lib/proc.c b/lib/proc.c
new file mode 100644 (file)
index 0000000..aab349c
--- /dev/null
@@ -0,0 +1,1402 @@
+/*
+ * proc.c - common process and file structure functions for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#include "common.h"
+#include "dlsof.h"
+#include "lsof.h"
+#include "proto.h"
+
+#if defined(HASEPTOPTS)
+static void prt_pinfo(struct lsof_context *ctx, pxinfo_t *pp, int ps);
+static void prt_psxmqinfo(struct lsof_context *ctx, pxinfo_t *pp, int ps);
+static void prt_evtfdinfo(struct lsof_context *ctx, pxinfo_t *pp, int ps);
+#endif /* defined(HASEPTOPTS) */
+#if defined(HASPTYEPT)
+static void prt_ptyinfo(struct lsof_context *ctx, pxinfo_t *pp, int prt_edev,
+                        int ps);
+#endif /* defined(HASPTYEPT) */
+
+/*
+ * add_nma() - add to NAME column addition
+ */
+
+void add_nma(struct lsof_context *ctx, char *cp, /* string to add */
+             int len)                            /* string length */
+{
+    int nl;
+    char fd[FDLEN];
+
+    if (!cp || !len)
+        return;
+    if (Lf->nma) {
+        nl = (int)strlen(Lf->nma);
+        Lf->nma =
+            (char *)realloc((MALLOC_P *)Lf->nma, (MALLOC_S)(len + nl + 2));
+    } else {
+        nl = 0;
+        Lf->nma = (char *)malloc((MALLOC_S)(len + 1));
+    }
+    if (!Lf->nma) {
+        fd_to_string(Lf->fd_type, Lf->fd_num, fd);
+        (void)fprintf(stderr, "%s: no name addition space: PID %ld, FD %s", Pn,
+                      (long)Lp->pid, fd);
+        Error(ctx);
+    }
+    if (nl) {
+        Lf->nma[nl] = ' ';
+        (void)strncpy(&Lf->nma[nl + 1], cp, len);
+        Lf->nma[nl + 1 + len] = '\0';
+    } else {
+        (void)strncpy(Lf->nma, cp, len);
+        Lf->nma[len] = '\0';
+    }
+}
+
+/*
+ * alloc_lfile() - allocate local file structure space
+ */
+
+void alloc_lfile(struct lsof_context *ctx,
+                 enum lsof_fd_type fd_type, /* file descriptor type */
+                 int num)                   /* file descriptor number -- -1 if
+                                             * none */
+{
+    int fds;
+
+    if (Lf) {
+        /*
+         * If reusing a previously allocated structure, release any allocated
+         * space it was using.
+         */
+        if (Lf->dev_ch)
+            (void)free((FREE_P *)Lf->dev_ch);
+        if (Lf->nm)
+            (void)free((FREE_P *)Lf->nm);
+        if (Lf->nma)
+            (void)free((FREE_P *)Lf->nma);
+
+#if defined(HASLFILEADD) && defined(CLRLFILEADD)
+        CLRLFILEADD(Lf)
+#endif /* defined(HASLFILEADD) && defined(CLRLFILEADD) */
+
+        /*
+         * Othwerise, allocate a new structure.
+         */
+    } else if (!(Lf = (struct lfile *)malloc(sizeof(struct lfile)))) {
+        (void)fprintf(stderr, "%s: no local file space at PID %d\n", Pn,
+                      Lp->pid);
+        Error(ctx);
+    }
+    /*
+     * Initialize the structure.
+     */
+    Lf->access = LSOF_FILE_ACCESS_NONE;
+    Lf->lock = LSOF_LOCK_NONE;
+    Lf->dev_def = Lf->inp_ty = Lf->is_com = Lf->is_nfs = Lf->is_stream =
+        Lf->lmi_srch = Lf->nlink_def = Lf->off_def = Lf->sz_def = Lf->rdev_def =
+            (unsigned char)0;
+    Lf->li[0].af = Lf->li[1].af = 0;
+    Lf->lts.type = -1;
+    Lf->nlink = 0l;
+
+#if defined(HASMNTSTAT)
+    Lf->mnt_stat = (unsigned char)0;
+#endif /* defined(HASMNTSTAT) */
+
+#if defined(HASEPTOPTS)
+    Lf->chend = 0;
+    Lf->eventfd_id = -1;
+#    if defined(HASPTYEPT)
+    Lf->tty_index = -1;
+#    endif /* defined(HASPTYEPT) */
+#endif     /* defined(HASEPTOPTS) */
+
+#if defined(HASSOOPT)
+    Lf->lts.kai = Lf->lts.ltm = 0;
+    Lf->lts.opt = Lf->lts.qlen = Lf->lts.qlim = Lf->lts.pqlen = (unsigned int)0;
+    Lf->lts.rbsz = Lf->lts.sbsz = (unsigned long)0;
+    Lf->lts.qlens = Lf->lts.qlims = Lf->lts.pqlens = Lf->lts.rbszs =
+        Lf->lts.sbszs = (unsigned char)0;
+#endif /* defined(HASSOOPT) */
+
+#if defined(HASSOSTATE)
+    Lf->lts.ss = 0;
+#endif /* defined(HASSOSTATE) */
+
+#if defined(HASTCPOPT)
+    Lf->lts.mss = (unsigned long)0;
+    Lf->lts.msss = (unsigned char)0;
+    Lf->lts.topt = (unsigned int)0;
+#endif /* defined(HASTCPOPT) */
+
+#if defined(HASTCPTPIQ)
+    Lf->lts.rqs = Lf->lts.sqs = (unsigned char)0;
+#endif /* defined(HASTCPTPIQ) */
+
+#if defined(HASTCPTPIW)
+    Lf->lts.rws = Lf->lts.wws = (unsigned char)0;
+#endif /* defined(HASTCPTPIW) */
+
+#if defined(HASFSINO)
+    Lf->fs_ino = 0;
+#endif /* defined(HASFSINO) */
+
+#if defined(HASVXFS) && defined(HASVXFSDNLC)
+    Lf->is_vxfs = 0;
+#endif /* defined(HASVXFS) && defined(HASVXFSDNLC) */
+
+    Lf->inode = (INODETYPE)0;
+    Lf->off = (SZOFFTYPE)0;
+    if (Lp->pss & PS_PRI)
+        Lf->sf = Lp->sf;
+    else
+        Lf->sf = 0;
+    Lf->iproto[0] = '\0';
+    Lf->type = LSOF_FILE_NONE;
+    Lf->unknown_file_type_number = 0;
+    Lf->fd_type = fd_type;
+    Lf->fd_num = num;
+    Lf->dev_ch = Lf->fsdir = Lf->fsdev = Lf->nm = Lf->nma = (char *)NULL;
+    Lf->ch = -1;
+
+#if defined(HASNCACHE) && HASNCACHE < 2
+    Lf->na = (KA_T)NULL;
+#endif /* defined(HASNCACHE) && HASNCACHE<2 */
+
+    Lf->next = (struct lfile *)NULL;
+    Lf->ntype = Ntype = N_REGLR;
+    Namech[0] = '\0';
+
+#if defined(HASFSTRUCT)
+    Lf->fct = Lf->ffg = Lf->pof = (long)0;
+    Lf->fna = (KA_T)NULL;
+    Lf->fsv = (unsigned char)0;
+#endif /* defined(HASFSTRUCT) */
+
+#if defined(HASLFILEADD) && defined(SETLFILEADD)
+    /*
+     * Do local initializations.
+     */
+    SETLFILEADD
+#endif /* defined(HASLFILEADD) && defined(SETLFILEADD) */
+
+    /*
+     * See if the file descriptor has been selected.
+     */
+    if (!Fdl || (fd_type == LSOF_FD_NUMERIC && num < 0))
+        return;
+    fds = ck_fd_status(ctx, fd_type, num);
+    switch (FdlTy) {
+    case 0: /* inclusion list */
+        if (fds == 2)
+            Lf->sf |= SELFD;
+        break;
+    case 1: /* exclusion list */
+        if (fds != 1)
+            Lf->sf |= SELFD;
+    }
+}
+
+/*
+ * alloc_lproc() - allocate local proc structure space
+ */
+
+void alloc_lproc(struct lsof_context *ctx, int pid, /* Process ID */
+                 int pgid,                          /* process group ID */
+                 int ppid,                          /* parent process ID */
+                 UID_ARG uid,                       /* User ID */
+                 char *cmd,                         /* command */
+                 int pss,                           /* process select state */
+                 int sf)                            /* process select flags */
+{
+    static int sz = 0;
+
+    if (!Lproc) {
+        if (!(Lproc = (struct lproc *)malloc(
+                  (MALLOC_S)(LPROCINCR * sizeof(struct lproc))))) {
+            (void)fprintf(stderr,
+                          "%s: no malloc space for %d local proc structures\n",
+                          Pn, LPROCINCR);
+            Error(ctx);
+        }
+        sz = LPROCINCR;
+    } else if ((Nlproc + 1) > sz) {
+        sz += LPROCINCR;
+        if (!(Lproc = (struct lproc *)realloc(
+                  (MALLOC_P *)Lproc, (MALLOC_S)(sz * sizeof(struct lproc))))) {
+            (void)fprintf(stderr,
+                          "%s: no realloc space for %d local proc structures\n",
+                          Pn, sz);
+            Error(ctx);
+        }
+    }
+    Lp = &Lproc[Nlproc++];
+    Lp->pid = pid;
+
+#if defined(HASEPTOPTS)
+    Lp->ept = 0;
+#endif /* defined(HASEPTOPTS) */
+
+#if defined(HASTASKS)
+    Lp->tid = 0;
+    Lp->tcmd = (char *)NULL;
+#endif /* defined(HASTASKS) */
+
+    Lp->pgid = pgid;
+    Lp->ppid = ppid;
+    Lp->file = (struct lfile *)NULL;
+    Lp->sf = (short)sf;
+    Lp->pss = (short)pss;
+    Lp->uid = (uid_t)uid;
+    /*
+     * Allocate space for the full command name and copy it there.
+     */
+    if (!(Lp->cmd = mkstrcpy(cmd, (MALLOC_S *)NULL))) {
+        (void)fprintf(stderr, "%s: PID %d, no space for command name: ", Pn,
+                      pid);
+        safestrprt(cmd, stderr, 1);
+        Error(ctx);
+    }
+
+#if defined(HASZONES)
+    /*
+     * Clear the zone name pointer.  The dialect's own code will set it.
+     */
+    Lp->zn = (char *)NULL;
+#endif /* defined(HASZONES) */
+
+#if defined(HASSELINUX)
+    /*
+     * Clear the security context pointer.  The dialect's own code will
+     * set it.
+     */
+    Lp->cntx = (char *)NULL;
+#endif /* defined(HASSELINUX) */
+}
+
+/*
+ * ck_fd_status() - check FD status
+ *
+ * return: 0 == FD is neither included nor excluded
+ *        1 == FD is excluded
+ *        2 == FD is included
+ */
+
+extern int ck_fd_status(struct lsof_context *ctx,
+                        enum lsof_fd_type fd_type, /* file descriptor type */
+                        int num) /* file descriptor number -- -1 if
+                                  * none */
+{
+    struct fd_lst *fp;
+
+    if (!(fp = Fdl) || (fd_type == LSOF_FD_NUMERIC && num < 0))
+        return (0);
+    /*
+     * Check for an exclusion match.
+     */
+    if (FdlTy == 1) {
+        for (; fp; fp = fp->next) {
+            if (fp->fd_type != fd_type)
+                continue;
+            if (fp->fd_type == LSOF_FD_NUMERIC) {
+                if (num >= fp->lo && num <= fp->hi)
+                    return (1);
+            } else {
+                return (1);
+            }
+        }
+        return (0);
+    }
+    /*
+     * If Fdl isn't an exclusion list, check for an inclusion match.
+     */
+    for (; fp; fp = fp->next) {
+        if (fp->fd_type != fd_type)
+            continue;
+        if (fp->fd_type == LSOF_FD_NUMERIC) {
+            if (num >= fp->lo && num <= fp->hi)
+                return (2);
+        } else {
+            return (2);
+        }
+    }
+    return (0);
+}
+
+/*
+ * comppid() - compare PIDs
+ */
+
+int comppid(COMP_P *a1, COMP_P *a2) {
+    struct lproc **p1 = (struct lproc **)a1;
+    struct lproc **p2 = (struct lproc **)a2;
+
+    if ((*p1)->pid < (*p2)->pid)
+        return (-1);
+    if ((*p1)->pid > (*p2)->pid)
+        return (1);
+
+#if defined(HASTASKS)
+    if ((*p1)->tid < (*p2)->tid)
+        return (-1);
+    if ((*p1)->tid > (*p2)->tid)
+        return (1);
+#endif /* defined(HASTASKS) */
+
+    return (0);
+}
+
+/*
+ * ent_inaddr() - enter Internet addresses
+ */
+
+void ent_inaddr(struct lsof_context *ctx,
+                unsigned char *la, /* local Internet address */
+                int lp,            /* local port */
+                unsigned char *fa, /* foreign Internet address -- may
+                                    * be NULL to indicate no foreign
+                                    * address is known */
+                int fp,            /* foreign port */
+                int af)            /* address family -- e.g, AF_INET,
+                                    * AF_INET */
+{
+    int m;
+
+    if (la) {
+        Lf->li[0].af = af;
+
+#if defined(HASIPv6)
+        if (af == AF_INET6)
+            Lf->li[0].ia.a6 = *(struct in6_addr *)la;
+        else
+#endif /* defined(HASIPv6) */
+
+            Lf->li[0].ia.a4 = *(struct in_addr *)la;
+        Lf->li[0].p = lp;
+    } else
+        Lf->li[0].af = 0;
+    if (fa) {
+        Lf->li[1].af = af;
+
+#if defined(HASIPv6)
+        if (af == AF_INET6)
+            Lf->li[1].ia.a6 = *(struct in6_addr *)fa;
+        else
+#endif /* defined(HASIPv6) */
+
+            Lf->li[1].ia.a4 = *(struct in_addr *)fa;
+        Lf->li[1].p = fp;
+    } else
+        Lf->li[1].af = 0;
+    /*
+     * If network address matching has been selected, check both addresses.
+     */
+    if ((Selflags & SELNA) && Nwad) {
+        m = (fa && is_nw_addr(ctx, fa, fp, af)) ? 1 : 0;
+        m |= (la && is_nw_addr(ctx, la, lp, af)) ? 1 : 0;
+        if (m)
+            Lf->sf |= SELNA;
+    }
+}
+
+/*
+ * examine_lproc() - examine local process
+ *
+ * return: 1 = last process
+ */
+
+int examine_lproc(struct lsof_context *ctx) {
+    int sbp = 0;
+
+    if (RptTm)
+        return (0);
+    /*
+     * List the process if the process is selected and:
+     *
+     * o  listing is limited to a single PID selection -- this one;
+     *
+     * o  listing is selected by an ANDed option set (not all options)
+     *    that includes a single PID selection -- this one.
+     */
+    if ((Lp->sf & SELPID) && !AllProc) {
+        if ((Selflags == SELPID) || (Fand && (Selflags & SELPID))) {
+            sbp = 1;
+            Npuns--;
+        }
+    }
+    /*
+     * Deprecate an unselected (or listed) process.
+     */
+    if (!Lp->pss) {
+        (void)free_lproc(Lp);
+        Nlproc--;
+    }
+    /*
+     * Indicate last-process if listing is limited to PID selections,
+     * and all selected processes have been listed.
+     */
+    return ((sbp && Npuns == 0) ? 1 : 0);
+}
+
+/*
+ * free_lproc() - free lproc entry and its associated malloc'd space
+ */
+
+void free_lproc(struct lproc *lp) {
+    struct lfile *lf, *nf;
+
+    for (lf = lp->file; lf; lf = nf) {
+        if (lf->dev_ch) {
+            (void)free((FREE_P *)lf->dev_ch);
+            lf->dev_ch = (char *)NULL;
+        }
+        if (lf->nm) {
+            (void)free((FREE_P *)lf->nm);
+            lf->nm = (char *)NULL;
+        }
+        if (lf->nma) {
+            (void)free((FREE_P *)lf->nma);
+            lf->nma = (char *)NULL;
+        }
+
+#if defined(HASLFILEADD) && defined(CLRLFILEADD)
+        CLRLFILEADD(lf)
+#endif /* defined(HASLFILEADD) && defined(CLRLFILEADD) */
+
+        nf = lf->next;
+        (void)free((FREE_P *)lf);
+    }
+    lp->file = (struct lfile *)NULL;
+    if (lp->cmd) {
+        (void)free((FREE_P *)lp->cmd);
+        lp->cmd = (char *)NULL;
+    }
+
+#if defined(HASTASKS)
+    if (lp->tcmd) {
+        (void)free((FREE_P *)lp->tcmd);
+        lp->tcmd = (char *)NULL;
+    }
+#endif /* defined(HASTASKS) */
+}
+
+/*
+ * is_cmd_excl() - is command excluded?
+ */
+
+int is_cmd_excl(struct lsof_context *ctx, char *cmd, /* command name */
+                short *pss,                          /* process state */
+                short *sf)                           /* process select flags */
+{
+    int i;
+    struct str_lst *sp;
+    /*
+     * See if the command is excluded by a "-c^<command>" option.
+     */
+    if (Cmdl && Cmdnx) {
+        for (sp = Cmdl; sp; sp = sp->next) {
+            if (sp->x && !strncmp(sp->str, cmd, sp->len))
+                return (1);
+        }
+    }
+    /*
+     * The command is not excluded if no command selection was requested,
+     * or if its name matches any -c <command> specification.
+     *
+     */
+    if ((Selflags & SELCMD) == 0)
+        return (0);
+    for (sp = Cmdl; sp; sp = sp->next) {
+        if (!sp->x && !strncmp(sp->str, cmd, sp->len)) {
+            sp->f = 1;
+            *pss |= PS_PRI;
+            *sf |= SELCMD;
+            return (0);
+        }
+    }
+    /*
+     * The command name doesn't match any -c <command> specification.  See if it
+     * matches a -c /RE/[bix] specification.
+     */
+    for (i = 0; i < NCmdRxU; i++) {
+        if (!regexec(&CmdRx[i].cx, cmd, 0, NULL, 0)) {
+            CmdRx[i].mc = 1;
+            *pss |= PS_PRI;
+            *sf |= SELCMD;
+            return (0);
+        }
+    }
+    /*
+     * The command name matches no -c specification.
+     *
+     * It's excluded if the only selection condition is command name,
+     * or if command name selection is part of an ANDed set.
+     */
+    if (Selflags == SELCMD)
+        return (1);
+    return (Fand ? 1 : 0);
+}
+
+/*
+ * is_file_sel() - is file selected?
+ */
+
+int is_file_sel(struct lsof_context *ctx, /* context */
+                struct lproc *lp,         /* lproc structure pointer */
+                struct lfile *lf)         /* lfile structure pointer */
+{
+    if (!lf || !lf->sf)
+        return (0);
+    if (lf->sf & SELEXCLF)
+        return (0);
+
+#if defined(HASSECURITY) && defined(HASNOSOCKSECURITY)
+    if (Myuid && (Myuid != lp->uid)) {
+        if (!(lf->sf & (SELNA | SELNET)))
+            return (0);
+    }
+#endif /* defined(HASSECURITY) && defined(HASNOSOCKSECURITY) */
+
+    if (AllProc)
+        return (1);
+    if (Fand && ((lf->sf & Selflags) != Selflags))
+        return (0);
+    return (1);
+}
+
+/*
+ * is_proc_excl() - is process excluded?
+ */
+
+int is_proc_excl(struct lsof_context *ctx, int pid, /* Process ID */
+                 int pgid,                          /* process group ID */
+                 UID_ARG uid,                       /* User ID */
+                 short *pss, /* process select state for lproc */
+#if defined(HASTASKS)
+                 short *sf, /* select flags for lproc */
+                 int tid)   /* task ID (not a task if zero) */
+#else
+                 short *sf) /* select flags for lproc */
+#endif /* defined(HASTASKS) */
+
+{
+    int i, j;
+
+    *pss = *sf = 0;
+
+#if defined(HASSECURITY)
+/*
+ * The process is excluded by virtue of the security option if it
+ * isn't owned by the owner of this lsof process, unless the
+ * HASNOSOCKSECURITY option is also specified.  In that case the
+ * selected socket files of any process may be listed.
+ */
+#    if !defined(HASNOSOCKSECURITY)
+    if (Myuid && Myuid != (uid_t)uid)
+        return (1);
+#    endif /* !defined(HASNOSOCKSECURITY) */
+#endif     /* defined(HASSECURITY) */
+
+    /*
+     * If the excluding of process listing by UID has been specified, see if the
+     * owner of this process is excluded.
+     */
+    if (Nuidexcl) {
+        for (i = j = 0; (i < Nuid) && (j < Nuidexcl); i++) {
+            if (!Suid[i].excl)
+                continue;
+            if (Suid[i].uid == (uid_t)uid)
+                return (1);
+            j++;
+        }
+    }
+    /*
+     * If the excluding of process listing by PGID has been specified, see if
+     * this PGID is excluded.
+     */
+    if (Npgidx) {
+        for (i = j = 0; (i < Npgid) && (j < Npgidx); i++) {
+            if (!Spgid[i].x)
+                continue;
+            if (Spgid[i].i == pgid)
+                return (1);
+            j++;
+        }
+    }
+    /*
+     * If the excluding of process listing by PID has been specified, see if
+     * this PID is excluded.
+     */
+    if (Npidx) {
+        for (i = j = 0; (i < Npid) && (j < Npidx); i++) {
+            if (!Spid[i].x)
+                continue;
+            if (Spid[i].i == pid)
+                return (1);
+            j++;
+        }
+    }
+    /*
+     * If the listing of all processes is selected, then this one is not
+     * excluded.
+     *
+     * However, if HASSECURITY and HASNOSOCKSECURITY are both specified, exclude
+     * network selections from the file flags, so that the tests in
+     * is_file_sel() work as expected.
+     */
+    if (AllProc) {
+        *pss = PS_PRI;
+
+#if defined(HASSECURITY) && defined(HASNOSOCKSECURITY)
+        *sf = SelAll & ~(SELNA | SELNET);
+#else  /* !defined(HASSECURITY) || !defined(HASNOSOCKSECURITY) */
+        *sf = SelAll;
+#endif /* defined(HASSECURITY) && defined(HASNOSOCKSECURITY) */
+
+        return (0);
+    }
+    /*
+     * If the listing of processes has been specified by process group ID, see
+     * if this one is included or excluded.
+     */
+    if (Npgidi && (Selflags & SELPGID)) {
+        for (i = j = 0; (i < Npgid) && (j < Npgidi); i++) {
+            if (Spgid[i].x)
+                continue;
+            if (Spgid[i].i == pgid) {
+                Spgid[i].f = 1;
+                *pss = PS_PRI;
+                *sf = SELPGID;
+                if (Selflags == SELPGID)
+                    return (0);
+                break;
+            }
+            j++;
+        }
+        if ((Selflags == SELPGID) && !*sf)
+            return (1);
+    }
+    /*
+     * If the listing of processes has been specified by PID, see if this one is
+     * included or excluded.
+     */
+    if (Npidi && (Selflags & SELPID)) {
+        for (i = j = 0; (i < Npid) && (j < Npidi); i++) {
+            if (Spid[i].x)
+                continue;
+            if (Spid[i].i == pid) {
+                Spid[i].f = 1;
+                *pss = PS_PRI;
+                *sf |= SELPID;
+                if (Selflags == SELPID)
+                    return (0);
+                break;
+            }
+            j++;
+        }
+        if ((Selflags == SELPID) && !*sf)
+            return (1);
+    }
+    /*
+     * If the listing of processes has been specified by UID, see if the owner
+     * of this process has been included.
+     */
+    if (Nuidincl && (Selflags & SELUID)) {
+        for (i = j = 0; (i < Nuid) && (j < Nuidincl); i++) {
+            if (Suid[i].excl)
+                continue;
+            if (Suid[i].uid == (uid_t)uid) {
+                Suid[i].f = 1;
+                *pss = PS_PRI;
+                *sf |= SELUID;
+                if (Selflags == SELUID)
+                    return (0);
+                break;
+            }
+            j++;
+        }
+        if (Selflags == SELUID && (*sf & SELUID) == 0)
+            return (1);
+    }
+
+#if defined(HASTASKS)
+    if ((Selflags & SELTASK) && tid) {
+
+        /*
+         * This is a task and tasks are selected.
+         */
+        *pss = PS_PRI;
+        *sf |= SELTASK;
+        if ((Selflags == SELTASK) || (Fand && ((*sf & Selflags) == Selflags)))
+            return (0);
+    }
+#endif /* defined(HASTASKS) */
+
+    /*
+     * When neither the process group ID, nor the PID, nor the task, nor the UID
+     * is selected:
+     *
+     * If list option ANDing of process group IDs, PIDs, UIDs or tasks is
+     * specified, the process is excluded;
+     *
+     * Otherwise, it's not excluded by the tests of this function.
+     */
+    if (!*sf)
+        return ((Fand && (Selflags & (SELPGID | SELPID | SELUID | SELTASK)))
+                    ? 1
+                    : 0);
+    /*
+     * When the process group ID, PID, task or UID is selected and the process
+     * group ID, PID, task or UID list option has been specified:
+     *
+     * If list option ANDing has been specified, and the correct
+     * combination of selections are in place, reply that the process is no
+     * excluded;
+     * or
+     * If list option ANDing has not been specified, reply that the
+     * process is not excluded by the tests of this function.
+     */
+    if (Selflags & (SELPGID | SELPID | SELUID | SELTASK)) {
+        if (Fand)
+            return (((Selflags & (SELPGID | SELPID | SELUID | SELTASK)) != *sf)
+                        ? 1
+                        : 0);
+        return (0);
+    }
+    /*
+     * Finally, when neither the process group ID, nor the PID, nor the UID, nor
+     * the task is selected, and no applicable list option has been specified:
+     *
+     * If list option ANDing has been specified, this process is
+     * excluded;
+     *
+     * Otherwise, it isn't excluded by the tests of this function.
+     */
+    return (Fand ? 1 : 0);
+}
+
+/*
+ * link_lfile() - link local file structures
+ */
+
+void link_lfile(struct lsof_context *ctx) {
+    if (Lf->sf & SELEXCLF)
+        return;
+
+#if defined(HASEPTOPTS)
+    /*
+     * If endpoint info has been requested, clear the SELPINFO flag from the
+     * local pipe file structure, since it was set only to insure this file
+     * would be linked.  While this might leave no file selection flags set, a
+     * later call to the process_pinfo() function might set some.  Also set the
+     * EPT_PIPE flag.
+     */
+    if (FeptE) {
+        if (Lf->sf & SELPINFO) {
+            Lp->ept |= EPT_PIPE;
+            Lf->sf &= ~SELPINFO;
+        }
+
+        /*
+         * Process posix mq endpoint files the same way by clearing the
+         * SELPSXMQINFO flag and setting the EPT_PSXMQ flag, letting a later
+         * call to process_psxmqinfo() set selection flags.
+         */
+        if (Lf->sf & SELPSXMQINFO) {
+            Lp->ept |= EPT_PSXMQ;
+            Lf->sf &= ~SELPSXMQINFO;
+        }
+
+#    if defined(HASUXSOCKEPT)
+        /*
+         * Process UNIX socket endpoint files the same way by clearing the
+         * SELUXINFO flag and setting the EPT_UXS flag, letting a later call to
+         * process_uxsinfo() set selection flags.
+         */
+        if (Lf->sf & SELUXSINFO) {
+            Lp->ept |= EPT_UXS;
+            Lf->sf &= ~SELUXSINFO;
+        }
+#    endif /* defined(HASUXSOCKEPT) */
+
+#    if defined(HASPTYEPT)
+        /*
+         * Process pseudoterminal endpoint files the same way by clearing the
+         * SELPTYINFO flag and setting the EPT_PTY flag, letting a later call to
+         * process_ptyinfo() set selection flags.
+         */
+        if (Lf->sf & SELPTYINFO) {
+            Lp->ept |= EPT_PTY;
+            Lf->sf &= ~SELPTYINFO;
+        }
+#    endif /* defined(HASPTYEPT) */
+
+        /*
+         * Process locally used INET socket endpoint files the same way by
+         * clearing the SENETSINFO flag and setting the EPT_NETS flag, letting a
+         * later call to process_netsinfo() set selection flags.
+         */
+        if (Lf->sf & SELNETSINFO) {
+            Lp->ept |= EPT_NETS;
+            Lf->sf &= ~SELNETSINFO;
+        }
+
+#    if defined(HASIPv6)
+        /*
+         * Process locally used INET6 socket endpoint files the same way by
+         * clearing the SENETS6INFO flag and setting the EPT_NETS6 flag, letting
+         * a later call to process_nets6info() set selection flags.
+         */
+        if (Lf->sf & SELNETS6INFO) {
+            Lp->ept |= EPT_NETS6;
+            Lf->sf &= ~SELNETS6INFO;
+        }
+#    endif /* defined(HASIPv6) */
+           /*
+            * Process eventfd endpoint files the same way by clearing the
+            * SELEVTFDINFO    flag and setting the EPT_EVTFD flag, letting a later
+            * call to    process_evtfdinfo()      set selection flags.
+            */
+        if (Lf->sf & SELEVTFDINFO) {
+            Lp->ept |= EPT_EVTFD;
+            Lf->sf &= ~SELEVTFDINFO;
+        }
+    }
+#endif /* defined(HASEPTOPTS) */
+
+    if (Lf->sf)
+        Lp->pss |= PS_SEC;
+    if (Plf)
+        Plf->next = Lf;
+    else
+        Lp->file = Lf;
+    Plf = Lf;
+    if (Fnet && (Lf->sf & SELNET))
+        Fnet = 2;
+    if (Fnfs && (Lf->sf & SELNFS))
+        Fnfs = 2;
+    if (Ftask && (Lf->sf & SELTASK))
+        Ftask = 2;
+    Lf = (struct lfile *)NULL;
+}
+
+#if defined(HASEPTOPTS)
+/*
+ * process_pinfo() -- process pipe info, adding it to selected files and
+ *                   selecting pipe end files (if requested)
+ */
+
+void process_pinfo(struct lsof_context *ctx,
+                   int f) /* function:
+                           *     0 == process selected pipe
+                           *     1 == process end point
+                           */
+{
+    pxinfo_t *pp; /* previous pipe info */
+
+    if (!FeptE)
+        return;
+    for (Lf = Lp->file; Lf; Lf = Lf->next) {
+        if ((Lf->ntype != N_FIFO) || (Lf->inp_ty != 1))
+            continue;
+        pp = (pxinfo_t *)NULL;
+        switch (f) {
+        case 0:
+
+            /*
+             * Process already selected pipe file.
+             */
+            if (is_file_sel(ctx, Lp, Lf)) {
+
+                /*
+                 * This file has been selected by some criterion other than
+                 * its being a pipe.  Look up the pipe's endpoints.
+                 */
+                do {
+                    if ((pp = find_pepti(ctx, Lp->pid, Lf, pp))) {
+
+                        /*
+                         * This pipe endpoint is linked to the selected pipe
+                         * file.  Add its PID and FD to the name column
+                         * addition.
+                         */
+                        prt_pinfo(ctx, pp, (FeptE == 2));
+                        pp = pp->next;
+                    }
+                } while (pp);
+            }
+            break;
+        case 1:
+            if (!is_file_sel(ctx, Lp, Lf) && (Lf->chend & CHEND_PIPE)) {
+
+                /*
+                 * This is an unselected end point file.  Select it and add
+                 * its end point information to its name column addition.
+                 */
+                Lf->sf = Selflags;
+                Lp->pss |= PS_SEC;
+                do {
+                    if ((pp = find_pepti(ctx, Lp->pid, Lf, pp))) {
+                        prt_pinfo(ctx, pp, 0);
+                        pp = pp->next;
+                    }
+                } while (pp);
+            }
+            break;
+        }
+    }
+}
+
+/*
+ * prt_pinfo() -- print pipe information
+ */
+
+static void prt_pinfo(struct lsof_context *ctx, pxinfo_t *pp, /* peer info */
+                      int ps) /* processing status:
+                               *    0 == process immediately
+                               *    1 == process later */
+{
+    struct lproc *ep; /* pipe endpoint process */
+    struct lfile *ef; /* pipe endpoint file */
+    int i;            /* temporary index */
+    char nma[1024];   /* name addition buffer */
+    char fd[FDLEN];
+
+    ep = &Lproc[pp->lpx];
+    ef = pp->lf;
+    fd_to_string(ef->fd_type, ef->fd_num, fd);
+    (void)snpf(nma, sizeof(nma) - 1, "%d,%.*s,%s%c", ep->pid, CmdLim, ep->cmd,
+               fd, access_to_char(ef->access));
+    (void)add_nma(ctx, nma, strlen(nma));
+    if (ps) {
+
+        /*
+         * Endpoint files have been selected, so mark this
+         * one for selection later. Set the type to PIPE.
+         */
+        ef->chend = CHEND_PIPE;
+        ep->ept |= EPT_PIPE_END;
+    }
+}
+
+/*
+ * process_psxmqinfo() -- posix mq info, adding it to selected files and
+ *                       selecting posix mq end files (if requested)
+ */
+
+void process_psxmqinfo(struct lsof_context *ctx,
+                       int f) /* function:
+                               *     0 == process selected posix mq
+                               *     1 == process end point
+                               */
+{
+    pxinfo_t *pp; /* previous posix mq info */
+
+    if (!FeptE)
+        return;
+    for (Lf = Lp->file; Lf; Lf = Lf->next) {
+        if (Lf->dev != MqueueDev)
+            continue;
+        pp = (pxinfo_t *)NULL;
+        switch (f) {
+        case 0:
+
+            /*
+             * Process already selected posix mq file.
+             */
+            if (is_file_sel(ctx, Lp, Lf)) {
+
+                /*
+                 * This file has been selected by some criterion other than
+                 * its being a posix mq.  Look up the posix mq's endpoints.
+                 */
+                do {
+                    if ((pp = find_psxmqinfo(ctx, Lp->pid, Lf, pp))) {
+
+                        /*
+                         * This posix mq endpoint is linked to the selected
+                         * posix mq file.  Add its PID and FD to the name column
+                         * addition.
+                         */
+                        prt_psxmqinfo(ctx, pp, (FeptE == 2));
+                        pp = pp->next;
+                    }
+                } while (pp);
+            }
+            break;
+        case 1:
+            if (!is_file_sel(ctx, Lp, Lf) && (Lf->chend & CHEND_PSXMQ)) {
+
+                /*
+                 * This is an unselected end point file.  Select it and add
+                 * its end point information to its name column addition.
+                 */
+                Lf->sf = Selflags;
+                Lp->pss |= PS_SEC;
+                do {
+                    if ((pp = find_psxmqinfo(ctx, Lp->pid, Lf, pp))) {
+                        prt_psxmqinfo(ctx, pp, 0);
+                        pp = pp->next;
+                    }
+                } while (pp);
+            }
+            break;
+        }
+    }
+}
+
+/*
+ * prt_psxmqinfo() -- print posix mq information
+ */
+
+static void prt_psxmqinfo(struct lsof_context *ctx,
+                          pxinfo_t *pp, /* peer info */
+                          int ps)       /* processing status:
+                                         *    0 == process immediately
+                                         *    1 == process later */
+{
+    struct lproc *ep; /* posix mq endpoint process */
+    struct lfile *ef; /* posix mq endpoint file */
+    int i;            /* temporary index */
+    char nma[1024];   /* name addition buffer */
+    char fd[FDLEN];
+
+    ep = &Lproc[pp->lpx];
+    ef = pp->lf;
+    fd_to_string(ef->fd_type, ef->fd_num, fd);
+    (void)snpf(nma, sizeof(nma) - 1, "%d,%.*s,%s%c", ep->pid, CmdLim, ep->cmd,
+               fd, access_to_char(ef->access));
+    (void)add_nma(ctx, nma, strlen(nma));
+    if (ps) {
+
+        /*
+         * Endpoint files have been selected, so mark this
+         * one for selection later. Set the type to posix mq.
+         */
+        ef->chend = CHEND_PSXMQ;
+        ep->ept |= EPT_PSXMQ_END;
+    }
+}
+
+/*
+ * process_evtfdinfo() -- process eventfd info, adding it to selected files and
+ *                       selecting envetfd end files (if requested)
+ */
+
+void process_evtfdinfo(struct lsof_context *ctx,
+                       int f) /* function:
+                               *     0 == process selected eventfd
+                               *     1 == process end point
+                               */
+{
+    pxinfo_t *pp; /* previous eventfd info */
+
+    if (!FeptE)
+        return;
+    for (Lf = Lp->file; Lf; Lf = Lf->next) {
+        if ((Lf->ntype != N_ANON_INODE) || (Lf->eventfd_id == -1))
+            continue;
+        pp = (pxinfo_t *)NULL;
+        switch (f) {
+        case 0:
+
+            /*
+             * Process already selected eventfd_id file.
+             */
+            if (is_file_sel(ctx, Lp, Lf)) {
+
+                /*
+                 * This file has been selected by some criterion other than
+                 * its being a eventfd.  Look up the eventfd's endpoints.
+                 */
+                do {
+                    if ((pp = find_evtfdinfo(ctx, Lp->pid, Lf, pp))) {
+
+                        /*
+                         * This eventfd endpoint is linked to the selected
+                         * eventfd file.  Add its PID and FD to the name column
+                         * addition.
+                         */
+                        prt_evtfdinfo(ctx, pp, (FeptE == 2));
+                        pp = pp->next;
+                    }
+                } while (pp);
+            }
+            break;
+        case 1:
+            if (!is_file_sel(ctx, Lp, Lf) && (Lf->chend & CHEND_EVTFD)) {
+
+                /*
+                 * This is an unselected end point file.  Select it and add
+                 * its end point information to its name column addition.
+                 */
+                Lf->sf = Selflags;
+                Lp->pss |= PS_SEC;
+                do {
+                    if ((pp = find_evtfdinfo(ctx, Lp->pid, Lf, pp))) {
+                        prt_evtfdinfo(ctx, pp, 0);
+                        pp = pp->next;
+                    }
+                } while (pp);
+            }
+            break;
+        }
+    }
+}
+
+/*
+ * prt_evtfdinfo() -- print eventfd information
+ */
+
+static void prt_evtfdinfo(struct lsof_context *ctx,
+                          pxinfo_t *pp, /* peer info */
+                          int ps)       /* processing status:
+                                         *    0 == process immediately
+                                         *    1 == process later */
+{
+    struct lproc *ep; /* eventfd endpoint process */
+    struct lfile *ef; /* eventfd endpoint file */
+    int i;            /* temporary index */
+    char nma[1024];   /* name addition buffer */
+    char fd[FDLEN];
+
+    ep = &Lproc[pp->lpx];
+    ef = pp->lf;
+    fd_to_string(ef->fd_type, ef->fd_num, fd);
+    (void)snpf(nma, sizeof(nma) - 1, "%d,%.*s,%s%c", ep->pid, CmdLim, ep->cmd,
+               fd, access_to_char(ef->access));
+    (void)add_nma(ctx, nma, strlen(nma));
+    if (ps) {
+
+        /*
+         * Endpoint files have been selected, so mark this
+         * one for selection later. Set the type to PIPE.
+         */
+        ef->chend = CHEND_EVTFD;
+        ep->ept |= EPT_EVTFD_END;
+    }
+}
+#endif /* defined(HASEPTOPTS) */
+
+#if defined(HASPTYEPT)
+/*
+ * process_ptyinfo() -- process pseudoterminal info, adding it to selected files
+ *and selecting pseudoterminal end files (if requested)
+ */
+
+void process_ptyinfo(struct lsof_context *ctx,
+                     int f) /* function:
+                             *  0 == process selected pseudoterminal
+                             *  1 == process end point */
+{
+    pxinfo_t *pp; /* previous pseudoterminal info */
+    int mos;      /* master or slave indicator
+                   *     0 == slave; 1 == master */
+    int pc;       /* print count */
+
+    if (!FeptE)
+        return;
+    for (Lf = Lp->file; Lf; Lf = Lf->next) {
+        if (Lf->rdev_def && is_pty_ptmx(Lf->rdev))
+            mos = 1;
+        else if (Lf->rdev_def && is_pty_slave(GET_MAJ_DEV(Lf->rdev)))
+            mos = 0;
+        else
+            continue;
+
+        pp = (pxinfo_t *)NULL;
+        switch (f) {
+        case 0:
+
+            /*
+             * Process already selected pseudoterminal file.
+             */
+            if (is_file_sel(ctx, Lp, Lf)) {
+
+                /*
+                 * This file has been selected by some criterion other than
+                 * its being a pseudoterminal.  Look up the pseudoterminal's
+                 * endpoints.
+                 */
+                pc = 1;
+                do {
+                    if ((pp = find_ptyepti(ctx, Lp->pid, Lf, !mos, pp))) {
+
+                        /*
+                         * This pseudoterminal endpoint is linked to the
+                         * selected pseudoterminal file.  Add its PID, FD and
+                         * access mode to the name column addition.
+                         */
+                        prt_ptyinfo(ctx, pp, (mos && pc), (FeptE == 2));
+                        pp = pp->next;
+                        pc = 0;
+                    }
+                } while (pp);
+            }
+            break;
+        case 1:
+            if (!is_file_sel(ctx, Lp, Lf) && (Lf->chend & CHEND_PTY)) {
+
+                /*
+                 * This is an unselected end point file.  Select it and add
+                 * its end point information to its name column addition.
+                 */
+                Lf->sf = Selflags;
+                Lp->pss |= PS_SEC;
+                pc = 1;
+                do {
+                    if ((pp = find_ptyepti(ctx, Lp->pid, Lf, !mos, pp))) {
+                        prt_ptyinfo(ctx, pp, (mos && pc), 0);
+                        pp = pp->next;
+                        pc = 0;
+                    }
+                } while (pp);
+            }
+            break;
+        }
+    }
+}
+
+/*
+ * prt_ptyinfo() -- print pseudoterminal information
+ */
+
+static void prt_ptyinfo(struct lsof_context *ctx, pxinfo_t *pp, /* peer info */
+                        int prt_edev, /* print the end point device file */
+                        int ps)       /* processing status:
+                                       *    0 == process immediately
+                                       *    1 == process later */
+{
+    struct lproc *ep; /* pseudoterminal endpoint process */
+    struct lfile *ef; /* pseudoterminal endpoint file */
+    int i;            /* temporary index */
+    char nma[1024];   /* name addition buffer */
+    char fd[FDLEN];
+
+    ep = &Lproc[pp->lpx];
+    ef = pp->lf;
+    fd_to_string(ef->fd_type, ef->fd_num, fd);
+    if (prt_edev) {
+        (void)snpf(nma, sizeof(nma) - 1, "->/dev/pts/%d %d,%.*s,%s%c",
+                   Lf->tty_index, ep->pid, CmdLim, ep->cmd, fd,
+                   access_to_char(ef->access));
+    } else {
+        (void)snpf(nma, sizeof(nma) - 1, "%d,%.*s,%s%c", ep->pid, CmdLim,
+                   ep->cmd, fd, access_to_char(ef->access));
+    }
+    (void)add_nma(ctx, nma, strlen(nma));
+    if (ps) {
+
+        /*
+         * Endpoint files have been selected, so mark this
+         * one for selection later. Set the type to PTY.
+         */
+        ef->chend = CHEND_PTY;
+        ep->ept |= EPT_PTY_END;
+    }
+}
+#endif /* defined(HASPTYEPT) */
+
+/* Convert lsof_fd_type and fd_num to string, sizeof(buf) should >= FDLEN */
+void fd_to_string(enum lsof_fd_type fd_type, int fd_num, char *buf) {
+    switch (fd_type) {
+    case LSOF_FD_NUMERIC:
+        /* strlen("TYPE") == 4, try to match width */
+        if (fd_num < 10000)
+            (void)snpf(buf, FDLEN, "%d", fd_num);
+        else
+            (void)snpf(buf, FDLEN, "*%03d", fd_num % 1000);
+        break;
+    case LSOF_FD_UNKNOWN:
+        (void)snpf(buf, FDLEN, "unk");
+        break;
+    case LSOF_FD_CWD:
+        (void)snpf(buf, FDLEN, "cwd");
+        break;
+    case LSOF_FD_ERROR:
+        (void)snpf(buf, FDLEN, "err");
+        break;
+    case LSOF_FD_NOFD:
+        (void)snpf(buf, FDLEN, "NOFD");
+        break;
+    case LSOF_FD_ROOT_DIR:
+        (void)snpf(buf, FDLEN, "rtd");
+        break;
+    case LSOF_FD_PARENT_DIR:
+        (void)snpf(buf, FDLEN, "pd");
+        break;
+    case LSOF_FD_PROGRAM_TEXT:
+        (void)snpf(buf, FDLEN, "txt");
+        break;
+    case LSOF_FD_LIBRARY_TEXT:
+        (void)snpf(buf, FDLEN, "ltx");
+        break;
+    case LSOF_FD_MEMORY:
+        (void)snpf(buf, FDLEN, "mem");
+        break;
+    case LSOF_FD_DELETED:
+        (void)snpf(buf, FDLEN, "DEL");
+        break;
+    case LSOF_FD_FILEPORT:
+        (void)snpf(buf, FDLEN, "fp.");
+        break;
+    case LSOF_FD_TASK_CWD:
+        (void)snpf(buf, FDLEN, "twd");
+        break;
+    case LSOF_FD_CTTY:
+        (void)snpf(buf, FDLEN, "ctty");
+        break;
+    case LSOF_FD_JAIL_DIR:
+        (void)snpf(buf, FDLEN, "jld");
+        break;
+    case LSOF_FD_VIRTUAL_8086:
+        (void)snpf(buf, FDLEN, "v86");
+        break;
+    case LSOF_FD_MERGE_386:
+        (void)snpf(buf, FDLEN, "m86");
+        break;
+    case LSOF_FD_MMAP_DEVICE:
+        (void)snpf(buf, FDLEN, "mmap");
+        break;
+    case LSOF_FD_LIBRARY_REF:
+        (void)snpf(buf, FDLEN, "L%02d", fd_num);
+        break;
+    case LSOF_FD_MMAP_UNKNOWN:
+        (void)snpf(buf, FDLEN, "M%02x", fd_num);
+        break;
+    case LSOF_FD_PREGION_UNKNOWN:
+        (void)snpf(buf, FDLEN, "R%02d", fd_num);
+        break;
+    default:
+        fprintf(stderr, "Unknown fd type: %d\n", (int)fd_type);
+        buf[0] = '\0';
+        break;
+    }
+}
\ No newline at end of file
diff --git a/lib/proto.h b/lib/proto.h
new file mode 100644 (file)
index 0000000..83dfb14
--- /dev/null
@@ -0,0 +1,331 @@
+/*
+ * proto.h - common function prototypes for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+/*
+ * $Id: proto.h,v 1.39 2018/02/14 14:20:14 abe Exp $
+ */
+
+#if !defined(PROTO_H)
+#    define PROTO_H 1
+
+/*
+ * The following define keeps gcc>=2.7 from complaining about the failure
+ * of the Exit() function to return.
+ *
+ * Paul Eggert supplied it.
+ */
+
+#    if defined(__GNUC__) &&                                                   \
+        !(__GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7))
+#        define exiting __attribute__((__noreturn__))
+#    else /* !gcc || gcc<2.7 */
+#        define exiting
+#    endif /* gcc && gcc>=2.7 */
+
+extern void add_nma(struct lsof_context *ctx, char *cp, int len);
+extern void alloc_lfile(struct lsof_context *ctx, enum lsof_fd_type fd_type,
+                        int num);
+extern void alloc_lproc(struct lsof_context *ctx, int pid, int pgid, int ppid,
+                        UID_ARG uid, char *cmd, int pss, int sf);
+extern void build_IPstates(struct lsof_context *ctx);
+extern void childx(struct lsof_context *ctx);
+extern void closefrom_shim(struct lsof_context *ctx, int low);
+extern int ck_fd_status(struct lsof_context *ctx, enum lsof_fd_type fd_type,
+                        int num);
+extern int ck_file_arg(struct lsof_context *ctx, int i, int ac, char *av[],
+                       int fv, int rs, struct stat *sbp,
+                       int accept_deleted_file);
+extern void ckkv(struct lsof_context *ctx, char *d, char *er, char *ev,
+                 char *ea);
+extern void clr_devtab(struct lsof_context *ctx);
+extern int compdev(COMP_P *a1, COMP_P *a2);
+extern int comppid(COMP_P *a1, COMP_P *a2);
+
+#    if defined(WILLDROPGID)
+extern void dropgid(struct lsof_context *ctx);
+#    endif /* defined(WILLDROPGID) */
+
+extern char *endnm(struct lsof_context *ctx, size_t *sz);
+extern int enter_cmd_rx(struct lsof_context *ctx, char *x);
+extern void enter_dev_ch(struct lsof_context *ctx, char *m);
+extern int enter_dir(struct lsof_context *ctx, char *d, int descend);
+
+#    if defined(HASEOPT)
+extern int enter_efsys(struct lsof_context *ctx, char *e, int rdlnk);
+#    endif /* defined(HASEOPT) */
+
+extern int enter_fd(struct lsof_context *ctx, char *f);
+extern int enter_network_address(struct lsof_context *ctx, char *na);
+extern int enter_id(struct lsof_context *ctx, enum IDType ty, char *p);
+extern void enter_IPstate(struct lsof_context *ctx, char *ty, char *nm, int nr);
+extern void enter_nm(struct lsof_context *ctx, char *m);
+
+#    if defined(HASTCPUDPSTATE)
+extern int enter_state_spec(struct lsof_context *ctx, char *ss);
+#    endif /* defined(HASTCPUDPSTATE) */
+
+extern int enter_cmd(struct lsof_context *ctx, char *opt, char *s);
+extern int enter_uid(struct lsof_context *ctx, char *us);
+extern void ent_inaddr(struct lsof_context *ctx, unsigned char *la, int lp,
+                       unsigned char *fa, int fp, int af);
+extern int examine_lproc(struct lsof_context *ctx);
+extern void Exit(struct lsof_context *ctx, enum ExitStatus xv) exiting;
+extern void Error(struct lsof_context *ctx) exiting;
+extern void find_ch_ino(struct lsof_context *ctx);
+
+#    if defined(HASEPTOPTS)
+extern void clear_pinfo(struct lsof_context *ctx);
+extern pxinfo_t *find_pepti(struct lsof_context *ctx, int pid, struct lfile *lf,
+                            pxinfo_t *pp);
+extern void process_pinfo(struct lsof_context *ctx, int f);
+extern void clear_psxmqinfo(struct lsof_context *ctx);
+extern pxinfo_t *find_psxmqinfo(struct lsof_context *ctx, int pid,
+                                struct lfile *lf, pxinfo_t *pp);
+extern void process_psxmqinfo(struct lsof_context *ctx, int f);
+#        if defined(HASUXSOCKEPT)
+extern void clear_uxsinfo(struct lsof_context *ctx);
+extern struct uxsin *find_uxsepti(struct lfile *lf);
+extern void process_uxsinfo(struct lsof_context *ctx, int f);
+#        endif /* defined(HASUXSOCKEPT) */
+#        if defined(HASPTYEPT)
+extern void clear_ptyinfo(struct lsof_context *ctx);
+extern void enter_ptmxi(struct lsof_context *ctx, int mn);
+extern pxinfo_t *find_ptyepti(struct lsof_context *ctx, int pid,
+                              struct lfile *lf, int m, pxinfo_t *pp);
+extern int is_pty_slave(int sm);
+extern int is_pty_ptmx(dev_t dev);
+extern void process_ptyinfo(struct lsof_context *ctx, int f);
+#        endif /* defined(HASPTYEPT) */
+extern void clear_evtfdinfo(struct lsof_context *ctx);
+extern void enter_evtfdinfo(struct lsof_context *ctx, int id);
+extern pxinfo_t *find_evtfdinfo(struct lsof_context *ctx, int pid,
+                                struct lfile *lf, pxinfo_t *pp);
+extern void process_evtfdinfo(struct lsof_context *ctx, int f);
+extern void clear_netsinfo(struct lsof_context *ctx);
+extern void process_netsinfo(struct lsof_context *ctx, int f);
+#        if defined(HASIPv6)
+extern void clear_nets6info(struct lsof_context *ctx);
+extern void process_nets6info(struct lsof_context *ctx, int f);
+#        endif /* defined(HASIPv6) */
+#    endif     /* defined(HASEPTOPTS) */
+
+extern void free_lproc(struct lproc *lp);
+extern void gather_proc_info(struct lsof_context *ctx);
+extern char *gethostnm(struct lsof_context *ctx, unsigned char *ia, int af);
+
+#    if !defined(GET_MAX_FD)
+/*
+ * This is not strictly a prototype, but GET_MAX_FD is the name of the
+ * function that, in lieu of getdtablesize(), returns the maximum file
+ * descriptor plus one (or file descriptor count).  GET_MAX_FD may be
+ * defined in the dialect's machine.h.  If it is not, the following
+ * selects getdtablesize().
+ */
+
+#        define GET_MAX_FD getdtablesize
+#    endif /* !defined(GET_MAX_FD) */
+
+extern int hashbyname(char *nm, int mod);
+extern void hashSfile(struct lsof_context *ctx);
+extern void initialize(struct lsof_context *ctx);
+extern int is_cmd_excl(struct lsof_context *ctx, char *cmd, short *pss,
+                       short *sf);
+extern int is_file_sel(struct lsof_context *ctx, struct lproc *lp,
+                       struct lfile *lf);
+extern int is_nw_addr(struct lsof_context *ctx, unsigned char *ia, int p,
+                      int af);
+
+#    if defined(HASTASKS)
+extern int is_proc_excl(struct lsof_context *ctx, int pid, int pgid,
+                        UID_ARG uid, short *pss, short *sf, int tid);
+#    else  /* !defined(HASTASKS) */
+extern int is_proc_excl(struct lsof_context *ctx, int pid, int pgid,
+                        UID_ARG uid, short *pss, short *sf);
+#    endif /* defined(HASTASKS) */
+
+extern int is_readable(struct lsof_context *ctx, char *path, int msg);
+extern int kread(struct lsof_context *ctx, KA_T addr, char *buf, READLEN_T len);
+extern void link_lfile(struct lsof_context *ctx);
+extern struct l_dev *lkupdev(struct lsof_context *ctx, dev_t *dev, dev_t *rdev,
+                             int i, int r);
+extern int main(int argc, char *argv[]);
+extern int lstatsafely(struct lsof_context *ctx, char *path, struct stat *buf);
+extern char *mkstrcpy(char *src, MALLOC_S *rlp);
+extern char *mkstrcat(char *s1, int l1, char *s2, int l2, char *s3, int l3,
+                      MALLOC_S *clp);
+extern int printdevname(struct lsof_context *ctx, dev_t *dev, dev_t *rdev,
+                        int f, int nty);
+extern void print_file(struct lsof_context *ctx);
+extern void print_init(struct lsof_context *ctx);
+extern void printname(struct lsof_context *ctx, int nl);
+extern char *print_kptr(KA_T kp, char *buf, size_t bufl);
+extern int print_proc(struct lsof_context *ctx);
+extern void fd_to_string(enum lsof_fd_type fd_type, int fd_num, char *buf);
+extern void printrawaddr(struct lsof_context *ctx, struct sockaddr *sa);
+extern void print_tcptpi(struct lsof_context *ctx, int nl);
+extern char *printuid(struct lsof_context *ctx, UID_ARG uid, int *ty);
+extern void printunkaf(struct lsof_context *ctx, int fam, int ty);
+extern char access_to_char(enum lsof_file_access_mode access);
+extern char lock_to_char(enum lsof_lock_mode access);
+extern void file_type_to_string(enum lsof_file_type type,
+                                uint32_t unknown_file_type_number, char *buf,
+                                size_t buf_len);
+extern char *printsockty(int ty);
+extern void process_file(struct lsof_context *ctx, KA_T fp);
+extern void process_node(struct lsof_context *ctx, KA_T f);
+extern char *Readlink(struct lsof_context *ctx, char *arg);
+extern void readdev(struct lsof_context *ctx, int skip);
+extern struct mounts *readmnt(struct lsof_context *ctx);
+extern void rereaddev(struct lsof_context *ctx);
+extern char *safepup(unsigned int c, int *cl);
+extern int safestrlen(char *sp, int flags);
+extern void safestrprtn(char *sp, int len, FILE *fs, int flags);
+extern void safestrprt(char *sp, FILE *fs, int flags);
+extern int statsafely(struct lsof_context *ctx, char *path, struct stat *buf);
+extern void stkdir(struct lsof_context *ctx, char *p);
+extern void usage(struct lsof_context *ctx, int err, int fh, int version);
+extern int util_strftime(char *fmtr, int fmtl, char *fmt);
+extern int vfy_dev(struct lsof_context *ctx, struct l_dev *dp);
+extern char *x2dev(char *s, dev_t *d);
+
+#    if defined(HASBLKDEV)
+extern void find_bl_ino(struct lsof_context *ctx);
+extern struct l_dev *lkupbdev(struct lsof_context *ctx, dev_t *dev, dev_t *rdev,
+                              int i, int r);
+extern int printbdevname(dev_t *dev, dev_t *rdev, int f);
+#    endif /* defined(HASBLKDEV) */
+
+#    if defined(HASCDRNODE)
+extern int readcdrnode(struct lsof_context *ctx, KA_T ca, struct cdrnode *c);
+#    endif /* defined(HASCDRNODE) */
+
+#    if defined(HASDCACHE)
+extern void alloc_dcache(struct lsof_context *ctx);
+extern void crc(char *b, int l, unsigned *s);
+extern void crdbld(void);
+extern int ctrl_dcache(struct lsof_context *ctx, char *p);
+extern int dcpath(struct lsof_context *ctx, int rw, int npw);
+extern int open_dcache(struct lsof_context *ctx, int m, int r, struct stat *sb);
+extern int read_dcache(struct lsof_context *ctx);
+extern int wr2DCfd(struct lsof_context *ctx, char *b, unsigned *c);
+extern void write_dcache(struct lsof_context *ctx);
+#    endif /* defined(HASDCACHE) */
+
+#    if defined(HASFIFONODE)
+extern int readfifonode(struct lsof_context *ctx, KA_T fa, struct fifonode *f);
+#    endif /* defined(HASFIFONODE) */
+
+#    if defined(HASFSTRUCT)
+extern char *print_fflags(struct lsof_context *ctx, long ffg, long pof);
+#    endif /* defined(HASFSTRUCT) */
+
+#    if defined(HASGNODE)
+extern int readgnode(struct lsof_context *ctx, KA_T ga, struct gnode *g);
+#    endif /* defined(HASGNODE) */
+
+#    if defined(HASKQUEUE)
+extern void process_kqueue(struct lsof_context *ctx, KA_T ka);
+#    endif /* defined(HASKQUEUE) */
+
+#    if defined(HASHSNODE)
+extern int readhsnode(struct lsof_context *ctx, KA_T ha, struct hsnode *h);
+#    endif /* defined(HASHSNODE) */
+
+#    if defined(HASINODE)
+extern int readinode(struct lsof_context *ctx, KA_T ia, struct inode *i);
+#    endif /* defined(HASINODE) */
+
+#    if defined(HASNCACHE)
+extern void ncache_load(struct lsof_context *ctx);
+extern char *ncache_lookup(struct lsof_context *ctx, char *buf, int blen,
+                           int *fp);
+#    endif /* defined(HASNCACHE) */
+
+#    if defined(HASNLIST)
+extern void build_Nl(struct lsof_context *ctx, struct drive_Nl *d);
+extern int get_Nl_value(struct lsof_context *ctx, char *nn, struct drive_Nl *d,
+                        KA_T *v);
+#    endif /* defined(HASNLIST) */
+
+#    if defined(HASPIPENODE)
+extern int readpipenode(struct lsof_context *ctx, KA_T pa, struct pipenode *p);
+#    endif /* defined(HASPIPENODE) */
+
+#    if defined(HASPRINTDEV)
+extern char *HASPRINTDEV(struct lfile *lf, dev_t *dev);
+#    endif /* defined(HASPRINTDEV) */
+
+#    if defined(HASPRINTINO)
+extern char *HASPRINTINO(struct lfile *lf);
+#    endif /* defined(HASPRINTINO) */
+
+#    if defined(HASPRINTNM)
+extern void HASPRINTNM(struct lsof_context *ctx, struct lfile *lf);
+#    endif /* defined(HASPRINTNM) */
+
+#    if defined(HASPRIVNMCACHE)
+extern int HASPRIVNMCACHE(struct lsof_context *ctx, struct lfile *lf);
+#    endif /* defined(HASPRIVNMCACHE) */
+
+#    if !defined(HASPRIVPRIPP)
+extern void printiproto(struct lsof_context *ctx, int p);
+#    endif /* !defined(HASPRIVPRIPP) */
+
+#    if defined(HASRNODE)
+extern int readrnode(struct lsof_context *ctx, KA_T ra, struct rnode *r);
+#    endif /* defined(HASRNODE) */
+
+#    if defined(HASSPECDEVD)
+extern void HASSPECDEVD(struct lsof_context *ctx, char *p, struct stat *s);
+#    endif /* defined(HASSPECDEVD) */
+
+#    if defined(HASSNODE)
+extern int readsnode(struct lsof_context *ctx, KA_T sa, struct snode *s);
+#    endif /* defined(HASSNODE) */
+
+#    if defined(HASSTREAMS)
+extern int readstdata(struct lsof_context *ctx, KA_T addr, struct stdata *buf);
+extern int readsthead(struct lsof_context *ctx, KA_T addr, struct queue *buf);
+extern int readstidnm(struct lsof_context *ctx, KA_T addr, char *buf,
+                      READLEN_T len);
+extern int readstmin(struct lsof_context *ctx, KA_T addr,
+                     struct module_info *buf);
+extern int readstqinit(struct lsof_context *ctx, KA_T addr, struct qinit *buf);
+#    endif /* defined(HASSTREAMS) */
+
+#    if defined(HASTMPNODE)
+extern int readtnode(struct lsof_context *ctx, KA_T ta, struct tmpnode *t);
+#    endif /* defined(HASTMPNODE) */
+
+#    if defined(HASVNODE)
+extern int readvnode(struct lsof_context *ctx, KA_T va, struct vnode *v);
+#    endif /* defined(HASVNODE) */
+
+#endif /* !defined(PROTO_H) */
diff --git a/lib/ptti.c b/lib/ptti.c
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/lib/rdev.c b/lib/rdev.c
new file mode 100644 (file)
index 0000000..96a5297
--- /dev/null
@@ -0,0 +1,491 @@
+/*
+ * rdev.c -- readdev() function for lsof library
+ */
+
+/*
+ * 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.
+ */
+
+#include "common.h"
+#include "machine.h"
+
+#if defined(USE_LIB_READDEV)
+
+static int rmdupdev(struct lsof_context *ctx, struct l_dev ***dp, int n,
+                    char *nm);
+
+/*
+ * To use this source file:
+ *
+ * 1. Define DIRTYPE as:
+ *
+ *       #define DIRTYPE direct
+ *    or  #define DIRTYPE dirent
+ *
+ * 2. Define HASDNAMLEN if struct DIRTYPE has a d_namlen element, giving
+ *    the length of d_name.
+ *
+ * 3. Define the RDEV_EXPDEV macro to apply special handling to device
+ *    numbers, as required.  For example, for EP/IX 2.1.1:
+ *
+ *     #define RDEV_EXPDEV(n)  expdev(n)
+ *
+ *    to use the expdev() function to expand device numbers.  If
+ *    no RDEV_EXPDEV macro is defined, it defaults to:
+ *
+ *     #define RDEV_EXPDEV(n)  (n)
+ *
+ * 4. Define HASBLKDEV to request that information on S_IFBLK devices be
+ *    recorded in BDevtp[].
+ *
+ *    Define NOWARNBLKDEV to suppress the issuance of a warning when no
+ *    block devices are found.
+ *
+ * 5. Define RDEV_STATFN to be a stat function other than stat() or lstat()
+ *    -- e.g.,
+ *
+ *     #define RDEV_STATFN     private_stat
+ *
+ * 6. Define HAS_STD_CLONE to request that clone device information be stored
+ *    in standard clone structures (defined in lsof.h and addressed via
+ *    Clone).  If HAS_STD_CLONE is defined, these must also be defined:
+ *
+ *     a.  Define CLONEMAJ to be the name of the constant or
+ *         variable that defines the clone major device -- e.g.,
+ *
+ *             #define CLONEMAJ CloneMaj
+ *
+ *     b.  Define HAVECLONEMAJ to be the name of the variable that
+ *         contains the status of the clone major device -- e.g.,
+ *
+ *             #define HAVECLONEMAJ HaveCloneMaj
+ *
+ *    Define HAS_STD_CLONE to be 1 if readdev() is expected to build the
+ *    clone table, the clone table is cached (if HASDCACHE is defined), and
+ *    there is a function to clear the cache table when the device table must
+ *    be reloaded.  (See dvch.c for naming the clone cache build and clear
+ *    functions.)
+ */
+
+#    if !defined(RDEV_EXPDEV)
+#        define RDEV_EXPDEV(n) (n)
+#    endif /* !defined(RDEV_EXPDEV) */
+
+#    if !defined(RDEV_STATFN)
+#        if defined(USE_STAT)
+#            define RDEV_STATFN stat
+#        else /* !defined(USE_STAT) */
+#            define RDEV_STATFN lstat
+#        endif /* defined(USE_STAT) */
+#    endif     /* !defined(RDEV_STATFN) */
+
+/*
+ * readdev() - read device names, modes and types
+ */
+
+void readdev(struct lsof_context *ctx,
+             int skip) /* skip device cache read if 1 */
+{
+
+#    if defined(HAS_STD_CLONE) && HAS_STD_CLONE == 1
+    struct clone *c;
+#    endif /* defined(HAS_STD_CLONE) && HAS_STD_CLONE==1 */
+
+#    if defined(HASDCACHE)
+    int dcrd;
+#    endif /* defined(HASDCACHE) */
+
+    DIR *dfp;
+    int dnamlen;
+    struct DIRTYPE *dp;
+    char *fp = (char *)NULL;
+    int i = 0;
+
+#    if defined(HASBLKDEV)
+    int j = 0;
+#    endif /* defined(HASBLKDEV) */
+
+    char *path = (char *)NULL;
+    MALLOC_S pl;
+    struct stat sb;
+
+    if (Sdev)
+        return;
+
+#    if defined(HASDCACHE)
+    /*
+     * Read device cache, as directed.
+     */
+    if (!skip) {
+        if (DCstate == 2 || DCstate == 3) {
+            if ((dcrd = read_dcache(ctx)) == 0)
+                return;
+        }
+    } else
+        dcrd = 1;
+#    endif /* defined(HASDCACHE) */
+
+    Dstkn = Dstkx = 0;
+    Dstk = (char **)NULL;
+    (void)stkdir(ctx, "/dev");
+    /*
+     * Unstack the next /dev or /dev/<subdirectory> directory.
+     */
+    while (--Dstkx >= 0) {
+        if (!(dfp = OpenDir(Dstk[Dstkx]))) {
+
+#    if defined(WARNDEVACCESS)
+            if (!Fwarn) {
+                (void)fprintf(stderr, "%s: WARNING: can't open: ", Pn);
+                safestrprt(Dstk[Dstkx], stderr, 1);
+            }
+#    endif /* defined(WARNDEVACCESS) */
+
+            (void)free((FREE_P *)Dstk[Dstkx]);
+            Dstk[Dstkx] = (char *)NULL;
+            continue;
+        }
+        if (path) {
+            (void)free((FREE_P *)path);
+            path = (char *)NULL;
+        }
+        if (!(path =
+                  mkstrcat(Dstk[Dstkx], -1, "/", 1, (char *)NULL, -1, &pl))) {
+            (void)fprintf(stderr, "%s: no space for: ", Pn);
+            safestrprt(Dstk[Dstkx], stderr, 1);
+            Error(ctx);
+        }
+        (void)free((FREE_P *)Dstk[Dstkx]);
+        Dstk[Dstkx] = (char *)NULL;
+        /*
+         * Scan the directory.
+         */
+        for (dp = ReadDir(dfp); dp; dp = ReadDir(dfp)) {
+            if (dp->d_ino == 0 || dp->d_name[0] == '.')
+                continue;
+                /*
+                 * Form the full path name and get its status.
+                 */
+
+#    if defined(HASDNAMLEN)
+            dnamlen = (int)dp->d_namlen;
+#    else  /* !defined(HASDNAMLEN) */
+            dnamlen = (int)strlen(dp->d_name);
+#    endif /* defined(HASDNAMLEN) */
+
+            if (fp) {
+                (void)free((FREE_P *)fp);
+                fp = (char *)NULL;
+            }
+            if (!(fp = mkstrcat(path, pl, dp->d_name, dnamlen, (char *)NULL, -1,
+                                (MALLOC_S *)NULL))) {
+                (void)fprintf(stderr, "%s: no space for: ", Pn);
+                safestrprt(path, stderr, 0);
+                safestrprtn(dp->d_name, dnamlen, stderr, 1);
+                Error(ctx);
+            }
+            if (RDEV_STATFN(fp, &sb) != 0) {
+                if (errno == ENOENT) /* a sym link to nowhere? */
+                    continue;
+
+#    if defined(WARNDEVACCESS)
+                if (!Fwarn) {
+                    int errno_save = errno;
+
+                    (void)fprintf(stderr, "%s: can't stat ", Pn);
+                    safestrprt(fp, stderr, 0);
+                    (void)fprintf(stderr, ": %s\n", strerror(errno_save));
+                }
+#    endif /* defined(WARNDEVACCESS) */
+
+                continue;
+            }
+            /*
+             * If it's a subdirectory, stack its name for later
+             * processing.
+             */
+            if ((sb.st_mode & S_IFMT) == S_IFDIR) {
+                (void)stkdir(ctx, fp);
+                continue;
+            }
+            if ((sb.st_mode & S_IFMT) == S_IFCHR) {
+
+                /*
+                 * Save character device information in Devtp[].
+                 */
+                if (i >= Ndev) {
+                    Ndev += DEVINCR;
+                    if (!Devtp)
+                        Devtp = (struct l_dev *)malloc(
+                            (MALLOC_S)(sizeof(struct l_dev) * Ndev));
+                    else
+                        Devtp = (struct l_dev *)realloc(
+                            (MALLOC_P *)Devtp,
+                            (MALLOC_S)(sizeof(struct l_dev) * Ndev));
+                    if (!Devtp) {
+                        (void)fprintf(
+                            stderr, "%s: no space for character device\n", Pn);
+                        Error(ctx);
+                    }
+                }
+                Devtp[i].rdev = RDEV_EXPDEV(sb.st_rdev);
+                Devtp[i].inode = (INODETYPE)sb.st_ino;
+                if (!(Devtp[i].name = mkstrcpy(fp, (MALLOC_S *)NULL))) {
+                    (void)fprintf(stderr, "%s: no space for device name: ", Pn);
+                    safestrprt(fp, stderr, 1);
+                    Error(ctx);
+                }
+                Devtp[i].v = 0;
+
+#    if defined(HAS_STD_CLONE) && HAS_STD_CLONE == 1
+                if (HAVECLONEMAJ && GET_MAJ_DEV(Devtp[i].rdev) == CLONEMAJ) {
+
+                    /*
+                     * Record clone device information.
+                     */
+                    if (!(c = (struct clone *)malloc(sizeof(struct clone)))) {
+                        (void)fprintf(stderr,
+                                      "%s: no space for clone device: ", Pn);
+                        safestrprt(fp, stderr, 1);
+                        Error(ctx);
+                    }
+                    c->dx = i;
+                    c->next = Clone;
+                    Clone = c;
+                }
+#    endif /* defined(HAS_STD_CLONE) && HAS_STD_CLONE==1 */
+
+                i++;
+            }
+
+#    if defined(HASBLKDEV)
+            if ((sb.st_mode & S_IFMT) == S_IFBLK) {
+
+                /*
+                 * Save block device information in BDevtp[].
+                 */
+                if (j >= BNdev) {
+                    BNdev += DEVINCR;
+                    if (!BDevtp)
+                        BDevtp = (struct l_dev *)malloc(
+                            (MALLOC_S)(sizeof(struct l_dev) * BNdev));
+                    else
+                        BDevtp = (struct l_dev *)realloc(
+                            (MALLOC_P *)BDevtp,
+                            (MALLOC_S)(sizeof(struct l_dev) * BNdev));
+                    if (!BDevtp) {
+                        (void)fprintf(stderr, "%s: no space for block device\n",
+                                      Pn);
+                        Error(ctx);
+                    }
+                }
+                BDevtp[j].name = fp;
+                fp = (char *)NULL;
+                BDevtp[j].inode = (INODETYPE)sb.st_ino;
+                BDevtp[j].rdev = RDEV_EXPDEV(sb.st_rdev);
+                BDevtp[j].v = 0;
+                j++;
+            }
+#    endif /* defined(HASBLKDEV) */
+        }
+        (void)CloseDir(dfp);
+    }
+    /*
+     * Free any allocated space.
+     */
+    if (!Dstk) {
+        (void)free((FREE_P *)Dstk);
+        Dstk = (char **)NULL;
+    }
+    if (fp)
+        (void)free((FREE_P *)fp);
+    if (path)
+        (void)free((FREE_P *)path);
+
+#    if defined(HASBLKDEV)
+    /*
+     * Reduce the BDevtp[] (optional) and Devtp[] tables to their minimum
+     * sizes; allocate and build sort pointer lists; and sort the tables by
+     * device number.
+     */
+    if (BNdev) {
+        if (BNdev > j) {
+            BNdev = j;
+            BDevtp = (struct l_dev *)realloc(
+                (MALLOC_P *)BDevtp, (MALLOC_S)(sizeof(struct l_dev) * BNdev));
+        }
+        if (!(BSdev = (struct l_dev **)malloc(
+                  (MALLOC_S)(sizeof(struct l_dev *) * BNdev)))) {
+            (void)fprintf(stderr,
+                          "%s: no space for block device sort pointers\n", Pn);
+            Error(ctx);
+        }
+        for (j = 0; j < BNdev; j++) {
+            BSdev[j] = &BDevtp[j];
+        }
+        (void)qsort((QSORT_P *)BSdev, (size_t)BNdev,
+                    (size_t)sizeof(struct l_dev *), compdev);
+        BNdev = rmdupdev(ctx, &BSdev, BNdev, "block");
+    }
+
+#        if !defined(NOWARNBLKDEV)
+    else {
+        if (!Fwarn)
+            (void)fprintf(stderr, "%s: WARNING: no block devices found\n", Pn);
+    }
+#        endif /* !defined(NOWARNBLKDEV) */
+#    endif     /* defined(HASBLKDEV) */
+
+    if (Ndev) {
+        if (Ndev > i) {
+            Ndev = i;
+            Devtp = (struct l_dev *)realloc(
+                (MALLOC_P *)Devtp, (MALLOC_S)(sizeof(struct l_dev) * Ndev));
+        }
+        if (!(Sdev = (struct l_dev **)malloc(
+                  (MALLOC_S)(sizeof(struct l_dev *) * Ndev)))) {
+            (void)fprintf(stderr,
+                          "%s: no space for character device sort pointers\n",
+                          Pn);
+            Error(ctx);
+        }
+        for (i = 0; i < Ndev; i++) {
+            Sdev[i] = &Devtp[i];
+        }
+        (void)qsort((QSORT_P *)Sdev, (size_t)Ndev,
+                    (size_t)sizeof(struct l_dev *), compdev);
+        Ndev = rmdupdev(ctx, &Sdev, Ndev, "char");
+    } else {
+        (void)fprintf(stderr, "%s: no character devices found\n", Pn);
+        Error(ctx);
+    }
+
+#    if defined(HASDCACHE)
+    /*
+     * Write device cache file, as required.
+     */
+    if (DCstate == 1 || (DCstate == 3 && dcrd))
+        write_dcache(ctx);
+#    endif /* defined(HASDCACHE) */
+}
+
+#    if defined(HASDCACHE)
+/*
+ * rereaddev() - reread device names, modes and types
+ */
+
+void rereaddev(struct lsof_context *ctx) {
+    (void)clr_devtab(ctx);
+
+#        if defined(DCACHE_CLR)
+    (void)DCACHE_CLR();
+#        endif /* defined(DCACHE_CLR) */
+
+    readdev(ctx, 1);
+    DCunsafe = 0;
+}
+#    endif /* defined(HASDCACHE) */
+
+/*
+ * rmdupdev() - remove duplicate (major/minor/inode) devices
+ */
+
+static int rmdupdev(struct lsof_context *ctx,
+                    struct l_dev ***dp, /* device table pointers address */
+                    int n,              /* number of pointers */
+                    char *nm) /* device table name for error message */
+{
+
+#    if defined(HAS_STD_CLONE) && HAS_STD_CLONE == 1
+    struct clone *c, *cp;
+#    endif /* defined(HAS_STD_CLONE) && HAS_STD_CLONE==1 */
+
+    int i, j, k;
+    struct l_dev **p;
+
+    for (i = j = 0, p = *dp; i < n;) {
+        for (k = i + 1; k < n; k++) {
+            if (p[i]->rdev != p[k]->rdev || p[i]->inode != p[k]->inode)
+                break;
+
+#    if defined(HAS_STD_CLONE) && HAS_STD_CLONE == 1
+            /*
+             * See if we're deleting a duplicate clone device.  If so,
+             * delete its clone table entry.
+             */
+            for (c = Clone, cp = (struct clone *)NULL; c; cp = c, c = c->next) {
+                if (&Devtp[c->dx] != p[k])
+                    continue;
+                if (!cp)
+                    Clone = c->next;
+                else
+                    cp->next = c->next;
+                (void)free((FREE_P *)c);
+                break;
+            }
+#    endif /* defined(HAS_STD_CLONE) && HAS_STD_CLONE==1 */
+        }
+        if (i != j)
+            p[j] = p[i];
+        j++;
+        i = k;
+    }
+    if (n == j)
+        return (n);
+    if (!(*dp = (struct l_dev **)realloc(
+              (MALLOC_P *)*dp, (MALLOC_S)(j * sizeof(struct l_dev *))))) {
+        (void)fprintf(stderr, "%s: can't realloc %s device pointers\n", Pn, nm);
+        Error(ctx);
+    }
+    return (j);
+}
+
+#    if defined(HASDCACHE)
+/*
+ * vfy_dev() - verify a device table entry (usually when DCunsafe == 1)
+ *
+ * Note: rereads entire device table when an entry can't be verified.
+ */
+
+int vfy_dev(struct lsof_context *ctx,
+            struct l_dev *dp) /* device table pointer */
+{
+    struct stat sb;
+
+    if (!DCunsafe || dp->v)
+        return (1);
+    if (RDEV_STATFN(dp->name, &sb) != 0 ||
+        dp->rdev != RDEV_EXPDEV(sb.st_rdev) || dp->inode != sb.st_ino) {
+        (void)rereaddev(ctx);
+        return (0);
+    }
+    dp->v = 1;
+    return (1);
+}
+#    endif /* defined(HASDCACHE) */
+#else      /* !defined(USE_LIB_READDEV) */
+char rdev_d1[] = "d";
+char *rdev_d2 = rdev_d1;
+#endif     /* defined(USE_LIB_READDEV) */
diff --git a/lib/rmnt.c b/lib/rmnt.c
new file mode 100644 (file)
index 0000000..a1ec588
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * rmnt.c -- readmnt() function for lsof library
+ */
+
+/*
+ * 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.
+ */
+
+#include "common.h"
+#include "machine.h"
+
+#if defined(USE_LIB_READMNT)
+
+/*
+ * The caller may define:
+ *
+ * 1.  An RMNT_EXPDEV macro to expand (ala EP/IX) device numbers;
+ *
+ *     EP/IX, for example, uses:
+ *
+ *     #define RMNT_EXPDEV(n) expdev(n)
+ *
+ * 2.  A custom macro, MNTSKIP, for making decisions to skip entries
+ *     -- e.g., ones whose mnt_type is MNTTYPE_IGNORE.
+ *
+ * 3.  RMNT_FSTYPE to specify the member name of the character string of the
+ *     mntent structure containing the file system type, and MOUNTS_FSTYPE to
+ *     specify the member name of the character string pointer of the local
+ *     mounts structure where RMNT_FSTYPE is to be copied.
+ *
+ * 4.  RMNT_STAT_FSTYPE to specify the member name of the stat structure
+ *     containing an integer file system type, and MOUNTS_STAT_FSTYPE to
+ *     specify the member name of the integer in the local mounts structure
+ *     where RMNT_STAT_FSTYPE is to be copied.
+ *
+ */
+
+#    if !defined(RMNT_EXPDEV)
+#        define RMNT_EXPDEV(n) n
+#    endif /* !defined(RMNT_EXPDEV) */
+
+/*
+ * Local static definitions
+ */
+
+/*
+ * readmnt() - read mount table
+ */
+
+struct mounts *readmnt(struct lsof_context *ctx) {
+    char *dn = (char *)NULL;
+    char *ln;
+    FILE *mfp;
+    struct mntent *mp;
+    struct mounts *mtp;
+    char *opt, *opte;
+    struct stat sb;
+
+    if (Lmi || Lmist)
+        return (Lmi);
+    /*
+     * Open access to the mount table.
+     */
+    if (!(mfp = setmntent(MOUNTED, "r"))) {
+        (void)fprintf(stderr, "%s: can't access %s\n", Pn, MOUNTED);
+        Error(ctx);
+    }
+    /*
+     * Read mount table entries.
+     */
+    while ((mp = getmntent(mfp))) {
+
+#    if defined(MNTSKIP)
+        /*
+         * Specfy in the MNTSKIP macro the decisions needed to determine
+         * that this entry should be skipped.
+         *
+         * Typically entries whose mnt_type is MNTTYPE_IGNORE are skipped.
+         *
+         * The MNTSKIP macro allows the caller to use other tests.
+         */
+        MNTSKIP
+#    endif /* MNTSKIP */
+
+        /*
+         * Interpolate a possible symbolic directory link.
+         */
+        if (dn)
+            (void)free((FREE_P *)dn);
+        if (!(dn = mkstrcpy(mp->mnt_dir, (MALLOC_S *)NULL)))
+            goto no_space_for_mount;
+        if (!(ln = Readlink(dn))) {
+            if (!Fwarn)
+                (void)fprintf(stderr,
+                              "      Output information may be incomplete.\n");
+            continue;
+        }
+        if (ln != dn) {
+            (void)free((FREE_P *)dn);
+            dn = ln;
+        }
+        if (*dn != '/')
+            continue;
+        /*
+         * Stat() the directory.
+         */
+        if (statsafely(dn, &sb)) {
+            if (!Fwarn) {
+                (void)fprintf(stderr, "%s: WARNING: can't stat() ", Pn);
+                safestrprt(mp->mnt_type, stderr, 0);
+                (void)fprintf(stderr, " file system ");
+                safestrprt(mp->mnt_dir, stderr, 1);
+                (void)fprintf(stderr,
+                              "      Output information may be incomplete.\n");
+            }
+            if ((opt = strstr(mp->mnt_opts, "dev="))) {
+                (void)zeromem(&sb, sizeof(sb));
+                if ((opte = x2dev(opt + 4, (dev_t *)&sb.st_dev))) {
+                    sb.st_mode = S_IFDIR | 0777;
+                    if (!Fwarn)
+                        (void)fprintf(stderr,
+                                      "      assuming \"%.*s\" from %s\n",
+                                      (int)(opte - opt), opt, MOUNTED);
+                } else
+                    opt = (char *)NULL;
+            }
+            if (!opt)
+                continue;
+        }
+        /*
+         * Allocate and fill a local mounts structure with the directory
+         * (mounted) information.
+         */
+        if (!(mtp = (struct mounts *)malloc(sizeof(struct mounts)))) {
+
+        no_space_for_mount:
+
+            (void)fprintf(stderr, "%s: no space for mount at ", Pn);
+            safestrprt(mp->mnt_fsname, stderr, 0);
+            (void)fprintf(stderr, " (");
+            safestrprt(mp->mnt_dir, stderr, 0);
+            (void)fprintf(stderr, ")\n");
+            Error(ctx);
+        }
+        mtp->dir = dn;
+        dn = (char *)NULL;
+        mtp->next = Lmi;
+        mtp->dev = RMNT_EXPDEV(sb.st_dev);
+        mtp->rdev = RMNT_EXPDEV(sb.st_rdev);
+        mtp->inode = (INODETYPE)sb.st_ino;
+        mtp->mode = sb.st_mode;
+
+#    if defined(RMNT_FSTYPE) && defined(MOUNTS_FSTYPE)
+        /*
+         * Make a copy of RMNT_FSTYPE in MOUNTS_FSTYPE.
+         */
+        if (!(mtp->MOUNTS_FSTYPE =
+                  mkstrcpy(mp->RMNT_FSTYPE, (MALLOC_S *)NULL))) {
+            (void)fprintf(stderr, "%s: no space for fstype (%s): %s\n", Pn,
+                          mtp->dir, mp->RMNT_FSTYPE);
+            Error(ctx);
+        }
+        (void)strcpy(mtp->MOUNTS_FSTYPE, mp->RMNT_FSTYPE);
+#    endif /* defined(RMNT_FSTYP) && defined(MOUNTS_FSTYP) */
+
+#    if defined(RMNT_STAT_FSTYPE) && defined(MOUNTS_STAT_FSTYPE)
+        /*
+         * Make a copy of RMNT_STAT_FSTYPE in MOUNTS_STAT_FSTYPE.
+         */
+        mtp->MOUNTS_STAT_FSTYPE = (int)sb.RMNT_STAT_FSTYPE;
+#    endif /* defined(RMNT_STAT_FSTYP) && defined(MOUNTS_STAT_FSTYP) */
+
+        /*
+         * Interpolate a possible file system (mounted-on device) name link.
+         */
+        if (!(dn = mkstrcpy(mp->mnt_fsname, (MALLOC_S *)NULL)))
+            goto no_space_for_mount;
+        mtp->fsname = dn;
+        ln = Readlink(dn);
+        dn = (char *)NULL;
+        /*
+         * Stat() the file system (mounted-on) name and add file system
+         * information to the local mounts structure.
+         */
+        if (!ln || statsafely(ln, &sb))
+            sb.st_mode = 0;
+        mtp->fsnmres = ln;
+        mtp->fs_mode = sb.st_mode;
+        Lmi = mtp;
+    }
+    (void)endmntent(mfp);
+    /*
+     * Clean up and return the local nount info table address.
+     */
+    if (dn)
+        (void)free((FREE_P *)dn);
+    Lmist = 1;
+    return (Lmi);
+}
+#else  /* !defined(USE_LIB_READMNT) */
+char rmnt_d1[] = "d";
+char *rmnt_d2 = rmnt_d1;
+#endif /* defined(USE_LIB_READMNT) */
diff --git a/lib/rnam.c b/lib/rnam.c
new file mode 100644 (file)
index 0000000..312ef75
--- /dev/null
@@ -0,0 +1,643 @@
+/*
+ * rnam.c -- BSD format name cache functions for lsof library
+ */
+
+/*
+ * 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.
+ */
+
+#include "common.h"
+#include "machine.h"
+
+#if defined(HASNCACHE) && defined(USE_LIB_RNAM)
+
+/*
+ * rnam.c - read BSD format (struct namecache or nch) name cache
+ *
+ * This code is effective only when HASNCACHE is defined.
+ */
+
+/*
+ * The caller must:
+ *
+ *     #include the relevant header file -- e.g., <sys/namei.h>.
+ *
+ *     Define X_NCACHE as the nickname for the kernel cache address.
+ *
+ *     Define X_NCSIZE as the nickname for the size of the kernel cache.
+ *
+ *     Define NCACHE_NXT if the kernel's name cache is a linked list, starting
+ *     at the X_NCACHE address, rather than a table, starting at that address.
+ *
+ *     Define NCACHE_NO_ROOT if the calling dialect doesn't support
+ *     the locating of the root node of a file system.
+ *
+ *     Define the name of the name cache structure -- e.g.,
+ *
+ *             #define NCACHE  <structure name>
+ *
+ *     Define the following casts, if they differ from the defaults:
+ *
+ *             NCACHE_SZ_CAST  cast for X_NCSIZE (default int)
+ *
+ *     e.g.,
+ *             #define NCACHE_SZ_CAST unsigned long
+ *
+ *     Define the names of these elements of struct NCACHE:
+ *
+ *     must            #define NCACHE_NM       <name>
+ *     must            #define NCACHE_NMLEN    <name length
+ *     optional        #define NCACHE_NXT      <link to next entry>
+ *     must            #define NCACHE_NODEADDR <node address>
+ *     must            #define NCACHE_NODEID   <node capability ID)
+ *     optional        #define NCACHE_PARADDR  <parent node address>
+ *     optional        #define NCACHE_PARID    <parent node capability ID)
+ *
+ * The caller may need to:
+ *
+ *     Define NCHNAMLEN as the length of the name element of NCACHE, if it's
+ *     not defined in the header file that defines the NCACHE structure.
+ *
+ *     Define this prototype for ncache_load():
+ *
+ *             _PROTOTYPE(static void ncache_load,(void));
+ */
+
+/*
+ * Local static values
+ */
+
+static int Mch; /* name cache hash mask */
+
+#    if !defined(NCACHE_NC_CAST)
+#        define NCACHE_SZ_CAST int
+#    endif /* !defined(NCACHE_NC_CAST) */
+
+static NCACHE_SZ_CAST Nc = 0; /* size of name cache */
+static int Nch = 0;           /* size of name cache hash pointer
+                               * table */
+struct l_nch {
+    KA_T na; /* node address */
+
+#    if defined(NCACHE_NODEID)
+    unsigned long id; /* capability ID */
+#    endif            /* defined(NCACHE_NODEID) */
+
+#    if defined(NCACHE_PARADDR) && defined(NCACHE_PARID)
+    KA_T pa;           /* parent node address */
+    struct l_nch *pla; /* parent local node address */
+    unsigned long did; /* parent capability ID */
+#    endif             /* defined(NCACHE_PARADDR) && defined(NCACHE_PARID) */
+
+    char nm[NCHNAMLEN + 1]; /* name */
+    int nl;                 /* name length */
+};
+
+static struct l_nch *Ncache = (struct l_nch *)NULL;
+/* the local name cache */
+static struct l_nch **Nchash = (struct l_nch **)NULL;
+/* Ncache hash pointers */
+static int Ncfirst = 1; /* first-call status */
+
+#    if defined(NCACHE_NODEID)
+#        define ncachehash(i, n)                                               \
+            Nchash + (((((int)(n) >> 2) + ((int)(i))) * 31415) & Mch)
+static struct l_nch *ncache_addr(unsigned long i, KA_T na);
+#    else /* !defined(NCACHE_NODEID) */
+#        define ncachehash(n) Nchash + ((((int)(n) >> 2) * 31415) & Mch)
+static struct l_nch *ncache_addr(KA_T na);
+#    endif /* defined(NCACHE_NODEID) */
+
+#    define DEFNCACHESZ 1024 /* local size if X_NCSIZE kernel value < 1 */
+#    define LNCHINCRSZ 64    /* local size increment */
+
+#    if !defined(NCACHE_NO_ROOT)
+static int ncache_isroot(KA_T na, char *cp);
+#    endif /* !defined(NCACHE_NO_ROOT) */
+
+/*
+ * ncache_addr() - look up a node's local ncache address
+ */
+
+static struct l_nch *
+
+#    if defined(NCACHE_NODEID)
+ncache_addr(unsigned long i, /* node's capability ID */
+#    else                    /* !defined(NCACHE_NODEID) */
+ncache_addr(
+#    endif                   /* defined(NCACHE_NODEID) */
+
+            KA_T na) /* node's address */
+{
+    struct l_nch **hp;
+
+#    if defined(NCACHE_NODEID)
+    for (hp = ncachehash(i, na); *hp; hp++)
+#    else  /* !defined(NCACHE_NODEID) */
+    for (hp = ncachehash(na); *hp; hp++)
+#    endif /* defined(NCACHE_NODEID) */
+
+    {
+
+#    if defined(NCACHE_NODEID)
+        if ((*hp)->id == i && (*hp)->na == na)
+#    else  /* !defined(NCACHE_NODEID) */
+        if ((*hp)->na == na)
+#    endif /* defined(NCACHE_NODEID) */
+
+            return (*hp);
+    }
+    return ((struct l_nch *)NULL);
+}
+
+#    if !defined(NCACHE_NO_ROOT)
+/*
+ * ncache_isroot() - is head of name cache path a file system root?
+ */
+
+static int ncache_isroot(struct lsof_context *ctx, /* context */
+                         KA_T na,                  /* kernel node address */
+                         char *cp)                 /* partial path */
+{
+    char buf[MAXPATHLEN];
+    int i;
+    MALLOC_S len;
+    struct mounts *mtp;
+    static int nca = 0;
+    static int ncn = 0;
+    static KA_T *nc = (KA_T *)NULL;
+    struct stat sb;
+    struct vnode v;
+
+    if (!na)
+        return (0);
+    /*
+     * Search the root vnode cache.
+     */
+    for (i = 0; i < ncn; i++) {
+        if (na == nc[i])
+            return (1);
+    }
+    /*
+     * Read the vnode and see if it's a VDIR node with the VROOT flag set.  If
+     * it is, then the path is complete.
+     *
+     * If it isn't, and if the file has an inode number, search the mount table
+     * and see if the file system's inode number is known.  If it is, form the
+     * possible full path, safely stat() it, and see if it's inode number
+     * matches the one we have for this file.  If it does, then the path is
+     * complete.
+     */
+    if (kread(ctx, (KA_T)na, (char *)&v, sizeof(v)) || v.v_type != VDIR ||
+        !(v.v_flag & VROOT)) {
+
+        /*
+         * The vnode tests failed.  Try the inode tests.
+         */
+        if (Lf->inp_ty != 1 || !Lf->inode || !Lf->fsdir ||
+            (len = strlen(Lf->fsdir)) < 1)
+            return (0);
+        if ((len + 1 + strlen(cp) + 1) > sizeof(buf))
+            return (0);
+        for (mtp = readmnt(); mtp; mtp = mtp->next) {
+            if (!mtp->dir || !mtp->inode)
+                continue;
+            if (strcmp(Lf->fsdir, mtp->dir) == 0)
+                break;
+        }
+        if (!mtp)
+            return (0);
+        (void)strcpy(buf, Lf->fsdir);
+        if (buf[len - 1] != '/')
+            buf[len++] = '/';
+        (void)strcpy(&buf[len], cp);
+        if (statsafely(buf, &sb) != 0 || (unsigned long)sb.st_ino != Lf->inode)
+            return (0);
+    }
+    /*
+     * Add the node address to the root node cache.
+     */
+    if (ncn >= nca) {
+        if (!nca) {
+            len = (MALLOC_S)(10 * sizeof(KA_T));
+            nc = (KA_T *)malloc(len);
+        } else {
+            len = (MALLOC_S)((nca + 10) * sizeof(KA_T));
+            nc = (KA_T *)realloc(nc, len);
+        }
+        if (!nc) {
+            (void)fprintf(stderr, "%s: no space for root node table\n", Pn);
+            Error(ctx);
+        }
+        nca += 10;
+    }
+    nc[ncn++] = na;
+    return (1);
+}
+#    endif /* !defined(NCACHE_NO_ROOT) */
+
+/*
+ * ncache_load() - load the kernel's name cache
+ */
+
+void ncache_load() {
+    struct l_nch **hp, *lc;
+    int i, len, n;
+    static int iNc = 0;
+    struct NCACHE *kc;
+    static KA_T kp = (KA_T)NULL;
+    KA_T v;
+
+#    if defined(NCACHE_NXT)
+    static KA_T kf;
+    struct NCACHE nc;
+#    else  /* !defined NCACHE_NXT) */
+    static struct NCACHE *kca = (struct NCACHE *)NULL;
+#    endif /* defined(NCACHE_NXT) */
+
+    if (!Fncache)
+        return;
+    if (Ncfirst) {
+
+        /*
+         * Do startup (first-time) functions.
+         */
+        Ncfirst = 0;
+        /*
+         * Establish kernel cache size.
+         */
+        v = (KA_T)0;
+        if (get_Nl_value(X_NCSIZE, (struct drive_Nl *)NULL, &v) < 0 || !v ||
+            kread(ctx, (KA_T)v, (char *)&Nc, sizeof(Nc))) {
+            if (!Fwarn)
+                (void)fprintf(stderr,
+                              "%s: WARNING: can't read name cache size: %s\n",
+                              Pn, print_kptr(v, (char *)NULL, 0));
+            iNc = Nc = 0;
+            return;
+        }
+        iNc = Nc;
+        if (Nc < 1) {
+            if (!Fwarn) {
+                (void)fprintf(stderr,
+                              "%s: WARNING: kernel name cache size: %d\n", Pn,
+                              Nc);
+                (void)fprintf(stderr, "      Cache size assumed to be: %d\n",
+                              DEFNCACHESZ);
+            }
+            iNc = Nc = DEFNCACHESZ;
+        }
+        /*
+         * Establish kernel cache address.
+         */
+        v = (KA_T)0;
+        if (get_Nl_value(X_NCACHE, (struct drive_Nl *)NULL, &v) < 0 || !v ||
+            kread(ctx, (KA_T)v, (char *)&kp, sizeof(kp))) {
+            if (!Fwarn)
+                (void)fprintf(
+                    stderr, "%s: WARNING: can't read name cache address: %s\n",
+                    Pn, print_kptr(v, (char *)NULL, 0));
+            iNc = Nc = 0;
+            return;
+        }
+
+#    if defined(NCACHE_NXT)
+        kf = kp;
+
+#    else  /* !defined(NCACHE_NXT) */
+        /*
+         * Allocate space for a local copy of the kernel's cache.
+         */
+        len = Nc * sizeof(struct NCACHE);
+        if (!(kca = (struct NCACHE *)malloc((MALLOC_S)len))) {
+            if (!Fwarn)
+                (void)fprintf(stderr,
+                              "%s: can't allocate name cache space: %d\n", Pn,
+                              len);
+            Error(ctx);
+        }
+#    endif /* defined(NCACHE_NXT) */
+
+        /*
+         * Allocate space for the local cache.
+         */
+        len = Nc * sizeof(struct l_nch);
+        if (!(Ncache = (struct l_nch *)malloc((MALLOC_S)len))) {
+
+        no_local_space:
+
+            if (!Fwarn)
+                (void)fprintf(stderr,
+                              "%s: no space for %d byte local name cache\n", Pn,
+                              len);
+            Error(ctx);
+        }
+    } else {
+
+        /*
+         * Do setup for repeat calls.
+         */
+        if ((Nc = iNc) == 0)
+            return;
+        if (Nchash) {
+            (void)free((FREE_P *)Nchash);
+            Nchash = (struct l_nch **)NULL;
+        }
+
+#    if defined(NCACHE_NXT)
+        kp = kf;
+#    endif /* defined(NCACHE_NXT) */
+    }
+
+#    if !defined(NCACHE_NXT)
+
+    /*
+     * Read the kernel's name cache.
+     */
+    if (kread(ctx, kp, (char *)kca, (Nc * sizeof(struct NCACHE)))) {
+        if (!Fwarn)
+            (void)fprintf(stderr,
+                          "%s: WARNING: can't read kernel's name cache: %s\n",
+                          Pn, print_kptr(kp, (char *)NULL, 0));
+        Nc = 0;
+        return;
+    }
+#    endif /* !defined(NCACHE_NXT) */
+
+    /*
+     * Build a local copy of the kernel name cache.
+     */
+
+#    if defined(NCACHE_NXT)
+    for (i = iNc * 16, kc = &nc, lc = Ncache, n = 0; kp;)
+#    else  /* !defined(NCACHE_NXT) */
+    for (i = n = 0, kc = kca, lc = Ncache; i < Nc; i++, kc++)
+#    endif /* defined(NCACHE_NXT) */
+
+    {
+
+#    if defined(NCACHE_NXT)
+        if (kread(ctx, kp, (char *)kc, sizeof(nc)))
+            break;
+        if ((kp = (KA_T)kc->NCACHE_NXT) == kf)
+            kp = (KA_T)NULL;
+#    endif /* defined(NCACHE_NXT) */
+
+        if (!kc->NCACHE_NODEADDR)
+            continue;
+        if ((len = kc->NCACHE_NMLEN) < 1 || len > NCHNAMLEN)
+            continue;
+        if (len < 3 && kc->NCACHE_NM[0] == '.') {
+            if (len == 1 || (len == 2 && kc->NCACHE_NM[1] == '.'))
+                continue;
+        }
+
+#    if defined(NCACHE_NXT)
+        if (n >= Nc) {
+            Nc += LNCHINCRSZ;
+            if (!(Ncache = (struct l_nch *)realloc(
+                      Ncache, (MALLOC_S)(Nc * sizeof(struct l_nch))))) {
+                (void)fprintf(
+                    stderr, "%s: no more space for %d entry local name cache\n",
+                    Pn, Nc);
+                Error(ctx);
+            }
+            lc = &Ncache[n];
+        }
+#    endif /* defined(NCACHE_NXT) */
+
+#    if defined(NCACHE_NODEID)
+        lc->na = (KA_T)kc->NCACHE_NODEADDR;
+        lc->id = kc->NCACHE_NODEID;
+#    endif /* defined(NCACHE_NODEID) */
+
+#    if defined(NCACHE_PARADDR)
+        lc->pa = (KA_T)kc->NCACHE_PARADDR;
+        lc->pla = (struct l_nch *)NULL;
+#    endif /* defined(NCACHE_PARADDR) */
+
+#    if defined(NCACHE_PARID)
+        lc->did = kc->NCACHE_PARID;
+#    endif /* defined(NCACHE_PARID) */
+
+        (void)strncpy(lc->nm, kc->NCACHE_NM, len);
+        lc->nm[len] = '\0';
+        lc->nl = strlen(lc->nm);
+        n++;
+        lc++;
+
+#    if defined(NCACHE_NXT)
+        if (n >= i) {
+            if (!Fwarn)
+                (void)fprintf(
+                    stderr, "%s: WARNING: name cache truncated at %d entries\n",
+                    Pn, n);
+            break;
+        }
+#    endif /* defined(NCACHE_NXT) */
+    }
+    /*
+     * Reduce memory usage, as required.
+     */
+
+#    if !defined(NCACHE_NXT)
+    if (!RptTm)
+        (void)free((FREE_P *)kca);
+#    endif /* !defined(NCACHE_NXT) */
+
+    if (n < 1) {
+        Nc = 0;
+        if (!RptTm) {
+            (void)free((FREE_P *)Ncache);
+            Ncache = (struct l_nch *)NULL;
+        }
+        if (!Fwarn)
+            (void)fprintf(stderr, "%s: WARNING: unusable name cache size: %d\n",
+                          Pn, n);
+        return;
+    }
+    if (n < Nc) {
+        Nc = n;
+        if (!RptTm) {
+            len = Nc * sizeof(struct l_nch);
+            if (!(Ncache = (struct l_nch *)realloc(Ncache, len)))
+                goto no_local_space;
+        }
+    }
+    /*
+     * Build a hash table to locate Ncache entries.
+     */
+    for (Nch = 1; Nch < Nc; Nch <<= 1)
+        ;
+    Nch <<= 1;
+    Mch = Nch - 1;
+    if (!(Nchash = (struct l_nch **)calloc(Nch + Nc, sizeof(struct l_nch *)))) {
+        if (!Fwarn)
+            (void)fprintf(stderr,
+                          "%s: no space for %d name cache hash pointers\n", Pn,
+                          Nch + Nc);
+        Error(ctx);
+    }
+    for (i = 0, lc = Ncache; i < Nc; i++, lc++) {
+
+#    if defined(NCACHE_NODEID)
+        for (hp = ncachehash(lc->id, lc->na), n = 1; *hp; hp++)
+#    else  /* defined(NCACHE_NODEID) */
+        for (hp = ncachehash(lc->na), n = 1; *hp; hp++)
+#    endif /* defined(NCACHE_NODEID) */
+
+        {
+
+#    if defined(NCACHE_NODEID)
+            if ((*hp)->na == lc->na && (*hp)->id == lc->id
+#    else  /* defined(NCACHE_NODEID) */
+            if ((*hp)->na == lc->na
+#    endif /* defined(NCACHE_NODEID) */
+
+                && strcmp((*hp)->nm, lc->nm) == 0
+
+#    if defined(NCACHE_PARADDR) && defined(NCACHE_PARID)
+                && (*hp)->pa == lc->pa && (*hp)->did == lc->did
+#    endif /* defined(NCACHE_PARADDR) && defined(NCACHE_PARID) */
+
+            ) {
+                n = 0;
+                break;
+            }
+        }
+        if (n)
+            *hp = lc;
+    }
+
+#    if defined(NCACHE_PARADDR) && defined(NCACHE_PARID)
+    /*
+     * Make a final pass through the local cache and convert parent node
+     * addresses to local name cache pointers.
+     */
+    for (i = 0, lc = Ncache; i < Nc; i++, lc++) {
+        if (!lc->pa)
+            continue;
+        lc->pla = ncache_addr(lc->did, lc->pa);
+    }
+#    endif /* defined(NCACHE_PARADDR) && defined(NCACHE_PARID) */
+}
+
+/*
+ * ncache_lookup() - look up a node's name in the kernel's name cache
+ */
+
+char *ncache_lookup(char *buf, /* receiving name buffer */
+                    int blen,  /* receiving buffer length */
+                    int *fp)   /* full path reply */
+{
+    char *cp = buf;
+    struct l_nch *lc;
+    struct mounts *mtp;
+    int nl, rlen;
+
+    *cp = '\0';
+    *fp = 0;
+
+#    if defined(HASFSINO)
+    /*
+     * If the entry has an inode number that matches the inode number of the
+     * file system mount point, return an empty path reply.  That tells the
+     * caller to print the file system mount point name only.
+     */
+    if ((Lf->inp_ty == 1) && Lf->fs_ino && (Lf->inode == Lf->fs_ino))
+        return (cp);
+#    endif /* defined(HASFSINO) */
+
+        /*
+         * Look up the name cache entry for the node address.
+         */
+
+#    if defined(NCACHE_NODEID)
+    if (Nc == 0 || !(lc = ncache_addr(Lf->id, Lf->na)))
+#    else  /* defined(NCACHE_NODEID) */
+    if (Nc == 0 || !(lc = ncache_addr(Lf->na)))
+#    endif /* defined(NCACHE_NODEID) */
+
+    {
+
+        /*
+         * If the node has no cache entry, see if it's the mount
+         * point of a known file system.
+         */
+        if (!Lf->fsdir || !Lf->dev_def || Lf->inp_ty != 1)
+            return ((char *)NULL);
+        for (mtp = readmnt(); mtp; mtp = mtp->next) {
+            if (!mtp->dir || !mtp->inode)
+                continue;
+            if (Lf->dev == mtp->dev && mtp->inode == Lf->inode &&
+                strcmp(mtp->dir, Lf->fsdir) == 0)
+                return (cp);
+        }
+        return ((char *)NULL);
+    }
+    /*
+     * Start the path assembly.
+     */
+    if ((nl = lc->nl) > (blen - 1))
+        return ((char *)NULL);
+    cp = buf + blen - nl - 1;
+    rlen = blen - nl - 1;
+    (void)strcpy(cp, lc->nm);
+
+#    if defined(NCACHE_PARADDR) && defined(NCACHE_PARID)
+    /*
+     * Look up the name cache entries that are parents of the node address.
+     * Quit when:
+     *
+     * there's no parent;
+     * the name length is too large to fit in the receiving buffer.
+     */
+    for (;;) {
+        if (!lc->pla) {
+
+#        if !defined(NCACHE_NO_ROOT)
+            if (ncache_isroot(lc->pa, cp))
+                *fp = 1;
+#        endif /* !defined(NCACHE_NO_ROOT) */
+
+            break;
+        }
+        lc = lc->pla;
+        if (((nl = lc->nl) + 1) > rlen)
+            break;
+        *(cp - 1) = '/';
+        cp--;
+        rlen--;
+        (void)strncpy((cp - nl), lc->nm, nl);
+        cp -= nl;
+        rlen -= nl;
+    }
+#    endif /* defined(NCACHE_PARADDR) && defined(NCACHE_PARID) */
+    return (cp);
+}
+#else  /* !defined(HASNCACHE) || !defined(USE_LIB_RNAM) */
+char rnam_d1[] = "d";
+char *rnam_d2 = rnam_d1;
+#endif /* defined(HASNCACHE) && defined(USE_LIB_RNAM) */
diff --git a/lib/rnch.c b/lib/rnch.c
new file mode 100644 (file)
index 0000000..ef13d1b
--- /dev/null
@@ -0,0 +1,777 @@
+/*
+ * rnch.c -- Sun format name cache functions for lsof library
+ */
+
+/*
+ * 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.
+ */
+
+#include "common.h"
+#include "machine.h"
+
+#if defined(HASNCACHE) && defined(USE_LIB_RNCH)
+
+/*
+ * rnch.c - read Sun format (struct ncache) name cache
+ *
+ * This code is effective only when HASNCACHE is defined.
+ */
+
+/*
+ * The caller must:
+ *
+ *     #include the relevant header file -- e.g., <sys/dnlc.h>.
+ *
+ *     Define X_NCSIZE as the nickname for the kernel cache size variable,
+ *     or, if X_NCSIZE is undefined, define FIXED_NCSIZE as the size of the
+ *     kernel cache.
+ *
+ *     Define X_NCACHE as the nickname for the kernel cache address and
+ *     define ADDR_NCACHE if the address is the address of the cache,
+ *     rather than the address of a pointer to it.
+ *
+ *     Define NCACHE_NXT if the kernel's name cache is a linked list, starting
+ *     at the X_NCACHE address, rather than a table, starting at that address.
+ *
+ *     Define any of the following casts that differ from their defaults:
+ *
+ *             NCACHE_SZ_CAST  cast for X_NCACHE (default int)
+ *
+ * The caller may:
+ *
+ *     Define NCACHE_DP        as the name of the element in the
+ *                             ncache structure that contains the
+ *                             parent vnode pointer.
+ *
+ *                             Default: dp
+ *
+ *     Define NCACHE_NAME      as the name of the element in the
+ *                             ncache structure that contains the
+ *                             name.
+ *
+ *                             Default: name
+ *
+ *     Define NCACHE_NAMLEN    as the name of the element in the
+ *                             ncache structure that contains the
+ *                             name length.
+ *
+ *                             Deafult: namlen
+ *
+ *     Define NCACHE_NEGVN     as the name of the name list element
+ *                             whose value is a vnode address to
+ *                             ignore when loading the kernel name
+ *                             cache.
+ *
+ *     Define NCACHE_NODEID    as the name of the element in the
+ *                             ncache structure that contains the
+ *                             vnode's capability ID.
+ *
+ *     Define NCACHE_PARID     as the name of the element in the
+ *                             ncache structure that contains the
+ *                             parent vnode's capability ID.
+ *
+ *     Define NCACHE_VP        as the name of the element in the
+ *                             ncache structure that contains the
+ *                             vnode pointer.
+ *
+ *                             Default: vp
+ *
+ * Note: if NCACHE_NODEID is defined, then NCACHE_PARID must be defined.
+ *
+ *
+ * The caller must:
+ *
+ *     Define this prototype for ncache_load():
+ *
+ *             _PROTOTYPE(void ncache_load,(void));
+ */
+
+/*
+ * Local static values
+ */
+
+static int Mch; /* name cache hash mask */
+
+#    if !defined(NCACHE_NC_CAST)
+#        define NCACHE_SZ_CAST int
+#    endif /* !defined(NCACHE_NC_CAST) */
+
+static NCACHE_SZ_CAST Nc = 0; /* size of name cache */
+static int Nch = 0;           /* size of name cache hash pointer
+                               * table */
+struct l_nch {
+    KA_T vp;          /* vnode address */
+    KA_T dp;          /* parent vnode address */
+    struct l_nch *pa; /* parent Ncache address */
+
+#    if defined(NCACHE_NODEID)
+    unsigned long id;  /* node's capability ID */
+    unsigned long did; /* parent node's capability ID */
+#    endif             /* defined(NCACHE_NODEID) */
+
+    char *nm; /* name */
+    int nl;   /* name length */
+};
+
+static struct l_nch *Ncache = (struct l_nch *)NULL;
+/* the local name cache */
+static struct l_nch **Nchash = (struct l_nch **)NULL;
+/* Ncache hash pointers */
+static int Ncfirst = 1; /* first-call status */
+
+#    if defined(NCACHE_NEGVN)
+static KA_T NegVN = (KA_T)NULL; /* negative vnode address */
+static int NegVNSt = 0;         /* NegVN status: 0 = not loaded */
+#    endif                      /* defined(NCACHE_NEGVN) */
+
+#    if defined(NCACHE_NODEID)
+static struct l_nch *ncache_addr(unsigned long i, KA_T v);
+#        define ncachehash(i, v)                                               \
+            Nchash + (((((int)(v) >> 2) + ((int)(i))) * 31415) & Mch)
+#    else /* !defined(NCACHE_NODEID) */
+static struct l_nch *ncache_addr(KA_T v);
+#        define ncachehash(v) Nchash + ((((int)(v) >> 2) * 31415) & Mch)
+#    endif /* defined(NCACHE_NODEID) */
+
+static int ncache_isroot(KA_T va, char *cp);
+
+#    define DEFNCACHESZ 1024 /* local size if X_NCSIZE kernel value < 1 */
+#    define LNCHINCRSZ 64    /* local size increment */
+
+#    if !defined(NCACHE_DP)
+#        define NCACHE_DP dp
+#    endif /* !defined(NCACHE_DP) */
+
+#    if !defined(NCACHE_NAME)
+#        define NCACHE_NAME name
+#    endif /* !defined(NCACHE_NAME) */
+
+#    if !defined(NCACHE_NAMLEN)
+#        define NCACHE_NAMLEN namlen
+#    endif /* !defined(NCACHE_NAMLEN) */
+
+#    if !defined(NCACHE_VP)
+#        define NCACHE_VP vp
+#    endif /* !defined(NCACHE_VP) */
+
+/*
+ * ncache_addr() - look up a node's local ncache address
+ */
+
+static struct l_nch *ncache_addr(
+#    if defined(NCACHE_NODEID)
+    unsigned long i, /* capability ID */
+#    endif           /* defined(NCACHE_NODEID) */
+    KA_T v)          /* vnode's address */
+{
+    struct l_nch **hp;
+
+#    if defined(NCACHE_NODEID)
+    for (hp = ncachehash(i, v); *hp; hp++)
+#    else  /* !defined(NCACHE_NODEID) */
+    for (hp = ncachehash(v); *hp; hp++)
+#    endif /* defined(NCACHE_NODEID) */
+
+    {
+
+#    if defined(NCACHE_NODEID)
+        if ((*hp)->vp == v && (*hp)->id == i)
+#    else  /* !defined(NCACHE_NODEID) */
+        if ((*hp)->vp == v)
+#    endif /* defined(NCACHE_NODEID) */
+
+            return (*hp);
+    }
+    return ((struct l_nch *)NULL);
+}
+
+/*
+ * ncache_isroot() - is head of name cache path a file system root?
+ */
+
+static int ncache_isroot(KA_T va,  /* kernel vnode address */
+                         char *cp) /* partial path */
+{
+    char buf[MAXPATHLEN];
+    int i;
+    MALLOC_S len;
+    struct mounts *mtp;
+    struct stat sb;
+    struct vnode v;
+    static int vca = 0;
+    static int vcn = 0;
+    static KA_T *vc = (KA_T *)NULL;
+
+    if (!va)
+        return (0);
+    /*
+     * Search the root vnode cache.
+     */
+    for (i = 0; i < vcn; i++) {
+        if (va == vc[i])
+            return (1);
+    }
+    /*
+     * Read the vnode and see if it's a VDIR node with the VROOT flag set.  If
+     * it is, then the path is complete.
+     *
+     * If it isn't, and if the file has an inode number, search the mount table
+     * and see if the file system's inode number is known.  If it is, form the
+     * possible full path, safely stat() it, and see if it's inode number
+     * matches the one we have for this file.  If it does, then the path is
+     * complete.
+     */
+    if (kread(ctx, (KA_T)va, (char *)&v, sizeof(v)) || v.v_type != VDIR ||
+        !(v.v_flag & VROOT)) {
+
+        /*
+         * The vnode tests failed.  Try the inode tests.
+         */
+        if (Lf->inp_ty != 1 || !Lf->inode || !Lf->fsdir ||
+            (len = strlen(Lf->fsdir)) < 1)
+            return (0);
+        if ((len + 1 + strlen(cp) + 1) > sizeof(buf))
+            return (0);
+        for (mtp = readmnt(); mtp; mtp = mtp->next) {
+            if (!mtp->dir || !mtp->inode)
+                continue;
+            if (strcmp(Lf->fsdir, mtp->dir) == 0)
+                break;
+        }
+        if (!mtp)
+            return (0);
+        (void)strcpy(buf, Lf->fsdir);
+        if (buf[len - 1] != '/')
+            buf[len++] = '/';
+        (void)strcpy(&buf[len], cp);
+        if (statsafely(buf, &sb) != 0 || (unsigned long)sb.st_ino != Lf->inode)
+            return (0);
+    }
+    /*
+     * Add the vnode address to the root vnode cache.
+     */
+    if (vcn >= vca) {
+        vca += 10;
+        len = (MALLOC_S)(vca * sizeof(KA_T));
+        if (!vc)
+            vc = (KA_T *)malloc(len);
+        else
+            vc = (KA_T *)realloc(vc, len);
+        if (!vc) {
+            (void)fprintf(stderr, "%s: no space for root vnode table\n", Pn);
+            Error(ctx);
+        }
+    }
+    vc[vcn++] = va;
+    return (1);
+}
+
+/*
+ * ncache_load() - load the kernel's name cache
+ */
+
+void ncache_load(struct lsof_context *ctx) {
+    char *cp, *np;
+    struct l_nch **hp, *lc;
+    int i, len, n;
+    static int iNc = 0;
+    struct ncache *kc;
+    static KA_T kp = (KA_T)NULL;
+    KA_T v;
+
+#    if defined(HASDNLCPTR)
+    static int na = 0;
+    static char *nb = (char *)NULL;
+#    endif /* defined(HASDNLCPTR) */
+
+#    if defined(NCACHE_NXT)
+    static KA_T kf;
+    struct ncache nc;
+#    else  /* !defined(NCACHE_NXT) */
+    static struct ncache *kca = (struct ncache *)NULL;
+#    endif /* defined(NCACHE_NXT) */
+
+    if (!Fncache)
+        return;
+    if (Ncfirst) {
+
+        /*
+         * Do startup (first-time) functions.
+         */
+        Ncfirst = 0;
+        /*
+         * Establish kernel cache size.
+         */
+
+#    if defined(X_NCSIZE)
+        v = (KA_T)0;
+        if (get_Nl_value(X_NCSIZE, (struct drive_Nl *)NULL, &v) < 0 || !v ||
+            kread(ctx, (KA_T)v, (char *)&Nc, sizeof(Nc))) {
+            if (!Fwarn)
+                (void)fprintf(stderr,
+                              "%s: WARNING: can't read name cache size: %s\n",
+                              Pn, print_kptr(v, (char *)NULL, 0));
+            iNc = Nc = 0;
+            return;
+        }
+        iNc = Nc;
+#    else  /* !defined(X_NCSIZE) */
+        iNc = Nc = FIXED_NCSIZE;
+#    endif /* defined(X_NCSIZE) */
+
+        if (Nc < 1) {
+            if (!Fwarn) {
+                (void)fprintf(stderr,
+                              "%s: WARNING: kernel name cache size: %d\n", Pn,
+                              Nc);
+                (void)fprintf(stderr, "      Cache size assumed to be: %d\n",
+                              DEFNCACHESZ);
+            }
+            iNc = Nc = DEFNCACHESZ;
+        }
+
+#    if defined(NCACHE_NEGVN)
+        /*
+         * Get negative vnode address.
+         */
+        if (!NegVNSt) {
+            if (get_Nl_value(NCACHE_NEGVN, (struct drive_Nl *)NULL, &NegVN) < 0)
+                NegVN = (KA_T)NULL;
+            NegVNSt = 1;
+        }
+#    endif /* defined(NCACHE_NEGVN) */
+
+        /*
+         * Establish kernel cache address.
+         */
+
+#    if defined(ADDR_NCACHE)
+        kp = (KA_T)0;
+        if (get_Nl_value(X_NCACHE, (struct drive_Nl *)NULL, (KA_T *)&kp) < 0 ||
+            !kp) {
+            if (!Fwarn)
+                (void)fprintf(stderr, "%s: WARNING: no name cache address\n",
+                              Pn);
+            iNc = Nc = 0;
+            return;
+        }
+#    else  /* !defined(ADDR_NCACHE) */
+        v = (KA_T)0;
+        if (get_Nl_value(X_NCACHE, (struct drive_Nl *)NULL, &v) < 0 || !v ||
+            kread(ctx, (KA_T)v, (char *)&kp, sizeof(kp))) {
+            if (!Fwarn)
+                (void)fprintf(stderr,
+                              "%s: WARNING: can't read name cache ptr: %s\n",
+                              Pn, print_kptr(v, (char *)NULL, 0));
+            iNc = Nc = 0;
+            return;
+        }
+#    endif /* defined(ADDR_NCACHE) */
+
+        /*
+         * Allocate space for a local copy of the kernel's cache.
+         */
+
+#    if !defined(NCACHE_NXT)
+        len = Nc * sizeof(struct ncache);
+        if (!(kca = (struct ncache *)malloc((MALLOC_S)len))) {
+            if (!Fwarn)
+                (void)fprintf(stderr,
+                              "%s: can't allocate name cache space: %d\n", Pn,
+                              len);
+            Error(ctx);
+        }
+#    endif /* !defined(NCACHE_NXT) */
+
+        /*
+         * Allocate space for the local cache.
+         */
+        len = Nc * sizeof(struct l_nch);
+        if (!(Ncache = (struct l_nch *)calloc(Nc, sizeof(struct l_nch)))) {
+
+        no_local_space:
+
+            if (!Fwarn)
+                (void)fprintf(stderr,
+                              "%s: no space for %d byte local name cache\n", Pn,
+                              len);
+            Error(ctx);
+        }
+    } else {
+
+        /*
+         * Do setup for repeat calls.
+         */
+        if (!iNc)
+            return;
+        if (Nchash) {
+            (void)free((FREE_P *)Nchash);
+            Nchash = (struct l_nch **)NULL;
+        }
+        if (Ncache) {
+
+            /*
+             * Free space malloc'd to names in local name cache.
+             */
+            for (i = 0, lc = Ncache; i < Nc; i++, lc++) {
+                if (lc->nm) {
+                    (void)free((FREE_P *)lc->nm);
+                    lc->nm = (char *)NULL;
+                }
+            }
+        }
+        Nc = iNc;
+
+#    if defined(NCACHE_NXT)
+        kp = kf;
+#    endif /* defined(NCACHE_NXT) */
+    }
+
+#    if !defined(NCACHE_NXT)
+
+    /*
+     * Read the kernel's name cache.
+     */
+    if (kread(ctx, kp, (char *)kca, (Nc * sizeof(struct ncache)))) {
+        if (!Fwarn)
+            (void)fprintf(stderr,
+                          "%s: WARNING: can't read kernel's name cache: %s\n",
+                          Pn, print_kptr(kp, (char *)NULL, 0));
+        Nc = 0;
+        return;
+    }
+#    endif /* !defined(NCACHE_NXT) */
+
+    /*
+     * Build a local copy of the kernel name cache.
+     */
+
+#    if defined(NCACHE_NXT)
+    for (i = iNc * 16, kc = &nc, kf = kp, lc = Ncache, n = 0; kp;)
+#    else  /* !defined(NCACHE_NXT) */
+    for (i = n = 0, kc = kca, lc = Ncache; i < Nc; i++, kc++)
+#    endif /* defined(NCACHE_NXT) */
+
+    {
+
+#    if defined(NCACHE_NXT)
+        if (kread(ctx, kp, (char *)kc, sizeof(nc)))
+            break;
+        if ((kp = (KA_T)kc->NCACHE_NXT) == kf)
+            kp = (KA_T)NULL;
+#    endif /* defined(NCACHE_NXT) */
+
+        if (!kc->NCACHE_VP || (len = kc->NCACHE_NAMLEN) < 1)
+            continue;
+
+#    if defined(NCACHE_NEGVN)
+        if (NegVN && ((KA_T)kc->NCACHE_VP == NegVN))
+            continue;
+#    endif /* defined(NCACHE_NEGVN) */
+
+#    if defined(HASDNLCPTR)
+        /*
+         * Read name from kernel to a temporary buffer.
+         */
+        if (len > na) {
+            na = len;
+            if (!nb)
+                nb = (char *)malloc(na);
+            else
+                nb = (char *)realloc((MALLOC_P *)nb, na);
+            if (!nb) {
+                (void)fprintf(
+                    stderr,
+                    "%s: can't allocate %d byte temporary name buffer\n", Pn,
+                    na);
+                Error(ctx);
+            }
+        }
+        if (!kc->NCACHE_NAME || kread(ctx, (KA_T)kc->NCACHE_NAME, nb, len))
+            continue;
+        np = nb;
+#    else  /* !defined(HASDNLCPTR) */
+        /*
+         * Use name that is in the kernel cache entry.
+         */
+        if (len > NC_NAMLEN)
+            continue;
+        np = kc->NCACHE_NAME;
+#    endif /* defined(HASDNLCPTR) */
+
+        if (len < 3 && *np == '.') {
+            if (len == 1 || (len == 2 && np[1] == '.'))
+                continue;
+        }
+        /*
+         * Allocate space for name in local cache entry.
+         */
+        if (!(cp = (char *)malloc(len + 1))) {
+            (void)fprintf(
+                stderr, "%s: can't allocate %d bytes for name cache name: %s\n",
+                Pn, len + 1, np);
+            Error(ctx);
+        }
+        (void)strncpy(cp, np, len);
+        cp[len] = '\0';
+
+#    if defined(NCACHE_NXT)
+        if (n >= Nc) {
+
+            /*
+             * Allocate more local space to receive the kernel's linked
+             * entries.
+             */
+            Nc += LNCHINCRSZ;
+            if (!(Ncache = (struct l_nch *)realloc(
+                      Ncache, (MALLOC_S)(Nc * sizeof(struct l_nch))))) {
+                (void)fprintf(
+                    stderr, "%s: no more space for %d entry local name cache\n",
+                    Pn, Nc);
+                Error(ctx);
+            }
+            lc = &Ncache[n];
+            iNc = Nc;
+        }
+#    endif /* defined(NCACHE_NXT) */
+
+        /*
+         * Complete the local cache entry.
+         */
+        lc->vp = (KA_T)kc->NCACHE_VP;
+        lc->dp = (KA_T)kc->NCACHE_DP;
+        lc->pa = (struct l_nch *)NULL;
+        lc->nm = cp;
+        lc->nl = len;
+
+#    if defined(NCACHE_NODEID)
+        lc->id = (unsigned long)kc->NCACHE_NODEID;
+        lc->did = (unsigned long)kc->NCACHE_PARID;
+#    endif /* defined(NCACHE_NODEID) */
+
+        n++;
+        lc++;
+
+#    if defined(NCACHE_NXT)
+        if (n >= i) {
+            if (!Fwarn)
+                (void)fprintf(
+                    stderr, "%s: WARNING: name cache truncated at %d entries\n",
+                    Pn, n);
+            break;
+        }
+#    endif /* defined(NCACHE_NXT) */
+    }
+    /*
+     * Reduce memory usage, as required.
+     */
+
+#    if !defined(NCACHE_NXT)
+    if (!RptTm)
+        (void)free((FREE_P *)kca);
+#    endif /* !defined(NCACHE_NXT) */
+
+    if (n < 1) {
+        if (!RptTm && Ncache) {
+
+            /*
+             * If not in repeat mode, free the space that has been malloc'd
+             * to the local name cache.
+             */
+            for (i = 0, lc = Ncache; i < Nc; i++, lc++) {
+                if (lc->nm) {
+                    (void)free((FREE_P *)lc->nm);
+                    lc->nm = (char *)NULL;
+                }
+            }
+            (void)free((FREE_P *)Ncache);
+            Ncache = (struct l_nch *)NULL;
+            Nc = 0;
+        }
+        if (!Fwarn)
+            (void)fprintf(stderr, "%s: WARNING: unusable name cache size: %d\n",
+                          Pn, n);
+        return;
+    }
+    if (n < Nc) {
+        Nc = n;
+        if (!RptTm) {
+            len = Nc * sizeof(struct l_nch);
+            if (!(Ncache = (struct l_nch *)realloc(Ncache, len)))
+                goto no_local_space;
+        }
+    }
+    /*
+     * Build a hash table to locate Ncache entries.
+     */
+    for (Nch = 1; Nch < Nc; Nch <<= 1)
+        ;
+    Nch <<= 1;
+    Mch = Nch - 1;
+    if (!(Nchash = (struct l_nch **)calloc(Nch + Nc, sizeof(struct l_nch *)))) {
+        if (!Fwarn)
+            (void)fprintf(stderr,
+                          "%s: no space for %d name cache hash pointers\n", Pn,
+                          Nch + Nc);
+        Error(ctx);
+    }
+    for (i = 0, lc = Ncache; i < Nc; i++, lc++) {
+
+#    if defined(NCACHE_NODEID)
+        for (hp = ncachehash(lc->id, lc->vp), n = 1; *hp; hp++)
+#    else  /* !defined(NCACHE_NODEID) */
+        for (hp = ncachehash(lc->vp), n = 1; *hp; hp++)
+#    endif /* defined(NCACHE_NODEID) */
+
+        {
+            if ((*hp)->vp == lc->vp && strcmp((*hp)->nm, lc->nm) == 0 &&
+                (*hp)->dp == lc->dp
+
+#    if defined(NCACHE_NODEID)
+                && (*hp)->id == lc->id && (*hp)->did == lc->did
+#    endif /* defined(NCACHE_NODEID) */
+
+            ) {
+                n = 0;
+                break;
+            }
+        }
+        if (n)
+            *hp = lc;
+    }
+    /*
+     * Make a final pass through the local cache and convert parent vnode
+     * addresses to local name cache pointers.
+     */
+    for (i = 0, lc = Ncache; i < Nc; i++, lc++) {
+        if (!lc->dp)
+            continue;
+
+#    if defined(NCACHE_NEGVN)
+        if (NegVN && (lc->dp == NegVN)) {
+            lc->pa = (struct l_nch *)NULL;
+            continue;
+        }
+#    endif /* defined(NCACHE_NEGVN) */
+
+#    if defined(NCACHE_NODEID)
+        lc->pa = ncache_addr(lc->did, lc->dp);
+#    else  /* !defined(NCACHE_NODEID) */
+        lc->pa = ncache_addr(lc->dp);
+#    endif /* defined(NCACHE_NODEID) */
+    }
+}
+
+/*
+ * ncache_lookup() - look up a node's name in the kernel's name cache
+ */
+
+char *ncache_lookup(char *buf, /* receiving name buffer */
+                    int blen,  /* receiving buffer length */
+                    int *fp)   /* full path reply */
+{
+    char *cp = buf;
+    struct l_nch *lc;
+    struct mounts *mtp;
+    int nl, rlen;
+
+    *cp = '\0';
+    *fp = 0;
+
+#    if defined(HASFSINO)
+    /*
+     * If the entry has an inode number that matches the inode number of the
+     * file system mount point, return an empty path reply.  That tells the
+     * caller to print the file system mount point name only.
+     */
+    if ((Lf->inp_ty == 1) && Lf->fs_ino && (Lf->inode == Lf->fs_ino))
+        return (cp);
+#    endif /* defined(HASFSINO) */
+
+    /*
+     * Look up the name cache entry for the node address.
+     */
+    if (!Nc
+
+#    if defined(NCACHE_NODEID)
+        || !(lc = ncache_addr(Lf->id, Lf->na))
+#    else  /* !defined(NCACHE_NODEID) */
+        || !(lc = ncache_addr(Lf->na))
+#    endif /* defined(NCACHE_NODEID) */
+
+    ) {
+
+        /*
+         * If the node has no cache entry, see if it's the mount
+         * point of a known file system.
+         */
+        if (!Lf->fsdir || !Lf->dev_def || Lf->inp_ty != 1)
+            return ((char *)NULL);
+        for (mtp = readmnt(); mtp; mtp = mtp->next) {
+            if (!mtp->dir || !mtp->inode)
+                continue;
+            if (Lf->dev == mtp->dev && mtp->inode == Lf->inode &&
+                strcmp(mtp->dir, Lf->fsdir) == 0)
+                return (cp);
+        }
+        return ((char *)NULL);
+    }
+    /*
+     * Begin the path assembly.
+     */
+    if ((nl = lc->nl) > (blen - 1))
+        return ((char *)NULL);
+    cp = buf + blen - nl - 1;
+    rlen = blen - nl - 1;
+    (void)strcpy(cp, lc->nm);
+    /*
+     * Look up the name cache entries that are parents of the node address.
+     * Quit when:
+     *
+     * there's no parent;
+     * the name is too large to fit in the receiving buffer.
+     */
+    for (;;) {
+        if (!lc->pa) {
+            if (ncache_isroot(lc->dp, cp))
+                *fp = 1;
+            break;
+        }
+        lc = lc->pa;
+        if (((nl = lc->nl) + 1) > rlen)
+            break;
+        *(cp - 1) = '/';
+        cp--;
+        rlen--;
+        (void)strncpy((cp - nl), lc->nm, nl);
+        cp -= nl;
+        rlen -= nl;
+    }
+    return (cp);
+}
+#else  /* !defined(HASNCACHE) || !defined(USE_LIB_RNCH) */
+char rnch_d1[] = "d";
+char *rnch_d2 = rnch_d1;
+#endif /* defined(HASNCACHE) && defined(USE_LIB_RNCH) */
diff --git a/lib/rnmh.c b/lib/rnmh.c
new file mode 100644 (file)
index 0000000..b296382
--- /dev/null
@@ -0,0 +1,716 @@
+/*
+ * rnmh.c -- functions to read BSD format name cache information from a
+ *          kernel hash table
+ */
+
+/*
+ * 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.
+ */
+
+#include "common.h"
+#include "machine.h"
+
+#if defined(HASNCACHE) && defined(USE_LIB_RNMH)
+
+/*
+ * rnmh.c - read BSD format hashed kernel name cache
+ */
+
+/*
+ * The caller must:
+ *
+ *     #include the relevant header file -- e.g., <sys/namei.h>.
+ *
+ *     Define X_NCACHE as the nickname for the kernel cache hash tables
+ *     address.
+ *
+ *     Define X_NCSIZE as the nickname for the size of the kernel cache has
+ *     table length.
+ *
+ *     Define NCACHE_NO_ROOT if the calling dialect doesn't support
+ *     the locating of the root node of a file system.
+ *
+ *     Define the name of the name cache structure -- e.g.,
+ *
+ *             #define NCACHE  <structure name>
+ *
+ *
+ *     Define the following casts, if they differ from the defaults:
+ *
+ *             NCACHE_SZ_CAST  case for X_NCSIZE (default unsigned long)
+ *
+ *     Define the names of these elements of struct NCACHE:
+ *
+ *             #define NCACHE_NM       <name>
+ *             #define NCACHE_NXT      <link to next entry>
+ *             #define NCACHE_NODEADDR <node address>
+ *             #define NCACHE_PARADDR  <parent node address>
+ *
+ *     Optionally define:
+ *
+ *             #define NCACHE_NMLEN    <name length>
+ *
+ *     Optionally define *both*:
+ *
+ *             #define NCACHE_NODEID   <node capability ID>
+ *             #define NCACHE_PARID    <parent node capability ID>
+ *
+ * The caller may need to:
+ *
+ *     Define this prototype for ncache_load():
+ *
+ *             _PROTOTYPE(static void ncache_load,(void));
+ *
+ *     Define NCACHE_VROOT to be the value of the flag that signifies that
+ *     the vnode is the root of its file system.
+ *
+ *             E.g., for BSDI >= 5:
+ *
+ *                     #define NCACHE_VROOT    VV_ROOT
+ *
+ *     If not defined, NCACHE_VROOT is defined as "VROOT".
+ *
+ *     Define VNODE_VFLAG if the vnode's flag member's name isn't v_flag.
+ *
+ * Note: if NCHNAMLEN is defined, the name is assumed to be in
+ * NCACHE_NM[NCHNAMLEN]; if it isn't defined, the name is assumed to be in an
+ * extension that begins at NCACHE_NM[0].
+ *
+ * Note: if NCACHE_NMLEN is not defined, then NCACHE_NM must be a pointer to
+ * a kernel allocated, NUL-terminated, string buffer.
+ */
+
+/*
+ * Casts
+ */
+
+#    if !defined(NCACHE_NC_CAST)
+#        define NCACHE_SZ_CAST unsigned long
+#    endif /* !defined(NCACHE_NC_CAST) */
+
+/*
+ * Flags
+ */
+
+#    if !defined(NCACHE_NMLEN)
+#        undef NCHNAMLEN
+#    endif /* !defined(NCACHE_NMLEN) */
+
+#    if !defined(NCACHE_VROOT)
+#        define NCACHE_VROOT VROOT /* vnode is root of its file system */
+#    endif                         /* !defined(NCACHE_VROOT) */
+
+#    if !defined(VNODE_VFLAG)
+#        define VNODE_VFLAG v_flag
+#    endif /* !defined(VNODE_VFLAG) */
+
+/*
+ * Local static values
+ */
+
+static int Mch; /* name cache hash mask */
+
+struct l_nch {
+    KA_T na;            /* node address */
+    KA_T pa;            /* parent node address */
+    struct l_nch *pla;  /* parent local node address */
+    int nl;             /* name length */
+    struct l_nch *next; /* next entry */
+
+#    if defined(NCACHE_NODEID)
+    unsigned long id;  /* capability ID */
+    unsigned long did; /* parent capability ID */
+#    endif             /* defined(NCACHE_NODEID) */
+
+#    if defined(NCHNAMLEN)
+    char nm[NCHNAMLEN + 1]; /* name */
+#    else                   /* !defined(NCHNAMLEN) */
+    char nm[1]; /* variable length name */
+#    endif                  /* defined(NCHNAMLEN) */
+};
+
+static struct l_nch *Ncache = (struct l_nch *)NULL;
+/* the head of the local name cache */
+static struct l_nch **Nchash = (struct l_nch **)NULL;
+/* Ncache hash pointers */
+
+#    if defined(NCACHE_NODEID)
+#        define ncachehash(i, n)                                               \
+            Nchash + (((((int)(n) >> 2) + ((int)(i))) * 31415) & Mch)
+static struct l_nch *ncache_addr(unsigned long i, KA_T na);
+#    else /* !defined(NCACHE_NODEID) */
+#        define ncachehash(n) Nchash + ((((int)(n) >> 2) * 31415) & Mch)
+static struct l_nch *ncache_addr(KA_T na);
+#    endif /* defined(NCACHE_NODEID) */
+
+#    if !defined(NCACHE_NO_ROOT)
+static int ncache_isroot(struct lsof_context *ctx, KA_T na, char *cp);
+#    endif /* !defined(NCACHE_NO_ROOT) */
+
+/*
+ * ncache_addr() - look up a node's local ncache address
+ */
+
+static struct l_nch *
+
+#    if defined(NCACHE_NODEID)
+ncache_addr(unsigned long i, /* node's capability ID */
+#    else                    /* !defined(NCACHE_NODEID) */
+ncache_addr(
+#    endif                   /* defined(NCACHE_NODEID) */
+            KA_T na)         /* node's address */
+{
+    struct l_nch **hp;
+
+#    if defined(NCACHE_NODEID)
+    for (hp = ncachehash(i, na); *hp; hp++)
+#    else  /* !defined(NCACHE_NODEID) */
+    for (hp = ncachehash(na); *hp; hp++)
+#    endif /* defined(NCACHE_NODEID) */
+
+    {
+
+#    if defined(NCACHE_NODEID)
+        if ((*hp)->id == i && (*hp)->na == na)
+#    else  /* !defined(NCACHE_NODEID) */
+        if ((*hp)->na == na)
+#    endif /* defined(NCACHE_NODEID) */
+
+            return (*hp);
+    }
+    return ((struct l_nch *)NULL);
+}
+
+#    if !defined(NCACHE_NO_ROOT)
+/*
+ * ncache_isroot() - is head of name cache path a file system root?
+ */
+
+static int ncache_isroot(struct lsof_context *ctx,
+                         KA_T na,  /* kernel node address */
+                         char *cp) /* partial path */
+{
+    char buf[MAXPATHLEN];
+    int i;
+    MALLOC_S len;
+    struct mounts *mtp;
+    static int nca = 0;
+    static int ncn = 0;
+    static KA_T *nc = (KA_T *)NULL;
+    struct stat sb;
+    struct vnode v;
+
+    if (!na)
+        return (0);
+    /*
+     * Search the root vnode cache.
+     */
+    for (i = 0; i < ncn; i++) {
+        if (na == nc[i])
+            return (1);
+    }
+    /*
+     * Read the vnode and see if it's a VDIR node with the NCACHE_VROOT flag
+     * set. If it is, then the path is complete.
+     *
+     * If it isn't, and if the file has an inode number, search the mount table
+     * and see if the file system's inode number is known.  If it is, form the
+     * possible full path, safely stat() it, and see if it's inode number
+     * matches the one we have for this file.  If it does, then the path is
+     * complete.
+     */
+    if (kread(ctx, (KA_T)na, (char *)&v, sizeof(v)) || v.v_type != VDIR ||
+        !(v.VNODE_VFLAG & NCACHE_VROOT)) {
+
+        /*
+         * The vnode tests failed.  Try the inode tests.
+         */
+        if (Lf->inp_ty != 1 || !Lf->inode || !Lf->fsdir ||
+            (len = strlen(Lf->fsdir)) < 1)
+            return (0);
+        if ((len + 1 + strlen(cp) + 1) > sizeof(buf))
+            return (0);
+        for (mtp = readmnt(ctx); mtp; mtp = mtp->next) {
+            if (!mtp->dir || !mtp->inode)
+                continue;
+            if (strcmp(Lf->fsdir, mtp->dir) == 0)
+                break;
+        }
+        if (!mtp)
+            return (0);
+        (void)strcpy(buf, Lf->fsdir);
+        if (buf[len - 1] != '/')
+            buf[len++] = '/';
+        (void)strcpy(&buf[len], cp);
+        if (statsafely(ctx, buf, &sb) != 0 ||
+            (unsigned long)sb.st_ino != Lf->inode)
+            return (0);
+    }
+    /*
+     * Add the node address to the root node cache.
+     */
+    if (ncn >= nca) {
+        if (!nca) {
+            len = (MALLOC_S)(10 * sizeof(KA_T));
+            nc = (KA_T *)malloc(len);
+        } else {
+            len = (MALLOC_S)((nca + 10) * sizeof(KA_T));
+            nc = (KA_T *)realloc(nc, len);
+        }
+        if (!nc) {
+            (void)fprintf(stderr, "%s: no space for root node table\n", Pn);
+            Error(ctx);
+        }
+        nca += 10;
+    }
+    nc[ncn++] = na;
+    return (1);
+}
+#    endif /* !defined(NCACHE_NO_ROOT) */
+
+/*
+ * ncache_load() - load the kernel's name cache
+ */
+
+void ncache_load(struct lsof_context *ctx) {
+    struct NCACHE c;
+    struct l_nch **hp, *ln;
+    KA_T ka, knx;
+    static struct NCACHE **khp = (struct namecache **)NULL;
+    static int khpl = 0;
+    NCACHE_SZ_CAST khsz;
+    unsigned long kx;
+    static struct l_nch *lc = (struct l_nch *)NULL;
+    static int lcl = 0;
+    int len, lim, n, nch, nchl, nlcl;
+    char tbuf[32];
+    KA_T v;
+
+#    if !defined(NCHNAMLEN)
+    int cin = sizeof(c.NCACHE_NM);
+    KA_T nmo = (KA_T)offsetof(struct NCACHE, NCACHE_NM);
+#    endif /* !defined(NCHNAMLEN) */
+
+#    if !defined(NCACHE_NMLEN)
+    char nbf[MAXPATHLEN + 1];
+    int nbfl = (int)(sizeof(nbf) - 1);
+    KA_T nk;
+    char *np;
+    int rl;
+
+    nbf[nbfl] = '\0';
+#    endif /* !defined(NCACHE_NMLEN) */
+
+    if (!Fncache)
+        return;
+    /*
+     * Free previously allocated space.
+     */
+    for (lc = Ncache; lc; lc = ln) {
+        ln = lc->next;
+        (void)free((FREE_P *)lc);
+    }
+    Ncache = (struct l_nch *)NULL;
+    if (Nchash)
+        (void)free((FREE_P *)Nchash);
+    Nchash = (struct l_nch **)NULL;
+    /*
+     * Get kernel cache hash table size
+     */
+    v = (KA_T)0;
+    if (get_Nl_value(ctx, X_NCSIZE, (struct drive_Nl *)NULL, &v) < 0 || !v ||
+        kread(ctx, (KA_T)v, (char *)&khsz, sizeof(khsz))) {
+        if (!Fwarn)
+            (void)fprintf(stderr,
+                          "%s: WARNING: can't read name cache hash size: %s\n",
+                          Pn, print_kptr(v, (char *)NULL, 0));
+        return;
+    }
+    if (khsz < 1) {
+        if (!Fwarn)
+            (void)fprintf(
+                stderr,
+                "%s: WARNING: name cache hash size length error: %#lx\n", Pn,
+                khsz);
+        return;
+    }
+    /*
+     * Get kernel cache hash table address.
+     */
+    ka = (KA_T)0;
+    v = (KA_T)0;
+    if (get_Nl_value(ctx, X_NCACHE, (struct drive_Nl *)NULL, &v) < 0 || !v ||
+        kread(ctx, (KA_T)v, (char *)&ka, sizeof(ka)) || !ka) {
+        if (!Fwarn)
+            (void)fprintf(
+                stderr,
+                "%s: WARNING: unusable name cache hash pointer: (%s)=%s\n", Pn,
+                print_kptr(v, tbuf, sizeof(tbuf)),
+                print_kptr(ka, (char *)NULL, 0));
+        return;
+    }
+    /*
+     * Allocate space for the hash table pointers and read them.
+     */
+    len = (MALLOC_S)(khsz * sizeof(struct NCACHE *));
+    if (len > khpl) {
+        if (khp)
+            khp = (struct NCACHE **)realloc((MALLOC_P *)khp, len);
+        else
+            khp = (struct NCACHE **)malloc(len);
+        if (!khp) {
+            (void)fprintf(
+                stderr,
+                "%s: can't allocate %d bytes for name cache hash table\n", Pn,
+                len);
+            Error(ctx);
+        }
+        khpl = len;
+    }
+    if (kread(ctx, (KA_T)ka, (char *)khp, len)) {
+        (void)fprintf(stderr,
+                      "%s: can't read name cache hash pointers from: %s\n", Pn,
+                      print_kptr(ka, (char *)NULL, 0));
+        return;
+    }
+    /*
+     * Process the kernel's name cache hash table buckets.
+     */
+    lim = khsz * 10;
+    for (kx = nch = 0; kx < khsz; kx++) {
+
+        /*
+         * Loop through the entries for a hash bucket.
+         */
+        for (ka = (KA_T)khp[kx], n = 0; ka; ka = knx, n++) {
+            if (n > lim) {
+                if (!Fwarn)
+                    (void)fprintf(
+                        stderr, "%s: WARNING: name cache hash chain too long\n",
+                        Pn);
+                break;
+            }
+            if (kread(ctx, ka, (char *)&c, sizeof(c)))
+                break;
+            knx = (KA_T)c.NCACHE_NXT;
+            if (!c.NCACHE_NODEADDR)
+                continue;
+
+#    if defined(NCACHE_NMLEN)
+            if ((len = c.NCACHE_NMLEN) < 1)
+                continue;
+#    else  /* !defined(NCACHE_NMLEN) */
+            /*
+             * If it's possible to read the first four characters of the name,
+             * do so and check for "." and "..".
+             */
+            if (!c.NCACHE_NM || kread(ctx, (KA_T)c.NCACHE_NM, nbf, 4))
+                continue;
+            if (nbf[0] == '.') {
+                if (!nbf[1] || ((nbf[1] == '.') && !nbf[2]))
+                    continue;
+            }
+            /*
+             * Read the rest of the name, 32 characters at a time, until a NUL
+             * character has been read or nbfl characters have been read.
+             */
+            nbf[4] = '\0';
+            if ((len = (int)strlen(nbf)) < 4) {
+                if (!len)
+                    continue;
+            } else {
+                for (np = &nbf[4]; len < nbfl; np += rl) {
+                    if ((rl = nbfl - len) > 32) {
+                        rl = 32;
+                        nbf[len + rl] = '\0';
+                    }
+                    nk = (KA_T)((char *)c.NCACHE_NM + len);
+                    if (kread(ctx, nk, np, rl)) {
+                        rl = -1;
+                        break;
+                    }
+                    rl = (int)strlen(np);
+                    len += rl;
+                    if (rl < 32)
+                        break;
+                }
+                if (rl < 0)
+                    continue;
+            }
+#    endif /* defined(NCACHE_NMLEN) */
+
+                /*
+                 * Allocate a cache entry long enough to contain the name and
+                 * move the name to it.
+                 */
+
+#    if defined(NCHNAMLEN)
+            if (len > NCHNAMLEN)
+                continue;
+            if (len < 3 && c.NCACHE_NM[0] == '.') {
+                if (len == 1 || (len == 2 && c.NCACHE_NM[1] == '.'))
+                    continue;
+            }
+            if ((nlcl = sizeof(struct l_nch)) > lcl)
+#    else  /* !defined(NCHNAMLEN) */
+            if ((nlcl = sizeof(struct l_nch) + len) > lcl)
+#    endif /* defined(NCHNAMLEN) */
+
+            {
+                if (lc)
+                    lc = (struct l_nch *)realloc(lc, nlcl);
+                else
+                    lc = (struct l_nch *)malloc(nlcl);
+                if (!lc) {
+                    (void)fprintf(
+                        stderr,
+                        "%s: can't allocate %d local name cache bytes\n", Pn,
+                        nlcl);
+                    Error(ctx);
+                }
+                lcl = nlcl;
+            }
+
+#    if defined(NCHNAMLEN)
+            (void)strncpy(lc->nm, c.NCACHE_NM, len);
+#    else /* !defined(NCHNAMLEN) */
+#        if defined(NCACHE_NMLEN)
+            if ((len < 3) && (cin > 1)) {
+
+                /*
+                 * If this is a one or two character name, and if NCACHE_NM[]
+                 * in c has room for at least two characters, check for "."
+                 * and ".." first, ignoring this entry if the name is either.
+                 */
+                if (len < 3 && c.NCACHE_NM[0] == '.') {
+                    if (len == 1 || (len == 2 && c.NCACHE_NM[1] == '.'))
+                        continue;
+                }
+            }
+            if (len > cin) {
+
+                /*
+                 * If not all (possibly not any, depending on the value in
+                 * cin) of the name has yet been read to lc->nm[], read it
+                 * or the rest of it.  If it wasn't possible before to check
+                 * for "." or "..", do that. too.
+                 */
+                if (cin > 0)
+                    (void)strncpy(lc->nm, c.NCACHE_NM, cin);
+                if (kread(ctx, ka + (KA_T)(nmo + cin), &lc->nm[cin], len - cin))
+                    continue;
+                if ((cin < 2) && (len < 3) && (lc->nm[0] == '.')) {
+                    if (len == 1 || (len == 2 && lc->nm[1] == '.'))
+                        continue;
+                }
+            } else
+                (void)strncpy(lc->nm, c.NCACHE_NM, len);
+#        else  /* !defined(NCACHE_NMLEN) */
+            (void)strncpy(lc->nm, nbf, len);
+#        endif /* defined(NCACHE_NMLEN) */
+
+#    endif /* defined(NCHNAMLEN) */
+            lc->nm[len] = '\0';
+            /*
+             * Complete the new local cache entry and link it to the previous
+             * local cache chain.
+             */
+            lc->next = Ncache;
+            Ncache = lc;
+            lc->na = (KA_T)c.NCACHE_NODEADDR;
+            lc->nl = len;
+            lc->pa = (KA_T)c.NCACHE_PARADDR;
+            lc->pla = (struct l_nch *)NULL;
+
+#    if defined(NCACHE_NODEID)
+            lc->id = c.NCACHE_NODEID;
+            lc->did = c.NCACHE_PARID;
+#    endif /* defined(NCACHE_NODEID) */
+
+            lcl = 0;
+            lc = (struct l_nch *)NULL;
+            nch++;
+        }
+    }
+    /*
+     * Reduce memory usage, as required.
+     */
+    if (!RptTm) {
+        (void)free((FREE_P *)khp);
+        khp = (struct NCACHE **)NULL;
+        khpl = 0;
+    }
+    if (nch < 1) {
+        if (!Fwarn)
+            (void)fprintf(stderr, "%s: WARNING: unusable name cache size: %d\n",
+                          Pn, nch);
+        return;
+    }
+    /*
+     * Build a hash table to locate Ncache entries.
+     */
+    for (nchl = 1; nchl < nch; nchl <<= 1)
+        ;
+    nchl <<= 1;
+    Mch = nchl - 1;
+    len = nchl + nch;
+    if (!(Nchash = (struct l_nch **)calloc(len, sizeof(struct l_nch *)))) {
+        if (!Fwarn)
+            (void)fprintf(
+                stderr, "%s: no space for %d local name cache hash pointers\n",
+                Pn, len);
+        Error(ctx);
+    }
+    for (lc = Ncache; lc; lc = lc->next) {
+
+#    if defined(NCACHE_NODEID)
+        for (hp = ncachehash(lc->id, lc->na),
+#    else  /* !defined(NCACHE_NODEID) */
+        for (hp = ncachehash(lc->na),
+#    endif /* defined(NCACHE_NODEID) */
+
+            n = 1;
+             *hp; hp++) {
+            if ((*hp)->na == lc->na && strcmp((*hp)->nm, lc->nm) == 0) {
+                n = 0;
+                break;
+            }
+        }
+        if (n)
+            *hp = lc;
+        else
+            lc->pa = (KA_T)0;
+    }
+    /*
+     * Make a final pass through the local cache and convert parent node
+     * addresses to local name cache pointers.
+     */
+    for (lc = Ncache; lc; lc = lc->next) {
+        if (!lc->pa)
+            continue;
+
+#    if defined(NCACHE_NODEID)
+        lc->pla = ncache_addr(lc->did, lc->pa);
+#    else  /* !defined(NCACHE_NODEID) */
+        lc->pla = ncache_addr(lc->pa);
+#    endif /* defined(NCACHE_NODEID) */
+    }
+}
+
+/*
+ * ncache_lookup() - look up a node's name in the kernel's name cache
+ */
+
+char *ncache_lookup(struct lsof_context *ctx,
+                    char *buf, /* receiving name buffer */
+                    int blen,  /* receiving buffer length */
+                    int *fp)   /* full path reply */
+{
+    char *cp = buf;
+    struct l_nch *lc;
+    struct mounts *mtp;
+    int nl, rlen;
+
+    *cp = '\0';
+    *fp = 0;
+
+#    if defined(HASFSINO)
+    /*
+     * If the entry has an inode number that matches the inode number of the
+     * file system mount point, return an empty path reply.  That tells the
+     * caller to print the file system mount point name only.
+     */
+    if ((Lf->inp_ty == 1) && Lf->fs_ino && (Lf->inode == Lf->fs_ino))
+        return (cp);
+#    endif /* defined(HASFSINO) */
+
+        /*
+         * Look up the name cache entry for the node address.
+         */
+
+#    if defined(NCACHE_NODEID)
+    if (!Nchash || !(lc = ncache_addr(Lf->id, Lf->na)))
+#    else  /* !defined(NCACHE_NODEID) */
+    if (!Nchash || !(lc = ncache_addr(Lf->na)))
+#    endif /* defined(NCACHE_NODEID) */
+
+    {
+
+        /*
+         * If the node has no cache entry, see if it's the mount
+         * point of a known file system.
+         */
+        if (!Lf->fsdir || !Lf->dev_def || Lf->inp_ty != 1)
+            return ((char *)NULL);
+        for (mtp = readmnt(ctx); mtp; mtp = mtp->next) {
+            if (!mtp->dir || !mtp->inode)
+                continue;
+            if (Lf->dev == mtp->dev && mtp->inode == Lf->inode &&
+                (strcmp(mtp->dir, Lf->fsdir) == 0))
+                return (cp);
+        }
+        return ((char *)NULL);
+    }
+    /*
+     * Start the path assembly.
+     */
+    if ((nl = lc->nl) > (blen - 1))
+        return ((char *)NULL);
+    cp = buf + blen - nl - 1;
+    rlen = blen - nl - 1;
+    (void)strcpy(cp, lc->nm);
+    /*
+     * Look up the name cache entries that are parents of the node address.
+     * Quit when:
+     *
+     * there's no parent;
+     * the name length is too large to fit in the receiving buffer.
+     */
+    for (;;) {
+        if (!lc->pla) {
+
+#    if !defined(NCACHE_NO_ROOT)
+            if (ncache_isroot(ctx, lc->pa, cp))
+                *fp = 1;
+#    endif /* !defined(NCACHE_NO_ROOT) */
+
+            break;
+        }
+        lc = lc->pla;
+        if (((nl = lc->nl) + 1) > rlen)
+            break;
+        *(cp - 1) = '/';
+        cp--;
+        rlen--;
+        (void)strncpy((cp - nl), lc->nm, nl);
+        cp -= nl;
+        rlen -= nl;
+    }
+    return (cp);
+}
+#else  /* !defined(HASNCACHE) || !defined(USE_LIB_RNMH) */
+char rnmh_d1[] = "d";
+char *rnmh_d2 = rnmh_d1;
+#endif /* defined(HASNCACHE) && defined(USE_LIB_RNMH) */
diff --git a/lib/rnmt.c b/lib/rnmt.c
new file mode 100644 (file)
index 0000000..709aad5
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2022  Tobias Nygren <tnn@NetBSD.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "common.h"
+#include "machine.h"
+
+#if defined(HASNCACHE) && defined(USE_LIB_RNMT)
+#    include <sys/rbtree.h>
+#    include <sys/vnode_impl.h>
+#    include <err.h>
+
+/*
+ * rnmt.c - read NetBSD=>10-style red-black tree kernel name cache
+ */
+
+static int lnc_compare_nodes(void *, const void *, const void *);
+static int lnc_compare_key(void *, const void *, const void *);
+
+static rb_tree_t lnc_rbtree;
+
+/* local name cache entry */
+struct lnc {
+    struct rb_node lnc_tree;      /* red-black tree */
+    KA_T lnc_vp;                  /* vnode address */
+    const struct lnc *lnc_plnc;   /* parent lnc address */
+    int lnc_nlen;                 /* name length */
+    char lnc_name[NCHNAMLEN + 1]; /* name */
+};
+
+static const rb_tree_ops_t lnc_rbtree_ops = {
+    .rbto_compare_nodes = lnc_compare_nodes,
+    .rbto_compare_key = lnc_compare_key,
+    .rbto_node_offset = offsetof(struct lnc, lnc_tree),
+    .rbto_context = NULL};
+
+static int lnc_compare_nodes(void *context, const void *node1,
+                             const void *node2) {
+    const struct lnc *lnc1 = node1;
+    const struct lnc *lnc2 = node2;
+
+    if (lnc1->lnc_vp < lnc2->lnc_vp) {
+        return -1;
+    }
+    if (lnc1->lnc_vp > lnc2->lnc_vp) {
+        return 1;
+    }
+
+    return 0;
+}
+
+static int lnc_compare_key(void *context, const void *node, const void *key) {
+    const struct lnc *lnc = node;
+    const KA_T vp = (KA_T)key;
+
+    if (lnc->lnc_vp < vp) {
+        return -1;
+    }
+    if (lnc->lnc_vp > vp) {
+        return 1;
+    }
+
+    return 0;
+}
+
+static struct lnc *ncache_enter_local(KA_T vp, const struct lnc *plnc,
+                                      const struct namecache *nc) {
+    struct lnc *lnc;
+
+    lnc = malloc(sizeof(*lnc));
+    if (!lnc) {
+        errx(1, "can't allocate local name cache entry\n");
+    }
+    lnc->lnc_vp = vp;
+    lnc->lnc_plnc = plnc;
+    lnc->lnc_nlen = nc->nc_nlen;
+    memcpy(lnc->lnc_name, nc->nc_name, lnc->lnc_nlen);
+    lnc->lnc_name[lnc->lnc_nlen] = 0;
+
+    rb_tree_insert_node(&lnc_rbtree, lnc);
+
+    return lnc;
+}
+
+static int sanity_check_vnode_impl(const struct vnode_impl *vi) {
+    if (vi->vi_vnode.v_type >= VBAD)
+        return -1;
+
+    return 0;
+}
+
+static int sanity_check_namecache(const struct namecache *nc) {
+    if (nc->nc_vp == NULL)
+        return -1;
+
+    if (nc->nc_nlen > NCHNAMLEN)
+        return -1;
+
+    if (nc->nc_nlen == 1 && nc->nc_name[0] == '.')
+        return -1;
+
+    if (nc->nc_nlen == 2 && nc->nc_name[0] == '.' && nc->nc_name[1] == '.')
+        return -1;
+
+    return 0;
+}
+
+static void ncache_walk(struct lsof_context *ctx, KA_T ncp,
+                        const struct lnc *plnc) {
+    struct l_nch *lc;
+    static struct vnode_impl vi;
+    static struct namecache nc;
+    struct lnc *lnc;
+    KA_T vp;
+    KA_T left, right;
+
+    if (kread(ctx, ncp, (char *)&nc, sizeof(nc))) {
+        return;
+    }
+    vp = (KA_T)nc.nc_vp;
+    if (kread(ctx, vp, (char *)&vi, sizeof(vi))) {
+        vi.vi_vnode.v_type = VBAD;
+    }
+    left = (KA_T)nc.nc_tree.rb_nodes[0];
+    right = (KA_T)nc.nc_tree.rb_nodes[1];
+    if (sanity_check_vnode_impl(&vi) == 0 && sanity_check_namecache(&nc) == 0) {
+        lnc = ncache_enter_local(vp, plnc, &nc);
+        if (vi.vi_vnode.v_type == VDIR && vi.vi_nc_tree.rbt_root != NULL) {
+            ncache_walk((KA_T)vi.vi_nc_tree.rbt_root, lnc);
+        }
+    }
+    if (left)
+        ncache_walk(left, plnc);
+    if (right)
+        ncache_walk(right, plnc);
+}
+
+void ncache_load(struct lsof_context *ctx) {
+    KA_T rootvnode_addr;
+    struct vnode_impl vi;
+
+    rootvnode_addr = (KA_T)0;
+    if (get_Nl_value("rootvnode", (struct drive_Nl *)NULL, &rootvnode_addr) <
+            0 ||
+        !rootvnode_addr ||
+        kread(ctx, (KA_T)rootvnode_addr, (char *)&rootvnode_addr,
+              sizeof(rootvnode_addr)) ||
+        kread(ctx, (KA_T)rootvnode_addr, (char *)&vi, sizeof(vi))) {
+        errx(1, "can't read rootvnode\n");
+    }
+
+    rb_tree_init(&lnc_rbtree, &lnc_rbtree_ops);
+    ncache_walk((KA_T)vi.vi_nc_tree.rbt_root, 0);
+}
+
+static void build_path(char **buf, size_t *remaining, const struct lnc *lnc) {
+    size_t len;
+
+    if (lnc == NULL)
+        return;
+
+    build_path(buf, remaining, lnc->lnc_plnc);
+    if (remaining == 0) {
+        return;
+    }
+    if (lnc->lnc_plnc != NULL) {
+        **buf = '/';
+        (*buf)++;
+        remaining--;
+    }
+    len = lnc->lnc_nlen;
+    if (*remaining < len)
+        len = *remaining;
+    memcpy(*buf, lnc->lnc_name, len);
+    *remaining -= len;
+    *buf += len;
+}
+
+char *ncache_lookup(char *buf, int blen, int *fp) {
+    const struct lnc *lnc;
+    char *p;
+    size_t remaining;
+
+    *fp = 0;
+    lnc = rb_tree_find_node(&lnc_rbtree, (void *)Lf->na);
+    if (lnc != NULL) {
+        p = buf;
+        remaining = blen;
+        build_path(&p, &remaining, lnc);
+        if (remaining == 0) {
+            buf[blen - 1] = 0;
+        } else {
+            *p = 0;
+        }
+        *fp = 1;
+        return buf;
+    }
+
+    return NULL;
+}
+#endif
diff --git a/m4/.gitignore b/m4/.gitignore
new file mode 100644 (file)
index 0000000..f10a1b5
--- /dev/null
@@ -0,0 +1,2 @@
+*.m4
+!header.m4
diff --git a/m4/header.m4 b/m4/header.m4
new file mode 100644 (file)
index 0000000..e57661a
--- /dev/null
@@ -0,0 +1,82 @@
+# header.m4 -- Generate headers from kernel source
+
+# Copyright 2002 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.
+
+# HEADER_GENERATE([HEADER_NAME, KERNEL_SOURCE, PATTERN_BEGIN, PATTERN_END, MACRO])
+# Create HEADER_NAME header from KERNEL_SOURCE,
+# copying the code between lines matching PATTERN_BEGIN and PATTERN_END.
+# The header is guarded from including twice by defining MACRO.
+AC_DEFUN([HEADER_GENERATE], [
+       # Generate HEADER_NAME($1) from KERNEL_SOURCE($2)
+       rm -rf $1
+       AS_IF([test -r $2], [
+               # Find the line number of PATTERN_BEGIN($3)
+               # Note extra quoting [[]] for M4
+               LSOF_TMP1=$(grep -n $3 $2 | sed 's/\([[0-9]]*\):.*$/\1/')
+               AS_IF([test "X$LSOF_TMP1" != "X"], [
+                       LSOF_TMP2=0
+                       # Find the end of PATTERN_END($4)
+                       for i in $(grep -n $4 $2 | sed 's/\([[0-9]]*\):.*/\1/') # {
+                       do
+                               AS_IF([test $LSOF_TMP2 -eq 0 -a $i -gt $LSOF_TMP1], [
+                                       LSOF_TMP2=$i
+                               ])
+                       done
+                       AS_IF([test $LSOF_TMP2 -eq 0], [
+                               LSOF_TMP1=""
+                       ], [
+                               cat > $1 << EOF
+/*
+ * $1 -- created by lsof configure script on
+EOF
+                               printf " * " >> $1
+                               date >> $1
+                               cat >> $1 << EOF
+ */
+
+#if    !defined($5)
+#define        $5
+
+EOF
+                               ed -s $2 >> $1 << EOF
+${LSOF_TMP1},${LSOF_TMP2}p
+EOF
+                               AS_IF([test $? -ne 0], [
+                                       AC_MSG_ERROR([can't extract source from $2])
+                               ], [
+                                       cat >> $1 << EOF
+
+#endif /* defined($5) */
+EOF
+                               ])
+                       ])
+               ])
+       ], [
+               AC_MSG_ERROR([can't read $2])
+       ])
+]))
diff --git a/mkdocs.yml b/mkdocs.yml
new file mode 100644 (file)
index 0000000..3248c32
--- /dev/null
@@ -0,0 +1,18 @@
+site_name: lsof
+theme:
+  name: readthedocs
+  highlightjs: true
+nav:
+  - index.md
+  - getting-started.md
+  - tutorial.md
+  - options.md
+  - faq.md
+  - manpage.md
+  - credits.md
+  - contributing.md
+  - maintaining.md
+plugins:
+  - search
+markdown_extensions:
+  - admonition
\ No newline at end of file
diff --git a/scripts/00MANIFEST b/scripts/00MANIFEST
new file mode 100644 (file)
index 0000000..f5f66d9
--- /dev/null
@@ -0,0 +1,49 @@
+The scripts in this subdirectory give examples of using lsof's
+field output.
+
+big_brother.pl         Perl 5 script, contributed by Lionel Cons
+                       <Lionel.Cons@cern.ch>, that watches for new
+                       network connections.
+
+count_pf.pl            Perl 5 script that runs lsof in repeat mode,
+                       gathering process, file, TCP, and UDP counts
+
+                       This script uses NUL terminated lsof field
+                       output.
+
+identd.pl              Perl 5 script, contributed by Kapil Chowksey
+                       <kchowksey@hss.hns.com> that implements an
+                       identd server. (Thanks, Kapil!)
+
+idrlogin.pl            Perl 5 script that identifies the shell and
+                       network source address of users who have logged
+                       on from remote locations via rlogin, ssh, or
+                       telnet
+
+list_NULf.pl           Perl 5 script that prints lsof's NUL terminated
+                       field output
+
+list_fields.awk                AWK script that prints lsof's field output
+
+list_fields.pl         Perl 4 or 5 script that prints lsof's field
+                       output
+
+shared.pl              Perl 5 script that uses +ffn output to produce
+                       a list of file descriptors or files shared by
+                       processes.
+
+sort_res.pl            Perl 5 script, contributed by Fabian Frederick
+                       <fabian.frederick@gmx.fr>, to display top resource
+                       usage.
+
+watch_a_file.pl                Perl 4 or 5 script that watches the use of a
+                       named file
+
+xusers.awk             an AWK (actually NAWK) script, written by
+                       Dan A. Mercer <damercer@mmm.com> that, "Prints
+                       list of users and applications signed on X
+                       workstations."  This script was developed
+                       and is used with lsof on HP-UX systems.
+
+Vic Abell
+December 28, 1998
diff --git a/scripts/00README b/scripts/00README
new file mode 100644 (file)
index 0000000..0d07f34
--- /dev/null
@@ -0,0 +1,43 @@
+
+           Notes on Using the Scripts in This Subdirectory
+
+The scripts in this subdirectory are examples of post-processing
+lsof field output.  Some are contributed by lsof users and are
+reproduced substantially as written by those users.  Since the
+scripts are examples, they are not guaranteed to work on all UNIX
+dialects.  Use them to learn about processing field output, don't
+expect them to be ready for production, and expect to be required
+to modify them to make them work.
+
+If you want to do field output post-processing in a C program, take
+a look at the test suite C library in ../tests/LTlib.c.  You may
+be able to adapt it to your needs.
+
+Supply AWK scripts to your AWK interpreter with its -f option.  Supply
+lsof field output via a pipe -- e.g.,
+
+       lsof -F | awk -f list_fields.awk
+
+The Perl scripts use the Unix command interpreter line feature to
+specify the location of Perl -- i.e., the first line begins with
+``#!'' and the path to the Perl interpreter follows.  If your system
+supports the command interpreter feature, but your Perl interpreters
+have different paths to them, just change the interpreter lines in
+the scripts.  These scripts assume Perl lives at /usr/bin/perl.
+
+If your system doesn't support the command interpreter feature,
+you'll have to supply the scripts to your Perl interpreter on its
+command line -- e.g.,
+
+       lsof -F | /<path_to_your_perl> list_fields.pl
+
+The Perl scripts attempt to establish a path to lsof, putting their
+result in the $LSOF variable.  Assuming you'll run them from the
+scripts subdirectory, they look there first, then in the directories
+of the PATH environment variable.  If that proves unsuitable, modify
+the &isexec() subroutine calls in the scripts to suit your lsof
+location.
+
+
+Vic Abell
+April 4, 2002
diff --git a/scripts/big_brother.pl b/scripts/big_brother.pl
new file mode 100755 (executable)
index 0000000..8a19757
--- /dev/null
@@ -0,0 +1,210 @@
+#!/usr/bin/perl -w
+#+##############################################################################
+#                                                                              #
+# File: big_brother.pl                                                         #
+#                                                                              #
+# Description: check the network sockets with lsof to detect new connections   #
+#                                                                             #
+# Contributed by Lionel Cons <Lionel.Cons@cern.ch>                            #
+#                                                                              #
+#-##############################################################################
+
+# @(#)big_brother      1.12 08/14/96 Written by Lionel.Cons@cern.ch
+
+# no waranty! use this at your own risks!
+
+#
+# init & setup
+#
+$verbose = 1;
+$lsof_opt = "-itcp -iudp -Di -FcLPn -r 5";
+$SIG{'HUP'} = \&hangup;
+chop($hostname = `/bin/hostname`);
+$fq_hostname = (gethostbyname($hostname))[0];
+
+# Set path to lsof.
+
+if (($LSOF = &isexec("../lsof")) eq "") {      # Try .. first
+    if (($LSOF = &isexec("lsof")) eq "") {     # Then try . and $PATH
+       print "can't execute $LSOF\n"; exit 1
+    }
+}
+
+#
+# spy forever...
+#
+$| = 1;
+die "$LSOF is not executable\n" unless -x $LSOF;
+while (1) {
+    $lsof_pid = open(PIPE, "$LSOF $lsof_opt 2>&1 |")
+       || die "can't start $LSOF: $!\n";
+    print "# ", &timestamp, " $LSOF $lsof_opt, pid=$lsof_pid\n"
+       if $verbose;
+    print "#COMMAND     PID     USER P NAME\n";
+    $printed = $hanguped = $pid = $proto = 0;
+    while (<PIPE>) {
+       if (/^lsof: PID \d+, /) {
+           # fatal error message?
+           print "*** $_";
+           last;
+       } elsif (/^lsof: /) {
+           # warning
+           warn "* $_";
+       } elsif (/^p(\d+)$/) {
+           &flush;
+           $pid = $1;
+           $proto = 0;
+       } elsif (/^c(.*)$/) {
+           $command = $1;
+       } elsif (/^L(.*)$/) {
+           $user = $1;
+       } elsif (/^P(.*)$/) {
+           &flush;
+           $proto = $1;
+       } elsif (/^n(.*)$/) {
+           $name = $1;
+           # replace local hostname by 'localhost'
+           $name =~ s/\Q$fq_hostname\E/localhost/g;
+           $name =~ s/[0-9hms]+ ago//g;
+       } elsif (/^m$/) {
+           &flush;
+           &clean;
+       } else {
+           warn "* bad output ignored: $_";
+       }
+    }
+    kill('INT',  $lsof_pid);
+    kill('KILL', $lsof_pid);
+    close(PIPE);
+}
+
+sub hangup {
+    $hanguped = 1;
+    $SIG{'HUP'} = \&hangup;
+}
+
+sub flush {
+    return unless $pid && $proto;
+    return if &skip;
+    $tag = sprintf("%-9s %5d %8s %1s %s", $command, $pid, $user,
+                  substr($proto, 0, 1), $name);
+    unless (defined($seen{$tag})) {
+       print "+$tag\n";
+       $printed++;
+    }
+    $seen{$tag} = 1;
+}
+
+sub clean {
+    my(@to_delete, $tag);
+
+    if ($hanguped) {
+       $hanguped = 0;
+       @to_delete = keys(%seen);
+       print "# ", &timestamp, " hangup received, rescanning all connections\n"
+           if $verbose;
+    } else {
+       @to_delete = ();
+       foreach $tag (keys(%seen)) {
+           if ($seen{$tag} == 0) {
+               # not seen this time: delete it
+               push(@to_delete, $tag);
+               print "-$tag\n";
+               $printed++;
+           } else {
+               # seen this time: reset the flag
+               $seen{$tag} = 0;
+           }
+       }
+    }
+    grep(delete($seen{$_}), @to_delete);
+    if ($printed > 10) {
+       print "# ", &timestamp, "\n" if $verbose;
+       $printed = 0;
+    }
+}
+
+sub skip {
+    #
+    # put stuff here to ignore some connections, for instance:
+    #
+
+    # what we get when the socket gets created...
+    return(1) if $name eq '*:0';
+    return(1) if $name =~ /^localhost:(\d+)$/ && $1 > 1000;
+#
+# UDP & TCP stuff
+#
+    #
+    # ignore common daemons
+    #
+    if ($name =~ /^\*:/ && $user eq 'root' && $pid < 300) {
+       return(1) if $command =~ /^inetd(\.afs)?$/;
+       return(1) if $command =~ /^rpc\.(stat|lock)d$/;
+       return(1) if $command eq 'syslogd' && $name eq '*:syslog';
+    }
+    #
+    # forking beasts: portmap, ypbind, inetd
+    #
+    if ($command eq 'portmap' && $user eq 'daemon') {
+       return(1) if $name =~ /^\*:/;
+    } elsif ($command eq 'ypbind') {
+       return(1) if $name =~ /^\*:\d+$/;
+    }
+#
+# TCP-only stuff
+#
+    return(0) unless $proto eq 'TCP';
+    #
+    # outgoing commands: ftp, telnet, r*
+    #
+    if ($command eq 'ftp') {
+       return(1) if $name =~ /:ftp(-data)?$/;
+    } elsif ($command eq 'telnet') {
+       return(1) if $name =~ /:telnet$/;
+    } elsif ($command eq 'remsh') {
+       if ($name =~ /:(\d?\d\d\d)->.+:(\d?\d\d\d)$/) {
+           return(1) if $1 < 1024 && $1 > 990 && $2 < 1024 && $2 > 990;
+       } elsif ($name =~ /:(\d?\d\d\d)->.+:(shell|ta-rauth)$/) {
+           return(1) if $1 < 1024 && $1 > 990;
+       } elsif ($name =~ /^\*:(\d?\d\d\d)$/) {
+           return(1) if $1 < 1024 && $1 > 990;
+       }
+    }
+    return(0);
+}
+
+sub timestamp {
+    my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst);
+
+    ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
+    sprintf("%d/%02d/%02d-%02d:%02d:%02d", $year + 1900, $mon+1, $mday,
+      $hour, $min, $sec);
+}
+
+
+## isexec($path) -- is $path executable
+#
+# $path   = absolute or relative path to file to test for executabiity.
+#          Paths that begin with neither '/' nor '.' that arent't found as
+#          simple references are also tested with the path prefixes of the
+#          PATH environment variable.
+
+sub
+isexec {
+    my ($path) = @_;
+    my ($i, @P, $PATH);
+
+    $path =~ s/^\s+|\s+$//g;
+    if ($path eq "") { return(""); }
+    if (($path =~ m#^[\/\.]#)) {
+       if (-x $path) { return($path); }
+       return("");
+    }
+    $PATH = $ENV{PATH};
+    @P = split(":", $PATH);
+    for ($i = 0; $i <= $#P; $i++) {
+       if (-x "$P[$i]/$path") { return("$P[$i]/$path"); }
+    }
+    return("");
+}
diff --git a/scripts/count_pf.pl b/scripts/count_pf.pl
new file mode 100755 (executable)
index 0000000..fc0299c
--- /dev/null
@@ -0,0 +1,94 @@
+#!/usr/bin/perl
+#
+# count_pf.pl    -- run lsof in repeat mode and count processes and
+#                  files
+
+sub interrupt { print "\n"; exit 0; }
+
+$RPT = 15;                             # lsof repeat time
+
+# Set path to lsof.
+
+if (($LSOF = &isexec("../lsof")) eq "") {      # Try .. first
+    if (($LSOF = &isexec("lsof")) eq "") {     # Then try . and $PATH
+       print "can't execute $LSOF\n"; exit 1
+    }
+}
+
+# Read lsof -nPF0 output repeatedly from a pipe.
+
+$| = 1;                                        # unbuffer output
+$SIG{'INT'} = 'interrupt';             # catch interrupt
+$proc = $files = $tcp = $udp = 0;
+$progress="/";
+open(P, "$LSOF -nPF0 -r $RPT|") || die "can't open pipe to $LSOF\n";
+
+LSOF_LINE:
+
+while (<P>) {
+    chop;
+    if (/^m/) {
+
+    # A marker line signals the end of an lsof repetition.
+
+       printf "%s  Processes: %5d,  Files: %6d,  TCP: %6d, UDP: %6d\r",
+           $progress, $proc, $files, $tcp, $udp;
+       $proc = $files = $tcp = $udp = 0;
+       if ($progress eq "/") { $progress = "\\"; } else { $progress = "/"; }
+       next LSOF_LINE;
+    }
+    if (/^p/) {
+
+    # Count process.
+
+       $proc++;
+       next LSOF_LINE;
+    }
+    if (/^f/) {
+
+    # Count files.
+
+       $files++;
+       @F = split("\0", $_, 999);
+       foreach $i (0 .. ($#F - 1)) {
+
+       # Search for protocol field.
+
+           if ($F[$i] =~ /^P(.*)/) {
+
+           # Count instances of TCP and UDP protocols.
+
+               if ($1 eq "TCP") { $tcp++; }
+               elsif ($1 eq "UDP") { $udp++; }
+               next LSOF_LINE;
+           }
+       }
+    }
+}
+
+
+## isexec($path) -- is $path executable
+#
+# $path   = absolute or relative path to file to test for executabiity.
+#          Paths that begin with neither '/' nor '.' that arent't found as
+#          simple references are also tested with the path prefixes of the
+#          PATH environment variable.
+
+sub
+isexec {
+    my ($path) = @_;
+    my ($i, @P, $PATH);
+
+    $path =~ s/^\s+|\s+$//g;
+    if ($path eq "") { return(""); }
+    if (($path =~ m#^[\/\.]#)) {
+       if (-x $path) { return($path); }
+       return("");
+    }
+    $PATH = $ENV{PATH};
+    @P = split(":", $PATH);
+    for ($i = 0; $i <= $#P; $i++) {
+       if (-x "$P[$i]/$path") { return("$P[$i]/$path"); }
+    }
+    return("");
+}
diff --git a/scripts/identd.pl b/scripts/identd.pl
new file mode 100755 (executable)
index 0000000..20661fb
--- /dev/null
@@ -0,0 +1,130 @@
+#!/usr/bin/perl
+###################################################################
+# identd.pl    : An implementation of RFC 1413 Ident Server
+#                using Vic Abell's lsof.
+#
+# - Started from inetd with 'nowait' option. This entry in
+#   /etc/inetd.conf will suffice :
+#
+#   ident   stream  tcp     nowait  root    /usr/local/bin/identd.pl -t200
+#
+# - Multiple instances of the server are not a performance penalty
+#   since they shall use lsof's cacheing mechanism. (compare with
+#   Peter Eriksson's pidentd)
+# - Command line arguments :
+#   -t TIMEOUT Number of seconds to wait for a query before aborting.
+#              Default is 120.
+#
+# Kapil Chowksey <kchowksey@hss.hns.com>
+# Nicholas Bamber <nicholas@periapt.co.uk>
+###################################################################
+use strict;
+use Socket;
+use Getopt::Long;
+
+# Set path to lsof.
+
+my $LSOF;
+if (($LSOF = &isexec("../lsof")) eq "") {      # Try .. first
+    if (($LSOF = &isexec("lsof")) eq "") {     # Then try . and $PATH
+       print "can't execute $LSOF\n"; exit 1
+    }
+}
+
+# redirect lsof's warnings/errors to /dev/null
+close(STDERR);
+open(STDERR, ">/dev/null");
+
+my $Timeout = "120";
+
+GetOptions('timeout=i'=>\$Timeout);
+
+my ($port, $iaddr) = sockaddr_in(getpeername(STDIN));
+my $peer_addr = inet_ntoa($iaddr);
+my $query;
+
+# read ident-query from socket (STDIN) with a timeout.
+my $timeout = int($Timeout);
+eval {
+    local $SIG{ALRM} = sub { die "alarm\n" };
+    alarm $timeout;
+    $query = <STDIN>;
+    alarm 0;
+};
+die if $@ && $@ ne "alarm\n";
+if ($@) {
+    # timed out
+    exit;
+}
+
+# remove all white-spaces from query
+$query =~ s/\s//g;
+
+my $serv_port = "";
+my $cli_port = "";
+($serv_port,$cli_port) = split(/,/,$query);
+
+if ($serv_port =~ /^[0-9]+$/) {
+    if (int($serv_port) < 1 || int($serv_port) > 65535) {
+        print $query." : ERROR : INVALID-PORT"."\n";
+        exit;
+    }
+} else {
+    print $query." : ERROR : INVALID-PORT"."\n";
+    exit;
+}
+
+if ($cli_port =~ /^[0-9]+$/) {
+    if (int($cli_port) < 1 || int($cli_port) > 65535) {
+        print $query." : ERROR : INVALID-PORT"."\n";
+        exit;
+    }
+} else {
+    print $query." : ERROR : INVALID-PORT"."\n";
+    exit;
+}
+
+open(LSOFP,"$LSOF -nPDi -T -FLn -iTCP@".$peer_addr.":".$cli_port."|");
+
+my $user = "UNKNOWN";
+while (my $a_line = <LSOFP>) {
+    # extract user name.
+    if ($a_line =~ /^L.*/) {
+        ($user) = ($a_line =~ /^L(.*)/);
+    }
+
+    # make sure local port matches.
+    if ($a_line =~ /^n.*:\Q$serv_port->/) {
+        print $serv_port.", ".$cli_port." : USERID : UNIX :".$user."\n";
+        exit;
+    }
+}
+
+print $serv_port.", ".$cli_port." : ERROR : NO-USER"."\n";
+
+
+## isexec($path) -- is $path executable
+#
+# $path   = absolute or relative path to file to test for executabiity.
+#          Paths that begin with neither '/' nor '.' that arent't found as
+#          simple references are also tested with the path prefixes of the
+#          PATH environment variable.
+
+sub
+isexec {
+    my ($path) = @_;
+    my ($i, @P, $PATH);
+
+    $path =~ s/^\s+|\s+$//g;
+    if ($path eq "") { return(""); }
+    if (($path =~ m#^[\/\.]#)) {
+       if (-x $path) { return($path); }
+       return("");
+    }
+    $PATH = $ENV{PATH};
+    @P = split(":", $PATH);
+    for ($i = 0; $i <= $#P; $i++) {
+       if (-x "$P[$i]/$path") { return("$P[$i]/$path"); }
+    }
+    return("");
+}
diff --git a/scripts/idrlogin.pl b/scripts/idrlogin.pl
new file mode 100755 (executable)
index 0000000..ab1c3e4
--- /dev/null
@@ -0,0 +1,195 @@
+#!/usr/bin/perl
+#
+# idrlogin.pl    -- sample Perl 5 script to identify the network source of a
+#                  network (remote) login via rlogind, sshd, or telnetd
+
+
+# IMPORTANT DEFINITIONS
+# =====================
+#
+# 1.  Set the interpreter line of this script to the local path of the
+#     Perl 5 executable.
+
+
+# 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.
+
+# Initialize variables.
+
+$dev = $faddr = $tty = "";                                     # fd variables
+$pidst = 0;                                                    # process state
+$cmd = $login = $pgrp = $pid = $ppid = "";                     # process var.
+
+# Set path to lsof.
+
+if (($LSOF = &isexec("../lsof")) eq "") {      # Try .. first
+    if (($LSOF = &isexec("lsof")) eq "") {     # Then try . and $PATH
+       print "can't execute $LSOF\n"; exit 1
+    }
+}
+
+# Open a pipe from lsof
+
+if (! -x "$LSOF") { die "Can't execute $LSOF\n"; }
+open (P, "$LSOF -R -FcDfLpPRn0|") || die "Can't pipe from $LSOF\n";
+
+# Process the lsof output a line at a time
+
+while (<P>) {
+    chop;
+    @F = split('\0', $_, 999);
+    if ($F[0] =~ /^p/) {
+
+# A process set begins with a PID field whose ID character is `p'.
+
+       if ($pidst) { &save_proc }
+       foreach $i (0 .. ($#F - 1)) {
+
+           PROC: {
+               if ($F[$i] =~ /^c(.*)/) { $cmd = $1; last PROC }
+               if ($F[$i] =~ /^p(.*)/) { $pid = $1; last PROC }
+               if ($F[$i] =~ /^R(.*)/) { $ppid = $1; last PROC }
+               if ($F[$i] =~ /^L(.*)/) { $login = $1; last PROC }
+           }
+       }
+       $pidst = 1;
+       next;
+    }
+
+# A file descriptor set begins with a file descriptor field whose ID
+# character is `f'.
+
+    if ($F[0] =~ /^f/) {
+       if ($faddr ne "") { next; }
+       $proto = $name = "";
+       foreach $i (0 .. ($#F - 1)) {
+
+           FD: {
+               if ($F[$i] =~ /^P(.*)/) { $proto = $1; last FD; }
+               if ($F[$i] =~ /^n(.*)/) { $name = $1; last FD; }
+               if ($F[$i] =~ /^D(.*)/) { $dev = $1; last FD; }
+           }
+       }
+       if ($proto eq "TCP"
+       &&  $faddr eq ""
+       &&  (($cmd =~ /rlogind/) || ($cmd =~ /sshd/) || ($cmd =~ /telnetd/))) {
+           if (($name =~ /[^:]*:[^-]*->([^:]*):.*/)) {
+               $faddr = $1;
+           }
+       } elsif ($tty eq "" && ($cmd =~ /.*sh$/)) {
+           if (($name =~ m#/dev.*ty.*#)) {
+               ($tty) = ($name =~ m#/dev.*/(.*)#);
+           } elsif (($name =~ m#/dev/(pts/\d+)#)) {
+               $tty = $1;
+           } elsif (($name =~ m#/dev.*pts.*#)) {
+               $d = oct($dev);
+               $tty = sprintf("pts/%d", $d & 0xffff);
+           }
+       }
+       next;
+    }
+}
+
+# Flush any stored file or process output.
+
+if ($pidst) { &save_proc }
+
+# List the shell processes that have rlogind/sshd/telnetd parents.
+
+$hdr = 0;
+foreach $pid (sort keys(%shcmd)) {
+    $p = $pid;
+    if (!defined($raddr{$pid})) {
+        for ($ff = 0; !$ff && defined($Ppid{$p}); ) {
+           $p = $Ppid{$p};
+           if ($p < 2 || defined($raddr{$p})) { $ff = 1; }
+        }
+    } else { $ff = 2; }
+    if ($ff && defined($raddr{$p})) {
+       if (!$hdr) {
+           printf "%-8.8s %-8.8s %6s %-10.10s %6s %-10.10s %s\n",
+               "Login", "Shell", "PID", "Via", "PID", "TTY", "From";
+           $hdr = 1;
+       }
+       printf "%-8.8s %-8.8s %6d %-10.10s %6s %-10.10s %s\n",
+           $shlogin{$pid}, $shcmd{$pid}, $pid,
+           ($ff == 2) ? "(direct)" : $rcmd{$p},
+           ($ff == 2) ? "" : $p,
+           ($shtty{$pid} eq "") ? "(unknown)" : $shtty{$pid},
+           $raddr{$p};
+    }
+}
+exit(0);
+
+
+# save_proc -- save process information
+#             Values are stored inelegantly in global variables.
+
+sub save_proc {
+    if (!defined($Ppid{$pid})) { $Ppid{$pid} = $ppid; }
+    if ($faddr ne "") {
+       $raddr{$pid} = $faddr;
+       if (($cmd =~ /.*sh$/)) {
+           $shcmd{$pid} = $cmd;
+           $shlogin{$pid} = $login;
+       } else { $rcmd{$pid} = $cmd; }
+    }
+    if ($tty ne "") {
+       $shcmd{$pid} = $cmd;
+       $shtty{$pid} = $tty;
+       $shlogin{$pid} = $login;
+    }
+
+# Clear variables.
+
+    $cmd = $dev = $faddr = $pgrp = $pid = $ppid = $tty = "";
+    $pidst = 0;
+}
+
+
+## isexec($path) -- is $path executable
+#
+# $path   = absolute or relative path to file to test for executabiity.
+#          Paths that begin with neither '/' nor '.' that arent't found as
+#          simple references are also tested with the path prefixes of the
+#          PATH environment variable.
+
+sub
+isexec {
+    my ($path) = @_;
+    my ($i, @P, $PATH);
+
+    $path =~ s/^\s+|\s+$//g;
+    if ($path eq "") { return(""); }
+    if (($path =~ m#^[\/\.]#)) {
+       if (-x $path) { return($path); }
+       return("");
+    }
+    $PATH = $ENV{PATH};
+    @P = split(":", $PATH);
+    for ($i = 0; $i <= $#P; $i++) {
+       if (-x "$P[$i]/$path") { return("$P[$i]/$path"); }
+    }
+    return("");
+}
diff --git a/scripts/list_NULf.pl b/scripts/list_NULf.pl
new file mode 100755 (executable)
index 0000000..c4c123d
--- /dev/null
@@ -0,0 +1,159 @@
+#!/usr/bin/perl
+#
+# list_NULf.pl    -- sample Perl 5 script to list lsof NUL-terminated
+#                   full field output (i.e., -F0 output)
+#
+# This script has been tested under perl version 5.001e.
+#
+# Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+# 47907.  All rights reserved.
+#
+# Written by Victor A. Abell
+#
+# This software is not subject to any license of the American Telephone
+# and Telegraph Company or the Regents of the University of California.
+#
+# Permission is granted to anyone to use this software for any purpose on
+# any computer system, and to alter it and redistribute it freely, subject
+# to the following restrictions:
+#
+# 1. Neither the authors nor Purdue University are responsible for any
+#    consequences of the use of this software.
+#
+# 2. The origin of this software must not be misrepresented, either by
+#    explicit claim or by omission.  Credit to the authors and Purdue
+#    University must appear in documentation and sources.
+#
+# 3. Altered versions must be plainly marked as such, and must not be
+#    misrepresented as being the original software.
+#
+# 4. This notice may not be removed or altered.
+
+# Initialize variables.
+
+$fhdr = 0;                                                     # fd hdr. flag
+$fdst = 0;                                                     # fd state
+$access = $devch = $devn = $fd = $inode = $lock = $name = "";  # | file descr.
+$offset = $proto = $size = $state = $stream = $type = "";      # | variables
+$pidst = 0;                                                    # process state
+$cmd = $login = $pgrp = $pid = $ppid = $uid = "";              # process var.
+
+# Process the ``lsof -F'' output a line at a time, gathering
+# the variables for a process together before printing them;
+# then gathering the variables for each file descriptor
+# together before printing them.
+
+while (<>) {
+    chop;
+    @F = split('\0', $_, 999);
+    if ($F[0] =~ /^p/) {
+
+# A process set begins with a PID field whose ID character is `p'.
+
+       if ($pidst) { &list_proc }
+       if ($fdst) { &list_fd; $fdst = 0; }
+       foreach $i (0 .. ($#F - 1)) {
+
+           PROC: {
+               if ($F[$i] =~ /^c(.*)/) { $cmd = $1; last PROC }
+               if ($F[$i] =~ /^g(.*)/) { $pgrp = $1; last PROC }
+               if ($F[$i] =~ /^p(.*)/) { $pid = $1; last PROC }
+               if ($F[$i] =~ /^u(.*)/) { $uid = $1; last PROC }
+               if ($F[$i] =~ /^L(.*)/) { $login = $1; last PROC }
+               if ($F[$i] =~ /^R(.*)/) { $ppid = $1; last PROC }
+               print "ERROR: unrecognized process field: \"$F[$i]\"\n";
+           }
+       }
+       $pidst = 1;
+       next;
+    }
+
+# A file descriptor set begins with a file descriptor field whose ID
+# character is `f'.
+
+    if ($F[0] =~ /^f/) {
+       if ($pidst) { &list_proc }
+       if ($fdst) { &list_fd }
+       foreach $i (0 .. ($#F - 1)) {
+
+           FD: {
+               if ($F[$i] =~ /^a(.*)/) { $access = $1; last FD; }
+               if ($F[$i] =~ /^C(.*)/) { last FD; }
+               if ($F[$i] =~ /^f(.*)/) { $fd = $1; last FD; }
+               if ($F[$i] =~ /^F(.*)/) { last FD; }
+               if ($F[$i] =~ /^d(.*)/) { $devch = $1; last FD; }
+               if ($F[$i] =~ /^D(.*)/) { $devn = $1; last FD; }
+               if ($F[$i] =~ /^G(.*)/) { last FD; }
+               if ($F[$i] =~ /^i(.*)/) { $inode = $1; last FD; }
+               if ($F[$i] =~ /^k(.*)/) { last FD; }
+               if ($F[$i] =~ /^l(.*)/) { $lock = $1; last FD; }
+               if ($F[$i] =~ /^N(.*)/) { last FD; }
+               if ($F[$i] =~ /^o(.*)/) { $offset = $1; last FD; }
+               if ($F[$i] =~ /^P(.*)/) { $proto = $1; last FD; }
+               if ($F[$i] =~ /^s(.*)/) { $size = $1; last FD; }
+               if ($F[$i] =~ /^S(.*)/) { $stream = $1; last FD; }
+               if ($F[$i] =~ /^t(.*)/) { $type = $1; last FD; }
+               if ($F[$i] =~ /^T(.*)/) {
+                   if ($state eq "") { $state = "(" . $1; }
+                   else { $state = $state . " " . $1; }
+                   last FD;
+               }
+               if ($F[$i] =~ /^n(.*)/) { $name = $1; last FD; }
+               print "ERROR: unrecognized file set field: \"$F[$i]\"\n";
+           }
+       }
+       $fdst = 1;
+       next;
+    }
+    print "ERROR: unrecognized: \"$_\"\n";
+}
+
+# Flush any stored file or process output.
+
+if ($fdst) { &list_fd }
+if ($pidst) { &list_proc }
+exit(0);
+
+
+## list_fd -- list file descriptor information
+#            Values are stored inelegantly in global variables.
+
+sub list_fd {
+    if ( ! $fhdr) {
+
+    # Print header once.
+
+       print "      FD   TYPE      DEVICE   SIZE/OFF      INODE  NAME\n";
+       $fhdr = 1;
+    }
+    printf "    %4s%1.1s%1.1s %4.4s", $fd, $access, $lock, $type;
+    $tmp = $devn; if ($devch ne "") { $tmp = $devch }
+    printf "  %10.10s", $tmp;
+    $tmp = $size; if ($offset ne "") { $tmp = $offset }
+    printf " %10.10s", $tmp;
+    $tmp = $inode; if ($proto ne "") { $tmp = $proto }
+    printf " %10.10s", $tmp;
+    $tmp = $stream; if ($name ne "") { $tmp = $name }
+    print "  ", $tmp;
+    if ($state ne "") { printf " %s)\n", $state; } else { print "\n"; }
+
+# Clear variables.
+
+    $access = $devch = $devn = $fd = $inode = $lock = "";
+    $name = $offset = $proto = $size = $state = $stream = $type = "";
+}
+
+
+# list_proc -- list process information
+#             Values are stored inelegantly in global variables.
+
+sub list_proc {
+    print "COMMAND       PID    PGRP    PPID  USER\n";
+    $tmp = $uid; if ($login ne "") {$tmp = $login }
+    printf "%-9.9s  %6d  %6d  %6d  %s\n", $cmd, $pid, $pgrp, $ppid, $tmp;
+
+# Clear variables.
+
+    $cmd = $login = $pgrp = $pid = $uid = "";
+    $fhdr = $pidst = 0;
+}
diff --git a/scripts/list_fields.awk b/scripts/list_fields.awk
new file mode 100644 (file)
index 0000000..d8fbbb4
--- /dev/null
@@ -0,0 +1,198 @@
+# $Id: list_fields.awk,v 1.3 97/09/23 09:32:38 abe Exp $
+#
+# list_fields.awk -- sample awk script to list lsof full field output
+#                   (i.e., -F output without -0)
+#
+# NB: this is not particularly elegant awk; several sections were
+#     replicated, perhaps unnecessarily, to produce a sample quickly
+#     and simply.
+#
+#
+# Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+# 47907.  All rights reserved.
+#
+# Written by Victor A. Abell
+#
+# This software is not subject to any license of the American Telephone
+# and Telegraph Company or the Regents of the University of California.
+#
+# Permission is granted to anyone to use this software for any purpose on
+# any computer system, and to alter it and redistribute it freely, subject
+# to the following restrictions:
+#
+# 1. Neither the authors nor Purdue University are responsible for any
+#    consequences of the use of this software.
+#
+# 2. The origin of this software must not be misrepresented, either by
+#    explicit claim or by omission.  Credit to the authors and Purdue
+#    University must appear in documentation and sources.
+#
+# 3. Altered versions must be plainly marked as such, and must not be
+#    misrepresented as being the original software.
+#
+# 4. This notice may not be removed or altered.
+
+# Clear file and process status.
+
+BEGIN {
+  fhdr = fdst = pidst = 0;
+  access = dev = devch = fd = inode = lock = name = offset = "";
+  proto = size = state = stream = type = "";
+  cmd = login = pgrp = pid = ppid = uid = "";
+}
+
+# Start a new process.
+
+/^p/ {
+  val = substr($0, 2);
+  if (pidst) {
+
+  # Print a previously accumulated process set.
+
+    printf "COMMAND       PID    PGRP    PPID  USER\n";
+    printf "%-9.9s  %6d  %6d  %6d", cmd, pid, pgrp, ppid;
+    if (login != "") { printf "  %s\n", login }
+    else { printf "  %s\n", uid }
+    pidst = 0;
+    cmd = login = pgrp = pid = uid = "";
+  }
+  if (fdst) {
+
+  # Print a previously accumulated file set.
+
+    if (fhdr == 0) {
+      printf "      FD   TYPE      DEVICE   SIZE/OFF      INODE  NAME\n";
+    }
+    printf "    %4.4s%1.1s%1.1s %4.4s", fd, access, lock, type;
+    t = dev; if (devch != "") { t = devch }
+    printf("  %10.10s", t);
+    t = size; if (offset != "") { t = offset }
+    printf " %10.10s", t;
+    t = inode; if (proto != "") { t = proto }
+    printf " %10.10s", t;
+    t = stream; if (name != "") {t = name }
+    printf "  %s", t;
+    if (state != "") { printf " %s)\n", state } else { printf "\n" }
+    access = dev = devch = fd = inode = lock = name = offset = "";
+    proto = size = state = stream = type = "";
+    fdst = fhdr = 0
+  }
+
+# Record a new process.
+
+  pidst = 1;
+  pid = val;
+}
+
+/^g|^c|^u|^L|^R/ {
+
+# Save process set information.
+
+  id = substr($0, 1, 1);
+  val = substr($0, 2);
+  if (id == "g") { pgrp = val; next }          # PGRP
+  if (id == "c") { cmd = val; next }           # command
+  if (id == "u") { uid = val; next }           # UID
+  if (id == "L") { login = val; next }         # login name
+  if (id == "R") { ppid = val; next }          # PPID
+}
+
+/^f|^a|^l|^t|^d|^D|^s|^o|^i|^P|^S|^T|^n/ {
+
+# Save file set information.
+
+  id = substr($0, 1, 1);
+  val = substr($0, 2);
+  if (id == "f") {
+    if (pidst) {
+
+    # Print a previously accumulated process set.
+
+      printf "COMMAND       PID    PGRP    PPID  USER\n";
+      printf "%-9.9s  %6d  %6d  %6d", cmd, pid, pgrp, ppid;
+      if (login != "") { printf "  %s\n", login }
+      else { printf "  %s\n", uid }
+      pidst = 0;
+      cmd = login = pgrp = pid = uid = "";
+    }
+    if (fdst) {
+
+      # Print a previously accumulated file set.
+
+       if (fhdr == 0) {
+         printf "      FD   TYPE      DEVICE   SIZE/OFF      INODE  NAME\n";
+       }
+       fhdr = 1;
+       printf "    %4.4s%1.1s%1.1s %4.4s", fd, access, lock, type;
+       t = dev; if (devch != "") { t = devch }
+       printf("  %10.10s", t);
+       t = size; if (offset != "") { t = offset }
+       printf " %10.10s", t;
+       t = inode; if (proto != "") { t = proto }
+       printf " %10.10s", t;
+       t = stream; if (name != "") {t = name }
+       printf "  %s", t;
+       if (state != "") { printf " %s)\n", state } else { printf "\n" }
+       access = dev = devch = fd = inode = lock = name = offset = "";
+       proto = size = state = stream = type = "";
+    }
+
+  # Start an new file set.
+
+    fd = val;
+    fdst = 1;
+    next;
+  }
+
+# Save file set information.
+
+  if (id == "a") { access = val; next }                # access
+  if (id == "l") { lock = val; next }          # lock
+  if (id == "t") { type = val; next }          # type
+  if (id == "d") { devch = val; next }         # device characters
+  if (id == "D") { dev = val; next }           # device major/minor numbers
+  if (id == "s") { size = val; next }          # size
+  if (id == "o") { offset = val; next }                # offset
+  if (id == "i") { inode = val; next }         # inode number
+  if (id == "P") { proto = val; next }         # protocol
+  if (id == "S") { stream = val; next }                # stream name
+  if (id == "T") {                             # TCP/TPI state
+    if (state == "") {
+      state = sprintf("(%s", val);
+    } else {
+      state = sprintf("%s %s", state, val);
+    }
+    next
+  }
+  if (id == "n") { name = val; next }          # name, comment, etc.
+}
+
+END {
+  if (pidst) {
+
+  # Print last process set.
+
+    printf "COMMAND       PID    PGRP    PPID  USER\n";
+    printf "%-9.9s  %6d  %6d  %6d", cmd, pid, pgrp, ppid;
+    if (login != "") { printf "  %s\n", login }
+    else { printf "  %s\n", uid }
+  }
+  if (fdst) {
+
+  # Print last file set.
+
+    if (fhdr == 0) {
+      printf "      FD   TYPE      DEVICE   SIZE/OFF      INODE  NAME\n";
+    }
+    printf "    %4.4s%1.1s%1.1s %4.4s", fd, access, lock, type;
+    t = dev; if (devch != "") { t = devch }
+    printf("  %10.10s", t);
+    t = size; if (offset != "") { t = offset }
+    printf " %10.10s", t;
+    t = inode; if (proto != "") { t = proto }
+    printf " %10.10s", t;
+    t = stream; if (name != "") {t = name }
+    printf "  %s", t;
+    if (state != "") { printf " %s)\n", state; } else { printf "\n"; }
+  }
+}
diff --git a/scripts/list_fields.pl b/scripts/list_fields.pl
new file mode 100755 (executable)
index 0000000..4d71e13
--- /dev/null
@@ -0,0 +1,154 @@
+#!/usr/bin/perl
+#
+# list_fields.pl   -- sample Perl script to list lsof full field output
+#                    (i.e., -F output without -0)
+#
+# This script has been tested under perl versions 4.036 and 5.001e.
+#
+# Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+# 47907.  All rights reserved.
+#
+# Written by Victor A. Abell
+#
+# This software is not subject to any license of the American Telephone
+# and Telegraph Company or the Regents of the University of California.
+#
+# Permission is granted to anyone to use this software for any purpose on
+# any computer system, and to alter it and redistribute it freely, subject
+# to the following restrictions:
+#
+# 1. Neither the authors nor Purdue University are responsible for any
+#    consequences of the use of this software.
+#
+# 2. The origin of this software must not be misrepresented, either by
+#    explicit claim or by omission.  Credit to the authors and Purdue
+#    University must appear in documentation and sources.
+#
+# 3. Altered versions must be plainly marked as such, and must not be
+#    misrepresented as being the original software.
+#
+# 4. This notice may not be removed or altered.
+
+# Initialize variables.
+
+$fhdr = 0;                                                     # fd hdr. flag
+$fdst = 0;                                                     # fd state
+$access = $devch = $devn = $fd = $inode = $lock = $name = "";  # | file descr.
+$offset = $proto = $size = $state = $stream = $type = "";      # | variables
+$pidst = 0;                                                    # process state
+$cmd = $login = $pgrp = $pid = $ppid = $uid = "";              # process var.
+
+# Process the ``lsof -F'' output a line at a time, gathering
+# the variables for a process together before printing them;
+# then gathering the variables for each file descriptor
+# together before printing them.
+
+while (<>) {
+    chop;
+    if (/^p(.*)/) {
+
+# A process set begins with a PID field whose ID character is `p'.
+
+       $tpid = $1;
+       if ($pidst) { &list_proc }
+       $pidst = 1;
+       $pid = $tpid;
+       if ($fdst) { &list_fd; $fdst = 0; }
+       next;
+    }
+
+# Save process-related values.
+
+    if (/^g(.*)/) { $pgrp = $1; next; }
+    if (/^c(.*)/) { $cmd = $1; next; }
+    if (/^u(.*)/) { $uid = $1; next; }
+    if (/^L(.*)/) { $login = $1; next; }
+    if (/^R(.*)/) { $ppid = $1; next; }
+
+# A file descriptor set begins with a file descriptor field whose ID
+# character is `f'.
+
+    if (/^f(.*)/) {
+       $tfd = $1;
+       if ($pidst) { &list_proc }
+       if ($fdst) { &list_fd }
+       $fd = $tfd;
+       $fdst = 1;
+       next;
+    }
+
+# Save file set information.
+
+    if (/^a(.*)/) { $access = $1; next; }
+    if (/^C(.*)/) { next; }
+    if (/^d(.*)/) { $devch = $1; next; }
+    if (/^D(.*)/) { $devn = $1; next; }
+    if (/^F(.*)/) { next; }
+    if (/^G(.*)/) { next; }
+    if (/^i(.*)/) { $inode = $1; next; }
+    if (/^k(.*)/) { next; }
+    if (/^l(.*)/) { $lock = $1; next; }
+    if (/^N(.*)/) { next; }
+    if (/^o(.*)/) { $offset = $1; next; }
+    if (/^P(.*)/) { $proto = $1; next; }
+    if (/^s(.*)/) { $size = $1; next; }
+    if (/^S(.*)/) { $stream = $1; next; }
+    if (/^t(.*)/) { $type = $1; next; }
+    if (/^T(.*)/) {
+       if ($state eq "") { $state = "(" . $1; }
+       else { $state = $state . " " . $1; }
+       next;
+    }
+    if (/^n(.*)/) { $name = $1; next; }
+    print "ERROR: unrecognized: \"$_\"\n";
+}
+
+# Flush any stored file or process output.
+
+if ($fdst) { &list_fd }
+if ($pidst) { &list_proc }
+exit(0);
+
+
+## list_fd -- list file descriptor information
+#            Values are stored inelegantly in global variables.
+
+sub list_fd {
+    if ( ! $fhdr) {
+
+    # Print header once.
+
+       print "      FD   TYPE      DEVICE   SIZE/OFF      INODE  NAME\n";
+       $fhdr = 1;
+    }
+    printf "    %4s%1.1s%1.1s %4.4s", $fd, $access, $lock, $type;
+    $tmp = $devn; if ($devch ne "") { $tmp = $devch }
+    printf "  %10.10s", $tmp;
+    $tmp = $size; if ($offset ne "") { $tmp = $offset }
+    printf " %10.10s", $tmp;
+    $tmp = $inode; if ($proto ne "") { $tmp = $proto }
+    printf " %10.10s", $tmp;
+    $tmp = $stream; if ($name ne "") { $tmp = $name }
+    print "  ", $tmp;
+    if ($state ne "") { printf " %s)\n", $state; } else { print "\n"; }
+
+# Clear variables.
+
+    $access = $devch = $devn = $fd = $inode = $lock = $name = "";
+    $offset = $proto = $size = $state = $stream = $type = "";
+}
+
+
+# list_proc -- list process information
+#             Values are stored inelegantly in global variables.
+
+sub list_proc {
+    print "COMMAND       PID    PGRP    PPID  USER\n";
+    $tmp = $uid; if ($login ne "") {$tmp = $login }
+    printf "%-9.9s  %6d  %6d  %6d  %s\n", $cmd, $pid, $pgrp, $ppid, $tmp;
+
+# Clear variables.
+
+    $cmd = $login = $pgrp = $pid = $uid = "";
+    $fhdr = $pidst = 0;
+}
diff --git a/scripts/shared.pl b/scripts/shared.pl
new file mode 100755 (executable)
index 0000000..25840f0
--- /dev/null
@@ -0,0 +1,407 @@
+#!/usr/bin/perl
+#
+# shared.pl    -- sample Perl 5 script to list processes that share
+#                file descriptors or files, using `lsof +ffn -F..."
+#                output
+#
+# Usage:       shared [fd|file]
+#
+# where:       fd to list file descriptors (default)
+#
+#              file to list files
+#
+# This script has been tested under perl version 5.001e.
+
+
+# IMPORTANT DEFINITIONS
+# =====================
+#
+# 1.  Set the interpreter line of this script to the local path of the
+#     Perl5 executable.
+
+
+# Copyright 1998 Purdue Research Foundation, West Lafayette, Indiana
+# 47907.  All rights reserved.
+#
+# Written by Victor A. Abell <abe@purdue.edu>
+#
+# 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.
+
+# Initialize variables.
+
+$Access = $Devch = $Devn = $Fd = $Fsa = $Inode = $Lock =       # file
+         $Na = $Name = "";                                     # | descriptor
+$Cmd = $Login = $Pgrp = $Pid = $Ppid = $Uid = "";              # process var.
+$Fdst = 0;                                                     # fd state
+$Hdr = 0;                                                      # header state
+$Offset = $Proto = $Size = $State = $Stream = $Type = "";      # | variables
+$Pidst = 0;                                                    # process state
+$Pn = "shared";
+
+# Set path to lsof.
+
+if (($LSOF = &isexec("../lsof")) eq "") {      # Try .. first
+    if (($LSOF = &isexec("lsof")) eq "") {     # Then try . and $PATH
+       print "can't execute $LSOF\n"; exit 1
+    }
+}
+
+# Define print field constants.
+
+$CmdTtl = "CMD";
+$CmdW = length($CmdTtl);
+$DevTtl = "DEVICE";
+$DevW = length($DevTtl);
+$FdTtl = "FD";
+$FdW = length($FdTtl);
+$InoTtl = "NODE";
+$InoW = length($InoTtl);
+$KeyTtl = "FILEADDR";
+$KeyW = length($KeyTtl);
+$PidTtl = "PID";
+$PidW = length($PidTtl);
+$PpidTtl = "PPID";
+$PpidW = length(PpidTtl);
+
+# Process one (optional) argument.
+
+if ($#ARGV >= 0) {
+    $err = 0;
+    if ($#ARGV > 1) { $err = 1; }
+    elsif ($ARGV[0] eq "fd") {
+       $KeyTtl = "FILEADDR";
+       $Shfd = 1;
+       $Shfile = 0;
+    } elsif ($ARGV[0] eq "file") {
+       $KeyTtl = "NODEID";
+       $Shfd = 0;
+       $Shfile = 1;
+    } else { $err = 1; }
+    if ($err) { die "$Pn: usage [fd|file]\n"; }
+    shift;
+} else { $Shfd = 1; $Shfile = 0; }
+$KeyW = length($KeyTtl);
+
+# Open a pipe from lsof.
+
+if (!open(LSOF_PIPE, "$LSOF -R +ffn -F0pcRDfFinN |")) {
+    die "$Pn: can't open pipe to: $LSOF\n";
+}
+
+# Process the lsof output a line at a time, gathering the variables for
+# processes and files.
+
+while (<LSOF_PIPE>) {
+    chop;
+    @F = split('\0', $_, 999);
+    if ($F[0] =~ /^p/) {
+
+# A process set begins with a PID field whose ID character is `p'.
+
+       if ($Fdst) { &End_fd }
+       if ($Pidst) { &End_proc }
+       foreach $i (0 .. ($#F - 1)) {
+
+           PROC: {
+               if ($F[$i] =~ /^c(.*)/) { $Cmd = $1; last PROC }
+               if ($F[$i] =~ /^g(.*)/) { $Pgrp = $1; last PROC }
+               if ($F[$i] =~ /^p(.*)/) { $Pid = $1; last PROC }
+               if ($F[$i] =~ /^u(.*)/) { $Uid = $1; last PROC }
+               if ($F[$i] =~ /^L(.*)/) { $Login = $1; last PROC }
+               if ($F[$i] =~ /^R(.*)/) { $Ppid = $1; last PROC }
+               print "ERROR: unrecognized process field: \"$F[$i]\"\n";
+           }
+       }
+       $Pidst = 1;
+       next;
+    }
+
+# A file descriptor set begins with a file descriptor field whose ID
+# character is `f'.
+
+    if ($F[0] =~ /^f/) {
+       if ($Fdst) { &End_fd }
+       foreach $i (0 .. ($#F - 1)) {
+
+           FD: {
+               if ($F[$i] =~ /^a(.*)/) { $Access = $1; last FD; }
+               if ($F[$i] =~ /^f(.*)/) { $Fd = $1; last FD; }
+               if ($F[$i] =~ /^F(.*)/) { $Fsa = $1; last FD; }
+               if ($F[$i] =~ /^l(.*)/) { $Lock = $1; last FD; }
+               if ($F[$i] =~ /^t(.*)/) { $Type = $1; last FD; }
+               if ($F[$i] =~ /^d(.*)/) { $Devch = $1; last FD; }
+               if ($F[$i] =~ /^D(.*)/) { $Devn = $1; last FD; }
+               if ($F[$i] =~ /^s(.*)/) { $Size = $1; last FD; }
+               if ($F[$i] =~ /^o(.*)/) { $Offset = $1; last FD; }
+               if ($F[$i] =~ /^i(.*)/) { $Inode = $1; last FD; }
+               if ($F[$i] =~ /^P(.*)/) { $Proto = $1; last FD; }
+               if ($F[$i] =~ /^S(.*)/) { $Stream = $1; last FD; }
+               if ($F[$i] =~ /^T(.*)/) {
+                   if ($State eq "") { $State = "(" . $1; }
+                   else { $State = $State . " " . $1; }
+                   last FD;
+               }
+               if ($F[$i] =~ /^n(.*)/) { $Name = $1; last FD; }
+               if ($F[$i] =~ /^N(.*)/) { $Na = $1; last FD; }
+               print "ERROR: unrecognized file set field: \"$F[$i]\"\n";
+           }
+       }
+       $Fdst = 1;
+       next;
+    }
+    print "ERROR: unrecognized: \"$_\"\n";
+}
+close(LSOF_PIPE);
+if ($Fdst) { &End_fd }
+if ($Pidst) { &End_proc }
+
+# List matching files or file descriptors.
+
+for ($pass = 0; $pass < 2; $pass++) {
+    foreach $key (sort keys(%Fds)) {
+       @Praw = split(' ', $Fds{$key}, 999);
+       if ($#Praw < 1) { next; }
+       if ($Shfd) { @P = sort Sort_by_FD_and_PID @Praw; }
+       else { @P = sort Sort_by_PID_and_FD @Praw; }
+
+    # Accumulate and print blocks of (key, PID, FD) triplets.
+
+       for ($i = 0; $i < $#P; $i++) {
+           if ($Shfile) {
+               for ($n = 0; $n <= $#P; $n++) {
+                   ($pid, $fd) = split(",", $P[$n], 999);
+                   $PrtPid[$n] = $pid;
+                   $PrtFd[$n] = $fd;
+               }
+               $i = $n;
+           } else {
+               ($pid, $fd) = split(",", $P[$i], 999);
+               $PrtFd[0] = $fd;
+               $PrtPid[0] = $pid;
+               for ($n = 1; $i < $#P; $i++, $n++) {
+                   ($nxtpid, $nxtfd) = split(",", $P[$i + 1], 999);
+                   if ($fd ne $nxtfd) { last; }
+                   $PrtFd[$n] = $nxtfd;
+                   $PrtPid[$n] = $nxtpid;
+               }
+           }
+           if ($n > 1) { &Print_block($key, $n, $pass); }
+       }
+    }
+}
+exit(0);
+
+
+## End_fd() -- process end of file descriptor
+
+sub End_fd {
+
+    local ($key);
+
+    if ($Fdst && $Pidst && $Pid ne "") {
+       if ($Cmd ne "") { $Cmds{$Pid} = $Cmd; }
+       if ($Ppid ne "") { $Ppids{$Pid} = $Ppid; }
+       $key = $Shfd ? $Fsa : $Na;
+       if ($key ne "") {
+           if (!defined($Fds{$key})) { $Fds{$key} = "$Pid,$Fd"; }
+           else { $Fds{$key} .= " $Pid,$Fd"; }
+           if ($Name ne "" && !defined($Name{$key})) { $Name{$key} = $Name }
+           if ($Inode ne "" && !defined($Inodes{$key})) {
+               $Inodes{$key} = $Inode;
+           }
+           if ($Devn ne "" && !defined($Devns{$key})) {
+               $Devns{$key} = $Devn;
+           }
+       }
+    }
+
+# Clear variables.
+
+    $Access = $Devch = $Devn = $Fd = $Fsa = $Inode = $Lock = "";
+    $Na = $Name = $Offset = $Proto = $Size = $State = $Stream = $Type = "";
+    $Fdst = 0;
+}
+
+
+## End_proc() -- process end of process
+
+sub End_proc {
+
+# Clear variables.
+
+    $Cmd = $Login = $Pgrp = $Pid = $Ppid = $Uid = "";
+    $Fdst = $Pidst = 0;
+}
+
+
+## Print_block() -- print a block of entries
+#
+# entry:
+#
+#      @_[0] = block's key
+#      @_[1] = number of entries in the block
+#      @_[2] = print pass status (1 == print)
+
+sub Print_block {
+
+    my ($key, $n, $pass) = @_;
+
+    local ($fd, $i, $pid, $t, $tW);
+
+    if ($pass) {
+       if (!$Hdr) {
+           printf "%${KeyW}.${KeyW}s", $KeyTtl;
+           printf " %${PidW}.${PidW}s", $PidTtl;
+           printf " %${PpidW}.${PpidW}s", $PpidTtl;
+           printf " %-${CmdW}.${CmdW}s", $CmdTtl;
+           printf " %${FdW}.${FdW}s", $FdTtl;
+           printf " %${DevW}.${DevW}s", $DevTtl;
+           printf " %${InoW}.${InoW}s", $InoTtl;
+           printf " NAME\n";
+           $Hdr = 1;
+       } else { print "\n"; }
+    }
+
+# Loop through block.  During a non-print pass, caclulate maximum field widths.
+
+    for ($i = 0; $i < $n; $i++) {
+       $fd = $PrtFd[$i];
+       $pid = $PrtPid[$i];
+
+    # Process key.
+
+       if (!$pass) {
+           $tW = length(sprintf("%s", $key));
+           if ($tW > $KeyW) { $KeyW = $tW; }
+       } else { printf "%s", $key; }
+
+    # Process PID.
+
+       if (!$pass) {
+           $tW = length(sprintf(" %s", $pid));
+           if ($tW > $PidW) { $PidW = $tW; }
+       } else { printf " %${PidW}.${PidW}s", $pid; }
+
+    # Process parent PID.
+
+       $t = defined($Ppids{$pid}) ? $Ppids{$pid} : "";
+       if (!$pass) {
+           $tW = length(sprintf(" %s", $t));
+           if ($tW > $PpidW) { $PpidW = $tW; }
+       } else { printf " %${PpidW}.${PpidW}s", $t; }
+
+    # Process command name.
+
+       $t = defined($Cmds{$pid}) ? $Cmds{$pid} : "";
+       if (!$pass) {
+           $tW = length(sprintf(" %s", $t));
+           if ($tW > $CmdW) { $CmdW = $tW; }
+       } else { printf " %-${CmdW}.${CmdW}s", $t; }
+
+    # Process file descriptor.
+
+       if (!$pass) {
+           $tW = length(sprintf(" %s", $fd));
+           if ($tW > $FdW) { $FdW = $tW; }
+       } else { printf " %${FdW}.${FdW}s", $fd; }
+
+    # Process device number.
+
+       $t = defined($Devns{$key}) ? $Devns{$key} : "";
+       if (!$pass) {
+           $tW = length(sprintf(" %s", $t));
+           if ($tW > $DevW) { $DevW = $tW; }
+       } else { printf " %${DevW}.${DevW}s", $t; }
+
+    # Process node number.
+
+       $t = defined($Inodes{$key}) ? $Inodes{$key} : $t;
+       if (!$pass) {
+           $tW = length(sprintf (" %s", $t));
+           if ($tW > $InoW) { $InoW = $tW; }
+       } else { printf " %${InoW}.${InoW}s", $t; }
+
+    # Print name and line terminater, if this is a print pass.
+
+       if ($pass) {
+           if (defined($Name{$key})) { print " $Name{$key}\n"; }
+           else { print "\n"; }
+       }
+    }
+}
+
+
+## Sort_by_FD_and_PID() -- sort (PID,FD) doublets by FD first, then PID
+
+sub Sort_by_FD_and_PID {
+
+    local ($pida, $pidb, $fda, $fdj, $rv);
+
+    ($pida, $fda) = split(",", $a);
+    ($pidb, $fdb) = split(",", $b);
+    if ($fda < $fdb) { return(-1); }
+    if ($fda > $fdb) { return(1); }
+    if ($pida < $pidb) { return(-1); }
+    if ($pida > $pidb) { return(1); }
+    return(0);
+}
+
+
+## Sort_by_PID_and_FD() -- sort (PID,FD) doublets by PID first, then FD
+
+sub Sort_by_PID_and_FD {
+
+    local ($pida, $pidb, $fda, $fdj, $rv);
+
+    ($pida, $fda) = split(",", $a);
+    ($pidb, $fdb) = split(",", $b);
+    if ($pida < $pidb) { return(-1); }
+    if ($pida > $pidb) { return(1); }
+    if ($fda < $fdb) { return(-1); }
+    return(0);
+    if ($fda > $fdb) { return(1); }
+}
+
+
+## isexec($path) -- is $path executable
+#
+# $path   = absolute or relative path to file to test for executabiity.
+#          Paths that begin with neither '/' nor '.' that arent't found as
+#          simple references are also tested with the path prefixes of the
+#          PATH environment variable.
+
+sub
+isexec {
+    my ($path) = @_;
+    my ($i, @P, $PATH);
+
+    $path =~ s/^\s+|\s+$//g;
+    if ($path eq "") { return(""); }
+    if (($path =~ m#^[\/\.]#)) {
+       if (-x $path) { return($path); }
+       return("");
+    }
+    $PATH = $ENV{PATH};
+    @P = split(":", $PATH);
+    for ($i = 0; $i <= $#P; $i++) {
+       if (-x "$P[$i]/$path") { return("$P[$i]/$path"); }
+    }
+    return("");
+}
diff --git a/scripts/sort_res.pl b/scripts/sort_res.pl
new file mode 100755 (executable)
index 0000000..374dcda
--- /dev/null
@@ -0,0 +1,134 @@
+#!/usr/bin/perl
+# sort_res.pl - Script to group & sort lsof output by resource
+#
+# Copyright (c) 2004, 2005 - Fabian Frederick <fabian.frederick@gmx.fr>
+#
+# This program/include file is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as published
+# by the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program/include file is distributed in the hope that it will be
+# useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program (in the main directory of the Linux-NTFS
+# distribution in the file COPYING); if not, write to the Free Software
+# Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+# Note :
+#      -This script uses lsof released by Victor A. Abell
+#      -lsof path recovery comes from standard perl scripts in there.
+#
+# Usage :
+#      perl sort_res.pl -> display used resources + size
+#      or perl sort_res.pl <program name>
+#
+# 12/2005 (FabF)
+#      -size reset in loop (script was broken in 4.76)
+#      -isexec looking in .. (like other scripts)
+#      -display for one or all processes
+#      -removing unuseful line number arg.
+#      -display global size
+
+my @args = @_;
+
+# Set path to lsof.
+if (($LSOF = &isexec("../lsof")) eq "") {    # Some distros use lsof
+                                                   # out of $PATH
+    if (($LSOF = &isexec("lsof")) eq "") {         # Then try . and $PATH
+       if (($LSOF = &isexec("../lsof")) eq "") {    # Then try ..
+           print "can't execute $LSOF\n"; exit 1
+       }
+    }
+}
+
+if ($ARGV[0] ne ""){
+    $cmd="$LSOF -nPl -Fcns -c".$ARGV[0]."|";
+}else{
+    $cmd="$LSOF -nPl -Fcns|";
+}
+
+#Parse lsof output to gather command, resource name, pid and size
+#Some extradata stand to keep script genericity
+$i=0;
+if (open(FILE, $cmd)){
+    while (defined ($line=<FILE>)){
+       $cline=$line;
+       $cline =~ s"^(.)"";
+       $cline =~ s/^\s+|\s+$//g;
+       if($line=~m/^p/){
+           $pid=$cline;
+       }else{
+           if($line=~/^s/){
+               $size = $cline;
+           }else{
+               if($line=~/^c/){
+                   $command = $cline;
+               }else{
+                   if($line=~/^n/){
+                       $name = $cline;
+                       $data{$i} = { command => $command, name => $name,
+                                     pid => $pid , size => $size};
+                       $size=0;
+                       $i = $i+1;
+                   }
+               }
+           }
+       }
+    }
+}
+
+#Resource name sorting
+sub byresname { $data{$a}{name} cmp $data{$b}{name}}
+@ks=sort byresname (keys %data);
+
+#Resource grouping
+$i=0;
+$cname="a";
+foreach $k (@ks){
+    if ($data{$k}{name} ne $cname){
+       $dgroup{$i} = { name => $data{$k}{name}, size => $data{$k}{size}};
+       $cname = $data{$k}{name};
+       $i++;
+    }
+}
+
+#Size sort on resource hash
+sub bysize { $dgroup{$a}{size} <=> $dgroup{$b}{size} }
+@ks=sort bysize (keys %dgroup);
+$gsize=0;
+printf("  -- KB --  -- Resource --\n", );
+foreach $k (@ks){
+       printf("%10d  %s\n", $dgroup{$k}{size}/1024, $dgroup{$k}{name});
+       $gsize+=$dgroup{$k}{size};
+}
+
+printf("Total KB : %10d\n", $gsize/1024);
+## isexec($path) -- is $path executable
+#
+# $path   = absolute or relative path to file to test for executabiity.
+#          Paths that begin with neither '/' nor '.' that arent't found as
+#          simple references are also tested with the path prefixes of the
+#          PATH environment variable.
+
+sub
+isexec {
+    my ($path) = @_;
+    my ($i, @P, $PATH);
+
+    $path =~ s/^\s+|\s+$//g;
+    if ($path eq "") { return(""); }
+    if (($path =~ m#^[\/\.]#)) {
+       if (-x $path) { return($path); }
+       return("");
+    }
+    $PATH = $ENV{PATH};
+    @P = split(":", $PATH);
+    for ($i = 0; $i <= $#P; $i++) {
+       if (-x "$P[$i]/$path") { return("$P[$i]/$path"); }
+    }
+    return("");
+}
diff --git a/scripts/watch_a_file.pl b/scripts/watch_a_file.pl
new file mode 100755 (executable)
index 0000000..095c821
--- /dev/null
@@ -0,0 +1,94 @@
+#!/usr/bin/perl
+#
+# watch_a_file.pl   -- use lsof -F output to watch a specific file
+#                     (or file system)
+#
+# usage:       watch_a_file.pl file_name
+
+## Interrupt handler
+
+sub interrupt { wait; print "\n"; exit 0; }
+
+
+## Start main program
+
+$Pn = "watch_a_file";
+# Check file argument.
+
+if ($#ARGV != 0) { print "$#ARGV\n"; die "$Pn usage: file_name\n"; }
+$fnm = $ARGV[0];
+if (! -r $fnm) { die "$Pn: can't read $fnm\n"; }
+
+# Do setup.
+
+$RPT = 15;                             # lsof repeat time
+$| = 1;                                        # unbuffer output
+$SIG{'INT'} = 'interrupt';             # catch interrupt
+
+# Set path to lsof.
+
+if (($LSOF = &isexec("../lsof")) eq "") {      # Try .. first
+    if (($LSOF = &isexec("lsof")) eq "") {     # Then try . and $PATH
+       print "can't execute $LSOF\n"; exit 1
+    }
+}
+
+# Read lsof -nPF output from a pipe and gather the PIDs of the processes
+# and file descriptors to watch.
+
+open(P, "$LSOF -nPFpf $fnm|") || die "$Pn: can't pipe to $LSOF\n";
+
+$curpid = -1;
+$pids = "";
+while (<P>) {
+    chop;
+    if (/^p(.*)/) { $curpid = $1; next; }      # Identify process.
+    if (/^f/) {
+       if ($curpid > 0) {
+           if ($pids eq "") { $pids = $curpid; }
+           else { $pids = $pids . "," . $curpid; }
+           $curpid = -1;
+       }
+    }
+}
+close(P);
+wait;
+if ($pids eq "") { die "$Pn: no processes using $fnm located.\n"; }
+print "watch_file: $fnm being used by processes:\n\t$pids\n\n";
+
+# Read repeated lsof output from a pipe and display.
+
+$pipe = "$LSOF -ap $pids -r $RPT $fnm";
+open(P, "$pipe|") || die "$Pn: can't pipe: $pipe\n";
+
+while (<P>) { print $_; }
+close(P);
+print "$Pn: unexpected EOF from \"$pipe\"\n";
+exit 1;
+
+
+## isexec($path) -- is $path executable
+#
+# $path   = absolute or relative path to file to test for executabiity.
+#          Paths that begin with neither '/' nor '.' that arent't found as
+#          simple references are also tested with the path prefixes of the
+#          PATH environment variable.
+
+sub
+isexec {
+    my ($path) = @_;
+    my ($i, @P, $PATH);
+
+    $path =~ s/^\s+|\s+$//g;
+    if ($path eq "") { return(""); }
+    if (($path =~ m#^[\/\.]#)) {
+       if (-x $path) { return($path); }
+       return("");
+    }
+    $PATH = $ENV{PATH};
+    @P = split(":", $PATH);
+    for ($i = 0; $i <= $#P; $i++) {
+       if (-x "$P[$i]/$path") { return("$P[$i]/$path"); }
+    }
+    return("");
+}
diff --git a/scripts/xusers.awk b/scripts/xusers.awk
new file mode 100755 (executable)
index 0000000..ac818b4
--- /dev/null
@@ -0,0 +1,137 @@
+#!/usr/bin/awk -f
+################################################################
+#  
+#  Program Name  :  xusers
+#  Date Created  :  02-27-97
+#  Author        :  Dan A. Mercer
+#  Email         :  damercer@mmm.com
+#                :
+#  Description   : Print list of users and applications signed on
+#                : X workstations
+################################################################
+# standard help message
+function help(hlpmsg) {
+basename = ARGV[0]
+sub(/.*\//,"",basename)
+printf "Format:  %s [o=[hi]] [s=cdlp] [pattern]\n", basename
+print  "Print list of users and applications signed on X workstations"
+print  "NOTE: applicationname is truncated to 9 chars"
+print  "Arguments:"
+print  "           o=[h|i]      - Options"
+print  "              h         - help - print this message"
+print  "              i         - case insensitive pattern search"
+print  "           s=[c|d|l|p]  - Sort Options"
+print  "              c         - sort by command"
+print  "              d         - sort by display name"
+print  "              l         - sort by login name"
+print  "              p         - sort by pid"
+print  "           pattern      - regex pattern to search commands against"
+
+if (length(hlpmsg)) print hlpmsg
+exit
+}
+BEGIN {
+# process command line
+for (i=1;i<ARGC;i++) {
+   if (ARGV[i] ~ /^o=/) {
+      if (options)
+         help("duplicate option string")
+      options = ARGV[i]
+      sub(/^o=/,"",options)
+      if (options !~ /^[hi]$/)
+         help("Invalid options " options)
+      if ("h" == options)
+         help("")
+      else
+         igncase = 1
+      }
+   else if (ARGV[i] ~ /^s=/) {
+      if (sortorder)
+         help("duplicate sort order string")
+      sortorder = ARGV[i]
+      sub(/^s=/,"",sortorder)
+      if (sortorder !~ /^[cdlp]$/)
+         help("Invalid sort order: '" sortorder "'")
+      if ("p" == sortorder) {
+         sort = "sort -kn2"
+         }
+      else if ("c" == sortorder) {
+         # the 'b' option means ignore leading blanks
+         sort = "sort -kb3"
+         }
+      else if ("l" == sortorder) {
+         sort = "sort -kb1"
+         }
+      else {
+         sort = "sort -kb4"
+         }
+      }
+   else {
+      if (pattern)
+         help("duplicate pattern string")
+      pattern = ARGV[i]
+      }
+   }
+
+# default is to sort by pid
+sort = (sort) ? sort : "sort -kn2"
+
+# check for igncase
+if (pattern && igncase)
+   pattern = tolower(pattern)
+
+# set default pattern
+pattern = (pattern) ? pattern : ".*"
+
+cmd = "lsof -FpLcn  -awP -iTCP:6000"
+#            ||||| ||||  |
+#            ||||| ||||  X servers use port 6000
+#            ||||| |||don't list port names
+#            ||||| ||suppress warning messages
+#            ||||| |and all conditions
+#            ||||| |options
+#            |||||
+#            ||||Internet addresses
+#            |||command name
+#            ||login name
+#            |process id
+#            Format string
+# Output consists of one record per pid,  followed by newline
+# delimited fields for command, Login name, and network address
+# The pid is preceded by a 'p',  command by a 'c',
+# Login name by an L, and network connection by an 'n'.  There may
+# be multiple 'n' entries (for instance for vuewm)
+
+while ((cmd | getline field) > 0) {
+   type = substr(field,1,1)
+   sub("^.","",field)
+   if ("p" == type) {
+      # always output first
+      pid = field
+      PID[pid] = ++ct
+      }
+   else if ("c" == type) {
+      # always output second
+      XAPPL[pid] = field
+      }
+   else if ("L" == type) {
+      # always output fourth
+      USER[pid] = field
+      }
+   else if ("n" == type) {
+      # may be multiple instances - we just use the last
+      gsub(".*->|:6000","",field)
+      DPY[pid] = field
+      }
+   }
+close(cmd)
+
+printf "%8s  %5s  %-9s  %s\n","USER","PID","COMMAND","DISPLAY"
+for (pid in PID) {
+   if (((igncase) ? tolower(XAPPL[pid]) : XAPPL[pid]) ~ pattern)
+      printf "%8s  %5d  %-9s  %s\n", USER[pid],pid,XAPPL[pid],DPY[pid] | sort
+   }
+
+close(sort)
+exit
+}
diff --git a/src/arg.c b/src/arg.c
new file mode 100644 (file)
index 0000000..ac40a00
--- /dev/null
+++ b/src/arg.c
@@ -0,0 +1,2193 @@
+/*
+ * arg.c - common argument processing support functions for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#include "common.h"
+#include "cli.h"
+#include "lsof.h"
+#include <limits.h>
+
+/*
+ * Local definitions
+ */
+
+#define CMDRXINCR 32 /* CmdRx[] allocation increment */
+
+/*
+ * Local static variables
+ */
+
+/*
+ * Local function prototypes
+ */
+
+static int ckfd_range(struct lsof_context *ctx, char *first, char *dash,
+                      char *last, int *lo, int *hi);
+static int enter_fd_lst(struct lsof_context *ctx, char *nm, int lo, int hi,
+                        int excl);
+static int enter_nwad(struct lsof_context *ctx, struct nwad *n, int sp, int ep,
+                      char *s, struct hostent *he);
+static struct hostent *lkup_hostnm(char *hn, struct nwad *n);
+static char *isIPv4addr(char *hn, unsigned char *a, int al);
+
+/*
+ * ckfd_range() - check fd range
+ */
+
+static int ckfd_range(struct lsof_context *ctx, /* context */
+                      char *first,              /* starting character */
+                      char *dash,               /* '-' location */
+                      char *last,               /* '\0' location */
+                      int *lo,                  /* returned low value */
+                      int *hi)                  /* returned high value */
+{
+    char *cp;
+    /*
+     * See if the range character pointers make sense.
+     */
+    if (first >= dash || dash >= last) {
+        (void)fprintf(stderr, "%s: illegal FD range for -d: ", Pn);
+        safestrprt(first, stderr, 1);
+        return (1);
+    }
+    /*
+     * Assemble and check the high and low values.
+     */
+    for (cp = first, *lo = 0; *cp && cp < dash; cp++) {
+        if (!isdigit((unsigned char)*cp)) {
+
+        FD_range_nondigit:
+
+            (void)fprintf(stderr, "%s: non-digit in -d FD range: ", Pn);
+            safestrprt(first, stderr, 1);
+            return (1);
+        }
+        *lo = (*lo * 10) + (int)(*cp - '0');
+    }
+    for (cp = dash + 1, *hi = 0; *cp && cp < last; cp++) {
+        if (!isdigit((unsigned char)*cp))
+            goto FD_range_nondigit;
+        *hi = (*hi * 10) + (int)(*cp - '0');
+    }
+    if (*lo >= *hi) {
+        (void)fprintf(stderr, "%s: -d FD range's low >= its high: ", Pn);
+        safestrprt(first, stderr, 1);
+        return (1);
+    }
+    return (0);
+}
+
+/*
+ * ck_file_arg() - check file arguments
+ */
+
+int ck_file_arg(struct lsof_context *ctx, int i, /* first file argument index */
+                int ac,                          /* argument count */
+                char *av[],                      /* argument vector */
+                int fv,           /* Ffilesys value (real or temporary) */
+                int rs,           /* Readlink() status if argument count == 1:
+                                   *   0 = undone; 1 = done */
+                struct stat *sbp, /* if non-NULL, pointer to stat(2) buffer
+                                   * when argument count == 1 */
+                int accept_deleted_file) /* if non-zero, don't report an error
+                                          * even when the file doesn't exist. */
+{
+    char *ap, *fnm, *fsnm, *path;
+    short err = 0;
+    int fsm, ftype, j, k;
+    MALLOC_S l;
+    struct mounts *mp;
+    static struct mounts **mmp = (struct mounts **)NULL;
+    int mx, nm;
+    static int nma = 0;
+    struct stat sb;
+    struct sfile *sfp;
+    short ss = 0;
+
+#if defined(CKFA_EXPDEV)
+    dev_t dev, rdev;
+#endif /* defined(CKFA_EXPDEV) */
+
+#if defined(HASPROCFS)
+    unsigned char ad, an;
+    int pfsnl = -1;
+    pid_t pid;
+    struct procfsid *pfi;
+#endif /* defined(HASPROCFS) */
+
+    /*
+     * Loop through arguments.
+     */
+    for (; i < ac; i++) {
+        if (rs && (ac == 1) && (i == 0))
+            path = av[i];
+        else {
+            if (!(path = Readlink(ctx, av[i]))) {
+                ErrStat = 1;
+                continue;
+            }
+        }
+        /*
+         * Remove terminating `/' characters from paths longer than one.
+         */
+        j = k = strlen(path);
+        while ((k > 1) && (path[k - 1] == '/')) {
+            k--;
+        }
+        if (k < j) {
+            if (path != av[i])
+                path[k] = '\0';
+            else {
+                if (!(ap = (char *)malloc((MALLOC_S)(k + 1)))) {
+                    (void)fprintf(stderr, "%s: no space for copy of %s\n", Pn,
+                                  path);
+                    Error(ctx);
+                }
+                (void)strncpy(ap, path, k);
+                ap[k] = '\0';
+                path = ap;
+            }
+        }
+        /*
+         * Check for file system argument.
+         */
+        for (ftype = 1, mp = readmnt(ctx), nm = 0; (fv != 1) && mp;
+             mp = mp->next) {
+            fsm = 0;
+            if (strcmp(mp->dir, path) == 0)
+                fsm++;
+            else if (fv == 2 || (mp->fs_mode & S_IFMT) == S_IFBLK) {
+                if (mp->fsnmres && strcmp(mp->fsnmres, path) == 0)
+                    fsm++;
+            }
+            if (!fsm)
+                continue;
+            ftype = 0;
+            /*
+             * Skip duplicates.
+             */
+            for (mx = 0; mx < nm; mx++) {
+                if (strcmp(mp->dir, mmp[mx]->dir) == 0 &&
+                    mp->dev == mmp[mx]->dev && mp->rdev == mmp[mx]->rdev &&
+                    mp->inode == mmp[mx]->inode)
+                    break;
+            }
+            if (mx < nm)
+                continue;
+            /*
+             * Allocate space for and save another mount point match and
+             * the type of match -- directory name (mounted) or file system
+             * name (mounted-on).
+             */
+            if (nm >= nma) {
+                nma += 5;
+                l = (MALLOC_S)(nma * sizeof(struct mounts *));
+                if (mmp)
+                    mmp = (struct mounts **)realloc((MALLOC_P *)mmp, l);
+                else
+                    mmp = (struct mounts **)malloc(l);
+                if (!mmp) {
+                    (void)fprintf(stderr, "%s: no space for mount pointers\n",
+                                  Pn);
+                    Error(ctx);
+                }
+            }
+            mmp[nm++] = mp;
+        }
+        if (fv == 2 && nm == 0) {
+            if (!accept_deleted_file) {
+                (void)fprintf(stderr, "%s: not a file system: ", Pn);
+                safestrprt(av[i], stderr, 1);
+            }
+            ErrStat = 1;
+            continue;
+        }
+        /*
+         * Loop through the file system matches.  If there were none, make one
+         * pass through the loop, using simply the path name.
+         */
+        mx = 0;
+        do {
+
+            /*
+             * Allocate an sfile structure and fill in the type and link.
+             */
+            if (!(sfp = (struct sfile *)malloc(sizeof(struct sfile)))) {
+                (void)fprintf(stderr, "%s: no space for files\n", Pn);
+                Error(ctx);
+            }
+            sfp->next = Sfile;
+            Sfile = sfp;
+            sfp->f = 0;
+            if ((sfp->type = ftype)) {
+
+                /*
+                 * For a non-file system path, use the path as the file name
+                 * and set a NULL file system name.
+                 */
+                fnm = path;
+                fsnm = (char *)NULL;
+                /*
+                 * Stat the path to obtain its characteristics.
+                 */
+                if (sbp && (ac == 1))
+                    sb = *sbp;
+                else {
+                    if (statsafely(ctx, fnm, &sb) != 0) {
+                        int en = errno;
+                        if (!accept_deleted_file) {
+                            (void)fprintf(stderr, "%s: status error on ", Pn);
+                            safestrprt(fnm, stderr, 0);
+                            (void)fprintf(stderr, ": %s\n", strerror(en));
+                        }
+                        Sfile = sfp->next;
+                        (void)free((FREE_P *)sfp);
+                        ErrStat = 1;
+                        continue;
+                    }
+
+#if defined(HASSPECDEVD)
+                    (void)HASSPECDEVD(ctx, fnm, &sb);
+#endif /* defined(HASSPECDEVD) */
+                }
+                sfp->i = (INODETYPE)sb.st_ino;
+                sfp->mode = sb.st_mode & S_IFMT;
+
+#if defined(CKFA_EXPDEV)
+                /*
+                 * Expand device numbers before saving, so that they match the
+                 * already-expanded local mount info table device numbers.
+                 * (This is an EP/IX 2.1.1 and above artifact.)
+                 */
+                sfp->dev = expdev(sb.st_dev);
+                sfp->rdev = expdev(sb.st_rdev);
+#else  /* !defined(CKFA_EXPDEV) */
+                sfp->dev = sb.st_dev;
+                sfp->rdev = sb.st_rdev;
+#endif /* defined(CKFA_EXPDEV) */
+
+#if defined(CKFA_MPXCHAN)
+                /*
+                 * Save a (possible) multiplexed channel number.  (This is an
+                 * AIX artifact.)
+                 */
+                sfp->ch = getchan(path);
+#endif /* defined(CKFA_MPXCHAN) */
+
+            } else {
+
+#if defined(SAVE_MP_IN_SFILE)
+                sfp->mp = mp = mmp[mx++];
+#else  /* !defined(SAVE_MP_IN_SFILE) */
+                mp = mmp[mx++];
+#endif /* defined(SAVE_MP_IN_SFILE) */
+
+                ss++;
+
+#if defined(HASPROCFS)
+                /*
+                 * If this is a /proc file system, set the search flag and
+                 * abandon the sfile entry.
+                 */
+                if (mp == Mtprocfs) {
+                    Sfile = sfp->next;
+                    (void)free((FREE_P *)sfp);
+                    Procsrch = 1;
+                    continue;
+                }
+#endif /* defined(HASPROCFS) */
+
+                /*
+                 * Derive file name and file system name for a mount point.
+                 *
+                 * Save the device numbers, inode number, and modes.
+                 */
+                fnm = mp->dir;
+                fsnm = mp->fsname;
+                sfp->dev = mp->dev;
+                sfp->rdev = mp->rdev;
+                sfp->i = mp->inode;
+                sfp->mode = mp->mode & S_IFMT;
+            }
+            ss = 1; /* indicate a "safe" stat() */
+                    /*
+                     * Store the file name and file system name pointers in the sfile
+                     * structure, allocating space as necessary.
+                     */
+            if (!fnm || fnm == path) {
+                sfp->name = fnm;
+
+#if defined(HASPROCFS)
+                an = 0;
+#endif /* defined(HASPROCFS) */
+
+            } else {
+                if (!(sfp->name = mkstrcpy(fnm, (MALLOC_S *)NULL))) {
+                    (void)fprintf(stderr, "%s: no space for file name: ", Pn);
+                    safestrprt(fnm, stderr, 1);
+                    Error(ctx);
+                }
+
+#if defined(HASPROCFS)
+                an = 1;
+#endif /* defined(HASPROCFS) */
+            }
+            if (!fsnm || fsnm == path) {
+                sfp->devnm = fsnm;
+
+#if defined(HASPROCFS)
+                ad = 0;
+#endif /* defined(HASPROCFS) */
+
+            } else {
+                if (!(sfp->devnm = mkstrcpy(fsnm, (MALLOC_S *)NULL))) {
+                    (void)fprintf(stderr,
+                                  "%s: no space for file system name: ", Pn);
+                    safestrprt(fsnm, stderr, 1);
+                    Error(ctx);
+                }
+
+#if defined(HASPROCFS)
+                ad = 1;
+#endif /* defined(HASPROCFS) */
+            }
+            if (!(sfp->aname = mkstrcpy(av[i], (MALLOC_S *)NULL))) {
+                (void)fprintf(stderr,
+                              "%s: no space for argument file name: ", Pn);
+                safestrprt(av[i], stderr, 1);
+                Error(ctx);
+            }
+
+#if defined(HASPROCFS)
+            /*
+             * See if this is an individual member of a proc file system.
+             */
+            if (!Mtprocfs || Procsrch)
+                continue;
+
+#    if defined(HASFSTYPE) && HASFSTYPE == 1
+            if (strcmp(sb.st_fstype, HASPROCFS) != 0)
+                continue;
+#    endif /* defined(HASFSTYPE) && HASFSTYPE==1 */
+
+            if (pfsnl == -1)
+                pfsnl = strlen(Mtprocfs->dir);
+            if (!pfsnl)
+                continue;
+            if (strncmp(Mtprocfs->dir, path, pfsnl) != 0)
+                continue;
+            if (path[pfsnl] != '/')
+
+#    if defined(HASPINODEN)
+                pid = 0;
+#    else  /* !defined(HASPINODEN) */
+                continue;
+#    endif /* defined(HASPINODEN) */
+
+            else {
+                for (j = pfsnl + 1; path[j]; j++) {
+                    if (!isdigit((unsigned char)path[j]))
+                        break;
+                }
+                if (path[j] || (j - pfsnl - 1) < 1 ||
+                    (sfp->mode & S_IFMT) != S_IFREG)
+
+#    if defined(HASPINODEN)
+                    pid = 0;
+#    else  /* !defined(HASPINODEN) */
+                    continue;
+#    endif /* defined(HASPINODEN) */
+
+                else
+                    pid = atoi(&path[pfsnl + 1]);
+            }
+            if (!(pfi = (struct procfsid *)malloc(
+                      (MALLOC_S)sizeof(struct procfsid)))) {
+                (void)fprintf(stderr, "%s: no space for %s ID: ", Pn,
+                              Mtprocfs->dir);
+                safestrprt(path, stderr, 1);
+                Error(ctx);
+            }
+            pfi->pid = pid;
+            pfi->f = 0;
+            pfi->nm = sfp->aname;
+            pfi->next = Procfsid;
+            Procfsid = pfi;
+
+#    if defined(HASPINODEN)
+            pfi->inode = (INODETYPE)sfp->i;
+#    endif /* defined(HASPINODEN) */
+
+            /*
+             * Abandon the Sfile entry, lest it be used in is_file_named().
+             */
+            Sfile = sfp->next;
+            if (ad)
+                (void)free((FREE_P *)sfp->devnm);
+            if (an)
+                (void)free((FREE_P *)sfp->name);
+            (void)free((FREE_P *)sfp);
+#endif /* defined(HASPROCFS) */
+
+        } while (mx < nm);
+    }
+
+    if (accept_deleted_file) {
+        if (!ss && ErrStat == 0)
+            err = 1;
+        if (ErrStat)
+            ErrStat = 0;
+    } else if (!ss) {
+        err = 1;
+    }
+    return ((int)err);
+}
+
+#if defined(HASDCACHE)
+/*
+ * ctrl_dcache() - enter device cache control
+ */
+
+int ctrl_dcache(struct lsof_context *ctx, /* context */
+                char *c)                  /* control string */
+{
+    int rc = 0;
+
+    if (!c) {
+        (void)fprintf(stderr, "%s: no device cache option control string\n",
+                      Pn);
+        return (1);
+    }
+    /*
+     * Decode argument function character.
+     */
+    switch (*c) {
+    case '?':
+        if (*(c + 1) != '\0') {
+            (void)fprintf(stderr, "%s: nothing should follow -D?\n", Pn);
+            return (1);
+        }
+        DChelp = 1;
+        return (0);
+    case 'b':
+    case 'B':
+        if (Setuidroot
+
+#    if !defined(WILLDROPGID)
+            || Myuid
+#    endif /* !defined(WILLDROPGID) */
+
+        )
+            rc = 1;
+        else
+            DCstate = 1;
+        break;
+    case 'r':
+    case 'R':
+        if (Setuidroot && *(c + 1))
+            rc = 1;
+        else
+            DCstate = 2;
+        break;
+    case 'u':
+    case 'U':
+        if (Setuidroot
+
+#    if !defined(WILLDROPGID)
+            || Myuid
+#    endif /* !defined(WILLDROPGID) */
+
+        )
+            rc = 1;
+        else
+            DCstate = 3;
+        break;
+    case 'i':
+    case 'I':
+        if (*(c + 1) == '\0') {
+            DCstate = 0;
+            return (0);
+        }
+        /* fall through */
+    default:
+        (void)fprintf(stderr, "%s: unknown -D option: ", Pn);
+        safestrprt(c, stderr, 1);
+        return (1);
+    }
+    if (rc) {
+        (void)fprintf(stderr, "%s: -D option restricted to root: ", Pn);
+        safestrprt(c, stderr, 1);
+        return (1);
+    }
+    /*
+     * Skip to optional path name and save it.
+     */
+    for (c++; *c && (*c == ' ' || *c == '\t'); c++)
+        ;
+    if (strlen(c)) {
+        if (!(DCpathArg = mkstrcpy(c, (MALLOC_S *)NULL))) {
+            (void)fprintf(stderr, "%s: no space for -D path: ", Pn);
+            safestrprt(c, stderr, 1);
+            Error(ctx);
+        }
+    }
+    return (0);
+}
+#endif /* defined(HASDCACHE) */
+
+
+#if defined(HASEOPT)
+/*
+ * enter_efsys() -- enter path of file system whose kernel blocks are to be
+ *                 eliminated
+ */
+
+int enter_efsys(struct lsof_context *ctx, /* context */
+                char *e,                  /* file system path */
+                int rdlnk)                /* avoid readlink(2) if non-zero */
+{
+    char *ec;         /* pointer to copy of path */
+    efsys_list_t *ep; /* file system path list pointer */
+    int i;            /* temporary index */
+    char *path;       /* Readlink() of file system path */
+
+    if (!e || (*e != '/')) {
+        if (!Fwarn)
+            (void)fprintf(stderr,
+                          "%s: -e not followed by a file system path: \"%s\"\n",
+                          Pn, e);
+        return (1);
+    }
+    if (!(ec = mkstrcpy(e, (MALLOC_S *)NULL))) {
+        (void)fprintf(stderr, "%s: no space for -e string: ", Pn);
+        safestrprt(e, stderr, 1);
+        Error(ctx);
+    }
+    if (rdlnk)
+        path = ec;
+    else {
+        if (!(path = Readlink(ctx, ec)))
+            return (1);
+    }
+    /*
+     * Remove terminating `/' characters from paths longer than one.
+     */
+    for (i = (int)strlen(path); (i > 1) && (path[i - 1] == '/'); i--) {
+        path[i - 1] = '\0';
+    }
+    /*
+     * Enter file system path on list, avoiding duplicates.
+     */
+    for (ep = Efsysl; ep; ep = ep->next) {
+        if (!strcmp(ep->path, path)) {
+            (void)free((FREE_P *)path);
+            return (0);
+        }
+    }
+    if (!(ep = (efsys_list_t *)malloc((MALLOC_S)(sizeof(efsys_list_t))))) {
+        (void)fprintf(stderr, "%s: no space for \"-e %s\" entry\n", Pn, e);
+        Error(ctx);
+    }
+    ep->path = path;
+    ep->pathl = i;
+    ep->rdlnk = rdlnk;
+    ep->mp = (struct mounts *)NULL;
+    ep->next = Efsysl;
+    Efsysl = ep;
+    return (0);
+}
+#endif /* defined(HASEOPT) */
+
+/*
+ * enter_fd() - enter file descriptor list for searching
+ */
+
+int enter_fd(struct lsof_context *ctx, /* context */
+             char *f)                  /* file descriptor list pointer */
+{
+    char c, *cp1, *cp2, *dash;
+    int err, excl, hi, lo;
+    char *fc;
+    /*
+     *  Check for non-empty list and make a copy.
+     */
+    if (!f || (strlen(f) + 1) < 2) {
+        (void)fprintf(stderr, "%s: no file descriptor specified\n", Pn);
+        return (1);
+    }
+    if (!(fc = mkstrcpy(f, (MALLOC_S *)NULL))) {
+        (void)fprintf(stderr, "%s: no space for fd string: ", Pn);
+        safestrprt(f, stderr, 1);
+        Error(ctx);
+    }
+    /*
+     * Isolate each file descriptor in the comma-separated list, then enter it
+     * in the file descriptor string list.  If a descriptor has the form:
+     *
+     * [0-9]+-[0-9]+
+     *
+     * treat it as an ascending range of file descriptor numbers.
+     *
+     * Accept a leading '^' as an excusion on match.
+     */
+    for (cp1 = fc, err = 0; *cp1;) {
+        if (*cp1 == '^') {
+            excl = 1;
+            cp1++;
+        } else
+            excl = 0;
+        for (cp2 = cp1, dash = (char *)NULL; *cp2 && *cp2 != ','; cp2++) {
+            if (*cp2 == '-')
+                dash = cp2;
+        }
+        if ((c = *cp2) != '\0')
+            *cp2 = '\0';
+        if (cp2 > cp1) {
+            if (dash) {
+                if (ckfd_range(ctx, cp1, dash, cp2, &lo, &hi))
+                    err = 1;
+                else {
+                    if (enter_fd_lst(ctx, (char *)NULL, lo, hi, excl))
+                        err = 1;
+                }
+            } else {
+                if (enter_fd_lst(ctx, cp1, 0, 0, excl))
+                    err = 1;
+            }
+        }
+        if (c == '\0')
+            break;
+        cp1 = cp2 + 1;
+    }
+    (void)free((FREE_P *)fc);
+    return (err);
+}
+
+/*
+ * enter_fd_lst() - make an entry in the FD list, Fdl
+ */
+
+static int enter_fd_lst(struct lsof_context *ctx, /* context */
+                        char *nm,                 /* FD name (none if NULL) */
+                        int lo,   /* FD low boundary (if nm NULL) */
+                        int hi,   /* FD high boundary (if nm NULL) */
+                        int excl) /* exclusion on match */
+{
+    char buf[256], *cp;
+    int n;
+    struct fd_lst *f, *ft;
+    /*
+     * Don't allow a mixture of exclusions and inclusions.
+     */
+    if (FdlTy >= 0) {
+        if (FdlTy != excl) {
+            if (!Fwarn) {
+
+                /*
+                 * If warnings are enabled, report a mixture.
+                 */
+                if (nm) {
+                    (void)snpf(buf, sizeof(buf) - 1, "%s%s", excl ? "^" : "",
+                               nm);
+                } else {
+                    if (lo != hi) {
+                        (void)snpf(buf, sizeof(buf) - 1, "%s%d-%d",
+                                   excl ? "^" : "", lo, hi);
+                    } else {
+                        (void)snpf(buf, sizeof(buf) - 1, "%s%d",
+                                   excl ? "^" : "", lo);
+                    }
+                }
+                buf[sizeof(buf) - 1] = '\0';
+                (void)fprintf(stderr, "%s: %s in an %s -d list: %s\n", Pn,
+                              excl ? "exclude" : "include",
+                              FdlTy ? "exclude" : "include", buf);
+            }
+            return (1);
+        }
+    }
+    /*
+     * Allocate an fd_lst entry.
+     */
+    if (!(f = (struct fd_lst *)malloc((MALLOC_S)sizeof(struct fd_lst)))) {
+        (void)fprintf(stderr, "%s: no space for FD list entry\n", Pn);
+        Error(ctx);
+    }
+    if (nm) {
+
+        /*
+         * Process an FD name.  First see if it contains only digits; if it
+         * does, convert them to an integer and set the low and high
+         * boundaries to the result.
+         *
+         * If the name has a non-digit, store it as a string, and set the
+         * boundaries to impossible values (i.e., low > high).
+         */
+        for (cp = nm, n = 0; *cp; cp++) {
+            if (!isdigit((unsigned char)*cp))
+                break;
+            n = (n * 10) + (int)(*cp - '0');
+        }
+        if (*cp) {
+            lo = 1;
+            hi = 0;
+            if (strcmp(nm, "unk") == 0) {
+                f->fd_type = LSOF_FD_UNKNOWN;
+            } else if (strcmp(nm, "cwd") == 0) {
+                f->fd_type = LSOF_FD_CWD;
+            } else if (strcmp(nm, "err") == 0) {
+                f->fd_type = LSOF_FD_ERROR;
+            } else if (strcmp(nm, "NOFD") == 0) {
+                f->fd_type = LSOF_FD_NOFD;
+            } else if (strcmp(nm, "rtd") == 0) {
+                f->fd_type = LSOF_FD_ROOT_DIR;
+            } else if (strcmp(nm, "pd") == 0) {
+                f->fd_type = LSOF_FD_PARENT_DIR;
+            } else if (strcmp(nm, "txt") == 0) {
+                f->fd_type = LSOF_FD_PROGRAM_TEXT;
+            } else if (strcmp(nm, "ltx") == 0) {
+                f->fd_type = LSOF_FD_LIBRARY_TEXT;
+            } else if (strcmp(nm, "mem") == 0) {
+                f->fd_type = LSOF_FD_MEMORY;
+            } else if (strcmp(nm, "DEL") == 0) {
+                f->fd_type = LSOF_FD_DELETED;
+            } else if (strcmp(nm, "fp") == 0) {
+                f->fd_type = LSOF_FD_FILEPORT;
+            } else if (strcmp(nm, "twd") == 0) {
+                f->fd_type = LSOF_FD_TASK_CWD;
+            } else if (strcmp(nm, "ctty") == 0) {
+                f->fd_type = LSOF_FD_CTTY;
+            } else if (strcmp(nm, "jd.") == 0) {
+                f->fd_type = LSOF_FD_JAIL_DIR;
+            } else if (strcmp(nm, "v86") == 0) {
+                f->fd_type = LSOF_FD_VIRTUAL_8086;
+            } else if (strcmp(nm, "m86") == 0) {
+                f->fd_type = LSOF_FD_MERGE_386;
+            } else if (strcmp(nm, "mmap") == 0) {
+                f->fd_type = LSOF_FD_MMAP_DEVICE;
+            } else if (strcmp(nm, "fd") == 0) {
+                /* pseudo fd type meaning whole range of fd */
+                f->fd_type = LSOF_FD_NUMERIC;
+                hi = INT_MAX;
+                lo = 0;
+            } else {
+                (void)fprintf(stderr,
+                              "%s: invalid fd type given in -d option\n", Pn);
+                Error(ctx);
+                return (1);
+            }
+        } else {
+            f->fd_type = LSOF_FD_NUMERIC;
+            lo = hi = n;
+        }
+    } else
+        f->fd_type = LSOF_FD_NUMERIC;
+    /*
+     * Skip duplicates.
+     */
+    for (ft = Fdl; ft; ft = ft->next) {
+        if (ft->fd_type != f->fd_type)
+            continue;
+        if (ft->fd_type == LSOF_FD_NUMERIC) {
+            if ((lo != ft->lo) || (hi != ft->hi))
+                continue;
+        }
+        (void)free((FREE_P *)f);
+        return (0);
+    }
+    /*
+     * Complete the fd_lst entry and link it to the head of the chain.
+     */
+    f->hi = hi;
+    f->lo = lo;
+    f->next = Fdl;
+    Fdl = f;
+    FdlTy = excl;
+    return (0);
+}
+
+/*
+ * enter_dir() - enter the files of a directory for searching
+ */
+
+#define EDDEFFNL 128 /* default file name length */
+
+int enter_dir(struct lsof_context *ctx, /* context */
+              char *d,                  /* directory path name pointer */
+              int descend)              /* subdirectory descend flag:
+                                         *     0 = don't descend
+                                         *     1 = descend */
+{
+    char *av[2];
+    dev_t ddev;
+    DIR *dfp;
+    char *dn = (char *)NULL;
+    MALLOC_S dnl, dnamlen;
+    struct DIRTYPE *dp;
+    int en, sl;
+    int fct = 0;
+    char *fp = (char *)NULL;
+    MALLOC_S fpl = (MALLOC_S)0;
+    MALLOC_S fpli = (MALLOC_S)0;
+    struct stat sb;
+    /*
+     * Check the directory path; reduce symbolic links; stat(2) it; make sure
+     * it's really a directory.
+     */
+    if (!d || !*d || *d == '+' || *d == '-') {
+        if (!Fwarn)
+            (void)fprintf(stderr, "%s: +d not followed by a directory path\n",
+                          Pn);
+        return (1);
+    }
+    if (!(dn = Readlink(ctx, d)))
+        return (1);
+    if (statsafely(ctx, dn, &sb)) {
+        if (!Fwarn) {
+            en = errno;
+            (void)fprintf(stderr, "%s: WARNING: can't stat(", Pn);
+            safestrprt(dn, stderr, 0);
+            (void)fprintf(stderr, "): %s\n", strerror(en));
+        }
+        if (dn && dn != d) {
+            (void)free((FREE_P *)dn);
+            dn = (char *)NULL;
+        }
+        return (1);
+    }
+    if ((sb.st_mode & S_IFMT) != S_IFDIR) {
+        if (!Fwarn) {
+            (void)fprintf(stderr, "%s: WARNING: not a directory: ", Pn);
+            safestrprt(dn, stderr, 1);
+        }
+        if (dn && dn != d) {
+            (void)free((FREE_P *)dn);
+            dn = (char *)NULL;
+        }
+        return (1);
+    }
+
+#if defined(HASSPECDEVD)
+    (void)HASSPECDEVD(ctx, dn, &sb);
+#endif /* defined(HASSPECDEVD) */
+
+    ddev = sb.st_dev;
+    /*
+     * Stack the directory and record it in Sfile for searching.
+     */
+    Dstkn = Dstkx = 0;
+    Dstk = (char **)NULL;
+    (void)stkdir(ctx, dn);
+    av[0] = (dn == d) ? mkstrcpy(dn, (MALLOC_S *)NULL) : dn;
+    av[1] = (char *)NULL;
+    dn = (char *)NULL;
+    if (!ck_file_arg(ctx, 0, 1, av, 1, 1, &sb, 0)) {
+        av[0] = (char *)NULL;
+        fct++;
+    }
+    /*
+     * Unstack the next directory and examine it.
+     */
+    while (--Dstkx >= 0) {
+        if (!(dn = Dstk[Dstkx]))
+            continue;
+        Dstk[Dstkx] = (char *)NULL;
+        /*
+         * Open the directory path and prepare its name for use with the
+         * files in the directory.
+         */
+        if (!(dfp = OpenDir(dn))) {
+            if (!Fwarn) {
+                if ((en = errno) != ENOENT) {
+                    (void)fprintf(stderr, "%s: WARNING: can't opendir(", Pn);
+                    safestrprt(dn, stderr, 0);
+                    (void)fprintf(stderr, "): %s\n", strerror(en));
+                }
+            }
+            (void)free((FREE_P *)dn);
+            dn = (char *)NULL;
+            continue;
+        }
+        dnl = strlen(dn);
+        sl = ((dnl > 0) && (*(dn + dnl - 1) == '/')) ? 0 : 1;
+        /*
+         * Define space for possible addition to the directory path.
+         */
+        fpli = (MALLOC_S)(dnl + sl + EDDEFFNL + 1);
+        if ((int)fpli > (int)fpl) {
+            fpl = fpli;
+            if (!fp)
+                fp = (char *)malloc(fpl);
+            else
+                fp = (char *)realloc(fp, fpl);
+            if (!fp) {
+                (void)fprintf(
+                    stderr,
+                    "%s: no space for path to entries in directory: %s\n", Pn,
+                    dn);
+                Error(ctx);
+            }
+        }
+        (void)snpf(fp, (size_t)fpl, "%s%s", dn, sl ? "/" : "");
+        (void)free((FREE_P *)dn);
+        dn = (char *)NULL;
+        /*
+         * Read the contents of the directory.
+         */
+        for (dp = ReadDir(dfp); dp; dp = ReadDir(dfp)) {
+
+            /*
+             * Skip: entries with no inode number;
+             *      entries with a zero length name;
+             *      ".";
+             *      and "..".
+             */
+            if (!dp->d_ino)
+                continue;
+
+#if defined(HASDNAMLEN)
+            dnamlen = (MALLOC_S)dp->d_namlen;
+#else  /* !defined(HASDNAMLEN) */
+            dnamlen = (MALLOC_S)strlen(dp->d_name);
+#endif /* defined(HASDNAMLEN) */
+
+            if (!dnamlen)
+                continue;
+            if (dnamlen <= 2 && dp->d_name[0] == '.') {
+                if (dnamlen == 1)
+                    continue;
+                if (dp->d_name[1] == '.')
+                    continue;
+            }
+            /*
+             * Form the entry's path name.
+             */
+            fpli = (MALLOC_S)(dnamlen - (fpl - dnl - sl - 1));
+            if ((int)fpli > 0) {
+                fpl += fpli;
+                if (!(fp = (char *)realloc(fp, fpl))) {
+                    (void)fprintf(stderr, "%s: no space for: ", Pn);
+                    safestrprt(dn, stderr, 0);
+                    putc('/', stderr);
+                    safestrprtn(dp->d_name, dnamlen, stderr, 1);
+                    Error(ctx);
+                }
+            }
+            (void)strncpy(fp + dnl + sl, dp->d_name, dnamlen);
+            fp[dnl + sl + dnamlen] = '\0';
+            /*
+             * Lstatsafely() the entry; complain if that fails.
+             *
+             * Stack entries that represent subdirectories.
+             */
+            if (lstatsafely(ctx, fp, &sb)) {
+                if ((en = errno) != ENOENT) {
+                    if (!Fwarn) {
+                        (void)fprintf(stderr, "%s: WARNING: can't lstat(", Pn);
+                        safestrprt(fp, stderr, 0);
+                        (void)fprintf(stderr, "): %s\n", strerror(en));
+                    }
+                }
+                continue;
+            }
+
+#if defined(HASSPECDEVD)
+            (void)HASSPECDEVD(ctx, fp, &sb);
+#endif /* defined(HASSPECDEVD) */
+
+            if (!(Fxover & XO_FILESYS)) {
+
+                /*
+                 * Unless "-x" or "-x f" was specified, don't cross over file
+                 * system mount points.
+                 */
+                if (sb.st_dev != ddev)
+                    continue;
+            }
+            if ((sb.st_mode & S_IFMT) == S_IFLNK) {
+
+                /*
+                 * If this is a symbolic link and "-x_ or "-x l" was specified,
+                 * Statsafely() the entry and process it.
+                 *
+                 * Otherwise skip symbolic links.
+                 */
+                if (Fxover & XO_SYMLINK) {
+                    if (statsafely(ctx, fp, &sb)) {
+                        if ((en = errno) != ENOENT) {
+                            if (!Fwarn) {
+                                (void)fprintf(stderr,
+                                              "%s: WARNING: can't stat(", Pn);
+                                safestrprt(fp, stderr, 0);
+                                (void)fprintf(stderr, ") symbolc link: %s\n",
+                                              strerror(en));
+                            }
+                        }
+                        continue;
+                    }
+                } else
+                    continue;
+            }
+            if (av[0]) {
+                (void)free((FREE_P *)av[0]);
+                av[0] = (char *)NULL;
+            }
+            av[0] = mkstrcpy(fp, (MALLOC_S *)NULL);
+            if ((sb.st_mode & S_IFMT) == S_IFDIR && descend)
+
+                /*
+                 * Stack a subdirectory according to the descend argument.
+                 */
+                stkdir(ctx, av[0]);
+            /*
+             * Use ck_file_arg() to record the entry for searching.  Force it
+             * to consider the entry a file, not a file system.
+             */
+            if (!ck_file_arg(ctx, 0, 1, av, 1, 1, &sb, 0)) {
+                av[0] = (char *)NULL;
+                fct++;
+            }
+        }
+        (void)CloseDir(dfp);
+        if (dn && dn != d) {
+            (void)free((FREE_P *)dn);
+            dn = (char *)NULL;
+        }
+    }
+    /*
+     * Free malloc()'d space.
+     */
+    if (dn && dn != d) {
+        (void)free((FREE_P *)dn);
+        dn = (char *)NULL;
+    }
+    if (av[0] && av[0] != fp) {
+        (void)free((FREE_P *)av[0]);
+        av[0] = (char *)NULL;
+    }
+    if (fp) {
+        (void)free((FREE_P *)fp);
+        fp = (char *)NULL;
+    }
+    if (Dstk) {
+        (void)free((FREE_P *)Dstk);
+        Dstk = (char **)NULL;
+    }
+    if (!fct) {
+
+        /*
+         * Warn if no files were recorded for searching.
+         */
+        if (!Fwarn) {
+            (void)fprintf(stderr,
+                          "%s: WARNING: no files found in directory: ", Pn);
+            safestrprt(d, stderr, 1);
+        }
+        return (1);
+    }
+    return (0);
+}
+
+/*
+ * enter_id() - enter PGID or PID for searching
+ */
+
+int enter_id(struct lsof_context *ctx, /* context */
+             enum IDType ty,           /* type: PGID or PID */
+             char *p)                  /* process group ID string pointer */
+{
+    char *cp;
+    int err, i, id, j, mx, n, ni, nx, x;
+    struct int_lst *s;
+
+    if (!p) {
+        (void)fprintf(stderr, "%s: no process%s ID specified\n", Pn,
+                      (ty == PGID) ? " group" : "");
+        return (1);
+    }
+    /*
+     * Convert and store the ID.
+     */
+    for (cp = p, err = 0; *cp;) {
+
+        /*
+         * Assemble ID.
+         */
+        for (i = id = x = 0; *cp && *cp != ','; cp++) {
+            if (!i) {
+                i = 1;
+                if (*cp == '^') {
+                    x = 1;
+                    continue;
+                }
+            }
+
+#if defined(__STDC__)
+            if (!isdigit((unsigned char)*cp))
+#else  /* !defined(__STDC__) */
+            if (!isascii(*cp) || !isdigit((unsigned char)*cp))
+#endif /* __STDC__ */
+
+            {
+                (void)fprintf(stderr, "%s: illegal process%s ID: ", Pn,
+                              (ty == PGID) ? " group" : "");
+                safestrprt(p, stderr, 1);
+                return (1);
+            }
+            id = (id * 10) + *cp - '0';
+        }
+        if (*cp)
+            cp++;
+        if (ty == PGID) {
+            if (lsof_select_pgid(ctx, id, x)) {
+                err = 1;
+            }
+        } else {
+            if (lsof_select_pid(ctx, id, x)) {
+                err = 1;
+            }
+        }
+    }
+    return (err);
+}
+
+/*
+ * enter_network_address() - enter Internet address for searching
+ */
+
+int enter_network_address(struct lsof_context *ctx, /* context */
+                          char *na) /* Internet address string pointer */
+{
+    int ae, i, pr;
+    int ep = -1;
+    int ft = 0;
+    struct hostent *he = (struct hostent *)NULL;
+    char *hn = (char *)NULL;
+    MALLOC_S l;
+    struct nwad n;
+    char *p, *wa;
+    int pt = 0;
+    int pu = 0;
+    struct servent *se, *se1;
+    char *sn = (char *)NULL;
+    int sp = -1;
+    MALLOC_S snl = 0;
+
+#if defined(HASIPv6)
+    char *cp;
+#endif /* defined(HASIPv6) */
+
+    if (!na) {
+        (void)fprintf(stderr, "%s: no network address specified\n", Pn);
+        return (1);
+    }
+    zeromem((char *)&n, sizeof(n));
+    wa = na;
+    /*
+     * Process an IP version type specification, IPv4 or IPv6, optionally
+     * followed by a '@' and a host name or Internet address, or a ':' and a
+     * service name or port number.
+     */
+    if ((*wa == '4') || (*wa == '6')) {
+        if (*wa == '4')
+            ft = 4;
+        else if (*wa == '6') {
+
+#if defined(HASIPv6)
+            ft = 6;
+#else  /* !defined(HASIPv6) */
+            (void)fprintf(stderr, "%s: IPv6 not supported: -i ", Pn);
+            safestrprt(na, stderr, 1);
+            goto nwad_exit;
+#endif /* defined(HASIPv6) */
+        }
+        wa++;
+        if (!*wa) {
+
+            /*
+             * If nothing follows 4 or 6, then all network files of the
+             * specified IP version are selected.  Sequential -i, -i4, and
+             * -i6 specifications interact logically -- e.g., -i[46] followed
+             * by -i[64] is the same as -i.
+             */
+            if (!Fnet) {
+                Fnet = 1;
+                FnetTy = ft;
+            } else {
+                if (FnetTy) {
+                    if (FnetTy != ft)
+                        FnetTy = 0;
+                } else
+                    FnetTy = ft;
+            }
+            return (0);
+        }
+    } else if (Fnet)
+        ft = FnetTy;
+    /*
+     * If an IP version has been specified, use it to set the address family.
+     */
+    switch (ft) {
+    case 4:
+        n.af = AF_INET;
+        break;
+
+#if defined(HASIPv6)
+    case 6:
+        n.af = AF_INET6;
+        break;
+#endif /* defined(HASIPv6) */
+    }
+    /*
+     * Process protocol name, optionally followed by a '@' and a host name or
+     * Internet address, or a ':' and a service name or port number.
+     */
+    if (*wa && *wa != '@' && *wa != ':') {
+        for (p = wa; *wa && *wa != '@' && *wa != ':'; wa++)
+            ;
+        if ((l = wa - p)) {
+            if (!(n.proto = mkstrcat(p, l, (char *)NULL, -1, (char *)NULL, -1,
+                                     (MALLOC_S *)NULL))) {
+                (void)fprintf(stderr,
+                              "%s: no space for protocol name from: -i ", Pn);
+                safestrprt(na, stderr, 1);
+            nwad_exit:
+                if (n.proto)
+                    (void)free((FREE_P *)n.proto);
+                if (hn)
+                    (void)free((FREE_P *)hn);
+                if (sn)
+                    (void)free((FREE_P *)sn);
+                return (1);
+            }
+            /*
+             * The protocol name should be "tcp", "udp" or "udplite".
+             */
+            if ((strcasecmp(n.proto, "tcp") != 0) &&
+                (strcasecmp(n.proto, "udp") != 0) &&
+                (strcasecmp(n.proto, "udplite") != 0)) {
+                (void)fprintf(stderr, "%s: unknown protocol name (%s) in: -i ",
+                              Pn, n.proto);
+                safestrprt(na, stderr, 1);
+                goto nwad_exit;
+            }
+            /*
+             * Convert protocol name to lower case.
+             */
+            for (p = n.proto; *p; p++) {
+                if (*p >= 'A' && *p <= 'Z')
+                    *p = *p - 'A' + 'a';
+            }
+        }
+    }
+    /*
+     * Process an IPv4 address (1.2.3.4), IPv6 address ([1:2:3:4:5:6:7:8]),
+     * or host name, preceded by a '@' and optionally followed by a colon
+     * and a service name or port number.
+     */
+    if (*wa == '@') {
+        wa++;
+        if (!*wa || *wa == ':') {
+
+#if defined(HASIPv6)
+        unacc_address:
+#endif /* defined(HASIPv6) */
+
+            (void)fprintf(stderr, "%s: unacceptable Internet address in: -i ",
+                          Pn);
+            safestrprt(na, stderr, 1);
+            goto nwad_exit;
+        }
+
+        if ((p = isIPv4addr(wa, n.a, sizeof(n.a)))) {
+
+            /*
+             * Process IPv4 address.
+             */
+            if (ft == 6) {
+                (void)fprintf(stderr, "%s: IPv4 addresses are prohibited: -i ",
+                              Pn);
+                safestrprt(na, stderr, 1);
+                goto nwad_exit;
+            }
+            wa = p;
+            n.af = AF_INET;
+        } else if (*wa == '[') {
+
+#if defined(HASIPv6)
+            /*
+             * Make sure IPv6 addresses are permitted.  If they are, assemble
+             * one.
+             */
+            if (ft == 4) {
+                (void)fprintf(stderr, "%s: IPv6 addresses are prohibited: -i ",
+                              Pn);
+                safestrprt(na, stderr, 1);
+                goto nwad_exit;
+            }
+            if (!(cp = strrchr(++wa, ']')))
+                goto unacc_address;
+            *cp = '\0';
+            i = inet_pton(AF_INET6, wa, (void *)&n.a);
+            *cp = ']';
+            if (i != 1)
+                goto unacc_address;
+            for (ae = i = 0; i < MAX_AF_ADDR; i++) {
+                if ((ae |= n.a[i]))
+                    break;
+            }
+            if (!ae)
+                goto unacc_address;
+            if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)&n.a[0])) {
+                if (ft == 6) {
+                    (void)fprintf(stderr,
+                                  "%s: IPv4 addresses are prohibited: -i ", Pn);
+                    safestrprt(na, stderr, 1);
+                    goto nwad_exit;
+                }
+                for (i = 0; i < 4; i++) {
+                    n.a[i] = n.a[i + 12];
+                }
+                n.af = AF_INET;
+            } else
+                n.af = AF_INET6;
+            wa = cp + 1;
+#else  /* !defined(HASIPv6) */
+            (void)fprintf(stderr, "%s: unsupported IPv6 address in: -i ", Pn);
+            safestrprt(na, stderr, 1);
+            goto nwad_exit;
+#endif /* defined(HASIPv6) */
+
+        } else {
+
+            /*
+             * Assemble host name.
+             */
+            for (p = wa; *p && *p != ':'; p++)
+                ;
+            if ((l = p - wa)) {
+                if (!(hn = mkstrcat(wa, l, (char *)NULL, -1, (char *)NULL, -1,
+                                    (MALLOC_S *)NULL))) {
+                    (void)fprintf(stderr, "%s: no space for host name: -i ",
+                                  Pn);
+                    safestrprt(na, stderr, 1);
+                    goto nwad_exit;
+                }
+
+#if defined(HASIPv6)
+
+                /*
+                 * If no IP version has been specified, look up an IPv6 host
+                 * name first.  If that fails, look up an IPv4 host name.
+                 *
+                 * If the IPv6 version has been specified, look up the host
+                 * name only under its IP version specification.
+                 */
+                if (!ft)
+                    n.af = AF_INET6;
+                if (!(he = lkup_hostnm(hn, &n)) && !ft) {
+                    n.af = AF_INET;
+                    he = lkup_hostnm(hn, &n);
+                }
+#else  /* !defined(HASIPv6) */
+                if (!ft)
+                    n.af = AF_INET;
+                he = lkup_hostnm(hn, &n);
+#endif /* defined(HASIPv6) */
+
+                if (!he) {
+                    fprintf(stderr, "%s: unknown host name (%s) in: -i ", Pn,
+                            hn);
+                    safestrprt(na, stderr, 1);
+                    goto nwad_exit;
+                }
+            }
+            wa = p;
+        }
+    }
+    /*
+     * If there is no port number, enter the address.
+     */
+    if (!*wa)
+        goto nwad_enter;
+    /*
+     * Process a service name or port number list, preceded by a colon.
+     *
+     * Entries of the list are separated with commas; elements of a numeric
+     * range are specified with a separating minus sign (`-'); all service names
+     * must belong to the same protocol; embedded spaces are not allowed.  An
+     * embedded minus sign in a name is taken to be part of the name, the
+     * starting entry of a range can't be a service name.
+     */
+    if (*wa != ':' || *(wa + 1) == '\0') {
+
+    unacc_port:
+        (void)fprintf(stderr, "%s: unacceptable port specification in: -i ",
+                      Pn);
+        safestrprt(na, stderr, 1);
+        goto nwad_exit;
+    }
+    for (++wa; wa && *wa; wa++) {
+        for (ep = pr = sp = 0; *wa; wa++) {
+            if (*wa < '0' || *wa > '9') {
+
+                /*
+                 * Convert service name to port number, using already-specified
+                 * protocol name.  A '-' is taken to be part of the name; hence
+                 * the starting entry of a range can't be a service name.
+                 */
+                for (p = wa; *wa && *wa != ','; wa++)
+                    ;
+                if (!(l = wa - p)) {
+                    (void)fprintf(stderr, "%s: invalid service name: -i ", Pn);
+                    safestrprt(na, stderr, 1);
+                    goto nwad_exit;
+                }
+                if (sn) {
+                    if (l > snl) {
+                        sn = (char *)realloc((MALLOC_P *)sn, l + 1);
+                        snl = l;
+                    }
+                } else {
+                    sn = (char *)malloc(l + 1);
+                    snl = l;
+                }
+                if (!sn) {
+                    (void)fprintf(stderr, "%s: no space for service name: -i ",
+                                  Pn);
+                    safestrprt(na, stderr, 1);
+                    goto nwad_exit;
+                }
+                (void)strncpy(sn, p, l);
+                *(sn + l) = '\0';
+                if (n.proto) {
+
+                    /*
+                     * If the protocol has been specified, look up the port
+                     * number for the service name for the specified protocol.
+                     */
+                    if (!(se = getservbyname(sn, n.proto))) {
+                        (void)fprintf(stderr,
+                                      "%s: unknown service %s for %s in: -i ",
+                                      Pn, sn, n.proto);
+                        safestrprt(na, stderr, 1);
+                        goto nwad_exit;
+                    }
+                    pt = (int)ntohs(se->s_port);
+                } else {
+
+                    /*
+                     * If no protocol has been specified, look up the port
+                     * numbers for the service name for both TCP and UDP.
+                     */
+                    if ((se = getservbyname(sn, "tcp")))
+                        pt = (int)ntohs(se->s_port);
+                    if ((se1 = getservbyname(sn, "udp")))
+                        pu = (int)ntohs(se1->s_port);
+                    if (!se && !se1) {
+                        (void)fprintf(stderr, "%s: unknown service %s in: -i ",
+                                      Pn, sn);
+                        safestrprt(na, stderr, 1);
+                        goto nwad_exit;
+                    }
+                    if (se && se1 && pt != pu) {
+                        (void)fprintf(
+                            stderr,
+                            "%s: TCP=%d and UDP=%d %s ports conflict;\n", Pn,
+                            pt, pu, sn);
+                        (void)fprintf(
+                            stderr,
+                            "      specify \"tcp:%s\" or \"udp:%s\": -i ", sn,
+                            sn);
+                        safestrprt(na, stderr, 1);
+                        goto nwad_exit;
+                    }
+                    if (!se && se1)
+                        pt = pu;
+                }
+                if (pr)
+                    ep = pt;
+                else {
+                    sp = pt;
+                    if (*wa == '-')
+                        pr++;
+                }
+            } else {
+
+                /*
+                 * Assemble port number.
+                 */
+                for (; *wa && *wa != ','; wa++) {
+                    if (*wa == '-') {
+                        if (pr)
+                            goto unacc_port;
+                        pr++;
+                        break;
+                    }
+                    if (*wa < '0' || *wa > '9')
+                        goto unacc_port;
+                    if (pr)
+                        ep = (ep * 10) + *wa - '0';
+                    else
+                        sp = (sp * 10) + *wa - '0';
+                }
+            }
+            if (!*wa || *wa == ',')
+                break;
+            if (pr)
+                continue;
+            goto unacc_port;
+        }
+        if (!pr)
+            ep = sp;
+        if (ep < sp)
+            goto unacc_port;
+        /*
+         * Enter completed port or port range specification.
+         */
+
+    nwad_enter:
+
+        for (i = 1; i;) {
+            if (enter_nwad(ctx, &n, sp, ep, na, he))
+                goto nwad_exit;
+
+#if defined(HASIPv6)
+            /*
+             * If IPv6 is enabled, a host name was specified, and the
+             * associated * address is for the AF_INET6 address family,
+             * try to get and address for the AF_INET family, too, unless
+             * IPv4 is prohibited.
+             */
+            if (hn && (n.af == AF_INET6) && (ft != 6)) {
+                n.af = AF_INET;
+                if ((he = lkup_hostnm(hn, &n)))
+                    continue;
+            }
+#endif /* defined(HASIPv6) */
+
+            i = 0;
+        }
+        if (!*wa)
+            break;
+    }
+    if (sn)
+        (void)free((FREE_P *)sn);
+    return (0);
+}
+
+/*
+ * enter_nwad() - enter nwad structure
+ */
+
+static int enter_nwad(struct lsof_context *ctx, /* context */
+                      struct nwad *n,     /* pointer to partially completed
+                                           * nwad (less port) */
+                      int sp,             /* starting port number */
+                      int ep,             /* ending port number */
+                      char *s,            /* string that states the address */
+                      struct hostent *he) /* pointer to hostent struct from
+                                           * which network address came */
+{
+    int ac;
+    unsigned char *ap;
+    static int na = 0;
+    struct nwad nc;
+    struct nwad *np;
+    /*
+     * Allocate space for the argument specification.
+     */
+    if (strlen(s)) {
+        if (!(n->arg = mkstrcpy(s, (MALLOC_S *)NULL))) {
+            (void)fprintf(stderr, "%s: no space for Internet argument: -i ",
+                          Pn);
+            safestrprt(s, stderr, 1);
+            Error(ctx);
+        }
+    } else
+        n->arg = (char *)NULL;
+    /*
+     * Loop through all hostent addresses.
+     */
+    for (ac = 1, nc = *n;;) {
+
+        /*
+         * Test address specification -- it must contain at least one of:
+         * protocol, Internet address or port.  If correct, link into search
+         * list.
+         */
+        if (!nc.proto && !nc.a[0] && !nc.a[1] && !nc.a[2] && !nc.a[3]
+
+#if defined(HASIPv6)
+            && (nc.af != AF_INET6 ||
+                (!nc.a[4] && !nc.a[5] && !nc.a[6] && !nc.a[7] && !nc.a[8] &&
+                 !nc.a[9] && !nc.a[10] && !nc.a[11] && !nc.a[12] && !nc.a[13] &&
+                 !nc.a[14] && !nc.a[15]))
+#endif /* defined(HASIPv6) */
+
+            && sp == -1) {
+            (void)fprintf(stderr,
+                          "%s: incomplete Internet address specification: -i ",
+                          Pn);
+            safestrprt(s, stderr, 1);
+            return (1);
+        }
+        /*
+         * Limit the network address chain length to MAXNWAD for reasons of
+         * search efficiency.
+         */
+        if (na >= MAXNWAD) {
+            (void)fprintf(stderr,
+                          "%s: network address limit (%d) exceeded: -i ", Pn,
+                          MAXNWAD);
+            safestrprt(s, stderr, 1);
+            return (1);
+        }
+        /*
+         * Allocate space for the address specification.
+         */
+        if ((np = (struct nwad *)malloc(sizeof(struct nwad))) == NULL) {
+            (void)fprintf(stderr, "%s: no space for network address from: -i ",
+                          Pn);
+            safestrprt(s, stderr, 1);
+            return (1);
+        }
+        /*
+         * Construct and link the address specification.
+         */
+        *np = nc;
+        np->sport = sp;
+        np->eport = ep;
+        np->f = 0;
+        np->next = Nwad;
+        Nwad = np;
+        na++;
+        /*
+         * If the network address came from gethostbyname(), advance to
+         * the next address; otherwise quit.
+         */
+        if (!he)
+            break;
+        if (!he->h_addr_list[ac -
+                             1]) /* Check if address list ended prematurely */
+            break;
+        if (!(ap = (unsigned char *)he->h_addr_list[ac++]))
+            break;
+
+#if defined(HASIPv6)
+        {
+            int i;
+
+            for (i = 0; (i < (he->h_length - 1)) && (i < (MAX_AF_ADDR - 1));
+                 i++) {
+                nc.a[i] = *ap++;
+            }
+            nc.a[i] = *ap;
+        }
+#else  /* !defined(HASIPv6) */
+        nc.a[0] = *ap++;
+        nc.a[1] = *ap++;
+        nc.a[2] = *ap++;
+        nc.a[3] = *ap;
+#endif /* defined(HASIPv6) */
+    }
+    return (0);
+}
+
+#if defined(HASTCPUDPSTATE)
+/*
+ * enter_state_spec() -- enter TCP and UDP state specifications
+ */
+
+int enter_state_spec(struct lsof_context *ctx,
+                     char *ss) /* state specification string */
+{
+    char *cp, *ne, *ns, *pr;
+    int err, d, f, i, tx, x;
+    static char *ssc = (char *)NULL;
+    char *ty;
+    /*
+     * Check the protocol specification.
+     */
+    if (!strncasecmp(ss, "tcp:", 4)) {
+        pr = "TCP";
+        tx = 0;
+    }
+
+#    if !defined(USE_LIB_PRINT_TCPTPI)
+    else if (!strncasecmp(ss, "UDP:", 4)) {
+        pr = "UDP";
+        tx = 1;
+    }
+
+#    endif /* !defined(USE_LIB_PRINT_TCPTPI) */
+
+    else {
+        (void)fprintf(stderr, "%s: unknown -s protocol: \"%s\"\n", Pn, ss);
+        return (1);
+    }
+    cp = ss + 4;
+    if (!*cp) {
+        (void)fprintf(stderr, "%s: no %s state names in: %s\n", Pn, pr, ss);
+        return (1);
+    }
+    (void)build_IPstates(ctx);
+    if (!(tx ? UdpSt : TcpSt)) {
+        (void)fprintf(stderr, "%s: no %s state names available: %s\n", Pn, pr,
+                      ss);
+        return (1);
+    }
+    /*
+     * Allocate the inclusion and exclusion tables for the protocol.
+     */
+    if (tx) {
+        if (UdpNstates) {
+            if (!UdpStI) {
+                if (!(UdpStI = (unsigned char *)calloc(
+                          (MALLOC_S)UdpNstates, sizeof(unsigned char)))) {
+                    ty = "UDP state inclusion";
+
+                no_IorX_space:
+
+                    (void)fprintf(stderr, "%s: no %s table space\n", Pn, ty);
+                    Error(ctx);
+                }
+            }
+            if (!UdpStX) {
+                if (!(UdpStX = (unsigned char *)calloc(
+                          (MALLOC_S)UdpNstates, sizeof(unsigned char)))) {
+                    ty = "UDP state exclusion";
+                    goto no_IorX_space;
+                }
+            }
+        }
+    } else {
+        if (TcpNstates) {
+            if (!TcpStI) {
+                if (!(TcpStI = (unsigned char *)calloc(
+                          (MALLOC_S)TcpNstates, sizeof(unsigned char)))) {
+                    ty = "TCP state inclusion";
+                    goto no_IorX_space;
+                }
+            }
+            if (!TcpStX) {
+                if (!(TcpStX = (unsigned char *)calloc(
+                          (MALLOC_S)TcpNstates, sizeof(unsigned char)))) {
+                    ty = "TCP state exclusion";
+                    goto no_IorX_space;
+                }
+            }
+        }
+    }
+    /*
+     * Convert the state names in the rest of the string to state indexes and
+     * record them in the appropriate inclusion or exclusion table.
+     */
+    if (ssc)
+        (void)free((MALLOC_P *)ssc);
+    if (!(ssc = mkstrcpy(cp, (MALLOC_S *)NULL))) {
+        (void)fprintf(stderr, "%s: no temporary state argument space for: %s\n",
+                      Pn, ss);
+        Error(ctx);
+    }
+    cp = ssc;
+    err = 0;
+    while (*cp) {
+
+        /*
+         * Determine inclusion or exclusion for this state name.
+         */
+        if (*cp == '^') {
+            x = 1;
+            cp++;
+        } else
+            x = 0;
+        /*
+         * Find the end of the state name.  Make sure it is non-null in length
+         * and terminated with '\0'.
+         */
+        ns = cp;
+        while (*cp && (*cp != ',')) {
+            cp++;
+        }
+        ne = cp;
+        if (*cp) {
+            *cp = '\0';
+            cp++;
+        }
+        if (!(size_t)(ne - ns)) {
+            (void)fprintf(stderr, "%s: NULL %s state name in: %s\n", Pn, pr,
+                          ss);
+            err = 1;
+            continue;
+        }
+        /*
+         * Find the state name in the appropriate table.
+         */
+        f = 0;
+        if (tx) {
+            if (UdpSt) {
+                for (i = 0; i < UdpNstates; i++) {
+                    if (!strcasecmp(ns, UdpSt[i])) {
+                        f = 1;
+                        break;
+                    }
+                }
+            }
+        } else {
+            if (TcpSt) {
+                for (i = 0; i < TcpNstates; i++) {
+                    if (!strcasecmp(ns, TcpSt[i])) {
+                        f = 1;
+                        break;
+                    }
+                }
+            }
+        }
+        if (!f) {
+            (void)fprintf(stderr, "%s: unknown %s state name: %s\n", Pn, pr,
+                          ns);
+            err = 1;
+            continue;
+        }
+        /*
+         * Set the inclusion or exclusion status in the appropriate table.
+         */
+        d = 0;
+        if (x) {
+            if (tx) {
+                if (!UdpStX[i]) {
+                    UdpStX[i] = 1;
+                    UdpStXn++;
+                } else
+                    d = 1;
+            } else {
+                if (!TcpStX[i]) {
+                    TcpStX[i] = 1;
+                    TcpStXn++;
+                } else
+                    d = 1;
+            }
+        } else {
+            if (tx) {
+                if (!UdpStI[i]) {
+                    UdpStI[i] = 1;
+                    UdpStIn++;
+                } else
+                    d = 1;
+            } else {
+                if (!TcpStI[i]) {
+                    TcpStI[i] = 1;
+                    TcpStIn++;
+                } else
+                    d = 1;
+            }
+        }
+        if (d) {
+
+            /*
+             * Report a duplicate.
+             */
+            (void)fprintf(stderr, "%s: duplicate %s %sclusion: %s\n", Pn, pr,
+                          x ? "ex" : "in", ns);
+            err = 1;
+        }
+    }
+    /*
+     * Release any temporary space and return.
+     */
+    if (ssc) {
+        (void)free((MALLOC_P *)ssc);
+        ssc = (char *)NULL;
+    }
+    return (err);
+}
+#endif /* defined(HASTCPUDPSTATE) */
+
+/*
+ * enter_cmd() - enter -c option
+ */
+
+int enter_cmd(struct lsof_context *ctx, /* context */
+              char *opt,                /* option name */
+              char *s)                  /* string to enter */
+{
+    char *cp;
+    short x;
+    MALLOC_S len;
+    struct str_lst *lpt;
+
+    if (!s || *s == '-' || *s == '+') {
+        (void)fprintf(stderr, "%s: missing %s option value\n", Pn, opt);
+        return (1);
+    }
+    if (*s == '^') {
+        x = 1;
+        s++;
+    } else {
+        x = 0;
+    }
+    if (lsof_select_process(ctx, s, x) != LSOF_SUCCESS) {
+        return 1;
+    }
+    return 0;
+}
+
+/*
+ * enter_uid() - enter User Identifier for searching
+ */
+
+int enter_uid(struct lsof_context *ctx, /* context */
+              char *us)                 /* User IDentifier string pointer */
+{
+    int err, i, j, lnml, nn;
+    unsigned char excl;
+    MALLOC_S len;
+    char lnm[LOGINML + 1], *lp;
+    struct passwd *pw;
+    char *s, *st;
+    uid_t uid;
+
+    if (!us) {
+        (void)fprintf(stderr, "%s: no UIDs specified\n", Pn);
+        return (1);
+    }
+    for (err = 0, s = us; *s;) {
+
+        /*
+         * Assemble next User IDentifier.
+         */
+        for (excl = i = j = lnml = nn = uid = 0, st = s; *s && *s != ',';
+             i++, s++) {
+            if (lnml >= LOGINML) {
+                while (*s && *s != ',') {
+                    s++;
+                    lnml++;
+                }
+                (void)fprintf(stderr, "%s: -u login name > %d characters: ", Pn,
+                              (int)LOGINML);
+                safestrprtn(st, lnml, stderr, 1);
+                err = j = 1;
+                break;
+            }
+            if (i == 0 && *s == '^') {
+                excl = 1;
+                continue;
+            }
+            lnm[lnml++] = *s;
+            if (nn)
+                continue;
+
+#if defined(__STDC__)
+            if (isdigit((unsigned char)*s))
+#else  /* !defined(__STDC__) */
+            if (isascii(*s) && isdigit((unsigned char)*s))
+#endif /* defined(__STDC__) */
+
+                uid = (uid * 10) + *s - '0';
+            else
+                nn++;
+        }
+        if (*s)
+            s++;
+        if (j)
+            continue;
+        if (nn) {
+            lnm[lnml++] = '\0';
+            if ((pw = getpwnam(lnm)) == NULL) {
+                (void)fprintf(stderr, "%s: can't get UID for ", Pn);
+                safestrprt(lnm, stderr, 1);
+                err = 1;
+                continue;
+            } else
+                uid = pw->pw_uid;
+        }
+
+#if defined(HASSECURITY) && !defined(HASNOSOCKSECURITY)
+        /*
+         * If the security mode is enabled, only the root user may list files
+         * belonging to user IDs other than the real user ID of this lsof
+         * process.  If HASNOSOCKSECURITY is also defined, then anyone may
+         * list anyone else's socket files.
+         */
+        if (Myuid && uid != Myuid) {
+            (void)fprintf(
+                stderr,
+                "%s: ID %d request rejected because of security mode.\n", Pn,
+                uid);
+            err = 1;
+            continue;
+        }
+#endif /* defined(HASSECURITY)  && !defined(HASNOSOCKSECURITY) */
+
+        if (nn) {
+            if (lsof_select_login(ctx, lnm, excl)) {
+                Error(ctx);
+                return (1);
+            }
+        } else {
+            if (lsof_select_uid(ctx, uid, excl)) {
+                Error(ctx);
+                return (1);
+            }
+        }
+    }
+    return (err);
+}
+
+/*
+ * isIPv4addr() - is host name an IPv4 address
+ */
+
+static char *isIPv4addr(char *hn,         /* host name */
+                        unsigned char *a, /* address receptor */
+                        int al)           /* address receptor length */
+{
+    int dc = 0;          /* dot count */
+    int i;               /* temorary index */
+    int ov[MIN_AF_ADDR]; /* octet values */
+    int ovx = 0;         /* ov[] index */
+                         /*
+                          * The host name must begin with a number and the return octet value
+                          * arguments must be acceptable.
+                          */
+    if ((*hn < '0') || (*hn > '9'))
+        return ((char *)NULL);
+    if (!a || (al < MIN_AF_ADDR))
+        return ((char *)NULL);
+    /*
+     * Start the first octet assembly, then parse tge remainder of the host
+     * name for four octets, separated by dots.
+     */
+    ov[0] = (int)(*hn++ - '0');
+    while (*hn && (*hn != ':')) {
+        if (*hn == '.') {
+
+            /*
+             * Count a dot.  Make sure a preceding octet value has been
+             * assembled.  Don't assemble more than MIN_AF_ADDR octets.
+             */
+            dc++;
+            if ((ov[ovx] < 0) || (ov[ovx] > 255))
+                return ((char *)NULL);
+            if (++ovx > (MIN_AF_ADDR - 1))
+                return ((char *)NULL);
+            ov[ovx] = -1;
+        } else if ((*hn >= '0') && (*hn <= '9')) {
+
+            /*
+             * Assemble an octet.
+             */
+            if (ov[ovx] < 0)
+                ov[ovx] = (int)(*hn - '0');
+            else
+                ov[ovx] = (ov[ovx] * 10) + (int)(*hn - '0');
+        } else {
+
+            /*
+             * A non-address character has been detected.
+             */
+            return ((char *)NULL);
+        }
+        hn++;
+    }
+    /*
+     * Make sure there were three dots and four non-null octets.
+     */
+    if ((dc != 3) || (ovx != (MIN_AF_ADDR - 1)) || (ov[ovx] < 0) ||
+        (ov[ovx] > 255))
+        return ((char *)NULL);
+    /*
+     * Copy the octets as unsigned characters and return the ending host name
+     * character position.
+     */
+    for (i = 0; i < MIN_AF_ADDR; i++) {
+        a[i] = (unsigned char)ov[i];
+    }
+    return (hn);
+}
+
+/*
+ * lkup_hostnm() - look up host name
+ */
+
+static struct hostent *
+lkup_hostnm(char *hn,       /* host name */
+            struct nwad *n) /* network address destination */
+{
+    unsigned char *ap;
+    struct hostent *he;
+    int ln;
+    /*
+     * Get hostname structure pointer.  Return NULL if there is none.
+     */
+
+#if defined(HASIPv6)
+    he = gethostbyname2(hn, n->af);
+#else  /* !defined(HASIPv6) */
+    he = gethostbyname(hn);
+#endif /* defined(HASIPv6) */
+
+    if (!he || !he->h_addr)
+        return (he);
+        /*
+         * Copy first hostname structure address to destination structure.
+         */
+
+#if defined(HASIPv6)
+    if (n->af != he->h_addrtype)
+        return ((struct hostent *)NULL);
+    if (n->af == AF_INET6) {
+
+        /*
+         * Copy an AF_INET6 address.
+         */
+        if (he->h_length > MAX_AF_ADDR)
+            return ((struct hostent *)NULL);
+        (void)memcpy((void *)&n->a[0], (void *)he->h_addr, he->h_length);
+        if ((ln = MAX_AF_ADDR - he->h_length) > 0)
+            zeromem((char *)&n->a[he->h_length], ln);
+        return (he);
+    }
+#endif /* defined(HASIPv6) */
+
+    /*
+     * Copy an AF_INET address.
+     */
+    if (he->h_length != 4)
+        return ((struct hostent *)NULL);
+    ap = (unsigned char *)he->h_addr;
+    n->a[0] = *ap++;
+    n->a[1] = *ap++;
+    n->a[2] = *ap++;
+    n->a[3] = *ap;
+    if ((ln = MAX_AF_ADDR - 4) > 0)
+        zeromem((char *)&n->a[4], ln);
+    return (he);
+}
diff --git a/src/cli.h b/src/cli.h
new file mode 100644 (file)
index 0000000..8c9dfdd
--- /dev/null
+++ b/src/cli.h
@@ -0,0 +1,37 @@
+/*
+ * cli.h - header file for lsof cli
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#if !defined(CLI_H)
+#    define CLI_H
+
+#    include "lsof.h"
+#    include "proto.h"
+
+#endif
\ No newline at end of file
diff --git a/src/dialects/linux/dprint.c b/src/dialects/linux/dprint.c
new file mode 100644 (file)
index 0000000..f8d8422
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * dprint.c - Linux printing 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.
+ */
+
+#include "common.h"
+#include "cli.h"
+
+#if defined(HASSOSTATE)
+#    include <linux/net.h> /* for SS_* */
+#endif                     /* defined(HASSOSTATE) */
+
+#if defined(HASSOSTATE)
+static char *socket_state_to_str(struct lsof_context *ctx, unsigned int ss);
+#endif /* defined(HASSOSTATE) */
+
+/*
+ * print_unix() - print state of UNIX domain socket e.g. UNCONNECTED
+ */
+static void print_unix(struct lsof_context *ctx, int nl) {
+    if (Ftcptpi & TCPTPI_STATE) {
+#if defined(HASSOSTATE) && defined(HASSOOPT)
+        char *cp = (Lf->lts.opt == __SO_ACCEPTCON)
+                       ? "LISTEN"
+                       : socket_state_to_str(ctx, Lf->lts.ss);
+
+        if (Ffield)
+            (void)printf("%cST=%s%c", LSOF_FID_TCPTPI, cp, Terminator);
+        else {
+            putchar('(');
+            (void)fputs(cp, stdout);
+            putchar(')');
+        }
+#endif /* defined(HASSOSTATE) && defined(HASSOOPT) */
+    }
+    if (nl)
+        putchar('\n');
+}
+
+/*
+ * print_tcptpi() - print TCP/TPI state e.g. ESTBALISHED
+ */
+void print_tcptpi(struct lsof_context *ctx, /* context */
+                  int nl)                   /* 1 == '\n' required */
+{
+    char buf[128];
+    char *cp = (char *)NULL;
+    int ps = 0;
+    int s;
+
+    if (Lf->type == LSOF_FILE_UNIX) {
+        print_unix(ctx, nl);
+        return;
+    }
+    if ((Ftcptpi & TCPTPI_STATE) && Lf->lts.type == 0) {
+        if (!TcpSt)
+            (void)build_IPstates(ctx);
+        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');
+}
+
+#if defined(HASSOSTATE)
+/*
+ * socket_state_to_str() -- convert socket state number to a string
+ *
+ * returns "UNKNOWN" for unknown state.
+ */
+static char *socket_state_to_str(struct lsof_context *ctx, unsigned int ss) {
+    char *sr;
+    switch (Lf->lts.ss) {
+    case SS_UNCONNECTED:
+        sr = "UNCONNECTED";
+        break;
+    case SS_CONNECTING:
+        sr = "CONNECTING";
+        break;
+    case SS_CONNECTED:
+        sr = "CONNECTED";
+        break;
+    case SS_DISCONNECTING:
+        sr = "DISCONNECTING";
+        break;
+    default:
+        sr = "UNKNOWN";
+        break;
+    }
+    return sr;
+}
+#endif /* defined(HASSOSTATE) */
\ No newline at end of file
diff --git a/src/main.c b/src/main.c
new file mode 100644 (file)
index 0000000..9dff66f
--- /dev/null
@@ -0,0 +1,1956 @@
+/*
+ * main.c - common main function for lsof
+ *
+ * V. Abell, Purdue University
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#include "common.h"
+#include "cli.h"
+
+/*
+ * Local definitions
+ */
+
+static int GObk[] = {1, 1};      /* option backspace values */
+static char GOp;                 /* option prefix -- '+' or '-' */
+static char *GOv = (char *)NULL; /* option `:' value pointer */
+static int GOx1 = 1;             /* first opt[][] index */
+static int GOx2 = 0;             /* second opt[][] index */
+
+static int GetOpt(struct lsof_context *ctx, int ct, char *opt[], char *rules,
+                  int *err);
+static char *sv_fmt_str(struct lsof_context *ctx, char *f);
+
+/*
+ * main() - main function for lsof
+ */
+
+int main(int argc, char *argv[]) {
+    enum ExitStatus rv;
+    int gopt_rv;
+    int ad, c, i, n, se1, se2, ss;
+    char *cp;
+    int err = 0;
+    enum ExitStatus ev = LSOF_EXIT_SUCCESS;
+    int fh = 0;
+    char *fmtr = (char *)NULL;
+    long l;
+    MALLOC_S len;
+    struct lfile *lf;
+    struct nwad *np, *npn;
+    char options[128];
+    int rc = 0;
+    struct stat sb;
+    struct sfile *sfp;
+    struct lproc **slp = (struct lproc **)NULL;
+    int sp = 0;
+    struct str_lst *str, *strt;
+    int version = 0;
+    int xover = 0;
+    int pr_count = 0;
+    /** liblsof context */
+    struct lsof_context *ctx = NULL;
+
+#if defined(HAS_STRFTIME)
+    char *fmt = (char *)NULL;
+    size_t fmtl = (size_t)0;
+#endif /* defined(HAS_STRFTIME) */
+
+#if defined(HASZONES)
+    znhash_t *zp;
+#endif /* defined(HASZONES) */
+
+#if defined(HASSELINUX)
+    /*
+     * This stanza must be immediately before the "Save progam name." code,
+     * since it contains code itself.
+     */
+    cntxlist_t *cntxp;
+
+    CntxStatus = is_selinux_enabled() ? 1 : 0;
+#endif /* defined(HASSELINUX) */
+
+    /* Initialize lsof context */
+    ctx = lsof_new();
+
+    /*
+     * Save program name.
+     */
+    if ((Pn = strrchr(argv[0], '/')))
+        Pn++;
+    else
+        Pn = argv[0];
+    lsof_set_output_stream(ctx, stderr, Pn, 0);
+
+    /*
+     * Close enough file descriptors above 2 that library functions will have
+     * open descriptors.
+     *
+     * Make sure stderr, stdout, and stdin are open descriptors.  Open /dev/null
+     * for ones that aren't.  Be terse.
+     *
+     * Make sure umask allows lsof to define its own file permissions.
+     */
+
+    if ((MaxFd = (int)GET_MAX_FD()) < 53)
+        MaxFd = 53;
+
+    closefrom_shim(ctx, 3);
+
+    while (((i = open("/dev/null", O_RDWR, 0)) >= 0) && (i < 2))
+        ;
+    if (i < 0)
+        Error(ctx);
+    if (i > 2)
+        (void)close(i);
+    (void)umask(0);
+
+#if defined(HASSETLOCALE)
+    /*
+     * Set locale to environment's definition.
+     */
+    (void)setlocale(LC_CTYPE, "");
+#endif /* defined(HASSETLOCALE) */
+
+    /*
+     * Common initialization.
+     */
+    Mypid = getpid();
+    if ((Mygid = (gid_t)getgid()) != getegid())
+        Setgid = 1;
+    Euid = geteuid();
+    if ((Myuid = (uid_t)getuid()) && !Euid)
+        Setuidroot = 1;
+    /*
+     * Create option mask.
+     */
+    (void)snpf(options, sizeof(options),
+               "?a%sbc:%sD:d:%s%sf:F:g:hHi:%s%slL:%s%snNo:Op:QPr:%ss:S:tT:u:"
+               "UvVwx:%s%s%s",
+
+#if defined(HAS_AFS) && defined(HASAOPT)
+               "A:",
+#else  /* !defined(HAS_AFS) || !defined(HASAOPT) */
+               "",
+#endif /* defined(HAS_AFS) && defined(HASAOPT) */
+
+#if defined(HASNCACHE)
+               "C",
+#else  /* !defined(HASNCACHE) */
+               "",
+#endif /* defined(HASNCACHE) */
+
+#if defined(HASEOPT)
+               "e:",
+#else  /* !defined(HASEOPT) */
+               "",
+#endif /* defined(HASEOPT) */
+
+#if defined(HASEPTOPTS)
+               "E",
+#else  /* !defined(HASEPTOPTS) */
+               "",
+#endif /* defined(HASEPTOPTS) */
+
+#if defined(HASKOPT)
+               "k:",
+#else  /* !defined(HASKOPT) */
+               "",
+#endif /* defined(HASKOPT) */
+
+#if defined(HASTASKS)
+               "K:",
+#else  /* !defined(HASTASKS) */
+               "",
+#endif /* defined(HASTASKS) */
+
+#if defined(HASMOPT) || defined(HASMNTSUP)
+               "m:",
+#else  /* !defined(HASMOPT) && !defined(HASMNTSUP) */
+               "",
+#endif /* defined(HASMOPT) || defined(HASMNTSUP) */
+
+#if defined(HASNORPC_H)
+               "",
+#else  /* !defined(HASNORPC_H) */
+               "M",
+#endif /* defined(HASNORPC_H) */
+
+#if defined(HASPPID)
+               "R",
+#else  /* !defined(HASPPID) */
+               "",
+#endif /* defined(HASPPID) */
+
+#if defined(HASXOPT)
+#    if defined(HASXOPT_ROOT)
+               (Myuid == 0) ? "X" : "",
+#    else  /* !defined(HASXOPT_ROOT) */
+               "X",
+#    endif /* defined(HASXOPT_ROOT) */
+#else      /* !defined(HASXOPT) */
+               "",
+#endif     /* defined(HASXOPT) */
+
+#if defined(HASZONES)
+               "z:",
+#else  /* !defined(HASZONES) */
+               "",
+#endif /* defined(HASZONES) */
+
+#if defined(HASSELINUX)
+               "Z:"
+#else  /* !defined(HASSELINUX) */
+               ""
+#endif /* defined(HASSELINUX) */
+
+    );
+    /*
+     * Loop through options.
+     */
+    while ((c = GetOpt(ctx, argc, argv, options, &gopt_rv)) != EOF) {
+        if (gopt_rv) {
+            err = 1;
+            continue;
+        }
+        switch (c) {
+        case 'a':
+            Fand = 1;
+            break;
+
+#if defined(HAS_AFS) && defined(HASAOPT)
+        case 'A':
+            if (!GOv || *GOv == '-' || *GOv == '+') {
+                (void)fprintf(stderr, "%s: -A not followed by path\n", Pn);
+                err = 1;
+                if (GOv) {
+                    GOx1 = GObk[0];
+                    GOx2 = GObk[1];
+                }
+            } else
+                AFSApath = GOv;
+            break;
+#endif /* defined(HAS_AFS) && defined(HASAOPT) */
+
+        case 'b':
+            lsof_avoid_blocking(ctx, 1);
+            break;
+        case 'c':
+            if (GOp == '+') {
+                if (!GOv || (*GOv == '-') || (*GOv == '+') ||
+                    !isdigit((int)*GOv)) {
+                    (void)fprintf(stderr,
+                                  "%s: +c not followed by width number\n", Pn);
+                    err = 1;
+                    if (GOv) {
+                        GOx1 = GObk[0];
+                        GOx2 = GObk[1];
+                    }
+                } else {
+                    CmdLim = TaskCmdLim = atoi(GOv);
+
+#if defined(MAXSYSCMDL)
+                    if (CmdLim > MAXSYSCMDL) {
+                        (void)fprintf(stderr,
+                                      "%s: +c %d > what system provides (%d)\n",
+                                      Pn, CmdLim, MAXSYSCMDL);
+                        err = 1;
+                    }
+#endif /* defined(MAXSYSCMDL) */
+                }
+                break;
+            }
+            if (GOv && (*GOv == '/')) {
+                if (lsof_select_process_regex(ctx, GOv))
+                    err = 1;
+            } else {
+                if (enter_cmd(ctx, "-c", GOv))
+                    err = 1;
+            }
+            break;
+
+#if defined(HASNCACHE)
+        case 'C':
+            Fncache = (GOp == '-') ? 0 : 1;
+            break;
+
+#endif /* defined(HASNCACHE) */
+        case 'd':
+            if (GOp == '+') {
+                if (enter_dir(ctx, GOv, 0))
+                    err = 1;
+                else {
+                    Selflags |= SELNM;
+                    xover = 1;
+                }
+            } else {
+                if (enter_fd(ctx, GOv))
+                    err = 1;
+            }
+            break;
+        case 'D':
+            if (GOp == '+') {
+                if (enter_dir(ctx, GOv, 1))
+                    err = 1;
+                else {
+                    Selflags |= SELNM;
+                    xover = 1;
+                }
+            } else {
+
+#if defined(HASDCACHE)
+                if (ctrl_dcache(ctx, GOv))
+                    err = 1;
+#else  /* !defined(HASDCACHE) */
+                (void)fprintf(stderr, "%s: unsupported option: -D\n", Pn);
+                err = 1;
+#endif /* defined(HASDCACHE) */
+            }
+            break;
+
+#if defined(HASEOPT)
+        case 'e':
+            if (enter_efsys(ctx, GOv, ((GOp == '+') ? 1 : 0)))
+                err = 1;
+            break;
+#endif /* defined(HASEOPT) */
+
+#if defined(HASEPTOPTS)
+        case 'E':
+            FeptE = (GOp == '+') ? 2 : 1;
+            break;
+#endif /* defined(HASEPTOPTS) */
+
+        case 'f':
+            if (!GOv || *GOv == '-' || *GOv == '+') {
+                Ffilesys = (GOp == '+') ? 2 : 1;
+                if (GOv) {
+                    GOx1 = GObk[0];
+                    GOx2 = GObk[1];
+                }
+                break;
+            }
+
+#if defined(HASFSTRUCT)
+            for (; *GOv; GOv++) {
+                switch (*GOv) {
+
+#    if !defined(HASNOFSCOUNT)
+                case 'c':
+                case 'C':
+                    if (GOp == '+') {
+                        Fsv |= FSV_CT;
+                        FsvByf = 1;
+                    } else
+                        Fsv &= (unsigned char)~FSV_CT;
+                    break;
+#    endif /* !defined(HASNOFSCOUNT) */
+
+#    if !defined(HASNOFSADDR)
+                case 'f':
+                case 'F':
+                    if (GOp == '+') {
+                        Fsv |= FSV_FA;
+                        FsvByf = 1;
+                    } else
+                        Fsv &= (unsigned char)~FSV_FA;
+                    break;
+#    endif /* !defined(HASNOFSADDR) */
+
+#    if !defined(HASNOFSFLAGS)
+                case 'g':
+                case 'G':
+                    if (GOp == '+') {
+                        Fsv |= FSV_FG;
+                        FsvByf = 1;
+                    } else
+                        Fsv &= (unsigned char)~FSV_FG;
+                    FsvFlagX = (*GOv == 'G') ? 1 : 0;
+                    break;
+#    endif /* !defined(HASNOFSFLAGS) */
+
+#    if !defined(HASNOFSNADDR)
+                case 'n':
+                case 'N':
+                    if (GOp == '+') {
+                        Fsv |= FSV_NI;
+                        FsvByf = 1;
+                    } else
+                        Fsv &= (unsigned char)~FSV_NI;
+                    break;
+#    endif /* !defined(HASNOFSNADDR */
+
+                default:
+                    (void)fprintf(stderr,
+                                  "%s: unknown file struct option: %c\n", Pn,
+                                  *GOv);
+                    err++;
+                }
+            }
+#else  /* !defined(HASFSTRUCT) */
+            (void)fprintf(stderr, "%s: unknown string for %cf: %s\n", Pn, GOp,
+                          GOv);
+            err++;
+#endif /* defined(HASFSTRUCT) */
+
+            break;
+        case 'F':
+            if (!GOv || *GOv == '-' || *GOv == '+' || strcmp(GOv, "0") == 0) {
+                if (GOv) {
+                    if (*GOv == '-' || *GOv == '+') {
+                        GOx1 = GObk[0];
+                        GOx2 = GObk[1];
+                    } else if (*GOv == '0')
+                        Terminator = '\0';
+                }
+                for (i = 0; FieldSel[i].nm; i++) {
+
+#if !defined(HASPPID)
+                    if (FieldSel[i].id == LSOF_FID_PPID)
+                        continue;
+#endif /* !defined(HASPPID) */
+
+#if !defined(HASTASKS)
+                    if (FieldSel[i].id == LSOF_FID_TCMD)
+                        continue;
+#endif /* !defined(HASTASKS) */
+
+#if !defined(HASFSTRUCT)
+                    if (FieldSel[i].id == LSOF_FID_CT ||
+                        FieldSel[i].id == LSOF_FID_FA ||
+                        FieldSel[i].id == LSOF_FID_FG ||
+                        FieldSel[i].id == LSOF_FID_NI)
+                        continue;
+#endif /* !defined(HASFSTRUCT) */
+
+#if defined(HASSELINUX)
+                    if ((FieldSel[i].id == LSOF_FID_CNTX) && !CntxStatus)
+                        continue;
+#else  /* !defined(HASSELINUX) */
+                    if (FieldSel[i].id == LSOF_FID_CNTX)
+                        continue;
+#endif /* !defined(HASSELINUX) */
+
+                    if (FieldSel[i].id == LSOF_FID_RDEV)
+                        continue; /* for compatibility */
+
+#if !defined(HASTASKS)
+                    if (FieldSel[i].id == LSOF_FID_TID)
+                        continue;
+#endif /* !defined(HASTASKS) */
+
+#if !defined(HASZONES)
+                    if (FieldSel[i].id == LSOF_FID_ZONE)
+                        continue;
+#endif /* !defined(HASZONES) */
+
+                    FieldSel[i].st = 1;
+                    if (FieldSel[i].opt && FieldSel[i].ov)
+                        *(FieldSel[i].opt) |= FieldSel[i].ov;
+                }
+
+#if defined(HASFSTRUCT)
+                Ffield = FsvFlagX = 1;
+#else  /* !defined(HASFSTRUCT) */
+                Ffield = 1;
+#endif /* defined(HASFSTRUCT) */
+
+                break;
+            }
+            if (strcmp(GOv, "?") == 0) {
+                fh = 1;
+                break;
+            }
+            for (; *GOv; GOv++) {
+                for (i = 0; FieldSel[i].nm; i++) {
+
+#if !defined(HASPPID)
+                    if (FieldSel[i].id == LSOF_FID_PPID)
+                        continue;
+#endif /* !defined(HASPPID) */
+
+#if !defined(HASTASKS)
+                    if (FieldSel[i].id == LSOF_FID_TCMD)
+                        continue;
+#endif /* !defined(HASTASKS) */
+
+#if !defined(HASFSTRUCT)
+                    if (FieldSel[i].id == LSOF_FID_CT ||
+                        FieldSel[i].id == LSOF_FID_FA ||
+                        FieldSel[i].id == LSOF_FID_FG ||
+                        FieldSel[i].id == LSOF_FID_NI)
+                        continue;
+#endif /* !defined(HASFSTRUCT) */
+
+#if !defined(HASTASKS)
+                    if (FieldSel[i].id == LSOF_FID_TID)
+                        continue;
+#endif /* !defined(HASTASKS) */
+
+                    if (FieldSel[i].id == *GOv) {
+                        FieldSel[i].st = 1;
+                        if (FieldSel[i].opt && FieldSel[i].ov)
+                            *(FieldSel[i].opt) |= FieldSel[i].ov;
+
+#if defined(HASFSTRUCT)
+                        if (i == LSOF_FIX_FG)
+                            FsvFlagX = 1;
+#endif /* defined(HASFSTRUCT) */
+
+                        if (i == LSOF_FIX_TERM)
+                            Terminator = '\0';
+
+                        if (i == LSOF_FIX_OFFSET)
+                            Foffset = 1;
+
+                        break;
+                    }
+                }
+                if (!FieldSel[i].nm) {
+                    (void)fprintf(stderr, "%s: unknown field: %c\n", Pn, *GOv);
+                    err++;
+                }
+            }
+            Ffield = 1;
+            break;
+        case 'g':
+            if (GOv) {
+                if (*GOv == '-' || *GOv == '+') {
+                    GOx1 = GObk[0];
+                    GOx2 = GObk[1];
+                } else if (enter_id(ctx, PGID, GOv))
+                    err = 1;
+            }
+            Fpgid = 1;
+            break;
+        case 'H':
+            Fhuman = 1;
+            break;
+        case 'h':
+        case '?':
+            Fhelp = 1;
+            break;
+        case 'i':
+            if (!GOv || *GOv == '-' || *GOv == '+') {
+                Fnet = 1;
+                FnetTy = 0;
+                if (GOv) {
+                    GOx1 = GObk[0];
+                    GOx2 = GObk[1];
+                }
+                break;
+            }
+            if (enter_network_address(ctx, GOv))
+                err = 1;
+            break;
+
+#if defined(HASKOPT)
+        case 'k':
+            if (!GOv || *GOv == '-' || *GOv == '+') {
+                (void)fprintf(stderr, "%s: -k not followed by path\n", Pn);
+                err = 1;
+                if (GOv) {
+                    GOx1 = GObk[0];
+                    GOx2 = GObk[1];
+                }
+            } else
+                Nmlst = GOv;
+            break;
+#endif /* defined(HASKOPT) */
+
+#if defined(HASTASKS)
+        case 'K':
+            if (!GOv || *GOv == '-' || *GOv == '+') {
+                Ftask = 1;
+                IgnTasks = 0;
+                Selflags |= SELTASK;
+                if (GOv) {
+                    GOx1 = GObk[0];
+                    GOx2 = GObk[1];
+                }
+            } else {
+                if (!strcasecmp(GOv, "i")) {
+                    Ftask = 0;
+                    IgnTasks = 1;
+                    Selflags &= ~SELTASK;
+                } else {
+                    (void)fprintf(stderr,
+                                  "%s: -K not followed by i (but by %s)\n", Pn,
+                                  GOv);
+                    err = 1;
+                }
+            }
+            break;
+#endif /* defined(HASTASKS) */
+
+        case 'l':
+            Futol = 0;
+            break;
+        case 'L':
+            Fnlink = (GOp == '+') ? 1 : 0;
+            if (!GOv || *GOv == '-' || *GOv == '+') {
+                Nlink = 0l;
+                if (GOv) {
+                    GOx1 = GObk[0];
+                    GOx2 = GObk[1];
+                }
+                break;
+            }
+            for (cp = GOv, l = 0l, n = 0; *cp; cp++) {
+                if (!isdigit((unsigned char)*cp))
+                    break;
+                l = (l * 10l) + ((long)*cp - (long)'0');
+                n++;
+            }
+            if (n) {
+                if (GOp != '+') {
+                    (void)fprintf(stderr, "%s: no number may follow -L\n", Pn);
+                    err = 1;
+                } else {
+                    Nlink = l;
+                    Selflags |= SELNLINK;
+                }
+            } else
+                Nlink = 0l;
+            if (*cp) {
+                GOx1 = GObk[0];
+                GOx2 = GObk[1] + n;
+            }
+            break;
+
+#if defined(HASMOPT) || defined(HASMNTSUP)
+        case 'm':
+            if (GOp == '-') {
+
+#    if defined(HASMOPT)
+                if (!GOv || *GOv == '-' || *GOv == '+') {
+                    (void)fprintf(stderr, "%s: -m not followed by path\n", Pn);
+                    err = 1;
+                    if (GOv) {
+                        GOx1 = GObk[0];
+                        GOx2 = GObk[1];
+                    }
+                } else
+                    Memory = GOv;
+#    else  /* !defined(HASMOPT) */
+                (void)fprintf(stderr, "%s: -m not supported\n", Pn);
+                err = 1;
+#    endif /* defined(HASMOPT) */
+
+            } else if (GOp == '+') {
+
+#    if defined(HASMNTSUP)
+                if (!GOv || *GOv == '-' || *GOv == '+') {
+                    MntSup = 1;
+                    if (GOv) {
+                        GOx1 = GObk[0];
+                        GOx2 = GObk[1];
+                    }
+                } else {
+                    MntSup = 2;
+                    MntSupP = GOv;
+                }
+#    else  /* !defined(HASMNTSUP) */
+                (void)fprintf(stderr, "%s: +m not supported\n", Pn);
+                err = 1;
+#    endif /* defined(HASMNTSUP) */
+
+            } else {
+                (void)fprintf(stderr, "%s: %cm not supported\n", Pn, GOp);
+                err = 1;
+            }
+            break;
+#endif /* defined(HASMOPT) || defined(HASMNTSUP) */
+
+#if !defined(HASNORPC_H)
+        case 'M':
+            FportMap = (GOp == '+') ? 1 : 0;
+            break;
+#endif /* !defined(HASNORPC_H) */
+
+        case 'n':
+            Fhost = (GOp == '-') ? 0 : 1;
+            break;
+        case 'N':
+            Fnfs = 1;
+            break;
+        case 'o':
+            if (!GOv || *GOv == '-' || *GOv == '+') {
+                Foffset = 1;
+                if (GOv) {
+                    GOx1 = GObk[0];
+                    GOx2 = GObk[1];
+                }
+                break;
+            }
+            for (cp = GOv, i = n = 0; *cp; cp++) {
+                if (!isdigit((unsigned char)*cp))
+                    break;
+                i = (i * 10) + ((int)*cp - '0');
+                n++;
+            }
+            if (n)
+                OffDecDig = i;
+            else
+                Foffset = 1;
+            if (*cp) {
+                GOx1 = GObk[0];
+                GOx2 = GObk[1] + n;
+            }
+            break;
+        case 'O':
+            lsof_avoid_forking(ctx, (GOp == '-') ? 1 : 0);
+            break;
+        case 'p':
+            if (enter_id(ctx, PID, GOv))
+                err = 1;
+            break;
+        case 'Q':
+            FsearchErr = 0;
+            break;
+        case 'P':
+            Fport = (GOp == '-') ? 0 : 1;
+            break;
+        case 'r':
+            if (GOp == '+') {
+                ev = LSOF_EXIT_ERROR;
+                rc = 1;
+            }
+            if (!GOv || *GOv == '-' || *GOv == '+') {
+                RptTm = RPTTM;
+                if (GOv) {
+                    GOx1 = GObk[0];
+                    GOx2 = GObk[1];
+                }
+                break;
+            }
+            for (cp = GOv, i = n = 0; *cp; cp++) {
+                if (!isdigit((unsigned char)*cp))
+                    break;
+                i = (i * 10) + ((int)*cp - '0');
+                n++;
+            }
+            if (n)
+                RptTm = i;
+            else
+                RptTm = RPTTM;
+            if (!*cp)
+                break;
+            while (*cp && (*cp == ' '))
+                cp++;
+
+            if (*cp == 'c') {
+                cp++;
+                for (i = 0; *cp && isdigit((unsigned char)*cp); cp++)
+                    i = (i * 10) + ((int)*cp - '0');
+                RptMaxCount = i;
+            }
+
+            if (*cp != LSOF_FID_MARK) {
+                GOx1 = GObk[0];
+                GOx2 = GObk[1] + n;
+                break;
+            }
+
+#if defined(HAS_STRFTIME)
+
+            /*
+             * Collect the strftime(3) format and test it.
+             */
+            cp++;
+            if ((fmtl = strlen(cp) + 1) < 1) {
+                (void)fprintf(stderr, "%s: <fmt> too short: \"%s\"\n", Pn, cp);
+                err = 1;
+            } else {
+                fmt = cp;
+                fmtl = (fmtl * 8) + 1;
+                if (!(fmtr = (char *)malloc((MALLOC_S)fmtl))) {
+                    (void)fprintf(
+                        stderr, "%s: no space (%d) for <fmt> result: \"%s\"\n",
+                        Pn, (int)fmtl, cp);
+                    Error(ctx);
+                }
+                if (util_strftime(fmtr, fmtl - 1, fmt) < 1) {
+                    (void)fprintf(stderr, "%s: illegal <fmt>: \"%s\"\n", Pn,
+                                  fmt);
+                    err = 1;
+                }
+            }
+
+#else  /* !defined(HAS_STRFTIME) */
+            (void)fprintf(stderr, "%s: m<fmt> not supported: \"%s\"\n", Pn, cp);
+            err = 1;
+#endif /* defined(HAS_STRFTIME) */
+
+            break;
+
+#if defined(HASPPID)
+        case 'R':
+            Fppid = 1;
+            break;
+#endif /* defined(HASPPID) */
+
+        case 's':
+
+#if defined(HASTCPUDPSTATE)
+            if (!GOv || *GOv == '-' || *GOv == '+') {
+                Fsize = 1;
+                if (GOv) {
+                    GOx1 = GObk[0];
+                    GOx2 = GObk[1];
+                }
+            } else {
+                if (enter_state_spec(ctx, GOv))
+                    err = 1;
+            }
+#else  /* !defined(HASTCPUDPSTATE) */
+            Fsize = 1;
+#endif /* defined(HASTCPUDPSTATE) */
+
+            break;
+        case 'S':
+            if (!GOv || *GOv == '-' || *GOv == '+') {
+                TmLimit = TMLIMIT;
+                if (GOv) {
+                    GOx1 = GObk[0];
+                    GOx2 = GObk[1];
+                }
+                break;
+            }
+            for (cp = GOv, i = n = 0; *cp; cp++) {
+                if (!isdigit((unsigned char)*cp))
+                    break;
+                i = (i * 10) + ((int)*cp - '0');
+                n++;
+            }
+            if (n)
+                TmLimit = i;
+            else
+                TmLimit = TMLIMIT;
+            if (*cp) {
+                GOx1 = GObk[0];
+                GOx2 = GObk[1] + n;
+            }
+            if (TmLimit < TMLIMMIN) {
+                (void)fprintf(stderr,
+                              "%s: WARNING: -S time (%d) changed to %d\n", Pn,
+                              TmLimit, TMLIMMIN);
+                TmLimit = TMLIMMIN;
+            }
+            break;
+        case 't':
+            Fterse = Fwarn = 1;
+            break;
+        case 'T':
+            if (!GOv || *GOv == '-' || *GOv == '+') {
+                Ftcptpi = (GOp == '-') ? 0 : TCPTPI_STATE;
+                if (GOv) {
+                    GOx1 = GObk[0];
+                    GOx2 = GObk[1];
+                }
+                break;
+            }
+            for (Ftcptpi = 0; *GOv; GOv++) {
+                switch (*GOv) {
+
+#if defined(HASSOOPT) || defined(HASSOSTATE) || defined(HASTCPOPT)
+                case 'f':
+                    Ftcptpi |= TCPTPI_FLAGS;
+                    break;
+#endif /* defined(HASSOOPT) || defined(HASSOSTATE) || defined(HASTCPOPT) */
+
+#if defined(HASTCPTPIQ)
+                case 'q':
+                    Ftcptpi |= TCPTPI_QUEUES;
+                    break;
+#endif /* defined(HASTCPTPIQ) */
+
+                case 's':
+                    Ftcptpi |= TCPTPI_STATE;
+                    break;
+
+#if defined(HASTCPTPIW)
+                case 'w':
+                    Ftcptpi |= TCPTPI_WINDOWS;
+                    break;
+#endif /* defined(HASTCPTPIW) */
+
+                default:
+                    (void)fprintf(
+                        stderr, "%s: unsupported TCP/TPI info selection: %c\n",
+                        Pn, *GOv);
+                    err = 1;
+                }
+            }
+            break;
+        case 'u':
+            if (enter_uid(ctx, GOv))
+                err = 1;
+            break;
+        case 'U':
+            Funix = 1;
+            break;
+        case 'v':
+            version = 1;
+            break;
+        case 'V':
+            Fverbose = 1;
+            break;
+        case 'w':
+            Fwarn = (GOp == '+') ? 0 : 1;
+            break;
+        case 'x':
+            if (!GOv || *GOv == '-' || *GOv == '+') {
+                Fxover = XO_ALL;
+                if (GOv) {
+                    GOx1 = GObk[0];
+                    GOx2 = GObk[1];
+                }
+                break;
+            } else {
+                for (; *GOv; GOv++) {
+                    switch (*GOv) {
+                    case 'f':
+                        Fxover |= XO_FILESYS;
+                        break;
+                    case 'l':
+                        Fxover |= XO_SYMLINK;
+                        break;
+                    default:
+                        (void)fprintf(stderr,
+                                      "%s: unknown cross-over option: %c\n", Pn,
+                                      *GOv);
+                        err++;
+                    }
+                }
+            }
+            break;
+
+#if defined(HASXOPT)
+        case 'X':
+            Fxopt = Fxopt ? 0 : 1;
+            break;
+#endif /* defined(HASXOPT) */
+
+#if defined(HASZONES)
+        case 'z':
+            Fzone = 1;
+            if (GOv && (*GOv != '-') && (*GOv != '+')) {
+
+                /*
+                 * Add to the zone name argument hash.
+                 */
+                if (enter_zone_arg(ctx, GOv))
+                    err = 1;
+            } else if (GOv) {
+                GOx1 = GObk[0];
+                GOx2 = GObk[1];
+            }
+            break;
+#endif /* defined(HASZONES) */
+
+#if defined(HASSELINUX)
+        case 'Z':
+            if (!CntxStatus) {
+                (void)fprintf(stderr, "%s: -Z limited to SELinux\n", Pn);
+                err = 1;
+            } else {
+                Fcntx = 1;
+                if (GOv && (*GOv != '-') && (*GOv != '+')) {
+
+                    /*
+                     * Add to the context name argument hash.
+                     */
+                    if (enter_cntx_arg(ctx, GOv))
+                        err = 1;
+                } else if (GOv) {
+                    GOx1 = GObk[0];
+                    GOx2 = GObk[1];
+                }
+            }
+            break;
+#endif /* defined(HASSELINUX) */
+
+        default:
+            (void)fprintf(stderr, "%s: unknown option (%c)\n", Pn, c);
+            err = 1;
+        }
+    }
+    /*
+     * If IgnTasks is set, remove SELTASK from SelAll and SelProc.
+     */
+    SelAll = IgnTasks ? (SELALL & ~SELTASK) : SELALL;
+    SelProc = IgnTasks ? (SELPROC & ~SELTASK) : SELPROC;
+    /*
+     * Check for argument consistency.
+     */
+    if (Cmdnx && Cmdni) {
+
+        /*
+         * Check for command inclusion/exclusion conflicts.
+         */
+        for (str = Cmdl; str; str = str->next) {
+            if (str->x) {
+                for (strt = Cmdl; strt; strt = strt->next) {
+                    if (!strt->x) {
+                        if (!strcmp(str->str, strt->str)) {
+                            (void)fprintf(stderr,
+                                          "%s: -c^%s and -c%s conflict.\n", Pn,
+                                          str->str, strt->str);
+                            err++;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+#if defined(HASTCPUDPSTATE)
+    if (TcpStXn && TcpStIn) {
+
+        /*
+         * Check for excluded and included TCP states.
+         */
+        for (i = 0; i < TcpNstates; i++) {
+            if (TcpStX[i] && TcpStI[i]) {
+                (void)fprintf(stderr,
+                              "%s: can't include and exclude TCP state: %s\n",
+                              Pn, TcpSt[i]);
+                err = 1;
+            }
+        }
+    }
+    if (UdpStXn && UdpStIn) {
+
+        /*
+         * Check for excluded and included UDP states.
+         */
+        for (i = 0; i < UdpNstates; i++) {
+            if (UdpStX[i] && UdpStI[i]) {
+                (void)fprintf(stderr,
+                              "%s: can't include and exclude UDP state: %s\n",
+                              Pn, UdpSt[i]);
+                err = 1;
+            }
+        }
+    }
+#endif /* defined(HASTCPUDPSTATE) */
+
+    if (Fsize && Foffset) {
+        (void)fprintf(stderr, "%s: -o and -s are mutually exclusive\n", Pn);
+        err++;
+    }
+    if (Ffield) {
+        if (Fterse) {
+            (void)fprintf(stderr, "%s: -F and -t are mutually exclusive\n", Pn);
+            err++;
+        }
+        FieldSel[LSOF_FIX_PID].st = 1;
+
+#if defined(HAS_STRFTIME)
+        if (fmtr) {
+
+            /*
+             * The field output marker format can't contain "%n" new line
+             * requests.
+             */
+            for (cp = strchr(fmt, '%'); cp; cp = strchr(cp, '%')) {
+                if (*++cp == 'n') {
+                    (void)fprintf(
+                        stderr, "%s: %%n illegal in -r m<fmt> when -F has", Pn);
+                    (void)fprintf(stderr, " been specified: \"%s\"\n", fmt);
+                    err++;
+                    break;
+                } else if (*cp == '%')
+                    cp++;
+            }
+        }
+#endif /* defined(HAS_STRFTIME) */
+    }
+    if (Fxover && !xover) {
+        (void)fprintf(stderr, "%s: -x must accompany +d or +D\n", Pn);
+        err++;
+    }
+
+#if defined(HASEOPT)
+    if (Efsysl) {
+
+        /*
+         * If there are file systems specified by -e options, check them.
+         */
+        efsys_list_t *ep;        /* Efsysl pointer */
+        struct mounts *mp, *mpw; /* local mount table pointers */
+
+        if ((mp = readmnt(ctx))) {
+            for (ep = Efsysl; ep; ep = ep->next) {
+                for (mpw = mp; mpw; mpw = mpw->next) {
+                    if (!strcmp(mpw->dir, ep->path)) {
+                        ep->mp = mpw;
+                        break;
+                    }
+                }
+                if (!ep->mp) {
+                    (void)fprintf(
+                        stderr, "%s: \"-e %s\" is not a mounted file system.\n",
+                        Pn, ep->path);
+                    err++;
+                }
+            }
+        }
+    }
+#endif /* defined(HASEOPT) */
+
+    if (DChelp || err || Fhelp || fh || version)
+        usage(ctx, err ? 1 : 0, fh, version);
+    /*
+     * Reduce the size of Suid[], if necessary.
+     */
+    if (Suid && Nuid && Nuid < Mxuid) {
+        if (!(Suid = (struct seluid *)realloc(
+                  (MALLOC_P *)Suid,
+                  (MALLOC_S)(sizeof(struct seluid) * Nuid)))) {
+            (void)fprintf(stderr, "%s: can't realloc UID table\n", Pn);
+            Error(ctx);
+        }
+        Mxuid = Nuid;
+    }
+    /*
+     * Compute the selection flags.
+     */
+    if ((Cmdl && Cmdni) || CmdRx)
+        Selflags |= SELCMD;
+
+#if defined(HASSELINUX)
+    if (CntxArg)
+        Selflags |= SELCNTX;
+#endif /* defined(HASSELINUX) */
+
+    if (Fdl)
+        Selflags |= SELFD;
+    if (Fnet)
+        Selflags |= SELNET;
+    if (Fnfs)
+        Selflags |= SELNFS;
+    if (Funix)
+        Selflags |= SELUNX;
+    if (Npgid && Npgidi)
+        Selflags |= SELPGID;
+    if (Npid && Npidi)
+        Selflags |= SELPID;
+    if (Nuid && Nuidincl)
+        Selflags |= SELUID;
+    if (Nwad)
+        Selflags |= SELNA;
+
+#if defined(HASZONES)
+    if (ZoneArg)
+        Selflags |= SELZONE;
+#endif /* defined(HASZONES) */
+
+    if (GOx1 < argc)
+        Selflags |= SELNM;
+    if (Selflags == 0) {
+        if (Fand) {
+            (void)fprintf(stderr, "%s: no select options to AND via -a\n", Pn);
+            usage(ctx, 1, 0, 0);
+        }
+        Selflags = SelAll;
+    } else {
+        if (GOx1 >= argc && (Selflags & (SELNA | SELNET)) != 0 &&
+            (Selflags & ~(SELNA | SELNET)) == 0)
+            Selinet = 1;
+        AllProc = 0;
+    }
+    /*
+     * Get the device for DEVDEV_PATH.
+     */
+    if (stat(DEVDEV_PATH, &sb)) {
+        se1 = errno;
+        if ((ad = strcmp(DEVDEV_PATH, "/dev"))) {
+            if ((ss = stat("/dev", &sb)))
+                se2 = errno;
+            else
+                se2 = 0;
+        } else {
+            se2 = 0;
+            ss = 1;
+        }
+        if (ss) {
+            (void)fprintf(stderr, "%s: can't stat(%s): %s\n", Pn, DEVDEV_PATH,
+                          strerror(se1));
+            if (ad) {
+                (void)fprintf(stderr, "%s: can't stat(/dev): %s\n", Pn,
+                              strerror(se2));
+            }
+            Error(ctx);
+        }
+    }
+    DevDev = sb.st_dev;
+    /*
+     * Process the file arguments.
+     */
+    if (GOx1 < argc) {
+        if (ck_file_arg(ctx, GOx1, argc, argv, Ffilesys, 0, (struct stat *)NULL,
+                        FsearchErr == 0))
+            Error(ctx);
+    }
+    /*
+     * Do dialect-specific initialization.
+     */
+    initialize(ctx);
+#if defined(LINUX_LSOF_H)
+    if (Fsv && (OffType != OFFSET_FDINFO)) {
+        if (!Fwarn && FsvByf)
+            (void)fprintf(
+                stderr,
+                "%s: WARNING: can't report file flags; disregarding +f.\n", Pn);
+        Fsv = 0;
+    }
+#endif
+    if (Sfile)
+        (void)hashSfile(ctx);
+
+#if defined(WILLDROPGID)
+    /*
+     * If this process isn't setuid(root), but it is setgid(not_real_gid),
+     * relinquish the setgid power.  (If it hasn't already been done.)
+     */
+    (void)dropgid(ctx);
+#endif /* defined(WILLDROPGID) */
+
+#if defined(HASDCACHE)
+    /*
+     * If there is a device cache, prepare the device table.
+     */
+    if (DCstate)
+        readdev(ctx, 0);
+#endif /* defined(HASDCACHE) */
+
+    /*
+     * Define the size and offset print formats.
+     */
+    (void)snpf(options, sizeof(options), "%%%su", INODEPSPEC);
+    InodeFmt_d = sv_fmt_str(ctx, options);
+    (void)snpf(options, sizeof(options), "%%#%sx", INODEPSPEC);
+    InodeFmt_x = sv_fmt_str(ctx, options);
+    (void)snpf(options, sizeof(options), "0t%%%su", SZOFFPSPEC);
+    SzOffFmt_0t = sv_fmt_str(ctx, options);
+    (void)snpf(options, sizeof(options), "%%%su", SZOFFPSPEC);
+    SzOffFmt_d = sv_fmt_str(ctx, options);
+    (void)snpf(options, sizeof(options), "%%*%su", SZOFFPSPEC);
+    SzOffFmt_dv = sv_fmt_str(ctx, options);
+    (void)snpf(options, sizeof(options), "%%#%sx", SZOFFPSPEC);
+    SzOffFmt_x = sv_fmt_str(ctx, options);
+
+#if defined(HASMNTSUP)
+    /*
+     * Report mount supplement information, as requested.
+     */
+    if (MntSup == 1) {
+        (void)readmnt(ctx);
+        Exit(ctx, LSOF_EXIT_SUCCESS);
+    }
+#endif /* defined(HASMNTSUP) */
+
+    /*
+     * Gather and report process information every RptTm seconds.
+     */
+    if (RptTm)
+        CkPasswd = 1;
+    do {
+
+        /*
+         * Gather information about processes.
+         */
+        gather_proc_info(ctx);
+        /*
+         * If the local process table has more than one entry, sort it by PID.
+         */
+        if (Nlproc > 1) {
+            if (Nlproc > sp) {
+                len = (MALLOC_S)(Nlproc * sizeof(struct lproc *));
+                sp = Nlproc;
+                if (!slp)
+                    slp = (struct lproc **)malloc(len);
+                else
+                    slp = (struct lproc **)realloc((MALLOC_P *)slp, len);
+                if (!slp) {
+                    (void)fprintf(stderr, "%s: no space for %d sort pointers\n",
+                                  Pn, Nlproc);
+                    Error(ctx);
+                }
+            }
+            for (i = 0; i < Nlproc; i++) {
+                slp[i] = &Lproc[i];
+            }
+            (void)qsort((QSORT_P *)slp, (size_t)Nlproc,
+                        (size_t)sizeof(struct lproc *), comppid);
+        }
+        if ((n = Nlproc)) {
+
+#if defined(HASNCACHE)
+            /*
+             * If using the kernel name cache, force its reloading.
+             */
+            NcacheReload = 1;
+#endif /* defined(HASNCACHE) */
+
+#if defined(HASEPTOPTS)
+            /*
+             * If endpoint info has been requested, make sure it is coded for
+             * printing.
+             *
+             * Lf contents must be preserved, since they may point to a
+             * malloc()'d area, and since Lf is used throughout the printing
+             * of the selected processes.
+             */
+            if (FeptE) {
+                lf = Lf;
+                /*
+                 * Scan all selected processes.
+                 */
+                for (i = 0; i < Nlproc; i++) {
+                    Lp = (Nlproc > 1) ? slp[i] : &Lproc[i];
+
+                    /*
+                     * For processes that have been selected for printing
+                     * and have files that are the end point(s) of pipe(s),
+                     * process the file endpoints.
+                     */
+                    if (Lp->pss && (Lp->ept & EPT_PIPE))
+                        (void)process_pinfo(ctx, 0);
+                    /*
+                     * Process POSIX MQ endpoints.
+                     */
+                    if (Lp->ept & EPT_PSXMQ)
+                        (void)process_psxmqinfo(ctx, 0);
+
+#    if defined(HASUXSOCKEPT)
+                    /*
+                     * For processes that have been selected for printing
+                     * and have files that are the end point(s) of UNIX
+                     * socket(s), process the file endpoints.
+                     */
+                    if (Lp->pss && (Lp->ept & EPT_UXS))
+                        (void)process_uxsinfo(ctx, 0);
+#    endif /* defined(HASUXSOCKEPT) */
+
+#    if defined(HASPTYEPT)
+                    /*
+                     * For processes that have been selected for printing
+                     * and have files that are the end point(s) of pseudo-
+                     * terminal files(s), process the file endpoints.
+                     */
+                    if (Lp->pss && (Lp->ept & EPT_PTY))
+                        (void)process_ptyinfo(ctx, 0);
+#    endif /* defined(HASPTYEPT) */
+
+                    /*
+                     * Process INET socket endpoints.
+                     */
+                    if (Lp->ept & EPT_NETS)
+                        (void)process_netsinfo(ctx, 0);
+
+#    if defined(HASIPv6)
+                    /*
+                     * Process INET6 socket endpoints.
+                     */
+                    if (Lp->ept & EPT_NETS6)
+                        (void)process_nets6info(ctx, 0);
+#    endif /* defined(HASIPv6) */
+                    /*
+                     * Process eventfd endpoints.
+                     */
+                    if (Lp->ept & EPT_EVTFD)
+                        (void)process_evtfdinfo(ctx, 0);
+                }
+                /*
+                 * In a second pass, look for unselected endpoint files,
+                 * possibly selecting them for printing.
+                 */
+                for (i = 0; i < Nlproc; i++) {
+                    Lp = (Nlproc > 1) ? slp[i] : &Lproc[i];
+
+                    /*
+                     * Process pipe endpoints.
+                     */
+                    if (Lp->ept & EPT_PIPE_END)
+                        (void)process_pinfo(ctx, 1);
+                    /*
+                     * Process POSIX MQ endpoints.
+                     */
+                    if (Lp->ept & EPT_PSXMQ_END)
+                        (void)process_psxmqinfo(ctx, 1);
+
+#    if defined(HASUXSOCKEPT)
+                    /*
+                     * Process UNIX socket endpoints.
+                     */
+                    if (Lp->ept & EPT_UXS_END)
+                        (void)process_uxsinfo(ctx, 1);
+#    endif /* defined(HASUXSOCKEPT) */
+
+#    if defined(HASPTYEPT)
+                    /*
+                     * Process pseudo-terminal endpoints.
+                     */
+                    if (Lp->ept & EPT_PTY_END)
+                        (void)process_ptyinfo(ctx, 1);
+#    endif /* defined(HASPTYEPT) */
+
+                    /*
+                     * Process INET socket endpoints.
+                     */
+                    if (Lp->ept & EPT_NETS_END)
+                        (void)process_netsinfo(ctx, 1);
+
+#    if defined(HASIPv6)
+                    /*
+                     * Process INET6 socket endpoints.
+                     */
+                    if (Lp->ept & EPT_NETS6_END)
+                        (void)process_nets6info(ctx, 1);
+#    endif /* defined(HASIPv6) */
+
+                    /*
+                     * Process envetfd endpoints.
+                     */
+                    if (Lp->ept & EPT_EVTFD_END)
+                        (void)process_evtfdinfo(ctx, 1);
+                }
+                Lf = lf;
+            }
+#endif /* defined(HASEPTOPTS) */
+
+            /*
+             * Print the selected processes and count them.
+             *
+             * Lf contents must be preserved, since they may point to a
+             * malloc()'d area, and since Lf is used throughout the print
+             * process.
+             */
+            for (lf = Lf, print_init(ctx); PrPass < 2; PrPass++) {
+                for (i = n = 0; i < Nlproc; i++) {
+                    Lp = (Nlproc > 1) ? slp[i] : &Lproc[i];
+                    if (Lp->pss) {
+                        if (print_proc(ctx))
+                            n++;
+                    }
+                    if (RptTm && PrPass)
+                        (void)free_lproc(Lp);
+                }
+            }
+            Lf = lf;
+        }
+        /*
+         * If a repeat time is set, sleep for the specified time.
+         *
+         * If conditional repeat mode is in effect, see if it's time to exit.
+         */
+        if (RptTm) {
+
+#if defined(HASEPTOPTS)
+            (void)clear_pinfo(ctx);
+
+            (void)clear_psxmqinfo(ctx);
+
+#    if defined(HASUXSOCKEPT)
+            (void)clear_uxsinfo(ctx);
+#    endif /* defined(HASUXSOCKEPT) */
+
+#    if defined(HASPTYEPT)
+            (void)clear_ptyinfo(ctx);
+#    endif /* defined(HASPTYEPT) */
+
+            (void)clear_netsinfo(ctx);
+
+#    if defined(HASIPv6)
+            (void)clear_nets6info(ctx);
+#    endif /* defined(HASIPv6) */
+
+            (void)clear_evtfdinfo(ctx);
+#endif /* defined(HASEPTOPTS) */
+
+            if (rc) {
+                if (!n)
+                    break;
+                else
+                    ev = LSOF_EXIT_SUCCESS;
+            }
+
+#if defined(HAS_STRFTIME)
+            if (fmt && fmtr) {
+
+                /*
+                 * Format the marker line.
+                 */
+                (void)util_strftime(fmtr, fmtl - 1, fmt);
+                fmtr[fmtl - 1] = '\0';
+            }
+#endif /* defined(HAS_STRFTIME) */
+
+            if (Ffield) {
+                putchar(LSOF_FID_MARK);
+
+#if defined(HAS_STRFTIME)
+                if (fmtr)
+                    (void)printf("%s", fmtr);
+#endif /* defined(HAS_STRFTIME) */
+
+                putchar(Terminator);
+                if (Terminator != '\n')
+                    putchar('\n');
+            } else {
+
+#if defined(HAS_STRFTIME)
+                if (fmtr)
+                    cp = fmtr;
+                else
+#endif /* defined(HAS_STRFTIME) */
+
+                    cp = "=======";
+                puts(cp);
+            }
+            (void)fflush(stdout);
+            (void)childx(ctx);
+            (void)sleep(RptTm);
+            Hdr = Nlproc = 0;
+            CkPasswd = 1;
+        }
+        if (RptMaxCount && (++pr_count == RptMaxCount))
+            RptTm = 0;
+    } while (RptTm);
+    /*
+     * See if all requested information was displayed.  Return zero if it
+     * was; one, if not.  If -V was specified, report what was not displayed.
+     */
+    (void)childx(ctx);
+    rv = LSOF_EXIT_SUCCESS;
+    for (str = Cmdl; str; str = str->next) {
+
+        /*
+         * Check command specifications.
+         */
+        if (str->f)
+            continue;
+        rv = LSOF_SEARCH_FAILURE;
+        if (Fverbose) {
+            (void)printf("%s: command not located: ", Pn);
+            safestrprt(str->str, stdout, 1);
+        }
+    }
+    for (i = 0; i < NCmdRxU; i++) {
+
+        /*
+         * Check command regular expressions.
+         */
+        if (CmdRx[i].mc)
+            continue;
+        rv = LSOF_SEARCH_FAILURE;
+        if (Fverbose) {
+            (void)printf("%s: no command found for regex: ", Pn);
+            safestrprt(CmdRx[i].exp, stdout, 1);
+        }
+    }
+    for (sfp = Sfile; sfp; sfp = sfp->next) {
+
+        /*
+         * Check file specifications.
+         */
+        if (sfp->f)
+            continue;
+        rv = LSOF_SEARCH_FAILURE;
+        if (Fverbose) {
+            (void)printf("%s: no file%s use located: ", Pn,
+                         sfp->type ? "" : " system");
+            safestrprt(sfp->aname, stdout, 1);
+        }
+    }
+
+#if defined(HASPROCFS)
+    /*
+     * Report on proc file system search results.
+     */
+    if (Procsrch && !Procfind) {
+        rv = LSOF_SEARCH_FAILURE;
+        if (Fverbose) {
+            (void)printf("%s: no file system use located: ", Pn);
+            safestrprt(Mtprocfs ? Mtprocfs->dir : HASPROCFS, stdout, 1);
+        }
+    }
+    {
+        struct procfsid *pfi;
+
+        for (pfi = Procfsid; pfi; pfi = pfi->next) {
+            if (!pfi->f) {
+                rv = LSOF_SEARCH_FAILURE;
+                if (Fverbose) {
+                    (void)printf("%s: no file use located: ", Pn);
+                    safestrprt(pfi->nm, stdout, 1);
+                }
+            }
+        }
+    }
+#endif /* defined(HASPROCFS) */
+
+    if ((np = Nwad)) {
+
+        /*
+         * Check Internet address specifications.
+         *
+         * If any Internet address derived from the same argument was found,
+         * consider all derivations found.  If no derivation from the same
+         * argument was found, report only the first failure.
+         *
+         */
+        for (; np; np = np->next) {
+            if (!(cp = np->arg))
+                continue;
+            for (npn = np->next; npn; npn = npn->next) {
+                if (!npn->arg)
+                    continue;
+                if (!strcmp(cp, npn->arg)) {
+
+                    /*
+                     * If either of the duplicate specifications was found,
+                     * mark them both found.  If neither was found, mark all
+                     * but the first one found.
+                     */
+                    if (np->f)
+                        npn->f = np->f;
+                    else if (npn->f)
+                        np->f = npn->f;
+                    else
+                        npn->f = 1;
+                }
+            }
+        }
+        for (np = Nwad; np; np = np->next) {
+            if (!np->f && (cp = np->arg)) {
+                rv = LSOF_SEARCH_FAILURE;
+                if (Fverbose) {
+                    (void)printf("%s: Internet address not located: ", Pn);
+                    safestrprt(cp ? cp : "(unknown)", stdout, 1);
+                }
+            }
+        }
+    }
+    if (Fnet && Fnet < 2) {
+
+        /*
+         * Report no Internet files located.
+         */
+        rv = LSOF_SEARCH_FAILURE;
+        if (Fverbose)
+            (void)printf("%s: no Internet files located\n", Pn);
+    }
+
+#if defined(HASTCPUDPSTATE)
+    if (TcpStIn) {
+
+        /*
+         * Check for included TCP states not located.
+         */
+        for (i = 0; i < TcpNstates; i++) {
+            if (TcpStI[i] == 1) {
+                rv = LSOF_SEARCH_FAILURE;
+                if (Fverbose)
+                    (void)printf("%s: TCP state not located: %s\n", Pn,
+                                 TcpSt[i]);
+            }
+        }
+    }
+    if (UdpStIn) {
+
+        /*
+         * Check for included UDP states not located.
+         */
+        for (i = 0; i < UdpNstates; i++) {
+            if (UdpStI[i] == 1) {
+                rv = LSOF_SEARCH_FAILURE;
+                if (Fverbose)
+                    (void)printf("%s: UDP state not located: %s\n", Pn,
+                                 UdpSt[i]);
+            }
+        }
+    }
+#endif /* defined(HASTCPUDPSTATE) */
+
+    if (Fnfs && Fnfs < 2) {
+
+        /*
+         * Report no NFS files located.
+         */
+        rv = LSOF_SEARCH_FAILURE;
+        if (Fverbose)
+            (void)printf("%s: no NFS files located\n", Pn);
+    }
+    for (i = 0; i < Npid; i++) {
+
+        /*
+         * Check inclusionary process ID specifications.
+         */
+        if (Spid[i].f || Spid[i].x)
+            continue;
+        rv = LSOF_SEARCH_FAILURE;
+        if (Fverbose)
+            (void)printf("%s: process ID not located: %d\n", Pn, Spid[i].i);
+    }
+
+#if defined(HASTASKS)
+    if (Ftask && Ftask < 2) {
+
+        /*
+         * Report no tasks located.
+         */
+        rv = LSOF_SEARCH_FAILURE;
+        if (Fverbose)
+            (void)printf("%s: no tasks located\n", Pn);
+    }
+#endif /* defined(HASTASKS) */
+
+#if defined(HASZONES)
+    if (ZoneArg) {
+
+        /*
+         * Check zone argument results.
+         */
+        for (i = 0; i < HASHZONE; i++) {
+            for (zp = ZoneArg[i]; zp; zp = zp->next) {
+                if (!zp->f) {
+                    rv = LSOF_SEARCH_FAILURE;
+                    if (Fverbose) {
+                        (void)printf("%s: zone not located: ", Pn);
+                        safestrprt(zp->zn, stdout, 1);
+                    }
+                }
+            }
+        }
+    }
+#endif /* defined(HASZONES) */
+
+#if defined(HASSELINUX)
+    if (CntxArg) {
+
+        /*
+         * Check context argument results.
+         */
+        for (cntxp = CntxArg; cntxp; cntxp = cntxp->next) {
+            if (!cntxp->f) {
+                rv = LSOF_SEARCH_FAILURE;
+                if (Fverbose) {
+                    (void)printf("%s: context not located: ", Pn);
+                    safestrprt(cntxp->cntx, stdout, 1);
+                }
+            }
+        }
+    }
+#endif /* defined(HASSELINUX) */
+
+    for (i = 0; i < Npgid; i++) {
+
+        /*
+         * Check inclusionary process group ID specifications.
+         */
+        if (Spgid[i].f || Spgid[i].x)
+            continue;
+        rv = LSOF_SEARCH_FAILURE;
+        if (Fverbose)
+            (void)printf("%s: process group ID not located: %d\n", Pn,
+                         Spgid[i].i);
+    }
+    for (i = 0; i < Nuid; i++) {
+
+        /*
+         * Check inclusionary user ID specifications.
+         */
+        if (Suid[i].excl || Suid[i].f)
+            continue;
+        rv = LSOF_SEARCH_FAILURE;
+        if (Fverbose) {
+            if (Suid[i].lnm) {
+                (void)printf("%s: login name (UID %lu) not located: ", Pn,
+                             (unsigned long)Suid[i].uid);
+                safestrprt(Suid[i].lnm, stdout, 1);
+            } else
+                (void)printf("%s: user ID not located: %lu\n", Pn,
+                             (unsigned long)Suid[i].uid);
+        }
+    }
+    if (!rv && rc)
+        rv = ev;
+    if (!rv && ErrStat)
+        rv = LSOF_EXIT_ERROR;
+    Exit(ctx, rv);
+    return (rv); /* to make code analyzers happy */
+}
+
+/*
+ * GetOpt() -- Local get option
+ *
+ * Liberally adapted from the public domain AT&T getopt() source,
+ * distributed at the 1985 UNIFORM conference in Dallas
+ *
+ * The modifications allow `?' to be an option character and allow
+ * the caller to decide that an option that may be followed by a
+ * value doesn't have one -- e.g., has a default instead.
+ */
+
+static int GetOpt(struct lsof_context *ctx, /* context */
+                  int ct,                   /* option count */
+                  char *opt[],              /* options */
+                  char *rules,              /* option rules */
+                  int *err)                 /* error return */
+{
+    register int c;
+    register char *cp = (char *)NULL;
+
+    if (GOx2 == 0) {
+
+        /*
+         * Move to a new entry of the option array.
+         *
+         * EOF if:
+         *
+         *     Option list has been exhausted;
+         *     Next option doesn't start with `-' or `+';
+         *     Next option has nothing but `-' or `+';
+         *     Next option is ``--'' or ``++''.
+         */
+        if (GOx1 >= ct || (opt[GOx1][0] != '-' && opt[GOx1][0] != '+') ||
+            !opt[GOx1][1])
+            return (EOF);
+        if (strcmp(opt[GOx1], "--") == 0 || strcmp(opt[GOx1], "++") == 0) {
+            GOx1++;
+            return (EOF);
+        }
+        GOp = opt[GOx1][0];
+        GOx2 = 1;
+    }
+    /*
+     * Flag `:' option character as an error.
+     *
+     * Check for a rule on this option character.
+     */
+    *err = 0;
+    if ((c = opt[GOx1][GOx2]) == ':') {
+        (void)fprintf(stderr, "%s: colon is an illegal option character.\n",
+                      Pn);
+        *err = 1;
+    } else if (!(cp = strchr(rules, c))) {
+        (void)fprintf(stderr, "%s: illegal option character: %c\n", Pn, c);
+        *err = 2;
+    }
+    if (*err) {
+
+        /*
+         * An error was detected.
+         *
+         * Advance to the next option character.
+         *
+         * Return the character causing the error.
+         */
+        if (opt[GOx1][++GOx2] == '\0') {
+            GOx1++;
+            GOx2 = 0;
+        }
+        return (c);
+    }
+    if (*(cp + 1) == ':') {
+
+        /*
+         * The option may have a following value.  The caller decides
+         * if it does.
+         *
+         * Save the position of the possible value in case the caller
+         * decides it does not belong to the option and wants it
+         * reconsidered as an option character.  The caller does that
+         * with:
+         *             GOx1 = GObk[0]; GOx2 = GObk[1];
+         *
+         * Don't indicate that an option of ``--'' is a possible value.
+         *
+         * Finally, on the assumption that the caller will decide that
+         * the possible value belongs to the option, position to the
+         * option following the possible value, so that the next call
+         * to GetOpt() will find it.
+         */
+        if (opt[GOx1][GOx2 + 1] != '\0') {
+            GObk[0] = GOx1;
+            GObk[1] = ++GOx2;
+            GOv = &opt[GOx1++][GOx2];
+        } else if (++GOx1 >= ct)
+            GOv = (char *)NULL;
+        else {
+            GObk[0] = GOx1;
+            GObk[1] = 0;
+            GOv = opt[GOx1];
+            if (strcmp(GOv, "--") == 0)
+                GOv = (char *)NULL;
+            else
+                GOx1++;
+        }
+        GOx2 = 0;
+    } else {
+
+        /*
+         * The option character stands alone with no following value.
+         *
+         * Advance to the next option character.
+         */
+        if (opt[GOx1][++GOx2] == '\0') {
+            GOx2 = 0;
+            GOx1++;
+        }
+        GOv = (char *)NULL;
+    }
+    /*
+     * Return the option character.
+     */
+    return (c);
+}
+
+/*
+ * sv_fmt_str() - save format string
+ */
+
+static char *sv_fmt_str(struct lsof_context *ctx, char *f) /* format string */
+{
+    char *cp;
+    MALLOC_S l;
+
+    l = (MALLOC_S)(strlen(f) + 1);
+    if (!(cp = (char *)malloc(l))) {
+        (void)fprintf(stderr, "%s: can't allocate %d bytes for format: %s\n",
+                      Pn, (int)l, f);
+        Error(ctx);
+    }
+    (void)snpf(cp, l, "%s", f);
+    return (cp);
+}
diff --git a/src/print.c b/src/print.c
new file mode 100644 (file)
index 0000000..494f9eb
--- /dev/null
@@ -0,0 +1,2137 @@
+/*
+ * print.c - common print support functions for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#include "common.h"
+#include "cli.h"
+#include "proto.h"
+
+/*
+ * Local definitions, structures and function prototypes
+ */
+
+#define HCINC 64 /* host cache size increase chunk */
+#define PORTHASHBUCKETS                                                        \
+    128 /* port hash bucket count                                              \
+         * !!MUST BE A POWER OF 2!! */
+#define PORTTABTHRESH                                                          \
+    10 /* threshold at which we will switch                                    \
+        * from using getservbyport() to                                        \
+        * getservent() -- see lkup_port()                                      \
+        * and fill_porttab() */
+
+struct hostcache {
+    unsigned char a[MAX_AF_ADDR]; /* numeric address */
+    int af;                       /* address family -- e.g., AF_INET
+                                   * or AF_INET6 */
+    char *name;                   /* name */
+};
+
+struct porttab {
+    int port;
+    MALLOC_S nl; /* name length (excluding '\0') */
+    int ss;      /* service name status, 0 = lookup not
+                  * yet performed */
+    char *name;
+    struct porttab *next;
+};
+
+#if defined(HASNORPC_H)
+static struct porttab **Pth[2] = {NULL, NULL};
+/* port hash buckets:
+ * Pth[0] for TCP service names
+ * Pth[1] for UDP service names
+ */
+#else  /* !defined(HASNORPC_H) */
+static struct porttab **Pth[4] = {NULL, NULL, NULL, NULL};
+/* port hash buckets:
+ * Pth[0] for TCP service names
+ * Pth[1] for UDP service names
+ * Pth[2] for TCP portmap info
+ * Pth[3] for UDP portmap info
+ */
+#endif /* defined(HASNORPC_H) */
+
+#define HASHPORT(p) (((((int)(p)) * 31415) >> 3) & (PORTHASHBUCKETS - 1))
+
+#if !defined(HASNORPC_H)
+static void fill_portmap(struct lsof_context *ctx);
+static void update_portmap(struct lsof_context *ctx, struct porttab *pt,
+                           char *pn);
+#endif /* !defined(HASNORPC_H) */
+
+static void fill_porttab(struct lsof_context *ctx);
+static char *lkup_port(struct lsof_context *ctx, int p, int pr, int src);
+static char *lkup_svcnam(struct lsof_context *ctx, int h, int p, int pr,
+                         int ss);
+static int printinaddr(struct lsof_context *ctx);
+static int human_readable_size(SZOFFTYPE sz, int print, int col);
+
+#if !defined(HASNORPC_H)
+/*
+ * fill_portmap() -- fill the RPC portmap program name table via a conversation
+ *                  with the portmapper
+ *
+ * The following copyright notice acknowledges that this function was adapted
+ * from getrpcportnam() of the source code of the OpenBSD netstat program.
+ */
+
+/*
+ * Copyright (c) 1983, 1988, 1993
+ *      The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by the University of
+ *      California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+static void fill_portmap(struct lsof_context *ctx) {
+    static int already_run = 0;
+    char buf[128], *cp, *nm;
+    CLIENT *c;
+    int h, port, pr;
+    MALLOC_S nl;
+    struct pmaplist *p = (struct pmaplist *)NULL;
+    struct porttab *pt;
+    struct rpcent *r;
+    struct TIMEVAL_LSOF tm;
+
+#    if !defined(CAN_USE_CLNT_CREATE)
+    struct hostent *he;
+    struct sockaddr_in ia;
+    int s = RPC_ANYSOCK;
+#    endif /* !defined(CAN_USE_CLNT_CREATE) */
+
+    /*
+     * Make sure this is only run once.
+     */
+    if (already_run)
+        return;
+    already_run = 1;
+
+    /*
+     * Construct structures for communicating with the portmapper.
+     */
+
+#    if !defined(CAN_USE_CLNT_CREATE)
+    zeromem(&ia, sizeof(ia));
+    ia.sin_family = AF_INET;
+    if ((he = gethostbyname("localhost")))
+        MEMMOVE((caddr_t)&ia.sin_addr, he->h_addr, he->h_length);
+    ia.sin_port = htons(PMAPPORT);
+#    endif /* !defined(CAN_USE_CLNT_CREATE) */
+
+    tm.tv_sec = 60;
+    tm.tv_usec = 0;
+    /*
+     * Get an RPC client handle.  Then ask for a dump of the port map.
+     */
+
+#    if defined(CAN_USE_CLNT_CREATE)
+    if (!(c = clnt_create("localhost", PMAPPROG, PMAPVERS, "tcp")))
+#    else  /* !defined(CAN_USE_CLNT_CREATE) */
+    if (!(c = clnttcp_create(&ia, PMAPPROG, PMAPVERS, &s, 0, 0)))
+#    endif /* defined(CAN_USE_CLNT_CREATE) */
+
+        return;
+    if (clnt_call(c, PMAPPROC_DUMP, XDR_VOID, NULL, XDR_PMAPLIST, (caddr_t)&p,
+                  tm) != RPC_SUCCESS) {
+        clnt_destroy(c);
+        return;
+    }
+    /*
+     * Loop through the port map dump, creating portmap table entries from TCP
+     * and UDP members.
+     */
+    for (; p; p = p->pml_next) {
+
+        /*
+         * Determine the port map entry's protocol; ignore all but TCP and UDP.
+         */
+        if (p->pml_map.pm_prot == IPPROTO_TCP)
+            pr = 2;
+        else if (p->pml_map.pm_prot == IPPROTO_UDP)
+            pr = 3;
+        else
+            continue;
+        /*
+         * See if there's already a portmap entry for this port.  If there is,
+         * ignore this entry.
+         */
+        h = HASHPORT((port = (int)p->pml_map.pm_port));
+        for (pt = Pth[pr][h]; pt; pt = pt->next) {
+            if (pt->port == port)
+                break;
+        }
+        if (pt)
+            continue;
+        /*
+         * Save the registration name or number.
+         */
+        cp = (char *)NULL;
+        if ((r = (struct rpcent *)getrpcbynumber(p->pml_map.pm_prog))) {
+            if (r->r_name && strlen(r->r_name))
+                cp = r->r_name;
+        }
+        if (!cp) {
+            (void)snpf(buf, sizeof(buf), "%lu",
+                       (unsigned long)p->pml_map.pm_prog);
+            cp = buf;
+        }
+        if (!strlen(cp))
+            continue;
+        /*
+         * Allocate space for the portmap name entry and copy it there.
+         */
+        if (!(nm = mkstrcpy(cp, &nl))) {
+            (void)fprintf(stderr,
+                          "%s: can't allocate space for portmap entry: ", Pn);
+            safestrprt(cp, stderr, 1);
+            Error(ctx);
+        }
+        if (!nl) {
+            (void)free((FREE_P *)nm);
+            continue;
+        }
+        /*
+         * Allocate and fill a porttab struct entry for the portmap table.
+         * Link it to the head of its hash bucket, and make it the new head.
+         */
+        if (!(pt = (struct porttab *)malloc(sizeof(struct porttab)))) {
+            (void)fprintf(stderr,
+                          "%s: can't allocate porttab entry for portmap: ", Pn);
+            safestrprt(nm, stderr, 1);
+            Error(ctx);
+        }
+        pt->name = nm;
+        pt->nl = nl;
+        pt->port = port;
+        pt->next = Pth[pr][h];
+        pt->ss = 0;
+        Pth[pr][h] = pt;
+    }
+    clnt_destroy(c);
+}
+#endif /* !defined(HASNORPC_H) */
+
+/*
+ * fill_porttab() -- fill the TCP and UDP service name port table with a
+ *                  getservent() scan
+ */
+
+static void fill_porttab(struct lsof_context *ctx) {
+    int h, p, pr;
+    MALLOC_S nl;
+    char *nm;
+    struct porttab *pt;
+    struct servent *se;
+
+    (void)endservent();
+    /*
+     * Scan the services data base for TCP and UDP entries that have a non-null
+     * name associated with them.
+     */
+    (void)setservent(1);
+    while ((se = getservent())) {
+        if (!se->s_name || !se->s_proto)
+            continue;
+        if (strcasecmp(se->s_proto, "TCP") == 0)
+            pr = 0;
+        else if (strcasecmp(se->s_proto, "UDP") == 0)
+            pr = 1;
+        else
+            continue;
+        if (!se->s_name || !strlen(se->s_name))
+            continue;
+        p = ntohs(se->s_port);
+        /*
+         * See if a port->service entry is already cached for this port and
+         * prototcol.  If it is, leave it alone.
+         */
+        h = HASHPORT(p);
+        for (pt = Pth[pr][h]; pt; pt = pt->next) {
+            if (pt->port == p)
+                break;
+        }
+        if (pt)
+            continue;
+        /*
+         * Add a new entry to the cache for this port and protocol.
+         */
+        if (!(nm = mkstrcpy(se->s_name, &nl))) {
+            (void)fprintf(stderr,
+                          "%s: can't allocate %d bytes for port %d name: %s\n",
+                          Pn, (int)(nl + 1), p, se->s_name);
+            Error(ctx);
+        }
+        if (!nl) {
+            (void)free((FREE_P *)nm);
+            continue;
+        }
+        if (!(pt = (struct porttab *)malloc(sizeof(struct porttab)))) {
+            (void)fprintf(stderr,
+                          "%s: can't allocate porttab entry for port %d: %s\n",
+                          Pn, p, se->s_name);
+            Error(ctx);
+        }
+        pt->name = nm;
+        pt->nl = nl - 1;
+        pt->port = p;
+        pt->next = Pth[pr][h];
+        pt->ss = 0;
+        Pth[pr][h] = pt;
+    }
+    (void)endservent();
+}
+
+/*
+ * gethostnm() - get host name
+ */
+
+char *gethostnm(struct lsof_context *ctx, /* context */
+                unsigned char *ia,        /* Internet address */
+                int af)                   /* address family -- e.g., AF_INET
+                                           * or AF_INET6 */
+{
+    int al = MIN_AF_ADDR;
+    char hbuf[256];
+    static struct hostcache *hc = (struct hostcache *)NULL;
+    static int hcx = 0;
+    char *hn, *np;
+    struct hostent *he = (struct hostent *)NULL;
+    int i, j;
+    MALLOC_S len;
+    static int nhc = 0;
+    /*
+     * Search cache.
+     */
+
+#if defined(HASIPv6)
+    if (af == AF_INET6)
+        al = MAX_AF_ADDR;
+#endif /* defined(HASIPv6) */
+
+    for (i = 0; i < hcx; i++) {
+        if (af != hc[i].af)
+            continue;
+        for (j = 0; j < al; j++) {
+            if (ia[j] != hc[i].a[j])
+                break;
+        }
+        if (j >= al)
+            return (hc[i].name);
+    }
+    /*
+     * If -n has been specified, construct a numeric address.  Otherwise, look
+     * up host name by address.  If that fails, or if there is no name in the
+     * returned hostent structure, construct a numeric version of the address.
+     */
+    if (Fhost)
+        he = gethostbyaddr((char *)ia, al, af);
+    if (!he || !he->h_name) {
+
+#if defined(HASIPv6)
+        if (af == AF_INET6) {
+
+            /*
+             * Since IPv6 numeric addresses use `:' as a separator, enclose
+             * them in brackets.
+             */
+            hbuf[0] = '[';
+            if (!inet_ntop(af, ia, hbuf + 1, sizeof(hbuf) - 3)) {
+                (void)snpf(&hbuf[1], (sizeof(hbuf) - 1),
+                           "can't format IPv6 address]");
+            } else {
+                len = strlen(hbuf);
+                (void)snpf(&hbuf[len], sizeof(hbuf) - len, "]");
+            }
+        } else
+#endif /* defined(HASIPv6) */
+
+            if (af == AF_INET)
+                (void)snpf(hbuf, sizeof(hbuf), "%u.%u.%u.%u", ia[0], ia[1],
+                           ia[2], ia[3]);
+            else
+                (void)snpf(hbuf, sizeof(hbuf), "(unknown AF value: %d)", af);
+        hn = hbuf;
+    } else
+        hn = (char *)he->h_name;
+    /*
+     * Allocate space for name and copy name to it.
+     */
+    if (!(np = mkstrcpy(hn, (MALLOC_S *)NULL))) {
+        (void)fprintf(stderr, "%s: no space for host name: ", Pn);
+        safestrprt(hn, stderr, 1);
+        Error(ctx);
+    }
+    /*
+     * Add address/name entry to cache.  Allocate cache space in HCINC chunks.
+     */
+    if (hcx >= nhc) {
+        nhc += HCINC;
+        len = (MALLOC_S)(nhc * sizeof(struct hostcache));
+        if (!hc)
+            hc = (struct hostcache *)malloc(len);
+        else
+            hc = (struct hostcache *)realloc((MALLOC_P *)hc, len);
+        if (!hc) {
+            (void)fprintf(stderr, "%s: no space for host cache\n", Pn);
+            Error(ctx);
+        }
+    }
+    hc[hcx].af = af;
+    for (i = 0; i < al; i++) {
+        hc[hcx].a[i] = ia[i];
+    }
+    hc[hcx++].name = np;
+    return (np);
+}
+
+/*
+ * lkup_port() - look up port for protocol
+ */
+
+static char *lkup_port(struct lsof_context *ctx, /* context */
+                       int p,                    /* port number */
+                       int pr,  /* protocol index: 0 = tcp, 1 = udp */
+                       int src) /* port source: 0 = local
+                                 *             1 = foreign */
+{
+    int h, nh;
+    MALLOC_S nl;
+    char *nm, *pn;
+    static char pb[128];
+    struct porttab *pt;
+    /*
+     * If the hash buckets haven't been allocated, do so.
+     */
+    if (!Pth[0]) {
+
+#if defined(HASNORPC_H)
+        nh = 2;
+#else  /* !defined(HASNORPC_H) */
+        nh = FportMap ? 4 : 2;
+#endif /* defined(HASNORPC_H) */
+
+        for (h = 0; h < nh; h++) {
+            if (!(Pth[h] = (struct porttab **)calloc(
+                      PORTHASHBUCKETS, sizeof(struct porttab *)))) {
+                (void)fprintf(
+                    stderr,
+                    "%s: can't allocate %d bytes for %s %s hash buckets\n", Pn,
+                    (int)(2 * (PORTHASHBUCKETS * sizeof(struct porttab *))),
+                    (h & 1) ? "UDP" : "TCP", (h > 1) ? "portmap" : "port");
+                Error(ctx);
+            }
+        }
+    }
+
+#if !defined(HASNORPC_H)
+    /*
+     * If we're looking up program names for portmapped ports, make sure the
+     * portmap table has been loaded.
+     */
+    if (FportMap)
+        (void)fill_portmap(ctx);
+#endif /* !defined(HASNORPC_H) */
+
+    /*
+     * Hash the port and see if its name has been cached.  Look for a local
+     * port first in the portmap, if portmap searching is enabled.
+     */
+    h = HASHPORT(p);
+
+#if !defined(HASNORPC_H)
+    if (!src && FportMap) {
+        for (pt = Pth[pr + 2][h]; pt; pt = pt->next) {
+            if (pt->port != p)
+                continue;
+            if (!pt->ss) {
+                pn = Fport ? lkup_svcnam(ctx, h, p, pr, 0) : (char *)NULL;
+                if (!pn) {
+                    (void)snpf(pb, sizeof(pb), "%d", p);
+                    pn = pb;
+                }
+                (void)update_portmap(ctx, pt, pn);
+            }
+            return (pt->name);
+        }
+    }
+#endif /* !defined(HASNORPC_H) */
+
+    for (pt = Pth[pr][h]; pt; pt = pt->next) {
+        if (pt->port == p)
+            return (pt->name);
+    }
+    /*
+     * Search for a possible service name, unless the -P option has been
+     * specified.
+     *
+     * If there is no service name, return a %d conversion.
+     *
+     * Don't cache %d conversions; a zero port number is a %d conversion that
+     * is represented by "*".
+     */
+    pn = Fport ? lkup_svcnam(ctx, h, p, pr, 1) : (char *)NULL;
+    if (!pn || !strlen(pn)) {
+        if (p) {
+            (void)snpf(pb, sizeof(pb), "%d", p);
+            return (pb);
+        } else
+            return ("*");
+    }
+    /*
+     * Allocate a new porttab entry for the TCP or UDP service name.
+     */
+    if (!(pt = (struct porttab *)malloc(sizeof(struct porttab)))) {
+        (void)fprintf(stderr, "%s: can't allocate porttab entry for port %d\n",
+                      Pn, p);
+        Error(ctx);
+    }
+    /*
+     * Allocate space for the name; copy it to the porttab entry; and link the
+     * porttab entry to its hash bucket.
+     *
+     * Return a pointer to the name.
+     */
+    if (!(nm = mkstrcpy(pn, &nl))) {
+        (void)fprintf(stderr, "%s: can't allocate space for port name: ", Pn);
+        safestrprt(pn, stderr, 1);
+        Error(ctx);
+    }
+    pt->name = nm;
+    pt->nl = nl;
+    pt->port = p;
+    pt->next = Pth[pr][h];
+    pt->ss = 0;
+    Pth[pr][h] = pt;
+    return (nm);
+}
+
+/*
+ * lkup_svcnam() - look up service name for port
+ */
+
+static char *lkup_svcnam(struct lsof_context *ctx, /* context */
+                         int h,                    /* porttab hash index */
+                         int p,                    /* port number */
+                         int pr, /* protocol: 0 = TCP, 1 = UDP */
+                         int ss) /* search status: 1 = Pth[pr][h]
+                                  *              already searched */
+{
+    static int fl[PORTTABTHRESH];
+    static int fln = 0;
+    static int gsbp = 0;
+    int i;
+    struct porttab *pt;
+    static int ptf = 0;
+    struct servent *se;
+    /*
+     * Do nothing if -P has been specified.
+     */
+    if (!Fport)
+        return ((char *)NULL);
+
+    for (;;) {
+
+        /*
+         * Search service name cache, if it hasn't already been done.
+         * Return the name of a match.
+         */
+        if (!ss) {
+            for (pt = Pth[pr][h]; pt; pt = pt->next) {
+                if (pt->port == p)
+                    return (pt->name);
+            }
+        }
+        /*
+         * If fill_porttab() has been called, there is no service name.
+         *
+         * Do PORTTABTHRES getservbport() calls, remembering the failures, so
+         * they won't be repeated.
+         *
+         * After PORTABTHRESH getservbyport() calls, call fill_porttab() once,
+         */
+        if (ptf)
+            break;
+        if (gsbp < PORTTABTHRESH) {
+            for (i = 0; i < fln; i++) {
+                if (fl[i] == p)
+                    return ((char *)NULL);
+            }
+            gsbp++;
+            if ((se = getservbyport(htons(p), pr ? "udp" : "tcp")))
+                return (se->s_name);
+            if (fln < PORTTABTHRESH)
+                fl[fln++] = p;
+            return ((char *)NULL);
+        }
+        (void)fill_porttab(ctx);
+        ptf++;
+        ss = 0;
+    }
+    return ((char *)NULL);
+}
+
+/*
+ * print_file() - print file
+ */
+
+void print_file(struct lsof_context *ctx) {
+    char buf[128];
+    char *cp = (char *)NULL;
+    dev_t dev;
+    int devs, len;
+    char access;
+    char lock;
+    char fd[FDLEN];
+    char type[TYPEL];
+
+    if (PrPass && !Hdr) {
+
+        /*
+         * Print the header line if this is the second pass and the
+         * header hasn't already been printed.
+         */
+        (void)printf("%-*.*s %*s", CmdColW, CmdColW, CMDTTL, PidColW, PIDTTL);
+
+#if defined(HASTASKS)
+        if (TaskPrtTid)
+            (void)printf(" %*s", TaskTidColW, TASKTIDTTL);
+        if (TaskPrtCmd)
+            (void)printf(" %-*.*s", TaskCmdColW, TaskCmdColW, TASKCMDTTL);
+#endif /* defined(HASTASKS) */
+
+#if defined(HASZONES)
+        if (Fzone)
+            (void)printf(" %-*s", ZoneColW, ZONETTL);
+#endif /* defined(HASZONES) */
+
+#if defined(HASSELINUX)
+        if (Fcntx)
+            (void)printf(" %-*s", CntxColW, CNTXTTL);
+#endif /* defined(HASSELINUX) */
+
+#if defined(HASPPID)
+        if (Fppid)
+            (void)printf(" %*s", PpidColW, PPIDTTL);
+#endif /* defined(HASPPID) */
+
+        if (Fpgid)
+            (void)printf(" %*s", PgidColW, PGIDTTL);
+        (void)printf(" %*s %*s   %*s", UserColW, USERTTL, FdColW - 2, FDTTL,
+                     TypeColW, TYPETTL);
+
+#if defined(HASFSTRUCT)
+        if (Fsv) {
+
+#    if !defined(HASNOFSADDR)
+            if (Fsv & FSV_FA)
+                (void)printf(" %*s", FsColW, FSTTL);
+#    endif /* !defined(HASNOFSADDR) */
+
+#    if !defined(HASNOFSCOUNT)
+            if (Fsv & FSV_CT)
+                (void)printf(" %*s", FcColW, FCTTL);
+#    endif /* !defined(HASNOFSCOUNT) */
+
+#    if !defined(HASNOFSFLAGS)
+            if (Fsv & FSV_FG)
+                (void)printf(" %*s", FgColW, FGTTL);
+#    endif /* !defined(HASNOFSFLAGS) */
+
+#    if !defined(HASNOFSNADDR)
+            if (Fsv & FSV_NI)
+                (void)printf(" %*s", NiColW, NiTtl);
+#    endif /* !defined(HASNOFSNADDR) */
+        }
+#endif /* defined(HASFSTRUCT) */
+
+        (void)printf(" %*s", DevColW, DEVTTL);
+        if (Foffset)
+            (void)printf(" %*s", SzOffColW, OFFTTL);
+        else if (Fsize)
+            (void)printf(" %*s", SzOffColW, SZTTL);
+        else
+            (void)printf(" %*s", SzOffColW, SZOFFTTL);
+        if (Fnlink)
+            (void)printf(" %*s", NlColW, NLTTL);
+        (void)printf(" %*s %s\n", NodeColW, NODETTL, NMTTL);
+        Hdr++;
+    }
+    /*
+     * Size or print the command.
+     *
+     * CAUTION: command can be empty, see issue #246,
+     * use NULL to represent failure instead of empty string
+     */
+    cp = Lp->cmd ? Lp->cmd : "(unknown)";
+    if (!PrPass) {
+        len = safestrlen(cp, 2);
+        if (CmdLim && (len > CmdLim))
+            len = CmdLim;
+        if (len > CmdColW)
+            CmdColW = len;
+    } else
+        safestrprtn(cp, CmdColW, stdout, 2);
+    /*
+     * Size or print the process ID.
+     */
+    if (!PrPass) {
+        (void)snpf(buf, sizeof(buf), "%d", Lp->pid);
+        if ((len = strlen(buf)) > PidColW)
+            PidColW = len;
+    } else
+        (void)printf(" %*d", PidColW, Lp->pid);
+
+#if defined(HASTASKS)
+    /*
+     * Size or print task ID and command name.
+     */
+    if (!PrPass) {
+        if ((cp = Lp->tcmd)) {
+            len = safestrlen(cp, 2);
+            if (TaskCmdLim && (len > TaskCmdLim))
+                len = TaskCmdLim;
+            if (len > TaskCmdColW)
+                TaskCmdColW = len;
+            TaskPrtCmd = 1;
+        }
+        if (Lp->tid) {
+            (void)snpf(buf, sizeof(buf), "%d", Lp->tid);
+            if ((len = strlen(buf)) > TaskTidColW)
+                TaskTidColW = len;
+            TaskPrtTid = 1;
+        }
+    } else {
+        if (TaskPrtTid) {
+            if (Lp->tid)
+                (void)printf(" %*d", TaskTidColW, Lp->tid);
+            else
+                (void)printf(" %*s", TaskTidColW, "");
+        }
+        if (TaskPrtCmd) {
+            cp = Lp->tcmd ? Lp->tcmd : "";
+            printf(" ");
+            safestrprtn(cp, TaskCmdColW, stdout, 2);
+        }
+    }
+#endif /* defined(HASTASKS) */
+
+#if defined(HASZONES)
+    /*
+     * Size or print the zone.
+     */
+    if (Fzone) {
+        if (!PrPass) {
+            if (Lp->zn) {
+                if ((len = strlen(Lp->zn)) > ZoneColW)
+                    ZoneColW = len;
+            }
+        } else
+            (void)printf(" %-*s", ZoneColW, Lp->zn ? Lp->zn : "");
+    }
+#endif /* defined(HASZONES) */
+
+#if defined(HASSELINUX)
+    /*
+     * Size or print the context.
+     */
+    if (Fcntx) {
+        if (!PrPass) {
+            if (Lp->cntx) {
+                if ((len = strlen(Lp->cntx)) > CntxColW)
+                    CntxColW = len;
+            }
+        } else
+            (void)printf(" %-*s", CntxColW, Lp->cntx ? Lp->cntx : "");
+    }
+#endif /* defined(HASSELINUX) */
+
+#if defined(HASPPID)
+    if (Fppid) {
+
+        /*
+         * Size or print the parent process ID.
+         */
+        if (!PrPass) {
+            (void)snpf(buf, sizeof(buf), "%d", Lp->ppid);
+            if ((len = strlen(buf)) > PpidColW)
+                PpidColW = len;
+        } else
+            (void)printf(" %*d", PpidColW, Lp->ppid);
+    }
+#endif /* defined(HASPPID) */
+
+    if (Fpgid) {
+
+        /*
+         * Size or print the process group ID.
+         */
+        if (!PrPass) {
+            (void)snpf(buf, sizeof(buf), "%d", Lp->pgid);
+            if ((len = strlen(buf)) > PgidColW)
+                PgidColW = len;
+        } else
+            (void)printf(" %*d", PgidColW, Lp->pgid);
+    }
+    /*
+     * Size or print the user ID or login name.
+     */
+    if (!PrPass) {
+        if ((len = strlen(printuid(ctx, (UID_ARG)Lp->uid, NULL))) > UserColW)
+            UserColW = len;
+    } else
+        (void)printf(" %*.*s", UserColW, UserColW,
+                     printuid(ctx, (UID_ARG)Lp->uid, NULL));
+    /*
+     * Size or print the file descriptor, access mode and lock status.
+     */
+    fd_to_string(Lf->fd_type, Lf->fd_num, fd);
+    access = access_to_char(Lf->access);
+    lock = lock_to_char(Lf->lock);
+    if (!PrPass) {
+        (void)snpf(buf, sizeof(buf), "%s%c%c", fd,
+                   (lock == ' ')     ? access
+                   : (access == ' ') ? '-'
+                                     : access,
+                   lock);
+        if ((len = strlen(buf)) > FdColW)
+            FdColW = len;
+    } else
+        (void)printf(" %*.*s%c%c", FdColW - 2, FdColW - 2, fd,
+                     (lock == ' ')     ? access
+                     : (access == ' ') ? '-'
+                                       : access,
+                     lock);
+    /*
+     * Size or print the type.
+     */
+    file_type_to_string(Lf->type, Lf->unknown_file_type_number, type,
+                        sizeof(type));
+    if (!PrPass) {
+        if ((len = strlen(type)) > TypeColW)
+            TypeColW = len;
+    } else
+        (void)printf(" %*.*s", TypeColW, TypeColW, type);
+
+#if defined(HASFSTRUCT)
+    /*
+     * Size or print the file structure address, file usage count, and node
+     * ID (address).
+     */
+
+    if (Fsv) {
+
+#    if !defined(HASNOFSADDR)
+        if (Fsv & FSV_FA) {
+            cp =
+                (Lf->fsv & FSV_FA) ? print_kptr(Lf->fsa, buf, sizeof(buf)) : "";
+            if (!PrPass) {
+                if ((len = strlen(cp)) > FsColW)
+                    FsColW = len;
+            } else
+                (void)printf(" %*.*s", FsColW, FsColW, cp);
+        }
+#    endif /* !defined(HASNOFSADDR) */
+
+#    if !defined(HASNOFSCOUNT)
+        if (Fsv & FSV_CT) {
+            if (Lf->fsv & FSV_CT) {
+                (void)snpf(buf, sizeof(buf), "%ld", Lf->fct);
+                cp = buf;
+            } else
+                cp = "";
+            if (!PrPass) {
+                if ((len = strlen(cp)) > FcColW)
+                    FcColW = len;
+            } else
+                (void)printf(" %*.*s", FcColW, FcColW, cp);
+        }
+#    endif /* !defined(HASNOFSCOUNT) */
+
+#    if !defined(HASNOFSFLAGS)
+        if (Fsv & FSV_FG) {
+            if ((Lf->fsv & FSV_FG) && (FsvFlagX || Lf->ffg || Lf->pof))
+                cp = print_fflags(ctx, Lf->ffg, Lf->pof);
+            else
+                cp = "";
+            if (!PrPass) {
+                if ((len = strlen(cp)) > FgColW)
+                    FgColW = len;
+            } else
+                (void)printf(" %*.*s", FgColW, FgColW, cp);
+        }
+#    endif /* !defined(HASNOFSFLAGS) */
+
+#    if !defined(HASNOFSNADDR)
+        if (Fsv & FSV_NI) {
+            cp =
+                (Lf->fsv & FSV_NI) ? print_kptr(Lf->fna, buf, sizeof(buf)) : "";
+            if (!PrPass) {
+                if ((len = strlen(cp)) > NiColW)
+                    NiColW = len;
+            } else
+                (void)printf(" %*.*s", NiColW, NiColW, cp);
+        }
+#    endif /* !defined(HASNOFSNADDR) */
+    }
+#endif /* defined(HASFSTRUCT) */
+
+    /*
+     * Size or print the device information.
+     */
+
+    if (Lf->rdev_def) {
+        dev = Lf->rdev;
+        devs = 1;
+    } else if (Lf->dev_def) {
+        dev = Lf->dev;
+        devs = 1;
+    } else
+        devs = 0;
+    if (devs) {
+
+#if defined(HASPRINTDEV)
+        cp = HASPRINTDEV(Lf, &dev);
+#else  /* !defined(HASPRINTDEV) */
+        (void)snpf(buf, sizeof(buf), "%u,%u", GET_MAJ_DEV(dev),
+                   GET_MIN_DEV(dev));
+        cp = buf;
+#endif /* defined(HASPRINTDEV) */
+    }
+
+    if (!PrPass) {
+        if (devs)
+            len = strlen(cp);
+        else if (Lf->dev_ch)
+            len = strlen(Lf->dev_ch);
+        else
+            len = 0;
+        if (len > DevColW)
+            DevColW = len;
+    } else {
+        if (devs)
+            (void)printf(" %*.*s", DevColW, DevColW, cp);
+        else {
+            if (Lf->dev_ch)
+                (void)printf(" %*.*s", DevColW, DevColW, Lf->dev_ch);
+            else
+                (void)printf(" %*.*s", DevColW, DevColW, "");
+        }
+    }
+    /*
+     * Size or print the size or offset.
+     */
+    if (!PrPass) {
+        if (!Foffset && Lf->sz_def) {
+            if (Fhuman) {
+                len = human_readable_size(Lf->sz, 0, 0);
+            } else {
+                (void)snpf(buf, sizeof(buf), SzOffFmt_d, Lf->sz);
+                len = strlen(buf);
+            }
+        } else if (!Fsize && Lf->off_def) {
+
+            (void)snpf(buf, sizeof(buf), SzOffFmt_0t, Lf->off);
+            cp = buf;
+
+            len = strlen(cp);
+            if (OffDecDig && len > (OffDecDig + 2)) {
+
+                (void)snpf(buf, sizeof(buf), SzOffFmt_x, Lf->off);
+                cp = buf;
+
+                len = strlen(cp);
+            }
+        } else
+            len = 0;
+        if (len > SzOffColW)
+            SzOffColW = len;
+    } else {
+        putchar(' ');
+        if (!Foffset && Lf->sz_def) {
+            if (Fhuman) {
+                human_readable_size(Lf->sz, 1, SzOffColW);
+            } else {
+                (void)snpf(buf, sizeof(buf), SzOffFmt_d, Lf->sz);
+                len = strlen(buf);
+                (void)printf(SzOffFmt_dv, SzOffColW, Lf->sz);
+            }
+        } else if (!Fsize && Lf->off_def) {
+
+            (void)snpf(buf, sizeof(buf), SzOffFmt_0t, Lf->off);
+            cp = buf;
+
+            if (OffDecDig && (int)strlen(cp) > (OffDecDig + 2)) {
+
+                (void)snpf(buf, sizeof(buf), SzOffFmt_x, Lf->off);
+                cp = buf;
+            }
+            (void)printf("%*.*s", SzOffColW, SzOffColW, cp);
+        } else
+            (void)printf("%*.*s", SzOffColW, SzOffColW, "");
+    }
+    /*
+     * Size or print the link count.
+     */
+    if (Fnlink) {
+        if (Lf->nlink_def) {
+            (void)snpf(buf, sizeof(buf), " %ld", Lf->nlink);
+            cp = buf;
+        } else
+            cp = "";
+        if (!PrPass) {
+            if ((len = strlen(cp)) > NlColW)
+                NlColW = len;
+        } else
+            (void)printf(" %*s", NlColW, cp);
+    }
+    /*
+     * Size or print the inode information.
+     */
+    switch (Lf->inp_ty) {
+    case 1:
+
+#if defined(HASPRINTINO)
+        cp = HASPRINTINO(Lf);
+#else  /* !defined(HASPRINTINO) */
+        (void)snpf(buf, sizeof(buf), InodeFmt_d, Lf->inode);
+        cp = buf;
+#endif /* defined(HASPRINTINO) */
+
+        break;
+    case 2:
+        if (Lf->iproto[0])
+            cp = Lf->iproto;
+        else
+            cp = "";
+        break;
+    case 3:
+        (void)snpf(buf, sizeof(buf), InodeFmt_x, Lf->inode);
+        cp = buf;
+        break;
+    default:
+        cp = "";
+    }
+    if (!PrPass) {
+        if ((len = strlen(cp)) > NodeColW)
+            NodeColW = len;
+    } else {
+        (void)printf(" %*.*s", NodeColW, NodeColW, cp);
+    }
+    /*
+     * If this is the second pass, print the name column.  (It doesn't need
+     * to be sized.)
+     */
+    if (PrPass) {
+        putchar(' ');
+
+#if defined(HASPRINTNM)
+        HASPRINTNM(ctx, Lf);
+#else  /* !defined(HASPRINTNM) */
+        printname(ctx, 1);
+#endif /* defined(HASPRINTNM) */
+    }
+}
+
+/*
+ * printinaddr() - print Internet addresses
+ */
+
+static int printinaddr(struct lsof_context *ctx) {
+    int i, len, src;
+    char *host, *port;
+    int nl = Namechl - 1;
+    char *np = Namech;
+    char pbuf[32];
+    /*
+     * Process local network address first.  If there's a foreign address,
+     * separate it from the local address with "->".
+     */
+    for (i = 0, *np = '\0'; i < 2; i++) {
+        if (!Lf->li[i].af)
+            continue;
+        host = port = (char *)NULL;
+        if (i) {
+
+            /*
+             * If this is the foreign address, insert the separator.
+             */
+            if (nl < 2)
+
+            addr_too_long :
+
+            {
+                (void)snpf(Namech, Namechl, "network addresses too long");
+                return (1);
+            }
+                (void)snpf(np, nl, "->");
+            np += 2;
+            nl -= 2;
+        }
+        /*
+         * Convert the address to a host name.
+         */
+
+#if defined(HASIPv6)
+        if ((Lf->li[i].af == AF_INET6 &&
+             IN6_IS_ADDR_UNSPECIFIED(&Lf->li[i].ia.a6)) ||
+            (Lf->li[i].af == AF_INET && Lf->li[i].ia.a4.s_addr == INADDR_ANY))
+            host = "*";
+        else
+            host = gethostnm(ctx, (unsigned char *)&Lf->li[i].ia, Lf->li[i].af);
+#else  /* !defined(HASIPv6) */
+        if (Lf->li[i].ia.a4.s_addr == INADDR_ANY)
+            host = "*";
+        else
+            host = gethostnm(ctx, (unsigned char *)&Lf->li[i].ia, Lf->li[i].af);
+#endif /* defined(HASIPv6) */
+
+        /*
+         * Process the port number.
+         */
+        if (Lf->li[i].p > 0) {
+
+            if (Fport
+
+#if !defined(HASNORPC_H)
+                || FportMap
+#endif /* defined(HASNORPC_H) */
+
+            ) {
+
+                /*
+                 * If converting port numbers to service names, or looking
+                 * up portmap program names and numbers, do so by protocol.
+                 *
+                 * Identify the port source as local if: 1) it comes from the
+                 * local entry (0) of the file's Internet address array; or
+                 * 2) it comes from  the foreign entry (1), and the foreign
+                 * Internet address matches the local one; or 3) it is the
+                 * loopback address 127.0.0.1.  (Test 2 may not always work
+                 * -- e.g., on hosts with multiple interfaces.)
+                 */
+#if !defined(HASNORPC_H)
+                if ((src = i) && FportMap) {
+
+#    if defined(HASIPv6)
+                    if (Lf->li[0].af == AF_INET6) {
+                        if (IN6_IS_ADDR_LOOPBACK(&Lf->li[i].ia.a6) ||
+                            IN6_ARE_ADDR_EQUAL(&Lf->li[0].ia.a6,
+                                               &Lf->li[1].ia.a6))
+                            src = 0;
+                    } else
+#    endif /* defined(HASIPv6) */
+
+                        if (Lf->li[0].af == AF_INET) {
+                            if (Lf->li[i].ia.a4.s_addr ==
+                                    htonl(INADDR_LOOPBACK) ||
+                                Lf->li[0].ia.a4.s_addr ==
+                                    Lf->li[1].ia.a4.s_addr)
+                                src = 0;
+                        }
+                }
+#else
+                /*
+                 * Just for suppressing warnings reported from compiler.
+                 *
+                 * src is referenced in lkup_port() only if
+                 * "!defined(HASNORPC_H)" is true. The condition here is
+                 * !defined(HASNORPC_H) is false. Therefore the value of src has
+                 * no impact.
+                 */
+                src = 1;
+#endif /* !defined(HASNORPC_H) */
+
+                if (strcasecmp(Lf->iproto, "TCP") == 0)
+                    port = lkup_port(ctx, Lf->li[i].p, 0, src);
+                else if (strcasecmp(Lf->iproto, "UDP") == 0)
+                    port = lkup_port(ctx, Lf->li[i].p, 1, src);
+            }
+            if (!port) {
+                (void)snpf(pbuf, sizeof(pbuf), "%d", Lf->li[i].p);
+                port = pbuf;
+            }
+        } else if (Lf->li[i].p == 0)
+            port = "*";
+        /*
+         * Enter the host name.
+         */
+        if (host) {
+            if ((len = strlen(host)) > nl)
+                goto addr_too_long;
+            if (len) {
+                (void)snpf(np, nl, "%s", host);
+                np += len;
+                nl -= len;
+            }
+        }
+        /*
+         * Enter the port number, preceded by a colon.
+         */
+        if (port) {
+            if (((len = strlen(port)) + 1) >= nl)
+                goto addr_too_long;
+            (void)snpf(np, nl, ":%s", port);
+            np += len + 1;
+            nl -= len - 1;
+        }
+    }
+    if (Namech[0]) {
+        safestrprt(Namech, stdout, 0);
+        return (1);
+    }
+    return (0);
+}
+
+/*
+ * print_init() - initialize for printing
+ */
+
+void print_init(struct lsof_context *ctx) {
+
+    /*
+     * Preset standard values.
+     */
+    PrPass = (Ffield || Fterse) ? 1 : 0;
+    LastPid = -1;
+    TaskPrtCmd = TaskPrtTid = 0;
+    /*
+     * Size columns by their titles.
+     */
+    CmdColW = strlen(CMDTTL);
+    DevColW = strlen(DEVTTL);
+    FdColW = strlen(FDTTL);
+    if (Fnlink)
+        NlColW = strlen(NLTTL);
+    NmColW = strlen(NMTTL);
+    NodeColW = strlen(NODETTL);
+    PgidColW = strlen(PGIDTTL);
+    PidColW = strlen(PIDTTL);
+    PpidColW = strlen(PPIDTTL);
+    if (Fsize)
+        SzOffColW = strlen(SZTTL);
+    else if (Foffset)
+        SzOffColW = strlen(OFFTTL);
+    else
+        SzOffColW = strlen(SZOFFTTL);
+
+#if defined(HASTASKS)
+    TaskCmdColW = strlen(TASKCMDTTL);
+    TaskTidColW = strlen(TASKTIDTTL);
+#endif /* defined(HASTASKS) */
+
+    TypeColW = strlen(TYPETTL);
+    UserColW = strlen(USERTTL);
+
+#if defined(HASFSTRUCT)
+
+#    if !defined(HASNOFSADDR)
+    FsColW = strlen(FSTTL);
+#    endif /* !defined(HASNOFSADDR) */
+
+#    if !defined(HASNOFSCOUNT)
+    FcColW = strlen(FCTTL);
+#    endif /* !defined(HASNOFSCOUNT) */
+
+#    if !defined(HASNOFSFLAGS)
+    FgColW = strlen(FGTTL);
+#    endif /* !defined(HASNOFSFLAGS) */
+
+#    if !defined(HASNOFSNADDR)
+    NiColW = strlen(NiTtl);
+#    endif /* !defined(HASNOFSNADDR) */
+#endif     /* defined(HASFSTRUCT) */
+
+#if defined(HASSELINUX)
+    if (Fcntx)
+        CntxColW = strlen(CNTXTTL);
+#endif /* defined(HASSELINUX) */
+
+#if defined(HASZONES)
+    if (Fzone)
+        ZoneColW = strlen(ZONETTL);
+#endif /* defined(HASZONES) */
+}
+
+/*
+ * printname() - print output name field
+ */
+
+void printname(struct lsof_context *ctx, int nl) /* NL status */
+{
+
+#if defined(HASNCACHE)
+    char buf[MAXPATHLEN];
+    char *cp;
+    int fp;
+#endif /* defined(HASNCACHE) */
+
+    int ps = 0;
+
+    if (Lf->nm && Lf->nm[0]) {
+
+        /*
+         * Print the name characters, if there are some.
+         */
+        safestrprt(Lf->nm, stdout, 0);
+        ps++;
+        if (!Lf->li[0].af && !Lf->li[1].af)
+            goto print_nma;
+    }
+    if (Lf->li[0].af || Lf->li[1].af) {
+        if (ps)
+            putchar(' ');
+        /*
+         * If the file has Internet addresses, print them.
+         */
+        if (printinaddr(ctx))
+            ps++;
+        goto print_nma;
+    }
+    if (((Lf->ntype == N_BLK) || (Lf->ntype == N_CHR)) && Lf->dev_def &&
+        Lf->rdev_def && printdevname(ctx, &Lf->dev, &Lf->rdev, 0, Lf->ntype)) {
+
+        /*
+         * If this is a block or character device and it has a name, print it.
+         */
+        ps++;
+        goto print_nma;
+    }
+    if (Lf->is_com) {
+
+        /*
+         * If this is a common node, print that fact.
+         */
+        (void)fputs("COMMON: ", stdout);
+        ps++;
+        goto print_nma;
+    }
+
+#if defined(HASPRIVNMCACHE)
+    if (HASPRIVNMCACHE(ctx, Lf)) {
+        ps++;
+        goto print_nma;
+    }
+#endif /* defined(HASPRIVNMCACHE) */
+
+    if (Lf->lmi_srch) {
+        struct mounts *mp;
+        /*
+         * Do a deferred local mount info table search for the file system
+         * (mounted) directory name and inode number, and mounted device name.
+         */
+        for (mp = readmnt(ctx); mp; mp = mp->next) {
+            if (Lf->dev == mp->dev) {
+                Lf->fsdir = mp->dir;
+                Lf->fsdev = mp->fsname;
+
+#if defined(HASFSINO)
+                Lf->fs_ino = mp->inode;
+#endif /* defined(HASFSINO) */
+
+                break;
+            }
+        }
+        Lf->lmi_srch = 0;
+    }
+    if (Lf->fsdir || Lf->fsdev) {
+
+        /*
+         * Print the file system directory name, device name, and
+         * possible path name components.
+         */
+
+#if !defined(HASNCACHE) || HASNCACHE < 2
+        if (Lf->fsdir) {
+            safestrprt(Lf->fsdir, stdout, 0);
+            ps++;
+        }
+#endif /* !defined(HASNCACHE) || HASNCACHE<2 */
+
+#if defined(HASNCACHE)
+
+#    if HASNCACHE < 2
+        if (Lf->na) {
+            if (NcacheReload) {
+
+#        if defined(NCACHELDPFX)
+                NCACHELDPFX
+#        endif /* defined(NCACHELDPFX) */
+
+                    (void)
+                ncache_load(ctx);
+
+#        if defined(NCACHELDSFX)
+                NCACHELDSFX
+#        endif /* defined(NCACHELDSFX) */
+
+                NcacheReload = 0;
+            }
+            if ((cp = ncache_lookup(ctx, buf, sizeof(buf), &fp))) {
+                char *cp1;
+
+                if (*cp == '\0')
+                    goto print_nma;
+                if (fp && Lf->fsdir) {
+                    if (*cp != '/') {
+                        cp1 = strrchr(Lf->fsdir, '/');
+                        if (cp1 == (char *)NULL || *(cp1 + 1) != '\0')
+                            putchar('/');
+                    }
+                } else
+                    (void)fputs(" -- ", stdout);
+                safestrprt(cp, stdout, 0);
+                ps++;
+                goto print_nma;
+            }
+        }
+#    else /* HASNCACHE>1 */
+        if (NcacheReload) {
+
+#        if defined(NCACHELDPFX)
+            NCACHELDPFX
+#        endif /* defined(NCACHELDPFX) */
+
+                (void)
+            ncache_load();
+
+#        if defined(NCACHELDSFX)
+            NCACHELDSFX
+#        endif /* defined(NCACHELDSFX) */
+
+            NcacheReload = 0;
+        }
+        if ((cp = ncache_lookup(buf, sizeof(buf), &fp))) {
+            if (fp) {
+                safestrprt(cp, stdout, 0);
+                ps++;
+            } else {
+                if (Lf->fsdir) {
+                    safestrprt(Lf->fsdir, stdout, 0);
+                    ps++;
+                }
+                if (*cp) {
+                    (void)fputs(" -- ", stdout);
+                    safestrprt(cp, stdout, 0);
+                    ps++;
+                }
+            }
+            goto print_nma;
+        }
+        if (Lf->fsdir) {
+            safestrprt(Lf->fsdir, stdout, 0);
+            ps++;
+        }
+#    endif     /* HASNCACHE<2 */
+#endif         /* defined(HASNCACHE) */
+
+        if (Lf->fsdev) {
+            if (Lf->fsdir)
+                (void)fputs(" (", stdout);
+            else
+                (void)putchar('(');
+            safestrprt(Lf->fsdev, stdout, 0);
+            (void)putchar(')');
+            ps++;
+        }
+    }
+    /*
+     * Print the NAME column addition, if there is one.  If there isn't
+     * make sure a NL is printed, as requested.
+     */
+
+print_nma:
+
+    if (Lf->nma) {
+        if (ps)
+            putchar(' ');
+        safestrprt(Lf->nma, stdout, 0);
+        ps++;
+    }
+    /*
+     * If this file has TCP/IP state information, print it.
+     */
+    if (!Ffield && Ftcptpi &&
+        (Lf->lts.type >= 0
+
+#if defined(HASTCPTPIQ)
+         || ((Ftcptpi & TCPTPI_QUEUES) && (Lf->lts.rqs || Lf->lts.sqs))
+#endif /* defined(HASTCPTPIQ) */
+
+#if defined(HASTCPTPIW)
+         || ((Ftcptpi & TCPTPI_WINDOWS) && (Lf->lts.rws || Lf->lts.wws))
+#endif /* defined(HASTCPTPIW) */
+
+             )) {
+        if (ps)
+            putchar(' ');
+        (void)print_tcptpi(ctx, 0);
+    }
+    if (nl)
+        putchar('\n');
+}
+
+/*
+ * printrawaddr() - print raw socket address
+ */
+
+void printrawaddr(struct lsof_context *ctx,
+                  struct sockaddr *sa) /* socket address */
+{
+    char *ep;
+    size_t sz;
+
+    ep = endnm(ctx, &sz);
+    (void)snpf(ep, sz, "%u/%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u",
+               sa->sa_family, (unsigned char)sa->sa_data[0],
+               (unsigned char)sa->sa_data[1], (unsigned char)sa->sa_data[2],
+               (unsigned char)sa->sa_data[3], (unsigned char)sa->sa_data[4],
+               (unsigned char)sa->sa_data[5], (unsigned char)sa->sa_data[6],
+               (unsigned char)sa->sa_data[7], (unsigned char)sa->sa_data[8],
+               (unsigned char)sa->sa_data[9], (unsigned char)sa->sa_data[10],
+               (unsigned char)sa->sa_data[11], (unsigned char)sa->sa_data[12],
+               (unsigned char)sa->sa_data[13]);
+}
+
+/*
+ * printsockty() - print socket type
+ */
+
+char *printsockty(int ty) /* socket type -- e.g., from so_type */
+{
+    static char buf[64];
+    char *cp;
+
+    switch (ty) {
+
+#if defined(SOCK_STREAM)
+    case SOCK_STREAM:
+        cp = "STREAM";
+        break;
+#endif /* defined(SOCK_STREAM) */
+
+#if defined(SOCK_STREAM)
+    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) */
+
+    default:
+        (void)snpf(buf, sizeof(buf), "SOCK_%#x", ty);
+        return (buf);
+    }
+    (void)snpf(buf, sizeof(buf), "SOCK_%s", cp);
+    return (buf);
+}
+
+/*
+ * printuid() - print User ID or login name
+ */
+
+char *printuid(struct lsof_context *ctx, /* context */
+               UID_ARG uid,              /* User IDentification number */
+               int *ty)                  /* returned UID type pointer (NULL
+                                          * (if none wanted).  If non-NULL
+                                          * then: *ty = 0 = login name
+                                          *         = 1 = UID number */
+{
+    int i;
+    struct passwd *pw;
+    struct stat sb;
+    static struct stat sbs;
+    static struct uidcache {
+        uid_t uid;
+        char nm[LOGINML + 1];
+        struct uidcache *next;
+    } **uc = (struct uidcache **)NULL;
+    struct uidcache *up, *upn;
+    static char user[USERPRTL + 1];
+
+    if (Futol) {
+        if (CkPasswd) {
+
+            /*
+             * Get the mtime and ctime of /etc/passwd, as required.
+             */
+            if (stat("/etc/passwd", &sb) != 0) {
+                (void)fprintf(stderr, "%s: can't stat(/etc/passwd): %s\n", Pn,
+                              strerror(errno));
+                Error(ctx);
+            }
+        }
+        /*
+         * Define the UID cache, if necessary.
+         */
+        if (!uc) {
+            if (!(uc = (struct uidcache **)calloc(UIDCACHEL,
+                                                  sizeof(struct uidcache *)))) {
+                (void)fprintf(
+                    stderr, "%s: no space for %d byte UID cache hash buckets\n",
+                    Pn, (int)(UIDCACHEL * (sizeof(struct uidcache *))));
+                Error(ctx);
+            }
+            if (CkPasswd) {
+                sbs = sb;
+                CkPasswd = 0;
+            }
+        }
+        /*
+         * If it's time to check /etc/passwd and if its the mtime/ctime has
+         * changed, destroy the existing UID cache.
+         */
+        if (CkPasswd) {
+            if (sbs.st_mtime != sb.st_mtime || sbs.st_ctime != sb.st_ctime) {
+                for (i = 0; i < UIDCACHEL; i++) {
+                    if ((up = uc[i])) {
+                        do {
+                            upn = up->next;
+                            (void)free((FREE_P *)up);
+                        } while ((up = upn) != (struct uidcache *)NULL);
+                        uc[i] = (struct uidcache *)NULL;
+                    }
+                }
+                sbs = sb;
+            }
+            CkPasswd = 0;
+        }
+        /*
+         * Search the UID cache.
+         */
+        i = (int)((((unsigned long)uid * 31415L) >> 7) & (UIDCACHEL - 1));
+        for (up = uc[i]; up; up = up->next) {
+            if (up->uid == (uid_t)uid) {
+                if (ty)
+                    *ty = 0;
+                return (up->nm);
+            }
+        }
+        /*
+         * The UID is not in the cache.
+         *
+         * Look up the login name from the UID for a new cache entry.
+         */
+        if (!(pw = getpwuid((uid_t)uid))) {
+            if (!Fwarn) {
+                (void)fprintf(stderr, "%s: no pwd entry for UID %lu\n", Pn,
+                              (unsigned long)uid);
+            }
+        } else {
+
+            /*
+             * Allocate and fill a new cache entry.  Link it to its hash bucket.
+             */
+            if (!(upn = (struct uidcache *)malloc(sizeof(struct uidcache)))) {
+                (void)fprintf(
+                    stderr, "%s: no space for UID cache entry for: %lu, %s)\n",
+                    Pn, (unsigned long)uid, pw->pw_name);
+                Error(ctx);
+            }
+            (void)strncpy(upn->nm, pw->pw_name, LOGINML);
+            upn->nm[LOGINML] = '\0';
+            upn->uid = (uid_t)uid;
+            upn->next = uc[i];
+            uc[i] = upn;
+            if (ty)
+                *ty = 0;
+            return (upn->nm);
+        }
+    }
+    /*
+     * Produce a numeric conversion of the UID.
+     */
+    (void)snpf(user, sizeof(user), "%*lu", USERPRTL, (unsigned long)uid);
+    if (ty)
+        *ty = 1;
+    return (user);
+}
+
+#if !defined(HASNORPC_H)
+/*
+ * update_portmap() - update a portmap entry with its port number or service
+ *                   name
+ */
+
+static void update_portmap(struct lsof_context *ctx, /* context */
+                           struct porttab *pt,       /* porttab entry */
+                           char *pn)                 /* port name */
+{
+    MALLOC_S al, nl;
+    char *cp;
+
+    if (pt->ss)
+        return;
+    if (!(al = strlen(pn))) {
+        pt->ss = 1;
+        return;
+    }
+    nl = al + pt->nl + 2;
+    if (!(cp = (char *)malloc(nl + 1))) {
+        (void)fprintf(stderr,
+                      "%s: can't allocate %d bytes for portmap name: %s[%s]\n",
+                      Pn, (int)(nl + 1), pn, pt->name);
+        Error(ctx);
+    }
+    (void)snpf(cp, nl + 1, "%s[%s]", pn, pt->name);
+    (void)free((FREE_P *)pt->name);
+    pt->name = cp;
+    pt->nl = nl;
+    pt->ss = 1;
+}
+#endif /* !defined(HASNORPC_H) */
+
+/*
+ * Convert sz to human readable format, print to stdout if print=1
+ *
+ * Return the length of output
+ */
+int human_readable_size(SZOFFTYPE sz, int print, int col) {
+    char buf[128];
+    SZOFFTYPE base = 1024;
+    SZOFFTYPE unit = base;
+    SZOFFTYPE upper = base * base;
+    int suffix_count = 6;
+    char *suffix[6] = {"K", "M", "G", "T", "P", "E"};
+    int i;
+    int len;
+    double val;
+
+    if (sz < base) {
+        /* <1KB */
+        (void)snpf(buf, sizeof(buf), "%" SZOFFPSPEC "uB", sz);
+    } else {
+        for (i = 0; i < suffix_count - 1; i++) {
+            if (sz < upper) {
+                break;
+            }
+            unit = upper;
+            upper = upper * base;
+        }
+
+        /* Avoid floating point overflow */
+        val = (double)(sz / (unit / base)) / base;
+        (void)snpf(buf, sizeof(buf), "%.1lf%s", val, suffix[i]);
+    }
+    if (print) {
+        printf("%*s", col, buf);
+    }
+    return strlen(buf);
+}
+
+/*
+ * print_proc() - print process
+ */
+int print_proc(struct lsof_context *ctx) {
+    char buf[128], *cp;
+    int lc, len, st, ty;
+    int rv = 0;
+    unsigned long ul;
+    char fd[FDLEN];
+    char type[TYPEL];
+    /*
+     * If nothing in the process has been selected, skip it.
+     */
+    if (!Lp->pss)
+        return (0);
+    if (Fterse) {
+        if (Lp->pid == LastPid) /* eliminate duplicates */
+            return (0);
+        LastPid = Lp->pid;
+        /*
+         * The mode is terse and something in the process appears to have
+         * been selected.  Make sure of that by looking for a selected file,
+         * so that the HASSECURITY and HASNOSOCKSECURITY option combination
+         * won't produce a false positive result.
+         */
+        for (Lf = Lp->file; Lf; Lf = Lf->next) {
+            if (is_file_sel(ctx, Lp, Lf)) {
+                (void)printf("%d\n", Lp->pid);
+                return (1);
+            }
+        }
+        return (0);
+    }
+    /*
+     * If fields have been selected, output the process-only ones, provided
+     * that some file has also been selected.
+     */
+    if (Ffield) {
+        for (Lf = Lp->file; Lf; Lf = Lf->next) {
+            if (is_file_sel(ctx, Lp, Lf))
+                break;
+        }
+        if (!Lf)
+            return (rv);
+        rv = 1;
+        (void)printf("%c%d%c", LSOF_FID_PID, Lp->pid, Terminator);
+
+#if defined(HASTASKS)
+        if (FieldSel[LSOF_FIX_TID].st && Lp->tid)
+            (void)printf("%c%d%c", LSOF_FID_TID, Lp->tid, Terminator);
+        if (FieldSel[LSOF_FIX_TCMD].st && Lp->tcmd)
+            (void)printf("%c%s%c", LSOF_FID_TCMD, Lp->tcmd, Terminator);
+#endif /* defined(HASTASKS) */
+
+#if defined(HASZONES)
+        if (FieldSel[LSOF_FIX_ZONE].st && Fzone && Lp->zn)
+            (void)printf("%c%s%c", LSOF_FID_ZONE, Lp->zn, Terminator);
+#endif /* defined(HASZONES) */
+
+#if defined(HASSELINUX)
+        if (FieldSel[LSOF_FIX_CNTX].st && Fcntx && Lp->cntx && CntxStatus)
+            (void)printf("%c%s%c", LSOF_FID_CNTX, Lp->cntx, Terminator);
+#endif /* defined(HASSELINUX) */
+
+        if (FieldSel[LSOF_FIX_PGID].st && Fpgid)
+            (void)printf("%c%d%c", LSOF_FID_PGID, Lp->pgid, Terminator);
+
+#if defined(HASPPID)
+        if (FieldSel[LSOF_FIX_PPID].st && Fppid)
+            (void)printf("%c%d%c", LSOF_FID_PPID, Lp->ppid, Terminator);
+#endif /* defined(HASPPID) */
+
+        if (FieldSel[LSOF_FIX_CMD].st) {
+            putchar(LSOF_FID_CMD);
+            safestrprt(Lp->cmd ? Lp->cmd : "(unknown)", stdout, 0);
+            putchar(Terminator);
+        }
+        if (FieldSel[LSOF_FIX_UID].st)
+            (void)printf("%c%d%c", LSOF_FID_UID, (int)Lp->uid, Terminator);
+        if (FieldSel[LSOF_FIX_LOGIN].st) {
+            cp = printuid(ctx, (UID_ARG)Lp->uid, &ty);
+            if (ty == 0)
+                (void)printf("%c%s%c", LSOF_FID_LOGIN, cp, Terminator);
+        }
+        if (Terminator == '\0')
+            putchar('\n');
+    }
+    /*
+     * Print files.
+     */
+    for (Lf = Lp->file; Lf; Lf = Lf->next) {
+        if (!is_file_sel(ctx, Lp, Lf))
+            continue;
+        rv = 1;
+        /*
+         * If no field output selected, print dialect-specific formatted
+         * output.
+         */
+        if (!Ffield) {
+            print_file(ctx);
+            continue;
+        }
+        lc = st = 0;
+        if (FieldSel[LSOF_FIX_FD].st) {
+
+            fd_to_string(Lf->fd_type, Lf->fd_num, fd);
+            (void)printf("%c%s%c", LSOF_FID_FD, fd, Terminator);
+            lc++;
+        }
+        /*
+         * Print selected fields.
+         */
+        if (FieldSel[LSOF_FIX_ACCESS].st) {
+            (void)printf("%c%c%c", LSOF_FID_ACCESS, access_to_char(Lf->access),
+                         Terminator);
+            lc++;
+        }
+        if (FieldSel[LSOF_FIX_LOCK].st) {
+            (void)printf("%c%c%c", LSOF_FID_LOCK, lock_to_char(Lf->lock),
+                         Terminator);
+            lc++;
+        }
+        if (FieldSel[LSOF_FIX_TYPE].st) {
+            if (Lf->type != LSOF_FILE_NONE) {
+                file_type_to_string(Lf->type, Lf->unknown_file_type_number,
+                                    type, TYPEL);
+                (void)printf("%c%s%c", LSOF_FID_TYPE, type, Terminator);
+                lc++;
+            }
+        }
+
+#if defined(HASFSTRUCT)
+        if (FieldSel[LSOF_FIX_FA].st && (Fsv & FSV_FA) && (Lf->fsv & FSV_FA)) {
+            (void)printf("%c%s%c", LSOF_FID_FA,
+                         print_kptr(Lf->fsa, (char *)NULL, 0), Terminator);
+            lc++;
+        }
+        if (FieldSel[LSOF_FIX_CT].st && (Fsv & FSV_CT) && (Lf->fsv & FSV_CT)) {
+            (void)printf("%c%ld%c", LSOF_FID_CT, Lf->fct, Terminator);
+            lc++;
+        }
+        if (FieldSel[LSOF_FIX_FG].st && (Fsv & FSV_FG) && (Lf->fsv & FSV_FG) &&
+            (FsvFlagX || Lf->ffg || Lf->pof)) {
+            (void)printf("%c%s%c", LSOF_FID_FG,
+                         print_fflags(ctx, Lf->ffg, Lf->pof), Terminator);
+            lc++;
+        }
+        if (FieldSel[LSOF_FIX_NI].st && (Fsv & FSV_NI) && (Lf->fsv & FSV_NI)) {
+            (void)printf("%c%s%c", LSOF_FID_NI,
+                         print_kptr(Lf->fna, (char *)NULL, 0), Terminator);
+            lc++;
+        }
+#endif /* defined(HASFSTRUCT) */
+
+        if (FieldSel[LSOF_FIX_DEVCH].st && Lf->dev_ch && Lf->dev_ch[0]) {
+            for (cp = Lf->dev_ch; *cp == ' '; cp++)
+                ;
+            if (*cp) {
+                (void)printf("%c%s%c", LSOF_FID_DEVCH, cp, Terminator);
+                lc++;
+            }
+        }
+        if (FieldSel[LSOF_FIX_DEVN].st && Lf->dev_def) {
+            if (sizeof(unsigned long) > sizeof(dev_t))
+                ul = (unsigned long)((unsigned int)Lf->dev);
+            else
+                ul = (unsigned long)Lf->dev;
+            (void)printf("%c0x%lx%c", LSOF_FID_DEVN, ul, Terminator);
+            lc++;
+        }
+        if (FieldSel[LSOF_FIX_RDEV].st && Lf->rdev_def) {
+            if (sizeof(unsigned long) > sizeof(dev_t))
+                ul = (unsigned long)((unsigned int)Lf->rdev);
+            else
+                ul = (unsigned long)Lf->rdev;
+            (void)printf("%c0x%lx%c", LSOF_FID_RDEV, ul, Terminator);
+            lc++;
+        }
+        if (FieldSel[LSOF_FIX_SIZE].st && Lf->sz_def) {
+            putchar(LSOF_FID_SIZE);
+
+            (void)snpf(buf, sizeof(buf), SzOffFmt_d, Lf->sz);
+            cp = buf;
+
+            (void)printf("%s", cp);
+            putchar(Terminator);
+            lc++;
+        }
+        if (FieldSel[LSOF_FIX_OFFSET].st && Lf->off_def) {
+            putchar(LSOF_FID_OFFSET);
+
+            (void)snpf(buf, sizeof(buf), SzOffFmt_0t, Lf->off);
+            cp = buf;
+
+            len = strlen(cp);
+            if (OffDecDig && len > (OffDecDig + 2)) {
+
+                (void)snpf(buf, sizeof(buf), SzOffFmt_x, Lf->off);
+                cp = buf;
+            }
+            (void)printf("%s", cp);
+            putchar(Terminator);
+            lc++;
+        }
+        if (FieldSel[LSOF_FIX_INODE].st && Lf->inp_ty == 1) {
+            putchar(LSOF_FID_INODE);
+            (void)printf(InodeFmt_d, Lf->inode);
+            putchar(Terminator);
+            lc++;
+        }
+        if (FieldSel[LSOF_FIX_NLINK].st && Lf->nlink_def) {
+            (void)printf("%c%ld%c", LSOF_FID_NLINK, Lf->nlink, Terminator);
+            lc++;
+        }
+        if (FieldSel[LSOF_FIX_PROTO].st && Lf->inp_ty == 2) {
+            for (cp = Lf->iproto; *cp == ' '; cp++)
+                ;
+            if (*cp) {
+                (void)printf("%c%s%c", LSOF_FID_PROTO, cp, Terminator);
+                lc++;
+            }
+        }
+        if (FieldSel[LSOF_FIX_STREAM].st && Lf->nm && Lf->is_stream) {
+            if (strncmp(Lf->nm, "STR:", 4) == 0 ||
+                strcmp(Lf->iproto, "STR") == 0) {
+                putchar(LSOF_FID_STREAM);
+                printname(ctx, 0);
+                putchar(Terminator);
+                lc++;
+                st++;
+            }
+        }
+        if (st == 0 && FieldSel[LSOF_FIX_NAME].st) {
+            putchar(LSOF_FID_NAME);
+            printname(ctx, 0);
+            putchar(Terminator);
+            lc++;
+        }
+        if (Lf->lts.type >= 0 && FieldSel[LSOF_FIX_TCPTPI].st) {
+            print_tcptpi(ctx, 0);
+            lc++;
+        }
+        if (Terminator == '\0' && lc)
+            putchar('\n');
+    }
+    return (rv);
+}
+
+#if defined(HASFSTRUCT)
+static char *alloc_fflbuf(struct lsof_context *ctx, char **bp, int *al, int lr);
+
+/*
+ * alloc_fflbuf() - allocate file flags print buffer
+ */
+
+static char *alloc_fflbuf(struct lsof_context *ctx,
+                          char **bp, /* current buffer pointer */
+                          int *al,   /* current allocated length */
+                          int lr)    /* length required */
+{
+    int sz;
+
+    sz = (int)(lr + 1); /* allocate '\0' space */
+    if (*bp && (sz <= *al))
+        return (*bp);
+    if (*bp)
+        *bp = (char *)realloc((MALLOC_P *)*bp, (MALLOC_S)sz);
+    else
+        *bp = (char *)malloc((MALLOC_S)sz);
+    if (!*bp) {
+        (void)fprintf(stderr, "%s: no space (%d) for print flags\n", Pn, sz);
+        Error(ctx);
+    }
+    *al = sz;
+    return (*bp);
+}
+#endif /* defined(HASFSTRUCT) */
+
+#if defined(HASFSTRUCT)
+/*
+ * print_fflags() - print interpreted f_flag[s]
+ */
+char *print_fflags(struct lsof_context *ctx,
+                   long ffg, /* file structure's flags value */
+                   long pof) /* process open files flags value */
+{
+    int al, ct, fx;
+    static int bl = 0;
+    static char *bp = (char *)NULL;
+    char *sep;
+    int sepl;
+    struct pff_tab *tp;
+    long wf;
+    char xbuf[64];
+    /*
+     * Reduce the supplied flags according to the definitions in Pff_tab[] and
+     * Pof_tab[].
+     */
+    for (ct = fx = 0; fx < 2; fx++) {
+        if (fx == 0) {
+            sep = "";
+            sepl = 0;
+            tp = Pff_tab;
+            wf = ffg;
+        } else {
+            sep = ";";
+            sepl = 1;
+            tp = Pof_tab;
+            wf = pof;
+        }
+        for (; wf && !FsvFlagX; ct += al) {
+            while (tp->nm) {
+                if (wf & tp->val)
+                    break;
+                tp++;
+            }
+            if (!tp->nm)
+                break;
+            al = (int)strlen(tp->nm) + sepl;
+            bp = alloc_fflbuf(ctx, &bp, &bl, al + ct);
+            (void)snpf(bp + ct, al + 1, "%s%s", sep, tp->nm);
+            sep = ",";
+            sepl = 1;
+            wf &= ~(tp->val);
+        }
+        /*
+         * If flag bits remain, print them in hex.  If hex output was
+         * specified with +fG, print all flag values, including zero,
+         * in hex.
+         */
+        if (wf || FsvFlagX) {
+            (void)snpf(xbuf, sizeof(xbuf), "0x%lx", wf);
+            al = (int)strlen(xbuf) + sepl;
+            bp = alloc_fflbuf(ctx, &bp, &bl, al + ct);
+            (void)snpf(bp + ct, al + 1, "%s%s", sep, xbuf);
+            ct += al;
+        }
+    }
+    /*
+     * Make sure there is at least a NUL terminated reply.
+     */
+    if (!bp) {
+        bp = alloc_fflbuf(ctx, &bp, &bl, 0);
+        *bp = '\0';
+    }
+    return (bp);
+}
+#endif /* defined(HASFSTRUCT) */
diff --git a/src/ptti.c b/src/ptti.c
new file mode 100644 (file)
index 0000000..ae3e005
--- /dev/null
@@ -0,0 +1,1355 @@
+/*
+ * ptti.c -- BSD style print_tcptpi() function for lsof library
+ */
+
+/*
+ * 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.
+ */
+
+#define TCPSTATES /* activate tcpstates[] */
+
+#include "common.h"
+#include "machine.h"
+
+#if defined(USE_LIB_PRINT_TCPTPI)
+
+/*
+ * build_IPstates() -- build the TCP and UDP state tables
+ *
+ * Note: this module does not support a UDP state table.
+ */
+
+void build_IPstates(struct lsof_context *ctx) {
+
+    /*
+     * Set the TcpNstates global variable.
+     */
+    TcpNstates = TCP_NSTATES;
+    TcpSt = (char **)&tcpstates;
+}
+
+/*
+ * print_tcptpi() - print TCP/TPI info
+ */
+
+void print_tcptpi(struct lsof_context *ctx, int nl) /* 1 == '\n' required */
+{
+    int ps = 0;
+    int s;
+
+    if ((Ftcptpi & TCPTPI_STATE) && Lf->lts.type == 0) {
+        if (Ffield)
+            (void)printf("%cST=", LSOF_FID_TCPTPI);
+        else
+            putchar('(');
+        if (!TcpNstates)
+            (void)build_IPstates(ctx);
+        if ((s = Lf->lts.state.i) < 0 || s >= TcpNstates)
+            (void)printf("UNKNOWN_TCP_STATE_%d", s);
+        else
+            (void)fputs(TcpSt[s], stdout);
+        ps++;
+        if (Ffield)
+            putchar(Terminator);
+    }
+
+#    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(HASSOOPT)
+    if (Ftcptpi & TCPTPI_FLAGS) {
+        int opt;
+
+        if ((opt = Lf->lts.opt) || Lf->lts.pqlens || Lf->lts.qlens ||
+            Lf->lts.qlims || Lf->lts.rbszs || Lf->lts.sbsz) {
+            char sep = ' ';
+
+            if (Ffield)
+                sep = LSOF_FID_TCPTPI;
+            else if (!ps)
+                sep = '(';
+            (void)printf("%cSO", sep);
+            ps++;
+            sep = '=';
+
+#        if defined(SO_ACCEPTCONN)
+            if (opt & SO_ACCEPTCONN) {
+                (void)printf("%cACCEPTCONN", sep);
+                opt &= ~SO_ACCEPTCONN;
+                sep = ',';
+            }
+#        endif /* defined(SO_ACCEPTCONN) */
+
+#        if defined(SO_ACCEPTFILTER)
+            if (opt & SO_ACCEPTFILTER) {
+                (void)printf("%cACCEPTFILTER", sep);
+                opt &= ~SO_ACCEPTFILTER;
+                sep = ',';
+            }
+#        endif /* defined(SO_ACCEPTFILTER) */
+
+#        if defined(SO_AUDIT)
+            if (opt & SO_AUDIT) {
+                (void)printf("%cAUDIT", sep);
+                opt &= ~SO_AUDIT;
+                sep = ',';
+            }
+#        endif /* defined(SO_AUDIT) */
+
+#        if defined(SO_BINDANY)
+            if (opt & SO_BINDANY) {
+                (void)printf("%cBINDANY", sep);
+                opt &= ~SO_BINDANY;
+                sep = ',';
+            }
+#        endif /* defined(SO_BINDANY) */
+
+#        if defined(SO_BINTIME)
+            if (opt & SO_BINTIME) {
+                (void)printf("%cBINTIME", sep);
+                opt &= ~SO_BINTIME;
+                sep = ',';
+            }
+#        endif /* defined(SO_BINTIME) */
+
+#        if defined(SO_BROADCAST)
+            if (opt & SO_BROADCAST) {
+                (void)printf("%cBROADCAST", sep);
+                opt &= ~SO_BROADCAST;
+                sep = ',';
+            }
+#        endif /* defined(SO_BROADCAST) */
+
+#        if defined(SO_CKSUMRECV)
+            if (opt & SO_CKSUMRECV) {
+                (void)printf("%cCKSUMRECV", sep);
+                opt &= ~SO_CKSUMRECV;
+                sep = ',';
+            }
+#        endif /* defined(SO_CKSUMRECV) */
+
+#        if defined(SO_CLUA_IN_NOALIAS)
+            if (opt & SO_CLUA_IN_NOALIAS) {
+                (void)printf("%cCLUA_IN_NOALIAS", sep);
+                opt &= ~SO_CLUA_IN_NOALIAS;
+                sep = ',';
+            }
+#        endif /* defined(SO_CLUA_IN_NOALIAS) */
+
+#        if defined(SO_CLUA_IN_NOLOCAL)
+            if (opt & SO_CLUA_IN_NOLOCAL) {
+                (void)printf("%cCLUA_IN_NOLOCAL", sep);
+                opt &= ~SO_CLUA_IN_NOLOCAL;
+                sep = ',';
+            }
+#        endif /* defined(SO_CLUA_IN_NOLOCAL) */
+
+#        if defined(SO_DEBUG)
+            if (opt & SO_DEBUG) {
+                (void)printf("%cDEBUG", sep);
+                opt &= ~SO_DEBUG;
+                sep = ',';
+            }
+#        endif /* defined(SO_DEBUG) */
+
+#        if defined(SO_DGRAM_ERRIND)
+            if (opt & SO_DGRAM_ERRIND) {
+                (void)printf("%cDGRAM_ERRIND", sep);
+                opt &= ~SO_DGRAM_ERRIND;
+                sep = ',';
+            }
+#        endif /* defined(SO_DGRAM_ERRIND) */
+
+#        if defined(SO_DONTROUTE)
+            if (opt & SO_DONTROUTE) {
+                (void)printf("%cDONTROUTE", sep);
+                opt &= ~SO_DONTROUTE;
+                sep = ',';
+            }
+#        endif /* defined(SO_DONTROUTE) */
+
+#        if defined(SO_DONTTRUNC)
+            if (opt & SO_DONTTRUNC) {
+                (void)printf("%cDONTTRUNC", sep);
+                opt &= ~SO_DONTTRUNC;
+                sep = ',';
+            }
+#        endif /* defined(SO_DONTTRUNC) */
+
+#        if defined(SO_EXPANDED_RIGHTS)
+            if (opt & SO_EXPANDED_RIGHTS) {
+                (void)printf("%cEXPANDED_RIGHTS", sep);
+                opt &= ~SO_EXPANDED_RIGHTS;
+                sep = ',';
+            }
+#        endif /* defined(SO_EXPANDED_RIGHTS) */
+
+#        if defined(SO_KEEPALIVE)
+            if (opt & SO_KEEPALIVE) {
+                (void)printf("%cKEEPALIVE", sep);
+                if (Lf->lts.kai)
+                    (void)printf("=%d", Lf->lts.kai);
+                opt &= ~SO_KEEPALIVE;
+                sep = ',';
+            }
+#        endif /* defined(SO_KEEPALIVE) */
+
+#        if defined(SO_KERNACCEPT)
+            if (opt & SO_KERNACCEPT) {
+                (void)printf("%cKERNACCEPT", sep);
+                opt &= ~SO_KERNACCEPT;
+                sep = ',';
+            }
+#        endif /* defined(SO_KERNACCEPT) */
+
+#        if defined(SO_IMASOCKET)
+            if (opt & SO_IMASOCKET) {
+                (void)printf("%cIMASOCKET", sep);
+                opt &= ~SO_IMASOCKET;
+                sep = ',';
+            }
+#        endif /* defined(SO_IMASOCKET) */
+
+#        if defined(SO_LINGER)
+            if (opt & SO_LINGER) {
+                (void)printf("%cLINGER", sep);
+                if (Lf->lts.ltm)
+                    (void)printf("=%d", Lf->lts.ltm);
+                opt &= ~SO_LINGER;
+                sep = ',';
+            }
+#        endif /* defined(SO_LINGER) */
+
+#        if defined(SO_LISTENING)
+            if (opt & SO_LISTENING) {
+                (void)printf("%cLISTENING", sep);
+                opt &= ~SO_LISTENING;
+                sep = ',';
+            }
+#        endif /* defined(SO_LISTENING) */
+
+#        if defined(SO_MGMT)
+            if (opt & SO_MGMT) {
+                (void)printf("%cMGMT", sep);
+                opt &= ~SO_MGMT;
+                sep = ',';
+            }
+#        endif /* defined(SO_MGMT) */
+
+#        if defined(SO_PAIRABLE)
+            if (opt & SO_PAIRABLE) {
+                (void)printf("%cPAIRABLE", sep);
+                opt &= ~SO_PAIRABLE;
+                sep = ',';
+            }
+#        endif /* defined(SO_PAIRABLE) */
+
+#        if defined(SO_RESVPORT)
+            if (opt & SO_RESVPORT) {
+                (void)printf("%cRESVPORT", sep);
+                opt &= ~SO_RESVPORT;
+                sep = ',';
+            }
+#        endif /* defined(SO_RESVPORT) */
+
+#        if defined(SO_NOREUSEADDR)
+            if (opt & SO_NOREUSEADDR) {
+                (void)printf("%cNOREUSEADDR", sep);
+                opt &= ~SO_NOREUSEADDR;
+                sep = ',';
+            }
+#        endif /* defined(SO_NOREUSEADDR) */
+
+#        if defined(SO_NOSIGPIPE)
+            if (opt & SO_NOSIGPIPE) {
+                (void)printf("%cNOSIGPIPE", sep);
+                opt &= ~SO_NOSIGPIPE;
+                sep = ',';
+            }
+#        endif /* defined(SO_NOSIGPIPE) */
+
+#        if defined(SO_OOBINLINE)
+            if (opt & SO_OOBINLINE) {
+                (void)printf("%cOOBINLINE", sep);
+                opt &= ~SO_OOBINLINE;
+                sep = ',';
+            }
+#        endif /* defined(SO_OOBINLINE) */
+
+#        if defined(SO_ORDREL)
+            if (opt & SO_ORDREL) {
+                (void)printf("%cORDREL", sep);
+                opt &= ~SO_ORDREL;
+                sep = ',';
+            }
+#        endif /* defined(SO_ORDREL) */
+
+            if (Lf->lts.pqlens) {
+                (void)printf("%cPQLEN=%u", sep, Lf->lts.pqlen);
+                sep = ',';
+            }
+            if (Lf->lts.qlens) {
+                (void)printf("%cQLEN=%u", sep, Lf->lts.qlen);
+                sep = ',';
+            }
+            if (Lf->lts.qlims) {
+                (void)printf("%cQLIM=%u", sep, Lf->lts.qlim);
+                sep = ',';
+            }
+            if (Lf->lts.rbszs) {
+                (void)printf("%cRCVBUF=%lu", sep, Lf->lts.rbsz);
+                sep = ',';
+            }
+
+#        if defined(SO_REUSEADDR)
+            if (opt & SO_REUSEADDR) {
+                (void)printf("%cREUSEADDR", sep);
+                opt &= ~SO_REUSEADDR;
+                sep = ',';
+            }
+#        endif /* defined(SO_REUSEADDR) */
+
+#        if defined(SO_REUSEALIASPORT)
+            if (opt & SO_REUSEALIASPORT) {
+                (void)printf("%cREUSEALIASPORT", sep);
+                opt &= ~SO_REUSEALIASPORT;
+                sep = ',';
+            }
+#        endif /* defined(SO_REUSEALIASPORT) */
+
+#        if defined(SO_REUSEPORT)
+            if (opt & SO_REUSEPORT) {
+                (void)printf("%cREUSEPORT", sep);
+                opt &= ~SO_REUSEPORT;
+                sep = ',';
+            }
+#        endif /* defined(SO_REUSEPORT) */
+
+#        if defined(SO_REUSERAD)
+            if (opt & SO_REUSERAD) {
+                (void)printf("%cREUSERAD", sep);
+                opt &= ~SO_REUSERAD;
+                sep = ',';
+            }
+#        endif /* defined(SO_REUSERAD) */
+
+#        if defined(SO_SECURITY_REQUEST)
+            if (opt & SO_SECURITY_REQUEST) {
+                (void)printf("%cSECURITY_REQUEST", sep);
+                opt &= ~SO_SECURITY_REQUEST;
+                sep = ',';
+            }
+#        endif /* defined(SO_SECURITY_REQUEST) */
+
+            if (Lf->lts.sbszs) {
+                (void)printf("%cSNDBUF=%lu", sep, Lf->lts.sbsz);
+                sep = ',';
+            }
+
+#        if defined(SO_TIMESTAMP)
+            if (opt & SO_TIMESTAMP) {
+                (void)printf("%cTIMESTAMP", sep);
+                opt &= ~SO_TIMESTAMP;
+                sep = ',';
+            }
+#        endif /* defined(SO_TIMESTAMP) */
+
+#        if defined(SO_UMC)
+            if (opt & SO_UMC) {
+                (void)printf("%cUMC", sep);
+                opt &= ~SO_UMC;
+                sep = ',';
+            }
+#        endif /* defined(SO_UMC) */
+
+#        if defined(SO_USE_IFBUFS)
+            if (opt & SO_USE_IFBUFS) {
+                (void)printf("%cUSE_IFBUFS", sep);
+                opt &= ~SO_USE_IFBUFS;
+                sep = ',';
+            }
+#        endif /* defined(SO_USE_IFBUFS) */
+
+#        if defined(SO_USELOOPBACK)
+            if (opt & SO_USELOOPBACK) {
+                (void)printf("%cUSELOOPBACK", sep);
+                opt &= ~SO_USELOOPBACK;
+                sep = ',';
+            }
+#        endif /* defined(SO_USELOOPBACK) */
+
+#        if defined(SO_WANTMORE)
+            if (opt & SO_WANTMORE) {
+                (void)printf("%cWANTMORE", sep);
+                opt &= ~SO_WANTMORE;
+                sep = ',';
+            }
+#        endif /* defined(SO_WANTMORE) */
+
+#        if defined(SO_WANTOOBFLAG)
+            if (opt & SO_WANTOOBFLAG) {
+                (void)printf("%cWANTOOBFLAG", sep);
+                opt &= ~SO_WANTOOBFLAG;
+                sep = ',';
+            }
+#        endif /* defined(SO_WANTOOBFLAG) */
+
+            if (opt)
+                (void)printf("%cUNKNOWN=%#x", sep, opt);
+            if (Ffield)
+                putchar(Terminator);
+        }
+    }
+#    endif /* defined(HASSOOPT) */
+
+#    if defined(HASSOSTATE)
+    if (Ftcptpi & TCPTPI_FLAGS) {
+        unsigned int ss;
+
+        if ((ss = Lf->lts.ss)) {
+            char sep = ' ';
+
+            if (Ffield)
+                sep = LSOF_FID_TCPTPI;
+            else if (!ps)
+                sep = '(';
+            (void)printf("%cSS", sep);
+            ps++;
+            sep = '=';
+
+#        if defined(SS_ASYNC)
+            if (ss & SS_ASYNC) {
+                (void)printf("%cASYNC", sep);
+                ss &= ~SS_ASYNC;
+                sep = ',';
+            }
+#        endif /* defined(SS_ASYNC) */
+
+#        if defined(SS_BOUND)
+            if (ss & SS_BOUND) {
+                (void)printf("%cBOUND", sep);
+                ss &= ~SS_BOUND;
+                sep = ',';
+            }
+#        endif /* defined(SS_BOUND) */
+
+#        if defined(HASSBSTATE)
+#            if defined(SBS_CANTRCVMORE)
+            if (Lf->lts.sbs_rcv & SBS_CANTRCVMORE) {
+                (void)printf("%cCANTRCVMORE", sep);
+                Lf->lts.sbs_rcv &= ~SBS_CANTRCVMORE;
+                sep = ',';
+            }
+#            endif /* defined(SBS_CANTRCVMORE) */
+
+#            if defined(SBS_CANTSENDMORE)
+            if (Lf->lts.sbs_snd & SBS_CANTSENDMORE) {
+                (void)printf("%cCANTSENDMORE", sep);
+                Lf->lts.sbs_snd &= ~SBS_CANTSENDMORE;
+                sep = ',';
+            }
+#            endif /* defined(SS_CANTSENDMORE) */
+#        else      /* !defined(HASSBSTATE) */
+
+#            if defined(SS_CANTRCVMORE)
+            if (ss & SS_CANTRCVMORE) {
+                (void)printf("%cCANTRCVMORE", sep);
+                ss &= ~SS_CANTRCVMORE;
+                sep = ',';
+            }
+#            endif /* defined(SS_CANTRCVMORE) */
+
+#            if defined(SS_CANTSENDMORE)
+            if (ss & SS_CANTSENDMORE) {
+                (void)printf("%cCANTSENDMORE", sep);
+                ss &= ~SS_CANTSENDMORE;
+                sep = ',';
+            }
+#            endif /* defined(SS_CANTSENDMORE) */
+#        endif     /* defined(HASSBSTATE) */
+
+#        if defined(SS_COMP)
+            if (ss & SS_COMP) {
+                (void)printf("%cCOMP", sep);
+                ss &= ~SS_COMP;
+                sep = ',';
+            }
+#        endif /* defined(SS_COMP) */
+
+#        if defined(SS_CONNECTOUT)
+            if (ss & SS_CONNECTOUT) {
+                (void)printf("%cCONNECTOUT", sep);
+                ss &= ~SS_CONNECTOUT;
+                sep = ',';
+            }
+#        endif /* defined(SS_CONNECTOUT) */
+
+#        if defined(SS_HIPRI)
+            if (ss & SS_HIPRI) {
+                (void)printf("%cHIPRI", sep);
+                ss &= ~SS_HIPRI;
+                sep = ',';
+            }
+#        endif /* defined(SS_HIPRI) */
+
+#        if defined(SS_IGNERR)
+            if (ss & SS_IGNERR) {
+                (void)printf("%cIGNERR", sep);
+                ss &= ~SS_IGNERR;
+                sep = ',';
+            }
+#        endif /* defined(SS_IGNERR) */
+
+#        if defined(SS_INCOMP)
+            if (ss & SS_INCOMP) {
+                (void)printf("%cINCOMP", sep);
+                ss &= ~SS_INCOMP;
+                sep = ',';
+            }
+#        endif /* defined(SS_INCOMP) */
+
+#        if defined(SS_IOCWAIT)
+            if (ss & SS_IOCWAIT) {
+                (void)printf("%cIOCWAIT", sep);
+                ss &= ~SS_IOCWAIT;
+                sep = ',';
+            }
+#        endif /* defined(SS_IOCWAIT) */
+
+#        if defined(SS_ISCONFIRMING)
+            if (ss & SS_ISCONFIRMING) {
+                (void)printf("%cISCONFIRMING", sep);
+                ss &= ~SS_ISCONFIRMING;
+                sep = ',';
+            }
+#        endif /* defined(SS_ISCONFIRMING) */
+
+#        if defined(SS_ISCONNECTED)
+            if (ss & SS_ISCONNECTED) {
+                (void)printf("%cISCONNECTED", sep);
+                ss &= ~SS_ISCONNECTED;
+                sep = ',';
+            }
+#        endif /* defined(SS_ISCONNECTED) */
+
+#        if defined(SS_ISCONNECTING)
+            if (ss & SS_ISCONNECTING) {
+                (void)printf("%cISCONNECTING", sep);
+                ss &= ~SS_ISCONNECTING;
+                sep = ',';
+            }
+#        endif /* defined(SS_ISCONNECTING) */
+
+#        if defined(SS_ISDISCONNECTING)
+            if (ss & SS_ISDISCONNECTING) {
+                (void)printf("%cISDISCONNECTING", sep);
+                ss &= ~SS_ISDISCONNECTING;
+                sep = ',';
+            }
+#        endif /* defined(SS_ISDISCONNECTING) */
+
+#        if defined(SS_MORETOSEND)
+            if (ss & SS_MORETOSEND) {
+                (void)printf("%cMORETOSEND", sep);
+                ss &= ~SS_MORETOSEND;
+                sep = ',';
+            }
+#        endif /* defined(SS_MORETOSEND) */
+
+#        if defined(SS_NBIO)
+            if (ss & SS_NBIO) {
+                (void)printf("%cNBIO", sep);
+                ss &= ~SS_NBIO;
+                sep = ',';
+            }
+#        endif /* defined(SS_NBIO) */
+
+#        if defined(SS_NOCONN)
+            if (ss & SS_NOCONN) {
+                (void)printf("%cNOCONN", sep);
+                ss &= ~SS_NOCONN;
+                sep = ',';
+            }
+#        endif /* defined(SS_NOCONN) */
+
+#        if defined(SS_NODELETE)
+            if (ss & SS_NODELETE) {
+                (void)printf("%cNODELETE", sep);
+                ss &= ~SS_NODELETE;
+                sep = ',';
+            }
+#        endif /* defined(SS_NODELETE) */
+
+#        if defined(SS_NOFDREF)
+            if (ss & SS_NOFDREF) {
+                (void)printf("%cNOFDREF", sep);
+                ss &= ~SS_NOFDREF;
+                sep = ',';
+            }
+#        endif /* defined(SS_NOFDREF) */
+
+#        if defined(SS_NOGHOST)
+            if (ss & SS_NOGHOST) {
+                (void)printf("%cNOGHOST", sep);
+                ss &= ~SS_NOGHOST;
+                sep = ',';
+            }
+#        endif /* defined(SS_NOGHOST) */
+
+#        if defined(SS_NOINPUT)
+            if (ss & SS_NOINPUT) {
+                (void)printf("%cNOINPUT", sep);
+                ss &= ~SS_NOINPUT;
+                sep = ',';
+            }
+#        endif /* defined(SS_NOINPUT) */
+
+#        if defined(SS_PRIV)
+            if (ss & SS_PRIV) {
+                (void)printf("%cPRIV", sep);
+                ss &= ~SS_PRIV;
+                sep = ',';
+            }
+#        endif /* defined(SS_PRIV) */
+
+#        if defined(SS_QUEUE)
+            if (ss & SS_QUEUE) {
+                (void)printf("%cQUEUE", sep);
+                ss &= ~SS_QUEUE;
+                sep = ',';
+            }
+#        endif /* defined(SS_QUEUE) */
+
+#        if defined(HASSBSTATE)
+#            if defined(SBS_RCVATMARK)
+            if (Lf->lts.sbs_rcv & SBS_RCVATMARK) {
+                (void)printf("%cRCVATMARK", sep);
+                Lf->lts.sbs_rcv &= ~SBS_RCVATMARK;
+                sep = ',';
+            }
+#            endif /* defined(SBS_RCVATMARK) */
+
+#        else /* !defined(HASSBSTATE) */
+#            if defined(SS_RCVATMARK)
+            if (ss & SS_RCVATMARK) {
+                (void)printf("%cRCVATMARK", sep);
+                ss &= ~SS_RCVATMARK;
+                sep = ',';
+            }
+#            endif /* defined(SS_RCVATMARK) */
+#        endif     /* defined(HASSBSTATE) */
+
+#        if defined(SS_READWAIT)
+            if (ss & SS_READWAIT) {
+                (void)printf("%cREADWAIT", sep);
+                ss &= ~SS_READWAIT;
+                sep = ',';
+            }
+#        endif /* defined(SS_READWAIT) */
+
+#        if defined(SS_SETRCV)
+            if (ss & SS_SETRCV) {
+                (void)printf("%cSETRCV", sep);
+                ss &= ~SS_SETRCV;
+                sep = ',';
+            }
+#        endif /* defined(SS_SETRCV) */
+
+#        if defined(SS_SETSND)
+            if (ss & SS_SETSND) {
+                (void)printf("%cSETSND", sep);
+                ss &= ~SS_SETSND;
+                sep = ',';
+            }
+#        endif /* defined(SS_SETSND) */
+
+#        if defined(SS_SIGREAD)
+            if (ss & SS_SIGREAD) {
+                (void)printf("%cSIGREAD", sep);
+                ss &= ~SS_SIGREAD;
+                sep = ',';
+            }
+#        endif /* defined(SS_SIGREAD) */
+
+#        if defined(SS_SIGWRITE)
+            if (ss & SS_SIGWRITE) {
+                (void)printf("%cSIGWRITE", sep);
+                ss &= ~SS_SIGWRITE;
+                sep = ',';
+            }
+#        endif /* defined(SS_SIGWRITE) */
+
+#        if defined(SS_SPLICED)
+            if (ss & SS_SPLICED) {
+                (void)printf("%cSPLICED", sep);
+                ss &= ~SS_SPLICED;
+                sep = ',';
+            }
+#        endif /* defined(SS_SPLICED) */
+
+#        if defined(SS_WRITEWAIT)
+            if (ss & SS_WRITEWAIT) {
+                (void)printf("%cWRITEWAIT", sep);
+                ss &= ~SS_WRITEWAIT;
+                sep = ',';
+            }
+#        endif /* defined(SS_WRITEWAIT) */
+
+#        if defined(SS_ZOMBIE)
+            if (ss & SS_ZOMBIE) {
+                (void)printf("%cZOMBIE", sep);
+                ss &= ~SS_ZOMBIE;
+                sep = ',';
+            }
+#        endif /* defined(SS_ZOMBIE) */
+
+            if (ss)
+                (void)printf("%cUNKNOWN=%#x", sep, ss);
+            if (Ffield)
+                putchar(Terminator);
+        }
+    }
+#    endif /* defined(HASSOSTATE) */
+
+#    if defined(HASTCPOPT)
+    if (Ftcptpi & TCPTPI_FLAGS) {
+        int topt;
+
+        if ((topt = Lf->lts.topt) || Lf->lts.msss) {
+            char sep = ' ';
+
+            if (Ffield)
+                sep = LSOF_FID_TCPTPI;
+            else if (!ps)
+                sep = '(';
+            (void)printf("%cTF", sep);
+            ps++;
+            sep = '=';
+
+#        if defined(TF_ACKNOW)
+            if (topt & TF_ACKNOW) {
+                (void)printf("%cACKNOW", sep);
+                topt &= ~TF_ACKNOW;
+                sep = ',';
+            }
+#        endif /* defined(TF_ACKNOW) */
+
+#        if defined(TF_CANT_TXSACK)
+            if (topt & TF_CANT_TXSACK) {
+                (void)printf("%cCANT_TXSACK", sep);
+                topt &= ~TF_CANT_TXSACK;
+                sep = ',';
+            }
+#        endif /* defined(TF_CANT_TXSACK) */
+
+#        if defined(TF_DEAD)
+            if (topt & TF_DEAD) {
+                (void)printf("%cDEAD", sep);
+                topt &= ~TF_DEAD;
+                sep = ',';
+            }
+#        endif /* defined(TF_DEAD) */
+
+#        if defined(TF_DELACK)
+            if (topt & TF_DELACK) {
+                (void)printf("%cDELACK", sep);
+                topt &= ~TF_DELACK;
+                sep = ',';
+            }
+#        endif /* defined(TF_DELACK) */
+
+#        if defined(TF_DELAY_ACK)
+            if (topt & TF_DELAY_ACK) {
+                (void)printf("%cDELAY_ACK", sep);
+                topt &= ~TF_DELAY_ACK;
+                sep = ',';
+            }
+#        endif /* defined(TF_DELAY_ACK) */
+
+#        if defined(TF_DISABLE_ECN)
+            if (topt & TF_DISABLE_ECN) {
+                (void)printf("%cDISABLE_ECN", sep);
+                topt &= ~TF_DISABLE_ECN;
+                sep = ',';
+            }
+#        endif /* defined(TF_DISABLE_ECN) */
+
+#        if defined(TF_ECN)
+            if (topt & TF_ECN) {
+                (void)printf("%cECN", sep);
+                topt &= ~TF_ECN;
+                sep = ',';
+            }
+#        endif /* defined(TF_ECN) */
+
+#        if defined(TF_ECN_PERMIT)
+            if (topt & TF_ECN_PERMIT) {
+                (void)printf("%cECN_PERMIT", sep);
+                topt &= ~TF_ECN_PERMIT;
+                sep = ',';
+            }
+#        endif /* defined(TF_ECN_PERMIT) */
+
+#        if defined(TF_FASTRECOVERY)
+            if (topt & TF_FASTRECOVERY) {
+                (void)printf("%cFASTRECOVERY", sep);
+                topt &= ~TF_FASTRECOVERY;
+                sep = ',';
+            }
+#        endif /* defined(TF_FASTRECOVERY) */
+
+#        if defined(TF_FASTRXMT_PHASE)
+            if (topt & TF_FASTRXMT_PHASE) {
+                (void)printf("%cFASTRXMT_PHASE", sep);
+                topt &= ~TF_FASTRXMT_PHASE;
+                sep = ',';
+            }
+#        endif /* defined(TF_FASTRXMT_PHASE) */
+
+#        if defined(TF_HAVEACKED)
+            if (topt & TF_HAVEACKED) {
+                (void)printf("%cHAVEACKED", sep);
+                topt &= ~TF_HAVEACKED;
+                sep = ',';
+            }
+#        endif /* defined(TF_HAVEACKED) */
+
+#        if defined(TF_HAVECLOSED)
+            if (topt & TF_HAVECLOSED) {
+                (void)printf("%cHAVECLOSED", sep);
+                topt &= ~TF_HAVECLOSED;
+                sep = ',';
+            }
+#        endif /* defined(TF_HAVECLOSED) */
+
+#        if defined(TF_IGNR_RXSACK)
+            if (topt & TF_IGNR_RXSACK) {
+                (void)printf("%cIGNR_RXSACK", sep);
+                topt &= ~TF_IGNR_RXSACK;
+                sep = ',';
+            }
+#        endif /* defined(TF_IGNR_RXSACK) */
+
+#        if defined(TF_IOLOCK)
+            if (topt & TF_IOLOCK) {
+                (void)printf("%cIOLOCK", sep);
+                topt &= ~TF_IOLOCK;
+                sep = ',';
+            }
+#        endif /* defined(TF_IOLOCK) */
+
+#        if defined(TF_LARGESEND)
+            if (topt & TF_LARGESEND) {
+                (void)printf("%cLARGESEND", sep);
+                topt &= ~TF_LARGESEND;
+                sep = ',';
+            }
+#        endif /* defined(TF_LARGESEND) */
+
+#        if defined(TF_LASTIDLE)
+            if (topt & TF_LASTIDLE) {
+                (void)printf("%cLASTIDLE", sep);
+                topt &= ~TF_LASTIDLE;
+                sep = ',';
+            }
+#        endif /* defined(TF_LASTIDLE) */
+
+#        if defined(TF_LQ_OVERFLOW)
+            if (topt & TF_LQ_OVERFLOW) {
+                (void)printf("%cLQ_OVERFLOW", sep);
+                topt &= ~TF_LQ_OVERFLOW;
+                sep = ',';
+            }
+#        endif /* defined(TF_LQ_OVERFLOW) */
+
+            if (Lf->lts.msss) {
+                (void)printf("%cMSS=%lu", sep, Lf->lts.mss);
+                sep = ',';
+            }
+
+#        if defined(TF_MORETOCOME)
+            if (topt & TF_MORETOCOME) {
+                (void)printf("%cMORETOCOME", sep);
+                topt &= ~TF_MORETOCOME;
+                sep = ',';
+            }
+#        endif /* defined(TF_MORETOCOME) */
+
+#        if defined(TF_NEEDACK)
+            if (topt & TF_NEEDACK) {
+                (void)printf("%cNEEDACK", sep);
+                topt &= ~TF_NEEDACK;
+                sep = ',';
+            }
+#        endif /* defined(TF_NEEDACK) */
+
+#        if defined(TF_NEEDCLOSE)
+            if (topt & TF_NEEDCLOSE) {
+                (void)printf("%cNEEDCLOSE", sep);
+                topt &= ~TF_NEEDCLOSE;
+                sep = ',';
+            }
+#        endif /* defined(TF_NEEDCLOSE) */
+
+#        if defined(TF_NEEDFIN)
+            if (topt & TF_NEEDFIN) {
+                (void)printf("%cNEEDFIN", sep);
+                topt &= ~TF_NEEDFIN;
+                sep = ',';
+            }
+#        endif /* defined(TF_NEEDFIN) */
+
+#        if defined(TF_NEEDIN)
+            if (topt & TF_NEEDIN) {
+                (void)printf("%cNEEDIN", sep);
+                topt &= ~TF_NEEDIN;
+                sep = ',';
+            }
+#        endif /* defined(TF_NEEDIN) */
+
+#        if defined(TF_NEEDOUT)
+            if (topt & TF_NEEDOUT) {
+                (void)printf("%cNEEDOUT", sep);
+                topt &= ~TF_NEEDOUT;
+                sep = ',';
+            }
+#        endif /* defined(TF_NEEDOUT) */
+
+#        if defined(TF_NEEDSYN)
+            if (topt & TF_NEEDSYN) {
+                (void)printf("%cNEEDSYN", sep);
+                topt &= ~TF_NEEDSYN;
+                sep = ',';
+            }
+#        endif /* defined(TF_NEEDSYN) */
+
+#        if defined(TF_NEEDTIMER)
+            if (topt & TF_NEEDTIMER) {
+                (void)printf("%cNEEDTIMER", sep);
+                topt &= ~TF_NEEDTIMER;
+                sep = ',';
+            }
+#        endif /* defined(TF_NEEDTIMER) */
+
+#        if defined(TF_NEWRENO_RXMT)
+            if (topt & TF_NEWRENO_RXMT) {
+                (void)printf("%cNEWRENO_RXMT", sep);
+                topt &= ~TF_NEWRENO_RXMT;
+                sep = ',';
+            }
+#        endif /* defined(TF_NEWRENO_RXMT) */
+
+#        if defined(TF_NODELACK)
+            if (topt & TF_NODELACK) {
+                (void)printf("%cNODELACK", sep);
+                topt &= ~TF_NODELACK;
+                sep = ',';
+            }
+#        endif /* defined(TF_NODELACK) */
+
+#        if defined(TF_NODELAY)
+            if (topt & TF_NODELAY) {
+                (void)printf("%cNODELAY", sep);
+                topt &= ~TF_NODELAY;
+                sep = ',';
+            }
+#        endif /* defined(TF_NODELAY) */
+
+#        if defined(TF_NOOPT)
+            if (topt & TF_NOOPT) {
+                (void)printf("%cNOOPT", sep);
+                topt &= ~TF_NOOPT;
+                sep = ',';
+            }
+#        endif /* defined(TF_NOOPT) */
+
+#        if defined(TF_NOPUSH)
+            if (topt & TF_NOPUSH) {
+                (void)printf("%cNOPUSH", sep);
+                topt &= ~TF_NOPUSH;
+                sep = ',';
+            }
+#        endif /* defined(TF_NOPUSH) */
+
+#        if defined(TF_NO_PMTU)
+            if (topt & TF_NO_PMTU) {
+                (void)printf("%cNO_PMTU", sep);
+                topt &= ~TF_NO_PMTU;
+                sep = ',';
+            }
+#        endif /* defined(TF_NO_PMTU) */
+
+#        if defined(TF_RAW)
+            if (topt & TF_RAW) {
+                (void)printf("%cRAW", sep);
+                topt &= ~TF_RAW;
+                sep = ',';
+            }
+#        endif /* defined(TF_RAW) */
+
+#        if defined(TF_RCVD_CC)
+            if (topt & TF_RCVD_CC) {
+                (void)printf("%cRCVD_CC", sep);
+                topt &= ~TF_RCVD_CC;
+                sep = ',';
+            }
+#        endif /* defined(TF_RCVD_CC) */
+
+#        if defined(TF_RCVD_SCALE)
+            if (topt & TF_RCVD_SCALE) {
+                (void)printf("%cRCVD_SCALE", sep);
+                topt &= ~TF_RCVD_SCALE;
+                sep = ',';
+            }
+#        endif /* defined(TF_RCVD_SCALE) */
+
+#        if defined(TF_RCVD_CE)
+            if (topt & TF_RCVD_CE) {
+                (void)printf("%cRCVD_CE", sep);
+                topt &= ~TF_RCVD_CE;
+                sep = ',';
+            }
+#        endif /* defined(TF_RCVD_CE) */
+
+#        if defined(TF_RCVD_TS)
+            if (topt & TF_RCVD_TS) {
+                (void)printf("%cRCVD_TS", sep);
+                topt &= ~TF_RCVD_TS;
+                sep = ',';
+            }
+#        endif /* defined(TF_RCVD_TS) */
+
+#        if defined(TF_RCVD_TSTMP)
+            if (topt & TF_RCVD_TSTMP) {
+                (void)printf("%cRCVD_TSTMP", sep);
+                topt &= ~TF_RCVD_TSTMP;
+                sep = ',';
+            }
+#        endif /* defined(TF_RCVD_TSTMP) */
+
+#        if defined(TF_RCVD_WS)
+            if (topt & TF_RCVD_WS) {
+                (void)printf("%cRCVD_WS", sep);
+                topt &= ~TF_RCVD_WS;
+                sep = ',';
+            }
+#        endif /* defined(TF_RCVD_WS) */
+
+#        if defined(TF_REASSEMBLING)
+            if (topt & TF_REASSEMBLING) {
+                (void)printf("%cREASSEMBLING", sep);
+                topt &= ~TF_REASSEMBLING;
+                sep = ',';
+            }
+#        endif /* defined(TF_REASSEMBLING) */
+
+#        if defined(TF_REQ_CC)
+            if (topt & TF_REQ_CC) {
+                (void)printf("%cREQ_CC", sep);
+                topt &= ~TF_REQ_CC;
+                sep = ',';
+            }
+#        endif /* defined(TF_REQ_CC) */
+
+#        if defined(TF_REQ_SCALE)
+            if (topt & TF_REQ_SCALE) {
+                (void)printf("%cREQ_SCALE", sep);
+                topt &= ~TF_REQ_SCALE;
+                sep = ',';
+            }
+#        endif /* defined(TF_REQ_SCALE) */
+
+#        if defined(TF_REQ_TSTMP)
+            if (topt & TF_REQ_TSTMP) {
+                (void)printf("%cREQ_TSTMP", sep);
+                topt &= ~TF_REQ_TSTMP;
+                sep = ',';
+            }
+#        endif /* defined(TF_REQ_TSTMP) */
+
+#        if defined(TF_RFC1323)
+            if (topt & TF_RFC1323) {
+                (void)printf("%cRFC1323", sep);
+                topt &= ~TF_RFC1323;
+                sep = ',';
+            }
+#        endif /* defined(TF_RFC1323) */
+
+#        if defined(TF_RXWIN0SENT)
+            if (topt & TF_RXWIN0SENT) {
+                (void)printf("%cRXWIN0SENT", sep);
+                topt &= ~TF_RXWIN0SENT;
+                sep = ',';
+            }
+#        endif /* defined(TF_RXWIN0SENT) */
+
+#        if defined(TF_SACK_GENERATE)
+            if (topt & TF_SACK_GENERATE) {
+                (void)printf("%cSACK_GENERATE", sep);
+                topt &= ~TF_SACK_GENERATE;
+                sep = ',';
+            }
+#        endif /* defined(TF_SACK_GENERATE) */
+
+#        if defined(TF_SACK_PERMIT)
+            if (topt & TF_SACK_PERMIT) {
+                (void)printf("%cSACK_PERMIT", sep);
+                topt &= ~TF_SACK_PERMIT;
+                sep = ',';
+            }
+#        endif /* defined(TF_SACK_PERMIT) */
+
+#        if defined(TF_SACK_PROCESS)
+            if (topt & TF_SACK_PROCESS) {
+                (void)printf("%cSACK_PROCESS", sep);
+                topt &= ~TF_SACK_PROCESS;
+                sep = ',';
+            }
+#        endif /* defined(TF_SACK_PROCESS) */
+
+#        if defined(TF_SEND)
+            if (topt & TF_SEND) {
+                (void)printf("%cSEND", sep);
+                topt &= ~TF_SEND;
+                sep = ',';
+            }
+#        endif /* defined(TF_SEND) */
+
+#        if defined(TF_SEND_AND_DISCONNECT)
+            if (topt & TF_SEND_AND_DISCONNECT) {
+                (void)printf("%cSEND_AND_DISCONNECT", sep);
+                topt &= ~TF_SEND_AND_DISCONNECT;
+                sep = ',';
+            }
+#        endif /* defined(TF_SEND_AND_DISCONNECT) */
+
+#        if defined(TF_SENDCCNEW)
+            if (topt & TF_SENDCCNEW) {
+                (void)printf("%cSENDCCNEW", sep);
+                topt &= ~TF_SENDCCNEW;
+                sep = ',';
+            }
+#        endif /* defined(TF_SENDCCNEW) */
+
+#        if defined(TF_SEND_CWR)
+            if (topt & TF_SEND_CWR) {
+                (void)printf("%cSEND_CWR", sep);
+                topt &= ~TF_SEND_CWR;
+                sep = ',';
+            }
+#        endif /* defined(TF_SEND_CWR) */
+
+#        if defined(TF_SEND_ECHO)
+            if (topt & TF_SEND_ECHO) {
+                (void)printf("%cSEND_ECHO", sep);
+                topt &= ~TF_SEND_ECHO;
+                sep = ',';
+            }
+#        endif /* defined(TF_SEND_ECHO) */
+
+#        if defined(TF_SEND_TSTMP)
+            if (topt & TF_SEND_TSTMP) {
+                (void)printf("%cSEND_TSTMP", sep);
+                topt &= ~TF_SEND_TSTMP;
+                sep = ',';
+            }
+#        endif /* defined(TF_SEND_TSTMP) */
+
+#        if defined(TF_SENTFIN)
+            if (topt & TF_SENTFIN) {
+                (void)printf("%cSENTFIN", sep);
+                topt &= ~TF_SENTFIN;
+                sep = ',';
+            }
+#        endif /* defined(TF_SENTFIN) */
+
+#        if defined(TF_SENT_TS)
+            if (topt & TF_SENT_TS) {
+                (void)printf("%cSENT_TS", sep);
+                topt &= ~TF_SENT_TS;
+                sep = ',';
+            }
+#        endif /* defined(TF_SENT_TS) */
+
+#        if defined(TF_SENT_WS)
+            if (topt & TF_SENT_WS) {
+                (void)printf("%cSENT_WS", sep);
+                topt &= ~TF_SENT_WS;
+                sep = ',';
+            }
+#        endif /* defined(TF_SENT_WS) */
+
+#        if defined(TF_SIGNATURE)
+            if (topt & TF_SIGNATURE) {
+                (void)printf("%cSIGNATURE", sep);
+                topt &= ~TF_SIGNATURE;
+                sep = ',';
+            }
+#        endif /* defined(TF_SIGNATURE) */
+
+#        if defined(TF_SLOWLINK)
+            if (topt & TF_SLOWLINK) {
+                (void)printf("%cSLOWLINK", sep);
+                topt &= ~TF_SLOWLINK;
+                sep = ',';
+            }
+#        endif /* defined(TF_SLOWLINK) */
+
+#        if defined(TF_STDURG)
+            if (topt & TF_STDURG) {
+                (void)printf("%cSTDURG", sep);
+                topt &= ~TF_STDURG;
+                sep = ',';
+            }
+#        endif /* defined(TF_STDURG) */
+
+#        if defined(TF_SYN_REXMT)
+            if (topt & TF_SYN_REXMT) {
+                (void)printf("%cSYN_REXMT", sep);
+                topt &= ~TF_SYN_REXMT;
+                sep = ',';
+            }
+#        endif /* defined(TF_SYN_REXMT) */
+
+#        if defined(TF_UIOMOVED)
+            if (topt & TF_UIOMOVED) {
+                (void)printf("%cUIOMOVED", sep);
+                topt &= ~TF_UIOMOVED;
+                sep = ',';
+            }
+#        endif /* defined(TF_UIOMOVED) */
+
+#        if defined(TF_USE_SCALE)
+            if (topt & TF_USE_SCALE) {
+                (void)printf("%cUSE_SCALE", sep);
+                topt &= ~TF_USE_SCALE;
+                sep = ',';
+            }
+#        endif /* defined(TF_USE_SCALE) */
+
+#        if defined(TF_WASIDLE)
+            if (topt & TF_WASIDLE) {
+                (void)printf("%cWASIDLE", sep);
+                topt &= ~TF_WASIDLE;
+                sep = ',';
+            }
+#        endif /* defined(TF_WASIDLE) */
+
+#        if defined(TF_WASFRECOVERY)
+            if (topt & TF_WASFRECOVERY) {
+                (void)printf("%cWASFRECOVERY", sep);
+                topt &= ~TF_WASFRECOVERY;
+                sep = ',';
+            }
+#        endif /* defined(TF_WASFRECOVERY) */
+
+#        if defined(TF_WILL_SACK)
+            if (topt & TF_WILL_SACK) {
+                (void)printf("%cWILL_SACK", sep);
+                topt &= ~TF_WILL_SACK;
+                sep = ',';
+            }
+#        endif /* defined(TF_WILL_SACK) */
+
+            if (topt)
+                (void)printf("%cUNKNOWN=%#x", sep, topt);
+            if (Ffield)
+                putchar(Terminator);
+        }
+    }
+#    endif /* defined(HASTCPOPT) */
+
+#    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 (ps && !Ffield)
+        putchar(')');
+    if (nl)
+        putchar('\n');
+}
+#else  /* !defined(USE_LIB_PRINT_TCPTPI) */
+char ptti_d1[] = "d";
+char *ptti_d2 = ptti_d1;
+#endif /* defined(USE_LIB_PRINT_TCPTPI) */
diff --git a/src/store.c b/src/store.c
new file mode 100644 (file)
index 0000000..8e7dfd2
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * store.c - common global storage for lsof
+ */
+
+/*
+ * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by Victor A. Abell
+ *
+ * This software is not subject to any license of the American Telephone
+ * and Telegraph Company or the Regents of the University of California.
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. Neither the authors nor Purdue University are responsible for any
+ *    consequences of the use of this software.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ *    explicit claim or by omission.  Credit to the authors and Purdue
+ *    University must appear in documentation and sources.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+
+#include "common.h"
+
+/*
+ * Global storage definitions
+ */
+
+int CkPasswd = 0; /* time to check /etc/passwd for change */
+
+#if defined(HAS_STD_CLONE)
+struct clone *Clone = (struct clone *)NULL;
+/* clone device list */
+#endif /* defined(HAS_STD_CLONE) */
+
+int CmdColW;       /* COMMAND column width */
+
+#if defined(HASSELINUX)
+int CntxColW;       /* security context column width */
+int CntxStatus = 0; /* security context status: 0 == disabled,
+                     * 1 == enabled */
+#endif              /* defined(HASSELINUX) */
+
+int DChelp = 0; /* -D? status */
+
+int DevColW; /* DEVICE column width */
+
+/*
+ * Externals for a stkdir(), dumbed-down for older AIX compilers.
+ */
+
+int ErrStat = 0;  /* path stat() error count */
+uid_t Euid;       /* effective UID of this lsof process */
+int FcColW;       /* FCT column width */
+int Fcntx = 0;    /* -Z option status */
+int FdColW;       /* FD column width */
+int Ffilesys = 0; /* -f option status:
+                   *    0 = paths may be file systems
+                   *    1 = paths are just files
+                   *    2 = paths must be file systems */
+
+#if defined(HASNCACHE)
+int NcacheReload = 1; /* 1 == call ncache_load() */
+#endif                /* defined(HASNCACHE) */
+
+int Ffield = 0;  /* -f and -F status */
+int FgColW;      /* FILE-FLAG column width */
+int Fhelp = 0;   /* -h option status */
+int Fhost = 1;   /* -H option status */
+int Fnlink = 0;  /* -L option status */
+int Fport = 1;   /* -P option status */
+
+#if !defined(HASNORPC_H)
+#    if defined(HASPMAPENABLED)
+int FportMap = 1; /* +|-M option status */
+#    else         /* !defined(HASPMAPENABLED) */
+int FportMap = 0; /* +|-M option status */
+#    endif        /* defined(HASPMAPENABLED) */
+#endif            /* !defined(HASNORPC_H) */
+
+int Fpgid = 0;              /* -g option status */
+int Fppid = 0;              /* -R option status */
+int Fhuman = 0;             /* -H option status */
+int FsColW;                 /* FSTR-ADDR column width */
+int Fsv = FSV_DEFAULT;      /* file struct value selections */
+int NiColW;                 /* NODE-ID column width */
+char *NiTtl = NITTL;        /* NODE-ID column title */
+int FsearchErr = 1;         /* -Q option status */
+int Ftcptpi = TCPTPI_STATE; /* -T option status */
+int Fterse = 0;             /* -t option status */
+int Futol = 1;              /* -l option status */
+int Fverbose = 0;           /* -V option status */
+
+int Fxover = 0; /* -x option value */
+int Fzone = 0;  /* -z option status */
+
+struct fieldsel FieldSel[] = {
+    {LSOF_FID_ACCESS, 0, LSOF_FNM_ACCESS, NULL, 0},              /*  0 */
+    {LSOF_FID_CMD, 0, LSOF_FNM_CMD, NULL, 0},                    /*  1 */
+    {LSOF_FID_CT, 0, LSOF_FNM_CT, &Fsv, FSV_CT},                 /*  2 */
+    {LSOF_FID_DEVCH, 0, LSOF_FNM_DEVCH, NULL, 0},                /*  3 */
+    {LSOF_FID_DEVN, 0, LSOF_FNM_DEVN, NULL, 0},                  /*  4 */
+    {LSOF_FID_FD, 0, LSOF_FNM_FD, NULL, 0},                      /*  5 */
+    {LSOF_FID_FA, 0, LSOF_FNM_FA, &Fsv, FSV_FA},                 /*  6 */
+    {LSOF_FID_FG, 0, LSOF_FNM_FG, &Fsv, FSV_FG},                 /*  7 */
+    {LSOF_FID_INODE, 0, LSOF_FNM_INODE, NULL, 0},                /*  8 */
+    {LSOF_FID_NLINK, 0, LSOF_FNM_NLINK, &Fnlink, 1},             /*  9 */
+    {LSOF_FID_TID, 0, LSOF_FNM_TID, NULL, 0},                    /* 11 */
+    {LSOF_FID_LOCK, 0, LSOF_FNM_LOCK, NULL, 0},                  /* 11 */
+    {LSOF_FID_LOGIN, 0, LSOF_FNM_LOGIN, NULL, 0},                /* 12 */
+    {LSOF_FID_MARK, 1, LSOF_FNM_MARK, NULL, 0},                  /* 13 */
+    {LSOF_FID_TCMD, 0, LSOF_FNM_TCMD, NULL, 0},                  /* 14 */
+    {LSOF_FID_NAME, 0, LSOF_FNM_NAME, NULL, 0},                  /* 15 */
+    {LSOF_FID_NI, 0, LSOF_FNM_NI, &Fsv, FSV_NI},                 /* 16 */
+    {LSOF_FID_OFFSET, 0, LSOF_FNM_OFFSET, NULL, 0},              /* 17 */
+    {LSOF_FID_PID, 1, LSOF_FNM_PID, NULL, 0},                    /* 18 */
+    {LSOF_FID_PGID, 0, LSOF_FNM_PGID, &Fpgid, 1},                /* 19 */
+    {LSOF_FID_PROTO, 0, LSOF_FNM_PROTO, NULL, 0},                /* 20 */
+    {LSOF_FID_RDEV, 0, LSOF_FNM_RDEV, NULL, 0},                  /* 21 */
+    {LSOF_FID_PPID, 0, LSOF_FNM_PPID, &Fppid, 1},                /* 22 */
+    {LSOF_FID_SIZE, 0, LSOF_FNM_SIZE, NULL, 0},                  /* 23 */
+    {LSOF_FID_STREAM, 0, LSOF_FNM_STREAM, NULL, 0},              /* 24 */
+    {LSOF_FID_TYPE, 0, LSOF_FNM_TYPE, NULL, 0},                  /* 25 */
+    {LSOF_FID_TCPTPI, 0, LSOF_FNM_TCPTPI, &Ftcptpi, TCPTPI_ALL}, /* 26 */
+    {LSOF_FID_UID, 0, LSOF_FNM_UID, NULL, 0},                    /* 27 */
+    {LSOF_FID_ZONE, 0, LSOF_FNM_ZONE, &Fzone, 1},                /* 28 */
+    {LSOF_FID_CNTX, 0, LSOF_FNM_CNTX, &Fcntx, 1},                /* 29 */
+    {LSOF_FID_TERM, 0, LSOF_FNM_TERM, NULL, 0},                  /* 30 */
+    {' ', 0, NULL, NULL, 0}};
+
+int Hdr = 0; /* header print status */
+char *InodeFmt_d = (char *)NULL;
+/* INODETYPE decimal printf specification */
+char *InodeFmt_x = (char *)NULL;
+/* INODETYPE hexadecimal printf specification */
+int LastPid = -1; /* last PID listed (for eliminating duplicates
+                   * in terse output) */
+
+int NlColW;                /* NLINK column width */
+int NmColW;                /* NAME column width */
+int NodeColW;              /* NODE column width */
+int OffDecDig = OFFDECDIG; /* offset decimal form (0t...) digit limit */
+int OffColW;               /* OFFSET column width */
+int PgidColW;              /* PGID column width */
+int PidColW;               /* PID column width */
+int PpidColW;              /* PPID column width */
+
+int PrPass = 0;                   /* print pass: 0 = compute column widths
+                                   *          1 = print */
+int RptMaxCount = 0;              /* count of repeasts: 0 = no limit
+                                   * -- set by -r */
+int SzColW;                       /* SIZE column width */
+int SzOffColW;                    /* SIZE/OFF column width */
+char *SzOffFmt_0t = (char *)NULL; /* SZOFFTYPE 0t%u printf specification */
+char *SzOffFmt_d = (char *)NULL;  /* SZOFFTYPE %d printf specification */
+char *SzOffFmt_dv = (char *)NULL; /* SZOFFTYPE %*d printf specification */
+char *SzOffFmt_x = (char *)NULL;  /* SZOFFTYPE %#x printf specification */
+int TaskCmdColW = 0;              /* task command column width */
+int TaskCmdLim = TASKCMDL;        /* TASKCMD column width limit (same as
+                                   * CmdLim) */
+int TaskPrtCmd = 0;               /* task print task command flag */
+int TaskPrtTid = 0;               /* task print TID flag */
+char Terminator = '\n';           /* output field terminator */
+int TaskTidColW = 0;              /* task TID column width */
+int TypeColW;                     /* TYPE column width */
+int UserColW;                     /* USER column width */
+
+int ZoneColW; /* ZONE column width */
diff --git a/src/usage.c b/src/usage.c
new file mode 100644 (file)
index 0000000..ec5790b
--- /dev/null
@@ -0,0 +1,997 @@
+/*
+ * usage.c - usage functions for lsof
+ */
+
+/*
+ * Copyright 1998 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.
+ */
+
+static char copyright[] =
+    "Copyright 1998 Purdue Research Foundation. All rights reserved.";
+
+#include "common.h"
+#include "cli.h"
+#include "version.h"
+
+/*
+ * Local function prototypes
+ */
+
+static char *isnullstr(char *s);
+static int print_in_col(int col, char *cp);
+static void report_HASDCACHE(struct lsof_context *ctx, int type, char *ttl,
+                             char *det);
+static void report_HASKERNIDCK(char *pfx, char *verb);
+static void report_SECURITY(char *pfx, char *punct);
+static void report_WARNDEVACCESS(char *pfx, char *verb, char *punct);
+
+/*
+ * isnullstr() - is it a null string?
+ */
+
+static char *isnullstr(char *s) /* string pointer */
+{
+    if (!s)
+        return ((char *)NULL);
+    while (*s) {
+        if (*s != ' ')
+            return (s);
+        s++;
+    }
+    return ((char *)NULL);
+}
+
+/*
+ * print_in_col() -- print character string in help column
+ */
+
+static int print_in_col(int col,  /* column number */
+                        char *cp) /* what to print */
+{
+    if (cp && *cp) {
+        switch (col) {
+        case 1:
+            (void)fprintf(stderr, "  %-23.23s", cp);
+            break;
+        case 2:
+            (void)fprintf(stderr, "  %-25.25s", cp);
+            break;
+        default:
+            (void)fprintf(stderr, "  %s\n", cp);
+            col = 0;
+        }
+        col++;
+    }
+    return (col);
+}
+
+/*
+ * report_HASDCACHE() -- report device cache file state
+ */
+
+static void report_HASDCACHE(struct lsof_context *ctx, /* context */
+                             int type,  /* type: 0 == read path report
+                                         *       1 == full report */
+                             char *ttl, /* title lines prefix
+                                         * (NULL if none) */
+                             char *det) /* detail lines prefix
+                                         * (NULL if none) */
+{
+
+#if defined(HASDCACHE)
+    char *cp;
+    int dx;
+
+#    if defined(WILLDROPGID)
+    int saved_Setgid = Setgid;
+
+    Setgid = 0;
+#    endif /* defined(WILLDROPGID) */
+
+    if (type) {
+
+        /*
+         * Report full device cache information.
+         */
+        (void)fprintf(stderr, "%sDevice cache file read-only paths:\n",
+                      ttl ? ttl : "");
+        if ((dx = dcpath(ctx, 1, 0)) < 0)
+            (void)fprintf(stderr, "%snone\n", det ? det : "");
+        else {
+            (void)fprintf(stderr, "%sNamed via -D: %s\n", det ? det : "",
+                          DCpath[0] ? DCpath[0] : "none");
+
+#    if defined(HASENVDC)
+            (void)fprintf(stderr, "%sNamed in environment variable %s: %s\n",
+                          det ? det : "", HASENVDC,
+                          DCpath[1] ? DCpath[1] : "none");
+#    endif /* defined(HASENVDC) */
+
+#    if defined(HASSYSDC)
+            if (DCpath[2])
+                (void)fprintf(stderr, "%sSystem-wide device cache: %s\n",
+                              det ? det : "", DCpath[2]);
+#    endif /* defined(HASSYSDC) */
+
+#    if defined(HASPERSDC)
+            (void)fprintf(stderr,
+                          "%sPersonal path format (HASPERSDC): \"%s\"\n",
+                          det ? det : "", HASPERSDC);
+#        if defined(HASPERSDCPATH)
+            (void)fprintf(stderr,
+                          "%sModified personal path environment variable: %s\n",
+                          det ? det : "", HASPERSDCPATH);
+            cp = getenv(HASPERSDCPATH);
+            (void)fprintf(stderr, "%s%s value: %s\n", det ? det : "",
+                          HASPERSDCPATH, cp ? cp : "none");
+#        endif /* defined(HASPERSDCPATH) */
+            (void)fprintf(stderr, "%sPersonal path: %s\n", det ? det : "",
+                          DCpath[3] ? DCpath[3] : "none");
+#    endif /* defined(HASPERSDC) */
+        }
+        (void)fprintf(stderr, "%sDevice cache file write paths:\n",
+                      ttl ? ttl : "");
+        if ((dx = dcpath(ctx, 2, 0)) < 0)
+            (void)fprintf(stderr, "%snone\n", det ? det : "");
+        else {
+            (void)fprintf(stderr, "%sNamed via -D: %s\n", det ? det : "",
+                          DCstate == 2 ? "none"
+                          : DCpath[0]  ? DCpath[0]
+                                       : "none");
+
+#    if defined(HASENVDC)
+            (void)fprintf(stderr, "%sNamed in environment variable %s: %s\n",
+                          det ? det : "", HASENVDC,
+                          DCpath[1] ? DCpath[1] : "none");
+#    endif /* defined(HASENVDC) */
+
+#    if defined(HASPERSDC)
+            (void)fprintf(stderr,
+                          "%sPersonal path format (HASPERSDC): \"%s\"\n",
+                          det ? det : "", HASPERSDC);
+#        if defined(HASPERSDCPATH)
+            (void)fprintf(stderr,
+                          "%sModified personal path environment variable: %s\n",
+                          det ? det : "", HASPERSDCPATH);
+            cp = getenv(HASPERSDCPATH);
+            (void)fprintf(stderr, "%s%s value: %s\n", det ? det : "",
+                          HASPERSDCPATH, cp ? cp : "none");
+#        endif /* defined(HASPERSDCPATH) */
+            (void)fprintf(stderr, "%sPersonal path: %s\n", det ? det : "",
+                          DCpath[3] ? DCpath[3] : "none");
+#    endif /* defined(HASPERSDC) */
+        }
+    } else {
+
+        /*
+         * Report device cache read file path.
+         */
+
+#    if defined(HASENVDC) || defined(HASPERSDC) || defined(HASSYSDC)
+        cp = NULL;
+#        if defined(HASENVDC)
+        if ((dx = dcpath(ctx, 1, 0)) >= 0)
+            cp = DCpath[1];
+#        endif /* defined(HASENVDC) */
+#        if defined(HASSYSDC)
+        if (!cp)
+            cp = HASSYSDC;
+#        endif /* defined(HASSYSDC) */
+#        if defined(HASPERSDC)
+        if (!cp && dx != -1 && (dx = dcpath(ctx, 1, 0)) >= 0)
+            cp = DCpath[3];
+#        endif /* defined(HASPERSDC) */
+        if (cp)
+            (void)fprintf(stderr,
+                          "%s%s is the default device cache file read path.\n",
+                          ttl ? ttl : "", cp);
+#    endif /* defined(HASENVDC) || defined(HASPERSDC) || defined(HASSYSDC) */
+    }
+
+#    if defined(WILLDROPGID)
+    Setgid = saved_Setgid;
+#    endif /* defined(WILLDROPGID) */
+
+#endif /* defined(HASDCACHE) */
+}
+
+/*
+ * report_HASKERNIDCK() -- report HASKERNIDCK state
+ */
+
+static void report_HASKERNIDCK(pfx, verb) char *pfx; /* prefix (NULL if none) */
+char *verb;                                          /* verb (NULL if none) */
+{
+    (void)fprintf(stderr, "%sernel ID check %s%s%s.\n", pfx ? pfx : "",
+                  verb ? verb : "", verb ? " " : "",
+
+#if defined(HASKERNIDCK)
+                  "enabled"
+#else  /* !defined(HASKERNIDCK) */
+                  "disabled"
+#endif /* defined(HASKERNIDCK) */
+
+    );
+}
+
+/*
+ * report_SECURITY() -- report *SECURITY states
+ */
+
+static void report_SECURITY(pfx, punct) char *pfx; /* prefix (NULL if none) */
+char *punct;                                       /* short foem punctuation
+                                                    * (NULL if none) */
+{
+    fprintf(stderr, "%s%s can list all files%s", pfx ? pfx : "",
+
+#if defined(HASSECURITY)
+            "Only root",
+#    if defined(HASNOSOCKSECURITY)
+            ", but anyone can list socket files.\n"
+#    else  /* !defined(HASNOSOCKSECURITY) */
+            punct ? punct : ""
+#    endif /* defined(HASNOSOCKSECURITY) */
+#else      /* !defined(HASSECURITY) */
+            "Anyone", punct ? punct : ""
+#endif     /* defined(HASSECURITY) */
+
+    );
+}
+
+/*
+ * report_WARNDEVACCESS() -- report WEARNDEVACCESS state
+ */
+
+static void report_WARNDEVACCESS(pfx, verb,
+                                 punct) char *pfx; /* prefix (NULL if none) */
+char *verb;                                        /* verb (NULL if none) */
+char *punct;                                       /* punctuation */
+{
+    (void)fprintf(stderr, "%s/dev warnings %s%s%s%s", pfx ? pfx : "",
+                  verb ? verb : "", verb ? " " : "",
+
+#if defined(WARNDEVACCESS)
+                  "enabled",
+#else  /* !defined(WARNDEVACCESS) */
+                  "disabled",
+#endif /* defined(WARNDEVACCESS) */
+
+                  punct);
+}
+
+/*
+ * usage() - display usage and exit
+ */
+
+void usage(struct lsof_context *ctx, /* context */
+           int err,     /* it is called as part of error handlng? */
+           int fh,      /* ``-F ?'' status */
+           int version) /* ``-v'' status */
+{
+    char buf[MAXPATHLEN + 1], *cp, *cp1, *cp2;
+    int col, i;
+
+    if (Fhelp || err) {
+        (void)fprintf(stderr, "%s %s\n latest revision: %s\n", Pn, LSOF_VERSION,
+                      LSOF_REPO_URL);
+        (void)fprintf(stderr, " latest FAQ: %s\n", LSOF_FAQ_URL);
+        (void)fprintf(stderr, " latest (non-formatted) man page: %s\n",
+                      LSOF_MAN_URL);
+        (void)fprintf(stderr, " usage: [-?ab%shH%slnNoOP%s%stUvV%s]",
+
+#if defined(HASNCACHE)
+                      "C",
+#else  /* !defined(HASNCACHE) */
+                      "",
+#endif /* defined(HASNCACHE) */
+
+#if defined(HASTASKS)
+                      "K",
+#else  /* !defined(HASTASKS) */
+                      "",
+#endif /* defined(HASTASKS) */
+
+#if defined(HASPPID)
+                      "R",
+#else  /* !defined(HASPPID) */
+                      "",
+#endif /* defined(HASPPID) */
+
+#if defined(HASTCPUDPSTATE)
+                      "",
+#else  /* !defined(HASTCPUDPSTATE) */
+                      "s",
+#endif /* defined(HASTCPUDPSTATE) */
+
+#if defined(HASXOPT)
+#    if defined(HASXOPT_ROOT)
+                      (Myuid == 0) ? "X" : ""
+#    else  /* !defined(HASXOPT_ROOT) */
+                      "X"
+#    endif /* defined(HASXOPT_ROOT) */
+#else      /* !defined(HASXOPT) */
+                      ""
+#endif     /* defined(HASXOPT) */
+
+        );
+
+#if defined(HAS_AFS) && defined(HASAOPT)
+        (void)fprintf(stderr, " [-A A]");
+#endif /* defined(HAS_AFS) && defined(HASAOPT) */
+
+        (void)fprintf(stderr, " [+|-c c] [+|-d s] [+%sD D]%s",
+#if defined(HASDCACHE)
+                      "|-",
+#else  /* !defined(HASDCACHE) */
+                      "",
+#endif /* defined(HASDCACHE) */
+
+#if defined(HASEPTOPTS)
+                      " [+|-E]"
+#else  /* !defined(HASEPTOPTS) */
+                      ""
+#endif /* defined(HASEPTOPTS) */
+
+        );
+
+        (void)fprintf(stderr,
+                      " %s[+|-f%s%s%s%s%s%s]\n [-F [f]] [-g [s]] [-i [i]]",
+
+#if defined(HASEOPT)
+                      "[+|-e s] ",
+#else  /* !defined(HASEOPT) */
+                      "",
+#endif /* defined(HASEOPT) */
+
+#if defined(HASFSTRUCT)
+                      "[",
+
+#    if defined(HASNOFSCOUNT)
+                      "",
+#    else  /* !defined(HASNOFSCOUNT) */
+                      "c",
+#    endif /* defined(HASNOFSCOUNT) */
+
+#    if defined(HASNOFSADDR)
+                      "",
+#    else  /* !defined(HASNOFSADDR) */
+                      "f",
+#    endif /* defined(HASNOFSADDR) */
+
+#    if defined(HASNOFSFLAGS)
+                      "",
+#    else  /* !defined(HASNOFSFLAGS) */
+                      "gG",
+#    endif /* defined(HASNOFSFLAGS) */
+
+#    if defined(HASNOFSNADDR)
+                      "",
+#    else  /* !defined(HASNOFSNADDR) */
+                      "n",
+#    endif /* defined(HASNOFSNADDR) */
+
+                      "]"
+#else  /* !defined(HASFSTRUCT) */
+                      "", "", "", "", "", ""
+#endif /* defined(HASFSTRUCT) */
+
+        );
+
+#if defined(HASKOPT)
+        (void)fprintf(stderr, " [-k k]");
+#endif /* defined(HASKOPT) */
+
+        (void)fprintf(stderr, " [+|-L [l]]");
+
+#if defined(HASMOPT) || defined(HASMNTSUP)
+        (void)fprintf(stderr,
+#    if defined(HASMOPT)
+#        if defined(HASMNTSUP)
+                      " [+|-m [m]]"
+#        else  /* !defined(HASMNTSUP) */
+                      " [-m m]"
+#        endif /* defined(HASMNTSUP) */
+#    else      /* !defined(HASMOPT) */
+                      " [+m [m]]"
+#    endif     /* defined(HASMOPT) */
+        );
+#endif /* defined(HASMOPT) || defined(HASMNTSUP) */
+
+#if !defined(HASNORPC_H)
+        (void)fprintf(stderr, " [+|-M]");
+#endif /* !defined(HASNORPC_H) */
+
+        (void)fprintf(stderr,
+                      " [-o [o]] [-p s]\n [+|-r [t]]%s [-S [t]] [-T [t]]",
+
+#if defined(HASTCPUDPSTATE)
+                      " [-s [p:s]]"
+#else  /* !defined(HASTCPUDPSTATE) */
+                      ""
+#endif /* defined(HASTCPUDPSTATE) */
+
+        );
+        (void)fprintf(stderr, " [-u s] [+|-w] [-x [fl]]");
+
+#if defined(HASZONES)
+        (void)fprintf(stderr, " [-z [z]]");
+#else /* !defined(HASZONES) */
+#    if defined(HASSELINUX)
+        if (CntxStatus)
+            (void)fprintf(stderr, " [-Z [Z]]");
+#    endif /* defined(HASSELINUX) */
+#endif     /* defined(HASZONES) */
+
+        (void)fprintf(stderr, " [--] [names]\n");
+    }
+    if (err && !Fhelp) {
+        (void)fprintf(stderr,
+                      "Use the ``-h'' option to get more help information.\n");
+        if (!fh)
+            Exit(ctx, err ? LSOF_EXIT_ERROR : LSOF_EXIT_SUCCESS);
+    }
+    if (Fhelp) {
+        (void)fprintf(
+            stderr, "Defaults in parentheses; comma-separated set (s) items;");
+        (void)fprintf(stderr, " dash-separated ranges.\n");
+        col = print_in_col(1, "-?|-h list help");
+        col = print_in_col(col, "-a AND selections (OR)");
+        col = print_in_col(col, "-b avoid kernel blocks");
+        col = print_in_col(col, "-c c  cmd c ^c /c/[bix]");
+        (void)snpf(buf, sizeof(buf), "+c w  COMMAND width (%d)", CMDL);
+        col = print_in_col(col, buf);
+
+#if defined(HASNCACHE)
+        col = print_in_col(col, "-C no kernel name cache");
+#endif /* defined(HASNCACHE) */
+
+        col = print_in_col(col, "+d s  dir s files");
+        col = print_in_col(col, "-d s  select by FD set");
+        col = print_in_col(col, "+D D  dir D tree *SLOW?*");
+
+#if defined(HASDCACHE)
+        if (Setuidroot)
+            cp = "?|i|r";
+
+#    if !defined(WILLDROPGID)
+        else if (Myuid)
+            cp = "?|i|r<path>";
+#    endif /* !defined(WILLDROPGID) */
+
+        else
+            cp = "?|i|b|r|u[path]";
+        (void)snpf(buf, sizeof(buf), "-D D  %s", cp);
+#else  /* !defined(HASDCACHE) */
+        buf[0] = '\0';
+#endif /* defined(HASDCACHE) */
+
+        col = print_in_col(col, buf);
+
+#if defined(HASEOPT)
+        col = print_in_col(col, "+|-e s  exempt s *RISKY*");
+#endif /* defined(HASEOPT) */
+
+        (void)snpf(buf, sizeof(buf), "-i select IPv%s files",
+
+#if defined(HASIPv6)
+                   "[46]"
+#else  /* !defined(HASIPv6) */
+                   "4"
+#endif /* defined(HASIPv6) */
+
+        );
+        col = print_in_col(col, buf);
+
+#if defined(HASTASKS)
+        /* DEBUG           col = print_in_col(col, "-K list tasKs (threads)");
+         */
+        col = print_in_col(col, "-K [i] list|(i)gn tasKs");
+#endif /* defined(HASTASKS) */
+
+        col = print_in_col(col, "-l list UID numbers");
+        col = print_in_col(col, "-n no host names");
+        col = print_in_col(col, "-N select NFS files");
+        col = print_in_col(col, "-o list file offset");
+        col = print_in_col(col, "-O no overhead *RISKY*");
+        col = print_in_col(col, "-P no port names");
+        col = print_in_col(col, "-Q allow failed search");
+
+#if defined(HASPPID)
+        col = print_in_col(col, "-R list paRent PID");
+#endif /* defined(HASPPID) */
+
+        col = print_in_col(col, "-s list file size");
+        col = print_in_col(col, "-t terse listing");
+        col = print_in_col(col, "-T disable TCP/TPI info");
+        col = print_in_col(col, "-U select Unix socket");
+        col = print_in_col(col, "-v list version info");
+        col = print_in_col(col, "-V verbose search");
+        (void)snpf(buf, sizeof(buf), "+|-w  Warnings (%s)",
+
+#if defined(WARNINGSTATE)
+                   "-"
+#else  /* !defined(WARNINGSTATE) */
+                   "+"
+#endif /* defined(WARNINGSTATE) */
+        );
+
+        col = print_in_col(col, buf);
+
+#if defined(HASXOPT)
+#    if defined(HASXOPT_ROOT)
+        if (Myuid == 0)
+            (void)snpf(buf, sizeof(buf), "-X %s", HASXOPT);
+        else
+            buf[0] = '\0';
+#    else  /* !defined(HASXOPT_ROOT) */
+        (void)snpf(buf, sizeof(buf), "-X %s", HASXOPT);
+#    endif /* defined(HASXOPT_ROOT) */
+#else      /* !defined(HASXOPT) */
+        buf[0] = '\0';
+#endif     /* defined(HASXOPT) */
+
+        col = print_in_col(col, buf);
+
+#if defined(HASZONES)
+        col = print_in_col(col, "-z z  zone [z]");
+#endif /* defined(HASZONES) */
+
+#if defined(HASSELINUX)
+        col = print_in_col(col, "-Z Z  context [Z]");
+#endif /* defined(HASSELINUX) */
+
+        col = print_in_col(col, "-H human readable size");
+
+        col = print_in_col(col, "-- end option scan");
+        if (col != 1)
+            (void)fprintf(stderr, "\n");
+
+#if defined(HASEPTOPTS)
+        (void)fprintf(stderr, "  %-36.36s  %s\n", "-E display endpoint info",
+                      "+E display endpoint info and files");
+#endif /* defined(HASEPTOPTS) */
+
+        (void)fprintf(stderr, "  %-36.36s",
+                      "+f|-f  +filesystem or -file names");
+
+#if defined(HASFSTRUCT)
+        (void)fprintf(stderr, "  +|-f[%s%s%s%s]%s%s%s%s %s%s%s%s%s%s%s\n",
+
+#    if defined(HASNOFSCOUNT)
+                      "",
+#    else  /* !defined(HASNOFSCOUNT) */
+                      "c",
+#    endif /* defined(HASNOFSCOUNT) */
+
+#    if defined(HASNOFSADDR)
+                      "",
+#    else  /* !defined(HASNOFSADDR) */
+                      "f",
+#    endif /* defined(HASNOFSADDR) */
+
+#    if defined(HASNOFSFLAGS)
+                      "",
+#    else  /* !defined(HASNOFSFLAGS) */
+                      "gG",
+#    endif /* defined(HASNOFSFLAGS) */
+
+#    if defined(HASNOFSNADDR)
+                      "",
+#    else  /* !defined(HASNOFSNADDR) */
+                      "n",
+#    endif /* defined(HASNOFSNADDR) */
+
+#    if defined(HASNOFSCOUNT)
+                      "",
+#    else  /* !defined(HASNOFSCOUNT) */
+                      " Ct",
+#    endif /* defined(HASNOFSCOUNT) */
+
+#    if defined(HASNOFSADDR)
+                      "",
+#    else  /* !defined(HASNOFSADDR) */
+                      " Fstr",
+#    endif /* defined(HASNOFSADDR) */
+
+#    if defined(HASNOFSFLAGS)
+                      "",
+#    else  /* !defined(HASNOFSFLAGS) */
+                      " flaGs",
+#    endif /* defined(HASNOFSFLAGS) */
+
+#    if defined(HASNOFSNADDR)
+                      "",
+#    else  /* !defined(HASNOFSNADDR) */
+                      " Node",
+#    endif /* defined(HASNOFSNADDR) */
+
+                      Fsv ? "(" : "", (Fsv & FSV_CT) ? "C" : "",
+                      (Fsv & FSV_FA) ? "F" : "",
+                      ((Fsv & FSV_FG) && FsvFlagX) ? "g" : "",
+                      ((Fsv & FSV_FG) && !FsvFlagX) ? "G" : "",
+                      (Fsv & FSV_NI) ? "N" : "", Fsv ? ")" : "");
+#else  /* !defined(HASFSTRUCT) */
+        putc('\n', stderr);
+#endif /* defined(HASFSTRUCT) */
+
+        (void)fprintf(stderr, "  %-36.36s",
+                      "-F [f] select fields; -F? for help");
+
+#if defined(HASKOPT)
+        (void)fprintf(stderr, "  -k k   kernel symbols (%s)\n",
+                      Nmlst ? Nmlst
+#    if defined(N_UNIX)
+                            : N_UNIX
+#    else  /* !defined(N_UNIX) */
+                      : (Nmlst = get_nlist_path(ctx, 1)) ? Nmlst
+                                                         : "none found"
+#    endif /* defined(N_UNIX) */
+
+        );
+#else  /* !defined(HASKOPT) */
+        putc('\n', stderr);
+#endif /* defined(HASKOPT) */
+
+        (void)fprintf(stderr,
+                      "  +|-L [l] list (+) suppress (-) link counts < l (0 "
+                      "= all; default = 0)\n");
+
+#if defined(HASMOPT) || defined(HASMNTSUP)
+#    if defined(HASMOPT)
+        (void)snpf(buf, sizeof(buf), "-m m   kernel memory (%s)", KMEM);
+#    else  /* !defined(HASMOPT) */
+        buf[0] = '\0';
+#    endif /* defined(HASMOPT) */
+
+        (void)fprintf(stderr, "  %-36.36s", buf);
+
+#    if defined(HASMNTSUP)
+        (void)fprintf(stderr, "  +m [m] use|create mount supplement\n");
+#    else  /* !defined(HASMNTSUP) */
+        (void)fprintf(stderr, "\n");
+#    endif /* defined(HASMNTSUP) */
+#endif     /* defined(HASMOPT) || defined(HASMNTSUP) */
+
+#if !defined(HASNORPC_H)
+        (void)snpf(buf, sizeof(buf), "+|-M   portMap registration (%s)",
+
+#    if defined(HASPMAPENABLED)
+                   "+"
+#    else  /* !defined(HASPMAPENABLED) */
+                   "-"
+#    endif /* defined(HASPMAPENABLED) */
+
+        );
+#else  /* defined(HASNORPC_H) */
+        buf[0] = '\0';
+#endif /* !defined(HASNORPC_H) */
+
+        (void)fprintf(stderr, "  %-36.36s", buf);
+        (void)snpf(buf, sizeof(buf), "-o o   o 0t offset digits (%d)",
+                   OFFDECDIG);
+        (void)fprintf(stderr, "  %s\n", buf);
+        (void)fprintf(stderr, "  %-36.36s", "-p s   exclude(^)|select PIDs");
+        (void)fprintf(stderr, "  -S [t] t second stat timeout (%d)\n", TMLIMIT);
+        (void)snpf(buf, sizeof(buf), "-T %s%ss%s TCP/TPI %s%sSt%s (s) info",
+
+#if defined(HASSOOPT) || defined(HASSOSTATE) || defined(HASTCPOPT)
+                   "f",
+#else  /* !defined(HASSOOPT) && !defined(HASSOSTATE) && !defined(HASTCPOPT)*/
+                   "",
+#endif /* defined(HASSOOPT) || defined(HASSOSTATE) || defined(HASTCPOPT)*/
+
+#if defined(HASTCPTPIQ)
+                   "q",
+#else  /* !defined(HASTCPTPIQ) */
+                   " ",
+#endif /* defined(HASTCPTPIQ) */
+
+#if defined(HASTCPTPIW)
+                   "w",
+#else  /* !defined(HASTCPTPIW) */
+                   "",
+#endif /* defined(HASTCPTPIW) */
+
+#if defined(HASSOOPT) || defined(HASSOSTATE) || defined(HASTCPOPT)
+                   "Fl,",
+#else  /* !defined(HASSOOPT) && !defined(HASSOSTATE) && !defined(HASTCPOPT)*/
+                   "",
+#endif /* defined(HASSOOPT) || defined(HASSOSTATE) || defined(HASTCPOPT)*/
+
+#if defined(HASTCPTPIQ)
+                   "Q,",
+#else  /* !defined(HASTCPTPIQ) */
+                   "",
+#endif /* defined(HASTCPTPIQ) */
+
+#if defined(HASTCPTPIW)
+                   ",Win"
+#else  /* !defined(HASTCPTPIW) */
+                   ""
+#endif /* defined(HASTCPTPIW) */
+
+        );
+        (void)fprintf(stderr, "  %s\n", buf);
+
+#if defined(HAS_AFS) && defined(HASAOPT)
+        (void)fprintf(stderr, "  -A A   AFS name list file (%s)\n",
+                      AFSAPATHDEF);
+#endif /* defined(HAS_AFS) && defined(HASAOPT) */
+
+        (void)fprintf(
+            stderr, "  -g [s] exclude(^)|select and print process group IDs\n");
+        (void)fprintf(stderr, "  -i i   select by IPv%s address:",
+
+#if defined(HASIPv6)
+                      "[46]"
+#else  /* !defined(HASIPv6) */
+                      "4"
+#endif /* defined(HASIPv6) */
+
+        );
+        (void)fprintf(stderr, " [%s][proto][@host|addr][:svc_list|port_list]\n",
+
+#if defined(HASIPv6)
+                      "46"
+#else  /* !defined(HASIPv6) */
+                      "4"
+#endif /* defined(HASIPv6) */
+
+        );
+
+        (void)fprintf(stderr, "  +|-r [%s] repeat every t seconds (%d); %s",
+
+#if defined(HAS_STRFTIME)
+                      "t[m<fmt>]",
+#else  /* !defined(has_STRFTIME) */
+                      "t",
+#endif /* defined(HAS_STRFTIME) */
+
+                      RPTTM, " + until no files, - forever.\n");
+
+#if defined(HAS_STRFTIME)
+        (void)fprintf(
+            stderr,
+            "       An optional suffix to t is m<fmt>; m must separate %s",
+            "t from <fmt> and\n");
+        (void)fprintf(stderr, "      <fmt> is an strftime(3) format %s",
+                      "for the marker line.\n");
+#endif /* defined(HAS_STRFTIME) */
+
+#if defined(HASTCPUDPSTATE)
+        (void)fprintf(
+            stderr,
+            "  -s p:s  exclude(^)|select protocol (p = TCP|UDP) states");
+        (void)fprintf(stderr, " by name(s).\n");
+#endif /* defined(HASTCPUDPSTATE) */
+
+        (void)fprintf(stderr, "  -u s   exclude(^)|select login|UID set s\n");
+        (void)fprintf(
+            stderr,
+            "  -x [fl] cross over +d|+D File systems or symbolic Links\n");
+        (void)fprintf(
+            stderr,
+            "  names  select named files or files on named file systems\n");
+        (void)report_SECURITY(NULL, "; ");
+        (void)report_WARNDEVACCESS(NULL, NULL, ";");
+        (void)report_HASKERNIDCK(" k", NULL);
+        (void)report_HASDCACHE(ctx, 0, NULL, NULL);
+
+#if defined(DIALECT_WARNING)
+        (void)fprintf(stderr, "WARNING: %s\n", DIALECT_WARNING);
+#endif /* defined(DIALECT_WARNING) */
+    }
+    if (fh) {
+        (void)fprintf(stderr, "%s:\tID    field description\n", Pn);
+        for (i = 0; FieldSel[i].nm; i++) {
+
+#if !defined(HASPPID)
+            if (FieldSel[i].id == LSOF_FID_PPID)
+                continue;
+#endif /* !defined(HASPPID) */
+
+#if !defined(HASFSTRUCT)
+            if (FieldSel[i].id == LSOF_FID_FA ||
+                FieldSel[i].id == LSOF_FID_CT ||
+                FieldSel[i].id == LSOF_FID_FG || FieldSel[i].id == LSOF_FID_NI)
+                continue;
+#else /* defined(HASFSTRUCT) */
+#    if defined(HASNOFSADDR)
+            if (FieldSel[i].id == LSOF_FID_FA)
+                continue;
+#    endif /* defined(HASNOFSADDR) */
+
+#    if defined(HASNOFSCOUNT)
+            if (FieldSel[i].id == LSOF_FID_CT)
+                continue;
+#    endif /* !defined(HASNOFSCOUNT) */
+
+#    if defined(HASNOFSFLAGS)
+            if (FieldSel[i].id == LSOF_FID_FG)
+                continue;
+#    endif /* defined(HASNOFSFLAGS) */
+
+#    if defined(HASNOFSNADDR)
+            if (FieldSel[i].id == LSOF_FID_NI)
+                continue;
+#    endif /* defined(HASNOFSNADDR) */
+#endif     /* !defined(HASFSTRUCT) */
+
+#if !defined(HASZONES)
+            if (FieldSel[i].id == LSOF_FID_ZONE)
+                continue;
+#endif /* !defined(HASZONES) */
+
+#if defined(HASSELINUX)
+            if ((FieldSel[i].id == LSOF_FID_CNTX) && !CntxStatus)
+                continue;
+#else  /* !defined(HASSELINUX) */
+            if (FieldSel[i].id == LSOF_FID_CNTX)
+                continue;
+#endif /* !defined(HASSELINUX) */
+
+            (void)fprintf(stderr, "\t %c    %s\n", FieldSel[i].id,
+                          FieldSel[i].nm);
+        }
+    }
+
+#if defined(HASDCACHE)
+    if (DChelp)
+        report_HASDCACHE(ctx, 1, NULL, "    ");
+#endif /* defined(HASDCACHE) */
+
+    if (version) {
+
+        /*
+         * Display version information in reponse to ``-v''.
+         */
+        (void)fprintf(stderr, "%s version information:\n", Pn);
+        (void)fprintf(stderr, "    revision: %s\n", LSOF_VERSION);
+        (void)fprintf(stderr, "    copyright notice: %s\n", copyright);
+        (void)fprintf(stderr, "    latest revision: %s\n", LSOF_REPO_URL);
+        (void)fprintf(stderr, "    latest FAQ: %s\n", LSOF_FAQ_URL);
+        (void)fprintf(stderr, "    latest (non-formatted) man page: %s\n",
+                      LSOF_MAN_URL);
+
+#if defined(LSOF_CINFO)
+        if ((cp = isnullstr(LSOF_CINFO)))
+            (void)fprintf(stderr, "    configuration info: %s\n", cp);
+#endif /* defined(LSOF_CINFO) */
+
+        cp = isnullstr(LSOF_HOST);
+        if (!(cp1 = isnullstr(LSOF_LOGNAME)))
+            cp1 = isnullstr(LSOF_USER);
+        if (cp || cp1) {
+            if (cp && cp1)
+                cp2 = "by and on";
+            else if (cp)
+                cp2 = "on";
+            else
+                cp2 = "by";
+            (void)fprintf(stderr, "    constructed %s: %s%s%s\n", cp2,
+                          cp1 ? cp1 : "", (cp && cp1) ? "@" : "", cp ? cp : "");
+        }
+
+#if defined(LSOF_BLDCMT)
+        if ((cp = isnullstr(LSOF_BLDCMT)))
+            (void)fprintf(stderr, "    builder's comment: %s\n", cp);
+#endif /* defined(LSOF_BLDCMT) */
+
+        if ((cp = isnullstr(LSOF_CC)))
+            (void)fprintf(stderr, "    compiler: %s\n", cp);
+        if ((cp = isnullstr(LSOF_CCV)))
+            (void)fprintf(stderr, "    compiler version: %s\n", cp);
+        if ((cp = isnullstr(LSOF_CCFLAGS)))
+            (void)fprintf(stderr, "    compiler flags: %s\n", cp);
+        if ((cp = isnullstr(LSOF_LDFLAGS)))
+            (void)fprintf(stderr, "    loader flags: %s\n", cp);
+        if ((cp = isnullstr(LSOF_SYSINFO)))
+            (void)fprintf(stderr, "    system info: %s\n", cp);
+        // display configurations that might affect output
+        char *features[] = {
+#if defined(HASEFFNLINK)
+            "effnlink",
+#endif
+#if defined(HASFDESCFS)
+            "fdescfs",
+#endif
+#if defined(HASF_VNODE)
+            "f_vnode",
+#endif
+#if defined(HASIPv6)
+            "ipv6",
+#endif
+#if defined(HAS_KF_SOCK_SENDQ)
+            "kf_sock_sendq",
+#endif
+#if defined(HAS_KF_FILE_NLINK)
+            "kf_file_nlink",
+#endif
+#if defined(HASNULLFS)
+            "nullfs",
+#endif
+#if defined(HAS_SYS_PIPEH)
+            "pipe",
+#endif
+#if defined(HASPROCFS)
+            "procfs",
+#endif
+#if defined(HASPSEUDOFS)
+            "pseudofs",
+#endif
+#if defined(HASPTYEPT)
+            "ptyept",
+#endif
+#if defined(HASPTYFS)
+            "ptyfs",
+#endif
+#if !defined(HASNORPC_H)
+            "rpc",
+#endif
+#if defined(HASSBSTATE)
+            "sbstate",
+#endif
+#if defined(HASSELINUX)
+            "selinux",
+#endif
+#if defined(HASSOOPT)
+            "soopt",
+#endif
+#if defined(HASSOSTATE)
+            "sostate",
+#endif
+#if defined(HASTASKS)
+            "tasks",
+#endif
+#if defined(HAS_TMPFS) || defined(HASTMPFS)
+            "tmpfs",
+#endif
+#if defined(HAS_XTCPCB_TMAXSEG)
+            "xtcpcb_tmaxseg",
+#endif
+#if defined(HASUXSOCKEPT)
+            "uxsockept",
+#endif
+#if defined(HAS_V_LOCKF)
+            "v_lockf",
+#endif
+        };
+        (void)fprintf(stderr, "    features enabled:");
+        for (i = 0; i < sizeof(features) / sizeof(features[0]); i++) {
+            (void)fprintf(stderr, " %s", features[i]);
+        }
+        (void)fprintf(stderr, "\n");
+        (void)report_SECURITY("    ", ".\n");
+        (void)report_WARNDEVACCESS("    ", "are", ".\n");
+        (void)report_HASKERNIDCK("    K", "is");
+
+#if defined(DIALECT_WARNING)
+        (void)fprintf(stderr, "    WARNING: %s\n", DIALECT_WARNING);
+#endif /* defined(DIALECT_WARNING) */
+
+        (void)report_HASDCACHE(ctx, 1, "    ", "\t");
+    }
+    Exit(ctx, err ? LSOF_EXIT_ERROR : LSOF_EXIT_SUCCESS);
+}
diff --git a/src/util.c b/src/util.c
new file mode 100644 (file)
index 0000000..bc6e231
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * dutil.c - AIX utility functions whose compilation conflicts with the
+ *          general header file tree defined by lsof.h and dlsof.h -- e.g.,
+ *          the conflict between <time.h> and <sys/time.h> for the time(2)
+ *          and localtime(3) functions
+ *
+ * V. Abell
+ * Purdue University
+ */
+
+/*
+ * Copyright 2008 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.
+ */
+
+#include "common.h"
+
+#if defined(HAS_STRFTIME)
+#    include <time.h>
+#endif /* defined(HAS_STRFTIME) */
+
+/*
+ * util_strftime() -- utility function to call strftime(3) without header
+ *                   file distractions
+ */
+
+int util_strftime(char *fmtr, /* format output receiver */
+                  int fmtl,   /* sizeof(*fmtr) */
+                  char *fmt)  /* format */
+{
+
+#if defined(HAS_STRFTIME)
+    struct tm *lt;
+    time_t tm;
+
+    tm = time((time_t *)NULL);
+    lt = localtime(&tm);
+    return (strftime(fmtr, fmtl, fmt, lt));
+#else  /* !defined(HAS_STRFTIME) */
+    return (0);
+#endif /* defined(HAS_STRFTIME) */
+}
diff --git a/support/AIXDistrib b/support/AIXDistrib
new file mode 100755 (executable)
index 0000000..1d13db6
--- /dev/null
@@ -0,0 +1,14 @@
+#!/bin/ksh
+#
+# AIXDistrib -- make AIX distribution of lsof 4.x
+#
+# Usage: AIXDistrib [<suffix>]
+#
+#       <suffix>       optional suffix for identification
+
+if test $# -gt 1
+then
+  echo "Usage: [<suffix>]"
+  exit 1
+fi
+$HOME/src/lsof4/support/GenericDistrib aix $1
diff --git a/support/DarwinDistrib b/support/DarwinDistrib
new file mode 100755 (executable)
index 0000000..9ade012
--- /dev/null
@@ -0,0 +1,14 @@
+#!/bin/ksh
+#
+# DarwinDistrib -- make Apple Darwin distribution of lsof 4.x
+#
+# Usage: DarwindDistrib [<suffix>]
+#
+#       <suffix>       optional suffix for identification
+
+if test $# -gt 1
+then
+  echo "Usage: [<suffix>]"
+  exit 1
+fi
+$HOME/src/lsof4/support/GenericDistrib2 darwin $1
diff --git a/support/Distfile.msrc b/support/Distfile.msrc
new file mode 100644 (file)
index 0000000..2c175c3
--- /dev/null
@@ -0,0 +1,17 @@
+# $Id: Distfile.msrc,v 1.3 97/03/04 09:32:13 abe Exp $
+
+( . ) -> ( HOST )
+       except_pat ( /RCS /Makefile\$ /Distfile /Make\.host /dialects /Lsof.8 );
+       install ${INTO};
+
+( @Make.host@ ) -> ( HOST )
+       install -b ${INTO}/makefile;
+
+ifelse(
+HOSTTYPE,`IBMR2',`( ./dialects/aix ) -> ( HOST )
+       except_pat ( /RCS );
+       install ${INTO}/dialects/aix;',
+HOSTTYPE,`SUN5',`( ./dialects/sun ) -> ( HOST )
+       except_pat ( /RCS );
+       install ${INTO}/dialects/sun;',
+)dnl
diff --git a/support/FreeBSDDistrib b/support/FreeBSDDistrib
new file mode 100755 (executable)
index 0000000..b58a4a9
--- /dev/null
@@ -0,0 +1,14 @@
+#!/bin/ksh
+#
+# FreeBSDDistrib -- make FreeBSD distribution of lsof 4.x
+#
+# Usage: FreeBSDDistrib [<suffix>]
+#
+#       <suffix>       optional suffix for identification
+
+if test $# -gt 1
+then
+  echo "Usage: [<suffix>]"
+  exit 1
+fi
+$HOME/src/lsof4/support/GenericDistrib2 freebsd $1
diff --git a/support/GPGDistrib b/support/GPGDistrib
new file mode 100755 (executable)
index 0000000..ac02e6d
--- /dev/null
@@ -0,0 +1,493 @@
+#!/bin/ksh
+#
+# GPGDistrib -- make lsof 4.x GPG distribution files
+
+# Define DEBUG to 1 in the environment to skip to the README file construction.
+#
+# Usage: GPGDistrib [edition]
+#
+#      edition         optional edition suffix to add to version number
+#set -x        # DEBUG
+
+if test "X$DEBUG" = "X"
+then
+  DEBUG=0
+fi
+
+# Check for GPG pass phrase.
+
+if test $DEBUG -eq 0
+then
+  if test "X$PGPPASS" = "X"
+  then
+    echo "No GPG pass phrase is defined in the environment."
+    exit 1
+  fi
+fi
+
+# Change working directory.
+
+HD=$HOME/src/lsof4
+echo Changing to $HD
+cd $HD
+
+# Get version number.
+
+V=`sed '/VN/s/.ds VN \(.*\)/\1/' version`
+if test $? -ne 0
+then
+  echo $V
+  exit 1
+fi
+
+# Handle optional edition suffix.
+
+if test $# -gt 0
+then
+  if test $# -gt 1
+  then
+    echo "Usage: GPGDistrib [edition]"
+    exit 1
+  fi
+  V=${V}$1
+fi
+
+# Define directory and archive file names.
+
+CK=CHECKSUMS_${V}
+DN=lsof_${V}
+DT=${DN}.tar
+M=00MANIFEST
+MC=${DN}/manifest_check.${V}
+R=README.lsof_${V}
+RM=00.README.FIRST_${V}
+SF=support/lsof.README
+DSF=RELEASE.SUMMARY_${V}
+SN=${DN}_src
+SD=${DN}/$SN
+ST=${SN}.tar
+echo "Creating lsof ${V} GPG distribution ..."
+
+# Define source files to copy.
+
+F="00.README.FIRST 00CREDITS 00DCACHE 00DIALECTS 00DIST 00FAQ 00LSOF-L 00MANIFEST 00PORTING 00QUICKSTART 00README 00TEST 00XCONFIG AFSConfig ChangeLog Configure Customize Inventory dialects arg.c lib common.h lsof_fields.h main.c misc.c node.c print.c proc.c proto.h regex.h scripts store.c tests usage.c util.c version"
+MS=Lsof.8
+MD=${DN}/${SN}/lsof.8
+MF=${DN}/${SN}/lsof.man
+
+# Set exit cleanup trap.
+
+trap 'rm -rf support/$CK $DN; exit' 1 2 3 15
+
+# Create source directory.
+
+if test $DEBUG -eq 0
+then
+  echo Creating $DN and ${DN}/${SN}
+  rm -rf $DN
+  mkdir $DN
+  (cd $DN; mkdir $SN)
+  echo "Copying to ${SD}:\c"
+  for i in $F
+  do
+    echo " $i\c"
+    cp -rp $i $SD
+  done
+  echo " ... done"
+  echo "Removing extraneous stuff from lib ...\c"
+  find $SD/lib -name OLD -exec rm -rf {} \; > /dev/null 2>&1
+  find $SD/lib -name RCS -exec rm -rf {} \; > /dev/null 2>&1
+  find $SD/lib -name NEW -exec rm -rf {} \; > /dev/null 2>&1
+  rm -rf $SD/lib/Makefile
+  rm -rf $SD/lib/*.[oa]
+  echo " done"
+  echo "Removing extraneous stuff from dialects ...\c"
+  find $SD/dialects -name OLD -exec rm -rf {} \; > /dev/null 2>&1
+  find $SD/dialects -name RCS -exec rm -rf {} \; > /dev/null 2>&1
+  find $SD/dialects -name NEW -exec rm -rf {} \; > /dev/null 2>&1
+  find $SD/dialects -name Makefile.local -exec rm -f {} \; > /dev/null 2>&1
+  find $SD/dialects -name distfile.kvm -exec rm -f {} \; > /dev/null 2>&1
+  find $SD/dialects -name support -exec rm -rf {} \; > /dev/null 2>&1
+  echo " done"
+  echo "Removing extraneous stuff from scripts ...\c"
+  find $SD/scripts -name OLD -exec rm -rf {} \; > /dev/null 2>&1
+  find $SD/scripts -name RCS -exec rm -rf {} \; > /dev/null 2>&1
+  find $SD/scripts -name NEW -exec rm -rf {} \; > /dev/null 2>&1
+  echo " done"
+  echo "Removing extraneous stuff from tests ...\c"
+  find $SD/tests -name OLD -exec rm -rf {} \; > /dev/null 2>&1
+  find $SD/tests -name RCS -exec rm -rf {} \; > /dev/null 2>&1
+  find $SD/tests -name NEW -exec rm -rf {} \; > /dev/null 2>&1
+  rm -rf $SD/tests/config.* $SD/tests/*.o
+  rm -rf $SD/tests/LTbasic $SD/tests/LTbigf $SD/tests/LTdnlc
+  rm -rf $SD/tests/LTlock $SD/tests/LTnfs $SD/tests/LTnlink
+  rm -rf $SD/tests/LTsock $SD/tests/LTszoff $SD/tests/LTunix
+  echo " done"
+fi
+
+# Create manual page files.
+
+if test $DEBUG -eq 0
+then
+  echo Producing $MD
+  soelim < $MS > $MD
+  echo Producing $MF
+  nroff -man $MD | colcrt - | cat -s > $MF
+fi
+
+# Check distribution directory for completeness.
+
+if test $DEBUG -eq 0
+then
+  echo "Checking $SD for completeness"
+  rm -f $MC
+  (cd $SD; ls -FR) > $MC
+  diff $M $MC > /dev/null
+  if test $? -ne 0
+  then
+    (echo Some files may be missing.; echo diff $M $MC; diff $M $MC) | less
+    exit 1
+  fi
+fi
+
+# Create source distribution tar file.
+
+if test $DEBUG -eq 0
+then
+  echo Creating $ST in $DN
+  (cd $DN; tar cf $ST $SN; ls -l $ST)
+  echo Removing $SD
+  rm -rf $SD
+fi
+
+# Create source distribution README.lsof_<version> file.
+
+if test $DEBUG -eq 0
+then
+  echo Creating $R for $DT
+  rm -f ${DN}/$R
+  EO=${DN}/$R
+else
+  echo "==== The $R file ====="
+  EO=""
+fi
+cat > $EO << END_README_1
+
+                Information About This Lsof Distribution
+
+
+What You Have
+=============
+
+If you got this far without being confused, then you are probably
+familiar with the construction of the lsof distribution or you have
+read RELEASE.SUMMARY_${V}.  If either is the case, please skip to
+the Inventory section.  If you haven't read RELEASE.SUMMARY_${V},
+I suggest you do it now, because it explains how the lsof distribution
+is constructed and other useful things about lsof, including a
+summary of changes for the past few lsof revisions.
+
+Even though you may have thought you were getting lsof.tar.bz2,
+lsof.tar.gz or lsof.tar.Z with ftp, you really got ${DT}.bz2,
+${DT}.gz or ${DT}.Z.  That's because the triplet of
+lsof.tar.* files are symbolic links to their longer-named counterparts.
+
+The bzip2'd, gzip'd or compressed tar files with lsof_, followed by a
+number, are wrapper archives, designed to package the lsof source
+archive, this file, other documentation files, and a GPG authentication
+certificate together.
+
+The number, ${V}, is the lsof revision number.  When you bunzip2'd,
+gunzip'd or uncompressed ${DT}.* and used tar to unpack
+${DT}, you got: ${RM}, describing the contents
+of ${DN}; ${R}; ${ST}; and
+${ST}.sig.  All are identified with the revision number.
+You're reading ${R}.  ${ST}.sig is a GPG
+certificate that authenticates the lsof source archive,
+${ST}.
+
+After you read the Inventory and Security sections, and hopefully
+after you check the GPG certificate, unpack the ${ST}
+source archive and you will get a sub-directory, named ${SN},
+that contains the lsof ${V} source distribution.
+
+
+Inventory
+=========
+
+Once you have unpacked ${ST}.tar, you can check
+${SN} for completeness by changing to that sub-directory
+and running the Inventory script.  The ${SN}/Configure
+script runs the Inventory script, too.  The Configure script also
+calls a customization script, called Customize.  You can direct
+Configure to avoid calling Inventory and Customize with the -n
+option.
+
+See the Distribution Contents section of the 00DIST file and The
+Inventory Script section of the 00README file for more information
+on the contents of the lsof distribution, and the Configure,
+Customize and Inventory scripts.  The 00DIST and 00README files
+will be found in the ${SN} sub-directory you just created.
+
+
+Security
+========
+
+The md5 checksum for $ST is:
+
+END_README_1
+echo "  \c" >> $EO
+if test $DEBUG -eq 1
+then
+  echo "MD5 checksum of $ST would go here." >> $EO
+else
+  (cd $DN; md5 $ST) >> $EO
+fi
+cat >> $EO << END_README_2
+
+A good source for an MD5 checksum computation tool is the OpenSSL
+project whose work may be found at:
+
+  www.openssl.org
+
+You can use the openssl "dgst" operator to compute an MD5 checksum --
+e.g.,
+
+  $ openssl dgst -md5 $SN
+
+The old-style sum(1) checksum for $ST (Please read
+the next paragraph if you don't get this value.) is:
+
+END_README_2
+echo "  \c" >> $EO
+if test $DEBUG -eq 1
+then
+  echo "Sum checksum of $ST would go here." >> $EO
+else
+  sum -r ${DN}/$ST >> $EO
+fi
+cat >> $EO << END_README_3
+
+If your dialect's sum(1) program defaults to the new style algorithm
+(e.g., Solaris), you may have to use its -r option (or use the
+Solaris /usr/ucb/sum).  If your Unix dialect doesn't have a sum(1)
+program (e.g., FreeBSD, or NetBSD), use its cksum(1) program with
+the -o1 option to get an old-style checksum.  You may also need to
+ignore the block count, depending on the block size used on your
+your system (i.e., 512 or 1,024).  The sum(1) that produced the
+above checksum considers block size to be 512; in contrast the BSD
+cksum(1) programs' -o1 option considers block size to be 1,024.
+
+${ST}.sig is a GPG certificate file, using my public
+key.  My key may be available on some public key servers under the
+names:
+
+    Victor A. Abell <abe@cc.purdue.edu>
+ or
+    Victor A. Abell <abe@purdue.edu>
+
+You will also find it at:
+
+  ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/Victor_A_Abell.gpg
+
+Get my key and install it in your public key ring.
+
+Once my key is installed, use this command to check the certificate
+of $ST:
+
+    gpg --verify ${ST}.sig $ST
+
+If the certificate check isn't good, $ST is suspect.
+Report the problem to me via e-mail at <abe@purdue.edu>.
+
+If you don't have GPG, you can compare the md5 checksum of
+$ST to the value listed in this file.  However, that
+is a less reliable authentication method, since it can't detect
+changes to both $ST and the md5 checksum value listed
+in this tile.
+
+Other Security
+==============
+
+Signature information for the distribution file that contains
+this file may be found in the CHECKSUMS file that is located
+where the distribution file was found.
+
+
+Victor A. Abell <abe@purdue.edu>
+END_README_3
+
+date >> $EO
+
+# Create GPG certificate.
+
+if test $DEBUG -eq 0
+then
+  echo Creating ${ST}.sig in $DN
+  (cd $DN; rm -f ${ST}.sig; \
+   echo $PGPPASS | gpg -o ${ST}.sig --passphrase-fd 0 -b $ST; \
+   chmod 644 ${ST}.sig)
+fi
+
+# Construct distribution's 00.README_FIRST_<version> file.
+
+if test $DEBUG -eq 0
+then
+  echo Creating $RM for $DT
+  rm -f ${DN}/$RM
+  EO=${DN}/$RM
+else
+  echo ""
+  echo "==== The $RM file ====="
+  echo ""
+  EO=""
+fi
+echo "A tour of the lsof_${V} distribution:" > $EO
+echo "" >> $EO
+echo "  $RM is this file." >> $EO
+echo "" >> $EO
+echo "  $R contains distribution and security information." >> $EO
+echo "" >> $EO
+echo "  ${DSF} contains a summary of the lsof ${V}" >> $EO
+echo "  distribution." >> $EO
+echo "" >> $EO
+echo "  $ST is the lsof ${V} source tar archive." >> $EO
+echo "" >> $EO
+echo "  ${ST}.sig is a detached GPG certificate for" >> $EO
+echo "  ${ST}." >> $EO
+echo "" >> $EO
+echo "I suggest you follow these steps:" >> $EO
+echo "" >> $EO
+echo "1.  Read ${RM}." >> $EO
+echo "" >> $EO
+echo "2.  Read ${R} and follow its instructions to verify" >> $EO
+echo "    the authenticity of ${ST}." >> $EO
+echo "" >> $EO
+echo "3.  Unpack ${ST} -- use \`tar xf ${ST}\`." >> $EO
+echo "    That will produce an ${SN} sub-directory." >> $EO
+echo "" >> $EO
+echo "4.  Change to the ${SN} sub-directory and read its" >> $EO
+echo "    00.README.FIRST file." >> $EO
+echo "" >> $EO
+echo "Vic Abell <abe@purdue.edu>" >> $EO
+echo `date` >> $EO
+
+# Create distribution summary file.
+
+if test $DEBUG -eq 0
+then
+  echo Creating ${DN}/$DSF
+  rm -f ${DN}/$DSF
+  cp $SF ${DN}/$DSF
+else
+  echo Distribution summary file would be ${DN}/$DSF, copied from $SF.
+fi
+
+# Create distribution tar file, then bzip2, compress and gzip it.
+
+if test $DEBUG -eq 0
+then
+  rm -f $MC
+  echo Creating $DT
+  rm -f $DT ${DT}.bz2 ${DT}.gz ${DT}.Z
+  tar cf $DT $DN
+  ls -l $DT
+  echo Bzip2ing $DT
+  bzip2 -c $DT > support/${DT}.bz2
+  ls -l support/${DT}.bz2
+  echo Gzipping $DT
+  gzip -c $DT > support/${DT}.gz
+  ls -l support/${DT}.gz
+  echo Compressing $DT
+  compress < $DT > support/${DT}.Z
+  ls -l support/${DT}.Z
+  echo Removing $DN and $DT
+  rm -rf $DN $DT
+
+  # Create checksum files.
+
+  for i in bz2 gz Z
+  do
+    echo Creating ${DT}.${i}.sig
+    SIG=support/${DT}.${i}.sig
+    SRC=support/${DT}.${i}
+    rm -f $SIG
+    echo $PGPPASS | gpg -o $SIG --passphrase-fd 0 -b $SRC
+  done
+  echo Creating $CK
+  rm -f support/$CK
+  cat >> support/$CK << END_CKSUM_1
+
+                        Checksums for lsof_${V}
+
+This file was created when the official lsof ${V} distribution files
+were created.  It contains MD5 checksums and GPG certificate
+information for the lsof ${V} bzip2, gzip and compressed distribution
+files.
+
+There are additional opportunities to validate the lsof distribution
+with infomation found inside it.  Consult the file ${R}
+inside the distribution.
+
+MD5 Checksums
+=============
+
+The MD5 checksums are:
+
+END_CKSUM_1
+
+  for i in bz2 gz Z
+  do
+    echo "  \c" >> support/$CK
+    (cd support; md5 ${DT}.$i >> $CK)
+  done
+
+cat >> support/$CK << END_CKSUM_2
+
+GPG Certificates
+================
+
+The following files, found with the lsof distribution files, contain
+GPG certificates:
+
+  lsof.tar.bz2.sig or ${DT}.bz2.sig
+  lsof.tar.gz.sig  or ${DT}.gz.sig
+  lsof.tar.Z.sig   or ${DT}.Z.sig
+
+Validating a GPG certificate is the best way to make sure no one has
+tampered with a distribution file.
+
+Use the GPG certificate files with the GPG public key for:
+
+  Victor A. Abell <abe@purdue.edu>
+
+You may be able to find the key on some public key servers.  It is also
+available at:
+
+  ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/Victor_A_Abell.gpg
+
+Get the key and install it in your public key ring.  Once the key is
+installed, use one of these command forms to check the certificate of a
+distribution file:
+
+  gpg --verify ${DT}.<type>.sig ${DT}.<type>
+
+or
+
+  gpg --verify lsof.tar.<type>.sig lsof.tar.<type>
+
+Where <type> is bz2, gz or Z.
+
+Problems
+========
+
+If an MD5 or GPG check reveals a problem, please report it via e-mail
+to <abe@purdue.edu>.
+
+
+Vic Abell
+END_CKSUM_2
+date >> support/$CK
+(cd support; ls -l $CK)
+fi
+echo "all done"
diff --git a/support/GenericCopy b/support/GenericCopy
new file mode 100755 (executable)
index 0000000..93abf9b
--- /dev/null
@@ -0,0 +1,88 @@
+#!/bin/ksh
+#
+# GenericCopy -- generically copy lsof 4.x sources to a specified destination
+#
+# Usage: GenericCopy <destination> <login> <dialect> [<directory>]
+#
+#       <destination>  destination host
+#
+#       <login>        login name at destination host
+#
+#       <dialect>      dialect subdirectory name
+#
+#       [<directory>]  directory if other than src/lsof4
+
+if test $# -lt 1 -o $? -gt 4
+then
+  echo "Usage: <destination> <login> <dialect> [<directory>]"
+  exit
+fi
+D=$1
+L=$2
+DSDIR=$3
+if test $# -eq 4
+then
+  DDIR=$4
+else
+  DDIR=src/lsof4
+fi
+
+# Set useful definitions.
+
+SDIR=src/lsof4
+F="00DIALECTS AFSConfig Configure Customize Inventory arg.c lsof_fields.h common.h main.c misc.c node.c print.c proc.c proto.h regex.h store.c usage.c util.c version"
+
+cd $HOME/$SDIR
+
+# Make sure the destination directories exist.
+
+rsh $D -l $L -n mkdir $DDIR $DDIR/dialects $DDIR/lib $DDIR/dialects/$DSDIR
+
+# Copy new base directory files to destination.
+
+rsh $D -l $L -n "(cd $DDIR; rm -f $F)"
+for i in $F
+do
+  rcp $i ${L}@${D}:${DDIR}
+  echo "$i \c"
+done
+echo ""
+
+# Remove old files in lib/ and dialects/<dialect>/.
+
+rsh $D -l $L -n "rm -rf $DDIR/lib/* $DDIR/dialects/$DSDIR/*"
+
+# Copy lib/*.
+
+cd lib
+echo "lib: \c"
+for i in *.c Makefile.skel
+do
+  if test ! -d $i
+  then
+    rcp $i ${L}@${D}:${DDIR}/lib
+    echo "$i \c"
+  fi
+done
+echo ""
+
+# Copy dialects/<dialect>/*.
+
+cd ../dialects/$DSDIR
+echo "dialects/$DSDIR: \c"
+for i in *
+do
+  if test -d $i
+  then
+    if test $i != OLD -a $i != NEW -a $i != RCS
+    then
+      rcp -r $i ${L}@${D}:${DDIR}/dialects/$DSDIR
+      echo "$i \c"
+    fi
+  else
+    rcp $i ${L}@${D}:${DDIR}/dialects/$DSDIR
+    echo "$i \c"
+  fi
+done
+echo ""
+echo "done"
diff --git a/support/GenericDistrib b/support/GenericDistrib
new file mode 100755 (executable)
index 0000000..ebe25fe
--- /dev/null
@@ -0,0 +1,70 @@
+#!/bin/ksh
+#
+# GenericDistrib -- generic lsof 4.x distribution gzip'd archive builder
+# GenericDistrib2 -- generic lsof 4.x distribution bzip2'd archive builder
+#
+# Usage: GenericDistrib <dialect> [<suffix>]
+#
+#      <dialect>       dialect's subdirectory name
+#
+#      [<suffix>]      optional suffix for version number
+
+cd $(dirname $0)/..
+
+# Get version number.
+
+V=`sed '/VN/s/.ds VN \(.*\)/\1/' version`
+if test $? -ne 0
+then
+  echo $V
+  exit 1
+fi
+
+# Handle arguments.
+
+if test $# -lt 1 -o $# -gt 2
+then
+  echo "Usage: <dialect> [<suffix>]"
+  exit 1
+fi
+DIALECT=$1
+if test $# -eq 2
+then
+  V=${V}$2
+fi
+
+# Set variable names.
+
+DIR=lsof_${V}.${DIALECT}
+TAR=${DIR}.tar
+echo $0 | grep 2 > /dev/null
+if test $? -eq 0
+then
+  TARC=${TAR}.bz2
+  COMP=bzip2
+else
+  TARC=${TAR}.gz
+  COMP=gzip
+fi
+
+# Prepare for premature exit.
+
+trap 'rm -rf $DIR $TAR $TARC; exit' 1 2 3 15
+
+# Make a temporary directory with the relevant files in it and
+# create a gzip'd tar archive of it.
+
+rm -rf $TAR $TARC
+./support/GenericSubdir $1 $2
+echo "Making $TAR ...\c"
+tar cf $TAR $DIR
+echo " done"
+ls -l $TAR
+echo "Removing $DIR ...\c"
+rm -rf $DIR
+echo " done"
+echo "$COMP $TAR ...\c"
+$COMP -c $TAR > support/$TARC
+echo " done"
+ls -l support/$TARC
+rm -f $TAR
diff --git a/support/GenericDistrib2 b/support/GenericDistrib2
new file mode 120000 (symlink)
index 0000000..e2306c6
--- /dev/null
@@ -0,0 +1 @@
+GenericDistrib
\ No newline at end of file
diff --git a/support/GenericRdist b/support/GenericRdist
new file mode 100755 (executable)
index 0000000..d001156
--- /dev/null
@@ -0,0 +1,80 @@
+#!/bin/ksh
+#
+# GenericRdist -- generically rdist lsof 4.x sources to a specified destination
+#
+# Usage: GenericRdist <destination> <dialect> <shell>
+#
+#       <destination>  destination host
+#
+#       <dialect>      dialect subdirectory name
+#
+#       <shell>        remote shell -- rsh or ssh
+
+# Process arguments.
+
+if test $# -ne 3
+then
+  echo "Usage: <destination> <dialect> <shell>"
+  exit
+fi
+H=$1
+D=$2
+S=$3
+
+# Test the shell and define it's full path, as required.
+
+if test "X$S" = "Xrsh"
+then
+  SHP=""
+else
+  if test "X$S" = "Xssh"
+  then
+    SHP="-P /opt/openssh/bin/ssh"
+  else
+    echo "$S is not an acceptable shell; specify rsh or ssh."
+    exit
+  fi
+fi
+
+# Define the distfile and make sure it's removed on premature exit.
+
+R=/tmp/distfile.$$
+trap 'rm $R; exit 1' 1 2 3 15
+
+rm -f $R
+cat > $R << .DISTFILE
+. -> $H
+       except ( ./00.README.FIRST ./00DCACHE ./00DIST ./00FAQ );
+       except ( ./00PORTING ./00README ./00CREDITS ./00QUICKSTART );
+       except ( ./00LSOF-L ./00MANIFEST ./00XCONFIG ./.ck00MAN );
+       except ( ./00TEST ./.neverCust ./.neverInv );
+       except ( ./ChangeLog ./Makefile );
+       except ( ./lsof ./lsof32 ./lsof64 ./lsof_old /lsof_32.old );
+       except ( ./lsof_64.old ./Lsof.8 );
+       except ( ./ddev.c ./dfile.c ./dlsof.h ./dmnt.c ./dnode.c ./dnode1.c );
+       except ( ./dnode2.c ./dproc.c ./dproto.h ./dsock.c ./dstore.c );
+       except ( ./kernelbase.h ./machine.h ./version.h ./zipme );
+       except ( ./NEW ./OLD ./RCS ./dialects ./support ) ;
+       except ( ./make.out ./new ./old ./out ./X ./xxx ./errs ) ;
+       except ( ./lib/Makefile ./lib/RCS ./lib/OLD ./lib/NEW );
+       except ( ./scripts/OLD ./scripts/NEW ./scripts/RCS );
+       except ( ./scripts/00MANIFEST ./scripts/00README ) ;
+       except ( ./tests/OLD ./tests/NEW ./tests/RCS );
+       except ( ./tests/00README );
+       except ( ./tests/LTbasic ./tests/LTbigf ./tests/LTdnlc );
+       except ( ./tests/LTlock ./tests/LTnfs ./tests/LTnlink );
+       except ( ./tests/LTsock ./tests/LTszoff ./tests/LTunix );
+       except_pat ( \\.o\\$ \\.a\\$ ./tests/config\\. );
+       install src/lsof4;
+
+./dialects/$D -> $H
+       except ( ./dialects/$D/NEW );
+       except ( ./dialects/$D/OLD ./dialects/$D/RCS );
+       install src/lsof4/dialects/$D ;
+.DISTFILE
+
+# Do the actual distribution.
+
+(cd $HOME/src/lsof4; /usr/local/bin/rdist $SHP -f $R)
+rm $R
+echo done
diff --git a/support/GenericSubdir b/support/GenericSubdir
new file mode 100755 (executable)
index 0000000..5921414
--- /dev/null
@@ -0,0 +1,106 @@
+#!/bin/ksh
+#
+# GenericSubdir -- create generic lsof 4.x distribution subdirectory
+#
+# Usage: GenericSubdir <dialect> [<suffix>]
+#
+#      <dialect>       dialect's subdirectory name
+#
+#      [<suffix>]      optional suffix for version number
+
+cd $(dirname $0)/..
+
+# Get version number.
+
+V=`sed '/VN/s/.ds VN \(.*\)/\1/' version`
+if test $? -ne 0
+then
+  echo $V
+  exit 1
+fi
+
+# Handle arguments.
+
+if test $# -lt 1 -o $# -gt 2
+then
+  echo "Usage: <dialect> [<suffix>]"
+  exit 1
+fi
+DIALECT=$1
+if test $# -eq 2
+then
+  V=${V}$2
+fi
+
+# Set variable names.
+
+DIR=lsof_${V}.${DIALECT}
+F=
+F="$F 0..README.BEFORE.README.FIRST README.md check.bash"
+F="$F 00.README.FIRST 00CREDITS 00DCACHE 00DIALECTS 00DIST 00FAQ 00LSOF-L 00PORTING 00QUICKSTART 00README 00TEST 00XCONFIG"
+F="$F AFSConfig ChangeLog Configure Customize Inventory"
+F="$F arg.c lsof_fields.h common.h main.c misc.c node.c print.c proc.c proto.h regex.h store.c usage.c util.c"
+F="$F version"
+MS=Lsof.8
+MD=lsof.8
+MF=lsof.man
+
+# Prepare for premature exit.
+
+trap 'rm -rf $DIR; exit' 1 2 3 15
+
+# Make a temporary directory and copy the relevant files to it.
+
+rm -rf $DIR
+mkdir $DIR
+echo "Copying:\c"
+for i in $F
+do
+  echo " $i\c"
+  cp -r $i $DIR
+done
+echo " ... done"
+echo "Copying lib ...\c"
+cp -r lib $DIR/lib
+echo " done"
+echo "Removing extraneous stuff from lib ...\c"
+rm -rf $DIR/lib/RCS $DIR/lib/OLD $DIR/lib/NEW
+rm -rf $DIR/lib/Makefile $DIR/lib/*.[oa]
+echo " done"
+mkdir $DIR/dialects
+echo "Copying dialects/${DIALECT} ...\c"
+cp -r dialects/${DIALECT} $DIR/dialects
+echo " done"
+echo "Removing extraneous stuff from dialects/${DIALECT} ...\c"
+rm -rf $DIR/dialects/${DIALECT}/distfile.kvm
+rm -rf $DIR/dialects/${DIALECT}/Makefile.LOCAL
+rm -rf $DIR/dialects/${DIALECT}/version.h
+find ${DIR}/dialects -name OLD -exec rm -rf {} \; > /dev/null 2>&1
+find ${DIR}/dialects -name NEW -exec rm -rf {} \; > /dev/null 2>&1
+find ${DIR}/dialects -name support -exec rm -rf {} \; > /dev/null 2>&1
+find ${DIR}/dialects -name RCS -exec rm -rf {} \; > /dev/null 2>&1
+echo " done"
+echo "Copying scripts ...\c"
+cp -r scripts $DIR
+echo " done"
+echo "Removing extraneous stuff from scripts ...\c"
+rm -rf $DIR/scripts/NEW $DIR/scripts/OLD $DIR/scripts/RCS
+echo " done"
+echo "Copying tests ...\c"
+cp -r tests $DIR
+echo " done"
+echo "Removing extraneous stuff from tests ...\c"
+rm -rf $DIR/tests/NEW $DIR/tests/OLD $DIR/tests/RCS $DIR/tests/*.o
+rm -rf $DIR/tests/00README
+rm -rf $DIR/tests/config.* $DIR/tests/LTbasic $DIR/tests/LTbigf
+rm -rf $DIR/tests/LTdnlc $DIR/tests/LTlock $DIR/tests/LTnfs
+rm -rf $DIR/tests/LTnlink $DIR/tests/LTsock $DIR/tests/LTszoff
+rm -rf $DIR/tests/LTunix
+echo " done"
+echo "Producing $MD and $MF ...\c"
+soelim < $MS > $DIR/$MD
+nroff -man $MS | colcrt - | cat -s > $DIR/$MF
+echo " done"
+echo "Producing 00MANIFEST ...\c"
+(cd $DIR; ls -FR > 00MANIFEST)
+echo " done"
diff --git a/support/GitHub-release/00README b/support/GitHub-release/00README
new file mode 100644 (file)
index 0000000..fd69bbe
--- /dev/null
@@ -0,0 +1,10 @@
+There are two files in this directory that document the release
+of lsof to GitHub by Purdue officials.
+
+ITaP   contains a release from Purdue's Vice President for
+       Information technology, Gerry McCartney.
+
+Purdue contains a release from Purdue's Senior Intellectual
+       Property Officer, Ken L. Sandel.
+
+14 July 2018
diff --git a/support/GitHub-release/ITaP b/support/GitHub-release/ITaP
new file mode 100644 (file)
index 0000000..0a115b4
--- /dev/null
@@ -0,0 +1,47 @@
+From:  McCartney, William G <mccart@purdue.edu>
+Sent:  Wednesday, June 27, 2018 16:35
+To:    Victor Abell
+Cc:    Vic Abell
+Subject:       RE: retiring lsof
+
+No objection at all Vic,  and thank you for so many years of valuable service to the community.
+
+From one my senior people: \93Lsof is one of the most amazing UNIX tools that retired PUCC
+wizard Vic wrote and still supports. Github is a much better answer than running a server in
+ITaP for it.\94
+
+Best wishes,   Gerry-
+
+From: Victor Abell <vabell@lsof.comcastbiz.net>
+Sent: Wednesday, June 27, 2018 5:06 AM
+To: McCartney, William G <mccart@purdue.edu>
+Cc: Vic Abell <abe@purdue.edu>
+Subject: retiring lsof
+
+Gerry,
+
+Since I retired from ITaP in 2003, I have received support from ITaP
+to continue distributing lsof, the open source UNIX tool that I developed
+at PUCC and released in 1994.  That support extends to a Visiting
+Scholar appointment and a Sun Solaris system, lsof.itap.purdue.edu
+from which lsof is distributed.
+
+I am nearing 80 in age and it is time for me to end my support before
+circumstances do it for me.  I announced that intention to the lsof \96l
+mailing list (lsof-l@lists.purdue.edu) and several readers replied that
+they would like to continue support by moving lsof to the GitHub
+open source development platform (https://github.com/).
+
+Because the lsof source code contains a Purdue Research Foundation
+copyright, I have been discussing the release with Joseph R. Kasper
+(JRKasper@prf.org) in Purdue\92s Office of Technology Commercialization.
+Joe is supportive of the move, but asks if I have discussed it with anyone
+in ITaP.  Only Greg Veldman (gv@purdue.edu) , who has provided
+support for lsof.itap, has been aware of the GitHub request.
+I have been remiss in not contacting you about this.  Please excuse my
+omission and let me know if you have any objection to the release of
+lsof to GitHub.
+
+Regards,
+
+Vic Abell
diff --git a/support/GitHub-release/Purdue b/support/GitHub-release/Purdue
new file mode 100644 (file)
index 0000000..d7fd360
--- /dev/null
@@ -0,0 +1,156 @@
+From:  Sandel, Ken L. <sandel@purdue.edu>
+Sent:  Tuesday, July 10, 2018 14:28
+To:    Victor Abell
+Subject:       RE: One more question regarding GitHub release
+
+Vic,
+
+For clarity \96 I approved the release.
+
+Ken
+
+Ken L. Sandel
+Senior Director, Sponsored Program Services
+Senior Intellectual Property Officer
+Purdue University
+610 Purdue Mall
+Hovde Hall Room 328
+West Lafayette, IN 47907
+sandel@purdue.edu
+(765) 494-1063 (office)
+(765) 426-2530 (cell)
+
+From: Kasper, Joseph R. <JRKasper@prf.org>
+Sent: Tuesday, July 10, 2018 11:23 AM
+To: Victor Abell <vabell@lsof.comcastbiz.net>
+Cc: Sandel, Ken L. <sandel@purdue.edu>
+Subject: RE: One more question regarding GitHub release
+
+Hi Vic,
+
+My apologies for not following up. Mr. Sandel approves the release on GitHub under the copyright
+notice text currently in use.
+
+Best,
+Joe
+
+Joseph R. Kasper, Ph.D.
+Senior Business Development Manager & Director of Marketing
+Office of Technology Commercialization
+765-588-3486
+jrkasper@prf.org
+Purdue Technology Center Aerospace
+1801 Newman Road
+West Lafayette, IN 47906
+www.innovation-entrepreneurship-purdue.com
+www.prf.org/otc/
+
+
+CONFIDENTIALITY NOTICE:  This email and any attachments are for the exclusive and confidential use of the intended recipient.  If you are not
+the intended recipient, please do not read, distribute or take action in reliance upon this message.  If you have received this in error, please
+notify us immediately by return email and promptly delete this message and its attachments from your computer system.
+
+
+
+
+From: Victor Abell <vabell@lsof.comcastbiz.net>
+Sent: Monday, July 9, 2018 8:26 PM
+To: Kasper, Joseph R. <JRKasper@prf.org>
+Subject: RE: One more question regarding GitHub release
+
+Joe,
+
+Has there been any word from Ken about the release
+of lsof to GitHub?
+
+Vic
+
+From: Kasper, Joseph R. [mailto:JRKasper@prf.org]
+Sent: Thursday, June 28, 2018 1:15 PM
+To: Victor Abell
+Subject: RE: One more question regarding GitHub release
+
+Hi Vic,
+
+One more request. Ken would like a copy of the email from Gerry. If for any reason you aren\92t
+comfortable sending it to me, please contact Ken directly (765-494-1063, sandel@purdue.edu).
+
+If this last piece of information is satisfactory to Ken, I expect to get his approval.
+
+Thanks for your cooperation throughout this process.
+
+Best,
+Joe
+
+From: Victor Abell <vabell@lsof.comcastbiz.net>
+Sent: Thursday, June 28, 2018 7:43 AM
+To: Kasper, Joseph R. <JRKasper@prf.org>
+Subject: RE: One more question regarding GitHub release
+
+Joe,
+
+I sent e-mail to Gerry McCartney and in his answer he
+says he has no objection.
+
+Vic
+
+From: Kasper, Joseph R. [mailto:JRKasper@prf.org]
+Sent: Tuesday, June 26, 2018 4:03 PM
+To: Victor Abell
+Subject: RE: One more question regarding GitHub release
+
+Hi Vic,
+
+Thanks for the extra detail. I think it would put Ken\92s mind at ease if you have Gerry\92s blessing. Let me
+know if you\92ll reach out to him.
+
+Best,
+Joe
+
+From: Victor Abell <vabell@lsof.comcastbiz.net>
+Sent: Tuesday, June 26, 2018 3:57 PM
+To: Kasper, Joseph R. <JRKasper@prf.org>
+Subject: RE: One more question regarding GitHub release
+
+Joe,
+
+I have had no communication with ITaP about the move to GitHub.
+The extent of their involvement with lsof has been minimal \96 the
+Visiting Scholar appointment and the maintenance of a distribution
+system.
+
+I know Gerry McCartney well.  Would it be helpful if I contacted
+him about the GitHub move?
+
+Vic
+
+From: Kasper, Joseph R. [mailto:JRKasper@prf.org]
+Sent: Tuesday, June 26, 2018 3:44 PM
+To: Vic Abell; Victor Abell
+Subject: One more question regarding GitHub release
+
+Hi Vic,
+
+Ken Sandel, Senior IP Officer, just got back to me. He wants to know if the leadership of ITaP supports
+the contribution to Github. Please let me know. If you have any communication to this effect that you
+can forward to me, it would be helpful.
+
+Best,
+Joe
+
+Joseph R. Kasper, Ph.D.
+Business Development Manager
+Purdue Research Foundation
+Office of Technology Commercialization
+765-588-3486
+jrkasper@prf.org
+Purdue Technology Center Aerospace
+1801 Newman Road
+West Lafayette, IN 47906
+www.innovation-entrepreneurship-purdue.com
+www.prf.org/otc/
+
+
+CONFIDENTIALITY NOTICE:  This email and any attachments are for the exclusive and confidential use of the intended recipient.  If you are not
+the intended recipient, please do not read, distribute or take action in reliance upon this message.  If you have received this in error, please
+notify us immediately by return email and promptly delete this message and its attachments from your computer system.
diff --git a/support/HPUXDistrib b/support/HPUXDistrib
new file mode 100755 (executable)
index 0000000..082e253
--- /dev/null
@@ -0,0 +1,14 @@
+#!/bin/ksh
+#
+# HPUXDistrib -- make HP-UX distribution of lsof 4.x
+#
+# Usage: HPUXDistrib [<suffix>]
+#
+#       <suffix>       optional suffix for identification
+
+if test $# -gt 1
+then
+  echo "Usage: [<suffix>]"
+  exit 1
+fi
+$HOME/src/lsof4/support/GenericDistrib hpux $1
diff --git a/support/NSDistrib b/support/NSDistrib
new file mode 100755 (executable)
index 0000000..ed72809
--- /dev/null
@@ -0,0 +1,14 @@
+#!/bin/ksh
+#
+# NSDistrib -- make NeXTSTEP distribution of lsof 4.x
+#
+# Usage: NSDistrib [<suffix>]
+#
+#       <suffix>       optional suffix for identification
+
+if test $# -gt 1
+then
+  echo "Usage: [<suffix>]"
+  exit 1
+fi
+$HOME/src/lsof4/support/GenericDistrib ns $1
diff --git a/support/NetBSDDistrib b/support/NetBSDDistrib
new file mode 100755 (executable)
index 0000000..c23abb1
--- /dev/null
@@ -0,0 +1,14 @@
+#!/bin/ksh
+#
+# NetBSDDistrib -- make NetBSD distribution of lsof 4.x
+#
+# Usage: NetBSDDistrib [<suffix>]
+#
+#       <suffix>       optional suffix for identification
+
+if test $# -gt 1
+then
+  echo "Usage: [<suffix>]"
+  exit 1
+fi
+$HOME/src/lsof4/support/GenericDistrib2 netbsd $1
diff --git a/support/OSRDistrib b/support/OSRDistrib
new file mode 100755 (executable)
index 0000000..16c860c
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/ksh
+#
+# OSRDistrib -- make SCO OpenServer distribution of lsof 4.x
+#
+# Usage: OSRDistrib [<suffix>]
+#
+#       <suffix>       optional suffix for identification
+
+if test $# -gt 1
+then
+  echo "Usage: [<suffix>]"
+  exit 1
+fi
+cd $HOME/src/lsof4/support
+./GenericDistrib osr $1
diff --git a/support/OpenBSDDistrib b/support/OpenBSDDistrib
new file mode 100755 (executable)
index 0000000..3f124e8
--- /dev/null
@@ -0,0 +1,14 @@
+#!/bin/ksh
+#
+# OpenBSDDistrib -- make OpenBSD distribution of lsof 4.x
+#
+# Usage: OpenBSDDistrib [<suffix>]
+#
+#       <suffix>       optional suffix for identification
+
+if test $# -gt 1
+then
+  echo "Usage: [<suffix>]"
+  exit 1
+fi
+$HOME/src/lsof4/support/GenericDistrib2 openbsd $1
diff --git a/support/SpecialRdist b/support/SpecialRdist
new file mode 100755 (executable)
index 0000000..eeaf21a
--- /dev/null
@@ -0,0 +1,74 @@
+#!/bin/ksh
+#
+# SpecialRdist -- specially rdist lsof 4.x sources to a specified destination
+#
+# Usage: GenericRdist <destination> <dialect> <shell>
+#
+#       <destination>  destination host
+#
+#       <dialect>      dialect subdirectory name
+#
+#       <shell>        remote shell -- rsh or ssh
+
+# Process arguments.
+
+if test $# -ne 3
+then
+  echo "Usage: <destination> <dialect> <shell>"
+  exit
+fi
+H=$1
+D=$2
+S=$3
+
+# Test the shell and define it's full path, as required.
+
+if test "X$S" = "Xrsh"
+then
+  SHP=""
+else
+  if test "X$S" = "Xssh"
+  then
+    SHP="-P /opt/openssh/bin/ssh"
+  else
+    echo "$S is not an acceptable shell; specify rsh or ssh."
+    exit
+  fi
+fi
+
+# Define the distfile and make sure it's removed on premature exit.
+
+R=/tmp/distfile.$$
+trap 'rm $R; exit 1' 1 2 3 15
+
+rm -f $R
+echo ". -> $H" > $R
+echo " except ( ./.ck00MAN );" >> $R
+echo " except ( ./.neverCust ./.neverInv );" >> $R
+echo " except ( ./Makefile ./ddev.c ./dfile.c ./dlsof.h ./dmnt.c );" >> $R
+echo " except ( ./dnode.c ./dnode1.c ./dproc.c ./dproto.h ./dsock.c );" >> $R
+echo " except ( ./dstore.c ./lib/Makefile ./lib/RCS ./lib/OLD ./lib/NEW );" >> $R
+echo " except ( ./lsof ./machine.h ./version.h ./zipme );" >> $R
+echo " except ( ./NEW ./OLD ./RCS ./dialects ./support ) ;" >> $R
+echo " except ( ./new ./old ./X ./xxx ./errs ) ;" >> $R
+echo " except ( ./scripts/OLD ./scripts/NEW ./scripts/RCS ) ;" >> $R
+echo " except ( ./scripts/00MANIFEST ./scripts/00README ) ;" >> $R
+echo " except ( ./tests/OLD ./tests/NEW ./tests/RCS ) ;" >> $R
+echo " except ( ./tests/00README ) ;" >> $R
+echo " except ( ./tests/LTbasic ./tests/LTbigf ./tests/LTdnlc ) ;" >> $R
+echo " except ( ./tests/LTlock ./tests/LTnfs ./tests/LTnlink ) ;" >> $R
+echo " except ( ./tests/LTsock ./tests/LTszoff ./tests/LTunix ) ;" >> $R
+echo " except_pat ( \\\\./tests/config\\\\. );" >> $R
+echo " except_pat ( \\\\.gz \\\\.o \\\\.a );" >> $R
+echo " install src/lsof4 ;" >> $R
+echo "" >> $R
+echo "./dialects/$D -> $H" >> $R
+echo " except ( ./dialects/$D/NEW );" >> $R
+echo " except ( ./dialects/$D/OLD ./dialects/$D/RCS );" >> $R
+echo " install src/lsof4/dialects/$D ;" >> $R
+
+# Do the actual distribution.
+
+(cd $HOME/src/lsof4; rdist $SHP -f $R)
+rm $R
+echo done
diff --git a/support/SunDistrib b/support/SunDistrib
new file mode 100755 (executable)
index 0000000..d569d59
--- /dev/null
@@ -0,0 +1,14 @@
+#!/bin/ksh
+#
+# SunDistrib -- make Solaris and SunOS distribution of lsof 4.x
+#
+# Usage: SunDistrib [<suffix>]
+#
+#       <suffix>       optional suffix for identification
+
+if test $# -gt 1
+then
+  echo "Usage: [<suffix>]"
+  exit 1
+fi
+$HOME/src/lsof4/support/GenericDistrib2 sun $1
diff --git a/support/UWDistrib b/support/UWDistrib
new file mode 100755 (executable)
index 0000000..3710b7e
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/ksh
+#
+# UWDistrib -- make SCO UnixWare distribution of lsof 4.x
+#
+# Usage: UWDistrib [<suffix>]
+#
+#       <suffix>       optional suffix for identification
+
+if test $# -gt 1
+then
+  echo "Usage: [<suffix>]"
+  exit 1
+fi
+cd $HOME/src/lsof4/support
+./GenericDistrib2 uw $1
diff --git a/support/argtest b/support/argtest
new file mode 100755 (executable)
index 0000000..b84ffff
--- /dev/null
@@ -0,0 +1,104 @@
+#!/bin/sh
+#
+# argtest -- test lsof arguments for stack overflows
+#
+# usage: argtest [path_to_lsof]
+#
+#   where:
+#          path_to_lsof        optional *absolute* path to lsof (default
+#                              ${HOME}/src/lsof4/lsof)
+
+ARG_A=`pwd`/argtest_a.$$
+ARG_N=`pwd`/argtest_n.$$
+ERR=0
+SH=`pwd`/lsoftest.$$
+SH1=`pwd`/lsoftestc.$$
+T=`pwd`/argtest_tmp.$$
+T1=`pwd`/argtest_tmp1.$$
+trap 'rm -f $ARG_A $ARG_N $SH $SH1 $T $T1; exit 1' 1 2 3 15
+
+# Decide how to use echo.
+
+ECHO=`echo -n ""`
+if test "X$ECHO" = "X-n "
+then
+  EC="\c"
+  EO=""
+else
+  EC=""
+  EO="-n"
+fi
+
+# Establish the lsof path.
+
+if test $# -gt 0
+then
+  LSOF=$1
+else
+  LSOF=${HOME}/src/lsof4/lsof
+fi
+
+# Create temporary files that can be used as very large alphabetic
+# and numeric arguments.
+
+rm -f $ARG_A $T $T1
+echo $EO "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345678901$EC" > $T
+cp $T $T1
+for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+do
+  cat $T >> $T1
+done
+cp $T1 $ARG_A
+for i in 1 2 3 4 5 6 7
+do
+  cat $T1 >> $ARG_A
+done
+rm -f $T $T1
+ls -l $ARG_A
+rm -f $ARG_N $T $T1
+echo $EO "0123456789012345678901234567890123456789012345678901234567890123$EC" > $T
+cp $T $T1
+for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+do
+  cat $T >> $T1
+done
+cp $T1 $ARG_N
+for i in 1 2 3 4 5 6 7
+do
+  cat $T1 >> $ARG_N
+done
+rm -f $T $T1
+ls -l $ARG_N
+
+# Create a temporary shell script to execute lsof with options that require
+# arguments, and use the contents of $ARG_A and $ARG_N as the arguments.
+
+rm -f $SH $SH1
+echo "#!/bin/sh" > $SH
+echo "#!/bin/sh" > $SH1
+echo "$LSOF \$1 \`cat $ARG_A\`" >> $SH
+echo "$LSOF -c/\`cat $ARG_A\`/" >> $SH1
+echo "$LSOF \$1 \`cat $ARG_N\`" >> $SH
+echo "$LSOF -c/\`cat $ARG_N\`/" >> $SH1
+chmod +x $SH $SH1
+ls -l $SH $SH1
+
+for a in -A -c -c/ +c +d +D -e +e -f +f -F -g -i -i4 -i6 -i@ -i: -k +L -m +m -p -s -stcp: -sudp: -T -u -x -z -Z
+do
+  echo $EO "Testing: $a ... $EC"
+  if test "X$a" = "X-c/"
+  then
+    $SH1 2>&1 | egrep "Memory fault|Segmentation fault|Bus Error" > /dev/null 2>&1
+  else
+    $SH $a 2>&1 | egrep "Memory fault|Segmentation fault|Bus Error" > /dev/null 2>&1
+  fi
+  if test $? -eq 0
+  then
+    echo "!!!!FAILED!!!!"
+    ERR=1
+  else
+   echo "OK"
+  fi
+done
+rm -f $ARG_A $ARG_N $SH $SH1 core
+exit $ERR
diff --git a/support/binaries/README b/support/binaries/README
new file mode 100644 (file)
index 0000000..37015e7
--- /dev/null
@@ -0,0 +1,27 @@
+
+                           Lsof Binaries
+
+I do not recommend that you use a pre-compiled lsof binary and I no
+longer provide any.
+
+It is important that you compile lsof for yourself from the distributed
+sources to allow its Configure script to tailor the binary to your
+system.
+
+    *************************************************************
+    * DON'T TRY TO USE AN LSOF BINARY, COMPILED FOR ONE UNIX OS *
+    * VERSION, ON ANOTHER.                                      *
+    *************************************************************
+
+On some UNIX dialects lsof versions may be even more restricted by
+architecture types.
+
+    *************************************************************
+    * AVOID USING BINARIES FOR LSOF REVISIONS BELOW 4.63.  THEY *
+    * ARE VULNERABLE TO THE STANDARD I/O DESCRIPTOR ATTACK.     *
+    * (See 00FAQ for more information.)                         *
+    *************************************************************
+
+
+Vic Abell
+April 15, 2008
diff --git a/support/contrib.00INDEX b/support/contrib.00INDEX
new file mode 100644 (file)
index 0000000..89ab9e7
--- /dev/null
@@ -0,0 +1,22 @@
+
+       Index of Files in pub/tools/unix/lsof/contrib
+
+
+00INDEX                        is this file.
+
+BSDI-1.1                contains information on a BSDI BSD/386 1.1
+                       port to lsof 3.25 from Bob Thrush
+                       <rd@tarpit.oau.org>.
+
+NCR                     a directory containing a complete distribution
+                       of lsof 3.88 for NCR System Vr4 (3.0) releases
+                       2.2.1 and 3.0.0, done by Boyd Roberts
+                       <boyd@france3.fr>
+
+RT_PC.BSD4.3            contains information on a RT/PC BSD 4.3
+                       port to lsof 3.24 from R. Bernstein
+                       <rocky@panix.com>.
+
+
+Vic Abell
+February 20, 1997
diff --git a/support/contrib.README b/support/contrib.README
new file mode 100644 (file)
index 0000000..3c6f84e
--- /dev/null
@@ -0,0 +1,8 @@
+
+                   pub/tools/unix/lsof/contrib
+
+This subdirectory contains user-contributed patches, sources, and
+subdirectories for porting lsof to other Unix dialects.
+
+Vic Abell
+February 20, 1997
diff --git a/support/install-lsof b/support/install-lsof
new file mode 100755 (executable)
index 0000000..c518f32
--- /dev/null
@@ -0,0 +1,143 @@
+#!/bin/sh
+#
+# install-lsof <revision> -- install lsof <revision>
+
+DD=/var/ftpd/pub/tools/unix/lsof
+# DEBUG DD=/tmp/lsof   # DEBUG
+SD=$HOME/src/lsof4/support
+
+# Check for version specification.
+
+if test $# -ne 1
+then
+  echo "Usage: install-lsof <version>"
+  exit 1
+fi
+R=$1
+echo $R | grep '^4\.[0-9]*$' > /dev/null 2>&1
+if test $? -ne 0
+then
+  echo "<revision> must be 4.nn"
+  exit 1
+fi
+SR=`echo $R | sed 's/^4\.\([0-9]*\)$/\1/'`
+if test $SR -lt 73
+then
+  echo "Sub-revision must be 73 or greater."
+  exit 1
+fi
+PR=4.`expr $SR - 1`
+PPR=4.`expr $SR - 2`
+
+# Check for the presence of files for the new revision.
+
+err=0
+if test ! -f ${SD}/lsof_${R}.man
+then
+  echo "Creating lsof_${R}.man"
+  (cd $SD; ./makeman) > /dev/null
+fi
+for i in CHECKSUMS_$R ../00FAQ ../00DIST lsof_${R}.man lsof.00INDEX \
+        lsof.README \
+        lsof_${R}.tar.bz2 lsof_${R}.tar.bz2.sig \
+        lsof_${R}.tar.gz lsof_${R}.tar.gz.sig \
+        lsof_${R}.tar.Z  lsof_${R}.tar.Z.sig 
+do
+  if test ! -f ${SD}/$i
+  then
+    echo "${SD}/$i not found"
+    err=1
+  fi
+done
+
+# Check for the presence of files for the previous revision.
+
+for i in lsof_${PR}.man \
+        lsof_${PR}.tar.bz2 \
+        lsof_${PR}.tar.bz2.sig \
+        lsof_${PR}.tar.gz \
+        lsof_${PR}.tar.gz.sig \
+        lsof_${PR}.tar.Z \
+        lsof_${PR}.tar.Z.sig 
+do
+  if test ! -f ${DD}/$i
+  then
+    echo "${DD}/$i not found"
+    err=1
+  fi
+done
+
+# Quit if there are missing files.
+
+if test $err -ne 0
+then
+  echo "Quitting because of missing files"
+  exit 1
+fi
+
+# Archive previous revision files.
+
+for i in CHECKSUMS_$PR lsof_${PR}.man \
+        lsof_${PR}.tar.bz2 lsof_${PR}.tar.bz2.sig \
+        lsof_${PR}.tar.gz  lsof_${PR}.tar.gz.sig  \
+        lsof_${PR}.tar.Z   lsof_${PR}.tar.Z.sig 
+do
+  if test -f ${DD}/$i
+  then
+    mv ${DD}/$i ${DD}/OLD
+  else
+    echo "No ${DD}/$i to archive"
+  fi
+done
+
+# Remove some previously archived files.  Save the gz archive and signature.
+
+for i in CHECKSUMS_$PPR lsof_${PPR}.man \
+        lsof_${PPR}.tar.bz2  lsof_${PPR}.tar.bz2.sig  \
+        lsof_${PPR}.tar.Z   lsof_${PPR}.tar.Z.sig 
+do
+  if test -f ${DD}/OLD/$i
+  then
+    echo "Removing ${DD}/OLD/$i"
+    rm -f ${DD}/OLD/$i
+  fi
+done
+
+# Install new files.
+
+for i in lsof.00INDEX lsof.README 
+do
+  echo "Installing $i"
+  rm -f $DD/$i
+  cp ${SD}/$i $DD
+  chmod 444 $DD/$i
+done
+rm -f ${DD}/00INDEX; mv ${DD}/lsof.00INDEX ${DD}/00INDEX
+rm -f ${DD}/README; mv ${DD}/lsof.README ${DD}/README
+for i in CHECKSUMS_$R lsof_${R}.man \
+        lsof_${R}.tar.bz2 lsof_${R}.tar.bz2.sig \
+        lsof_${R}.tar.gz lsof_${R}.tar.gz.sig \
+        lsof_${R}.tar.Z  lsof_${R}.tar.Z.sig 
+do
+  echo "Installing $i"
+  rm -f $DD/$i
+  mv ${SD}/$i $DD
+  chmod 444 $DD/$i
+done
+(cd $DD; rm -f CHECKSUMS; ln -s CHECKSUMS_$R CHECKSUMS; ls -lL CHECKSUMS)
+(cd $DD; rm -f lsof_man; ln -s lsof_${R}.man lsof_man; ls -lL lsof_man)
+echo "Installing FAQ"
+rm -f ${DD}/FAQ; cp ${SD}/../00FAQ ${DD}/FAQ; chmod 644 ${DD}/FAQ
+rm -f ${DD}/ChangeLog; cp ${SD}/../00DIST ${DD}/ChangeLog; chmod 644 ${DD}/ChangeLog
+for i in bz2 gz Z
+do
+  rm -f ${DD}/lsof.tar.$i ${DD}/lsof.tar.${i}.sig
+  (cd $DD; ln -s lsof_${R}.tar.$i lsof.tar.$i)
+  (cd $DD; ln -s lsof_${R}.tar.${i}.sig lsof.tar.${i}.sig)
+  (cd $DD; ls -lL lsof.tar.$i lsof.tar.${i}.sig)
+done
+
+# Install binaries. (Disabled April 15, 2008.)
+
+#(cd $SD; rdist -f distfile.binaries)
+exit 0
diff --git a/support/install.log b/support/install.log
new file mode 100644 (file)
index 0000000..bd6a15e
--- /dev/null
@@ -0,0 +1,156 @@
+Removing /var/ftpd/pub/tools/unix/lsof/OLD/CHECKSUMS_4.84
+Removing /var/ftpd/pub/tools/unix/lsof/OLD/lsof_4.84.man
+Removing /var/ftpd/pub/tools/unix/lsof/OLD/lsof_4.84.tar.bz2
+Removing /var/ftpd/pub/tools/unix/lsof/OLD/lsof_4.84.tar.bz2.sig
+Removing /var/ftpd/pub/tools/unix/lsof/OLD/lsof_4.84.tar.Z
+Removing /var/ftpd/pub/tools/unix/lsof/OLD/lsof_4.84.tar.Z.sig
+Installing lsof.00INDEX
+Installing lsof.README
+Installing CHECKSUMS_4.86
+Installing lsof_4.86.man
+Installing lsof_4.86.tar.bz2
+Installing lsof_4.86.tar.bz2.sig
+Installing lsof_4.86.tar.gz
+Installing lsof_4.86.tar.gz.sig
+Installing lsof_4.86.tar.Z
+Installing lsof_4.86.tar.Z.sig
+-r--r--r--   1 abe      pucc        1726 Apr 10 13:06 CHECKSUMS
+-r--r--r--   1 abe      pucc           0 Apr 10 13:01 lsof_man
+Installing FAQ
+-r--r--r--   1 abe      pucc      769231 Apr 10 13:06 lsof.tar.bz2
+-r--r--r--   1 abe      pucc         152 Apr 10 13:06 lsof.tar.bz2.sig
+-r--r--r--   1 abe      pucc     1079288 Apr 10 13:06 lsof.tar.gz
+-r--r--r--   1 abe      pucc         152 Apr 10 13:06 lsof.tar.gz.sig
+-r--r--r--   1 abe      pucc     1630733 Apr 10 13:06 lsof.tar.Z
+-r--r--r--   1 abe      pucc         152 Apr 10 13:06 lsof.tar.Z.sig
+Creating lsof_4.87.man
+Removing /var/ftpd/pub/tools/unix/lsof/OLD/CHECKSUMS_4.85
+Removing /var/ftpd/pub/tools/unix/lsof/OLD/lsof_4.85.man
+Removing /var/ftpd/pub/tools/unix/lsof/OLD/lsof_4.85.tar.bz2
+Removing /var/ftpd/pub/tools/unix/lsof/OLD/lsof_4.85.tar.bz2.sig
+Removing /var/ftpd/pub/tools/unix/lsof/OLD/lsof_4.85.tar.Z
+Removing /var/ftpd/pub/tools/unix/lsof/OLD/lsof_4.85.tar.Z.sig
+Installing lsof.00INDEX
+Installing lsof.README
+Installing CHECKSUMS_4.87
+Installing lsof_4.87.man
+Installing lsof_4.87.tar.bz2
+Installing lsof_4.87.tar.bz2.sig
+Installing lsof_4.87.tar.gz
+Installing lsof_4.87.tar.gz.sig
+Installing lsof_4.87.tar.Z
+Installing lsof_4.87.tar.Z.sig
+-r--r--r--   1 abe      pucc        1726 Jan  2 12:52 CHECKSUMS
+-r--r--r--   1 abe      pucc      151915 Jan  2 12:56 lsof_man
+Installing FAQ
+-r--r--r--   1 abe      pucc      773664 Jan  2 12:52 lsof.tar.bz2
+-r--r--r--   1 abe      pucc         152 Jan  2 12:52 lsof.tar.bz2.sig
+-r--r--r--   1 abe      pucc     1084323 Jan  2 12:52 lsof.tar.gz
+-r--r--r--   1 abe      pucc         152 Jan  2 12:52 lsof.tar.gz.sig
+-r--r--r--   1 abe      pucc     1632799 Jan  2 12:52 lsof.tar.Z
+-r--r--r--   1 abe      pucc         152 Jan  2 12:52 lsof.tar.Z.sig
+Creating lsof_4.88.man
+Removing /var/ftpd/pub/tools/unix/lsof/OLD/CHECKSUMS_4.86
+Removing /var/ftpd/pub/tools/unix/lsof/OLD/lsof_4.86.man
+Removing /var/ftpd/pub/tools/unix/lsof/OLD/lsof_4.86.tar.bz2
+Removing /var/ftpd/pub/tools/unix/lsof/OLD/lsof_4.86.tar.bz2.sig
+Removing /var/ftpd/pub/tools/unix/lsof/OLD/lsof_4.86.tar.Z
+Removing /var/ftpd/pub/tools/unix/lsof/OLD/lsof_4.86.tar.Z.sig
+Installing lsof.00INDEX
+Installing lsof.README
+Installing CHECKSUMS_4.88
+Installing lsof_4.88.man
+Installing lsof_4.88.tar.bz2
+Installing lsof_4.88.tar.bz2.sig
+Installing lsof_4.88.tar.gz
+Installing lsof_4.88.tar.gz.sig
+Installing lsof_4.88.tar.Z
+Installing lsof_4.88.tar.Z.sig
+-r--r--r--   1 abe      pucc        1726 Oct 14 12:04 CHECKSUMS
+-r--r--r--   1 abe      pucc      152630 Oct 14 12:12 lsof_man
+Installing FAQ
+-r--r--r--   1 abe      pucc      778563 Oct 14 12:04 lsof.tar.bz2
+-r--r--r--   1 abe      pucc         152 Oct 14 12:04 lsof.tar.bz2.sig
+-r--r--r--   1 abe      pucc     1090289 Oct 14 12:04 lsof.tar.gz
+-r--r--r--   1 abe      pucc         152 Oct 14 12:04 lsof.tar.gz.sig
+-r--r--r--   1 abe      pucc     1643851 Oct 14 12:04 lsof.tar.Z
+-r--r--r--   1 abe      pucc         152 Oct 14 12:04 lsof.tar.Z.sig
+Creating lsof_4.89.man
+Removing /var/ftpd/pub/tools/unix/lsof/OLD/CHECKSUMS_4.87
+Removing /var/ftpd/pub/tools/unix/lsof/OLD/lsof_4.87.man
+Removing /var/ftpd/pub/tools/unix/lsof/OLD/lsof_4.87.tar.bz2
+Removing /var/ftpd/pub/tools/unix/lsof/OLD/lsof_4.87.tar.bz2.sig
+Removing /var/ftpd/pub/tools/unix/lsof/OLD/lsof_4.87.tar.Z
+Removing /var/ftpd/pub/tools/unix/lsof/OLD/lsof_4.87.tar.Z.sig
+Installing lsof.00INDEX
+Installing lsof.README
+Installing CHECKSUMS_4.89
+Installing lsof_4.89.man
+Installing lsof_4.89.tar.bz2
+Installing lsof_4.89.tar.bz2.sig
+Installing lsof_4.89.tar.gz
+Installing lsof_4.89.tar.gz.sig
+Installing lsof_4.89.tar.Z
+Installing lsof_4.89.tar.Z.sig
+-r--r--r--   1 abe      pucc        1726 Jul 13 10:04 CHECKSUMS
+-r--r--r--   1 abe      pucc      153636 Jul 13 10:05 lsof_man
+Installing FAQ
+-r--r--r--   1 abe      pucc      784560 Jul 13 10:04 lsof.tar.bz2
+-r--r--r--   1 abe      pucc         152 Jul 13 10:04 lsof.tar.bz2.sig
+-r--r--r--   1 abe      pucc     1096819 Jul 13 10:04 lsof.tar.gz
+-r--r--r--   1 abe      pucc         152 Jul 13 10:04 lsof.tar.gz.sig
+-r--r--r--   1 abe      pucc     1649885 Jul 13 10:04 lsof.tar.Z
+-r--r--r--   1 abe      pucc         152 Jul 13 10:04 lsof.tar.Z.sig
+Creating lsof_4.90.man
+Removing /var/ftpd/pub/tools/unix/lsof/OLD/CHECKSUMS_4.88
+Removing /var/ftpd/pub/tools/unix/lsof/OLD/lsof_4.88.man
+Removing /var/ftpd/pub/tools/unix/lsof/OLD/lsof_4.88.tar.bz2
+Removing /var/ftpd/pub/tools/unix/lsof/OLD/lsof_4.88.tar.bz2.sig
+Removing /var/ftpd/pub/tools/unix/lsof/OLD/lsof_4.88.tar.Z
+Removing /var/ftpd/pub/tools/unix/lsof/OLD/lsof_4.88.tar.Z.sig
+Installing lsof.00INDEX
+Installing lsof.README
+Installing CHECKSUMS_4.90
+Installing lsof_4.90.man
+Installing lsof_4.90.tar.bz2
+Installing lsof_4.90.tar.bz2.sig
+Installing lsof_4.90.tar.gz
+Installing lsof_4.90.tar.gz.sig
+Installing lsof_4.90.tar.Z
+Installing lsof_4.90.tar.Z.sig
+-r--r--r--   1 abe      pucc        1726 Feb 14 15:33 CHECKSUMS
+-r--r--r--   1 abe      pucc      155331 Feb 15 13:12 lsof_man
+Installing FAQ
+-r--r--r--   1 abe      pucc      791758 Feb 14 15:32 lsof.tar.bz2
+-r--r--r--   1 abe      pucc         152 Feb 14 15:33 lsof.tar.bz2.sig
+-r--r--r--   1 abe      pucc     1104570 Feb 14 15:32 lsof.tar.gz
+-r--r--r--   1 abe      pucc         152 Feb 14 15:33 lsof.tar.gz.sig
+-r--r--r--   1 abe      pucc     1663473 Feb 14 15:33 lsof.tar.Z
+-r--r--r--   1 abe      pucc         152 Feb 14 15:33 lsof.tar.Z.sig
+sof: 44 = install-lsof 4.91
+Creating lsof_4.91.man
+Removing /var/ftpd/pub/tools/unix/lsof/OLD/CHECKSUMS_4.89
+Removing /var/ftpd/pub/tools/unix/lsof/OLD/lsof_4.89.man
+Removing /var/ftpd/pub/tools/unix/lsof/OLD/lsof_4.89.tar.bz2
+Removing /var/ftpd/pub/tools/unix/lsof/OLD/lsof_4.89.tar.bz2.sig
+Removing /var/ftpd/pub/tools/unix/lsof/OLD/lsof_4.89.tar.Z
+Removing /var/ftpd/pub/tools/unix/lsof/OLD/lsof_4.89.tar.Z.sig
+Installing lsof.00INDEX
+Installing lsof.README
+Installing CHECKSUMS_4.91
+Installing lsof_4.91.man
+Installing lsof_4.91.tar.bz2
+Installing lsof_4.91.tar.bz2.sig
+Installing lsof_4.91.tar.gz
+Installing lsof_4.91.tar.gz.sig
+Installing lsof_4.91.tar.Z
+Installing lsof_4.91.tar.Z.sig
+-r--r--r--   1 abe      pucc        1726 Mar 26 17:56 CHECKSUMS
+-r--r--r--   1 abe      pucc      155331 Mar 26 18:00 lsof_man
+Installing FAQ
+-r--r--r--   1 abe      pucc      791734 Mar 26 17:56 lsof.tar.bz2
+-r--r--r--   1 abe      pucc         152 Mar 26 17:56 lsof.tar.bz2.sig
+-r--r--r--   1 abe      pucc     1104767 Mar 26 17:56 lsof.tar.gz
+-r--r--r--   1 abe      pucc         152 Mar 26 17:56 lsof.tar.gz.sig
+-r--r--r--   1 abe      pucc     1658305 Mar 26 17:56 lsof.tar.Z
+-r--r--r--   1 abe      pucc         152 Mar 26 17:56 lsof.tar.Z.sig
diff --git a/support/look_rlog b/support/look_rlog
new file mode 100755 (executable)
index 0000000..d1f8653
--- /dev/null
@@ -0,0 +1,21 @@
+#!/bin/ksh
+#
+# look_rlog
+#set -v                        # for DEBUGging
+
+if test $# -ne 2
+then
+  echo "$0 usage: file highest-revision"
+  exit 1
+fi
+if test ! -r RCS/${1},v
+then
+  echo "$0: no RCS/${1},v"
+  exit 1
+fi
+r=$2
+while test $r -gt 0
+do
+  (echo 1.$r; co -p1.$r $1) | less
+  r=`expr $r - 1`
+done
diff --git a/support/lsof-log.xls b/support/lsof-log.xls
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/support/lsof.00INDEX b/support/lsof.00INDEX
new file mode 100644 (file)
index 0000000..7d1fe7e
--- /dev/null
@@ -0,0 +1,128 @@
+
+       Index of Files and Directories in pub/tools/unix/lsof
+
+
+00INDEX                        is this file.
+
+00LSOF-L               contains information on the lsof-l LISTSERV
+                       mailing list for lsof.
+
+ChangeLog              contains information about changes to lsof, also
+                       found in the 00DIST distribution notes file of
+                       the lsof distribution.
+
+CHECKSUMS              contains information on external checksums for
+                       the current lsof distribution files.
+
+FAQ                    is the lsof FAQ, also found in the file 00FAQ
+                       of the lsof distribution.
+
+                       NOTE: this file is as current as possible.
+                       Therefore it may contain information that
+                       applies to an upcoming revision.  When in
+                       doubt, send email to <abe@purdue.edu>.
+
+NEW/                   is a directory that may sometimes contain
+                       new information -- usually bzip2'd or gzip'd
+                       tar files for ports to specific dialects that
+                       are under development.  Please don't get
+                       anything from this directory without contacting
+                       me first.
+
+OLD/                   is a directory that contains OLD lsof
+                       distribution files.
+
+README                 contains information on the lsof distribution.
+                       This file is included in the lsof distribution
+                       tar files, lsof.tar.bz2, lsof.tar.gz and
+                       lsof.tar.Z.
+
+Victor_A_Abell.gpg      contains the GnuPG 5.0 public key for Victor
+                       A. Abell (abe@purdue.edu).
+
+                       MAY BE USED TO AUTHENTICATE THE LSOF
+                       DISTRIBUTION AND BINARY FILES.
+
+Victor_A_Abell.pgp      contains the PGP 2.62 public key for Victor A.
+                       Abell (abe@purdue.edu).
+
+                       MAY BE USED TO AUTHENTICATE THE LSOF
+                       DISTRIBUTION AND BINARY FILES.
+
+binaries/              is a directory tree that contains selected
+                       lsof executables, not always for the latest
+                       source distribution.  I strongly recommend
+                       you avoid using one of these binaries and
+                       build your own instead.
+
+contrib/               is a directory of user-contributed information
+                       on porting lsof to other Unix dialects.
+
+lsof_man               is a symbolic link to the man page for the
+                       current lsof revision.  This file is included
+                       in the lsof distribution tar files,
+                       lsof.tar.bz2, lsof.tar.gz and lsof.tar.Z.
+
+lsof.tar.bz2           is a symbolic link to the bzip2'd lsof
+                       distribution tar archive for the latest
+                       revision of lsof.  Consult the README file
+                       in this directory for information on its
+                       contents.
+
+lsof.tar.bz2.sig       is a symbolic link to the GPG authentication
+                       certificate for lsof.tar.bz2.
+
+lsof.tar.gz            is a symbolic link to the gzip'd lsof
+                       distribution tar archive for the latest
+                       revision of lsof.  Consult the README file
+                       in this directory for information on its
+                       contents.
+
+lsof.tar.gz.sig                is a symbolic link to the GPG authentication
+                       certificate for lsof.tar.gz.
+
+lsof.tar.Z             is a symbolic link to the compressed lsof
+                       distribution tar archive for the latest
+                       revision of lsof.  Consult the README file
+                       in this directory for information on its
+                       contents.
+
+lsof.tar.Z.sig         is a symbolic link to the GPG authentication
+                       certificate for lsof.tar.Z.
+
+lsof_4.92.man          is the man page for the current lsof
+                       distribution.
+
+lsof_4.92.tar.bz2      is the current bzip2'd lsof distribution.
+                       Consult the README file in this directory for
+                       information on its contents.
+
+lsof_4.92.tar.bz2.sig  is the GPG authentication certificate for
+                       lsof_4.92.tar.bz2.
+
+lsof_4.92.tar.gz       is the current gzip'd lsof distribution.
+                       Consult the README file in this directory for
+                       information on its contents.
+
+lsof_4.92.tar.gz.sig   is the GPG authentication certificate for
+                       lsof_4.92.tar.gz.
+
+lsof_4.92.tar.Z                is the current compressed lsof distribution.
+                       Consult the README file in this directory for
+                       information on its contents.
+
+lsof_4.92.tar.Z.sig    is the GPG authentication certificate for
+                       lsof_4.92.tar.Z.
+
+mirrors                        is a list of ftp sites where lsof is mirrored.
+
+patches/               contains lsof patches.
+
+solaris_kaddr_filters   contains a discussion of the Solaris kernel
+                       address filters installed in lsof 4.50 and
+                       above.  This file may also be found in
+                       lsof_4.92/dialects/sun.
+
+
+Vic Abell <abe@purdue.edu>
+July 14, 2018
diff --git a/support/lsof.README b/support/lsof.README
new file mode 100644 (file)
index 0000000..411a372
--- /dev/null
@@ -0,0 +1,326 @@
+                   lsof (LiSt Open Files) version 4
+                           (revision 4.92)
+
+
+    ********************************************************************
+    | The latest release of lsof is always available via anonymous ftp |
+    | from lsof.itap.purdue.edu.  Look in pub/tools/unix/lsof.         |
+    ********************************************************************
+
+******************************************************************************
+| CHECK THE PATCHES/ SUBDIRECTORY FOR FIXES TO THE LATEST LSOF DISTRIBUTION. |
+******************************************************************************
+
+ **************************************************************************
+ | AVOID USING PRE-BUILT LSOF BINARIES: SEE THE "PRE-BUILT LSOF BINARIES" |
+ |                 SECTION IN 00README FOR AN EXPLANATION.                |
+ **************************************************************************
+
+   **********************************************************************
+   | READ 00LSOF-L FOR INFORMATION ON THE LSOF-L LISTSERV MAILING LIST. |
+   **********************************************************************
+
+    *********************************************************************
+    |      CHECK 00FAQ BEFORE REPORTING BUGS TO <abe@purdue.edu>.       |
+    | 00FAQ ALSO AT: ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/FAQ |
+    *********************************************************************
+
+    ********************************************************************
+    | IMPORTANT!  This README file explains how the lsof tar archive   |
+    | is assembled -- it's a "wrapper" tar archive.  Please read the   |
+    | explanation of its naming and construction, immediately          |
+    | following the initial list of supported dialects.                |
+    ********************************************************************
+
+
+Lsof version 4 lists open files for running UNIX processes.  It is a
+descendent of ofiles, fstat, and lsof versions 1, 2, and 3.  It has
+been tested recently on these UNIX dialects.
+
+       Apple Darwin 9 and Mac OS X 10.[567]
+       FreeBSD 8.[234], 9.0 and 1[012].0 for AMD64-based systems
+       Linux 2.1.72 and above for x86-based systems
+       Solaris 9, 10 and 11
+
+Lsof 4 may work on other versions of these dialects, but hasn't been
+tested there recently.  Lsof versions 2 and 3 are still available and
+may provide older dialect version support.  See the notes on them in
+this file.
+
+The pub/tools/unix/lsof/contrib directory on lsof.itap.purdue.edu also
+contains information on other ports.
+
+Version 4 of lsof is distributed as bzip2'd, gzip'd and compressed tar
+archives in the files:
+
+    ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/lsof.tar.bz2
+  and
+    ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/lsof.tar.gz
+  and
+    ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/lsof.tar.Z
+
+These files are links to the current distribution, whose name includes
+the revision number:
+
+    ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof_<rev>.tar.bz2
+  and
+    ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof_<rev>.tar.gz
+  and
+    ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof_<rev>.tar.Z
+
+<rev> is the revision number -- e.g., 4.92.  These archives are called
+wrappers, because the lsof source tar archive, its GPG certificate
+(lsof_<rev>_src.tar.sig), and some documentation files are wrapped
+together inside them.  (The GPG certificate authenticates the source
+tar archive.)  A tar archive with: a ``.bz2'' suffix has been
+compressed with bzip2; ``.gz'', with gzip; and ``.Z'', with compress.
+
+When the wrapper tar is gunzip'd or uncompressed, and its tar archive
+contents are extracted, an lsof_4.92 subdirectory is created in the
+directory where the extraction was performed.  The lsof_4.92
+subdirectory contains these files:
+
+       00.README.FIRST         contains introductory distribution
+                               information.
+
+       README.lsof_4.92        contains instructions for the
+                               security-conscious on how to be
+                               sure that no one has tampered with
+                               the distribution.
+
+       RELEASE_SUMMARY_4.92    is this file.
+
+       lsof_4.92_src.tar       is a tar archive, containing the
+                               lsof sources.  When extracted with
+                               tar it creates a subdirectory named
+                               lsof_4.92_src in the directory
+                               where the extraction was performed.
+                               The lsof source files will be found
+                               in lsof_4.92_src.
+
+       lsof_4.92_src.tar.sig   is a GPG certificate, authenticating
+                               the lsof_4.92_src.tar archive.  See the
+                               README.lsof_4.92 file for more
+                               information on GPG authentication of
+                               lsof_4.92_src.tar.
+
+If you've obtained this file and an lsof distribution from a mirror
+site, please be aware that THE LATEST VERSION OF LSOF IS AVAILABLE VIA
+ANONYMOUS FTP FROM LSOF.ITAP.PURDUE.EDU IN THE PUB/TOOLS/UNIX/LSOF
+DIRECTORY.
+
+Patches to lsof distributions may be found in the patches/ sub-
+directory where you found lsof.tar.bz2, lsof.tar.gz or lsof.tar.Z.
+If there are any patches to the current distribution, they will be
+found in the patches/4.92/ branch.
+
+(If you need a copy of gunzip, look for it at prep.ai.mit.edu in
+pub/gnu/gzip*.)
+
+The March 26, 2018 revision (4.91): corrects a bug in the processing of Linux
+  PTY endpoint information.
+
+The June 6, 2018 revision (4.92:) is a FreeBSD-only revision; it corrects a bug
+  in the Configure script section that creates a local lockf_owner.h header
+  file; removes a <string,h> kernel header conflicts.
+
+Read the 00.README.FIRST in the lsof distribution first.
+
+Read the 00DIST distribution file for more details on feature additions
+and bug fixes.
+
+The 00README distribution file has build instructions, dialect
+descriptions, special feature discussions, and installation hints.
+
+The 00FAQ file contains a list of frequently asked questions and their
+answers.
+
+The 00DCACHE file explains device cache file path formation.
+
+The 00PORTING file contains information on porting lsof to other UNIX
+dialects.
+
+The 00QUICKSTART file gives a quick introduction to using lsof.
+
+The distribution files lsof.8 (nroff source) and lsof.man (nroff
+formatted output) contain the manual page for lsof; it is the only
+other documentation besides the source code (it's included).
+
+
+Version 4 Binaries
+==================
+
+Version 4 binaries for some revisions, dialects, and platforms may be
+found in pub/tools/unix/lsof/binaries.  Check the README files for
+exact descriptions.  Check the dialect-specific Makefiles for
+installation instructions.  CHECKSUMS and GPG certificates are provided
+for authentication.
+
+Please think very carefully before you decide to use a pre-built binary
+instead of making your own from the sources.  Here are some points to
+consider:
+
+1. Lsof must run setgid or setuid.  Are you willing to trust that
+   power to a binary you didn't construct yourself?
+
+2. Lsof binaries may be generated on a system whose configuration
+   header files differ from yours.  Under Digital UNIX (DEC OSF/1), for
+   example, lsof includes header files from the machine's configuration
+   directory, /sys/<name>.  Are you willing to gamble that your
+   configuration directory's header files match the ones used to
+   compile lsof?
+
+3. Lsof is often configured with specific options that are determined
+   from the configuration of the system on which it is configured --
+   e.g., Solaris patch level, dynamic loader libraries, etc.  Are you
+   sure that the lsof binary you retrieve will have been configured for
+   your system? If you get a binary that is misconfigured for you, it
+   may not work at all.
+
+If you haven't already guessed, I believe firmly that you should
+retrieve sources and build your own binary.  If you still want to use
+the distribution binaries, please authenticate what you retrieved with
+the GPG certificates; please compare checksums, too.
+
+
+Version 4 Checksums
+===================
+
+Security checksums -- both MD5 and sum(1) -- for revisions of lsof
+version 4 are contained in the README.lsof_<rev> files in the wrapper
+tar archives of pub/tools/unix/lsof.
+
+The CHECKSUMS file, found with the distribution archives, contains
+information on validating the archives with external MD5 checksums and
+external GPG certificates.
+
+
+GPG Certificates
+================
+
+The lsof wrapper tar archive includes a GPG certificate file in its
+contained lsof_4.71_src.tar.sig file.
+
+Binary files have detached GPG certificates that may be found in their
+directories with ".sig" extensions.
+
+The certificates are signed with my GPG public key, which may be found
+in the file:
+
+    ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/Victor_A_Abell.gpg
+
+My key may also be available at some public key servers,
+
+There is also authentication information in the CHECKSUMS file (a link
+to CHECKSUMS_<rev>), found with the lsof distribution files.  CHECKSUMS
+contains external MD5 checksums for the distribution files and
+information on using the external GPG certificates, found with the lsof
+distribution files.
+
+
+Old Dialect Support
+===================
+
+Remnants of source code and binaries for dialects for which lsof once
+provided support may be obtained by request.  Send the request to
+abe@purdue.edu.
+
+Dialects no longer supported include:
+
+       CDC EP/IX
+       MIPS RISC/os
+       Motorola V/88
+       Pyramid DC/OSx
+       Pyramid Reliant UNIX
+       Sequent DYNIX
+       SGI IRIX
+       SunOS 4.1.x
+       Ultrix
+
+Generally I drop support for a dialect when I no longer have access to
+a test system.
+
+
+Lsof Version 2
+==============
+
+The version 3 predecessor, revision 36 of version 2, is also available
+upon request.  Send the request to abe@purdue.edu.
+
+I recommend you avoid lsof version 2.  It's out of date and I no
+longer provide support for it.  (Versions 3 and 4 support more
+dialects, and have many enhancements, bug fixes, and improvements.)
+Version 2 was tested on the following UNIX dialects:
+
+       AIX 3.2.[1234] for the IBM RISC/System 6000
+       DEC OSF/1 1.[23] and 2.0 for the DEC Alpha
+       EP/IX 1.4.3 and 2.1.1 for the CDC 4680
+       ETAV 1.17 for the ETA-10P*
+       FreeBSD 1.0e for x86-based systems
+       HP-UX [789].x for HP systems
+       IRIX 4.0.5 and 5.1.1 for SGI systems
+       NEXTSTEP 2.1, 3.0, 3.1 for NeXT systems
+       Sequent Dynix 3.0.12 for Sequent Symmetry systems
+       SunOS 4.1.[123] for Sun 3 and 4 systems
+       SunOS 5.[13] (Solaris 2.[13]) for Sun 4 systems
+       Ultrix 2.2 and 4.2 for DEC systems
+
+(If you need a copy of gunzip, look for it at prep.ai.mit.edu in
+pub/gnu.)
+
+
+Version 2 Checksums
+===================
+
+MD5:
+       (OLD/lsof236tar.gz) = f8a1ab3971ea2f6a3ea16752f84409e8
+
+sum(1):
+       39996   106 OLD/lsof236tar.gz
+
+The file OLD/lsof236tar.gz.asc is a detached PGP certificate that may
+be used to authenticate OLD/lsof236tar.gz with my PGP public key.  You
+may find my PGP public key at:
+
+  ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/OLD/Victor_A_Abell.pgp
+    
+
+Lsof Version 3
+==============
+
+The last revision of lsof version 3, 3.88, may obtained by request.
+Send the request to abe@purdue.edu.
+
+I recommend version 4 over version 3.  It is the version I actively
+support.
+
+Lsof version 3 was tested on these UNIX dialects:
+
+       AIX 3.2.5, 4.1[.[1234]], and 4.2
+       BSDI BSD/OS 2.0, 2.0.1, and 2.1 for x86-based systems
+       DC/OSx 1.1 for Pyramid systems
+       Digital UNIX (DEC OSF/1) 2.0, 3.0, 3.2, and 4.0
+       EP/IX 2.1.1 for the CDC 4680
+       FreeBSD 1.1.5.1, 2.0, 2.0.5, 2.1, 2.1.5 for x86-based
+           systems
+       HP-UX 8.x, 9.x, 10.01, 10.10, and 10.20
+       IRIX 5.2, 5.3, 6.0, 6.0.1, and 6.[124]
+       Linux 2.0.3[01] and 2.1.57 for x86-based systems
+       NetBSD 1.0, 1.1, and 1.2 for x86 and SPARC-based
+           systems
+       NEXTSTEP 2.1 and 3.[0123] for NEXTSTEP architectures
+       OpenBSD 1.2 and 2.0 for x86-based systems
+       Reliant UNIX 5.43 for Pyramid systems
+       RISC/os 4.52 for MIPS R2000-based systems
+       SCO OpenServer 1.1, 3.0, and 5.0.[024] for x86-based 
+           systems
+       SCO UnixWare 2.1 and 2.1.1 for x86-based systems
+       Sequent PTX 2.1.[1569], 4.0.[23], 4.1.[024], 4.2[.1],
+           and 4.3
+       Solaris 2.[12345], 2.5.1, and 2.6-Beta
+       SunOS 4.1.x
+       Ultrix 4.2, 4.3, 4.4, and 4.5
+
+
+Vic Abell <abe@purdue.edu>
+July 14, 2018
diff --git a/support/makeman b/support/makeman
new file mode 100755 (executable)
index 0000000..d330abb
--- /dev/null
@@ -0,0 +1,46 @@
+#!/bin/ksh
+#
+# makman -- make lsof 4.x man page for ftp tree
+
+SD=${HOME}/src/lsof4
+cd $SD
+
+# Get version number.
+
+V=`sed '/VN/s/.ds VN \(.*\)/\1/' version`
+if test $? -ne 0
+then
+  echo $V
+  exit 1
+fi
+
+# Handle optional edition suffix.
+
+if test $# -gt 0
+then
+  if test $# -gt 1
+  then
+    echo "Usage: makeman [edition]"
+    exit 1
+  fi
+  V=${V}$1
+fi
+
+# Define man file names.
+
+MS=Lsof.8
+MD=${SD}/support/lsof.8
+MF=${SD}/support/lsof_${V}.man
+
+# Set exit cleanup trap.
+
+trap 'rm -rf $MD $MF; exit' 1 2 3 15
+
+# Create manual page files.
+
+echo Producing $MD
+soelim < $MS > $MD
+echo Producing $MF
+nroff -man $MD | colcrt - | cat -s > $MF
+rm -f $MD
+ls -l $MF
diff --git a/support/mentor b/support/mentor
new file mode 100755 (executable)
index 0000000..3c8b155
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/ksh
+#
+# mentor - rdist Sun sources to mentor.cc
+
+$HOME/src/lsof4/support/GenericRdist mentor sun ssh
diff --git a/support/mirrors b/support/mirrors
new file mode 100644 (file)
index 0000000..4821f6f
--- /dev/null
@@ -0,0 +1,9 @@
+Lsof is available via anonymous ftp from these mirror hosts.
+
+ ftp://ftp.fu-berlin.de/pub/unix/tools/lsof
+ ftp://sunsite.ualberta.ca/pub/Mirror/lsof
+ http://www.mirrorservice.org/sites/lsof.itap.purdue.edu/pub/tools/unix/lsof/
+ ftp://ftp.mirrorservice.org/sites/lsof.itap.purdue.edu/pub/tools/unix/lsof/
+
+
+WANT YOUR LSOF MIRROR LISTED HERE?  SEND E-MAIL TO <abe@purdue.edu>.
diff --git a/support/rdist.distrib b/support/rdist.distrib
new file mode 100755 (executable)
index 0000000..5afd538
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/sh
+#
+# rdist.distrib - distribute lsof via rdist
+
+cd $HOME/src/lsof4
+for i in cloud mentor
+do
+        echo "::::: " $i " :::::"
+       support/$i
+done
diff --git a/tests/00README b/tests/00README
new file mode 100644 (file)
index 0000000..eee8e4d
--- /dev/null
@@ -0,0 +1,102 @@
+
+               .../lsof_<version>/tests
+
+This sub-directory contains support for lsof's test suite.  Find
+more information about the test suite in the 00TESTS file of the
+lsof distribution, which should be in in the parent of this
+subdirectory.
+
+These tests can be activated from .. with:
+
+    $ make test
+
+They can be activated from this directory with:
+
+    $ make
+    $ make test
+    $ make all
+
+These tests are all written in C, so individual tests may be
+activated by executing them directly -- e.g.,
+
+    $ ./LTlock
+
+It may sometimes be necessary to use execution-time options
+alter test behavior.  (Some tests will suggest that when they
+encounter certain kinds of errors.)  See the 00FAQ and 00TEST files
+in .. for more information.
+
+These tests check lsof field output, not lsof text output.  There
+are no tests for lsof text output.
+
+Here is a brief description of the files in this subdirectory:
+
+    00README           this file
+
+    Add2TestDB          a script to add the identity of the current
+                       test to TestDB
+
+    CkTestDB           a script to check the identity of this
+                       dialect against the TestDB file
+
+    config.cc           a file prepared by ../Configure that contains
+                       the name (and possibly the path) to the C
+                       compiler for the programs of this sub-directory
+
+    config.cflags       a file prepared by ../Configure that contains
+                       C compiler flags for the programs of this
+                       sub-directory
+
+    config.libs                a file prepared by ../Configure that contains
+                       library load specifications -- i.e, make(1)
+                       LDFLAGS
+
+    config.xobj         a file prepared by ../Configure that contains
+                       paths to any extra object files (*.o) needed
+                       by the C programs in this directory
+
+    LsofTest.h         lsof test definitions for C programs
+
+    LTbasic.c          C source to basic lsof tests
+
+    LTbigf.c           C source to a program that tests large file
+                       sizes and offsets on dialects that support
+                       file sizes > 32 bits
+
+    LTdnlc.c            C source to a program that tests the
+                       effectiveness of assembling path names from
+                       the kernel's Dynamic Name Lookup Cache
+                       (DNLC)
+
+    LTlib.c            a support library in C
+
+    LTlock.c           C source to a program that tests lock reporting
+
+    LTnfs              C source to a program that tests for open NFS
+                       files
+
+    LTnlink.c           C source to a program that tests lsof's
+                       reporting of open file link counts
+
+    LTsock.c            C source to program that tests the finding
+                       of IPv4 sockets
+
+    LTszoff.c           C source to a program that tests file sizes
+                       and offsets  -- see LTbigf.c for a large
+                       file (size > 32 bits) test
+
+    LTunix.c           C source to a program that tests the finding
+                       of UNIX domain sockets
+
+    Makefile           the make(1) control file
+
+                       The Makefile clean rule will not remove
+                       config.* files, but the spotless rule will.
+                       One the spotless rule has been used,
+                       ../Configure must be re-run.
+
+    TestDB              a data base of dialects where the test
+                       suite has been validated
+
+Vic Abell
+April 11, 2002
diff --git a/tests/Add2TestDB b/tests/Add2TestDB
new file mode 100755 (executable)
index 0000000..015d8f9
--- /dev/null
@@ -0,0 +1,83 @@
+#!/bin/sh
+#
+# Add2TestDB -- add the current test to the lsof test suite DB
+#
+# This script saves the current TestDB file in TestDB.old and adds
+# the words in config.cflags to it.  "-D" prefixes on the words are
+# removed, the words are sorted, and they are joint in a single
+# line that is catenated to TestDB if it isn't already there.
+#
+# $Id: Add2TestDB,v 1.3 2015/07/07 20:22:07 abe Exp $
+
+# Check for config.flags.
+
+if test ! -r config.cflags
+then
+  echo "$0: no ./config.cflags file"
+  exit 1
+fi
+
+# Check for a current data base file.
+
+if test ! -r TestDB
+then
+  echo "$0: no ./TestDB file"
+  exit 1
+fi
+
+# Form a new data base line.
+
+new=""
+for i in $(LC_ALL=C sort < config.cflags)
+do
+  w=$(echo $i | sed 's/^-D//')
+  if test "X$new" = "X"
+  then
+    new=$w
+  else
+    new="$new $w"
+  fi
+done
+
+# See if the new line is already in the data base.
+
+grep "$new" TestDB > /dev/null 2>&1
+if test $? -eq 0
+then
+  echo "\"$new\" is already in TestDB."
+  exit 1
+fi
+
+# Build a new data base file.
+
+if test ! -w TestDB
+then
+  echo "$0: can't write the following to the end of TestDB:"
+  echo  "    \"$new\""
+  exit 1
+fi
+rm -f TestDB.new
+cp TestDB TestDB.new
+chmod 644 TestDB.new
+echo "$new" >> TestDB.new
+
+# Archive the current data base file, if possible.
+
+if test -d OLD
+then
+  dt=$(date)
+  dtm="========== $dt =========="
+  if test -r OLD/TestDB
+  then
+    echo "$dtm" >> OLD/TestDB
+  else
+    echo "$dtm" > OLD/TestDB
+  fi
+  cat TestDB >> OLD/TestDB
+fi
+
+# Put the new data base file in place.
+
+mv TestDB.new TestDB
+echo "\"$new\" added to TestDB."
+exit 0
diff --git a/tests/CkTestDB b/tests/CkTestDB
new file mode 100755 (executable)
index 0000000..a63ba00
--- /dev/null
@@ -0,0 +1,140 @@
+#!/bin/sh
+#
+# CkTestDB -- see if this dialect is has been tested
+#
+# This script builds a line from config.flags in the form of lines in
+# ./TestDB,  (See Add2TestDB.)
+#
+# It then compares the line to TestDB.  If the line is found, the script
+# exits.  if the line is not found, the script issues a warning and requests
+# a go-ahead confirmation.
+#
+# The script will exit 0 if the test line is in the DB or the go-ahead
+# confirmation is positive.
+#
+# $Id: CkTestDB,v 1.3 2010/01/18 19:02:21 abe Exp abe $
+
+# Check for config.flags.
+
+if test ! -r config.cflags
+then
+  echo "$0: no ./config.cflags file"
+  exit 1
+fi
+
+# Check for a current data base file.
+
+if test ! -r TestDB
+then
+  echo "$0: no ./TestDB file"
+  exit 1
+fi
+
+# Form a data base line.
+
+new=""
+for i in $(LC_ALL=C sort < config.cflags)
+do
+  w=$(echo $i | sed 's/^-D//')
+  if test "X$new" = "X"
+  then
+    new=$w
+  else
+    new="$new $w"
+  fi
+done
+
+# See if the line is already in the data base.  Exit with success (0), if it is.
+
+grep "^$new\$" TestDB > /dev/null 2>&1
+if test $? -eq 0
+then
+  exit 0
+fi
+
+# This dialect may never have been validated with the test suite.
+
+# If the standard input is not a TTY, quit, because no interaction
+# is possible.
+
+tty -s > /dev/null 2>&1
+if test $? -ne 0
+then
+  echo ""
+  echo "This suite has not been validated on:"
+  echo ""
+  echo "     $new"
+  echo ""
+  exit 1
+fi
+
+# Establish trap and stty handling.
+
+ISIG=":"
+trap '$ISIG; exit 1'  1 2 3 15
+stty -a 2>&1 | grep isig > /dev/null
+if test $? -eq 0
+then
+  stty -a 2>&1 | egrep -e -isig > /dev/null
+  if test $? -eq 0
+  then
+    ISIG="stty -isig"
+    stty isig
+  fi
+fi
+
+# Establish echo type -- Berkeley or SYSV.
+
+j=$(echo -n "")
+if test "X$j" = "X-n "
+then
+  EC="\c"
+  EO=""
+else
+  EC=""
+  EO="-n"
+fi
+
+if [ x"$CI" = x1 ]; then
+    exit 0
+fi
+
+# Display a validation warning.
+
+cat << .CAT_MARK > /dev/tty
+
+==================================================================
+
+!!!WARNING!!!
+
+This dialect or its particular version may not have been validated
+with the lsof test suite.  Consequently some tests may fail or may
+not even compile.
+
+This is the computed identity of this dialect, not found in the
+test data base file, ./TestDB:
+
+.CAT_MARK
+echo "    $new" > /dev/tty
+END=0
+while test $END = 0
+do
+  echo "" > /dev/tty
+  echo $EO "Do you want to continue (y|n) [n]? $EC" > /dev/tty
+  read ANS EXCESS
+  if test "X$ANS" = "Xn" -o "X$ANS" = "XN"
+  then
+    exit 1
+  fi
+  if test "X$ANS" = "Xy" -o "X$ANS" = "XY"
+  then
+    exit 0
+  else
+    echo "Please answer y or n." > /dev/tty
+  fi
+done
+
+# Should never get here!
+
+echo "$0: unexpected failure!"
+exit 2
diff --git a/tests/LTbasic.c b/tests/LTbasic.c
new file mode 100644 (file)
index 0000000..3db186b
--- /dev/null
@@ -0,0 +1,416 @@
+/*
+ * LTbasic.c -- Lsof Test basic tests
+ *
+ * The basic tests measure the finding by lsof of its own open CWD, open
+ * executable (when possible), and open /dev/kmem files.
+ *
+ * V. Abell
+ * Purdue University
+ */
+
+/*
+ * Copyright 2002 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by V. 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.
+ */
+
+#include "LsofTest.h"
+#include "lsof_fields.h"
+
+/*
+ * Local definitions
+ */
+
+/*
+ * Globals
+ */
+
+char *Pn = (char *)NULL; /* program name */
+
+/*
+ * Local function prototypes
+ */
+
+static void cleanup(void);
+static char *tstlsof(char **texec, char **tkmem, char **tproc);
+
+/*
+ * Main program for dialects that support locking tests.
+ */
+
+int main(int argc,     /* argument count */
+         char *argv[]) /* arguments */
+{
+    char buf[2048];             /* temporary buffer */
+    char *em;                   /* error message pointer */
+    char *texec = (char *)NULL; /* lsof executable test result */
+    char *tkmem = (char *)NULL; /* /dev/kmem test result */
+    char *tproc = (char *)NULL; /* lsof process test result */
+    int xv = 0;                 /* exit value */
+                                /*
+                                 * Get program name and PID, issue start message, and build space prefix.
+                                 */
+    if ((Pn = strrchr(argv[0], '/')))
+        Pn++;
+    else
+        Pn = argv[0];
+    (void)printf("%s ... ", Pn);
+    (void)fflush(stdout);
+    PrtMsg((char *)NULL, Pn);
+    /*
+     * Process arguments.
+     */
+    if (ScanArg(argc, argv, "h", Pn))
+        xv = 1;
+    if (xv || LTopt_h) {
+        (void)PrtMsg("usage: [-h]", Pn);
+        PrtMsgX("       -h       print help (this panel)", Pn, cleanup, xv);
+    }
+    /*
+     * See if lsof can be executed and can access kernel memory.
+     */
+    if ((em = IsLsofExec()))
+        (void)PrtMsgX(em, Pn, cleanup, 1);
+    if ((em = CanRdKmem()))
+        (void)PrtMsgX(em, Pn, cleanup, 1);
+    /*
+     * Test lsof.
+     */
+    if ((em = tstlsof(&texec, &tkmem, &tproc)))
+        PrtMsg(em, Pn);
+    if (texec)
+        PrtMsg(texec, Pn);
+    if (tkmem)
+        PrtMsg(tkmem, Pn);
+    if (tproc)
+        PrtMsg(tproc, Pn);
+    /*
+     * Compute exit value and exit.
+     */
+    if (em || texec || tkmem || tproc) {
+        if (strcmp(LT_DEF_LSOF_PATH, LsofPath)) {
+            PrtMsg(" ", Pn);
+            PrtMsg("Hint: you used the LT_LSOF_PATH environment variable to",
+                   Pn);
+            PrtMsg("  specify this path to the lsof executable:\n", Pn);
+            (void)snprintf(buf, sizeof(buf) - 1, "      %s\n", LsofPath);
+            buf[sizeof(buf) - 1] = '\0';
+            PrtMsg(buf, Pn);
+            PrtMsgX("  Make sure its revision is 4.63 or higher.", Pn, cleanup,
+                    1);
+        } else
+            PrtMsgX("", Pn, cleanup, 1);
+    }
+    (void)PrtMsgX("OK", Pn, cleanup, 0);
+    return (0);
+}
+
+/*
+ * cleanup() -- release resources
+ */
+
+static void cleanup() {}
+
+/*
+ * tstlsof() -- test for the lsof process
+ */
+
+static char *tstlsof(char **texec, /* result of the executable test */
+                     char **tkmem, /* result of the /dev/kmem test */
+                     char **tproc) /* result of the lsof process test */
+{
+    char buf[2048];           /* temporary buffer */
+    char buf2[2048] = {};     /* temporary buffer */
+    char *cem;                /* current error message pointer */
+    LTfldo_t *cmdp;           /* command pointer */
+    LTdev_t cwddc;            /* CWD device components */
+    struct stat cwdsb;        /* CWD stat(2) buffer */
+    LTfldo_t *devp;           /* device pointer */
+    int execs = 0;            /* executable status */
+    int fdn;                  /* FD is a number */
+    LTfldo_t *fdp;            /* file descriptor pointer */
+    LTfldo_t *fop;            /* field output pointer */
+    char ibuf[64];            /* inode string buffer */
+    LTfldo_t *inop;           /* inode number pointer */
+    LTdev_t kmemdc;           /* /dev/kmem device components */
+    int kmems = 0;            /* kmem status */
+    struct stat kmemsb;       /* /dev/kmem stat(2) buffer */
+    LTdev_t lsofdc;           /* lsof device components */
+    struct stat lsofsb;       /* lsof stat(2) buffer */
+    int nf;                   /* number of fields */
+    char *opv[4];             /* option vector for ExecLsof() */
+    char *pem = (char *)NULL; /* previous error message */
+    pid_t pid;                /* PID */
+    int pids = 0;             /* PID found status */
+    int procs = 0;            /* process status */
+    LTfldo_t *rdevp;          /* raw device pointer */
+    char *tcp;                /* temporary character pointer */
+    int ti;                   /* temporary integer */
+    LTdev_t tmpdc;            /* temporary device components */
+    LTfldo_t *typ;            /* file type pointer */
+    int xwhile;               /* exit while() flag */
+
+    /*
+     * Get lsof executable's stat(2) information.
+     */
+    /* lsof could be a wrapper script when building with libtool, try
+     * ./.libs/lsof first */
+    (void)snprintf(buf, sizeof(buf) - 1, "%s", LsofPath);
+    if (strlen(buf) >= 4) {
+        /* strip lsof suffix */
+        buf[strlen(buf) - 4] = '\0';
+        (void)snprintf(buf2, sizeof(buf2) - 1, "%s.libs/lsof", buf);
+    }
+    if ((buf2[0] && stat(buf2, &lsofsb)) && stat(LsofPath, &lsofsb)) {
+        (void)snprintf(buf, sizeof(buf) - 1, "ERROR!!!  stat(%s): %s", LsofPath,
+                       strerror(errno));
+        buf[sizeof(buf) - 1] = '\0';
+        cem = MkStrCpy(buf, &ti);
+        if (pem)
+            (void)PrtMsg(pem, Pn);
+        pem = cem;
+        execs = 1;
+    } else if ((cem = ConvStatDev(&lsofsb.st_dev, &lsofdc))) {
+        if (pem)
+            (void)PrtMsg(pem, Pn);
+        pem = cem;
+        execs = 1;
+    }
+
+#if defined(LT_KMEM)
+    /*
+     * Get /dev/kmem's stat(2) information.
+     */
+    if (stat("/dev/kmem", &kmemsb)) {
+        (void)snprintf(buf, sizeof(buf) - 1,
+                       "ERROR!!!  can't stat(2) /dev/kmem: %s",
+                       strerror(errno));
+        buf[sizeof(buf) - 1] = '\0';
+        cem = MkStrCpy(buf, &ti);
+        if (pem)
+            (void)PrtMsg(pem, Pn);
+        pem = cem;
+        kmems = 1;
+    } else if ((cem = ConvStatDev(&kmemsb.st_rdev, &kmemdc))) {
+        if (pem)
+            (void)PrtMsg(pem, Pn);
+        pem = cem;
+        kmems = 1;
+    }
+#else  /* !defined(LT_KMEM) */
+    kmems = 1;
+#endif /* defined(LT_KMEM) */
+
+    /*
+     * Get CWD's stat(2) information.
+     */
+    if (stat(".", &cwdsb)) {
+        (void)snprintf(buf, sizeof(buf) - 1, "ERROR!!!  stat(.): %s",
+                       strerror(errno));
+        buf[sizeof(buf) - 1] = '\0';
+        cem = MkStrCpy(buf, &ti);
+        if (pem)
+            (void)PrtMsg(pem, Pn);
+        pem = cem;
+        procs = 1;
+    } else if ((cem = ConvStatDev(&cwdsb.st_dev, &cwddc))) {
+        if (pem)
+            (void)PrtMsg(pem, Pn);
+        pem = cem;
+        procs = 1;
+    }
+
+    /*
+     * Complete the option vector and start lsof execution.
+     */
+    ti = 0;
+
+#if defined(USE_LSOF_C_OPT)
+    opv[ti++] = "-C";
+#endif /* defined(USE_LSOF_C_OPT) */
+
+#if defined(USE_LSOF_X_OPT)
+    opv[ti++] = "-X";
+#endif /* defined(USE_LSOF_X_OPT) */
+
+    opv[ti++] = "-clsof";
+    opv[ti] = (char *)NULL;
+    if ((cem = ExecLsof(opv))) {
+        if (pem)
+            (void)PrtMsg(pem, Pn);
+        return (cem);
+    }
+    /*
+     * Read lsof output.
+     */
+    xwhile = execs + kmems + procs;
+    while ((xwhile < 3) && (fop = RdFrLsof(&nf, &cem))) {
+        if (pem)
+            (void)PrtMsg(pem, Pn);
+        pem = cem;
+        switch (fop->ft) {
+        case LSOF_FID_PID:
+
+            /*
+             * This is a process information line.
+             */
+            pid = (pid_t)atoi(fop->v);
+            pids = 1;
+            cmdp = (LTfldo_t *)NULL;
+            for (fop++, ti = 1; ti < nf; fop++, ti++) {
+                switch (fop->ft) {
+                case LSOF_FID_CMD:
+                    cmdp = fop;
+                    break;
+                }
+            }
+            if (!cmdp || (pid != LsofPid))
+                pids = 0;
+            break;
+        case LSOF_FID_FD:
+
+            /*
+             * This is a file descriptor line.  Scan its fields.
+             */
+            if (!pids)
+                break;
+            devp = inop = rdevp = typ = (LTfldo_t *)NULL;
+            fdp = fop;
+            for (fop++, ti = 1; ti < nf; fop++, ti++) {
+                switch (fop->ft) {
+                case LSOF_FID_DEVN:
+                    devp = fop;
+                    break;
+                case LSOF_FID_INODE:
+                    inop = fop;
+                    break;
+                case LSOF_FID_RDEV:
+                    rdevp = fop;
+                    break;
+                case LSOF_FID_TYPE:
+                    typ = fop;
+                    break;
+                }
+            }
+            /*
+             * A file descriptor line has been processes.
+             *
+             * Set the descriptor's numeric status.
+             *
+             * Check descriptor by FD type.
+             */
+
+            for (fdn = 0, tcp = fdp->v; *tcp; tcp++) {
+                if (!isdigit((unsigned char)*tcp)) {
+                    fdn = -1;
+                    break;
+                }
+                fdn = (fdn * 10) + (int)(*tcp - '0');
+            }
+            if (!procs && (fdn == -1) && !strcasecmp(fdp->v, "cwd") && typ &&
+                (!strcasecmp(typ->v, "DIR") || !strcasecmp(typ->v, "VDIR"))) {
+
+                /*
+                 * This is the CWD for the process.  Make sure its information
+                 * matches what stat(2) said about the CWD.
+                 */
+                if (!devp || !inop)
+                    break;
+                if ((cem = ConvLsofDev(devp->v, &tmpdc))) {
+                    if (pem)
+                        (void)PrtMsg(pem, Pn);
+                    pem = cem;
+                    break;
+                }
+                (void)snprintf(ibuf, sizeof(ibuf) - 1, "%" PRIu64,
+                               (uint64_t)cwdsb.st_ino);
+                ibuf[sizeof(ibuf) - 1] = '\0';
+                if ((tmpdc.maj == cwddc.maj) && (tmpdc.min == cwddc.min) &&
+                    (tmpdc.unit == cwddc.unit) && !strcmp(inop->v, ibuf)) {
+                    procs = 1;
+                    xwhile++;
+                }
+                break;
+            }
+            if (!kmems && (fdn >= 0) && typ &&
+                (!strcasecmp(typ->v, "CHR") || !strcasecmp(typ->v, "VCHR"))) {
+
+                /*
+                 * /dev/kmem hasn't been found and this is an open character
+                 * device file with a numeric descriptor.
+                 *
+                 * See if it is /dev/kmem.
+                 */
+                if (!inop || !rdevp)
+                    break;
+                if ((cem = ConvLsofDev(rdevp->v, &tmpdc))) {
+                    if (pem)
+                        (void)PrtMsg(pem, Pn);
+                    pem = cem;
+                    break;
+                }
+                (void)snprintf(ibuf, sizeof(ibuf) - 1, "%" PRIu64,
+                               (uint64_t)kmemsb.st_ino);
+                ibuf[sizeof(ibuf) - 1] = '\0';
+                if ((tmpdc.maj == kmemdc.maj) && (tmpdc.min == kmemdc.min) &&
+                    (tmpdc.unit == kmemdc.unit) && !strcmp(inop->v, ibuf)) {
+                    kmems = 1;
+                    xwhile++;
+                }
+                break;
+            }
+            if (!execs && (fdn == -1) && typ &&
+                (!strcasecmp(typ->v, "REG") || !strcasecmp(typ->v, "VREG"))) {
+
+                /*
+                 * If this is a regular file with a non-numeric FD, it may be
+                 * the executable.
+                 */
+                if (!devp || !inop)
+                    break;
+                if ((cem = ConvLsofDev(devp->v, &tmpdc))) {
+                    if (pem)
+                        (void)PrtMsg(pem, Pn);
+                    pem = cem;
+                    break;
+                }
+                (void)snprintf(ibuf, sizeof(ibuf) - 1, "%" PRIu64,
+                               (uint64_t)lsofsb.st_ino);
+                ibuf[sizeof(ibuf) - 1] = '\0';
+                if ((tmpdc.maj == lsofdc.maj) && (tmpdc.min == lsofdc.min) &&
+                    (tmpdc.unit == lsofdc.unit) && !strcmp(inop->v, ibuf)) {
+                    execs = 1;
+                    xwhile++;
+                }
+            }
+        }
+    }
+    (void)StopLsof();
+    if (!execs)
+        *texec = "ERROR!!!  open lsof executable wasn't found.";
+    if (!kmems)
+        *tkmem = "ERROR!!!  open lsof /dev/kmem usage wasn't found.";
+    if (!procs)
+        *tproc = "ERROR!!!  lsof process wasn't found.";
+    return (pem);
+}
diff --git a/tests/LTbasic2.c b/tests/LTbasic2.c
new file mode 100644 (file)
index 0000000..4ad9024
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * LTbasic2.c -- Lsof Test basic tests 2
+ *
+ * The basic tests measure the finding by liblsof of its own open CWD, open
+ * executable (when possible).
+ *
+ * V. Abell
+ * Purdue University
+ */
+
+/*
+ * Copyright 2002 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by V. 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.
+ */
+
+#include "lsof.h"
+#include <stdio.h>
+#include <sys/stat.h>
+
+int main(int argc, char **argv) {
+    struct lsof_result *result;
+    struct lsof_context *ctx;
+    struct lsof_process *p;
+    struct lsof_file *f;
+    int pi, fi;
+    char buffer[128];
+    int exec_found = 0; /* executable found in result */
+    int cwd_found = 0;  /* cwd found in result */
+    struct stat exec_stat;
+    struct stat cwd_stat;
+    if (stat(argv[0], &exec_stat)) {
+        fprintf(stderr, "Cannot stat %s, skipping executable check\n", argv[0]);
+        exec_found = 1;
+    }
+    if (stat(".", &cwd_stat)) {
+        fprintf(stderr, "Cannot stat '.', skipping cwd check\n");
+        cwd_found = 1;
+    }
+
+    ctx = lsof_new();
+    lsof_select_process(ctx, "LTbasic2", 0);
+    lsof_freeze(ctx);
+    lsof_gather(ctx, &result);
+
+    for (pi = 0; pi < result->num_processes; pi++) {
+        p = &result->processes[pi];
+        for (fi = 0; fi < p->num_files; fi++) {
+            f = &p->files[fi];
+            if (f->fd_type == LSOF_FD_PROGRAM_TEXT) {
+                /* check if device and inode matches */
+                if ((f->flags &
+                     (LSOF_FILE_FLAG_DEV_VALID | LSOF_FILE_FLAG_INODE_VALID)) &&
+                    f->dev == exec_stat.st_dev &&
+                    f->inode == exec_stat.st_ino) {
+                    exec_found = 1;
+                }
+            } else if (f->fd_type == LSOF_FD_CWD) {
+                /* check if device and inode matches */
+                if ((f->flags &
+                     (LSOF_FILE_FLAG_DEV_VALID | LSOF_FILE_FLAG_INODE_VALID)) &&
+                    f->dev == cwd_stat.st_dev && f->inode == cwd_stat.st_ino) {
+                    cwd_found = 1;
+                }
+            }
+        }
+    }
+
+    lsof_free_result(result);
+    lsof_destroy(ctx);
+
+    if (!exec_found) {
+        fprintf(stderr, "ERROR!!!  open LTbasic2 executable wasn't found.\n");
+    }
+    if (!cwd_found) {
+        fprintf(stderr, "ERROR!!!  current working directory wasn't found.\n");
+    }
+    return !(exec_found && cwd_found);
+}
\ No newline at end of file
diff --git a/tests/LTbigf.c b/tests/LTbigf.c
new file mode 100644 (file)
index 0000000..f641632
--- /dev/null
@@ -0,0 +1,728 @@
+/*
+ * LTbigf.c -- Lsof Test big file size and offset tests
+ *
+ * V. Abell
+ * Purdue University
+ */
+
+/*
+ * Copyright 2002 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by V. 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.
+ */
+
+#include "LsofTest.h"
+
+#if !defined(LT_BIGF)
+
+/*
+ * Here begins the version of this program for dialects that don't support
+ * large files.
+ */
+
+/*
+ * Main program for dialects that don't support large files
+ */
+
+int main(int argc,     /* argument count */
+         char *argv[]) /* arguments */
+{
+    char *pn; /* program name */
+              /*
+               * Get program name and issue start and exit message.
+               */
+    if ((pn = (char *)strrchr(argv[0], '/')))
+        pn++;
+    else
+        pn = argv[0];
+
+    (void)printf("%s ... %s\n", pn, LT_DONT_DO_TEST);
+    return (0);
+}
+#else /* defined(LT_BIGF) */
+
+/*
+ * Here begins the version of this program for dialects that support
+ * large files.
+ */
+
+#    include "lsof_fields.h"
+
+/*
+ * Pre-definitions that may be changed by specific dialects
+ */
+
+#    define OFFTST_STAT 1 /* offset tests status */
+
+#    if defined(LT_DIAL_aix)
+/*
+ * AIX-specific definitions
+ */
+
+#        define OFFSET_T off64_t /* define offset type */
+#    endif                       /* defined(LT_DIAL_aix) */
+
+#    if defined(LT_DIAL_bsdi)
+/*
+ * BSDI-specific definitions
+ */
+
+#        define OFFSET_T off_t    /* define offset type */
+#        define OPENF open        /* define open function */
+#        define SEEKF lseek       /* define seek function */
+#        define STATF stat        /* define stat function */
+#        define STATS struct stat /* define stat structure */
+#    endif                        /* defined(LT_DIAL_bsdi) */
+
+#    if defined(LT_DIAL_darwin)
+/*
+ * Darwin-specific definitions
+ */
+
+#        if LT_VERS >= 900
+#            define OFFSET_T off_t    /* define offset type */
+#            define OPENF open        /* define open function */
+#            define SEEKF lseek       /* define seek function */
+#            define STATF stat        /* define stat function */
+#            define STATS struct stat /* define stat structure */
+#        endif                        /* LT_VERS>=900 */
+#    endif                            /* defined(LT_DIAL_darwin) */
+
+#    if defined(LT_DIAL_du)
+/*
+ * DEC_OSF/1|Digital_UNIX|Tru64_UNIX-specific items
+ */
+
+#        define OFFSET_T off_t    /* define offset type */
+#        define OPENF open        /* define open function */
+#        define SEEKF lseek       /* define seek function */
+#        define STATF stat        /* define stat function */
+#        define STATS struct stat /* define stat structure */
+#    endif                        /* defined(LT_DIAL_du) */
+
+#    if defined(LT_DIAL_freebsd)
+/*
+ * FreeBSD-specific definitions
+ */
+
+#        define OFFSET_T off_t    /* define offset type */
+#        define OPENF open        /* define open function */
+#        define SEEKF lseek       /* define seek function */
+#        define STATF stat        /* define stat function */
+#        define STATS struct stat /* define stat structure */
+#    endif                        /* defined(LT_DIAL_freebsd) */
+
+#    if defined(LT_DIAL_linux)
+/*
+ * Linux-specific definitions
+ */
+
+#        undef OFFTST_STAT
+#        define OFFTST_STAT                                                    \
+            0                     /* Linux lsof may not be able to report      \
+                                   * offsets -- see the function               \
+                                   * ck_Linux_offset_support() */
+#        define OFFSET_T off_t    /* define offset type */
+#        define OPENF open        /* define open function */
+#        define SEEKF lseek       /* define seek function */
+#        define STATF stat        /* define stat function */
+#        define STATS struct stat /* define stat structure */
+
+static int ck_Linux_offset_support(void);
+#    endif                        /* defined(LT_DIAL_linux) */
+
+#    if defined(LT_DIAL_hpux)
+/*
+ * HP-UX-specific definitions
+ */
+
+#        define OFFSET_T off64_t /* define offset type */
+#    endif                       /* defined(LT_DIAL_hpux) */
+
+#    if defined(LT_DIAL_netbsd)
+/*
+ * NetBSD-specific definitions
+ */
+
+#        define OFFSET_T off_t    /* define offset type */
+#        define OPENF open        /* define open function */
+#        define SEEKF lseek       /* define seek function */
+#        define STATF stat        /* define stat function */
+#        define STATS struct stat /* define stat structure */
+#    endif                        /* defined(LT_DIAL_netbsd) */
+
+#    if defined(LT_DIAL_openbsd)
+/*
+ * OpenBSD-specific definitions
+ */
+
+#        define OFFSET_T off_t    /* define offset type */
+#        define OPENF open        /* define open function */
+#        define SEEKF lseek       /* define seek function */
+#        define STATF stat        /* define stat function */
+#        define STATS struct stat /* define stat structure */
+#    endif                        /* defined(LT_DIAL_openbsd) */
+
+#    if defined(LT_DIAL_ou)
+/*
+ * OpenUNIX-specific items
+ */
+
+#        include <signal.h>
+
+#        define IGNORE_SIGXFSZ
+#        define OFFSET_T off64_t /* define offset type */
+#    endif                       /* defined(LT_DIAL_ou) */
+
+#    if defined(LT_DIAL_solaris)
+/*
+ * Solaris-specific definitions
+ */
+
+#        define OFFSET_T off64_t /* define offset type */
+#    endif                       /* defined(LT_DIAL_solaris) */
+
+#    if defined(LT_DIAL_uw)
+/*
+ * UnixWare-specific items
+ */
+
+#        include <signal.h>
+
+#        define IGNORE_SIGXFSZ
+#        define OFFSET_T off64_t /* define offset type */
+#    endif                       /* defined(LT_DIAL_uw) */
+
+/*
+ * Local definitions
+ */
+
+#    if !defined(OPENF)
+#        define OPENF open64 /* open() function */
+#    endif                   /* !defined(OPENF) */
+
+#    if !defined(OFFSET_T)
+#        define OFFSET_T unsigned long long /* offset type */
+#    endif                                  /* !defined(OFFSET_T) */
+
+#    if !defined(SEEKF)
+#        define SEEKF lseek64 /* seek() function */
+#    endif                    /* !defined(SEEKF) */
+
+#    if !defined(STATF)
+#        define STATF stat64 /* stat(2) structure */
+#    endif                   /* !defined(STATF) */
+
+#    if !defined(STATS)
+#        define STATS struct stat64 /* stat(2) structure */
+#    endif                          /* !defined(STATS) */
+
+#    define TST_OFFT 0 /* test offset in 0t decimal*/
+#    define TST_OFFX 1 /* test offset in hex */
+#    define TST_SZ 2   /* test size */
+
+/*
+ * Globals
+ */
+
+int Fd = -1;               /* test file descriptor; open if >= 0 */
+pid_t MyPid = (pid_t)0;    /* PID of this process */
+char *Path = (char *)NULL; /* test file path; none if NULL */
+char *Pn = (char *)NULL;   /* program name */
+
+/*
+ * Local function prototypes
+ */
+
+static void cleanup(void);
+static int tstwlsof(int tt, char *opt, OFFSET_T sz);
+
+/*
+ * Main program for dialects that support large files
+ */
+
+int main(int argc,     /* argument count */
+         char *argv[]) /* arguments */
+{
+    char buf[2048];              /* temporary buffer */
+    int do_offt = OFFTST_STAT;   /* do offset tests if == 1 */
+    char *em;                    /* error message pointer */
+    int i;                       /* temporary integer */
+    int len;                     /* string length */
+    OFFSET_T sz = 0x140000000ll; /* test file size */
+    char szbuf[64];              /* size buffer */
+    char *tcp;                   /* temporary character pointer */
+    int tofft = 0;               /* 0t offset test result */
+    int toffx = 0;               /* 0x offset test result */
+    int tsz = 0;                 /* size test result */
+    int xv = 0;                  /* exit value */
+                                 /*
+                                  * Get program name and PID, issue start message, and build space prefix.
+                                  */
+    if ((Pn = strrchr(argv[0], '/')))
+        Pn++;
+    else
+        Pn = argv[0];
+    MyPid = getpid();
+    (void)printf("%s ... ", Pn);
+    (void)fflush(stdout);
+    PrtMsg((char *)NULL, Pn);
+    /*
+     * Process arguments.
+     */
+    if (ScanArg(argc, argv, "hp:", Pn))
+        xv = 1;
+    if (xv || LTopt_h) {
+        (void)PrtMsg("usage: [-h] [-p path]", Pn);
+        PrtMsg("       -h       print help (this panel)", Pn);
+        PrtMsgX("       -p path  define test file path", Pn, cleanup, xv);
+    }
+
+#    if defined(LT_DIAL_linux)
+    /*
+     * If this is Linux, see if lsof can report file offsets.
+     */
+    do_offt = ck_Linux_offset_support();
+#    endif /* defined(LT_DIAL_linux) */
+
+    /*
+     * See if lsof can be executed and can access kernel memory.
+     */
+    if ((em = IsLsofExec()))
+        (void)PrtMsgX(em, Pn, cleanup, 1);
+    if ((em = CanRdKmem()))
+        (void)PrtMsgX(em, Pn, cleanup, 1);
+    /*
+     * Construct the path.  If LT_BIGSZOFF_PATH is defined in the environment,
+     * use it. otherwise construct a path in the CWD.
+     */
+    if (!(Path = LTopt_p)) {
+        (void)snprintf(buf, sizeof(buf), "./config.LTbigf%ld", (long)MyPid);
+        buf[sizeof(buf) - 1] = '\0';
+        Path = MkStrCpy(buf, &len);
+    }
+    /*
+     * Fill buffer for writing to the test file.
+     */
+    for (i = 0; i < sizeof(buf); i++) {
+        buf[i] = (char)(i & 0xff);
+    }
+
+#    if defined(IGNORE_SIGXFSZ)
+    /*
+     * Ignore SIGXFSZ, if directed by a dialect-specific option.
+     */
+    (void)signal(SIGXFSZ, SIG_IGN);
+#    endif /* defined(IGNORE_SIGXFSZ) */
+
+    /*
+     * Open a new test file at the specified path.
+     */
+    (void)unlink(Path);
+    if ((Fd = OPENF(Path, O_RDWR | O_CREAT, 0600)) < 0) {
+        (void)fprintf(stderr, "ERROR!!!  can't open %s\n", Path);
+
+    print_hint:
+
+        /*
+         * Print a hint about the LT_BIGSZOFF_PATH environment variable.
+         */
+
+        MsgStat = 1;
+        (void)snprintf(buf, sizeof(buf) - 1, "      Errno %d: %s", errno,
+                       strerror(errno));
+        buf[sizeof(buf) - 1] = '\0';
+        (void)PrtMsg(buf, Pn);
+        (void)PrtMsg("Hint: try using \"-p path\" to supply a path in a", Pn);
+        (void)PrtMsg("file system that has large file support enabled.\n", Pn);
+        (void)PrtMsg("Hint: try raising the process ulimit file block", Pn);
+        (void)PrtMsg("size to a value that will permit this test to", Pn);
+        (void)snprintf(szbuf, sizeof(szbuf) - 1, "%lld", (long long)sz);
+        szbuf[sizeof(szbuf) - 1] = '\0';
+        (void)snprintf(buf, sizeof(buf) - 1,
+                       "write a file whose size appears to be %s", szbuf);
+        buf[sizeof(buf) - 1] = '\0';
+        (void)PrtMsg(buf, Pn);
+        (void)PrtMsg("bytes.  (The file really isn't that big -- it", Pn);
+        (void)PrtMsg("just has a large \"hole\" in its mid-section.)\n", Pn);
+        (void)PrtMsgX("See 00FAQ and 00TEST for more information.", Pn, cleanup,
+                      1);
+    }
+    /*
+     * Write a buffer load at the beginning of the file.
+     */
+    if (SEEKF(Fd, (OFFSET_T)0, SEEK_SET) < 0) {
+        (void)fprintf(stderr, "ERROR!!!  can't seek to the beginning of %s\n",
+                      Path);
+        goto print_hint;
+    }
+    if (write(Fd, buf, sizeof(buf)) != sizeof(buf)) {
+        (void)fprintf(stderr,
+                      "ERROR!!!  can't write %d bytes to the beginning of %s\n",
+                      (int)sizeof(buf), Path);
+        goto print_hint;
+    }
+    /*
+     * Write a buffer load near the end of the file to bring it to the
+     * specified length.  Leave the file open so lsof can find it.
+     */
+    if (SEEKF(Fd, (OFFSET_T)(sz - sizeof(buf)), SEEK_SET) < 0) {
+        (void)snprintf(szbuf, sizeof(szbuf) - 1, "%lld",
+                       (unsigned long long)(sz - sizeof(buf)));
+        (void)fprintf(stderr, "ERROR!!!  can't seek to %s in %s\n", szbuf,
+                      Path);
+        goto print_hint;
+    }
+    if (write(Fd, buf, sizeof(buf)) != sizeof(buf)) {
+        (void)fprintf(stderr,
+                      "ERROR!!!  can't write %d bytes near the end of %s\n",
+                      (int)sizeof(buf), Path);
+        goto print_hint;
+    }
+    /*
+     * Fsync() the file.
+     */
+    if (fsync(Fd)) {
+        (void)fprintf(stderr, "ERROR!!!  can't fsync %s\n", Path);
+        goto print_hint;
+    }
+
+    /*
+     * If this dialect can't report offsets, disable the offset tests.
+     */
+    if (!do_offt) {
+        tofft = toffx = 1;
+        PrtMsg("WARNING!!!  lsof can't return file offsets for this dialect,",
+               Pn);
+        PrtMsg("  so offset tests have been disabled.", Pn);
+    }
+    /*
+     * Do file size test.
+     */
+    tsz = tstwlsof(TST_SZ, "-s", sz);
+    /*
+     * If enabled, do offset tests.
+     */
+    if (!tofft)
+        tofft = tstwlsof(TST_OFFT, "-oo20", sz);
+    if (!toffx)
+        toffx = tstwlsof(TST_OFFX, "-oo2", sz);
+    /*
+     * Compute exit value and exit.
+     */
+    if ((tsz != 1) || (tofft != 1) || (toffx != 1)) {
+        tcp = (char *)NULL;
+        xv = 1;
+    } else {
+        tcp = "OK";
+        xv = 0;
+    }
+    (void)PrtMsgX(tcp, Pn, cleanup, xv);
+    return (0);
+}
+
+#    if defined(LT_DIAL_linux)
+/*
+ * ck_Linux_offset_support() -- see if lsof can report offsets for this
+ *                             Linux implementation
+ */
+
+static int ck_Linux_offset_support() {
+    char buf[1024];         /* lsof output line buffer */
+    int bufl = sizeof(buf); /* size of buf[] */
+    char *opv[5];           /* option vector for lsof */
+    int rv = 1;             /* return value:
+                             *     0 == no lsof offset support
+                             *     1 == lsof offset support */
+                            /*
+                             * Ask lsof to report the test's FD zero offset.
+                             */
+    if (IsLsofExec())
+        return (0);
+    opv[0] = "-o";
+    snprintf(buf, bufl - 1, "-p%d", (int)getpid());
+    opv[1] = buf;
+    opv[2] = "-ad0";
+    opv[3] = "+w";
+    opv[4] = (char *)NULL;
+    if (ExecLsof(opv))
+        return (0);
+    /*
+     * Read the lsof output.  Look for a line with "WARNING: can't report
+     * offset" in it.  If it is found, then this Linux lsof can't report
+     * offsets.
+     */
+    while (fgets(buf, bufl - 1, LsofFs)) {
+        if (strstr(buf, "WARNING: can't report offset")) {
+            rv = 0;
+            break;
+        }
+    }
+    (void)StopLsof();
+    return (rv);
+}
+#    endif /* defined(LT_DIAL_linux) */
+
+/*
+ * cleanup() -- release resources
+ */
+
+static void cleanup() {
+    if (Fd >= 0) {
+        /*
+         * Close the test file.
+         *
+         * But first unlink it to discourage some kernel file system
+         * implementations (e.g., HFS on Apple Darwin, aka Mac OS X) from trying
+         * to fill the file's large holes.  (Filling can take a long time.)
+         */
+        if (Path) {
+            (void)unlink(Path);
+            Path = (char *)NULL;
+        }
+        (void)close(Fd);
+        Fd = -1;
+    }
+}
+
+/*
+ * tstwlsof() -- test the open file with lsof
+ */
+
+static int tstwlsof(int tt,      /* test type -- i.e., TST_* */
+                    char *opt,   /* additional lsof options */
+                    OFFSET_T sz) /* expected size (and offset) */
+{
+    char buf[2048], buf1[2048]; /* temporary buffers */
+    LTfldo_t *cmdp;             /* command pointer */
+    LTfldo_t *devp;             /* device pointer */
+    char *em;                   /* error message pointer */
+    int ff = 0;                 /* file found status */
+    LTfldo_t *fop;              /* field output pointer */
+    LTfldo_t *inop;             /* inode number pointer */
+    LTdev_t lsofdc;             /* lsof device components */
+    int nf;                     /* number of fields */
+    LTfldo_t *nmp;              /* file name pointer */
+    LTfldo_t *offp;             /* file offset pointer */
+    char *opv[4];               /* option vector for ExecLsof() */
+    pid_t pid;                  /* PID */
+    int pids = 0;               /* PID found status */
+    STATS sb;                   /* stat(2) buffer */
+    LTdev_t stdc;               /* stat(2) device components */
+    LTfldo_t *szp;              /* file size pointer */
+    LTfldo_t *tfop;             /* temporary field output pointer */
+    int ti;                     /* temporary index */
+    LTfldo_t *typ;              /* file type pointer */
+    int xv = 0;                 /* exit value */
+                                /*
+                                 * Check the test type.
+                                 */
+    switch (tt) {
+    case TST_OFFT:
+    case TST_OFFX:
+    case TST_SZ:
+        break;
+    default:
+        (void)snprintf(buf, sizeof(buf) - 1, "ERROR!!! unknown test type: %d",
+                       tt);
+        buf[sizeof(buf) - 1] = '\0';
+        (void)PrtMsgX(buf, Pn, cleanup, 1);
+    }
+    /*
+     * Get test file's information.
+     */
+    if (STATF(Path, &sb)) {
+        (void)snprintf(buf, sizeof(buf) - 1, "ERROR!!! can't stat(2) %s: %s",
+                       Path, strerror(errno));
+        buf[sizeof(buf) - 1] = '\0';
+        (void)PrtMsgX(buf, Pn, cleanup, 1);
+    }
+    /*
+     * Extract components from test file's device number.
+     */
+    if ((em = ConvStatDev(&sb.st_dev, &stdc))) {
+        (void)PrtMsg(em, Pn);
+        return (0);
+    }
+    /*
+     * Complete the option vector and start lsof execution.
+     */
+    ti = 0;
+    if (opt && *opt)
+        opv[ti++] = opt;
+
+#    if defined(USE_LSOF_C_OPT)
+    opv[ti++] = "-C";
+#    else  /* !defined(USE_LSOF_C_OPT) */
+    opv[ti++] = "--";
+#    endif /* defined(USE_LSOF_C_OPT) */
+
+    opv[ti++] = Path;
+    opv[ti] = (char *)NULL;
+    if ((em = ExecLsof(opv))) {
+        (void)PrtMsg(em, Pn);
+        return (0);
+    }
+    /*
+     * Read lsof output.
+     */
+    while (!ff && (fop = RdFrLsof(&nf, &em))) {
+        switch (fop->ft) {
+        case LSOF_FID_PID:
+
+            /*
+             * This is a process information line.
+             */
+            pid = (pid_t)atoi(fop->v);
+            pids = 1;
+            cmdp = (LTfldo_t *)NULL;
+            for (fop++, ti = 1; ti < nf; fop++, ti++) {
+                switch (fop->ft) {
+                case LSOF_FID_CMD:
+                    cmdp = fop;
+                    break;
+                }
+            }
+            if (!cmdp || (pid != MyPid))
+                pids = 0;
+            break;
+        case LSOF_FID_FD:
+
+            /*
+             * This is a file descriptor line.
+             *
+             * Scan for device number, inode number, name, offset, size, and
+             * type fields.
+             */
+            if (!pids)
+                break;
+            devp = inop = nmp = offp = szp = typ = (LTfldo_t *)NULL;
+            for (fop++, ti = 1; ti < nf; fop++, ti++) {
+                switch (fop->ft) {
+                case LSOF_FID_DEVN:
+                    devp = fop;
+                    break;
+                case LSOF_FID_INODE:
+                    inop = fop;
+                    break;
+                case LSOF_FID_NAME:
+                    nmp = fop;
+                    break;
+                case LSOF_FID_OFFSET:
+                    offp = fop;
+                    break;
+                case LSOF_FID_SIZE:
+                    szp = fop;
+                    break;
+                case LSOF_FID_TYPE:
+                    typ = fop;
+                    break;
+                }
+            }
+            /*
+             * Check the results of the file descriptor field scan.
+             *
+             * (Don't compare path names because of symbolic link interference.)
+             */
+            if (!devp || !inop || !nmp || !typ)
+                break;
+            if (strcasecmp(typ->v, "reg") && strcasecmp(typ->v, "vreg"))
+                break;
+            if (ConvLsofDev(devp->v, &lsofdc))
+                break;
+            if ((stdc.maj != lsofdc.maj) || (stdc.min != lsofdc.min) ||
+                (stdc.unit != lsofdc.unit))
+                break;
+            (void)snprintf(buf, sizeof(buf) - 1, "%llu",
+                           (unsigned long long)sb.st_ino);
+            buf[sizeof(buf) - 1] = '\0';
+            if (strcmp(inop->v, buf))
+                break;
+            /*
+             * The specifed file has been located.  Check its size or offset,
+             * according to the tt argument.
+             */
+            ff = 1;
+            switch (tt) {
+            case TST_OFFT:
+            case TST_SZ:
+
+                /*
+                 * Test the size as an offset in decimal with a leading "0t", or
+                 * test the size as a size in decimal.
+                 */
+                (void)snprintf(buf, sizeof(buf) - 1,
+                               (tt == TST_SZ) ? "%llu" : "0t%llu",
+                               (unsigned long long)sz);
+                buf[sizeof(buf) - 1] = '\0';
+                tfop = (tt == TST_SZ) ? szp : offp;
+                if (!tfop || strcmp(tfop->v, buf)) {
+                    (void)snprintf(buf1, sizeof(buf1) - 1,
+                                   "%s mismatch: expected %s, got %s",
+                                   (tt == TST_SZ) ? "size" : "0t offset", buf,
+                                   tfop ? tfop->v : "nothing");
+                    buf1[sizeof(buf1) - 1] = '\0';
+                    (void)PrtMsg(buf1, Pn);
+                    xv = 0;
+                } else
+                    xv = 1;
+                break;
+            case TST_OFFX:
+
+                /*
+                 * Test the size as an offset in hex.
+                 */
+                (void)snprintf(buf, sizeof(buf) - 1, "0x%llx",
+                               (unsigned long long)sz);
+                buf[sizeof(buf) - 1] = '\0';
+                if (!offp || strcmp(offp->v, buf)) {
+                    (void)snprintf(buf1, sizeof(buf1) - 1,
+                                   "0x offset mismatch: expected %s, got %s",
+                                   buf, offp ? offp->v : "nothing");
+                    buf1[sizeof(buf1) - 1] = '\0';
+                    (void)PrtMsg(buf1, Pn);
+                    xv = 0;
+                } else
+                    xv = 1;
+            }
+            break;
+        }
+    }
+    (void)StopLsof();
+    if (em) {
+
+        /*
+         * RdFrLsof() encountered an error.
+         */
+        (void)PrtMsg(em, Pn);
+        xv = 0;
+    }
+    if (!ff) {
+        (void)snprintf(buf, sizeof(buf) - 1, "%s not found by lsof", Path);
+        buf[sizeof(buf) - 1] = '\0';
+        PrtMsg(buf, Pn);
+        xv = 0;
+    }
+    return (xv);
+}
+#endif     /* defined(LT_BIG) */
diff --git a/tests/LTdnlc.c b/tests/LTdnlc.c
new file mode 100644 (file)
index 0000000..3f1b377
--- /dev/null
@@ -0,0 +1,398 @@
+/*
+ * LTdnlc.c -- Lsof Test Dynamic Name Lookup Cache test
+ *
+ * V. Abell
+ * Purdue University
+ */
+
+/*
+ * Copyright 2002 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by V. 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.
+ */
+
+#include "LsofTest.h"
+#include "lsof_fields.h"
+
+/*
+ * Pre-definitions that may be revoked by specific dialects
+ */
+
+#define DO_TEST /* do the test */
+
+/*
+ * Dialect-specific items
+ */
+
+#if defined(LT_DIAL_aix)
+/*
+ * AIX-specific items
+ */
+
+#    undef DO_TEST
+#endif /* defined(LT_DIAL_aix) */
+
+#if defined(LT_DIAL_darwin)
+/*
+ * Darwin-specific items
+ */
+
+#    if LT_VERS < 800
+#        undef DO_TEST
+#    endif /* LT_VERS<800 */
+#endif     /* defined(LT_DIAL_darwin) */
+
+/*
+ * Local definitions
+ */
+
+#define ATTEMPT_CT 5        /* number of lsof CWD lookup attempts */
+#define LSPATH "/bin/ls"    /* path to ls(1) */
+#define SUCCESS_THRESH 50.0 /* success threshold */
+
+/*
+ * Globals
+ */
+
+pid_t MyPid = (pid_t)0;  /* PID of this process */
+char *Pn = (char *)NULL; /* program name */
+
+/*
+ * Local function prototypes
+ */
+
+static void cleanup(void);
+static char *FindLsofCwd(int *ff, LTdev_t *cwddc, char *ibuf);
+
+/*
+ * Main program
+ */
+
+int main(int argc,     /* argument count */
+         char *argv[]) /* arguments */
+{
+    char buf[2048];                    /* temporary buffer */
+    char cwd[MAXPATHLEN + 1];          /* CWD */
+    LTdev_t cwddc;                     /* CWD device components */
+    char *em;                          /* error message pointer */
+    int ff;                            /* FindFile() file-found flag */
+    int fpathct;                       /* full path found count */
+    char ibuf[32];                     /* inode buffer */
+    char lsbuf[2048 + MAXPATHLEN + 1]; /* ls(1) system() command */
+    double pct;                        /* performance percentage */
+    struct stat sb;                    /* CWD stat(2) results */
+    int ti;                            /* temporary index */
+    int xv = 0;                        /* exit value */
+                                       /*
+                                        * Get program name and PID, issue start message, and build space prefix.
+                                        */
+    if ((Pn = strrchr(argv[0], '/')))
+        Pn++;
+    else
+        Pn = argv[0];
+    MyPid = getpid();
+    (void)printf("%s ... ", Pn);
+    (void)fflush(stdout);
+    PrtMsg((char *)NULL, Pn);
+    /*
+     * Process arguments.
+     */
+    if (ScanArg(argc, argv, "h", Pn))
+        xv = 1;
+    if (xv || LTopt_h) {
+        (void)PrtMsg("usage: [-h] [-p path]", Pn);
+        PrtMsgX("       -h       print help (this panel)", Pn, cleanup, xv);
+    }
+
+#if !defined(DO_TEST)
+    /*
+     * If the dialect has disabled the test, echo that result and exit with
+     * a successful return code.
+     */
+    (void)PrtMsgX(LT_DONT_DO_TEST, Pn, cleanup, 0);
+#endif /* !defined(DO_TEST) */
+
+    /*
+     * See if lsof can be executed and can access kernel memory.
+     */
+    if ((em = IsLsofExec()))
+        (void)PrtMsgX(em, Pn, cleanup, 1);
+    if ((em = CanRdKmem()))
+        (void)PrtMsgX(em, Pn, cleanup, 1);
+        /*
+         * Get the CWD and form the ls(1) system() command.
+         */
+
+#if defined(USE_GETCWD)
+    em = "getcwd";
+    if (!getcwd(cwd, sizeof(cwd)))
+#else  /* ! defined(USE_GETCWD) */
+    em = "getwd";
+    if (!getwd(cwd))
+#endif /* defined(USE_GETCWD) */
+
+    {
+        (void)snprintf(buf, sizeof(buf) - 1, "ERROR!!!  %s() error: %s", em,
+                       strerror(errno));
+        buf[sizeof(buf) - 1] = '\0';
+        (void)PrtMsgX(buf, Pn, cleanup, 1);
+    }
+    (void)snprintf(lsbuf, sizeof(lsbuf) - 1, "%s %s > /dev/null 2>&1", LSPATH,
+                   cwd);
+    /*
+     * Get the CWD stat(2) results.
+     */
+    if (stat(cwd, &sb)) {
+        (void)snprintf(buf, sizeof(buf) - 1, "ERROR!!!  stat(%s) error: %s",
+                       cwd, strerror(errno));
+        buf[sizeof(buf) - 1] = '\0';
+        (void)PrtMsgX(buf, Pn, cleanup, 1);
+    }
+    if ((em = ConvStatDev(&sb.st_dev, &cwddc)))
+        PrtMsgX(em, Pn, cleanup, 1);
+    (void)snprintf(ibuf, sizeof(ibuf) - 1, "%" PRIu64, (uint64_t)sb.st_ino);
+    ibuf[sizeof(ibuf) - 1] = '\0';
+    /*
+     * Loop ATTEMPT_CT times.
+     */
+    for (fpathct = ti = 0; ti < ATTEMPT_CT; ti++) {
+
+        /*
+         * Call ls(1) to list the CWD to /dev/null.
+         */
+        (void)system(lsbuf);
+        /*
+         * Call lsof to look up its own CWD -- i.e., this one.
+         */
+        if ((em = FindLsofCwd(&ff, &cwddc, ibuf))) {
+
+            /*
+             * FindLsofCwd() returned a message.  Decode it via ff.
+             */
+            if (ff == -1)
+                PrtMsgX(em, Pn, cleanup, 1);
+            else if (ff == 1) {
+
+                /*
+                 * This shouldn't happen.  If FindLsof() found lsof's CWD, it
+                 * should set ff to one and return NULL.
+                 */
+                PrtMsgX("ERROR!!!  inconsistent FindLsofCwd() return", Pn,
+                        cleanup, 1);
+            }
+        } else if (ff == 1) {
+            fpathct++;
+        }
+    }
+    /*
+     * Compute, display, and measure the success percentage.
+     */
+    pct = ((double)fpathct * (double)100.0) / (double)ATTEMPT_CT;
+    PrtMsg((char *)NULL, Pn);
+    (void)printf("%s found: %.2f%%\n", cwd, pct); /* NeXT snpf.c has no
+                                                   * %f support */
+    MsgStat = 1;
+    if (pct < (double)SUCCESS_THRESH) {
+        PrtMsg("ERROR!!!  the find rate was too low.", Pn);
+        if (!fpathct) {
+            (void)PrtMsg(
+                "Hint: since the find rate is zero, it may be that this file",
+                Pn);
+            (void)PrtMsg(
+                "system does not fully participate in kernel DNLC processing",
+                Pn);
+            (void)PrtMsg(
+                "-- e.g., NFS file systems often do not, /tmp file systems",
+                Pn);
+            (void)PrtMsg(
+                "sometimes do not, Solaris loopback file systems do not.\n",
+                Pn);
+            (void)PrtMsg(
+                "As a work-around rebuild and test lsof on a file system that",
+                Pn);
+            (void)PrtMsg("fully participates in kernel DNLC processing.\n", Pn);
+            (void)PrtMsg("See 00FAQ and 00TEST for more information.", Pn);
+        }
+        exit(1);
+    }
+    /*
+     * Exit successfully.
+     */
+    (void)PrtMsgX("OK", Pn, cleanup, 0);
+    return (0);
+}
+
+/*
+ * cleanup() -- release resources
+ */
+
+static void cleanup() {}
+
+/*
+ * FindLsofCwd() -- find the lsof CWD
+ */
+
+static char *FindLsofCwd(int *ff,        /* file-found response receptor */
+                         LTdev_t *cwddc, /* CWD device components */
+                         char *ibuf)     /* CWD inode number in ASCII */
+{
+    char *cp;                 /* temporary character pointer */
+    char *cem;                /* current error message pointer */
+    LTfldo_t *cmdp;           /* command pointer */
+    LTdev_t devdc;            /* devp->v device components */
+    LTfldo_t *devp;           /* device pointer */
+    LTfldo_t *fop;            /* field output pointer */
+    LTfldo_t *inop;           /* inode number pointer */
+    int nf;                   /* number of fields */
+    LTfldo_t *nmp;            /* name pointer */
+    char *opv[3];             /* option vector for ExecLsof() */
+    char *pem = (char *)NULL; /* previous error message pointer */
+    pid_t pid;                /* PID */
+    int pids = 0;             /* PID found status */
+    int ti;                   /* temporary integer */
+    LTfldo_t *typ;            /* file type pointer */
+                              /*
+                               * Check the argument pointers.
+                               *
+                               * Set the file-found response false.
+                               */
+    if (!ff || !cwddc || !ibuf)
+        (void)PrtMsgX("ERROR!!!  missing argument to FindFile()", Pn, cleanup,
+                      1);
+    *ff = 0;
+    /*
+     * Complete the option vector and start lsof execution.
+     */
+    opv[0] = "-clsof";
+    opv[1] = "-adcwd";
+    opv[2] = (char *)NULL;
+    if ((cem = ExecLsof(opv))) {
+        *ff = -1;
+        return (cem);
+    }
+    /*
+     * Read lsof output.
+     */
+    while (!*ff && (fop = RdFrLsof(&nf, &cem))) {
+        if (cem) {
+            if (pem)
+                (void)PrtMsg(pem, Pn);
+            *ff = -1;
+            return (cem);
+        }
+        switch (fop->ft) {
+        case LSOF_FID_PID:
+
+            /*
+             * This is a process information line.
+             */
+            pid = (pid_t)atoi(fop->v);
+            pids = 1;
+            cmdp = (LTfldo_t *)NULL;
+            for (fop++, ti = 1; ti < nf; fop++, ti++) {
+                switch (fop->ft) {
+                case LSOF_FID_CMD:
+                    cmdp = fop;
+                    break;
+                }
+            }
+            if (!cmdp || (pid != LsofPid))
+                pids = 0;
+            break;
+        case LSOF_FID_FD:
+
+            /*
+             * This is a file descriptor line.  Make sure it's for the expected
+             * PID and its type is "cwd".
+             */
+            if (!pids)
+                break;
+            if (strcasecmp(fop->v, "cwd"))
+                break;
+            /*
+             * Scan for device, inode, name, and type fields.
+             */
+            devp = inop = nmp = typ = (LTfldo_t *)NULL;
+            for (fop++, ti = 1; ti < nf; fop++, ti++) {
+                switch (fop->ft) {
+                case LSOF_FID_DEVN:
+                    devp = fop;
+                    break;
+                case LSOF_FID_INODE:
+                    inop = fop;
+                    break;
+                case LSOF_FID_NAME:
+                    nmp = fop;
+                    break;
+                case LSOF_FID_TYPE:
+                    typ = fop;
+                    break;
+                }
+            }
+            /*
+             * Check the device, inode, and type of the file.
+             */
+            if (!devp || !inop || !nmp || !typ)
+                break;
+            if (strcasecmp(typ->v, "dir") && strcasecmp(typ->v, "vdir"))
+                break;
+            if ((cem = ConvLsofDev(devp->v, &devdc))) {
+                if (pem)
+                    (void)PrtMsg(pem, Pn);
+                pem = cem;
+                break;
+            }
+            if ((cwddc->maj != devdc.maj) || (cwddc->min != devdc.min) ||
+                (cwddc->unit != devdc.unit) || strcmp(inop->v, ibuf)) {
+                break;
+            }
+            /*
+             * Check the name for spaces.  If it has none, set a file-found
+             * response.
+             */
+            if (!(cp = strchr(nmp->v, ' ')))
+                *ff = 1;
+            else {
+
+                /*
+                 * If a parenthesized file system name follows the space in the
+                 * file's name, it probably is an NFS file system name and can
+                 * be ignored.  Accordingly set a file-found response.
+                 */
+                if ((*(cp + 1) == '(') && *(cp + 2) && !strchr(cp + 2, ' ')) {
+                    if ((cp = strchr(cp + 2, ')')) && !*(cp + 1))
+                        *ff = 1;
+                }
+            }
+        }
+    }
+    /*
+     * Clean up and return.
+     */
+    (void)StopLsof();
+    if (pem) {
+        *ff = -1;
+        return (pem);
+    }
+    return ((char *)NULL);
+}
diff --git a/tests/LTlib.c b/tests/LTlib.c
new file mode 100644 (file)
index 0000000..6cf8fe5
--- /dev/null
@@ -0,0 +1,1053 @@
+/*
+ * LTlib.c -- the lsof test library
+ *
+ * V. Abell
+ * Purdue University
+ */
+
+/*
+ * Copyright 2002 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by V. 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.
+ */
+
+#include "LsofTest.h"
+
+/*
+ * Pre-defintions that may be changed by a specific dialect
+ */
+
+#define X2DEV_T unsigned int /* cast for result of x2dev() */
+#define XDINDEV                                                                \
+    8 /* number of hex digits in an lsof                                       \
+       * device field -- should be                                             \
+       * 2 X sizeof(X2DEV_T) */
+
+#if defined(LT_DIAL_aix)
+/*
+ * AIX-specific items
+ */
+
+#    include <sys/sysmacros.h>
+
+#    if defined(LT_AIXA) && LT_AIXA >= 1
+
+/*
+ * Note: the DEVNO64 and ISDEVNO54 #define's come from <sys/sysmacros.h>, but
+ * only when _KERNEL is #define'd.
+ */
+
+#        undef DEVNO64
+#        define DEVNO64 0x8000000000000000LL
+#        undef ISDEVNO64
+#        define ISDEVNO64(d) (((ulong)(d)&DEVNO64) ? 1 : 0)
+
+/*
+ * Define major and minor extraction macros that work on 64 bit AIX
+ * architectures.
+ */
+
+#        define major_S(d) (ISDEVNO64(d) ? major64(d) : minor(d & ~SDEV_REMOTE))
+#        define minor_S(d)                                                     \
+            (ISDEVNO64(d) ? (minor64(d) & ~SDEV_REMOTE) : minor(d))
+#        undef X2DEV_T
+#        define X2DEV_T unsigned long long
+#        undef XDINDEV
+#        define XDINDEV 16
+#        define major_X(dp, em) major_S(x2dev(dp, em))
+#        define minor_X(dp, em) minor_S(x2dev(dp, em))
+#    endif /* defined(LT_AIXA) && LT_AIXA>=1 */
+
+#endif /* defined(LT_DIAL_aix) */
+
+#if defined(LT_DIAL_bsdi)
+/*
+ * BSDI-specific items
+ */
+
+#    define minor_S(dev) dv_subunit(dev)
+#    define unit_S(dev) dv_unit(dev)
+#    define minor_X(dp, em) dv_subunit(x2dev(dp, em))
+#    define unit_X(dp, em) dv_unit(x2dev(dp, em))
+#endif /* defined(LT_DIAL_bsdi) */
+
+#if defined(LT_DIAL_freebsd)
+/*
+ *FreeBSD-specific items
+ */
+
+#    undef XDINDEV
+#    define XDINDEV 16
+#    if defined(LT_DEV64)
+#        undef X2DEV_T
+#        define X2DEV_T unsigned long long
+#    endif /* defined(LT_DEV64) */
+#endif     /* defined(LT_DIAL_freebsd) */
+
+#if defined(LT_DIAL_osr)
+/*
+ * OpenUNIX-specific items
+ */
+
+#    include <sys/sysmacros.h>
+#endif /* defined(LT_DIAL_osr) */
+
+#if defined(LT_DIAL_ou)
+/*
+ * OpenUNIX-specific items
+ */
+
+#    include <sys/mkdev.h>
+#endif /* defined(LT_DIAL_ou) */
+
+#if defined(LT_DIAL_solaris)
+/*
+ * Solaris-specific items
+ */
+
+#    include <sys/sysmacros.h>
+
+/*
+ * Define maximum major device number in a stat(2) dev_t
+ */
+
+#    if LT_VERS >= 20501
+#        define LT_MJX                                                         \
+            L_MAXMAJ /* Get maximum major device number from                   \
+                      * <sys/sysmacros.h>. */
+#    else            /* LT_VERS<20501 */
+#        define LT_MJX                                                         \
+            0x3fff /* Avoid <sys/sysmacros.h> when                             \
+                    * Solaris < 2.5.1. */
+#    endif         /* LT_VERS>=20501 */
+
+#    define major_S(dev) ((int)((dev >> L_BITSMINOR) & LT_MJX))
+#    define minor_S(dev) ((int)(dev & L_MAXMIN))
+
+#    if defined(LT_DEV64)
+
+#        undef X2DEV_T
+#        define X2DEV_T unsigned long long
+#        undef XDINDEV
+#        define XDINDEV 16
+#    endif /* !defined(LT_DEV64) */
+
+#    define major_X(dp, em) (major_S(x2dev(dp, em)))
+#    define minor_X(dp, em) (minor_S(x2dev(dp, em)))
+
+#endif /* defined(LT_DIAL_solaris) */
+
+#if defined(LT_DIAL_uw)
+/*
+ * UnixWare-specific items
+ */
+
+#    include <sys/mkdev.h>
+#endif /* defined(LT_DIAL_uw) */
+
+#if defined(LT_DIAL_linux)
+/*
+ * Linux-specific items
+ */
+
+#    include <sys/sysmacros.h>
+#endif /* defined(LT_DIAL_linux) */
+
+/*
+ * Global variables
+ */
+
+int LsofFd = -1;               /* lsof pipe FD */
+FILE *LsofFs = (FILE *)NULL;   /* stream for lsof pipe FD */
+char *LsofPath = (char *)NULL; /* path to lsof executable */
+pid_t LsofPid = (pid_t)0;      /* PID of lsof child process */
+int LTopt_h = 0;               /* "-h" option's switch value */
+char *LTopt_p = (char *)NULL;  /* "-p path" option's path value */
+int MsgStat = 0;               /* message status: 1 means prefix needs
+                                * to be issued */
+
+/*
+ * Local static variables
+ */
+
+static int Afo = 0;                     /* Fo[] structures allocated */
+static char *GOv = (char *)NULL;        /* option `:' value pointer */
+static int GOx1 = 1;                    /* first opt[][] index */
+static int GOx2 = 0;                    /* second opt[][] index */
+static LTfldo_t *Fo = (LTfldo_t *)NULL; /* allocated LTfldo_t structures */
+static int Ufo = 0;                     /* Fo[] structures used */
+
+/*
+ * Local function prototypes
+ */
+
+static void closepipe(void);
+static void getlsofpath(void);
+static int GetOpt(int ct, char *opt[], char *rules, char **em, char *pn);
+static X2DEV_T x2dev(char *x, char **em);
+
+/*
+ * Default major, minor, and unit macros.
+ */
+
+#if !defined(major_S)
+#    define major_S major
+#endif /* defined(major_S) */
+
+#if !defined(minor_S)
+#    define minor_S minor
+#endif /* defined(minor_S) */
+
+#if !defined(unit_S)
+#    define unit_S(x) 0
+#endif /* defined(unit_S) */
+
+#if !defined(major_X)
+#    define major_X(dp, em) major(x2dev(dp, em))
+#endif /* defined(major_X) */
+
+#if !defined(minor_X)
+#    define minor_X(dp, em) minor(x2dev(dp, em))
+#endif /* defined(minor_X) */
+
+#if !defined(unit_X)
+#    define unit_X(dp, em) 0
+#endif /* defined(unit_X) */
+
+/*
+ * CanRdKmem() -- can lsof read kernel memory devices?
+ */
+
+char *CanRdKmem() {
+
+#if defined(LT_KMEM)
+    char buf[2048]; /* temporary buffer */
+    char *dn;       /* memory device name */
+    char *em;       /* error message pointer */
+    int fd;         /* temporary file descriptor */
+    struct stat sb; /* memory device stat(2) buffer */
+    int ti;         /* temporary integer */
+                    /*
+                     * Get the lsof path.  If it is not the default, check no further.
+                     */
+    (void)getlsofpath();
+    if (!strcmp(LsofPath, LT_DEF_LSOF_PATH))
+        return ((char *)NULL);
+    /*
+     * Check /dev/kmem access.
+     */
+    dn = "/dev/kmem";
+    if (stat(dn, &sb)) {
+        em = "stat";
+
+    kmem_error:
+
+        (void)snprintf(buf, sizeof(buf) - 1, "ERROR!!!  can't %s(%s): %s\n", em,
+                       dn, strerror(errno));
+        buf[sizeof(buf) - 1] = '\0';
+        return (MkStrCpy(buf, &ti));
+    }
+    if ((fd = open(dn, O_RDONLY, 0)) < 0) {
+        em = "open";
+        goto kmem_error;
+    }
+    (void)close(fd);
+    /*
+     * Check /dev/mem access.
+     */
+    dn = "/dev/mem";
+    if (stat(dn, &sb)) {
+
+        /*
+         * If /dev/mem can't be found, ignore the error.
+         */
+        return ((char *)NULL);
+    }
+    if ((fd = open(dn, O_RDONLY, 0)) < 0) {
+        em = "open";
+        goto kmem_error;
+    }
+    (void)close(fd);
+#endif /* defined(LT_KMEM) */
+
+    return ((char *)NULL);
+}
+
+/*
+ * closepipe() -- close pipe from lsof
+ */
+
+static void closepipe() {
+    if (LsofFd >= 0) {
+
+        /*
+         * A pipe from lsof is open.  Close it and the associated stream.
+         */
+        if (LsofFs) {
+            (void)fclose(LsofFs);
+            LsofFs = (FILE *)NULL;
+        }
+        (void)close(LsofFd);
+        LsofFd = -1;
+    }
+}
+
+/*
+ * ConvLsofDev() -- convert lsof device string
+ *
+ * Note: this function is dialect-specific.
+ */
+
+char *ConvLsofDev(char *dev,     /* lsof device string -- the value to the
+                                  * LSOF_FID_DEVN field of a LSOF_FID_FD block
+                                  * (see lsof_fields.h) */
+                  LTdev_t *ldev) /* results are returned to this structure */
+{
+    char *dp; /* device pointer */
+    char *em; /* error message pointer */
+    int tlen; /* temporary length */
+              /*
+               * Check function arguments.
+               *
+               * Establish values for decoding the device string.
+               */
+    if (!dev)
+        return ("ERROR!!!  no ConvLsofDev() device");
+    if (!ldev)
+        return ("ERROR!!!  no ConvLsofDev() result pointer");
+    if (strncmp(dev, "0x", 2))
+        return ("ERROR!!!  no leading 0x in ConvLsofDev() device");
+    dp = dev + 2;
+    if (((tlen = (int)strlen(dp)) < 1) || (tlen > XDINDEV))
+        return ("ERROR!!!  bad ConvLsofDev() device length");
+    /*
+     * Use the pre-defined *_X() macros to do the decomposition.
+     */
+    ldev->maj = (unsigned int)major_X(dp, &em);
+    if (em)
+        return (em);
+    ldev->min = (unsigned int)minor_X(dp, &em);
+    if (em)
+        return (em);
+    ldev->unit = (unsigned int)unit_X(dp, &em);
+    return (em);
+}
+
+/*
+ * ConvStatDev() -- convert stat(2) device number
+ *
+ * Note: this function is dialect-specific.
+ */
+
+char *ConvStatDev(dev_t *dev,    /* device number to be converted */
+                  LTdev_t *ldev) /* results are returned to this structure */
+{
+
+    /*
+     * Check function arguments.
+     */
+    if (!dev)
+        return ("ERROR!!!  no ConvStatDev() device");
+    if (!ldev)
+        return ("ERROR!!!  no ConvStatDev() result pointer");
+    /*
+     * Use the pre-defined *_S() macros to do the decomposition.
+     */
+    ldev->maj = (unsigned int)major_S(*dev);
+    ldev->min = (unsigned int)minor_S(*dev);
+    ldev->unit = (unsigned int)unit_S(*dev);
+    return ((char *)NULL);
+}
+
+/*
+ * ExecLsof() -- execute lsof with full field output and a NUL field terminator
+ *              in a child process
+ */
+
+char *ExecLsof(char **opt) /* lsof options -- a pointer to an
+                            * array of character pointers,
+                            * terminated by a NULL pointer */
+{
+    static char **av = (char **)NULL; /* lsof argument vector, dynamically
+                                       * allocated */
+    static int ava = 0;               /* **av entries allocated */
+    char buf[2048];                   /* temporary buffer */
+    char *em;                         /* error message pointer */
+    int fd;                           /* temporary file descriptor */
+    int optc;                         /* option count */
+    int nf;                           /* number of files */
+    int p[2];                         /* pipe FDs */
+    char **tcpp;                      /* temporary character pointer
+                                       * pointer */
+    int ti;                           /* temporary integer */
+    int tlen;                         /* temporary length */
+    pid_t tpid;                       /* temporary PID holder */
+                                      /*
+                                       * It's an error if lsof is already in execution or if no lsof options
+                                       * were supplied.
+                                       */
+    (void)getlsofpath();
+    if (LsofPid)
+        return ("ERROR!!!  ExecLsof() says lsof is already in execution");
+    if (!opt)
+        return ("ERROR!!!  no ExecLsof() option list");
+    for (optc = 0, tcpp = opt; *tcpp; optc++, tcpp++)
+        ;
+    /*
+     * Make sure lsof is executable.
+     */
+    if ((em = IsLsofExec()))
+        return (em);
+    /*
+     * Open a pipe through which lsof can return output.
+     */
+    if (pipe(p)) {
+        (void)snprintf(buf, sizeof(buf) - 1, "ERROR!!!  can't open pipe: %s",
+                       strerror(errno));
+        return (MkStrCpy(buf, &ti));
+    }
+    /*
+     * Allocate and build an argument vector.  The first entry will be set
+     * to "lsof", the second to "-wFr", and the third to "-F0".  Additional
+     * entries will be set as supplied by the caller.
+     */
+    if ((optc + 4) > ava) {
+        tlen = (int)(sizeof(char *) * (optc + 4));
+        if (!av)
+            av = (char **)malloc(tlen);
+        else
+            av = (char **)realloc((void *)av, tlen);
+        if (!av) {
+            (void)snprintf(
+                buf, sizeof(buf) - 1,
+                "LTlib: ExecLsof() can't allocat pointers for %d arguments",
+                optc + 4);
+            return (MkStrCpy(buf, &ti));
+        }
+        ava = optc + 4;
+    }
+    for (ti = 0, tcpp = opt; ti < (optc + 3); ti++) {
+        switch (ti) {
+        case 0:
+            av[ti] = "lsof";
+            break;
+        case 1:
+            av[ti] = "-wFr";
+            break;
+        case 2:
+            av[ti] = "-F0";
+            break;
+        default:
+            av[ti] = *tcpp;
+            tcpp++;
+        }
+    }
+    av[ti] = (char *)NULL;
+    /*
+     * Fork a child process to run lsof.
+     */
+    switch ((tpid = fork())) {
+    case (pid_t)0:
+
+        /*
+         * This is the child process.
+         *
+         * First close all file descriptors except the output side of the pipe.
+         *
+         * Make the output side of the pipe STDOUT and STDERR.
+         */
+        for (fd = 0, nf = getdtablesize(); fd < nf; fd++) {
+            if (fd == p[1])
+                continue;
+            (void)close(fd);
+        }
+        if (p[1] != 1)
+            (void)dup2(p[1], 1);
+        if (p[1] != 2)
+            (void)dup2(p[1], 2);
+        if ((p[1] != 1) && (p[1] != 2))
+            (void)close(p[1]);
+        /*
+         * Execute lsof.
+         */
+        (void)execv(LsofPath, av);
+        _exit(0); /* (Shouldn't get here.) */
+    case (pid_t)-1:
+
+        /*
+         * A fork error occurred.  Form and return a message.
+         */
+        (void)snprintf(buf, sizeof(buf) - 1,
+                       "ERROR!!!  ExecLsof() can't fork: %s", strerror(errno));
+        buf[sizeof(buf) - 1] = '\0';
+        return (MkStrCpy(buf, &ti));
+    default:
+
+        /*
+         * This is the parent.
+         *
+         * Save the lsof child PID.
+         *
+         * Close the output side of the pipe.
+         *
+         * Save the input side of the pipe as LsofFd; open a stream for it.
+         */
+        LsofPid = tpid;
+        (void)close(p[1]);
+        LsofFd = p[0];
+        if (!(LsofFs = fdopen(LsofFd, "r")))
+            return ("ERROR!!!  ExecLsof() can't open stream to lsof output FD");
+    }
+    /*
+     * Wait a bit for lsof to start and put something in its pipe, then return
+     * an "All is well." response.
+     */
+    sleep(1);
+    return ((char *)NULL);
+}
+
+/*
+ * getlsofpath() -- get lsof path, either from LT_LSOF_PATH in the environment
+ *                 or from LT_DEF_LSOF_PATH
+ */
+
+static void getlsofpath() {
+    char *tcp; /* temporary character pointer */
+    int ti;    /* temporary integer */
+
+    if (LsofPath)
+        return;
+    if ((tcp = getenv("LT_LSOF_PATH")))
+        LsofPath = MkStrCpy(tcp, &ti);
+    else
+        LsofPath = LT_DEF_LSOF_PATH;
+}
+
+/*
+ * GetOpt() -- Local get option
+ *
+ * Borrowed from lsof's main.c source file.
+ *
+ * Liberally adapted from the public domain AT&T getopt() source,
+ * distributed at the 1985 UNIFORM conference in Dallas
+ *
+ * The modifications allow `?' to be an option character and allow
+ * the caller to decide that an option that may be followed by a
+ * value doesn't have one -- e.g., has a default instead.
+ */
+
+static int GetOpt(int ct,      /* option count */
+                  char *opt[], /* options */
+                  char *rules, /* option rules */
+                  char **em,   /* error message return */
+                  char *pn) {
+    register int c;                   /* character value */
+    register char *cp = (char *)NULL; /* character pointer */
+    char embf[2048];                  /* error message buffer */
+    int tlen;                         /* temporary message length from
+                                       * MkStrCpy() */
+
+    *em = (char *)NULL;
+    if (GOx2 == 0) {
+
+        /*
+         * Move to a new entry of the option array.
+         *
+         * EOF if:
+         *
+         *     Option list has been exhausted;
+         *     Next option doesn't start with `-' or `+';
+         *     Next option has nothing but `-' or `+';
+         *     Next option is ``--'' or ``++''.
+         */
+        if (GOx1 >= ct || (opt[GOx1][0] != '-' && opt[GOx1][0] != '+') ||
+            !opt[GOx1][1])
+            return (EOF);
+        if (strcmp(opt[GOx1], "--") == 0 || strcmp(opt[GOx1], "++") == 0) {
+            GOx1++;
+            return (EOF);
+        }
+        GOx2 = 1;
+    }
+    /*
+     * Flag `:' option character as an error.
+     *
+     * Check for a rule on this option character.
+     */
+    if ((c = opt[GOx1][GOx2]) == ':') {
+        (void)snprintf(embf, sizeof(embf) - 1,
+                       "ERROR!!!  colon is an illegal option character.");
+        embf[sizeof(embf) - 1] = '\0';
+        *em = MkStrCpy(embf, &tlen);
+    } else if (!(cp = strchr(rules, c))) {
+        (void)snprintf(embf, sizeof(embf) - 1,
+                       "ERROR!!!  illegal option character: %c", c);
+        embf[sizeof(embf) - 1] = '\0';
+        *em = MkStrCpy(embf, &tlen);
+    }
+    if (*em) {
+
+        /*
+         * An error was detected.
+         *
+         * Advance to the next option character.
+         *
+         * Return the character causing the error.
+         */
+        if (opt[GOx1][++GOx2] == '\0') {
+            GOx1++;
+            GOx2 = 0;
+        }
+        return (c);
+    }
+    if (*(cp + 1) == ':') {
+
+        /*
+         * The option may have a following value.  The caller decides if it
+         * does.
+         *
+         * Don't indicate that an option of ``--'' is a possible value.
+         *
+         * Finally, on the assumption that the caller will decide that the
+         * possible value belongs to the option, position to the option
+         * following the possible value, so that the next call to GetOpt() will
+         * find it.
+         */
+        if (opt[GOx1][GOx2 + 1] != '\0') {
+            GOv = &opt[GOx1++][GOx2];
+        } else if (++GOx1 >= ct)
+            GOv = (char *)NULL;
+        else {
+            GOv = opt[GOx1];
+            if (strcmp(GOv, "--") == 0)
+                GOv = (char *)NULL;
+            else
+                GOx1++;
+        }
+        GOx2 = 0;
+    } else {
+
+        /*
+         * The option character stands alone with no following value.
+         *
+         * Advance to the next option character.
+         */
+        if (opt[GOx1][++GOx2] == '\0') {
+            GOx2 = 0;
+            GOx1++;
+        }
+        GOv = (char *)NULL;
+    }
+    /*
+     * Return the option character.
+     */
+    return (c);
+}
+
+/*
+ * IsLsofExec() -- see if lsof is executable
+ */
+
+char *IsLsofExec() {
+    char buf[2048]; /* temporary buffer */
+    int len;        /* temporary length */
+
+    (void)getlsofpath();
+    if (access(LsofPath, X_OK) < 0) {
+        (void)snprintf(buf, sizeof(buf) - 1, "ERROR!!!  can't execute %s: %s",
+                       LsofPath, strerror(errno));
+        return (MkStrCpy(buf, &len));
+    }
+    return ((char *)NULL);
+}
+
+/*
+ * LTlibClean() -- clean up LTlib resource accesses
+ */
+
+void LTlibClean() { (void)StopLsof(); }
+
+/*
+ * MkStrCpy() -- make string copy
+ */
+
+char *MkStrCpy(char *src, /* string source to copy */
+               int *len)  /* returned length allocation */
+{
+    char *rp;   /* return pointer */
+    int srclen; /* source string length */
+
+    if (!src) {
+        (void)fprintf(stderr, "ERROR!!!  no string supplied to MkStrCpy()\n");
+        exit(1);
+    }
+    srclen = (int)strlen(src);
+    *len = srclen++;
+    if (!(rp = (char *)malloc(srclen))) {
+        (void)fprintf(stderr, "ERROR!!!  MkStrCpy() -- no malloc() space");
+        exit(1);
+    }
+    (void)strcpy(rp, src);
+    return (rp);
+}
+
+/*
+ * PrtMsg() -- print message
+ */
+
+void PrtMsg(mp, pn) char *mp; /* message pointer -- may be NULL to
+                               * trigger space prefix initialization
+                               */
+char *pn;                     /* program name */
+{
+    static int pfxlen = -1;          /* prefix length, based on program */
+                                     /* name -- computed on first call
+                                      * when pfxlen == -1 */
+    static char *pfx = (char *)NULL; /* prefix (spaces) */
+    int ti;                          /* temporary index */
+
+    if (pfxlen == -1) {
+
+        /*
+         * This is the first call.  Compute the prefix length and build the
+         * prefix.
+         */
+        if (!pn)
+            pfxlen = 0;
+        else
+            pfxlen = (int)(strlen(pn));
+        pfxlen += (int)strlen(" ... ");
+        if (!(pfx = (char *)malloc(pfxlen + 1))) {
+            (void)printf("ERROR!!!  not enough space for %d space prefix\n",
+                         pfxlen);
+            exit(1);
+        }
+        for (ti = 0; ti < pfxlen; ti++) {
+            pfx[ti] = ' ';
+        }
+        pfx[pfxlen] = '\0';
+        MsgStat = 0;
+    }
+    /*
+     * Process the message.
+     */
+    if (MsgStat)
+        (void)printf("%s", pfx);
+    if (mp && *mp) {
+        (void)printf("%s\n", mp);
+        MsgStat = 1;
+    }
+}
+
+/*
+ * PrtMsgX() -- print message and exit
+ */
+
+void PrtMsgX(mp, pn, f, xv) char *mp; /* message pointer */
+char *pn;                             /* program name */
+void (*f)();                          /* clean-up function pointer */
+int xv;                               /* exit value */
+{
+    if (mp)
+        PrtMsg(mp, pn);
+    if (f)
+        (void)(*f)();
+    (void)LTlibClean();
+    exit(xv);
+}
+
+/*
+ * RdFrLsof() -- read from lsof
+ */
+
+LTfldo_t *RdFrLsof(int *nf,   /* number of fields receiver */
+                   char **em) /* error message pointer receiver */
+{
+    char buf[2048];              /* temporary buffer */
+    int bufl = (int)sizeof(buf); /* size of buf[] */
+    char *blim = &buf[bufl - 1]; /* buf[] limit (last character
+                                  * address) */
+    char *fsp;                   /* field start pointer */
+    char *tcp;                   /* temporary character pointer */
+    LTfldo_t *tfop;              /* temporary field output pointer */
+    int ti;                      /* temporary index */
+    int tlen;                    /* remporary length */
+    char *vp;                    /* value character pointer */
+                                 /*
+                                  * Check for errors.
+                                  */
+    if (!em)
+        return ((LTfldo_t *)NULL);
+    if (!nf) {
+        *em = "ERROR!!!  RdFrLsof() not given a count return pointer";
+        return ((LTfldo_t *)NULL);
+    }
+    *em = (char *)NULL;
+    *nf = 0;
+    /*
+     * If fields are in use, release their resources.
+     */
+    for (ti = 0, tfop = Fo; (ti < Ufo); ti++, tfop++) {
+        if (tfop->v)
+            (void)free((void *)tfop->v);
+    }
+    Ufo = 0;
+    /*
+     * Read a line from lsof.
+     */
+    if (!fgets(buf, bufl - 2, LsofFs)) {
+
+        /*
+         * An lsof pipe EOF has been reached.  Indicate that with a NULL
+         * pointer return, coupled with a NULL error message return pointer
+         * (set above), and a field count of zero (set above).
+         */
+        return ((LTfldo_t *)NULL);
+    }
+    /*
+     * Parse the lsof line, allocating field output structures as appropriate.
+     *
+     * It is expected that fields will end in a NUL ('\0') or a NL ('\0') and
+     * that a NL ends all fields in the lsof line.
+     */
+    for (tcp = buf, Ufo = 0; (*tcp != '\n') && (tcp < blim); tcp++) {
+
+        /*
+         * Start a new field.  The first character is the LSOF_FID_*.
+         *
+         * First allocate an LTfldo_t structure.
+         */
+        if (Ufo >= Afo) {
+
+            /*
+             * More LTfldo_t space is required.
+             */
+            Afo += LT_FLDO_ALLOC;
+            tlen = (int)(Afo * sizeof(LTfldo_t));
+            if (Fo)
+                Fo = (LTfldo_t *)realloc(Fo, tlen);
+            else
+                Fo = (LTfldo_t *)malloc(tlen);
+            if (!Fo) {
+
+                /*
+                 * A serious error has occurred; no LTfldo_t space is available.
+                 */
+                (void)snprintf(
+                    buf, bufl,
+                    "ERROR!!!  RdFrLsof() can't allocate %d pointer bytes",
+                    tlen);
+                *em = MkStrCpy(buf, &ti);
+                *nf = -1;
+                return ((LTfldo_t *)NULL);
+            }
+        }
+        tfop = Fo + Ufo;
+        tfop->v = (char *)NULL;
+        Ufo++;
+        /*
+         * Save the LSOF_FID_* character.  Then compute the field value length,
+         * and make a copy of it.
+         */
+        tfop->ft = *tcp++;
+        fsp = tcp;
+        tlen = 0;
+        while (*tcp && (*tcp != '\n') && (tcp < blim)) {
+            tcp++;
+            tlen++;
+        }
+        if (!(vp = (char *)malloc(tlen + 1))) {
+
+            /*
+             * A serious error has occurred; there's no space for the field
+             * value.
+             */
+            (void)snprintf(buf, bufl,
+                           "ERROR!!!  RdFrLsof() can't allocate %d field bytes",
+                           tlen + 1);
+            *em = MkStrCpy(buf, &ti);
+            *nf = -1;
+            return ((LTfldo_t *)NULL);
+        }
+        (void)memcpy((void *)vp, (void *)fsp, tlen);
+        vp[tlen] = '\0';
+        tfop->v = vp;
+        if (*tcp == '\n')
+            break;
+        if (tcp >= blim) {
+
+            /*
+             * The lsof line has no NL terminator; that's an error.
+             */
+            *em = "ERROR!!! RdFrLsof() didn't find a NL";
+            *nf = -1;
+            return ((LTfldo_t *)NULL);
+        }
+    }
+    /*
+     * The end of the lsof line has been reached.  If no fields were assembled,
+     * return an error indicate.  Otherwise return the fields and their count.
+     */
+    if (!Ufo) {
+        *em = "ERROR!!! RdFrLsof() read an empty lsof line";
+        *nf = -1;
+        return ((LTfldo_t *)NULL);
+    }
+    *nf = Ufo;
+    *em = (char *)NULL;
+    return (Fo);
+}
+
+/*
+ * ScanArg() -- scan arguments
+ */
+
+int ScanArg(int ac,     /* argument count */
+            char *av[], /* argument pointers */
+            char *opt,  /* option string */
+            char *pn)   /* program name */
+{
+    char *em;        /* pointer to error message returned by
+                      * GetOpt() */
+    char embf[2048]; /* error message buffer */
+    int rv = 0;      /* return value */
+    int tc;          /* temporary character value */
+                     /*
+                      * Preset possible argument values.
+                      */
+    LTopt_h = 0;
+    if (LTopt_p) {
+        (void)free((void *)LTopt_p);
+        LTopt_p = (char *)NULL;
+    }
+    /*
+     * Process the options according to the supplied option string.
+     */
+    while ((tc = GetOpt(ac, av, opt, &em, pn)) != EOF) {
+        if (em) {
+            rv = 1;
+            PrtMsg(em, pn);
+            continue;
+        }
+        switch (tc) {
+        case 'h':
+            LTopt_h = 1;
+            break;
+        case 'p':
+            if (!GOv || *GOv == '-' || *GOv == '+') {
+                rv = 1;
+                (void)PrtMsg("ERROR!!!  -p not followed by a path", pn);
+            } else
+                LTopt_p = GOv;
+            break;
+        default:
+            rv = 1;
+            (void)snprintf(embf, sizeof(embf) - 1,
+                           "ERROR!!!  unknown option: %c", tc);
+            PrtMsg(embf, pn);
+        }
+    }
+    for (; GOx1 < ac; GOx1++) {
+
+        /*
+         * Report extraneous arguments.
+         */
+        rv = 1;
+        (void)snprintf(embf, sizeof(embf) - 1,
+                       "ERROR!!!  extraneous option: \"%s\"", av[GOx1]);
+        PrtMsg(embf, pn);
+    }
+    return (rv);
+}
+
+/*
+ * StopLsof() -- stop a running lsof process and close the pipe from it
+ */
+
+void StopLsof() {
+    pid_t pid;
+
+    if (LsofPid) {
+
+        /*
+         * An lsof child process may be active.  Wait for (or kill) it.
+         */
+        pid = wait3(NULL, WNOHANG, NULL);
+        if (pid != LsofPid) {
+            (void)kill(LsofPid, SIGKILL);
+            sleep(2);
+            pid = wait3(NULL, WNOHANG, NULL);
+        }
+        LsofPid = (pid_t)0;
+    }
+    (void)closepipe();
+}
+
+/*
+ * x2dev() -- convert hex string to device number
+ */
+
+static X2DEV_T x2dev(char *x,   /* hex string */
+                     char **em) /* error message receiver */
+{
+    char buf[2048]; /* temporary message buffer */
+    int c;          /* character holder */
+    X2DEV_T dev;    /* device number result */
+    char *wx;       /* working hex string pointer */
+    int xl;         /* hex string length */
+
+    if (!x || !*x) {
+        *em = "ERROR!!!  no hex string supplied to x2dev()";
+        return (0);
+    }
+    wx = strncasecmp(x, "0x", 2) ? x : (x + 2);
+    if (((xl = (int)strlen(wx)) < 1) || (xl > XDINDEV)) {
+        (void)snprintf(buf, sizeof(buf) - 1,
+                       "ERROR!!!  x2dev(\"%s\") bad length: %d", x, xl + 2);
+        buf[sizeof(buf) - 1] = '\0';
+        *em = MkStrCpy(buf, &c);
+        return (0);
+    }
+    /*
+     * Assemble the device number result from the hex string.
+     */
+    for (dev = (X2DEV_T)0; *wx; wx++) {
+        if (isdigit((unsigned char)*wx)) {
+            dev = (dev << 4) | (unsigned int)(((int)*wx - (int)'0') & 0xf);
+            continue;
+        }
+        c = (int)tolower((unsigned char)*wx);
+        if ((c >= (int)'a') && (c <= (int)'f')) {
+            dev = (dev << 4) | (unsigned int)((c - 'a' + 10) & 0xf);
+            continue;
+        }
+        (void)snprintf(buf, sizeof(buf) - 1,
+                       "ERROR!!!  x2dev(\"%s\") non-hex character: %c", x, c);
+        *em = MkStrCpy(buf, &c);
+    }
+    /*
+     * Return result and no error indication.
+     */
+    *em = (char *)NULL;
+    return (dev);
+}
diff --git a/tests/LTlock.c b/tests/LTlock.c
new file mode 100644 (file)
index 0000000..60aa0f3
--- /dev/null
@@ -0,0 +1,739 @@
+/*
+ * LTlock.c -- Lsof Test locking tests
+ *
+ * V. Abell
+ * Purdue University
+ */
+
+/*
+ * Copyright 2002 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by V. 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.
+ */
+
+#include "LsofTest.h"
+#include "lsof_fields.h"
+
+#if defined(LT_DIAL_aix)
+/*
+ * AIX-specific items
+ */
+
+#    define USE_FCNTL
+#endif /* defined(LT_DIAL_aix) */
+
+#if defined(LT_DIAL_bsdi)
+/*
+ * BSDI-specific items
+ */
+
+#    define USE_FCNTL
+#endif /* defined(LT_DIAL_bsdi) */
+
+#if defined(LT_DIAL_darwin)
+/*
+ * Darwin-specific items
+ */
+
+/*
+ * There is no Darwin USE_* definition, because lock support in lsof for
+ * Darwin is inadequate for this test.
+ */
+#endif /* defined(LT_DIAL_darwin) */
+
+#if defined(LT_DIAL_du)
+/*
+ * DEC_OSF/1|Digital_UNIX|Tru64_UNIX-specific items
+ */
+
+#    define USE_FCNTL
+#endif /* defined(LT_DIAL_du) */
+
+#if defined(LT_DIAL_freebsd)
+/*
+ * FreeBSD-specific items
+ */
+
+#    define USE_FCNTL
+#endif /* defined(LT_DIAL_freebsd) */
+
+#if defined(LT_DIAL_linux)
+/*
+ * Linux-specific items
+ */
+
+#    define USE_FCNTL
+#endif /* defined(LT_DIAL_linux) */
+
+#if defined(LT_DIAL_netbsd)
+/*
+ * NetBSD-specific items
+ */
+
+#    define USE_FCNTL
+#endif /* defined(LT_DIAL_netbsd) */
+
+#if defined(LT_DIAL_openbsd)
+/*
+ * OpenBSD-specific items
+ */
+
+#    define USE_FCNTL
+#endif /* defined(LT_DIAL_openbsd) */
+
+#if defined(LT_DIAL_hpux)
+/*
+ * HP-UX-specific items
+ */
+
+#    define USE_FCNTL
+#endif /* defined(LT_DIAL_hpux) */
+
+#if defined(LT_DIAL_ns)
+/*
+ * NEXTSTEP-specific items
+ */
+
+#    define USE_FLOCK
+#endif /* defined(LT_DIAL_ns) */
+
+#if defined(LT_DIAL_osr)
+/*
+ * OSR-specific items
+ */
+
+#    define USE_FCNTL
+#endif /* defined(LT_DIAL_osr) */
+
+#if defined(LT_DIAL_ou)
+/*
+ * OpenUNIX-specific items
+ */
+
+#    define USE_FCNTL
+#endif /* defined(LT_DIAL_ou) */
+
+#if defined(LT_DIAL_openbsd)
+/*
+ * OpenBSD-specific items
+ */
+
+#    define USE_FCNTL
+#endif /* defined(LT_DIAL_openbsd) */
+
+#if defined(LT_DIAL_solaris)
+/*
+ * Solaris-specific items
+ */
+
+#    define USE_FCNTL
+#endif /* defined(solaris) */
+
+#if defined(LT_DIAL_uw)
+/*
+ * UnixWare-specific items
+ */
+
+#    define USE_FCNTL
+#endif /* defined(LT_DIAL_uw) */
+
+#if !defined(USE_FLOCK) && !defined(USE_FCNTL)
+/*
+ * Here begins the version of this program for dialects that don't support
+ * flock() or fcntl() locking.
+ */
+
+/*
+ * Main program for dialects that don't support flock() of fcntl() locking.
+ */
+
+int main(int argc,     /* argument count */
+         char *argv[]) /* arguments */
+{
+    char *pn; /* program name */
+              /*
+               * Get program name and issue error message.
+               */
+    if ((pn = (char *)strrchr(argv[0], '/')))
+        pn++;
+    else
+        pn = argv[0];
+    (void)printf("%s ... %s\n", pn, LT_DONT_DO_TEST);
+    return (0);
+}
+#else /* defined(USE_FLOCK) || defined(USE_FCNTL) */
+
+/*
+ * Local definitions
+ */
+
+#    define FULL_EX_LOCK 0 /* get a full file exclusive lock */
+#    define FULL_SH_LOCK 1 /* get a full file shared lock */
+#    define PART_EX_LOCK 2 /* get a partial file exclusive lock */
+#    define PART_SH_LOCK 3 /* get a partial file shared lock */
+
+/*
+ * Globals
+ */
+
+int Fd = -1;               /* test file descriptor; open if >= 0 */
+pid_t MyPid = (pid_t)0;    /* PID of this process */
+char *Path = (char *)NULL; /* test file path; none if NULL */
+char *Pn = (char *)NULL;   /* program name */
+
+/*
+ * Local function prototypes
+ */
+
+static void cleanup(void);
+static char *lkfile(int ty);
+static char *tstwlsof(char *opt, char *xlk);
+static char *unlkfile(int ty);
+
+/*
+ * Main program for dialects that support locking tests.
+ */
+
+int main(int argc,     /* argument count */
+         char *argv[]) /* arguments */
+{
+    char buf[2048];            /* temporary buffer */
+    char *em;                  /* error message pointer */
+    int ti;                    /* temporary index */
+    char *tcp;                 /* temporary character pointer */
+    int tlen;                  /* temporary length -- e.g., as
+                                * returned by MkStrCpy() */
+    char *tstR = (char *)NULL; /* "R" lock test result */
+    char *tstr = (char *)NULL; /* "r" lock test result */
+    char *tstW = (char *)NULL; /* "W" lock test result */
+    char *tstw = (char *)NULL; /* "w" lock test result */
+    int xv = 0;                /* exit value */
+                               /*
+                                * Get program name and PID, issue start message, and build space prefix.
+                                */
+    if ((Pn = strrchr(argv[0], '/')))
+        Pn++;
+    else
+        Pn = argv[0];
+    MyPid = getpid();
+    (void)printf("%s ... ", Pn);
+    (void)fflush(stdout);
+    (void)PrtMsg((char *)NULL, Pn);
+    /*
+     * Process arguments.
+     */
+    if (ScanArg(argc, argv, "hp:", Pn))
+        xv = 1;
+    if (xv || LTopt_h) {
+        (void)PrtMsg("usage: [-h] [-p path]", Pn);
+        (void)PrtMsg("       -h       print help (this panel)", Pn);
+        (void)PrtMsgX("       -p path  define test file path", Pn, cleanup, xv);
+    }
+    /*
+     * See if lsof can be executed and can access kernel memory.
+     */
+    if ((em = IsLsofExec()))
+        (void)PrtMsgX(em, Pn, cleanup, 1);
+    if ((em = CanRdKmem()))
+        (void)PrtMsgX(em, Pn, cleanup, 1);
+    /*
+     * If a path was supplied in an "-p path" option, use it.  Otherwise
+     * construct a path in the CWD.
+     */
+    if (!(Path = LTopt_p)) {
+        (void)snprintf(buf, sizeof(buf), "./config.LTlock%ld", (long)MyPid);
+        buf[sizeof(buf) - 1] = '\0';
+        Path = MkStrCpy(buf, &tlen);
+    }
+    /*
+     * Fill buffer for writing to the test file.
+     */
+    for (ti = 0; ti < sizeof(buf); ti++) {
+        buf[ti] = (char)(ti & 0xff);
+    }
+    /*
+     * Open a new test file at the specified path.
+     */
+    (void)unlink(Path);
+    if ((Fd = open(Path, O_RDWR | O_CREAT, 0600)) < 0) {
+        (void)fprintf(stderr, "ERROR!!!  can't open %s\n", Path);
+
+    print_file_error:
+
+        MsgStat = 1;
+        (void)snprintf(buf, sizeof(buf) - 1, "      Errno %d: %s", errno,
+                       strerror(errno));
+        buf[sizeof(buf) - 1] = '\0';
+        (void)PrtMsgX(buf, Pn, cleanup, 1);
+    }
+    /*
+     * Write a buffer load at the beginning of the file.
+     */
+    if (write(Fd, buf, sizeof(buf)) != sizeof(buf)) {
+        (void)fprintf(stderr,
+                      "ERROR!!!  can't write %d bytes to the beginning of %s\n",
+                      (int)sizeof(buf), Path);
+        goto print_file_error;
+    }
+    /*
+     * Fsync() the file.
+     */
+    if (fsync(Fd)) {
+        (void)fprintf(stderr, "ERROR!!!  can't fsync %s\n", Path);
+        goto print_file_error;
+    }
+    /*
+     * Quit (with a hint) if the test file is on an NFS file system.
+     */
+    if (!tstwlsof("-wNa", " ")) {
+        (void)printf("ERROR!!!  %s is NFS-mounted.\n", Path);
+        MsgStat = 1;
+        (void)PrtMsg("Lsof can't report lock information on files that", Pn);
+        (void)PrtMsg("are located on file systems mounted from a remote", Pn);
+        (void)PrtMsg("NFS server.\n", Pn);
+        (void)PrtMsg("Hint: try using \"-p path\" to supply a path in a", Pn);
+        (void)PrtMsg("non-NFS file system.\n", Pn);
+        (void)PrtMsgX("See 00FAQ and 00TEST for more information.", Pn, cleanup,
+                      1);
+    }
+    /*
+     * Get an exclusive lock on the entire file and test it with lsof.
+     */
+    if ((em = lkfile(FULL_EX_LOCK)))
+        (void)PrtMsgX(em, Pn, cleanup, 1);
+    if ((tstW = tstwlsof("-w", "W")))
+        (void)PrtMsg(tstW, Pn);
+    /*
+     * Get a shared lock on the entire file and test it with lsof.
+     */
+    if ((em = unlkfile(FULL_EX_LOCK)))
+        (void)PrtMsgX(em, Pn, cleanup, 1);
+    if ((em = lkfile(FULL_SH_LOCK)))
+        (void)PrtMsgX(em, Pn, cleanup, 1);
+    if ((tstR = tstwlsof("-w", "R")))
+        (void)PrtMsg(tstR, Pn);
+
+#    if defined(USE_FLOCK)
+    /*
+     * If using flock(), skip the byte lock tests.
+     */
+    tstr = tstw = (char *)NULL;
+#    endif /* defined(USE_FLOCK) */
+
+#    if defined(USE_FCNTL)
+    /*
+     * If using fcntl(), do exclusive and shared byte lock tests,
+     */
+    if ((em = unlkfile(FULL_SH_LOCK)))
+        (void)PrtMsgX(em, Pn, cleanup, 1);
+    if ((em = lkfile(PART_EX_LOCK)))
+        (void)PrtMsgX(em, Pn, cleanup, 1);
+    if ((tstw = tstwlsof("-w", "w")))
+        (void)PrtMsg(tstw, Pn);
+    if ((em = unlkfile(PART_EX_LOCK)))
+        (void)PrtMsgX(em, Pn, cleanup, 1);
+    if ((em = lkfile(PART_SH_LOCK)))
+        (void)PrtMsgX(em, Pn, cleanup, 1);
+    if ((tstr = tstwlsof("-w", "r")))
+        (void)PrtMsg(tstr, Pn);
+#    endif /* defined(USE_FCNTL) */
+
+    /*
+     * Compute exit value and exit.
+     */
+    if (tstr || tstR || tstw || tstW) {
+        tcp = (char *)NULL;
+#    if defined(LT_DIAL_freebsd)
+        /*
+         * Note: in future FreeBSD releases with
+         * https://reviews.freebsd.org/D34756, this will work as non-root user
+         */
+        (void)PrtMsg("Hint: lsof is unable to get the lock status when running "
+                     "as non-root",
+                     Pn);
+        (void)PrtMsg("in certain FreeBSD releases (e.g. FreeBSD 13.1), thus "
+                     "skipping the test",
+                     Pn);
+        xv = 77;
+#    elif defined(LT_DIAL_openbsd)
+        (void)PrtMsg("Hint: lsof is unable to get the lock status in OpenBSD",
+                     Pn);
+        (void)PrtMsg(
+            "since OpenBSD kernel forbids kvm_read, thus skipping the test",
+            Pn);
+        xv = 77;
+#    else
+        xv = 1;
+#    endif
+    } else {
+        tcp = "OK";
+        xv = 0;
+    }
+    (void)PrtMsgX(tcp, Pn, cleanup, xv);
+    return (0);
+}
+
+/*
+ * cleanup() -- release resources
+ */
+
+static void cleanup() {
+    if (Fd >= 0) {
+        (void)close(Fd);
+        Fd = -1;
+        if (Path) {
+            (void)unlink(Path);
+            Path = (char *)NULL;
+        }
+    }
+}
+
+/*
+ * lkfile() -- lock the test file
+ */
+
+static char *lkfile(int ty) /* a *_*_LOCK requested */
+{
+    char buf[2048];  /* temporary buffer */
+    int ti;          /* temporary integer */
+
+#    if defined(USE_FLOCK)
+    int flf;         /* flock() function */
+#    endif /* defined(USE_FLOCK) */
+
+#    if defined(USE_FCNTL)
+    struct flock fl; /* flock control structure */
+                     /*
+                      * Check fcntl() lock request.
+                      */
+    (void)memset((void *)&fl, 0, sizeof(fl));
+    switch (ty) {
+    case FULL_EX_LOCK:
+        fl.l_type = F_WRLCK;
+        break;
+    case FULL_SH_LOCK:
+        fl.l_type = F_RDLCK;
+        break;
+    case PART_EX_LOCK:
+        fl.l_type = F_WRLCK;
+        fl.l_len = (off_t)1;
+        break;
+    case PART_SH_LOCK:
+        fl.l_type = F_RDLCK;
+        fl.l_len = (off_t)1;
+        break;
+    default:
+        (void)snprintf(buf, sizeof(buf) - 1, "ERROR!!!  unknown lock type: %d",
+                       ty);
+        buf[sizeof(buf) - 1] = '\0';
+        return (MkStrCpy(buf, &ti));
+    }
+    /*
+     * Lock test file with fcntl().
+     */
+    if (fcntl(Fd, F_SETLK, &fl) != -1)
+        return ((char *)NULL);
+    (void)snprintf(buf, sizeof(buf) - 1, "ERROR!!!  fcntl() lock error: %s",
+                   strerror(errno));
+    buf[sizeof(buf) - 1] = '\0';
+    return (MkStrCpy(buf, &ti));
+#    endif /* defined(USE_FCNTL) */
+
+#    if defined(USE_FLOCK)
+    /*
+     * Check flock() lock request.
+     */
+    switch (ty) {
+    case FULL_EX_LOCK:
+        flf = LOCK_EX;
+        break;
+    case FULL_SH_LOCK:
+        flf = LOCK_SH;
+        break;
+    case PART_EX_LOCK:
+    case PART_SH_LOCK:
+        return ("ERROR!!!  flock() doesn't support partial locks");
+        break;
+    default:
+        (void)snprintf(buf, sizeof(buf) - 1,
+                       "ERROR!!!  unknown flock() type: %d", ty);
+        buf[sizeof(buf) - 1] = '\0';
+        return (MkStrCpy(buf, &ti));
+    }
+    /*
+     * Acquire lock.
+     */
+    if (!flock(Fd, flf))
+        return ((char *)NULL);
+    (void)snprintf(buf, sizeof(buf) - 1, "ERROR!!!  flock() %s lock failed: %s",
+                   (flf == LOCK_EX) ? "exclusive" : "shared", strerror(errno));
+    buf[sizeof(buf) - 1] = '\0';
+    return (MkStrCpy(buf, &ti));
+#    endif /* defined(USE_FLOCK) */
+}
+
+/*
+ * tstwlsof() -- test the open file with lsof
+ */
+
+static char *tstwlsof(char *opt, /* extra lsof options */
+                      char *xlk) /* expected lock value */
+{
+    char buf[2048];           /* temporary buffer */
+    LTfldo_t *cmdp;           /* command pointer */
+    LTfldo_t *devp;           /* device pointer */
+    char *cem;                /* current error message pointer */
+    int ff = 0;               /* file found status */
+    LTfldo_t *fop;            /* field output pointer */
+    LTfldo_t *inop;           /* inode number pointer */
+    LTfldo_t *lkp;            /* lock pointer */
+    LTdev_t lsofdc;           /* lsof device components */
+    int nf;                   /* number of fields */
+    LTfldo_t *nmp;            /* file name pointer */
+    char *opv[4];             /* option vector for ExecLsof() */
+    char *pem = (char *)NULL; /* previous error message pointer */
+    pid_t pid;                /* PID */
+    int pids = 0;             /* PID found status */
+    struct stat sb;           /* stat(2) buffer */
+    LTdev_t stdc;             /* stat(2) device components */
+    char *tcp;                /* temporary character pointer */
+    int ti;                   /* temporary integer */
+    LTfldo_t *typ;            /* file type pointer */
+                              /*
+                               * Make sure there is an expected lock value.
+                               */
+    if (!xlk || !*xlk)
+        (void)PrtMsgX("ERROR!!!  no expected lock value", Pn, cleanup, 1);
+    /*
+     * Get test file's information.
+     */
+    if (stat(Path, &sb)) {
+        (void)snprintf(buf, sizeof(buf) - 1, "ERROR!!!  can't stat(2) %s: %s",
+                       Path, strerror(errno));
+        buf[sizeof(buf) - 1] = '\0';
+        (void)PrtMsgX(buf, Pn, cleanup, 1);
+    }
+    /*
+     * Extract components from test file's device number.
+     */
+    if ((cem = ConvStatDev(&sb.st_dev, &stdc)))
+        (void)PrtMsgX(cem, Pn, cleanup, 1);
+    /*
+     * Complete the option vector and start lsof execution.
+     */
+    ti = 0;
+    if (opt && *opt)
+        opv[ti++] = opt;
+
+#    if defined(USE_LSOF_C_OPT)
+    opv[ti++] = "-C";
+#    endif /* defined(USE_LSOF_C_OPT) */
+
+    opv[ti++] = Path;
+    opv[ti] = (char *)NULL;
+    if ((cem = ExecLsof(opv)))
+        return (cem);
+    /*
+     * Read lsof output.
+     */
+    while (!ff && (fop = RdFrLsof(&nf, &cem))) {
+        if (cem) {
+            if (pem)
+                (void)PrtMsg(pem, Pn);
+            return (cem);
+        }
+        switch (fop->ft) {
+        case LSOF_FID_PID:
+
+            /*
+             * This is a process information line.
+             */
+            pid = (pid_t)atoi(fop->v);
+            pids = 1;
+            cmdp = (LTfldo_t *)NULL;
+            for (fop++, ti = 1; ti < nf; fop++, ti++) {
+                switch (fop->ft) {
+                case LSOF_FID_CMD:
+                    cmdp = fop;
+                    break;
+                }
+            }
+            if (!cmdp || (pid != MyPid))
+                pids = 0;
+            break;
+        case LSOF_FID_FD:
+
+            /*
+             * This is a file descriptor line.  Make sure its number matches the
+             * test file's descriptor number.
+             *
+             * Scan for lock and name fields.
+             */
+            if (!pids)
+                break;
+            for (ti = 0, tcp = fop->v; *tcp; tcp++) {
+
+                /*
+                 * Convert file descriptor to a number.
+                 */
+                if (*tcp == ' ')
+                    continue;
+                if (((int)*tcp < (int)'0') || ((int)*tcp > (int)'9')) {
+                    ti = -1;
+                    break;
+                }
+                ti = (ti * 10) + (int)*tcp - (int)'0';
+            }
+            if (Fd != ti)
+                break;
+            devp = inop = lkp = nmp = (LTfldo_t *)NULL;
+            for (fop++, ti = 1; ti < nf; fop++, ti++) {
+                switch (fop->ft) {
+                case LSOF_FID_DEVN:
+                    devp = fop;
+                    break;
+                case LSOF_FID_INODE:
+                    inop = fop;
+                    break;
+                case LSOF_FID_LOCK:
+                    lkp = fop;
+                    break;
+                case LSOF_FID_NAME:
+                    nmp = fop;
+                    break;
+                case LSOF_FID_TYPE:
+                    typ = fop;
+                    break;
+                }
+            }
+            /*
+             * Check the results of the file descriptor field scan.
+             *
+             * (Don't compare path names because of symbolic link interference.)
+             */
+            if (!devp || !inop || !nmp || !typ)
+                break;
+            if (strcasecmp(typ->v, "reg") && strcasecmp(typ->v, "vreg"))
+                break;
+            if (ConvLsofDev(devp->v, &lsofdc))
+                break;
+            if ((stdc.maj != lsofdc.maj) || (stdc.min != lsofdc.min) ||
+                (stdc.unit != lsofdc.unit))
+                break;
+            (void)snprintf(buf, sizeof(buf) - 1, "%u", (unsigned int)sb.st_ino);
+            buf[sizeof(buf) - 1] = '\0';
+            if (strcmp(inop->v, buf))
+                break;
+            /*
+             * The specified file has been located.  Check its lock status.
+             */
+            ff = 1;
+            if (!lkp || strcmp(lkp->v, xlk)) {
+                if (pem)
+                    (void)PrtMsg(pem, Pn);
+                (void)snprintf(buf, sizeof(buf) - 1,
+                               "lock mismatch: expected %s, got \"%s\"", xlk,
+                               lkp ? lkp->v : "(none)");
+                pem = MkStrCpy(buf, &ti);
+            }
+            break;
+        }
+    }
+    (void)StopLsof();
+    if (!ff) {
+        if (pem)
+            (void)PrtMsg(pem, Pn);
+        (void)snprintf(buf, sizeof(buf) - 1,
+                       "lock test file %s not found by lsof", Path);
+        buf[sizeof(buf) - 1] = '\0';
+        return (MkStrCpy(buf, &ti));
+    }
+    return (pem);
+}
+
+/*
+ * unlkfile() -- unlock the test file
+ */
+
+static char *unlkfile(int ty) /* current *_*_LOCK lock typ */
+{
+    char buf[2048];  /* temporary buffer */
+    int ti;          /* temporary integer */
+
+#    if defined(USE_FCNTL)
+    struct flock fl; /* flock control structure */
+                     /*
+                      * Check current fcntl() lock type.
+                      */
+    (void)memset((void *)&fl, 0, sizeof(fl));
+    switch (ty) {
+    case FULL_EX_LOCK:
+    case FULL_SH_LOCK:
+        break;
+    case PART_EX_LOCK:
+    case PART_SH_LOCK:
+        fl.l_len = (off_t)1;
+        break;
+    default:
+        (void)snprintf(buf, sizeof(buf) - 1,
+                       "ERROR!!!  unknown unlock type: %d", ty);
+        buf[sizeof(buf) - 1] = '\0';
+        return (MkStrCpy(buf, &ti));
+    }
+    /*
+     * Unlock test file with fcntl().
+     */
+    fl.l_type = F_UNLCK;
+    if (fcntl(Fd, F_SETLK, &fl) != -1)
+        return ((char *)NULL);
+    (void)snprintf(buf, sizeof(buf) - 1, "ERROR!!!  fcntl() unlock error: %s",
+                   strerror(errno));
+    buf[sizeof(buf) - 1] = '\0';
+    return (MkStrCpy(buf, &ti));
+#    endif /* defined(USE_FCNTL) */
+
+#    if defined(USE_FLOCK)
+    /*
+     * Check current flock() lock type.
+     */
+    switch (ty) {
+    case FULL_EX_LOCK:
+    case FULL_SH_LOCK:
+        break;
+    default:
+        (void)snprintf(buf, sizeof(buf) - 1,
+                       "ERROR!!!   unknown unlock type: %s", ty);
+        buf[sizeof(buf) - 1] = '\0';
+        return (MkStrCpy(buf, &ti));
+    }
+    /*
+     * Unlock file with flock().
+     */
+    if (!flock(Fd, LOCK_UN))
+        return ((char *)NULL);
+    (void)snprintf(buf, sizeof(buf) - 1, "ERROR!!!  flock() unlock error: %s",
+                   strerror(errno));
+    return (MkStrCpy(buf, &ti));
+#    endif /* defined(USE_FLOCK) */
+}
+#endif     /* !defined(USE_FLOCK) && !defined(USE_FCNTL) */
diff --git a/tests/LTnfs.c b/tests/LTnfs.c
new file mode 100644 (file)
index 0000000..df28412
--- /dev/null
@@ -0,0 +1,501 @@
+/*
+ * LTnfs.c -- Lsof Test NFS tests
+ *
+ * V. Abell
+ * Purdue University
+ */
+
+/*
+ * Copyright 2002 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by V. 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.
+ */
+
+#include "LsofTest.h"
+#include "lsof_fields.h"
+
+/*
+ * Pre-definitions that may be revoked by specific dialects
+ */
+
+#define DO_TEST /* do the test */
+
+#if defined(LT_DIAL_darwin)
+/*
+ * Darwin-specific items
+ */
+
+#    if LT_VERS < 800
+#        undef DO_TEST
+#    endif /* LT_VERS<800 */
+#endif     /* defined(LT_DIAL_darwin) */
+
+/*
+ * Globals
+ */
+
+int Fd = -1;               /* test file descriptor; open if >= 0 */
+pid_t MyPid = (pid_t)0;    /* PID of this process */
+int NFstat = 0;            /* NFS file status: 0 == closed
+                            *              1 == not created by this
+                            *                   these and must not be
+                            *                   unlinked
+                            *              2 == created by this test
+                            *                   and must be unlinked
+                            */
+char *Path = (char *)NULL; /* test file path; none if NULL */
+char *Pn = (char *)NULL;   /* program name */
+
+/*
+ * Local function prototypes
+ */
+
+static void cleanup(void);
+static char *FindNFSfile(int *ff, char *szbuf);
+
+/*
+ * Main program
+ */
+
+int main(int argc,     /* argument count */
+         char *argv[]) /* arguments */
+{
+    char buf[2048]; /* temporary buffer */
+    char *em;       /* error message pointer */
+    int ff;         /* FindNFSfile() file-found flag */
+    int sz;         /* file size (if created) */
+    char szbuf[32]; /* created test file size in ASCII */
+    int ti;         /* temporary index */
+    int xv = 0;     /* exit value */
+                    /*
+                     * Get program name and PID, issue start message, and build space prefix.
+                     */
+    if ((Pn = strrchr(argv[0], '/')))
+        Pn++;
+    else
+        Pn = argv[0];
+    MyPid = getpid();
+    (void)printf("%s ... ", Pn);
+    (void)fflush(stdout);
+    PrtMsg((char *)NULL, Pn);
+
+#if !defined(DO_TEST)
+    /*
+     * If the dialect has disabled the test, echo that result and exit with
+     * a successful return code.
+     */
+    (void)PrtMsgX(LT_DONT_DO_TEST, Pn, cleanup, 0);
+#endif /* !defined(DO_TEST) */
+
+    /*
+     * Process arguments.
+     */
+    if (ScanArg(argc, argv, "hp:", Pn))
+        xv = 1;
+    if (xv || LTopt_h) {
+        (void)PrtMsg("usage: [-h] [-p path]", Pn);
+        PrtMsg("       -h       print help (this panel)", Pn);
+        PrtMsgX("       -p path  define test file path", Pn, cleanup, xv);
+    }
+    /*
+     * See if lsof can be executed and can access kernel memory.
+     */
+    if ((em = IsLsofExec()))
+        (void)PrtMsgX(em, Pn, cleanup, 1);
+    if ((em = CanRdKmem()))
+        (void)PrtMsgX(em, Pn, cleanup, 1);
+    /*
+     * Process the file path and open it.
+     */
+    if ((Path = LTopt_p)) {
+
+        /*
+         * The file path was supplied.  Open the file read-only.
+         */
+        if ((Fd = open(Path, O_RDONLY, 0400)) < 0) {
+            (void)fprintf(stderr, "ERROR!!!  can't read-only open %s\n", Path);
+            goto print_file_error;
+        }
+        /*
+         * Record that an existing file is being used.  Clear its ASCII size.
+         */
+        NFstat = 1;
+        szbuf[0] = '\0';
+    } else {
+
+        /*
+         * The file path wasn't supplied with -p, so generate one.
+         */
+        (void)snprintf(buf, sizeof(buf) - 1, "./config.LTnfs%ld", (long)MyPid);
+        buf[sizeof(buf) - 1] = '\0';
+        Path = MkStrCpy(buf, &ti);
+        /*
+         * Open a new test file at the specified path.
+         */
+        (void)unlink(Path);
+        if ((Fd = open(Path, O_RDWR | O_CREAT, 0600)) < 0) {
+            (void)fprintf(stderr, "ERROR!!!  can't create %s\n", Path);
+
+        print_file_error:
+
+            MsgStat = 1;
+            (void)snprintf(buf, sizeof(buf) - 1, "      Errno %d: %s", errno,
+                           strerror(errno));
+            buf[sizeof(buf) - 1] = '\0';
+            (void)PrtMsgX(buf, Pn, cleanup, 1);
+        }
+        NFstat = 2;
+        /*
+         * Write the test file to its expected size.
+         */
+        sz = sizeof(buf);
+        for (ti = 0; ti < sz; ti++) {
+            buf[ti] = (char)(ti & 0xff);
+        }
+        if (write(Fd, buf, sz) != sz) {
+            (void)fprintf(stderr, "ERROR!!!  can't write %d bytes to %s\n", sz,
+                          Path);
+            goto print_file_error;
+        }
+        /*
+         * Fsync() the file.
+         */
+        if (fsync(Fd)) {
+            (void)fprintf(stderr, "ERROR!!!  can't fsync %s\n", Path);
+            goto print_file_error;
+        }
+        /*
+         * Convert the file size to ASCII.
+         */
+        (void)snprintf(szbuf, sizeof(szbuf) - 1, "%d", sz);
+        szbuf[sizeof(szbuf) - 1] = '\0';
+    }
+    /*
+     * Make sure the test file can be found on an NFS file system.
+     */
+    if ((em = FindNFSfile(&ff, szbuf))) {
+
+        /*
+         * Print the error message returned by FindNFSfile().
+         */
+        (void)PrtMsg(em, Pn);
+        if (!ff) {
+
+            /*
+             * If the file couldn't be found, print hints.
+             */
+            if (NFstat == 1) {
+                (void)PrtMsg(
+                    "Hint: this test must be able to open for read access", Pn);
+                (void)PrtMsg(
+                    "the file at the path supplied with the -p option and", Pn);
+                (void)PrtMsg(
+                    "that file must be a regular file (not a directory) on",
+                    Pn);
+                (void)PrtMsg("an NFS file system.\n", Pn);
+                (void)PrtMsgX("See 00FAQ and 00TEST for more information.", Pn,
+                              cleanup, 77);
+            } else if (NFstat == 2) {
+                (void)PrtMsg(
+                    "Hint: the temporary path generated by this test might",
+                    Pn);
+                (void)PrtMsg(
+                    "not be on an NFS file system, or this test might be", Pn);
+                (void)PrtMsg(
+                    "unable to create a file on the NFS file system.\n", Pn);
+                (void)PrtMsg(
+                    "As a work-around use the -p option to specify a path to",
+                    Pn);
+                (void)PrtMsg(
+                    "a regular file (not a directory) on an NFS file system",
+                    Pn);
+                (void)PrtMsg("to which this test will have read access.\n", Pn);
+                (void)PrtMsgX("See 00FAQ and 00TEST for more information.", Pn,
+                              cleanup, 77);
+            }
+        }
+    }
+    /*
+     * Exit successfully.
+     */
+    (void)PrtMsgX("OK", Pn, cleanup, 0);
+    return (0);
+}
+
+/*
+ * cleanup() -- release resources
+ */
+
+static void cleanup() {
+    if (Fd >= 0) {
+        (void)close(Fd);
+        Fd = -1;
+        if (Path) {
+            if (NFstat == 2)
+                (void)unlink(Path);
+            Path = (char *)NULL;
+        }
+    }
+}
+
+/*
+ * FindNFSfile() -- find the NFS file with lsof
+ */
+
+static char *FindNFSfile(int *ff,     /* file-found response receptor */
+                         char *szbuf) /* expected file size in ASCII (if
+                                       * the file was created by this test */
+{
+    char buf[2048];           /* temporary buffer */
+    char *cem;                /* current error message pointer */
+    LTfldo_t *cmdp;           /* command pointer */
+    LTfldo_t *devp;           /* device pointer */
+    LTfldo_t *fop;            /* field output pointer */
+    char ibuf[64];            /* inode number buffer */
+    LTfldo_t *inop;           /* inode number pointer */
+    LTdev_t lsofdc;           /* lsof device components */
+    int nf;                   /* number of fields */
+    char nlkbuf[32];          /* link count buffer */
+    LTfldo_t *nlkp;           /* nlink pointer */
+    char *opv[5];             /* option vector for ExecLsof() */
+    char *pem = (char *)NULL; /* previous error message pointer */
+    pid_t pid;                /* PID */
+    int pids = 0;             /* PID found status */
+    struct stat sb;           /* stat(2) buffer */
+    LTdev_t stdc;             /* stat(2) device components */
+    LTfldo_t *szp;            /* size pointer */
+    char *tcp;                /* temporary character pointer */
+    int ti;                   /* temporary integer */
+    LTfldo_t *typ;            /* file type pointer */
+                              /*
+                               * Check the argument pointers.
+                               *
+                               * Set the file-found response false.
+                               */
+    if (!ff || !szbuf)
+        (void)PrtMsgX("ERROR!!!  missing argument to FindNFSfile()", Pn,
+                      cleanup, 1);
+    *ff = 0;
+    /*
+     * Get test file's information.
+     */
+    if (stat(Path, &sb)) {
+        (void)snprintf(buf, sizeof(buf) - 1, "ERROR!!!  can't stat(2) %s: %s",
+                       Path, strerror(errno));
+        buf[sizeof(buf) - 1] = '\0';
+        PrtMsgX(buf, Pn, cleanup, 1);
+    }
+    /*
+     * Extract components from test file's stat buffer.
+     */
+    if ((cem = ConvStatDev(&sb.st_dev, &stdc)))
+        PrtMsgX(cem, Pn, cleanup, 1);
+    (void)snprintf(ibuf, sizeof(ibuf) - 1, "%u", (unsigned int)sb.st_ino);
+    ibuf[sizeof(ibuf) - 1] = '\0';
+    (void)snprintf(nlkbuf, sizeof(nlkbuf) - 1, "%d", (int)sb.st_nlink);
+    nlkbuf[sizeof(nlkbuf) - 1] = '\0';
+    /*
+     * Complete the option vector and start lsof execution.
+     */
+    ti = 0;
+    opv[ti++] = "-s";
+    opv[ti++] = "-Na";
+
+#if defined(USE_LSOF_C_OPT)
+    opv[ti++] = "-C";
+#endif /* defined(USE_LSOF_C_OPT) */
+
+    opv[ti++] = Path;
+    opv[ti] = (char *)NULL;
+    if ((cem = ExecLsof(opv)))
+        return (cem);
+    /*
+     * Read lsof output.
+     */
+    while (!*ff && (fop = RdFrLsof(&nf, &cem))) {
+        if (cem) {
+            if (pem)
+                (void)PrtMsg(pem, Pn);
+            return (cem);
+        }
+        switch (fop->ft) {
+        case LSOF_FID_PID:
+
+            /*
+             * This is a process information line.
+             */
+            pid = (pid_t)atoi(fop->v);
+            pids = 1;
+            cmdp = (LTfldo_t *)NULL;
+            for (fop++, ti = 1; ti < nf; fop++, ti++) {
+                switch (fop->ft) {
+                case LSOF_FID_CMD:
+                    cmdp = fop;
+                    break;
+                }
+            }
+            if (!cmdp || (pid != MyPid))
+                pids = 0;
+            break;
+        case LSOF_FID_FD:
+
+            /*
+             * This is a file descriptor line.  Make sure its number matches the
+             * test file's descriptor number.
+             */
+            if (!pids)
+                break;
+            for (ti = 0, tcp = fop->v; *tcp; tcp++) {
+
+                /*
+                 * Convert file descriptor to a number.
+                 */
+                if (*tcp == ' ')
+                    continue;
+                if (((int)*tcp < (int)'0') || ((int)*tcp > (int)'9')) {
+                    ti = -1;
+                    break;
+                }
+                ti = (ti * 10) + (int)*tcp - (int)'0';
+            }
+            if (Fd != ti)
+                break;
+            /*
+             * Scan for device, inode, nlink, offset, size and type fields.
+             */
+            devp = inop = nlkp, szp = typ = (LTfldo_t *)NULL;
+            for (fop++, ti = 1; ti < nf; fop++, ti++) {
+                switch (fop->ft) {
+                case LSOF_FID_DEVN:
+                    devp = fop;
+                    break;
+                case LSOF_FID_INODE:
+                    inop = fop;
+                    break;
+                case LSOF_FID_NLINK:
+                    nlkp = fop;
+                    break;
+                case LSOF_FID_OFFSET:
+                    break;
+                case LSOF_FID_SIZE:
+                    szp = fop;
+                    break;
+                case LSOF_FID_TYPE:
+                    typ = fop;
+                    break;
+                }
+            }
+            /*
+             * Check the device, inode, and type of the file.
+             */
+            if (!devp || !inop || !typ)
+                break;
+            if (strcasecmp(typ->v, "reg") && strcasecmp(typ->v, "vreg"))
+                break;
+            if ((cem = ConvLsofDev(devp->v, &lsofdc))) {
+                if (pem)
+                    (void)PrtMsg(pem, Pn);
+                pem = cem;
+                break;
+            }
+            if ((stdc.maj != lsofdc.maj) || (stdc.min != lsofdc.min) ||
+                (stdc.unit != lsofdc.unit) || strcmp(inop->v, ibuf)) {
+                break;
+            }
+            /*
+             * Indicate the file was found.
+             */
+            *ff = 1;
+            /*
+             * Check the link count.
+             */
+            if (!nlkp) {
+                (void)snprintf(
+                    buf, sizeof(buf) - 1,
+                    "ERROR!!!  lsof didn't report a link count for %s", Path);
+                buf[sizeof(buf) - 1] = '\0';
+                cem = MkStrCpy(buf, &ti);
+                if (pem)
+                    (void)PrtMsg(pem, Pn);
+                pem = cem;
+                break;
+            }
+            if (strcmp(nlkp->v, nlkbuf)) {
+                (void)snprintf(
+                    buf, sizeof(buf) - 1,
+                    "ERROR!!!  wrong link count: expected %s, got %s", nlkbuf,
+                    nlkp->v);
+                buf[sizeof(buf) - 1] = '\0';
+                cem = MkStrCpy(buf, &ti);
+                if (pem)
+                    (void)PrtMsg(pem, Pn);
+                pem = cem;
+                break;
+            }
+            /*
+             * If the file was created by this test, check its size.
+             */
+            if (NFstat == 2) {
+                if (!szp) {
+                    (void)snprintf(buf, sizeof(buf) - 1,
+                                   "ERROR!!!  lsof didn't report a size for %s",
+                                   Path);
+                    buf[sizeof(buf) - 1] = '\0';
+                    cem = MkStrCpy(buf, &ti);
+                    if (pem)
+                        (void)PrtMsg(pem, Pn);
+                    pem = cem;
+                    break;
+                }
+                if (strcmp(szp->v, szbuf)) {
+                    (void)snprintf(
+                        buf, sizeof(buf) - 1,
+                        "ERROR!!!  wrong file size: expected %s, got %s", szbuf,
+                        szp->v);
+                    buf[sizeof(buf) - 1] = '\0';
+                    cem = MkStrCpy(buf, &ti);
+                    if (pem)
+                        (void)PrtMsg(pem, Pn);
+                    pem = cem;
+                    break;
+                }
+            }
+            /*
+             * The requested file was located.  Return the previous error
+             * message pointer.  (It will be NULL if no error was detected.)
+             */
+            (void)StopLsof();
+            return (pem);
+        }
+    }
+    /*
+     * The test file wasn't found.
+     */
+    (void)StopLsof();
+    if (pem)
+        (void)PrtMsg(pem, Pn);
+    (void)snprintf(buf, sizeof(buf) - 1,
+                   "ERROR!!!  test file %s not found by lsof", Path);
+    buf[sizeof(buf) - 1] = '\0';
+    return (MkStrCpy(buf, &ti));
+}
diff --git a/tests/LTnlink.c b/tests/LTnlink.c
new file mode 100644 (file)
index 0000000..a61136b
--- /dev/null
@@ -0,0 +1,569 @@
+/*
+ * LTnlink.c -- Lsof Test nlink tests
+ *
+ * V. Abell
+ * Purdue University
+ */
+
+/*
+ * Copyright 2002 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by V. 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.
+ */
+
+#include "LsofTest.h"
+#include "lsof_fields.h"
+
+/*
+ * Pre-definitions that may be changed by specific dialects
+ */
+
+#define DO_TEST /* do the test */
+
+/*
+ * Dialect-specific items
+ */
+
+#if defined(LT_DIAL_darwin)
+/*
+ * Darwin-specific items
+ */
+
+#    if defined(LT_KMEM)
+#        undef DO_TEST
+#    endif /* defined(LT_KMEM) */
+
+#endif /* defined(LT_DIAL_darwin) */
+
+/*
+ * Globals
+ */
+
+int Fd = -1;               /* test file descriptor; open if >= 0 */
+pid_t MyPid = (pid_t)0;    /* PID of this process */
+char *Path = (char *)NULL; /* test file path; none if NULL */
+char *Pn = (char *)NULL;   /* program name */
+
+/*
+ * Local function prototypes
+ */
+
+static void cleanup(void);
+static char *FindFile(char *opt, int *ff, int ie, LTdev_t *tfdc, char *ibuf,
+                      char *xlnk, char *szbuf);
+
+/*
+ * Main program
+ */
+
+int main(int argc,     /* argument count */
+         char *argv[]) /* arguments */
+{
+    char buf[2048];    /* temporary buffer */
+    int do_unlink = 1; /* do the unlink test section */
+    char *em;          /* error message pointer */
+    int ff;            /* FindFile() file-found flag */
+    char ibuf[32];     /* inode number in ASCII */
+    char *opt;         /* lsof option */
+    int sz;            /* file size */
+    char szbuf[32];    /* file size in ASCII */
+    LTdev_t tfdc;      /* device components */
+    struct stat tfsb;  /* test file stat(2) buffer */
+    int ti, tj;        /* temporary indexes */
+    char xlnk[32];     /* expected link count in ASCII */
+    int xv = 0;        /* exit value */
+                       /*
+                        * Get program name and PID, issue start message, and build space prefix.
+                        */
+    if ((Pn = strrchr(argv[0], '/')))
+        Pn++;
+    else
+        Pn = argv[0];
+    MyPid = getpid();
+    (void)printf("%s ... ", Pn);
+    (void)fflush(stdout);
+    PrtMsg((char *)NULL, Pn);
+
+#if !defined(DO_TEST)
+    /*
+     * Quit if lsof for this dialect doesn't support adequate nlink reporting.
+     */
+    (void)PrtMsgX(LT_DONT_DO_TEST, Pn, cleanup, 0);
+#endif /* !defined(DO_TEST) */
+
+    /*
+     * Process arguments.
+     */
+    if (ScanArg(argc, argv, "hp:", Pn))
+        xv = 1;
+    if (xv || LTopt_h) {
+        (void)PrtMsg("usage: [-h] [-p path]", Pn);
+        PrtMsg("       -h       print help (this panel)", Pn);
+        PrtMsgX("       -p path  define test file path", Pn, cleanup, xv);
+    }
+    /*
+     * See if lsof can be executed and can access kernel memory.
+     */
+    if ((em = IsLsofExec()))
+        (void)PrtMsgX(em, Pn, cleanup, 1);
+    if ((em = CanRdKmem()))
+        (void)PrtMsgX(em, Pn, cleanup, 1);
+    /*
+     * Process the file path.
+     */
+    if (!(Path = LTopt_p)) {
+
+        /*
+         * The file path was not supplied, so make one.
+         */
+        (void)snprintf(buf, sizeof(buf) - 1, "./config.LTnlink%ld",
+                       (long)MyPid);
+        buf[sizeof(buf) - 1] = '\0';
+        Path = MkStrCpy(buf, &ti);
+    }
+    /*
+     * Create the test file.
+     */
+    (void)unlink(Path);
+    if ((Fd = open(Path, O_RDWR | O_CREAT, 0600)) < 0) {
+        (void)fprintf(stderr, "ERROR!!!  can't create %s\n", Path);
+
+    print_file_error:
+
+        MsgStat = 1;
+        (void)snprintf(buf, sizeof(buf) - 1, "      Errno %d: %s", errno,
+                       strerror(errno));
+        buf[sizeof(buf) - 1] = '\0';
+        (void)PrtMsgX(buf, Pn, cleanup, 1);
+    }
+    /*
+     * Write the test file to its expected size.
+     */
+    sz = sizeof(buf);
+    for (ti = 0; ti < sz; ti++) {
+        buf[ti] = (char)(ti & 0xff);
+    }
+    if (write(Fd, buf, sz) != sz) {
+        (void)fprintf(stderr, "ERROR!!!  can't write %d bytes to %s\n", sz,
+                      Path);
+        goto print_file_error;
+    }
+    /*
+     * Fsync() the file.
+     */
+    if (fsync(Fd)) {
+        (void)fprintf(stderr, "ERROR!!!  can't fsync %s\n", Path);
+        goto print_file_error;
+    }
+    /*
+     * Stat(2) the test file.
+     */
+    if (stat(Path, &tfsb)) {
+        (void)snprintf(buf, sizeof(buf) - 1, "ERROR!!!  can't stat(2) %s: %s",
+                       Path, strerror(errno));
+        buf[sizeof(buf) - 1] = '\0';
+        PrtMsgX(buf, Pn, cleanup, 1);
+    }
+    /*
+     * Set the test file status to open and linked.
+     *
+     * Get the test file's parameters:
+     *
+     *    * device paramters in LTdev_t form;
+     *    * inode number in ASCII;
+     *    * link count in ASCII;
+     *    * file size in ASCII.
+     */
+    if ((em = ConvStatDev(&tfsb.st_dev, &tfdc)))
+        PrtMsgX(em, Pn, cleanup, 1);
+    (void)snprintf(ibuf, sizeof(ibuf) - 1, "%" PRIu64, (uint64_t)tfsb.st_ino);
+    ibuf[sizeof(szbuf) - 1] = '\0';
+    (void)snprintf(xlnk, sizeof(xlnk) - 1, "%d", (int)tfsb.st_nlink);
+    ibuf[sizeof(szbuf) - 1] = '\0';
+    (void)snprintf(szbuf, sizeof(szbuf) - 1, "%d", sz);
+    szbuf[sizeof(szbuf) - 1] = '\0';
+    /*
+     * See if the file is on an NFS file system.
+     */
+    (void)FindFile("-Na", &ff, 1, &tfdc, ibuf, xlnk, szbuf);
+    if (ff) {
+
+        /*
+         * The file was found on an NFS file system.
+         */
+        (void)snprintf(buf, sizeof(buf) - 1,
+                       "WARNING!!!  Test file %s is NFS mounted.", Path);
+        (void)PrtMsg(buf, Pn);
+        (void)PrtMsg(
+            "  As a result this test probably won't be able to unlink it and",
+            Pn);
+        (void)PrtMsg(
+            "  find its open and unlinked instance with lsof's +L option.", Pn);
+        (void)PrtMsg(
+            "  Therefore, that section of this test has been disabled.\n", Pn);
+        (void)PrtMsg(
+            "  Hint: supply a path with the -p option to a file in a non-NFS",
+            Pn);
+        (void)PrtMsg("  file system that this test can write and unlink.\n",
+                     Pn);
+        (void)PrtMsg("  See 00FAQ and 00TEST for more information.", Pn);
+        do_unlink = 0;
+    }
+#if defined(LT_DIAL_freebsd)
+    // See https://github.com/lsof-org/lsof/issues/264, unlinked files are not
+    // found by lsof
+    do_unlink = 0;
+#endif
+    /*
+     * Find the test file.
+     */
+    if ((em = FindFile("+L", &ff, 0, &tfdc, ibuf, xlnk, szbuf)))
+        (void)PrtMsgX(em, Pn, cleanup, 1);
+    /*
+     * If the unlink test is enabled, do it.
+     */
+    if (do_unlink) {
+        if (unlink(Path)) {
+            (void)snprintf(buf, sizeof(buf) - 1,
+                           "ERROR!!!  unlink(%s) failed: (%s).", Path,
+                           strerror(errno));
+            buf[sizeof(buf) - 1] = '\0';
+            (void)PrtMsg(buf, Pn);
+            (void)snprintf(buf, sizeof(buf) - 1,
+                           "  %s may be on a ZFS file system, where it", Path);
+            buf[sizeof(buf) - 1] = '\0';
+            (void)PrtMsg(buf, Pn);
+            (void)snprintf(
+                buf, sizeof(buf) - 1,
+                "  is not possible for %s to unlink the file it has open.", Pn);
+            buf[sizeof(buf) - 1] = '\0';
+            (void)PrtMsg(buf, Pn);
+            (void)snprintf(
+                buf, sizeof(buf) - 1,
+                "  To run the %s test, use the \"-p path\" option to specify",
+                Pn);
+            buf[sizeof(buf) - 1] = '\0';
+            (void)PrtMsg(buf, Pn);
+            (void)PrtMsg("  a file on a file system -- e.g., UFS -- that "
+                         "supports unlink",
+                         Pn);
+            (void)PrtMsg(
+                "  while the file is open.  Usually /tmp can do that -- e.g.,",
+                Pn);
+            (void)snprintf(buf, sizeof(buf) - 1,
+                           "  run the test as \"./%s -p /tmp/<name>\".\n", Pn);
+            buf[sizeof(buf) - 1] = '\0';
+            (void)PrtMsg(buf, Pn);
+            (void)PrtMsgX("  See 00FAQ and 00TEST for more information.", Pn,
+                          cleanup, 1);
+        }
+        for (opt = "+L1", ti = 0, tj = 30; ti < tj; ti++) {
+
+            /*
+             * Wait a while for the link count to be updated before concluding
+             * lsof can't find the unlinked file.  Use "+L1" for only the first
+             * third of the tries, then switch to "+L".
+             */
+            if ((ti + ti + ti) >= tj)
+                opt = "+L";
+            if (!(em = FindFile(opt, &ff, 0, &tfdc, ibuf, "0", szbuf)))
+                break;
+            if (ti)
+                (void)printf(".");
+            else
+                (void)printf("waiting for link count update: .");
+            (void)fflush(stdout);
+            (void)sleep(2);
+        }
+        if (ti) {
+
+            /*
+             * End the delay message.
+             */
+            printf("\n");
+            (void)fflush(stdout);
+            MsgStat = 1;
+        }
+        if (em)
+            (void)PrtMsgX(em, Pn, cleanup, 1);
+    }
+    /*
+     * Exit successfully.
+     */
+    (void)PrtMsgX("OK", Pn, cleanup, 0);
+    return (0);
+}
+
+/*
+ * cleanup() -- release resources
+ */
+
+static void cleanup() {
+    if (Fd >= 0) {
+        (void)close(Fd);
+        Fd = -1;
+    }
+    if (Path)
+        (void)unlink(Path);
+}
+
+/*
+ * FindFile() -- find a file with lsof
+ */
+
+static char *FindFile(char *opt,     /* additional lsof options */
+                      int *ff,       /* file-found response receptor */
+                      int ie,        /* ignore errors if == 1 */
+                      LTdev_t *tfdc, /* test file device components */
+                      char *ibuf,    /* inode number in ASCII */
+                      char *xlnk,    /* expected link count */
+                      char *szbuf)   /* file size in ASCII */
+{
+    char buf[2048];           /* temporary buffer */
+    char *cem;                /* current error message pointer */
+    LTfldo_t *cmdp;           /* command pointer */
+    LTfldo_t *devp;           /* device pointer */
+    LTfldo_t *fop;            /* field output pointer */
+    LTfldo_t *inop;           /* inode number pointer */
+    LTdev_t lsofdc;           /* lsof device components */
+    int nf;                   /* number of fields */
+    LTfldo_t *nlkp;           /* nlink pointer */
+    char *opv[4];             /* option vector for ExecLsof() */
+    char *pem = (char *)NULL; /* previous error message pointer */
+    pid_t pid;                /* PID */
+    int pids = 0;             /* PID found status */
+    LTfldo_t *szp;            /* size pointer */
+    char *tcp;                /* temporary character pointer */
+    int ti;                   /* temporary integer */
+    LTfldo_t *typ;            /* file type pointer */
+                              /*
+                               * Check the argument pointers.
+                               *
+                               * Set the file-found response false.
+                               */
+    if (!ff || !ibuf || !szbuf || !tfdc || !xlnk)
+        (void)PrtMsgX("ERROR!!!  missing argument to FindFile()", Pn, cleanup,
+                      1);
+    *ff = 0;
+    /*
+     * Complete the option vector and start lsof execution.
+     */
+    ti = 0;
+    if (opt && *opt)
+        opv[ti++] = opt;
+
+#if defined(USE_LSOF_C_OPT)
+    opv[ti++] = "-C";
+#endif /* defined(USE_LSOF_C_OPT) */
+
+    if (strcmp(xlnk, "0"))
+        opv[ti++] = Path;
+    opv[ti] = (char *)NULL;
+    if ((cem = ExecLsof(opv))) {
+        if (ie)
+            return ((char *)NULL);
+        return (cem);
+    }
+    /*
+     * Read lsof output.
+     */
+    while (!*ff && (fop = RdFrLsof(&nf, &cem))) {
+        if (cem) {
+            if (ie)
+                return ((char *)NULL);
+            if (pem)
+                (void)PrtMsg(pem, Pn);
+            return (cem);
+        }
+        switch (fop->ft) {
+        case LSOF_FID_PID:
+
+            /*
+             * This is a process information line.
+             */
+            pid = (pid_t)atoi(fop->v);
+            pids = 1;
+            cmdp = (LTfldo_t *)NULL;
+            for (fop++, ti = 1; ti < nf; fop++, ti++) {
+                switch (fop->ft) {
+                case LSOF_FID_CMD:
+                    cmdp = fop;
+                    break;
+                }
+            }
+            if (!cmdp || (pid != MyPid))
+                pids = 0;
+            break;
+        case LSOF_FID_FD:
+
+            /*
+             * This is a file descriptor line.  Make sure its number matches the
+             * test file's descriptor number.
+             */
+            if (!pids)
+                break;
+            for (ti = 0, tcp = fop->v; *tcp; tcp++) {
+
+                /*
+                 * Convert file descriptor to a number.
+                 */
+                if (*tcp == ' ')
+                    continue;
+                if (((int)*tcp < (int)'0') || ((int)*tcp > (int)'9')) {
+                    ti = -1;
+                    break;
+                }
+                ti = (ti * 10) + (int)*tcp - (int)'0';
+            }
+            if (Fd != ti)
+                break;
+            /*
+             * Scan for device, inode, nlink, size and type fields.
+             */
+            devp = inop = nlkp = szp = typ = (LTfldo_t *)NULL;
+            for (fop++, ti = 1; ti < nf; fop++, ti++) {
+                switch (fop->ft) {
+                case LSOF_FID_DEVN:
+                    devp = fop;
+                    break;
+                case LSOF_FID_INODE:
+                    inop = fop;
+                    break;
+                case LSOF_FID_NLINK:
+                    nlkp = fop;
+                    break;
+                case LSOF_FID_SIZE:
+                    szp = fop;
+                    break;
+                case LSOF_FID_TYPE:
+                    typ = fop;
+                    break;
+                }
+            }
+            /*
+             * Check the device, inode, and type of the file.
+             */
+            if (!devp || !inop || !szp || !typ)
+                break;
+            if (strcasecmp(typ->v, "reg") && strcasecmp(typ->v, "vreg"))
+                break;
+            if ((cem = ConvLsofDev(devp->v, &lsofdc))) {
+                if (pem)
+                    (void)PrtMsg(pem, Pn);
+                pem = cem;
+                break;
+            }
+            if ((tfdc->maj != lsofdc.maj) || (tfdc->min != lsofdc.min) ||
+                (tfdc->unit != lsofdc.unit) || strcmp(inop->v, ibuf)) {
+                break;
+            }
+            /*
+             * Indicate the file was found.
+             */
+            *ff = 1;
+            /*
+             * Check the size and link count.
+             */
+            if (!szp) {
+                (void)snprintf(
+                    buf, sizeof(buf) - 1,
+                    "ERROR!!!  lsof didn't report a file size for %s", Path);
+                buf[sizeof(buf) - 1] = '\0';
+                cem = MkStrCpy(buf, &ti);
+                if (pem)
+                    (void)PrtMsg(pem, Pn);
+                pem = cem;
+                break;
+            }
+            if (strcmp(szp->v, szbuf)) {
+                (void)snprintf(buf, sizeof(buf) - 1,
+                               "ERROR!!!  wrong file size: expected %s, got %s",
+                               szbuf, szp->v);
+                buf[sizeof(buf) - 1] = '\0';
+                cem = MkStrCpy(buf, &ti);
+                if (pem)
+                    (void)PrtMsg(pem, Pn);
+                pem = cem;
+                break;
+            }
+            if (!nlkp) {
+                if (strcmp(xlnk, "0")) {
+
+                    /*
+                     * If lsof returned no link count and the expected return is
+                     * not "0", it's an error.  Otherwise, interpret no link
+                     * count as equivalent to a "0" link count.
+                     */
+                    (void)snprintf(
+                        buf, sizeof(buf) - 1,
+                        "ERROR!!!  lsof didn't report a link count for %s",
+                        Path);
+                    buf[sizeof(buf) - 1] = '\0';
+                    cem = MkStrCpy(buf, &ti);
+                    if (pem)
+                        (void)PrtMsg(pem, Pn);
+                    pem = cem;
+                    break;
+                }
+            } else {
+                if (strcmp(nlkp->v, xlnk)) {
+                    (void)snprintf(
+                        buf, sizeof(buf) - 1,
+                        "ERROR!!!  wrong link count: expected %s, got %s", xlnk,
+                        nlkp->v);
+                    buf[sizeof(buf) - 1] = '\0';
+                    cem = MkStrCpy(buf, &ti);
+                    if (pem)
+                        (void)PrtMsg(pem, Pn);
+                    pem = cem;
+                    break;
+                }
+            }
+            /*
+             * The requested file was located.  Return the previous error
+             * message pointer unless errors are being ignored.  (The previous
+             * error message pointer  will be NULL if no error was detected.)
+             */
+            (void)StopLsof();
+            if (ie)
+                return ((char *)NULL);
+            return (pem);
+        }
+    }
+    /*
+     * Clean up and return.
+     */
+    (void)StopLsof();
+    if (!*ff && !ie) {
+        if (pem)
+            (void)PrtMsg(pem, Pn);
+        (void)snprintf(buf, sizeof(buf) - 1,
+                       "ERROR!!!  %s test file %s not found by lsof",
+                       strcmp(xlnk, "0") ? "linked" : "unlinked", Path);
+        buf[sizeof(buf) - 1] = '\0';
+        pem = MkStrCpy(buf, &ti);
+    }
+    if (ie)
+        return ((char *)NULL);
+    return (pem);
+}
diff --git a/tests/LTsock.c b/tests/LTsock.c
new file mode 100644 (file)
index 0000000..7c582e1
--- /dev/null
@@ -0,0 +1,842 @@
+/*
+ * LTsock.c -- Lsof Test IPv4 sockets
+ *
+ * V. Abell
+ * Purdue University
+ */
+
+/*
+ * Copyright 2002 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by V. 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.
+ */
+
+#include "LsofTest.h"
+#include "lsof_fields.h"
+
+#include <netdb.h>
+#include <signal.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+/*
+ * Pre-definitions that make be changed or revoked by dialects
+ */
+
+#define SIGHANDLER_T void /* signal handler function type */
+#define LT_SOCKLEN_T int  /* socket length type */
+
+#if defined(LT_DIAL_aix)
+/*
+ * AIX-specific items
+ */
+
+#    undef LT_SOCKLEN_T
+#    define LT_SOCKLEN_T size_t
+#endif /* defined(LT_DIAL_aix) */
+
+#if defined(LT_DIAL_darwin)
+/*
+ * Darwin-specific items
+ */
+
+#    if LT_VERS >= 800
+#        undef LT_SOCKLEN_T
+#        define LT_SOCKLEN_T socklen_t
+#    endif /* LT_VERS>=800 */
+#endif     /* defined(LT_DIAL_darwin) */
+
+#if defined(LT_DIAL_freebsd)
+/*
+ * FreeBSD-specific items
+ */
+#    undef LT_SOCKLEN_T
+#    define LT_SOCKLEN_T socklen_t
+#endif /* defined(LT_DIAL_freebsd) */
+
+#if defined(LT_DIAL_hpux)
+/*
+ * HP-UX-specific items
+ */
+
+#    if LT_VERS >= 1123 && defined(__GNUC__)
+#        undef LT_SOCKLEN_T
+#        define LT_SOCKLEN_T size_t
+#    endif /* LT_VERS>=1123 && defined(__GNUC__) */
+#endif     /* defined(LT_DIAL_hpux) */
+
+#if defined(LT_DIAL_linux)
+/*
+ * Linux-specific items
+ */
+
+#    undef LT_SOCKLEN_T
+#    define LT_SOCKLEN_T socklen_t
+#endif /* defined(LT_DIAL_linux) */
+
+#if defined(LT_DIAL_ou)
+/*
+ * OpenUNIX-specific items
+ */
+
+#    undef LT_SOCKLEN_T
+#    define LT_SOCKLEN_T size_t
+#endif /* defined(LT_DIAL_ou) */
+
+#if defined(LT_DIAL_uw)
+/*
+ * UnixWare-specific items
+ */
+
+#    undef LT_SOCKLEN_T
+#    define LT_SOCKLEN_T size_t
+#endif /* defined(LT_DIAL_uw) */
+
+/*
+ * Local definitions
+ */
+
+#define ALARMTM 30 /* alarm timer */
+
+#define LT_CLNT 0 /* child process index */
+#define LT_SRVR 1 /* parent process index */
+
+#define LT_FNF 0     /* file not found */
+#define LT_FBYIP 1   /* file found by IP address */
+#define LT_FBYHN 2   /* file found by host name */
+#define LT_FBYPORT 4 /* file found by port */
+
+#if !defined(MAXHOSTNAMELEN)
+#    define MAXHOSTNAMELEN 256 /* maximum host name length */
+#endif                         /* !defined(MAXHOSTNAMELEN) */
+
+#if !defined(MAXPATHLEN)
+#    define MAXPATHLEN 1024 /* maximum path length */
+#endif                      /* !defined(MAXPATHLEN) */
+
+/*
+ * Local structure definitions.
+ */
+
+typedef struct fdpara {    /* file descriptor parameters */
+    int fd;                /* FD */
+    char *fds;             /* FD in ASCII */
+    int ff;                /* file found flags (see LT_F*) */
+    char *host;            /* host name */
+    int hlen;              /* strlen(host) */
+    char *ipaddr;          /* dotted IP address */
+    int ilen;              /* strlen(ipaddr) */
+    pid_t pid;             /* PID of process */
+    char *port;            /* port in ASCII */
+    int plen;              /* strlen(port) */
+    struct sockaddr_in sa; /* socket's address */
+} fdpara_t;
+
+/*
+ * Globals
+ */
+
+pid_t CPid = (pid_t)0; /* client PID */
+fdpara_t FdPara[2];    /* file descriptor parameters */
+#define NFDPARA (sizeof(FdPara) / sizeof(fdpara_t))
+struct sockaddr_in Myad; /* my (server) socket address */
+pid_t MyPid = (pid_t)0;  /* PID of this process */
+char *Pn = (char *)NULL; /* program name */
+char *PtNm[] = {"client", "server"};
+/* program type name */
+int Ssock = -1; /* server socket */
+
+/*
+ * Local function prototypes
+ */
+
+static void CleanupClnt(void);
+static void CleanupSrvr(void);
+static SIGHANDLER_T HandleClntAlarm(int sig);
+static SIGHANDLER_T HandleSrvrAlarm(int sig);
+static char *FindSock(int fn);
+static void StartClnt(struct sockaddr_in *cad);
+
+/*
+ * Main program
+ */
+
+int main(int argc,     /* argument count */
+         char *argv[]) /* arguments */
+{
+    struct sockaddr_in aa;        /* accept address */
+    struct sockaddr_in ba;        /* bind address */
+    char buf[2048];               /* temporary buffer */
+    int bufl = sizeof(buf);       /* size of buf[] */
+    struct sockaddr_in ca;        /* connect address */
+    char *cem;                    /* current error message pointer */
+    char *ep;                     /* error message parameter */
+    char hnm[MAXHOSTNAMELEN + 1]; /* this host's name */
+    char *host;                   /* host name */
+    struct hostent *hp;           /* this host's hostent structure */
+    char *ipaddr;                 /* IP address */
+    char *pem = (char *)NULL;     /* previous error message */
+    char *port;                   /* port */
+    LT_SOCKLEN_T sal;             /* socket address length */
+    char *tcp;                    /* temporary character size */
+    int ti, tj, tk;               /* temporary indexes */
+    int tsfd;                     /* temporary socket FD */
+    int xv = 0;                   /* exit value */
+                                  /*
+                                   * Get program name and PID, issue start message, and build space prefix.
+                                   */
+    if ((Pn = strrchr(argv[0], '/')))
+        Pn++;
+    else
+        Pn = argv[0];
+    MyPid = getpid();
+    (void)printf("%s ... ", Pn);
+    (void)fflush(stdout);
+    PrtMsg((char *)NULL, Pn);
+    /*
+     * Initalize the FdPara[] array before any CleanupClnt() call.
+     */
+    for (ti = 0; ti < NFDPARA; ti++) {
+        (void)memset((void *)&FdPara[ti], 0, sizeof(fdpara_t));
+        FdPara[ti].fd = -1;
+        FdPara[ti].ff = LT_FNF;
+    }
+    /*
+     * Process arguments.
+     */
+    if (ScanArg(argc, argv, "h", Pn))
+        xv = 1;
+    if (xv || LTopt_h) {
+        (void)PrtMsg("usage: [-h]", Pn);
+        PrtMsgX("       -h       print help (this panel)", Pn, CleanupSrvr, xv);
+    }
+    /*
+     * See if lsof can be executed and can access kernel memory.
+     */
+    if ((cem = IsLsofExec()))
+        (void)PrtMsgX(cem, Pn, CleanupSrvr, 1);
+    if ((cem = CanRdKmem()))
+        (void)PrtMsgX(cem, Pn, CleanupSrvr, 1);
+    /*
+     * Get the host name and its IP address.  Convert the IP address to dotted
+     * ASCII form.
+     */
+    if (gethostname(hnm, sizeof(hnm) - 1)) {
+        cem = "ERROR!!!  can't get this host's name";
+        goto print_errno;
+    }
+    hnm[sizeof(hnm) - 1] = '\0';
+    if (!(hp = gethostbyname(hnm))) {
+        // fallback to localhost if hostname cannot be resolved
+        strcpy(hnm, "localhost");
+        if (!(hp = gethostbyname(hnm))) {
+            (void)snprintf(buf, bufl - 1,
+                           "ERROR!!!  can't get IP address for %s", hnm);
+            buf[bufl - 1] = '\0';
+            cem = buf;
+            goto print_errno;
+        }
+    }
+    (void)memset((void *)&Myad, 0, sizeof(Myad));
+    if ((ti = hp->h_length) > sizeof(Myad.sin_addr))
+        ti = sizeof(Myad.sin_addr);
+    (void)memcpy((void *)&Myad.sin_addr, (void *)hp->h_addr, ti);
+    Myad.sin_family = hp->h_addrtype;
+    /*
+     * Get INET domain socket FDs.
+     */
+    for (ti = 0; ti < NFDPARA; ti++) {
+        if ((tsfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+            ep = "socket";
+
+        print_errno_by_ti:
+
+            /*
+             * Report socket function error.
+             *
+             * Entry: ep   = function name
+             *   hnm  = this host's name
+             *   Myad = this host's IP address
+             *   ti   =  FdPara[] index
+             */
+            (void)snprintf(buf, bufl - 1, "ERROR!!!  %s %s() failure", PtNm[ti],
+                           ep);
+            buf[bufl - 1] = '\0';
+            PrtMsg(buf, Pn);
+            (void)snprintf(buf, bufl - 1, "    host: %s",
+                           FdPara[ti].host ? FdPara[ti].host : hnm);
+            buf[bufl - 1] = '\0';
+            PrtMsg(buf, Pn);
+            (void)snprintf(buf, bufl - 1, "    IP: %s",
+                           FdPara[ti].ipaddr ? FdPara[ti].ipaddr
+                                             : inet_ntoa(Myad.sin_addr));
+            buf[bufl - 1] = '\0';
+            cem = buf;
+
+        print_errno:
+
+            /*
+             * Report errno.
+             *
+             * Entry: errno = error number
+             */
+            PrtMsg(cem, Pn);
+            (void)snprintf(buf, bufl - 1, "    Errno %d: %s", errno,
+                           strerror(errno));
+            buf[bufl - 1] = '\0';
+            PrtMsgX(buf, Pn, CleanupSrvr, 1);
+        }
+        /*
+         * Put the FD just acquired in FdPara[ti].fd.
+         *
+         * Set the file-not-found to LT_FNF.
+         *
+         * Save the server socket if this FdPara[] is for it.
+         */
+        FdPara[ti].fd = tsfd;
+        (void)snprintf(buf, bufl - 1, "%d", tsfd);
+        buf[bufl - 1] = '\0';
+        FdPara[ti].fds = MkStrCpy(buf, &tj);
+        if (ti == LT_SRVR)
+            Ssock = tsfd;
+    }
+    /*
+     * Bind the host name to the server socket.
+     *
+     * Get and save the server's socket address.
+     *
+     * Initiate a listen with an address list of one.
+     */
+    (void)memcpy((void *)&ba, (void *)&Myad, sizeof(ba));
+    ti = LT_SRVR;
+    FdPara[ti].pid = MyPid;
+    if (bind(Ssock, (struct sockaddr *)&ba, sizeof(ba)) < 0) {
+        ep = "bind";
+        goto print_errno_by_ti;
+    }
+    sal = (LT_SOCKLEN_T)sizeof(ca);
+    if (getsockname(Ssock, (struct sockaddr *)&ca, &sal)) {
+        ep = "getsockname";
+        goto print_errno_by_ti;
+    }
+    (void)memcpy((void *)&FdPara[ti].sa, (void *)&ca, sizeof(FdPara[ti].sa));
+    if (listen(Ssock, 1) < 0) {
+        ep = "listen";
+        goto print_errno_by_ti;
+    }
+    /*
+     * Fork a child process to run as the client.
+     */
+    switch ((CPid = (pid_t)fork())) {
+    case (pid_t)0:
+
+        /*
+         * This is the child.  Start the client.
+         */
+        StartClnt(&ca);
+        (void)PrtMsgX("ERROR!!!  unexpected client return", Pn, CleanupSrvr, 1);
+    case (pid_t)-1:
+
+        /*
+         * This is a fork error.
+         */
+        cem = "ERROR!!! fork() error";
+        goto print_errno;
+    default:
+
+        /*
+         * This is the parent.
+         *
+         * Save the client's PID.
+         *
+         * Close the client's socket.
+         */
+        FdPara[LT_CLNT].pid = CPid;
+        if (FdPara[LT_CLNT].fd >= 0) {
+            (void)close(FdPara[LT_CLNT].fd);
+            FdPara[LT_CLNT].fd = -1;
+        }
+    }
+    /*
+     * Set a SIGALRM, then accept() the connection from the client.
+     *
+     * Save the client's socket address.
+     *
+     * Replace the server's FD with the accepted one and close the original.
+     */
+    sal = (LT_SOCKLEN_T)sizeof(aa);
+    (void)alarm(0);
+    (void)signal(SIGALRM, HandleSrvrAlarm);
+    (void)alarm(ALARMTM);
+    tsfd = FdPara[LT_SRVR].fd = accept(Ssock, (struct sockaddr *)&aa, &sal);
+    (void)alarm(0);
+    (void)signal(SIGALRM, SIG_DFL);
+    if (tsfd < 0) {
+        ep = "accept";
+        goto print_errno_by_ti;
+    }
+    (void)snprintf(buf, bufl - 1, "%d", tsfd);
+    buf[bufl - 1] = '\0';
+    if (FdPara[LT_SRVR].fds)
+        (void)free((void *)FdPara[LT_SRVR].fds);
+    FdPara[LT_SRVR].fds = MkStrCpy(buf, &tj);
+    ti = LT_CLNT;
+    (void)memcpy((void *)&FdPara[ti].sa, (void *)&aa, sizeof(FdPara[ti].sa));
+    (void)close(Ssock);
+    Ssock = -1;
+    /*
+     * Convert the client and server IP address to ASCII form.
+     *
+     * Look up the client and server host names for their IP addresses.
+     *
+     * Convert the port from the socket address to host form.
+     */
+    for (ti = 0; ti < NFDPARA; ti++) {
+        tcp = inet_ntoa(FdPara[ti].sa.sin_addr);
+        FdPara[ti].ipaddr = MkStrCpy(tcp, &FdPara[ti].ilen);
+        (void)snprintf(buf, bufl - 1, "%d", (int)ntohs(FdPara[ti].sa.sin_port));
+        buf[bufl - 1] = '\0';
+        FdPara[ti].port = MkStrCpy(buf, &FdPara[ti].plen);
+        if (!(hp = gethostbyaddr((char *)&FdPara[ti].sa.sin_addr,
+                                 sizeof(FdPara[ti].sa.sin_addr),
+                                 FdPara[ti].sa.sin_family))) {
+            ep = "gethostbyaddr";
+            goto print_errno_by_ti;
+        }
+        if (hp->h_name)
+            FdPara[ti].host = MkStrCpy(hp->h_name, &FdPara[ti].hlen);
+        else {
+
+            /*
+             * The connected client's socket address can't be mapped to a host
+             * name.
+             */
+
+            (void)snprintf(buf, bufl - 1,
+                           "ERROR!!!  can't map %s (client) to a host name",
+                           FdPara[ti].ipaddr);
+            buf[bufl - 1] = '\0';
+            PrtMsgX(buf, Pn, CleanupSrvr, 1);
+        }
+    }
+    /*
+     * Call lsof three times to find the two sockets: 1) by host name and port;
+     * 2) by IP address and port; and 3) by port.
+     */
+    if ((cem = FindSock(LT_FBYHN)))
+        PrtMsgX(cem, Pn, CleanupSrvr, 1);
+    if ((cem = FindSock(LT_FBYIP)))
+        PrtMsgX(cem, Pn, CleanupSrvr, 1);
+    if ((cem = FindSock(LT_FBYPORT)))
+        PrtMsgX(cem, Pn, CleanupSrvr, 1);
+    /*
+     * Check the FindSock() results.
+     */
+    for (pem = (char *)NULL, ti = 0; ti < NFDPARA; ti++) {
+        if ((tj = FdPara[ti].ff) != (LT_FBYHN | LT_FBYIP | LT_FBYPORT)) {
+            host = FdPara[ti].host;
+            ipaddr = FdPara[ti].ipaddr;
+            port = FdPara[ti].port;
+
+            /*
+             * This FD wasn't found by some search method.
+             */
+            if (!(tj & LT_FBYHN)) {
+
+                /*
+                 * The search by host name and port failed.
+                 */
+                (void)snprintf(buf, bufl - 1,
+                               "ERROR!!!  no %s socket by host and port: %s@%s",
+                               PtNm[ti], host, port);
+                buf[bufl - 1] = '\0';
+                if (pem)
+                    (void)PrtMsg(pem, Pn);
+                pem = MkStrCpy(buf, &tk);
+            }
+            if (!(tj & LT_FBYIP)) {
+
+                /*
+                 * The search by IP address and port failed.
+                 */
+                (void)snprintf(buf, bufl - 1,
+                               "ERROR!!!  no %s socket by IP and port: %s@%s",
+                               PtNm[ti], ipaddr, port);
+                buf[bufl - 1] = '\0';
+                if (pem)
+                    (void)PrtMsg(pem, Pn);
+                pem = MkStrCpy(buf, &tk);
+            }
+            if (!(tj & LT_FBYPORT)) {
+
+                /*
+                 * The search by port number failed.
+                 */
+                (void)snprintf(buf, bufl - 1,
+                               "ERROR!!!  no %s socket by port: %s", PtNm[ti],
+                               port);
+                buf[bufl - 1] = '\0';
+                if (pem)
+                    (void)PrtMsg(pem, Pn);
+                pem = MkStrCpy(buf, &tk);
+            }
+        }
+    }
+    if (pem)
+        (void)PrtMsgX(pem, Pn, CleanupSrvr, 1);
+    /*
+     * Exit successfully.
+     */
+    (void)PrtMsgX("OK", Pn, CleanupSrvr, 0);
+    return (0);
+}
+
+/*
+ * ClntCleanup() -- release client resources
+ */
+
+static void CleanupClnt() {
+    int tfd; /* temporary file descriptor */
+
+    if ((tfd = FdPara[LT_CLNT].fd) >= 0) {
+        (void)shutdown(tfd, 2);
+        (void)close(tfd);
+        FdPara[LT_CLNT].fd = -1;
+    }
+}
+
+/*
+ * CleanupSrvr() -- release server resources
+ */
+
+static void CleanupSrvr() {
+    int tfd;    /* temporary file descriptor */
+    int ti;     /* temporary index */
+    pid_t wpid; /* wait() PID */
+
+    if ((Ssock >= 0) && (Ssock != FdPara[LT_SRVR].fd)) {
+        (void)shutdown(Ssock, 2);
+        (void)close(Ssock);
+        Ssock = -1;
+    }
+    for (ti = 0; ti < NFDPARA; ti++) {
+        if ((tfd = FdPara[ti].fd) >= 0) {
+            (void)shutdown(tfd, 2);
+            (void)close(tfd);
+            FdPara[ti].fd = -1;
+        }
+    }
+    if (CPid > 0) {
+        wpid = wait3(NULL, WNOHANG, NULL);
+        if (wpid != CPid) {
+            kill(CPid, SIGKILL);
+            (void)wait3(NULL, WNOHANG, NULL);
+        }
+        CPid = (pid_t)0;
+    }
+}
+
+/*
+ * FindSock() -- find sockets with lsof
+ */
+
+static char *FindSock(int fn) /* function -- an LT_FBY* value */
+{
+    char buf[2048];           /* temporary buffer */
+    int bufl = sizeof(buf);   /* size of buf[] */
+    char *cem;                /* current error message pointer */
+    LTfldo_t *cmdp;           /* command pointer */
+    LTfldo_t *fop;            /* field output pointer */
+    int nf;                   /* number of fields */
+    int nl;                   /* name length */
+    LTfldo_t *nmp;            /* name pointer */
+    char *opv[5];             /* option vector for ExecLsof() */
+    char *pem = (char *)NULL; /* previous error message pointer */
+    pid_t pid;                /* PID */
+    int pids = 0;             /* PID found status */
+    int pl;                   /* port length */
+    int px;                   /* process index -- LT_CLNT or
+                               * LT_SRVR */
+    char *tcp, *tcp1;         /* temporary character pointers */
+    int ti, tj;               /* temporary integers */
+    LTfldo_t *typ;            /* file type pointer */
+                              /*
+                               * Check the function and determine the first lsof option from it.
+                               */
+    ti = 0;
+    switch (fn) {
+    case LT_FBYHN:
+        opv[ti++] = "-P";
+        for (tj = 0; tj < NFDPARA; tj++) {
+            (void)snprintf(buf, bufl - 1, "-i@%s:%s", FdPara[tj].host,
+                           FdPara[tj].port);
+            buf[bufl - 1] = '\0';
+            opv[ti++] = MkStrCpy(buf, &pl);
+        }
+        break;
+    case LT_FBYIP:
+        opv[ti++] = "-Pn";
+        for (tj = 0; tj < NFDPARA; tj++) {
+            (void)snprintf(buf, bufl - 1, "-i@%s:%s", FdPara[tj].ipaddr,
+                           FdPara[tj].port);
+            buf[bufl - 1] = '\0';
+            opv[ti++] = MkStrCpy(buf, &pl);
+        }
+        break;
+    case LT_FBYPORT:
+        opv[ti++] = "-P";
+        for (tj = 0; tj < NFDPARA; tj++) {
+            (void)snprintf(buf, bufl - 1, "-i:%s", FdPara[tj].port);
+            buf[bufl - 1] = '\0';
+            opv[ti++] = MkStrCpy(buf, &pl);
+        }
+        break;
+    default:
+        (void)snprintf(buf, bufl - 1,
+                       "ERROR!!!  illegal FindSock() function: %d", fn);
+        buf[bufl - 1] = '\0';
+        return (MkStrCpy(buf, &ti));
+    }
+    /*
+     * Complete the option vector and start lsof execution.
+     */
+
+#if defined(USE_LSOF_C_OPT)
+    opv[ti++] = "-C";
+#endif /* defined(USE_LSOF_C_OPT) */
+
+    opv[ti] = (char *)NULL;
+    if ((cem = ExecLsof(opv)))
+        return (cem);
+    /*
+     * Read lsof output.
+     */
+    while ((((FdPara[LT_CLNT].ff & fn) == 0) ||
+            ((FdPara[LT_SRVR].ff & fn) == 0)) &&
+           (fop = RdFrLsof(&nf, &cem))) {
+        if (cem) {
+            if (pem)
+                (void)PrtMsg(pem, Pn);
+            return (cem);
+        }
+        switch (fop->ft) {
+        case LSOF_FID_PID:
+
+            /*
+             * This is a process information line.
+             */
+            pid = (pid_t)atoi(fop->v);
+            pids = 1;
+            cmdp = (LTfldo_t *)NULL;
+            for (fop++, ti = 1; ti < nf; fop++, ti++) {
+                switch (fop->ft) {
+                case LSOF_FID_CMD:
+                    cmdp = fop;
+                    break;
+                }
+            }
+            if (!cmdp || ((pid != CPid) && (pid != MyPid)))
+                pids = 0;
+            break;
+        case LSOF_FID_FD:
+
+            /*
+             * This is a file descriptor line.
+             *
+             * Identify the process -- client or server.
+             */
+            if (!pids)
+                break;
+            if (pid == CPid)
+                px = LT_CLNT;
+            else if (pid == MyPid)
+                px = LT_SRVR;
+            else
+                break;
+            /*
+             * Make sure the FD matches the identified process.
+             */
+            if (strcmp(fop->v, FdPara[px].fds))
+                break;
+            /*
+             * Scan for name and type.
+             */
+            nmp = typ = (LTfldo_t *)NULL;
+            for (fop++, ti = 1; ti < nf; fop++, ti++) {
+                switch (fop->ft) {
+                case LSOF_FID_NAME:
+                    nmp = fop;
+                    break;
+                case LSOF_FID_TYPE:
+                    typ = fop;
+                    break;
+                }
+            }
+            /*
+             * Check the type of the file.
+             */
+            if (!typ ||
+                (strcasecmp(typ->v, "inet") && strcasecmp(typ->v, "ipv4"))) {
+                break;
+            }
+            /*
+             * Check the addess in the name, based on the calling function.
+             */
+            if (!nmp)
+                break;
+            tcp = nmp->v;
+            switch (fn) {
+            case LT_FBYHN:
+                if (((nl = FdPara[px].hlen) <= 0) ||
+                    !(tcp1 = FdPara[px].host) || strncasecmp(tcp, tcp1, nl)) {
+                    break;
+                }
+                tcp += nl;
+                if ((*tcp++ != ':') || !(tcp1 = FdPara[px].port) ||
+                    ((pl = FdPara[px].plen) <= 0) || strncmp(tcp, tcp1, pl)) {
+                    break;
+                }
+                tcp += pl;
+                if ((*tcp == '-') || (*tcp == ' ') || !*tcp) {
+                    FdPara[px].ff |= LT_FBYHN;
+                }
+                break;
+            case LT_FBYIP:
+                if (((nl = FdPara[px].ilen) <= 0) ||
+                    !(tcp1 = FdPara[px].ipaddr) || strncasecmp(tcp, tcp1, nl)) {
+                    break;
+                }
+                tcp += nl;
+                if ((*tcp++ != ':') || !(tcp1 = FdPara[px].port) ||
+                    ((pl = FdPara[px].plen) <= 0) || strncmp(tcp, tcp1, pl)) {
+                    break;
+                }
+                tcp += pl;
+                if ((*tcp == '-') || (*tcp == ' ') || !*tcp) {
+                    FdPara[px].ff |= LT_FBYIP;
+                }
+                break;
+            case LT_FBYPORT:
+                if (!(tcp = strchr(tcp, ':')))
+                    break;
+                tcp++;
+                if (!(tcp1 = FdPara[px].port) ||
+                    ((pl = FdPara[px].plen) <= 0) || strncmp(tcp, tcp1, pl)) {
+                    break;
+                }
+                tcp += pl;
+                if ((*tcp == '-') || (*tcp == ' ') || !*tcp) {
+                    FdPara[px].ff |= LT_FBYPORT;
+                }
+                break;
+            }
+        }
+    }
+    /*
+     * Clean up and return.
+     */
+    (void)StopLsof();
+    return (pem);
+}
+
+/*
+ * HandleClntAlarm() -- handle client alarm
+ */
+
+static SIGHANDLER_T HandleClntAlarm(int sig) /* the signal (SIGALRM) */
+{
+    (void)PrtMsgX("ERROR!!!  client caught an alarm signal", Pn, CleanupClnt,
+                  1);
+}
+
+/*
+ * Handle SrvrAlarm() -- handle server alarm
+ */
+
+static SIGHANDLER_T HandleSrvrAlarm(int sig) /* the signal (SIGALRM) */
+{
+    (void)PrtMsgX("ERROR!!!  server caught an alarm signal.", Pn, CleanupSrvr,
+                  1);
+}
+
+/*
+ * StartClnt() -- start network client
+ */
+
+static void StartClnt(cad) struct sockaddr_in *cad; /* connection address */
+{
+    struct sockaddr_in ba;       /* bind address */
+    int br;                      /* bytes read */
+    char buf[2048];              /* temporary buffer */
+    int bufl = sizeof(buf);      /* size of buf[] */
+    int cr;                      /* connect() reply */
+    char *em;                    /* error message pointer */
+    int fd = FdPara[LT_CLNT].fd; /* client's socket FD */
+                                 /*
+                                  * Close the server's sockets.
+                                  */
+    if ((Ssock >= 0) && (Ssock != FdPara[LT_SRVR].fd)) {
+        (void)close(Ssock);
+        Ssock = -1;
+    }
+    if (FdPara[LT_SRVR].fd >= 0) {
+        (void)close(FdPara[LT_SRVR].fd);
+        FdPara[LT_SRVR].fd = -1;
+    }
+    /*
+     * Bind to the local address.
+     */
+    (void)memcpy((void *)&ba, (void *)&Myad, sizeof(ba));
+    if (bind(fd, (struct sockaddr *)&ba, sizeof(ba)) < 0) {
+        em = "bind";
+
+    client_errno:
+
+        (void)snprintf(buf, bufl - 1, "ERROR!!!  client %s error: %s", em,
+                       strerror(errno));
+        buf[bufl - 1] = '\0';
+        (void)PrtMsgX(em, Pn, CleanupClnt, 1);
+    }
+    /*
+     * Set an alarm timeout and connect to the server.
+     */
+    (void)signal(SIGALRM, HandleClntAlarm);
+    (void)alarm(ALARMTM);
+    cr = connect(fd, (struct sockaddr *)cad, sizeof(struct sockaddr_in));
+    (void)alarm(0);
+    (void)signal(SIGALRM, SIG_DFL);
+    if (cr) {
+        em = "connect";
+        goto client_errno;
+    }
+    /*
+     * Sleep until the socket closes or the parent kills the process.
+     */
+    for (br = 0; br >= 0;) {
+        sleep(1);
+        br = read(fd, buf, bufl);
+    }
+    (void)CleanupClnt();
+    exit(0);
+}
diff --git a/tests/LTszoff.c b/tests/LTszoff.c
new file mode 100644 (file)
index 0000000..148a891
--- /dev/null
@@ -0,0 +1,486 @@
+/*
+ * LTszoff.c -- Lsof Test small file (< 32 bits) size and offset tests
+ *
+ * V. Abell
+ * Purdue University
+ */
+
+/*
+ * Copyright 2002 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by V. 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.
+ */
+
+#include "LsofTest.h"
+#include "lsof_fields.h"
+
+/*
+ * Pre-definitions that might be undefined by dialects
+ */
+
+#define OFFTST_STAT 1 /* offset tests status */
+
+#if defined(LT_DIAL_linux)
+/*
+ * Linux-specific items
+ */
+
+#    undef OFFTST_STAT
+#    define OFFTST_STAT                                                        \
+        0 /* Linux lsof may not be able to report                              \
+           * offsets -- see the function                                       \
+           * ck_Linux_offset_support() */
+
+static int ck_Linux_offset_support(void);
+#endif /* defined(LT_DIAL_linux) */
+
+/*
+ * Local definitions
+ */
+
+#define TYTST_SZ 0   /* size test type */
+#define TYTST_0to 1  /* 0t offset test type */
+#define TYTST_0xo 2  /* 0x offset test type */
+#define TSTFSZ 32768 /* test file size */
+
+/*
+ * Globals
+ */
+
+int Fd = -1;               /* test file descriptor; open if >= 0 */
+pid_t MyPid = (pid_t)0;    /* PID of this process */
+char *Path = (char *)NULL; /* test file path; none if NULL */
+char *Pn = (char *)NULL;   /* program name */
+
+/*
+ * Local function prototypes
+ */
+
+static void cleanup(void);
+static char *testlsof(int tt, char *opt, char *xval);
+
+/*
+ * Main program
+ */
+
+int main(int argc,     /* argument count */
+         char *argv[]) /* arguments */
+{
+    char buf[2048];              /* temporary buffer */
+    int do_offt = OFFTST_STAT;   /* do offset tests if == 1 */
+    char *em;                    /* error message pointer */
+    int ti;                      /* temporary index */
+    char *tcp;                   /* temporary character pointer */
+    char *tstsz = (char *)NULL;  /* size test status */
+    char *tst0to = (char *)NULL; /* offset 0t form test */
+    char *tst0xo = (char *)NULL; /* offset 0x form test */
+    int xv = 0;                  /* exit value */
+    char xbuf[64];               /* expected value buffer */
+                                 /*
+                                  * Get program name and PID, issue start message, and build space prefix.
+                                  */
+    if ((Pn = strrchr(argv[0], '/')))
+        Pn++;
+    else
+        Pn = argv[0];
+    MyPid = getpid();
+    (void)printf("%s ... ", Pn);
+    (void)fflush(stdout);
+    PrtMsg((char *)NULL, Pn);
+    /*
+     * Process arguments.
+     */
+    if (ScanArg(argc, argv, "hp:", Pn))
+        xv = 1;
+    if (xv || LTopt_h) {
+        (void)PrtMsg("usage: [-h] [-p path]", Pn);
+        PrtMsg("       -h       print help (this panel)", Pn);
+        PrtMsgX("       -p path  define test file path", Pn, cleanup, xv);
+    }
+
+#if defined(LT_DIAL_linux)
+    /*
+     * If this is Linux, see if lsof can report file offsets.
+     */
+    do_offt = ck_Linux_offset_support();
+#endif /* defined(LT_DIAL_linux) */
+
+    /*
+     * See if lsof can be executed and can access kernel memory.
+     */
+    if ((em = IsLsofExec()))
+        (void)PrtMsgX(em, Pn, cleanup, 1);
+    if ((em = CanRdKmem()))
+        (void)PrtMsgX(em, Pn, cleanup, 1);
+    /*
+     * If a path was supplied in an "-p path" option, use it.  Otherwise
+     * construct a path in the CWD.
+     */
+    if (!(Path = LTopt_p)) {
+        (void)snprintf(buf, sizeof(buf) - 1, "./config.LTszoff%ld",
+                       (long)MyPid);
+        buf[sizeof(buf) - 1] = '\0';
+        Path = MkStrCpy(buf, &ti);
+    }
+    /*
+     * Open a new test file at the specified path.
+     */
+    (void)unlink(Path);
+    if ((Fd = open(Path, O_RDWR | O_CREAT, 0600)) < 0) {
+        (void)fprintf(stderr, "ERROR!!!  can't open %s\n", Path);
+
+    print_file_error:
+
+        MsgStat = 1;
+        (void)snprintf(buf, sizeof(buf) - 1, "      Errno %d: %s", errno,
+                       strerror(errno));
+        buf[sizeof(buf) - 1] = '\0';
+        (void)PrtMsgX(buf, Pn, cleanup, 1);
+    }
+    /*
+     * Write the test file to its expected size.
+     */
+    for (ti = 0; ti < sizeof(buf); ti++) {
+        buf[ti] = (char)(ti & 0xff);
+    }
+    for (ti = 0; ti < TSTFSZ; ti += sizeof(buf)) {
+        if (write(Fd, buf, sizeof(buf)) != sizeof(buf)) {
+            (void)fprintf(stderr, "ERROR!!!  can't write %d bytes to %s\n",
+                          (int)sizeof(buf), Path);
+            goto print_file_error;
+        }
+    }
+    /*
+     * Fsync() the file.
+     */
+    if (fsync(Fd)) {
+        (void)fprintf(stderr, "ERROR!!!  can't fsync %s\n", Path);
+        goto print_file_error;
+    }
+    /*
+     * Do the tests.  Skip offset tests as indicated.
+     */
+    (void)snprintf(xbuf, sizeof(xbuf) - 1, "%d", TSTFSZ);
+    xbuf[sizeof(xbuf) - 1] = '\0';
+    if ((tstsz = testlsof(TYTST_SZ, "-s", xbuf)))
+        (void)PrtMsg(tstsz, Pn);
+    if (do_offt) {
+        (void)snprintf(xbuf, sizeof(xbuf) - 1, "0t%d", TSTFSZ);
+        xbuf[sizeof(xbuf) - 1] = '\0';
+        if ((tst0to = testlsof(TYTST_0to, "-o", xbuf)))
+            (void)PrtMsg(tst0to, Pn);
+        (void)snprintf(xbuf, sizeof(xbuf) - 1, "0x%x", TSTFSZ);
+        xbuf[sizeof(xbuf) - 1] = '\0';
+        if ((tst0xo = testlsof(TYTST_0xo, "-oo2", xbuf)))
+            (void)PrtMsg(tst0to, Pn);
+    } else {
+        PrtMsg("WARNING!!!  lsof can't return file offsets for this dialect,",
+               Pn);
+        PrtMsg("  so offset tests have been disabled.", Pn);
+    }
+    /*
+     * Compute exit value and exit.
+     */
+    if (tstsz || tst0to || tst0xo) {
+        tcp = (char *)NULL;
+        xv = 1;
+    } else {
+        tcp = "OK";
+        xv = 0;
+    }
+    (void)PrtMsgX(tcp, Pn, cleanup, xv);
+    return (0);
+}
+
+#if defined(LT_DIAL_linux)
+/*
+ * ck_Linux_offset_support() -- see if lsof can report offsets for this
+ *                             Linux implementation
+ */
+
+static int ck_Linux_offset_support() {
+    char buf[1024];         /* lsof output line buffer */
+    int bufl = sizeof(buf); /* size of buf[] */
+    char *opv[5];           /* option vector for lsof */
+    int rv = 1;             /* return value:
+                             *     0 == no lsof offset support
+                             *     1 == lsof offset support */
+                            /*
+                             * Ask lsof to report the test's FD zero offset.
+                             */
+    if (IsLsofExec())
+        return (0);
+    opv[0] = "-o";
+    snprintf(buf, bufl - 1, "-p%d", (int)getpid());
+    opv[1] = buf;
+    opv[2] = "-ad0";
+    opv[3] = "+w";
+    opv[4] = (char *)NULL;
+    if (ExecLsof(opv))
+        return (0);
+    /*
+     * Read the lsof output.  Look for a line with "WARNING: can't report
+     * offset" in it.  If it is found, then this Linux lsof can't report
+     * offsets.
+     */
+    while (fgets(buf, bufl - 1, LsofFs)) {
+        if (strstr(buf, "WARNING: can't report offset")) {
+            rv = 0;
+            break;
+        }
+    }
+    (void)StopLsof();
+    return (rv);
+}
+#endif /* defined(LT_DIAL_linux) */
+
+/*
+ * cleanup() -- release resources
+ */
+
+static void cleanup() {
+    if (Fd >= 0) {
+        (void)close(Fd);
+        Fd = -1;
+        if (Path) {
+            (void)unlink(Path);
+            Path = (char *)NULL;
+        }
+    }
+}
+
+/*
+ * testlsof() -- test the open file with lsof
+ */
+
+static char *testlsof(int tt,     /* test type -- TYTST_* symbol */
+                      char *opt,  /* extra lsof options */
+                      char *xval) /* expected value */
+{
+    char buf[2048];           /* temporary buffer */
+    char *cem;                /* current error message pointer */
+    LTfldo_t *cmdp;           /* command pointer */
+    LTfldo_t *devp;           /* device pointer */
+    int ff = 0;               /* file found status */
+    LTfldo_t *fop;            /* field output pointer */
+    char ibuf[64];            /* inode number buffer */
+    LTfldo_t *inop;           /* inode number pointer */
+    LTdev_t lsofdc;           /* lsof device components */
+    int nf;                   /* number of fields */
+    LTfldo_t *offp;           /* offset pointer */
+    char *opv[4];             /* option vector for ExecLsof() */
+    char *pem = (char *)NULL; /* previous error message pointer */
+    pid_t pid;                /* PID */
+    int pids = 0;             /* PID found status */
+    struct stat sb;           /* stat(2) buffer */
+    LTdev_t stdc;             /* stat(2) device components */
+    LTfldo_t *szp;            /* size pointer */
+    char *tcp;                /* temporary character pointer */
+    int ti;                   /* temporary integer */
+    char *tnm1, *tnm2;        /* test names */
+    int ts = 0;               /* test status flag */
+    LTfldo_t *typ;            /* file type pointer */
+                              /*
+                               * Check the test type.
+                               */
+    switch (tt) {
+    case TYTST_SZ:
+        tnm1 = "";
+        tnm2 = " size";
+        break;
+    case TYTST_0to:
+        tnm1 = " 0t";
+        tnm2 = " offset";
+        break;
+    case TYTST_0xo:
+        tnm1 = " 0x";
+        tnm2 = " offset";
+        break;
+    default:
+        (void)snprintf(buf, sizeof(buf) - 1, "ERROR!!!  illegal test type: %d",
+                       tt);
+        buf[sizeof(buf) - 1] = '\0';
+        (void)PrtMsgX(buf, Pn, cleanup, 1);
+    }
+    /*
+     * Get test file's information.
+     */
+    if (stat(Path, &sb)) {
+        (void)snprintf(buf, sizeof(buf) - 1, "ERROR!!!  can't stat(2) %s: %s",
+                       Path, strerror(errno));
+        buf[sizeof(buf) - 1] = '\0';
+        PrtMsgX(buf, Pn, cleanup, 1);
+    }
+    /*
+     * Extract components from test file's stat buffer.
+     */
+    if ((cem = ConvStatDev(&sb.st_dev, &stdc)))
+        PrtMsgX(buf, Pn, cleanup, 1);
+    (void)snprintf(ibuf, sizeof(ibuf) - 1, "%" PRIu64, (uint64_t)sb.st_ino);
+    ibuf[sizeof(ibuf) - 1] = '\0';
+    /*
+     * Complete the option vector and start lsof execution.
+     */
+    ti = 0;
+    if (opt && *opt)
+        opv[ti++] = opt;
+
+#if defined(USE_LSOF_C_OPT)
+    opv[ti++] = "-C";
+#else  /* !defined(USE_LSOF_C_OPT) */
+    opv[ti++] = "--";
+#endif /* defined(USE_LSOF_C_OPT) */
+
+    opv[ti++] = Path;
+    opv[ti] = (char *)NULL;
+    if ((cem = ExecLsof(opv)))
+        return (cem);
+    /*
+     * Read lsof output.
+     */
+    while (!ff && !cem && (fop = RdFrLsof(&nf, &cem))) {
+        if (cem) {
+            if (pem)
+                (void)PrtMsg(pem, Pn);
+            return (cem);
+        }
+        switch (fop->ft) {
+        case LSOF_FID_PID:
+
+            /*
+             * This is a process information line.
+             */
+            pid = (pid_t)atoi(fop->v);
+            pids = 1;
+            cmdp = (LTfldo_t *)NULL;
+            for (fop++, ti = 1; ti < nf; fop++, ti++) {
+                switch (fop->ft) {
+                case LSOF_FID_CMD:
+                    cmdp = fop;
+                    break;
+                }
+            }
+            if (!cmdp || (pid != MyPid))
+                pids = 0;
+            break;
+        case LSOF_FID_FD:
+
+            /*
+             * This is a file descriptor line.  Make sure its number matches the
+             * test file's descriptor number.
+             */
+            if (!pids)
+                break;
+            for (ti = 0, tcp = fop->v; *tcp; tcp++) {
+
+                /*
+                 * Convert file descriptor to a number.
+                 */
+                if (*tcp == ' ')
+                    continue;
+                if (((int)*tcp < (int)'0') || ((int)*tcp > (int)'9')) {
+                    ti = -1;
+                    break;
+                }
+                ti = (ti * 10) + (int)*tcp - (int)'0';
+            }
+            if (Fd != ti)
+                break;
+            /*
+             * Scan for device, inode, offset, size and type fields.
+             */
+            devp = inop = offp = szp = typ = (LTfldo_t *)NULL;
+            for (fop++, ti = 1; ti < nf; fop++, ti++) {
+                switch (fop->ft) {
+                case LSOF_FID_DEVN:
+                    devp = fop;
+                    break;
+                case LSOF_FID_INODE:
+                    inop = fop;
+                    break;
+                case LSOF_FID_OFFSET:
+                    offp = fop;
+                    break;
+                case LSOF_FID_SIZE:
+                    szp = fop;
+                    break;
+                case LSOF_FID_TYPE:
+                    typ = fop;
+                    break;
+                }
+            }
+            /*
+             * Check the results of the file descriptor field scan.
+             */
+            if (!devp || !inop || !typ)
+                break;
+            if (strcasecmp(typ->v, "reg") && strcasecmp(typ->v, "vreg"))
+                break;
+            if ((cem = ConvLsofDev(devp->v, &lsofdc))) {
+                if (pem)
+                    (void)PrtMsg(pem, Pn);
+                pem = cem;
+                break;
+            }
+            if ((stdc.maj != lsofdc.maj) || (stdc.min != lsofdc.min) ||
+                (stdc.unit != lsofdc.unit) || strcmp(inop->v, ibuf)) {
+                break;
+            }
+            /*
+             * The specified file has been located.  Do the specified test.
+             */
+            ff = 1;
+            fop = (tt == TYTST_SZ) ? szp : offp;
+            if (!fop) {
+                (void)snprintf(buf, sizeof(buf) - 1,
+                               "ERROR!!! %s%s test, but no lsof%s", tnm1, tnm2,
+                               tnm2);
+                ts = 1;
+            } else if (strcmp(fop->v, xval)) {
+                (void)snprintf(buf, sizeof(buf) - 1,
+                               "ERROR!!! %s%s mismatch: expected %s, got %s",
+                               tnm1, tnm2, xval, fop->v);
+                ts = 1;
+            }
+            if (ts) {
+                buf[sizeof(buf) - 1] = '\0';
+                cem = MkStrCpy(buf, &ti);
+                if (pem)
+                    (void)PrtMsg(pem, Pn);
+                pem = cem;
+            }
+            break;
+        }
+    }
+    (void)StopLsof();
+    if (!ff) {
+        (void)snprintf(buf, sizeof(buf) - 1,
+                       "ERROR!!!  test file %s not found by lsof", Path);
+        buf[sizeof(buf) - 1] = '\0';
+        cem = MkStrCpy(buf, &ti);
+        if (pem)
+            (void)PrtMsg(pem, Pn);
+        return (cem);
+    }
+    return (pem);
+}
diff --git a/tests/LTunix.c b/tests/LTunix.c
new file mode 100644 (file)
index 0000000..46c544b
--- /dev/null
@@ -0,0 +1,345 @@
+/*
+ * LTunix.c -- Lsof Test UNIX domain socket test
+ *
+ * V. Abell
+ * Purdue University
+ */
+
+/*
+ * Copyright 2002 Purdue Research Foundation, West Lafayette, Indiana
+ * 47907.  All rights reserved.
+ *
+ * Written by V. 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.
+ */
+
+#include "LsofTest.h"
+#include "lsof_fields.h"
+
+#include <sys/socket.h>
+#include <sys/un.h>
+
+/*
+ * Local definitions
+ */
+
+#if !defined(MAXPATHLEN)
+#    define MAXPATHLEN 1024 /* maximum path length */
+#endif                      /* !defined(MAXPATHLEN) */
+
+/*
+ * Globals
+ */
+
+pid_t MyPid = (pid_t)0;  /* PID of this process */
+char *Pn = (char *)NULL; /* program name */
+int SpFd[2] = {-1, -1};  /* socket pair FDs */
+char *Path[2] = {(char *)NULL, (char *)NULL};
+/* socket pair paths */
+
+/*
+ * Local function prototypes
+ */
+
+static void cleanup(void);
+static char *FindUsocks(void);
+
+/*
+ * Main program
+ */
+
+int main(int argc,     /* argument count */
+         char *argv[]) /* arguments */
+{
+    char buf[2048];           /* temporary buffer */
+    char cwd[MAXPATHLEN + 1]; /* CWD buffer */
+    char *em;                 /* error message pointer */
+    int ti, tj;               /* temporary indexes */
+    struct sockaddr_un ua;    /* UNIX socket address */
+    int xv = 0;               /* exit value */
+                              /*
+                               * Get program name and PID, issue start message, and build space prefix.
+                               */
+    if ((Pn = strrchr(argv[0], '/')))
+        Pn++;
+    else
+        Pn = argv[0];
+    MyPid = getpid();
+    (void)printf("%s ... ", Pn);
+    (void)fflush(stdout);
+    PrtMsg((char *)NULL, Pn);
+    /*
+     * Process arguments.
+     */
+    if (ScanArg(argc, argv, "h", Pn))
+        xv = 1;
+    if (xv || LTopt_h) {
+        (void)PrtMsg("usage: [-h]", Pn);
+        PrtMsgX("       -h       print help (this panel)", Pn, cleanup, xv);
+    }
+    /*
+     * See if lsof can be executed and can access kernel memory.
+     */
+    if ((em = IsLsofExec()))
+        (void)PrtMsgX(em, Pn, cleanup, 1);
+    if ((em = CanRdKmem()))
+        (void)PrtMsgX(em, Pn, cleanup, 1);
+        /*
+         * Construct the socket paths.
+         */
+
+#if defined(USE_GETCWD)
+    if (!getcwd(cwd, sizeof(cwd)))
+#else  /* ! defined(USE_GETCWD) */
+    if (!getwd(cwd))
+#endif /* defined(USE_GETCWD) */
+
+    {
+        em = "ERROR!!!  can't get CWD";
+        goto print_errno;
+    }
+    cwd[sizeof(cwd) - 1] = '\0';
+    if ((strlen(cwd) + strlen("/config.LT#U9223372036854775807") + 1) >
+        sizeof(ua.sun_path)) {
+        strncpy(cwd, "/tmp", sizeof(cwd) - 1);
+    }
+    for (ti = 0; ti < 2; ti++) {
+        (void)snprintf(buf, sizeof(buf) - 1, "%s/config.LT%dU%ld", cwd, ti,
+                       (long)MyPid);
+        buf[sizeof(buf) - 1] = '\0';
+        Path[ti] = MkStrCpy(buf, &tj);
+        (void)unlink(Path[ti]);
+    }
+    /*
+     * Get two UNIX domain socket FDs.
+     */
+    for (ti = 0; ti < 2; ti++) {
+        if ((SpFd[ti] = socket(AF_UNIX, SOCK_STREAM, PF_UNSPEC)) < 0) {
+            em = "socket";
+
+        print_errno_by_ti:
+
+            (void)snprintf(buf, sizeof(buf) - 1, "ERROR!!!  %s(%s) failure", em,
+                           Path[ti]);
+            buf[sizeof(buf) - 1] = '\0';
+            em = buf;
+
+        print_errno:
+
+            PrtMsg(em, Pn);
+            (void)snprintf(buf, sizeof(buf) - 1, "    Errno %d: %s", errno,
+                           strerror(errno));
+            buf[sizeof(buf) - 1] = '\0';
+            PrtMsgX(buf, Pn, cleanup, 1);
+        }
+    }
+    /*
+     * Bind file system names to the sockets.
+     */
+    for (ti = 0; ti < 2; ti++) {
+        (void)memset((void *)&ua, 0, sizeof(ua));
+        ua.sun_family = AF_UNIX;
+        (void)strncpy(ua.sun_path, Path[ti], sizeof(ua.sun_path));
+        ua.sun_path[sizeof(ua.sun_path) - 1] = '\0';
+        if (bind(SpFd[ti], (struct sockaddr *)&ua, sizeof(ua)) < 0) {
+            em = "bind";
+            goto print_errno_by_ti;
+        }
+    }
+    /*
+     * Look for the open UNIX domain socket files with lsof.
+     */
+    if ((em = FindUsocks()))
+        (void)PrtMsgX(em, Pn, cleanup, 1);
+    /*
+     * Exit successfully.
+     */
+    (void)PrtMsgX("OK", Pn, cleanup, 0);
+    return (0);
+}
+
+/*
+ * cleanup() -- release resources
+ */
+
+static void cleanup() {
+    int ti;
+
+    for (ti = 0; ti < 2; ti++) {
+        if (SpFd[ti] >= 0) {
+            (void)close(SpFd[ti]);
+            SpFd[ti] = -1;
+        }
+        if (Path[ti]) {
+            (void)unlink(Path[ti]);
+            (void)free((void *)Path[ti]);
+            Path[ti] = (char *)NULL;
+        }
+    }
+}
+
+/*
+ * FindUsocks() -- find UNIX sockets with lsof
+ */
+
+static char *FindUsocks() {
+    char buf[2048];           /* temporary buffer */
+    char *cem;                /* current error message pointer */
+    LTfldo_t *cmdp;           /* command pointer */
+    int ff[2];                /* file-found flags */
+    LTfldo_t *fop;            /* field output pointer */
+    int nf;                   /* number of fields */
+    int nl;                   /* name length */
+    LTfldo_t *nmp;            /* name pointer */
+    char *opv[5];             /* option vector for ExecLsof() */
+    char *pem = (char *)NULL; /* previous error message pointer */
+    pid_t pid;                /* PID */
+    int pids = 0;             /* PID found status */
+    char *tcp;                /* temporary character pointer */
+    int ti, tj;               /* temporary integers */
+    LTfldo_t *typ;            /* file type pointer */
+                              /*
+                               * Build the option vector and start lsof execution.
+                               */
+    ff[0] = ff[1] = ti = 0;
+    opv[ti++] = "-aU";
+    opv[ti++] = "-p";
+    (void)snprintf(buf, sizeof(buf) - 1, "%ld", (long)MyPid);
+    buf[sizeof(buf) - 1] = '\0';
+    opv[ti++] = MkStrCpy(buf, &tj);
+
+#if defined(USE_LSOF_C_OPT)
+    opv[ti++] = "-C";
+#endif /* defined(USE_LSOF_C_OPT) */
+
+    opv[ti] = (char *)NULL;
+    if ((cem = ExecLsof(opv)))
+        return (cem);
+    /*
+     * Read lsof output.
+     */
+    while (((ff[0] + ff[1]) < 2) && (fop = RdFrLsof(&nf, &cem))) {
+        if (cem) {
+            if (pem)
+                (void)PrtMsg(pem, Pn);
+            return (cem);
+        }
+        switch (fop->ft) {
+        case LSOF_FID_PID:
+
+            /*
+             * This is a process information line.
+             */
+            pid = (pid_t)atoi(fop->v);
+            pids = 1;
+            cmdp = (LTfldo_t *)NULL;
+            for (fop++, ti = 1; ti < nf; fop++, ti++) {
+                switch (fop->ft) {
+                case LSOF_FID_CMD:
+                    cmdp = fop;
+                    break;
+                }
+            }
+            if (!cmdp || (pid != MyPid))
+                pids = 0;
+            break;
+        case LSOF_FID_FD:
+
+            /*
+             * This is a file descriptor line.  Make sure its number matches a
+             * test file descriptor number.
+             */
+            if (!pids)
+                break;
+            for (ti = 0, tcp = fop->v; *tcp; tcp++) {
+
+                /*
+                 * Convert file descriptor to a number.
+                 */
+                if (*tcp == ' ')
+                    continue;
+                if (((int)*tcp < (int)'0') || ((int)*tcp > (int)'9')) {
+                    ti = -1;
+                    break;
+                }
+                ti = (ti * 10) + (int)*tcp - (int)'0';
+            }
+            for (tj = 0; tj < 2; tj++) {
+                if (ff[tj])
+                    continue;
+                if (SpFd[tj] == ti)
+                    break;
+            }
+            if (tj >= 2)
+                break;
+            /*
+             * Scan for name and type.
+             */
+            nmp = typ = (LTfldo_t *)NULL;
+            for (fop++, ti = 1; ti < nf; fop++, ti++) {
+                switch (fop->ft) {
+                case LSOF_FID_NAME:
+                    nmp = fop;
+                    break;
+                case LSOF_FID_TYPE:
+                    typ = fop;
+                    break;
+                }
+            }
+            /*
+             * Check the type of the file.
+             */
+            if (!typ || strcasecmp(typ->v, "unix"))
+                break;
+            /*
+             * Look for the name.
+             */
+            if (!nmp)
+                break;
+            nl = strlen(Path[tj]);
+            for (tcp = nmp->v; tcp; tcp = strchr(tcp + 1, '/')) {
+                if (!strncmp(tcp, Path[tj], nl)) {
+
+                    /*
+                     * Mark a file as found.
+                     */
+                    ff[tj] = 1;
+                    break;
+                }
+            }
+        }
+    }
+    /*
+     * Clean up and return.
+     */
+    (void)StopLsof();
+    for (ti = 0; ti < 2; ti++) {
+        if (ff[tj])
+            continue;
+        (void)snprintf(buf, sizeof(buf) - 1, "ERROR!!!  not found: %s",
+                       Path[ti]);
+        buf[sizeof(buf) - 1] = '\0';
+        if (pem)
+            (void)PrtMsg(pem, Pn);
+        pem = MkStrCpy(buf, &tj);
+    }
+    return (pem);
+}
diff --git a/tests/LsofTest.h b/tests/LsofTest.h
new file mode 100644 (file)
index 0000000..c4eff23
--- /dev/null
@@ -0,0 +1,333 @@
+/*
+ * LsofTest.h -- header file for lsof tests
+ */
+
+/*
+ * Copyright 2002 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: LsofTest.h,v 1.13 2018/02/14 14:21:44 abe Exp $
+ */
+
+#if !defined(LSOF_TEST_H)
+#    define LSOF_TEST_H 1
+
+/*
+ * The following define keeps gcc>=2.7 from complaining about the failure
+ * of the Exit() function to return.
+ *
+ * Paul Eggert <eggert@twinsun.com> supplied it.
+ */
+
+#    if defined(__GNUC__) &&                                                   \
+        !(__GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7))
+#        define exiting __attribute__((__noreturn__))
+#    else /* !gcc || gcc<2.7 */
+#        define exiting
+#    endif /* gcc && gcc>=2.7 */
+
+/*
+ * Necessary header files.
+ */
+
+#    include <stdio.h>
+#    include <ctype.h>
+#    include <errno.h>
+#    include <signal.h>
+#    include <inttypes.h>
+
+#    include <sys/types.h>
+
+#    if defined(LT_DIAL_linux) && LT_VERS >= 414014
+#        undef major
+#        include <sys/sysmacros.h>
+#    endif /* defined(LT_DIAL_linux) && LT_VERS>=414014 */
+
+#    include <sys/param.h>
+#    include <sys/stat.h>
+
+/*
+ * Definitions that may be revoked by a particular dialect.
+ */
+
+#    define USE_GETCWD     /* use the POSIX getcwd() function in               \
+                            * place of getwd() */
+#    define USE_LSOF_C_OPT /* use lsof's -C option */
+#    undef USE_LSOF_X_OPT  /* don't use lsof's -X option */
+
+#    if defined(LT_DIAL_aix)
+/*
+ * AIX-specific items
+ */
+
+#        include <fcntl.h>
+#        include <stdlib.h>
+#        include <string.h>
+#        include <unistd.h>
+#        include <sys/access.h>
+#        undef USE_LSOF_C_OPT
+#        define USE_LSOF_X_OPT
+#    endif /* defined(LT_DIAL_aix) */
+
+#    if defined(LT_DIAL_bsdi)
+/*
+ * BSDI-specific items
+ */
+
+#        include <fcntl.h>
+#        include <stdlib.h>
+#        include <string.h>
+#        include <unistd.h>
+#        include <sys/wait.h>
+#    endif /* defined(LT_DIAL_bsdi) */
+
+#    if defined(LT_DIAL_darwin)
+/*
+ * Darwin-specific items
+ */
+
+#        include <fcntl.h>
+#        include <stdlib.h>
+#        include <string.h>
+#        include <unistd.h>
+#        include <sys/wait.h>
+#        undef USE_LSOF_C_OPT
+#    endif /* defined(LT_DIAL_darwin) */
+
+#    if defined(LT_DIAL_du)
+/*
+ * DEC_OSF/1|Digital_UNIX|Tru64_UNIX-specific items
+ */
+
+#        include <fcntl.h>
+#        include <string.h>
+#        include <unistd.h>
+#        include <sys/wait.h>
+
+#        if LT_VERS < 50000
+#            define snprintf snpf /* use lsof's snpf() */
+#        endif                    /* LT_VERS<50000 */
+#    endif                        /* defined(LT_DIAL_du) */
+
+#    if defined(LT_DIAL_freebsd)
+/*
+ * FreeBSD-specific items
+ */
+
+#        include <fcntl.h>
+#        include <stdlib.h>
+#        include <string.h>
+#        include <unistd.h>
+#        include <sys/wait.h>
+#        undef USE_LSOF_C_OPT
+#    endif /* defined(LT_DIAL_freebsd) */
+
+#    if defined(LT_DIAL_linux)
+/*
+ * Linux-specific items
+ */
+
+#        include <fcntl.h>
+#        include <stdlib.h>
+#        include <string.h>
+#        include <unistd.h>
+#        include <sys/wait.h>
+#        undef USE_LSOF_C_OPT
+#    endif /* defined(LT_DIAL_linux) */
+
+#    if defined(LT_DIAL_hpux)
+/*
+ * HP-UX-specific items
+ */
+
+#        include <fcntl.h>
+#        include <stdlib.h>
+#        include <string.h>
+#        include <strings.h>
+#        include <unistd.h>
+#    endif /* defined(LT_DIAL_hpux) */
+
+#    if defined(LT_DIAL_netbsd)
+/*
+ * NetBSD-specific items
+ */
+
+#        include <fcntl.h>
+#        include <stdlib.h>
+#        include <string.h>
+#        include <unistd.h>
+#        include <sys/wait.h>
+#    endif /* defined(LT_DIAL_netbsd) */
+
+#    if defined(LT_DIAL_openbsd)
+/*
+ * OpenBSD-specific items
+ */
+
+#        include <fcntl.h>
+#        include <stdlib.h>
+#        include <string.h>
+#        include <unistd.h>
+#        include <sys/wait.h>
+#        undef USE_LSOF_C_OPT
+#    endif /* defined(LT_DIAL_openbsd) */
+
+#    if defined(LT_DIAL_ou)
+/*
+ * OpenUNIX-specific items
+ */
+
+#        include <fcntl.h>
+#        include <stdlib.h>
+#        include <string.h>
+#        include <unistd.h>
+#    endif /* defined(LT_DIAL_ou) */
+
+#    if defined(LT_DIAL_osr)
+/*
+ * OSR-specific items
+ */
+
+#        include <fcntl.h>
+#        include <stdlib.h>
+#        include <string.h>
+#        include <unistd.h>
+#    endif /* defined(LT_DIAL_osr) */
+
+#    if defined(LT_DIAL_ns)
+/*
+ * NEXTSTEP-specific items
+ */
+
+#        include <stdlib.h>
+#        include <string.h>
+#        include <sys/file.h>
+#        include <sys/wait.h>
+
+typedef int pid_t;
+#        define snprintf snpf
+
+#        undef USE_GETCWD
+#    endif /* defined(LT_DIAL_ns) */
+
+#    if defined(LT_DIAL_solaris)
+/*
+ * Solaris-specific items
+ */
+
+#        include <fcntl.h>
+#        include <stdlib.h>
+#        include <strings.h>
+#        include <unistd.h>
+#        include <sys/wait.h>
+
+#        if defined(LT_VPATH)
+#            undef USE_LSOF_C_OPT
+#        endif /* defined(LT_VPATH) */
+#    endif     /* defined(LT_DIAL_solaris) */
+
+#    if defined(LT_DIAL_uw)
+/*
+ * UnixWare-specific items
+ */
+
+#        include <fcntl.h>
+#        include <stdlib.h>
+#        include <string.h>
+#        include <unistd.h>
+#    endif /* defined(LT_DIAL_uw) */
+
+/*
+ * Local definitions, including ones may have been left undefined by
+ * dialect-specific header files
+ */
+
+#    define LT_DONT_DO_TEST "this test does not run on this dialect."
+#    if !defined(LT_DEF_LSOF_PATH)
+#        define LT_DEF_LSOF_PATH "../lsof"
+#    endif /* !defined(LT_DEF_LSOF_PATH) */
+
+#    if !defined(MAXPATHLEN)
+#        define MAXPATHLEN 1024
+#    endif /* !defined(MAXPATHLEN) */
+
+/*
+ * Local structure definitions
+ */
+
+typedef struct LTdev { /* local device parameters */
+    unsigned int maj;  /* major device number */
+    unsigned int min;  /* minor device number */
+    unsigned int unit; /* unit number (where applicable) */
+} LTdev_t;
+
+typedef struct LTfldo { /* lsof field output information */
+    char ft;            /* field identifier (see the LSOF_FID_*
+                         * definitions in ../lsof_fields.h) */
+    char *v;            /* field value character string */
+} LTfldo_t;
+#    define LT_FLDO_ALLOC 16 /* LTfldo_t allocation increment */
+
+/*
+ * Lsof test library global variable external declarations:
+ *
+ *     these global variables may be found in LTlib.c.
+ */
+
+extern int LsofFd;     /* lsof pipe FD */
+extern FILE *LsofFs;   /* stream for lsof pipe FD */
+extern char *LsofPath; /* path to lsof executable */
+extern pid_t LsofPid;  /* PID of lsof child process */
+extern int LTopt_h;    /* "-h" option's switch value */
+extern char *LTopt_p;  /* "-p path" option's path value */
+extern int MsgStat;    /* message status */
+
+/*
+ * External declarations
+ */
+
+extern int errno; /* error number */
+
+/*
+ * Lsof test library function prototypes:
+ *
+ *     these functions may be found in LTlib.c.
+ */
+
+extern char *CanRdKmem(void);
+extern char *ConvStatDev(dev_t *dev, LTdev_t *ldev);
+extern char *ConvLsofDev(char *dev, LTdev_t *ldev);
+extern char *ExecLsof(char **opt);
+extern char *IsLsofExec(void);
+extern void LTlibClean(void);
+extern char *MkStrCpy(char *src, int *len);
+extern LTfldo_t *RdFrLsof(int *nf, char **em);
+extern void PrtMsg(char *mp, char *pn);
+extern void PrtMsgX(char *mp, char *pn, void (*f)(), int xv);
+extern int ScanArg(int ac, char *av[], char *opt, char *pn);
+extern void StopLsof(void);
+
+#endif /* LSOF_TEST_H */
diff --git a/tests/Makefile b/tests/Makefile
new file mode 100644 (file)
index 0000000..0b82654
--- /dev/null
@@ -0,0 +1,165 @@
+# Makefile for testing lsof
+#
+# V. Abell
+# Purdue University
+#
+# $Id: Makefile,v 1.17 2005/05/17 00:40:53 abe Exp abe $
+
+DEBUG=
+CFLAGS=        ${DEBUG} -I. -I.. -I../include
+
+HDR=   LsofTest.h
+
+CKTSTDB= CkTestDB
+CONFCFL= ./config.cflags
+CONFIG=        ./config.cc ${CONFCFL} ./config.xobj
+LTOBJ= LTlib.o
+LTSRC= LTlib.c
+LIBOBJ=        ${LTOBJ}
+
+BASTST=        LTbasic
+STDTST=        LTnlink LTsock LTszoff LTunix
+OPTTST=        LTbigf LTdnlc LTlock LTnfs
+
+all:   ${CKTSTDB} ${BASTST} ${STDTST} FRC
+       @./${CKTSTDB}; xv=$$?; \
+       if [ $$xv -ne 0 ]; then \
+         exit 1 ;\
+       fi
+       @rm -f config.LT*
+       @err=0; \
+       echo ""; \
+       echo "Basic test:"; \
+       ./${BASTST}; \
+       if [ $$? -ne 0 ]; then \
+         exit 1; \
+       fi; \
+       echo ""; \
+       echo "Standard tests:"; \
+       for i in ${STDTST}; do \
+         ./$$i; \
+         if [ $$? -ne 0 ]; then \
+           err=`expr $$err + 1`; \
+         fi; \
+       done; \
+       if [ $$err -ne 0 ]; then \
+         echo "Failed tests: $$err"; \
+         echo ""; \
+         echo "See 00FAQ and 00TEST for more information."; \
+       else \
+         echo "All standard tests succeeded."; \
+         echo ""; \
+         grep LT_DIAL_darwin ${CONFCFL} > /dev/null 2>&1; \
+         if [ $$? -ne 0 ]; then \
+           echo "Suggestion: try the optional tests: \"make opt\""; \
+           echo ""; \
+         fi; \
+       fi; \
+       rm -f config.LT*; \
+       if [ $$err -ne 0 ]; then \
+         exit 1; \
+       fi
+
+auto:  ckDB silent FRC
+
+ckDB:  ${CKTSTDB} FRC
+       @echo "" | ./${CKTSTDB}; xv=$$?; \
+       if [ $$xv -ne 0 ]; then \
+         exit 1 ;\
+       fi
+
+clean: FRC
+       rm -f ${BASTST} ${STDTST} ${OPTTST} *.o *.err *.out config.LT*
+
+FRC:
+
+LTbasic: LTbasic.c ${CONFIG} ${LIBOBJ} ${HDR}
+       `cat config.cc` ${CFLAGS} `cat config.cflags` LTbasic.c \
+       ${LIBOBJ} `cat config.xobj` -o LTbasic
+
+LTbigf: LTbigf.c ${CONFIG} ${LIBOBJ} ${HDR}
+       `cat config.cc` ${CFLAGS} `cat config.cflags` LTbigf.c \
+       ${LIBOBJ} `cat config.xobj` -o LTbigf
+
+LTdnlc: LTdnlc.c ${CONFIG} ${LIBOBJ} ${HDR}
+       `cat config.cc` ${CFLAGS} `cat config.cflags` LTdnlc.c \
+       ${LIBOBJ} `cat config.xobj` -o LTdnlc
+
+LTlock: LTlock.c ${CONFIG} ${LIBOBJ} ${HDR}
+       `cat config.cc` ${CFLAGS} `cat config.cflags` LTlock.c \
+       ${LIBOBJ} `cat config.xobj` -o LTlock
+
+${LTOBJ}: ${HDR} ${LTSRC} config.cflags config.cc
+       `cat config.cc` ${CFLAGS} `cat config.cflags` -c ${LTSRC} \
+       -o ${LTOBJ}
+
+LTnfs: LTnfs.c ${CONFIG} ${LIBOBJ} ${HDR}
+       `cat config.cc` ${CFLAGS} `cat config.cflags` LTnfs.c \
+       ${LIBOBJ} `cat config.xobj` -o LTnfs
+
+LTnlink: LTnlink.c ${CONFIG} ${LIBOBJ} ${HDR}
+       `cat config.cc` ${CFLAGS} `cat config.cflags` LTnlink.c \
+       ${LIBOBJ} `cat config.xobj` -o LTnlink
+
+LTsock: LTsock.c ${CONFIG} ${LIBOBJ} ${HDR}
+       `cat config.cc` ${CFLAGS} `cat config.cflags` LTsock.c \
+       ${LIBOBJ} `cat config.xobj` -o LTsock `cat config.ldflags`
+
+LTszoff: LTszoff.c ${CONFIG} ${LIBOBJ} ${HDR}
+       `cat config.cc` ${CFLAGS} `cat config.cflags` LTszoff.c \
+       ${LIBOBJ} `cat config.xobj` -o LTszoff
+
+LTunix: LTunix.c ${CONFIG} ${LIBOBJ} ${HDR} config.ldflags
+       `cat config.cc` ${CFLAGS} `cat config.cflags` LTunix.c \
+       ${LIBOBJ} `cat config.xobj` -o LTunix `cat config.ldflags`
+
+opt:   ${CKTSTDB} ${OPTTST} FRC
+       @rm -f config.LT*
+       @err=0; \
+       echo ""; \
+       echo "Optional tests:"; \
+       for i in ${OPTTST}; do \
+         ./$$i; \
+         if [ $$? -ne 0 ]; then \
+           err=`expr $$err + 1`; \
+         fi; \
+       done; \
+       if [ $$err -ne 0 ]; then \
+         echo "Failed tests: $$err"; \
+       else \
+         echo "All optional tests succeeded."; \
+       fi; \
+       echo ""; \
+       rm -f config.LT*; \
+       if [ $$err -ne 0 ]; then \
+         exit 1; \
+       fi
+
+optional: opt
+
+silent:        ${BASTST} ${STDTST} FRC
+       @rm -f config.LT*
+       @err=0; \
+       ./${BASTST} > /dev/null 2>&1; \
+       if [ $$? -ne 0 ]; then \
+         exit 1; \
+       fi; \
+       for i in ${STDTST}; do \
+         ./$$i > /dev/null 2>&1; \
+         if [ $$? -ne 0 ]; then \
+           err=`expr $$err + 1`; \
+         fi; \
+       done; \
+       rm -f config.LT*; \
+       if [ $$err -ne 0 ]; then \
+         exit 1; \
+       fi
+
+spotless: clean
+       rm -f config.*
+
+standard: all
+
+std: all
+
+test: all
diff --git a/tests/TestDB b/tests/TestDB
new file mode 100644 (file)
index 0000000..ee7c940
--- /dev/null
@@ -0,0 +1,153 @@
+# TestDB -- lsof test suite data base
+#
+# This file contains the sorted words from config.cflags, less any leading "-D"
+# strings, joined on one line.
+#
+# See Add2TestDB for a script that will build a line for this file.
+#
+# $Id: TestDB,v 1.41 2018/02/14 14:21:44 abe Exp $
+
+LT_AIXA=0 LT_BIGF LT_CC LT_DIAL_aix LT_KMEM LT_VERS=4320
+LT_AIXA=0 LT_BIGF LT_CC LT_DIAL_aix LT_KMEM LT_VERS=4330
+LT_AIXA=1 LT_BIGF LT_CC LT_DIAL_aix LT_K64 LT_KMEM LT_VERS=5000
+LT_AIXA=0 LT_BIGF LT_CC LT_DIAL_aix LT_KMEM LT_VERS=5100
+LT_AIXA=0 LT_BIGF LT_DIAL_aix LT_GCC LT_KMEM LT_VERS=5100
+LT_AIXA=1 LT_BIGF LT_CC LT_DIAL_aix LT_K64 LT_KMEM LT_VERS=5100
+LT_AIXA=0 LT_BIGF LT_CC LT_DIAL_aix LT_KMEM LT_VERS=5200
+LT_AIXA=0 LT_BIGF LT_DIAL_aix LT_GCC LT_KMEM LT_VERS=5200
+LT_AIXA=1 LT_BIGF LT_CC LT_DIAL_aix LT_K64 LT_KMEM LT_VERS=5200
+LT_AIXA=1 LT_BIGF LT_DIAL_aix LT_GCC LT_K64 LT_KMEM LT_VERS=5200
+LT_AIXA=1 LT_BIGF LT_CC LT_DIAL_aix LT_K64 LT_KMEM LT_VERS=5300
+LT_BIGF LT_DIAL_bsdi LT_GCC LT_KMEM LT_VERS=40100
+LT_BIGF LT_DIAL_bsdi LT_GCC LT_KMEM LT_VERS=40300
+LT_CC LT_DIAL_darwin LT_KMEM LT_VERS=140
+LT_CC LT_DIAL_darwin LT_KMEM LT_VERS=530
+LT_CC LT_DIAL_darwin LT_KMEM LT_VERS=600
+LT_CC LT_DIAL_darwin LT_KMEM LT_VERS=700
+LT_CC LT_DIAL_darwin LT_KMEM LT_VERS=800
+LT_CC LT_DIAL_darwin LT_VERS=800
+LT_BIGF LT_CC LT_DIAL_darwin LT_KMEM LT_VERS=800
+LT_CC LT_DIAL_darwin LT_VERS=900
+LT_BIGF LT_CC LT_DIAL_darwin LT_VERS=900
+LT_BIGF LT_CC LT_DIAL_darwin LT_VERS=1000
+LT_BIGF LT_CC LT_DIAL_darwin LT_VERS=1100
+LT_BIGF LT_CC LT_DIAL_du LT_K64 LT_KMEM LT_VERS=40000
+LT_BIGF LT_CC LT_DIAL_du LT_K64 LT_KMEM LT_VERS=50000
+LT_BIGF LT_CC LT_DIAL_du LT_K64 LT_KMEM LT_VERS=50100
+LT_BIGF LT_CC LT_DIAL_freebsd LT_KMEM LT_VERS=4050
+LT_BIGF LT_CC LT_DIAL_freebsd LT_KMEM LT_VERS=4060
+LT_BIGF LT_CC LT_DIAL_freebsd LT_KMEM LT_VERS=4070
+LT_BIGF LT_CC LT_DIAL_freebsd LT_KMEM LT_VERS=4080
+LT_BIGF LT_CC LT_DIAL_freebsd LT_KMEM LT_VERS=4090
+LT_BIGF LT_CC LT_DIAL_freebsd LT_KMEM LT_VERS=4100
+LT_BIGF LT_CC LT_DIAL_freebsd LT_KMEM LT_VERS=4110
+LT_BIGF LT_CC LT_DIAL_freebsd LT_KMEM LT_VERS=5000
+LT_BIGF LT_CC LT_DIAL_freebsd LT_KMEM LT_VERS=5010
+LT_BIGF LT_CC LT_DIAL_freebsd LT_KMEM LT_VERS=5020
+LT_BIGF LT_CC LT_DIAL_freebsd LT_KMEM LT_VERS=5030
+LT_BIGF LT_CC LT_DIAL_freebsd LT_KMEM LT_VERS=5040
+LT_BIGF LT_CC LT_DIAL_freebsd LT_KMEM LT_VERS=5050
+LT_BIGF LT_CC LT_DIAL_freebsd LT_KMEM LT_VERS=6000
+LT_BIGF LT_CC LT_DIAL_freebsd LT_KMEM LT_VERS=6010
+LT_BIGF LT_CC LT_DIAL_freebsd LT_KMEM LT_VERS=6020
+LT_BIGF LT_CC LT_DIAL_freebsd LT_KMEM LT_VERS=6040
+LT_BIGF LT_CC LT_DIAL_freebsd LT_KMEM LT_VERS=7000
+LT_BIGF LT_CC LT_DIAL_freebsd LT_KMEM LT_VERS=7010
+LT_BIGF LT_CC LT_DIAL_freebsd LT_KMEM LT_VERS=7020
+LT_BIGF LT_CC LT_DIAL_freebsd LT_KMEM LT_VERS=7030
+LT_BIGF LT_CC LT_DIAL_freebsd LT_KMEM LT_VERS=7040
+LT_BIGF LT_CC LT_DIAL_freebsd LT_KMEM LT_VERS=8000
+LT_BIGF LT_CC LT_DIAL_freebsd LT_KMEM LT_VERS=8020
+LT_BIGF LT_CC LT_DIAL_freebsd LT_KMEM LT_VERS=8030
+LT_BIGF LT_CC LT_DIAL_freebsd LT_KMEM LT_VERS=8040
+LT_BIGF LT_CC LT_DIAL_freebsd LT_KMEM LT_VERS=9000
+LT_BIGF LT_CC LT_DIAL_freebsd LT_KMEM LT_VERS=10000
+LT_BIGF LT_DIAL_freebsd LT_GCC LT_KMEM LT_VERS=10000
+LT_BIGF LT_CC LT_DIAL_freebsd LT_KMEM LT_VERS=11000
+LT_BIGF LT_DIAL_freebsd LT_GCC LT_KMEM LT_VERS=11000
+LT_BIGF LT_CC LT_DIAL_freebsd LT_KMEM LT_VERS=12000
+LT_BIGF LT_CC LT_DEV64 LT_DIAL_freebsd LT_KMEM LT_VERS=12000
+LT_BIGF LT_CC LT_DIAL_hpux LT_KMEM LT_VERS=1020 _LARGEFILE64_SOURCE
+LT_BIGF LT_DIAL_hpux LT_GCC LT_KMEM LT_VERS=1020 _LARGEFILE64_SOURCE
+LT_BIGF LT_CC LT_DIAL_hpux LT_KMEM LT_VERS=1100 _LARGEFILE64_SOURCE
+LT_BIGF LT_CC LT_DIAL_hpux LT_K64 LT_KMEM LT_VERS=1100 _LARGEFILE64_SOURCE
+LT_BIGF LT_CC LT_DIAL_hpux LT_K64 LT_VERS=1111 _LARGEFILE64_SOURCE
+LT_BIGF LT_CC LT_DIAL_hpux LT_K64 LT_VERS=1123 _LARGEFILE64_SOURCE
+LT_BIGF LT_DIAL_hpux LT_GCC LT_K64 LT_VERS=1123 _LARGEFILE64_SOURCE
+LT_BIGF LT_CC LT_DIAL_hpux LT_K64 LT_VERS=1131 _LARGEFILE64_SOURCE
+LT_BIGF LT_CC LT_DIAL_linux LT_VERS=24012 _FILE_OFFSET_BITS=64
+LT_BIGF LT_CC LT_DIAL_linux LT_VERS=24018 _FILE_OFFSET_BITS=64
+LT_BIGF LT_CC LT_DIAL_linux LT_VERS=24021 _FILE_OFFSET_BITS=64
+LT_BIGF LT_CC LT_DIAL_linux LT_VERS=24023 _FILE_OFFSET_BITS=64
+LT_BIGF LT_CC LT_DIAL_linux LT_VERS=24024 _FILE_OFFSET_BITS=64
+LT_BIGF LT_CC LT_DIAL_linux LT_VERS=24025 _FILE_OFFSET_BITS=64
+LT_BIGF LT_CC LT_DIAL_linux LT_VERS=24026 _FILE_OFFSET_BITS=64
+LT_BIGF LT_CC LT_DIAL_linux LT_VERS=24027 _FILE_OFFSET_BITS=64
+LT_BIGF LT_CC LT_DIAL_linux LT_VERS=24028 _FILE_OFFSET_BITS=64
+LT_BIGF LT_CC LT_DIAL_linux LT_VERS=24029 _FILE_OFFSET_BITS=64
+LT_BIGF LT_CC LT_DIAL_linux LT_VERS=24030 _FILE_OFFSET_BITS=64
+LT_BIGF LT_CC LT_DIAL_linux LT_VERS=26000 _FILE_OFFSET_BITS=64
+LT_BIGF LT_CC LT_DIAL_linux LT_VERS=26018 _FILE_OFFSET_BITS=64
+LT_BIGF LT_CC LT_DIAL_linux LT_VERS=26022 _FILE_OFFSET_BITS=64
+LT_BIGF LT_CC LT_DIAL_linux LT_VERS=26032 _FILE_OFFSET_BITS=64
+LT_BIGF LT_CC LT_DIAL_linux LT_VERS=26038 _FILE_OFFSET_BITS=64
+LT_BIGF LT_CC LT_DIAL_linux LT_VERS=310000 _FILE_OFFSET_BITS=64
+LT_BIGF LT_CC LT_DIAL_linux LT_VERS=310004 _FILE_OFFSET_BITS=64
+LT_BIGF LT_CC LT_DIAL_linux LT_VERS=31008 _FILE_OFFSET_BITS=64
+LT_BIGF LT_CC LT_DIAL_linux LT_VERS=414014 _FILE_OFFSET_BITS=64
+LT_BIGF LT_CC LT_DIAL_netbsd LT_KMEM LT_VERS=1005000
+LT_BIGF LT_CC LT_DIAL_netbsd LT_KMEM LT_VERS=1006000
+LT_BIGF LT_CC LT_DIAL_netbsd LT_KMEM LT_VERS=2000000
+LT_BIGF LT_CC LT_DIAL_netbsd LT_KMEM LT_VERS=2099009
+LT_BIGF LT_CC LT_DIAL_netbsd LT_KMEM LT_VERS=2099010
+LT_BIGF LT_CC LT_DIAL_netbsd LT_KMEM LT_VERS=2099011
+LT_BIGF LT_CC LT_DIAL_netbsd LT_KMEM LT_VERS=2099012
+LT_BIGF LT_CC LT_DIAL_netbsd LT_KMEM LT_VERS=3099000
+LT_CC LT_DIAL_netbsd LT_KMEM LT_VERS=1040
+LT_BIGF LT_CC LT_DIAL_openbsd LT_KMEM LT_VERS=3000
+LT_BIGF LT_CC LT_DIAL_openbsd LT_KMEM LT_VERS=3010
+LT_BIGF LT_CC LT_DIAL_openbsd LT_KMEM LT_VERS=3020
+LT_BIGF LT_CC LT_DIAL_openbsd LT_KMEM LT_VERS=3030
+LT_BIGF LT_CC LT_DIAL_openbsd LT_KMEM LT_VERS=3040
+LT_BIGF LT_CC LT_DIAL_openbsd LT_KMEM LT_VERS=3050
+LT_BIGF LT_CC LT_DIAL_openbsd LT_KMEM LT_VERS=3060
+LT_BIGF LT_CC LT_DIAL_openbsd LT_KMEM LT_VERS=3070
+LT_BIGF LT_CC LT_DIAL_openbsd LT_KMEM LT_VERS=3090
+LT_CC LT_DIAL_osr LT_KMEM LT_VERS=504
+LT_CC LT_DIAL_osr LT_KMEM LT_VERS=506
+LT_DIAL_ns LT_GCC LT_KMEM LT_VERS=31
+LT_CC LT_DIAL_ns LT_KMEM LT_VERS=42
+LT_CC LT_DIAL_solaris LT_KMEM LT_VERS=20600
+LT_DIAL_solaris LT_GCC LT_KMEM LT_VERS=20600
+LT_BIGF LT_CC LT_DIAL_solaris LT_KMEM LT_VERS=70000
+LT_BIGF LT_CC LT_DIAL_solaris LT_K64 LT_KMEM LT_VERS=70000
+LT_BIGF LT_DIAL_solaris LT_GCC LT_KMEM LT_VERS=70000
+LT_BIGF LT_CC LT_DIAL_solaris LT_KMEM LT_VERS=80000
+LT_BIGF LT_DIAL_solaris LT_GCC LT_KMEM LT_VERS=80000
+LT_BIGF LT_DIAL_solaris LT_GCC LT_K64 LT_KMEM LT_VERS=80000
+LT_BIGF LT_CC LT_DIAL_solaris LT_K64 LT_KMEM LT_VERS=80000
+LT_BIGF LT_DIAL_solaris LT_GCC LT_KMEM LT_VERS=90000
+LT_BIGF LT_CC LT_DIAL_solaris LT_K64 LT_KMEM LT_VERS=90000
+LT_BIGF LT_DIAL_solaris LT_GCC LT_K64 LT_KMEM LT_VERS=90000
+LT_BIGF LT_CC LT_DIAL_solaris LT_KMEM LT_VERS=100000
+LT_BIGF LT_CC LT_DIAL_solaris LT_K64 LT_KMEM LT_VERS=100000 LT_VPATH
+LT_BIGF LT_DIAL_solaris LT_GCC LT_KMEM LT_VERS=100000
+LT_BIGF LT_DIAL_solaris LT_GCC LT_KMEM LT_VERS=100000 LT_VPATH
+LT_BIGF LT_CC LT_DIAL_solaris LT_K64 LT_KMEM LT_VERS=100000
+LT_BIGF LT_DIAL_solaris LT_GCC LT_K64 LT_KMEM LT_VERS=100000
+LT_BIGF LT_DIAL_solaris LT_GCC LT_K64 LT_KMEM LT_VERS=100000 LT_VPATH
+LT_BIGF LT_CC LT_DIAL_solaris LT_K64 LT_KMEM LT_VERS=110000 LT_VPATH
+LT_BIGF LT_DIAL_solaris LT_GCC LT_K64 LT_KMEM LT_VERS=110000 LT_VPATH
+LT_BIGF LT_CC LT_DIAL_uw LT_KMEM LT_VERS=70101
+LT_BIGF LT_CC LT_DIAL_uw LT_KMEM LT_VERS=70103
+LT_BIGF LT_CC LT_DIAL_uw LT_KMEM LT_VERS=70104
+LT_BIGF LT_CC LT_DEV64 LT_DIAL_freebsd LT_KMEM LT_VERS=13000
+LT_BIGF LT_CC LT_DEV64 LT_DIAL_freebsd LT_VERS=12000
+LT_BIGF LT_CC LT_DEV64 LT_DIAL_freebsd LT_VERS=13000
+LT_BIGF LT_CC LT_DEV64 LT_DIAL_freebsd LT_VERS=14000
+LT_BIGF LT_CC LT_DIAL_linux LT_VERS=50009 _FILE_OFFSET_BITS=64
+LT_BIGF LT_CC LT_DIAL_linux LT_VERS=60005 _FILE_OFFSET_BITS=64
+LT_CC LT_DIAL_darwin LT_VERS=1900
+LT_BIGF LT_CC LT_DIAL_darwin LT_VERS=1900
+LT_BIGF LT_CC LT_DIAL_openbsd LT_VERS=7020
+LT_BIGF LT_CC LT_DIAL_openbsd LT_VERS=7030
diff --git a/tests/case-00-hello.bash b/tests/case-00-hello.bash
new file mode 100755 (executable)
index 0000000..f647fcd
--- /dev/null
@@ -0,0 +1,34 @@
+#
+# An example of test case.
+#
+
+name=$(basename $0 .bash)
+
+#
+# The file path for lsof executable.
+#
+lsof=$1
+
+#
+# Used only when a test case is failed.
+# $report specifies a temporary file.
+# Store how the test case is failed to the temporary file.
+# The test harness uses this temporary file to make summary messages.
+# The test harness removes this temporary file.
+#
+report=$2
+
+#
+# Directory where this test case is.
+#
+tcasedir=$3
+
+#
+# Dialect of lsof
+#
+dialect=$4
+
+# Return 0 means the case is run successfully.
+# Return 1 means the case is run in failure.
+# Return 2 means the case is skipped.
+exit 0
diff --git a/tests/case-01-version.bash b/tests/case-01-version.bash
new file mode 100755 (executable)
index 0000000..b1a18bf
--- /dev/null
@@ -0,0 +1,27 @@
+#!/usr/bin/env bash
+#
+# check that the version numbers are updated
+#
+source tests/common.bash
+
+expected_version=$(sed '/VN/s/.ds VN \([0-9.a-z]*\)/\1/' ./version)
+actual_version=$($lsof -v 2>&1 | sed -ne 's/^ *revision: *\([0-9.a-z]*\)/\1/p')
+dist_version=$(sed -ne 's/^\([0-9][0-9.a-z]*\)         .*$/\1/p' 00DIST | tail -1)
+
+if [ "${expected_version}" != "${actual_version}" ]; then
+    {
+       echo "expected version defined in version file: ${expected_version}"
+       echo "lsof executable says: ${actual_version}"
+    } > $report
+    exit 1
+fi
+
+if [ "${expected_version}" != "${dist_version}" ]; then
+    {
+       echo "expected version defined in version file: ${expected_version}"
+       echo "the last entry of 00DIST is: ${dist_version}"
+    } > $report
+    exit 1
+fi
+
+exit 0
diff --git a/tests/case-13-classic.bash b/tests/case-13-classic.bash
new file mode 100755 (executable)
index 0000000..cf595ea
--- /dev/null
@@ -0,0 +1,49 @@
+name=$(basename $0 .bash)
+lsof=$1
+report=$2
+base=$(pwd)
+
+(
+    f=/tmp/${name}-$$
+    cd tests
+    make > $f 2>&1
+
+    cat $f >> $report
+
+    echo "------------------------------------" >> $report
+
+    if ! grep -q "LTbasic \.\.\. OK" $f; then
+       echo '"LTbasic ... OK" is not found in the output' >> $report
+       s=1
+    fi
+
+    if ! grep -q "LTnlink \.\.\. OK" $f; then
+       echo '"LTnlink ... OK" is not found in the output' >> $report
+       s=1
+    fi
+
+    if ! grep -q "LTsock \.\.\. OK" $f; then
+       echo '"LTsock ... OK" is not found in the output' >> $report
+       s=1
+    fi
+
+    if ! grep -q "LTszoff \.\.\. OK" $f; then
+       echo '"LTszoff ... OK" is not found in the output' >> $report
+       s=1
+    fi
+
+    if ! grep -q "LTunix \.\.\. OK" $f; then
+       echo '"LTunix ... OK" is not found in the output' >> $report
+       s=1
+    fi
+
+    {
+       echo
+       echo "output"
+       echo .............................................................................
+       cat $f
+    }  >> $report
+    rm $f
+
+    exit $s
+)
diff --git a/tests/case-14-classic-opt.bash b/tests/case-14-classic-opt.bash
new file mode 100755 (executable)
index 0000000..61133e9
--- /dev/null
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+name=$(basename $0 .bash)
+lsof=$1
+report=$2
+dialect=$4
+base=$(pwd)
+
+(
+    s=0
+    f=/tmp/${name}-$$
+    cd tests
+    make opt > $f 2>&1
+
+    if ! grep -q "LTbigf \.\.\. OK" $f; then
+       echo '"LTbigf ... OK" is not found in the output' >> $report
+       s=1
+    fi
+
+    # TODO: don't ignore "OK".
+    if ! grep -q "LTdnlc \.\.\. .*/tests found: 100.00%" $f; then
+       echo '"LTdnlc ... .*/tests found: 100.00%" is not found in the output' >> $report
+       s=1
+    fi
+
+    if [ -n "$CI" ] && { [ "$dialect" = "darwin" ] || [ "$dialect" = "openbsd" ]; }; then
+       :                       # TODO: temporary skip this
+    elif ! grep -q "LTlock \.\.\. OK" $f; then
+       echo '"LTlock ... OK" is not found in the output' >> $report
+       s=1
+    fi
+
+    # TODO: LTnfs
+
+    {
+       echo
+       echo "output"
+       echo .............................................................................
+       cat $f
+    }  >> $report
+    rm $f
+
+    exit $s
+)
diff --git a/tests/case-20-exit-status.bash b/tests/case-20-exit-status.bash
new file mode 100755 (executable)
index 0000000..ee6b46e
--- /dev/null
@@ -0,0 +1,58 @@
+#!/usr/bin/env bash
+source tests/common.bash
+
+f=/tmp/lsof-${name}-$$
+
+{
+    # should fail if not exists
+    $lsof $f > /dev/null
+    s=$?
+    case $s in
+       1)
+           echo "ok: $lsof $f => 1"
+           ;;
+       *)
+           echo "unexpected exit status: $s"
+           echo "      cmdline: $lsof $f"
+           exit 1
+           ;;
+    esac
+
+    # should fail if no one opens the file
+    touch $f
+    $lsof $f > /dev/null
+    s=$?
+    case $s in
+       1)
+           echo "ok: touch $f; $lsof $f => 1"
+           rm $f
+           ;;
+       *)
+           echo "unexpected exit status: $2"
+           echo "      cmdline: $lsof $f"
+           rm $f
+           exit 1
+           ;;
+    esac
+
+    # should succeed if some one opens the file
+    g=/dev/null
+    cat < /dev/zero > $g &
+    pid=$!
+    $lsof $g > /dev/null
+    s=$?
+    case $s in
+       0)
+           echo "ok: lsof $g => 0"
+           kill $pid
+           ;;
+       *)
+           echo "unexpected exit status: $s"
+           echo "      cmdline: $lsof $g"
+           kill $pid
+           exit 1
+           ;;
+    esac
+} > $report 2>&1
+
+
diff --git a/tests/case-20-fd-only-inclusion.bash b/tests/case-20-fd-only-inclusion.bash
new file mode 100755 (executable)
index 0000000..bae89c4
--- /dev/null
@@ -0,0 +1,35 @@
+#!/usr/bin/env bash
+source tests/common.bash
+
+echo "inclusion test" >> $report
+while read line; do
+    if [[ $line =~ ^f[^0-9].* ]]; then
+       echo "Unexpectedly, a named file descriptor is included: "
+       echo "${line}"
+       echo
+       echo "## whole output for debugging (-d fd -F fd): "
+       ${lsof} -p $$ -a -d fd -F fd
+       echo "## whole output for debugging (-d fd): "
+       ${lsof} -p $$ -a -d fd
+       echo "## whole output for debugging (no -d): "
+       ${lsof} -p $$
+       exit 1
+    fi
+done < <(${lsof} -p $$ -a -d fd -F fd) >> $report
+
+echo "exclusion test" >> $report
+while read line; do
+    if [[ $line =~ ^f[0-9]+ ]]; then
+       echo "Unexpectedly, a numbered file descriptor is included: "
+       echo "${line}"
+       echo "## whole output for debugging (-d fd -F fd): "
+       ${lsof} -p $$ -a -d '^fd' -F fd
+       echo "## whole output for debugging (-d ^fd): "
+       ${lsof} -p $$ -a -d '^fd'
+       echo "## whole output for debugging (no -d): "
+       ${lsof} -p $$
+       exit 1
+    fi
+done < <(${lsof} -p $$ -a -d "^fd" -F fd) >> $report
+
+exit 0
diff --git a/tests/case-20-handle-missing-files.bash b/tests/case-20-handle-missing-files.bash
new file mode 100755 (executable)
index 0000000..00e0063
--- /dev/null
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+# See https://github.com/lsof-org/lsof/issues/90
+source tests/common.bash
+
+msg=$(${lsof} /NO-SUCH-FILE 2>&1)
+
+if [[ "${msg}" == \
+              *': status error on /NO-SUCH-FILE: No such file or directory' ]]; then
+    exit 0
+else
+    {
+       echo "unexpected output: "
+       echo "${msg}"
+    } > $report
+    exit 1
+fi
diff --git a/tests/case-20-offset-field.bash b/tests/case-20-offset-field.bash
new file mode 100755 (executable)
index 0000000..6924661
--- /dev/null
@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+source tests/common.bash
+
+base=$(pwd)
+
+t=/tmp/lsof-test-reg-file-$$
+p=/tmp/lsof-test-reg-fifo-$$
+
+mkfifo $p
+{
+    printf "%d" 1
+    read < $p &
+} | cat > $t &
+
+r=1
+if [ "$($lsof -Fo $t | grep '^o')" = o0t1 ]; then
+    echo > $p
+    r=0
+fi
+
+rm /tmp/lsof-test-reg-file-$$
+rm /tmp/lsof-test-reg-fifo-$$
+
+exit $r
diff --git a/tests/case-20-repeat-count.bash b/tests/case-20-repeat-count.bash
new file mode 100755 (executable)
index 0000000..6962bc6
--- /dev/null
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+source tests/common.bash
+# need gnu grep for -e in solaris
+export PATH=/usr/gnu/bin:$PATH
+base=$(pwd)
+
+output=$(${lsof} -r 1c1 -p $$)
+echo "$output" >> $report
+if [ $(echo "$output" | grep -e '=======' | wc -l) != 1 ]; then
+    exit 1
+fi
+
+output=$(${lsof} -r 1c5 -p $$)
+echo "$output" >> $report
+if [ $(echo "$output" | grep -e '=======' | wc -l) != 5 ]; then
+    exit 1
+fi
+
+exit 0
diff --git a/tests/case-21-exit-Q-status.bash b/tests/case-21-exit-Q-status.bash
new file mode 100755 (executable)
index 0000000..e6be3a0
--- /dev/null
@@ -0,0 +1,108 @@
+#!/usr/bin/env bash
+# See https://github.com/lsof-org/lsof/issues/128
+source tests/common.bash
+
+lsof0="$lsof"
+lsof=
+
+f=/tmp/lsof-${name}-$$
+r=0
+
+{
+    lsof="$lsof0"
+    $lsof $f > /dev/null
+    s=$?
+    case $s in
+       1)
+           echo "ok: $lsof $f => 1"
+           ;;
+       *)
+           echo "unexpected exit status: $s"
+           echo "      cmdline: $lsof $f"
+           r=1
+           ;;
+    esac
+
+    lsof="$lsof0 -Q"
+    $lsof $f > /dev/null
+    s=$?
+    case $s in
+       0)
+           echo "ok: $lsof $f => 0"
+           ;;
+       *)
+           echo "unexpected exit status: $s"
+           echo "      cmdline: $lsof $f"
+           r=1
+           ;;
+    esac
+
+    lsof="$lsof0"
+    touch $f
+    $lsof $f > /dev/null
+    s=$?
+    case $s in
+       1)
+           echo "ok: touch $f; $lsof $f => 1"
+           rm $f
+           ;;
+       *)
+           echo "unexpected exit status: $2"
+           echo "      cmdline: $lsof $f"
+           rm $f
+           r=1
+           ;;
+    esac
+
+    lsof="$lsof0 -Q"
+    touch $f
+    $lsof $f > /dev/null
+    s=$?
+    case $s in
+       0)
+           echo "ok: touch $f; $lsof $f => 1"
+           rm $f
+           ;;
+       *)
+           echo "unexpected exit status: $2"
+           echo "      cmdline: $lsof $f"
+           rm $f
+           r=1
+           ;;
+    esac
+
+    g=/dev/null
+    cat < /dev/zero > $g &
+    pid=$!
+
+    lsof="$lsof"
+    $lsof $g > /dev/null
+    s=$?
+    case $s in
+       0)
+           echo "ok: lsof $g => 0"
+           ;;
+       *)
+           echo "unexpected exit status: $s"
+           echo "      cmdline: $lsof $g"
+           r=1
+           ;;
+    esac
+
+    lsof="$lsof -Q"
+    $lsof $g > /dev/null
+    s=$?
+    case $s in
+       0)
+           echo "ok: lsof $g => 0"
+           ;;
+       *)
+           echo "unexpected exit status: $s"
+           echo "      cmdline: $lsof $g"
+           r=1
+           ;;
+    esac
+
+    kill $pid
+    exit $r
+} > $report 2>&1
diff --git a/tests/case-22-empty-process-name.bash b/tests/case-22-empty-process-name.bash
new file mode 100755 (executable)
index 0000000..ff1d75e
--- /dev/null
@@ -0,0 +1,31 @@
+#!/usr/bin/env bash
+# See https://github.com/lsof-org/lsof/issues/246
+source tests/common.bash
+
+{
+    perl -e '$0 = ""; sleep 999' &
+    pid=$!
+    sleep 1
+
+    output=$($lsof -w -ad cwd -F c -p "$pid")
+    echo "lsof output:" >> $report
+    echo "$output" >> $report
+    kill $pid
+    for entry in $output
+    do
+       if [[ $entry =~ ^p[0-9]+$ ]]; then
+           if [[ $entry != p$pid ]]; then
+               echo "Incorrect pid, expect p$pid, got $entry" >> $report
+               exit 1
+           fi
+       elif [[ $entry =~ c* ]]; then
+           if [[ $entry =~ cperl* ]]; then
+               echo "The platform does not report changed command name, that's okay" >> $report
+           elif [[ $entry != c ]]; then
+               echo "Process name should be empty, expect c, got $entry" >> $report
+               exit 1
+           fi
+       fi
+    done
+    exit 0
+} > $report 2>&1
diff --git a/tests/common.bash b/tests/common.bash
new file mode 100644 (file)
index 0000000..b621787
--- /dev/null
@@ -0,0 +1,14 @@
+name=$(basename $0 .bash)
+if [ "$#" -ne 0 ]; then
+       # Legacy
+       lsof=$1
+       report=$2
+       tcasedir=$3
+       dialect=$4
+else
+       # Autotools
+       lsof=$PWD/lsof
+       report=/dev/stdout
+       tcasedir=lib/dialects/${LSOF_DIALECT_DIR}/tests
+       dialect=${LSOF_DIALECT}
+fi
\ No newline at end of file
diff --git a/version b/version
new file mode 100644 (file)
index 0000000..22fe449
--- /dev/null
+++ b/version
@@ -0,0 +1 @@
+.ds VN 4.99.3
diff --git a/version.in b/version.in
new file mode 100644 (file)
index 0000000..5aaf5d6
--- /dev/null
@@ -0,0 +1 @@
+.ds VN @PACKAGE_VERSION@
\ No newline at end of file
diff --git a/zipme b/zipme
new file mode 100755 (executable)
index 0000000..22fac32
--- /dev/null
+++ b/zipme
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+# zipme -- make a bzip2'd tar archive of ~/src/lsof4
+
+cd $HOME/src/lsof4
+V=$(sed '/VN/s/.ds VN \(.*\)/\1/' $HOME/src/lsof4/version)
+if test $? -ne 0
+then
+  echo $V
+  exit 1
+fi
+cd ..
+T=lsof${V}.tar.bz2
+rm -f $T
+tar cf - lsof4 | bzip2 -c > $T
+ls -l $T