From: Andres Salomon Date: Tue, 3 Sep 2019 13:52:06 +0000 (+0000) Subject: Import lsof_4.93.2+dfsg.orig.tar.xz X-Git-Tag: archive/raspbian/4.99.4+dfsg-2+rpi1~1^2^2^2^2~8 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=72168f13d9061ed73c92ebc3976d8b3044f29775;p=lsof.git Import lsof_4.93.2+dfsg.orig.tar.xz [dgit import orig lsof_4.93.2+dfsg.orig.tar.xz] --- 72168f13d9061ed73c92ebc3976d8b3044f29775 diff --git a/.cirrus.yml b/.cirrus.yml new file mode 100644 index 0000000..e04fe1b --- /dev/null +++ b/.cirrus.yml @@ -0,0 +1,28 @@ +# freebsd13_task: +# freebsd_instance: +# image: freebsd-13-0-current-amd64-v20190503 +# timeout_in: 120m +# install_script: pkg install -y gcc git bash +# script: +# - ./Configure freebsd +# - make + +freebsd12_task: + freebsd_instance: + image: freebsd-12-0-release-amd64 + timeout_in: 120m + install_script: pkg install -y gcc git bash + script: + - ./Configure -n freebsd + - make + - bash ./check.bash freebsd + +freebsd11_task: + freebsd_instance: + image: freebsd-11-2-release-amd64 + timeout_in: 120m + install_script: pkg install -y gcc git bash + script: + - ./Configure -n freebsd + - make + - bash ./check.bash freebsd diff --git a/.ck00MAN b/.ck00MAN new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/.ck00MAN @@ -0,0 +1 @@ + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c200ad6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,96 @@ +# +# 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 +TAGS +lsof +tags +tests/config.* +version.h + +# +# Symbolic links to a diaclt implementation +# +/dfile.c +/dlsof.h +/dmnt.c +/dnode.c +/dproc.c +/dproto.h +/dsock.c +/dstore.c +/machine.h + +# +# Traditional test related files +# +LTbasic +LTbigf +LTdnlc +LTlock +LTnfs +LTnlink +LTsock +LTszoff +LTunix diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..285f8c1 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,63 @@ +# +# 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 + sudo 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 index 0000000..61cfe9a --- /dev/null +++ b/0..README.BEFORE.README.FIRST @@ -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 index 0000000..ea1355c --- /dev/null +++ b/00.README.FIRST @@ -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 + (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 +January 2, 2013 diff --git a/00CREDITS b/00CREDITS new file mode 100644 index 0000000..714e496 --- /dev/null +++ b/00CREDITS @@ -0,0 +1,548 @@ + + Lsof 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 + 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 + 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 + 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 + Conrad Meyer + Gary Millen + Timothy Miller + Davin Milun + Yuliy Minchev + Jim Mintha + Mike Miscevic + Arkadiusz Miskiewicz + Janardhan Molumuri + Nasser Momtaheni + Laurent Montaron + 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 + 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 + 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 and + @eranik (github account) + +If I have omitted a contributor's name, the fault is wholly mine, +and I apologize for the error. + + +Vic Abell +March 27, 2018 diff --git a/00DCACHE b/00DCACHE new file mode 100644 index 0000000..b1efa26 --- /dev/null +++ b/00DCACHE @@ -0,0 +1,745 @@ + + 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'' 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]'' 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 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]'' 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]'' 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]'' 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]'' 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]''. + +==================================================================== +* * +* 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]'' 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 ``#!''. + + 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 + NEXTSTEP 3.[13] + OpenBSD 2.[89] and 3.[0-9] for x86-based systems + OPENSTEP 4.x + 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 + Tru64 UNIX 5.1 + + +Vic Abell +February 14, 2018 diff --git a/00DIALECTS b/00DIALECTS new file mode 100644 index 0000000..2c01779 --- /dev/null +++ b/00DIALECTS @@ -0,0 +1,4 @@ + 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 diff --git a/00DIST b/00DIST new file mode 100644 index 0000000..352af29 --- /dev/null +++ b/00DIST @@ -0,0 +1,4940 @@ + + 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 + + +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 and 12.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 contact me at +. + +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 me via email at +. + + +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[_] + and 00RELEASE.SUMMARY_ -- 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 + 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 + on the 6.2 IMPACT distribution. + Heddy Boubaker + 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 + prompted this. + +4.02 March 21, 1997 + + Based on a report from Pasi Kaara , + 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 taught + HP-UX 10.x lsof to name file systems better by + using the virtual file system device number. Elias + Halldor Agustsson provided a test + system. + + Changed NEXTSTEP and UNIXWARE Makefiles to use + safer quoting when generating version.h. The change + was suggested by Bob Farmer . + + Added SHELL=/bin/sh string to all Makefiles. + + Added support for Linux 2.1.28 on a test system, + kindly provided by Jonathan Sergent . + 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 who helped test it. + Updated the old get_kernel_syms() code to recognize + and skip module name entries. + + Prompted by Marty Leisner , + 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 + 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 . Terry Kennedy + 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 , + 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 + 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 + 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 + helped develop and test the 5.3 definition. John + R. Vanderpool 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 + 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 + 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 + , 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 . + + 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 . (Configure's + -clean argument already did this.) + + Fixed an incorrect awk argument in the sunos*) + Configure stanza, reported by Alexandre Oliva + . + + Added CD9660 (aka ISO) file system support to + FreeBSD, NetBSD, and OpenBSD with mods and help + from Kenneth Stailey . + (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 + . Improved + the handling of IRIX 5.1 and greater FIFOs. + +4.07 May 12, 1997 + Based on AIX problem reports from David Capshaw + , 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 . + + 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 . + + 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 + and Jonathan Sergent + 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 + 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 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 + , 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 + 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 . 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 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 . 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 + + 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 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 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 , 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 . + +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 + . + + Cleaned up some typos and confusion in Configure's + help output, based on comments from Bela Lubkin + + + 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 + . + + Added socket state -- TCO or TPI -- for socket + files at the suggestion of Ian Fitchet + . + +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 . + + 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 + . 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 . + + 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 + 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 supplied the + changes. Kevin Smith 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 for + Solaris 2.x. W. Richard Stevens + 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 + 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 . + + 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 . 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 . + + 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 + 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 . + +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 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 . + +4.23 January 16, 1998 + Fixed conflict arising from the quondam replacement + of the Sun Solaris with a BIND/BSD version. + + With help from Jonathan Sergent + 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 . + + Added NFS node compensation for NetBSD 1.3. The + code and suggestion for it was supplied by Jean-Luc + Richier . + + 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 . + + 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 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 , enabling lsof to + compile for BSDI BSD/OS 2.0. + + Corrected a documentation error in 00DCACHE, pointed + out by Thomas Anders . 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 + 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 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 . + + 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 . + 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 + 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 + by IRIX 6.4 patch 2536. Added a + work-around for it to the lsof Configure script. + Igor Schein 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 , 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 , + , and .) + + 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 . The fix was + offered as a 4.28 patch. + + Adjusted for Digital UNIX 4.0D; the spec_node + structure is now defined in . Kris + Chandrasekhar + identified the need for the adjustment. + + Incorporated a bug fix from Brian McAllister + 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 reported the problem. + + Added a Solaris 2.6 work-around to keep the BIND + from colliding with the Solaris + . + + Strengthened the Configure test for /proc-based + Linux lsof, based on a report from Marty Leisner + . + + Tested on OpenBSD 2.3. + + Made AIX changes that allow use with 3.2.5. The + changes were suggested and tested by Brett Hogden + . + + 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 . He + supplied the correction. This was offered as a + patch to 4.29. + + Had a report from Igor Schein + 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 . 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 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 + 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 + provided a test system and Don + Draper 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 reported the + need for the update. Greg and Roger Klorese + provided technical information. + Scott McClung 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 . + This was offered as a patch to 4.30. + + Added support for Solaris 2.7 (first Beta release). + Mike Sullivan provided + technical advice and helped test. Charles Stephens + also helped test. + + Fixed bug in /proc-based Linux that caused it to + access /proc/mounts excessively. Marty Leisner + 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 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 + 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 . + 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 . + 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 + provided a test + system. Andrew Kephart + and Tom Weaver provided + technical assistance. Niklas Edmundsson + 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 + 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 supplied the + additions and helped with testing. Bill Pemberton + 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 supplied + technical details. + + Bracketed HP-UX 11 use of 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 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 . + Compensated for ncache element naming differences, + introduced at PTX 4.4.2; Kurtis D. Rader + 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 + 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 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 + requested this. + + Completed the HP-UX 11 port with support for its + optional 64 bit kernel. Rich Rauenzahn + 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 . + +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'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 . + This fix was offered as a patch to 4.35. + + Updated the Customize script to cause ENTER to use + all defaults. Amir J. Katz + suggested this and helped test the changes. + + Updated Solaris ICMP and IP stream handling, based + on a report from Igor Schein . + + Fixed a bug in the Digital UNIX mount table handling, + reported by Bob Ward . + 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 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 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 + 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 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 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 + . 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 + provided a test system. + + Added support for OpenBSD 2.4 with changes supplied + by Kenneth Stailey . + + 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 + and Carl Lindberg . + The combined dialect subdirectory is named n+os. + One of Carl's changes propagates RC_CFLAGS to the + library Makefile. Timothy J. Luoma + 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 . Lee + Penn 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 + . + + Acquired a new UnixWare 2.x test system, generously + provided by Computer Classroom, Inc. -- Matthew + Thurmaier , Ken Laing + , and Andrew Merril + . 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 . 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 + . + + For Bela Lubkin 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 and Maciej + Lesniewski . Jeff helped test + them on various Linux architectures. + + Tested on AIX 4.3.2; no changes were required. + Doug Crabill 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 . + + Based on a report from Michael Schmitz + 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 " and "+d " options for directory + searching. +D searches the entire tree, starting + at , including , its contents, and its + subdirectory branches; +d searches only 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 + 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 + . + + Fixed an AIX 4.3+ bug in procinfo struct space + allocation, reported by Jeff Stewart . + 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 + 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 , David O'Brien + , and John Polstra . + + 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 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 + . This was offered as a + patch to 4.40. + + Installed an HP-UX 11 patch, suggested by Kevin + Vajk , 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 + + 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 + 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 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 + 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 + 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 + . + + 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 , 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 . + + Corrected HP-UX error message about HP-UX 11 q4 usage. + Amir Katz reported the correction. + + Fixed a GlibC 2.1 conflict in /proc-based Linux lsof. + + Fixed a man page typo reported by Vlad Harchev + . + + 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 + . + + Fixed a PTX real vnode to real inode interpretation + bug. + + Added link count to lsof output. Eric Dumazet + 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 + 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 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 + 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 + 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 + and Don Draper . + + 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 . + 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 . 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 . 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 . + 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 , who + provided information and did testing. + + Enabled IPv6 support code for NetBSD and OpenBSD, + conditional on Configure script tests. Wolfgang + Rupprecht 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 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 and Andrew + Thomas Sydelko 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 + . + + Sylvain Robitaille 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 + , who also tested the fix. + + Added a libc5 library /dev/kmem-based Linux lsof + circumvention, supplied by Jason Lingohr + . + + Corrected a bug in -t (terse) AIX output, reported + by Wendy Lin . 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 header file. Volker Borchert + 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 + . + + Fixed a gawk POSIX-mode pattern error in the Linux + /dev/kmem-based Mksrc script, based on a tip from + Ambrose C. Li . + + Fixed a bug in the Tru64 UNIX IPv6 handling, courtesy + of a report from Casper Dik . + + Enabled support for OpenBSD 2.6. + + Enabled support for BSDI BSD/OS 4.1, based on a + report from Jeffrey C Honig 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 + helped test. + + Fixed a DEC OSF/1, Digital UNIX, Tru64 UNIX repeat + mode bug, reported by Mayer Ilovitz . + 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 . + The fix was offered as a patch to 4.45. + + Added support for INRIA IPv6 to NetBSD. Jean-Luc + Richier provided patches + and a test system on which to verify them. + + Added support for AIX 4.3.3. Jeff W. Stewart + 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 , + 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 , + 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 with the + patches. The problem was reported by Will Partain + . Elias Halldor Agustsson + 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 . + + 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 . 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 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 + improved AFS configuration + for AIX and Solaris, and updated AIX AFS 3.5 support. + Johannes Tax , Hung T. + Pham , and Curt Freeland + provided test systems. + + Updated lsof's private rnode definition for AIX + 4.3.3, since IBM still doesn't ship the + header file and the rnode + structure definition in 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 . + + Adjusted for a FreeBSD 4.0 change in the definition + of [_]KERNEL. David O'Brien 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 . + +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 + 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 + 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 + 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 + . 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 + . + + 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 , 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 . + +4.50 June 29, 2000 + Added a NetBSD alpha test host, courtesy of Ray + Phillips . 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 + and Jim Mintha . + + Forced AIX to use the large-file-enabled versions + of lstat (lstat64) and stat (stat64) if + 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 and + puts -DHASSTAT64 in the Makefile's CFLAGS to make + this happen. Fernando A.B. Whitaker + reported the problem. + This was offered as a patch to 4.48. + + Enabled Configure script to handle OpenBSD 2.7. + Angelos D. Keromytis + 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 supplied + patches and did testing. David O'Brien + 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 for + a FreeBSD 3.4 test system. + + In response to an lsof 3.72 bug report from Jim Mewes + , added more kernel address + filtering to the lsof function, kread(), that reads + Solaris kernel data. + + In response to a report from Marc Duponcheel + , 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 , 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 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 . + Dan supplied a patch and did FreeBSD testing. + + Added Configure script recognition of NetBSD 1.5, + based on a report from Andrew Brown . + Thomas Klausner 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 . + + 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 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 + and Klaus Saggerer USG + [saggerer@zk3.dec.com> helped put me in contact + with Chang Song , 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 , Thomas Klausner + , and Wolfgang + Rupprecht 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 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 provided a test system. + + Based on a report from Marc Christensen + 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 + 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 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 , + Diane Lebel , and John Speno. + The support only provides information about cached + file attributes. + + Installed a Configure patch for HP-UX 11 supplied by + Kenneth Stailey that adds + another command to q4 input. + + Tested on FreeBSD 4.2. + + Will Day and Frank + Winkler graciously + supplied Solaris 8 binaries. + + Added Solaris 9 text file support, supplied by + Casper Dik . + +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 . 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 + . + + 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 + provided the necessary clue. + + Based on a report from Valdis Kletnieks + , 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 + , 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 . + + 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 . + + 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 requested and helped + test it. + +4.55 February 15, 2001 + Based on a report from Bernd Eckenfels + added support in lsof for files in /proc//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 + 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 + 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. helped test. + + Added support for UnixWare 7.1.1 and above in-kernel + UNIX sockets. John Hughes 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 . + + Archived a set of compilation hints (patches) from + Bill Melvin 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 + 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 conditional + on the Solaris version. (It's apparently not needed + at 2.6 and above.) Bill Watson + brought this to my attention. + + Added alternate Linux 2.4.x lock extent test, supplied + by Jim Mintha . + + 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 , + Gary Millen , Rainer Orth + , Peter C. Vernam + , and Donna Yobs + + + 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 + , 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 + 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 . Troyan Krastev + brought the bug to + my attention and Michael Bracewell + 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 . + Lsof will use setlocale(), when that function and + its supporting header file are available. + + Added OpenBSD 2.9 support. + + Based on a report from Aaron Rhodes + 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 + help test. The lsof + FreeBSD ports packager, David O'Brien , + 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 . + + 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 + . + + 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 . 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 . + + Made available for re-distribution a user-contributed + port of lsof 4.51 to Reliant UNIX 5.45. Thomas + Mauterer 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 + . + + Corrected a bug in the way Linux lsof identifies + the owner of a process. Lionel Cons + 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 . + Matthew Thurmaier and many + people from Caldera provided technical assistance. + + Added an additional UVM test to the NetBSD Configure + stanza. Andrew Brown 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 + for Darwin 1.4. + + Added for Bela Lubkin + 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 . + + 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 + helped test. + + Made lsof's method of killing its child process + more robust, based on a suggestion from Bela Lubkin + . + + 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 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 . + + In response to a report from Joshua Wright + 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 + 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 + + Based on a report from Mark W. Eichin + 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 and Marc + Stephenson , and on a test + system provided by Loc Le . + +4.62 March 7, 2002 + Updated 00README to reflect the usefulness of gcc + for building AIX lsof. Documented a report from + Brian L. Gentry 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 . + 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 . + + 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 + 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 . + 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 , + based on a report from Larry Rosenman + 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 . + + 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 . + 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 + . 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 + . + + Added defense against the standard I/O descriptor + attack. + +4.64 June 26, 2002 + Corrected some FreeBSD pre-processor directives. + David O'Brien 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 . + 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 + 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 + 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 , + and new a bug in the fix, reported by Eric Cronin + + + Added nullfs support for FreeBSD, NetBSD, and OpenBSD + at the request of Andrew Brown . + + 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 sent me the + dnode.c change and Casper Dik + 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 . + Larry Rosenman 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 . + Adjusted for changes in FreeBSD 5.0-CURRENT . + One change was reported by Anders Nordby + . 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 . + + Enabled compiling of lsof for NetBSD 1.5 with the + NULL file system, using a patch from Andrew Brown + . + + 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 + brought the need for this change to my attention. + + Applied a patch, supplied by Andrew Brown + , 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 . + + Updated to FreeBSD 4.7. + + Updated to Apple Darwin 1.5, 5.x and 6.x with + patches supplied by Allan Nathanson . + 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 + 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 . 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 + , 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 . Updated + 00TEST and tests/TestDB accordingly. + + Clarified FreeBSD 5.0 architecture claims at the + suggestion of David O'Brien . + 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 + . + + Upgraded True 64 UNIX support to the 5.1B release + on a test system provided by Berkley Shands + 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 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 + + +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 + added the "+c " option to enable optional + changing of the COMMAND column output maximum width + from the default to . 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 , who tested the fixes. + + Added kernel event queue file support for FreeBSD, + NetBSD and OpenBSD. Andrew Brown + supplied the code. + + Updated to AIX 5.2 on a test system provided by + Dale Talcott . Had to build + work-arounds for two missing AIX 5.2 header files, + and . 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 + Toshiya Nakamura 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 . + + 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 . + + Improved the description of the detached PGP + signature certificate file in the main lsof README + file, based on a suggestion from Diana Stockdale + . + + 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 + 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 + determined the NetBSD snapshot (1.6F) at which + 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 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_ file of the + distribution archive. John Jackson + and Ray Phillips + 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 + 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 , 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 + . 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 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 . + 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 + 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 + to handle NetBSD enum conflicts and changes in the + and + header files. + + Added a "#define _KERNEL" to the AIX dnode2.c source + file for compatibility with a new + AIX 5.2 header file version. The addition was + supplied by Dick Dunbar + and was offered as a patch to lsof 4.68/ + + Added support for a second type of Solaris SAMFS. + Stuart Anderson 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 . Casper Dik + 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 . + 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 . + + Validated lsof on FreeBSD 5.1-CURRENT for Amd64. + David O'Brien 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 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 + . + + 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 . 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 . + + 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 . + + Based on a report from John Jackson , + enabled a Solaris 10 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 and + John Heasley 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 + . + + 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 + and Eric Williams (aka The Ghost + In The Machine) 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 + and Tristan Nefzger 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 + 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's + fix was offered as a patch to 4.71. + + Based on a report from Jean-Pierre Radley + 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 . 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 . + + Added support for FreeBSD 4.10. Larry Rosenman + kindly provided a test system. + + Added support for NetBSD 2.0 with patches supplied by + Andrew Brown . Andrew also + provided two test systems. + + Made handling of Linux maps file more robust, based on + a report from Jan Blunck . As + a side benefit, made handling of generated stat(2) + information more flexible. + + As a result of a discussion with Jason Fortezzo + , adjusted lsof for Solaris + to obtain the maximum user name length from ut_name of + the utmpx structure, if exists. + + Tested under OpenBSD 3.5. + + Updated 00README information about using gcc (via the + Configure aixgcc abbrevisiation) to compile lsof on + AIX. Ann Janssen 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 + about lsof memory usage. + + Added scripts/sort_res.perl5, contributed by Fabian + Frederick . 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 . + + Updated FreeBSD 5.2-CURRENT support, based on a problem + report from Filippo Natali . + + Corrected improper FreeeBSD 5.x-CURRENT #if condition, + reported by Kim Culhan . + + 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 . + +4.73 October 21, 2004 + Added an __XPG4_CHAR_CLASS__ #define before + #include'ing 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 + . 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 , + supplied by Sergey A. Osokin . + + Implemented a Linux feature request made by Jakub + Jelinek 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 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 . (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 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 + . + + Updated lsof for FreeBSD 6.0 and higher for a change in + , based on a report from Sergey A. Osokin + . 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 . + 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 helped + test. + + Updated for Solaris 10, build s10_69, with a patch + supplied by Mike Miscevic . + + 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 . + + Updated lsof for NetBSD 2.99.10 and tested it on a + system provided by Andrew Brown . + + 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 . + + Added abbreviations for AXI FCIO and FSNAPSHOT file + flags. Holger VanKoll + 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 for it.) + + Corrected a Linux socket inode printing bug reported by + Igor Schein . + + 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 . + +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 + 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 + changed DEC OSF/1 process table + allocation to request memory in smaller increments. + + Based on a report from jayjwa + 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 . 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 . + + 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 + . 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 + . 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 . Marc provided + a test system. + + Supplied a missing quote in the FreeBSD Configure + stanza. Carl Cook 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 . Allan also provided a + test system. + + Completed documentation of CLRLFILEADD in all machine.h + files. + + At the request of Chris Markle + 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 . + + Updated Solaris VxFS support for VxFS versions 4 and + above with technical advice from Craig Harmer + , Gary Millen + and Chuck Silvers + . Testing help was + provided by Michael Antlitz , + Steve Ginsberg and Kenneth + Stailey . + + Fixed a Solaris address space map processing bug. + Janardhan Molumuri 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 + 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 . 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 + reported those needs. + + Fixed an HP-UX 11 file descriptor "chunk" size problem, + reported by Per Allansson . 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 , the + author of the script. + + Corrected +|-M man page documentation error, reported + by Roger Cornelius . + + Improved FreeBSD user device random seed generation in + response to a problem report from Danny Braniss + . + + Eliminated three syntax error bugs and other compiler + complaints from the PSTAT-based lsof. H. Merijn Brand + 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 . 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 + . Devised a work-around to gcc's + omission of the rpcent structure definition of + 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 . + + 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 , + 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 . 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 . + + Based on a bug report from Karel Zak + 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 + reported the problem. + + Added code to avoid processing Linux /proc//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 reported + lsof's mishandling of such entries. + + Added SELinux security context support, provided by + James Antill . I have not + tested this, but James and Karel Zak + have. + + Added the #include of 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 + and Tom Whitty . + + 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 . + + 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 + provided a development + system and helped test the support. + + Corrected a typo in the man page, reported by Eric S. + Raymond . + + Changed the spelling of macroes to macros in lsof + source and documentations files, based on a suggestion + from Josh Soref 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 . Gregory tested the + fix. + + Moved an #include later in FreeBSD dlsof.h + to enable compilation on recent FreeBSD releases. The + change was supplied by Roy Marples . + + Improved Linux /proc file stream reading speed by applying + an expanded version of a patch from Eric Dumazet + 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 + . + + Fixed a Linux maps file processing bug that prevented path + names from having an embedded colon. James Lingard + reported the bug and helped with its + fix. + + Based on reports from Eric Dumazet and Samuel Thibault + added support for the + Linux 2.6.22 kernel's /proc//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 . 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 + . Pekka tested the fix. + + Based on a report and using suggested fixes from Karel Zak + , 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 + 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 + 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 . + + Updated FreeBSD lsof with ZFS support. Larry Rosenman + , Erwin Lansing , Wesley + Shields and Dmitry Morozovsky + provided test systems. + + Fixed a socket file identification problem reported by + Pavol Rusnak . 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 , + 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 + and Pav Lucistnik + 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 + , who helped test the update. Wesley + Shields 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 + . + + Added warnings for unsupported dialects or versions. + + Added Linux support for the UDPLITE protocol. Eric + Dumazet 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 + who tested the corrected + Makefile. + +4.81 October 21, 2008 + Updated the Darwin libproc sources with changes from + Allan Nathanson . 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 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 + . + + 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 . An updated + test system was provided by Erwin Lansing . + + 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 + and Phil Shin 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^" 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 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 . + + Corrected mishandling of file system path name arguments + that have trailing slashes, except, of course, the root + file system, "/". Allan Nathanson 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 reported the bug and + supplied information for reproducing it. + + Based on a report from Dan Trinkle + corrected use of 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 . + + Updated the Darwin libproc sources with changes from + Allan Nathanson . 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 . + + Improved the Solaris VxFS library location test, based on a + suggestion from Jason Fortezzo . + 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 . Renata + Maria Dart 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 + reported the device number problem, + provided a test system, and tested the changes. Peter + Vines 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 + . Larry Rosenman + 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 . + + Corrected a typo in the testing of the LINUX_HASSELINUX + environment variable in the Configure script. The error + was reported by Mike Frysinger . + 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 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 . + + Adjusted to the disappearance of 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 + 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 > + + Made corrections to FAQ typographical errors, suggested + by Josh Soref . + + Added __UCLIBC__ test to Linux dlsof.h so lsof would compile + on an Intel ARM XScale processor. The addition was provided + by Doug Kehn . + + Added test for to FreeBSD configuration. Improved + its use in lsof.h. The changes were supplied by Martin Wilke + . + +4.84 July 29, 2010 + Fixed a man page nroff command error with a correction + supplied by Josh Soref . + + Made Configure script recognize FreeBSD 7.3. Larry Rosenman + provided a test system. + + Improved task support, initially for Linux only, with help + provided by Jerome Marchand and + Miklos Szeredi . 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 . 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 . + +4.85 September 27, 2011 + John Dzubera 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 + . Carson Gaspar reported + the problem and supplied the work-around. + + Added support for FreeBSD 7.4 and 8.2; tested on systems + provided by Larry Rosenman . + + Added support for 32 bit Solaris 11 lsof with mods supplied + by Jan Wortelboer . + + Added Solaris 11 support for using an alternate genunix + location. Bill Goodridge + reported the alternate location. + + Added further Linux cross configuration support to lsof's + Configure script. The additional support was supplied by + Grant Erickson . 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 . Allan also provided a test + system. + + Tested on FreeBSD 6.4 i386, using a test system provided by + Terry Kennedy . 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 + . + + Added compensation for Solaris 10 systems that have patch + 144488-10. The patch requires that the new header file + be included while _KERNEL is defined. + Brett Bartick reported the problem + first, followed by Stuart Anderson . + Michael Hocke 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 + + + 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 + , 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 + reported the bug and supplied a patch. + + Added compensation for the removal of RPC header files from + GlibC 2.14 for Linux. Marek Behun + reported the problem and supplied a patch. + + Added support for Linux Netlink protocol. Masatake Yamato + requested the support and supplied a patch. Peter Schiffer + 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 . + 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 . + + Updated for latest Solaris 11 with patches supplied by + Carson Gaspar . 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 , who + provided a test system. + + At the request of Peter Schiffer , 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 . Allan also supplied a test + system. + + Enabled FreeBSD 8.3 support and tested it there on a system + provided by Larry Rosenman . + + Corrected the FAQ information on ZFS with Solaris 10 after + Steven Blackmon and Prasad Jampala + 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 + 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 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 . + + Added support for Linux anon_inodefs, provided by Masatake + YAMATO . + + Documented a Solaris 9 and 10 portmap reporting problem + (+M) in 00FAQ. The problem was reported by Clint + Roberts . 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 reported the + need for the addition. + + Added ICMP socket support for Linux with code provided by + Masatake YAMATO . + + Corrected the reporting of process group ID for libproc + versions of Mac OS X with a patch from Jeff Trawick + . 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 . + + 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 . 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 + 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 . 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 and a + Solaris 11 patch he provided is included in this revision. + + Initialized local variables in the Linux process_id() function. + Jia He 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 + 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 + reported the problem. + + Added support for Linux RDMA and CRYPTO protocal names and UNIX + socket type with code from Masatake YAMATO . + + 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 . + +4.89 July 7, 2015 + Applied correction from Casper Dik 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 provided + a test system. Andrey Chernov provided + useful advice. + + Improved tests/Add2TestDB script with a patch from Peter + Schiffer . Added patches from Peter to + eliminate Linux gcc warnings. Updated Lsof.8 with improvements + supplied by Bjarni Ingi Gislason . + + Changed FreeBSD global CFLAGS extraction per Terry Kennedy + . 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 did the testing. + + Fixed Linux UNIX socket search by name bug reported by + Stephane Chazelas . + + Added Linux display of UNIX socket endpoint information with + code provided by Masatake YAMATO . Peter + Schiffer provided a test system. + + Insured that type definitions from 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 ! + ! ! + !!!NOTE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + Taught the Configure script to create a dummy opt_random.h + for FreeBSD systems whose 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 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 . + + Enhanced -K option with the form "-K i" to direct lsof to + (i)gnore tasks. A query from Rachel Kroll + suggested this option. Linux task reports now include both + process and task command names, making lsof's "-c " + option work correctly. + + Added a patch to prevent NFS blocking in Linux supplied by + Kristyna Streitova . + + Installed a FreeBSD patch that prevents examining a TCP state + structure during a race condition. The patch was supplied by + Bryan Drewery . + + Updated FreeBSD for new UFS inode structure that lacks an i_dev + member in the most recent 12.0-CURRENT. Larry Rosenman + reported the problem and provided a test + system. + + Added "#define KLD_MODULE" to dlsof.h and dnode2.c to prevent + 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 supplied the fix. + + Added a patch from Larry Rosenman 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 , based on information provided by Jorn + Clausen . 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 . + + 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 + . + + Added patch to dlsof.h that avoids a _KERNEL conflict with + bzero. Mateusz Guzik supplied the patch. + + Corrected test library to handle 64 bit FreeBSD device numbers. + + Added #defines for FreeBSD 12, src r324225, from Gleb Smirnoff + . + + Incorporated Linux pseudoterminal endpoint processing (+|-E) + provided by Masatake YAMATO with access to + test systems provided by Peter Schiffer . + + 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 , 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 + 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 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. + +Vic Abell +July 14, 2018 + + +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. + +Masatake YAMATO , a member of lsof-org +May 8, 2019 diff --git a/00FAQ b/00FAQ new file mode 100644 index 0000000..2937ff8 --- /dev/null +++ b/00FAQ @@ -0,0 +1,8039 @@ + + 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 +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_? +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 "... 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 + +7.0 DEC OSF/1, Digital UNIX, and Tru64 UNIX Problems +7.1 Why does lsof complain about non-existent /dev/fd entries? +7.2 Why does the Digital UNIX V3.2 ld complain about Ots* symbols? +7.3 Why can't lsof locate named pipes (FIFOs) under V3.2? +7.4 Why does lsof use the wrong configuration header files? + For example, why can't the lsof compilation find cpus.h? +7.5 Why does lsof indicate incomplete paths with " -- " for Tru64 + UNIX 5.1 files? +7.6 Why doesn't lsof report link count, node number, and size + for some Tru64 5.x CFS files? +7.7 Why does lsof say it can't read the kernel name list or + proc table on Digital UNIX 4.x or Tru64 UNIX? + +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 + 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? + +12.0 NEXTSTEP and OPENSTEP Problems +12.1 Why can't lsof report on 3.1 lockf() or fcntl(F_SETLK) + locks? +12.2 Why doesn't lsof compile for NEXTSTEP with AFS? + +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 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 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//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 lastest + 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_ + 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_ 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_? + + The "Security" section of the README.lsof_ 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_, 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 via e-mail to . Do NOT report lsof + bugs to the UNIX dialect vendor. Make sure "lsof" appears in + the "Subject:" line so my e-mail filter won't classify your + letter as Spam. + + Before you send me 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 . 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 + $ (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 + 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 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 . + 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 + NEXTSTEP + OpenBSD + OPENSTEP + 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 -inum -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 '' 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. + Digital UNIX and Tru64 UNIX 4.0 + 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. + OPENSTEP 4.2 + 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. + Digital UNIX 4.0 + This dialect is no longer supported, so no attempt + was made to add partial listen queue length support + for it. + 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. + OPENSTEP 4.2 + 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 + 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 + 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 ` 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 specify the individual path names + of those files, or use the lsof +D and +d options. + + 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, , with the rpcent + structure definition, and there is a Solaris C pre-processor + test that can tell when the BIND is in place and + hence 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 and any other header files BIND might + have replaced. (I think BIND replaces , + , -- 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 + 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 : 2 sections + ... + lsof: WARNING: created device cache file: + + 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 " + or "like character special ". + + The value for 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 . 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 '' 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 '' 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 + $ 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 ... : + 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: + + + + 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 . 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 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() 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 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 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/ + + where is a unique name in /tmp of your choosing. To + be safe, create a subdirectory in /tmp, named by your login: + + $ rm -f /tmp/ + $ mkdir /tmp/ + $ ./LTnlink -p /tmp// + +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 "... 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 + + 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 + in ./dialects/aix/aix 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 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 . + + 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 that was compiled into the lsof executable. + + On AIX 4.3.3 there are two different user structure + definitions in two separate 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 , 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 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 . 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. + + +7.0 DEC OSF/1, Digital UNIX, and Tru64 UNIX Problems + +7.1 Why does lsof complain about non-existent /dev/fd entries? + + When you run lsof for Digital UNIX 3.2, lsof may complain: + + lsof: can't lstat /dev/fd/xxx: No such file or directory + lsof: can't lstat /dev/fd/yyy: No such file or directory + + (Or it may warn about other missing /dev/fd paths.) When + you do an ``ls /dev/fd'' none of the missing paths are listed. + + This is caused by a bug in the DEC library function + getdirentries(). For some reason, when /dev/fd is a file + system mount point, getdirentries() returns an incorrect + size for it to readdir(). (Lsof calls readdir() in its + ddev.c readdev() function.) Because of the incorrect size, + readdir() goes past the end of the /dev/fd directory buffer, + encounters random paths and returns them to lsof. Lsof + then attempts to lstat(2) the random paths, gets error + replies from lstat(2), and complains about the paths. + + Duncan McEwan discovered this error and has reported it to + DEC. Duncan also supplied an alternate readdir() function + as a work-around. I've incorporated his readdir() in + dialects/osf/ddev.c (as the static ReadDir() function) with + some slight modifications, and enabled its use when the + USELOCALREADDIR symbol is defined. + + The Configure script defines USELOCALREADDIR for Digital + UNIX version and 3.2. If you don't want to use Duncan's + local readdir() function, edit the Makefile and remove + -DUSELOCALREADDIR from the CFGF string. When DEC releases + a corrected getdirentries() function, I'll modify the + Configure script to stop defining USELOCALREADDIR. + +7.2 Why does the Digital UNIX V3.2 ld complain about Ots* symbols? + + When you compile lsof on your Digital UNIX V3.2 system, ld + may complain: + + ld: + Unresolved: + knlist + _OtsRemainder32Unsigned + _OtsDivide64Unsigned + _OtsRemainder64Unsigned + _OtsDivide32Unsigned + _OtsMove + _OtsDivide32 + _OtsRemainder32 + *** Exit 1 + + Chris Eleveld reports this happens on Digital UNIX V3.2 + systems after the Fortran compiler has been installed. + + The best work-around seems to be to remove -lmld from the + CFGL string in the Makefile produced by Configure -- i.e., + change: + + CFGL= -lmld + to + CFGL= + + According to the V3.2 man page for nlist(3), this shouldn't + work, but my testing shows that it does. Although I haven't + been able to test this second work-around, you might try + adding -lots to CFGL, rather than removing -lmld -- i.e., + change: + + CFGL= -lmld + to + CFGL= -lmld -lots + + WARNING: my testing also shows that the V2.0 nlist(3) man + page means what it says when it calls for -lmld -- lsof + loaded without -mld under V2.0 can't locate the proc + (process) table address. + + DON'T REMOVE -lmld FROM THE DIGITAL UNIX V2.0 MAKEFILE. + + If you run into this problem, please let me know what + problem you encountered and how you solved it. + +7.3 Why can't lsof locate named pipes (FIFOs) under V3.2? + + While lsof for V3.2 can report on named pipes (FIFOs), it + can't find them by name. That appears to happen because + of the way the V3.2 kernel lstat(2) function reports named + pipe device numbers. + + The V3.2 kernel reports the device number as 0xfffffff, + while the kernel structures for named pipes that lsof + examines contain the device number of the file system on + which the named pipe resides. + + Consequently, lsof can't match the device and inode number + pair it receives from applying lstat(2) to the named pipe + with any device and inode number pair it finds when scanning + kernel structures. + + I don't have a work-around. You can, of course, ask for + full lsof output and use a post-processing filer (e.g., + grep) to locate the named pipe of interest. + + This problem doesn't exist under V2.0. + +7.4 Why does lsof use the wrong configuration header files? + For example, why can't the lsof compilation find cpus.h? + + DEC OSF/1, Digital UNIX, and Tru64 UNIX configuration header + files describe the hardware and software environment for + which your kernel boot file was constructed. For example, + /sys//cpus.h defines the number of CPUs in its NCPUS + #define. + + Lsof searches for the configuration header file subdirectory + in /sys (/usr/sys for Digital UNIX version 4.0 and Tru64 + UNIX) by converting the first host name component to capital + letters -- e.g., TOMIS is derived from tomis.bio.purdue.edu. + If that subdirectory exists, lsof uses header files from + it. (Configure reports what subdirectory is being used.) + + If Configure doesn't find a host-name derived subdirectory, + it prompts you for the entry of a subdirectory name. If + you can't find one, quit Configure and run the kernel + generation process to create a proper configuration sub- + directory. If you don't identify a proper configuration + subdirectory and you try to compile lsof, the compiler will + complain about missing header files -- e.g., a missing + cpus.h. + + Once you have located or generated a proper configuration + subdirectory, rerun Configure. If you have generated a + configuration subdirectory whose name is derived from the + host name, Configure will find and use it. If not, you + will have to specify its name to Configure. + +7.5 Why does lsof indicate incomplete paths with " -- " for Tru64 + UNIX 5.1 files? + + When lsof can't find a component of a path in the kernel's + name cache (aka DNLC), or can't determine that the left-most + component has as its parent the file system root, it uses + an "incomplete path" notation. That notation begins with + the file system root name, followed by " -- ", followed by + the consecutive path name components lsof was able to find + in the DNLC -- e.g., "/ -- init". + + Because the DNLC was significantly redesigned in Tru64 UNIX + 5.1, lsof's handling of the cache had to be completely + redone. As part of the DNLC redesign a name cache entry + parameter lsof formerly used to locate the file system root + of a path was removed. With help from Chang Song I've been + able to implement an alternate method for detecting the + root of these file system types: AdvFS (MSFS), CDFS, DVDFS, + FDFS, NFS, NFS3, and UFS. + + When lsof doesn't know how to identify the root for a file + system type, it will resort to the " -- " incomplete path + notation. + +7.6 Why doesn't lsof report link count, node number, and size + for some Tru64 5.x 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 system where lsof runs, so lsof cannot report them. + +7.7 Why does lsof say it can't read the kernel name list or + proc table on Digital UNIX 4.x or Tru64 UNIX? + + By default on Digital UNIX 4 and Tru64 UNIX lsof reads the + addresses for kernel symbols with the knlist(3) function. + That function can fail, for example, when the kloadsrv + daemon isn't running or is malfunctioning. When that + happens, lsof may abort with one of these error messages: + + lsof: can't read kernel name list from knlist(3): ... + or + lsof: can't read proc table info + + The first message suggests a complete knlist(3) or kloadsrv + failure; the second, a partial one. + + If you know the name of the file from which the running + system was booted, e.g., /vmunix, you can use lsof's -k + option to direct it to read kernel symbol addresses from + the name list of that file -- + + $ lsof -k /vmunix ... + + If that works, then knlist(3) is malfunctioning and you + need to fix it. + + +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 . + 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 0 + # chmod 440 /dev/mem + # chgrp kmem /dev/mem + + For 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 and introduce a new structure, + lockf_entry, to that header file. When Configure detects the + presence of the lockf_entry definition in , 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 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_/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 . 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 + 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 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., + + : 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 + 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 header file. + Sometimes it is missing from /usr/include/sys/fs. + + is a header file that must be obtained from + Veritas. If that proves impossible, please contact me via + e-mail at . 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_/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 bytes of pst_static + lsof: FATAL: pst_static doesn't contain _size + lsof: FATAL: _size should be + + These messages indicate that lsof's tests for the proper + level of PSTAT support have failed. The structure names, + given in , and sizes, given in , 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: / + + 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 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 . + + 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 ( 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//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 /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 + . 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/ + + if the header line of the indicated 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 . + 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//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//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 /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//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//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 (or ) + 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//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//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/ directory, it reports a + single file of the type ``NOFD'' (for no file descriptors). + + Lsof reports the the /proc//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/'' entry -- + e.g., it can't convert the entry to a full and more meaningful + path name, or it can't access the /proc//fd subdirectory + with opendir() -- it will report the /proc/ 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 + + The 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. + + +12.0 NEXTSTEP and OPENSTEP Problems + +12.1 Why can't lsof report on 3.1 lockf() or fcntl(F_SETLK) + locks? + + Lsof has code to test for locks defined with lockf() or + fcntl(F_SETLK) under NEXTSTEP 3.1, but that code has never + been tested. I couldn't test it, because my NEXTSTEP 3.1 + lockf() and fcntl(F_SETLK) functions return "Invalid + argument" every way I have tried to invoke them. + + If your NEXTSTEP 3.1 system does allow you to use lockf() + and fcntl(F_SETLK) and lsof doesn't report locks set with + them, then the code in .../dialects/next/dnode.c probably + isn't correct. Please contact me via e-mail at + and tell me how you got your lockf() and fcntl(F_SETLK) system + calls to work. Make sure "lsof" appears in the "Subject:" line + so my e-mail filter won't classify your letter as Spam. + +12.2 Why doesn't lsof compile for NEXTSTEP with AFS? + + I no longer have a NEXTSTEP test system that has AFS. + Changes to lsof since I once had a test system have caused + me to change the AFS code in NEXTSTEP without being able + to test the changes. + + If you need AFS support for NEXTSTEP and can't get it to + compile, please contact me. Perhaps we can jointly fix + the problems. + + +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 + 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 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 uses NBPG from + 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/n+obsd/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 + #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 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 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 + , , , , + o, and 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 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 . 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 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 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 . 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 . + 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(): + + 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 | 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 + + It means that lsof can't find the booted kernel image file + at . 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 " 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: + + + + + + + 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 . 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 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 header file whose NUM_*_VECTORS + definitions don't match the ones in the updated + by Solaris patch 102303-02. + + NUM_*_VECTORS in the kernel of patch 101945-32 are smaller + than the ones in the of patch 102303-02. The + consequence is that when lsof is compiled with the + 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//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 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 + or + mkfs -m + or + vxupgrade + + 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 . 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 header file, but the libctl + library is not indicated via the 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 and when _KMEMUSER or + _KERNEL is #define'd before 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) + NEXTSTEP 3.2 (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 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 +March ??? 2018 diff --git a/00MANIFEST b/00MANIFEST new file mode 100644 index 0000000..6e2fae8 --- /dev/null +++ b/00MANIFEST @@ -0,0 +1,364 @@ +.: +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 +lsof.h +lsof.man +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 + +./dialects: +aix/ +darwin/ +du/ +freebsd/ +hpux/ +linux/ +n+obsd/ +n+os/ +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: +get-hdr-loc.sh* +kmem/ +libproc/ + +./dialects/darwin/kmem: +Makefile +Mksrc* +ddev.c +dfile.c +dlsof.h +dmnt.c +dnode.c +dnode1.c +dproc.c +dproto.h +dsock.c +dstore.c +machine.h + +./dialects/darwin/libproc: +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/n+obsd: +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 +regex.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 index 0000000..8e6d45d --- /dev/null +++ b/00PORTING @@ -0,0 +1,1890 @@ + + 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/ 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//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 / 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 +/ 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//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. + + +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. + +Unusual situations occur for NetBSD and OpenBSD, and for NEXTSTEP +and OPENSTEP. Each pair of dialects is so close in design that +the same dialect sources from the n+obsd subdirectory serves NetBSD +and OpenBSD; from n+os, NEXTSTEP and OPENSTEP. + +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 + + lsof.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. + + snpf.c Source for the snprintf() family of functions + + USE_LIB_SNPF selects it. + + +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) + + in preference to + + #ifdef + + 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., -- +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 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 lsof.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 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. + + HAS_ATOMIC_T indicates the Linux version has an + header file and it contains + "typedef struct .* atomic_t;" + + HASAOPT indicates the dialect supports the AFS -A + option when HAS_AFS is also defined. + + HAS_ASM_TERMIOBITS indicates for Linux Alpha that the + header file exists. + + HASAX25CBPTR indicates that the Linux sock struct has an + ax25_db pointer. + + HASBLKDEV indicates the dialect has block device support. + + HASBUFQ_H indicates the *NSD dialect has the + header file. + + HASCACHEFS enables cache file system support for the + dialect. + + HAS_CDFS enables CDFS 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 + header file available. + + HASCWDINFO indicates the cwdinfo structure is defined + in the NetBSD . + + 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. + + HASDENTRY indicates the Linux version has a dentry + struct defined in . + + HASDEVKNC indicates the Linux version has a kernel + name cached keyed on device number. + + 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 + 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_FDESCENTTBL indicates the FreeBSD system has the fdescenttbl + structure. + + HAS_FILEDESCENT indicates the FreeBSD system has the filedescent + definition in the header file. + + HASFDESCFS enables file descriptor file system support + for the dialect. A value of 1 indicates + 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_FL_FD indicates the Linux version has an fl_fd + element in the lock structure of . + + HAS_FL_FILE indicates the Linux version has an fl_file + element in the lock structure of . + + HAS_FL_WHENCE indicates the Linux version has an fl_whence + element in the lock structure of . + + 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 lsof.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 + + HASFUSEFS is defined when the FreeBSD system has FUSE file system + support. + + HASGETBOOTFILE indicates the NetBSD or OpenBSD dialect has + a getbootfile() function. + + HASGNODE enables/disables readgnode() in node.c. + + HASHASHPID is defined when the Linux version (probably + above 2.1.35) has a pidhash_next member in + its task structure. + + 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 . + + 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 or + . + + HASINODE enables/disables readinode() in node.c. + + HASINOKNC indicates the Linux version has a kernel + name cache keyed on inode address. + + HASINADDRSTR is defined when the inp_[fl]addr members + of the inpcb structure are structures. + + 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., ). + + HASINT32TYPE is defined when the dialect has a typedef + for int32 that may conflict with some other + header file's redefinition (e.g., ). + + HASINTSIGNAL is defined when signal() returns an int. + + HAS_IPCLASSIFIER_H is defined for Solaris dialects that have the + 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. + + HASKERNELKEYT indicates the Linux version has a + __kernel_key_t typedef in . + + 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 + . + + HASKOPT enables/disables the ability to read the + kernel's name list from a file -- e.g., from + a crash dump file. + + HAS_PAUSE_SBT indicates the FreeBSD system's systm.h has the + pause to pause_sbt definition. + + 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 . + + HASLFILEADD defines additional, dialect-specific elements + SETLFILEADD in the lfile structure (defined in lsof.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 + and 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 header file. + + HAS_LWP_H is defined for BSD dialects that have the + 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 . + + 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. + + HASNETDEVICE_H indicates the Linux version has a netdevice.h + header file. + + HAS_NFS enables NFS support for the dialect. + + HASNFSKNC indicates the LINUX version has a separate + NFS name cache. + + 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_IDEV indicates the FreeBSD system's inode has no i_dev + member. + + HAS_NO_ISO_DEV indicates the FreeBSD 6 and higher system has + no i_dev member in its iso_node structure. + + 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. + + HAS_NO_SI_UDEV indicates the FreeBSD 6 and higher system has + no si_udev member in its cdev structure. + + 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 + header file has the pc_direntpersec() macro. + + HAS_PAD_MUTEX indicates the Solaris 11 system has the pad_mutex_t + typedef in its 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 *) + + HASPRINTOFF this value names a private function for + printing the dialect's file offset. Used + by print.c/print_file(). Takes two arguments: + + char *HASPRINTOFF(struct lfile *, int ty) + + Where ty == 0 if the offset is to be printed + in 0t format; 1, 0x. + + HASPRINTSZ this value names a private function for + printing the dialect's file size. Used + by print.c/print_file(). Takes one argument: + + char *HASPRINTSZ(struct lfile *) + + 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 + . + + 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 . + + 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 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 + . + + HASSOUXSOUA indicates that the Solaris 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. + + HASSPECNODE indicates the DEC OSF/1, or Digital UNIX, + or Tru64 UNIX has a spec_node + structure definition. + + HASSNODE indicates the dialect has snode support. + + HAS_SOCKET_SK indicates that the Linux socket structure + has the ``struct sock *sk'' member. + + 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 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 + header file. + + HAS_SYS_SX_H indicates the FreeBSD 7.0 and higher system has + a header file. + + HASTAGTOPATH indicates the DEC OSF/1, Digital UNIX, or + Tru64 UNIX dialect has a libmsfs.so, + containing tag_to_path(). + + HAS_TMPFS indicates the FreeBSD system has the + 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. + + HASUNMINSOCK indicates the Linux version has a user name + element in the socket structure; a value of + 0 says there is no unix_address member; 1, + there is. + + HASUINT16TYPE is defined when the dialect has a typedef + for u_int16 that may conflict with some other + header file's redefinition (e.g., ). + + HASUXSOCKEPT indicates the Linux version has support for the + UNIX socket endpoint option. + + HASUTMPX indicates the dialect has a header + file. + + HAS_UVM_INCL indicates the NetBSD or OpenBSD dialect has + a 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 + . + + HAS_VM_MEMATTR_T indicates the FreeBSD uses the + vm_memattr_t typedef. + + HASVMLOCKH indicates the FreeBSD dialect has . + + 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 exists. + + HASVXFS_MACHDEP_H indicates exists. + + HASVXFS_OFF64_T indicates exists and + has an off64_t typedef. + + HASXVFSRNL indicates the dialect has VxFS Reverse Name + Lookup (RNL) support. + + HASVXFS_SOL_H indicates exists. + + HASVXFS_SOLARIS_H indicates exists. + + HASVXFS_U64_T if HASVXFS_SOLARIS_H is defined, this + variable indicates that + 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 contains + a vx_inode structure. + + HASWCTYPE_H indicates the FreeBSD version has wide-character + support and the 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 . + + 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_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 . + + NEEDS_DEVICE_T indicates the FreeBSD header file + needs the device_t typedef. + + NEEDS_MACH_PORT_T is defined for Darwin versions that need the inclusion + of the header file . + + NEEDS_NETINET_TCPH is defined when the Linux version needs to #include + in place of 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= + clause in your Makefile. Leave off the ``\"'' even though + you want 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 +and the user structure from -- 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 `.) + + 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/`. + +* 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 | 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 +July 14, 2018 diff --git a/00QUICKSTART b/00QUICKSTART new file mode 100644 index 0000000..48bebd1 --- /dev/null +++ b/00QUICKSTART @@ -0,0 +1,1022 @@ + + A Quick Start for Lsof + +1. Introduction +================ + + Agreed, the lsof man page is dense and lsof has a plethora of + options. There are examples, but the manual page format buries + them at the end. How does one get started with lsof? + + This file is an attempt to answer that question. It plunges + immediately into examples of lsof use to solve problems that + involve looking at the open files of Unix processes. + + + Contents + + 1. Introduction + 2. Finding Uses of a Specific Open File + 3. Finding Open Files Filling a File System + a. Finding an Unlinked Open File + 4. Finding Processes Blocking Umount + 5. Finding Listening Sockets + 6. Finding a Particular Network Connection + 7. Identifying a Netstat Connection + 8. Finding Files Open to a Named Command + 9. Deciphering the Remote Login Trail + a. The Fundamentals + b. The idrlogin.perl[5] Scripts + 10. Watching an Ftp or Rcp Transfer + 11. Listing Open NFS Files + 12. Listing Files Open by a Specific Login + a. Ignoring a Specific Login + 13. Listing Files Open to a Specific Process Group + 14. When Lsof Seems to Hang + a. Kernel lstat(), readlink(), and stat() Blockages + b. Problems with /dev or /devices + c. Host and Service Name Lookup Hangs + d. UID to Login Name Conversion Delays + 15. Output for Other Programs + 16. The Lsof Exit Code and Shell Scripts + 17. Strange messages in the NAME column + + Options + + A. Selection Options + B. Output Options + C. Precautionary Options + D. Miscellaneous Lsof Options + + +2. 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., + + $ 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 -- this AIX example won't work: + + 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 00FAQ + file of the lsof distribution. + + $ lsof /etc/security/passwd + lsof: status error on /etc/security/passwd: Permission denied + + +3. 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, + + $ 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., + + $ 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. + + a. 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., + + $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: + + $ 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: + + $ 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. + + +4. 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: + + $ lsof + + 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. + + +5. 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: + + $ 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.) + + +6. 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: + + $ 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: + + $ 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: + + $ lsof -i4 + $ lsof -i6 + + +7. 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: + + $ 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: + + $ 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 adress for it, + like this Solaris 11 example: + + $ 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: + + $ lsof -U | grep ffffff0084253b68 + squid 1638 nobody 12u unix 18,98 0t10 9437188 /devices/pseudo/tl@0:ticots->0xffffff0084253b68 stream-ord + + +8. 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. + + $ lsof -p + + 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. + + $ lsof -c + + 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. + + $ lsof -c sendmail + + +9. 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. + + a. 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, + + $ lsof -i@lsof.itap + + yields (among other things): + + 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: + + $ 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, + + $ 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: + + $ 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, + + $ 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. + + $ 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: + + $ 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: + + $ 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: + + $ 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 + + b. 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: + + 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. + + 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 + + +10. 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, + + $ lsof -p + + 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): + + $ lsof -p -ad9,10 -r + or + $ lsof -p -ad10,11 -r + + Some options need explaining: + + -p specifies that lsof is to restrict its attention + to the process whose ID is . 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: + + $ lsof -p -ad3,4 -r + + +11. Listing Open NFS Files +========================== + + Lsof will list all files open on remote file systems, supported + by an NFS server. Just use: + + $ 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. + + +12. 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. + + $ lsof -u + or + $ lsof -u + + 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. + + $ 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. + + a. 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: + + $ lsof -u ^root + or + $ lsof -u ^0 + + +13. 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: + + $ 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: + + $ lsof -g12717 -adcwd + + would produce on a Solaris 8 system: + + $ 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. + + +14. 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. + + a. 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. + + $ 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.) + + $ 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. + + b. 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 + + $ 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. + + c. 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. + + $ lsof -n + or + $ lsof -P + or + $ lsof -nP + + d. 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. + + $ lsof -l + + +15. 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. + + +16. The Lsof Exit Code and Shell Scripts +======================================== + + When lsof exits 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 lsof detects an error and makes an unsuccessful exit, it + returns an exit code of 1 (one). + + 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., + + #!/bin/sh + lsof > /dev/null 2>&1 + if test $? -eq 0 + then + echo " has some users." + else + echo " may have no users." + fi + + +17. 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., + + $ 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., + + $ 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] + + +Options +======= + + The following appendices describe the lsof options in detail. + + +A. 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 and -u + 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 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, , 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. + + +B. 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. + + +C. 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. + + +D. Miscellaneous Lsof Options +============================== + + There are some lsof options that are hard to classify, including: + + -? these options select help output. + -h + + -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 + + -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. + + +Vic Abell +October 13, 2014 diff --git a/00README b/00README new file mode 100644 index 0000000..075c764 --- /dev/null +++ b/00README @@ -0,0 +1,1525 @@ + + 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 + DEC OSF/1, Digital UNIX, Tru64 UNIX + FreeBSD + HP-UX + IPv6 + Linux + NetBSD + NEXTSTEP and OPENSTEP + 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 + $ ./Configure + $ 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 + decosf DEC OSF/1, Digital UNIX, Tru64 UNIX 4.0 and 5.1 + digital_unix Digital UNIX, DEC OSF/1, Tru64 UNIX 4.0 and 5.1 + du Digital UNIX, DEC OSF/1, Tru64 UNIX 4.0 and 5.1 + 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 + next NEXTSTEP 3.[13] + nextstep NEXTSTEP 3.[13] + ns NEXTSTEP 3.[13] + nxt NEXTSTEP 3.[13] + openbsd OpenBSD 2.[89] and 3.[0-9] + openstep OPENSTEP 4.x + os OPENSTEP 4.x + 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 + tru64 Tru64 UNIX, DEC OSF/1, Digital UNIX 4.0 and 5.1 + 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() 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 + ... + 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 +. 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) + NEXTSTEP 3.2 (AFS 3.3) (untested on recent lsof revisions) + 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. + + +DEC OSF/1, Digital UNIX, Tru64 UNIX +=================================== + +Robert Benites, Dean Brock, Angel Li, Dwight McKay, Berkley Shands, +Ron Young and Steve Wilson have kindly provided test systems. +Jeffrey Mogul has provided technical assistance. Dave Morrison +and Lawrence MacIntyre did Digital UNIX V3.2 testing. + +Lsof supports the ADVFS/MSFS layered file system product. Lsof +can locate all the open files of an ADVFS/MSFS file system when +its path is specified, provided the file system is listed in +/etc/fstab with an ``advfs'' type. (This /etc/fstab caveat applies +only to Digital UNIX 2.0.) At Digital UNIX 4.0 and Tru64 UNIX, +using code provided by David Brock, lsof 4.20 and above can locate +ADVFS file paths. + +Testing of lsof on DEC OSF/1 and Digital UNIX 4.0 ended with lsof +revision 4.74. Hence, the lsof documentation has dropped the claim +that it works there. For a distribution of lsof 4.74 that was tested +on DEC OSF/1 and Digital UNIX 4.0, check pub/tools/unix/lsof/OLD/src +on the lsof ftp home, lsof.itap.purdue.edu. + +Lsof revisions past 4.74 have only been tested on Tru64 UNIX 5.1. + + +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 it shares with OpenBSD in the n+obsd dialect sub-directory. + + +NEXTSTEP and OPENSTEP +===================== + +Virtual memory header files that allow lsof to display text references +were derived from the contents of /usr/include/vm of NEXTSTEP 2.0. +NeXT did not ship the virtual memory header files with other NEXTSTEP +or OPENSTEP versions. + +You may use the RC_FLAGS environment variable to declare compiler +options outside the Makefile. A common use of this variable is to +define the architecture types to be included in a "fat" executable. +See the comments in dialects/next/Makefile for an example. + + +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 n+obsd 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 and . + +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 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 and the 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 . 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 + DEC OSF/1, Digital UNIX, Tru64 UNIX 2.0, 3.2, 4.0, and 5.[01] + 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 + NEXTSTEP 3.[13] + OpenBSD 2.[89] and 3.[0-9] + OPENSTEP 4.x + 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 +February 14, 2018 diff --git a/00TEST b/00TEST new file mode 100644 index 0000000..c465da8 --- /dev/null +++ b/00TEST @@ -0,0 +1,1038 @@ + + 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 + $ 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_/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_ always ends in (the 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= 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 + ` 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, 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 ] + +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, +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 ] + +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, 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 ] + +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, 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 ] + +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 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 ] + +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 (client) and +config.LT1U (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 + DEC OSF/1 4.0, cc + 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 + NEXTSTEP 3.1, gcc LTnfs + 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 + OPENSTEP 4.2, gcc LTnfs + 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 + Tru64 UNIX 5.0, cc + Tru64 UNIX 5.0, cc + 5.1, 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 , +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 , +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 +February 14, 2018 diff --git a/00XCONFIG b/00XCONFIG new file mode 100644 index 0000000..6db0db0 --- /dev/null +++ b/00XCONFIG @@ -0,0 +1,731 @@ + + 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 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 + du DU 2.0 20000 + 3.0 30000 + 3.2 30200 + 4.0 40000 + 5.0 50000 + 5.1 50100 + 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 + ns NEXTSTEP 3.1 31 + 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 + os OPENSTEP 4.x 4x + 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 + +* -- The optional Configure abbreviations -- e.g., the ``decosf'' + and ``digital_unix'' alternatives to ``du'' -- aren't listed + here. + + +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 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 + +DU_ADVFSV specifies the DEC OSF/1, Digital UNIX, or Tru64 UNIX + ADVFS file system version -- e.g., 200 for 2.0, 400 + for 4.0, etc. + + default: determined via /usr/sbin/setld + +DU_CDIR specifies the name of the DEC OSF/1, Digital UNIX, or + Tru64 UNIX system configuration directory. + + default: first host name component, converted to upper + case + +DU_SHLIB specifies the DEC OSF/1, Digital UNIX, or Tru64 UNIX + shared library directory path. + + default: /usr/shlib + +DU_SYSDIR DEC OSF/1, Digital UNIX, or Tru64 UNIX system + directory path. + + 2.x and 3.x default: /sys + 4.x default: /usr/sys + +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 + 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//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 +October 13, 2014 diff --git a/AFSConfig b/AFSConfig new file mode 100755 index 0000000..0c68cbd --- /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 | 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 (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 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//include\"." + cat << .CAT_MARK +The 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 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/ChangeLog b/ChangeLog new file mode 100644 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 index 0000000..b253274 --- /dev/null +++ b/Configure @@ -0,0 +1,5803 @@ +#!/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, , this script +# requires that the subdirectory ./dialects/ 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 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 + : -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 + (****USE -d TO GET TESTED DIALECT VERSION NUMBERS****): + aix|aixgcc : IBM AIX xlc (aix) or gcc (aixgcc) + darwin : Apple Darwin + decosf : DEC OSF/1 + digital_unix|du : Digital UNIX + freebsd : FreeBSD + hpux|hpuxgcc : HP-UX cc (hpux) or gcc (hpuxgcc) + linux : Linux + netbsd : NetBSD + nextstep|next|ns|nxt : NEXTSTEP + openbsd : OpenBSD + openstep|os : OPENSTEP + 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) + tru64 : Tru64 UNIX + 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 dialects/aix/aix5/j2/j2_snapshot.h + echo "rm -f 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/du/du5_sys_malloc.h + echo "rm -f dialects/du/du5_sys_malloc.h" + rm -f dialects/hpux/kmem/hpux_mount.h + echo "rm -f dialects/hpux/kmem/hpux_mount.h" + rm -rf dialects/n+obsd/include + echo "rm -rf dialects/n+obsd/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 \` 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 dialects/aix/aix5/j2/j2_snapshot.h + (cd 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`/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 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 + # . + + 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 " > ${LSOF_TMPC}.c + echo '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 " > ${LSOF_TMPC}.c + echo "#include " >> ${LSOF_TMPC}.c + echo "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 "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.*) # Next Mac OS X + LSOF_VERS=1300 + ;; + *) + echo Unknown Darwin release: `uname -r` + echo Assuming Darwin 12.0 + LSOF_VERS=1200 + ;; + 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) + LSOF_CFGF="$LSOF_CFGF -DHASIPv6" + LSOF_TMP1="" + ;; + *) + 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" + + if test "X$DARWIN_XNUDIR" != "X" # { + then + LSOF_TMP2="${DARWIN_XNUDIR}/bsd" + LSOF_TMP3="${DARWIN_XNUDIR}/osfmk" + LSOF_TMP4="" + else + LSOF_TMP2="${DARWIN_XNU_HEADERS}/System/Library/Frameworks/Kernel.framework/Versions/A/PrivateHeaders" + LSOF_TMP3="${DARWIN_XNU_HEADERS}/System/Library/Frameworks/System.framework/Versions/B/PrivateHeaders" + LSOF_TMP4="" + if test "X$DARWIN_XNU_HEADERS" != "X" # { + then + LSOF_TMP4="${DARWIN_XNU_HEADERS}/usr/include" + fi # } + fi # } + + # 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="-I${LSOF_INCLUDE}/../local/include" + else + echo "FATAL: can't find libproc.h" + rm -f $LSOF_HLP + exit 1 + fi # } + fi # } + else + + # The default Darwin base is /dev/kmem. + + DARWIN_BASE="/dev/kmem" + 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/libproc + if test $LSOF_VERS -lt 1000 # { + then + LSOF_CFGL="$LSOF_CFGL -lproc" + fi # } + LSOF_TSTKMEM=0 + LSOF_DINC="$LSOF_DINC $LSOF_TMP5" + 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 # } + else + if test "X$DARWIN_BASE" != "X/dev/kmem" # { + then + echo "Darwin base unrecognized: $DARWIN_BASE" + rm -f $LSOF_HLP + exit 1 + fi # } + + # Configure for /dev/kmem-based Darwin lsof. + + echo "Configuring /dev/kmem-based Darwin lsof" + LSOF_CINFO="/dev/kmem-based" + LSOF_DIALECT_DIR=darwin/kmem + + # Make sure needed /dev/kmem-base XNU Darwin kernel header files are + # present. + + LSOF_TMP5="" + for i in $LSOF_TMP1 # { + do + LSOF_TMP6=0 + for j in $LSOF_TMP2 $LSOF_TMP3 $LSOF_TMP4 $LSOF_INCLUDE # { + do + if test "X${j}" != "X" -a -r ${j}/${i} # { + then + LSOF_TMP6=1 + break + fi # } + done # } + if test $LSOF_TMP6 -ne 1 # { + then + if test "X$LSOF_TMP5" = "X" # { + then + LSOF_TMP5=$i + else + LSOF_TMP5="$LSOF_TMP5 $i" + fi # } + fi # } + done # } + if test "X$LSOF_TMP5" != "X" # { + then + + # If any Darwin XNU kernel header files are missing, call the + # get-hdr-loc.sh script to find the path. + + LSOF_TMP6=`pwd`/dialects/darwin/get-hdr-loc.sh + if test ! -x $LSOF_TMP6 # { + then + echo "FATAL: can't execute: $LSOF_TMP6" + rm -f $LSOF_HLP + exit 1 + fi # } + DARWIN_XNUDIR=`$LSOF_TMP6 $LSOF_TMP5` + if test $? -ne 0 # { + then + echo "FATAL: $LSOF_TMP6 returns: $DARWIN_XNUDIR" + rm -f $LSOF_HLP + exit 1 + fi # } + LSOF_TMP2="${DARWIN_XNUDIR}/bsd" + LSOF_TMP3="${DARWIN_XNUDIR}/osfmk" + LSOF_TMP4="" + fi # } + + # Add header file paths for /dev/kmem-based Darwin lsof. + + for i in $LSOF_TMP2 $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 # } + + # Make conditional feature definitions for /dev/kmem-based Darwin lsof. + + for i in $LSOF_TMP2 $LSOF_TMP3 $LSOF_TMP4 $LSOF_INCLUDE # { + do + if test "X${i}" != "X" -a -r ${i}/sys/namei.h # { + then + grep -q nc_vpid ${i}/sys/namei.h + if test $? -eq 0 # { + then + LSOF_CFGF="$LSOF_CFGF -DHASNCVPID" + fi # } + break + fi # } + done # } + for i in $LSOF_TMP2 $LSOF_TMP3 $LSOF_TMP4 $LSOF_INCLUDE # { + do + if test "X${i}" != "X" # { + then + if test $LSOF_VERS -ge 800 # { + then + if test -r ${i}/sys/file_internal.h # { + then + grep -q DTYPE_KQUEUE ${i}/sys/file_internal.h + if test $? -eq 0 # { + then + LSOF_CFGF="$LSOF_CFGF -DHASKQUEUE" + fi # } + break + fi # } + else + if test $LSOF_VERS -ge 700 # { + then + if test -r ${i}/sys/file.h # { + then + grep -q DTYPE_KQUEUE ${i}/sys/file.h + if test $? -eq 0 # { + then + LSOF_CFGF="$LSOF_CFGF -DHASKQUEUE" + fi # } + fi # } + break + fi # } + fi # } + fi # } + done # } + LSOF_CFGF="$LSOF_CFGF -DHAS9660FS" + fi # } + LSOF_CFGF="$LSOF_CFGF -DDARWINV=$LSOF_VERS" + LSOF_CFLAGS_OVERRIDE=1 + ;; + +# Configure for DEC OSF/1, Digital UNIX, or Tru64 UNIX. + + digital_unix|du|decosf|tru64) + LSOF_TGT="du" + LSOF_TSTBIGF=" " + LSOF_TSTK64=1 + if test "X$LSOF_DINC" = "X" # { + then + LSOF_DINC="-I/usr/include" + fi # } + if test "X$LSOF_VSTR" = "X" # { + then + LSOF_VSTR=`uname -r` + fi # } + if test "X$LSOF_VERS" = "X" # { + then + + # If the DEC OSF/1, Digital UNIX, or Tru64 UNIX version isn't + # predefined, determine it. + + case $LSOF_VSTR in # { + V2.0) + LSOF_VERS=20000 + ;; + V3.0) + LSOF_VERS=30000 + ;; + V3.2) + LSOF_VERS=30200 + ;; + ?4.0) + LSOF_TSTXO="../lib/snpf.o" + LSOF_VERS=40000 + ;; + ?5.0) + LSOF_VERS=50000 + ;; + ?5.1) + LSOF_VERS=50100 + ;; + *) + echo "WARNING: unknown version; assuming version is 2.0" + LSOF_VERS=20000 + ;; + esac # } + fi # } + + # Do DEC OSF/1, Digital UNIX, or Tru64 UNIX version specific stuff. + + case $LSOF_VERS in # { + 20000) + LSOF_CFGF="$LSOF_CFGF -Olimit 1024" + LSOF_TMP1="/sys" + ;; + 30000) + LSOF_CFGF="$LSOF_CFGF -Olimit 1024" + LSOF_TMP1="/sys" + LSOF_TMP2=-DUSELOCALREADDIR + ;; + 30200) + LSOF_CFGF="$LSOF_CFGF -Olimit 1024" + LSOF_TMP1="/sys" + LSOF_TMP2=-DUSELOCALREADDIR + ;; + 40000) + LSOF_TMP1="/usr/sys" + ;; + 50000|50100) + LSOF_CFGF="$LSOF_CFGF -DUSE_STAT" + LSOF_TMP1="/usr/sys" + ;; + *) + echo "WARNING: unknown version: $LSOF_VERS" + rm -f $LSOF_HLP + exit 1 + ;; + esac # } + if test "X$DU_SYSDIR" = "X" # { + then + DU_SYSDIR=$LSOF_TMP1 + fi # } + LSOF_HOST=`uname -n` + if test "X$DU_CDIR" = "X" # { + then + LSOF_CDIR=`expr $LSOF_HOST : '\([^\.]*\)\..*$'` + if test "X$LSOF_CDIR" = "X" # { + then + LSOF_CDIR=$LSOF_HOST + fi # } + LSOF_CDIR=`echo $LSOF_CDIR | tr a-z A-Z` + else + LSOF_CDIR=$DU_CDIR + fi # } + LSOF_LOOP=1 + while test $LSOF_LOOP = 1 # { + do + if test -d ${DU_SYSDIR}/$LSOF_CDIR # { + then + echo "Using header files in ${DU_SYSDIR}/$LSOF_CDIR" + LSOF_LOOP=0 + else + cat << .CAT_MARK + +Please enter the name of the subdirectory in $DU_SYSDIR that contains the +configuration files for this host. Usually its name would be $LSOF_CDIR, but +that subdirectory doesn't seem to exist. The lsof compilation needs header +files specific to this machine's configuration found in that directory. + +If you can't specify the appropriate configuration subdirectory, quit this +Configure step now and generate a proper configuration subdirectory with the +kernel generation process. + +.CAT_MARK + + echo "$DU_SYSDIR contains:" + echo "" + ls -CF $DU_SYSDIR + echo "" + echo -n "Configuration subdirectory name? " + read LSOF_CDIR LSOF_EXCESS + if test "X$LSOF_CDIR" = "X" -o ! -d ${DU_SYSDIR}/$LSOF_CDIR # { + then + echo "" + echo Cannot access directory ${DU_SYSDIR}/$LSOF_CDIR. + fi # } + fi # } + done # } + + # Determine the ADVFS file system version. + + if test "X$DU_ADVFSV" = "X" # { + then + echo "Determining the ADVFS version -- this will take a while." + LSOF_ADVFSV=`/usr/sbin/setld -i | grep "^OSFADVFSBIN[0-9]" | sed 's/\([^ ]*\).*/\1/' | sort -u | tail -1 | sed 's/OSFADVFSBIN//'` + else + LSOF_ADVFSV=$DU_ADVFSV + fi # } + case $LSOF_ADVFSV in # { + 1*) + LSOF_ADVFSV=100 + echo "The ADVFS version is 1." + ;; + 2*) + LSOF_ADVFSV=200 + echo "The ADVFS version is 2." + ;; + 3*) + LSOF_ADVFSV=300 + echo "The ADVFS version is 3." + ;; + 4*) + LSOF_ADVFSV=400 + echo "The ADVFS version is 4." + ;; + 5*) + LSOF_ADVFSV=500 + echo "The ADVFS version is 5." + ;; + *) + echo "The ADVFS version is unknown; it will be assumed to be 1." + LSOF_ADVFSV=100 + ;; + esac # } + LSOF_CFGF="$LSOF_CFGF -DDUV=$LSOF_VERS -DADVFSV=$LSOF_ADVFSV $LSOF_TMP2" + if test "X$DU_SYSINC" = "X" # { + then + DU_SYSINC="/usr/sys/include" + fi # } + LSOF_DINC="$LSOF_DINC -I${DU_SYSDIR}/$LSOF_CDIR -I$DU_SYSINC" + LSOF_CFGL="$LSOF_CFGL -lmld" + if test "X${DU_SHLIB}" = "X" # { + then + DU_SHLIB=/usr/shlib + fi # } + if test -r ${DU_SHLIB}/libmsfs.so # { + then + nm ${DU_SHLIB}/libmsfs.so | grep tag_to_path > /dev/null 2>&1 + if test $? -eq 0 # { + then + LSOF_CFGF="$LSOF_CFGF -DHASTAGTOPATH" + LSOF_CFGL="$LSOF_CFGL -lmsfs" + fi # } + fi # } + grep "^struct spec_node {" ${DU_SYSDIR}/include/sys/specdev.h > /dev/null 2>&1 + if test $? -eq 0 # { + then + LSOF_CFGF="$LSOF_CFGF -DHASSPECNODE" + fi # } + if test $LSOF_VERS -ge 50000 # { + then + + # Make du5_sys_malloc.h for DU 5.0 and above. Enable strict ANSI checking + # on 5.0 and 5.1A, but not 5.1B. Enable IPv6 handling. + + LSOF_TMP1="-std1" + if test $LSOF_VERS -ge 50100 # { + then + LSOF_TMP1="-std" + if test -x /usr/sbin/sizer # { + then + /usr/sbin/sizer -v | grep -q 5.1A + if test $? -eq 0 # { + then + LSOF_TMP1="-std1" + fi # } + fi # } + fi # } + LSOF_CFGF="$LSOF_CFGF $LSOF_TMP1" + LSOF_TMP1=${LSOF_INCLUDE}/sys/malloc.h + if test -r $LSOF_TMP1 # { + then + LSOF_TMP2=dialects/du/du5_sys_malloc.h + rm -f $LSOF_TMP2 + echo "#if !defined(MANUFACTURED_DU5_SYS_MALLOC_H)" > $LSOF_TMP2 + echo "/* By lsof Configure:" `date` " */" >> $LSOF_TMP2 + echo "#define MANUFACTURED_DU5_SYS_MALLOC_H" >> $LSOF_TMP2 + grep "^#define[ ]MALLOC_NUM_BUCKETS" $LSOF_TMP1 >> $LSOF_TMP2 + echo "struct percpukmembuckets {" >> $LSOF_TMP2 + sed '1,/^struct percpukmembuckets/d' $LSOF_TMP1 | sed -n '1,/^};/p' >> $LSOF_TMP2 + echo "#endif" >> $LSOF_TMP2 + LSOF_CFGF="$LSOF_CFGF -I`pwd`/dialects/du" + fi # } + + # Enable IPv6 for Tru64 UNIX 5.0 and above. + + LSOF_CFGF="$LSOF_CFGF -DHASIPv6" + 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 # } + LSOF_DIALECT_DIR=du + ;; + +# Configure for FreeBSD. + + freebsd) + LSOF_FBSD_ZFS=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 # { + 1.*) + LSOF_VERS=1000 + ;; + 2.0-*) + LSOF_VERS=2000 + ;; + 2.0.5-*) + LSOF_VERS=2005 + ;; + 2.1*) + LSOF_VERS=2010 + ;; + 2.2*) + LSOF_VERS=2020 + ;; + 3.0*) + LSOF_VERS=3000 + ;; + 3.1*) + LSOF_VERS=3010 + ;; + 3.2*) + LSOF_VERS=3020 + ;; + 3.3*) + LSOF_VERS=3030 + ;; + 3.4*) + LSOF_VERS=3040 + ;; + 3.5*) + LSOF_VERS=3050 + ;; + 3*) + LSOF_VERS=3050 + echo "!!!WARNING!!! Unsupported FreeBSD version: $LSOF_VSTR" + echo "!!!WARNING!!! Configuring for FreeBSD 3.5" + ;; + 4.0*) + LSOF_TSTBIGF=" " + LSOF_VERS=4000 + ;; + 4.1-*) + LSOF_TSTBIGF=" " + LSOF_VERS=4010 + ;; + 4.2*) + LSOF_TSTBIGF=" " + LSOF_VERS=4020 + ;; + 4.3*) + LSOF_TSTBIGF=" " + LSOF_VERS=4030 + ;; + 4.4*) + LSOF_TSTBIGF=" " + LSOF_VERS=4040 + ;; + 4.5*) + LSOF_TSTBIGF=" " + LSOF_VERS=4050 + ;; + 4.6*) + LSOF_TSTBIGF=" " + LSOF_VERS=4060 + ;; + 4.7*) + LSOF_TSTBIGF=" " + LSOF_VERS=4070 + ;; + 4.8*) + LSOF_TSTBIGF=" " + LSOF_VERS=4080 + ;; + 4.9*) + LSOF_TSTBIGF=" " + LSOF_VERS=4090 + ;; + 4.10*) + LSOF_TSTBIGF=" " + LSOF_VERS=4100 + ;; + 4.11*) + LSOF_TSTBIGF=" " + LSOF_VERS=4110 + ;; + 4*) + LSOF_VERS=4100 + echo "!!!WARNING!!! Unsupported FreeBSD version: $LSOF_VSTR" + echo "!!!WARNING!!! Configuring for FreeBSD 4.10" + ;; + 5.0*) + LSOF_TSTBIGF=" " + LSOF_VERS=5000 + ;; + 5.1*) + LSOF_TSTBIGF=" " + LSOF_VERS=5010 + ;; + 5.2*) + LSOF_TSTBIGF=" " + LSOF_VERS=5020 + ;; + 5.3*) + LSOF_TSTBIGF=" " + LSOF_VERS=5030 + ;; + 5.4*) + LSOF_TSTBIGF=" " + LSOF_VERS=5040 + ;; + 5.5*) + LSOF_TSTBIGF=" " + LSOF_VERS=5050 + ;; + 5*) + LSOF_VERS=5050 + echo "!!!WARNING!!! Unsupported FreeBSD version: $LSOF_VSTR" + echo "!!!WARNING!!! Configuring for FreeBSD 5.5" + ;; + 6.0*) + LSOF_TSTBIGF=" " + LSOF_VERS=6000 + ;; + 6.1*) + LSOF_TSTBIGF=" " + LSOF_VERS=6010 + ;; + 6.2*) + LSOF_TSTBIGF=" " + LSOF_VERS=6020 + ;; + 6.3*) + LSOF_TSTBIGF=" " + LSOF_VERS=6030 + ;; + 6.4*) + LSOF_TSTBIGF=" " + LSOF_VERS=6040 + ;; + 6*) + LSOF_VERS=6000 + echo "!!!WARNING!!! Unsupported FreeBSD version: $LSOF_VSTR" + echo "!!!WARNING!!! Configuring for FreeBSD 6.0" + ;; + 7.0*) + LSOF_TSTBIGF=" " + LSOF_VERS=7000 + ;; + 7.1*) + LSOF_TSTBIGF=" " + LSOF_VERS=7010 + ;; + 7.2*) + LSOF_TSTBIGF=" " + LSOF_VERS=7020 + ;; + 7.3*) + LSOF_TSTBIGF=" " + LSOF_VERS=7030 + ;; + 7.4*) + LSOF_TSTBIGF=" " + LSOF_VERS=7040 + ;; + 7*) + LSOF_VERS=7000 + echo "!!!WARNING!!! Unsupported FreeBSD version: $LSOF_VSTR" + echo "!!!WARNING!!! Configuring for FreeBSD 7.0" + ;; + 8.0*) + LSOF_TSTBIGF=" " + LSOF_VERS=8000 + ;; + 8.1*) + LSOF_TSTBIGF=" " + LSOF_VERS=8010 + ;; + 8.2*) + LSOF_TSTBIGF=" " + LSOF_VERS=8020 + ;; + 8.3*) + LSOF_TSTBIGF=" " + LSOF_VERS=8030 + ;; + 8.4*) + LSOF_TSTBIGF=" " + LSOF_VERS=8040 + ;; + 9*) + LSOF_TSTBIGF=" " + LSOF_VERS=9000 + ;; + 10*) + LSOF_TSTBIGF=" " + LSOF_VERS=10000 + ;; + 11*) + LSOF_TSTBIGF=" " + LSOF_VERS=11000 + ;; + 12*) + LSOF_TSTBIGF=" " + LSOF_VERS=12000 + ;; + 13*) + LSOF_TSTBIGF=" " + LSOF_VERS=13000 + ;; + *) + 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 # { + 4090|8020|8030|8040|9000|10000|11000|12000) + LSOF_UNSUP="" + ;; + esac # } + + # Get system CFLAGS, if possible. + + LSOF_TMP1=`echo "all:\n.include " | $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" + 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 # } + + # Test pause() status in system.h. + + if test -r ${FREEBSD_SYS}/sys/systm.h # { + then + grep -q pause_sbt ${FREEBSD_SYS}/sys/systm.h + if test $? -eq 0 # { + then + LSOF_CFGF="$LSOF_CFGF -DHAS_PAUSE_SBT" + fi # } + fi # } + + # Check the C library for closefrom and dup2. + + if test -r /usr/lib/libc.a # { + then + nm /usr/lib/libc.a | grep -q "W dup2" + if test $? -eq 0 # { + then + LSOF_CFGF="$LSOF_CFGF -DHAS_DUP2" + fi # } + nm /usr/lib/libc.a | grep -q "W closefrom" + if test $? -eq 0 # { + then + LSOF_CFGF="$LSOF_CFGF -DHAS_CLOSEFROM" + fi # } + fi # } + + # Do FreeBSD version-specific stuff. + + case $LSOF_VERS in # { + 1000) + LSOF_CFGF="$LSOF_CFGF -DHASPROCFS" + 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 +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 # } + grep -q i_dev ${LSOF_INCLUDE}/ufs/ufs/inode.h + if test $? -ne 0 # { + then + LSOF_CFGF="$LSOF_CFGF -DHAS_NO_IDEV" + 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_udev;" ${LSOF_INCLUDE}/sys/conf.h + if test $? -ne 0 # { + then + LSOF_CFGF="$LSOF_CFGF -DHAS_NO_SI_UDEV" + 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 FUSE file system test, + + if test -r ${FREEBSD_SYS}/fs/fuse/fuse_node.h # { + then + LSOF_CFGF="$LSOF_CFGF -DHASFUSEFS" + 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 # } + if test -r ${LSOF_INCLUDE}/sys/filedesc.h # { + then + grep -q '^struct fdescenttbl {' ${LSOF_INCLUDE}/sys/filedesc.h + if test $? -eq 0 # { + then + LSOF_CFGF="$LSOF_CFGF -DHAS_FDESCENTTBL" + 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 # } + if test $LSOF_VERS -lt 5000 # { + then + if test -d ${FREEBSD_SYS}/${LSOF_TMP1}/procfs # { + then + LSOF_CFGF="$LSOF_CFGF -DHASPROCFS" + LSOF_DINC_ADD=1 + fi # } + else + if test -d ${FREEBSD_SYS}/${LSOF_TMP1}/pseudofs # { + then + LSOF_CFGF="$LSOF_CFGF -DHASPSEUDOFS" + LSOF_DINC_ADD=1 + fi # } + 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 + rm -f cd9660_node.h + grep -q "^#ifdef [_]*KERNEL" ${FREEBSD_SYS}/isofs/cd9660/cd9660_node.h + if test $? -eq 0 # { + then + ln -s ${FREEBSD_SYS}/isofs/cd9660/cd9660_node.h cd9660_node.h + else + sed -e '/^ \* Prototypes for ISOFS vnode operations/,$c\ + \ The ISOFS prototypes were removed by Configure. */' \ + < ${FREEBSD_SYS}/isofs/cd9660/cd9660_node.h > cd9660_node.h + echo "" >> cd9660_node.h + fi # } + LSOF_CFGF="$LSOF_CFGF -DHAS9660FS" + if test $LSOF_VERS -ge 6000 # { + then + grep -q "i_dev;" cd9660_node.h + if test $? -ne 0 # { + then + LSOF_CFGF="$LSOF_CFGF -DHAS_NO_ISO_DEV" + fi # } + fi # } + 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 # } + 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 "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 "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=; 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 +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 . + + 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 # } + 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" + ;; + *) + echo "Unknown NetBSD release: $LSOF_VSTR" + echo Assuming NetBSD 1.6 + LSOF_VERS="1006000" + ;; + esac # } + fi # } + + # Test for legal NetBSD version. + + case $LSOF_VERS in # { + 1002000|1003000|1004000|1005000|1006000) + ;; + 2000000|2099009|2099010) + ;; + 3000000|3099000) + ;; + *) + echo "Unknown NetBSD version: $LSOF_VERS" + rm -f $LSOF_HLP + exit 1 + ;; + esac # } + LSOF_CFGF="$LSOF_CFGF -DNETBSDV=$LSOF_VERS" + LSOF_TMP1="-DN_UNIXV=/netbsd" + if 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 + 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 # } + if test "X$NETBSD_UVM" = "X" # { + then + grep -q UVM $LSOF_TMP3 + if test $? -ne 0 # { + then + egrep -q "v_uvm;|v_uobj;" $LSOF_TMP3 + if test $? -eq 0 # { + then + NETBSD_UVM="Y" + fi # } + 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 dialects/n+obsd/include + if test "X$NETBSD_UVM" = "XY" -o "X$NETBSD_UVM" = "Xy" # { + then + mkdir dialects/n+obsd/include + touch dialects/n+obsd/include/opt_uvmhist.h + touch dialects/n+obsd/include/opt_lockdebug.h + LSOF_CFGF="$LSOF_CFGF -DUVM -I`pwd`/dialects/n+obsd/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 + # . 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=dialects/n+obsd/include/netexport.h + if test ! -d dialects/n+obsd/include # { + then + mkdir dialects/n+obsd/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 " >> $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 /dialects/n+obsd/include > /dev/null 2>&1 + if test $? -ne 0 # { + then + LSOF_CFGF="$LSOF_CFGF -I`pwd`/dialects/n+obsd/include" + fi # } + fi # } + if test $LSOF_NBSD_BUFQH -eq 1 # { + then + + # Make a local copy of $NETBSD_SYS/sys/bufq.h. + + if test ! -d dialects/n+obsd/include # { + then + mkdir dialects/n+obsd/include + fi # } + if test ! -d dialects/n+obsd/include/sys # { + then + mkdir dialects/n+obsd/include/sys + fi # } + cp $NETBSD_SYS/sys/bufq.h dialects/n+obsd/include/sys + echo $LSOF_CFGF | grep /dialects/n+obsd/include > /dev/null 2>&1 + if test $? -ne 0 # { + then + LSOF_CFGF="$LSOF_CFGF -I`pwd`/dialects/n+obsd/include" + fi # } + fi # } + if test $LSOF_NBSD_PTYFS -eq 1 # { + then + + # Make a local copy of $NETBSD_SYS/sys/fs/ptyfs/. + + if test ! -d dialects/n+obsd/include # { + then + mkdir dialects/n+obsd/include + fi # } + if test ! -d dialects/n+obsd/include/fs # { + then + mkdir dialects/n+obsd/include/fs + fi # } + rm -rf dialects/n+obsd/include/fs/ptyfs + mkdir dialects/n+obsd/include/fs/ptyfs + cp $NETBSD_SYS/fs/ptyfs/*.h dialects/n+obsd/include/fs/ptyfs + echo $LSOF_CFGF | grep /dialects/n+obsd/include > /dev/null 2>&1 + if test $? -ne 0 # { + then + LSOF_CFGF="$LSOF_CFGF -I`pwd`/dialects/n+obsd/include" + fi # } + fi # } + LSOF_CFGL="$LSOF_CFGL -lkvm" + LSOF_DIALECT_DIR=n+obsd + ;; + +# Configure for NeXTSTEP or OPENSTEP. + + nextstep|next|ns|nxt|openstep|os) + LSOF_TGT="ns" + LSOF_TSTXO="../lib/snpf.o" + if test "X$LSOF_AR" = "X" # { + then + LSOF_AR="rm -f \${LIB}; ar cr" + fi # } + if test "X$LSOF_VSTR" = "X" # { + then + LSOF_VSTR=`hostinfo | sed -n 's/.*NeXT Mach \([0-9\.]*\).*/\1/p'` + fi # } + if test "X$LSOF_VERS" = "X" # { + then + + # If the NeXSTEP version isn't predefined, determine it. + + LSOF_VERS=`echo $LSOF_VSTR | sed -n 's/\([0-9]*\)\.\([0-9]*\)/\1\2/p'` + fi # } + if test "X$LSOF_CC" = "X" # { + then + if test -x /usr/local/bin/gcc # { + then + LSOF_CC=/usr/local/bin/gcc + LSOF_CCV=`$LSOF_CC -v 2>&1 | sed -n 's/.*version \(.*\)/\1/p'` + else + LSOF_CC=cc + LSOF_CCV=`$LSOF_CC -v 2>&1 | sed -n 's/.*version \(.*\)/\1/p'` + fi # } + fi # } + echo $LSOF_CC | grep gcc > /dev/null + if test $? -eq 0 # { + then + LSOF_CFGL="$LSOF_CFGL -w" + LSOF_DEBUG="-pedantic -O" + fi # } + LSOF_CFGF="$LSOF_CFGF -DSTEPV=$LSOF_VERS" + LSOF_DIALECT_DIR=n+os + + # 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 # } + ;; + +# Configure for OpenBSD. (OpenBSD uses NetBSD dialect sources and version +# numbering. + + openbsd) + 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" + ;; + *) + 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) + ;; + *) + echo "Unknown OpenBSD version: $LSOF_VERS" + rm -f $LSOF_HLP + exit 1 + ;; + esac # } + LSOF_CFGF="$LSOF_CFGF -DOPENBSDV=$LSOF_VERS" + if test -r /dev/ksyms # { + then + LSOF_CFGF="$LSOF_CFGF -DN_UNIXV=/dev/ksyms" + else + LSOF_CFGF="$LSOF_CFGF -DN_UNIXV=/bsd" + fi + if test -r ${LSOF_INCLUDE}/nfs/nfsproto.h # { + then + LSOF_CFGF="$LSOF_CFGF -DHASNFSPROTO" + fi # } + if test -r ${LSOF_INCLUDE}/netinet6/in6.h # { + then + LSOF_CFGF="$LSOF_CFGF -DHASIPv6" + fi # } + LSOF_TMP1=0 + if test "X$OPENBSD_SYS" = "X" # { + then + OPENBSD_SYS="/sys" + fi # } + if test -r ${OPENBSD_SYS}/miscfs/fdesc/fdesc.h # { + then + grep -q Fctty ${OPENBSD_SYS}/miscfs/fdesc/fdesc.h + if test $? -eq 0 # { + then + LSOF_CFGF="$LSOF_CFGF -DHASFDESCFS=1" + else + LSOF_CFGF="$LSOF_CFGF -DHASFDESCFS=2" + fi # } + grep -q fd_link ${OPENBSD_SYS}/miscfs/fdesc/fdesc.h + if test $? -eq 0 # { + then + LSOF_CFGF="$LSOF_CFGF -DHASFDLINK" + fi # } + LSOF_TMP1=1 + fi # } + if test -r ${LSOF_INCLUDE}/sys/vnode.h # { + then + grep -q VT_LFS ${LSOF_INCLUDE}/sys/vnode.h + if test $? -eq 0 # { + then + LSOF_CFGF="$LSOF_CFGF -DHASLFS" + fi # } + fi # } + if test -r ${LSOF_INCLUDE}/miscfs/nullfs/null.h # { + then + LSOF_CFGF="$LSOF_CFGF -DHASNULLFS" + else + if test -r ${OPENBSD_SYS}/miscfs/nullfs/null.h # { + then + LSOF_CFGF="$LSOF_CFGF -DHASNULLFS" + LSOF_TMP1=1 + fi # } + fi # } + if test -d ${OPENBSD_SYS}/miscfs/procfs # { + then + LSOF_CFGF="$LSOF_CFGF -DHASPROCFS" + LSOF_TMP1=1 + fi # } + if test -d ${OPENBSD_SYS}/isofs/cd9660 # { + then + LSOF_CFGF="$LSOF_CFGF -DHAS9660FS=1" + LSOF_TMP1=1 + else + if test -d ${OPENBSD_SYS}/fs/cd9660 # { + then + LSOF_CFGF="$LSOF_CFGF -DHAS9660FS=2" + LSOF_TMP1=1 + fi # } + fi # } + if test -d ${OPENBSD_SYS}/msdosfs # { + then + LSOF_CFGF="$LSOF_CFGF -DHASMSDOSFS=1" + LSOF_TMP1=1 + else + if test -d ${OPENBSD_SYS}/fs/msdosfs # { + then + LSOF_CFGF="$LSOF_CFGF -DHASMSDOSFS=2" + LSOF_TMP1=1 + fi # } + fi # } + if test -r ${OPENBSD_SYS}/miscfs/kernfs/kernfs.h # { + then + grep -q "kt_name;" ${OPENBSD_SYS}/miscfs/kernfs/kernfs.h + if test $? -eq 0 # { + then + LSOF_CFGF="$LSOF_CFGF -DHASKERNFS" + LSOF_TMP1=1 + fi # } + fi # } + if test $LSOF_TMP1 -eq 1 -a "X$LSOF_INCLUDE" != "X$OPENBSD_SYS" # { + then + LSOF_DINC="-I$LSOF_INCLUDE -I$OPENBSD_SYS" + fi # } + grep -q VT_EXT2FS ${LSOF_INCLUDE}/sys/vnode.h + if test $? -eq 0 # { + then + LSOF_TMP1=1 + if test -r ${LSOF_INCLUDE}/ufs/ufs/inode.h # { + then + grep -q "*e2fs_din" ${LSOF_INCLUDE}/ufs/ufs/inode.h + if test $? -eq 0 # { + then + LSOF_CFGF="$LSOF_CFGF -DHASI_E2FS_PTR" + fi # } + grep -q "^#define[ ]i_e2din" ${LSOF_INCLUDE}/ufs/ufs/inode.h + if test $? -eq 0 # { + then + LSOF_TMP1=2 + fi # } + fi # } + LSOF_CFGF="$LSOF_CFGF -DHASEXT2FS=$LSOF_TMP1" + 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 # } + grep -q dinode_u ${LSOF_INCLUDE}/ufs/ufs/inode.h + if test $? -eq 0 # { + then + LSOF_CFGF="$LSOF_CFGF -DHAS_DINODE_U" + fi # } + grep -q i_ffs1_size ${LSOF_INCLUDE}/ufs/ufs/inode.h + if test $? -eq 0 # { + then + LSOF_CFGF="$LSOF_CFGF -DHASI_FFS1" + fi # } + grep -q UM_UFS ${LSOF_INCLUDE}/ufs/ufs/inode.h + if test $? -eq 0 # { + then + LSOF_CFGF="$LSOF_CFGF -DHAS_UM_UFS" + fi # } + 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 "X$OPENBSD_UVM" = "X" # { + then + if test -r ${LSOF_INCLUDE}/sys/vnode.h # { + then + grep -q UVM ${LSOF_INCLUDE}/sys/vnode.h + if test $? -ne 0 # { + then + egrep -q "v_uvm;|v_uobj;" ${LSOF_INCLUDE}/sys/vnode.h + if test $? -eq 0 # { + then + OPENBSD_UVM="Y" + fi # } + fi # } + fi # } + fi # } + if test "X$OPENBSD_UVM" = "XY" -o "X$OPENBSD_UVM" = "Xy" # { + then + LSOF_CFGF="$LSOF_CFGF -DUVM" + if test -d ${LSOF_INCLUDE}/uvm # { + then + LSOF_CFGF="$LSOF_CFGF -DHAS_UVM_INCL" + fi # } + fi # } + if test -r ${LSOF_INCLUDE}/sys/mount.h -a $LSOF_VERS -lt 3030 # { + then + + # Build a local OpenBSD netexport.h header file for possible use by + # . 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=dialects/n+obsd/include/netexport.h + if test ! -d dialects/n+obsd/include # { + then + mkdir dialects/n+obsd/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 " >> $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 /dialects/n+obsd/include > /dev/null 2>&1 + if test $? -ne 0 # { + then + LSOF_CFGF="$LSOF_CFGF -I`pwd`/dialects/n+obsd/include" + fi # } + fi # } + if test -r ${LSOF_INCLUDE}/sys/lockf.h # { + then + grep vop_advlock_args ${LSOF_INCLUDE}/sys/lockf.h > /dev/null + if test $? -eq 0 # { + then + LSOF_CFGF="$LSOF_CFGF -DHAS_ADVLOCK_ARGS" + fi # } + fi # } + if test -r ${LSOF_INCLUDE}/sys/pipe.h # { + then + LSOF_CFGF="$LSOF_CFGF -DHAS_SYS_PIPEH" + fi # } + LSOF_CFGL="$LSOF_CFGL -lkvm" + LSOF_DIALECT_DIR=n+obsd + ;; + +# 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 " 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 " >> ${LSOF_TMPC}.c + echo "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 " >> ${LSOF_TMPC}.c + echo "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 "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 "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 "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 '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 . + + if test -r ${LSOF_INCLUDE}/sys/fs/cachefs_fs.h # { + then + LSOF_CFGF="$LSOF_CFGF -DHASCACHEFS" + fi # } + + # Test for + + 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 " > ${LSOF_TMPC}.c + echo "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 ./dialects/$LSOF_DIALECT_DIR # { +then + echo "Can't configure for $LSOF_TGT -- ./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 ./dialects/$LSOF_DIALECT_DIR/$LSOF_MK # { +then + echo "Can't configure for $LSOF_TGT -- ./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 ./dialects/$LSOF_DIALECT_DIR/$LSOF_REST # { +then + echo "Can't configure for $LSOF_TGT -- ./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 +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 ./dialects/$LSOF_DIALECT_DIR/$LSOF_MK $LSOF_TGT $LSOF_VERS + +# 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="-O" +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 # } +rm -f ${LSOF_LIB}/$LSOF_LIBMKF +if test "X$LSOF_LIB_NO" = "X" # { +then + cp $LSOF_MKFC ${LSOF_LIB}/$LSOF_LIBMKF +fi # } +cat ./dialects/$LSOF_DIALECT_DIR/$LSOF_REST >> $LSOF_MKFC +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 + 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 index 0000000..8fc9921 --- /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 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/Inventory b/Inventory new file mode 100755 index 0000000..6b16fe5 --- /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 | 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 + +# 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 index 0000000..5ad6234 --- /dev/null +++ b/Lsof.8 @@ -0,0 +1,4527 @@ +.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 \-?abChlnNOPRtUvVX +] [ +.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]]" +] [ +.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]]" +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. +.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 and Linux pseudoterminal files +should be displayed with endpoint information and the files of the endpoints should also be displayed. +Note: UNIX socket file endpoint information is only available when the +compile flags line of +.B \-v +output contains HASUXSOCKEPT, and psudoterminal endpoint information is only +available when the compile flags line contains HASPTYEPT. +.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 compile +flags line of +.B \-V +output contains HASPTYEPT. +.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 +compile flags line of +.B \-v +output contains HASUXSOCKEPT. +.IP +Multiple occurrences of this information can appear in a file's +NAME column. +.IP +.B -E +specfies that Linux pipe and Linux UNIX socket 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) + \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 +.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 +.br or \fBUDPLITE\fP. +.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\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 +.BI +|\-r " [t[m]]" +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. +.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" argument specifies a format for the marker line. +The 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, cannot contain the NL format, ``%n''. +Note also that when contains spaces or other characters that +affect the shell's interpretation of arguments, 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 + + QR= + QS= + SO= + SS= + TF= + WR= + WW= +.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 , and . +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.) +.TP \w'names'u+4 +.B \-t +specifies that +.I lsof +should produce terse output with process identifiers only and no header \- +e.g., so that the output may be piped to +.IR kill (1). +.B \-t +selects 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 selects 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 + \fBerr\fR FD information error (see NAME column); +.br + \fBjld\fR jail directory (FreeBSD); +.br + \fBltx\fP shared library text (code and data); +.br + \fBMxx\fP 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 + \fBpd\fP parent directory; +.br + \fBrtd\fP root directory; +.br + \fBtr\fR kernel trace file (OpenBSD); +.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. +.TP +TYPE +is the type of the node associated with the file \- e.g., GDIR, GREG, +VDIR, VREG, etc. +.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 ``ax25'' for a Linux AX.25 socket; +.IP +or ``inet'' for an Internet domain socket; +.IP +or ``lla'' for a HP\-UX link level access file; +.IP +or ``rte'' for an AF_ROUTE socket; +.IP +or ``sock'' for a socket of unknown domain; +.IP +or ``unix'' for a UNIX domain socket; +.IP +or ``x.25'' for an HP\-UX x.25 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 ``FIFO'' for a FIFO special file; +.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 ``NOFD'' for a Linux /proc//fd directory that can't be opened \-- +the directory path appears in the NAME column, followed by an error +message; +.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 ``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 ``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 ``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 ``SMT'' for a shared memory transport file; +.IP +or ``STSO'' for a stream socket; +.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 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 + 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 + 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 +, , , , and ; +see the lsof.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 +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='' and ``wr='' 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 :[:], 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:)'' to the NAME column. + and are hexadecimal vnode addresses. + will be ``<-'' if has been fattach'ed to +this vnode whose address is ; +and ``->'' if , the vnode address of this vnode, has been +fattach'ed to . + 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. +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 +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) + f file descriptor (always selected) + F file structure address (0x) + G file flaGs (0x; 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 + M the task comMand name + n file name, comment, Internet address + N node identifier (ox + o file's offset (decimal) + p process ID (always selected) + P protocol name + r raw device number (0x) + 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= + QS= + SO= (not all dialects) + SS= (not all dialects) + ST= + TF= (not all dialects) + WR= (not all dialects) + WW= (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 + NEXTSTEP + OpenBSD + OPENSTEP + SCO OpenServer + SCO|Caldera UnixWare + Solaris + Tru64 UNIX +.fi +.PP +.I Lsof +can't report path name components for these dialects: +.PP +.nf + AIX +.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 + NEXTSTEP 3.[13] for NEXTSTEP architectures + OpenBSD 2.[89] and 3.[0\-9] for x86-based systems + OPENSTEP 4.x + 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. +.PP +It returns a zero (0) if no errors were detected and if 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 +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, use: +.IP +lsof /u/abe/foo +.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 file is also available via anonymous ftp from +.I lsof.itap.purdue.edu +at +.IR pub/tools/unix/lsof FAQ . +The URL is: +.IP +ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/FAQ +.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 of Purdue University. +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 via anonymous ftp from the host +.IR lsof.itap.purdue.edu . +You'll find the +.I lsof +distribution in the +.I pub/tools/unix/lsof +directory. +.PP +You can also use this URL: +.IP +ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof +.PP +.I Lsof +is also mirrored elsewhere. +When you access +.I lsof.itap.purdue.edu +and change to its +.I pub/tools/unix/lsof +directory, you'll be given a list of some mirror sites. +The +.I pub/tools/unix/lsof +directory also contains a more complete list in its +.I mirrors +file. +Use mirrors with caution \- not all mirrors always have the latest +.I lsof +revision. +.PP +Some pre\-compiled +.I Lsof +executables are available on +.IR lsof.itap.purdue.edu , +but their use is discouraged \- it's better that you build +your own from the sources. +If you feel you must use a pre\-compiled executable, please +read the cautions that appear in the README files of the +.I pub/tools/unix/lsof/binaries +subdirectories and in the 00* files of the distribution. +.PP +More information on the +.I lsof +distribution can be found in its +.I README.lsof_ +file. +If you intend to get the +.I lsof +distribution and build it, please read +.I README.lsof_ +and the other 00* files of the distribution before sending questions +to the author. +.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), +perl(1), +ps(1), +readlink(2), +setlocale(3), +stat(2), +strftime(3), +time(2), +uname(1). diff --git a/NEW/2004-2005-report.bz2 b/NEW/2004-2005-report.bz2 new file mode 100644 index 0000000..28656e6 Binary files /dev/null and b/NEW/2004-2005-report.bz2 differ diff --git a/NEW/PSTAT-white-paper b/NEW/PSTAT-white-paper new file mode 100644 index 0000000..64652c1 --- /dev/null +++ b/NEW/PSTAT-white-paper @@ -0,0 +1 @@ +http://docs.hp.com/hpux/onlinedocs/os/11i/pstat_whitepaper.pdf diff --git a/NEW/basic_RE b/NEW/basic_RE new file mode 100644 index 0000000..6c6aee8 --- /dev/null +++ b/NEW/basic_RE @@ -0,0 +1,20 @@ + Obsolete (``basic'') regular expressions differ in several + respects. `|', `+', and `?' are ordinary characters and + there is no equivalent for their functionality. The + delimiters for bounds are `\{' and `\}', with `{' and `}' + by themselves ordinary characters. The parentheses for + nested subexpressions are `\(' and `\)', with `(' and `)' + by themselves ordinary characters. `^' is an ordinary + character except at the beginning of the RE or the begin + ning of a parenthesized subexpression, `$' is an ordinary + character except at the end of the RE or the end of a + parenthesized subexpression, and `*' is an ordinary char + acter if it appears at the beginning of the RE or the + beginning of a parenthesized subexpression (after a possi + ble leading `^'). Finally, there is one new type of atom, + a back reference: `\' followed by a non-zero decimal digit + d matches the same sequence of characters matched by the + dth parenthesized subexpression (numbering subexpressions + by the positions of their opening parentheses, left to + right), so that (e.g.) `\([bc]\)\1' matches `bb' or `cc' + but not `bc'. diff --git a/NEW/ckssh.gz b/NEW/ckssh.gz new file mode 100755 index 0000000..c78e5c8 Binary files /dev/null and b/NEW/ckssh.gz differ diff --git a/NEW/cktn.gz b/NEW/cktn.gz new file mode 100755 index 0000000..f2979be Binary files /dev/null and b/NEW/cktn.gz differ diff --git a/NEW/faker.c.gz b/NEW/faker.c.gz new file mode 100644 index 0000000..57dacda Binary files /dev/null and b/NEW/faker.c.gz differ diff --git a/NEW/getcc b/NEW/getcc new file mode 100755 index 0000000..4b15da7 --- /dev/null +++ b/NEW/getcc @@ -0,0 +1,9 @@ +#!/bin/sh +D=/etc/ftpd/access +R=ftp.dom +rm -f $R +for i in $D/9*.gz +do + gunzip -c $i | sed '1,/^Domains/d' | sed '/^$/d' | sed '/^ -- /,$d' >> $R + echo $i +done diff --git a/NEW/irix.zip b/NEW/irix.zip new file mode 100644 index 0000000..d0ae175 Binary files /dev/null and b/NEW/irix.zip differ diff --git a/NEW/lsofAPI.tar.gz b/NEW/lsofAPI.tar.gz new file mode 100644 index 0000000..7432da6 Binary files /dev/null and b/NEW/lsofAPI.tar.gz differ diff --git a/NEW/lsofAPI/lsofAPI.1 b/NEW/lsofAPI/lsofAPI.1 new file mode 100644 index 0000000..e3a0f87 --- /dev/null +++ b/NEW/lsofAPI/lsofAPI.1 @@ -0,0 +1,278 @@ + + Current lsof data sources + and what it does with the data. + + From the proc and user structures: + + process status (p_stat) (e.g., SZOMB) + + Lsof uses this information to decide if the process + is active or is a "zombie" it should ignore. + + command name + + Lsof reports this information to the user. + + Process IDentification number (PID) (p_pid) + + Lsof reports this information to the user and uses + it in some error messages. + + Process Group ID (PGRP) (p_pgrp) + + Lsof reports this information to the user, if requested + to do so with an option. Lsof post-processing scripts + may use this information to establish process chains. + + Parent PID (PPID) (p_ppid) + + Lsof reports this information to the user, if requested. + to do so with an option. + + User ID (UID) (p_uid) + + Lsof reports this information to the user. By + default it converts UID to login name, but the default + mode can be change with an option. + + Current working directory vnode pointer (p_cdir) + + Lsof normally reports CWD, but its reporting can be + suppressed. CWD vnode pointer processing is handled as + any other vnode pointer from the file structure would be. + + Root directory vnode pointer (p_rdir) + + Lsof normally reports a root directory, if it exists, + but the reporting can be suppressed. Root directory + vnode pointer processing is handled as any other + vnode pointer from the file structure would be. + + Text and loader file information (via VM map) + + Lsof follows the pregion and region changes leading + from the process' VM pointer to any vnodes that are + shadowed by memory regions. It then processes their + vnode pointers just as it processes any others. This + results in a display of the text file used by the + process, and the shared library files it uses. + + From file structures: + + The file structure address (from the open file "chunk") + + Lsof uses this pointer to read the file structure. + + It also reports the address for post-processing scripts + that need to identify unique file structure usage -- + e.g., check for file descriptor leakage between child + and parent processes. + + The usage count (f_count) + + Lsof uses this to determine if the file structure is + worth further examination. + + The node address (f_data) + + Lsof uses this to read file structure successor -- + e.g., socket, vnode. + + Lsof also reports this address for post-processing + scripts that need to identify unique file usage. + + The access code (f_flag) + + Lsof uses this code to report whether the file was opened + for read access, write access, or read/write access. Lsof + can also be asked to report the full contents of f_flag. + + The file structure type (f_type) + + Lsof determines the processing to be applied to the + file structure successor, pointed at by f_data. + + The file offset (f_offset) + + Lsof saves this *most* useful information for reporting + to the user. It's particularly interesting, for example, + on character device tape files, because when it changes, + the tape user knows the tape is moving. + + From socket structures: + + Lsof sometimes uses the file structure alone to identify + socket files. At other times it also uses the socket stream + header pointer. + + Lsof gets the socket structure pointer from f_data in file + structures whose f_type is DTYPE_SOCKET. (UNIX dialects + whose socket implementations are stream based often don't + have file structure types.) It then reads the socket + structure and uses these fields: + + Socket type (so_type) + + Lsof uses the socket type -- e.g., SOCK_RAW for + special processing of its structures. + + Socket protocol (so_proto) + + Lsof reads the protocol domain switch, protosw, + to get the domain structure, so it can find out + to what domain -- e.g., AF_INET -- the socket + belongs. + + Socket receive buffer parameters (so_rcv) + Socket send parameters (so_snd) + + Lsof reads these buffer parameters to be able to + report file size or position. For example, an + advancing position on an ftp socket can be used + as an indicator that the transfer is making progress. + + Socket protocol control block address (so_pcb) + + Lsof gets TCP/IP addresses from the protocol control + block. + + Socket stream header (so_sth) + + Lsof sometimes uses the stream head pointer to + learn information about the socket file. It reads + the stream module names, looking for IP, TCP and + UDP modules and their private q_ptr addresses. + + If an IP q_ptr is located, lsof reads the ipcs_s + structure to which it points to get TCP/IP connection + addresses. + + Lsof also reads other TCP and UDP structures to + get state and read/write buffer information that + it can report to the lsof user. + + From the vnode: + + Lsof gets the vnode address from the f_data member of file + structures. + + It saves the vnode address for use in extracting path + name components from the kernel name cache. + + Reading the vnode: + + Usually f_data values point to vnodes. Lsof reads the + structure appropriate to the file type. + + Vnode type (derived from v_op) + + Lsof must know the vnode type in order to be able to + read any further information about the open file from + the structures that follow the vnode. It determines + the vnode type by comparing the v_op address to a + set of *_vnodeops switch addresses it gets from the + kernel via nlist(). + + Vnode locks (v_locklist) + + If the vnode has a lock list pointer, lsof examines + the chain it addresses, looking for locks belonging + to the process owning the file. + + Vnode virtual file system structure (v_vfsp) + + Lsof reads the virtual file system structure to + determine the file system on which the vnode resides. + The vfs structure yields the file system information -- + mounted-on directory, mounted-on device, NFS device + number, etc. This information is cached by vfs structure + address so vfs information for later vnodes can be + found quickly. + + Vnode successors (v_data) + + Based on the vnode type it established from v_op, lsof + reads the vnode successor structures addressed by v_data. + + AFS type vnodes lead to an AFS node structure; VxFS type + vnodes lead to a vxnode; CDFS nodes to a cdnode; NFS vnodes + to an rnode; etc. + + There are many special cases -- e.g., FIFOs and pipes. + The most special are VCHR nodes. They can lead to + snodes, and from there back to vnodes. They can lead + to device nodes on a special file system -- e.g., /dev + nodes on a VxFS file system. They can lead to simple + inodes. + + Eventually lsof derives the following data from the + nodes it reads: + + Vnode address + + File device numbers -- cooked and raw + + File node number + + Most node structures have a number, but lsof may + have to generate a node number from /dev information + for some character device files. + + File size + + Link count + + File type (v_type) (e.g., FIFO, VREG, etc.) + + It's a good indicator of the purpose of the file. + + Streams (v_stream) + + Lsof saves the device numbers for streams and checks + their module names for IP, TCP, and UDP. If any of + those three appear, lsof processes the vnode stream as + a socket stream. + + The kernel name cache: + + While device and inode number uniquely identify files, + they aren't easy to use by people who read lsof output. + Lsof output readers want path names. + + Lsof tries to accommodate that by reading the contents of + the kernel name cache, keyed by vnode addresses, and matching + that to vnode addresses accumulated while reading open file + structures and vnodes. + + Since the kernel cache for a particular vnode also points + to the vnode of its parent, lsof is often successful in + constructing an entire path name from the kernel cache. + Sometimes it can't construct the entire name, but some + terminating components, and even that is helpful. + + The mount table: + + Lsof reads the mount table via the setmntent()/getmntent() + interface and stores the information for decoding file + system residence, especially when printing open file results. + The file system, for example, is the first component of a + full path name, derived from the kernel name cache, even + when lsof finds all other path name components in the kernel + name cache. + + The device table: + + Lsof reads the device table (/dev) using opendir(), readdir(), + and stat() calls, so it can report full device names on + VCHR files. + + Since the above operations are sometimes time-consuming + and the information seldom changes, lsof caches the + information and tries to get it first from a cache file, + located in the user's home directory. (The cache file may + be stored globally, but it's much more restricted [for + security reasons] in that case.) + + + Vic Abell + March 15, 1999 diff --git a/NEW/lsofAPI/lsofAPI.2 b/NEW/lsofAPI/lsofAPI.2 new file mode 100644 index 0000000..30f565f --- /dev/null +++ b/NEW/lsofAPI/lsofAPI.2 @@ -0,0 +1,247 @@ + + Data lsof reports and where + lsof got the data. + + COMMAND + + This is the command name from the process or user structure. + Lsof prints only the first 9 characters. However, it + reports all characters in field output. + + Lsof can be told to filter output by the command name via + its -c option. + + PID + + This is the Process IDentification number from the process + structure. + + Lsof can be told to filter output by PID number via its -p + option. + + PPID + + This is the Parent Process IDentification number. + + There is no filter option for PPID. + + PGRP + + This is the Process Group IDentification number. + + Lsof can be told to filter output by PGRP ID via its -g + option. + + USER + + This is the identification of the user who owns the process. + Sometimes UID is taken from the p_uid member of the process + structure and sometimes from the pid struct to which the + proc structure points. + + User identification is normally reported as a login name, + but can be reported as a User IDentification number via + lsof's -l option. + + Lsof can be told to filter by use identification with its + -u option. + + FD + + Usually this is the file descriptor number, but can have + some special forms for open files that aren't connected + to file descriptors: + + cwd for the current working directory + rtd for the root directory + txt for text (executable) files occupying + memory regions + mem for other memory-mapped files + Rxx for unrecognized region files whose + p_type is the two digit number xx. + + The file descriptor is followed by two characters: 1) a + file access mode; and 2) a file lock status. + + The file access mode is 'r' for read; 'w', write; and 'u' + for read and write. This information is taken from the + f_flag member of the file structure. Lsof can also be + directed to report the contents of f_flag. + + The file lock status is determined by following the lock + list chain from the vnode. The first lock encountered in + the list determine what is reported: 'r' for a 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; and 'W" + for a write lock on the entire file. + + TYPE + + Usually this is the type reported in v_type -- e.g., VCHR, + VDIR, VREG, etc. However, lsof tries to limit the length + to four characters, so VFIFO becomes FIFO. + + Lsof also uses the TYPE column to indicate socket files: + + inet Internet domain + IPv4 where lsof supports IPv4 and IPv6 + IPv6 where lsof supports IPv4 and IPv6 + sock unknown domain + unix Unix domain + + FILE-ADDR + + This is the kernel file structure address lsof read from + the proc structure or file chunks. It is useful for + detecting (usually via scripts that post-process lsof field + output) file descriptors shared between processes -- e.g., + inherited by a child from its parent -- especially when + excessive file descriptor use ("leaks") appear to be + occurring. + + This item is only reported when selected with lsof's +ff + option, and when the open file is represented by a file + descriptor. + + + FCT + + This is the f_count member of the file structure. It is + useful when chasing file descriptor "leaks" for determining + how many references a file descriptor has. + + This item is only reported when selected with lsof's +fc + option, and when the open file is represented by a file + descriptor. + + NODE-ID + + This is the vnode address from the f_data member of the + file structure. It is useful for detecting (usually via + scripts that post-process lsof field output) files that + are shared between processes. + + This item is only reported when selected with lsof's +fp + option, and when the open file is represented by a file + descriptor. + + DEVICE + + Two things may appear in the device column: 1) the major + and minor device number doublet of character and block + devices; or 2) a hexadecimal number that represents the + "device" of a pipe or socket -- e.g., the TCP/IP protocol + address also reported by netstat -A. + + There are two reasons for reporting a hex number: 1) to + match with netstat -A output; and 2) to match a pipe or + socket whose only destination address is a similar hex + number. + + SIZE/OFF + + Lsof reports the file size or current position (offset from + f_offset of the file structure) in this column. + + The default mode is to report offset for files that don't + have size in their node structures -- e.g., pipes, sockets, + character device files -- and size from the node structure + for everything else. + + Several lsof options control what is reported: -o selects + offset (and suppresses size); -s selects size (and suppresses + offset); and -o[n] specifies how many offset digits are + to be reported in decimal (default 8) before the output + form switches to hexadecimal. + + File size is very useful when a system administrator is + searching for unlinked files that are still consuming disk + space. + + File offset is very useful to anyone who is watching for + activity on a character device file or socket. I use it + to measure progress of ftp transfers, for example. + + NLINK + + The file (e.g. inode) link count. This is usefile for + locating large unlinked files that are still being written + and are consuming needed disk space. + + Lsof has a elementary filter for link count. + + NODE + + Usually the value in the NODE column is the associated node + structure's ID number -- e.g., the inode number. + + However, some open files don't have a node structure. For + them lsof uses this column in a variety of ways. + + NODE may contain the protocol (PF_*) value for TCP/IP + sockets. + + NODE is blank for Unix sockets. + + NODE may contain STR for streams. + + NAME + + The NAME column is the most complicated and overloaded + output field lsof produces. + + Originally it was designed to receive the node name of + files attached to device nodes (VCHR) files or the mounted-on + directory and mounted-on device names for file systems In + many cases that information still appears in the NAME column. + + However, along the way the NAME column has become used for + a wide variety of miscellaneous file information, including: + + * Error messages about situations lsof has encountered -- + e.g., it can't read a node structure via /dev/kmem. + + * Socket file information: + + o TCP/IP connection addresses (ports or service names, and + host names or IP numbers) + + o TCP/IP connection information -- states (e.g., ESTABLISH, + or Unbound), received and send queue sizes, receive and + send queue window sizes + + o FIFO and pipe information -- peer connection ID, data + in the pipes + + o Unix socket information -- peer connection ID, file + system object (i.e., path name) + + o The name of a file or file system specified as a search + search argument + + o NFS mount points + + o Stream module names, perhaps accompanied by a device, + clone device, or pseudo device name + + o Raw socket address information + + o Socket pair information + + o Namefs (via fattach(3C)) information + + o Full and partial path names, anchored at the containing + file system and extending through some or all kernel + name cache components + + o Clone device names + + o Pseudo device names + + Of all these NAME column items, file system name, socket + connection parameters, character device node names, and + full path names are the most useful. + + + Vic Abell + March 16, 1999 diff --git a/NEW/lsofAPI/lsofAPI.3 b/NEW/lsofAPI/lsofAPI.3 new file mode 100644 index 0000000..7938593 --- /dev/null +++ b/NEW/lsofAPI/lsofAPI.3 @@ -0,0 +1,70 @@ + + General lsof Features + + Lsof does more than just report on open files, or look for + Internet addresses for disovering the processes associated with + them. + + It has two major additional features: 1) extensive filtering + of open file information; and 2) reporting open file information + in a way convenient for post-processing with filters (e.g., + AWK or Perl) scripts. + + Filtering + + Lsof has the following options for filtering open file + information: + + -c select a command or list of commands for reporting + + +|-d search for open files in a specified directory + +|-D + + -d select by file descriptor + + -g select by process group ID + + -i select by Internet service names or port numbers, + addresses or host names, and protocol + + +L select by node link count + + -N select NFS files + + -p select by PID + + -u select by login or UID + + -U select Unix domain socket files + + search for an open file by name + search for all open files on a named file system + + Output for Filtering + + Lsof produces output for post-filtering scripts. It's + called field output, because it's organized in field records, + identified by key characters. + + The lsof distribution comes with sample scripts that use + field output to: + + Watch a particular file. + + Watch for new TCP/IP connections. + + Count processes and files. + + Implement an identd or pidentd server. + + Identify the Internet source of rlogin, telnet and ssh + connections. + + Identifying processes that share file descriptors or + files. + + Identify users and applications on X Window System work + stations. + + Vic Abell + March 17 1999 diff --git a/NEW/lsofAPI/lsofAPI.4 b/NEW/lsofAPI/lsofAPI.4 new file mode 100644 index 0000000..0cbd7f5 --- /dev/null +++ b/NEW/lsofAPI/lsofAPI.4 @@ -0,0 +1,136 @@ + + + An Lsof API + + This lsof API definition is based on obtaining the information + lsof currently delivers in its /dev/kmem configuration. There + may be better ways to get the necessary information, and I'll + try to indicate where options are possible. + + I've not tried to determine if any current API already provides + any of the following information. + + Lsof needs information on processes and their open files, so + I'll divide the API discussion into those two sections, and + add a section on how lsof might be provided path name information. + + Process Information + =================== + + For each process lsof needs the following information: + + The name of the command executing for the process. + + The process PID. + + The process parent PID. + + The process group ID. + + The UID of the owner of the process. + + All open file information on: + + The current working directory + + The root directory + + The executing text file + + Share libraries + + Any memory-mapped files + + Open File Information + ===================== + + For each open file, lsof needs this information: + + File table address -- this information is used for + checking for file descriptor leaks, for example. + Any sort of unique ID that would enable that check + would suffice. + + Current file position + + Number of open instances of the file + + File size + + Link count + + Device (raw and cooked) major and minor numbers + + File system identification -- mounted-on directory + and mounted-on device name + + Open state -- read, write, or read/write + + File type -- e.g., regular, directory, fifo, pipe, + socket, etc. + + Vnode address -- this information is used in two ways: + 1) to identify files shared by processes; and 2) to + locate path name components in the kernel name cache. + + Sometimes the vnode has a "capability" ID that connects + it to the cache entry. Lsof might need that. + + A unique identifier could satisfy the first need. + A full path name could satisfy the second. + + Node number -- CD node number, NFS node number, inode + number, etc. + + Full path names or a way to get path names from the + kernel's name cache + + For sockets: + + Protocol, including AF_*, PF_*, and IPPROTO_* + values, IPv4 or IPv6, etc. + + Local and remote IP (v4 or v6) addresses and ports + + Unix domain information -- peer ID, file system + object (path name, device, node number) + + For pipes: + + Pipe ID + + Peer ID + + Pipe status -- read or write, amount in the pipe, etc. + + + Path Names + + Lsof currently reports path names by using vnode addresses to + assemble their components from the kernel name cache. + + I see two options here: 1) report full path names directly + in the API; or 2) provide an API that delivers the kernel + name cache data to lsof that it can connect to open files + -- e.g., via vnode address, or (device,node_number) doublet. + + Here's what lsof extracts from the kernel name cache that + an API would need to supply: + + A connection between open files and cache entries, such + a vnode address or a (device,node_number) doublet + + The path entry name component -- e.g., the "stat.h" + part of "/usr/include/sys/stat.h". + + A connection from the cache entry to its immediate + directory parent -- e.g., from stat.h to sys. + In this cache this is usually done with a vnode + pointer. + + Any unique ID (i.e., a "capability" ID from the vnode) + that might distinguish the cache entry. + + + Vic Abell + March 18, 1999 diff --git a/NEW/lsofAPI/lsofAPI.5 b/NEW/lsofAPI/lsofAPI.5 new file mode 100644 index 0000000..78dba09 --- /dev/null +++ b/NEW/lsofAPI/lsofAPI.5 @@ -0,0 +1,240 @@ + + + Functions of An Lsof API + + In the functions I describe I have made no direct reference to + a particular API. Instead, I've tried to describe a general + interface as independent of Unix dialect implementation details + as I can make it. + + I envision an lsof API having these functions: + + * Get basic process information about a process or a set + of processes. + + * Get extended information for a single process. + + * Get extended information for a file or a set of files. + + * Get file name cache information. (This function may + not be needed if the extended file information has + path name.) + + Get Basic Process Information + ============================= + + Lsof should be able to get the following basic information + on a single process or a set of processes. The process set + might include all processes -- and generally will. + + * The process ID (PID) + + * The parent process ID (PPID) + + * The process group ID (PGRP) + + * The owner of the process (UID) + + * The status of the process -- i.e., is it a "zombie", is + it a system process, is it swapped out, etc.? + + * The command being executed by the process + + * Reference values for the current working and root directories + that can be supplied to the get extended file information + function to learn more about these directories. + + File Reference Value + ==================== + The file reference values should be globally unique, so lsof + can report them for analysis of all open files by the lsof + user. Vnode address might be a good reference value. Adding + file structure address and file descriptor number to the + file reference value, when they are available, might be + necessary. + + The file reference value might look like this: + + struct file_ref_val { + pid_t frv_pid; /* PID owning or using this file */ + void *frv_node: /* file's kernel vnode address */ + void *frv_file; /* file's kernel file structure address + * (NULL if not applicable) */ + int frv_fd; /* file's descriptor number + * (if frv_file is non-NULL) */ + }; + + Implementation Suggestion: + ========================= + + I like best the way AIX delivers a full process table + information set. It supplies its getproc() function with + a receiving table address and count. Those parameters are + started at a table of size 1. Getproc() returns an ENOSPC + error if the supplied size isn't big enough, and an estimate + in the first entry of the supplied structure buffer of how + many entries would be enough. The caller realloc()s its + buffer to the suggested reply value and calls getproc() + again. + + Get Extended Process Information + ================================ + + I envision this function applying to a single process. Lsof + would use it after determining a given process is of further + interest by looking at its basic information. + + This function needs to return two variable size arrays: + + * A list of file reference values for the executing text + file, shared libraries, and memory mapped files -- and any + other process-related files -- in use by the process. Lsof + should be able to use these as arguments to the get extended + file information function. + + * A list of file reference values for open file descriptors. + Lsof should be able to use these as arguments to the get + extended file information function. + + These file reference values should also be usable in + identifying processes that share the same file descriptor. + The file structure address could be used to do that. + + Get Extended File Information + ============================= + + This function takes a file reference value -- a process current + working directory response value or a file descriptor reference + value -- and returns the information lsof needs for a full + report on the file. The basic information would include: + + * File type -- regular file, directory, socket, NFS file, + FIFO, pipe, etc. + + * Access mode -- how the file was opened -- read, write, or + read and write + + * Type of lock that the owning process has applied to the + file -- read, write, full file, partial file + + * Current position -- file offset + + * File link count + + * Number of current users of the file + + * FIle system information (when the file resides on a file + system) -- mounted-on directory and device names, file + system type, file system (major,minor) device doublets (raw + and cooked), file system root inode number + + * Indication of the type of further file data -- socket, FIFO, + character, etc. + + o For sockets: + + . Protocol -- Internet, Unix, etc. + + . For TCP/IP sockets: + + x Protocol -- IPPROTO_* + + x Identifier -- e.g. protocol control block address + + x Type -- IPv4 or IPv6 + + x Local and remote host Internet numbers and port numbers + + x Connection state -- e.g. ESTABLISHED or Unbound + + x Read and write queue sizes + + x Read and write window sizes + + . For Unix domain sockets + + x Identifier -- e.g., protocol control block address + + x Remote peer identifier + + x File reference value for any name bound to the + Unix domain socket + + x Name bound to the Unix domain socket + + x Read and write queue sizes + + o For pipes and FIFOs: + + . Remote peer identifier -- e.g., a file reference value + + . Any associated name + + . Node number, if applicable + + . Data in pipe or FIFO -- read and write quantities + + o For streams + + . Stream device identification: + + x (major,minor) device number doublets (raw and "cooked") + + x Node number + + x Path name + + . Stream module names + + . Stream queue read and write sizes + + o For character device files + + . raw and cooked (major,minor) device number doublets + + . Character device node number + + . Optional -- device node path name + + o For regular files + + . File system (major,minor) device number doublet -- both raw + and "cooked" + + . Device "node" number + + . File size + + . Full path name (optional -- see the get file name cache + function description) + + o For fattach()'d files: + + . Attached-to file's file reference value + + + Get File Name Cache Information + =============================== + + This function is an option to having the get extended file + information function return full path names. + + If this function is used, it would return information from + the kernel's name cache with file reference values that can + be connected to extended file information. + + For example, this function might return: + + * Vnode address + + * (major,minor) device number doublet + + * Capability ID (a unique-ifier) + + * Name + + * Parent vnode address and capability ID + + + Vic Abell + March 20, 1999 diff --git a/NEW/paper b/NEW/paper new file mode 100644 index 0000000..9f6fc1e --- /dev/null +++ b/NEW/paper @@ -0,0 +1,43 @@ + + Topics for lsof Paper + +Why? + To look at open files with a consistent output interface, + both readable and program-parsable, across many Unix dialects + +How? + How variants: + /dev/kmem + Problems caused by dynamics + Get proc structures in tight loop + KERNELBASE + /proc + syssgi/sysi86 + getproc/getuser + pstat + How problems + Authorization + /proc + Swapped users + Filters + Built-in + External (Field Output) + Porting + Special purpose additions -- i.e., -X + +Uses and Examples + Watching ftp/rlogin transfers + My lsofwho script + Searching for TCP/IP listeners + Watching a tape drive + +The Lsof Data Source + Field output + Terminators + +Lsof Alternatives + crash + ff + fuser + fstat + ofiles diff --git a/NEW/posting.gz b/NEW/posting.gz new file mode 100644 index 0000000..843c0fa Binary files /dev/null and b/NEW/posting.gz differ diff --git a/NEW/pstat.proto.gz b/NEW/pstat.proto.gz new file mode 100644 index 0000000..aadee0d Binary files /dev/null and b/NEW/pstat.proto.gz differ diff --git a/NEW/rns.c.gz b/NEW/rns.c.gz new file mode 100644 index 0000000..84a7560 Binary files /dev/null and b/NEW/rns.c.gz differ diff --git a/NEW/samples b/NEW/samples new file mode 100644 index 0000000..a028f18 --- /dev/null +++ b/NEW/samples @@ -0,0 +1,26 @@ +char * +print_off(lf, ty) + struct lfile *lf; /* file whose size is to be printed */ + int ty; /* format type: 0 == 0t + * 1 == 0x */ +{ + static buf[128]; + + if (!ty) + (void) sprintf(buf, SzOffFmt_0t, lf->off); + else + (void) sprintf(buf, SzOffFmt_x, lf->off); + return(buf); + +} + + +char * +print_sz(lf) + struct lfile *lf; /* file whose size is to be printed */ +{ + static buf[128]; + + (void) sprintf(buf, SzOffFmt_d, lf->sz); + return(buf); +} diff --git a/NEW/self_hex_dmp b/NEW/self_hex_dmp new file mode 100644 index 0000000..af24303 --- /dev/null +++ b/NEW/self_hex_dmp @@ -0,0 +1,23 @@ +/* DEBUG */ + { + int iD, jD; + unsigned long *upD; + + fprintf(stderr, "%ld: %s, fd=%s\n", (long)Lp->pid, Lp->cmd, Lf->fd); + for (iD = jD = 0, upD = (unsigned long *)&fsc; + iD < sizeof(struct fsContext)/8; + iD++, upD++) + { + if (!jD) + fprintf(stderr, " %2d: %016lx", iD, *upD); + else + fprintf(stderr, " %016lx", *upD); + if (++jD >= 4) { + jD = 0; + putc((int)'\n', stderr); + } + } + if (jD) + putc((int)'\n', stderr); + } +/* DEBUG */ diff --git a/NEW/sgi b/NEW/sgi new file mode 100644 index 0000000..a612d68 --- /dev/null +++ b/NEW/sgi @@ -0,0 +1,22 @@ + + Lsof for IRIX; Contacts and Information + + comp.sys.sgi.admin: + + IRIX lsof end-of-life proposed + + SGI IRIX case 0982584 + + E-mail addresses: + + Mark Bartelt + Mike Kienenberger + Robinson, George H + Igor Schein + Dave Sill + Peter Van Epp + + + SGI Contact: + + Dave Olson diff --git a/NEW/sleeper.c b/NEW/sleeper.c new file mode 100644 index 0000000..357bb4c --- /dev/null +++ b/NEW/sleeper.c @@ -0,0 +1,5 @@ +#include + +main() { +sleep(3600); +} diff --git a/NEW/usage.c b/NEW/usage.c new file mode 100644 index 0000000..6b913b2 --- /dev/null +++ b/NEW/usage.c @@ -0,0 +1,754 @@ +/* + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright 1998 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: usage.c,v 1.22 2004/07/06 19:09:32 abe Exp $"; +#endif + + +#include "lsof.h" +#include "version.h" + + +/* + * Local function prototypes + */ + +_PROTOTYPE(static char *isnullstr,(char *s)); +_PROTOTYPE(static void report_HASDCACHE,(int type, char *ttl, char *det)); +_PROTOTYPE(static void report_HASKERNIDCK,(char *pfx, char *verb)); +_PROTOTYPE(static void report_SECURITY,(char *pfx, char *punct)); +_PROTOTYPE(static void report_WARNDEVACCESS,(char *pfx, char *verb, + char *punct)); + + +/* + * isnullstr() - is it a null string? + */ + +static char * +isnullstr(s) + char *s; /* string pointer */ +{ + if (!s) + return((char *)NULL); + while (*s) { + if (*s != ' ') + return(s); + s++; + } + return((char *)NULL); +} + + +/* + * report_HASDCACHE() -- report device cache file state + */ + +static void +report_HASDCACHE(type, ttl, det) + 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(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(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(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(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(xv, fh, version) + int xv; /* exit value */ + int fh; /* ``-F ?'' status */ + int version; /* ``-v'' status */ +{ + char buf[MAXPATHLEN+1], *cp, *cp1, *cp2; + int i; + + if (Fhelp || xv) { + (void) fprintf(stderr, "%s %s\n latest revision: %s\n", + Pn, LSOF_VERSION, LSOF_URL); + (void) fprintf(stderr, " latest FAQ: %sFAQ\n", LSOF_URL); + (void) fprintf(stderr, " latest man page: %slsof_man\n", LSOF_URL); + (void) fprintf(stderr, + " usage: [-?ab%shlnNoOP%sstUvV%s]", + +#if defined(HASNCACHE) + "C", +#else /* !defined(HASNCACHE) */ + "", +#endif /* defined(HASNCACHE) */ + +#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(HAS_AFS) && defined(HASAOPT) + (void) fprintf(stderr, " [-A A]"); +#endif /* defined(HAS_AFS) && defined(HASAOPT) */ + + (void) fprintf(stderr, " [+|-c c] [+|-d s] [+%sD D]", + +#if defined(HASDCACHE) + "|-" +#else /* !defined(HASDCACHE) */ + "" +#endif /* defined(HASDCACHE) */ + + ); + + (void) fprintf(stderr, " [+|-f%s]\n [-F [f]] [-g [s]] [-i [i]]", + +#if defined(HASFSTRUCT) + "[cfgGn]" +#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) */ + + (void) fprintf(stderr, + " [+|-M] [-o [o]]\n[-p s] [+|-r [t]] [-S [t]] [-T [t]]"); + (void) fprintf(stderr, " [-u s] [+|-w] [-x [fl]]"); + +#if defined(HASZONES) + (void) fprintf(stderr, " [-z [z]]"); +#endif /* defined(HASZONES) */ + + (void) fprintf(stderr, " [--] [names]\n"); + } + if (xv && !Fhelp) { + (void) fprintf(stderr, + "Use the ``-h'' option to get more help information.\n"); + if (!fh) + Exit(xv); + } + if (Fhelp) { + (void) fprintf(stderr, + "Defaults in parentheses; comma-separate set (s) items;"); + (void) fprintf(stderr, " dash-separate ranges.\n"); + (void) fprintf(stderr, " %-23.23s", "-?|-h list help"); + (void) fprintf(stderr, " %-25.25s", "-a AND selections (OR)"); + (void) fprintf(stderr, " %s\n", "-b avoid kernel blocks"); + (void) fprintf(stderr, " %-23.23s", "-c c cmd c, /c/[bix]"); + (void) snpf(buf, sizeof(buf), "+c w COMMAND width (%d)", CMDL); + (void) fprintf(stderr, " %-25.25s", buf); + + (void) fprintf(stderr, " %s\n", + +#if defined(HASNCACHE) + "-C no kernel name cache"); +#else /* !defined(HASNCACHE) */ + " "); +#endif /* defined(HASNCACHE) */ + + (void) fprintf(stderr, " %-23.23s", "+d s dir s files"); + (void) fprintf(stderr, " %-25.25s", "-d s select by FD set"); + (void) fprintf(stderr, " %s\n", "+D D dir D tree *SLOW?*"); + +#if defined(HASDCACHE) + if (Setuidroot) + cp = "?|i|r"; + +# if !defined(WILLDROPGID) + else if (Myuid) + cp = "?|i|r"; +# endif /* !defined(WILLDROPGID) */ + + else + cp = "?|i|b|r|u[path]"; + (void) snpf(buf, sizeof(buf), "-D D %s", cp); +#else /* !defined(HASDCACHE) */ + (void) snpf(buf, sizeof(buf), " "); +#endif /* defined(HASDCACHE) */ + + (void) fprintf(stderr, " %-23.23s", buf); + (void) snpf(buf, sizeof(buf), "-i select IPv%s files", + +#if defined(HASIPv6) + "[46]" +#else /* !defined(HASIPv6) */ + "4" +#endif /* defined(HASIPv6) */ + + ); + (void) fprintf(stderr, " %-25.25s", buf); + (void) fprintf(stderr, " %s\n", "-l list UID numbers"); + (void) fprintf(stderr, " %-23.23s", "-n no host names"); + (void) fprintf(stderr, " %-25.25s", "-N select NFS files"); + (void) fprintf(stderr, " %s\n", "-o list file offset"); + (void) fprintf(stderr, " %-23.23s", "-O avoid overhead *RISKY*"); + (void) fprintf(stderr, " %-25.25s", "-P no port names"); + (void) fprintf(stderr, " %s\n", + +#if defined(HASPPID) + "-R list paRent PID" +#else /* !defined(HASPPID) */ + "" +#endif /* defined(HASPPID) */ + + ); + (void) fprintf(stderr, " %-23.23s", "-s list file size"); + (void) fprintf(stderr, " %-25.25s", "-t terse listing"); + (void) fprintf(stderr, " %s\n", "-T disable TCP/TPI info"); + (void) fprintf(stderr, " %-23.23s", "-U select Unix socket"); + (void) fprintf(stderr, " %-25.25s", "-v list version info"); + (void) fprintf(stderr, " %s\n", "-V verbose search"); + (void) snpf(buf, sizeof(buf), "+|-w Warnings (%s)", + +#if defined(WARNINGSTATE) + "-" +#else /* !defined(WARNINGSTATE) */ + "+" +#endif /* defined(WARNINGSTATE) */ + + ); + (void) fprintf(stderr, " %-23.23s", 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) */ + + if (buf[0]) + (void) fprintf(stderr, " %-25.25s", buf); + +#if defined(HASZONES) + (void) fprintf(stderr, + (buf[0]) ? " %s\n" : " %-25.25s", "-z z zone [z]"); +#endif /* defined(HASZONES) */ + + (void) fprintf(stderr, " %s\n", "-- end option scan"); + (void) fprintf(stderr, " %-36.36s", + "+f|-f +filesystem or -file names"); + +#if defined(HASFSTRUCT) + (void) fprintf(stderr, + " +|-f[cfgGn] Ct,Fstr,flaGs,Node %s%s%s%s%s%s%s\n", + 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(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) */ + + (void) snpf(buf, sizeof(buf), "+|-M portMap registration (%s)", + +#if defined(HASPMAPENABLED) + "+" +#else /* !defined(HASPMAPENABLED) */ + "-" +#endif /* defined(HASPMAPENABLED) */ + + ); + (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 [t] repeat every t seconds (%d);", RPTTM); + (void) fprintf(stderr, " + until no files, - forever\n"); + (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(0, NULL, NULL); + } + 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; +#endif /* !defined(HASFSTRUCT) */ + +#if !defined(HASZONES) + if (FieldSel[i].id == LSOF_FID_ZONE) + continue; +#endif /* !defined(HASZONES) */ + + (void) fprintf(stderr, "\t %c %s\n", + FieldSel[i].id, FieldSel[i].nm); + } + } + +#if defined(HASDCACHE) + if (DChelp) + report_HASDCACHE(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, " latest revision: %s\n", LSOF_URL); + (void) fprintf(stderr, " latest FAQ: %sFAQ\n", + LSOF_URL); + (void) fprintf(stderr, " latest man page: %slsof_man\n", + LSOF_URL); + +#if defined(LSOF_CINFO) + if ((cp = isnullstr(LSOF_CINFO))) + (void) fprintf(stderr, " configuration info: %s\n", cp); +#endif /* defined(LSOF_CINFO) */ + + if ((cp = isnullstr(LSOF_CCDATE))) + (void) fprintf(stderr, " constructed: %s\n", cp); + 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); + (void) report_SECURITY(" ", ".\n"); + (void) report_WARNDEVACCESS(" ", "are", ".\n"); + (void) report_HASKERNIDCK(" K", "is"); + (void) report_HASDCACHE(1, " ", "\t"); + } + Exit(xv); +} diff --git a/NEW/version b/NEW/version new file mode 100644 index 0000000..bdfb893 --- /dev/null +++ b/NEW/version @@ -0,0 +1 @@ +.ds VN 4.75 diff --git a/OLD/00PORTING b/OLD/00PORTING new file mode 100644 index 0000000..d84c1f5 --- /dev/null +++ b/OLD/00PORTING @@ -0,0 +1,1884 @@ + + 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/ 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//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 / 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 +/ 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//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. + + +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. + +Unusual situations occur for NetBSD and OpenBSD, and for NEXTSTEP +and OPENSTEP. Each pair of dialects is so close in design that +the same dialect sources from the n+obsd subdirectory serves NetBSD +and OpenBSD; from n+os, NEXTSTEP and OPENSTEP. + +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 + + lsof.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. + + snpf.c Source for the snprintf() family of functions + + USE_LIB_SNPF selects it. + + +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) + + in preference to + + #ifdef + + 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., -- +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 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 lsof.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 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. + + HAS_ATOMIC_T indicates the Linux version has an + header file and it contains + "typedef struct .* atomic_t;" + + HASAOPT indicates the dialect supports the AFS -A + option when HAS_AFS is also defined. + + HAS_ASM_TERMIOBITS indicates for Linux Alpha that the + header file exists. + + HASAX25CBPTR indicates that the Linux sock struct has an + ax25_db pointer. + + HASBLKDEV indicates the dialect has block device support. + + HASBUFQ_H indicates the *NSD dialect has the + header file. + + HASCACHEFS enables cache file system support for the + dialect. + + HAS_CDFS enables CDFS 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 + header file available. + + HASCWDINFO indicates the cwdinfo structure is defined + in the NetBSD . + + 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. + + HASDENTRY indicates the Linux version has a dentry + struct defined in . + + HASDEVKNC indicates the Linux version has a kernel + name cached keyed on device number. + + 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 + 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_FDESCENTTBL indicates the FreeBSD system has the fdescenttbl + structure. + + HAS_FILEDESCENT indicates the FreeBSD system has the filedescent + definition in the header file. + + HASFDESCFS enables file descriptor file system support + for the dialect. A value of 1 indicates + 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_FL_FD indicates the Linux version has an fl_fd + element in the lock structure of . + + HAS_FL_FILE indicates the Linux version has an fl_file + element in the lock structure of . + + HAS_FL_WHENCE indicates the Linux version has an fl_whence + element in the lock structure of . + + 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 lsof.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 + + HASFUSEFS is defined when the FreeBSD system has FUSE file system + support. + + HASGETBOOTFILE indicates the NetBSD or OpenBSD dialect has + a getbootfile() function. + + HASGNODE enables/disables readgnode() in node.c. + + HASHASHPID is defined when the Linux version (probably + above 2.1.35) has a pidhash_next member in + its task structure. + + 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 . + + 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 or + . + + HASINODE enables/disables readinode() in node.c. + + HASINOKNC indicates the Linux version has a kernel + name cache keyed on inode address. + + HASINADDRSTR is defined when the inp_[fl]addr members + of the inpcb structure are structures. + + 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., ). + + HASINT32TYPE is defined when the dialect has a typedef + for int32 that may conflict with some other + header file's redefinition (e.g., ). + + HASINTSIGNAL is defined when signal() returns an int. + + HAS_IPCLASSIFIER_H is defined for Solaris dialects that have the + 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. + + HASKERNELKEYT indicates the Linux version has a + __kernel_key_t typedef in . + + 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 + . + + HASKOPT enables/disables the ability to read the + kernel's name list from a file -- e.g., from + a crash dump file. + + HAS_PAUSE_SBT indicates the FreeBSD system's systm.h has the + pause to pause_sbt definition. + + 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 . + + HASLFILEADD defines additional, dialect-specific elements + SETLFILEADD in the lfile structure (defined in lsof.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 + and 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 header file. + + HAS_LWP_H is defined for BSD dialects that have the + 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 . + + 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. + + HASNETDEVICE_H indicates the Linux version has a netdevice.h + header file. + + HAS_NFS enables NFS support for the dialect. + + HASNFSKNC indicates the LINUX version has a separate + NFS name cache. + + 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_IDEV indicates the FreeBSD system's inode has no i_dev + member. + + HAS_NO_ISO_DEV indicates the FreeBSD 6 and higher system has + no i_dev member in its iso_node structure. + + 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. + + HAS_NO_SI_UDEV indicates the FreeBSD 6 and higher system has + no si_udev member in its cdev structure. + + 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 + header file has the pc_direntpersec() macro. + + HAS_PAD_MUTEX indicates the Solaris 11 system has the pad_mutex_t + typedef in its 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 *) + + HASPRINTOFF this value names a private function for + printing the dialect's file offset. Used + by print.c/print_file(). Takes two arguments: + + char *HASPRINTOFF(struct lfile *, int ty) + + Where ty == 0 if the offset is to be printed + in 0t format; 1, 0x. + + HASPRINTSZ this value names a private function for + printing the dialect's file size. Used + by print.c/print_file(). Takes one argument: + + char *HASPRINTSZ(struct lfile *) + + 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 + . + + 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. + + 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 . + + 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 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 + . + + HASSOUXSOUA indicates that the Solaris 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. + + HASSPECNODE indicates the DEC OSF/1, or Digital UNIX, + or Tru64 UNIX has a spec_node + structure definition. + + HASSNODE indicates the dialect has snode support. + + HAS_SOCKET_SK indicates that the Linux socket structure + has the ``struct sock *sk'' member. + + 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 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 + header file. + + HAS_SYS_SX_H indicates the FreeBSD 7.0 and higher system has + a header file. + + HASTAGTOPATH indicates the DEC OSF/1, Digital UNIX, or + Tru64 UNIX dialect has a libmsfs.so, + containing tag_to_path(). + + HAS_TMPFS indicates the FreeBSD system has the + 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. + + HASUNMINSOCK indicates the Linux version has a user name + element in the socket structure; a value of + 0 says there is no unix_address member; 1, + there is. + + HASUINT16TYPE is defined when the dialect has a typedef + for u_int16 that may conflict with some other + header file's redefinition (e.g., ). + + HASUXSOCKEPT indicates the Linux version has support for the + UNIX socket endpoint option. + + HASUTMPX indicates the dialect has a header + file. + + HAS_UVM_INCL indicates the NetBSD or OpenBSD dialect has + a 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 + . + + HAS_VM_MEMATTR_T indicates the FreeBSD uses the + vm_memattr_t typedef. + + HASVMLOCKH indicates the FreeBSD dialect has . + + 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 exists. + + HASVXFS_MACHDEP_H indicates exists. + + HASVXFS_OFF64_T indicates exists and + has an off64_t typedef. + + HASXVFSRNL indicates the dialect has VxFS Reverse Name + Lookup (RNL) support. + + HASVXFS_SOL_H indicates exists. + + HASVXFS_SOLARIS_H indicates exists. + + HASVXFS_U64_T if HASVXFS_SOLARIS_H is defined, this + variable indicates that + 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 contains + a vx_inode structure. + + HASWCTYPE_H indicates the FreeBSD version has wide-character + support and the 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 . + + 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_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 . + + NEEDS_MACH_PORT_T is defined for Darwin versions that need the inclusion + of the header file . + + NEEDS_NETINET_TCPH is defined when the Linux version needs to #include + in place of 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= + clause in your Makefile. Leave off the ``\"'' even though + you want 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 +and the user structure from -- 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 `.) + + 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/`. + +* 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 | 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 +??? ???, 2016 diff --git a/OLD/Configure b/OLD/Configure new file mode 100755 index 0000000..43d43ec --- /dev/null +++ b/OLD/Configure @@ -0,0 +1,5777 @@ +#!/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, , this script +# requires that the subdirectory ./dialects/ contain a +# shell script, named $LSOF_MK, that places its source modules in this +# directory. +# +# $Id: Configure,v 1.164 2015/07/07 20:16:58 abe Exp abe $ + +# 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 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 + : -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 + (****USE -d TO GET TESTED DIALECT VERSION NUMBERS****): + aix|aixgcc : IBM AIX xlc (aix) or gcc (aixgcc) + darwin : Apple Darwin + decosf : DEC OSF/1 + digital_unix|du : Digital UNIX + freebsd : FreeBSD + hpux|hpuxgcc : HP-UX cc (hpux) or gcc (hpuxgcc) + linux : Linux + netbsd : NetBSD + nextstep|next|ns|nxt : NEXTSTEP + openbsd : OpenBSD + openstep|os : OPENSTEP + 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) + tru64 : Tru64 UNIX + 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 dialects/aix/aix5/j2/j2_snapshot.h + echo "rm -f 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/du/du5_sys_malloc.h + echo "rm -f dialects/du/du5_sys_malloc.h" + rm -f dialects/hpux/kmem/hpux_mount.h + echo "rm -f dialects/hpux/kmem/hpux_mount.h" + rm -rf dialects/n+obsd/include + echo "rm -rf dialects/n+obsd/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 \` 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 dialects/aix/aix5/j2/j2_snapshot.h + (cd 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`/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 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 + # . + + 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 " > ${LSOF_TMPC}.c + echo '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 " > ${LSOF_TMPC}.c + echo "#include " >> ${LSOF_TMPC}.c + echo "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 "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.*) # Next Mac OS X + LSOF_VERS=1300 + ;; + *) + echo Unknown Darwin release: `uname -r` + echo Assuming Darwin 12.0 + LSOF_VERS=1200 + ;; + 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) + LSOF_CFGF="$LSOF_CFGF -DHASIPv6" + LSOF_TMP1="" + ;; + *) + 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" + + if test "X$DARWIN_XNUDIR" != "X" # { + then + LSOF_TMP2="${DARWIN_XNUDIR}/bsd" + LSOF_TMP3="${DARWIN_XNUDIR}/osfmk" + LSOF_TMP4="" + else + LSOF_TMP2="${DARWIN_XNU_HEADERS}/System/Library/Frameworks/Kernel.framework/Versions/A/PrivateHeaders" + LSOF_TMP3="${DARWIN_XNU_HEADERS}/System/Library/Frameworks/System.framework/Versions/B/PrivateHeaders" + LSOF_TMP4="" + if test "X$DARWIN_XNU_HEADERS" != "X" # { + then + LSOF_TMP4="${DARWIN_XNU_HEADERS}/usr/include" + fi # } + fi # } + + # 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="-I${LSOF_INCLUDE}/../local/include" + else + echo "FATAL: can't find libproc.h" + rm -f $LSOF_HLP + exit 1 + fi # } + fi # } + else + + # The default Darwin base is /dev/kmem. + + DARWIN_BASE="/dev/kmem" + 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/libproc + if test $LSOF_VERS -lt 1000 # { + then + LSOF_CFGL="$LSOF_CFGL -lproc" + fi # } + LSOF_TSTKMEM=0 + LSOF_DINC="$LSOF_DINC $LSOF_TMP5" + 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 # } + else + if test "X$DARWIN_BASE" != "X/dev/kmem" # { + then + echo "Darwin base unrecognized: $DARWIN_BASE" + rm -f $LSOF_HLP + exit 1 + fi # } + + # Configure for /dev/kmem-based Darwin lsof. + + echo "Configuring /dev/kmem-based Darwin lsof" + LSOF_CINFO="/dev/kmem-based" + LSOF_DIALECT_DIR=darwin/kmem + + # Make sure needed /dev/kmem-base XNU Darwin kernel header files are + # present. + + LSOF_TMP5="" + for i in $LSOF_TMP1 # { + do + LSOF_TMP6=0 + for j in $LSOF_TMP2 $LSOF_TMP3 $LSOF_TMP4 $LSOF_INCLUDE # { + do + if test "X${j}" != "X" -a -r ${j}/${i} # { + then + LSOF_TMP6=1 + break + fi # } + done # } + if test $LSOF_TMP6 -ne 1 # { + then + if test "X$LSOF_TMP5" = "X" # { + then + LSOF_TMP5=$i + else + LSOF_TMP5="$LSOF_TMP5 $i" + fi # } + fi # } + done # } + if test "X$LSOF_TMP5" != "X" # { + then + + # If any Darwin XNU kernel header files are missing, call the + # get-hdr-loc.sh script to find the path. + + LSOF_TMP6=`pwd`/dialects/darwin/get-hdr-loc.sh + if test ! -x $LSOF_TMP6 # { + then + echo "FATAL: can't execute: $LSOF_TMP6" + rm -f $LSOF_HLP + exit 1 + fi # } + DARWIN_XNUDIR=`$LSOF_TMP6 $LSOF_TMP5` + if test $? -ne 0 # { + then + echo "FATAL: $LSOF_TMP6 returns: $DARWIN_XNUDIR" + rm -f $LSOF_HLP + exit 1 + fi # } + LSOF_TMP2="${DARWIN_XNUDIR}/bsd" + LSOF_TMP3="${DARWIN_XNUDIR}/osfmk" + LSOF_TMP4="" + fi # } + + # Add header file paths for /dev/kmem-based Darwin lsof. + + for i in $LSOF_TMP2 $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 # } + + # Make conditional feature definitions for /dev/kmem-based Darwin lsof. + + for i in $LSOF_TMP2 $LSOF_TMP3 $LSOF_TMP4 $LSOF_INCLUDE # { + do + if test "X${i}" != "X" -a -r ${i}/sys/namei.h # { + then + grep -q nc_vpid ${i}/sys/namei.h + if test $? -eq 0 # { + then + LSOF_CFGF="$LSOF_CFGF -DHASNCVPID" + fi # } + break + fi # } + done # } + for i in $LSOF_TMP2 $LSOF_TMP3 $LSOF_TMP4 $LSOF_INCLUDE # { + do + if test "X${i}" != "X" # { + then + if test $LSOF_VERS -ge 800 # { + then + if test -r ${i}/sys/file_internal.h # { + then + grep -q DTYPE_KQUEUE ${i}/sys/file_internal.h + if test $? -eq 0 # { + then + LSOF_CFGF="$LSOF_CFGF -DHASKQUEUE" + fi # } + break + fi # } + else + if test $LSOF_VERS -ge 700 # { + then + if test -r ${i}/sys/file.h # { + then + grep -q DTYPE_KQUEUE ${i}/sys/file.h + if test $? -eq 0 # { + then + LSOF_CFGF="$LSOF_CFGF -DHASKQUEUE" + fi # } + fi # } + break + fi # } + fi # } + fi # } + done # } + LSOF_CFGF="$LSOF_CFGF -DHAS9660FS" + fi # } + LSOF_CFGF="$LSOF_CFGF -DDARWINV=$LSOF_VERS" + LSOF_CFLAGS_OVERRIDE=1 + ;; + +# Configure for DEC OSF/1, Digital UNIX, or Tru64 UNIX. + + digital_unix|du|decosf|tru64) + LSOF_TGT="du" + LSOF_TSTBIGF=" " + LSOF_TSTK64=1 + if test "X$LSOF_DINC" = "X" # { + then + LSOF_DINC="-I/usr/include" + fi # } + if test "X$LSOF_VSTR" = "X" # { + then + LSOF_VSTR=`uname -r` + fi # } + if test "X$LSOF_VERS" = "X" # { + then + + # If the DEC OSF/1, Digital UNIX, or Tru64 UNIX version isn't + # predefined, determine it. + + case $LSOF_VSTR in # { + V2.0) + LSOF_VERS=20000 + ;; + V3.0) + LSOF_VERS=30000 + ;; + V3.2) + LSOF_VERS=30200 + ;; + ?4.0) + LSOF_TSTXO="../lib/snpf.o" + LSOF_VERS=40000 + ;; + ?5.0) + LSOF_VERS=50000 + ;; + ?5.1) + LSOF_VERS=50100 + ;; + *) + echo "WARNING: unknown version; assuming version is 2.0" + LSOF_VERS=20000 + ;; + esac # } + fi # } + + # Do DEC OSF/1, Digital UNIX, or Tru64 UNIX version specific stuff. + + case $LSOF_VERS in # { + 20000) + LSOF_CFGF="$LSOF_CFGF -Olimit 1024" + LSOF_TMP1="/sys" + ;; + 30000) + LSOF_CFGF="$LSOF_CFGF -Olimit 1024" + LSOF_TMP1="/sys" + LSOF_TMP2=-DUSELOCALREADDIR + ;; + 30200) + LSOF_CFGF="$LSOF_CFGF -Olimit 1024" + LSOF_TMP1="/sys" + LSOF_TMP2=-DUSELOCALREADDIR + ;; + 40000) + LSOF_TMP1="/usr/sys" + ;; + 50000|50100) + LSOF_CFGF="$LSOF_CFGF -DUSE_STAT" + LSOF_TMP1="/usr/sys" + ;; + *) + echo "WARNING: unknown version: $LSOF_VERS" + rm -f $LSOF_HLP + exit 1 + ;; + esac # } + if test "X$DU_SYSDIR" = "X" # { + then + DU_SYSDIR=$LSOF_TMP1 + fi # } + LSOF_HOST=`uname -n` + if test "X$DU_CDIR" = "X" # { + then + LSOF_CDIR=`expr $LSOF_HOST : '\([^\.]*\)\..*$'` + if test "X$LSOF_CDIR" = "X" # { + then + LSOF_CDIR=$LSOF_HOST + fi # } + LSOF_CDIR=`echo $LSOF_CDIR | tr a-z A-Z` + else + LSOF_CDIR=$DU_CDIR + fi # } + LSOF_LOOP=1 + while test $LSOF_LOOP = 1 # { + do + if test -d ${DU_SYSDIR}/$LSOF_CDIR # { + then + echo "Using header files in ${DU_SYSDIR}/$LSOF_CDIR" + LSOF_LOOP=0 + else + cat << .CAT_MARK + +Please enter the name of the subdirectory in $DU_SYSDIR that contains the +configuration files for this host. Usually its name would be $LSOF_CDIR, but +that subdirectory doesn't seem to exist. The lsof compilation needs header +files specific to this machine's configuration found in that directory. + +If you can't specify the appropriate configuration subdirectory, quit this +Configure step now and generate a proper configuration subdirectory with the +kernel generation process. + +.CAT_MARK + + echo "$DU_SYSDIR contains:" + echo "" + ls -CF $DU_SYSDIR + echo "" + echo -n "Configuration subdirectory name? " + read LSOF_CDIR LSOF_EXCESS + if test "X$LSOF_CDIR" = "X" -o ! -d ${DU_SYSDIR}/$LSOF_CDIR # { + then + echo "" + echo Cannot access directory ${DU_SYSDIR}/$LSOF_CDIR. + fi # } + fi # } + done # } + + # Determine the ADVFS file system version. + + if test "X$DU_ADVFSV" = "X" # { + then + echo "Determining the ADVFS version -- this will take a while." + LSOF_ADVFSV=`/usr/sbin/setld -i | grep "^OSFADVFSBIN[0-9]" | sed 's/\([^ ]*\).*/\1/' | sort -u | tail -1 | sed 's/OSFADVFSBIN//'` + else + LSOF_ADVFSV=$DU_ADVFSV + fi # } + case $LSOF_ADVFSV in # { + 1*) + LSOF_ADVFSV=100 + echo "The ADVFS version is 1." + ;; + 2*) + LSOF_ADVFSV=200 + echo "The ADVFS version is 2." + ;; + 3*) + LSOF_ADVFSV=300 + echo "The ADVFS version is 3." + ;; + 4*) + LSOF_ADVFSV=400 + echo "The ADVFS version is 4." + ;; + 5*) + LSOF_ADVFSV=500 + echo "The ADVFS version is 5." + ;; + *) + echo "The ADVFS version is unknown; it will be assumed to be 1." + LSOF_ADVFSV=100 + ;; + esac # } + LSOF_CFGF="$LSOF_CFGF -DDUV=$LSOF_VERS -DADVFSV=$LSOF_ADVFSV $LSOF_TMP2" + if test "X$DU_SYSINC" = "X" # { + then + DU_SYSINC="/usr/sys/include" + fi # } + LSOF_DINC="$LSOF_DINC -I${DU_SYSDIR}/$LSOF_CDIR -I$DU_SYSINC" + LSOF_CFGL="$LSOF_CFGL -lmld" + if test "X${DU_SHLIB}" = "X" # { + then + DU_SHLIB=/usr/shlib + fi # } + if test -r ${DU_SHLIB}/libmsfs.so # { + then + nm ${DU_SHLIB}/libmsfs.so | grep tag_to_path > /dev/null 2>&1 + if test $? -eq 0 # { + then + LSOF_CFGF="$LSOF_CFGF -DHASTAGTOPATH" + LSOF_CFGL="$LSOF_CFGL -lmsfs" + fi # } + fi # } + grep "^struct spec_node {" ${DU_SYSDIR}/include/sys/specdev.h > /dev/null 2>&1 + if test $? -eq 0 # { + then + LSOF_CFGF="$LSOF_CFGF -DHASSPECNODE" + fi # } + if test $LSOF_VERS -ge 50000 # { + then + + # Make du5_sys_malloc.h for DU 5.0 and above. Enable strict ANSI checking + # on 5.0 and 5.1A, but not 5.1B. Enable IPv6 handling. + + LSOF_TMP1="-std1" + if test $LSOF_VERS -ge 50100 # { + then + LSOF_TMP1="-std" + if test -x /usr/sbin/sizer # { + then + /usr/sbin/sizer -v | grep -q 5.1A + if test $? -eq 0 # { + then + LSOF_TMP1="-std1" + fi # } + fi # } + fi # } + LSOF_CFGF="$LSOF_CFGF $LSOF_TMP1" + LSOF_TMP1=${LSOF_INCLUDE}/sys/malloc.h + if test -r $LSOF_TMP1 # { + then + LSOF_TMP2=dialects/du/du5_sys_malloc.h + rm -f $LSOF_TMP2 + echo "#if !defined(MANUFACTURED_DU5_SYS_MALLOC_H)" > $LSOF_TMP2 + echo "/* By lsof Configure:" `date` " */" >> $LSOF_TMP2 + echo "#define MANUFACTURED_DU5_SYS_MALLOC_H" >> $LSOF_TMP2 + grep "^#define[ ]MALLOC_NUM_BUCKETS" $LSOF_TMP1 >> $LSOF_TMP2 + echo "struct percpukmembuckets {" >> $LSOF_TMP2 + sed '1,/^struct percpukmembuckets/d' $LSOF_TMP1 | sed -n '1,/^};/p' >> $LSOF_TMP2 + echo "#endif" >> $LSOF_TMP2 + LSOF_CFGF="$LSOF_CFGF -I`pwd`/dialects/du" + fi # } + + # Enable IPv6 for Tru64 UNIX 5.0 and above. + + LSOF_CFGF="$LSOF_CFGF -DHASIPv6" + 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 # } + LSOF_DIALECT_DIR=du + ;; + +# Configure for FreeBSD. + + freebsd) + LSOF_FBSD_ZFS=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 # { + 1.*) + LSOF_VERS=1000 + ;; + 2.0-*) + LSOF_VERS=2000 + ;; + 2.0.5-*) + LSOF_VERS=2005 + ;; + 2.1*) + LSOF_VERS=2010 + ;; + 2.2*) + LSOF_VERS=2020 + ;; + 3.0*) + LSOF_VERS=3000 + ;; + 3.1*) + LSOF_VERS=3010 + ;; + 3.2*) + LSOF_VERS=3020 + ;; + 3.3*) + LSOF_VERS=3030 + ;; + 3.4*) + LSOF_VERS=3040 + ;; + 3.5*) + LSOF_VERS=3050 + ;; + 3*) + LSOF_VERS=3050 + echo "!!!WARNING!!! Unsupported FreeBSD version: $LSOF_VSTR" + echo "!!!WARNING!!! Configuring for FreeBSD 3.5" + ;; + 4.0*) + LSOF_TSTBIGF=" " + LSOF_VERS=4000 + ;; + 4.1-*) + LSOF_TSTBIGF=" " + LSOF_VERS=4010 + ;; + 4.2*) + LSOF_TSTBIGF=" " + LSOF_VERS=4020 + ;; + 4.3*) + LSOF_TSTBIGF=" " + LSOF_VERS=4030 + ;; + 4.4*) + LSOF_TSTBIGF=" " + LSOF_VERS=4040 + ;; + 4.5*) + LSOF_TSTBIGF=" " + LSOF_VERS=4050 + ;; + 4.6*) + LSOF_TSTBIGF=" " + LSOF_VERS=4060 + ;; + 4.7*) + LSOF_TSTBIGF=" " + LSOF_VERS=4070 + ;; + 4.8*) + LSOF_TSTBIGF=" " + LSOF_VERS=4080 + ;; + 4.9*) + LSOF_TSTBIGF=" " + LSOF_VERS=4090 + ;; + 4.10*) + LSOF_TSTBIGF=" " + LSOF_VERS=4100 + ;; + 4.11*) + LSOF_TSTBIGF=" " + LSOF_VERS=4110 + ;; + 4*) + LSOF_VERS=4100 + echo "!!!WARNING!!! Unsupported FreeBSD version: $LSOF_VSTR" + echo "!!!WARNING!!! Configuring for FreeBSD 4.10" + ;; + 5.0*) + LSOF_TSTBIGF=" " + LSOF_VERS=5000 + ;; + 5.1*) + LSOF_TSTBIGF=" " + LSOF_VERS=5010 + ;; + 5.2*) + LSOF_TSTBIGF=" " + LSOF_VERS=5020 + ;; + 5.3*) + LSOF_TSTBIGF=" " + LSOF_VERS=5030 + ;; + 5.4*) + LSOF_TSTBIGF=" " + LSOF_VERS=5040 + ;; + 5.5*) + LSOF_TSTBIGF=" " + LSOF_VERS=5050 + ;; + 5*) + LSOF_VERS=5050 + echo "!!!WARNING!!! Unsupported FreeBSD version: $LSOF_VSTR" + echo "!!!WARNING!!! Configuring for FreeBSD 5.5" + ;; + 6.0*) + LSOF_TSTBIGF=" " + LSOF_VERS=6000 + ;; + 6.1*) + LSOF_TSTBIGF=" " + LSOF_VERS=6010 + ;; + 6.2*) + LSOF_TSTBIGF=" " + LSOF_VERS=6020 + ;; + 6.3*) + LSOF_TSTBIGF=" " + LSOF_VERS=6030 + ;; + 6.4*) + LSOF_TSTBIGF=" " + LSOF_VERS=6040 + ;; + 6*) + LSOF_VERS=6000 + echo "!!!WARNING!!! Unsupported FreeBSD version: $LSOF_VSTR" + echo "!!!WARNING!!! Configuring for FreeBSD 6.0" + ;; + 7.0*) + LSOF_TSTBIGF=" " + LSOF_VERS=7000 + ;; + 7.1*) + LSOF_TSTBIGF=" " + LSOF_VERS=7010 + ;; + 7.2*) + LSOF_TSTBIGF=" " + LSOF_VERS=7020 + ;; + 7.3*) + LSOF_TSTBIGF=" " + LSOF_VERS=7030 + ;; + 7.4*) + LSOF_TSTBIGF=" " + LSOF_VERS=7040 + ;; + 7*) + LSOF_VERS=7000 + echo "!!!WARNING!!! Unsupported FreeBSD version: $LSOF_VSTR" + echo "!!!WARNING!!! Configuring for FreeBSD 7.0" + ;; + 8.0*) + LSOF_TSTBIGF=" " + LSOF_VERS=8000 + ;; + 8.1*) + LSOF_TSTBIGF=" " + LSOF_VERS=8010 + ;; + 8.2*) + LSOF_TSTBIGF=" " + LSOF_VERS=8020 + ;; + 8.3*) + LSOF_TSTBIGF=" " + LSOF_VERS=8030 + ;; + 8.4*) + LSOF_TSTBIGF=" " + LSOF_VERS=8040 + ;; + 9*) + LSOF_TSTBIGF=" " + LSOF_VERS=9000 + ;; + 10*) + LSOF_TSTBIGF=" " + LSOF_VERS=10000 + ;; + 11*) + LSOF_TSTBIGF=" " + LSOF_VERS=11000 + ;; + 12*) + LSOF_TSTBIGF=" " + LSOF_VERS=12000 + ;; + *) + 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 # { + 4090|8020|8030|8040|9000|10000|11000|12000) + LSOF_UNSUP="" + ;; + esac # } + + # Get system CFLAGS, if possible. + + LSOF_TMP1=`echo "all:\n.include " | $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" + 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 # } + + # Test pause() status in system.h. + + if test -r ${FREEBSD_SYS}/sys/systm.h # { + then + grep -q pause_sbt ${FREEBSD_SYS}/sys/systm.h + if test $? -eq 0 # { + then + LSOF_CFGF="$LSOF_CFGF -DHAS_PAUSE_SBT" + fi # } + fi # } + + # Check the C library for closefrom and dup2. + + if test -r /usr/lib/libc.a # { + then + nm /usr/lib/libc.a | grep -q "W dup2" + if test $? -eq 0 # { + then + LSOF_CFGF="$LSOF_CFGF -DHAS_DUP2" + fi # } + nm /usr/lib/libc.a | grep -q "W closefrom" + if test $? -eq 0 # { + then + LSOF_CFGF="$LSOF_CFGF -DHAS_CLOSEFROM" + fi # } + fi # } + + # Do FreeBSD version-specific stuff. + + case $LSOF_VERS in # { + 1000) + LSOF_CFGF="$LSOF_CFGF -DHASPROCFS" + 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 +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 # } + grep -q i_dev ${LSOF_INCLUDE}/ufs/ufs/inode.h + if test $? -ne 0 # { + then + LSOF_CFGF="$LSOF_CFGF -DHAS_NO_IDEV" + 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 "^#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_udev;" ${LSOF_INCLUDE}/sys/conf.h + if test $? -ne 0 # { + then + LSOF_CFGF="$LSOF_CFGF -DHAS_NO_SI_UDEV" + 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 FUSE file system test, + + if test -r ${FREEBSD_SYS}/fs/fuse/fuse_node.h # { + then + LSOF_CFGF="$LSOF_CFGF -DHASFUSEFS" + 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 # } + if test -r ${LSOF_INCLUDE}/sys/filedesc.h # { + then + grep -q '^struct fdescenttbl {' ${LSOF_INCLUDE}/sys/filedesc.h + if test $? -eq 0 # { + then + LSOF_CFGF="$LSOF_CFGF -DHAS_FDESCENTTBL" + 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 # } + if test $LSOF_VERS -lt 5000 # { + then + if test -d ${FREEBSD_SYS}/${LSOF_TMP1}/procfs # { + then + LSOF_CFGF="$LSOF_CFGF -DHASPROCFS" + LSOF_DINC_ADD=1 + fi # } + else + if test -d ${FREEBSD_SYS}/${LSOF_TMP1}/pseudofs # { + then + LSOF_CFGF="$LSOF_CFGF -DHASPSEUDOFS" + LSOF_DINC_ADD=1 + fi # } + 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 + rm -f cd9660_node.h + grep -q "^#ifdef [_]*KERNEL" ${FREEBSD_SYS}/isofs/cd9660/cd9660_node.h + if test $? -eq 0 # { + then + ln -s ${FREEBSD_SYS}/isofs/cd9660/cd9660_node.h cd9660_node.h + else + sed -e '/^ \* Prototypes for ISOFS vnode operations/,$c\ + \ The ISOFS prototypes were removed by Configure. */' \ + < ${FREEBSD_SYS}/isofs/cd9660/cd9660_node.h > cd9660_node.h + echo "" >> cd9660_node.h + fi # } + LSOF_CFGF="$LSOF_CFGF -DHAS9660FS" + if test $LSOF_VERS -ge 6000 # { + then + grep -q "i_dev;" cd9660_node.h + if test $? -ne 0 # { + then + LSOF_CFGF="$LSOF_CFGF -DHAS_NO_ISO_DEV" + fi # } + fi # } + 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 # } + 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 "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 "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=; 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 +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 . + + if ! test -r ${LSOF_INCLUDE}/rpc/rpc.h # { + then + 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 # } + 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" + ;; + *) + echo "Unknown NetBSD release: $LSOF_VSTR" + echo Assuming NetBSD 1.6 + LSOF_VERS="1006000" + ;; + esac # } + fi # } + + # Test for legal NetBSD version. + + case $LSOF_VERS in # { + 1002000|1003000|1004000|1005000|1006000) + ;; + 2000000|2099009|2099010) + ;; + 3000000|3099000) + ;; + *) + echo "Unknown NetBSD version: $LSOF_VERS" + rm -f $LSOF_HLP + exit 1 + ;; + esac # } + LSOF_CFGF="$LSOF_CFGF -DNETBSDV=$LSOF_VERS" + LSOF_TMP1="-DN_UNIXV=/netbsd" + if 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 + 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 # } + if test "X$NETBSD_UVM" = "X" # { + then + grep -q UVM $LSOF_TMP3 + if test $? -ne 0 # { + then + egrep -q "v_uvm;|v_uobj;" $LSOF_TMP3 + if test $? -eq 0 # { + then + NETBSD_UVM="Y" + fi # } + 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 dialects/n+obsd/include + if test "X$NETBSD_UVM" = "XY" -o "X$NETBSD_UVM" = "Xy" # { + then + mkdir dialects/n+obsd/include + touch dialects/n+obsd/include/opt_uvmhist.h + touch dialects/n+obsd/include/opt_lockdebug.h + LSOF_CFGF="$LSOF_CFGF -DUVM -I`pwd`/dialects/n+obsd/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 + # . 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=dialects/n+obsd/include/netexport.h + if test ! -d dialects/n+obsd/include # { + then + mkdir dialects/n+obsd/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 " >> $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 /dialects/n+obsd/include > /dev/null 2>&1 + if test $? -ne 0 # { + then + LSOF_CFGF="$LSOF_CFGF -I`pwd`/dialects/n+obsd/include" + fi # } + fi # } + if test $LSOF_NBSD_BUFQH -eq 1 # { + then + + # Make a local copy of $NETBSD_SYS/sys/bufq.h. + + if test ! -d dialects/n+obsd/include # { + then + mkdir dialects/n+obsd/include + fi # } + if test ! -d dialects/n+obsd/include/sys # { + then + mkdir dialects/n+obsd/include/sys + fi # } + cp $NETBSD_SYS/sys/bufq.h dialects/n+obsd/include/sys + echo $LSOF_CFGF | grep /dialects/n+obsd/include > /dev/null 2>&1 + if test $? -ne 0 # { + then + LSOF_CFGF="$LSOF_CFGF -I`pwd`/dialects/n+obsd/include" + fi # } + fi # } + if test $LSOF_NBSD_PTYFS -eq 1 # { + then + + # Make a local copy of $NETBSD_SYS/sys/fs/ptyfs/. + + if test ! -d dialects/n+obsd/include # { + then + mkdir dialects/n+obsd/include + fi # } + if test ! -d dialects/n+obsd/include/fs # { + then + mkdir dialects/n+obsd/include/fs + fi # } + rm -rf dialects/n+obsd/include/fs/ptyfs + mkdir dialects/n+obsd/include/fs/ptyfs + cp $NETBSD_SYS/fs/ptyfs/*.h dialects/n+obsd/include/fs/ptyfs + echo $LSOF_CFGF | grep /dialects/n+obsd/include > /dev/null 2>&1 + if test $? -ne 0 # { + then + LSOF_CFGF="$LSOF_CFGF -I`pwd`/dialects/n+obsd/include" + fi # } + fi # } + LSOF_CFGL="$LSOF_CFGL -lkvm" + LSOF_DIALECT_DIR=n+obsd + ;; + +# Configure for NeXTSTEP or OPENSTEP. + + nextstep|next|ns|nxt|openstep|os) + LSOF_TGT="ns" + LSOF_TSTXO="../lib/snpf.o" + if test "X$LSOF_AR" = "X" # { + then + LSOF_AR="rm -f \${LIB}; ar cr" + fi # } + if test "X$LSOF_VSTR" = "X" # { + then + LSOF_VSTR=`hostinfo | sed -n 's/.*NeXT Mach \([0-9\.]*\).*/\1/p'` + fi # } + if test "X$LSOF_VERS" = "X" # { + then + + # If the NeXSTEP version isn't predefined, determine it. + + LSOF_VERS=`echo $LSOF_VSTR | sed -n 's/\([0-9]*\)\.\([0-9]*\)/\1\2/p'` + fi # } + if test "X$LSOF_CC" = "X" # { + then + if test -x /usr/local/bin/gcc # { + then + LSOF_CC=/usr/local/bin/gcc + LSOF_CCV=`$LSOF_CC -v 2>&1 | sed -n 's/.*version \(.*\)/\1/p'` + else + LSOF_CC=cc + LSOF_CCV=`$LSOF_CC -v 2>&1 | sed -n 's/.*version \(.*\)/\1/p'` + fi # } + fi # } + echo $LSOF_CC | grep gcc > /dev/null + if test $? -eq 0 # { + then + LSOF_CFGL="$LSOF_CFGL -w" + LSOF_DEBUG="-pedantic -O" + fi # } + LSOF_CFGF="$LSOF_CFGF -DSTEPV=$LSOF_VERS" + LSOF_DIALECT_DIR=n+os + + # 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 # } + ;; + +# Configure for OpenBSD. (OpenBSD uses NetBSD dialect sources and version +# numbering. + + openbsd) + 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" + ;; + *) + 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) + ;; + *) + echo "Unknown OpenBSD version: $LSOF_VERS" + rm -f $LSOF_HLP + exit 1 + ;; + esac # } + LSOF_CFGF="$LSOF_CFGF -DOPENBSDV=$LSOF_VERS" + if test -r /dev/ksyms # { + then + LSOF_CFGF="$LSOF_CFGF -DN_UNIXV=/dev/ksyms" + else + LSOF_CFGF="$LSOF_CFGF -DN_UNIXV=/bsd" + fi + if test -r ${LSOF_INCLUDE}/nfs/nfsproto.h # { + then + LSOF_CFGF="$LSOF_CFGF -DHASNFSPROTO" + fi # } + if test -r ${LSOF_INCLUDE}/netinet6/in6.h # { + then + LSOF_CFGF="$LSOF_CFGF -DHASIPv6" + fi # } + LSOF_TMP1=0 + if test "X$OPENBSD_SYS" = "X" # { + then + OPENBSD_SYS="/sys" + fi # } + if test -r ${OPENBSD_SYS}/miscfs/fdesc/fdesc.h # { + then + grep -q Fctty ${OPENBSD_SYS}/miscfs/fdesc/fdesc.h + if test $? -eq 0 # { + then + LSOF_CFGF="$LSOF_CFGF -DHASFDESCFS=1" + else + LSOF_CFGF="$LSOF_CFGF -DHASFDESCFS=2" + fi # } + grep -q fd_link ${OPENBSD_SYS}/miscfs/fdesc/fdesc.h + if test $? -eq 0 # { + then + LSOF_CFGF="$LSOF_CFGF -DHASFDLINK" + fi # } + LSOF_TMP1=1 + fi # } + if test -r ${LSOF_INCLUDE}/sys/vnode.h # { + then + grep -q VT_LFS ${LSOF_INCLUDE}/sys/vnode.h + if test $? -eq 0 # { + then + LSOF_CFGF="$LSOF_CFGF -DHASLFS" + fi # } + fi # } + if test -r ${LSOF_INCLUDE}/miscfs/nullfs/null.h # { + then + LSOF_CFGF="$LSOF_CFGF -DHASNULLFS" + else + if test -r ${OPENBSD_SYS}/miscfs/nullfs/null.h # { + then + LSOF_CFGF="$LSOF_CFGF -DHASNULLFS" + LSOF_TMP1=1 + fi # } + fi # } + if test -d ${OPENBSD_SYS}/miscfs/procfs # { + then + LSOF_CFGF="$LSOF_CFGF -DHASPROCFS" + LSOF_TMP1=1 + fi # } + if test -d ${OPENBSD_SYS}/isofs/cd9660 # { + then + LSOF_CFGF="$LSOF_CFGF -DHAS9660FS=1" + LSOF_TMP1=1 + else + if test -d ${OPENBSD_SYS}/fs/cd9660 # { + then + LSOF_CFGF="$LSOF_CFGF -DHAS9660FS=2" + LSOF_TMP1=1 + fi # } + fi # } + if test -d ${OPENBSD_SYS}/msdosfs # { + then + LSOF_CFGF="$LSOF_CFGF -DHASMSDOSFS=1" + LSOF_TMP1=1 + else + if test -d ${OPENBSD_SYS}/fs/msdosfs # { + then + LSOF_CFGF="$LSOF_CFGF -DHASMSDOSFS=2" + LSOF_TMP1=1 + fi # } + fi # } + if test -r ${OPENBSD_SYS}/miscfs/kernfs/kernfs.h # { + then + grep -q "kt_name;" ${OPENBSD_SYS}/miscfs/kernfs/kernfs.h + if test $? -eq 0 # { + then + LSOF_CFGF="$LSOF_CFGF -DHASKERNFS" + LSOF_TMP1=1 + fi # } + fi # } + if test $LSOF_TMP1 -eq 1 -a "X$LSOF_INCLUDE" != "X$OPENBSD_SYS" # { + then + LSOF_DINC="-I$LSOF_INCLUDE -I$OPENBSD_SYS" + fi # } + grep -q VT_EXT2FS ${LSOF_INCLUDE}/sys/vnode.h + if test $? -eq 0 # { + then + LSOF_TMP1=1 + if test -r ${LSOF_INCLUDE}/ufs/ufs/inode.h # { + then + grep -q "*e2fs_din" ${LSOF_INCLUDE}/ufs/ufs/inode.h + if test $? -eq 0 # { + then + LSOF_CFGF="$LSOF_CFGF -DHASI_E2FS_PTR" + fi # } + grep -q "^#define[ ]i_e2din" ${LSOF_INCLUDE}/ufs/ufs/inode.h + if test $? -eq 0 # { + then + LSOF_TMP1=2 + fi # } + fi # } + LSOF_CFGF="$LSOF_CFGF -DHASEXT2FS=$LSOF_TMP1" + 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 # } + grep -q dinode_u ${LSOF_INCLUDE}/ufs/ufs/inode.h + if test $? -eq 0 # { + then + LSOF_CFGF="$LSOF_CFGF -DHAS_DINODE_U" + fi # } + grep -q i_ffs1_size ${LSOF_INCLUDE}/ufs/ufs/inode.h + if test $? -eq 0 # { + then + LSOF_CFGF="$LSOF_CFGF -DHASI_FFS1" + fi # } + grep -q UM_UFS ${LSOF_INCLUDE}/ufs/ufs/inode.h + if test $? -eq 0 # { + then + LSOF_CFGF="$LSOF_CFGF -DHAS_UM_UFS" + fi # } + 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 "X$OPENBSD_UVM" = "X" # { + then + if test -r ${LSOF_INCLUDE}/sys/vnode.h # { + then + grep -q UVM ${LSOF_INCLUDE}/sys/vnode.h + if test $? -ne 0 # { + then + egrep -q "v_uvm;|v_uobj;" ${LSOF_INCLUDE}/sys/vnode.h + if test $? -eq 0 # { + then + OPENBSD_UVM="Y" + fi # } + fi # } + fi # } + fi # } + if test "X$OPENBSD_UVM" = "XY" -o "X$OPENBSD_UVM" = "Xy" # { + then + LSOF_CFGF="$LSOF_CFGF -DUVM" + if test -d ${LSOF_INCLUDE}/uvm # { + then + LSOF_CFGF="$LSOF_CFGF -DHAS_UVM_INCL" + fi # } + fi # } + if test -r ${LSOF_INCLUDE}/sys/mount.h -a $LSOF_VERS -lt 3030 # { + then + + # Build a local OpenBSD netexport.h header file for possible use by + # . 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=dialects/n+obsd/include/netexport.h + if test ! -d dialects/n+obsd/include # { + then + mkdir dialects/n+obsd/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 " >> $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 /dialects/n+obsd/include > /dev/null 2>&1 + if test $? -ne 0 # { + then + LSOF_CFGF="$LSOF_CFGF -I`pwd`/dialects/n+obsd/include" + fi # } + fi # } + if test -r ${LSOF_INCLUDE}/sys/lockf.h # { + then + grep vop_advlock_args ${LSOF_INCLUDE}/sys/lockf.h > /dev/null + if test $? -eq 0 # { + then + LSOF_CFGF="$LSOF_CFGF -DHAS_ADVLOCK_ARGS" + fi # } + fi # } + if test -r ${LSOF_INCLUDE}/sys/pipe.h # { + then + LSOF_CFGF="$LSOF_CFGF -DHAS_SYS_PIPEH" + fi # } + LSOF_CFGL="$LSOF_CFGL -lkvm" + LSOF_DIALECT_DIR=n+obsd + ;; + +# 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 " 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 " >> ${LSOF_TMPC}.c + echo "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 " >> ${LSOF_TMPC}.c + echo "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 "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 "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 "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 '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 . + + if test -r ${LSOF_INCLUDE}/sys/fs/cachefs_fs.h # { + then + LSOF_CFGF="$LSOF_CFGF -DHASCACHEFS" + fi # } + + # Test for + + 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 " > ${LSOF_TMPC}.c + echo "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 ./dialects/$LSOF_DIALECT_DIR # { +then + echo "Can't configure for $LSOF_TGT -- ./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 ./dialects/$LSOF_DIALECT_DIR/$LSOF_MK # { +then + echo "Can't configure for $LSOF_TGT -- ./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 ./dialects/$LSOF_DIALECT_DIR/$LSOF_REST # { +then + echo "Can't configure for $LSOF_TGT -- ./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 +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 ./dialects/$LSOF_DIALECT_DIR/$LSOF_MK $LSOF_TGT $LSOF_VERS + +# 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="-O" +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 # } +rm -f ${LSOF_LIB}/$LSOF_LIBMKF +if test "X$LSOF_LIB_NO" = "X" # { +then + cp $LSOF_MKFC ${LSOF_LIB}/$LSOF_LIBMKF +fi # } +cat ./dialects/$LSOF_DIALECT_DIR/$LSOF_REST >> $LSOF_MKFC +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 + 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/OLD/HOSTCC_00DIST b/OLD/HOSTCC_00DIST new file mode 100644 index 0000000..8171790 --- /dev/null +++ b/OLD/HOSTCC_00DIST @@ -0,0 +1,5 @@ +This patch adds support for cross-compilation by adding the notion of an +LSOF_HOSTCC and by auto-detecting the C library and Linux kernel version +from project-local sources and opposed to those from the build machine. + +Grant Erickson [erick205@umn.edu] diff --git a/OLD/HOSTCC_patch b/OLD/HOSTCC_patch new file mode 100644 index 0000000..4444418 --- /dev/null +++ b/OLD/HOSTCC_patch @@ -0,0 +1,69 @@ +diff -aruN a/lsof_4.84_src/Configure b/lsof_4.84_src/Configure +--- a/lsof_4.84_src/Configure 2010-07-29 08:59:32.000000000 -0700 ++++ b/lsof_4.84_src/Configure 2010-09-08 12:30:24.000000000 -0700 +@@ -96,6 +96,7 @@ + # $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_HOSTCC Host C compiler name (may be supplied externally) + # $LSOF_INCLUDE directory where header files are found + # (default = /usr/include) + # $LSOF_LD loader name if not $LSOF_CC +@@ -174,7 +175,6 @@ + fi # } + LSOF_LD="" + LSOF_LIB_NO="" +-LSOF_LINUX_INCL="" + LSOF_PL="" + if test "X$LSOF_RANLIB" = "X" # { + then +@@ -2653,12 +2653,30 @@ + linux) + LSOF_TSTBIGF="-D_FILE_OFFSET_BITS=64" + LSOF_TSTKMEM=0 ++ if test "X$LSOF_HOSTCC" = "X" # { ++ then ++ LSOF_HOSTCC=cc ++ fi # } + if test "X$LSOF_CC" = "X" # { + then + LSOF_CC=cc + LSOF_CCV=`$LSOF_CC -v 2>&1 | sed -n 's/.*version \(.*\)/\1/p'` + fi # } + LSOF_DIALECT_DIR="" ++ if test "X$LSOF_LINUX_INCL" = "X" # { ++ then ++ LSOF_LINUX_INCL=/usr/include ++ else ++ LSOF_DINC="$LSOF_DINC -I${LSOF_LINUX_INCL}" ++ fi # } ++ if test "X$LINUX_VERSION_CODE" = "X" # { ++ then ++ if test -r "$LSOF_LINUX_INCL/linux/version.h" # { ++ then ++ LINUX_VERSION_CODE=`cat $LSOF_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=; 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` +@@ -2690,7 +2708,7 @@ + + if test "X$LINUX_CLIB" = "X" # { + then +- echo -n "Testing C library type with $LSOF_CC ... " ++ echo -n "Testing C library type with $LSOF_HOSTCC ... " + rm -f ${LSOF_TMPC}.* + cat > $LSOF_TMPC.c << .LSOF_END_HERE_DOC1 + #include +@@ -2704,7 +2722,7 @@ + #endif + return(0); } + .LSOF_END_HERE_DOC1 +- $LSOF_CC ${LSOF_TMPC}.c -I$LSOF_INCLUDE -o ${LSOF_TMPC}.x > /dev/null 2>&1 ++ $LSOF_HOSTCC ${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` + diff --git a/OLD/Lsof.8 b/OLD/Lsof.8 new file mode 100644 index 0000000..3b68f3e --- /dev/null +++ b/OLD/Lsof.8 @@ -0,0 +1,4512 @@ +.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 \-?abChlnNOPRtUvVX +] [ +.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]]" +] [ +.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]]" +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. +.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 and Linux UNIX socket files should be displayed with +endpoint information and the files of the endpoints should also be +displayed. +Note: UNIX socket file endpoint information is available only when the +compile flags line of +.B \-v +output contains HASUXSOCKEPT. +.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 +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 +compile flags line of +.B \-v +output contains HASUXSOCKEPT. +.IP +Multiple occurrences of this information can appear in a file's +NAME column. +.IP +.B -E +specfies that Linux pipe and Linux UNIX socket 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) + \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 +.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 +.br or \fBUDPLITE\fP. +.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\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 +.BI +|\-r " [t[m]]" +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. +.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" argument specifies a format for the marker line. +The 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, cannot contain the NL format, ``%n''. +Note also that when contains spaces or other characters that +affect the shell's interpretation of arguments, 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 + + QR= + QS= + SO= + SS= + TF= + WR= + WW= +.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 , and . +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.) +.TP \w'names'u+4 +.B \-t +specifies that +.I lsof +should produce terse output with process identifiers only and no header \- +e.g., so that the output may be piped to +.IR kill (1). +.B \-t +selects 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 selects 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 + \fBerr\fR FD information error (see NAME column); +.br + \fBjld\fR jail directory (FreeBSD); +.br + \fBltx\fP shared library text (code and data); +.br + \fBMxx\fP 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 + \fBpd\fP parent directory; +.br + \fBrtd\fP root directory; +.br + \fBtr\fR kernel trace file (OpenBSD); +.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. +.TP +TYPE +is the type of the node associated with the file \- e.g., GDIR, GREG, +VDIR, VREG, etc. +.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 ``ax25'' for a Linux AX.25 socket; +.IP +or ``inet'' for an Internet domain socket; +.IP +or ``lla'' for a HP\-UX link level access file; +.IP +or ``rte'' for an AF_ROUTE socket; +.IP +or ``sock'' for a socket of unknown domain; +.IP +or ``unix'' for a UNIX domain socket; +.IP +or ``x.25'' for an HP\-UX x.25 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 ``FIFO'' for a FIFO special file; +.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 ``NOFD'' for a Linux /proc//fd directory that can't be opened \-- +the directory path appears in the NAME column, followed by an error +message; +.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 ``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 ``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 ``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 ``SMT'' for a shared memory transport file; +.IP +or ``STSO'' for a stream socket; +.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 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 + 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 + 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 +, , , , and ; +see the lsof.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 +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='' and ``wr='' 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 :[:], 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:)'' to the NAME column. + and are hexadecimal vnode addresses. + will be ``<-'' if has been fattach'ed to +this vnode whose address is ; +and ``->'' if , the vnode address of this vnode, has been +fattach'ed to . + 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. +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 +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) + f file descriptor (always selected) + F file structure address (0x) + G file flaGs (0x; 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 + M the task comMand name + n file name, comment, Internet address + N node identifier (ox + o file's offset (decimal) + p process ID (always selected) + P protocol name + r raw device number (0x) + 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= + QS= + SO= (not all dialects) + SS= (not all dialects) + ST= + TF= (not all dialects) + WR= (not all dialects) + WW= (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 + NEXTSTEP + OpenBSD + OPENSTEP + SCO OpenServer + SCO|Caldera UnixWare + Solaris + Tru64 UNIX +.fi +.PP +.I Lsof +can't report path name components for these dialects: +.PP +.nf + AIX +.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 + NEXTSTEP 3.[13] for NEXTSTEP architectures + OpenBSD 2.[89] and 3.[0\-9] for x86-based systems + OPENSTEP 4.x + 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. +.PP +It returns a zero (0) if no errors were detected and if 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 +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, use: +.IP +lsof /u/abe/foo +.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 [cfgGn] +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 file is also available via anonymous ftp from +.I lsof.itap.purdue.edu +at +.IR pub/tools/unix/lsof FAQ . +The URL is: +.IP +ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/FAQ +.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 of Purdue University. +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 via anonymous ftp from the host +.IR lsof.itap.purdue.edu . +You'll find the +.I lsof +distribution in the +.I pub/tools/unix/lsof +directory. +.PP +You can also use this URL: +.IP +ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof +.PP +.I Lsof +is also mirrored elsewhere. +When you access +.I lsof.itap.purdue.edu +and change to its +.I pub/tools/unix/lsof +directory, you'll be given a list of some mirror sites. +The +.I pub/tools/unix/lsof +directory also contains a more complete list in its +.I mirrors +file. +Use mirrors with caution \- not all mirrors always have the latest +.I lsof +revision. +.PP +Some pre\-compiled +.I Lsof +executables are available on +.IR lsof.itap.purdue.edu , +but their use is discouraged \- it's better that you build +your own from the sources. +If you feel you must use a pre\-compiled executable, please +read the cautions that appear in the README files of the +.I pub/tools/unix/lsof/binaries +subdirectories and in the 00* files of the distribution. +.PP +More information on the +.I lsof +distribution can be found in its +.I README.lsof_ +file. +If you intend to get the +.I lsof +distribution and build it, please read +.I README.lsof_ +and the other 00* files of the distribution before sending questions +to the author. +.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), +perl(1), +ps(1), +readlink(2), +setlocale(3), +stat(2), +strftime(3), +time(2), +uname(1). diff --git a/OLD/comprev b/OLD/comprev new file mode 100755 index 0000000..b25ab71 --- /dev/null +++ b/OLD/comprev @@ -0,0 +1,11 @@ +#!/bin/sh +# +# comprev -- compare revisions + +n=1 +while test 1 -eq 1 +do + np=`expr $n + 1` + rcsdiff -r1.$n -r1.$np Configure | grep make.conf + n=`expr $n + 1` +done diff --git a/OLD/leak b/OLD/leak new file mode 100755 index 0000000..fd75602 --- /dev/null +++ b/OLD/leak @@ -0,0 +1,51 @@ +#!/usr/local/bin/perl + +# leak < + +while (<>) { + if (!/^MEM[afr]/) { next; } + chop; + if (/^MEMa ([^ ]*) (.*)/) { + $new = $1; $loc = $2; + if (defined($mem{$new})) { + print "ERROR: $new already allocated;\n"; + print " OLD: $mem{$new}\n"; + print " NEW: $_\n"; + } else {$mem{$new} = $loc; } + next; + } elsif (/^MEMf ([^ ]*) (.*)/) { + $old = $1; $loc = $2; + if (!defined($mem{$old})) { + print "ERROR: $old not allocated: $_\n"; + } else { undef($mem{$old}); } + next; + } elsif (/^MEMr ([^ ]*) ([^ ]*) (.*)/) { + $old = $1; $new = $2; $loc = $3; + if (!defined($mem{$old})) { + print "ERROR: $old not allocated: $_\n"; + } else { undef($mem{$old}); } + if (defined($mem{$new})) { + print "ERROR: $new already allocated;\n"; + print " OLD: $mem{$new}\n"; + print " NEW: $_\n"; + } else {$mem{$new} = $loc; } + next; + } else { print "ERROR: MEM what? $_\n"; } +} +foreach $addr (sort keys(%mem)) { + if (defined($mem{$addr})) { + if (($mem{$addr} =~ /^rnch.c/)) { next; } + if (($mem{$addr} =~ /^print.c:14[18]/)) { next; } + if (($mem{$addr} =~ /^print.c:323/)) { next; } + if (($mem{$addr} =~ /^print.c:1135/)) { next; } + if (($mem{$addr} =~ /^print.c:207/)) { next; } + if (($mem{$addr} =~ /^print.c:219/)) { next; } + if (($mem{$addr} =~ /^print.c:335/)) { next; } + if (($mem{$addr} =~ /^print.c:261/)) { next; } + if (($mem{$addr} =~ /^print.c:1076/)) { next; } + if (($mem{$addr} =~ /^proc.c:191/)) { next; } + if (($mem{$addr} =~ /^main.c:581/)) { next; } + if (($mem{$addr} =~ /^rvfs.c:68/)) { next; } + print "IN USE $addr: $mem{$addr}\n"; + } +} diff --git a/OLD/lsof.h b/OLD/lsof.h new file mode 100644 index 0000000..06903fa --- /dev/null +++ b/OLD/lsof.h @@ -0,0 +1,1075 @@ +/* + * lsof.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: lsof.h,v 1.69 2018/02/14 14:19:25 abe Exp $ + */ + + +#if !defined(LSOF_H) +#define LSOF_H 1 + +#include "machine.h" + +# if !defined(FSV_DEFAULT) +#define FSV_DEFAULT 0 +# endif /* !defined(FSV_DEFAULT) */ + +#include "lsof_fields.h" + +#include +#include + +# if defined(HASSETLOCALE) +#include +# endif /* defined(HASSETLOCALE) */ + +#include +#include +#include + +#include +#include + + +/* + * 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 1 /* pipe endpoint ID */ +#define CHEND_PTY 4 /* pseudoterminal endpoint ID */ +#define EPT_PIPE 1 /* process has pipe file */ +#define EPT_PIPE_END 2 /* process has pipe end point file */ +#define EPT_PTY 8 /* process has a pseudoterminal file */ +#define EPT_PTY_END 16 /* process has a pseudoterminal end + * point file */ + +# if defined(HASUXSOCKEPT) +#define CHEND_UXS 2 /* UNIX socket endpoint ID */ +#define EPT_UXS 4 /* process has a UNIX socket file */ +#define EPT_UXS_END 8 /* process has a UNIX socket end point + * file */ +# endif /* defined(HASUXSOCKEPT) */ +# 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_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_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 /* just in case -- because utmp.h + * may need it */ +#include "./regex.h" + +# if defined(EMPTY) +#undef EMPTY +# endif /* defined(EMPTY) */ + +# if defined(HASUTMPX) +#include +# else /* !defined(HASUTMPX) */ +#include +# 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) +static struct utmpx dummy_utmp; /* to get login name length */ +#define LOGINML sizeof(dummy_utmp.ut_user) + /* login name length */ +# else /* !defined(HASUTMPX) */ +static struct utmp dummy_utmp; /* to get login name length */ +#define LOGINML sizeof(dummy_utmp.ut_name) + /* login name length */ +# endif /* defined(HASUTMPX) */ +# endif /* !defined(LOGINML) */ + +#define LPROCINCR 128 /* Lproc[] allocation increment */ +#define LSOF_URL "ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/" +#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 */ + +# 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 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 */ + +/* + * 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) */ + +extern int AllProc; + +# 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; +extern efsys_list_t *Efsysl; /* file systems for which kernel blocks + * are to be eliminated */ + +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; +extern lsof_rx_t *CmdRx; +extern int NCmdRxU; + +# 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) */ + +# 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; + +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 */ + +# 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; +# endif /* defined(HASEPTOPTS) */ + + +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) */ +}; + +# if defined(HASBLKDEV) +extern struct l_dev *BDevtp, **BSdev; +extern int BNdev; +# endif /* defined(HASBLKDEV) */ + +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 */ +}; +extern struct str_lst *Cmdl; +extern int CmdLim; +extern int Cmdni; +extern int Cmdnx; + +# if defined(HASSELINUX) +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 cntxlist_t *CntxArg; +extern int CntxStatus; +# endif /* defined(HASSELINUX) */ + +# if defined(HASDCACHE) +extern unsigned DCcksum; +extern int DCfd; +extern FILE *DCfs; +extern char *DCpathArg; +extern char *DCpath[]; +extern int DCpathX; +extern int DCrebuilt; +extern int DCstate; +extern int DCunsafe; +# endif /* defined(HASDCACHE) */ + +extern int DChelp; +extern dev_t DevDev; +extern struct l_dev *Devtp; +extern char **Dstk; +extern int Dstkn; +extern int Dstkx; +extern int ErrStat; +extern uid_t Euid; +extern int Fand; +extern int Fblock; +extern int Fcntx; +extern int Ffield; +extern int Ffilesys; +extern int Fhelp; +extern int Fhost; + +# if defined(HASNCACHE) +extern int Fncache; +extern int NcacheReload; +# endif /* defined(HASNCACHE) */ + +extern int Fnet; +extern int FnetTy; +extern int Fnfs; +extern int Fnlink; +extern int Foffset; +extern int Fovhd; +extern int FeptE; + +extern int Fport; + +# if !defined(HASNORPC_H) +extern int FportMap; +# endif /* !defined(HASNORPC_H) */ + +extern int Fpgid; +extern int Fppid; +extern int Fsize; +extern int Fsv; +extern int FsvByf; +extern int FsvFlagX; +extern int Ftask; +extern int Ftcptpi; +extern int Fterse; +extern int Funix; +extern int Futol; +extern int Fverbose; +extern int Fwarn; + +# if defined(HASXOPT_VALUE) +extern int Fxopt; +# endif /* defined(HASXOPT_VALUE) */ + +extern int Fxover; +extern int Fzone; + +struct fd_lst { + char *nm; /* file descriptor name -- range if + * NULL */ + int lo; /* range start (if nm NULL) */ + int hi; /* range end (if nm NULL) */ + struct fd_lst *next; +}; +extern struct fd_lst *Fdl; +extern int FdlTy; /* Fdl[] type: -1 == none + * 0 == include + * 1 == exclude */ + +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 int IgnTasks; +extern char *InodeFmt_d; +extern char *InodeFmt_x; +extern int LastPid; + +struct lfile { + char access; + char 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 */ +# 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) */ + + char fd[FDLEN]; + char iproto[IPROTOL]; + char type[TYPEL]; + 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; +}; +extern struct lfile *Lf, *Plf; + + +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 struct lproc *Lp, *Lproc; + +extern int MaxFd; +extern char *Memory; +extern int MntSup; +extern char *MntSupP; + +# if defined(HASPROCFS) +extern struct mounts *Mtprocfs; +# endif + +extern int Mxpgid; +extern int Mxpid; +extern int Mxuid; +extern gid_t Mygid; +extern int Mypid; +extern uid_t Myuid; +extern char *Namech; +extern size_t Namechl; +extern int Ndev; + +# 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 long Nlink; +extern int Nlproc; +extern char *Nmlst; +extern int Npgid; +extern int Npgidi; +extern int Npgidx; +extern int Npid; +extern int Npidi; +extern int Npidx; +extern int Npuns; +extern int Ntype; +extern int Nuid; +extern int Nuidexcl; +extern int Nuidincl; + +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; +extern char *Pn; + +# 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 RptTm; +extern struct l_dev **Sdev; +extern int SelAll; +extern int Selflags; +extern int SelProc; +extern int Setgid; +extern int Selinet; +extern int Setuidroot; +extern struct sfile *Sfile; +extern struct int_lst *Spgid; +extern struct int_lst *Spid; +extern struct seluid *Suid; +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 TmLimit; +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; + +# if defined(HASZONES) +typedef struct znhash { + char *zn; /* zone name */ + int f; /* "find" flag (used only in ZoneArg) */ + struct znhash *next; /* next zone hash entry */ +} znhash_t; +extern znhash_t **ZoneArg; +# endif /* defined(HASZONES) */ + +#include "proto.h" +#include "dproto.h" + +#endif /* LSOF_H */ diff --git a/OLD/lsof1_00DIST b/OLD/lsof1_00DIST new file mode 100644 index 0000000..29122d5 --- /dev/null +++ b/OLD/lsof1_00DIST @@ -0,0 +1,31 @@ + Notes for the comp.sources.unix distribution of lsof 1.0 + +Lsof (for LiSt Open Files) lists files opened by processes on selected +Unix systems. It is my answer to those who regularly ask me when I am +going to make fstat (comp.sources.unix volume 18, number 107) or ofiles +(volume 18, number 57) available on SunOS 4.1.1 or the like. + +Lsof is a complete redesign of the fstat/ofiles series, based on the SunOS +vnode model. Thus, it has been tested on AIX 3.1.[357], HP-UX [78].x, +NeXTStep 2.[01], Sequent Dynix 3.0.12 and 3.1.2, and Sunos 4.1 and 4.1.1. +Using available kernel access methods, such as nlist() and kvm_read(), +lsof reads process table entries, user areas and file pointers to reach +the underlying structures that describe files opened by processes. + +Lsof interprets most vnode extensions -- cdrnodes, fifonodes, gnodes, +inodes, rnodes, snodes and tmpnodes. It understands NFS connections. It +recognizes FIFOs, multiplexed files, Unix and Internet sockets. + +Lsof accepts options to limit and filter its output. That output describes +the process that has opened the file, the command the process is executing, +the owner of the process, the file descriptor of the file, and the file's +device, inode number, size and file system name. Additional special output +is provided for special files -- e. g., the local and destination Internet +addresses of Internet socket files. + +Lsof may be used and distributed freely, subject to the limited conditions +described in its source file. + +Victor A. Abell +Purdue University Computing Center +November 22, 1991 diff --git a/OLD/lsof2_00DIST b/OLD/lsof2_00DIST new file mode 100644 index 0000000..f7177ec --- /dev/null +++ b/OLD/lsof2_00DIST @@ -0,0 +1,360 @@ +*********** THIS IS THE FINAL RELEASE OF VERSION 2 OF LSOF. ************* +| | +| Version 3 of lsof is now available. Look in this directory for: | +| | +| lsof_3..tar.gz | +| | +| ( is the release level, 0 as of 24 May 1994.) | +| | +| Vic Abell | +| | +************************************************************************* + + Notes for the distribution of lsof version 2.36 + +Lsof (for LiSt Open Files) lists files opened by processes on selected UNIX +systems. It's my update to fstat (comp.sources.unix volume 18, number 107) +and ofiles (volume 18, number 57). A description of the changes lsof has +undergone to reach its current version is in What's new in Version 2.36? + --------------------------- + +Lsof is a complete redesign of the fstat/ofiles series and its closer parent, +lsof 1.09. It has been tested on: + + AIX 3.2.[1234] for the IBM RISC/System 6000 + BSDI BSD/386 1.0 for PC compatibles + EP/IX 2.1.1 for the CDC 4680 + FreeBSD 1.0e for PC compatibles + HP-UX [789].x for HP systems (some combinations) + IRIX 5.1.1 for SGI systems + NetBSD 0.9a for PC compatibles + NeXTStep 2.1, 3.0, 3.1 for NeXT work stations + OSF/1 1.[23] and 2.0 for DEC Alpha work stations + Sequent Dynix 3.0.12 for the Sequent Symmetry + SunOS 4.1.[123] for Sun 3 and 4 + SunOS 5.1 (Solaris 2.1) for Sun 4 systems + SunOS 5.3 (Solaris 2.3) for Sun 4 systems + Ultrix 2.2 and 4.2 for DEC work stations + +Although it has not been tested on them, lsof will probably work on AIX +3.1.[357], EP/IX 1.4.3, ETAV 1.17, IRIX 4.0.5, NeXTStep 2.0 and SunOS 4.1. +(It used to work on those UNIX dialects, but I no longer have access to +them for testing.) + +Using available kernel data access methods -- getproc(), getuser(), kvm_*(), +nlist(), pstat(), read(), readx() -- lsof reads process table entries, user +areas and file pointers to reach the underlying structures that describe +files opened by processes. + +Lsof interprets most file node structures -- cdrnodes, devnodes, fifonodes, +gnodes, High Sierra nodes, inodes, mfsnodes, procnodes, rnodes, snodes, +specnodes, s5inodes, tmpnodes. It understands NFS connections. It +recognizes FIFOs, multiplexed files, UNIX and Internet sockets. It knows +about System V streams. On many systems it recognizes execution text and +library references. + +Lsof accepts options to limit and filter its output. That output describes +the process that has opened the file, the command the process is executing, +the owner of the process, the file descriptor of the file, and the file's +access mode, lock status, device, inode number, size or offset, file system +name and stream head name. Additional special output is provided for special +files -- e. g., the local and destination Internet addresses of Internet +socket files. (Lsof has a special filter that limits output to the listing +of Internet socket files having designated protocol usage, host name or +address, or service name or port.) + +Lsof may be used and distributed freely, subject to the limitations described +in its source files. + +What's new in Version 2.36? +--------------------------- + +This is a list of the changes that have led to version 2.36. + + * The version 1.09 sources were reorganized and broken into smaller + files. There are three header files -- one for includes and + defines, one for function prototypes and a third for machine- + dependent definitions. + + * Lsof understands some System V platforms: the ETA-10P* running + Release 3.1 and Lachman Associates, Inc. TCP/IP Release 3.0; + Silicon Graphics Indigo systems running IRIX 4.0.5 and 5.1.1; + CDC 4680 systems running EP/IX 1.4.3 and 2.1.1. + + * Lsof has a security compilation option, enabled by defining the + HASSECURITY symbol (e.g., in the Makefile or in machine.h). When + the security mode is enabled, only the root user may list all + open files; the non-root user 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). Lsof is + distributed with the security mode disabled, but there is a + skeleton for defining it in the machine.h header file. + + * Lsof has a SLOWDEV mode for systems whose /dev directory tree is + deep and whose stat() function is slow. This mode is activated + with the -T option and prevents lsof from plumbing the depths of + the /dev tree. When the mode is active, lsof may be unable to + associate /dev path names with all major/minor device number pairs. + + This mode is enabled for EP/IX 1.4.3, because it takes a minimum + of 27 seconds to stat() all the entries in its /dev tree. The + mode is no longer needed for EP/IX 2.1.1. + + Note: at versions 2.07, 2.08 and 2.09, when SLOWDEV was enabled, + the -T option inhibited a full /dev search; at version 2.10 -T + enables a full search. + + * An attempt has been made to make the lsof sources ANSI C compliant. + Compliance has been tested with the -ansi and -pedantic options of + the NeXTStep gcc compiler. The compliance changes have been + verified to compile without error on all other available platforms. + However, there may be older platforms or untested ones where the + changes cause compilation errors. + + * In version 2.09 the timeout handling of stat() calls, particularly + on inaccessible NFS directories, was improved, thanks to a + suggestion from Benson I. Margulies . + + * In version 2.10 the Margulies stat() timeout suggestion was + significantly extended to handle more systems and situations. + + * In version 2.11 the interpolation of symbolic links was extended to + directory names, obtained via the getmntent() function, improving + the usability of lsof under HP-UX. + + Steinar Haug pointed out the need + for this addition. + + * At Steinar Haug's suggestion I added the -i network address option + in version 2.12. + + * At version 2.13 I enhanced network address argument processing + and correctly allocated the user area buffer for swapped DYNIX + processes. + + * I added a UID cache at version 2.14 to improve speed on systems + with many processes and many users. + + * I added SunOS support at 2.15 to read the current working directory + and root directory paths, thanks to a hint from Carl Johnson + . + + * I added SunOS 5.1 (Solaris 2.1) support at version 2.16, thanks to + Dave Curry . + + * February 24, 1993: I changed Makefile generation to produce more + generic Makefiles. No source code changes were involved, so the + version number didn't change. + + * April 12, 1993: at the suggestion of Dave Stevens of the Purdue + University Computing Center I added better + support in version 2.17 for raw sockets, especially determining + Internet addresses for applications like ping. This support is + uneven, because it depends on how a given UNIX OS supports raw + socket addressing. The changes of version 2.17 have not been + tested on older OS dialects -- e.g., AIX 3.1.x, HP-UX 7.x, etc. + + * May 11, 1993, version 2.18: in response to a bug report from Greg + Earle , I added support for Sun High + Sierra file system nodes. This support allows one to search for + processes using CD-ROM files, for example. The code has been tested + under Solaris 2.1 and SunOS 4.1.3. + + The High Sierra support code exposed a difficulty with identifying + the major/minor device numbers of some SunOS and Solaris files. It + seems that both systems will return different major/minor device + numbers for the directory on which a CD-ROM is mounted (e.g., + /cdrom) and the file system associated with it (e.g., /dev/sr0). + Further, some Solaris device values can't be converted to major/ + minor device numbers with the makedev(3) functions; lsof prints + such device values as one hexadecimal number. + + I fixed a bug in the SGI file pointer scan loop in response to a + report from Dave Olson . + + * May 24, 1993 -- I corrected an incompatibility with AIX 3.2.3. Its + strncpy() is now a built-in and can't be split by a #if. The fix + was supplied by Scott J. Ellentuch and Horst + Luehrsen . + + * July 1, 1993, version 2.19: in response to a request from Jos + Vos , I added network address to host name and port + number to port name conversions. I added the -H flag to disable + host name conversion; -P, port name. + + * July 22, 1993, version 2.19: at NeXTStep 3.1 it is no longer + possible to use the -ansi and -pedantic compiler flags to check for + ANSI C compliance. The flags cause compilation errors in system + header files. The Makefile for NeXTStep 3.1, Makefile.next31, + reflects this sad fact. + + * August 13, 1993, version 2.20: I added code for SunOS to skip + automountable file systems that are not mounted. The change was + suggested by Dominique Petitpierre . + + I shifted ANSI C conformance testing to gcc 2.3.3 under SunOS 4.1.3, + because of system header file problems under NeXTStep 3.1. The + CDEFS macro for gcc is: + + CDEFS= -ansi -Dsun + + * August 17, 1993, version 2.21: I added code to display SunOS and + Solaris text file usage. I added code to handle readlink() and + stat() deadlocks better, including the new options "-m" and "-S t". + + * September 10, 1993, version 2.22: I updated CLONEMAJ and N_UNIX + definitions for SunOS 5.1 (Solaris 2.1) per information received + from Casper Dik . + + * September 16, 1993, version 2.23: I updated EP/IX support to OS + version 2.1.1. Theoretically the EP/IX 1.4.3 support should still + work, provided the Makefile has "-D_EPIXV=10403". + + The SLOWDEV definition was removed for EP/IX 2.1.1. It remains + 27 for EP/IX 1.4.3. + + * October 14, 1993, version 2.24: I completely revised the breaking + of NFS deadlocks in response to a discovery that the AIX 3.2.4 + lstat() call can only be broken with a SIGKILL. Lsof now does + system calls that have NFS deadlock potential -- lstat() and + readlink() -- in a child process, retrieving the output via a + pipe, limiting the read via a SIGALRM, and stopping a deadlocked + child process with a SIGKILL. + + Version 2.24 has a correction that makes it possible to search + for EP/IX 2.1.1 files by name. + + * October 20, 1993, version 2.25: I added code, provided by John + Silva , that prints HP-UX [89].x text and + memory region nodes. The -L option was enabled for HP-UX [89].x + to allow the printing of duplicate text and memory region nodes. + + I added rudimentary support for HP-UX [89].x link level access + files. + + I removed a trailing `/' from path arguments longer than one + character to make file system name matching possible. The bug was + reported by John Silva . + + I made yet another correction to make it possible to search for + EP/IX 2.1.1 files by name and file system. + + I corrected some serious omissions and bugs in the version 2.24 + deadlock breaking code. A close() and wait() were missing, and + the child process was using exit() instead of _exit(). The + problems only seemed to bother the Solaris version of lsof. + + * November 14, 1993, version 2.26: I added support for SGI IRIX 5.1.1, + thanks to much help from Dave Olson . + There are now separate Makefiles for IRIX 4.0.5 and 5.1.1. + + All user ID references are now type cast uid_t to correct problems + in the UID cacheing algorithm, used by printuid() in print.c. + + * December 2, 1993, version 2.27: I added changes for SunOS 5.3 + (Solaris 2.3) to display socket information correctly, courtesy of + Casper Dik . Kernel structures for SunOS 5.3 + sockets whose connections originate locally no longer contain the + local network address -- hence lsof displays * for the INADDR_ANY + value they do contain. + + I added support for CCITT x.25 sockets under HP-UX 8.x and + (presumably) 9.x, courtesy of Pasi Kaara . + Pasi also helped find a couple bugs in the HP-UX [89].x handling + of virtual file system names. + + * December 20, 1993 (no version number change): I added display of + x.25 socket's PCB. I changed the Solaris Makefile to use the GID + for sys. I added fix to allow IRIX 4.0.5 usage, based on bug report + and testing by Brian Silver . + + * January 11, 1994, version 2.28: I ported lsof to OSF/1 1.[23] for + the DEC Alpha. Anthony Baxter , Dwight + McKay , and Jeffrey Mogul + gave generous assistance. Dwight provided the + test system; Anthony and Jeffrey advised on OSF/1 matters. + + * January 26, 1994, version 2.29; I ported lsof to OSF/1 2.0 for the + DEC Alpha. Axel Clauberg and Claus + Kalle graciously provided a test system. + Axel provided a critical clue to the organization of the + header file that enabled me to accomplish this port. + + * February 12, 1994, version 2.30: I ported lsof to Ultrix 2.2 and + 4.2 for DEC work stations. The system to which the 2.2 port was + directed is a local one that has been extensively updated with + 4.3BSD{Tahoe,Reno} network features, so it may not match a + standard 2.2 system, if there is any such system still in use. + + Terry Friedrichsen , Dwight McKay + , and Jeffrey Mogul + gave generous assistance. Dwight provided the + test system; Jeff and Terry advised on Ultrix matters. + + * February 17, 1994, version 2.31: this is a bug fix release. It + includes fixes to: + + o Allow specifying more than one file or file system argument; + + o Display correct SunOS 4.x VCHR inode numbers -- e.g., /dev/kmem, + /dev/console -- and allow searching for them by name in versions + of SunOS older than 4.1.3; + + o Search for OSF/1 /dev/ptyp? files by name, even though there is + no inode number in the kernel open file structures for these + files that corresponds to the inode number available from the + stat() function call. + + Terry Friedrichsen reported this bug. + Jeffrey Mogul provided conclusive evidence + that the inode number does not exists in the kernel open file + structures. + + * February 25, 1994, version 2.32: I ported lsof to BSDI BSD/386 1.0, + FreeBSD 1.0e, and NetBSD 0.9a for PC compatibles. + + Bill Bormann provided the FreeBSD test + platform. Dave Stevens provided the + BSDI BSD/386 test platform. + + Sean McDermott did the NetBSD 0.9a + testing. + + I added code to the handling of NFS deadlocks to time out the wait + for a child process to complete. The time-out is accompanied by a + warning that the child process may be hung. + + I fixed a few minor OSF/1 bugs. + + I corrected an #if test that made it impossible to compile misc.c + under IRIX 4.0.5. Bob Mende Pie + supplied the correction. + + * March 10, 1994, version 2.33: I added ADVFS/MSFS file system support + for DEC OSF/1 1.3a. This has not been tested under versions 1.2 + or 2.0 of DEC OSF/1. + + Achim Bohnet and Bernt Christandl + graciously provided test time on a 1.3a + system with the ADVFS/MSFS layered file system product. + + I fixed a Solaris 2.[13] bug that prevented proper lookup of socket + streams. Steve Kirsch reported the bug and + graciously provided test time for locating and fixing it. + + * April 13, 1994, version 2.34: I fixed some minor bugs, including: + using Purdue DYNIX's /etc/passwd stay-open mode; handling an + empty /etc/services file without causing a segmentation fault; + handling Unix domain sockets consistently; eliminating an IRIX + reference to a virtual memory region pointer that is obsolescent. + + * April 19, 1994, version 2.35: I extended the /etc/passwd stay-open + mode handling to another Purdue dialect: Ultrix 2.2. + + * May 2, 1994, version 2.36: a child process, blocked by NFS, is now + sent both the SIGINT and the SIGKILL signals in an attempt to + terminate it. David DiGiacomo +Purdue University Computing Center +May 24, 1994 diff --git a/OLD/lsof3_00DIST b/OLD/lsof3_00DIST new file mode 100644 index 0000000..4fee99f --- /dev/null +++ b/OLD/lsof3_00DIST @@ -0,0 +1,2460 @@ + + Notes for the distribution of lsof version 3 + +******************************************************************** +| The latest release of lsof is always available via anonymous ftp | +| from vic.cc.purdue.edu. Look in pub/tools/unix/lsof. | +******************************************************************** + + 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 + What's new in Version 3 + Version 3 Release Notes + 3.0, May 24, 1994 + 3.01, May 27, 1994 + 3.02, June 2, 1994 + 3.03, July 8, 1994 + 3.04, July 15, 1994 + 3.05, July 26, 1994 + 3.06, September 2, 1994 + 3.07, September 8, 1994 + 3.08, September 23, 1994 + 3.09, October 18, 1994 + 3.10, October 21, 1994 + 3.11, October 28, 1994 + 3.12, October 29, 1994 + 3.13, November 11, 1994 + 3.14, November 16, 1994 + 3.15, November 25, 1994 + 3.16, December 2, 1994 + 3.17, January 25, 1994 + 3.18, January 31, 1995 + 3.19, February 10, 1995 + 3.20, February 23, 1995 + 3.21, March 3, 1995 + 3.22, March 9, 1995 + 3.23, March 24, 1995 + 3.24, March 31, 1995 + 3.25, April 5, 1995 + 3.26, April 20, 1995 + 3.27, May 2, 1995 + 3.28, May 26, 1995 + 3.29, June 2, 1995 + 3.30, June 8, 1995 + 3.31, June 16, 1995 + 3.32, June 23, 1995 + 3.33, June 28, 1995 + 3.34, June 30, 1995 + 3.35, July 9, 1995 + 3.36, July 20, 1995 + 3.37, July 27, 1995 + 3.38, August 3, 1995 + 3.39, August 10, 1995 + 3.40, August 25, 1995 + 3.41, September 5, 1995 + 3.42, September 7, 1995 + 3.43, September 12, 1995 + 3.44, September 19, 1995 + 3.45, September 20, 1995 + 3.46, October 5, 1995 + 3.47, October 16, 1995 + 3.48, October 20, 1995 + 3.49, October 25, 1995 + 3.50, October 31, 1995 + 3.51, November 8, 1995 + 3.52, November 27, 1995 + 3.53, December 8, 1995 + 3.54, December 15, 1995 + 3.55, December 21, 1995 + 3.56, January 2, 1996 + 3.57, January 12, 1996 + 3.58, February 7, 1996 + 3.59, February 21, 1996 + 3.60, February 27, 1996 + 3.61, March 9, 1996 + 3.62, March 26, 1996 + 3.63, April 11, 1996 + 3.64, April 26, 1996 + 3.65, May 20, 1996 + 3.66, June 19, 1996 + 3.67, July 1, 1996 + 3.68, July 17, 1996 + 3.69, July 30, 1996 + 3.70, August 9, 1996 + 3.71, August 15, 1996 + 3.72, August 28, 1996 + 3.73, September 5, 1996 + 3.74, September 6, 1996 + 3.75, September 9, 1996 + 3.76, September 21, 1996 + 3.77, October 2, 1996 + 3.78, October 14, 1996 + 3.79, October 29, 1996 + 3.80, November 8, 1996 + 3.81, November 14, 1996 + 3.82, December 11, 1996 + 3.83, December 30, 1996 + 3.84, January 13, 1997 + 3.85, January 17, 1997 + 3.86, January 30, 1997 + 3.87, February 11, 1997 + 3.88, February 17, 1997 + + +Dialects Supported +================== + +Lsof (for LiSt Open Files) lists files opened by processes on +selected Unix systems. It's a major revision of lsof version 2, +and has been tested on: + + AIX 3.2.5, 4.1[.[1234]], the IBM RISC/System 6000 + and 4.2 + BSDI BSD/OS 2.0, 2.0.1, Intel-based systems + and 2.1 + DC/OSx 1.1 Pyramid systems + EP/IX 2.1.1 the CDC 4680 + FreeBSD 1.1.5.1, 2.0, Intel-based systems + 2.0.5, 2.1, 2.1.5, + 2.2, and 3.0 + HP-UX 8.x, 9.x, 10.01, HP systems (some combinations) + 10.10, and 10.20 + IRIX 5.2, 5.3, 6.0, 6.0.1, SGI systems + and 6.[1234] + Linux through 2.0 Intel-based systems + NetBSD 1.0, 1.1, and 1.2 Intel and SPARC-based systems + NEXTSTEP 2.1 and 3.[0123] all NEXTSTEP architectures + OpenBSD 1.2 and 2.0 Intel-based systems + OSF/1 2.0, 3.0, 3.2, and the DEC Alpha + 4.0-BETA + Reliant UNIX 5.43 Pyramid systems + RISC/os 4.52 MIPS R2000-based systems + SCO OpenServer 1.1, 3.0, Intel-based systems + and 5.[024] + SCO UnixWare 2.1 and 2.1.1 Intel-based systems + Sequent PTX 2.1.[1569], Sequent systems + 4.0.[23], 4.1.[024], + 4.2[.1], and 4.3 + Solaris 2.[123456], 2.5.1, Sun 4 and i86pc systems + and 2.6-Beta + SunOS 4.1.[1234] Sun 3 and 4 + Ultrix 4.2, 4.3, 4.4, DEC RISC and VAX + and 4.5 + +(The pub/tools/unix/lsof/contrib directory on vic.cc.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 contact me at +. + + +How Lsof Works +============== + +Using available kernel data access methods -- getproc(), getuser(), +kvm_*(), nlist(), pstat(), read(), readx(), /proc -- lsof reads +process 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 (PGRP) 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; + + * 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 (PGRP) -- 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. Although I have no evidence that they +exist, the potential for similar restrictions exists in Solaris +versions of lsof. + +AN LSOF BINARY, COMPILED FOR ONE SOLARIS ARCHITECTURE, ISN'T +GUARANTEED TO WORK ON A DIFFERENT SOLARIS 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.) + +If you're worried you don't have everything, run the Inventory +script. Here's aan approximate picture of what you should have: + +lsof_: + + 00CREDITS 00PORTING Customize lsof_fields.h proc.c + 00DCACHE 00QUICKSTART Inventory main.c proto.h + 00DIST 00README arg.c misc.c scripts/ + 00FAQ AFSConfig dialects/ node.c store.c + 00MANIFEST Configure lsof.h print.c version + +lsof_/dialects: + + aix/ epix/ linux/ osf/ riscos/ sun/ + bsdi/ freebsd/ netbsd/ ptx/ sco/ ultrix/ + common/ hpux/ next/ pyramid/ sgi/ unixware/ + +lsof_/dialects/common: + + 00Manifest dvch.frag lkud.frag prtf.frag rnam.frag + ckfa.frag fchi.frag pcdn.frag rdev.frag rnch.frag + cvfs.frag isfn.frag prfp.frag rmnt.frag rvfs.frag + +Specific dialects sub-directories may differ slightly, depending +on the needs of the dialect, but they should all contain: + +lsof_/dialects/next: + + Makefile ddev.c dlsof.h dnode.c dproto.h dstore.c + Mksrc* dfile.c dmnt.c dproc.c dsock.c machine.h + +lsof_/scripts: + + 00MANIFEST count_pf.perl* list_fields.awk + 00README count_pf.perl5* list_fields.perl* + big_brother.perl5 list_NULf.perl5* watch_a_file.perl* + + +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 me via email at +. + + +What's new in Version 3 +======================= + +I had three goals in mind for version 3: + + 1. Make it faster. + + Lsof 3 defers as many lookup operations -- /dev scan, mount + table scan, /etc/services scan -- until they're needed. + + I used prof on lsof and used its information to reduce lsof's + overhead. + + 2. Make it easier to maintain and port to other systems, and + eliminate complicated nestings of #if/#else/#endif + pre-processor statements. + + 3. Add a few features: + + o ANDing of options; + + o Sorting of output by Process ID; + + o Searching for Unix domain sockets by name -- to a limited + extent. + + o Process group ID support. (This was a late addition.) + +As a result of goal 2, the organization of lsof version 3 differs +greatly from version 2. The main directory contains totally common +functions, a dialect subdirectory contains subdirectories of code +specific to each Unix dialect that is supported. There is also a +dialects/common subdirectory that contains code fragments that are +used by more than one, but not all dialects. + +A top-level Configure script constructs the complete set of sources +for a given dialect and the Makefile at the top-level. Configure +is self-documenting. When it is finished, Configure calls a second +script, Customize, that assists with the modification of a few +important compile-time options. + + +Version 3 Release Notes +======================= + +3.0 May 24, 1994 + This is the first official release of lsof 3. + +3.01 May 27, 1994 + Corrected the #ifdef condition for HASPWSTAYOPEN + under Sequent Dynix 3.0.12. + + Fixed bug that prevented the display of current + working and root directory path names under SunOS + 4.1.x, even when the user area contained pointers + to them. + + Changed the strategy for allocating space to the + local proc table in EP/IX, NEXTSTEP, Solaris, and + SunOS. + + Closed the distance between reading the Solaris + proc structure and its companion pid structure in + an effort to avoid using a stale pid structure + pointer. A stale pid structure pointer sometimes + causes a segmentation violation in kvm_read(). + + Added code to the SunOS kread() function to filter + out non-kernel addresses that might lead kvm_read() + to a segmentation violation. The Configure script + was updated to create a header file, kernelbase.h, + with the necessary kernel memory boundary value; + and to remove the header file when the -clean option + is specified. The Configure script now passes the + target name to the Mksrc shell script. It's used + by sun/Mksrc to determine the source for kernelbase.h. + +3.02 June 2, 1994 + Added #if's to of kernelbase.h for Solaris and + SunOS. This eliminates a redeclaration complaint + from old versions of SunOS. + + Added code to process_file() in all dialects to + display "no more information" when f_count in the + file structure is zero. + +3.03 July 8, 1994 + Added support for displaying process group IDs. + This includes two new options: -j to select PGRP + display; and -g to specify a list of PGRPs + whose files are to be displayed. (-j was chosen + to match a similar option in some ps(1)'s.) + + Philippe-Andre Prindeville + suggested this addition. + +3.04 July 15, 1994 + Corrected handling of port name component of -i + option on systems where htons() is required. + + Corrected casting of UID arguments -- needed when + UID is a short and the compiler wants the minimum + argument size to be larger. + +3.05 July 26, 1994 + Added printing of DECnet socket information for + the Ultrix 4.2 and 4.3 dialects. John Beacom + kindly provided + the test system. A new Configure abbreviation, + ultrix42dn, must be used to activate the DECnet + support. + +3.06 September 2, 1994 + The major news in this revision are the V/88 R32V3 + and R40V4.2 ports for Motorola M88K systems. Chance + Neale kindly provided test systems + and Mike Feldman + provided technical assistance. + + Version 3.06 contains other, minor modifications: + + * The Configure script has been isolated from the + environment, thanks to a report of a CC=xlc + problem from Johnny Tolliver . + Johnny also suggested a better form for the install + commands in the Makefile's install rule. This + change affected all the dialect Mksrc scripts. + + A new HP-UX abbreviation (hpuxx25) was added + for systems that have the /etc/conf/x25 include + files. The old HP-UX abbreviation (hpux) no + longer references /etc/conf or defines HPUX_CCITT. + + * The command "lsof `tty`" now works most places (maybe + not always for SGI IRIX, but I tried) thanks to a bug + report from Casper Dik . + + * A mode has been added to disable forking when + debugging. The V/88 R40V4.2 debugger needed that. + + * Printing of stream NAMEs was standardized (IRIX + was different) and an attempt was made to avoid + stream NAMEs like /dev/ttyx4->/dev/ttyx4. + + * A new documentation file, 00FAQ, accompanies the + distribution. It contains frequently asked + questions about lsof, and the best answers I can + manage to give. + + * I have a new HP-UX test system, courtesy of Dave + Curry and George Goble + of Purdue's Engineering Computer + Network. I want to thank J. Nelson Howell + of Purdue's School of + Management for his prior support of lsof development + under HP-UX. + +3.07 September 8, 1994 + This revision contains a small security enhancement. + Tim Ramsey pointed out that lsof's + setgid or setuid power might allow it's user to + read an alternate kernel name list or memory file + via the -c and -k options that the real UID might + not have authority to read. In revision 3.07 lsof + uses access(2) to check the real UID's authority + to read files named with -c and -k. + +3.08 September 23, 1994 + This revision contains support for Novell's UnixWare, + versions 1.1, 1.1.1, and 1.1.2. Peter Lord + made this possible by providing + a copy of UnixWare and supplying technical advice. + Binaries and sources for this version will be + available from Novell sources. See the Novell + UnixWare section of the distribution's 00README + file for details. + + This version adds /proc file system support to the + dialects derived from SYSV R4 (except EP/IX 2.1.1): + FreeBSD, IRIX 5.2, Solaris, UnixWare, and V/88 + R40V4.2. + + This version compiles under IRIX 4.0.5 again, + correcting a problem introduced at version 3.06 in + the "lsof `tty`" fix. + + HP-UX now skips file systems whose mount type is + "ignore". The presence of the -c option is now + controlled by the HASCOPT definition in machine.h. + The HASSWAPPORT option is now documented and + implemented correctly. Hans Petter Christiansen + suggested these changes. + +3.09 October 18, 1994 + This revision recognizes the DEC Alpha OSF/1 V3.0, + IBM AIX 4.1, and Solaris 2.4 dialects. It has + support for the SunOS 4.1.3 PC file system and two + bug fixes: an IRIX, V/88, and Solaris file argument + processing bug; and a V/88 include error. + + Alex Kreis made the initial + request for DEC OSF/1 V3.0 support and provided + help with testing. Ron Young + graciously provided a test host. James Woodward + provided invaluable clues + to V3.0 kernel organization. Others who read the + alpha-osf-managers mailing list made generous offers + of test facilities, and I thank them, too. The + decosf3 abbreviation was added to the Configure + script, and the script was modified to request the + name of the system configuration subdirectory of + /sys where the configuration-specific header files + reside for the decosf1, decosf2, and decosf3 + configuration abbreviations. + + Mark Peek provided and + tested the AIX 4.1 changes. + + Casper Dik provided and tested + the Solaris 2.4 changes. + + Friedel Loinger suggested + the addition of support for the SunOS 4.1.3 PC file + system ("pcfs"). + + Andreas Stolcke supplied + a fix to a file argument processing bug that causes + lsof to crash when supplied the path of an NFS + mounted file. The bug affects lsof versions for + Motorola V/88 R40V4.2, SGI IRIX 5.2, and Solaris + 2.[123]. + + Corrected an error in the path to include prdata.h + in dlsof.h for Motorola V/88 R40V4.2. + +3.10 October 21, 1994 + This revision adds support for the cache and PC file + systems to Solaris. It fixes these bugs: a problem + with the display of Motorola V/88 R40V4.2 device + numbers; and a failure of Readlink() to resolve + symbolic links completely in all cases. + + Some major internal restructuring was necessary to + be able to display negative inode numbers for SunOS + PC file system nodes, while displaying them as + unsigned numbers for Solaris, hence all dialect + versions were affected. + +3.11 October 28, 1994 + This revision adds support for Linux version 1.0.9. + Tim Korb kindly provided + a development system in the Computer Science + Department at Purdue. It is likely that the Linux + revision will have to be adjusted for each installation, + and it is probable that this revision will not run + under later versions of Linux. See the 00FAQ and + 00REAME files for more information on Linux tuning. + +3.12 October 29, 1994 + This revision supports Linux version 1.1.47 -- the + Yggdrasil Plug-and-Play Linux Fall '94 release. + Both Linux versions now obtain kernel symbol + addresses from the /zSystem.map file. + + November 4, 1994 + Hendrik G. Seliger + reports that lsof compiles and seems to work under + Linux 1.1.61. He used the linux1147 Configure + abbreviation. Marty Leisner + reports that the linux1147 Configure abbreviation + produces a working lsof for Linux 1.1.64, too. + +3.13 November 11, 1994 + This revision contains Pyramid DC/OSx support, provided + by Anthony Shortland . + + Marty Leisner reported + a segmentation violation failure in Linux lsof. + In response I changed its task structure access to + use /dev/kmem instead of mmap'ing kernel memory. + This avoids a possible segmentation violation when + bad pointers are obtained from kernel memory. I + also enabled the setting of Linux INET and Unix + select flags so that the -n and -U options work -- + I forgot to do that when I did the Linux port. + + Marty Leisner reports that the lunix1147 Configure + abbreviation produces a working lsof for Linux + 1.1.64, too. + + Francois Pindard provided + a correction to the Linux install rule. + +3.14 November 16, 1994 + This revision adjusts the Configure script stanzas + for DEC OSF/1, Motorola V/88, Pyramid DC/OSx, and + Ultrix. It also contains additional support for + DC/OSx and Ultrix. + + Bruce Beare and Robert Vernon + helped me understand Pyramid + nomenclature. Robert Vernon provided DC/OSx support + for the RxFS file system and added machine series + auto-detection to the Configure script. Alex Podlecki + helped test the updated DC/OSx + distribution. + + Chris Timmons provided + information on RISC and VAX Ultrix 4.4 that led to + correct prefixing of nlist() names. I updated the + Configure script to detect Ultrix version, machine + hardware type, and the presence of DECnet support. + + I also updated the OSF/1 and V/88 Configure scripts + to determine configuration parameters automatically. + +3.15 November 25, 1994 + Corrected DEC OSF/1 V2.0 support of the ADVFS file + system. + + Bernt Christandl and Alex + Kreis helped test. No OSF/1 + V1.x system with ADVFS was available for testing. + +3.16 December 2, 1994 + Fixed some device number handling bugs in DEC OSF/1 + V2.0 and V3.0 support. + +3.17 January 25, 1994 + lsof now supports SGI IRIX 5.3, thanks to changes + supplied by Dave Olson ; + and SCO OpenDesktop or OpenServer releases 1.1 and + 3.0, thanks to support from Dion Johnson , + Bela Lubkin , and Nathan Peterson + . + + Dave Olson pointed out an IRIX stream handling bug + in sgi/dnode.c. When I investigated it, I found + that it had implications wider than SGI IRIX. The + eventual fix provided the display of inode numbers + for character devices when the inode number must + be obtained from /dev. IRIX, Solaris, and SunOS + benefit from the fix. + + I added version detection to the Configure script, + so there is now just one Configure abbreviation + for IRIX versions 4.05, 5.2, and 5.3 -- ``irix''. + (The Configure abbreviation for the SCO dialect + ``sco''.) + + Ian Darrow pointed out that lsof + wouldn't Configure or work properly under Solaris + on an i86pc. Sorting out the difficulties made + clear that the HASSWAPPORT definition should be + removed from every machine.h file and that ntohs() + should be used in every dsock.c on every port + supplied to printinaddr(). + + Andreas Stolcke pointed + out a method that sometimes allows lsof to report + on files open to a crashed or unavailable remote + NFS server. This led to the addition of code, + where possible, to estimate the device number of + mount points that cannot be stat()'d. The alternate + device number can come from /etc/mtab or /etc/mnttab, + or from the dialect's version of them. On systems + that use /etc/mtab or /etc/mnttab, it is sometimes + possible to add the device number manually to the + mount options field in the form ``dev=xxxx''. Some + internal changes in the way lsof handles device + numbers were necessary to prevent ones whose dev_t + typedef is a signed short from causing sign extension + when promoted to integers as function arguments. + + David Addison and Robert Ehrlich + pointed out that lsof + errs when reporting device numbers and other node + information for some special Sun files. I rewrote + most of sun/dnode.c to correct the problem; Robert + rewrote it again; and I rewrote it once more. + David and Robert helped me test it under Solaris + 2.[34] and SunOs 4.1.[23]. + + While using code from the Motorola V/88 port for + the SCO port, I found and fixed some NFS bugs in + the V/88 port. + +3.18 January 31, 1995 + I added the -b and -w options. The -b option causes + lsof to avoid the functions lstat(2), readlink(2), + and stat(2) that might block in the kernel -- e.g., + when they reference an inaccessible NFS file system. + Instead it uses alternate device numbers obtained + from the mount table, where possible. + + The -w option causes lsof to suppress warning + messages -- e.g., when the -b option has been + specified. The suppression of warning messages + was formerly bundled into the -t option. The -t + option now selects -w. + + I figured out how to make alternate AIX 3.2.5 device + numbers from the kernel mount structure. The new + -b option therefore works under AIX 3.2.5. + + With the help of Chance Neale + I fixed bugs in the Motorola V/88 R32V3 NFS support. + + I added a solariscc Configure abbreviation for those + who want to use Sun's C compiler. + +3.19 February 10, 1995 + Robert Ehrlich pointed out + that lsof might be able to gather more complete path + name information from the kernel's name cache. Name + cache access may be inhibited with the new -C option. + Revision 3.19 implements name cache access for: + + DEC OSF/1 [23].0 + Dynix (Purdue 3.0.12) + EP/IX 2.1.1 + FreeBSD 1.1.5.1 + HP-UX 9.01 + Motorola V/88 R40V4.2 + NEXTSTEP 3.1 + SGI IRIX 5.3 + Solaris 2.[34] + SunOS 4.1.x + Ultrix 2.2 and 4.2 + + Revision 3.19 does NOT implement name cache access for: + === + + AIX The knlist() function won't + return cache addresses -- + some IBM wisdom to "protect" + their customers. + + Linux My only access is to 1.0.9, + and it doesn't seem to have + a kernel name cache. + + Motorola V/88 It doesn't have a unified + R32V3 name cache. + + Novell UnixWare I don't have a test system. + + Pyramid DC/OSx I don't have a test system. + + SCO OpenDesktop It doesn't have a unified + OpenServer name cache. + + SGI IRIX 4.0.5H I saw no unified name cache + in the header files before + my 4.05H system was converted + to 5.2. + + SGI IRIX 5.2 I don't have a test system. + + Another Robert Ehrlich suggestion led to the + establishment of a device cache file feature. The + new -D option gives control of it. This feature + speeds lsof dramatically on some dialects after + lsof has been called once and the cache has been + built. (Calling stat(2) on several hundred or + thousand /dev nodes can take a long time.) The + feature can be disabled or modified in the machine.h + header file and the dialects/*/ddev.c source file + when lsof is built. + +3.20 February 23, 1995 + Upgraded Linux socket handling for versions 1.1.75 + or greater with help from Marty Leisner + and Linus Torvalds + . There is now a + single Configure script abbreviation for linux. + + Updated for Motorola V/88 R40V4.3 with help from + Mike Feldman feldman@charm.urbana.mcd.mot.com> + and Chance Neale . + + Updated for SGI IRIX 6.0 with help from Przemek + Klosowski . + + Corrected access of device cache file that needs + to be updated so that someone other than the file + owner can rewrite it. Deleted the chmod() failure + warning. + + Updated Configure and the Sun Makefile to specify + absolute paths to the Sun install program. + +3.21 March 3, 1995 + Removed BSDI BSD/386 support, because I no longer + have a test system, and I needed to have separate + sources for two of the three dialects (FreeBSD, + and NetBSD) once served by the BSDI BSD/386 sources. + FreeBSD sources are now in the freebsd subdirectory; + NetBSD, in netbsd. + + With the help of Greg Earle + and Paul Kranenburg installed + new NetBSD support for versions 1.0 and 1.0A. The + NetBSD 0.9 support was removed. The 1.0A support has + been tested on Intel and SPARC-based systems. + +3.22 March 9, 1995 + Fixed a bug in name cache handling that occasionally + caused lsof to cause a segmentation violation on + FreeBSD. Although the bug didn't do that anywhere + else, recreated the binaries of all dialect versions + that use the affected code from rnam.frag and rnch.frag. + +3.23 March 24, 1995 + Removed forgotten HASSWAPPORT reference from HP-UX + machine.h and inserted ntohs() calls in the printinaddr() + calls of dsock.c for HP-UX and NEXTSTEP. + + Added support for NEXTSTEP 3.3, courtesy of Allan + Nathanson + +3.24 March 31, 1995 + Changed Configure script to handle DEC OSF/1 V3.2. + Removed leading zero from DEC OSF/1 and ADVFS + version values. Added dialects/osf/dec_a/3.2 header + file directory, courtesy of Dave Morrison + , who also tested the 3.24 + DEC/OSF1 V3.2 lsof. + +3.25 April 5, 1995 + Ported to RISC/os on a R2030 (R2000-based) system, + provided by Zdenko Tomasic . + + Tightened security on the device cache file; lsof + always tries to change its ownerships to the effective + IDs after creating it. This was suggested by Stefan + Kelm . + + Ported to FreeBSD 2.0, starting with work done by + Kurt Jaeger on lsof revision + 3.16. Ade Barkah and William + McVey provided test systems. + +3.26 April 20, 1995 + Ported to SCO OpenDesktop or OpenServer 5.0 (aka + Everest and 3.2v5.0.0). Hugh Dickins , + Bela Lubkin , Craig B. Olofson + , and Nathan Peterson , + provided me an early-release version of 3.2v5.0.0 + and gave technical advice. + + Added length checking of the Namech buffer to the + printinaddr() function. + +3.27 May 2, 1995 + Corrected typo in AIX install rule, courtesy of a + report from John Colgrave . + + At the suggestion of Greg Earle + added a function to + print the name of the unknown protocol (the AF_* + symbol), when there is no specific processing for + it in dsock.c. This change affected most dialects: + exceptions are DC/OSx, Linux, Motorola V/88, and + UnixWare. + +3.28 May 26, 1995 + Added support for Sequent PTX 2 and PTX 4. The + PTX 2.1.6 and PTX 4.0.2 test systems and technical + advice were provided by Gerrit Huizenga + , Peter Jordan , + Kevin Smallwood , and Mike Spitzer + . (Thomas A. Endo) + and (David Putz). tested + under PTX 2.1.5. Bob Foertsch + tested under PTX 4. Kevin Smallwood tested under + 2.1.1. Others who helped include Shane Kenney + , Stephan Rossi , + Douglas R. Smith , and Joel + White . + + Changed the local dev structure's name to l_dev to + avoid conflicts with the PTX dev structure. Added + a common/rdev1.frag -- a variant of rdev.frag. It's + used by EP/IX, PTX, RISC/os, and V/88. + + Changed printname() to check Namech first and print + it if it contains something. This eliminates some + hacks in the handling of names for streams, but + generates some duplicate device name look-up code + in the dnode.c files of some dialects. + +3.29 June 2, 1995 + Added clone device support to Motorola V/88 R40V4.3. + + Added a generic ``-X'' option for dialect-specific + use. Used it in AIX to allow use of readx(). Lsof + no longer uses readx() by default, because its use + can cause an AIX 3.2.x and 4.1.x kernel error to + appear. Kevin Ruderman reported + this bug to me and the possibility that lsof might + trigger it. + + The error, known as the Stale Segment ID bug, hangs + the kernel in its dir_search() function, thus + hanging the application process that called it so + tightly that the application process can neither + be killed nor stopped. The bug does not directly + affect lsof, but may cause the hang when the kernel + is searching directories for other processes. + 00FAQ and 00README describe the Stale Segment ID + bug in more detail. Consult dialects/aix/machine.h + for options on enabling or disabling readx() by + default, or permanently enabling or disabling it + with the HASXOPT and HASXOPT_VALUE definitions. + + When not using readx(), AIX lsof may not report + fully on all text and loader references. Changes + to the kernel getuser() function in AIX 4.1.1 appear + to have eliminated the text file and loader file + reference information that once led lsof to use + readx(); of course, without that information, lsof + can no longer report on the executing text file or + shared libraries in 4.1.1. + + Changed the Configure script to use a single + abbreviation, aix, for AIX. Configure now uses + /usr/bin/oslevel to determine the AIX version; in + the absence of /usr/bin/oslevel, Configure issues + a warning and assumes the version is 3.2.0. Source + code changes were made to dialects/aix/*.[ch] to + accommodate the new form of the _AIXV value. + +3.30 June 8, 1995 + Added -c to the installation of the man page in + the Ultrix Makefile's install rule. Thanks go to + Jules van Weerden + for noticing this omission. + + Made FreeBSD 2.0 changes: 1) added automatic sensing + of the FreeBSD 2.0 boot file path, using the + getbootfile(3) function (suggested by Ade Barkah); + 2) changed kvm_getprocs(3) function call to use + KERN_PROC_ALL symbol from , thus + eliminating incorrect use of the and + header files; and 3) removed + and header files + from the dialects/freebsd/include/2/sys subdirectory + of distribution. + + Tested under AIX 4.1.2. + +3.31 June 16, 1995 + Added the NOUSAGEONERR definition to allow lsof to + be compiled with the displaying of usage information + after option error messages disabled. Lsof is + distributed without the NOUSAGEONERR definition -- + i.e., usage output is displayed after option error + messages. + + Worked on documentation in the 00* files and the + man page, adding tables of contents, making usage + more consistent, trying to insure proper dialect + titles, and inserting some notes about distribution + restrictions (few) and warranty (none). + + Fixed Motorola V88 R32V3 bug in handling Internet + files. This bug was introduced some time ago, but + I have only recently been able to test under R32V3 + again. + +3.32 June 23, 1995 + Added the ability to the Linux nlist() function to + automatically detect that the kernel binary is COFF + or ELF form. Also corrected the UID_ARG cast from + int to u_int. These changes were suggested by + Michael Shields . Joseph J. + Nuspl Jr. provided a + test system. + + Updated lsof for HP-UX 10. Richard Allen + provided a test system. The hpux stanza in the + HP-UX configure script was updated to sense the + HP-UX version automatically, and to sense the + availability of CCITT header files in /etc/conf/x25. + +3.33 June 28, 1994 + Added options to select "field" output that can be + parsed by a subsequent program. (The -f, -F, and + -0 options form the selection set.) Provided + sample awk and Perl scripts for parsing and displaying + field output. This feature was suggested by Dan + Bernstein . + + Tested under PTX 4.0.3. + +3.34 June 30, 1995 + Changed display of file offset to decimal in the + form "0t12345678" if it is less than 100,000,000. + The offset is displayed in hexadecimal in the form + "0x12abcdef" if it is larger than 99,999,999. + + Changed inode field output from signed to unsigned + decimal. Updated the list_fields.{awk,perl} and + list_NULf.perl5 scripts. + + Documented the truncated inode output form (leading + `*' and 5 digits) for inodes that are too large + for the output field; thanks go to Leonard Sitongia + for pointing out that + this wasn't documented. + +3.35 July 9, 1995 + Added loopback file system support to Solaris with + advice from Casper Dik . + + Removed the NOUSAGEONERR compile option in favor of + producing a shortened usage message when option + errors are detected. + + Marty Leisner provided + code to validate the Linux system map file (/System.map + or /zSystem.map). If lsof detects that the system + map file doesn't match the booted kernel, it + complains and quits. + + Updated host name cache to include dot forms -- e.g., + when the host name can't be obtained via gethostbydddr(). + This prevents subsequent lookup delays for the same address. + +3.36 July 20, 1995 + Updated kernel name cache handling to assume a default + size for pointer-linked caches (DEC OSF/1, FreeBSD, + NetBSD, and SGI IRIX 5.3) when the kernel's cache size + variable has a value of zero. A warning is issued, + but lsof proceeds to read and use the name cache. + + Folded rdev1.frag into rdev.frag by supporting a + HASDNAMLEN #define for those dialects whose DIRTYPE + structure has a d_namlen definition. + + Updated Linux distribution to avoid using d_namlen + from struct dirent if the Linux version is 1.2.10 or + greater. This avoidance might work on earlier + version of Linux, too, but I have no way of telling. + + Added support for FreeBSD 2.0.5. Ade Barkah + provided a test system. + + Added WARNDEVACCESS definition to machine.h control + the default issuance of device directory and + subdirectory access errors. + + Changed options: + + -m (mount warning) option deleted + -c (core file) option changed to -m + -c option redesignated as command selector + -d (device warning) option deleted + -d option redesignated as file descriptor selector + -O (order) option changed to less-overhead option + -r option added to enable repeat mode + + Added a repeat mode in which lsof will display + output, sleep for the number of seconds defined by + the repeat-mode option, -r , and then + display output again, doing this repetitively until + it receives an interrupt or quit signal. This + option is much more efficient for monitoring a file + than calling lsof repeatedly from a shell script, + since it entails only one set of lsof startup + operations. + + The CANDOCHILD compile-time option has been removed. + The -O run-time option will do the same thing. + +3.37 July 27, 1995 + Fixed incorrect setting of low-overhead flag from -O + option. + + Marty Leisner reports that d_namlen is not needed + under Linux 1.2.8. Changed the #if test that sets + HASDNAMLEN accordingly. + + Made more changes to option processing: combined + -f, -F, and -0 into -F (-0 becomes a field identifier + value for -F); now allow -F, -g, -r, and -S to have + an optional value; made -F? (help) and -F0 (all + fields plus NUL terminator) special forms of -F; + and added support for --. These option processing + changes are handled with a local getopt() function + (named GetOpt() to avoid confusion). + + Made yet another attempt to create "standard" + install and deinstall SunOS/Solaris Makefile rules. + + Corrected improper use of examine_lproc() when in + repeat mode. + +3.38 August 3, 1995 + Modified Linux and PTX to show TCP's "send next" + sequence number as the offset for TCP socket files. + + Added some version tests for Linux 1.3.0, provided by + Roman Gollent . + + Added some more PTX tests around code that shouldn't + be active when the NFS layered product is unavailable. + Mark Vasoll provided them. + +3.39 August 10, 1995 + Added generic support for dialect-specific elements + in the lfile structure. The HASLFILEADD and + SETLFILEADD macroes are used in lsof.h to define + the elements and in proc.c to preset them. Field + identifiers `1' through `9' are allocated to + dialect-specific files. The HASFIELDAP strings + define the -F? help text for the FieldSel[] table + of store.c, and LISTLFILEAP are macroes, used + in the print_proc() function of proc.c, to list + fields. ( is the field identifier.) Other + private element and field processing should be done + in dialect-specific modules. + + Used {HAS,SET}LFILEADD, HASFIELDAP[12], and + LISTLFILEAP[12] to define and list link count and + inode address lfile elements under PTX. Used the + -X option to control when the values are displayed. + +3.40 August 25, 1995 + Added support for Solaris 2.5-BETA, including + rudimentary support for door files and extensive + support for fattach'ed files with the help of Henry + Katz , Joseph Kowalski + , and Mike Tracy + . + + Changed most dialects to use slightly safer fchown() + on the device cache file. Changed dvch.frag to + avoid creating a device cache file that is owned + by root. Cleared caches when reading of device + cache file fails and removed extra NL from device + cache error messages. + + After receiving yet another complaint about Makefile + install rules, I decided to remove all install and + deinstall rules from the distribution Makefiles. + The Makefiles now contain a set of comments (echo + commands) that describe what the install rule might + be. The lsof user is now free to construct install + and deinstall rules that meet local conventions + and preferences. + +3.41 September 5, 1995 + Changed Linux kernel symbol handling to avoid the + stripping of leading `_' characters that was + installed in revision 3.32. (Recent Linux kernels + have some symbols that are the same except for the + leading `_'.) + + The Linux kernel loader format is now determined + by testing for "_system_utsname" (COFF) and + "system_utsname" (ELF) in the symbols returned by + the get_kernel_syms() syscall. If neither or both + symbols are present, a warning is issued and COFF + format is assumed. If the loader format is COFF, + then kernel symbols important to lsof are assumed + to have a leading `_'. + + Because recent Linux releases add a parameter + hashing suffix to kernel symbols, lsof removes it + before comparing kernel symbol names and addresses + to those in /[z]System.map. + + Marty Leisner, Keith Parks , + and Michael Shields helped me with the Linux changes. + + After much discussion of the security of the device + cache file on the bugtraq mailing list, I adopted + a suggestion from Dave Sill . + His suggestion removes the world-writable device + cache file from /tmp and creates instead a mode + 0600 device cache file in the home directory of + the real user ID that is executing lsof. Lsof + issues a warning message when it does this. (The + warning can be suppressed with -w.) The HASDCACHE + definition becomes a relative path. When lsof is + run from root, it will create a device cache file + in root's home directory, e.g., / or /root, but + the file will be readable and writable only by + root. This should make the device cache file much + more secure. + + Added support for SGI IRIX 6.1. Dave Olson provided + technical support and Przemek Klosowski supplied + a test system. Since Przemek's system formerly + supported my testing of lsof for IRIX 6.0, its + update to 6.1 means I have not tested lsof under + IRIX 6.0 since revision 3.39. + + Changed name list structure element initialization + for V/88 to make gcc happy. Albert Chin-A-Young + suggested this. + +3.42 September 7, 1995 + Changed device cache file naming process to add a + suffix formed of an underscore, followed by the + first component of the host name returned by + gethostname(2). This allows lsof to create separate + device cache files for each host from which it is + run for the same UID when the UID's home directory + is shared by the hosts via NFS. + +3.43 September 12, 1995 + Enabled SCO searching for stream files and Release + 5.0 Unix domain socket files by name. + + Defined HASDOPTPATH for dialects that can supply + a path with -Db, -Dr, and -Du. Defined it for all + but DC/OSx, UnixWare, and V/88. Used it in the + ctrl_dcache() function of arg.c to enable and + disable -Db, -Dr, and -Du. + + Used is_readable() in dvch.frag when opening the + device cache file for reading. + +3.44 September 19, 1995 + Added test for setuid-root state so that some + security-sensitive code now disabled by #define's + can by dynamically disabled. + + Enhanced, extended, improved, secured, and documented + formation and use of the device cache file path. + More options, more carefully controlled are now + available. A separate documentation file, 00DCACHE, + accompanies the distribution to explain the device + cache file path handling. + + Where possible, lsof now drops setgid permission + as soon as possible. Two exceptions are the Solaris + and SunOS versions of lsof which need to close and + re-open kvm access. Setuid-root lsof implementations + must retain that permission to access files in /proc. + + Improved the README.lsof_ file that + appears in the lsof wrapper tar file with help from + Jon A. Tankersley . + + Added Veritas file system support to the HP-UX + dialect port. + + Albert Chin-A-Young tested lsof under Motorola V/88 + R40V4.1 and provided #if/#else/#endif changes. + +3.45 September 20, 1995 + Enabled setgid permission surrender for Solaris + and SunOS dialects. + + +3.46 October 5, 1995 + Added more conversions to HASPERSDC, based on + suggestions from John Gardiner Myers . + They make it possible to locate the personal device + cache file in /tmp, for example. A new -D function, + `?', reports device cache file name formation + information. + + Gained access to AIX 4.1.3, compiled lsof there, and + found that it seems to work. + + Tested lsof under FreeBSD 2.1.0-950726-SNAP. John + Clear kindly provided + a test system. + + Added a Customize script that helps with the job + of modifying some important (e.g., security-related) + compile-time options. Configure calls Customize, + but can be told not to with the -n|-nocust options. + + Fixed over-sensitivity to unexpected kernel file + structure pointer values in HP-UX version that led + to premature exit. Lionel Cons + pointed out the problem. + + With the help of Leif Hedstrom + identified a pair of conflicting Solaris 2.4 patches + that prevent lsof from working. A work-around is + described in section 00FAQ. + +3.47 October 16, 1995 + Enabled suppression of an HP-UX pstat() warning + message. Added big_brother.perl5 to field output + scripts/ subdirectory. Both changes are courtesy + of Lionel Cons . + + Added a test for automount detritus in the SCO mount + table. + + Added kernel name cache support to SCO dialect. + Modified most name cache support to report full + path names without the intervening `` -- '' when + possible. + + Added an Inventory script to check the contents of + the distribution, using a new file, 00MANIFEST. + The Configure script normally calls Inventory. + Changed the -n option to Configure to avoid calling + the Customize and Inventory scripts and dropped + the -nocust option. The presence of .neverCust + suppresses the calling of Customize; .neverInv, + Inventory. The Inventory script creates .ck00MAN + when it completes, so that subsequent calls to + Inventory won't check the inventory again -- although + the caller is given the opportunity to have the + inventory rechecked. + + Added PTX 4.1.0 support, courtesy of a test system + supplied by Kevin Smallwood . + + Picked lint for gcc in the V/88 dproc.c from hints + provided by Albert Chin-A-Young . + +3.48 October 20, 1995 + Improved root directory detection during name cache + lookup. + + Remove the Novell UnixWare and Pyramid DC/OSx ports + from the distribution, because I have not been able + to test them for 40 or more revisions. Their pieces + may now be found on vic.cc.purdue.edu in + pub/tools/unix/lsof/OLD/{binaries,dialects}. + + Corrected an error in Customize that caused it to + incorrectly redefine HASSYSDC to HASSYSDCPATH. This + was reported by Michael Beirne . + + Made sure that lsof will compile when HASDCACHE is + undefined. A problem with a reference to the DChelp + symbol was reported by Vasco Pedro + and resolved by always defining DChelp. + + Corrected handling of -c and -m options. + + Corrected the reading of the SCO /etc/mnttab. Bela + Lubkin helped me understand its + special multi-line format. The "nothing/nowhere" + lines are continuations of the file system directory + and device names when either are > 31 characters. + + Corrected SCO version list in Configure help output. + + Update special SCO name cache code to make it more + robust. + + Add support for IRIX 6.0.1 with the help of Eberhard + Mater . + +3.49 October 25, 1995 + Removed need for dialects/sgi/irix601hdr subdirectory, + replacing it with one created by dialects/sgi/Mksrc + and composed of symbolic links to dialects/sgi/irix6hdr. + Eberhard Mater did the testing. + + Added file system inode number to the local file + structures of the DEC OSF/1, DYNIX, EP/IX, HP-UX, + NeXT, PTX, RISCos, SGI, Sun, and V/88 dialects. + Added code to name cache, node, and VFS functions + to set the file system inode number and use it for + faster recognition of files on the file system + mount point. + + Added kernel name cache support to Linux. This + has been tested only under release 1.2.13. + +3.50 October 31, 1995 + Updated 00FAQ: reorganized and renumbered sections; + added some DEC OSF/1 sections; section about the + Solaris and SunOS Sun KERNELBASE. + + Added an alternative readdir() function, called + ReadDir(), to dialects/osf/ddev.c This function + was supplied by Duncan McEwan , + who discovered that the getdirentries() function + in DEC OSF/1 versions 3.[02] returns an incorrect + length for the /dev/fd directory when it is a file + system mount point. Modified the Configure script + to define USELOCALREADDIR for 3.[02] to enable + using this local function. + + Modified the Solaris/SunOS Mksrc to create a dummy + (empty) kernelbase.h for Solaris 2.5 (5.5). + +3.51 November 8, 1995 + Modified the Configure script to declare the kernel + state definitions appropriate to IRIX 6.1 on IP21 + and IP26 platforms. News of the need for this came + from Kate Fissell + and Dave Olson . + + Modified the SGI IRIX dproc.c to provide more + information when the kernel's idea of the size of + a proc structure doesn't match sizeof(struct proc). + This mismatch can occur if the wrong kernel state + definitions are used to condition the header files + (e.g., ) included when compiling dproc.c. + + Made the -i option with no arguments equivalent to + the -n option -- i.e., they both select the listing + of all open Internet files. + + Supplied a missing "you" in the Customize script + introduction. John Jackson + noticed the omission. + + Modified the Customize script to put long messages + in here documents rather than echo statements, so + that changing and reformatting them is easier. + John Jackson offered this helpful suggestion. + + Fixed a port number cast bug in Solaris 2.[45], + courtesy of information and code supplied by Allan + Black . + + Automated the detection of Solaris 2.4 patches + 101945-32 and 102303-02 that cause the installed + kernel's user structure to differ from the one + defined by because of a patch to + that wasn't applied when the kernel + was built. The Configure script invokes an alternate + auxv.h file and warns that it is doing so. + + Fixed a problem with Inventory script that shows up + on systems where echo is not an sh built-in. The + bug was reported by Scott Ballew . + +3.52 November 27, 1995 + Added support for Linux versions 1.3.22 and above, + courtesy of changes supplied by Keith Parks + . + + Changed -d option processing to allow specification + of a comma-separated list of file descriptors. + + Modified SCO support to allow NFS code to be optional + at the request of Dave Gilbert + . + + Enabled HP-UX 10.x version to display device and + inode numbers for FIFOs. The problem was reported + by Jeff Earickson . + +3.53 December 8, 1995 + Enhanced NeXTSTEP FIFO reporting. + + Fixed a formatting problem in the man page, reported + by Angel Li . + + Added support for DEC OSF/1 4.0-BETA. Angel Li + provided the test system. + + Added a -v option to display lsof version information. + Marty Leisner suggested + this. + + Replaced touch with echo in Inventory script to avoid + DEC OSF/1 4.0 complaint. + + Tested under PTX 4.1.2. + +3.54 December 15, 1995 + Added support for IRIX 6.2-BETA. The support for + older IRIX versions changed considerably in the + process. Revision 3.54 has been tested under these + older IRIX versions: 5.3 and 6.1. Angel Li + provided a test + system and Jim Brown + helped. + + Tested under AIX 4.1.4. + + Decommissioned the DYNIX port -- I no longer have + access to a test system. + + Added the HASXOPT_ROOT define to allow the lsof + builder to restrict the use of the dialect-specific + X option (AIX and PTX currently) to processes whose + real user ID is root. Updated the Customize script + to provide an easy mechanism to change HASXOPT_ROOT. + AIX uses HASXOPT_ROOT; PTX does not. This change + was suggested by R. Lindsay Todd . + +3.55 December 22, 1995 + Eliminated need for modified DEC OSF/1 headers by + using #undef and #define statements. Chip Stettler + helped test. + + Added quick start documentation file, 00QUICKSTART, + containing examples and explanations of lsof use. + + Verified that lsof works under the released Solaris + 2.5. + +3.56 January 2, 1996 + Corrected lock reporting for Solaris 2.[345]. + + Corrected Linux malloc() kernel symbol handling bug, + reported by Keith Parks . + + Corrected AIX loader text file selection bug; it + caused all process IDs to be listed when the -t + option and one file system name was specified. + The bug was reported by Christopher C. Evert + . + + Made sure Solaris Kb variable is zeroed before + first use. + +3.57 January 12, 1996 + Updated SunOS port to obtain lock information from + v_filocks and the lock_list struct to which it + points. + + Changed -H to -n. The function formerly performed + by -n can be done by using -i with no address. + + Updated Linux FIFO support so that the display for FIFOs + contains device number, inode number, and NAME. Johannes + Kroeger reported the lack of + these items in the Linux FIFO display. + + Added RCS identification to header files, Makefiles, + and common fragments. + + Added BSDI BSD/OS support for 2.0, 2.0.1, and 2.1-BETA. + Terry Kennedy kindly provided a + 2.1-BETA test system and did the 2.0.1 testing. + + Modified the Inventory script to compensate for dialects + that have an expr that doesn't set its exit code when + string matches fail. + + Converted internal representations of file offset and + size to unsigned long. + + Corrected bug in NetBSD lock handling. + + Corrected bug in FreeBSD file system type name handling. + + Keith Parks reports lsof + 3.57 compiles and runs under Linux 1.3.56. + +3.58 February 7, 1996 + Changed Solaris 2.3 configuration to pass the level + of patch 101318 to the source code. This allows + a Solaris 2.3 lock handling difference to be + accommodated. + + Updated 00QUICKSTART to reflect -n and -H changes + made in revision 3.57. (Ooops!) + + Changed Configure script to compile lsof for SCO + versions beyond 3.2v5.0.0 as it is compiled for + 3.2v5.0.0. Bill Campbell + reported he has done this successfully. + + Added information to 00FAQ about a Linux kernel + symbol problem (section 3.7.6) and included a + patch to work around it. The patch + was supplied by Keith Parks . + +3.59 February 21, 1996 + In response to a query from Louis Rayman + , added special support + for Solaris "sockmod" streams, used for Unix domain + sockets, that allows their file system device type + and inode number to be displayed. It also allows + lsof to search for them by name or type (-U). + + Added range handling to -d argument. + + Added the display of CDFS file size to DEC OSF/1 output. + + Added an include of to keep gcc on HP-UX + 10 happy. Blair Zajac + suggested it. + + Added Ultrix 4.5 to support list, courtesy of a + notification from Gregory Neil Shapiro . + + Added AFS support for Solaris 2.4 at the request + of Michael L. Lewis and Phillip + Moore . Phillip helped me locate + a test host, generously provided by Heidi Hornstein + with support from Chaskiel + Moses Grundman and Sushila + R. Subramanian . Lsof is + configured for AFS with a new script, AFSConfig. + + Used a SunOS 4.1.4 test system, provided by Chaskiel, + to extend Solaris AFS support to cover SunOS. Used + another test system, provided by Chaskiel, to extend + AFS support to NEXTSTEP 3.2. + + Tested lsof under AFS on yet another Chaskiel-provided + system, running Linux 1.2.13 and AFS 3.3, and found + that lsof needed no changes to recognize its AFS files. + + Used a test system, provided by Curt Freeland + and Terry McCoy + to extend Solaris AFS + support to Solaris 2.5 with AFS 3.4-Alpha. + + Added the [-A A] option for specifying the name list + file that contains dynamic kernel module addresses. + This is defined for the NEXTSTEP, SunOS, and Solaris + implementations. + + Added stty isig handling (where appropriate) to + the Customize and Inventory scripts. + + Added support to Solaris for the nfs3 file system + type. Its absence was reported by Patrick D. + Sullivan . + + In response to a report from Tigran Aivazian + corrected bug in Linux + local nlist() function and based the default kernel + loader format on a Configure test for CONFIG_KERNEL_ELF + in /usr/src/linux/include/linux/autoconf.h. + + Fixed a bug in name cache exploration for BSD-derived + dialects -- e.g., FreeBSD. + + Updated for NetBSD 1.1. + +3.60 February 27, 1996 + Improved Unix domain socket reporting for Solaris. + Louis Rayman helped test. + + Added warning messages about absence of Linux + CONFIG_MODULES definition in autoconf.h, leading + to lack of get_kernel_syms() support. Tigran + Aivazian supplied the + information. + +3.61 March 8, 1996 + Added AFS support for AIX and HP-UX and verified + that the lsof Ultrix version needs no additions + for AFS. Chaskiel Moses Grundman + provided the HP-UX and Ultrix test systems. Jan + Tax provided an AIX 4.1.4 test + system. Bob Cook provided + 3.2.5 and 4.1.4 test systems. + + Fixed minor problems and made improvements to + NEXTSTEP, Solaris, and SunOS AFS support. Changed + the AFSConfig script to ask for AFS version. + + During the Hp-UX AFS work, added the hpuxgcc + abbreviation to the Configure script for configuring + lsof to be compiled with gcc under lsof. + + Fixed a NetBSD mount structure array referencing + bug, reported by Peter Svensson . + + Dropped support for Motorola V/88, because I no + longer have access to test systems. + + Added rudimentary support for the IRIX XFS file + system type, pending more information. + +3.61 March 12, 1996 + Corrected misuse of the LSOF_DINC shell variable + in the Configure script for HP-UX and Solaris. + Larry Rogers pointed out this problem. + Also removed an obsolete irix52 abbreviation from + Configure. + + I didn't consider this change sufficient to warrant + a new version number, but just rebuilt the 3.61 + distribution. + +3.62 March 26, 1996 + Updated AFS comments in 00README. + + Supplied missing break statement in a N_VXFS case + clause in the HP-UX dnode.c. + + Added Veritas file support to PTX, courtesy of code + supplied by Laurent Montaron and + help from Kevin Smallwood . + Created two new source modules (dnode[12].c) to + separate PTX header file node definitions and thus + eliminate symbol conflicts. Laurent did most of + the testing. + + Added tests to BSDI, FreeBSD, HP-UX, IRIX, NetBSD, + NEXTSTEP, PTX, Solaris and SunOS lsof versions that + allow them to report on unknown file system types. + + Added IRIX 6.0.1 #if/#else/#endif support in response + to a report and suggested modifications from Scott + Presnell . + + With the help of Dave Olson + improved the IRIX 6.2-BETA XFS support. + +3.62 March 27, 1996 + Corrected SunOS incompatibility with last-minute + addition of Solaris MVFS support. The problem was + reported by Larry W. Virden . + + I didn't consider this change sufficient to warrant + a new version number, but just rebuilt the 3.62 + distribution. + +3.63 April 11, 1996 + Upgraded Solaris MVFS support. In the process, + enlarged Solaris and SunOS DEVICE output column. + + Changed SunOS 4.1.x Configure to make -DNOCONST + Makefile definition dependent on SC version. + + At the suggestion of John DiMarco + suppressed two warning messages: the device cache + file creation warning when -Db has been specified; + and the one issued when -D? is used with a non-writable + system-wide device cache file and there is no other + writable path. Also at John's suggestion redid + the manner in which child processes are used to + avoid kernel calls that might block; the net effect + of the change is that normally one child process + is required, rather than one per kernel call. + + Refined the NetBSD test for with + a Configure script change. + + Modified Configure script to compute AIX version + with ``uname -rv'' when /usr/bin/oslevel can't be + executed. Stephen C. Woods + suggested this. + + Disabled conflicting prototype definitions in the + local netdb.h used when the SCO 3.0 netdb.h is + missing. Disabled #include of unless + the SCO version is 5.0 or above. Don Kirouac + pointed out these problems. + +3.63 April 15, 1996 + Improved Configure's SunOS 4.1.x CC test for compiler + support of the const keyword and avoided Configure's + ``test -f {Customize,Inventory}'' (because the + Ultrix test doesn't grok -x) in response to a report + from Larry Schwimmer . + + I didn't consider this change sufficient to warrant + a new version number, but just rebuilt the 3.63 + distribution. + +3.64 April 26, 1996 + Added a negate option for entries of the -u list. + Kurt Hillig suggested + it. + + Added a check for legal protocols in the -i option. + + Adjusted the Configure and SGI MkKernOpts scripts + to handle more IRIX situations per instructions + from Dave Olson . + + Added support for HP-UX 10.10, courtesy of a test + system provided by Mark Bixby . + +3.65 May 20, 1995 + Corrected errors, reported by Arne H. Juul + , in use of IRIX stat structure. + + Added support for the IRIX 6.2 cachefs, following + a report from Peter Van Epp . + + Added clone support for AIX 4.1.4 and above. + + Adjusted the IRIX configuration to work properly + for 64 bit IRIX 6.2 systems. Richard Chycoski + and Peter Van Epp + provided a test system. + +3.66 June 19, 1996 + Improved the HP-UX VXFS test in the Configure + script, based on a report from Robert Hall + . + + Added SCO information to 00FAQ. Added information + about lsof slowness and nameserver. + + Added an untested Configure abbreviation for Solaris + 2.5.1. + + Ambrose Li supplied + a Linux change that avoids a conflict with the + d_namlen definition in versions 1.99.8 and above. + + Added compiler version identification to the + Configure script for AIX and Solaris cc. + + Added support for FreeBSD 2.2-960612-SNAP. Ade + Barkah provided a test system. + +3.67 Jult 1, 1996 + Made miscellanous documentation corrections. + + Added support for gcc under AIX 4.1 and above, + including an aixgcc Configure abbreviation, and a + work-around for an long long alignment problem. + Stuart D. Gathman and Waldemar + Zurowski helped me to understand + the gcc problem and devise the work-around. + +3.68 July 17, 1996 + Malgorzata Roos : pointed + out the AIX lsof didn't report the inode number + for named pipes (FIFOs) and wouldn't locate them + by name; _and_ supplied a fix. (Now _that's_ the + kind of bug report I like. :-) + + Update Configure script to clean out aix41* + subdirectories created by the AIX gcc work-around. + + Taught IRIX lsof how to report the correct device + number, inode number, and size for named NFS pipes. + + Taught HP-UX 9.x lsof how to report size/offset + and inode number for named NFS pipes. (HP-UX 10.x + already knows.) + + Taught DEC OSF/1 (errr, Digital Unix) lsof to report + device and inode numbers correctly for named pipes. + Because stat(2) under DEC OSF/1 V3.2 doesn't report + the device number correctly for named pipes, lsof + can't locate them by name, but it can do that under + DEC OSF/1 V2.0. + + Taught EP/IX 2.1.1 lsof to report device and inode + numbers correctly for named pipes. + + Taught versions of lsof for PTX 2.1.6 and 4.1.2 to + report device and inode numbers correctly for named + pipes. + + Taught RISC/os 4.52 lsof to report device and inode + numbers correctly for named pipes. + + Taught versions of lsof for Ultrix 4.2 and above + to report inode numbers and file systems names + correctly for named pipes (FIFOs). + + Added safety check when trying to get a sockaddr_un + structure from a BSDI, FreeBSD, or NetBSD mbuf. + + Improved documentation on install permissions in + 00README at the suggestion of Paul Wickman + . + + Installed support for the DTYPE_PIPE file structure + in FreeBSD 2.2. Changed the FreeBSD version symbol + from _FREEBSDV to FREEBSDV. + + Added support for NetBSD 1.2. + +3.69 July 30, 1996 + Added block device name caching and reporting for + all dialects. + + Improved (I think) IRIX 6.2 64 bit configuration. + + Eliminated C name space pollution by removing the + leading `_' from all dialect version symbols that + had it: _AIXV, _BSDIV, _OSF1V, _ADVFSV, _EPIXV, + _HPUXV, _IRIXV, _PTXV, _RISCOSV, and _SCOV. + + Changed decosf stanza in Configure script to + automatically detect the subdirectory of /sys (or + /usr/sys) that contain's the configuration header + files for the machine. Added a 00FAQ entry about + this. + +3.70 August 9, 1996 + Set the execute bits on scripts/big_brother.perl5. + Changed -H in scripts/watch_a_file.perl to -n. + Retained all the command name characters that are + available in the proc or user struct for field + output. Improved sample install rules for BSDI + and HP-UX. Strengthened HP-UX CCITT test in the + Configure script. Gildas Perrot + suggested these changes. + + Improved Solaris local TCP address reporting, based + on a bug report from John Caruso . + + Improved HP-UX VFS handling, and corrected a bug + in VFS handling, based on bug reports from David + Capshaw . + + Added support to -i argument handling to allow port + lists and ranges, and service name lists to be + specified. John DuBois + suggested this. + + Dropped support for IRIX 4.0.5H. Revived support + for IRIX 5.2, courtesy of a test system from Dan + Trinkle . + +3.71 August 15, 1996 + Improved handling of port ranges specified with + the -i option. Improved performance when the only + option is -i. + +3.72 August 28, 1996 + Fixed bugs and typos in SCO mount table handling. + + Added support for OpenBSD (only the i386 architecture + type has been tested), using the NetBSD dialect + sources. David Mazieres + provided a test system. + + Added fdesc file system support to FreeBSD, NetBSD + and OpenBSD. Changed the way proc file system + support is activated with additions to the Configure + script and changes to the dialect machine.h files. + Dropped the distribution of the Freebsd + header file. + + Added support for PTX 4.1.4. + +3.73 September 5, 1996 + Added information to 00FAQ for missing CCITT HP-UX + header file x25L3.h. Pasi Kaara + provided the information. + + Changed AIX header file #include pattern to prevent + gcc's loader from complaining about multiply defined + etherbroadcastaddr[], fddi_broadcastaddr[], and + ie5_broadcastaddr[] CONST u_char arrays from + . (The AIX loader doesn't + complain.) David Capshaw + reported this problem. + + Removed the HASPWSTAYOPEN definition; it was only + used for two dialects that are no longer supported. + + Corrected a bug in UID cacheing that appeared during + long repeat-mode (-r) operations. The bug was + reported by Peter Van Epp . When + in repeat mode the UID cache will be cleared when + /etc/passwd changes. + + Fixed a bug in FreeBSD support that causes a + segmentation fault on VBAD vnodes. + + Deleted ultrix22 from Configure and RHF from Ultrix + source files. Dropped 2.2 from support list. + +3.74 September 6, 1996 + Corrected a bug in FreeBSD's proc table handling, + reported by David O'Brien . + +3.75 September 9, 1996 + Added FreeBSD proc table handling fix from revision + 3.74 to BSDI, NetBSD, and OpenBSD dialects. + + Improved Solaris VFS handling. + + Added pipe handling to OpenBSD. Changed Configure + script to define OPENBSDV for OpenBSD and used that + definition to include the pipe support in the NetBSD + sources. The Configure script defines NETBSDV for + NetBSD. So far neither dialect has any #if/#else/#endif + blocks that depend on version number. + + Added support for AIX 4.2. + +3.76 September 21, 1996 + Plugged a memory leak in command handling, introduced + in revision 3.70. The bug was reported by Peter + Van Epp . + + Fixed a bug in the reporting of size for IRIX 5.3 + EFS files, introduced in revision 3.69 by the name + space pollution abatement. The _IRIXV definition + was used in the IRIX 5.x private efs_inode.h header + file to configure the inode stricture for IRIX 5.3, + so I changed the tests to use IRIXV. + + Changed information on the AIX Stale Segment ID bug + to reflect the fact that IBM now says they won't + fix it. They have closed the APAR. + + Disabled the AIX gcc long long alignment hack under + AIX 4.2, because it doesn't work there. Installed + a fatal error message in Configure that gcc can't + be used to compile lsof under AIX 4.2 until a work- + around can be developed. + + Upgraded BSDI, FreeBSD (2.0 and above), NetBSD + (1.1B and above), and OpenBSD lock reporting. + David Mazieres reported + the need for the upgrade. + + Made similar lock reporting upgrades to (versions + tested are in parentheses): AIX (4.1.4 and 4.2); + DEC OSF/1 (2.0 and 3.2d); EP/IX (2.1.1); HP-UX (9.x + and 10.10); IRIX (5.2, 5.3, and 6.2); Linux; NEXTSTEP + (3.1); PTX (2.1.6 and 4.2); RISCos; SCO (releases + 3.0 and 5.0); Solaris (2.5); SunOS (4.1.3); and + Ultrix (4.2). + + Updated man page and 00FAQ with more information on + lock reporting. + + Updated PTX lsof for 4.2. Upgraded HP-UX lsof for + 10.20. Used a test system, provided by Richard + Allen , and received testing assistance + from Marc Winkler . + + Changed handling of Internet addresses to avoid DNS + lookup operations when the address has clearly not + been selected. John DuBois suggested + this. + +3.77 October 2, 1996 + Changed SCO Configure stanza to call nm by its full + path, thus avoiding possible confusion. The change + was suggested by Jean-Pierre Radley . + + Added changes to allow lsof to be compiled by gcc + under AIX 4.2 -- enabled some gcc-specific typedef's + in the AIX machine.h and disabled the Configure + script's rejection of aixgcc for AIX 4.2. The + typdef's were supplied by Henry Grebler + . + + Based on information supplied by Henry and David + J. Wilson , invented a + description and processing for an unknown file + struct that is established by AIX 4.2 (at least) + for X processes when DISPLAY=:0.0. For convenience + I gave its type the DTYPE_PIPE definition, but that + may be incorrect. + + Fixed some Solaris 2.[34] errors in locking code, + added at 3.76, that I couldn't test. Rainer Orth + reported the problem + and supplied the fixes. + + Made Configure script supply NeXTSTEP 3.x version + in Makefile so that the shadow vnode locking code, + introduced in 3.76, would be disabled for NeXTSTEP + 3.0. Rainer Orth discovered this problem, too. + + Added reporting of UNIX domain socket inode numbers + for Linux version 2.0 and above. The addition was + supplied by Matthew Burt . + + Enhanced file searching to report all instances of + references to automounted file systems, even when + they're direct mounts not yet realized. Enhanced + Solaris 2.5 lsof to grok autofs nodes. Victoria + H. Lau pointed out the need + for these enhancements and helped test them. + + Changed AIX lock length test so it will work with + gcc under AIX 4.2. + + Changed PTX HAS_VXFS symbol, indicating presence + of VxFS, to HASVXFS for consistency with the HP-UX + form of the symbol. + +3.78 October 14, 1996 + Changed strtol() call in private Linux nlist() + function to strtoul(). Linux kernel addresses at + 2.1.0 have their top bit set and appear to be + negative to strtol(). This information was provided + by Marty Leisner . + Marty also notes that other, unknown-as-of-yet + problems prevent lsof from working under 2.1. He + is investigating, since I don't have access to a + 2.1 system. + + Added definitions to machine.h for a private file + struct type (HASPRIVFILETYPE and PRIVFILETYPE) that + can be accommodated without changing prfp.frag, + much as HASPIPEFN works for PIPE file struct types. + + Used the new private file struct type support to + support the AIX f_type=0xf that DISPLAY=:0.0 causes. + Changed its output TYPE from PIPE to SMT; displayed + file size as buffer size less free bytes in buffer; + enabled recognizion under AIX 4.1.4. Mike Feldman + and others helped + me identify this file as a Shared Memory Transport + (SMT) socket. + + Corrected a function prototype in the HP-UX dnode.c + for HP-UX 10 and greater; gcc objected; HP's cc did + not. Christian Krackowizer + reported the problem. + + Made AFSConfig script more capable of locating the + cell's root directory. Updated AFS documentation + in 00FAQ and 00README. Both were suggested by + Timothy Miller . + + Installed update to big_brother.perl5 script from + Lionel Cons . + +3.79 October 29, 1996 + Added support for IRIX 6.4, courtesy of a test + system provided by Angel Li . + Fixed FIFO and NFS3 bugs in IRIX 6.2 lsof in the + process. Lsof has not been tested under IRIX 6.3, + but the Configure script has a stanza for it. + + Changed device functions to use stat() instead of + lstat(). Used WARNDEVACCESS to suppress stat(2) + failure messages. + + Tested under OpenBSD 2.0. + +3.80 November 8, 1996 + Corrected comments in 00README about using the + sunos413 and sunos413cc Configure abbreviations. + + Made some Configure and Customize script changes, + suggested by Bruce Jerrick . + + Added missing elements to definition of local + Solaris 2.3 lock_descriptor structure so that + dnode.c will compile and work properly under it. + Corrected a bug in Solaris 2.[34] lock descriptor + handling. + +3.81 November 14, 1996 + Corrected error in the "invented" HP-UX 10.20 proc + struct. The erroneous struct definition named the + set-UID member as the UID member, resulting in + occasional incorrect UID attributions in lsof + output. + + At the suggestion of Larry Schwimmer + , changed AFSConfig + to use awk to get the cell name from + /usr/etc/vice/ThisCell, thus avoiding a problem + when the cell name line has more than one word. + + Added -DSWASH to IRIX 6.2 options propagated from + the kernel build CCOPTS to lsof's Makefile. Randolph + J. Herber did the detective + work that revealed the need for this. IRIX 6.2 patch + 1488 added -DSWASH and its effects. + +3.82 December 11, 1996 + Updated Configure script for FreeBSD 3.0 and SCO + OpenServer 5.0.[24]. FreeBSD Configure script + change was supplied by David E. O'Brien + and SCO Configure script change + was supplied by Bela Lubkin . + + Tested lsof under FreeBSD 3.0, courtesy of a test + system provided by Ade Barkah . + + Added changes to support SCO OpenServer 5.0.4 + (Comet), supplied by Bela Lubkin . + + Added support for UnixWare 2.1. D. Chris Daniels + provided a test system and Bela + Lubkin provided technical assistance. + + Added support for Pyramid DC/OSx 1.1 and Reliant + UNIX 5.43. Bruce Beare and Kevin + Smith provided test systems + and technical assistance. This dialect version + must run setuid-root, since it accesses proc and + user structures vic the /proc file system. + + Tested under PTX 2.1.9 and added support for PTX + 4.2.1. + + At Bela Lubkin's suggestion added a commercial to + the lsof man page, -h option, and -v option output, + telling where to get the latest revision. This + entailed large scale rearrangement of the -h output + to keep it as short as possible. It also involved + shortening the -X explanation for PTX. + + Made sure that address segment access errors didn't + incorrectly force the listing of a process. This + fix was needed by the Sun, Pyramid, and UnixWare + ports. + + Corrected bug in the way the local device table is + sorted. + +3.83 December 30, 1996 + Added support for Solaris 2.6 (Beta) with help from + Casper Dik , May Jackson + , Joseph Kowalski + , and the Solaris 2.6 Beta test + program. + + Fixed an inode file system type processing bug in + SCO OpenServ 5.0 and greater, reported by Robert + Lipe . + + Fixed bugs in SCO kernel name cache probing, courtesy + of code and suggestions from Bela Lubkin . + + Revised kernel name list handling to remove the need + for changing two files (dlsof.h and dstore.c) when + altering, removing, or adding name list symbols. + All dialects were affected. + + Added support for SCO OpenServer event "clones." + Robert Lipe need for their support and Bela Lubkin + provided technical assistance in identifying them. + + Added display of bound name to Solaris UNIX domain + socket file handling. + + Correct bug in SunOS address space ("txt" file) + handling. + + Tested under UnixWare 2.1.1. + + Changed SGI IRIX lsof to use the kernel's proc + struct size when striding through its proc table + (IRIX versions below 6.4). The proc struct size + difference warning is still issued, and lsof still + uses the proc struct size and proc struct from + to read and process proc table + information. Added a note to 00FAQ about this. + + Deferred Internet host and port name lookups to + print time, thus avoiding lookups for files that + are not listed. + +3.84 January 13, 1997 + Updated the Pyramid private configuration script, + MkKernOpts, to propagate the R4000 definition for + DC/OSx systems so equipped. Anthony Shortland + pointed out the need + for this and Kevin Smith provided + access to a test system. + + Added information to 00FAQ about UDP ports for + which lsof can't find users, because the ports are + reserved to the kernel and aren't associated with + open files. + +3.85 January 17, 1987 + The DEC OSF/1 kernel name cache can be processed + as a simple table, rather than a linked list, so + changed the interface to rnam.frag accordingly. + + Added a new optional output field, parent process + ID (PPID). The -R option (for paRent) selects it, + and the `R' field identifier labels it. Updated + some scripts to handle it and developed two new + scripts, idrlogin.perl and idrlogin.perl5, to + use it in locating nework (rlogind and telnetd) + source addresses for shell processes. Added some + information about the new scripts to 00QUICKSTART. + +3.86 January 30, 1997 + Add explanation of why device warning messages + disappear when the device cache file is used. + + Changed Linux Configure stanza to check more + places for the [z]System.map file and warn if + the one located differs in date from /vmlinuz. + Bjorn S. Nilsson suggested + this for easier configuration at Linux 2.0.28. + + Changed Linux Confifgure stanza to check for the + presence of fl_fd, fl_file, and fl_whence in the + file_lock structure of and define + symbols appropriately. + + Changed Linux lock testing to test task structure + pointer (fl_owner) from file_lock struct as well + as (possibly) the file struct pointer (fl_file) or + file decriptor number (fl_fd) to identify the lock + owner, depending on what HAS_FL_* symbols were + defined by Configure's file_lock structure examination. + Added section to Linux Problems in 00FAQ about this. + + Corrected 00FAQ reference in Configure's Solaris + 2.4 stanza. + +3.87 February 11, 1997 + Corrected setting of VxFS device number for HP-UX + and PTX. + + Added VM map flag test #if/#else/#endif for recent + versions of FreeBSD 3.0, supplied by Chris Timmons + . + + Added a #define that removes a conflict between a + signal() prototype in the IRIX 6.4 + and one in its , exposed when cachefs + support is enabled. Wolfgang Hecht + identified the need for + this addition and helped test it. Refined IRIX + proc struct size test, warning, and use. + + Revised Linux system map file handling (yet again) + to search for the file at execution time, rather + than in the Configure script. Marty Leisner + suggested this. + + Added VxFS support to Solaris lsof with help from + Peter Radig . Philip Kizer + helped test. + + Added support for PTX 4.3, thanks to access provided + by Peter Jordan . + +3.87 February 11, 1997 +supplement Updated FreeBSD kernel name list handling. + +3.88 February 17, 1997 + Added documentation files -- 00.README.FIRST[_] + and 00RELEASE.SUMMARY_ -- to the distribution. + + +Vic Abell +Purdue University Computing Center +February 17, 1997 diff --git a/OLD/lsof_h.dbg b/OLD/lsof_h.dbg new file mode 100644 index 0000000..e483fa3 --- /dev/null +++ b/OLD/lsof_h.dbg @@ -0,0 +1,22 @@ + + +/* DEBUG -- where "appropriate in lsof.h */ +#define calloc next_calloc +#define free next_free +#define malloc next_malloc +#define realloc next_realloc +#include +#undef calloc +#undef free +#undef malloc +#undef realloc +#define calloc(n, s) lsofcalloc(__FILE__, __LINE__, n, s) +#define free(p) lsoffree(__FILE__, __LINE__, p) +#define malloc(s) lsofmalloc(__FILE__, __LINE__, s) +#define realloc(p, s) lsofrealloc(__FILE__, __LINE__, p, s) +extern void *lsofcalloc(char *f, int l, size_t n, size_t s); +extern void lsoffree(char *f, int l, void *p); +extern void *lsofmalloc(char *f, int l, size_t s); +extern void *lsofrealloc(char *f, int l, void *p, size_t s); +extern int DBMon; +/* end DEBUG section for lsof.h */ diff --git a/OLD/main.c b/OLD/main.c new file mode 100644 index 0000000..054cdcd --- /dev/null +++ b/OLD/main.c @@ -0,0 +1,1876 @@ +/* + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: main.c,v 1.57 2015/07/07 20:16:58 abe Exp abe $"; +#endif + + +#include "lsof.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 */ + + +_PROTOTYPE(static int GetOpt,(int ct, char *opt[], char *rules, int *err)); +_PROTOTYPE(static char *sv_fmt_str,(char *f)); + + +/* + * main() - main function for lsof + */ + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int ad, c, i, n, rv, se1, se2, ss; + char *cp; + int err = 0; + int ev = 0; + 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; + +#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) */ + +/* + * Save program name. + */ + if ((Pn = strrchr(argv[0], '/'))) + Pn++; + else + Pn = argv[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; + +#if defined(HAS_CLOSEFROM) + (void) closefrom(3); +#else /* !defined(HAS_CLOSEFROM) */ + for (i = 3; i < MaxFd; i++) + (void) close(i); +#endif /* !defined(HAS_CLOSEFROM) */ + + while (((i = open("/dev/null", O_RDWR, 0)) >= 0) && (i < 2)) + ; + if (i < 0) + Exit(1); + 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; + if (!(Namech = (char *)malloc(MAXPATHLEN + 1))) { + (void) fprintf(stderr, "%s: no space for name buffer\n", Pn); + Exit(1); + } + Namechl = (size_t)(MAXPATHLEN + 1); +/* + * Create option mask. + */ + (void) snpf(options, sizeof(options), + "?a%sbc:%sD:d:%s%sf:F:g:hi:%s%slL:%s%snNo:Op:Pr:%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(argc, argv, options, &rv)) != EOF) { + if (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': + Fblock = 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 (enter_cmd_rx(GOv)) + err = 1; + } else { + if (enter_str_lst("-c", GOv, &Cmdl, &Cmdni, &Cmdnx)) + err = 1; + +#if defined(MAXSYSCMDL) + else if (Cmdl->len > MAXSYSCMDL) { + (void) fprintf(stderr, "%s: \"-c ", Pn); + (void) safestrprt(Cmdl->str, stderr, 2); + (void) fprintf(stderr, "\" length (%d) > what system", + Cmdl->len); + (void) fprintf(stderr, " provides (%d)\n", + MAXSYSCMDL); + Cmdl->len = 0; /* (to avoid later error report) */ + err = 1; + } +#endif /* defined(MAXSYSCMDL) */ + + } + break; + +#if defined(HASNCACHE) + case 'C': + Fncache = (GOp == '-') ? 0 : 1; + break; + +#endif /* defined(HASNCACHE) */ + case 'd': + if (GOp == '+') { + if (enter_dir(GOv, 0)) + err = 1; + else { + Selflags |= SELNM; + xover = 1; + } + } else { + if (enter_fd(GOv)) + err = 1; + } + break; + case 'D': + if (GOp == '+') { + if (enter_dir(GOv, 1)) + err = 1; + else { + Selflags |= SELNM; + xover = 1; + } + } else { + +#if defined(HASDCACHE) + if (ctrl_dcache(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(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'; + 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(PGID, GOv)) + err = 1; + } + Fpgid = 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(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': + Fovhd = (GOp == '-') ? 1 : 0; + break; + case 'p': + if (enter_id(PID, GOv)) + err = 1; + break; + case 'P': + Fport = (GOp == '-') ? 0 : 1; + break; + case 'r': + if (GOp == '+') + ev = 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 != 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: 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 result: \"%s\"\n", + Pn, (int)fmtl, cp); + Exit(1); + } + if (util_strftime(fmtr, fmtl - 1, fmt) < 1) { + (void) fprintf(stderr, "%s: illegal : \"%s\"\n", + Pn, fmt); + err = 1; + } + } + +#else /* !defined(HAS_STRFTIME) */ + (void) fprintf(stderr, "%s: m 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(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(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(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(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 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())) { + 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(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); + Exit(1); + } + 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(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)); + } + Exit(1); + } + } + DevDev = sb.st_dev; +/* + * Process the file arguments. + */ + if (GOx1 < argc) { + if (ck_file_arg(GOx1, argc, argv, Ffilesys, 0, (struct stat *)NULL)) + usage(1, 0, 0); + } +/* + * Do dialect-specific initialization. + */ + initialize(); + if (Sfile) + (void) hashSfile(); + +#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(); +#endif /* defined(WILLDROPGID) */ + + +#if defined(HASDCACHE) +/* + * If there is a device cache, prepare the device table. + */ + if (DCstate) + readdev(0); +#endif /* defined(HASDCACHE) */ + +/* + * Define the size and offset print formats. + */ + (void) snpf(options, sizeof(options), "%%%su", INODEPSPEC); + InodeFmt_d = sv_fmt_str(options); + (void) snpf(options, sizeof(options), "%%#%sx", INODEPSPEC); + InodeFmt_x = sv_fmt_str(options); + (void) snpf(options, sizeof(options), "0t%%%su", SZOFFPSPEC); + SzOffFmt_0t = sv_fmt_str(options); + (void) snpf(options, sizeof(options), "%%%su", SZOFFPSPEC); + SzOffFmt_d = sv_fmt_str(options); + (void) snpf(options, sizeof(options), "%%*%su", SZOFFPSPEC); + SzOffFmt_dv = sv_fmt_str(options); + (void) snpf(options, sizeof(options), "%%#%sx", SZOFFPSPEC); + SzOffFmt_x = sv_fmt_str(options); + +#if defined(HASMNTSUP) +/* + * Report mount supplement information, as requested. + */ + if (MntSup == 1) { + (void) readmnt(); + Exit(0); + } +#endif /* defined(HASMNTSUP) */ + +/* + * Gather and report process information every RptTm seconds. + */ + if (RptTm) + CkPasswd = 1; + do { + + /* + * Gather information about processes. + */ + gather_proc_info(); + /* + * 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); + Exit(1); + } + } + 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 print + */ + if (FeptE) { + lf = Lf; + + /* + * Check the files that have been selected for printing by + * by some selection criterion other than being a pipe. + */ + for (i = 0; i < Nlproc; i++) { + Lp = (Nlproc > 1) ? slp[i] : &Lproc[i]; + if (Lp->pss && (Lp->ept & EPT_PIPE)) + (void) process_pinfo(0); + } + /* + * In a second pass, process unselected endpoint files, + * possibly selecting them for printing. + */ + for (i = 0; i < Nlproc; i++) { + Lp = (Nlproc > 1) ? slp[i] : &Lproc[i]; + if (Lp->ept & EPT_PIPE_END) + (void) process_pinfo(1); + } + +# if defined(HASUXSOCKEPT) + /* + * Process UNIX socket endpoint files in a similar fashion. + */ + for (i = 0; i < Nlproc; i++) { + Lp = (Nlproc > 1) ? slp[i] : &Lproc[i]; + if (Lp->pss && (Lp->ept & EPT_UXS)) + (void) process_uxsinfo(0); + } + for (i = 0; i < Nlproc; i++) { + Lp = (Nlproc > 1) ? slp[i] : &Lproc[i]; + if (Lp->ept & EPT_UXS_END) { + (void) process_uxsinfo(1); + } + } +# endif /* defined(HASUXSOCKEPT) */ + + 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(); PrPass < 2; PrPass++) { + for (i = n = 0; i < Nlproc; i++) { + Lp = (Nlproc > 1) ? slp[i] : &Lproc[i]; + if (Lp->pss) { + if (print_proc()) + 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(); +#endif /* defined(HASEPTOPTS) */ + + if (rc) { + if (!n) + break; + else + ev = 0; + } + +#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(); + (void) sleep(RptTm); + Hdr = Nlproc = 0; + CkPasswd = 1; + } + } 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(); + rv = 0; + for (str = Cmdl; str; str = str->next) { + + /* + * Check command specifications. + */ + if (str->f) + continue; + rv = 1; + 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 = 1; + 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 = 1; + 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 = 1; + 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 = 1; + 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 = 1; + 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 = 1; + 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 = 1; + 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 = 1; + 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 = 1; + 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 = 1; + 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 = 1; + 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 = 1; + 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 = 1; + 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 = 1; + 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 = 1; + 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 = 1; + Exit(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(ct, opt, rules, err) + 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(f) + 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); + Exit(1); + } + (void) snpf(cp, l, "%s", f); + return(cp); +} diff --git a/OLD/main.c.old b/OLD/main.c.old new file mode 100644 index 0000000..7266b82 --- /dev/null +++ b/OLD/main.c.old @@ -0,0 +1,1870 @@ +/* + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: main.c,v 1.57 2015/07/07 20:16:58 abe Exp abe $"; +#endif + + +#include "lsof.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 */ + + +_PROTOTYPE(static int GetOpt,(int ct, char *opt[], char *rules, int *err)); +_PROTOTYPE(static char *sv_fmt_str,(char *f)); + + +/* + * main() - main function for lsof + */ + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int ad, c, i, n, rv, se1, se2, ss; + char *cp; + int err = 0; + int ev = 0; + 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; + +#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) */ + +/* + * Save program name. + */ + if ((Pn = strrchr(argv[0], '/'))) + Pn++; + else + Pn = argv[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; + for (i = 3; i < MaxFd; i++) + (void) close(i); + while (((i = open("/dev/null", O_RDWR, 0)) >= 0) && (i < 2)) + ; + if (i < 0) + Exit(1); + 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; + if (!(Namech = (char *)malloc(MAXPATHLEN + 1))) { + (void) fprintf(stderr, "%s: no space for name buffer\n", Pn); + Exit(1); + } + Namechl = (size_t)(MAXPATHLEN + 1); +/* + * Create option mask. + */ + (void) snpf(options, sizeof(options), + "?a%sbc:%sD:d:%s%sf:F:g:hi:%s%slL:%s%snNo:Op:Pr:%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(argc, argv, options, &rv)) != EOF) { + if (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': + Fblock = 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 (enter_cmd_rx(GOv)) + err = 1; + } else { + if (enter_str_lst("-c", GOv, &Cmdl, &Cmdni, &Cmdnx)) + err = 1; + +#if defined(MAXSYSCMDL) + else if (Cmdl->len > MAXSYSCMDL) { + (void) fprintf(stderr, "%s: \"-c ", Pn); + (void) safestrprt(Cmdl->str, stderr, 2); + (void) fprintf(stderr, "\" length (%d) > what system", + Cmdl->len); + (void) fprintf(stderr, " provides (%d)\n", + MAXSYSCMDL); + Cmdl->len = 0; /* (to avoid later error report) */ + err = 1; + } +#endif /* defined(MAXSYSCMDL) */ + + } + break; + +#if defined(HASNCACHE) + case 'C': + Fncache = (GOp == '-') ? 0 : 1; + break; + +#endif /* defined(HASNCACHE) */ + case 'd': + if (GOp == '+') { + if (enter_dir(GOv, 0)) + err = 1; + else { + Selflags |= SELNM; + xover = 1; + } + } else { + if (enter_fd(GOv)) + err = 1; + } + break; + case 'D': + if (GOp == '+') { + if (enter_dir(GOv, 1)) + err = 1; + else { + Selflags |= SELNM; + xover = 1; + } + } else { + +#if defined(HASDCACHE) + if (ctrl_dcache(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(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'; + 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(PGID, GOv)) + err = 1; + } + Fpgid = 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(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': + Fovhd = (GOp == '-') ? 1 : 0; + break; + case 'p': + if (enter_id(PID, GOv)) + err = 1; + break; + case 'P': + Fport = (GOp == '-') ? 0 : 1; + break; + case 'r': + if (GOp == '+') + ev = 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 != 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: 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 result: \"%s\"\n", + Pn, (int)fmtl, cp); + Exit(1); + } + if (util_strftime(fmtr, fmtl - 1, fmt) < 1) { + (void) fprintf(stderr, "%s: illegal : \"%s\"\n", + Pn, fmt); + err = 1; + } + } + +#else /* !defined(HAS_STRFTIME) */ + (void) fprintf(stderr, "%s: m 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(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(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(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(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 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())) { + 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(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); + Exit(1); + } + 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(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)); + } + Exit(1); + } + } + DevDev = sb.st_dev; +/* + * Process the file arguments. + */ + if (GOx1 < argc) { + if (ck_file_arg(GOx1, argc, argv, Ffilesys, 0, (struct stat *)NULL)) + usage(1, 0, 0); + } +/* + * Do dialect-specific initialization. + */ + initialize(); + if (Sfile) + (void) hashSfile(); + +#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(); +#endif /* defined(WILLDROPGID) */ + + +#if defined(HASDCACHE) +/* + * If there is a device cache, prepare the device table. + */ + if (DCstate) + readdev(0); +#endif /* defined(HASDCACHE) */ + +/* + * Define the size and offset print formats. + */ + (void) snpf(options, sizeof(options), "%%%su", INODEPSPEC); + InodeFmt_d = sv_fmt_str(options); + (void) snpf(options, sizeof(options), "%%#%sx", INODEPSPEC); + InodeFmt_x = sv_fmt_str(options); + (void) snpf(options, sizeof(options), "0t%%%su", SZOFFPSPEC); + SzOffFmt_0t = sv_fmt_str(options); + (void) snpf(options, sizeof(options), "%%%su", SZOFFPSPEC); + SzOffFmt_d = sv_fmt_str(options); + (void) snpf(options, sizeof(options), "%%*%su", SZOFFPSPEC); + SzOffFmt_dv = sv_fmt_str(options); + (void) snpf(options, sizeof(options), "%%#%sx", SZOFFPSPEC); + SzOffFmt_x = sv_fmt_str(options); + +#if defined(HASMNTSUP) +/* + * Report mount supplement information, as requested. + */ + if (MntSup == 1) { + (void) readmnt(); + Exit(0); + } +#endif /* defined(HASMNTSUP) */ + +/* + * Gather and report process information every RptTm seconds. + */ + if (RptTm) + CkPasswd = 1; + do { + + /* + * Gather information about processes. + */ + gather_proc_info(); + /* + * 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); + Exit(1); + } + } + 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 print + */ + if (FeptE) { + lf = Lf; + + /* + * Check the files that have been selected for printing by + * by some selection criterion other than being a pipe. + */ + for (i = 0; i < Nlproc; i++) { + Lp = (Nlproc > 1) ? slp[i] : &Lproc[i]; + if (Lp->pss && (Lp->ept & EPT_PIPE)) + (void) process_pinfo(0); + } + /* + * In a second pass, process unselected endpoint files, + * possibly selecting them for printing. + */ + for (i = 0; i < Nlproc; i++) { + Lp = (Nlproc > 1) ? slp[i] : &Lproc[i]; + if (Lp->ept & EPT_PIPE_END) + (void) process_pinfo(1); + } + +# if defined(HASUXSOCKEPT) + /* + * Process UNIX socket endpoint files in a similar fashion. + */ + for (i = 0; i < Nlproc; i++) { + Lp = (Nlproc > 1) ? slp[i] : &Lproc[i]; + if (Lp->pss && (Lp->ept & EPT_UXS)) + (void) process_uxsinfo(0); + } + for (i = 0; i < Nlproc; i++) { + Lp = (Nlproc > 1) ? slp[i] : &Lproc[i]; + if (Lp->ept & EPT_UXS_END) { + (void) process_uxsinfo(1); + } + } +# endif /* defined(HASUXSOCKEPT) */ + + 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(); PrPass < 2; PrPass++) { + for (i = n = 0; i < Nlproc; i++) { + Lp = (Nlproc > 1) ? slp[i] : &Lproc[i]; + if (Lp->pss) { + if (print_proc()) + 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(); +#endif /* defined(HASEPTOPTS) */ + + if (rc) { + if (!n) + break; + else + ev = 0; + } + +#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(); + (void) sleep(RptTm); + Hdr = Nlproc = 0; + CkPasswd = 1; + } + } 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(); + rv = 0; + for (str = Cmdl; str; str = str->next) { + + /* + * Check command specifications. + */ + if (str->f) + continue; + rv = 1; + 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 = 1; + 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 = 1; + 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 = 1; + 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 = 1; + 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 = 1; + 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 = 1; + 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 = 1; + 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 = 1; + 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 = 1; + 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 = 1; + 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 = 1; + 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 = 1; + 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 = 1; + 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 = 1; + 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 = 1; + 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 = 1; + Exit(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(ct, opt, rules, err) + 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(f) + 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); + Exit(1); + } + (void) snpf(cp, l, "%s", f); + return(cp); +} diff --git a/OLD/main_c.dbg b/OLD/main_c.dbg new file mode 100644 index 0000000..89668f5 --- /dev/null +++ b/OLD/main_c.dbg @@ -0,0 +1,53 @@ +char psb[64]; /* DEBUG in main()'s declarations */ +(void) snpf(psb, sizeof(psb), "/bin/ps -l -p %d", Mypid); /* DEBUG before the do loop */ +DBMon=1; /* DEBUG in the do loop before gather_proc_info() */ +system(psb); /* DEBUG in the sleep section after fflush() */ +/* start DEBUG section after the end of main() */ + +int DBMon=0; + +void * +lsofcalloc(char *f, int l, size_t n, size_t s) +{ +#undef calloc + void *v; + v = (void *)calloc(n, s); + if (DBMon) + (void) fprintf(stderr, "MEMa %#x %s:%d calloc(%d, %d)\n", + v, f, l, n, s); + return(v); +} + +void +lsoffree(char *f, int l, void *p) +{ +#undef free + (void) free(p); + if (DBMon) + (void) fprintf(stderr, "MEMf %#x %s:%d free\n", p, f, l); +} + +void * +lsofmalloc(char *f, int l, size_t s) +{ +#undef malloc + void *v; + v = (void *)malloc(s); + if (DBMon) + (void) fprintf(stderr, "MEMa %#x %s:%d malloc(%d)\n", v, f, l, s); + return(v); +} + +void * +lsofrealloc(char *f, int l, void *p, size_t s) +{ +#undef realloc + void *v; + v = (void *)realloc(p, s); + if (DBMon) + (void) fprintf(stderr, "MEMr %#x %#x %s:%d realloc(%d)\n", + p, v, f, l, s); + return(v); +} + +/* end DEBUG section */ diff --git a/OLD/misc.c b/OLD/misc.c new file mode 100644 index 0000000..ba79ffd --- /dev/null +++ b/OLD/misc.c @@ -0,0 +1,1687 @@ +/* + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: misc.c,v 1.28 2014/10/13 22:36:20 abe Exp abe $"; +#endif + + +#include "lsof.h" + +#if defined(HASWIDECHAR) +# if defined(WIDECHARINCL) +#include WIDECHARINCL +# endif /* defined(WIDECHARINCL) */ +# if defined(HASWCTYPE_H) +#include +# endif /* defined(HASWCTYPE_H) */ +#endif /* defined(HASWIDECHAR) */ + + +/* + * Local definitions + */ + +#if !defined(MAXSYMLINKS) +#define MAXSYMLINKS 32 +#endif /* !defined(MAXSYMLINKS) */ + + +/* + * Local function prototypes + */ + +_PROTOTYPE(static void closePipes,(void)); +_PROTOTYPE(static int dolstat,(char *path, char *buf, int len)); +_PROTOTYPE(static int dostat,(char *path, char *buf, int len)); +_PROTOTYPE(static int doreadlink,(char *path, char *buf, int len)); +_PROTOTYPE(static int doinchild,(int (*fn)(), char *fp, char *rbuf, int rbln)); + +#if defined(HASINTSIGNAL) +_PROTOTYPE(static int handleint,(int sig)); +#else /* !defined(HASINTSIGNAL) */ +_PROTOTYPE(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(d) + 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); + Exit(1); + } + 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))); + Exit(1); + } + 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() +{ + 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(a1, a2) + COMP_P *a1, *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)); +} + + +/* + * doinchild() -- do a function in a child process + */ + +static int +doinchild(fn, fp, rbuf, rbln) + 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); + Exit(1); + } +/* + * 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(); + 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)); + Exit(1); + } + /* + * Fork a child to execute functions. + */ + if ((Cpid = fork()) == 0) { + + /* + * Begin the child process. + */ + + int r_al, r_rbln; + char r_arg[MAXPATHLEN+1], r_rbuf[MAXPATHLEN+1]; + int (*r_fn)(); + /* + * Close sufficient open file descriptors except Pipes[0] and + * Pipes[3]. + */ + +#if defined(HAS_DUP2) && defined(HAS_CLOSEFROM) + int rc; + + rc = dup2(Pipes[0], 0); + if (rc < 0) { + (void) fprintf(stderr, + "%s: can't dup fd 0 for pipe: %s\n", + Pn, strerror(errno)); + Exit(1); + } + Pipes[0] = 0; + rc = dup2(Pipes[3], 1); + if (rc < 0) { + (void) fprintf(stderr, + "%s: can't dup fd 3 for pipe: %s\n", + Pn, strerror(errno)); + Exit(1); + } + Pipes[3] = 1; + (void) closefrom(2); + Pipes[1] = -1; + Pipes[2] = -1; + +#else /* !defined(HAS_DUP2) && !defined(HAS_CLOSEFROM) */ + 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) && defined(HAS_CLOSEFROM) */ + + /* + * 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_rbuf)) + break; + rv = r_fn(r_arg, 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_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)); + Exit(1); + } + (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(); + 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(path, rbuf, rbln) + 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(path, rbuf, rbln) + 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(path, rbuf, rbln) + 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() +{ + if (!Setuidroot && Setgid) { + if (setgid(Mygid) < 0) { + (void) fprintf(stderr, "%s: can't setgid(%d): %s\n", + Pn, (int)Mygid, strerror(errno)); + Exit(1); + } + Setgid = 0; + } +} +#endif /* defined(WILLDROPGID) */ + + +/* + * enter_dev_ch() - enter device characters in file structure + */ + +void +enter_dev_ch(m) + 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); + Exit(1); + } + 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(ty, nm, nr) + 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); + Exit(1); + } + 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); + Exit(1); + } +/* + * 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); + Exit(1); + } + } + 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); + Exit(1); + } + } + TcpStAlloc = TcpNstates; + } + } + return; + } +/* + * Check the name and number. + */ + if ((len = (size_t)strlen(nm)) < 1) { + (void) fprintf(stderr, + "%s: bad %s name (\"%s\"), number=%d\n", Pn, ty, nm, nr); + Exit(1); + } +/* + * 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); + Exit(1); + } +/* + * 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); + Exit(1); + } + 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); + Exit(1); + } + 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(m) + 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); + Exit(1); + } + if (Lf->nm) + (void) free((FREE_P *)Lf->nm); + Lf->nm = mp; +} + + +/* + * Exit() - do a clean exit() + */ + +void +Exit(xv) + int xv; /* exit() value */ +{ + (void) childx(); + +#if defined(HASDCACHE) + if (DCrebuilt && !Fwarn) + (void) fprintf(stderr, "%s: WARNING: %s was updated.\n", + Pn, DCpath[DCpathX]); +#endif /* defined(HASDCACHE) */ + + exit(xv); +} + + +#if defined(HASNLIST) +/* + * get_Nl_value() - get Nl value for nickname + */ + +int +get_Nl_value(nn, d, v) + 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(sig) + int sig; +{ + longjmp(Jmp_buf, 1); +} + + +/* + * hashbyname() - hash by name + */ + +int +hashbyname(nm, mod) + 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(ia, p, af) + 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(src, rlp) + 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(s1, l1, s2, l2, s3, l3, clp) + 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(path, msg) + 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(path, buf) + 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(dolstat, path, (char *)buf, sizeof(struct stat))); +} + + +/* + * Readlink() - read and interpret file system symbolic links + */ + +char * +Readlink(arg) + 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(arg); + } +/* + * 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(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(arg); + } +/* + * 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); + Exit(1); + } + 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); + stk = (char **)NULL; + ss = sx = 0; + 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(s1)); +} + + +#if defined(HASSTREAMS) +/* + * readstdata() - read stream's stdata structure + */ + +int +readstdata(addr, buf) + KA_T addr; /* stdata address in kernel*/ + struct stdata *buf; /* buffer addess */ +{ + if (!addr + || kread(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(addr, buf) + 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(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(addr, buf, len) + KA_T addr; /* module ID name address in kernel */ + char *buf; /* receiving buffer address */ + READLEN_T len; /* buffer length */ +{ + if (!addr || kread(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(addr, buf) + KA_T addr; /* module info address in kernel */ + struct module_info *buf; /* receiving buffer address */ +{ + if (!addr || kread(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(addr, buf) + KA_T addr; /* queue info address in kernel */ + struct qinit *buf; /* receiving buffer address */ +{ + if (!addr || kread(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(c, cl) + 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(sp, flags) + 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(sp, fs, flags) + 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(sp, len, fs, flags) + 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(path, buf) + 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(dostat, path, (char *)buf, sizeof(struct stat))); +} + + +/* + * stkdir() - stack directory name + */ + +void +stkdir(p) + 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); + Exit(1); + } + } +/* + * 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); + Exit(1); + } + Dstkx++; +} + + +/* + * x2dev() - convert hexadecimal ASCII string to device number + */ + +char * +x2dev(s, d) + 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/OLD/print.c b/OLD/print.c new file mode 100644 index 0000000..c0af284 --- /dev/null +++ b/OLD/print.c @@ -0,0 +1,2821 @@ +/* + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: print.c,v 1.54 2012/04/10 16:30:51 abe Exp $"; +#endif + + +#include "lsof.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) +_PROTOTYPE(static void fill_portmap,(void)); +_PROTOTYPE(static void update_portmap,(struct porttab *pt, char *pn)); +#endif /* !defined(HASNORPC_H) */ + +_PROTOTYPE(static void fill_porttab,(void)); +_PROTOTYPE(static char *lkup_port,(int p, int pr, int src)); +_PROTOTYPE(static char *lkup_svcnam,(int h, int p, int pr, int ss)); +_PROTOTYPE(static int printinaddr,(void)); + + +/* + * endnm() - locate end of Namech + */ + +char * +endnm(sz) + 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); +} + + +#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() +{ + 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) */ + +/* + * 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); + Exit(1); + } + 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); + Exit(1); + } + 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() +{ + 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); + Exit(1); + } + 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); + Exit(1); + } + 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(ia, af) + 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); + Exit(1); + } +/* + * 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); + Exit(1); + } + } + 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(p, pr, src) + 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]; + static int pm = 0; + 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"); + Exit(1); + } + } + } + +#if !defined(HASNORPC_H) +/* + * If we're looking up program names for portmapped ports, make sure the + * portmap table has been loaded. + */ + if (FportMap && !pm) { + (void) fill_portmap(); + pm++; + } +#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(h, p, pr, 0) : (char *)NULL; + if (!pn) { + (void) snpf(pb, sizeof(pb), "%d", p); + pn = pb; + } + (void) update_portmap(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(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); + Exit(1); + } +/* + * 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); + Exit(1); + } + 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(h, p, pr, ss) + 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(); + ptf++; + ss = 0; + } + return((char *)NULL); +} + + +/* + * print_file() - print file + */ + +void +print_file() +{ + char buf[128]; + char *cp = (char *)NULL; + dev_t dev; + int devs, len; + + 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 (TaskPrtFl) + (void) printf(" %*s", TidColW, TIDTTL); +#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. + */ + cp = (Lp->cmd && *Lp->cmd != '\0') ? 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. + */ + if (!PrPass) { + if (Lp->tid) { + (void) snpf(buf, sizeof(buf), "%d", Lp->tid); + if ((len = strlen(buf)) > TidColW) + TidColW = len; + TaskPrtFl = 1; + } + } else if (TaskPrtFl) { + if (Lp->tid) + (void) printf(" %*d", TidColW, Lp->tid); + else + (void) printf(" %*s", TidColW, ""); + } +#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((UID_ARG)Lp->uid, NULL))) > UserColW) + UserColW = len; + } else + (void) printf(" %*.*s", UserColW, UserColW, + printuid((UID_ARG)Lp->uid, NULL)); +/* + * Size or print the file descriptor, access mode and lock status. + */ + if (!PrPass) { + (void) snpf(buf, sizeof(buf), "%s%c%c", + Lf->fd, + (Lf->lock == ' ') ? Lf->access + : (Lf->access == ' ') ? '-' + : Lf->access, + Lf->lock); + if ((len = strlen(buf)) > FdColW) + FdColW = len; + } else + (void) printf(" %*.*s%c%c", FdColW - 2, FdColW - 2, Lf->fd, + (Lf->lock == ' ') ? Lf->access + : (Lf->access == ' ') ? '-' + : Lf->access, + Lf->lock); +/* + * Size or print the type. + */ + if (!PrPass) { + if ((len = strlen(Lf->type)) > TypeColW) + TypeColW = len; + } else + (void) printf(" %*.*s", TypeColW, TypeColW, Lf->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(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 (Lf->sz_def) { + +#if defined(HASPRINTSZ) + cp = HASPRINTSZ(Lf); +#else /* !defined(HASPRINTSZ) */ + (void) snpf(buf, sizeof(buf), SzOffFmt_d, Lf->sz); + cp = buf; +#endif /* defined(HASPRINTSZ) */ + + len = strlen(cp); + } else if (Lf->off_def) { + +#if defined(HASPRINTOFF) + cp = HASPRINTOFF(Lf, 0); +#else /* !defined(HASPRINTOFF) */ + (void) snpf(buf, sizeof(buf), SzOffFmt_0t, Lf->off); + cp = buf; +#endif /* defined(HASPRINTOFF) */ + + len = strlen(cp); + if (OffDecDig && len > (OffDecDig + 2)) { + +#if defined(HASPRINTOFF) + cp = HASPRINTOFF(Lf, 1); +#else /* !defined(HASPRINTOFF) */ + (void) snpf(buf, sizeof(buf), SzOffFmt_x, Lf->off); + cp = buf; +#endif /* defined(HASPRINTOFF) */ + + len = strlen(cp); + } + } else + len = 0; + if (len > SzOffColW) + SzOffColW = len; + } else { + putchar(' '); + if (Lf->sz_def) + +#if defined(HASPRINTSZ) + (void) printf("%*.*s", SzOffColW, SzOffColW, HASPRINTSZ(Lf)); +#else /* !defined(HASPRINTSZ) */ + (void) printf(SzOffFmt_dv, SzOffColW, Lf->sz); +#endif /* defined(HASPRINTSZ) */ + + else if (Lf->off_def) { + +#if defined(HASPRINTOFF) + cp = HASPRINTOFF(Lf, 0); +#else /* !defined(HASPRINTOFF) */ + (void) snpf(buf, sizeof(buf), SzOffFmt_0t, Lf->off); + cp = buf; +#endif /* defined(HASPRINTOFF) */ + + if (OffDecDig && (int)strlen(cp) > (OffDecDig + 2)) { + +#if defined(HASPRINTOFF) + cp = HASPRINTOFF(Lf, 1); +#else /* !defined(HASPRINTOFF) */ + (void) snpf(buf, sizeof(buf), SzOffFmt_x, Lf->off); + cp = buf; +#endif /* defined(HASPRINTOFF) */ + + } + (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(Lf); +#else /* !defined(HASPRINTNM) */ + printname(1); +#endif /* defined(HASPRINTNM) */ + + } +} + + +/* + * printinaddr() - print Internet addresses + */ + +static int +printinaddr() +{ + 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((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((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; + } + } +#endif /* !defined(HASNORPC_H) */ + + if (strcasecmp(Lf->iproto, "TCP") == 0) + port = lkup_port(Lf->li[i].p, 0, src); + else if (strcasecmp(Lf->iproto, "UDP") == 0) + port = lkup_port(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() +{ + PrPass = (Ffield || Fterse) ? 1 : 0; + 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); + TaskPrtFl = 0; + +#if defined(HASTASKS) + TidColW = strlen(TIDTTL); +#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) */ + +} + + +#if !defined(HASPRIVPRIPP) +/* + * printiproto() - print Internet protocol name + */ + +void +printiproto(p) + 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) */ + + +/* + * printname() - print output name field + */ + +void +printname(nl) + 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()) + ps++; + goto print_nma; + } + if (((Lf->ntype == N_BLK) || (Lf->ntype == N_CHR)) + && Lf->dev_def && Lf->rdev_def + && printdevname(&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(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(); 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(); + +# if defined(NCACHELDSFX) + NCACHELDSFX +# endif /* defined(NCACHELDSFX) */ + + NcacheReload = 0; + } + if ((cp = ncache_lookup(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(0); + } + if (nl) + putchar('\n'); +} + + +/* + * printrawaddr() - print raw socket address + */ + +void +printrawaddr(sa) + struct sockaddr *sa; /* socket address */ +{ + char *ep; + size_t sz; + + ep = endnm(&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(ty) + 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(uid, ty) + 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)); + Exit(1); + } + } + /* + * 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 *)))); + Exit(1); + } + 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); + Exit(1); + } + (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); +} + + +/* + * printunkaf() - print unknown address family + */ + +void +printunkaf(fam, ty) + 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; +} + + +#if !defined(HASNORPC_H) +/* + * update_portmap() - update a portmap entry with its port number or service + * name + */ + +static void +update_portmap(pt, pn) + 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); + Exit(1); + } + (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) */ diff --git a/OLD/proc.c b/OLD/proc.c new file mode 100644 index 0000000..e181994 --- /dev/null +++ b/OLD/proc.c @@ -0,0 +1,1384 @@ +/* + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: proc.c,v 1.49 2015/07/07 20:16:58 abe Exp abe $"; +#endif + + +#include "lsof.h" + + +/* + * add_nma() - add to NAME column addition + */ + +void +add_nma(cp, len) + char *cp; /* string to add */ + int len; /* string length */ +{ + int nl; + + 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) { + (void) fprintf(stderr, "%s: no name addition space: PID %ld, FD %s", + Pn, (long)Lp->pid, Lf->fd); + Exit(1); + } + 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'; + } +} + + +#if defined(HASFSTRUCT) +_PROTOTYPE(static char *alloc_fflbuf,(char **bp, int *al, int lr)); + + +/* + * alloc_fflbuf() - allocate file flags print buffer + */ + +static char * +alloc_fflbuf(bp, al, lr) + 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); + Exit(1); + } + *al = sz; + return(*bp); +} +#endif /* defined(HASFSTRUCT) */ + + +/* + * alloc_lfile() - allocate local file structure space + */ + +void +alloc_lfile(nm, num) + char *nm; /* file descriptor name (may be NULL) */ + 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); + Exit(1); + } +/* + * Initialize the structure. + */ + Lf->access = Lf->lock = ' '; + 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; +#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] = Lf->type[0] = '\0'; + if (nm) { + (void) strncpy(Lf->fd, nm, FDLEN - 1); + Lf->fd[FDLEN - 1] = '\0'; + } else if (num >= 0) { + if (num < 10000) + (void) snpf(Lf->fd, sizeof(Lf->fd), "%4d", num); + else + (void) snpf(Lf->fd, sizeof(Lf->fd), "*%03d", num % 1000); + } else + Lf->fd[0] = '\0'; + 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 || (!nm && num < 0)) + return; + fds = ck_fd_status(nm, 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(pid, pgid, ppid, uid, cmd, pss, sf) + 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); + Exit(1); + } + 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); + Exit(1); + } + } + 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); + Exit(1); + } + +#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(nm, num) + char *nm; /* file descriptor name (may be NULL) */ + int num; /* file descriptor number -- -1 if + * none */ +{ + char *cp; + struct fd_lst *fp; + + if (!(fp = Fdl) || (!nm && num < 0)) + return(0); + if ((cp = nm)) { + while (*cp && *cp == ' ') + cp++; + } +/* + * Check for an exclusion match. + */ + if (FdlTy == 1) { + for (; fp; fp = fp->next) { + if (cp) { + if (fp->nm && strcmp(fp->nm, cp) == 0) + return(1); + continue; + } + if (num >= fp->lo && num <= fp->hi) + return(1); + } + return(0); + } +/* + * If Fdl isn't an exclusion list, check for an inclusion match. + */ + for (; fp; fp = fp->next) { + if (cp) { + if (fp->nm && strcmp(fp->nm, cp) == 0) + return(2); + continue; + } + if (num >= fp->lo && num <= fp->hi) + return(2); + } + return(0); +} + + +/* + * comppid() - compare PIDs + */ + +int +comppid(a1, a2) + COMP_P *a1, *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(la, lp, fa, fp, af) + 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(fa, fp, af)) ? 1 : 0; + m |= (la && is_nw_addr(la, lp, af)) ? 1 : 0; + if (m) + Lf->sf |= SELNA; + } +} + + +/* + * examine_lproc() - examine local process + * + * return: 1 = last process + */ + +int +examine_lproc() +{ + 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--; + } + } + if (Lp->pss && Npid == 1 && sbp) { + print_init(); + (void) print_proc(); + PrPass++; + if (PrPass < 2) + (void) print_proc(); + Lp->pss = 0; + } +/* + * 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(lp) + 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(cmd, pss, sf) + 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^" 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 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 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(lp, lf) + 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 + +#if defined(HASTASKS) +is_proc_excl(pid, pgid, uid, pss, sf, tid) +#else /* !defined(HASTASKS) */ +is_proc_excl(pid, pgid, uid, pss, sf) +#endif /* defined(HASTASKS) */ + + int pid; /* Process ID */ + int pgid; /* process group ID */ + UID_ARG uid; /* User ID */ + short *pss; /* process select state for lproc */ + short *sf; /* select flags for lproc */ + +#if defined(HASTASKS) + int tid; /* task ID (not a task if zero) */ +#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() +{ + 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; + } + +# 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) */ + + } +#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(f) + int f; /* function: + * 0 == process selected pipe + * 1 == process end point + */ +{ + struct lproc *ep; /* pipe endpoint process */ + struct lfile *ef; /* pipe endpoint file */ + int i; /* temporary index */ + char nma[1024]; /* name addition buffer */ + 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(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_pendinfo(Lf, pp))) { + + /* + * This pipe endpoint is linked to the selected pipe + * file. Add its PID and FD to the name column + * addition. + */ + ep = &Lproc[pp->lpx]; + ef = pp->lf; + for (i = 0; i < (FDLEN - 1); i++) { + if (ef->fd[i] != ' ') + break; + } + (void) snpf(nma, sizeof(nma) - 1, "%d,%.*s,%s%c", + ep->pid, CmdLim, ep->cmd,&ef->fd[i], + ef->access); + (void) add_nma(nma, strlen(nma)); + if (FeptE == 2) { + + /* + * 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; + } + pp = pp->next; + } + } while (pp); + } + break; + case 1: + if (!is_file_sel(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_pendinfo(Lf, pp))) { + ep = &Lproc[pp->lpx]; + ef = pp->lf; + for (i = 0; i < (FDLEN - 1); i++) { + if (ef->fd[i] != ' ') + break; + } + (void) snpf(nma, sizeof(nma) - 1, "%d,%.*s,%s%c", + ep->pid, CmdLim, ep->cmd, &ef->fd[i], + ef->access); + (void) add_nma(nma, strlen(nma)); + pp = pp->next; + } + } while (pp); + } + break; + } + } +} +#endif /* defined(HASEPTOPTS) */ + + +#if defined(HASFSTRUCT) +/* + * print_fflags() - print interpreted f_flag[s] + */ + +char * +print_fflags(ffg, pof) + 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(&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(&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(&bp, &bl, 0); + *bp = '\0'; + } + return(bp); +} +#endif /* defined(HASFSTRUCT) */ + + +/* + * print_proc() - print process + */ + +int +print_proc() +{ + char buf[128], *cp; + int lc, len, st, ty; + int rv = 0; + unsigned long ul; +/* + * 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(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(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((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(Lp, Lf)) + continue; + rv = 1; + /* + * If no field output selected, print dialect-specific formatted + * output. + */ + if (!Ffield) { + print_file(); + continue; + } + lc = st = 0; + if (FieldSel[LSOF_FIX_FD].st) { + + /* + * Skip leading spaces in the file descriptor. Print the field + * identifier even if there are no characters after leading + * spaces. + */ + for (cp = Lf->fd; *cp == ' '; cp++) + ; + (void) printf("%c%s%c", LSOF_FID_FD, cp, Terminator); + lc++; + } + /* + * Print selected fields. + */ + if (FieldSel[LSOF_FIX_ACCESS].st) { + (void) printf("%c%c%c", + LSOF_FID_ACCESS, Lf->access, Terminator); + lc++; + } + if (FieldSel[LSOF_FIX_LOCK].st) { + (void) printf("%c%c%c", LSOF_FID_LOCK, Lf->lock, Terminator); + lc++; + } + if (FieldSel[LSOF_FIX_TYPE].st) { + for (cp = Lf->type; *cp == ' '; cp++) + ; + if (*cp) { + (void) printf("%c%s%c", LSOF_FID_TYPE, cp, 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(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); + +#if defined(HASPRINTSZ) + cp = HASPRINTSZ(Lf); +#else /* !defined(HASPRINTSZ) */ + (void) snpf(buf, sizeof(buf), SzOffFmt_d, Lf->sz); + cp = buf; +#endif /* defined(HASPRINTSZ) */ + + (void) printf("%s", cp); + putchar(Terminator); + lc++; + } + if (FieldSel[LSOF_FIX_OFFSET].st && Lf->off_def) { + putchar(LSOF_FID_OFFSET); + +#if defined(HASPRINTOFF) + cp = HASPRINTOFF(Lf, 0); +#else /* !defined(HASPRINTOFF) */ + (void) snpf(buf, sizeof(buf), SzOffFmt_0t, Lf->off); + cp = buf; +#endif /* defined(HASPRINTOFF) */ + + len = strlen(cp); + if (OffDecDig && len > (OffDecDig + 2)) { + +#if defined(HASPRINTOFF) + cp = HASPRINTOFF(Lf, 1); +#else /* !defined(HASPRINTOFF) */ + (void) snpf(buf, sizeof(buf), SzOffFmt_x, Lf->off); + cp = buf; +#endif /* defined(HASPRINTOFF) */ + + } + (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(0); + putchar(Terminator); + lc++; + st++; + } + } + if (st == 0 && FieldSel[LSOF_FIX_NAME].st) { + putchar(LSOF_FID_NAME); + printname(0); + putchar(Terminator); + lc++; + } + if (Lf->lts.type >= 0 && FieldSel[LSOF_FIX_TCPTPI].st) { + print_tcptpi(0); + lc++; + } + if (Terminator == '\0' && lc) + putchar('\n'); + } + return(rv); +} diff --git a/OLD/zipme b/OLD/zipme new file mode 100755 index 0000000..33faade --- /dev/null +++ b/OLD/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 diff --git a/README.md b/README.md new file mode 100644 index 0000000..b7b5c3d --- /dev/null +++ b/README.md @@ -0,0 +1,45 @@ + +[![Cirrus CI FreeBSD 11 Build Status](https://api.cirrus-ci.com/github/lsof-org/lsof-legacy.svg?task=freebsd11&branch=master)](https://cirrus-ci.com/github/lsof-org/lsof-legacy) +[![Cirrus CI FreeBSD 12 Build Status](https://api.cirrus-ci.com/github/lsof-org/lsof-legacy.svg?task=freebsd12&branch=master)](https://cirrus-ci.com/github/lsof-org/lsof-legacy) +[![Travis CI Linux Build Status](https://travis-ci.org/lsof-org/lsof.svg?branch=master)](https://travis-ci.org/lsof-org/lsof) +[![Coveralls Linux Coverage Status on Travis CI](https://coveralls.io/repos/github/lsof-org/lsof-legacy/badge.svg?branch=master)](https://coveralls.io/github/lsof-org/lsof-legacy?branch=master) + +# lsof +lsof-org at GitHub team takes over the maintainership of lsof +originally 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 has supported many OSes. A term "dialect" represents code for +supporting a OSes. Because of limitted resources, we will maintain the +part of them. The current status of maintaince is as follows: + +
+
freebsd
+
partially maintained, and tested on Cirrus CI
+
linux
+
fully maintained, and tested on Travis CI
+
darwin
+
not maintained, but tested on Travis CI
+
+ +If you are interested in maintaining a dialect, let us know via the +issue tracker of GitHub (https://github.com/lsof-org/lsof). 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 are running another repository, lsof-org/"lsof-linux" derived from +lsof-4.91 that is also released by Vic. To the repository, we have +introduced some new features and fixes for building specific to +GNU/Linux. We will merge the fruits of "lsof-linux" repository to this +repository incrementally. If you are using GNU/Linux, you may want to +use the code in "lsof-linux" repository. + +lsof-org at GitHub team diff --git a/arg.c b/arg.c new file mode 100644 index 0000000..edbcc82 --- /dev/null +++ b/arg.c @@ -0,0 +1,2499 @@ +/* + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: arg.c,v 1.51 2012/04/10 16:30:06 abe Exp abe $"; +#endif + + +#include "lsof.h" + + +/* + * Local definitions + */ + +#define CMDRXINCR 32 /* CmdRx[] allocation increment */ + + +/* + * Local static variables + */ + +static int NCmdRxA = 0; /* space allocated to CmdRx[] */ + + +/* + * Local function prototypes + */ + +_PROTOTYPE(static int ckfd_range,(char *first, char *dash, char *last, int *lo, int *hi)); +_PROTOTYPE(static int enter_fd_lst,(char *nm, int lo, int hi, int excl)); +_PROTOTYPE(static int enter_nwad,(struct nwad *n, int sp, int ep, char *s, struct hostent *he)); +_PROTOTYPE(static struct hostent *lkup_hostnm,(char *hn, struct nwad *n)); +_PROTOTYPE(static char *isIPv4addr,(char *hn, unsigned char *a, int al)); + + +/* + * ckfd_range() - check fd range + */ + +static int +ckfd_range(first, dash, last, lo, hi) + 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(i, ac, av, fv, rs, sbp) + 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 */ +{ + 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(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); + Exit(1); + } + (void) strncpy(ap, path, k); + ap[k] = '\0'; + path = ap; + } + } + /* + * Check for file system argument. + */ + for (ftype = 1, mp = readmnt(), 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); + Exit(1); + } + } + mmp[nm++] = mp; + } + if (fv == 2 && nm == 0) { + (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); + Exit(1); + } + 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(fnm, &sb) != 0) { + int en = errno; + + (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(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); + Exit(1); + } + +#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); + Exit(1); + } + +#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); + Exit(1); + } + +#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); + Exit(1); + } + 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 (!ss) + err = 1; + return((int)err); +} + + +#if defined(HASDCACHE) +/* + * ctrl_dcache() - enter device cache control + */ + +int +ctrl_dcache(c) + 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); + Exit(1); + } + } + return(0); +} +#endif /* defined(HASDCACHE) */ + + +/* + * enter_cmd_rx() - enter command regular expression + */ + +int +enter_cmd_rx(x) + char *x; /* regular expression */ +{ + 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; +/* + * Make sure the supplied string starts a regular expression. + */ + if (!*x || (*x != '/')) { + (void) fprintf(stderr, "%s: regexp doesn't begin with '/': ", Pn); + if (x) + safestrprt(x, stderr, 1); + return(1); + } +/* + * Skip to the end ('/') of the regular expression. + */ + xb = x + 1; + for (xe = xb; *xe; xe++) { + if (*xe == '/') + break; + } + if (*xe != '/') { + (void) fprintf(stderr, "%s: regexp doesn't end with '/': ", Pn); + safestrprt(x, stderr, 1); + return(1); + } +/* + * 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) { + (void) fprintf(stderr, + "%s: b regexp modifier already used: ", Pn); + safestrprt(x, stderr, 1); + } + i = 1; + } else if (xmod) { + if (++bxmod == 1) { + (void) fprintf(stderr, + "%s: b and x regexp modifiers conflict: ", Pn); + safestrprt(x, stderr, 1); + } + i = 1; + } else + co &= ~REG_EXTENDED; + break; + case 'i': /* Ignore case. */ + if (++imod > 1) { + if (imod == 2) { + (void) fprintf(stderr, + "%s: i regexp modifier already used: ", Pn); + safestrprt(x, stderr, 1); + } + i = 1; + } else + co |= REG_ICASE; + break; + case 'x': /* This is an extended expression. */ + if (++xmod > 1) { + if (xmod == 2) { + (void) fprintf(stderr, + "%s: x regexp modifier already used: ", Pn); + safestrprt(x, stderr, 1); + } + i = 1; + } else if (bmod) { + if (++bxmod == 1) { + (void) fprintf(stderr, + "%s: b and x regexp modifiers conflict: ", Pn); + safestrprt(x, stderr, 1); + } + i = 1; + } else + co |= REG_EXTENDED; + break; + default: + (void) fprintf(stderr, "%s: invalid regexp modifier: %c\n", + Pn, (int)*xm); + i = 1; + } + } + if (i) + return(1); +/* + * Allocate space to hold expression and copy it there. + */ + xl = (MALLOC_S)(xe - xb); + if (!(xp = (char *)malloc(xl + 1))) { + (void) fprintf(stderr, "%s: no regexp space for: ", Pn); + safestrprt(x, stderr, 1); + Exit(1); + } + (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 += CMDRXINCR; + xl = (MALLOC_S)(NCmdRxA * sizeof(lsof_rx_t)); + if (CmdRx) + CmdRx = (lsof_rx_t *)realloc((MALLOC_P *)CmdRx, xl); + else + CmdRx = (lsof_rx_t *)malloc(xl); + if (!CmdRx) { + (void) fprintf(stderr, "%s: no space for regexp: ", Pn); + safestrprt(x, stderr, 1); + Exit(1); + } + } + i = NCmdRxU; + CmdRx[i].exp = xp; +/* + * Compile the expression. + */ + if ((re = regcomp(&CmdRx[i].cx, xp, co))) { + (void) fprintf(stderr, "%s: regexp error: ", Pn); + safestrprt(x, stderr, 0); + (void) regerror(re, &CmdRx[i].cx, &reb[0], sizeof(reb)); + (void) fprintf(stderr, ": %s\n", reb); + if (xp) { + (void) free((FREE_P *)xp); + xp = (char *)NULL; + } + return(1); + } +/* + * Complete the CmdRx[] table entry. + */ + CmdRx[i].mc = 0; + CmdRx[i].exp = xp; + NCmdRxU++; + return(0); +} + + +#if defined(HASEOPT) +/* + * enter_efsys() -- enter path of file system whose kernel blocks are to be + * eliminated + */ + +int +enter_efsys(e, rdlnk) + 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); + Exit(1); + } + if (rdlnk) + path = ec; + else { + if (!(path = Readlink(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); + Exit(1); + } + 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(f) + 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); + Exit(1); + } +/* + * 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(cp1, dash, cp2, &lo, &hi)) + err = 1; + else { + if (enter_fd_lst((char *)NULL, lo, hi, excl)) + err = 1; + } + } else { + if (enter_fd_lst(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(nm, lo, hi, excl) + 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); + Exit(1); + } + 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) { + if (!(f->nm = mkstrcpy(nm, (MALLOC_S *)NULL))) { + (void) fprintf(stderr, + "%s: no space for copy of: %s\n", Pn, nm); + Exit(1); + } + lo = 1; + hi = 0; + } else { + f->nm = (char *)NULL; + lo = hi = n; + } + } else + f->nm = (char *)NULL; +/* + * Skip duplicates. + */ + for (ft = Fdl; ft; ft = ft->next) { + if (f->nm) { + if (!ft->nm || strcmp(f->nm, ft->nm)) + continue; + } else 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(d, descend) + 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(d))) + return(1); + if (statsafely(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(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(dn); + av[0] = (dn == d) ? mkstrcpy(dn, (MALLOC_S *)NULL) : dn; + av[1] = (char *)NULL; + dn = (char *)NULL; + if (!ck_file_arg(0, 1, av, 1, 1, &sb)) { + 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); + Exit(1); + } + } + (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); + Exit(1); + } + } + (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(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(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(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(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(0, 1, av, 1, 1, &sb)) { + 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(ty, p) + 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); + } +/* + * Set up variables for the type of ID. + */ + switch (ty) { + case PGID: + mx = Mxpgid; + n = Npgid; + ni = Npgidi; + nx = Npgidx; + s = Spgid; + break; + case PID: + mx = Mxpid; + n = Npid; + ni = Npidi; + nx = Npidx; + s = Spid; + break; + default: + (void) fprintf(stderr, "%s: enter_id \"", Pn); + safestrprt(p, stderr, 0); + (void) fprintf(stderr, "\", invalid type: %d\n", ty); + Exit(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++; + /* + * Avoid entering duplicates and conflicts. + */ + for (i = j = 0; i < n; i++) { + if (id == s[i].i) { + if (x == s[i].x) { + j = 1; + continue; + } + (void) fprintf(stderr, + "%s: P%sID %d has been included and excluded.\n", + Pn, + (ty == PGID) ? "G" : "", + id); + err = j = 1; + break; + } + } + if (j) + continue; + /* + * Allocate table table space. + */ + if (n >= mx) { + mx += IDINCR; + if (!s) + s = (struct int_lst *)malloc( + (MALLOC_S)(sizeof(struct int_lst) * mx)); + else + s = (struct int_lst *)realloc((MALLOC_P *)s, + (MALLOC_S)(sizeof(struct int_lst) * mx)); + if (!s) { + (void) fprintf(stderr, "%s: no space for %d process%s IDs", + Pn, mx, (ty == PGID) ? " group" : ""); + Exit(1); + } + } + s[n].f = 0; + s[n].i = id; + s[n++].x = x; + if (x) + nx++; + else + ni++; + } +/* + * Save variables for the type of ID. + */ + if (ty == PGID) { + Mxpgid = mx; + Npgid = n; + Npgidi = ni; + Npgidx = nx; + Spgid = s; + } else { + Mxpid = mx; + Npid = Npuns = n; + Npidi = ni; + Npidx = nx; + Spid = s; + } + return(err); +} + + +/* + * enter_network_address() - enter Internet address for searching + */ + +int +enter_network_address(na) + 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(&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(n, sp, ep, s, he) + 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); + Exit(1); + } + } 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 (!(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(ss) + char *ss; /* state specification string */ +{ + char *cp, *ne, *ns, *pr; + int err, d, f, i, tx, x; + size_t len; + 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(); + 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); + Exit(1); + } + } + 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); + Exit(1); + } + 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 (!(len = (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_str_lst() - enter a string on a list + */ + +int +enter_str_lst(opt, s, lp, incl, excl) + char *opt; /* option name */ + char *s; /* string to enter */ + struct str_lst **lp; /* string's list */ + int *incl; /* included count */ + int *excl; /* excluded count */ +{ + char *cp; + short i, 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 == '^') { + i = 0; + x = 1; + s++; + } else { + i = 1; + x = 0; + } + if (!(cp = mkstrcpy(s, &len))) { + (void) fprintf(stderr, "%s: no string copy space: ", Pn); + safestrprt(s, stderr, 1); + return(1); + } + if ((lpt = (struct str_lst *)malloc(sizeof(struct str_lst))) == NULL) { + (void) fprintf(stderr, "%s: no list space: ", Pn); + safestrprt(s, stderr, 1); + (void) free((FREE_P *)cp); + return(1); + } + lpt->f = 0; + lpt->str = cp; + lpt->len = (int)len; + lpt->x = x; + if (i) + *incl += 1; + if (x) + *excl += 1; + lpt->next = *lp; + *lp = lpt; + return(0); +} + + +/* + * enter_uid() - enter User Identifier for searching + */ + +int +enter_uid(us) + 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) */ + + /* + * Avoid entering duplicates. + */ + for (i = j = 0; i < Nuid; i++) { + if (uid != Suid[i].uid) + continue; + if (Suid[i].excl == excl) { + j = 1; + continue; + } + (void) fprintf(stderr, + "%s: UID %d has been included and excluded.\n", + Pn, (int)uid); + err = j = 1; + break; + } + if (j) + continue; + /* + * Allocate space for User IDentifier. + */ + if (Nuid >= Mxuid) { + Mxuid += UIDINCR; + 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) { + (void) fprintf(stderr, "%s: no space for UIDs", Pn); + Exit(1); + } + } + if (nn) { + if (!(lp = mkstrcpy(lnm, (MALLOC_S *)NULL))) { + (void) fprintf(stderr, "%s: no space for login: ", Pn); + safestrprt(lnm, stderr, 1); + Exit(1); + } + Suid[Nuid].lnm = lp; + } else + Suid[Nuid].lnm = (char *)NULL; + Suid[Nuid].uid = uid; + Suid[Nuid++].excl = excl; + if (excl) + Nuidexcl++; + else + Nuidincl++; + } + return(err); +} + + +/* + * isIPv4addr() - is host name an IPv4 address + */ + +static char * +isIPv4addr(hn, a, al) + 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(hn, n) + 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) + 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/check.bash b/check.bash new file mode 100755 index 0000000..2e63748 --- /dev/null +++ b/check.bash @@ -0,0 +1,17 @@ +set -ex + +echo $1 +echo $BASH_VERSION +shopt +export -p + +./lsof -v + +# +# check that the version numbers are updated +# +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) +test "${expected_version}" = "${actual_version}" +test "${expected_version}" = "${dist_version}" diff --git a/dialects/aix/Makefile b/dialects/aix/Makefile new file mode 100644 index 0000000..830a25f --- /dev/null +++ b/dialects/aix/Makefile @@ -0,0 +1,169 @@ + +# 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} +CFLAGS= ${CDEFS} ${INCL} ${DEBUG} + +GRP= + +HDR= lsof.h lsof_fields.h dlsof.h machine.h proto.h dproto.h + +SRC= ddev.c dfile.c dmnt.c dnode.c dnode1.c 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.o + +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 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_CCDATE "'`date`'"' >> version.h + @echo '#define LSOF_CCFLAGS "'`echo ${CFLAGS} | sed 's/\\\\(/\\(/g' | sed 's/\\\\)/\\)/g' | sed 's/"/\\\\"/g'`'"' >> version.h + @echo '#define LSOF_CINFO "${CINFO}"' >> version.h + @if [ "X${LSOF_HOST}" = "X" ]; then \ + echo '#define LSOF_HOST "'`uname -n`'"' >> version.h; \ + else \ + if [ "${LSOF_HOST}" = "none" ]; then \ + echo '#define LSOF_HOST ""' >> version.h; \ + else \ + echo '#define LSOF_HOST "${LSOF_HOST}"' >> version.h; \ + fi \ + fi + @echo '#define LSOF_LDFLAGS "${CFGL}"' >> version.h + @if [ "X${LSOF_LOGNAME}" = "X" ]; then \ + echo '#define LSOF_LOGNAME "${LOGNAME}"' >> version.h; \ + else \ + if [ "${LSOF_LOGNAME}" = "none" ]; then \ + echo '#define LSOF_LOGNAME ""' >> version.h; \ + else \ + echo '#define LSOF_LOGNAME "${LSOF_LOGNAME}"' >> version.h; \ + fi; \ + fi + @if [ "X${LSOF_SYSINFO}" = "X" ]; then \ + echo '#define LSOF_SYSINFO "'`uname -a`'"' >> version.h; \ + else \ + if [ "${LSOF_SYSINFO}" = "none" ]; then \ + echo '#define LSOF_SYSINFO ""' >> version.h; \ + else \ + echo '#define LSOF_SYSINFO "${LSOF_SYSINFO}"' >> version.h; \ + fi \ + fi + @if [ "X${LSOF_USER}" = "X" ]; then \ + echo '#define LSOF_USER "${USER}"' >> version.h; \ + else \ + if [ "${LSOF_USER}" = "none" ]; then \ + echo '#define LSOF_USER ""' >> version.h; \ + else \ + echo '#define LSOF_USER "${LSOF_USER}"' >> version.h; \ + fi \ + fi + @sed '/VN/s/.ds VN \(.*\)/#define LSOF_VERSION "\1"/' < version >> version.h + +FRC: + +# DO NOT DELETE THIS LINE - make depend DEPENDS ON IT + +ddev.o: ${HDR} ddev.c + +dfile.o: ${HDR} dfile.c + +dmnt.o: ${HDR} dmnt.c + +dnode.o: ${HDR} dnode.c + +dnode1.o: ${HDR} dnode1.c + +dproc.o: ${HDR} dproc.c + +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/dialects/aix/Mksrc b/dialects/aix/Mksrc new file mode 100755 index 0000000..397b61e --- /dev/null +++ b/dialects/aix/Mksrc @@ -0,0 +1,24 @@ +#!/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 $ + + +D=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" + +for i in $L +do + rm -f $i + $LSOF_MKC $D/$i $i + echo "$LSOF_MKC $D/$i $i" +done diff --git a/dialects/aix/aix5/README b/dialects/aix/aix5/README new file mode 100644 index 0000000..28adc0c --- /dev/null +++ b/dialects/aix/aix5/README @@ -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/dialects/aix/aix5/j2/j2_lock.h b/dialects/aix/aix5/j2/j2_lock.h new file mode 100644 index 0000000..9bfc511 --- /dev/null +++ b/dialects/aix/aix5/j2/j2_lock.h @@ -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 and that header + * file is missing from AIX 5.2. + * + * V. Abell + * 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/dialects/aix/aix5/j2/private_j2_snapshot.h b/dialects/aix/aix5/j2/private_j2_snapshot.h new file mode 100644 index 0000000..0760c0a --- /dev/null +++ b/dialects/aix/aix5/j2/private_j2_snapshot.h @@ -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/dialects/aix/ddev.c b/dialects/aix/ddev.c new file mode 100644 index 0000000..4150aa6 --- /dev/null +++ b/dialects/aix/ddev.c @@ -0,0 +1,728 @@ +/* + * 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"; +static char *rcsid = "$Id: ddev.c,v 1.14 2005/08/08 19:46:38 abe Exp $"; +#endif + + +#include "lsof.h" + + +/* + * Local definitions + */ + +#define LIKE_BLK_SPEC "like block special" +#define LIKE_CHR_SPEC "like character special" + + +/* + * Local function prototypes + */ + +_PROTOTYPE(static int rmdupdev,(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 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(p) + 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(dev, rdev, f, nty) + dev_t *dev; /* device */ + dev_t *rdev; /* raw device */ + int f; /* 1 = follow with '\n' */ + int nty; /* node type: N_BLK or N_CHR */ +{ + struct l_dev *dp; +/* + * Search device table for a full match. + */ + if ((dp = lkupdev(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(&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); + Exit(1); + } + (void) snpf(cp, len + 1, "(%s %s)", ttl, dp->name); + (void) add_nma(cp, len); + (void) free((MALLOC_P *)cp); + return(0); + } + return(0); +} + + +/* + * readdev() - read device names, modes and types + */ + +void +readdev(skip) + 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()) == 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("/dev"); +/* + * Unstack the next /dev or /dev/ directory. + */ + while (--Dstkx >= 0) { + if (!(dfp = opendir(Dstk[Dstkx]))) { + +#if defined(WARNDEVACCESS) + if (!Fwarn) { + (void) fprintf(stderr, "%s: WARNING: can't open: ", Pn); + safestrprt(Dstk[Dstkx], stderr, 1); + } +#endif /* defined(WARNDEVACCESS) */ + + (void) free((FREE_P *)Dstk[Dstkx]); + Dstk[Dstkx] = (char *)NULL; + continue; + } + if (path) { + (void) free((FREE_P *)path); + path = (char *)NULL; + } + if (!(path = mkstrcat(Dstk[Dstkx], -1, "/", 1, (char *)NULL, + -1, &pl))) + { + (void) fprintf(stderr, "%s: no space for: ", Pn); + safestrprt(Dstk[Dstkx], stderr, 1); + Exit(1); + } + (void) free((FREE_P *)Dstk[Dstkx]); + Dstk[Dstkx] = (char *)NULL; + /* + * Scan the directory. + */ + for (dp = readdir(dfp); dp; dp = readdir(dfp)) { + if (!dp->d_ino || (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); + Exit(1); + } + +#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(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); + Exit(1); + } + } + Devtp[i].rdev = sb.st_rdev; + Devtp[i].inode = (INODETYPE)sb.st_ino; + if (!(Devtp[i].name = mkstrcpy(fp, (MALLOC_S *)NULL))) { + (void) fprintf(stderr, "%s: no space for: ", Pn); + safestrprt(fp, stderr, 1); + Exit(1); + } + 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); + exit(1); + } + if (!(c->cd.name = mkstrcpy(fp, (MALLOC_S)NULL))) { + (void) fprintf(stderr, + "%s: no space for clone name: ", Pn); + safestrprt(fp, stderr, 1); + exit(1); + } + 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); + Exit(1); + } + } + 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); + Exit(1); + } + for (j = 0; j < BNdev; j++) { + BSdev[j] = &BDevtp[j]; + } + (void) qsort((QSORT_P *)BSdev, (size_t)BNdev, + (size_t)sizeof(struct l_dev *), compdev); + BNdev = rmdupdev(&BSdev, BNdev, "block"); + } 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); + Exit(1); + } + for (i = 0; i < Ndev; i++) { + Sdev[i] = &Devtp[i]; + } + (void) qsort((QSORT_P *)Sdev, (size_t)Ndev, + (size_t)sizeof(struct l_dev *), compdev); + Ndev = rmdupdev(&Sdev, Ndev, "char"); + } else { + (void) fprintf(stderr, "%s: no character devices found\n", Pn); + Exit(1); + } + +#if defined(HASDCACHE) +/* + * Write device cache file, as required. + */ + if (DCstate == 1 || (DCstate == 3 && dcrd)) + write_dcache(); +#endif /* defined(HASDCACHE) */ + +} + + +#if defined(HASDCACHE) +/* + * rereaddev() - reread device names, modes and types + */ + +void +rereaddev() +{ + (void) clr_devtab(); + +# if defined(DCACHE_CLR) + (void) DCACHE_CLR(); +# endif /* defined(DCACHE_CLR) */ + + readdev(1); + DCunsafe = 0; +} +#endif /* defined(HASDCACHE) */ + + +/* + * rmdupdev() - remove duplicate (major/minor/inode) devices + */ + +static int +rmdupdev(dp, n, nm) + struct l_dev ***dp; /* device table pointers address */ + int n; /* number of pointers */ + char *nm; /* device table name for error message */ +{ + +#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); + Exit(1); + } + return(j); +} + + +#if defined(HASDCACHE) && AIXV>=4140 +/* + * rw_clone_sect() - read/write the device cache file clone section + */ + +int +rw_clone_sect(m) + 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); + Exit(1); + } + /* + * 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); + Exit(1); + } + 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); + Exit(1); +} +#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(dp) + 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(); + return(0); + } + dp->v = 1; + return(1); +} +#endif /* defined(HASDCACHE) */ diff --git a/dialects/aix/dfile.c b/dialects/aix/dfile.c new file mode 100644 index 0000000..74b30c8 --- /dev/null +++ b/dialects/aix/dfile.c @@ -0,0 +1,600 @@ +/* + * 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"; +static char *rcsid = "$Id: dfile.c,v 1.13 2005/08/08 19:46:38 abe Exp $"; +#endif + + +#include "lsof.h" + + +/* + * Local structures + */ + +struct hsfile { + struct sfile *s; /* the Sfile table address */ + struct hsfile *next; /* the next hash bucket entry */ +}; + + +/* + * Local static variables + */ + +static struct hsfile *HbyFdi = /* hash by file buckets */ + (struct hsfile *)NULL; +static int HbyFdiCt = 0; /* HbyFdi entry count */ +static struct hsfile *HbyFrd = /* hash by file raw device buckets */ + (struct hsfile *)NULL; +static int HbyFrdCt = 0; /* HbyFrd entry count */ +static struct hsfile *HbyFsd = /* hash by file system buckets */ + (struct hsfile *)NULL; +static int HbyFsdCt = 0; /* HbyFsd entry count */ +static struct hsfile *HbyMPC = /* hash by MPC file buckets */ + (struct hsfile *)NULL; +static int HbyMPCCt = 0; /* HbyMPC entry count */ +static struct hsfile *HbyNm = /* hash by name buckets */ + (struct hsfile *)NULL; +static int HbyNmCt = 0; /* HbyNm entry count */ + + +/* + * Local definitions + */ + +#define SFDIHASH 4094 /* Sfile hash by (device,inode) number + * pair bucket count (power of 2!) */ +#define SFFSHASH 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() +{ + 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); + Exit(1); + } + if (!(HbyFrd = (struct hsfile *)calloc((MALLOC_S)SFRDHASH, + sizeof(struct hsfile)))) + { + (void) fprintf(stderr, + "%s: can't allocate space for %d rdev hash buckets\n", + Pn, SFRDHASH); + Exit(1); + } + if (!(HbyFsd = (struct hsfile *)calloc((MALLOC_S)SFFSHASH, + sizeof(struct hsfile)))) + { + (void) fprintf(stderr, + "%s: can't allocate space for %d file sys hash buckets\n", + Pn, SFFSHASH); + Exit(1); + } + if (!(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); + Exit(1); + } + if (!(HbyNm = (struct hsfile *)calloc((MALLOC_S)SFNMHASH, + sizeof(struct hsfile)))) + { + (void) fprintf(stderr, + "%s: can't allocate space for %d name hash buckets\n", + Pn, SFNMHASH); + Exit(1); + } + hs++; +/* + * Scan the Sfile chain, building file, file system, 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); + Exit(1); + } + sn->s = s; + sn->next = sh->next; + sh->next = sn; + } + } + } +} + + +/* + * is_file_named() - is file named? + */ + +int +is_file_named(p, ty, ch, ic) + 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(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(&sz); + (void) snpf(ep, sz, "/%d", ch); + } + if (s->devnm) { + ep = endnm(&sz); + (void) snpf(ep, sz, " (%s)", s->devnm); + } + } + s->f = 1; + return(1); + } + return(0); +} + + +/* + * print_dev() - print device + */ + +char * +print_dev(lf, 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(vn) + 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); + Exit(1); + } + vp->dir = (char *)NULL; + vp->fsname = (char *)NULL; +/* + * Read the vfs structure. + */ + if (kread((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((KA_T)v.vfs_gfs, (char *)&g, sizeof(g))) + goto vfs_exit; + if (!v.vfs_mdata + || kread((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); + Exit(1); + } + if (kread((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); + Exit(1); + } + } 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/dialects/aix/dlsof.h b/dialects/aix/dlsof.h new file mode 100644 index 0000000..287b4c5 --- /dev/null +++ b/dialects/aix/dlsof.h @@ -0,0 +1,442 @@ +/* + * 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 +# endif /* AIXA>1 */ + +#include +#include +#include +#include +#include + +# if !defined(_KERNEL) +#define _KERNEL 1 +# endif /* !defined(_KERNEL) */ + +#include +#include +#include /* #includes */ +#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 +# endif /* AIXV<4300 */ + +#define p_uid pi_uid +#undef sleep +#undef _KERNEL + +# if AIXA>1 +#define _NET_NET_MALLOC /* to keep from #include'ing + * , which is missing from + * ia64 AIX 5L */ +# endif /* AIXA>1 */ + +#include +#include +#include +#include +#include + +# if AIXV>=4140 +#include +# endif /* AIXV>=4140 */ + +#include +#include +#include + +# if defined(HASKERNIDCK) && AIXV>=5000 +#include +# endif /* defined(HASKERNIDCK) && AIXV>=5000 */ + +#include +#include +#include + +# if AIXV>=4100 +#include +# endif /* AIXV>=4100 */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +# if defined(HAS_AFS) +#define __XDR_INCLUDE__ +# endif /* defined(HAS_AFS) */ + +#include +#include + +# 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 +# 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 . + */ + +# 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 +#include +#include +#include +# 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 */ + +#endif /* AIX_LSOF_H */ diff --git a/dialects/aix/dmnt.c b/dialects/aix/dmnt.c new file mode 100644 index 0000000..ef1d61c --- /dev/null +++ b/dialects/aix/dmnt.c @@ -0,0 +1,302 @@ +/* + * 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"; +static char *rcsid = "$Id: dmnt.c,v 1.13 2005/08/08 19:46:38 abe Exp $"; +#endif + + +#include "lsof.h" + + +/* + * Local static definitions + */ + +static struct mounts *Lmi = (struct mounts *)NULL; /* local mount info */ +static int Lmist = 0; /* Lmi status */ + + +/* + * readmnt() - read mount table + */ + +struct mounts * +readmnt() +{ + 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(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); + Exit(1); + } + if (!(ln = Readlink(dn))) { + if (!Fwarn) { + (void) fprintf(stderr, + " Output information may be incomplete.\n"); + } + continue; + } + if (ln != dn) { + (void) free((FREE_P *)dn); + dn = ln; + } + if (*dn != '/') + continue; + /* + * 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(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(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/dialects/aix/dnode.c b/dialects/aix/dnode.c new file mode 100644 index 0000000..10a07bb --- /dev/null +++ b/dialects/aix/dnode.c @@ -0,0 +1,1307 @@ +/* + * 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"; +static char *rcsid = "$Id: dnode.c,v 1.25 2008/10/21 16:14:18 abe Exp $"; +#endif + + +#include "lsof.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 +# else /* AIXV>=4210 */ +# if AIXA<2 +/* + * Private rnode struct definitions for AIX 4.2.1 and above + * + * The rnode struct IBM ships in doesn't match the one + * the kernel uses. The kernel's rnode struct definition comes from + * , 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 + */ + +char +isglocked(ga) + struct gnode *ga; /* local gnode address */ +{ + + struct filock *cfp, f, *ffp; + int l; + + if (!(ffp = ga->gn_filocks)) + return(' '); + cfp = ffp; + +#if AIXV>=4140 + do { +#endif /* AIXV>=4140 */ + + if (kread((KA_T)cfp, (char *)&f, sizeof(f))) + return(' '); + +#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) ? 'R' : 'r'); + case F_WRLCK: + return((l) ? 'W' : 'w'); + case (F_RDLCK + F_WRLCK): + return('u'); + } + return(' '); + +#if AIXV>=4140 + } while ((cfp = f.FL_NEXT) && cfp != ffp); + return(' '); +#endif /* AIXV>=4140 */ + +} + + +/* + * process_node() - process vnode + */ + +void +process_node(va) + 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], *ty; + 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("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) */ + + ); + Exit(1); + } + } +/* + * Read the vnode. + */ + if (readvnode(va, v)) { + enter_nm(Namech); + return; + } + +#if defined(HASFSTRUCT) + Lf->fsv |= FSV_NI; + Lf->fna = va; +#endif /* defined(HASFSTRUCT) */ + +/* + * Read the gnode. + */ + if (!v->v_gnode || readgnode((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(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(Namech); + return; + } + /* + * Read the special node. + */ + if (!g.gn_data || kread((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(Namech); + return; + } + /* + * Read the PFS gnode and its inode and vnode. + */ + if (sn.sn_pfsgnode) { + if (Selinet) { + Lf->sf = SELEXCLF; + return; + } + if (readgnode((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(Namech); + return; + } + if (!g.gn_data || readlino(&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(Namech); + return; + } + ins = 1; + if (!g.gn_vnode || readvnode((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(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((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(&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(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(qp, (char *)&q, sizeof(q))) + break; + if (!(ka = (KA_T)q.q_qinfo) + || kread(ka, (char *)&qi, sizeof(qi))) + continue; + if (!(ka = (KA_T)qi.qi_minfo) + || kread(ka, (char *)&mi, sizeof(mi))) + continue; + if (!(ka = (KA_T)mi.mi_idname) + || kread(ka, mn, sizeof(mn) - 1) + || !(ml = (int) strlen(mn)) + || !strcmp(mn, "sth")) + continue; + if (!strcmp(mn, "xtiso") + && (xp = (KA_T)q.q_ptr) + && !kread(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:". + */ + 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((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(Namech); + return; + } + /* + * Otherwise, read the devnode and its gnode. + */ + } else { + if (!sn.sn_devnode + || kread((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(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(print_kptr(va, (char *)NULL, 0)); + } 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; + } + } +/* + * 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(&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((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(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((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(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((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(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(&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(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(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(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(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(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. + */ + if (Foffset) + Lf->off_def = 1; + else { + 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: + if (!Fsize) + Lf->off_def = 1; + break; + case N_CHR: + case N_MPC: + if (!Fsize) + Lf->off_def = 1; + 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; + } + } else if (((type == VBLK) || (type == VCHR) || (type == VMPC)) + && !Fsize) + Lf->off_def = 1; + break; + } + } +/* + * Record link count. + */ + if (Fnlink) { + 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: + ty ="VNON"; + Lf->dev = dev; + Lf->dev_def = devs; + Lf->rdev = rdev; + Lf->rdev_def = rdevs; + break; + case VREG: + case VDIR: + ty = (type == VREG) ? "VREG" : "VDIR"; + Lf->dev = dev; + Lf->dev_def = devs; + Lf->rdev = rdev; + Lf->rdev_def = rdevs; + break; + case VBLK: + ty = "VBLK"; + Lf->dev = dev; + Lf->dev_def = devs; + Lf->rdev = rdev; + Lf->rdev_def = rdevs; + Ntype = N_BLK; + break; + case VCHR: + ty = "VCHR"; + Lf->dev = dev; + Lf->dev_def = devs; + Lf->rdev = rdev; + Lf->rdev_def = rdevs; + Ntype = N_CHR; + break; + case VLNK: + ty = "VLNK"; + Lf->dev = dev; + Lf->dev_def = devs; + Lf->rdev = rdev; + Lf->rdev_def = rdevs; + break; + +#if defined(VSOCK) + case VSOCK: + ty = "SOCK"; + Lf->dev = dev; + Lf->dev_def = devs; + Lf->rdev = rdev; + Lf->rdev_def = rdevs; + break; +#endif + + case VBAD: + ty = "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; + } + ty = "FIFO"; + 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; + ty = "VMPC"; + break; + default: + Lf->dev = dev; + Lf->dev_def = devs; + Lf->rdev = rdev; + Lf->rdev_def = rdevs; + (void) snpf(Lf->type, sizeof(Lf->type), "%04o", (type & 0xfff)); + ty = (char *)NULL; + } + if (ty) + (void) snpf(Lf->type, sizeof(Lf->type), "%s", ty); + Lf->ntype = Ntype; + +#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(NULL, type, g.gn_chan, ic)) + Lf->sf |= SELNM; +/* + * Enter name characters. + */ + if (Namech[0]) + enter_nm(Namech); +} + + +#if defined(HASPRIVFILETYPE) +/* + * process_shmt() -- process shared memory transport file + */ + +void +process_shmt(sa) + 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. + */ + (void) snpf(Lf->type, sizeof(Lf->type), " SMT"); + if (!sa || kread((KA_T)sa, (char *)&mn, sizeof(mn))) { + (void) snpf(Namech, Namechl, "can't read shmtnode: %s", + print_kptr(sa, (char *)NULL, 0)); + enter_nm(Namech); + return; + } + enter_dev_ch(print_kptr(sa, (char *)NULL, 0)); +/* + * If offset display has been requested or if buffer size less free bytes is + * negative, enable offset display. Otherwise set the file size as buffer + * size less free bytes. + */ + if (Foffset || mn.free > mn.sz) + Lf->off_def = 1; + else { + 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((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(Namech); +} +#endif /* AIXV>=4200 */ + + +/* + * readlino() -- read local inode + */ + +int +readlino(ga, li) + 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(ga, li)); +#endif /* defined(HAS_JFS2) */ + +/* + * Read a "standard" inode. + */ + if (readinode((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/dialects/aix/dnode1.c b/dialects/aix/dnode1.c new file mode 100644 index 0000000..e0f781f --- /dev/null +++ b/dialects/aix/dnode1.c @@ -0,0 +1,313 @@ +/* + * 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"; +static char *rcsid = "$Id: dnode1.c,v 1.10 2005/08/08 19:46:38 abe Exp $"; +#endif + + +#if defined(HAS_AFS) +#include "lsof.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 +#undef KERNEL + + +/* + * Local function prototypes + */ + +_PROTOTYPE(static struct volume *getvolume,(struct VenusFid *f, int *vols)); +_PROTOTYPE(static int is_rootFid,(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(f, vols) + 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(kh, (char *)&vp, sizeof(vp))) + return((struct volume *)NULL); + while (vp) { + if (kread((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(vp) + 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((KA_T)vp->v_vfsp, (char *)&v, sizeof(v))) + return(0); + if (!v.vfs_mdata + || kread((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(vc, rfid) + 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((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(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(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(&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 & 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/dialects/aix/dnode2.c b/dialects/aix/dnode2.c new file mode 100644 index 0000000..f7a8ce9 --- /dev/null +++ b/dialects/aix/dnode2.c @@ -0,0 +1,81 @@ +/* + * 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"; +static char *rcsid = "$Id: dnode2.c,v 1.4 2005/08/08 19:46:38 abe Exp $"; +#endif + + +#if defined(HAS_JFS2) +#define _H_JFS_INO /* prevent */ +#define _H_JFS_INODE /* prevent */ +#define PROTO_H /* prevent "proto.h" and + * "dproto.h" until struct + * inode is available from + * */ +#define DPROTO_H +#include "lsof.h" +#define _KERNEL +#include +#undef PROTO_H /* enable "proto.h" */ +#undef DPROTO_H /* enable "dproto.h" */ +#include "proto.h" +#include "dproto.h" + +int +readj2lino(ga, li) + 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((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/dialects/aix/dproc.c b/dialects/aix/dproc.c new file mode 100644 index 0000000..eb7fffb --- /dev/null +++ b/dialects/aix/dproc.c @@ -0,0 +1,1481 @@ +/* + * 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"; +static char *rcsid = "$Id: dproc.c,v 1.27 2018/02/14 14:23:27 abe Exp $"; +#endif + + +#include "lsof.h" + +_PROTOTYPE(static void get_kernel_access,(void)); + +#if AIXA<2 +_PROTOTYPE(static struct le *getle,(KA_T a, KA_T sid, char **err)); +#endif /* AIXA<2 */ + +#if AIXV>=4110 +_PROTOTYPE(static void getlenm,(struct le *le, KA_T sid)); +#endif /* AIXV>=4110 */ + +_PROTOTYPE(static int kreadx,(KA_T addr, char *buf, int len, KA_T sid)); + +#if AIXA<2 +_PROTOTYPE(static void process_text,(KA_T sid)); +#else /* AIXA>=2 */ +_PROTOTYPE(static void getsoinfo,(void)); +_PROTOTYPE(static void process_text,(pid_t pid)); +#endif /* AIXA<2 */ + +#if defined(SIGDANGER) +# if defined(HASINTSIGNAL) +_PROTOTYPE(static int lowpgsp,(int sig)); +# else /* !defined(HASINTSIGNAL) */ +_PROTOTYPE(static void lowpgsp,(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 + +#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=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(d, er, ev, ea) + 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)); + Exit(1); + } + 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); + Exit(1); + } +/* + * 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); + Exit(1); + } + 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)); + Exit(1); + } + (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; + + (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() +{ + 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); + Exit(1); + } + 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); + Exit(1); + } + } +#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); + Exit(1); + } + 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); + Exit(1); + } + 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(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(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(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); + Exit(1); + } + } + 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 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 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(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(CWD, -1); + process_node(cdir); + if (Lf->sf) + link_lfile(); + } + /* + * Save root directory information. + */ + if (!ckscko && rdir) { + alloc_lfile(RTD, -1); + process_node(rdir); + if (Lf->sf) + link_lfile(); + } + +#if AIXV<4100 + /* + * Save parent directory information. + */ + if (!ckscko && pdir) { + alloc_lfile(" pd", -1); + process_node(pdir); + if (Lf->sf) + link_lfile(); + } +#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(sid); + } +# endif /* AIXA<1 */ +#else /* AIXA>=2 */ + process_text(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((char *)NULL, i); + process_file(fp); + if (Lf->sf) { + +#if defined(HASFSTRUCT) + if (Fsv & FSV_FG) + +# 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(); + } + } + } + /* + * Examine results. + */ + if (examine_lproc()) + return; + } +} + + +/* + * get_kernel_access() - get access to kernel memory + */ + +static void +get_kernel_access() +{ + 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); + Exit(1); + } +#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(); +#else /* !defined(WILLDROPGID) */ +/* + * See if the non-KMEM memory file is readable. + */ + if (Memory && !is_readable(Memory, 1)) + Exit(1); +#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) + Exit(1); + +#if defined(WILLDROPGID) +/* + * Drop setgid permission, if necessary. + */ + if (!Memory) + (void) dropgid(); +#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); + Exit(1); + } + +#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("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(a, sid, err) + 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(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(le, sid) + 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((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(&buf[i+1]); + else if (buf[0]) + enter_nm(buf); +# else /* AIXA>=2 */ + if (!le->nm || kread(le->nm, buf, sizeof(buf))) + return; + buf[LIBNMLN - 1] = '\0'; + if (!strlen(buf)) + return; + enter_nm(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); + Exit(1); + } +/* + * 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); + Exit(1); + } + /* + * 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); + Exit(1); + } + 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() +{ + get_kernel_access(); + +#if AIXA>1 + (void) getsoinfo(); +#endif /* AIXA>1 */ + +} + + +/* + * kread() - read from kernel memory + */ + +int +kread(addr, buf, len) + KA_T addr; /* kernel memory address */ + char *buf; /* buffer to receive data */ + READLEN_T len; /* length to read */ +{ + int br; + +#if 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(addr, buf, len, sid) + 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(sig) + int sig; +{ + (void) fprintf(stderr, "%s: FATAL: system paging space is low.\n", Pn); + Exit(1); +} +#endif /* defined(SIGDANGER) */ + + +#if AIXA<2 +/* + * process_text() - process text file information for non-ia64 AIX + */ + +static void +process_text(sid) + 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(" txt", -1); + if ((le = getle(ll, sid, &err))) { + if ((xf = le->fp)) { + process_file((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(); + } + } + } else { + (void) snpf(Namech, Namechl, "text entry at %s: %s", + print_kptr((KA_T)ll, (char *)NULL, 0), err); + enter_nm(Namech); + if (Lf->sf) + link_lfile(); + } + } +/* + * 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) + { + (void) snpf(fd, sizeof(fd), " L%02d", i); + alloc_lfile(fd, -1); + if (!(le = getle(ll, sid, &err))) { + (void) snpf(Namech, Namechl, "loader entry at %s: %s", + print_kptr((KA_T)ll, (char *)NULL, 0), err); + enter_nm(Namech); + if (Lf->sf) + link_lfile(); + 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); + Exit(1); + } + } + f[n++] = le->fp; + /* + * Save the loader entry. + */ + process_file((KA_T)le->fp); + if (Lf->sf) { + +#if AIXV>=4110 + if (!Lf->nm || !Lf->nm[0]) + getlenm(le, sid); +#endif /* AIXV>=4110 */ + + link_lfile(); + i++; + } + } +} +#else /* AIXA>=2 */ +/* + * process_text() - process text file information for ia64 AIX >= 5 + */ + +static void +process_text(pid) + 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((KA_T)la->exec, (char *)&le, sizeof(le)) + && le.fp) { + alloc_lfile(" txt", -1); + process_file((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(); + } + } +/* + * 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. + */ + (void) snpf(fd, sizeof(fd), "L%02d", i++); + alloc_lfile(fd, -1); + Lf->dev_def = Lf->inp_ty = Lf->nlink_def = Lf->sz_def = 1; + Lf->dev = sb.st_dev; + Lf->inode = (INODETYPE)sb.st_ino; + (void) snpf(Lf->type, sizeof(Lf->type), "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; + 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; + } + /* + * 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(nm); + link_lfile(); + } + } + (void) closedir(dfp); +} +#endif /* AIXA<2 */ diff --git a/dialects/aix/dproto.h b/dialects/aix/dproto.h new file mode 100644 index 0000000..a844342 --- /dev/null +++ b/dialects/aix/dproto.h @@ -0,0 +1,68 @@ +/* + * 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) +_PROTOTYPE(extern struct vnode *alloc_vcache,(void)); +_PROTOTYPE(extern int hasAFS,(struct vnode *vp)); +_PROTOTYPE(extern int readafsnode,(KA_T va, struct vnode *v, struct afsnode *an)); +# endif /* defined(HAS_AFS) */ + +# if defined(HAS_JFS2) +_PROTOTYPE(extern int readj2lino,(struct gnode *ga, struct l_ino *li)); +# endif /* defined(HAS_JFS2) */ + +_PROTOTYPE(extern int getchan,(char *p)); +_PROTOTYPE(extern int is_file_named,(char *p, enum vtype ty, chan_t ch, int ic)); +_PROTOTYPE(extern char isglocked,(struct gnode *ga)); +_PROTOTYPE(extern int readlino,(struct gnode *ga, struct l_ino *li)); +_PROTOTYPE(extern struct l_vfs *readvfs,(struct vnode *vn)); + +# if AIXV>=4200 +_PROTOTYPE(extern void process_shmt,(KA_T sa)); +# endif /* AIV>=4200 */ + +# if defined(HASDCACHE) && AIXV>=4140 +_PROTOTYPE(extern void clr_sect,(void)); +_PROTOTYPE(extern int rw_clone_sect,(int m)); +# endif /* defined(HASDCACHE) && AIXV>=4140 */ + +#endif /* !defined(DPROTO_H) */ diff --git a/dialects/aix/dsock.c b/dialects/aix/dsock.c new file mode 100644 index 0000000..bd1756d --- /dev/null +++ b/dialects/aix/dsock.c @@ -0,0 +1,443 @@ +/* + * 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"; +static char *rcsid = "$Id: dsock.c,v 1.24 2008/10/21 16:14:18 abe Exp $"; +#endif + + +#include "lsof.h" + + +/* + * We include here instead of "dlsof.h" for gcc's benefit. + * Its loader can't handle the multiple CONST u_char arrays declared in + * -- e.g., etherbroadcastaddr[]. ( + * #include's .) + */ + +#include +#include + + +/* + * process_socket() - process socket file + */ + +void +process_socket(sa) + 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. + */ + (void) snpf(Lf->type, sizeof(Lf->type), "sock"); + Lf->inp_ty = 2; +/* + * Read socket and protocol switch structures. + */ + if (!sa) { + enter_nm("no socket address"); + return; + } + if (kread(sa, (char *) &s, sizeof(s))) { + (void) snpf(Namech, Namechl, "can't read socket struct from %s", + print_kptr(sa, (char *)NULL, 0)); + enter_nm(Namech); + return; + } + if (!s.so_type) { + enter_nm("no socket type"); + return; + } + if (!s.so_proto + || kread((KA_T)s.so_proto, (char *)&p, sizeof(p))) { + (void) snpf(Namech, Namechl, "can't read protocol switch from %s", + print_kptr((KA_T)s.so_proto, (char *)NULL, 0)); + enter_nm(Namech); + return; + } +/* + * Save size information. + */ + if (Fsize) { + if (Lf->access == 'r') + Lf->sz = (SZOFFTYPE)s.so_rcv.sb_cc; + else if (Lf->access == 'w') + Lf->sz = (SZOFFTYPE)s.so_snd.sb_cc; + else + Lf->sz = (SZOFFTYPE)(s.so_rcv.sb_cc + s.so_snd.sb_cc); + Lf->sz_def = 1; + } else + Lf->off_def = 1; + +#if defined(HASTCPTPIQ) + Lf->lts.rq = s.so_rcv.sb_cc; + Lf->lts.sq = s.so_snd.sb_cc; + Lf->lts.rqs = Lf->lts.sqs = 1; +#endif /* defined(HASTCPTPIQ) */ + +#if defined(HASSOOPT) + Lf->lts.ltm = (unsigned int)s.so_linger; + 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((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; + } + 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((KA_T) s.so_pcb, (char *) &inp, sizeof(inp))) { + if (!s.so_pcb) { + (void) snpf(Namech, Namechl, "no PCB%s%s", + (s.so_state & SS_CANTSENDMORE) ? ", CANTSENDMORE" : "", + (s.so_state & SS_CANTRCVMORE) ? ", CANTRCVMORE" : ""); + } else { + (void) snpf(Namech, Namechl, "can't read inpcb at %s", + print_kptr((KA_T)s.so_pcb, (char *)NULL, 0)); + } + enter_nm(Namech); + return; + } + if (p.pr_protocol == IPPROTO_TCP) { + + /* + * If this is a TCP socket, read its control block. + */ + if (inp.inp_ppcb + && !kread((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(p.pr_protocol); + +#if defined(HASIPv6) + (void) snpf(Lf->type, sizeof(Lf->type), + fam == AF_INET ? "IPv4" : "IPv6"); +#else /* !defined(HASIPv6) */ + (void) snpf(Lf->type, sizeof(Lf->type), "inet"); +#endif /* defined(HASIPv6) */ + + /* + * Save Internet socket information. + */ + enter_dev_ch(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(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: + (void) snpf(Lf->type, sizeof(Lf->type), "rte"); + if (s.so_pcb) + enter_dev_ch(print_kptr((KA_T)(s.so_pcb), (char *)NULL, 0)); + else + (void) snpf(Namech, Namechl, "no protocol control block"); + if (!Fsize) + Lf->off_def = 1; + break; +/* + * Process a Unix domain socket. + */ + case AF_UNIX: + if (Funix) + Lf->sf |= SELUNX; + (void) snpf(Lf->type, sizeof(Lf->type), "unix"); + /* + * Read Unix protocol control block and the Unix address structure. + */ + enter_dev_ch(print_kptr(sa, (char *)NULL, 0)); + if (kread((KA_T) s.so_pcb, (char *)&unp, sizeof(unp))) { + (void) snpf(Namech, Namechl, "can't read unpcb at %s", + print_kptr((KA_T)s.so_pcb, (char *)NULL, 0)); + break; + } + if ((struct socket *)sa != unp.unp_socket) { + (void) snpf(Namech, Namechl, "unp_socket (%s) mismatch", + print_kptr((KA_T)unp.unp_socket, (char *)NULL, 0)); + break; + } + if (unp.unp_addr) { + if (kread((KA_T) unp.unp_addr, (char *)&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((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((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((KA_T)unp.unp_vnode, &v)) { + if (v.v_gnode + && !readgnode((KA_T)v.v_gnode, &g)) { + Lf->lock = isglocked(&g); + if (g.gn_type == VSOCK && g.gn_data + && !readlino(&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(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(fam, 1); + } + if (Namech[0]) + enter_nm(Namech); +} diff --git a/dialects/aix/dstore.c b/dialects/aix/dstore.c new file mode 100644 index 0000000..c4e3ed9 --- /dev/null +++ b/dialects/aix/dstore.c @@ -0,0 +1,405 @@ +/* + * 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"; +static char *rcsid = "$Id: dstore.c,v 1.12 2004/12/30 18:40:59 abe Exp $"; +#endif + + +#include "lsof.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 */ + +# if AIXA>2 +void aix_dstore_dummy_function() {} /* for ia64 idebug */ +# endif /* AIXA>2 */ +#endif /* AIXV>=4110 */ diff --git a/dialects/aix/machine.h b/dialects/aix/machine.h new file mode 100644 index 0000000..d8f4a46 --- /dev/null +++ b/dialects/aix/machine.h @@ -0,0 +1,691 @@ +/* + * 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 requires that _SUN be defined to + * be able to get the rpcent structure definition. + */ + +#define _SUN +#include +#undef _SUN +# endif /* AIXV<=3250 */ + + +# if AIXV>=4200 +/* + * AIX 4.2 requires that be #include'd early. It needs + * and _KERNEL. + * + * AIX 4.3 requires that _KERNEL be defined before the #include of + * + * + * For gcc's sake, some redefinitions after including 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 + +# if AIXA>0 +#include +# 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 +#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 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? */ +/* #define HASPRINTOFF print_off? */ +/* #define HASPRINTSZ print_sz? */ + + +/* + * HASPRIVFILETYPE and PRIVFILETYPE are defined for dialects that have a + * file structure type that isn't defined by a DTYPE_* symbol. They are + * used in lib/prfp.c to select the type's processing. + * + * PRIVFILETYPE is the definition of the f_type value in the file struct. + * + * HASPRIVFILETYPE is the name of the processing function. + */ + +# 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 */ + + +/* + * 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 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 */ + + +/* + * 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_ is defined for dialects that use the + * in the lsof library. + * + * Note: other definitions and operations may be required to condition the + * library function source code. They may be found in the dialect dlsof.h + * header files. + */ + +/* #define USE_LIB_CKKV 1 ckkv.c */ +/* #define USE_LIB_COMPLETEVFS 1 cvfs.c */ +#define USE_LIB_FIND_CH_INO 1 /* fino.c */ +/* #define USE_LIB_IS_FILE_NAMED 1 isfn.c */ +#define USE_LIB_LKUPDEV 1 /* lkud.c */ +/* #define USE_LIB_PRINTDEVNAME 1 pdvn.c */ +#define USE_LIB_PROCESS_FILE 1 /* prfp.c */ +#define USE_LIB_PRINT_TCPTPI 1 /* ptti.c */ +/* #define USE_LIB_READDEV 1 rdev.c */ +/* #define USE_LIB_READMNT 1 rmnt.c */ +/* #define USE_LIB_REGEX 1 regex.c */ +/* #define USE_LIB_RNAM 1 rnam.c */ +/* #define USE_LIB_RNCH 1 rnch.c */ +/* #define USE_LIB_RNMH 1 rnmh.c */ +/* #define USE_LIB_SNPF 1 snpf.c */ +#define snpf snprintf /* use the system's snprintf() */ + + +/* + * WARNDEVACCESS is defined for those dialects that should issue a warning + * when lsof can't access /dev (or /device) or one of its sub-directories. + * The warning can be inhibited by the lsof caller with the -w option. + */ + +#define WARNDEVACCESS 1 + + +/* + * WARNINGSTATE is defined for those dialects that want to suppress all lsof + * warning messages. + */ + +/* #define WARNINGSTATE 1 warnings are enabled by default */ + + +/* + * WILLDROPGID is defined for those dialects whose lsof executable runs + * setgid(not_real_GID) and whose setgid power can be relinquished after + * the dialect's initialize() function has been executed. + */ + +#define WILLDROPGID 1 + + +/* + * zeromem is a macro that uses bzero or memset. + */ + +#define zeromem(a, l) bzero(a, l) + +#endif /* !defined(LSOF_MACHINE_H) */ diff --git a/dialects/darwin/get-hdr-loc.sh b/dialects/darwin/get-hdr-loc.sh new file mode 100755 index 0000000..c0d9880 --- /dev/null +++ b/dialects/darwin/get-hdr-loc.sh @@ -0,0 +1,119 @@ +#!/bin/sh +# +# get-hdr-loc.sh -- get Darwin XNU kernel header file location +# +# Interactively requests the specification of the path to the host's Darwin +# XNU kernel header files. Checks that path and returns it to the caller. +# +# Usage: file1 file2 ... fileN +# +# Where: file1 first header file needed +# file2 second header file needed +# ... +# fileN last header file needed +# +# Exit: +# +# Exit code: 0 if path found; path returned on STDOUT +# +# 1 if path not found: error message returned +# on STDOUT +# +#set -x # for DEBUGging + +# Check argument count. There must be at least one argument. + +if test $# -lt 1 # { +then + echo "insufficient arguments: $#" + exit 1 +fi # } +lst=$* + +# Request the path to the Darwin XNU kernel header files. + +trap 'stty echo; echo interrupted; exit 1' 1 2 3 15 +FOREVER=1 +while test $FOREVER -ge 1 # { +do + if test $FOREVER -eq 1 # { + then + echo "---------------------------------------------------------------" 1>&2 + echo "" 1>&2 + echo "Lsof cannot find some Darwin XNU kernel header files it needs." 1>&2 + echo "They should have already been downloaded from:" 1>&2 + echo "" 1>&2 + echo " http://www.opensource.apple.com/darwinsource/index.html" 1>&2 + echo "" 1>&2 + echo "and then installed. (See 00FAQ for download and installation" 1>&2 + echo "instructions.)" 1>&2 + echo "" 1>&2 + echo "Please specify the path to the place where they were installed." 1>&2 + echo "" 1>&2 + echo "---------------------------------------------------------------" 1>&2 + fi # } + + END=0 + while test $END = 0 # { + do + echo "" 1>&2 + echo -n "What is the path? " 1>&2 + read HP EXCESS + HP=`echo echo $HP | /bin/csh -fs` + if test $? -eq 0 # { + then + if test "X$HP" = "X" # { + then + echo "" 1>&2 + echo "+================================+" 1>&2 + echo "| Please enter a non-empty path. |" 1>&2 + echo "+================================+" 1>&2 + echo "" 1>&2 + else + END=1 + fi # } + else + echo "" 1>&2 + echo "+============================+" 1>&2 + echo "| Please enter a legal path. |" 1>&2 + echo "+============================+" 1>&2 + echo "" 1>&2 + fi # } + done # } + + # See if the header files are available in the specified path. + + MH="" + for i in $lst # { + do + if test ! -f ${HP}/bsd/$i -a ! -f ${HP}/osfmk/$i # { + then + if test "X$MH" = "X" # { + then + MH=$i + else + MH="$MH $i" + fi # } + fi # } + done # } + if test "X$MH" = "X" # { + then + + # All header files are available, so return the path and exit cleanly. + + echo $HP + exit 0 + else + echo "" 1>&2 + echo "ERROR: not all header files are in:" 1>&2 + echo "" 1>&2 + echo " ${HP}" 1>&2 + echo "" 1>&2 + echo " These are missing:" 1>&2 + echo "" 1>&2 + echo " $MH" 1>&2 + FOREVER=2 + fi # } +done # } +echo "unknown error" +exit 1 diff --git a/dialects/darwin/kmem/Makefile b/dialects/darwin/kmem/Makefile new file mode 100644 index 0000000..47ebfee --- /dev/null +++ b/dialects/darwin/kmem/Makefile @@ -0,0 +1,171 @@ + +# Darwin /dev/kmem-based lsof Makefile +# +# $Id: Makefile,v 1.8 2008/10/21 16:15:34 abe Exp $ + +PROG= lsof + +BIN= ${DSTROOT}/usr/sbin + +DOC= ${DSTROOT}/usr/share/man/man8 + +I=/usr/include +S=/usr/include/sys +L=/usr/include/local +P= + +CDEF= ${RC_CFLAGS} +CDEFS= ${CDEF} ${CFGF} +INCL= ${DINC} +override CFLAGS= ${CDEFS} ${INCL} ${DEBUG} + +GRP= + +HDR= lsof.h lsof_fields.h dlsof.h machine.h proto.h dproto.h + +SRC= ddev.c dfile.c dmnt.c dnode.c dnode1.c dproc.c dsock.c dstore.c \ + arg.c main.c misc.c node.c print.c proc.c store.c usage.c util.c + +OBJ= ddev.o dfile.o dmnt.o dnode.o dnode1.o dproc.o dsock.o dstore.o \ + arg.o main.o misc.o node.o print.o proc.o store.o usage.o util.o + +MAN= lsof.8 + +OTHER= + +SHELL= /bin/sh + +SOURCE= Makefile ${OTHER} ${MAN} ${HDR} ${SRC} + +all: ${PROG} + +${PROG}: ${LIB} ${P} ${OBJ} + ${CC} -o $@ ${CFLAGS} ${OBJ} ${CFGL} + +clean: FRC + rm -f Makefile.bak ${PROG} a.out core errs lint.out tags *.o version.h + rm -f machine.h.old new_machine.h + (cd lib; ${MAKE} -f Makefile.skel clean) + +install-strip: all FRC + mkdir -p ${BIN} + install -c -s -m 2755 -g kmem ${PROG} ${BIN} + mkdir -p ${DOC} + install -c -m 444 ${MAN} ${DOC} + +install: all FRC + @echo '' + @echo 'Please write your own install rule. Lsof for Darwin below 8' + @echo 'should be installed setgid to the group that has permission' + @echo 'to read /dev/kmem, often kmem or sys. Lsof for Darwin 8 and' + @echo 'above should be installed setuid-root. Your install rule' + @echo 'actions for Darwin below 8 might look something like this:' + @echo '' + @echo ' install -m 2xxx -g $${GRP} $${PROG} $${BIN}' + @echo ' install -m 444 $${MAN} $${DOC}' + @echo '' + @echo 'Your install rule actions for Darwin 8 and above might look' + @echo 'something like this:' + @echo '' + @echo ' install -m 4xxx -o root $${PROG} $${BIN}' + @echo ' install -m 444 $${MAN} $${DOC}' + @echo '' + @echo 'You will have to complete the xxx modes, the GRP value, and' + @echo 'the skeletons for the BIN and DOC strings, given at the' + @echo 'beginning of this Makefile, e.g.,' + @echo '' + @echo ' BIN= $${DESTDIR}/usr/local/etc' + @echo ' DOC= $${DESTDIR}/usr/man/man8' + @echo ' GRP= kmem' + @echo '' + +${LIB}: FRC + (cd lib; ${MAKE} DEBUG="${DEBUG}" CFGF="${CFGF}") + +version.h: FRC + @echo Constructing version.h + @rm -f version.h + @echo '#define LSOF_BLDCMT "${LSOF_BLDCMT}"' > version.h; + @echo '#define LSOF_CC "${CC}"' >> version.h + @echo '#define LSOF_CCV "${CCV}"' >> version.h + @echo '#define LSOF_CCDATE "'`date`'"' >> version.h + @echo '#define LSOF_CCFLAGS "'`echo ${CFLAGS} | sed 's/\\\\(/\\(/g' | sed 's/\\\\)/\\)/g' | sed 's/"/\\\\"/g'`'"' >> version.h + @echo '#define LSOF_CINFO "${CINFO}"' >> version.h + @if [ "X${LSOF_HOST}" = "X" ]; then \ + echo '#define LSOF_HOST "'`uname -n`'"' >> version.h; \ + else \ + if [ "${LSOF_HOST}" = "none" ]; then \ + echo '#define LSOF_HOST ""' >> version.h; \ + else \ + echo '#define LSOF_HOST "${LSOF_HOST}"' >> version.h; \ + fi \ + fi + @echo '#define LSOF_LDFLAGS "${CFGL}"' >> version.h + @if [ "X${LSOF_LOGNAME}" = "X" ]; then \ + echo '#define LSOF_LOGNAME "${LOGNAME}"' >> version.h; \ + else \ + if [ "${LSOF_LOGNAME}" = "none" ]; then \ + echo '#define LSOF_LOGNAME ""' >> version.h; \ + else \ + echo '#define LSOF_LOGNAME "${LSOF_LOGNAME}"' >> version.h; \ + fi; \ + fi + @if [ "X${LSOF_SYSINFO}" = "X" ]; then \ + echo '#define LSOF_SYSINFO "'`uname -a`'"' >> version.h; \ + else \ + if [ "${LSOF_SYSINFO}" = "none" ]; then \ + echo '#define LSOF_SYSINFO ""' >> version.h; \ + else \ + echo '#define LSOF_SYSINFO "${LSOF_SYSINFO}"' >> version.h; \ + fi \ + fi + @if [ "X${LSOF_USER}" = "X" ]; then \ + echo '#define LSOF_USER "${USER}"' >> version.h; \ + else \ + if [ "${LSOF_USER}" = "none" ]; then \ + echo '#define LSOF_USER ""' >> version.h; \ + else \ + echo '#define LSOF_USER "${LSOF_USER}"' >> version.h; \ + fi \ + fi + @sed '/VN/s/.ds VN \(.*\)/#define LSOF_VERSION "\1"/' < version >> version.h + +FRC: + +# DO NOT DELETE THIS LINE - make depend DEPENDS ON IT + +ddev.o: ${HDR} ddev.c + +dfile.o: ${HDR} dfile.c + +dmnt.o: ${HDR} dmnt.c + +dnode.o: ${HDR} dnode.c + +dnode1.o: ${HDR} dnode1.c + +dproc.o: ${HDR} dproc.c + +dsock.o: ${HDR} dsock.c + +dstore.o: ${HDR} dstore.c + +arg.o: ${HDR} arg.c + +main.o: ${HDR} main.c + +misc.o: ${HDR} misc.c + +node.o: ${HDR} node.c + +print.o: ${HDR} print.c + +proc.o: ${HDR} proc.c + +store.o: ${HDR} store.c + +usage.o: ${HDR} version.h usage.c + +util.o: ${HDR} util.c + +# *** Do not add anything here - It will go away. *** diff --git a/dialects/darwin/kmem/Mksrc b/dialects/darwin/kmem/Mksrc new file mode 100755 index 0000000..e576427 --- /dev/null +++ b/dialects/darwin/kmem/Mksrc @@ -0,0 +1,24 @@ +#!/bin/sh +# +# Mksrc - make Darwin /dev/kmem-based lsof source files +# +# WARNING: This script assumes it is running from the main directory +# of the lsof, version 4 distribution. +# +# One environment variable applies: +# +# LSOF_MKC is the method for creating the source files. +# It defaults to "ln -s". A common alternative is "cp". +# +# $Id: Mksrc,v 1.5 2006/03/27 23:24:50 abe Exp $ + + +D=dialects/darwin/kmem +L="dlsof.h ddev.c dfile.c dmnt.c dnode.c dnode1.c dproc.c dproto.h dsock.c dstore.c machine.h" + +for i in $L +do + rm -f $i + $LSOF_MKC $D/$i $i + echo "$LSOF_MKC $D/$i $i" +done diff --git a/dialects/darwin/kmem/ddev.c b/dialects/darwin/kmem/ddev.c new file mode 100644 index 0000000..fc6ce28 --- /dev/null +++ b/dialects/darwin/kmem/ddev.c @@ -0,0 +1,479 @@ +/* + * ddev.c - Darwin device support functions for /dev/kmem-based lsof + */ + + +/* + * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana + * 47907. All rights reserved. + * + * Written by Victor A. Abell + * + * This software is not subject to any license of the American Telephone + * and Telegraph Company or the Regents of the University of California. + * + * Permission is granted to anyone to use this software for any purpose on + * any computer system, and to alter it and redistribute it freely, subject + * to the following restrictions: + * + * 1. Neither the authors nor Purdue University are responsible for any + * consequences of the use of this software. + * + * 2. The origin of this software must not be misrepresented, either by + * explicit claim or by omission. Credit to the authors and Purdue + * University must appear in documentation and sources. + * + * 3. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 4. This notice may not be removed or altered. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: ddev.c,v 1.5 2006/03/27 23:24:50 abe Exp $"; +#endif + + +#include "lsof.h" + + +/* + * Local definitions + */ + +#if defined(DVCH_DEVPATH) +#define DDEV_DEVPATH DVCH_DEVPATH +#else /* !defined(DVCH_DEVPATH) */ +#define DDEV_DEVPATH "/dev" +#endif /* defined(DVCH_DEVPATH) */ + +#if defined(USE_STAT) +#define STATFN stat +#else /* !defined(USE_STAT) */ +#define STATFN lstat +#endif /* defined(USE_STAT) */ + + +/* + * Local static variables. + */ + +static dev_t *ADev = (dev_t *) NULL; /* device numbers besides DevDev found + * inside DDEV_DEVPATH */ +static int ADevA = 0; /* entries allocated to ADev[] */ +static int ADevU = 0; /* entries used in ADev[] */ + + +/* + * Local function prototypes + */ + +_PROTOTYPE(static int rmdupdev,(struct l_dev ***dp, int n, char *nm)); +_PROTOTYPE(static void saveADev,(struct stat *s)); + + +#if defined(HASSPECDEVD) +/* + * HASSPECDEVD() -- process stat(2) result to see if the device number is + * inside DDEV_DEVPATH "/" + * + * exit: s->st_dev changed to DevDev, as required + */ + +void +HASSPECDEVD(p, s) + char *p; /* file path */ + struct stat *s; /* stat(2) result for file */ +{ + int i; + + switch (s->st_mode & S_IFMT) { + case S_IFCHR: + case S_IFBLK: + if (s->st_dev == DevDev) + return; + (void) readdev(0); + if (!ADev) + return; + for (i = 0; i < ADevU; i++) { + if (s->st_dev == ADev[i]) { + s->st_dev = DevDev; + return; + } + } + } +} +#endif /* defined(HASSPECDEVD) */ + + +/* + * readdev() - read device names, modes and types + */ + +void +readdev(skip) + int skip; /* skip device cache read if 1 -- + * ignored since device cache not + * used */ +{ + DIR *dfp; + int dnamlen; + struct dirent *dp; + char *fp = (char *)NULL; + char *path = (char *)NULL; + int i = 0; + int j = 0; + MALLOC_S pl, sz; + struct stat sb; +/* + * Read device names but once. + */ + if (Sdev) + return; +/* + * Prepare to scan DDEV_DEVPATH. + */ + Dstkn = Dstkx = 0; + Dstk = (char **)NULL; + (void) stkdir(DDEV_DEVPATH); +/* + * Unstack the next directory. + */ + while (--Dstkx >= 0) { + if (!(dfp = OpenDir(Dstk[Dstkx]))) { + +# if defined(WARNDEVACCESS) + if (!Fwarn) { + (void) fprintf(stderr, "%s: WARNING: can't open: ", Pn); + safestrprt(Dstk[Dstkx], stderr, 1); + } +# endif /* defined(WARNDEVACCESS) */ + + (void) free((FREE_P *)Dstk[Dstkx]); + Dstk[Dstkx] = (char *)NULL; + continue; + } + if (path) { + (void) free((FREE_P *)path); + path = (char *)NULL; + } + if (!(path = mkstrcat(Dstk[Dstkx], -1, "/", 1, (char *)NULL, -1, + &pl))) + { + (void) fprintf(stderr, "%s: no space for: ", Pn); + safestrprt(Dstk[Dstkx], stderr, 1); + Exit(1); + } + (void) free((FREE_P *)Dstk[Dstkx]); + Dstk[Dstkx] = (char *)NULL; + /* + * Scan the directory. + */ + for (dp = ReadDir(dfp); dp; dp = ReadDir(dfp)) { + if (dp->d_ino == 0 || dp->d_name[0] == '.') + continue; + /* + * Form the full path name and get its status. + */ + dnamlen = (int)dp->d_namlen; + if (fp) { + (void) free((FREE_P *)fp); + fp = (char *)NULL; + } + if (!(fp = mkstrcat(path, pl, dp->d_name, dnamlen, + (char *)NULL, -1, (MALLOC_S *)NULL))) + { + (void) fprintf(stderr, "%s: no space for: ", Pn); + safestrprt(path, stderr, 0); + safestrprtn(dp->d_name, dnamlen, stderr, 1); + Exit(1); + } + if (STATFN(fp, &sb) != 0) { + if (errno == ENOENT) /* a sym link to nowhere? */ + continue; + +# if defined(WARNDEVACCESS) + if (!Fwarn) { + int errno_save = errno; + + (void) fprintf(stderr, "%s: can't stat ", Pn); + safestrprt(fp, stderr, 0); + (void) fprintf(stderr, ": %s\n", strerror(errno_save)); + } +# endif /* defined(WARNDEVACCESS) */ + + continue; + } + /* + * If it's a subdirectory, stack its name for later + * processing. + */ + if ((sb.st_mode & S_IFMT) == S_IFDIR) { + + /* + * Skip /dev/fd. + */ + if (strcmp(fp, "/dev/fd")) + (void) stkdir(fp); + continue; + } + if ((sb.st_mode & S_IFMT) == S_IFLNK) { + + /* + * Ignore symbolic links. + */ + continue; + } + if ((sb.st_mode & S_IFMT) == S_IFCHR) { + + /* + * Save character device information in Devtp[]. + */ + if (i >= Ndev) { + Ndev += DEVINCR; + if (!Devtp) + Devtp = (struct l_dev *)malloc( + (MALLOC_S)(sizeof(struct l_dev)*Ndev)); + else + Devtp = (struct l_dev *)realloc((MALLOC_P *)Devtp, + (MALLOC_S)(sizeof(struct l_dev)*Ndev)); + if (!Devtp) { + (void) fprintf(stderr, + "%s: no space for character device\n", Pn); + Exit(1); + } + } + Devtp[i].rdev = sb.st_rdev; + Devtp[i].inode = (INODETYPE)sb.st_ino; + if (!(Devtp[i].name = mkstrcpy(fp, (MALLOC_S *)NULL))) { + (void) fprintf(stderr, + "%s: no space for device name: ", Pn); + safestrprt(fp, stderr, 1); + Exit(1); + } + Devtp[i].v = 0; + i++; + } + +# if defined(HASBLKDEV) + if ((sb.st_mode & S_IFMT) == S_IFBLK) { + + /* + * Save block device information in BDevtp[]. + */ + if (j >= BNdev) { + BNdev += DEVINCR; + if (!BDevtp) + BDevtp = (struct l_dev *)malloc( + (MALLOC_S)(sizeof(struct l_dev)*BNdev)); + else + BDevtp = (struct l_dev *)realloc((MALLOC_P *)BDevtp, + (MALLOC_S)(sizeof(struct l_dev)*BNdev)); + if (!BDevtp) { + (void) fprintf(stderr, + "%s: no space for block device\n", Pn); + Exit(1); + } + } + BDevtp[j].name = fp; + fp = (char *)NULL; + BDevtp[j].inode = (INODETYPE)sb.st_ino; + BDevtp[j].rdev = sb.st_rdev; + BDevtp[j].v = 0; + j++; + } +# endif /* defined(HASBLKDEV) */ + + /* + * Save a possible new st_dev number within DDEV_DEVPATH. + */ + if (sb.st_dev != DevDev) + (void) saveADev(&sb); + } + (void) CloseDir(dfp); + } +/* + * Free any unneeded space that was allocated. + */ + if (ADev && (ADevU < ADevA)) { + + /* + * Reduce space allocated to additional DDEV_DEVPATH device numbers. + */ + if (!ADevU) { + + /* + * If no space was used, free the entire allocation. + */ + (void) free((FREE_P *)ADev); + ADev = (dev_t *)NULL; + ADevA = 0; + } else { + + /* + * Reduce the allocation to what was used. + */ + sz = (MALLOC_S)(ADevU * sizeof(dev_t)); + if (!(ADev = (dev_t *)realloc((MALLOC_P *)ADev, sz))) { + (void) fprintf(stderr, "%s: can't reduce ADev[]\n", Pn); + Exit(1); + } + } + } + if (!Dstk) { + (void) free((FREE_P *)Dstk); + Dstk = (char **)NULL; + } + if (fp) + (void) free((FREE_P *)fp); + if (path) + (void) free((FREE_P *)path); + +# if defined(HASBLKDEV) +/* + * Reduce the BDevtp[] (optional) and Devtp[] tables to their minimum + * sizes; allocate and build sort pointer lists; and sort the tables by + * device number. + */ + if (BNdev) { + if (BNdev > j) { + BNdev = j; + BDevtp = (struct l_dev *)realloc((MALLOC_P *)BDevtp, + (MALLOC_S)(sizeof(struct l_dev) * BNdev)); + } + if (!(BSdev = (struct l_dev **)malloc( + (MALLOC_S)(sizeof(struct l_dev *) * BNdev)))) + { + (void) fprintf(stderr, + "%s: no space for block device sort pointers\n", Pn); + Exit(1); + } + for (j = 0; j < BNdev; j++) { + BSdev[j] = &BDevtp[j]; + } + (void) qsort((QSORT_P *)BSdev, (size_t)BNdev, + (size_t)sizeof(struct l_dev *), compdev); + BNdev = rmdupdev(&BSdev, BNdev, "block"); + } + +# if !defined(NOWARNBLKDEV) + else { + if (!Fwarn) + (void) fprintf(stderr, + "%s: WARNING: no block devices found\n", Pn); + } +# endif /* !defined(NOWARNBLKDEV) */ +# endif /* defined(HASBLKDEV) */ + + if (Ndev) { + if (Ndev > i) { + Ndev = i; + Devtp = (struct l_dev *)realloc((MALLOC_P *)Devtp, + (MALLOC_S)(sizeof(struct l_dev) * Ndev)); + } + if (!(Sdev = (struct l_dev **)malloc( + (MALLOC_S)(sizeof(struct l_dev *) * Ndev)))) + { + (void) fprintf(stderr, + "%s: no space for character device sort pointers\n", Pn); + Exit(1); + } + for (i = 0; i < Ndev; i++) { + Sdev[i] = &Devtp[i]; + } + (void) qsort((QSORT_P *)Sdev, (size_t)Ndev, + (size_t)sizeof(struct l_dev *), compdev); + Ndev = rmdupdev(&Sdev, Ndev, "char"); + } else { + (void) fprintf(stderr, "%s: no character devices found\n", Pn); + Exit(1); + } +} + + +/* + * rmdupdev() - remove duplicate (major/minor/inode) devices + */ + +static int +rmdupdev(dp, n, nm) + struct l_dev ***dp; /* device table pointers address */ + int n; /* number of pointers */ + char *nm; /* device table name for error message */ +{ + int i, j, k; + struct l_dev **p; + + for (i = j = 0, p = *dp; i < n ;) { + for (k = i + 1; k < n; k++) { + if (p[i]->rdev != p[k]->rdev || p[i]->inode != p[k]->inode) + break; + } + if (i != j) + p[j] = p[i]; + j++; + i = k; + } + if (n == j) + return(n); + if (!(*dp = (struct l_dev **)realloc((MALLOC_P *)*dp, + (MALLOC_S)(j * sizeof(struct l_dev *))))) + { + (void) fprintf(stderr, "%s: can't realloc %s device pointers\n", + Pn, nm); + Exit(1); + } + return(j); +} + + +/* + * saveADev() - save additional device number appearing inside DDEV_DEVPATH + */ + +static void +saveADev(s) + struct stat *s; /* stat(2) buffer for file */ +{ + int i; + MALLOC_S sz; +/* + * Process VCHR files. + * + * Optionally process VBLK files. + */ + +#if defined(HASBLKDEV) + if (((s->st_mode & S_IFMT) != S_IFBLK) + && ((s->st_mode & S_IFMT) != S_IFCHR)) +#else /* !defined(HASBLKDEV) */ + if ((s->st_mode & S_IFCHR) != S_IFCHR) +#endif /* defined(HASBLKDEV) */ + + return; +/* + * See if this is a new VBLK or VCHR st_dev value for ADev[]. + */ + for (i = 0; i < ADevU; i++) { + if (s->st_dev == ADev[i]) + return; + } +/* + * This is a new device number to add to ADev[]. + */ + if (ADevU >= ADevA) { + ADevA += 16; + sz = (MALLOC_S)(ADevA * sizeof(dev_t)); + if (ADev) + ADev = (dev_t *)realloc((MALLOC_P *)ADev, sz); + else + ADev = (dev_t *)malloc(sz); + if (!ADev) { + (void) fprintf(stderr, "%s: no space for ADev[]\n", Pn); + Exit(1); + } + } + ADev[ADevU++] = s->st_dev; +} diff --git a/dialects/darwin/kmem/dfile.c b/dialects/darwin/kmem/dfile.c new file mode 100644 index 0000000..e1b23a7 --- /dev/null +++ b/dialects/darwin/kmem/dfile.c @@ -0,0 +1,390 @@ +/* + * dfile.c - Darwin file processing functions for /dev/kmem-based lsof + */ + + +/* + * Copyright 2005 Purdue Research Foundation, West Lafayette, Indiana + * 47907. All rights reserved. + * + * Written by Victor A. Abell + * + * This software is not subject to any license of the American Telephone + * and Telegraph Company or the Regents of the University of California. + * + * Permission is granted to anyone to use this software for any purpose on + * any computer system, and to alter it and redistribute it freely, subject + * to the following restrictions: + * + * 1. Neither the authors nor Purdue University are responsible for any + * consequences of the use of this software. + * + * 2. The origin of this software must not be misrepresented, either by + * explicit claim or by omission. Credit to the authors and Purdue + * University must appear in documentation and sources. + * + * 3. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 4. This notice may not be removed or altered. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright 2005 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id$"; +#endif + + +#include "lsof.h" + + +/* + * Local definitions + */ + +#if DARWINV>=800 +#define file fileglob +#define f_flag fg_flag +#define f_type fg_type +#define f_count fg_count +#define f_ops fg_ops +#define f_offset fg_offset +#define f_data fg_data +#endif /* DARWINV>=800 */ + +#if defined(HASPSXSEM) +#define PSEMNAMLEN 31 /* from kern/posix_sem.c */ +#endif /* defined(HASPSXSEM) */ + +#if defined(HASPSXSHM) +#define PSHMNAMLEN 31 /* from kern/posix_shm.c */ +#endif /* defined(HASPSXSHM) */ + + +/* + * Local structure definitions + */ + +#if defined(HASPSXSEM) +struct pseminfo { /* from kern/posix_sem.c */ + unsigned int psem_flags; + unsigned int psem_usecount; + mode_t psem_mode; + uid_t psem_uid; + gid_t psem_gid; + char psem_name[PSEMNAMLEN + 1]; + void *psem_semobject; + struct proc *sem_proc; +}; + +struct psemnode { + struct pseminfo *pinfo; +}; +#endif /* defined(HASPSXSEM) */ + +#if defined(HASPSXSHM) /* from kern/posix_shm.c */ +struct pshminfo { + unsigned int pshm_flags; + unsigned int pshm_usecount; + off_t pshm_length; + mode_t pshm_mode; + uid_t pshm_uid; + gid_t pshm_gid; + char pshm_name[PSHMNAMLEN + 1]; + void *pshm_memobject; +}; + +struct pshmnode { + off_t mapp_addr; + +# if DARWINV<800 + size_t map_size; +# else /* DARWINV>=800 */ + user_size_t map_size; +# endif /* DARWINV>=800 */ + + struct pshminfo *pinfo; +}; +#endif /* defined(HASPSXSHM) */ + + +#if DARWINV>=800 +/* + * print_v_path() - print vnode's path + */ + +int +print_v_path(lf) + struct lfile *lf; +{ + if (lf->V_path) { + safestrprt(lf->V_path, stdout, 0); + return(1); + } + return(0); +} +#endif /* DARWINV>=800 */ + + +#if defined(HASKQUEUE) +/* + * process_kqueue() -- process kqueue file + */ + +void +process_kqueue(ka) + KA_T ka; /* kqueue file structure address */ +{ + struct kqueue kq; /* kqueue structure */ + + (void) snpf(Lf->type, sizeof(Lf->type), "KQUEUE"); + enter_dev_ch(print_kptr(ka, (char *)NULL, 0)); + if (!ka || kread(ka, (char *)&kq, sizeof(kq))) + return; + (void) snpf(Namech, Namechl, "count=%d, state=%#x", kq.kq_count, + kq.kq_state); + enter_nm(Namech); +} +#endif /* defined(HASKQUEUE) */ + + +#if DARWINV>=800 +/* + * process_pipe() - process a file structure whose type is DTYPE_PIPE + */ + +void +process_pipe(pa) + KA_T pa; /* pipe structure address */ +{ + (void) snpf(Lf->type, sizeof(Lf->type), "PIPE"); + enter_dev_ch(print_kptr(pa, (char *)NULL, 0)); + Namech[0] = '\0'; +} +#endif /* DARWINV>=800 */ + + +#if defined(HASPSXSEM) +/* + * process_psxsem() -- process POSIX semaphore file + */ + +void +process_psxsem(pa) + KA_T pa; /* psxsem file structure address */ +{ + struct pseminfo pi; + struct psemnode pn; + + (void) snpf(Lf->type, sizeof(Lf->type), "PSXSEM"); + enter_dev_ch(print_kptr(pa, (char *)NULL, 0)); + if (!Fsize) + Lf->off_def = 1; + if (pa && !kread(pa, (char *)&pn, sizeof(pn))) { + if (pn.pinfo && !kread((KA_T)pn.pinfo, (char *)&pi, sizeof(pi))) { + if (pi.psem_name[0]) { + pi.psem_name[PSEMNAMLEN] = '\0'; + (void) snpf(Namech, Namechl, "%s", pi.psem_name); + enter_nm(Namech); + } + } + } +} +#endif /* defined(HASPSXSEM) */ + + +#if defined(HASPSXSHM) +/* + * process_psxshm() -- process POSIX shared memory file + */ + +void +process_psxshm(pa) + KA_T pa; /* psxshm file structure address */ +{ + struct pshminfo pi; + struct pshmnode pn; + int pns = 0; + + (void) snpf(Lf->type, sizeof(Lf->type), "PSXSHM"); + enter_dev_ch(print_kptr(pa, (char *)NULL, 0)); + if (pa && !kread(pa, (char *)&pn, sizeof(pn))) { + pns = 1; + if (pn.pinfo && !kread((KA_T)pn.pinfo, (char *)&pi, sizeof(pi))) { + if (pi.pshm_name[0]) { + pi.pshm_name[PSEMNAMLEN] = '\0'; + (void) snpf(Namech, Namechl, "%s", pi.pshm_name); + enter_nm(Namech); + } else if (pi.pshm_memobject) { + (void) snpf(Namech, Namechl, "obj=%s", + print_kptr((KA_T)pi.pshm_memobject, (char *)NULL, 0)); + enter_nm(Namech); + } + } + } + if (Foffset) + Lf->off_def = 1; + else if (pns) { + Lf->sz = (SZOFFTYPE)pn.map_size; + Lf->sz_def = 1; + } +} +#endif /* defined(HASPSXSHM) */ + + +/* + * process_file() - process file + */ + +/* + * The caller may define: + * + * FILEPTR as the name of the location to store a pointer + * to the current file struct -- e.g., + * + * struct file *foobar; + * #define FILEPTR foobar + */ + +void +process_file(fp) + KA_T fp; /* kernel file structure address */ +{ + +#if DARWINV<800 + struct file f; +#else /* DARWINV>=800 */ + struct fileglob f; + struct fileproc fileproc; +#endif /* DARWINV>=800 */ + + int flag; + +#if defined(FILEPTR) +/* + * Save file structure address for process_node(). + */ + FILEPTR = &f; +#endif /* defined(FILEPTR) */ + +/* + * Read file structure. + */ + +#if DARWINV<800 + if (kread((KA_T)fp, (char *)&f, sizeof(f))) { + (void) snpf(Namech, Namechl, "can't read file struct from %s", + print_kptr(fp, (char *)NULL, 0)); + enter_nm(Namech); + return; + } +#else /* DARWINV>=800 */ + if (kread((KA_T)fp, (char *)&fileproc, sizeof(fileproc))) { + (void) snpf(Namech, Namechl, "can't read fileproc struct from %s", + print_kptr(fp, (char *)NULL, 0)); + enter_nm(Namech); + return; + } + if (kread((KA_T)fileproc.f_fglob, (char *)&f, sizeof(f))) { + (void) snpf(Namech, Namechl, "can't read fileglob struct from %s", + print_kptr((KA_T)fileproc.f_fglob, (char *)NULL, 0)); + enter_nm(Namech); + return; + } +#endif /* DARWINV>=800 */ + + Lf->off = (SZOFFTYPE)f.f_offset; + if (f.f_count) { + + /* + * Construct access code. + */ + if ((flag = (f.f_flag & (FREAD | FWRITE))) == FREAD) + Lf->access = 'r'; + else if (flag == FWRITE) + Lf->access = 'w'; + else if (flag == (FREAD | FWRITE)) + Lf->access = 'u'; + +#if defined(HASFSTRUCT) + /* + * Save file structure values. + */ + if (Fsv & FSV_CT) { + Lf->fct = (long)f.f_count; + Lf->fsv |= FSV_CT; + } + if (Fsv & FSV_FA) { + Lf->fsa = fp; + Lf->fsv |= FSV_FA; + } + if (Fsv & FSV_FG) { + Lf->ffg = (long)f.f_flag; + Lf->fsv |= FSV_FG; + } + if (Fsv & FSV_NI) { + Lf->fna = (KA_T)f.f_data; + Lf->fsv |= FSV_NI; + } +#endif /* defined(HASFSTRUCT) */ + + /* + * Process structure by its type. + */ + switch (f.f_type) { + + +#if defined(DTYPE_PIPE) + case DTYPE_PIPE: +# if defined(HASPIPEFN) + if (!Selinet) + HASPIPEFN((KA_T)f.f_data); +# endif /* defined(HASPIPEFN) */ + return; +#endif /* defined(DTYPE_PIPE) */ + + case DTYPE_VNODE: + if (!Selinet) + process_node((KA_T)f.f_data); + return; + case DTYPE_SOCKET: + process_socket((KA_T)f.f_data); + return; + +#if defined(HASKQUEUE) + case DTYPE_KQUEUE: + process_kqueue((KA_T)f.f_data); + return; +#endif /* defined(HASKQUEUE) */ + +#if defined(HASPSXSEM) + case DTYPE_PSXSEM: + process_psxsem((KA_T)f.f_data); + return; +#endif /* defined(HASPSXSEM) */ + +#if defined(HASPSXSHM) + case DTYPE_PSXSHM: + process_psxshm((KA_T)f.f_data); + return; +#endif /* defined(HASPSXSHM) */ + +#if defined(HASPRIVFILETYPE) + case PRIVFILETYPE: + HASPRIVFILETYPE((KA_T)f.f_data); + return; +#endif /* defined(HASPRIVFILETYPE) */ + + default: + if (f.f_type || f.f_ops) { + (void) snpf(Namech, Namechl, + "%s file struct, ty=%#x, op=%p", + print_kptr(fp, (char *)NULL, 0), f.f_type, f.f_ops); + enter_nm(Namech); + return; + } + } + } + enter_nm("no more information"); +} diff --git a/dialects/darwin/kmem/dlsof.h b/dialects/darwin/kmem/dlsof.h new file mode 100644 index 0000000..f5e50eb --- /dev/null +++ b/dialects/darwin/kmem/dlsof.h @@ -0,0 +1,337 @@ +/* + * dlsof.h - Darwin header file for /dev/kmem-based lsof + */ + + +/* + * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana + * 47907. All rights reserved. + * + * Written by Victor A. Abell + * + * This software is not subject to any license of the American Telephone + * and Telegraph Company or the Regents of the University of California. + * + * Permission is granted to anyone to use this software for any purpose on + * any computer system, and to alter it and redistribute it freely, subject + * to the following restrictions: + * + * 1. Neither the authors nor Purdue University are responsible for any + * consequences of the use of this software. + * + * 2. The origin of this software must not be misrepresented, either by + * explicit claim or by omission. Credit to the authors and Purdue + * University must appear in documentation and sources. + * + * 3. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 4. This notice may not be removed or altered. + */ + + +/* + * $Id: dlsof.h,v 1.11 2005/11/01 20:24:51 abe Exp $ + */ + + +#if !defined(DARWIN_LSOF_H) +#define DARWIN_LSOF_H 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if DARWINV<800 +#include +#define m_stat mnt_stat +#else /* DARWINV>=800 */ +#include +#define m_stat mnt_vfsstat +#endif /* DARWINV>=800 */ + +#if DARWINV<800 +#include +#include +#else /* DARWINV>=800 */ +#include +#define _SYS_SYSTM_H_ +struct nameidata { int dummy; }; /* to satisfy function prototypes */ +#include +#endif /* DARWINV>=800 */ + +#include +#define KERNEL_PRIVATE +#include +#undef KERNEL_PRIVATE +#include +#include +#include +#include + +# if defined(AF_NDRV) +#include +#define KERNEL +#include +#undef KERNEL +#include +# if DARWINV>=530 +#define KERNEL 1 +#include +#undef KERNEL +# endif /* DARWINV>=530 */ +# endif /* defined(AF_NDRV) */ + +# if defined(AF_SYSTEM) +#include +#define KERNEL +#include +#undef KERNEL +# endif /* defined(AF_SYSTEM) */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define pmap RPC_pmap +#include +#include +#undef pmap + +#include +#include + +# if DARWINV<800 +#include +#undef MAXNAMLEN +#include +#include +#include +#include +#include +#include +#include +#include + +# if DARWINV<600 +#include +#undef offsetof +# else /* DARWINV>=600 */ +#define KERNEL +#include +#undef KERNEL +# endif /* DARWINV<600 */ +# endif /* DARWINV<800 */ + +# if DARWINV<800 +#define time t1 /* hack to make dn_times() happy */ +#include +#undef time +# endif /* DARWINV<800 */ + +# if DARWINV<800 +#define KERNEL +#include +#undef KERNEL +# endif /* DARWINV<800 */ + +# if DARWINV<800 +#include +# else /* DARWINV>=800 */ +#define PROC_DEF_ENABLED +#define sleep kernel_sleep +#include +#undef sleep +# endif /* DARWINV<800 */ + +#include +#undef TRUE +#undef FALSE + +# if DARWINV<800 +#include +# else /* DARWINV>=800 */ +#include "/usr/include/sys/sysctl.h" +# endif /* DARWINV<800 */ + +# if DARWINV<800 +#define KERNEL +#include +#include +#undef KERNEL +# else /* DARWINV>=800 */ +#include +#include +# endif /* DARWINV<800 */ + +# if defined(HASKQUEUE) +#include +# endif /* defined(HASKQUEUE) */ + +# if defined(DTYPE_PSXSEM) +#define HASPSXSEM /* has the POSIX semaphore file + * type */ +# endif /* defined(DTYPE_PSXSEM) */ + +# if defined(DTYPE_PSXSHM) +#define HASPSXSHM /* has the POSIX shared memory + * file type */ +# endif /* defined(DTYPE_PSXSHM) */ + +struct vop_advlock_args { int dummy; }; /* to satisfy lf_advlock() prototype */ +#include +#include + +/* + * Compensate for removal of MAP_ENTRY_IS_A_MAP from , + * This work-around was supplied by John Polstra . + */ + +# if defined(MAP_ENTRY_IS_SUB_MAP) && !defined(MAP_ENTRY_IS_A_MAP) +#define MAP_ENTRY_IS_A_MAP 0 +# endif /* defined(MAP_ENTRY_IS_SUB_MAP) && !defined(MAP_ENTRY_IS_A_MAP) */ + +#undef B_NEEDCOMMIT +#include +#include +#define user_sigaltstack sigaltstack +#include + +#define COMP_P const void +#define DEVINCR 1024 /* device table malloc() increment */ +#define DIRTYPE dirent /* directory entry type */ + +typedef u_long KA_T; + +#define KMEM "/dev/kmem" +#define LOGINML MAXLOGNAME +#define MALLOC_P void +#define FREE_P MALLOC_P +#define MALLOC_S size_t + +#define N_UNIX "/mach_kernel" + +#define QSORT_P void +#define READLEN_T int +#define STRNCPY_L size_t +#define SWAP "/dev/drum" + +# if DARWINV>=800 +#define SZOFFTYPE unsigned long long + /* size and offset internal storage + * type */ +#define SZOFFPSPEC "ll" /* SZOFFTYPE printf specification + * modifier */ +# endif /* DARWINV>=800 */ + + +/* + * Global storage definitions (including their structure definitions) + */ + +struct file * Cfp; + +extern int Kd; /* KMEM descriptor */ +extern KA_T Kpa; + +struct l_vfs { + KA_T addr; /* kernel address */ + fsid_t fsid; /* file system ID */ + +# if defined(MOUNT_NONE) + short type; /* type of file system */ +# else /* !defined(MOUNT_NONE) */ + char *typnm; /* file system type name */ +# endif /* defined(MOUNT_NONE) */ + + char *dir; /* mounted directory */ + char *fsname; /* file system name */ + struct l_vfs *next; /* forward link */ +}; +extern struct l_vfs *Lvfs; + +struct mounts { + char *dir; /* directory (mounted on) */ + char *fsname; /* file system + * (symbolic links unresolved) */ + char *fsnmres; /* file system + * (symbolic links resolved) */ + dev_t dev; /* directory st_dev */ + dev_t rdev; /* directory st_rdev */ + INODETYPE inode; /* directory st_ino */ + mode_t mode; /* directory st_mode */ + mode_t fs_mode; /* file system st_mode */ + struct mounts *next; /* forward link */ +}; + +#define X_NCACHE "ncache" +#define X_NCSIZE "ncsize" +#define NL_NAME n_name + +struct sfile { + char *aname; /* argument file name */ + char *name; /* file name (after readlink()) */ + char *devnm; /* device name (optional) */ + dev_t dev; /* device */ + dev_t rdev; /* raw device */ + u_short mode; /* S_IFMT mode bits from stat() */ + int type; /* file type: 0 = file system + * 1 = regular file */ + INODETYPE i; /* inode number */ + int f; /* file found flag */ + struct sfile *next; /* forward link */ + +}; + +#define XDR_VOID (const xdrproc_t)xdr_void +#define XDR_PMAPLIST (const xdrproc_t)xdr_pmaplist + + +/* + * Definitions for rnmh.c + */ + +# if defined(HASNCACHE) +#include +#include + +# if !defined(offsetof) +#define offsetof(type, member) ((size_t)(&((type *)0)->member)) +# endif /* !defined(offsetof) */ + +#define NCACHE namecache /* kernel's structure name */ + +#define NCACHE_NM nc_name /* name in NCACHE */ + +# if DARWINV<700 +#define NCACHE_NMLEN nc_nlen /* name length in NCACHE */ +# endif /* DARWINV<700 */ + +#define NCACHE_NXT nc_hash.le_next /* link in NCACHE */ +#define NCACHE_NODEADDR nc_vp /* node address in NCACHE */ +#define NCACHE_PARADDR nc_dvp /* parent node address in NCACHE */ + +# if defined(HASNCVPID) +#define NCACHE_NODEID nc_vpid /* node ID in NCACHE */ +#define NCACHE_PARID nc_dvpid /* parent node ID in NCACHE */ +# endif /* defined(HASNCVPID) */ +# endif /* defined(HASNCACHE) */ + +#endif /* DARWIN_LSOF_H */ diff --git a/dialects/darwin/kmem/dmnt.c b/dialects/darwin/kmem/dmnt.c new file mode 100644 index 0000000..7ba9453 --- /dev/null +++ b/dialects/darwin/kmem/dmnt.c @@ -0,0 +1,229 @@ +/* + * dmnt.c - Darwin mount support functions for /dev/kmem-based lsof + */ + + +/* + * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana + * 47907. All rights reserved. + * + * Written by Victor A. Abell + * + * This software is not subject to any license of the American Telephone + * and Telegraph Company or the Regents of the University of California. + * + * Permission is granted to anyone to use this software for any purpose on + * any computer system, and to alter it and redistribute it freely, subject + * to the following restrictions: + * + * 1. Neither the authors nor Purdue University are responsible for any + * consequences of the use of this software. + * + * 2. The origin of this software must not be misrepresented, either by + * explicit claim or by omission. Credit to the authors and Purdue + * University must appear in documentation and sources. + * + * 3. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 4. This notice may not be removed or altered. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: dmnt.c,v 1.4 2005/11/01 20:24:51 abe Exp $"; +#endif + + +#include "lsof.h" + + +/* + * Local static information + */ + +static struct mounts *Lmi = (struct mounts *)NULL; /* local mount info */ +static int Lmist = 0; /* Lmi status */ + +/* + * readmnt() - read mount table + */ + +struct mounts * +readmnt() +{ + char *dn = (char *)NULL; + char *ln; + struct statfs *mb = (struct statfs *)NULL; + struct mounts *mtp; + int n; + struct stat sb; + + if (Lmi || Lmist) + return(Lmi); +/* + * Access mount information. + */ + if ((n = getmntinfo(&mb, MNT_NOWAIT)) <= 0) { + (void) fprintf(stderr, "%s: no mount information\n", Pn); + return(0); + } +/* + * Read mount information. + */ + for (; n; n--, mb++) { + + if (!mb->f_type) + continue; + /* + * Interpolate a possible symbolic directory link. + */ + if (dn) + (void) free((FREE_P *)dn); + if (!(dn = mkstrcpy(mb->f_mntonname, (MALLOC_S *)NULL))) { + +no_space_for_mount: + + (void) fprintf(stderr, "%s: no space for mount at ", Pn); + safestrprt(mb->f_mntonname, stderr, 0); + (void) fprintf(stderr, " ("); + safestrprt(mb->f_mntfromname, stderr, 0); + (void) fprintf(stderr, ")\n"); + Exit(1); + } + if (!(ln = Readlink(dn))) { + if (!Fwarn) { + (void) fprintf(stderr, + " Output information may be incomplete.\n"); + } + continue; + } + if (ln != dn) { + (void) free((FREE_P *)dn); + dn = ln; + } + if (*dn != '/') + continue; + /* + * Stat() the directory. + */ + if (statsafely(dn, &sb)) { + if (!Fwarn) { + (void) fprintf(stderr, "%s: WARNING: can't stat() ", Pn); + + safestrprt(mb->f_fstypename, stderr, 0); + + (void) fprintf(stderr, " file system "); + safestrprt(mb->f_mntonname, stderr, 1); + (void) fprintf(stderr, + " Output information may be incomplete.\n"); + } + (void) bzero((char *)&sb, sizeof(sb)); + sb.st_dev = (dev_t)mb->f_fsid.val[0]; + sb.st_mode = S_IFDIR | 0777; + if (!Fwarn) { + (void) fprintf(stderr, + " assuming \"dev=%x\" from mount table\n", + sb.st_dev); + } + } + /* + * Allocate and fill a local mount structure. + */ + if (!(mtp = (struct mounts *)malloc(sizeof(struct mounts)))) + goto no_space_for_mount; + mtp->dir = dn; + dn = (char *)NULL; + + mtp->next = Lmi; + mtp->dev = sb.st_dev; + mtp->rdev = sb.st_rdev; + mtp->inode = (INODETYPE)sb.st_ino; + mtp->mode = sb.st_mode; + /* + * Interpolate a possible file system (mounted-on) device name link. + */ + if (!(dn = mkstrcpy(mb->f_mntfromname, (MALLOC_S *)NULL))) + goto no_space_for_mount; + mtp->fsname = dn; + ln = Readlink(dn); + dn = (char *)NULL; + /* + * Stat() the file system (mounted-on) name and add file system + * information to the local mount table entry. + */ + if (!ln || statsafely(ln, &sb)) + sb.st_mode = 0; + mtp->fsnmres = ln; + mtp->fs_mode = sb.st_mode; + Lmi = mtp; + } +/* + * Clean up and return the local mount info table address. + */ + if (dn) + (void) free((FREE_P *)dn); + Lmist = 1; + return(Lmi); +} + + +/* + * readvfs() - read vfs structure + */ + +struct l_vfs * +readvfs(vm) + KA_T vm; /* kernel mount address from vnode */ +{ + struct mount m; + struct l_vfs *vp; +/* + * Search for match on existing entry. + */ + for (vp = Lvfs; vp; vp = vp->next) { + if (vm == vp->addr) + return(vp); + } +/* + * Read the (new) mount structure, allocate a local entry, and fill it. + */ + if (kread((KA_T)vm, (char *)&m, sizeof(m)) != 0) + return((struct l_vfs *)NULL); + if (!(vp = (struct l_vfs *)malloc(sizeof(struct l_vfs)))) { + (void) fprintf(stderr, "%s: PID %d, no space for vfs\n", + Pn, Lp->pid); + Exit(1); + } + if (!(vp->dir = mkstrcpy(m.m_stat.f_mntonname, (MALLOC_S *)NULL)) + || !(vp->fsname = mkstrcpy(m.m_stat.f_mntfromname, (MALLOC_S *)NULL))) + { + (void) fprintf(stderr, "%s: PID %d, no space for mount names\n", + Pn, Lp->pid); + Exit(1); + } + vp->addr = vm; + vp->fsid = m.m_stat.f_fsid; + { + int len; + + if ((len = strlen(m.m_stat.f_fstypename))) { + if (len > (MFSNAMELEN - 1)) + len = MFSNAMELEN - 1; + if (!(vp->typnm = mkstrcat(m.m_stat.f_fstypename, len, + (char *)NULL, -1, (char *)NULL, -1, + (MALLOC_S *)NULL))) + { + (void) fprintf(stderr, + "%s: no space for fs type name: ", Pn); + safestrprt(m.m_stat.f_fstypename, stderr, 1); + Exit(1); + } + } else + vp->typnm = ""; + } + vp->next = Lvfs; + Lvfs = vp; + return(vp); +} diff --git a/dialects/darwin/kmem/dnode.c b/dialects/darwin/kmem/dnode.c new file mode 100644 index 0000000..d634c62 --- /dev/null +++ b/dialects/darwin/kmem/dnode.c @@ -0,0 +1,1038 @@ +/* + * dnode.c - Darwin node functions for /dev/kmem-based lsof + */ + + +/* + * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana + * 47907. All rights reserved. + * + * Written by Victor A. Abell + * + * This software is not subject to any license of the American Telephone + * and Telegraph Company or the Regents of the University of California. + * + * Permission is granted to anyone to use this software for any purpose on + * any computer system, and to alter it and redistribute it freely, subject + * to the following restrictions: + * + * 1. Neither the authors nor Purdue University are responsible for any + * consequences of the use of this software. + * + * 2. The origin of this software must not be misrepresented, either by + * explicit claim or by omission. Credit to the authors and Purdue + * University must appear in documentation and sources. + * + * 3. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 4. This notice may not be removed or altered. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: dnode.c,v 1.11 2006/03/27 23:24:50 abe Exp $"; +#endif + + +#include "lsof.h" + + +/* + * Local function prototypes + */ + +#if DARWINV<600 +_PROTOTYPE(static int lkup_dev_tty,(dev_t *dr, dev_t *rdr, INODETYPE *ir)); +#endif /* DARWINV<600 */ + +#if DARWINV>=800 +_PROTOTYPE(static char *getvpath,(KA_T va, struct vnode *rv)); +_PROTOTYPE(static int readvname,(KA_T addr, char *buf, int buflen)); +#endif /* DARWINV>=800 */ + + +#if DARWINV>=800 +/* + * getvpath() - get vnode path + * adapted from build_path() (.../bsd/vfs/vfs_subr.c) + */ + +static char * +getvpath(va, rv) + KA_T va; /* kernel address of the rightmost + * vnode in the path */ + struct vnode *rv; /* pointer to rightmost vnode */ +{ + char *ap; + static char *bp = (char *)NULL; + static size_t bl = (size_t)(MAXPATHLEN + MAXPATHLEN + 1); + static char *cb = (char *)NULL; + static size_t cbl = (size_t)0; + static int ce = 0; + struct mount mb; + int pl, vnl; + char *pp, vn[MAXPATHLEN+1]; + struct vnode vb; + KA_T vas = va; +/* + * Initialize the path assembly. + */ + if (!bp) { + if (!(bp = (char *)malloc((MALLOC_S)bl))) { + (void) fprintf(stderr, "%s: no space (%d) for path assembly\n", + Pn, (int)bl); + Exit(1); + } + } + pp = bp + bl - 1; + *pp = '\0'; + pl = 0; +/* + * Process the starting vnode. + */ + if (!va) + return(0); + if ((rv->v_flag & VROOT) && rv->v_mount) { + + /* + * This is the root of a file system and it has a mount structure. + * Read the mount structure. + */ + if (kread((KA_T)rv->v_mount, (char *)&mb, sizeof(mb))) + return(0); + if (mb.mnt_flag & MNT_ROOTFS) { + + /* + * This is the root file system, so the path is "/". + */ + pp--; + *pp = '/'; + pl = 1; + goto getvpath_alloc; + } else { + + /* + * Get the covered vnode's pointer and read it. Use it to + * form the path. + */ + if ((va = (KA_T)mb.mnt_vnodecovered)) { + if (readvnode(va, &vb)) + return(0); + } + } + } else { + + /* + * Use the supplied vnode. + */ + vb = *rv; + } +/* + * Accumulate the path from the vnode chain. + */ + while (va && ((KA_T)vb.v_parent != va)) { + if (!vb.v_name) { + + /* + * If there is no name pointer or parent, the assembly is complete. + */ + if (vb.v_parent) { + + /* + * It is an error if there is a parent but no name. + */ + return((char *)NULL); + } + break; + } + /* + * Read the name and add it to the assembly. + */ + if ((vnl = readvname((KA_T)vb.v_name, vn, sizeof(vn))) <= 0) + return((char *)NULL); + if ((vnl + 1 + pl + 1) > bl) + return((char *)NULL); + memmove((void *)(pp - vnl), (void *)vn, vnl); + pp -= (vnl + 1); + *pp = '/'; + pl += vnl + 1; + if ((va == vas) && (vb.v_flag & VROOT)) { + + /* + * This is the starting vnode and it is a root vnode. Read its + * mount structure. + */ + if (vb.v_mount) { + if (kread((KA_T)vb.v_mount, (char *)&mb, sizeof(mb))) + return((char *)NULL); + if (mb.mnt_vnodecovered) { + + /* + * If there's a covered vnode, read it and use it's parent + * vnode pointer. + */ + if ((va = (KA_T)mb.mnt_vnodecovered)) { + if (readvnode(va, &vb)) + return((char *)NULL); + va = (KA_T)vb.v_parent; + } + } else + va = (KA_T)NULL; + } else + va = (KA_T)NULL; + } else + va = (KA_T)vb.v_parent; + /* + * If there's a parent vnode, read it. + */ + if (va) { + if (readvnode(va, &vb)) + return((char *)NULL); + if ((vb.v_flag & VROOT) && vb.v_mount) { + + /* + * The mount point has been reached. Read the mount structure + * and use its covered vnode pointer. + */ + if (kread((KA_T)vb.v_mount, (char *)&mb, sizeof(mb))) + return((char *)NULL); + if ((va = (KA_T)mb.mnt_vnodecovered)) { + if (readvnode(va, &vb)) + return((char *)NULL); + } + } + } + } +/* + * As a special case the following code attempts to trim a path that is + * larger than MAXPATHLEN by seeing if the lsof process CWD can be removed + * from the start of the path to make it MAXPATHLEN characters or less. + */ + if (pl > MAXPATHLEN) { + + /* + * Get the cwd. If that can't be done, return an error. + */ + if (ce) + return((char *)NULL); + if (!cb) { + if (!(cb = (char *)malloc((MALLOC_S)(MAXPATHLEN + 1)))) { + (void) fprintf(stderr, "%s: no space (%d) for CWD\n", + Pn, (int)bl); + Exit(1); + } + if (!getcwd(cb, (size_t)(MAXPATHLEN + 1))) { + if (!Fwarn) { + (void) fprintf(stderr, "%s: WARNING: can't get CWD\n", + Pn); + } + ce = 1; + return((char *)NULL); + } + cb[MAXPATHLEN - 1] = '\0'; + if (!(cbl = (size_t)strlen(cb))) { + if (!Fwarn) { + (void) fprintf(stderr, "%s: WARNING: CWD is NULL\n", + Pn); + } + ce = 1; + return((char *)NULL); + } + } + /* + * See if trimming the CWD shortens the path to MAXPATHLEN or less. + */ + if ((pl <= cbl) || strncmp(cb, pp, cbl)) + return((char *)NULL); + pp += cbl; + pl -= cbl; + if (cb[cbl - 1] == '/') { + + /* + * The CWD ends in a '/', so the path must not begin with one. If + * it does, no trimming can be done. + */ + if (*pp == '/') + return((char *)NULL); + } else { + + /* + * The CWD doesn't end in a '/', so the path must begin with one. + * If it doesn't, no trimming can be done. + */ + if (*pp != '/') + return((char *)NULL); + /* + * Skip all leading path '/' characters. Some characters must + * remain. + */ + while ((pl > 0) && (*pp == '/')) { + pp++; + pl--; + } + if (!pl) + return((char *)NULL); + } + } +/* + * Allocate space for the assembled path, including terminator, and return its + * pointer. + */ + +getvpath_alloc: + + if (!(ap = (char *)malloc(pl + 1))) { + (void) fprintf(stderr, "%s: no getvpath space (%d)\n", + Pn, pl + 1); + Exit(1); + } + (void) memmove(ap, pp, pl + 1); + return(ap); +} +#endif /* DARWINV>=800 */ + + +#if DARWINV<600 +/* + * lkup_dev_tty() - look up /dev/tty + */ + +static int +lkup_dev_tty(dr, rdr, ir) + dev_t *dr; /* place to return device number */ + dev_t *rdr; /* place to return raw device number */ + INODETYPE *ir; /* place to return inode number */ +{ + int i; + + readdev(0); + for (i = 0; i < Ndev; i++) { + if (strcmp(Devtp[i].name, "/dev/tty") == 0) { + *dr = DevDev; + *rdr = Devtp[i].rdev; + *ir = (INODETYPE)Devtp[i].inode; + return(1); + } + } + return(-1); +} +#endif /* DARWINV<600 */ + + +/* + * process_node() - process vnode + */ + +void +process_node(va) + KA_T va; /* vnode kernel space address */ +{ + dev_t dev = (dev_t)0; + dev_t rdev = (dev_t)0; + unsigned char devs = 0; + unsigned char rdevs = 0; + +#if DARWINV<800 + struct devnode *d = (struct devnode *)NULL; + struct devnode db; + unsigned char lt; + char dev_ch[32]; + +# if defined(HASFDESCFS) + struct fdescnode *f = (struct fdescnode *)NULL; + struct fdescnode fb; +# endif /* defined(HASFDESCFS) */ + + static INODETYPE fi; + static dev_t fdev, frdev; + static int fs = 0; + struct inode *i = (struct inode *)NULL; + struct inode ib; + struct lockf lf, *lff, *lfp; + struct nfsnode *n = (struct nfsnode *)NULL; + struct nfsnode nb; +#else /* DARWINV>=800 */ + struct stat sb; + char *vn; +#endif /* DARWINV<800 */ + + char *ty; + enum vtype type; + struct vnode *v, vb; + struct l_vfs *vfs; + +#if DARWINV<600 + struct hfsnode *h = (struct hfsnode *)NULL; + struct hfsnode hb; + struct hfsfilemeta *hm = (struct hfsfilemeta *)NULL; + struct hfsfilemeta hmb; +#else /* DARWINV>=600 */ +# if DARWINV<800 + struct cnode *h = (struct cnode *)NULL; + struct cnode hb; + struct filefork *hf = (struct filefork *)NULL; + struct filefork hfb; +# endif /* DARWINV<800 */ +#endif /* DARWINV<600 */ + +#if defined(HAS9660FS) + dev_t iso_dev; + int iso_dev_def = 0; + INODETYPE iso_ino; + long iso_links; + int iso_stat = 0; + SZOFFTYPE iso_sz; +#endif /* defined(HAS9660FS) */ + +/* + * Read the vnode. + */ + if ( ! va) { + enter_nm("no vnode address"); + return; + } + v = &vb; + if (readvnode(va, v)) { + enter_nm(Namech); + return; + } + type = v->v_type; + +#if defined(HASNCACHE) + Lf->na = va; +# if defined(HASNCVPID) + Lf->id = v->v_id; +# endif /* defined(HASNCVPID) */ +#endif /* defined(HASNCACHE) */ + +#if defined(HASFSTRUCT) + Lf->fna = va; + Lf->fsv |= FSV_NI; +#endif /* defined(HASFSTRUCT) */ + +/* + * Get the vnode type. + */ + if (!v->v_mount) + vfs = (struct l_vfs *)NULL; + else { + vfs = readvfs((KA_T)v->v_mount); + if (vfs) { + if (strcasecmp(vfs->typnm, "nfs") == 0) + Ntype = N_NFS; + +#if DARWINV<130 + else if (strcasecmp(vfs->typnm, "afpfs") == 0) + Ntype = N_AFPFS; +#endif /* DARWINV<130 */ + + } + } + if (Ntype == N_REGLR) { + switch (v->v_type) { + case VFIFO: + Ntype = N_FIFO; + break; + default: + break; + } + } + +#if DARWINV<800 +/* + * Define the specific node pointer. + */ + switch (v->v_tag) { + +# if DARWINV>120 + case VT_AFP: + break; +# endif /* DARWINV>120 */ + +# if DARWINV>120 + case VT_CDDA: + break; +# endif /* DARWINV>120 */ + +# if DARWINV>120 + case VT_CIFS: + break; +# endif /* DARWINV>120 */ + + case VT_DEVFS: + if (!v->v_data + || kread((KA_T)v->v_data, (char *)&db, sizeof(db))) { + (void) snpf(Namech, Namechl, "no devfs node: %#x", v->v_data); + enter_nm(Namech); + return; + } + d = &db; + break; + +# if defined(HASFDESCFS) + case VT_FDESC: + if (!v->v_data + || kread((KA_T)v->v_data, (char *)&fb, sizeof(fb))) { + (void) snpf(Namech, Namechl, "no fdesc node: %s", + print_kptr((KA_T)v->v_data, (char *)NULL, 0)); + enter_nm(Namech); + return; + } + f = &fb; + break; +# endif /* defined(HASFDESCFS) */ + + case VT_HFS: + +# if DARWINV<130 + if (Ntype != N_AFPFS) { +# endif /* DARWINV<130 */ + + if (!v->v_data + || kread((KA_T)v->v_data, (char *)&hb, sizeof(hb))) { + (void) snpf(Namech, Namechl, "no hfs node: %s", + print_kptr((KA_T)v->v_data, (char *)NULL, 0)); + enter_nm(Namech); + return; + } + h = &hb; + +# if DARWINV<600 + if (!h->h_meta + || kread((KA_T)h->h_meta, (char *)&hmb, sizeof(hmb))) { + (void) snpf(Namech, Namechl, "no hfs node metadata: %s", + print_kptr((KA_T)v->v_data, (char *)NULL, 0)); + enter_nm(Namech); + return; + } + hm = &hmb; +# else /* DARWINV>=600 */ + if (v->v_type == VDIR) + break; + if (h->c_rsrc_vp == v) + hf = h->c_rsrcfork; + else + hf = h->c_datafork; + if (!hf + || kread((KA_T)hf, (char *)&hfb, sizeof(hfb))) { + (void) snpf(Namech, Namechl, "no hfs node fork: %s", + print_kptr((KA_T)v->v_data, (char *)NULL, 0)); + enter_nm(Namech); + return; + } + hf = &hfb; +# endif /* DARWINV<600 */ + +# if DARWINV<130 + } +# endif /* DARWINV<130 */ + + break; + +# if defined(HAS9660FS) + case VT_ISOFS: + if (read_iso_node(v, &iso_dev, &iso_dev_def, &iso_ino, &iso_links, + &iso_sz)) + { + (void) snpf(Namech, Namechl, "no iso node: %s", + print_kptr((KA_T)v->v_data, (char *)NULL, 0)); + enter_nm(Namech); + return; + } + iso_stat = 1; + break; +# endif /* defined(HAS9660FS) */ + + case VT_NFS: + if (!v->v_data + || kread((KA_T)v->v_data, (char *)&nb, sizeof(nb))) { + (void) snpf(Namech, Namechl, "no nfs node: %s", + print_kptr((KA_T)v->v_data, (char *)NULL, 0)); + enter_nm(Namech); + return; + } + n = &nb; + break; + +# if DARWINV>120 + case VT_UDF: + break; +# endif /* DARWINV>120 */ + + case VT_UFS: + if (!v->v_data + || kread((KA_T)v->v_data, (char *)&ib, sizeof(ib))) { + (void) snpf(Namech, Namechl, "no ufs node: %s", + print_kptr((KA_T)v->v_data, (char *)NULL, 0)); + enter_nm(Namech); + return; + } + i = &ib; + if ((lff = i->i_lockf)) { + + /* + * Determine the lock state. + */ + lfp = lff; + do { + if (kread((KA_T)lfp, (char *)&lf, sizeof(lf))) + break; + lt = 0; + switch (lf.lf_flags & (F_FLOCK|F_POSIX)) { + case F_FLOCK: + if (Cfp && (struct file *)lf.lf_id == Cfp) + lt = 1; + break; + case F_POSIX: + if ((KA_T)lf.lf_id == Kpa) + lt = 1; + break; + } + if (!lt) + continue; + if (lf.lf_start == (off_t)0 + && lf.lf_end == 0xffffffffffffffffLL) + lt = 1; + else + lt = 0; + if (lf.lf_type == F_RDLCK) + Lf->lock = lt ? 'R' : 'r'; + else if (lf.lf_type == F_WRLCK) + Lf->lock = lt ? 'W' : 'w'; + else if (lf.lf_type == (F_RDLCK | F_WRLCK)) + Lf->lock = 'u'; + break; + } while ((lfp = lf.lf_next) && lfp != lff); + } + break; + +# if DARWINV>120 + case VT_WEBDAV: + break; +# endif /* DARWINV>120 */ + + default: + if (v->v_type == VBAD || v->v_type == VNON) + break; + (void) snpf(Namech, Namechl, "unknown file system type: %d", + v->v_tag); + enter_nm(Namech); + return; + } +/* + * Get device and type for printing. + */ + if (n) { + dev = n->n_vattr.va_fsid; + devs = 1; + } else if (i) { + dev = i->i_dev; + devs = 1; + if ((type == VCHR) || (type == VBLK)) { + rdev = i->i_rdev ; + rdevs = 1; + } + } + +# if defined(HASFDESCFS) + else if (f) { + if (f->fd_link + && !kread((KA_T)f->fd_link, Namech, Namechl -1)) + Namech[Namechl - 1] = '\0'; + +# if DARWINV<600 + else if (f->fd_type == Fctty) { + if (fs == 0) + fs = lkup_dev_tty(&fdev, &frdev, &fi); + if (fs == 1) { + dev = fdev; + rdev = frdev; + devs = Lf->inp_ty = rdevs = 1; + Lf->inode = fi; + } + } + } +# endif /* DARWINV<600 */ +# endif /* defined(HASFDESCFS) */ + + else if (h) { + +# if DARWINV<600 + dev = hm->h_dev; +# else /* DARWINV>=600 */ + dev = h->c_dev; +# endif /* DARWINV<600 */ + + devs = 1; + if ((type == VCHR) || (type == VBLK)) { + +# if DARWINV<600 + rdev = hm->h_rdev; +# else /* DARWINV>=600 */ + rdev = h->c_rdev; +# endif /* DARWINV<600 */ + + rdevs = 1; + } + } else if (d) { + dev = DevDev; + devs = 1; + rdev = d->dn_typeinfo.dev; + rdevs = 1; + } + +# if defined(HAS9660FS) + else if (iso_stat && iso_dev_def) { + dev = iso_dev; + devs = Lf->inp_ty = 1; + } +# endif /* defined(HAS9660FS) */ + + +/* + * Obtain the inode number. + */ + if (i) { + Lf->inode = (INODETYPE)i->i_number; + Lf->inp_ty = 1; + } else if (n) { + Lf->inode = (INODETYPE)n->n_vattr.va_fileid; + Lf->inp_ty = 1; + } else if (h) { + +# if DARWINV<600 + Lf->inode = (INODETYPE)hm->h_nodeID; +# else /* DARWINV>=600 */ + Lf->inode = (INODETYPE)h->c_fileid; +# endif /* DARWINV<600 */ + + Lf->inp_ty = 1; + } + +# if defined(HAS9660FS) + else if (iso_stat) { + Lf->inode = iso_ino; + Lf->inp_ty = 1; + } +# endif /* defined(HAS9660FS) */ + +/* + * Obtain the file size. + */ + if (Foffset) + Lf->off_def = 1; + else { + switch (Ntype) { + case N_FIFO: + if (!Fsize) + Lf->off_def = 1; + break; + case N_NFS: + if (n) { + Lf->sz = (SZOFFTYPE)n->n_vattr.va_size; + Lf->sz_def = 1; + } + break; + +# if DARWINV<130 + case N_AFPFS: + break; +# endif /* DARWINV<130 */ + + case N_REGLR: + if (type == VREG || type == VDIR) { + if (i) { + Lf->sz = (SZOFFTYPE)i->i_size; + Lf->sz_def = 1; + } else if (h) { + +# if DARWINV<600 + Lf->sz = (type == VDIR) ? (SZOFFTYPE)hm->h_size + : (SZOFFTYPE)h->fcbEOF; +# else /* DARWINV>=600 */ + if (type == VDIR) + Lf->sz = (SZOFFTYPE)h->c_nlink * 128; + else + Lf->sz = (SZOFFTYPE)hf->ff_size; +# endif /* DARWINV<600 */ + + Lf->sz_def = 1; + } + +# if defined(HAS9660FS) + else if (iso_stat) { + Lf->sz = (SZOFFTYPE)iso_sz; + Lf->sz_def = 1; + } +# endif /* defined(HAS9660FS) */ + + } + else if ((type == VCHR || type == VBLK) && !Fsize) + Lf->off_def = 1; + break; + } + } +/* + * Record the link count. + */ + if (Fnlink) { + switch(Ntype) { + case N_NFS: + if (n) { + Lf->nlink = (long)n->n_vattr.va_nlink; + Lf->nlink_def = 1; + } + break; + +# if DARWINV<130 + case N_AFPFS: + break; +# endif /* DARWINV<130 */ + + case N_REGLR: + if (i) { + Lf->nlink = (long)i->i_nlink; + Lf->nlink_def = 1; + } else if (h) { + +# if DARWINV<600 + Lf->nlink = (long)hm->h_nlink; +# else /* DARWINV>=600 */ + Lf->nlink = (long)h->c_nlink; +# endif /* DARWINV<600 */ + + Lf->nlink_def = 1; + } + +# if defined(HAS9660FS) + else if (iso_stat) { + Lf->nlink = iso_links; + Lf->nlink_def = 1; + } +# endif /* defined(HAS9660FS) */ + + break; + } + if (Lf->nlink_def && Nlink && (Lf->nlink < Nlink)) + Lf->sf |= SELNLINK; + } +#else /* DARWINV>=800 */ + +/* + * Process a vnode for Darwin >= 8.0. + */ + if ((vn = getvpath(va, v))) { + + /* + * If the vnode yields a path, get the file's information by doing + * a "safe" stat(2) of the path. + */ + if (!statsafely(vn, &sb)) { + + /* + * Save file size or offset. + */ + if (Foffset) { + Lf->off_def = 1; + } else { + switch (Ntype) { + case N_FIFO: + if (!Fsize) + Lf->off_def = 1; + break; + case N_NFS: + case N_REGLR: + if (type == VREG || type == VDIR) { + Lf->sz = sb.st_size; + Lf->sz_def = 1; + } else if ((type == VCHR || type == VBLK) && !Fsize) + Lf->off_def = 1; + break; + } + } + /* + * Save node number. + */ + Lf->inode = (INODETYPE)sb.st_ino; + Lf->inp_ty = 1; + /* + * Optionally save link count. + */ + if (Fnlink) { + Lf->nlink = sb.st_nlink; + Lf->nlink_def = 1; + } + /* + * Save device number and path. + */ + switch (v->v_tag) { + case VT_DEVFS: + if (vn) + (void) free((FREE_P *)vn); + dev = DevDev; + devs = 1; + break; + default : + Lf->V_path = vn; + dev = sb.st_dev; + devs = 1; + break; + } + /* + * Save character and block device number. + */ + if ((type == VCHR) || (type == VBLK)) { + rdev = sb.st_rdev; + rdevs = 1; + } + } else { + + /* + * Indicate a stat(2) failure in Namech[]. + */ + (void) snpf(Namech, Namechl, "stat(%s): %s", vn, + strerror(errno)); + (void) free((FREE_P *)vn); + } + /* + * Record an NFS file. + */ + if (vfs && !strcmp(vfs->typnm, "nfs")) + Ntype = N_NFS; + } +#endif /* DARWINV>=800 */ + +/* + * Record an NFS file selection. + */ + if (Ntype == N_NFS && Fnfs) + Lf->sf |= SELNFS; +/* + * Save the file system names. + */ + if (vfs) { + Lf->fsdir = vfs->dir; + Lf->fsdev = vfs->fsname; + } +/* + * Save the device numbers and their states. + * + * Format the vnode type, and possibly the device name. + */ + Lf->dev = dev; + Lf->dev_def = devs; + Lf->rdev = rdev; + Lf->rdev_def = rdevs; + switch (type) { + case VNON: + ty ="VNON"; + break; + case VREG: + ty = "VREG"; + break; + case VDIR: + ty = "VDIR"; + break; + case VBLK: + ty = "VBLK"; + Ntype = N_BLK; + break; + case VCHR: + ty = "VCHR"; + Ntype = N_CHR; + break; + case VLNK: + ty = "VLNK"; + break; + +#if defined(VSOCK) + case VSOCK: + ty = "SOCK"; + break; +#endif /* defined(VSOCK) */ + + case VBAD: + ty = "VBAD"; + break; + case VFIFO: + ty = "FIFO"; + break; + default: + (void) snpf(Lf->type, sizeof(Lf->type), "%04o", (type & 0xfff)); + ty = (char *)NULL; + } + if (ty) + (void) snpf(Lf->type, sizeof(Lf->type), "%s", ty); + Lf->ntype = Ntype; +/* + * Handle some special cases: + * + * ioctl(fd, TIOCNOTTY) files; + * memory node files; + * /proc files. + */ + if (type == VBAD) + (void) snpf(Namech, Namechl, "(revoked)"); + +#if defined(HASBLKDEV) +/* + * If this is a VBLK file and it's missing an inode number, try to + * supply one. + */ + if ((Lf->inp_ty == 0) && (type == VBLK)) + find_bl_ino(); +#endif /* defined(HASBLKDEV) */ + +/* + * If this is a VCHR file and it's missing an inode number, try to + * supply one. + */ + if ((Lf->inp_ty == 0) && (type == VCHR)) + find_ch_ino(); +/* + * Test for specified file. + */ + if (Sfile && is_file_named((char *)NULL, + ((type == VCHR) || (type == VBLK) ? 1 + : 0))) + Lf->sf |= SELNM; +/* + * Enter name characters. + */ + if (Namech[0]) + enter_nm(Namech); +} + + +#if DARWINV>=800 +/* + * readvname() - read vnode's path name + */ + +static int +readvname(addr, buf, buflen) + KA_T addr; /* kernel v_path address */ + char *buf; /* receiving buffer */ + int buflen; /* sizeof(buf) */ +{ + int n, rl; +/* + * Read the name 32 characters at a time, until a NUL character + * has been read or the buffer has been filled. + */ + for (n = 0; n < buflen; addr += 32, n += 32) { + rl = buflen - n; + if (rl > 32) + rl = 32; + if (kread(addr, &buf[n], rl)) + return(0); + buf[n + rl] = '\0'; + if ((rl = (int)strlen(&buf[n])) < 32) { + return(n + rl); + } + } + return(0); +} +#endif /* DARWINV>=800 */ diff --git a/dialects/darwin/kmem/dnode1.c b/dialects/darwin/kmem/dnode1.c new file mode 100644 index 0000000..20a76c1 --- /dev/null +++ b/dialects/darwin/kmem/dnode1.c @@ -0,0 +1,107 @@ +/* + * dnode1.c - Darwin node functions for /dev/kmem-based lsof + * + * This module must be separate to keep separate the multiple kernel inode + * structure definitions. + */ + + +/* + * Copyright 1995 Purdue Research Foundation, West Lafayette, Indiana + * 47907. All rights reserved. + * + * Written by Victor A. Abell + * + * This software is not subject to any license of the American Telephone + * and Telegraph Company or the Regents of the University of California. + * + * Permission is granted to anyone to use this software for any purpose on + * any computer system, and to alter it and redistribute it freely, subject + * to the following restrictions: + * + * 1. Neither the authors nor Purdue University are responsible for any + * consequences of the use of this software. + * + * 2. The origin of this software must not be misrepresented, either by + * explicit claim or by omission. Credit to the authors and Purdue + * University must appear in documentation and sources. + * + * 3. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 4. This notice may not be removed or altered. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: dnode1.c,v 1.3 2005/11/01 20:24:51 abe Exp $"; +#endif + +#include "lsof.h" + +#if defined(HAS9660FS) + +/* + * Do a little preparation for #include'ing cd9660_node.h, then #include it. + */ + +#undef i_size; +#undef doff_t +#undef IN_ACCESS + +struct vop_abortop_args { int dummy; }; +struct vop_access_args { int dummy; }; +struct vop_blkatoff_args { int dummy; }; +struct vop_bmap_args { int dummy; }; +struct vop_close_args { int dummy; }; +struct vop_getattr_args { int dummy; }; +struct vop_inactive_args { int dummy; }; +struct vop_ioctl_args { int dummy; }; +struct vop_islocked_args { int dummy; }; +struct vop_lock_args { int dummy; }; +struct vop_lookup_args { int dummy; }; +struct vop_mmap_args { int dummy; }; +struct vop_open_args { int dummy; }; +struct vop_pathconf_args { int dummy; }; +struct vop_print_args { int dummy; }; +struct vop_read_args { int dummy; }; +struct vop_readdir_args { int dummy; }; +struct vop_readlink_args { int dummy; }; +struct vop_reclaim_args { int dummy; }; +struct vop_seek_args { int dummy; }; +struct vop_select_args { int dummy; }; +struct vop_strategy_args { int dummy; }; +struct vop_unlock_args { int dummy; }; + +#include + +/* + * read_iso_node() -- read CD 9660 iso_node + */ + +int +read_iso_node(v, d, dd, ino, nl, sz) + struct vnode *v; /* containing vnode */ + dev_t *d; /* returned device number */ + int *dd; /* returned device-defined flag */ + INODETYPE *ino; /* returned inode number */ + long *nl; /* returned number of links */ + SZOFFTYPE *sz; /* returned size */ +{ + + struct iso_node i; + + if (!v->v_data + || kread((KA_T)v->v_data, (char *)&i, sizeof(i))) + return(1); + + *d = i.i_dev; + *dd = 1; + *ino = (INODETYPE)i.i_number; + *nl = (long)i.inode.iso_links; + *sz = (SZOFFTYPE)i.i_size; + + return(0); +} +#endif /* defined(HAS9660FS) */ diff --git a/dialects/darwin/kmem/dproc.c b/dialects/darwin/kmem/dproc.c new file mode 100644 index 0000000..6fb0dd6 --- /dev/null +++ b/dialects/darwin/kmem/dproc.c @@ -0,0 +1,763 @@ +/* + * dproc.c - Darwin process access functions for /dev/kmem-based lsof + */ + + +/* + * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana + * 47907. All rights reserved. + * + * Written by Victor A. Abell + * + * This software is not subject to any license of the American Telephone + * and Telegraph Company or the Regents of the University of California. + * + * Permission is granted to anyone to use this software for any purpose on + * any computer system, and to alter it and redistribute it freely, subject + * to the following restrictions: + * + * 1. Neither the authors nor Purdue University are responsible for any + * consequences of the use of this software. + * + * 2. The origin of this software must not be misrepresented, either by + * explicit claim or by omission. Credit to the authors and Purdue + * University must appear in documentation and sources. + * + * 3. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 4. This notice may not be removed or altered. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: dproc.c,v 1.8 2005/11/01 20:24:51 abe Exp $"; +#endif + +#include "lsof.h" + +#include +#include +#include +#include + + +/* + * Local definitions + */ + +#define NPHASH 1024 /* Phash bucket count -- + * MUST BE A POWER OF 2!!! */ +#define PHASH(a) (((int)((a * 31415) >> 3)) & (NPHASH - 1)) +#define PINCRSZ 256 /* Proc[] size inrement */ + + +/* + * Local structures + */ + +struct phash { + KA_T ka; /* kernel proc struct address */ + struct proc *la; /* local proc struct address */ + struct phash *next; /* next phash entry */ +}; + + +/* + * Local function prototypes + */ + +_PROTOTYPE(static pid_t get_parent_pid,(KA_T kpa)); +_PROTOTYPE(static int read_procs,()); +_PROTOTYPE(static void process_map,(pid_t pid)); +_PROTOTYPE(static void enter_vn_text,(KA_T va, int *n)); + +#if DARWINV>=700 +_PROTOTYPE(static char *getcmdnm,(pid_t pid)); +#endif /* DARWINV>=700 */ + +_PROTOTYPE(static void get_kernel_access,(void)); + + +/* + * Local static values + */ + +static KA_T Akp = (KA_T)NULL; /* kernel allproc chain address */ +static int Np = 0; /* PA[] and Proc[] entry count */ +static int Npa = 0; /* Proc[] structure allocation count */ +static MALLOC_S Nv = 0; /* allocated Vp[] entries */ +static KA_T *Pa = (KA_T *)NULL; /* Proc[] addresses */ +struct phash **Phash = (struct phash **)NULL; + /* kernel proc address hash pointers */ +static struct proc *Proc = (struct proc *)NULL; + /* local copy of prc struct chain */ +static KA_T *Vp = NULL; /* vnode address cache */ + + +/* + * enter_vn_text() - enter a vnode text reference + */ + +static void +enter_vn_text(va, n) + KA_T va; /* vnode address */ + int *n; /* Vp[] entries in use */ +{ + int i; +/* + * Ignore the request if the vnode has already been entered. + */ + for (i = 0; i < *n; i++) { + if (va == Vp[i]) + return; + } +/* + * Save the text file information. + */ + alloc_lfile(" txt", -1); + Cfp = (struct file *)NULL; + process_node(va); + if (Lf->sf) + link_lfile(); + if (i >= Nv) { + + /* + * Allocate space for remembering the vnode. + */ + Nv += 10; + if (!Vp) + Vp=(KA_T *)malloc((MALLOC_S)(sizeof(struct vnode *)*10)); + else + Vp=(KA_T *)realloc((MALLOC_P *)Vp,(MALLOC_S)(Nv*sizeof(KA_T))); + if (!Vp) { + (void) fprintf(stderr, "%s: no txt ptr space, PID %d\n", + Pn, Lp->pid); + Exit(1); + } + } +/* + * Remember the vnode. + */ + Vp[*n] = va; + (*n)++; +} + + +/* + * gather_proc_info() -- gather process information + */ + +void +gather_proc_info() +{ + char *cmd; + struct filedesc fd; + int i, nf; + MALLOC_S nb; + static struct file **ofb = NULL; + static int ofbb = 0; + struct proc *p; + int pgid; + int ppid = 0; + static char *pof = (char *)NULL; + static int pofb = 0; + short pss, sf; + int px; + uid_t uid; + +#if DARWINV<800 + struct pcred pc; +#else /* DARWINV>=800 */ + struct ucred uc; +#endif /* DARWINV<800 */ + +/* + * Read the process table. + */ + if (read_procs()) { + (void) fprintf(stderr, "%s: can't read process table\n", Pn); + Exit(1); + } +/* + * Examine proc structures and their associated information. + */ + for (p = Proc, px = 0; px < Np; p++, px++) + { + +#if DARWINV<800 + if (!p->p_cred || kread((KA_T)p->p_cred, (char *)&pc, sizeof(pc))) + continue; + pgid = pc.p_rgid; + uid = pc.p_ruid; +#else /* DARWINV>=800 */ + if (!p->p_ucred || kread((KA_T)p->p_ucred, (char *)&uc, sizeof(uc))) + continue; + pgid = uc.cr_rgid; + uid = uc.cr_uid; +#endif /* DARWINV<800 */ + +#if defined(HASPPID) + ppid = get_parent_pid((KA_T)p->p_pptr); +#endif /* defined(HASPPID) */ + + /* + * Get the command name. + */ + +#if DARWINV<700 + cmd = p->P_COMM; +#else /* DARWINV>=700 */ + if (!strcmp(p->p_comm, "LaunchCFMApp")) { + if (!(cmd = getcmdnm(p->p_pid))) + cmd = p->p_comm; + } else + cmd = p->p_comm; +#endif /* DARWINV<700 */ + + /* + * See if process is excluded. + * + * Read file structure pointers. + */ + if (is_proc_excl(p->p_pid, pgid, (UID_ARG)uid, &pss, &sf)) + continue; + if (!p->p_fd || kread((KA_T)p->p_fd, (char *)&fd, sizeof(fd))) + continue; + if (!fd.fd_refcnt || fd.fd_lastfile > fd.fd_nfiles) + continue; + /* + * Allocate a local process structure. + * + * Set kernel's proc structure address. + */ + if (is_cmd_excl(cmd, &pss, &sf)) + continue; + alloc_lproc(p->p_pid, pgid, ppid, (UID_ARG)uid, cmd, (int)pss, + (int)sf); + Plf = (struct lfile *)NULL; + Kpa = Pa[px]; + /* + * Save current working directory information. + */ + if (fd.fd_cdir) { + alloc_lfile(CWD, -1); + Cfp = (struct file *)NULL; + process_node((KA_T)fd.fd_cdir); + if (Lf->sf) + link_lfile(); + } + /* + * Save root directory information. + */ + if (fd.fd_rdir) { + alloc_lfile(RTD, -1); + Cfp = (struct file *)NULL; + process_node((KA_T)fd.fd_rdir); + if (Lf->sf) + link_lfile(); + } + /* + * Process the VM map. + */ + process_map(p->p_pid); + /* + * Read open file structure pointers. + */ + if (!fd.fd_ofiles || (nf = fd.fd_nfiles) <= 0) + continue; + nb = (MALLOC_S)(sizeof(struct file *) * nf); + if (nb > ofbb) { + if (!ofb) + ofb = (struct file **)malloc(nb); + else + ofb = (struct file **)realloc((MALLOC_P *)ofb, nb); + if (!ofb) { + (void) fprintf(stderr, "%s: PID %d, no file * space\n", + Pn, p->p_pid); + Exit(1); + } + ofbb = nb; + } + if (kread((KA_T)fd.fd_ofiles, (char *)ofb, nb)) + continue; + + nb = (MALLOC_S)(sizeof(char) * nf); + if (nb > pofb) { + if (!pof) + pof = (char *)malloc(nb); + else + pof = (char *)realloc((MALLOC_P *)pof, nb); + if (!pof) { + (void) fprintf(stderr, "%s: PID %d, no file flag space\n", + Pn, p->p_pid); + Exit(1); + } + pofb = nb; + } + if (!fd.fd_ofileflags || kread((KA_T)fd.fd_ofileflags, pof, nb)) + zeromem(pof, nb); + + /* + * Save information on file descriptors. + */ + for (i = 0; i < nf; i++) { + if (ofb[i] && !(pof[i] & UF_RESERVED)) { + alloc_lfile(NULL, i); + process_file((KA_T)(Cfp = ofb[i])); + if (Lf->sf) { + +#if defined(HASFSTRUCT) + if (Fsv & FSV_FG) + Lf->pof = (long)pof[i]; +#endif /* defined(HASFSTRUCT) */ + + link_lfile(); + } + } + } + /* + * Examine results. + */ + if (examine_lproc()) + return; + } +} + + +#if DARWINV>=700 +static char * +getcmdnm(pid) + pid_t pid; /* process ID */ +{ + static int am; + static char *ap = (char *)NULL; + char *cp, *ep, *sp; + int mib[3]; + size_t sz; + + if (!ap) { + + /* + * Allocate space for the maximum argument size. + */ + mib[0] = CTL_KERN; + mib[1] = KERN_ARGMAX; + sz = sizeof(am); + if (sysctl(mib, 2, &am, &sz, NULL, 0) == -1) { + (void) fprintf(stderr, "%s: can't get arg max, PID %d\n", + Pn, pid); + Exit(1); + } + if (!(ap = (char *)malloc((MALLOC_S)am))) { + (void) fprintf(stderr, "%s: no arg ptr (%d) space, PID %d\n", + Pn, am, pid); + Exit(1); + } + } +/* + * Get the arguments for the process. + */ + mib[0] = CTL_KERN; + mib[1] = KERN_PROCARGS; + mib[2] = pid; + sz = (size_t)am; + if (sysctl(mib, 3, ap, &sz, NULL, 0) == -1) + return((char *)NULL); +/* + * Skip to the first NUL character, which should end the saved exec path. + */ + for (cp = ap; *cp && (cp < (ap + sz)); cp++) { + ; + } + if (cp >= (ap + sz)) + return((char *)NULL); +/* + * Skip trailing NULs, which should find the beginning of the command. + */ + while (!*cp && (cp < (ap + sz))) { + cp++; + } + if (cp >= (ap + sz)) + return((char *)NULL); +/* + * Make sure that the command is NUL-terminated. + */ + for (sp = cp; *cp && (cp < (ap + sz)); cp++) { + ; + } + if (cp >= (ap + sz)) + return((char *)NULL); + ep = cp; +/* + * Locate the start of the command's base name and return it. + */ + for (ep = cp, cp--; cp >= sp; cp--) { + if (*cp == '/') { + return(cp + 1); + } + } + return(sp); +} +#endif /* DARWINV>=700 */ + + +/* + * get_kernel_access() - get access to kernel memory + */ + +static void +get_kernel_access() +{ + +/* + * Check kernel version. + */ + (void) ckkv("Darwin", LSOF_VSTR, (char *)NULL, (char *)NULL); +/* + * Set name list file path. + */ + if (!Nmlst) + Nmlst = N_UNIX; + +#if defined(WILLDROPGID) +/* + * If kernel memory isn't coming from KMEM, drop setgid permission + * before attempting to open the (Memory) file. + */ + if (Memory) + (void) dropgid(); +#else /* !defined(WILLDROPGID) */ +/* + * See if the non-KMEM memory and the name list files are readable. + */ + if ((Memory && !is_readable(Memory, 1)) + || (Nmlst && !is_readable(Nmlst, 1))) + Exit(1); +#endif /* defined(WILLDROPGID) */ + +/* + * Open kernel memory access. + */ + if ((Kd = open(Memory ? Memory : KMEM, O_RDONLY, 0)) < 0) + { + (void) fprintf(stderr, "%s: open(%s): %s\n", Pn, + Memory ? Memory : KMEM, + strerror(errno)); + Exit(1); + } + (void) build_Nl(Drive_Nl); + if (nlist(Nmlst, Nl) < 0) { + (void) fprintf(stderr, "%s: can't read namelist from %s\n", + Pn, Nmlst); + Exit(1); + } + +#if defined(WILLDROPGID) +/* + * Drop setgid permission, if necessary. + */ + if (!Memory) + (void) dropgid(); +#endif /* defined(WILLDROPGID) */ + +} + + +/* + * get_parent_pid() - get parent process PID + */ + +static pid_t +get_parent_pid(kpa) + KA_T kpa; /* kernel parent process address */ +{ + struct phash *ph; + + if (kpa) { + for (ph = Phash[PHASH(kpa)]; ph; ph = ph->next) { + if (ph->ka == kpa) + return((pid_t)ph->la->p_pid); + } + } + return((pid_t)0); +} + + +/* + * initialize() - perform all initialization + */ + +void +initialize() +{ + get_kernel_access(); +} + + +/* + * kread() - read from kernel memory + */ + +int +kread(addr, buf, len) + KA_T addr; /* kernel memory address */ + char *buf; /* buffer to receive data */ + READLEN_T len; /* length to read */ +{ + int br; + + if ((off_t)addr & (off_t)0x3) { + + /* + * No read is possible if the address is not aligned on a word + * boundary. + */ + return(1); + } + if (lseek(Kd, (off_t)addr, SEEK_SET) == (off_t)-1) + return(1); + br = read(Kd, buf, len); + return((br == len) ? 0 : 1); +} + + +/* + * prcess_map() - process VM map + */ + +static void +process_map(pid) + pid_t pid; /* process id */ +{ + vm_address_t address = 0; + mach_msg_type_number_t count; + vm_region_extended_info_data_t e_info; + int n = 0; + mach_port_t object_name; + vm_size_t size = 0; + vm_map_t task; + vm_region_top_info_data_t t_info; + + struct vm_object { /* should come from */ + +#if DARWINV<800 + KA_T Dummy1[15]; +#else /* DARWINV>=800 */ + KA_T Dummy1[14]; +#endif /* DARWINV>=800 */ + + memory_object_t pager; + } vmo; + + struct vnode_pager { /* from */ + KA_T Dummy1[4]; + struct vnode *vnode; + } vp; + +/* + * Get the task port associated with the process + */ + if (task_for_pid((mach_port_name_t)mach_task_self(), pid, + (mach_port_name_t *)&task) + != KERN_SUCCESS) { + return; + } +/* + * Go through the task's address space, looking for blocks of memory + * backed by an external pager (i.e, a "vnode") + */ + for (address = 0;; address += size) { + count = VM_REGION_EXTENDED_INFO_COUNT; + if (vm_region(task, &address, &size, VM_REGION_EXTENDED_INFO, + (vm_region_info_t)&e_info, &count, &object_name) + != KERN_SUCCESS) { + break; + } + if (!e_info.external_pager) + continue; + count = VM_REGION_TOP_INFO_COUNT; + if (vm_region(task, &address, &size, VM_REGION_TOP_INFO, + (vm_region_info_t)&t_info, &count, &object_name) + != KERN_SUCCESS) { + break; + } + /* + * The returned "obj_id" is the "vm_object_t" address. + */ + if (!t_info.obj_id) + continue; + if (kread(t_info.obj_id, (char *)&vmo, sizeof(vmo))) + break; + /* + * If the "pager" is backed by a vnode then the "vm_object_t" + * "memory_object_t" address is actually a "struct vnode_pager *". + */ + if (!vmo.pager) + continue; + if (kread((KA_T)vmo.pager, (char *)&vp, sizeof(vp))) + break; + (void) enter_vn_text((KA_T)vp.vnode, &n); + } + return; +} + + +/* + * read_procs() - read proc structures + */ + +static int +read_procs() +{ + int h, i, np, pe; + KA_T kp, kpn; + MALLOC_S msz; + struct proc *p; + struct phash *ph, *phn; + + if (!Akp) { + + /* + * Get kernel allproc structure pointer once. + */ + if (get_Nl_value("aproc", Drive_Nl, &Akp) < 0 || !Akp) { + (void) fprintf(stderr, "%s: can't get proc table address\n", + Pn); + Exit(1); + } + } +/* + * Get the current number of processes and calculate PA and Proc[] allocation + * sizes large enough to handle it. + */ + if (get_Nl_value("nproc", Drive_Nl, &kp) < 0 || !kp) { + (void) fprintf(stderr, "%s: can't get nproc address\n", Pn); + Exit(1); + } + if (kread(kp, (char *)&np, sizeof(np))) { + (void) fprintf(stderr, "%s: can't read process count from %s\n", + Pn, print_kptr(kp, (char *)NULL, 0)); + Exit(1); + } + for (np += np, pe = PINCRSZ; pe < np; pe += PINCRSZ) + ; +/* + * Allocate or reallocate the Pa[] and Proc[] tables. + */ + msz = (MALLOC_S)(pe * sizeof(struct proc)); + if (!Proc) + Proc = (struct proc *)malloc(msz); + else if (pe > Npa) + Proc = (struct proc *)realloc((MALLOC_P *)Proc, msz); + if (!Proc) { + (void) fprintf(stderr, "%s: no space for proc table\n", Pn); + Exit(1); + } + msz = (MALLOC_S)(pe * sizeof(KA_T)); + if (!Pa) + Pa = (KA_T *)malloc(msz); + else if (pe > Npa) + Pa = (KA_T *)realloc((MALLOC_P *)Pa, msz); + if (!Pa) { + (void) fprintf(stderr, "%s: no space for proc addr table\n", Pn); + Exit(1); + } + Npa = pe; +/* + * Allocate or reset the Phash[] table. + */ + if (!Phash) { + Phash = (struct phash **)calloc(NPHASH, sizeof(struct phash *)); + } else { + for (h = 0; h < NPHASH; h++) { + for (ph = Phash[h]; ph; ph = phn) { + phn = ph->next; + (void) free((MALLOC_P *)ph); + } + Phash[h] = (struct phash *)NULL; + } + } + if (!Phash) { + (void) fprintf(stderr, "%s: no space for proc address hash\n", Pn); + Exit(1); + } +/* + * Read the proc structures on the kernel's chain. + */ + for (i = Np = 0, kp = Akp, p = Proc, pe += pe; + kp && i < pe; + i++, kp = kpn) + { + if (kread(kp, (char *)p, sizeof(struct proc))) + break; + kpn = (KA_T)(((KA_T)p->p_list.le_next == Akp) ? NULL + : p->p_list.le_next); + if (p->p_stat == 0 || p->p_stat == SZOMB) + continue; + /* + * Cache the proc structure's addresses. + */ + h = PHASH(kp); + if (!(ph = (struct phash *)malloc((MALLOC_S)sizeof(struct phash)))) + { + (void) fprintf(stderr, "%s: no space for phash struct\n", Pn); + Exit(1); + } + ph->ka = kp; + ph->la = p; + ph->next = Phash[h]; + Phash[h] = ph; + p++; + Pa[Np++] = kp; + if (Np >= Npa) { + + /* + * Enlarge Pa[] and Proc[]. + */ + msz = (int)((Npa + PINCRSZ) * sizeof(struct proc)); + if (!(Proc = (struct proc *)realloc((MALLOC_P *)Proc, msz))) { + (void) fprintf(stderr, "%s: no additional proc space\n", + Pn); + Exit(1); + } + msz = (int)((Npa + PINCRSZ) * sizeof(KA_T)); + if (!(Pa = (KA_T *)realloc((MALLOC_P *)Pa, msz))) { + (void) fprintf(stderr, + "%s: no additional proc addr space\n", Pn); + Exit(1); + } + Npa += PINCRSZ; + } + } +/* + * If too many processes were read, the chain following probably failed; + * report that and exit. + */ + if (i >= pe) { + (void) fprintf(stderr, "%s: can't follow kernel proc chain\n", Pn); + Exit(1); + } +/* + * If not in repeat mode, reduce Pa[] and Proc[] to their minimums. + */ + if (Np < Npa && !RptTm) { + msz = (MALLOC_S)(Np * sizeof(struct proc)); + if (!(Proc = (struct proc *)realloc((MALLOC_P *)Proc, msz))) { + (void) fprintf(stderr, "%s: can't reduce proc table\n", Pn); + Exit(1); + } + msz = (MALLOC_S)(Np * sizeof(KA_T)); + if (!(Pa = (KA_T *)realloc((MALLOC_P *)Pa, msz))) { + (void) fprintf(stderr, "%s: can't reduce proc addr table\n", + Pn); + Exit(1); + } + Npa = Np; + } +/* + * Return 0 if any processes were loaded; 1 if none were. + */ + return((Np > 0) ? 0 : 1); +} diff --git a/dialects/darwin/kmem/dproto.h b/dialects/darwin/kmem/dproto.h new file mode 100644 index 0000000..15ddb64 --- /dev/null +++ b/dialects/darwin/kmem/dproto.h @@ -0,0 +1,62 @@ +/* + * dproto.h - Darwin function prototypes for /dev/kmem-based lsof + * + * The _PROTOTYPE macro is defined in the common proto.h. + */ + + +/* + * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana + * 47907. All rights reserved. + * + * Written by Victor A. Abell + * + * This software is not subject to any license of the American Telephone + * and Telegraph Company or the Regents of the University of California. + * + * Permission is granted to anyone to use this software for any purpose on + * any computer system, and to alter it and redistribute it freely, subject + * to the following restrictions: + * + * 1. Neither the authors nor Purdue University are responsible for any + * consequences of the use of this software. + * + * 2. The origin of this software must not be misrepresented, either by + * explicit claim or by omission. Credit to the authors and Purdue + * University must appear in documentation and sources. + * + * 3. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 4. This notice may not be removed or altered. + */ + + +/* + * $Id: dproto.h,v 1.4 2005/11/01 20:24:51 abe Exp $ + */ + +_PROTOTYPE(extern int is_file_named,(char *p, int cd)); +_PROTOTYPE(extern struct l_vfs *readvfs,(KA_T vm)); + +#if defined(HASKQUEUE) +_PROTOTYPE(extern void process_kqueue,(KA_T ka)); +#endif /* defined(HASKQUEUE) */ + +#if defined(HASPIPEFN) +_PROTOTYPE(extern void process_pipe,(KA_T pa)); +#endif /* defined(HASPIPEFN) */ + +#if defined(HASPSXSEM) +_PROTOTYPE(extern void process_psxsem,(KA_T pa)); +#endif /* defined(HASPSXSEM) */ + +#if defined(HASPSXSHM) +_PROTOTYPE(extern void process_psxshm,(KA_T pa)); +#endif /* defined(HASPSXSHM) */ + +#if defined(HAS9660FS) +_PROTOTYPE(extern int read_iso_node,(struct vnode *v, dev_t *d, int *dd, INODETYPE *ino, long *nl, SZOFFTYPE *sz)); +#endif /* defined(HAS9660FS) */ + +_PROTOTYPE(extern void process_socket,(KA_T sa)); diff --git a/dialects/darwin/kmem/dsock.c b/dialects/darwin/kmem/dsock.c new file mode 100644 index 0000000..a5a993b --- /dev/null +++ b/dialects/darwin/kmem/dsock.c @@ -0,0 +1,478 @@ +/* + * dsock.c - Darwin socket processing functions for /dev/kmem-based lsof + */ + +/* + * Special Darwin socket info: Justin Walker, 000927 + */ + +/* + * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana + * 47907. All rights reserved. + * + * Written by Victor A. Abell + * + * This software is not subject to any license of the American Telephone + * and Telegraph Company or the Regents of the University of California. + * + * Permission is granted to anyone to use this software for any purpose on + * any computer system, and to alter it and redistribute it freely, subject + * to the following restrictions: + * + * 1. Neither the authors nor Purdue University are responsible for any + * consequences of the use of this software. + * + * 2. The origin of this software must not be misrepresented, either by + * explicit claim or by omission. Credit to the authors and Purdue + * University must appear in documentation and sources. + * + * 3. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 4. This notice may not be removed or altered. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: dsock.c,v 1.11 2005/11/01 20:24:51 abe Exp $"; +#endif + + +#include "lsof.h" + + +#if defined(HASIPv6) +/* + * IPv6_2_IPv4() -- macro to define the address of an IPv4 address contained + * in an IPv6 address + */ + +#define IPv6_2_IPv4(v6) (((uint8_t *)((struct in6_addr *)v6)->s6_addr)+12) +#endif /* defined(HASIPv6) */ + + +/* + * process_socket() - process socket + */ + +void +process_socket(sa) + KA_T sa; /* socket address in kernel */ +{ + struct domain d; + unsigned char *fa = (unsigned char *)NULL; + int fam, lp; + int fp = 0; + struct inpcb inp; + unsigned char *la = (unsigned char *)NULL; + struct protosw p; + struct socket s; + struct tcpcb t; + KA_T ta = (KA_T)NULL; + struct unpcb uc, unp; + struct sockaddr_un *ua = NULL; + struct sockaddr_un un; + int unl; + +#if defined(HASIPv6) + struct in6pcb in6p; +#endif /* defined(HASIPv6) */ + +#if defined(AF_SYSTEM) + struct kern_event_pcb kev_cb; +#endif /* defined(AF_SYSTEM) */ + +#if defined(AF_NDRV) + char buf[IFNAMSIZ]; + struct ndrv_cb ndrv_cb; + struct ifnet ifnet; +#endif /* defined(AF_NDRV) */ + + (void) snpf(Lf->type, sizeof(Lf->type), "sock"); + Lf->inp_ty = 2; +/* + * Read the socket, protocol, and domain structures. + */ + if (!sa) { + enter_nm("no socket address"); + return; + } + if (kread(sa, (char *)&s, sizeof(s))) { + (void) snpf(Namech, Namechl, "can't read socket struct from %s", + print_kptr(sa, (char *)NULL, 0)); + enter_nm(Namech); + return; + } + if (!s.so_type) { + enter_nm("no socket type"); + return; + } + if (!s.so_proto + || kread((KA_T)s.so_proto, (char *)&p, sizeof(p))) { + (void) snpf(Namech, Namechl, "can't read protocol switch from %s", + print_kptr((KA_T)s.so_proto, (char *)NULL, 0)); + enter_nm(Namech); + return; + } + if (!p.pr_domain + || kread((KA_T)p.pr_domain, (char *)&d, sizeof(d))) { + (void) snpf(Namech, Namechl, "can't read domain struct from %s", + print_kptr((KA_T)p.pr_domain, (char *)NULL, 0)); + enter_nm(Namech); + return; + } +/* + * Save size information. + */ + if (Fsize) { + if (Lf->access == 'r') + Lf->sz = (SZOFFTYPE)s.so_rcv.sb_cc; + else if (Lf->access == 'w') + Lf->sz = (SZOFFTYPE)s.so_snd.sb_cc; + else + Lf->sz = (SZOFFTYPE)(s.so_rcv.sb_cc + s.so_snd.sb_cc); + Lf->sz_def = 1; + } else + Lf->off_def = 1; + +#if defined(HASTCPTPIQ) + Lf->lts.rq = s.so_rcv.sb_cc; + Lf->lts.sq = s.so_snd.sb_cc; + Lf->lts.rqs = Lf->lts.sqs = 1; +#endif /* defined(HASTCPTPIQ) */ + +#if defined(HASSOOPT) + Lf->lts.ltm = (unsigned int)(s.so_linger & 0xffff); + Lf->lts.opt = (unsigned int)(s.so_options & 0xffff); + Lf->lts.pqlen = (unsigned int)s.so_incqlen; + Lf->lts.qlen = (unsigned int)s.so_qlen; + Lf->lts.qlim = (unsigned int)s.so_qlimit; + Lf->lts.rbsz = (unsigned long)s.so_rcv.sb_mbmax; + Lf->lts.sbsz = (unsigned long)s.so_snd.sb_mbmax; + Lf->lts.pqlens = Lf->lts.qlens = Lf->lts.qlims = Lf->lts.rbszs + = Lf->lts.sbszs = (unsigned char)1; +#endif /* defined(HASSOOPT) */ + +#if defined(HASSOSTATE) + Lf->lts.ss = (unsigned int)s.so_state; +#endif /* defined(HASSOSTATE) */ + +/* + * Process socket by the associated domain family. + */ + switch ((fam = d.dom_family)) { +/* + * Process an Internet domain socket. + */ + case AF_INET: + +#if defined(HASIPv6) + case AF_INET6: +#endif /* defined(HASIPv6) */ + + if (Fnet) { + if (!FnetTy + || ((FnetTy == 4) && (fam == AF_INET)) + +#if defined(HASIPv6) + || ((FnetTy == 6) && (fam == AF_INET6)) +#endif /* defined(HASIPv6) */ + + ) + Lf->sf |= SELNET; + } + printiproto(p.pr_protocol); + +#if defined(HASIPv6) + (void) snpf(Lf->type, sizeof(Lf->type), + (fam == AF_INET) ? "IPv4" : "IPv6"); +#else /* !defined(HASIPv6) */ + (void) snpf(Lf->type, sizeof(Lf->type), "inet"); +#endif /* defined(HASIPv6) */ + +#if defined(HASIPv6) + if (fam == AF_INET6) { + + /* + * Read IPv6 protocol control block. + */ + if (!s.so_pcb + || kread((KA_T)s.so_pcb, (char *)&in6p, sizeof(in6p))) + { + (void) snpf(Namech, Namechl, "can't read in6pcb at %s", + print_kptr((KA_T)s.so_pcb, (char *)NULL, 0)); + enter_nm(Namech); + return; + } + /* + * Save IPv6 address information. + */ + enter_dev_ch(print_kptr((KA_T)(in6p.in6p_ppcb ? in6p.in6p_ppcb + : s.so_pcb), + (char *)NULL, 0)); + if (p.pr_protocol == IPPROTO_TCP) + ta = (KA_T)in6p.in6p_ppcb; + la = (unsigned char *)&in6p.in6p_laddr; + lp = (int)ntohs(in6p.in6p_lport); + if (!IN6_IS_ADDR_UNSPECIFIED(&in6p.in6p_faddr) + || in6p.in6p_fport) + { + fa = (unsigned char *)&in6p.in6p_faddr; + fp = (int)ntohs(in6p.in6p_fport); + } + } else +#endif /* defined(HASIPv6) */ + + { + + /* + * Read IPv4 protocol control block. + */ + if (!s.so_pcb + || kread((KA_T)s.so_pcb, (char *)&inp, sizeof(inp))) { + if (!s.so_pcb) { + (void) snpf(Namech, Namechl, "no PCB%s%s", + (s.so_state & SS_CANTSENDMORE) ? ", CANTSENDMORE" + : "", + (s.so_state & SS_CANTRCVMORE) ? ", CANTRCVMORE" + : ""); + } else { + (void) snpf(Namech, Namechl, "can't read inpcb at %s", + print_kptr((KA_T)s.so_pcb, (char *)NULL, 0)); + } + enter_nm(Namech); + return; + } + /* + * Print Internet socket information. + */ + enter_dev_ch(print_kptr((KA_T)(inp.inp_ppcb ? inp.inp_ppcb + : s.so_pcb), + (char *)NULL, 0)); + /* + * Save IPv4 address information. + */ + if (p.pr_protocol == IPPROTO_TCP) + ta = (KA_T)inp.inp_ppcb; + la = (unsigned char *)&inp.inp_laddr; + lp = (int)ntohs(inp.inp_lport); + if (inp.inp_faddr.s_addr != INADDR_ANY || inp.inp_fport) { + fa = (unsigned char *)&inp.inp_faddr; + fp = (int)ntohs(inp.inp_fport); + } + } + +#if defined(HASIPv6) + if ((fam == AF_INET6) + && ((la && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)la)) + || ((fa && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)fa))))) { + + /* + * Adjust for IPv4 addresses mapped in IPv6 addresses. + */ + if (la) + la = (unsigned char *)IPv6_2_IPv4(la); + if (fa) + fa = (unsigned char *)IPv6_2_IPv4(fa); + fam = AF_INET; + } +#endif /* defined(HASIPv6) */ + + /* + * Enter local and remote addresses by address family. + */ + if (fa || la) + (void) ent_inaddr(la, lp, fa, fp, fam); + if (ta && !kread(ta, (char *)&t, sizeof(t))) { + Lf->lts.type = 0; + Lf->lts.state.i = (int)t.t_state; + +#if defined(HASSOOPT) + Lf->lts.kai = (unsigned int)t.t_timer[TCPT_KEEP]; +#endif /* defined(HASSOOPT) */ + +#if defined(HASTCPOPT) + Lf->lts.mss = (unsigned long)t.t_maxseg; + Lf->lts.msss = (unsigned char)1; + Lf->lts.topt = (unsigned int)t.t_flags; +#endif /* defined(HASTCPOPT) */ + + } + break; + +#if defined(AF_NDRV) +/* + * Process an NDRV domain socket. + */ + case AF_NDRV: + { + (void) snpf(Lf->type, sizeof(Lf->type), "ndrv"); + /* + * Read protocol control block. + */ + if (!s.so_pcb + || kread((KA_T)s.so_pcb, (char *)&ndrv_cb, sizeof(ndrv_cb))) { + (void) snpf(Namech, Namechl, "can't read ndrv_cb at %s", + print_kptr((KA_T)s.so_pcb, (char *)NULL, 0)); + enter_nm(Namech); + return; + } + /* + * Print NDRV socket information. + */ + enter_dev_ch(print_kptr((KA_T)(s.so_pcb), (char *)NULL, 0)); + /* + * Print device name, if bound + */ + if (!ndrv_cb.nd_if + || kread((KA_T)ndrv_cb.nd_if, (char *)&ifnet, sizeof(ifnet))) { + (void) snpf(Namech, Namechl, "can't read ifnet at %s", + print_kptr((KA_T)ndrv_cb.nd_if, (char *)NULL, 0)); + enter_nm(Namech); + return; + } + if (!ifnet.if_name + || kread((KA_T)ifnet.if_name, buf, sizeof(buf))) { + (void) snpf(Namech, Namechl, "can't read ifnet.if_name at %s", + print_kptr((KA_T)ifnet.if_name, (char *)NULL, 0)); + enter_nm(Namech); + return; + } + (void) snpf(Namech, Namechl, "-> %s%d", buf, ifnet.if_unit); + } + break; +#endif /* defined(AF_NDRV) */ + +#if defined(pseudo_AF_KEY) +/* + * Process an [internal] key-management function socket + */ + case pseudo_AF_KEY: + (void) snpf(Lf->type, sizeof(Lf->type), "key"); + break; +#endif /* defined(pseudo_AF_KEY) */ + +#if defined(AF_SYSTEM) +/* + * Process a SYSTEM domain socket + */ + case AF_SYSTEM: + (void) snpf(Lf->type, sizeof(Lf->type), "systm"); + /* + * Read protocol control block. + */ + if (!s.so_pcb + || kread((KA_T)s.so_pcb, (char *)&kev_cb, sizeof(kev_cb))) { + (void) snpf(Namech, Namechl, "can't read kev_cb at %s", + print_kptr((KA_T)s.so_pcb, (char *)NULL, 0)); + enter_nm(Namech); + return; + } + /* + * Print SYSTEM socket information. + */ + enter_dev_ch(print_kptr((KA_T)(s.so_pcb), (char *)NULL, 0)); + (void) snpf(Namech, Namechl, "[%lx:%lx:%lx]", + kev_cb.vendor_code_filter, + kev_cb.class_filter, kev_cb.subclass_filter); + break; +#endif /* defined(AF_SYSTEM) */ + +#if defined(AF_PPP) +/* + * Process a PPP domain socket + */ + case AF_PPP: + (void) snpf(Lf->type, sizeof(Lf->type), "ppp"); + break; +#endif /* defined(AF_PPP) */ + +/* + * Process a ROUTE domain socket. + */ + case AF_ROUTE: + (void) snpf(Lf->type, sizeof(Lf->type), "rte"); + if (s.so_pcb) + enter_dev_ch(print_kptr((KA_T)(s.so_pcb), (char *)NULL, 0)); + else + (void) snpf(Namech, Namechl, "no protocol control block"); + if (!Fsize) + Lf->off_def = 1; + break; +/* + * Process a Unix domain socket. + */ + case AF_UNIX: + if (Funix) + Lf->sf |= SELUNX; + (void) snpf(Lf->type, sizeof(Lf->type), "unix"); + /* + * Read Unix protocol control block and the Unix address structure. + */ + + enter_dev_ch(print_kptr(sa, (char *)NULL, 0)); + if (!s.so_pcb + || kread((KA_T)s.so_pcb, (char *)&unp, sizeof(unp))) { + (void) snpf(Namech, Namechl, "can't read unpcb at %s", + print_kptr((KA_T)s.so_pcb, (char *)NULL, 0)); + break; + } + if ((struct socket *)sa != unp.unp_socket) { + (void) snpf(Namech, Namechl, "unp_socket (%s) mismatch", + print_kptr((KA_T)unp.unp_socket, (char *)NULL, 0)); + break; + } + if (unp.unp_addr) { + if (kread((KA_T)unp.unp_addr, (char *)&un, sizeof(un))) { + (void) snpf(Namech, Namechl, "can't read unp_addr at %s", + print_kptr((KA_T)unp.unp_addr, (char *)NULL, 0)); + break; + } + ua = &un; + } + if (!ua) { + ua = &un; + (void) bzero((char *)ua, sizeof(un)); + ua->sun_family = AF_UNSPEC; + } + /* + * Print information on Unix socket that has no address bound + * to it, although it may be connected to another Unix domain + * socket as a pipe. + */ + if (ua->sun_family != AF_UNIX) { + if (ua->sun_family == AF_UNSPEC) { + if (unp.unp_conn) { + if (kread((KA_T)unp.unp_conn, (char *)&uc, sizeof(uc))) + (void) snpf(Namech, Namechl, + "can't read unp_conn at %s", + print_kptr((KA_T)unp.unp_conn,(char *)NULL,0)); + else + (void) snpf(Namech, Namechl, "->%s", + print_kptr((KA_T)uc.unp_socket,(char *)NULL,0)); + } else + (void) snpf(Namech, Namechl, "->(none)"); + } else + (void) snpf(Namech, Namechl, "unknown sun_family (%d)", + ua->sun_family); + break; + } + if (ua->sun_path[0]) { + unl = ua->sun_len - offsetof(struct sockaddr_un, sun_path); + if ((unl < 0) || (unl >= sizeof(ua->sun_path))) + unl = sizeof(ua->sun_path) - 1; + ua->sun_path[unl] = '\0'; + if (ua->sun_path[0] && Sfile && is_file_named(ua->sun_path, 0)) + Lf->sf |= SELNM; + if (ua->sun_path[0] && !Namech[0]) + (void) snpf(Namech, Namechl, "%s", ua->sun_path); + } else + (void) snpf(Namech, Namechl, "no address"); + break; + default: + printunkaf(fam, 1); + } + if (Namech[0]) + enter_nm(Namech); +} diff --git a/dialects/darwin/kmem/dstore.c b/dialects/darwin/kmem/dstore.c new file mode 100644 index 0000000..06a91f7 --- /dev/null +++ b/dialects/darwin/kmem/dstore.c @@ -0,0 +1,105 @@ +/* + * dstore.c - Darwin global storage for /dev/kmem-based lsof + */ + + +/* + * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana + * 47907. All rights reserved. + * + * Written by Victor A. Abell + * + * This software is not subject to any license of the American Telephone + * and Telegraph Company or the Regents of the University of California. + * + * Permission is granted to anyone to use this software for any purpose on + * any computer system, and to alter it and redistribute it freely, subject + * to the following restrictions: + * + * 1. Neither the authors nor Purdue University are responsible for any + * consequences of the use of this software. + * + * 2. The origin of this software must not be misrepresented, either by + * explicit claim or by omission. Credit to the authors and Purdue + * University must appear in documentation and sources. + * + * 3. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 4. This notice may not be removed or altered. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: dstore.c,v 1.5 2005/11/01 20:24:51 abe Exp $"; +#endif + + +#include "lsof.h" + +struct file *Cfp; /* curent file's file struct pointer */ + + +/* + * Drive_Nl -- table to drive the building of Nl[] via build_Nl() + * (See lsof.h and misc.c.) + */ + +struct drive_Nl Drive_Nl[] = { + + { "aproc", "_allproc" }, + { "nproc", "_nprocs" }, + { X_NCACHE, "_nchashtbl" }, + { X_NCSIZE, "_nchash" }, + { "", "" }, + { NULL, NULL } +}; + +int Kd = -1; /* KMEM descriptor */ +KA_T Kpa; /* kernel proc struct address */ +struct l_vfs *Lvfs = NULL; /* local vfs structure table */ + +int Np = 0; /* number of kernel processes */ + +struct kinfo_proc *P = NULL; /* local process table copy */ + +#if defined(HASFSTRUCT) +/* + * Pff_tab[] - table for printing file flags + */ + +struct pff_tab Pff_tab[] = { + { (long)FREAD, FF_READ }, + { (long)FWRITE, FF_WRITE }, + { (long)FNONBLOCK, FF_NBLOCK }, + { (long)FNDELAY, FF_NDELAY }, + { (long)FAPPEND, FF_APPEND }, + { (long)FASYNC, FF_ASYNC }, + { (long)FFSYNC, FF_FSYNC }, + { (long)FMARK, FF_MARK }, + { (long)FDEFER, FF_DEFER }, + { (long)FHASLOCK, FF_HASLOCK }, + { (long)O_NOCTTY, FF_NOCTTY }, + { (long)O_EVTONLY, FF_EVTONLY }, + { (long)0, NULL } +}; + + +/* + * Pof_tab[] - table for print process open file flags + */ + +struct pff_tab Pof_tab[] = { + +# if defined(UF_EXCLOSE) + { (long)UF_EXCLOSE, POF_CLOEXEC }, +# endif /* defined(UF_EXCLOSE) */ + +# if defined(UF_MAPPED) + { (long)UF_MAPPED, POF_MAPPED }, +# endif /* defined(UF_MAPPED) */ + + { (long)0, NULL } +}; +#endif /* defined(HASFSTRUCT) */ diff --git a/dialects/darwin/kmem/machine.h b/dialects/darwin/kmem/machine.h new file mode 100644 index 0000000..ebb2490 --- /dev/null +++ b/dialects/darwin/kmem/machine.h @@ -0,0 +1,647 @@ +/* + * machine.h - Darwin definitions for /dev/kmem-based lsof + */ + + +/* + * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana + * 47907. All rights reserved. + * + * Written by Victor A. Abell + * + * This software is not subject to any license of the American Telephone + * and Telegraph Company or the Regents of the University of California. + * + * Permission is granted to anyone to use this software for any purpose on + * any computer system, and to alter it and redistribute it freely, subject + * to the following restrictions: + * + * 1. Neither the authors nor Purdue University are responsible for any + * consequences of the use of this software. + * + * 2. The origin of this software must not be misrepresented, either by + * explicit claim or by omission. Credit to the authors and Purdue + * University must appear in documentation and sources. + * + * 3. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 4. This notice may not be removed or altered. + */ + + +/* + * $Id: machine.h,v 1.16 2010/07/29 16:03:04 abe Exp $ + */ + + +#if !defined(LSOF_MACHINE_H) +#define LSOF_MACHINE_H 1 + + +#include +#include + +# if DARWINV>=800 +#include "/usr/include/string.h" +# endif /* DARWINV>=800 */ + + +/* + * CAN_USE_CLNT_CREATE is defined for those dialects where RPC clnt_create() + * can be used to obtain a CLIENT handle in lieu of clnttcp_create(). + */ + +#define CAN_USE_CLNT_CREATE 1 + + +/* + * DEVDEV_PATH defines the path to the directory that contains device + * nodes. + */ + +#define DEVDEV_PATH "/dev" + + +/* + * GET_MAX_FD is defined for those dialects that provide a function other than + * getdtablesize() to obtain the maximum file descriptor number plus one. + */ + +/* #define GET_MAX_FD ? */ + + +/* + * HASAOPT is defined for those dialects that have AFS support; it specifies + * that the default path to an alternate AFS kernel name list file may be + * supplied with the -A option. + */ + +/* #define HASAOPT 1 */ + + +/* + * HASBLKDEV is defined for those dialects that want block device information + * recorded in BDevtp[]. + */ + +#define HASBLKDEV 1 + + +/* + * HASDCACHE is defined for those dialects that support a device cache + * file. + * + * HASENVDC defined the name of an environment variable that contains the + * device cache file path. The HASENVDC environment variable is ignored when + * the lsof process is setuid(root) or its real UID is 0. + * + * HASPERSDC defines the format for the last component of a personal device + * cache file path. The first will be the home directory of the real UID that + * executes lsof. + * + * HASPERSDCPATH defines the environment variable whose value is the middle + * component of the personal device cache file path. The middle component + * follows the home directory and precedes the results of applying HASPERSDC. + * The HASPERSDCPATH environment variable is ignored when the lsof process is + * setuid(root) or its real UID is 0. + * + * HASSYSDC defines a public device cache file path. When it's defined, it's + * used as the path from which to read the device cache. + * + * Consult the 00DCACHE and 00FAQ files of the lsof distribution for more + * information on device cache file path construction. + */ + +/* #define HASDCACHE 1 */ +/* #define HASENVDC "LSOFDEVCACHE" */ +/* #define HASPERSDC "%h/%p.lsof_%L" */ +/* #define HASPERSDCPATH "LSOFPERSDCPATH" */ +/* #define HASSYSDC "/your/choice/of/path" */ + + +/* + * HASCDRNODE is defined for those dialects that have CD-ROM nodes. + */ + +/* #define HASCDRNODE 1 */ + + +/* + * HASFIFONODE is defined for those dialects that have FIFO nodes. + */ + +/* #define HASFIFONODE 1 */ + + +/* + * HASFSINO is defined for those dialects that have the file system + * inode element, fs_ino, in the lfile structure definition in lsof.h. + */ + +/* #define HASFSINO 1 */ + + +/* + * HASFSTRUCT is defined if the dialect has a file structure. + * + * FSV_DEFAULT defines the default set of file structure values to list. + * It defaults to zero (0), but may be made up of a combination of the + * FSV_* symbols from lsof.h. + * + * HASNOFSADDR -- has no file structure address + * HASNOFSFLAGS -- has no file structure flags + * HASNOFSCOUNT -- has no file structure count + * HASNOFSNADDR -- has no file structure node address + */ + +#define HASFSTRUCT 1 +/* #define FSV_DEFAULT FSV_? | FSV_? | FSV_? */ +/* #define HASNOFSADDR 1 has no file structure address */ +/* #define HASNOFSFLAGS 1 has no file structure flags */ +/* #define HASNOFSCOUNT 1 has no file structure count */ +/* #define HASNOFSNADDR 1 has no file structure node address */ + + +/* + * HASGNODE is defined for those dialects that have gnodes. + */ + +/* #define HASGNODE 1 */ + + +/* + * HASHSNODE is defined for those dialects that have High Sierra nodes. + */ + +/* #define HASHSNODE 1 */ + + +/* + * HASINODE is defined for those dialects that have inodes and wish to + * use readinode() from node.c. + */ + +# if DARWINV<800 +#define HASINODE 1 +# endif /* DARWINV<800 */ + + +/* + * HASINTSIGNAL is defined for those dialects whose signal function returns + * an int. + */ + +/* #define HASINTSIGNAL 1 */ + + +/* + * HASKERNIDCK is defined for those dialects that support the comparison of + * the build to running kernel identity. + */ + +#define HASKERNIDCK 1 + + +/* + * HASKOPT is defined for those dialects that support the -k option of + * reading the kernel's name list from an optional file. + */ + +#define HASKOPT 1 + + +/* + * HASLFILEADD is defined for those dialects that need additional elements + * in struct lfile. The HASLFILEADD definition is a macro that defines + * them. If any of the additional elements need to be preset in the + * alloc_lfile() function of proc.c, the SETLFILEADD macro may be defined + * to do that. + * + * If any additional elements need to be cleared in alloc_lfile() or in the + * free_proc() function of proc.c, the CLRLFILEADD macro may be defined to + * do that. Note that CLRLFILEADD takes one argument, the pointer to the + * lfile struct. The CLRLFILEADD macro is expected to expand to statements + * that are complete -- i.e., have terminating semi-colons -- so the macro is + * called without a terminating semicolon by proc.c. + * + * The HASXOPT definition may be used to select the conditions under which + * private lfile elements are used. + */ + +# if DARWINV>=800 +#define HASLFILEADD char *V_path; +#define CLRLFILEADD(lf) if (lf->V_path) { \ + (void) free((FREE_P *)lf->V_path); \ + lf->V_path = (char *)NULL; \ + } +#define SETLFILEADD Lf->V_path = (char *)NULL; +# endif /* DARWINV>=800 */ + + +/* + * HASMNTSTAT indicates the dialect supports the mount stat(2) result option + * in its l_vfs and mounts structures. + */ + +/* #define HASMNTSTAT 1 */ + + +/* + * HASMNTSUP is defined for those dialects that support the mount supplement + * option. + */ + +/* #define HASMNTSUP 1 */ + + +/* + * HASMOPT is defined for those dialects that support the reading of + * kernel memory from an alternate file. + */ + +#define HASMOPT 1 + + +/* + * HASNCACHE is defined for those dialects that have a kernel name cache + * that lsof can search. A value of 1 directs printname() to prefix the + * cache value with the file system directory name; 2, avoid the prefix. + * + * NCACHELDPFX is a set of C commands to execute before calling ncache_load(). + * + * NCACHELDSFX is a set of C commands to execute after calling ncache_load(). + */ + +# if DARWINV<800 +#define HASNCACHE 1 +/* #define NCACHELDPFX ??? */ +/* #define NCACHELDSFX ??? */ +# else /* DARWINV>=800 */ +/* #define HASNCACHE 1 */ +/* #define NCACHELDPFX ??? */ +/* #define NCACHELDSFX ??? */ +# endif /* DARWINV<800 */ + + +/* + * HASNLIST is defined for those dialects that use nlist() to acccess + * kernel symbols. + */ + +#define HASNLIST 1 + + +/* + * HASPIPEFN is defined for those dialects that have a special function to + * process DTYPE_PIPE file structure entries. Its value is the name of the + * function. + * + * NOTE: don't forget to define a prototype for this function in dproto.h. + */ + +# if DARWINV<800 +/* #define HASPIPEFN process_pipe? */ +# else /* DARWINV>=800 */ +#define HASPIPEFN process_pipe +# endif /* DARWINV<800 */ + + +/* + * HASPIPENODE is defined for those dialects that have pipe nodes. + */ + +/* #define HASPIPENODE 1 */ + + +/* + * HASPMAPENABLED is defined when the reporting of portmapper registration + * info is enabled by default. + */ + +/* #define HASPMAPENABLED 1 */ + + +/* + * HASPPID is defined for those dialects that support identification of + * the parent process IDentifier (PPID) of a process. + */ +#define HASPPID 1 + + +/* + * HASPRINTDEV, HASPRINTINO, HASPRINTNM, HASPRINTOFF, and HASPRINTSZ + * define private dialect-specific functions for printing DEVice numbers, + * INOde numbers, NaMes, file OFFsets, and file SiZes. The functions are + * called from print_file(). + */ + +/* #define HASPRINTDEV print_dev? */ +/* #define HASPRINTINO print_ino? */ +/* #define HASPRINTNM print_nm? */ +/* #define HASPRINTOFF print_off? */ +/* #define HASPRINTSZ print_sz? */ + + +/* + * HASPRIVFILETYPE and PRIVFILETYPE are defined for dialects that have a + * file structure type that isn't defined by a DTYPE_* symbol. They are + * used in lib/prfp.c to select the type's processing. + * + * PRIVFILETYPE is the definition of the f_type value in the file struct. + * + * HASPRIVFILETYPE is the name of the processing function. + */ + +/* #define HASPRIVFILETYPE process_shmf? */ +/* #define PRIVFILETYPE ?? */ + + +/* + * HASPRIVNMCACHE is defined for dialects that have a private method for + * printing cached NAME column values for some files. HASPRIVNAMECACHE + * is defined to be the name of the function. + * + * The function takes one argument, a struct lfile pointer to the file, and + * returns non-zero if it prints a name to stdout. + */ + +# if DARWINV<800 +/* #define HASPRIVNMCACHE */ +# else /* DARWINV>=800 */ +#define HASPRIVNMCACHE print_v_path +# endif /* DARWINV<800 */ + + +/* + * HASPRIVPRIPP is defined for dialects that have a private function for + * printing IP protocol names. When HASPRIVPRIPP isn't defined, the + * IP protocol name printing function defaults to printiprto(). + */ + +/* #define HASPRIVPRIPP 1 */ + + +/* + * HASPROCFS is defined for those dialects that have a proc file system -- + * usually /proc and usually in SYSV4 derivatives. + * + * HASFSTYPE is defined as 1 for those systems that have a file system type + * string, st_fstype, in the stat() buffer; 2, for those systems that have a + * file system type integer in the stat() buffer, named MOUNTS_STAT_FSTYPE; + * 0, for systems whose stat(2) structure has no file system type member. The + * additional symbols MOUNTS_FSTYPE, RMNT_FSTYPE, and RMNT_STAT_FSTYPE may be + * defined in dlsof.h to direct how the readmnt() function in lib/rmnt.c + * preserves these stat(2) and getmntent(3) buffer values in the local mounts + * structure. + * + * The defined value is the string that names the file system type. + * + * The HASPROCFS definition usually must be accompanied by the HASFSTYPE + * definition and the providing of an fstype element in the local mounts + * structure (defined in dlsof.h). + * + * The HASPROCFS definition may be accompanied by the HASPINODEN definition. + * HASPINODEN specifies that searching for files in HASPROCFS is to be done + * by inode number. + */ + +# if defined(HASPROCFS) +#undef HASPROCFS +#define HASPROCFS "proc" +# endif /* defined(HASPROCFS) */ + +/* #define HASPROCFS "proc?" */ +/* #define HASFSTYPE 1 */ + +#define HASPINODEN 1 + + +/* + * HASRNODE is defined for those dialects that have rnodes. + */ + +/* #define HASRNODE 1 */ + + +/* + * Define HASSECURITY to restrict the listing of all open files to the + * root user. When HASSECURITY is defined, the non-root user may list + * only files whose processes have the same user ID as the real user ID + * (the one that its user logged on with) of the lsof process. + */ + +/* #define HASSECURITY 1 */ + + +/* + * If HASSECURITY is defined, define HASNOSOCKSECURITY to allow users + * restricted by HASSECURITY to list any open socket files, provide their + * listing is selected by the "-i" option. + */ + +/* #define HASNOSOCKSECURITY 1 */ + + +/* + * HASSETLOCALE is defined for those dialects that have and + * setlocale(). + * + * If the dialect also has wide character support for language locales, + * HASWIDECHAR activates lsof's wide character support and WIDECHARINCL + * defines the header file (if any) that must be #include'd to use the + * mblen() and mbtowc() functions. + */ + +#define HASSETLOCALE 1 + +# if DARWINV>=700 +#define HASWIDECHAR 1 +# endif /* DARWINV>=700 */ + +/* #define WIDECHARINCL */ + + +/* + * HASSNODE is defined for those dialects that have snodes. + */ + +/* #define HASSNODE 1 */ + + +/* + * HASTASKS is defined for those dialects that have task reporting support. + */ + +/* #define HASTASKS 1 */ + + +/* + * HASSOOPT, HASSOSTATE and HASTCPOPT define the availability of information + * on socket options (SO_* symbols), socket states (SS_* symbols) and TCP + * options. + */ + +#define HASSOOPT 1 /* has socket option information */ +#define HASSOSTATE 1 /* has socket state information */ +#define HASTCPOPT 1 /* has TCP options or flags */ + + +/* + * Define HASSPECDEVD to be the name of a function that handles the results + * of a successful stat(2) of a file name argument. + * + * For example, HASSPECDEVD() for Darwin makes sure that st_dev is set to + * what stat("/dev") returns -- i.e., what's in DevDev. + * + * The function takes two arguments: + * + * 1: pointer to the full path name of file + * 2: pointer to the stat(2) result + * + * The function returns void. + */ + +#define HASSPECDEVD process_dev_stat + + +/* + * HASSTREAMS is defined for those dialects that support streams. + */ + +/* #define HASSTREAMS 1 */ + + +/* + * HASTCPTPIQ is defined for dialects where it is possible to report the + * TCP/TPI Recv-Q and Send-Q values produced by netstat. + */ + +#define HASTCPTPIQ 1 + + +/* + * HASTCPTPIW is defined for dialects where it is possible to report the + * TCP/TPI send and receive window sizes produced by netstat. + */ + +/* #define HASTCPTPIW 1 */ + + +/* + * HASTMPNODE is defined for those dialects that have tmpnodes. + */ + +/* #define HASTMPNODE 1 */ + + +/* + * HASVNODE is defined for those dialects that use the Sun virtual file system + * node, the vnode. BSD derivatives usually do; System V derivatives prior + * to R4 usually don't. + * doesn't. + */ + +#define HASVNODE 1 + + +/* + * HASXOPT is defined for those dialects that have an X option. It + * defines the text for the usage display. HASXOPT_VALUE defines the + * option's default binary value -- 0 or 1. + */ + +/* #define HASXOPT "help text for X option" */ +/* #define HASXOPT_VALUE 1 */ + + +/* + * INODETYPE and INODEPSPEC define the internal node number type and its + * printf specification modifier. These need not be defined and lsof.h + * can be allowed to define defaults. + * + * These are defined here, because they must be used in dlsof.h. + */ + +# if DARWINV>=800 +#define INODETYPE unsigned long long + /* inode number internal storage type */ +#define INODEPSPEC "ll" /* INODETYPE printf specification + * modifier */ +# endif /* DARWINV>=800 */ + + +/* + * UID_ARG defines the size of a User ID number when it is passed + * as a function argument. + */ + +#define UID_ARG int + + +/* + * Each USE_LIB_ is defined for dialects that use the + * in the lsof library. + * + * Note: other definitions and operations may be required to condition the + * library function source code. They may be found in the dialect dlsof.h + * header files. + */ + +#define USE_LIB_CKKV 1 /* ckkv.c */ +/* #define USE_LIB_COMPLETEVFS 1 cvfs.c */ +#define USE_LIB_FIND_CH_INO 1 /* fino.c */ +#define USE_LIB_IS_FILE_NAMED 1 /* isfn.c */ +#define USE_LIB_LKUPDEV 1 /* lkud.c */ +#define USE_LIB_PRINTDEVNAME 1 /* pdvn.c */ +/* #define USE_LIB_PROCESS_FILE 1 prfp.c */ +#define USE_LIB_PRINT_TCPTPI 1 /* ptti.c */ +/* #define USE_LIB_READDEV 1 rdev.c */ +/* #define USE_LIB_READMNT 1 rmnt.c */ +/* #define USE_LIB_REGEX 1 regex.c */ +/* #define USE_LIB_RNAM 1 rnam.c */ + +#if DARWINV<800 +#define USE_LIB_RNMH 1 /* rnmh.c */ +#else /* DARWINV>800 */ +/* #define USE_LIB_RNMH 1 rnmh.c */ +#endif /* DARWINV<800 */ + +/* #define USE_LIB_RNCH 1 rnch.c */ +/* #define USE_LIB_SNPF 1 snpf.c */ +#define snpf snprintf /* use the system's snprintf() */ + + +/* + * WARNDEVACCESS is defined for those dialects that should issue a warning + * when lsof can't access /dev (or /device) or one of its sub-directories. + * The warning can be inhibited by the lsof caller with the -w option. + */ + +#define WARNDEVACCESS 1 + + +/* + * WARNINGSTATE is defined for those dialects that want to suppress all lsof + * warning messages. + */ + +/* #define WARNINGSTATE 1 warnings are enabled by default */ + + +/* + * WILLDROPGID is defined for those dialects whose lsof executable runs + * setgid(not_real_GID) and whose setgid power can be relinquished after + * the dialect's initialize() function has been executed. + */ + +#define WILLDROPGID 1 + + +/* + * zeromem is a macro that uses bzero or memset. + */ + +#define zeromem(a, l) memset(a, 0, l) + +#endif /* !defined(LSOF_MACHINE_H) */ diff --git a/dialects/darwin/libproc/Makefile b/dialects/darwin/libproc/Makefile new file mode 100644 index 0000000..a3bdc3c --- /dev/null +++ b/dialects/darwin/libproc/Makefile @@ -0,0 +1,176 @@ + +# Darwin libproc-based lsof Makefile +# +# $Id: Makefile,v 1.8 2018/02/14 14:27:57 abe Exp $ + +PROG= lsof + +BIN= ${DSTROOT}/usr/sbin + +DOC= ${DSTROOT}/usr/share/man/man8 + +DS= /usr/bin/dsymutil + +I=/usr/include +S=/usr/include/sys +L=/usr/include/local +P= + +CDEF= ${RC_CFLAGS} +CDEFS= ${CDEF} ${CFGF} +INCL= ${DINC} +override CFLAGS= ${CDEFS} ${INCL} ${DEBUG} + +GRP= wheel + +HDR= lsof.h lsof_fields.h dlsof.h machine.h proto.h dproto.h + +SRC= ddev.c dfile.c dmnt.c dproc.c dsock.c dstore.c \ + arg.c main.c misc.c node.c print.c proc.c store.c usage.c util.c + +OBJ= ddev.o dfile.o dmnt.o dproc.o dsock.o dstore.o \ + arg.o main.o misc.o node.o print.o proc.o store.o usage.o util.o + +MAN= lsof.8 + +OTHER= + +SHELL= /bin/sh + +SOURCE= Makefile ${OTHER} ${MAN} ${HDR} ${SRC} + +all: ${PROG} + +${PROG}: ${LIB} ${P} ${OBJ} + ${CC} -o $@ ${CFLAGS} ${OBJ} ${CFGL} + +clean: FRC + rm -f Makefile.bak ${PROG} a.out core errs lint.out tags *.o version.h + rm -f machine.h.old new_machine.h + (cd lib; ${MAKE} -f Makefile.skel clean) + +install-strip: all FRC + if [ -n "${SYMROOT}" ]; then \ + mkdir -p ${SYMROOT}; \ + cp -p ${PROG} ${SYMROOT}/${PROG}; \ + if [ -x "${DS}" ]; then \ + ${DS} -o ${SYMROOT}/${PROG}.dSYM ${SYMROOT}/${PROG}; \ + fi \ + fi + mkdir -p ${BIN} + install -c -s -m 755 -g ${GRP} ${PROG} ${BIN} + mkdir -p ${DOC} + install -c -m 444 ${MAN} ${DOC} + +install: all FRC + @echo '' + @echo 'Please write your own install rule. Lsof for Darwin below 8' + @echo 'should be installed setgid to the group that has permission' + @echo 'to read /dev/kmem, often kmem or sys. Lsof for Darwin 8 and' + @echo 'above should be installed setuid-root. Your install rule' + @echo 'actions for Darwin below 8 might look something like this:' + @echo '' + @echo ' install -m 2xxx -g $${GRP} $${PROG} $${BIN}' + @echo ' install -m 444 $${MAN} $${DOC}' + @echo '' + @echo 'Your install rule actions for Darwin 8 and above might look' + @echo 'something like this:' + @echo '' + @echo ' install -m 4xxx -o root $${PROG} $${BIN}' + @echo ' install -m 444 $${MAN} $${DOC}' + @echo '' + @echo 'You will have to complete the xxx modes, the GRP value, and' + @echo 'the skeletons for the BIN and DOC strings, given at the' + @echo 'beginning of this Makefile, e.g.,' + @echo '' + @echo ' BIN= $${DESTDIR}/usr/local/etc' + @echo ' DOC= $${DESTDIR}/usr/man/man8' + @echo ' GRP= kmem' + @echo '' + +${LIB}: FRC + (cd lib; ${MAKE} DEBUG="${DEBUG}" CFGF="${CFGF}") + +version.h: FRC + @echo Constructing version.h + @rm -f version.h + @echo '#define LSOF_BLDCMT "${LSOF_BLDCMT}"' > version.h; + @echo '#define LSOF_CC "${CC}"' >> version.h + @echo '#define LSOF_CCV "${CCV}"' >> version.h + @echo '#define LSOF_CCDATE "'`date`'"' >> version.h + @echo '#define LSOF_CCFLAGS "'`echo ${CFLAGS} | sed 's/\\\\(/\\(/g' | sed 's/\\\\)/\\)/g' | sed 's/"/\\\\"/g'`'"' >> version.h + @echo '#define LSOF_CINFO "${CINFO}"' >> version.h + @if [ "X${LSOF_HOST}" = "X" ]; then \ + echo '#define LSOF_HOST "'`uname -n`'"' >> version.h; \ + else \ + if [ "${LSOF_HOST}" = "none" ]; then \ + echo '#define LSOF_HOST ""' >> version.h; \ + else \ + echo '#define LSOF_HOST "${LSOF_HOST}"' >> version.h; \ + fi \ + fi + @echo '#define LSOF_LDFLAGS "${CFGL}"' >> version.h + @if [ "X${LSOF_LOGNAME}" = "X" ]; then \ + echo '#define LSOF_LOGNAME "${LOGNAME}"' >> version.h; \ + else \ + if [ "${LSOF_LOGNAME}" = "none" ]; then \ + echo '#define LSOF_LOGNAME ""' >> version.h; \ + else \ + echo '#define LSOF_LOGNAME "${LSOF_LOGNAME}"' >> version.h; \ + fi; \ + fi + @if [ "X${LSOF_SYSINFO}" = "X" ]; then \ + echo '#define LSOF_SYSINFO "'`uname -a`'"' >> version.h; \ + else \ + if [ "${LSOF_SYSINFO}" = "none" ]; then \ + echo '#define LSOF_SYSINFO ""' >> version.h; \ + else \ + echo '#define LSOF_SYSINFO "${LSOF_SYSINFO}"' >> version.h; \ + fi \ + fi + @if [ "X${LSOF_USER}" = "X" ]; then \ + echo '#define LSOF_USER "${USER}"' >> version.h; \ + else \ + if [ "${LSOF_USER}" = "none" ]; then \ + echo '#define LSOF_USER ""' >> version.h; \ + else \ + echo '#define LSOF_USER "${LSOF_USER}"' >> version.h; \ + fi \ + fi + @sed '/VN/s/.ds VN \(.*\)/#define LSOF_VERSION "\1"/' < version >> version.h + +FRC: + +# DO NOT DELETE THIS LINE - make depend DEPENDS ON IT + +ddev.o: ${HDR} ddev.c + +dfile.o: ${HDR} dfile.c + +dmnt.o: ${HDR} dmnt.c + +dproc.o: ${HDR} dproc.c + +dsock.o: ${HDR} dsock.c + +dstore.o: ${HDR} dstore.c + +arg.o: ${HDR} arg.c + +main.o: ${HDR} main.c + +misc.o: ${HDR} misc.c + +node.o: ${HDR} node.c + +print.o: ${HDR} print.c + +proc.o: ${HDR} proc.c + +store.o: ${HDR} store.c + +usage.o: ${HDR} version.h usage.c + +util.o: ${HDR} util.c + +# *** Do not add anything here - It will go away. *** diff --git a/dialects/darwin/libproc/Mksrc b/dialects/darwin/libproc/Mksrc new file mode 100755 index 0000000..870d6ca --- /dev/null +++ b/dialects/darwin/libproc/Mksrc @@ -0,0 +1,24 @@ +#!/bin/sh +# +# Mksrc -- make Darwin libproc-based lsof source files +# +# WARNING: This script assumes it is running from the main directory +# of the lsof, version 4 distribution. +# +# One environment variable applies: +# +# LSOF_MKC is the method for creating the source files. +# It defaults to "ln -s". A common alternative is "cp". +# +# $Id: Mksrc,v 1.5 2005/11/06 12:50:09 abe Exp $ + + +D=dialects/darwin/libproc +L="dlsof.h ddev.c dfile.c dmnt.c dproc.c dproto.h dsock.c dstore.c machine.h" + +for i in $L +do + rm -f $i + $LSOF_MKC $D/$i $i + echo "$LSOF_MKC $D/$i $i" +done diff --git a/dialects/darwin/libproc/ddev.c b/dialects/darwin/libproc/ddev.c new file mode 100644 index 0000000..2240501 --- /dev/null +++ b/dialects/darwin/libproc/ddev.c @@ -0,0 +1,549 @@ +/* + * ddev.c -- Darwin device support functions for libproc-based lsof + */ + + +/* + * Portions Copyright 2005 Apple Computer, Inc. All rights reserved. + * + * Copyright 2005 Purdue Research Foundation, West Lafayette, Indiana + * 47907. All rights reserved. + * + * Written by Allan Nathanson, Apple Computer, Inc., and Victor A. + * Abell, Purdue University. + * + * This software is not subject to any license of the American Telephone + * and Telegraph Company or the Regents of the University of California. + * + * Permission is granted to anyone to use this software for any purpose on + * any computer system, and to alter it and redistribute it freely, subject + * to the following restrictions: + * + * 1. Neither the authors, nor Apple Computer, Inc. nor Purdue University + * are responsible for any consequences of the use of this software. + * + * 2. The origin of this software must not be misrepresented, either + * by explicit claim or by omission. Credit to the authors, Apple + * Computer, Inc. and Purdue University must appear in documentation + * and sources. + * + * 3. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 4. This notice may not be removed or altered. + */ + + +#ifndef lint +static char copyright[] = +"@(#) Copyright 2005 Apple Computer, Inc. and Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: ddev.c,v 1.2 2006/03/27 23:23:13 abe Exp $"; +#endif + + +#include "lsof.h" + + +/* + * Local definitions + */ + +#if defined(DVCH_DEVPATH) +#define DDEV_DEVPATH DVCH_DEVPATH +#else /* !defined(DVCH_DEVPATH) */ +#define DDEV_DEVPATH "/dev" +#endif /* defined(DVCH_DEVPATH) */ + +#define LIKE_BLK_SPEC "like block special" +#define LIKE_CHR_SPEC "like character special" + +#if defined(USE_STAT) +#define STATFN stat +#else /* !defined(USE_STAT) */ +#define STATFN lstat +#endif /* defined(USE_STAT) */ + + +/* + * Local static variables. + */ + +static dev_t *ADev = (dev_t *) NULL; /* device numbers besides DevDev found + * inside DDEV_DEVPATH */ +static int ADevA = 0; /* entries allocated to ADev[] */ +static int ADevU = 0; /* entries used in ADev[] */ + + +/* + * Local function prototypes + */ + +_PROTOTYPE(static int rmdupdev,(struct l_dev ***dp, int n, char *nm)); +_PROTOTYPE(static void saveADev,(struct stat *s)); + + +#if defined(HASSPECDEVD) +/* + * HASSPECDEVD() -- process stat(2) result to see if the device number is + * inside DDEV_DEVPATH "/" + * + * exit: s->st_dev changed to DevDev, as required + */ + +void +HASSPECDEVD(p, s) + char *p; /* file path */ + struct stat *s; /* stat(2) result for file */ +{ + int i; + + switch (s->st_mode & S_IFMT) { + case S_IFCHR: + case S_IFBLK: + if (s->st_dev == DevDev) + return; + (void) readdev(0); + if (!ADev) + return; + for (i = 0; i < ADevU; i++) { + if (s->st_dev == ADev[i]) { + s->st_dev = DevDev; + return; + } + } + } +} +#endif /* defined(HASSPECDEVD) */ + + +/* + * printdevname() -- print character device name + */ + +int +printdevname(dev, rdev, f, nty) + dev_t *dev; /* device */ + dev_t *rdev; /* raw device */ + int f; /* 1 = follow with '\n' */ + int nty; /* node type: N_BLK or N_chr */ +{ + char *cp, *ttl; + struct l_dev *dp; + int i, len; +/* + * See if the device node resides in DDEV_DEVPATH. If it does, return zero + * to indicate the vnode path is to be used for the NAME column. + */ + if (*dev == DevDev) + return(0); + readdev(0); + for (i = 0; i < ADevU; i++) { + if (*dev == ADev[i]) + return(0); + } +/* + * This device is not in DDEV_DEVPATH. + * + * See if it has a DDEV_DEVPATH analogue by searching the device table for a + * match without inode number and dev. + */ + +#if defined(HASBLKDEV) + if (nty == N_BLK) + dp = lkupbdev(&DevDev, rdev, 0, 1); + else +#endif /* defined(HASBLKDEV) */ + + dp = lkupdev(&DevDev, rdev, 0, 1); + if (dp) { + + /* + * A match was found. Record it as a name column addition. + */ + ttl = (nty == N_BLK) ? LIKE_BLK_SPEC : LIKE_CHR_SPEC; + len = (int)(1 + strlen(ttl) + 1 + strlen(dp->name) + 1); + if (!(cp = (char *)malloc((MALLOC_S)(len + 1)))) { + (void) fprintf(stderr, "%s: no nma space for: (%s %s)\n", + Pn, ttl, dp->name); + Exit(1); + } + (void) snpf(cp, len + 1, "(%s %s)", ttl, dp->name); + (void) add_nma(cp, len); + (void) free((MALLOC_P *)cp); + } +/* + * Return zero to indicate the vnode path is to be used for the NAME column. + */ + return(0); +} + + +/* + * readdev() -- read device names, modes and types + */ + +void +readdev(skip) + int skip; /* skip device cache read if 1 -- + * ignored since device cache not + * used */ +{ + DIR *dfp; + int dnamlen; + struct dirent *dp; + char *fp = (char *)NULL; + char *path = (char *)NULL; + int i = 0; + int j = 0; + MALLOC_S pl, sz; + struct stat sb; +/* + * Read device names but once. + */ + if (Sdev) + return; +/* + * Prepare to scan DDEV_DEVPATH. + */ + Dstkn = Dstkx = 0; + Dstk = (char **)NULL; + (void) stkdir(DDEV_DEVPATH); +/* + * Unstack the next directory. + */ + while (--Dstkx >= 0) { + if (!(dfp = OpenDir(Dstk[Dstkx]))) { + +# if defined(WARNDEVACCESS) + if (!Fwarn) { + (void) fprintf(stderr, "%s: WARNING: can't open: ", Pn); + safestrprt(Dstk[Dstkx], stderr, 1); + } +# endif /* defined(WARNDEVACCESS) */ + + (void) free((FREE_P *)Dstk[Dstkx]); + Dstk[Dstkx] = (char *)NULL; + continue; + } + if (path) { + (void) free((FREE_P *)path); + path = (char *)NULL; + } + if (!(path = mkstrcat(Dstk[Dstkx], -1, "/", 1, (char *)NULL, -1, + &pl))) + { + (void) fprintf(stderr, "%s: no space for: ", Pn); + safestrprt(Dstk[Dstkx], stderr, 1); + Exit(1); + } + (void) free((FREE_P *)Dstk[Dstkx]); + Dstk[Dstkx] = (char *)NULL; + /* + * Scan the directory. + */ + for (dp = ReadDir(dfp); dp; dp = ReadDir(dfp)) { + if (dp->d_ino == 0 || dp->d_name[0] == '.') + continue; + /* + * Form the full path name and get its status. + */ + dnamlen = (int)dp->d_namlen; + if (fp) { + (void) free((FREE_P *)fp); + fp = (char *)NULL; + } + if (!(fp = mkstrcat(path, pl, dp->d_name, dnamlen, + (char *)NULL, -1, (MALLOC_S *)NULL))) + { + (void) fprintf(stderr, "%s: no space for: ", Pn); + safestrprt(path, stderr, 0); + safestrprtn(dp->d_name, dnamlen, stderr, 1); + Exit(1); + } + if (STATFN(fp, &sb) != 0) { + if (errno == ENOENT) /* a sym link to nowhere? */ + continue; + +# if defined(WARNDEVACCESS) + if (!Fwarn) { + int errno_save = errno; + + (void) fprintf(stderr, "%s: can't stat ", Pn); + safestrprt(fp, stderr, 0); + (void) fprintf(stderr, ": %s\n", strerror(errno_save)); + } +# endif /* defined(WARNDEVACCESS) */ + + continue; + } + /* + * If it's a subdirectory, stack its name for later + * processing. + */ + if ((sb.st_mode & S_IFMT) == S_IFDIR) { + + /* + * Skip /dev/fd. + */ + if (strcmp(fp, "/dev/fd")) + (void) stkdir(fp); + continue; + } + if ((sb.st_mode & S_IFMT) == S_IFLNK) { + + /* + * Ignore symbolic links. + */ + continue; + } + if ((sb.st_mode & S_IFMT) == S_IFCHR) { + + /* + * Save character device information in Devtp[]. + */ + if (i >= Ndev) { + Ndev += DEVINCR; + if (!Devtp) + Devtp = (struct l_dev *)malloc( + (MALLOC_S)(sizeof(struct l_dev)*Ndev)); + else + Devtp = (struct l_dev *)realloc((MALLOC_P *)Devtp, + (MALLOC_S)(sizeof(struct l_dev)*Ndev)); + if (!Devtp) { + (void) fprintf(stderr, + "%s: no space for character device\n", Pn); + Exit(1); + } + } + Devtp[i].rdev = sb.st_rdev; + Devtp[i].inode = (INODETYPE)sb.st_ino; + if (!(Devtp[i].name = mkstrcpy(fp, (MALLOC_S *)NULL))) { + (void) fprintf(stderr, + "%s: no space for device name: ", Pn); + safestrprt(fp, stderr, 1); + Exit(1); + } + Devtp[i].v = 0; + i++; + } + +# if defined(HASBLKDEV) + if ((sb.st_mode & S_IFMT) == S_IFBLK) { + + /* + * Save block device information in BDevtp[]. + */ + if (j >= BNdev) { + BNdev += DEVINCR; + if (!BDevtp) + BDevtp = (struct l_dev *)malloc( + (MALLOC_S)(sizeof(struct l_dev)*BNdev)); + else + BDevtp = (struct l_dev *)realloc((MALLOC_P *)BDevtp, + (MALLOC_S)(sizeof(struct l_dev)*BNdev)); + if (!BDevtp) { + (void) fprintf(stderr, + "%s: no space for block device\n", Pn); + Exit(1); + } + } + BDevtp[j].name = fp; + fp = (char *)NULL; + BDevtp[j].inode = (INODETYPE)sb.st_ino; + BDevtp[j].rdev = sb.st_rdev; + BDevtp[j].v = 0; + j++; + } +# endif /* defined(HASBLKDEV) */ + + /* + * Save a possible new st_dev number within DDEV_DEVPATH. + */ + if (sb.st_dev != DevDev) + (void) saveADev(&sb); + } + (void) CloseDir(dfp); + } +/* + * Free any unneeded space that was allocated. + */ + if (ADev && (ADevU < ADevA)) { + + /* + * Reduce space allocated to additional DDEV_DEVPATH device numbers. + */ + if (!ADevU) { + + /* + * If no space was used, free the entire allocation. + */ + (void) free((FREE_P *)ADev); + ADev = (dev_t *)NULL; + ADevA = 0; + } else { + + /* + * Reduce the allocation to what was used. + */ + sz = (MALLOC_S)(ADevU * sizeof(dev_t)); + if (!(ADev = (dev_t *)realloc((MALLOC_P *)ADev, sz))) { + (void) fprintf(stderr, "%s: can't reduce ADev[]\n", Pn); + Exit(1); + } + } + } + if (!Dstk) { + (void) free((FREE_P *)Dstk); + Dstk = (char **)NULL; + } + if (fp) + (void) free((FREE_P *)fp); + if (path) + (void) free((FREE_P *)path); + +# if defined(HASBLKDEV) +/* + * Reduce the BDevtp[] (optional) and Devtp[] tables to their minimum + * sizes; allocate and build sort pointer lists; and sort the tables by + * device number. + */ + if (BNdev) { + if (BNdev > j) { + BNdev = j; + BDevtp = (struct l_dev *)realloc((MALLOC_P *)BDevtp, + (MALLOC_S)(sizeof(struct l_dev) * BNdev)); + } + if (!(BSdev = (struct l_dev **)malloc( + (MALLOC_S)(sizeof(struct l_dev *) * BNdev)))) + { + (void) fprintf(stderr, + "%s: no space for block device sort pointers\n", Pn); + Exit(1); + } + for (j = 0; j < BNdev; j++) { + BSdev[j] = &BDevtp[j]; + } + (void) qsort((QSORT_P *)BSdev, (size_t)BNdev, + (size_t)sizeof(struct l_dev *), compdev); + BNdev = rmdupdev(&BSdev, BNdev, "block"); + } + +# if !defined(NOWARNBLKDEV) + else { + if (!Fwarn) + (void) fprintf(stderr, + "%s: WARNING: no block devices found\n", Pn); + } +# endif /* !defined(NOWARNBLKDEV) */ +# endif /* defined(HASBLKDEV) */ + + if (Ndev) { + if (Ndev > i) { + Ndev = i; + Devtp = (struct l_dev *)realloc((MALLOC_P *)Devtp, + (MALLOC_S)(sizeof(struct l_dev) * Ndev)); + } + if (!(Sdev = (struct l_dev **)malloc( + (MALLOC_S)(sizeof(struct l_dev *) * Ndev)))) + { + (void) fprintf(stderr, + "%s: no space for character device sort pointers\n", Pn); + Exit(1); + } + for (i = 0; i < Ndev; i++) { + Sdev[i] = &Devtp[i]; + } + (void) qsort((QSORT_P *)Sdev, (size_t)Ndev, + (size_t)sizeof(struct l_dev *), compdev); + Ndev = rmdupdev(&Sdev, Ndev, "char"); + } else { + (void) fprintf(stderr, "%s: no character devices found\n", Pn); + Exit(1); + } +} + + +/* + * rmdupdev() - remove duplicate (major/minor/inode) devices + */ + +static int +rmdupdev(dp, n, nm) + struct l_dev ***dp; /* device table pointers address */ + int n; /* number of pointers */ + char *nm; /* device table name for error message */ +{ + int i, j, k; + struct l_dev **p; + + for (i = j = 0, p = *dp; i < n ;) { + for (k = i + 1; k < n; k++) { + if (p[i]->rdev != p[k]->rdev || p[i]->inode != p[k]->inode) + break; + } + if (i != j) + p[j] = p[i]; + j++; + i = k; + } + if (n == j) + return(n); + if (!(*dp = (struct l_dev **)realloc((MALLOC_P *)*dp, + (MALLOC_S)(j * sizeof(struct l_dev *))))) + { + (void) fprintf(stderr, "%s: can't realloc %s device pointers\n", + Pn, nm); + Exit(1); + } + return(j); +} + + +/* + * saveADev() - save additional device number appearing inside DDEV_DEVPATH + */ + +static void +saveADev(s) + struct stat *s; /* stat(2) buffer for file */ +{ + int i; + MALLOC_S sz; +/* + * Process VCHR files. + * + * Optionally process VBLK files. + */ + +#if defined(HASBLKDEV) + if (((s->st_mode & S_IFMT) != S_IFBLK) + && ((s->st_mode & S_IFMT) != S_IFCHR)) +#else /* !defined(HASBLKDEV) */ + if ((s->st_mode & S_IFCHR) != S_IFCHR) +#endif /* defined(HASBLKDEV) */ + + return; +/* + * See if this is a new VBLK or VCHR st_dev value for ADev[]. + */ + for (i = 0; i < ADevU; i++) { + if (s->st_dev == ADev[i]) + return; + } +/* + * This is a new device number to add to ADev[]. + */ + if (ADevU >= ADevA) { + ADevA += 16; + sz = (MALLOC_S)(ADevA * sizeof(dev_t)); + if (ADev) + ADev = (dev_t *)realloc((MALLOC_P *)ADev, sz); + else + ADev = (dev_t *)malloc(sz); + if (!ADev) { + (void) fprintf(stderr, "%s: no space for ADev[]\n", Pn); + Exit(1); + } + } + ADev[ADevU++] = s->st_dev; +} diff --git a/dialects/darwin/libproc/dfile.c b/dialects/darwin/libproc/dfile.c new file mode 100644 index 0000000..0156174 --- /dev/null +++ b/dialects/darwin/libproc/dfile.c @@ -0,0 +1,752 @@ +/* + * dfile.c -- Darwin file processing functions for libproc-based lsof + */ + + +/* + * Portions Copyright 2005-2007 Apple Inc. All rights reserved. + * + * Copyright 2005 Purdue Research Foundation, West Lafayette, Indiana + * 47907. All rights reserved. + * + * Written by Allan Nathanson, Apple Inc., and Victor A. Abell, Purdue + * University. + * + * This software is not subject to any license of the American Telephone + * and Telegraph Company or the Regents of the University of California. + * + * Permission is granted to anyone to use this software for any purpose on + * any computer system, and to alter it and redistribute it freely, subject + * to the following restrictions: + * + * 1. Neither the authors, nor Apple Inc. nor Purdue University are + * responsible for any consequences of the use of this software. + * + * 2. The origin of this software must not be misrepresented, either + * by explicit claim or by omission. Credit to the authors, Apple + * Inc. and Purdue University must appear in documentation and sources. + * + * 3. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 4. This notice may not be removed or altered. + */ + + +#ifndef lint +static char copyright[] = +"@(#) Copyright 2005-2007 Apple Inc. and Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: dfile.c,v 1.9 2018/02/14 14:27:57 abe Exp $"; +#endif + + +#include "lsof.h" + +#if defined(PROC_FP_GUARDED) +extern struct pff_tab Pgf_tab[]; +#endif /* defined(PROC_FP_GUARDED) */ + + +/* + * enter_file_info() -- enter file information + */ + +void +enter_file_info(pfi) + struct proc_fileinfo *pfi; /* pointer to process file info */ +{ + int f; +/* + * Construct access code + */ + f = pfi->fi_openflags & (FREAD | FWRITE); + if (f == FREAD) + Lf->access = 'r'; + else if (f == FWRITE) + Lf->access = 'w'; + else if (f == (FREAD | FWRITE)) + Lf->access = 'u'; +/* + * Save the offset / size + */ + Lf->off = (SZOFFTYPE)pfi->fi_offset; + if (Foffset) + Lf->off_def = 1; +/* + * Save file structure information as requested. + */ + if (Fsv & FSV_FG) { + Lf->ffg = (long)pfi->fi_openflags; + Lf->fsv |= FSV_FG; + +#if defined(PROC_FP_GUARDED) + if (pfi->fi_status & PROC_FP_GUARDED) { + Lf->guardflags = pfi->fi_guardflags; + } +#endif /* defined(PROC_FP_GUARDED) */ + + } + Lf->pof = (long)pfi->fi_status; +} + + +/* + * enter_vnode_info() -- enter vnode information + */ + +void +enter_vnode_info(vip) + struct vnode_info_path *vip; /* pointer to vnode info with path */ +{ + char buf[32], *cp; + dev_t dev = 0; + int devs = 0; + struct mounts *mp; +/* + * Derive file type. + */ + switch ((int)(vip->vip_vi.vi_stat.vst_mode & S_IFMT)) { + case S_IFIFO: + cp = "FIFO"; + Ntype = N_FIFO; + break; + case S_IFCHR: + cp = "CHR"; + Ntype = N_CHR; + break; + case S_IFDIR: + cp = "DIR"; + Ntype = N_REGLR; + break; + case S_IFBLK: + cp = "BLK"; + Ntype = N_BLK; + break; + +#if defined(S_IFLNK) + case S_IFLNK: + cp = "LINK"; + Ntype = N_REGLR; + break; +#endif /* defined(S_IFLNK) */ + + case S_IFREG: + cp = "REG"; + Ntype = N_REGLR; + break; + default: + (void) snpf(buf, sizeof(buf), "%04o", + (((vip->vip_vi.vi_stat.vst_mode & S_IFMT) >> 12) & 0xfff)); + cp = buf; + Ntype = N_REGLR; + } + if (!Lf->type[0]) + (void) snpf(Lf->type, sizeof(Lf->type), "%s", cp); + Lf->ntype = Ntype; +/* + * Save device number and path + */ + switch (Ntype) { + case N_FIFO: + break; + case N_CHR: + case N_BLK: + Lf->rdev = vip->vip_vi.vi_stat.vst_rdev; + Lf->rdev_def = 1; + /* fall through */ + default: + Lf->dev = dev = vip->vip_vi.vi_stat.vst_dev; + Lf->dev_def = devs = 1; + } +/* + * Save path name. + */ + vip->vip_path[sizeof(vip->vip_path) - 1] = '\0'; + if (vip->vip_path[0] != '\0') { + Lf->V_path = mkstrcpy(vip->vip_path, (MALLOC_S *)NULL); + } +/* + * Save node number. + */ + Lf->inode = (INODETYPE)vip->vip_vi.vi_stat.vst_ino; + Lf->inp_ty = 1; +/* + * Save link count, as requested. + */ + if (Fnlink) { + Lf->nlink = vip->vip_vi.vi_stat.vst_nlink; + Lf->nlink_def = 1; + if (Nlink && (Lf->nlink < Nlink)) + Lf->sf |= SELNLINK; + } +/* + * If a device number is defined, locate file system and save its identity. + */ + if (devs) { + for (mp = readmnt(); mp; mp = mp->next) { + if (dev == mp->dev) { + Lf->fsdir = mp->dir; + Lf->fsdev = mp->fsname; + if (mp->is_nfs && Fnfs) + Lf->sf |= SELNFS; + break; + } + } + } +/* + * Save the file size. + */ + switch (Ntype) { + case N_CHR: + case N_FIFO: + Lf->off_def = 1; + break; + default: + Lf->sz = (SZOFFTYPE)vip->vip_vi.vi_stat.vst_size; + Lf->sz_def = 1; + } +/* + * Test for specified file. + */ + if (Sfile && is_file_named(NULL, + ((Ntype == N_CHR) || (Ntype == N_BLK) ? 1 + : 0))) + { + Lf->sf |= SELNM; + } +/* + * Enter name characters. + */ + if (!Lf->nm && Namech[0]) + enter_nm(Namech); +} + + +/* + * err2nm() -- convert errno to a message in Namech + */ + +void +err2nm(pfx) + char *pfx; /* Namech message prefix */ +{ + char *sfx; + + switch (errno) { + case EBADF: + + /* + * The file descriptor is no longer available. + */ + sfx = "FD unavailable"; + break; + case ESRCH: + + /* + * The process is no longer available. + */ + sfx = "process unavailable"; + break; + default: + + /* + * All other errors are reported with strerror() information. + */ + sfx = strerror(errno); + } + (void) snpf(Namech, Namechl, "%s: %s", pfx, sfx); + enter_nm(Namech); +} + + +/* + * print_nm() -- print Name column + */ +void +print_nm(lf) + struct lfile *lf; +{ + unsigned char extra = 0; + + printname(0); + +#if defined(PROC_PIDLISTFILEPORTS) + if (lf->fileport) + extra++; +#endif /* defined(PROC_PIDLISTFILEPORTS) */ + +#if defined(PROC_FP_GUARDED) + if (lf->guardflags) + extra++; +#endif /* defined(PROC_FP_GUARDED) */ + + if (extra) + (void) printf(" ("); + +#if defined(PROC_PIDLISTFILEPORTS) + if (lf->fileport) + (void) printf("fileport=0x%04x", lf->fileport); +#endif /* defined(PROC_PIDLISTFILEPORTS) */ + +#if defined(PROC_FP_GUARDED) + if (extra > 1) + putchar(','); + if (lf->guardflags) { + struct pff_tab *tp; + long gf; + + (void) printf("guard="); + tp = Pgf_tab; + gf = lf->guardflags; + while (gf && !FsvFlagX) { + while (tp->nm) { + if (gf & tp->val) + break; + tp++; + } + if (!tp->nm) + break; + gf &= ~(tp->val); + (void) printf("%s%s", tp->nm, gf ? "," : ""); + } + /* + * If flag bits remain, print them in hex. If hex output was + * specified with +fG, print all flag values, including zero, + * in hex. + */ + if (gf || FsvFlagX) + (void) printf("0x%lx", gf); + } +#endif /* defined(PROC_FP_GUARDED) */ + + if (extra) + (void) printf(")\n"); + else + putchar('\n'); +} + + +/* + * print_v_path() -- print vnode's path + */ + +int +print_v_path(lf) + struct lfile *lf; +{ + if (lf->V_path) { + safestrprt(lf->V_path, stdout, 0); + return(1); + } + return(0); +} + + +/* + * process_atalk() -- process an Apple Talk file + */ + +void +process_atalk(pid, fd) + int pid; /* PID */ + int32_t fd; /* FD */ +{ + (void) snpf(Lf->type, sizeof(Lf->type), "ATALK"); + return; +} + + +/* + * process_fsevents() -- process a file system events file + */ + +void +process_fsevents(pid, fd) + int pid; /* PID */ + int32_t fd; /* FD */ +{ + (void) snpf(Lf->type, sizeof(Lf->type), "FSEVENTS"); +} + + +/* + * process_kqueue() -- process a kernel queue file + */ + +void +process_kqueue(pid, fd) + int pid; /* PID */ + int32_t fd; /* FD */ +{ + struct kqueue_fdinfo kq; + int nb; +/* + * Get the kernel queue file information. + */ + (void) snpf(Lf->type, sizeof(Lf->type), "KQUEUE"); + nb = proc_pidfdinfo(pid, fd, PROC_PIDFDKQUEUEINFO, &kq, sizeof(kq)); + if (nb <= 0) { + (void) err2nm("kqueue"); + return; + } else if (nb < sizeof(kq)) { + (void) fprintf(stderr, + "%s: PID %d, FD %d; proc_pidfdinfo(PROC_PIDFDKQUEUEINFO);\n", + Pn, pid, fd); + (void) fprintf(stderr, + " too few bytes; expected %ld, got %d\n", + sizeof(kq), nb); + Exit(1); + } +/* + * Enter the kernel queue file information. + */ + enter_file_info(&kq.pfi); +/* + * Enter queue counts as NAME column information. + */ + (void) snpf(Namech, Namechl, + "count=%" SZOFFPSPEC "u, state=%#x", + (SZOFFTYPE)kq.kqueueinfo.kq_stat.vst_size, + kq.kqueueinfo.kq_state); + enter_nm(Namech); +} + + +/* + * process_pipe() -- process pipe file + */ + +static void +process_pipe_common(pi) + struct pipe_fdinfo *pi; +{ + char dev_ch[32], *ep; + size_t sz; + + (void) snpf(Lf->type, sizeof(Lf->type), "PIPE"); +/* + * Enter the pipe handle as the device. + */ + (void) snpf(dev_ch, sizeof(dev_ch), "%s", + print_kptr((KA_T)pi->pipeinfo.pipe_handle, (char *)NULL, 0)); + enter_dev_ch(dev_ch); +/* + * Enable offset or size reporting. + */ + if (Foffset) + Lf->off_def = 1; + else { + Lf->sz = (SZOFFTYPE)pi->pipeinfo.pipe_stat.vst_blksize; + Lf->sz_def = 1; + } +/* + * If there is a peer handle, enter it in as NAME column information. + */ + if (pi->pipeinfo.pipe_peerhandle) { + (void) snpf(Namech, Namechl, "->%s", + print_kptr((KA_T)pi->pipeinfo.pipe_peerhandle, (char *)NULL, 0)); + enter_nm(Namech); + } else + Namech[0] = '\0'; +/* + * If the pipe has a count, add it to the NAME column. + */ + if (pi->pipeinfo.pipe_stat.vst_size) { + ep = endnm(&sz); + (void) snpf(ep, sz, ", cnt=%" SZOFFPSPEC "u", + (SZOFFTYPE)pi->pipeinfo.pipe_stat.vst_size); + } +} + + +void +process_pipe(pid, fd) + int pid; /* PID */ + int32_t fd; /* FD */ +{ + int nb; + struct pipe_fdinfo pi; +/* + * Get pipe file information. + */ + nb = proc_pidfdinfo(pid, fd, PROC_PIDFDPIPEINFO, &pi, sizeof(pi)); + if (nb <= 0) { + (void) err2nm("pipe"); + return; + } else if (nb < sizeof(pi)) { + (void) fprintf(stderr, + "%s: PID %d, FD %d; proc_pidfdinfo(PROC_PIDFDPIPEINFO);\n", + Pn, pid, fd); + (void) fprintf(stderr, + " too few bytes; expected %ld, got %d\n", + sizeof(pi), nb); + Exit(1); + } + + process_pipe_common(&pi); +} + + +#ifdef PROC_PIDLISTFILEPORTS +void +process_fileport_pipe(pid, fp) + int pid; /* PID */ + uint32_t fp; /* FILEPORT */ +{ + int nb; + struct pipe_fdinfo pi; +/* + * Get pipe file information. + */ + nb = proc_pidfileportinfo(pid, fp, PROC_PIDFILEPORTPIPEINFO, &pi, sizeof(pi)); + if (nb <= 0) { + (void) err2nm("pipe"); + return; + } else if (nb < sizeof(pi)) { + (void) fprintf(stderr, + "%s: PID %d, FILEPORT %u; proc_pidfileportinfo(PROC_PIDFILEPORTPIPEINFO);\n", + Pn, pid, fp); + (void) fprintf(stderr, + " too few bytes; expected %ld, got %d\n", + sizeof(pi), nb); + Exit(1); + } + + process_pipe_common(&pi); +} +#endif /* PROC_PIDLISTFILEPORTS */ + + +/* + * process_psem() -- process a POSIX semaphore file + */ + +void +process_psem(pid, fd) + int pid; /* PID */ + int32_t fd; /* FD */ +{ + int nb; + struct psem_fdinfo ps; +/* + * Get the sempaphore file information. + */ + (void) snpf(Lf->type, sizeof(Lf->type), "PSXSEM"); + nb = proc_pidfdinfo(pid, fd, PROC_PIDFDPSEMINFO, &ps, sizeof(ps)); + if (nb <= 0) { + (void) err2nm("semaphore"); + return; + } else if (nb < sizeof(ps)) { + (void) fprintf(stderr, + "%s: PID %d, FD %d; proc_pidfdinfo(PROC_PIDFDPSEMINFO);\n", + Pn, pid, fd); + (void) fprintf(stderr, + " too few bytes; expected %ld, got %d\n", + sizeof(ps), nb); + Exit(1); + } +/* + * Enter the semaphore file information. + */ + enter_file_info(&ps.pfi); +/* + * If there is a semaphore file name, enter it. + */ + if (ps.pseminfo.psem_name[0]) { + ps.pseminfo.psem_name[sizeof(ps.pseminfo.psem_name) - 1] = '\0'; + (void) snpf(Namech, Namechl, "%s", ps.pseminfo.psem_name); + enter_nm(Namech); + } +/* + * Unless file size has been specifically requested, enable the printing of + * file offset. + */ + if (!Fsize) + Lf->off_def = 1; +} + + +/* + * process_pshm() -- process POSIX shared memory file + */ + +static void +process_pshm_common(ps) + struct pshm_fdinfo *ps; +{ + (void) snpf(Lf->type, sizeof(Lf->type), "PSXSHM"); +/* + * Enter the POSIX shared memory file information. + */ + enter_file_info(&ps->pfi); +/* + * If the POSIX shared memory file has a path name, enter it; otherwise, if it + * has a mapping address, enter that. + */ + if (ps->pshminfo.pshm_name[0]) { + ps->pshminfo.pshm_name[sizeof(ps->pshminfo.pshm_name) - 1] = '\0'; + (void) snpf(Namech, Namechl, "%s", ps->pshminfo.pshm_name); + enter_nm(Namech); + } else if (ps->pshminfo.pshm_mappaddr) { + (void) snpf(Namech, Namechl, "obj=%s", + print_kptr((KA_T)ps->pshminfo.pshm_mappaddr, (char *)NULL, 0)); + enter_nm(Namech); + } +/* + * Enable offset or size reporting. + */ + if (Foffset) + Lf->off_def = 1; + else { + Lf->sz = (SZOFFTYPE)ps->pshminfo.pshm_stat.vst_size; + Lf->sz_def = 1; + } +} + + +void +process_pshm(pid, fd) + int pid; /* PID */ + int32_t fd; /* FD */ +{ + int nb; + struct pshm_fdinfo ps; +/* + * Get the POSIX shared memory file information. + */ + nb = proc_pidfdinfo(pid, fd, PROC_PIDFDPSHMINFO, &ps, sizeof(ps)); + if (nb <= 0) { + (void) err2nm("POSIX shared memory"); + return; + } else if (nb < sizeof(ps)) { + (void) fprintf(stderr, + "%s: PID %d, FD %d; proc_pidfdinfo(PROC_PIDFDPSHMINFO);\n", + Pn, pid, fd); + (void) fprintf(stderr, + " too few bytes; expected %ld, got %d\n", + sizeof(ps), nb); + Exit(1); + } + + process_pshm_common(&ps); +} + + +#ifdef PROC_PIDLISTFILEPORTS +void +process_fileport_pshm(pid, fp) + int pid; /* PID */ + uint32_t fp; /* FILEPORT */ +{ + int nb; + struct pshm_fdinfo ps; +/* + * Get the POSIX shared memory file information. + */ + nb = proc_pidfileportinfo(pid, fp, PROC_PIDFILEPORTPSHMINFO, &ps, sizeof(ps)); + if (nb <= 0) { + (void) err2nm("POSIX shared memory"); + return; + } else if (nb < sizeof(ps)) { + (void) fprintf(stderr, + "%s: PID %d, FILEPORT %u; proc_pidfileportinfo(PROC_PIDFILEPORTPSHMINFO);\n", + Pn, pid, fp); + (void) fprintf(stderr, + " too few bytes; expected %ld, got %d\n", + sizeof(ps), nb); + Exit(1); + } + + process_pshm_common(&ps); +} +#endif /* PROC_PIDLISTFILEPORTS */ + + +/* + * process_vnode() -- process a vnode file + */ + +static void +process_vnode_common(vi) + struct vnode_fdinfowithpath *vi; +{ +/* + * Enter the file and vnode information. + */ + enter_file_info(&vi->pfi); + enter_vnode_info(&vi->pvip); +} + + +void +process_vnode(pid, fd) + int pid; /* PID */ + int32_t fd; /* FD */ +{ + int nb; + struct vnode_fdinfowithpath vi; + + nb = proc_pidfdinfo(pid, fd, PROC_PIDFDVNODEPATHINFO, &vi, sizeof(vi)); + if (nb <= 0) { + if (errno == ENOENT) { + + /* + * The file descriptor's vnode may have been revoked. This is a + * bit of a hack, since an ENOENT error might not always mean the + * descriptor's vnode has been revoked. As the libproc API + * matures, this code may need to be revisited. + */ + enter_nm("(revoked)"); + } else + (void) err2nm("vnode"); + return; + } else if (nb < sizeof(vi)) { + (void) fprintf(stderr, + "%s: PID %d, FD %d: proc_pidfdinfo(PROC_PIDFDVNODEPATHINFO);\n", + Pn, pid, fd); + (void) fprintf(stderr, + " too few bytes; expected %ld, got %d\n", + sizeof(vi), nb); + Exit(1); + } + + process_vnode_common(&vi); +} + + +#ifdef PROC_PIDLISTFILEPORTS +void +process_fileport_vnode(pid, fp) + int pid; /* PID */ + uint32_t fp; /* FILEPORT */ +{ + int nb; + struct vnode_fdinfowithpath vi; + + nb = proc_pidfileportinfo(pid, fp, PROC_PIDFILEPORTVNODEPATHINFO, &vi, sizeof(vi)); + if (nb <= 0) { + if (errno == ENOENT) { + + /* + * The file descriptor's vnode may have been revoked. This is a + * bit of a hack, since an ENOENT error might not always mean the + * descriptor's vnode has been revoked. As the libproc API + * matures, this code may need to be revisited. + */ + enter_nm("(revoked)"); + } else + (void) err2nm("vnode"); + return; + } else if (nb < sizeof(vi)) { + (void) fprintf(stderr, + "%s: PID %d, FILEPORT %u: proc_pidfdinfo(PROC_PIDFDVNODEPATHINFO);\n", + Pn, pid, fp); + (void) fprintf(stderr, + " too few bytes; expected %ld, got %d\n", + sizeof(vi), nb); + Exit(1); + } + + process_vnode_common(&vi); +} +#endif /* PROC_PIDLISTFILEPORTS */ diff --git a/dialects/darwin/libproc/dlsof.h b/dialects/darwin/libproc/dlsof.h new file mode 100644 index 0000000..c3a1c70 --- /dev/null +++ b/dialects/darwin/libproc/dlsof.h @@ -0,0 +1,136 @@ +/* + * dlsof.h -- Darwin header file for libproc-based lsof + */ + + +/* + * Portions Copyright 2005-2007 Apple Inc. All rights reserved. + * + * Copyright 2005 Purdue Research Foundation, West Lafayette, Indiana + * 47907. All rights reserved. + * + * Written by Allan Nathanson, Apple Inc., and Victor A. Abell, Purdue + * University. + * + * This software is not subject to any license of the American Telephone + * and Telegraph Company or the Regents of the University of California. + * + * Permission is granted to anyone to use this software for any purpose on + * any computer system, and to alter it and redistribute it freely, subject + * to the following restrictions: + * + * 1. Neither the authors, nor Apple Inc. nor Purdue University are + * responsible for any consequences of the use of this software. + * + * 2. The origin of this software must not be misrepresented, either + * by explicit claim or by omission. Credit to the authors, Apple + * Inc. and Purdue University must appear in documentation and sources. + * + * 3. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 4. This notice may not be removed or altered. + */ + + +/* + * $Id: dlsof.h,v 1.8 2012/04/10 16:41:04 abe Exp abe $ + */ + + +#if !defined(DARWIN_LSOF_H) +#define DARWIN_LSOF_H 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +# if DARWINV<900 +#define vst_blksize st_blksize +#define vst_dev st_dev +#define vst_ino st_ino +#define vst_mode st_mode +#define vst_nlink st_nlink +#define vst_rdev st_rdev +#define vst_size st_size +# endif /* DARWINV<=900 */ + +#define COMP_P const void +#define DEVINCR 1024 /* device table malloc() increment */ +#define DIRTYPE dirent /* directory entry type */ +typedef uintptr_t KA_T; +#define KA_T_FMT_X "0x%08lx" +#define LOGINML MAXLOGNAME +#define MALLOC_P void +#define FREE_P MALLOC_P +#define MALLOC_S size_t +#define MAXSYSCMDL (MAXCOMLEN - 1) /* max system command name length */ +#define MOUNTED MNT_MNTTAB +#define QSORT_P void +#define READLEN_T int +#define STRNCPY_L size_t +#define SZOFFTYPE unsigned long long + /* size and offset internal storage + * type */ +#define SZOFFPSPEC "ll" /* SZOFFTYPE printf specification + * modifier */ + + +/* + * Global storage definitions (including their structure definitions) + */ + +struct file *Cfp; + +struct mounts { + char *dir; /* directory (mounted on) */ + char *fsname; /* file system + * (symbolic links unresolved) */ + char *fsnmres; /* file system + * (symbolic links resolved) */ + dev_t dev; /* directory st_dev */ + dev_t rdev; /* directory st_rdev */ + INODETYPE inode; /* directory st_ino */ + mode_t mode; /* directory st_mode */ + mode_t fs_mode; /* file system st_mode */ + int is_nfs; /* 1 if NFS file system, 0 if not */ + struct mounts *next; /* forward link */ +}; + +struct sfile { + char *aname; /* argument file name */ + char *name; /* file name (after readlink()) */ + char *devnm; /* device name (optional) */ + dev_t dev; /* device */ + dev_t rdev; /* raw device */ + u_short mode; /* S_IFMT mode bits from stat() */ + int type; /* file type: 0 = file system + * 1 = regular file */ + INODETYPE i; /* inode number */ + int f; /* file found flag */ + struct sfile *next; /* forward link */ + +}; + +#define XDR_VOID (const xdrproc_t)xdr_void +#define XDR_PMAPLIST (const xdrproc_t)xdr_pmaplist + +# if !defined(offsetof) +#define offsetof(type, member) ((size_t)(&((type *)0)->member)) +# endif /* !defined(offsetof) */ + +#endif /* DARWIN_LSOF_H */ diff --git a/dialects/darwin/libproc/dmnt.c b/dialects/darwin/libproc/dmnt.c new file mode 100644 index 0000000..576f432 --- /dev/null +++ b/dialects/darwin/libproc/dmnt.c @@ -0,0 +1,201 @@ +/* + * dmnt.c -- Darwin mount support functions for libproc-based lsof + */ + + +/* + * Portions Copyright 2005 Apple Computer, Inc. All rights reserved. + * + * Copyright 2005 Purdue Research Foundation, West Lafayette, Indiana + * 47907. All rights reserved. + * + * Written by Allan Nathanson, Apple Computer, Inc., and Victor A. + * Abell, Purdue University. + * + * This software is not subject to any license of the American Telephone + * and Telegraph Company or the Regents of the University of California. + * + * Permission is granted to anyone to use this software for any purpose on + * any computer system, and to alter it and redistribute it freely, subject + * to the following restrictions: + * + * 1. Neither the authors, nor Apple Computer, Inc. nor Purdue University + * are responsible for any consequences of the use of this software. + * + * 2. The origin of this software must not be misrepresented, either + * by explicit claim or by omission. Credit to the authors, Apple + * Computer, Inc. and Purdue University must appear in documentation + * and sources. + * + * 3. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 4. This notice may not be removed or altered. + */ + + +#ifndef lint +static char copyright[] = +"@(#) Copyright 2005 Apple Computer, Inc. and Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: dmnt.c,v 1.6 2012/04/10 16:41:04 abe Exp $"; +#endif + + +#include "lsof.h" + + +/* + * Local static information + */ + +static struct mounts *Lmi = (struct mounts *)NULL; /* local mount info */ +static int Lmist = 0; /* Lmi status */ + +/* + * readmnt() -- read mount table + */ + +struct mounts * +readmnt() +{ +#if defined(DIR_MNTSTATUS_TRIGGER) + struct { + uint32_t length; + uint32_t mount_flags; + } ab; + struct attrlist al; +#endif /* defined(DIR_MNTSTATUS_TRIGGER) */ + char *dn = (char *)NULL; + char *ln; + struct statfs *mb = (struct statfs *)NULL; + struct mounts *mtp; + int n; + struct stat sb; + + if (Lmi || Lmist) + return(Lmi); +/* + * Access mount information. + */ + if ((n = getmntinfo(&mb, MNT_NOWAIT)) <= 0) { + (void) fprintf(stderr, "%s: no mount information\n", Pn); + return(0); + } +/* + * Read mount information. + */ + for (; n; n--, mb++) { + + if (!mb->f_type) + continue; + /* + * Avoid file systems that are not appropriate paths to + * user data (e.g. automount maps, triggers). + */ +#if defined(DIR_MNTSTATUS_TRIGGER) + (void) bzero((char *)&al, sizeof(al)); + al.bitmapcount = ATTR_BIT_MAP_COUNT; + al.dirattr = ATTR_DIR_MOUNTSTATUS; + if (getattrlist(mb->f_mntonname, &al, &ab, sizeof(ab), 0) == 0) { + if (ab.mount_flags & DIR_MNTSTATUS_TRIGGER) + continue; // if mount trigger + } +#else /* !defined(DIR_MNTSTATUS_TRIGGER) */ + if (mb->f_flags & MNT_AUTOMOUNTED) { + if (!strncmp(mb->f_mntfromname, "map ", 4) + || !strcmp(mb->f_mntfromname, "trigger")) + continue; + } +#endif /* defined(DIR_MNTSTATUS_TRIGGER) */ + + /* + * Interpolate a possible symbolic directory link. + */ + if (dn) + (void) free((FREE_P *)dn); + if (!(dn = mkstrcpy(mb->f_mntonname, (MALLOC_S *)NULL))) { + +no_space_for_mount: + + (void) fprintf(stderr, "%s: no space for mount at ", Pn); + safestrprt(mb->f_mntonname, stderr, 0); + (void) fprintf(stderr, " ("); + safestrprt(mb->f_mntfromname, stderr, 0); + (void) fprintf(stderr, ")\n"); + Exit(1); + } + if (!(ln = Readlink(dn))) { + if (!Fwarn) { + (void) fprintf(stderr, + " Output information may be incomplete.\n"); + } + continue; + } + if (ln != dn) { + (void) free((FREE_P *)dn); + dn = ln; + } + if (*dn != '/') + continue; + /* + * Stat() the directory. + */ + if (statsafely(dn, &sb)) { + if (!Fwarn) { + (void) fprintf(stderr, "%s: WARNING: can't stat() ", Pn); + + safestrprt(mb->f_fstypename, stderr, 0); + + (void) fprintf(stderr, " file system "); + safestrprt(mb->f_mntonname, stderr, 1); + (void) fprintf(stderr, + " Output information may be incomplete.\n"); + } + (void) bzero((char *)&sb, sizeof(sb)); + sb.st_dev = (dev_t)mb->f_fsid.val[0]; + sb.st_mode = S_IFDIR | 0777; + if (!Fwarn) { + (void) fprintf(stderr, + " assuming \"dev=%x\" from mount table\n", + sb.st_dev); + } + } + /* + * Allocate and fill a local mount structure. + */ + if (!(mtp = (struct mounts *)malloc(sizeof(struct mounts)))) + goto no_space_for_mount; + mtp->dir = dn; + dn = (char *)NULL; + mtp->next = Lmi; + mtp->dev = sb.st_dev; + mtp->rdev = sb.st_rdev; + mtp->inode = (INODETYPE)sb.st_ino; + mtp->mode = sb.st_mode; + mtp->is_nfs = strcasecmp(mb->f_fstypename, "nfs") ? 0 : 1; + /* + * Interpolate a possible file system (mounted-on) device name link. + */ + if (!(dn = mkstrcpy(mb->f_mntfromname, (MALLOC_S *)NULL))) + goto no_space_for_mount; + mtp->fsname = dn; + ln = Readlink(dn); + dn = (char *)NULL; + /* + * Stat() the file system (mounted-on) name and add file system + * information to the local mount table entry. + */ + if (!ln || statsafely(ln, &sb)) + sb.st_mode = 0; + mtp->fsnmres = ln; + mtp->fs_mode = sb.st_mode; + Lmi = mtp; + } +/* + * Clean up and return the local mount info table address. + */ + if (dn) + (void) free((FREE_P *)dn); + Lmist = 1; + return(Lmi); +} diff --git a/dialects/darwin/libproc/dproc.c b/dialects/darwin/libproc/dproc.c new file mode 100644 index 0000000..069dc2b --- /dev/null +++ b/dialects/darwin/libproc/dproc.c @@ -0,0 +1,839 @@ +/* + * dproc.c -- Darwin process access functions for libproc-based lsof + */ + + +/* + * Portions Copyright 2005-2007 Apple Inc. All rights reserved. + * + * Copyright 2005 Purdue Research Foundation, West Lafayette, Indiana + * 47907. All rights reserved. + * + * Written by Allan Nathanson, Apple Inc., and Victor A. Abell, Purdue + * University. + * + * This software is not subject to any license of the American Telephone + * and Telegraph Company or the Regents of the University of California. + * + * Permission is granted to anyone to use this software for any purpose on + * any computer system, and to alter it and redistribute it freely, subject + * to the following restrictions: + * + * 1. Neither the authors, nor Apple Inc. nor Purdue University are + * responsible for any consequences of the use of this software. + * + * 2. The origin of this software must not be misrepresented, either + * by explicit claim or by omission. Credit to the authors, Apple + * Inc. and Purdue University must appear in documentation and sources. + * and sources. + * + * 3. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 4. This notice may not be removed or altered. + */ + + +#ifndef lint +static char copyright[] = +"@(#) Copyright 2005-2007 Apple Inc. and Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: dproc.c,v 1.10 2018/02/14 14:27:57 abe Exp $"; +#endif + +#include "lsof.h" + + +/* + * Local definitions + */ + +#define PIDS_INCR (sizeof(int) * 32) /* PID space increment */ +#define VIPS_INCR 16 /* Vips space increment */ + +#if DARWINV>=900 +#define THREADS_INCR (sizeof(uint64_t) * 32) /* Threads space increment */ +#endif /* DARWINV>=900 */ + +#ifdef PROC_PIDLISTFILEPORTS +#define FILEPORTS_INCR (sizeof(struct proc_fileportinfo) * 32) /* Fileports space increment */ +#endif /* PROC_PIDLISTFILEPORTS */ + +/* + * Local static variables + */ + +static struct proc_fdinfo *Fds = (struct proc_fdinfo *)NULL; + /* FD buffer */ +static int NbPids = 0; /* bytes allocated to Pids */ +static int NbFds = 0; /* bytes allocated to FDs */ +static int *Pids = (int *)NULL; /* PID buffer */ + +#if DARWINV>=900 +static int NbThreads = 0; /* Threads bytes allocated */ +static uint64_t *Threads = (uint64_t *)NULL; /* Thread buffer */ +#endif /* DARWINV>=900 */ + +#ifdef PROC_PIDLISTFILEPORTS +static struct proc_fileportinfo *Fps = (struct proc_fileportinfo *)NULL; + /* fileport buffer */ +static int NbFps = 0; /* bytes allocated to fileports */ +#endif /* PROC_PIDLISTFILEPORTS */ + +/* + * Local structure definitions + */ + +static struct vips_info { + dev_t dev; + ino_t ino; +} *Vips = (struct vips_info *)NULL; /* recorded vnodes */ +static int NbVips = 0; /* bytes allocated to Vips */ +static int NVips = 0; /* entries allocated to Vips */ + + +/* + * Local function prototypes + */ +_PROTOTYPE(static void enter_vn_text,(struct vnode_info_path *vip, int *n)); +_PROTOTYPE(static void process_fds,(int pid, uint32_t n, int ckscko)); +_PROTOTYPE(static void process_text,(int pid)); + +#if DARWINV>=900 +_PROTOTYPE(static void process_threads,(int pid, uint32_t n)); +#endif /* DARWINV>=900 */ + +#ifdef PROC_PIDLISTFILEPORTS +_PROTOTYPE(static void process_fileports,(int pid, int ckscko)); +#endif /* PROC_PIDLISTFILEPORTS */ + +/* + * enter_vn_text() -- enter vnode information text reference + */ + +static void +enter_vn_text(vip, n) + struct vnode_info_path *vip; /* vnode info */ + int *n; /* number of vips[] entries in use */ +{ + int i; +/* + * Ignore the request if the vnode information has already been entered. + */ + for (i = 0; i < *n; i++) { + if ((vip->vip_vi.vi_stat.vst_dev == Vips[i].dev) + && (vip->vip_vi.vi_stat.vst_ino == Vips[i].ino)) + { + return; + } + } +/* + * Save the text file information. + */ + alloc_lfile(" txt", -1); + Cfp = (struct file *)NULL; + (void) enter_vnode_info(vip); + if (Lf->sf) + link_lfile(); +/* + * Record the entry of the vnode information. + */ + if (i >= NVips) { + + /* + * Allocate space for recording the vnode information. + */ + NVips += VIPS_INCR; + NbVips += (int)(VIPS_INCR * sizeof(struct vips_info)); + if (!Vips) + Vips = (struct vips_info *)malloc((MALLOC_S)NbVips); + else + Vips = (struct vips_info *)realloc((MALLOC_P *)Vips, + (MALLOC_S)NbVips); + if (!Vips) { + (void) fprintf(stderr, "%s: PID %d: no text recording space\n", + Pn, Lp->pid); + Exit(1); + } + } +/* + * Record the vnode information. + */ + Vips[*n].dev = vip->vip_vi.vi_stat.vst_dev; + Vips[*n].ino = vip->vip_vi.vi_stat.vst_ino; + (*n)++; +} + + +/* + * gather_proc_info() -- gather process information + */ + +void +gather_proc_info() +{ + short cckreg; /* conditional status of regular file + * checking: + * 0 = unconditionally check + * 1 = conditionally check */ + short ckscko; /* socket file only checking status: + * 0 = none + * 1 = check only socket files, + * including TCP and UDP + * streams with eXPORT data, + * where supported */ + int cre, cres, ef, i, nb, np, pid; + short pss, sf; + struct proc_taskallinfo tai; + struct proc_vnodepathinfo vpi; +/* + * Define socket and regular file conditional processing flags. + * + * If only socket files have been selected, or socket files have been + * selected, ANDed with other selection options, enable the skipping of + * regular files. + * + * If socket files and some process options have been selected, enable + * conditional skipping of regular file; i.e., regular files will be skipped + * unless they belong to a process selected by one of the specified options. + */ + if (Selflags & SELNW) { + + /* + * Some network files selection options have been specified. + */ + if (Fand || !(Selflags & ~SELNW)) { + + /* + * Selection ANDing or only network file options have been + * specified, so set unconditional skipping of regular files + * and socket file only checking. + */ + cckreg = 0; + ckscko = 1; + } else { + + /* + * If ORed file selection options have been specified, or no + * ORed process selection options have been specified, enable + * unconditional file checking and clear socket file only + * checking. + * + * If only ORed process selection options have been specified, + * enable conditional file skipping and socket file only checking. + */ + if ((Selflags & SELFILE) || !(Selflags & SelProc)) + cckreg = ckscko = 0; + else + cckreg = ckscko = 1; + } + } else { + + /* + * No network file selection options were specified. Enable + * unconditional file checking and clear socket file only checking. + */ + cckreg = ckscko = 0; + } +/* + * Determine how many bytes are needed to contain the PIDs on the system; + * make sure sufficient buffer space is allocated to hold them (and a few + * extra); then read the list of PIDs. + */ + if ((nb = proc_listpids(PROC_ALL_PIDS, 0, NULL, 0)) <= 0) { + (void) fprintf(stderr, "%s: can't get PID byte count: %s\n", + Pn, strerror(errno)); + Exit(1); + } + if (nb > NbPids) { + while (nb > NbPids) { + NbPids += PIDS_INCR; + } + if (!Pids) + Pids = (int *)malloc((MALLOC_S)NbPids); + else + Pids = (int *)realloc((MALLOC_P *)Pids, (MALLOC_S)NbPids); + if (!Pids) { + (void) fprintf(stderr, + "%s: can't allocate space for %d PIDs\n", Pn, + (int)(NbPids / sizeof(int *))); + Exit(1); + } + } +/* + * Get the list of PIDs. + */ + for (ef = 0; !ef;) { + if ((nb = proc_listpids(PROC_ALL_PIDS, 0, Pids, NbPids)) <= 0) { + (void) fprintf(stderr, "%s: can't get list of PIDs: %s\n", + Pn, strerror(errno)); + Exit(1); + } + + if ((nb + sizeof(int)) < NbPids) { + + /* + * There is room in the buffer for at least one more PID. + */ + np = nb / sizeof(int); + ef = 1; + } else { + + /* + * The PID buffer must be enlarged. + */ + NbPids += PIDS_INCR; + Pids = (int *)realloc((MALLOC_P *)Pids, (MALLOC_S)NbPids); + if (!Pids) { + (void) fprintf(stderr, + "%s: can't allocate space for %d PIDs\n", Pn, + (int)(NbPids / sizeof(int *))); + Exit(1); + } + } + } +/* + * Loop through the identified processes. + */ + for (i = 0; i < np; i++) { + if (!(pid = Pids[i])) + continue; + nb = proc_pidinfo(pid, PROC_PIDTASKALLINFO, 0, &tai, sizeof(tai)); + if (nb <= 0) { + if ((errno == EPERM) || (errno == ESRCH)) + continue; + if (!Fwarn) { + (void) fprintf(stderr, "%s: PID %d information error: %s\n", + Pn, pid, strerror(errno)); + } + continue; + } else if (nb < sizeof(tai)) { + (void) fprintf(stderr, + "%s: PID %d: proc_pidinfo(PROC_PIDTASKALLINFO);\n", + Pn, pid); + (void) fprintf(stderr, + " too few bytes; expected %ld, got %d\n", + sizeof(tai), nb); + Exit(1); + } + /* + * Check for process or command exclusion. + */ + if (is_proc_excl((int)pid, (int)tai.pbsd.pbi_pgid, + (UID_ARG)tai.pbsd.pbi_uid, &pss, &sf)) + { + continue; + } + tai.pbsd.pbi_comm[sizeof(tai.pbsd.pbi_comm) - 1] = '\0'; + if (is_cmd_excl(tai.pbsd.pbi_comm, &pss, &sf)) + continue; + if (tai.pbsd.pbi_name[0]) { + tai.pbsd.pbi_name[sizeof(tai.pbsd.pbi_name) - 1] = '\0'; + if (is_cmd_excl(tai.pbsd.pbi_name, &pss, &sf)) + continue; + } + if (cckreg) { + + /* + * If conditional checking of regular files is enabled, enable + * socket file only checking, based on the process' selection + * status. + */ + ckscko = (sf & SelProc) ? 0 : 1; + } + /* + * Get root and current directory information. + */ + if (!ckscko) { + nb = proc_pidinfo(pid, PROC_PIDVNODEPATHINFO, 0, &vpi, + sizeof(vpi)); + if (nb <= 0) { + cre = errno; + cres = 1; + } else if (nb < sizeof(vpi)) { + (void) fprintf(stderr, + "%s: PID %d: proc_pidinfo(PROC_PIDVNODEPATHINFO);\n", + Pn, pid); + (void) fprintf(stderr, + " too few bytes; expected %ld, got %d\n", + sizeof(vpi), nb); + Exit(1); + } else + cres = 0; + } + /* + * Allocate local process space. + */ + alloc_lproc((int)pid, (int)tai.pbsd.pbi_pgid, + (int)tai.pbsd.pbi_ppid, (UID_ARG)tai.pbsd.pbi_uid, + (tai.pbsd.pbi_name[0] != '\0') ? tai.pbsd.pbi_name + : tai.pbsd.pbi_comm, + (int)pss, (int)sf); + Plf = (struct lfile *)NULL; + /* + * Save current working directory information. + */ + if (!ckscko) { + if (cres || vpi.pvi_cdir.vip_path[0]) { + alloc_lfile(CWD, -1); + Cfp = (struct file *)NULL; + if (cres) { + + /* + * If the CWD|RTD information access error is ESRCH, + * ignore it; otherwise report the error's message in the + * CWD's NAME column. + */ + if (cre != ESRCH) { + (void) snpf(Namech, Namechl, "%s|%s info error: %s", + CWD + 1, RTD + 1, strerror(cre)); + Namech[Namechl - 1] = '\0'; + enter_nm(Namech); + if (Lf->sf) + link_lfile(); + } + } else { + (void) enter_vnode_info(&vpi.pvi_cdir); + if (Lf->sf) + link_lfile(); + } + } + } + /* + * Save root directory information. + */ + if (!ckscko) { + if (!cres && vpi.pvi_rdir.vip_path[0]) { + alloc_lfile(RTD, -1); + Cfp = (struct file *)NULL; + (void) enter_vnode_info(&vpi.pvi_rdir); + if (Lf->sf) + link_lfile(); + } + } + +#if DARWINV>=900 + /* + * Check for per-thread current working directories + */ + if (!ckscko) { + if (tai.pbsd.pbi_flags & PROC_FLAG_THCWD) { + (void) process_threads(pid, tai.ptinfo.pti_threadnum); + } + } +#endif /* DARWINV>=900 */ + + /* + * Print text file information. + */ + if (!ckscko) + (void) process_text(pid); + +#ifdef PROC_PIDLISTFILEPORTS + /* + * Loop through the fileports + */ + (void) process_fileports(pid, ckscko); +#endif /* PROC_PIDLISTFILEPORTS */ + + /* + * Loop through the file descriptors. + */ + (void) process_fds(pid, tai.pbsd.pbi_nfiles, ckscko); + /* + * Examine results. + */ + if (examine_lproc()) + return; + } +} + + +/* + * initialize() -- perform all initialization + */ + +void +initialize() +{ +} + + +/* + * process_fds() -- process file descriptors + */ + +static void +process_fds(pid, n, ckscko) + int pid; /* PID of interest */ + uint32_t n; /* max FDs */ + int ckscko; /* check socket files only */ +{ + int i, isock, nb, nf; + struct proc_fdinfo *fdp; +/* + * Make sure an FD buffer has been allocated. + */ + if (!Fds) { + NbFds = sizeof(struct proc_fdinfo) * n; + Fds = (struct proc_fdinfo *)malloc((MALLOC_S)NbFds); + } else if (NbFds < sizeof(struct proc_fdinfo) * n) { + + /* + * More proc_fdinfo space is required. Allocate it. + */ + NbFds = sizeof(struct proc_fdinfo) * n; + Fds = (struct proc_fdinfo *)realloc((MALLOC_P *)Fds, + (MALLOC_S)NbFds); + } + if (!Fds) { + (void) fprintf(stderr, + "%s: PID %d: can't allocate space for %d FDs\n", + Pn, pid, (int)(NbFds / sizeof(struct proc_fdinfo))); + Exit(1); + } +/* + * Get FD information for the process. + */ + nb = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, Fds, NbFds); + if (nb <= 0) { + if (errno == ESRCH) { + + /* + * Quit if no FD information is available for the process. + */ + return; + } + /* + * Make a dummy file entry with an error message in its NAME column. + */ + alloc_lfile(" err", -1); + (void) snpf(Namech, Namechl, "FD info error: %s", strerror(errno)); + Namech[Namechl - 1] = '\0'; + enter_nm(Namech); + if (Lf->sf) + link_lfile(); + return; + } + nf = (int)(nb / sizeof(struct proc_fdinfo)); +/* + * Loop through the file descriptors. + */ + for (i = 0; i < nf; i++) { + fdp = &Fds[i]; + alloc_lfile(NULL, (int)fdp->proc_fd); + /* + * Process the file by its type. + */ + isock = 0; + switch (fdp->proc_fdtype) { + case PROX_FDTYPE_ATALK: + if (!ckscko) + (void) process_atalk(pid, fdp->proc_fd); + break; + case PROX_FDTYPE_FSEVENTS: + if (!ckscko) + (void) process_fsevents(pid, fdp->proc_fd); + break; + case PROX_FDTYPE_KQUEUE: + if (!ckscko) + (void) process_kqueue(pid, fdp->proc_fd); + break; + case PROX_FDTYPE_PIPE: + if (!ckscko) + (void) process_pipe(pid, fdp->proc_fd); + break; + case PROX_FDTYPE_PSEM: + if (!ckscko) + (void) process_psem(pid, fdp->proc_fd); + break; + case PROX_FDTYPE_SOCKET: + (void) process_socket(pid, fdp->proc_fd); + isock = 1; + break; + case PROX_FDTYPE_PSHM: + (void) process_pshm(pid, fdp->proc_fd); + break; + case PROX_FDTYPE_VNODE: + (void) process_vnode(pid, fdp->proc_fd); + break; + default: + (void) snpf(Namech, Namechl - 1, "unknown file type: %d", + fdp->proc_fdtype); + Namech[Namechl - 1] = '\0'; + (void) enter_nm(Namech); + break; + } + if (Lf->sf) { + if (!ckscko || isock) + link_lfile(); + } + } +} + + +#ifdef PROC_PIDLISTFILEPORTS +/* + * process_fileports() -- process fileports + */ + +static void +process_fileports(pid, ckscko) + int pid; /* PID of interest */ + int ckscko; /* check socket files only */ +{ + int ef, i, isock, nb = 0, nf; + struct proc_fileportinfo *fpi; + +/* + * Get fileport information for the process. + */ + for (ef = 0; !ef;) { + nb = proc_pidinfo(pid, PROC_PIDLISTFILEPORTS, 0, Fps, NbFps); + if (nb == 0) { + + /* + * Quit if no fileport information + */ + return; + } else if (nb < 0) { + if (errno == ESRCH) { + + /* + * Quit if no fileport information is available for the process. + */ + return; + } + /* + * Make a dummy file entry with an error message in its NAME column. + */ + alloc_lfile(" err", -1); + (void) snpf(Namech, Namechl, "FILEPORT info error: %s", strerror(errno)); + Namech[Namechl - 1] = '\0'; + enter_nm(Namech); + if (Lf->sf) + link_lfile(); + } + + if ((nb + sizeof(struct proc_fileportinfo)) < NbFps) { + + /* + * There is room in the buffer for at least one more fileport. + */ + ef = 1; + } else { + if (Fps && ((nb = proc_pidinfo(pid, PROC_PIDLISTFILEPORTS, 0, NULL, 0)) <= 0)) { + (void) fprintf(stderr, "%s: can't get fileport byte count: %s\n", + Pn, strerror(errno)); + Exit(1); + } + + /* + * The fileport buffer must be enlarged. + */ + while (nb > NbFps) { + NbFps += FILEPORTS_INCR; + } + if (!Fps) + Fps = (struct proc_fileportinfo *)malloc((MALLOC_S)NbFps); + else + Fps = (struct proc_fileportinfo *)realloc((MALLOC_P *)Fps, (MALLOC_S)NbFps); + } + } + +/* + * Loop through the fileports. + */ + nf = (int)(nb / sizeof(struct proc_fileportinfo)); + for (i = 0; i < nf; i++) { + fpi = &Fps[i]; + /* + * fileport reported as "fp." with "(fileport=0xXXXX)" in the Name column + */ + alloc_lfile(" fp.", -1); + Lf->fileport = fpi->proc_fileport; + /* + * Process the file by its type. + */ + isock = 0; + switch (fpi->proc_fdtype) { + case PROX_FDTYPE_PIPE: + if (!ckscko) + (void) process_fileport_pipe(pid, fpi->proc_fileport); + break; + case PROX_FDTYPE_SOCKET: + (void) process_fileport_socket(pid, fpi->proc_fileport); + isock = 1; + break; + case PROX_FDTYPE_PSHM: + (void) process_fileport_pshm(pid, fpi->proc_fileport); + break; + case PROX_FDTYPE_VNODE: + (void) process_fileport_vnode(pid, fpi->proc_fileport); + break; + default: + (void) snpf(Namech, Namechl - 1, "unknown file type: %d", + fpi->proc_fileport); + Namech[Namechl - 1] = '\0'; + (void) enter_nm(Namech); + break; + } + if (Lf->sf) { + if (!ckscko || isock) + link_lfile(); + } + } +} +#endif /* PROC_PIDLISTFILEPORTS */ + + +/* + * process_text() -- process text information + */ + +static void +process_text(pid) + int pid; /* PID */ +{ + uint64_t a; + int i, n, nb; + struct proc_regionwithpathinfo rwpi; + + for (a = (uint64_t)0, i = n = 0; i < 10000; i++) { + nb = proc_pidinfo(pid, PROC_PIDREGIONPATHINFO, a, &rwpi, + sizeof(rwpi)); + if (nb <= 0) { + if ((errno == ESRCH) || (errno == EINVAL)) { + + /* + * Quit if no more text information is available for the + * process. + */ + return; + } + /* + * Warn about all other errors via a NAME column message. + */ + alloc_lfile(" txt", -1); + Cfp = (struct file *)NULL; + (void) snpf(Namech, Namechl, + "region info error: %s", strerror(errno)); + Namech[Namechl - 1] = '\0'; + enter_nm(Namech); + if (Lf->sf) + link_lfile(); + return; + } else if (nb < sizeof(rwpi)) { + (void) fprintf(stderr, + "%s: PID %d: proc_pidinfo(PROC_PIDREGIONPATHINFO);\n", + Pn, pid); + (void) fprintf(stderr, + " too few bytes; expected %ld, got %d\n", + sizeof(rwpi), nb); + Exit(1); + } + if (rwpi.prp_vip.vip_path[0]) + enter_vn_text(&rwpi.prp_vip, &n); + a = rwpi.prp_prinfo.pri_address + rwpi.prp_prinfo.pri_size; + } +} + + +#if DARWINV>=900 +/* + * process_threads() -- process thread information + */ + +#define TWD " twd" /* per-thread current working directory + * fd name */ + +static void +process_threads(pid, n) + int pid; /* PID */ + uint32_t n; /* number of threads */ +{ + int i, nb, nt; +/* + * Make sure a thread buffer has been allocated. + */ + n += 10; + if (n > NbThreads) { + while (n > NbThreads) { + NbThreads += THREADS_INCR; + } + if (!Threads) + Threads = (uint64_t *)malloc((MALLOC_S)NbThreads); + else + Threads = (uint64_t *)realloc((MALLOC_P *)Threads, + (MALLOC_S)NbThreads); + if (!Threads) { + (void) fprintf(stderr, + "%s: can't allocate space for %d Threads\n", Pn, + (int)(NbThreads / sizeof(int *))); + Exit(1); + } + } +/* + * Get thread information for the process. + */ + nb = proc_pidinfo(pid, PROC_PIDLISTTHREADS, 0, Threads, NbThreads); + if (nb <= 0) { + if (errno == ESRCH) { + + /* + * Quit if no thread information is available for the + * process. + */ + return; + } + } + nt = (int)(nb / sizeof(uint64_t)); +/* + * Loop through the threads. + */ + for (i = 0; i < nt; i++) { + uint64_t t; + struct proc_threadwithpathinfo tpi; + + t = Threads[i]; + nb = proc_pidinfo(pid, PROC_PIDTHREADPATHINFO, t, &tpi, + sizeof(tpi)); + if (nb <= 0) { + if ((errno == ESRCH) || (errno == EINVAL)) { + + /* + * Quit if no more thread information is available for the + * process. + */ + return; + } + /* + * Warn about all other errors via a NAME column message. + */ + alloc_lfile(TWD, -1); + Cfp = (struct file *)NULL; + (void) snpf(Namech, Namechl, + "thread info error: %s", strerror(errno)); + Namech[Namechl - 1] = '\0'; + enter_nm(Namech); + if (Lf->sf) + link_lfile(); + return; + } else if (nb < sizeof(tpi)) { + (void) fprintf(stderr, + "%s: PID %d: proc_pidinfo(PROC_PIDTHREADPATHINFO);\n", + Pn, pid); + (void) fprintf(stderr, + " too few bytes; expected %ld, got %d\n", + sizeof(tpi), nb); + Exit(1); + } + if (tpi.pvip.vip_path[0]) { + alloc_lfile(TWD, -1); + Cfp = (struct file *)NULL; + (void) enter_vnode_info(&tpi.pvip); + if (Lf->sf) + link_lfile(); + } + } +} +#endif /* DARWINV>=900 */ diff --git a/dialects/darwin/libproc/dproto.h b/dialects/darwin/libproc/dproto.h new file mode 100644 index 0000000..88931d2 --- /dev/null +++ b/dialects/darwin/libproc/dproto.h @@ -0,0 +1,61 @@ +/* + * dproto.h -- Darwin function prototypes for libproc-based lsof + * + * The _PROTOTYPE macro is defined in the common proto.h. + */ + + +/* + * Portions Copyright 2005 Apple Computer, Inc. All rights reserved. + * + * Copyright 2005 Purdue Research Foundation, West Lafayette, Indiana + * 47907. All rights reserved. + * + * Written by Allan Nathanson, Apple Computer, Inc., and Victor A. + * Abell, Purdue University. + * + * This software is not subject to any license of the American Telephone + * and Telegraph Company or the Regents of the University of California. + * + * Permission is granted to anyone to use this software for any purpose on + * any computer system, and to alter it and redistribute it freely, subject + * to the following restrictions: + * + * 1. Neither the authors, nor Apple Computer, Inc. nor Purdue University + * are responsible for any consequences of the use of this software. + * + * 2. The origin of this software must not be misrepresented, either + * by explicit claim or by omission. Credit to the authors, Apple + * Computer, Inc. and Purdue University must appear in documentation + * and sources. + * + * 3. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 4. This notice may not be removed or altered. + */ + + +/* + * $Id: dproto.h,v 1.6 2012/04/10 16:41:04 abe Exp abe $ + */ + +_PROTOTYPE(extern void enter_file_info,(struct proc_fileinfo *pfi)); +_PROTOTYPE(extern void enter_vnode_info,(struct vnode_info_path *vip)); +_PROTOTYPE(extern void err2nm,(char *pfx)); +_PROTOTYPE(extern int is_file_named,(char *p, int cd)); +_PROTOTYPE(extern void process_atalk,(int pid, int32_t fd)); +_PROTOTYPE(extern void process_fsevents,(int pid, int32_t fd)); +_PROTOTYPE(extern void process_kqueue,(int pid, int32_t fd)); +_PROTOTYPE(extern void process_pipe,(int pid, int32_t fd)); +_PROTOTYPE(extern void process_psem,(int pid, int32_t fd)); +_PROTOTYPE(extern void process_pshm,(int pid, int32_t fd)); +_PROTOTYPE(extern void process_socket,(int pid, int32_t fd)); +_PROTOTYPE(extern void process_vnode,(int pid, int32_t fd)); +#ifdef PROC_PIDLISTFILEPORTS +_PROTOTYPE(extern void process_fileport_pipe,(int pid, uint32_t fileport)); +_PROTOTYPE(extern void process_fileport_pshm,(int pid, uint32_t fileport)); +_PROTOTYPE(extern void process_fileport_socket,(int pid, uint32_t fileport)); +_PROTOTYPE(extern void process_fileport_vnode,(int pid, uint32_t fileport)); +#endif /* PROC_PIDLISTFILEPORTS */ + diff --git a/dialects/darwin/libproc/dsock.c b/dialects/darwin/libproc/dsock.c new file mode 100644 index 0000000..175ca21 --- /dev/null +++ b/dialects/darwin/libproc/dsock.c @@ -0,0 +1,449 @@ +/* + * dsock.c -- Darwin socket processing functions for libproc-based lsof + */ + + +/* + * Portions Copyright 2005 Apple Computer, Inc. All rights reserved. + * + * Copyright 2005 Purdue Research Foundation, West Lafayette, Indiana + * 47907. All rights reserved. + * + * Written by Allan Nathanson, Apple Computer, Inc., and Victor A. + * Abell, Purdue University. + * + * This software is not subject to any license of the American Telephone + * and Telegraph Company or the Regents of the University of California. + * + * Permission is granted to anyone to use this software for any purpose on + * any computer system, and to alter it and redistribute it freely, subject + * to the following restrictions: + * + * 1. Neither the authors, nor Apple Computer, Inc. nor Purdue University + * are responsible for any consequences of the use of this software. + * + * 2. The origin of this software must not be misrepresented, either + * by explicit claim or by omission. Credit to the authors, Apple + * Computer, Inc. and Purdue University must appear in documentation + * and sources. + * + * 3. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 4. This notice may not be removed or altered. + */ + + +#ifndef lint +static char copyright[] = +"@(#) Copyright 2005 Apple Computer, Inc. and Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: dsock.c,v 1.7 2012/04/10 16:41:04 abe Exp $"; +#endif + + +#include "lsof.h" + + +/* + * IPv6_2_IPv4() -- macro to define the address of an IPv4 address contained + * in an IPv6 address + */ + +#define IPv6_2_IPv4(v6) (((uint8_t *)((struct in6_addr *)v6)->s6_addr)+12) + + +/* + * process_socket() -- process socket file + */ + +static void +process_socket_common(si) + struct socket_fdinfo *si; +{ + unsigned char *fa = (unsigned char *)NULL; + int fam, fp, lp, unl; + unsigned char *la = (unsigned char *)NULL; + +/* + * Enter basic socket values. + */ + (void) snpf(Lf->type, sizeof(Lf->type), "sock"); + Lf->inp_ty = 2; +/* + * Enter basic file information. + */ + enter_file_info(&si->pfi); +/* + * Enable size or offset display. + */ + if (Fsize) { + if (Lf->access == 'r') + Lf->sz = (SZOFFTYPE)si->psi.soi_rcv.sbi_cc; + else if (Lf->access == 'w') + Lf->sz = (SZOFFTYPE)si->psi.soi_snd.sbi_cc; + else + Lf->sz = (SZOFFTYPE)(si->psi.soi_rcv.sbi_cc + + si->psi.soi_snd.sbi_cc); + Lf->sz_def = 1; + } else + Lf->off_def = 1; + +#if defined(HASTCPTPIQ) +/* + * Enter send and receive queue sizes. + */ + Lf->lts.rq = si->psi.soi_rcv.sbi_cc; + Lf->lts.sq = si->psi.soi_snd.sbi_cc; + Lf->lts.rqs = Lf->lts.sqs = (unsigned char)1; +#endif /* defined(HASTCPTPIQ) */ + +#if defined(HASSOOPT) +/* + * Enter socket options. + */ + Lf->lts.ltm = (unsigned int)(si->psi.soi_linger & 0xffff); + Lf->lts.opt = (unsigned int)(si->psi.soi_options & 0xffff); + Lf->lts.pqlen = (unsigned int)si->psi.soi_incqlen; + Lf->lts.qlen = (unsigned int)si->psi.soi_qlen; + Lf->lts.qlim = (unsigned int)si->psi.soi_qlimit; + Lf->lts.rbsz = (unsigned long)si->psi.soi_rcv.sbi_mbmax; + Lf->lts.sbsz = (unsigned long)si->psi.soi_snd.sbi_mbmax; + Lf->lts.pqlens = Lf->lts.qlens = Lf->lts.qlims = Lf->lts.rbszs + = Lf->lts.sbszs = (unsigned char)1; +#endif /* defined(HASSOOPT) */ + +#if defined(HASSOSTATE) +/* + * Enter socket state. + */ + Lf->lts.ss = (unsigned int)si->psi.soi_state; +#endif /* defined(HASSOSTATE) */ + +/* + * Process socket by its associated domain family. + */ + switch ((fam = si->psi.soi_family)) { + case AF_INET: + case AF_INET6: + + /* + * Process IPv[46] sockets. + */ + (void) snpf(Lf->type, sizeof(Lf->type), + (fam == AF_INET) ? "IPv4" : "IPv6"); + if ((si->psi.soi_kind != SOCKINFO_IN) && + (si->psi.soi_kind != SOCKINFO_TCP)) + { + break; + } + /* + * Process TCP state inclusions and exclusions, as required. + */ + if ((si->psi.soi_kind == SOCKINFO_TCP) && (TcpStXn || TcpStIn)) { + int tsnx = (int)si->psi.soi_proto.pri_tcp.tcpsi_state + + TcpStOff; + + if ((tsnx >= 0) && (tsnx < TcpNstates)) { + if (TcpStXn) { + if (TcpStX[tsnx]) { + Lf->sf |= SELEXCLF; + return; + } + } + if (TcpStIn) { + if (TcpStI[tsnx]) + TcpStI[tsnx] = 2; + else { + Lf->sf |= SELEXCLF; + return; + } + } + } + } + /* + * Process an Internet domain socket. + */ + if (Fnet) { + if (!FnetTy + || ((FnetTy == 4) && (fam == AF_INET)) + || ((FnetTy == 6) && (fam == AF_INET6)) + ) + Lf->sf |= SELNET; + } + printiproto(si->psi.soi_protocol); + if ((si->psi.soi_kind == SOCKINFO_TCP) + && si->psi.soi_proto.pri_tcp.tcpsi_tp) + { + enter_dev_ch(print_kptr((KA_T)si->psi.soi_proto.pri_tcp.tcpsi_tp, + (char *)NULL, 0)); + } else + enter_dev_ch(print_kptr((KA_T)si->psi.soi_pcb, (char *)NULL, 0)); + if (fam == AF_INET) { + + /* + * Enter IPv4 address information. + */ + if (si->psi.soi_kind == SOCKINFO_TCP) { + + /* + * Enter information for a TCP socket. + */ + la = (unsigned char *)&si->psi.soi_proto.pri_tcp.tcpsi_ini.insi_laddr.ina_46.i46a_addr4; + lp = (int)ntohs(si->psi.soi_proto.pri_tcp.tcpsi_ini.insi_lport); + fa = (unsigned char *)&si->psi.soi_proto.pri_tcp.tcpsi_ini.insi_faddr.ina_46.i46a_addr4; + fp = (int)ntohs(si->psi.soi_proto.pri_tcp.tcpsi_ini.insi_fport); + } else { + + /* + * Enter information for a non-TCP socket. + */ + la = (unsigned char *)&si->psi.soi_proto.pri_in.insi_laddr.ina_46.i46a_addr4; + lp = (int)ntohs(si->psi.soi_proto.pri_in.insi_lport); + fa = (unsigned char *)&si->psi.soi_proto.pri_in.insi_faddr.ina_46.i46a_addr4; + fp = (int)ntohs(si->psi.soi_proto.pri_in.insi_fport); + } + if ((fa && (*fa == INADDR_ANY)) && !fp) { + fa = (unsigned char *)NULL; + fp = 0; + } + } else { + + /* + * Enter IPv6 address information + */ + int v4mapped = 0; + + if (si->psi.soi_kind == SOCKINFO_TCP) + { + + /* + * Enter TCP socket information. + */ + la = (unsigned char *)&si->psi.soi_proto.pri_tcp.tcpsi_ini.insi_laddr.ina_6; + lp = (int)ntohs(si->psi.soi_proto.pri_tcp.tcpsi_ini.insi_lport); + fa = (unsigned char *)&si->psi.soi_proto.pri_tcp.tcpsi_ini.insi_faddr.ina_6; + fp = (int)ntohs(si->psi.soi_proto.pri_tcp.tcpsi_ini.insi_fport); + if ((si->psi.soi_proto.pri_tcp.tcpsi_ini.insi_vflag & INI_IPV4) != 0) + v4mapped = 1; + } else { + + /* + * Enter non-TCP socket information. + */ + la = (unsigned char *)&si->psi.soi_proto.pri_in.insi_laddr.ina_6; + lp = (int)ntohs(si->psi.soi_proto.pri_in.insi_lport); + fa = (unsigned char *)&si->psi.soi_proto.pri_in.insi_faddr.ina_6; + fp = (int)ntohs(si->psi.soi_proto.pri_in.insi_fport); + if ((si->psi.soi_proto.pri_in.insi_vflag & INI_IPV4) != 0) + v4mapped = 1; + } + if (IN6_IS_ADDR_UNSPECIFIED((struct in6_addr *)fa) && !fp) { + fa = (unsigned char *)NULL; + fp = 0; + } + if (v4mapped) { + + /* + * Adjust IPv4 addresses mapped in IPv6 addresses. + */ + fam = AF_INET; + if (la) + la = (unsigned char *)IPv6_2_IPv4(la); + if (fa) + fa = (unsigned char *)IPv6_2_IPv4(fa); + } + } + /* + * Enter local and remote addresses by address family. + */ + if (fa || la) + (void) ent_inaddr(la, lp, fa, fp, fam); + if (si->psi.soi_kind == SOCKINFO_TCP) { + + /* + * Enter a TCP socket definition and its state. + */ + Lf->lts.type = 0; + Lf->lts.state.i = (int)si->psi.soi_proto.pri_tcp.tcpsi_state; + /* + * Enter TCP options. + */ + +#if defined(HASSOOPT) + Lf->lts.kai = (unsigned int)si->psi.soi_proto.pri_tcp.tcpsi_timer[TCPT_KEEP]; +#endif /* defined(HASSOOPT) */ + +#if defined(HASTCPOPT) + Lf->lts.mss = (unsigned long)si->psi.soi_proto.pri_tcp.tcpsi_mss; + Lf->lts.msss = (unsigned char)1; + Lf->lts.topt = (unsigned int)si->psi.soi_proto.pri_tcp.tcpsi_flags; +#endif /* defined(HASTCPOPT) */ + + } + break; + case AF_UNIX: + + /* + * Process a UNIX domain socket. + */ + (void) snpf(Lf->type, sizeof(Lf->type), "unix"); + if (si->psi.soi_kind != SOCKINFO_UN) + break; + if (Funix) + Lf->sf |= SELUNX; + enter_dev_ch(print_kptr((KA_T)si->psi.soi_pcb, (char *)NULL, 0)); + /* + * Enter information on a UNIX domain socket that has no address bound + * to it, although it may be connected to another UNIX domain socket + * as a pipe. + */ + if (si->psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_family != AF_UNIX) + { + if (si->psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_family + == AF_UNSPEC) + { + if (si->psi.soi_proto.pri_un.unsi_conn_pcb) { + (void) snpf(Namech, Namechl, "->%s", + print_kptr((KA_T)si->psi.soi_proto.pri_un.unsi_conn_pcb, (char *)NULL, 0)); + } else + (void) snpf(Namech, Namechl, "->(none)"); + } else + (void) snpf(Namech, Namechl, "unknown sun_family (%d)", + si->psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_family); + break; + } + if (si->psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_path[0]) { + unl = si->psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_len - offsetof(struct sockaddr_un, sun_path); + if ((unl < 0) || (unl >= sizeof(si->psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_path))) + unl = sizeof(si->psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_path) - 1; + si->psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_path[unl] = '\0'; + if (si->psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_path[0] + && Sfile + && is_file_named(si->psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_path, 0)) + Lf->sf |= SELNM; + if (si->psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_path[0] + && !Namech[0]) + (void) snpf(Namech, Namechl, "%s", si->psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_path); + } else + (void) snpf(Namech, Namechl, "no address"); + break; + case AF_ROUTE: + + /* + * Process a ROUTE domain socket. + */ + (void) snpf(Lf->type, sizeof(Lf->type), "rte"); + if (!Fsize) + Lf->off_def = 1; + break; + case AF_NDRV: + + /* + * Process an NDRV domain socket. + */ + (void) snpf(Lf->type, sizeof(Lf->type), "ndrv"); + if (si->psi.soi_kind != SOCKINFO_NDRV) + break; + enter_dev_ch(print_kptr((KA_T)si->psi.soi_pcb, (char *)NULL, 0)); + si->psi.soi_proto.pri_ndrv.ndrvsi_if_name[sizeof(si->psi.soi_proto.pri_ndrv.ndrvsi_if_name) - 1] = '\0'; + (void) snpf(Namech, Namechl, "-> %s%d", + si->psi.soi_proto.pri_ndrv.ndrvsi_if_name, + si->psi.soi_proto.pri_ndrv.ndrvsi_if_unit); + break; + case pseudo_AF_KEY: + + /* + * Process an [internal] key-management function socket. + */ + (void) snpf(Lf->type, sizeof(Lf->type), "key"); + enter_dev_ch(print_kptr((KA_T)si->psi.soi_pcb, (char *)NULL, 0)); + break; + case AF_SYSTEM: + + /* + * Process a SYSTEM domain socket. + */ + (void) snpf(Lf->type, sizeof(Lf->type), "systm"); + if (si->psi.soi_kind != SOCKINFO_KERN_EVENT) + break; + enter_dev_ch(print_kptr((KA_T)si->psi.soi_pcb, (char *)NULL, 0)); + (void) snpf(Namech, Namechl, "[%x:%x:%x]", + si->psi.soi_proto.pri_kern_event.kesi_vendor_code_filter, + si->psi.soi_proto.pri_kern_event.kesi_class_filter, + si->psi.soi_proto.pri_kern_event.kesi_subclass_filter); + break; + case AF_PPP: + + /* + * Process a PPP domain socket. + */ + (void) snpf(Lf->type, sizeof(Lf->type), "ppp"); + enter_dev_ch(print_kptr((KA_T)si->psi.soi_pcb, (char *)NULL, 0)); + break; + default: + printunkaf(fam, 1); + } +/* + * If there are NAME column characters, enter them. + */ + if (Namech[0]) + enter_nm(Namech); +} + + +void +process_socket(pid, fd) + int pid; /* PID */ + int32_t fd; /* FD */ +{ + int nb; + struct socket_fdinfo si; +/* + * Get socket information. + */ + nb = proc_pidfdinfo(pid, fd, PROC_PIDFDSOCKETINFO, &si, sizeof(si)); + if (nb <= 0) { + (void) err2nm("socket"); + return; + } else if (nb < sizeof(si)) { + (void) fprintf(stderr, + "%s: PID %d, FD %d: proc_pidfdinfo(PROC_PIDFDSOCKETINFO);\n", + Pn, pid, fd); + (void) fprintf(stderr, + " too few bytes; expected %ld, got %d\n", + sizeof(si), nb); + Exit(1); + } + + process_socket_common(&si); +} + + +#ifdef PROC_PIDLISTFILEPORTS +void +process_fileport_socket(pid, fp) + int pid; /* PID */ + uint32_t fp; /* FILEPORT */ +{ + int nb; + struct socket_fdinfo si; +/* + * Get socket information. + */ + nb = proc_pidfileportinfo(pid, fp, PROC_PIDFILEPORTSOCKETINFO, &si, sizeof(si)); + if (nb <= 0) { + (void) err2nm("socket"); + return; + } else if (nb < sizeof(si)) { + (void) fprintf(stderr, + "%s: PID %d, FILEPORT %u: proc_pidfileportinfo(PROC_PIDFILEPORTSOCKETINFO);\n", + Pn, pid, fp); + (void) fprintf(stderr, + " too few bytes; expected %ld, got %d\n", + sizeof(si), nb); + Exit(1); + } + + process_socket_common(&si); +} +#endif /* PROC_PIDLISTFILEPORTS */ diff --git a/dialects/darwin/libproc/dstore.c b/dialects/darwin/libproc/dstore.c new file mode 100644 index 0000000..713070c --- /dev/null +++ b/dialects/darwin/libproc/dstore.c @@ -0,0 +1,119 @@ +/* + * dstore.c -- Darwin global storage for libproc-based lsof + */ + + +/* + * Portions Copyright 2005 Apple Computer, Inc. All rights reserved. + * + * Copyright 2005 Purdue Research Foundation, West Lafayette, Indiana + * 47907. All rights reserved. + * + * Written by Allan Nathanson, Apple Computer, Inc., and Victor A. + * Abell, Purdue University. + * + * This software is not subject to any license of the American Telephone + * and Telegraph Company or the Regents of the University of California. + * + * Permission is granted to anyone to use this software for any purpose on + * any computer system, and to alter it and redistribute it freely, subject + * to the following restrictions: + * + * 1. Neither the authors, nor Apple Computer, Inc. nor Purdue University + * are responsible for any consequences of the use of this software. + * + * 2. The origin of this software must not be misrepresented, either + * by explicit claim or by omission. Credit to the authors, Apple + * Computer, Inc. and Purdue University must appear in documentation + * and sources. + * + * 3. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 4. This notice may not be removed or altered. + */ + + +#ifndef lint +static char copyright[] = +"@(#) Copyright 2005 Apple Computer, Inc. and Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: dstore.c,v 1.5 2018/02/14 14:27:57 abe Exp $"; +#endif + + +#include "lsof.h" + + +#if defined(HASFSTRUCT) +/* + * Pff_tab[] - table for printing file flags + */ + +struct pff_tab Pff_tab[] = { + { (long)FREAD, FF_READ }, + { (long)FWRITE, FF_WRITE }, + { (long)FNONBLOCK, FF_NBLOCK }, + { (long)FNDELAY, FF_NDELAY }, + { (long)FAPPEND, FF_APPEND }, + { (long)FASYNC, FF_ASYNC }, + { (long)FFSYNC, FF_FSYNC }, + +# if defined(FHASLOCK) + { (long)FHASLOCK, FF_HASLOCK }, +# endif /* defined(FHASLOCK) */ + + { (long)O_NOCTTY, FF_NOCTTY }, + { (long)O_EVTONLY, FF_EVTONLY }, + { (long)0, NULL } +}; + + +/* + * Pof_tab[] - table for print process open file flags + */ + +struct pff_tab Pof_tab[] = { + +# if defined(PROC_FP_SHARED) + { (long)PROC_FP_SHARED, "SH" }, +# endif /* defined(PROC_FP_SHARED) */ + +# if defined(PROC_FP_CLEXEC) + { (long)PROC_FP_CLEXEC, POF_CLOEXEC }, +# endif /* defined(PROC_FP_CLEXEC) */ + +# if defined(PROC_FP_GUARDED) + { (long)PROC_FP_GUARDED,"GRD" }, +# endif /* defined(PROC_FP_GUARDED) */ + +# if defined(UF_CLOSING) + { (long)UF_CLOSING, POF_CLOSING }, +# endif /* defined(UF_CLOSING) */ + +# if defined(UF_EXCLOSE) + { (long)UF_EXCLOSE, POF_CLOEXEC }, +# endif /* defined(UF_EXCLOSE) */ + +# if defined(UF_RESERVED) + { (long)UF_RESERVED, POF_RESERVED }, +# endif /* defined(UF_RESERVED) */ + + { (long)0, NULL } +}; +#endif /* defined(HASFSTRUCT) */ + + +#if defined(PROC_FP_GUARDED) +/* + * Pgf_tab[] - table for print process open file guard flags + */ + +struct pff_tab Pgf_tab[] = { + { (long)PROC_FI_GUARD_CLOSE, "CLOSE" }, + { (long)PROC_FI_GUARD_DUP, "DUP" }, + { (long)PROC_FI_GUARD_SOCKET_IPC, "SOCKET" }, + { (long)PROC_FI_GUARD_FILEPORT, "FILEPORT" }, + + { (long)0, NULL } +}; +#endif /* defined(PROC_FP_GUARDED) */ diff --git a/dialects/darwin/libproc/machine.h b/dialects/darwin/libproc/machine.h new file mode 100644 index 0000000..9918eb7 --- /dev/null +++ b/dialects/darwin/libproc/machine.h @@ -0,0 +1,632 @@ +/* + * machine.h -- Darwin definitions for libproc-based lsof + */ + + +/* + * Portions Copyright 2005 Apple Computer, Inc. All rights reserved. + * + * Copyright 2005 Purdue Research Foundation, West Lafayette, Indiana + * 47907. All rights reserved. + * + * Written by Allan Nathanson, Apple Computer, Inc., and Victor A. + * Abell, Purdue University. + * + * This software is not subject to any license of the American Telephone + * and Telegraph Company or the Regents of the University of California. + * + * Permission is granted to anyone to use this software for any purpose on + * any computer system, and to alter it and redistribute it freely, subject + * to the following restrictions: + * + * 1. Neither the authors, nor Apple Computer, Inc. nor Purdue University + * are responsible for any consequences of the use of this software. + * + * 2. The origin of this software must not be misrepresented, either + * by explicit claim or by omission. Credit to the authors, Apple + * Computer, Inc. and Purdue University must appear in documentation + * and sources. + * + * 3. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 4. This notice may not be removed or altered. + */ + + +/* + * $Id: machine.h,v 1.11 2018/02/14 14:27:57 abe Exp $ + */ + + +#if !defined(LSOF_MACHINE_H) +#define LSOF_MACHINE_H 1 + + +#include +#include + +# if defined(NEEDS_MACH_PORT_T) +# include +# endif /* NEED_MACH_PORT_T */ + +#include "/usr/include/string.h" + + +/* + * CAN_USE_CLNT_CREATE is defined for those dialects where RPC clnt_create() + * can be used to obtain a CLIENT handle in lieu of clnttcp_create(). + */ + +#define CAN_USE_CLNT_CREATE 1 + + +/* + * DEVDEV_PATH defines the path to the directory that contains device + * nodes. + */ + +#define DEVDEV_PATH "/dev" + + +/* + * GET_MAX_FD is defined for those dialects that provide a function other than + * getdtablesize() to obtain the maximum file descriptor number plus one. + */ + +/* #define GET_MAX_FD ? */ + + +/* + * HASAOPT is defined for those dialects that have AFS support; it specifies + * that the default path to an alternate AFS kernel name list file may be + * supplied with the -A option. + */ + +/* #define HASAOPT 1 */ + + +/* + * HASBLKDEV is defined for those dialects that want block device information + * recorded in BDevtp[]. + */ + +#define HASBLKDEV 1 + + +/* + * HASDCACHE is defined for those dialects that support a device cache + * file. + * + * HASENVDC defined the name of an environment variable that contains the + * device cache file path. The HASENVDC environment variable is ignored when + * the lsof process is setuid(root) or its real UID is 0. + * + * HASPERSDC defines the format for the last component of a personal device + * cache file path. The first will be the home directory of the real UID that + * executes lsof. + * + * HASPERSDCPATH defines the environment variable whose value is the middle + * component of the personal device cache file path. The middle component + * follows the home directory and precedes the results of applying HASPERSDC. + * The HASPERSDCPATH environment variable is ignored when the lsof process is + * setuid(root) or its real UID is 0. + * + * HASSYSDC defines a public device cache file path. When it's defined, it's + * used as the path from which to read the device cache. + * + * Consult the 00DCACHE and 00FAQ files of the lsof distribution for more + * information on device cache file path construction. + */ + +/* #define HASDCACHE 1 */ +/* #define HASENVDC "LSOFDEVCACHE" */ +/* #define HASPERSDC "%h/%p.lsof_%L" */ +/* #define HASPERSDCPATH "LSOFPERSDCPATH" */ +/* #define HASSYSDC "/your/choice/of/path" */ + + +/* + * HASCDRNODE is defined for those dialects that have CD-ROM nodes. + */ + +/* #define HASCDRNODE 1 */ + + +/* + * HASFIFONODE is defined for those dialects that have FIFO nodes. + */ + +/* #define HASFIFONODE 1 */ + + +/* + * HASFSINO is defined for those dialects that have the file system + * inode element, fs_ino, in the lfile structure definition in lsof.h. + */ + +#define HASFSINO 1 + + +/* + * HASFSTRUCT is defined if the dialect has a file structure. + * + * FSV_DEFAULT defines the default set of file structure values to list. + * It defaults to zero (0), but may be made up of a combination of the + * FSV_* symbols from lsof.h. + * + * HASNOFSADDR -- has no file structure address + * HASNOFSFLAGS -- has no file structure flags + * HASNOFSCOUNT -- has no file structure count + * HASNOFSNADDR -- has no file structure node address + */ + +#define HASFSTRUCT 1 +/* #define FSV_DEFAULT FSV_? | FSV_? | FSV_? */ +#define HASNOFSADDR 1 /* has no file structure address */ +/* #define HASNOFSFLAGS 1 has no file structure flags */ +/* #define HASNOFSCOUNT 1 has no file structure count */ +#define HASNOFSNADDR 1 /* has no file structure node address */ + + +/* + * HASGNODE is defined for those dialects that have gnodes. + */ + +/* #define HASGNODE 1 */ + + +/* + * HASHSNODE is defined for those dialects that have High Sierra nodes. + */ + +/* #define HASHSNODE 1 */ + + +/* + * HASINODE is defined for those dialects that have inodes and wish to + * use readinode() from node.c. + */ + +/* #define HASINODE 1 */ + + +/* + * HASINTSIGNAL is defined for those dialects whose signal function returns + * an int. + */ + +/* #define HASINTSIGNAL 1 */ + + +/* + * HASKERNIDCK is defined for those dialects that support the comparison of + * the build to running kernel identity. + */ + +#define HASKERNIDCK 1 + + +/* + * HASKOPT is defined for those dialects that support the -k option of + * reading the kernel's name list from an optional file. + */ + +/* #define HASKOPT 1 */ + + +/* + * HASLFILEADD is defined for those dialects that need additional elements + * in struct lfile. The HASLFILEADD definition is a macro that defines + * them. If any of the additional elements need to be preset in the + * alloc_lfile() function of proc.c, the SETLFILEADD macro may be defined + * to do that. + * + * If any additional elements need to be cleared in alloc_lfile() or in the + * free_proc() function of proc.c, the CLRLFILEADD macro may be defined to + * do that. Note that CLRLFILEADD takes one argument, the pointer to the + * lfile struct. The CLRLFILEADD macro is expected to expand to statements + * that are complete -- i.e., have terminating semi-colons -- so the macro is + * called without a terminating semicolon by proc.c. + * + * The HASXOPT definition may be used to select the conditions under which + * private lfile elements are used. + */ + +#define HASLFILEADD char *V_path; \ + mach_port_t fileport; \ + uint32_t guardflags; +#define CLRLFILEADD(lf) if (lf->V_path) { \ + (void) free((FREE_P *)lf->V_path); \ + lf->V_path = (char *)NULL; \ + } \ + lf->fileport = MACH_PORT_NULL; \ + lf->guardflags = 0; +#define SETLFILEADD Lf->V_path = (char *)NULL; \ + Lf->fileport = MACH_PORT_NULL; \ + Lf->guardflags = 0; + + +/* + * HASMNTSTAT indicates the dialect supports the mount stat(2) result option + * in its l_vfs and mounts structures. + */ + +/* #define HASMNTSTAT 1 */ + + +/* + * HASMNTSUP is defined for those dialects that support the mount supplement + * option. + */ + +/* #define HASMNTSUP 1 */ + + +/* + * HASMOPT is defined for those dialects that support the reading of + * kernel memory from an alternate file. + */ + +/* #define HASMOPT 1 */ + + +/* + * HASNCACHE is defined for those dialects that have a kernel name cache + * that lsof can search. A value of 1 directs printname() to prefix the + * cache value with the file system directory name; 2, avoid the prefix. + * + * NCACHELDPFX is a set of C commands to execute before calling ncache_load(). + * + * NCACHELDSFX is a set of C commands to execute after calling ncache_load(). + */ + +/* #define HASNCACHE 1 */ +/* #define NCACHELDPFX ??? */ +/* #define NCACHELDSFX ??? */ + + +/* + * HASNLIST is defined for those dialects that use nlist() to acccess + * kernel symbols. + */ + +/* #define HASNLIST 1 */ + + +/* + * HASPIPEFN is defined for those dialects that have a special function to + * process DTYPE_PIPE file structure entries. Its value is the name of the + * function. + * + * NOTE: don't forget to define a prototype for this function in dproto.h. + */ + +/* #define HASPIPEFN process_pipe? */ + + +/* + * HASPIPENODE is defined for those dialects that have pipe nodes. + */ + +/* #define HASPIPENODE 1 */ + + +/* + * HASPMAPENABLED is defined when the reporting of portmapper registration + * info is enabled by default. + */ + +/* #define HASPMAPENABLED 1 */ + + +/* + * HASPPID is defined for those dialects that support identification of + * the parent process IDentifier (PPID) of a process. + */ + +#define HASPPID 1 + + +/* + * HASPRINTDEV, HASPRINTINO, HASPRINTNM, HASPRINTOFF, and HASPRINTSZ + * define private dialect-specific functions for printing DEVice numbers, + * INOde numbers, NaMes, file OFFsets, and file SiZes. The functions are + * called from print_file(). + */ + +/* #define HASPRINTDEV print_dev */ +/* #define HASPRINTINO print_ino? */ +#define HASPRINTNM print_nm +/* #define HASPRINTOFF print_off? */ +/* #define HASPRINTSZ print_sz? */ + + +/* + * HASPRIVFILETYPE and PRIVFILETYPE are defined for dialects that have a + * file structure type that isn't defined by a DTYPE_* symbol. They are + * used in lib/prfp.c to select the type's processing. + * + * PRIVFILETYPE is the definition of the f_type value in the file struct. + * + * HASPRIVFILETYPE is the name of the processing function. + */ + +/* #define HASPRIVFILETYPE process_shmf? */ +/* #define PRIVFILETYPE ?? */ + + +/* + * HASPRIVNMCACHE is defined for dialects that have a private method for + * printing cached NAME column values for some files. HASPRIVNAMECACHE + * is defined to be the name of the function. + * + * The function takes one argument, a struct lfile pointer to the file, and + * returns non-zero if it prints a name to stdout. + */ + +#define HASPRIVNMCACHE print_v_path + + +/* + * HASPRIVPRIPP is defined for dialects that have a private function for + * printing IP protocol names. When HASPRIVPRIPP isn't defined, the + * IP protocol name printing function defaults to printiprto(). + */ + +/* #define HASPRIVPRIPP 1 */ + + +/* + * HASPROCFS is defined for those dialects that have a proc file system -- + * usually /proc and usually in SYSV4 derivatives. + * + * HASFSTYPE is defined as 1 for those systems that have a file system type + * string, st_fstype, in the stat() buffer; 2, for those systems that have a + * file system type integer in the stat() buffer, named MOUNTS_STAT_FSTYPE; + * 0, for systems whose stat(2) structure has no file system type member. The + * additional symbols MOUNTS_FSTYPE, RMNT_FSTYPE, and RMNT_STAT_FSTYPE may be + * defined in dlsof.h to direct how the readmnt() function in lib/rmnt.c + * preserves these stat(2) and getmntent(3) buffer values in the local mounts + * structure. + * + * The defined value is the string that names the file system type. + * + * The HASPROCFS definition usually must be accompanied by the HASFSTYPE + * definition and the providing of an fstype element in the local mounts + * structure (defined in dlsof.h). + * + * The HASPROCFS definition may be accompanied by the HASPINODEN definition. + * HASPINODEN specifies that searching for files in HASPROCFS is to be done + * by inode number. + */ + +/* #define HASPROCFS "proc?" */ +/* #define HASFSTYPE 1 */ +/* #define HASPINODEN 1 */ + + +/* + * HASRNODE is defined for those dialects that have rnodes. + */ + +/* #define HASRNODE 1 */ + + +/* + * Define HASSECURITY to restrict the listing of all open files to the + * root user. When HASSECURITY is defined, the non-root user may list + * only files whose processes have the same user ID as the real user ID + * (the one that its user logged on with) of the lsof process. + */ + +/* #define HASSECURITY 1 */ + + +/* + * If HASSECURITY is defined, define HASNOSOCKSECURITY to allow users + * restricted by HASSECURITY to list any open socket files, provide their + * listing is selected by the "-i" option. + */ + +/* #define HASNOSOCKSECURITY 1 */ + + +/* + * HASSETLOCALE is defined for those dialects that have 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 */ + + +/* + * HASSNODE is defined for those dialects that have snodes. + */ + +/* #define HASSNODE 1 */ + + +/* + * HASTASKS is defined for those dialects that have task reporting support. + */ + +/* #define HASTASKS 1 */ + + +/* + * HASSOOPT, HASSOSTATE and HASTCPOPT define the availability of information + * on socket options (SO_* symbols), socket states (SS_* symbols) and TCP + * options. + */ + +#define HASSOOPT 1 /* has socket option information */ +#define HASSOSTATE 1 /* has socket state information */ +#define HASTCPOPT 1 /* has TCP options or flags */ + + +/* + * Define HASSPECDEVD to be the name of a function that handles the results + * of a successful stat(2) of a file name argument. + * + * For example, HASSPECDEVD() for Darwin makes sure that st_dev is set to + * what stat("/dev") returns -- i.e., what's in DevDev. + * + * The function takes two arguments: + * + * 1: pointer to the full path name of file + * 2: pointer to the stat(2) result + * + * The function returns void. + */ + +#define HASSPECDEVD process_dev_stat + + +/* + * HASSTREAMS is defined for those dialects that support streams. + */ + +/* #define HASSTREAMS 1 */ + + +/* + * HASTCPTPIQ is defined for dialects where it is possible to report the + * TCP/TPI Recv-Q and Send-Q values produced by netstat. + */ + +#define HASTCPTPIQ 1 + + +/* + * HASTCPTPIW is defined for dialects where it is possible to report the + * TCP/TPI send and receive window sizes produced by netstat. + */ + +/* #define HASTCPTPIW 1 */ + + +/* + * HASTCPUDPSTATE is defined for dialects that have TCP and UDP state + * support -- i.e., for the "-stcp|udp:state" option and its associated + * speed improvements. + */ + +#define HASTCPUDPSTATE 1 + + +/* + * HASTMPNODE is defined for those dialects that have tmpnodes. + */ + +/* #define HASTMPNODE 1 */ + + +/* + * HASVNODE is defined for those dialects that use the Sun virtual file system + * node, the vnode. BSD derivatives usually do; System V derivatives prior to + * R4 usually don't. + */ + +/* #define HASVNODE 1 */ + + +/* + * HASXOPT is defined for those dialects that have an X option. It + * defines the text for the usage display. HASXOPT_VALUE defines the + * option's default binary value -- 0 or 1. + */ + +/* #define HASXOPT "help text for X option" */ +/* #define HASXOPT_VALUE 1 */ + + +/* + * INODETYPE and INODEPSPEC define the internal node number type and its + * printf specification modifier. These need not be defined and lsof.h + * can be allowed to define defaults. + * + * These are defined here, because they must be used in dlsof.h. + */ + +#define INODETYPE unsigned long long + /* inode number internal storage type */ +#define INODEPSPEC "ll" /* INODETYPE printf specification + * modifier */ + + +/* + * UID_ARG defines the size of a User ID number when it is passed + * as a function argument. + */ + +#define UID_ARG int + + +/* + * Each USE_LIB_ is defined for dialects that use the + * in the lsof library. + * + * Note: other definitions and operations may be required to condition the + * library function source code. They may be found in the dialect dlsof.h + * header files. + */ + +#define USE_LIB_CKKV 1 /* ckkv.c */ +/* #define USE_LIB_COMPLETEVFS 1 cvfs.c */ +#define USE_LIB_FIND_CH_INO 1 /* fino.c */ +#define USE_LIB_IS_FILE_NAMED 1 /* isfn.c */ +#define USE_LIB_LKUPDEV 1 /* lkud.c */ +/* #define USE_LIB_PRINTDEVNAME 1 pdvn.c */ +/* #define USE_LIB_PROCESS_FILE 1 prfp.c */ +#define USE_LIB_PRINT_TCPTPI 1 /* ptti.c */ +/* #define USE_LIB_READDEV 1 rdev.c */ +/* #define USE_LIB_READMNT 1 rmnt.c */ +/* #define USE_LIB_REGEX 1 regex.c */ +/* #define USE_LIB_RNAM 1 rnam.c */ +/* #define USE_LIB_RNCH 1 rnch.c */ +/* #define USE_LIB_RNMH 1 rnmh.c */ +/* #define USE_LIB_SNPF 1 snpf.c */ +#define snpf snprintf /* use the system's snprintf() */ + + +/* + * WARNDEVACCESS is defined for those dialects that should issue a warning + * when lsof can't access /dev (or /device) or one of its sub-directories. + * The warning can be inhibited by the lsof caller with the -w option. + */ + +/* #define WARNDEVACCESS 1 */ + + +/* + * WARNINGSTATE is defined for those dialects that want to suppress all lsof + * warning messages. + */ + +/* #define WARNINGSTATE 1 warnings are enabled by default */ + + +/* + * WILLDROPGID is defined for those dialects whose lsof executable runs + * setgid(not_real_GID) and whose setgid power can be relinquished after + * the dialect's initialize() function has been executed. + */ + +#define WILLDROPGID 1 + + +/* + * zeromem is a macro that uses bzero or memset. + */ + +#define zeromem(a, l) memset(a, 0, l) + +#endif /* !defined(LSOF_MACHINE_H) */ diff --git a/dialects/du/Makefile b/dialects/du/Makefile new file mode 100644 index 0000000..3da0c04 --- /dev/null +++ b/dialects/du/Makefile @@ -0,0 +1,156 @@ + +# DU Makefile +# +# $Id: Makefile,v 1.13 2008/04/15 13:29:11 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= ddev.c dfile.c dmnt.c dnode.c dproc.c dsock.c dstore.c \ + arg.c main.c misc.c node.c print.c proc.c store.c usage.c \ + util.c + +OBJ= ddev.o dfile.o dmnt.o dnode.o dproc.o dsock.o dstore.o \ + arg.o main.o misc.o node.o print.o proc.o store.o usage.o \ + util.o + +MAN= lsof.8 + +OTHER= + +SHELL= /bin/sh + +SOURCE= Makefile ${OTHER} ${MAN} ${HDR} ${SRC} + +all: ${PROG} + +${PROG}:${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 mem group. Your install rule actions might look' + @echo 'something like this:' + @echo '' + @echo ' installbsd -c -s -m 2755 -g $${GRP} $${PROG} $${BIN}/$${PROG}' + @echo ' installbsd -c -m 444 $${MAN} $${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= mem' + @echo '' + +${LIB}: FRC + (cd lib; ${MAKE} DEBUG="${DEBUG}" CFGF="${CFGF}") + +version.h: FRC + @echo Constructing version.h + @rm -f version.h + @echo '#define LSOF_BLDCMT "${LSOF_BLDCMT}"' > version.h; + @echo '#define LSOF_CC "${CC}"' >> version.h + @echo '#define LSOF_CCV "${CCV}"' >> version.h + @echo '#define LSOF_CCDATE "'`date`'"' >> version.h + @echo '#define LSOF_CCFLAGS "'`echo ${CFLAGS} | sed 's/\\\\(/\\(/g' | sed 's/\\\\)/\\)/g' | sed 's/"/\\\\"/g'`'"' >> version.h + @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 + +dproc.o: ${HDR} dproc.c + +dsock.o: ${HDR} dsock.c + +dstore.o: ${HDR} dstore.c + +arg.o: ${HDR} arg.c + +main.o: ${HDR} main.c + +misc.o: ${HDR} misc.c + +node.o: ${HDR} node.c + +print.o: ${HDR} print.c + +proc.o: ${HDR} proc.c + +store.o: ${HDR} store.c + +usage.o: ${HDR} version.h usage.c + +util.o: ${HDR} util.c + +# *** Do not add anything here - It will go away. *** diff --git a/dialects/du/Mksrc b/dialects/du/Mksrc new file mode 100755 index 0000000..05ee4b1 --- /dev/null +++ b/dialects/du/Mksrc @@ -0,0 +1,24 @@ +#!/bin/sh +# +# Mksrc - make DEC OSF/1, Digital UNIX, Tru64 UNIX 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/15 06:40:21 abe Exp $ + + +D=dialects/du +L="ddev.c dfile.c dlsof.h dmnt.c dnode.c dproc.c dproto.h dsock.c dstore.c machine.h" + +for i in $L +do + rm -f $i + $LSOF_MKC $D/$i $i + echo "$LSOF_MKC $D/$i $i" +done diff --git a/dialects/du/ddev.c b/dialects/du/ddev.c new file mode 100644 index 0000000..bbc4c9c --- /dev/null +++ b/dialects/du/ddev.c @@ -0,0 +1,759 @@ +/* + * ddev.c - DEC OSF/1, Digital UNIX, Tru64 UNIX 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"; +static char *rcsid = "$Id: ddev.c,v 1.17 2005/08/12 15:35:14 abe Exp $"; +#endif + +#include "lsof.h" + + +/* + * Local static values + */ + +#if defined(USELOCALREADDIR) +static struct stat Dirsb; +#endif /* defined(USELOCALREADDIR) */ + + +/* + * Local definitions + */ + +#define LIKE_BLK_SPEC "like block special" +#define LIKE_CHR_SPEC "like character special" + + +/* + * Local function prototypes + */ + +_PROTOTYPE(static int rmdupdev,(struct l_dev ***dp, int n, char *nm)); + + +#if defined(HASDCACHE) +/* + * clr_sect() - clear cached clone and pseudo sections + */ + +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(HASDCACHE) */ + + +/* + * printdevname() - print block and character device names + */ + +int +printdevname(dev, rdev, f, nty) + dev_t *dev; /* device */ + dev_t *rdev; /* raw device */ + int f; /* 1 = follow with '\n' */ + int nty; /* node type: N_BLK or N_CHR */ +{ + struct clone *c; + struct l_dev *dp; + + readdev(0); +/* + * Search for clone. + */ + +#if defined(HASDCACHE) + +printdevname_again: + +#endif /* defined(HASDCACHE) */ + + if ((nty == N_CHR) && Clone && HAVECLONEMAJ && (*dev == DevDev) + && (GET_MAJ_DEV(*rdev) == CLONEMAJ)) + { + for (c = Clone; c; c = c->next) { + if (Devtp[c->dx].rdev == *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); + } + } + } +/* + * Search device table for a full match. + */ + +#if defined(HASBLKDEV) + if (nty == N_BLK) + dp = lkupbdev(dev, rdev, 1, 0); + else +#endif /* defined(HASBLKDEV) */ + + dp = lkupdev(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(&DevDev, rdev, 0, 0); + else +#endif /* defined(HASBLKDEV) */ + + dp = lkupdev(&DevDev, rdev, 0, 0); + if (dp) { + + /* + * 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); + Exit(1); + } + (void) snpf(cp, len + 1, "(%s %s)", ttl, dp->name); + (void) add_nma(cp, len); + (void) free((FREE_P *)cp); + return(0); + } + +#if defined(HASDCACHE) +/* + * If the device cache is "unsafe" and we haven't found any match, reload + * the device cache. + */ + if (DCunsafe) { + (void) rereaddev(); + goto printdevname_again; + } +#endif /* defined(HASDCACHE) */ + + return(0); +} + + +/* + * readdev() - read names, modes and device types of everything in /dev + */ + +void +readdev(skip) + int skip; /* skip device cache read if 1 */ +{ +#if defined(HASDCACHE) + int dcrd; +#endif /* defined(HASDCACHE) */ + + struct clone *c; + DIR *dfp; + struct DIRTYPE *dp; + char *fp = (char *)NULL; + int i = 0; + +#if defined(HASBLKDEV) + int j = 0; +#endif /* defined(HASBLKDEV) */ + + MALLOC_S nl; + 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()) == 0) + return; + } + } else + dcrd = 1; +#endif /* defined(HASDCACHE) */ + + Dstk = (char **)NULL; + Dstkn = Dstkx = 0; + (void) stkdir("/dev"); +/* + * Unstack the next /dev or /dev/ directory. + */ + while (--Dstkx >= 0) { + if (!(dfp = OpenDir(Dstk[Dstkx]))) { + +#if defined(WARNDEVACCESS) + if (!Fwarn) { + (void) fprintf(stderr, "%s: WARNING: can't open: ", Pn); + safestrprt(Dstk[Dstkx], stderr, 1); + } +#endif /* defined(WARNDEVACCESS) */ + + (void) free((FREE_P *)Dstk[Dstkx]); + Dstk[Dstkx] = (char *)NULL; + continue; + } + if (path) { + (void) free((FREE_P *)path); + path = (char *)NULL; + } + if (!(path = mkstrcat(Dstk[Dstkx], -1, "/", 1, (char *)NULL, -1, + &pl))) + { + (void) fprintf(stderr, "%s: no space for: ", Pn); + safestrprt(Dstk[Dstkx], stderr, 1); + Exit(1); + } + (void) free((FREE_P *)Dstk[Dstkx]); + Dstk[Dstkx] = (char *)NULL; + /* + * Scan the directory. + */ + for (dp = ReadDir(dfp); dp; dp = ReadDir(dfp)) { + if (dp->d_ino == 0 || dp->d_name[0] == '.') + continue; + /* + * Form the full path name and get its status. + */ + 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); + Exit(1); + } + +#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(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); + Exit(1); + } + } + 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); + Exit(1); + } + Devtp[i].rdev = sb.st_rdev; + Devtp[i].v = 0; + /* + * Save clone device location. + */ + if (HAVECLONEMAJ + && GET_MAJ_DEV(Devtp[i].rdev) == CLONEMAJ) + { + if (!(c = (struct clone *)malloc(sizeof(struct clone)))) + { + (void) fprintf(stderr, + "%s: no space for clone device: ", Pn); + safestrprt(fp, stderr, 1); + Exit(1); + } + c->dx = i; + c->next = Clone; + Clone = c; + } + i++; + } + +#if defined(HASBLKDEV) + if ((sb.st_mode & S_IFMT) == S_IFBLK) { + + /* + * Save block device information in BDevtp[]. + */ + if (j >= BNdev) { + BNdev += DEVINCR; + if (!BDevtp) + BDevtp = (struct l_dev *)malloc( + (MALLOC_S)(sizeof(struct l_dev)*BNdev)); + else + BDevtp = (struct l_dev *)realloc( + (MALLOC_P *)BDevtp, + (MALLOC_S)(sizeof(struct l_dev)*BNdev)); + if (!BDevtp) { + (void) fprintf(stderr, + "%s: no space for block device\n", Pn); + Exit(1); + } + } + BDevtp[j].inode = (INODETYPE)sb.st_ino; + BDevtp[j].name = fp; + fp = (char *)NULL; + BDevtp[j].rdev = 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; + 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); + Exit(1); + } + for (j = 0; j < BNdev; j++) { + BSdev[j] = &BDevtp[j]; + } + (void) qsort((QSORT_P *)BSdev, (size_t)BNdev, + (size_t)sizeof(struct l_dev *), compdev); + BNdev = rmdupdev(&BSdev, BNdev, "block"); + } + +# if !defined(NOWARNBLKDEV) + else { + if (!Fwarn) + (void) fprintf(stderr, + "%s: WARNING: no block devices found\n", Pn); + } +# endif /* !defined(NOWARNBLKDEV) */ +#endif /* defined(HASBLKDEV) */ + + if (Ndev) { + if (Ndev > i) { + Ndev = i; + Devtp = (struct l_dev *)realloc((MALLOC_P *)Devtp, + (MALLOC_S)(sizeof(struct l_dev) * Ndev)); + } + if (!(Sdev = (struct l_dev **)malloc( + (MALLOC_S)(sizeof(struct l_dev *) * Ndev)))) + { + (void) fprintf(stderr, + "%s: no space for character device sort pointers\n", Pn); + Exit(1); + } + for (i = 0; i < Ndev; i++) { + Sdev[i] = &Devtp[i]; + } + (void) qsort((QSORT_P *)Sdev, (size_t)Ndev, + (size_t)sizeof(struct l_dev *), compdev); + Ndev = rmdupdev(&Sdev, Ndev, "char"); + } else { + (void) fprintf(stderr, "%s: no character devices found\n", Pn); + Exit(1); + } + +#if defined(HASDCACHE) +/* + * Write device cache file, as required. + */ + if (DCstate == 1 || (DCstate == 3 && dcrd)) + write_dcache(); +#endif /* defined(HASDCACHE) */ + +} + + +#if defined(USELOCALREADDIR) +/* + * Copyright (c) 1983, 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. + */ + +/* + * This is a hacked version of NetBSD's readdir() function written to work + * around an apparent bug in the Digital UNIX 3.0 getdirentries() system call + * and/or their "/dev/fd" filesystem. The problem is that when applied to + * "/dev/fs", getdirentries() returns the wrong size, which can cause readdir() + * to run off the end of it's internal buffer and return bogus file names. + * + * The changes from the original NetBSD file are: + * + * - uses of the field dd_flags in the DIR structure have been removed since + * Digital UNIX doesn't have this field (it seems to be mostly used for + * dealing with whiteout's in NetBSD's union filesystem). + * + * - uses of the dd_len field were replaced with dd_bufsiz, since this appears + * to be where the Digital UNIX opendir() call stashes the size of the buffer + * it mallocs. Why does Digital UNIX have both? No idea -- as far as I + * could tell dd_len was always 0. + * + * - code within "#ifdef BROKEN_GETDIRENTRIES ... #endif" has been added to + * workaround the bug. Note: this code uses the (apparently) unused field, + * dd_len, in the Digital UNIX DIR structure. This is pretty nasty, but + * then, this whole routine *is* just a hack to get around a (hopefully) + * temporary problem in Digital UNIX. + * + * This routine has only been tested on a couple of Digital UNIX 3.0 systems. + * I make no guarantees that it will work for you...! + * + * Duncan McEwan (duncan@comp.vuw.ac.nz) + */ + +/* + * Additional changes by Vic Abell : + * + * - The BROKEN_GETDIRENTRIES symbol was deleted. Use of this function + * is controlled in the lsof distribution by the HASLOCALREADDIR + * definition. + */ + + +/* + * CloseDir() - close directory + */ + +int +CloseDir(dirp) + register DIR *dirp; +{ + return(closedir(dirp)); +} + + +/* + * OpenDir() - open directory + */ + +DIR * +OpenDir(dir) + char *dir; +{ + DIR *dirp; + + if ((dirp = opendir(dir))) { + + /* + * Get a stat(2) buffer for the directory. + * + * Warn if the stat(2) buffer operation fails, close the directory, + * and respond that the open failed. + */ + if (statsafely(dir, &Dirsb)) { + int en = errno; + + if (!Fwarn) { + (void) fprintf(stderr, + "%s: WARNING: can't statsafely(", Pn); + safestrprt(dir, stderr, 0); + (void) fprintf(stderr, "): %s\n", strerror(en)); + } + (void) CloseDir(dirp); + dirp = (DIR *)NULL; + errno = en; + } + } + return(dirp); +} + + +/* + * ReadDir() - read next directory entry + */ + +extern struct DIRTYPE * +ReadDir(dirp) + register DIR *dirp; +{ + register struct DIRTYPE *dp; + +/* + * Loop through the directory. + */ + for (;;) { + if (dirp->dd_loc >= dirp->dd_size) { + dirp->dd_loc = 0; + } + if (dirp->dd_loc == 0) { + dirp->dd_size = getdirentries(dirp->dd_fd, + dirp->dd_buf, dirp->dd_bufsiz, &dirp->dd_seek); + + if (dirp->dd_size <= 0) + return((struct DIRTYPE *)NULL); + /* + * If the size returned by getdirentries() exceeds what it + * should be (as determined by a stat(2) of the directory), + * set it to the proper value. This is an adjustment for an + * apparent bug in the Digital UNIX 3.[02] getdirentries() + * function, when applied to a /dev/fd mount point. + * + * This check was conceived by Duncan McEwan and modified by + * Vic Abell. + */ + if (dirp->dd_size > (long)Dirsb.st_size) + dirp->dd_size = (long)Dirsb.st_size; + Dirsb.st_size -= (off_t)dirp->dd_size; + } + dp = (struct DIRTYPE *)(dirp->dd_buf + dirp->dd_loc); + if ((long)dp & 03) /* bogus pointer check */ + return((struct DIRTYPE *)NULL); + if (dp->d_reclen <= 0 + || dp->d_reclen > dirp->dd_bufsiz + 1 - dirp->dd_loc) + return((struct DIRTYPE *)NULL); + dirp->dd_loc += dp->d_reclen; + if (dp->d_ino == 0) + continue; + return (dp); + } +} +#endif /* defined(USELOCALREADDIR) */ + + +#if defined(HASDCACHE) +/* + * rereaddev() - reread device names, modes and types + */ + +void +rereaddev() +{ + (void) clr_devtab(); + +# if defined(DCACHE_CLR) + (void) DCACHE_CLR(); +# endif /* defined(DCACHE_CLR) */ + + readdev(1); + DCunsafe = 0; +} +#endif /* defined(HASDCACHE) */ + + +/* + * rmdupdev() - remove duplicate (major/minor/inode) devices + */ + +static int +rmdupdev(dp, n, nm) + struct l_dev ***dp; /* device table pointers address */ + int n; /* number of pointers */ + char *nm; /* device table name for error message */ +{ + struct clone *c, *cp; + 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; + /* + * 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; + } + } + if (i != j) + p[j] = p[i]; + j++; + i = k; + } + if (n == j) + return(n); + if (!(*dp = (struct l_dev **)realloc((MALLOC_P *)*dp, + (MALLOC_S)(j * sizeof(struct l_dev *))))) + { + (void) fprintf(stderr, "%s: can't realloc %s device pointers\n", + Pn, nm); + Exit(1); + } + return(j); +} + + +#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(dp) + 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(); + return(0); + } + dp->v = 1; + return(1); +} +#endif /* defined(HASDCACHE) */ diff --git a/dialects/du/dfile.c b/dialects/du/dfile.c new file mode 100644 index 0000000..f96a455 --- /dev/null +++ b/dialects/du/dfile.c @@ -0,0 +1,118 @@ +/* + * dfile.c - DEC OSF/1, Digital UNIX, Tru64 UNIX 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"; +static char *rcsid = "$Id: dfile.c,v 1.12 2001/08/14 12:40:12 abe Exp $"; +#endif + + +#include "lsof.h" + + +#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) + 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); + hep = getipnodebyname(nm, prot, 0, &err); + return(hep); +} +#endif /* defined(HASIPv6) */ + + +#if defined(HASPRIVNMCACHE) +/* + * print_advfs_path() - print an ADVFS file path + * + * return: 1 if path printed + * + * This code was provided by Dean Brock . + * + * This function is called by the name HASPRIVNMCACHE from printname(). + */ + +int +print_advfs_path(lf) + struct lfile *lf; /* file whose name is to be printed */ +{ + char buf[MAXPATHLEN+1]; + mlBfTagT t2pb; +/* + * Print any non-NULL path returned by tag_to_path() for ADVFS files that + * have sequence and inode numbers. + */ + if (!lf->advfs_seq_stat || lf->inp_ty != 1 || !lf->fsdir || !*lf->fsdir) + return(0); + t2pb.ml_ino = (int)lf->inode; + t2pb.ml_seq = lf->advfs_seq; + if (tag_to_path(lf->fsdir, t2pb, MAXPATHLEN, buf) || !*buf) + return(0); + buf[MAXPATHLEN] = '\0'; + safestrprt((buf[0] == '/' && buf[1] == '/') ? &buf[1] : buf, stdout, 0); + return(1); +} +#endif /* defined(HASPRIVNMCACHE) */ + + +/* + * print_dev() - print device + */ + +char * +print_dev(lf, dev) + struct lfile *lf; /* file whose device is to be printed */ + dev_t *dev; /* device to be printed */ +{ + static char buf[128]; + + if (GET_MIN_DEV(*dev) > 9999999) + (void) snpf(buf, sizeof(buf), "%d,%#x", GET_MAJ_DEV(*dev), + GET_MIN_DEV(*dev)); + else + (void) snpf(buf, sizeof(buf), "%d,%d", GET_MAJ_DEV(*dev), + GET_MIN_DEV(*dev)); + return(buf); +} diff --git a/dialects/du/dlsof.h b/dialects/du/dlsof.h new file mode 100644 index 0000000..98fbb27 --- /dev/null +++ b/dialects/du/dlsof.h @@ -0,0 +1,400 @@ +/* + * dlsof.h - DEC OSF/1, Digital UNIX, Tru64 UNIX 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.27 2006/03/27 20:40:59 abe Exp $ + */ + + +#if !defined(DU_LSOF_H) +#define DU_LSOF_H 1 + +#include +#include + +# if DUV<30000 || DUV>=50000 +#include +# endif /* DUV<30000 || DUV>=50000 */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#undef queue +#undef queue_t +#define queue ___queue +#define queue_t ___queue_t +#include +#undef ___queue +#undef ___queue_t +#define ___queue queue +#define ___queue_t queue_t + +# if DUV<30000 +#include +#define KERNEL_FILE +#include +# endif /* DUV<30000 */ + +#include + +# if DUV>=50100 +#include +#define _SYS_USER_H_ +#include +#undef _SYS_USER_H_ +# endif /* DUV>=50100 */ + +/* + * The following header files need _KERNEL and KERNEL defined. Some + * ugly #undef preparation is necessary. + */ + +#define _KERNEL 1 +#define KERNEL 1 +#undef MACRO_END +#undef PIPSIZ +#undef i_forw +#undef i_gen +#undef i_gid +#undef i_lock +#undef i_mode +#undef i_nlink +#undef i_rdev +#undef i_size +#undef i_uid + +# if DUV>=30000 +#undef m_data +#undef m_next +#include +#include +# if DUV<50000 +#include +# endif /* DUV<50000 */ +# endif /* DUV>=30000 */ + +#undef calloc +#define calloc ___calloc +#undef exit +#define exit ___exit +#define pmap ___pmap +#undef pt_entry_t +#define pt_entry_t ___pt_entry_t +#undef timer_t +#define timer_t ___timer_t + +# if DUV>=50000 +#include "du5_sys_malloc.h" +#undef _SYS_WAIT_H_ /* allow to + * #include while + * _KERNEL is defined */ +# endif /* DUV>=50000 */ + +# if DUV<40000 +#include +#undef ___calloc +#define ___calloc calloc +#undef ___exit +#define ___exit exit +#undef ___pt_entry_t +#undef ___timer_t +# endif /* DUV<40000 */ + +#include +#include +#include +#include + +# if DUV>=40000 +#undef ___calloc +#define ___calloc calloc +#undef ___exit +#define ___exit exit +# endif /* DUV>=40000 */ + +#include +#undef u_comm +#define u_comm uu_comm +#include + +# if DUV>=30000 +#undef u +#endif /* DUV>=30000 */ + +#include +#include + +# if DUV>=30000 +#define quotactl __quotactl +#include +#undef quotactl +# endif /* DUV>=30000 */ + +#include +#include +#include +#include + +# if DUV>=40000 +#include +# else /* DUV<40000 */ +#include +# endif /* DUV>=40000 */ + + +# if !defined(HASSPECNODE) +/* + * The spec_node is not defined in a distributed header file, but in + * a kernel source file. + */ + +struct spec_node { + struct vnode *sn_vnode; + struct vattr sn_vattr; +}; +# endif /* !defined(HASSPECNODE) */ + + +# if ADVFSV<500 +/* + * This is an educated guess at an ADVFS/MSFS node for AdvFS versions below 5. + * + * Information that became available to me for AdvFS 5.0 and higher indicates + * multiple adjacent structures are involved. Those definitions may be found + * in dnode.c inside an ADVFSV #if|#endif block. + */ + +struct advfsnode { + +# if ADVFSV<200 + unsigned long d1[19]; +# else /* ADVFSV>=200 */ +# if ADVFSV<300 + unsigned long d1[20]; +# else /* ADVFSV>=300 */ +# if ADVFSV<400 + unsigned long d1[21]; +# else /* ADVFSV>=400 */ + unsigned long d1[17]; +# endif /* ADVFSV>=400 */ +# endif /* ADVFSV<300 */ +# endif /* ADVFSV<200 */ + + ino_t a_number; + int a_seq; + unsigned long d3; + int d4; + dev_t a_rdev; + unsigned long a_size; + +# if ADVFSV>=400 + unsigned long d5[5]; + int d6; + int a_nlink; +# endif /* ADVFSV>=400 */ + +}; +# endif /* ADVFSV<500 */ + + +# if defined(HASTAGTOPATH) +/* + * Define the structure used for passing inode and sequence numbers to the + * ADVFS 4.0 and greater tag_to_path() -lmsfs function. + * + * This structure definition was provided by Dean Brock . + */ + typedef struct { + int ml_ino; + int ml_seq; + } mlBfTagT; +# endif /* defined(HASTAGTOPATH) */ + + +# if DUV<50000 +#define COMP_P void +typedef unsigned long KA_T; +# else /* DUV>=50000 */ +#define COMP_P const void +typedef off_t KA_T; +#endif /* DUV<50000 */ + +#define DEVINCR 1024 /* device table malloc() increment */ +#define DIRTYPE dirent +#define KMEM "/dev/kmem" +#define MALLOC_P char +#define FREE_P MALLOC_P +#define MALLOC_S size_t +#define MAXSYSCMDL MAXCOMLEN /* max system command name length */ +#define PNSIZ 5 /* /proc PID name component length */ +#define PR_INOBIAS 64 /* /proc inode number bias */ +#define PR_ROOTINO 2 /* /proc root inode number */ +#define PROCMIN 3 /* processes that make a "good" scan */ +#define PROCTRYLM 5 /* times to try to read proc table */ +#define QSORT_P char +#define READLEN_T int +#define STRNCPY_L int +#define U_SIZE sizeof(struct user) + + +/* + * Global storage definitions (including their structure definitions) + */ + +extern int CloneMaj; +extern struct file *Fileptr; +#define FILEPTR Fileptr /* for process_file() in lib/prfp.c */ +extern int HaveCloneMaj; +extern int Kd; + +struct l_vfs { + KA_T addr; /* kernel address */ + fsid_t fsid; /* file system ID */ + short type; /* type of file system */ + char *dir; /* mounted directory */ + char *fsname; /* file system name */ + +# if defined(HASFSINO) + INODETYPE fs_ino; /* file system inode number */ +# endif /* defined(HASFSINO) */ + + dev_t dev; /* device number */ + dev_t rdev; /* raw device number */ + 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 */ + fsid_t fsid; /* directory file system ID */ +}; +extern struct mounts *Mtab; + +#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 */ + +}; + +# if DUV>=30000 +extern KA_T *Pa; /* kernel proc structure addresses */ +# endif /* DUV>=30000 */ + +extern struct proc *Ps; /* local proc structures */ +extern int Psn; /* entries in Pa[] and Ps[] */ + +extern int Vnmxp; + + +/* + * Definitions for dvch.c, isfn.c, and rdev.c + */ + +#define CLONEMAJ CloneMaj /* clone major variable name */ +#define DCACHE_CLR clr_sect /* function to clear clone cache + * when reading the device cache + * file fails */ +#define HASDNAMLEN 1 /* DIRTYPE has d_namlen element */ +#define HAS_STD_CLONE 1 /* has standard clone structure */ +#define HAVECLONEMAJ HaveCloneMaj /* clone major variable status name */ + + +/* + * Definitions for rnam.c + */ + +# if defined(HASNCACHE) && DUV<50100 +#include +#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(HASNCVPID) +#define NCACHE_NODEID nc_vpid /* node ID in NCACHE */ +#define NCACHE_PARID nc_dvpid /* parent node ID in NCACHE */ +# endif /* defined(HASNCVPID) */ +# endif /* defined(HASNCACHE) && DUV<50100 */ + +#endif /* !DU_LSOF_H */ diff --git a/dialects/du/dmnt.c b/dialects/du/dmnt.c new file mode 100644 index 0000000..962f7b2 --- /dev/null +++ b/dialects/du/dmnt.c @@ -0,0 +1,320 @@ +/* + * dmnt.c - DEC OSF/1, Digital UNIX, Tru64 UNIX 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"; +static char *rcsid = "$Id: dmnt.c,v 1.11 2005/08/08 19:56:44 abe Exp $"; +#endif + + +#include "lsof.h" + +#undef KERNEL +#include /* this defines char *mnt_names[] */ + + +/* + * Local static definitions + */ + +static struct mounts *Lmi = (struct mounts *)NULL; /* local mount info */ +static int Lmist = 0; /* Lmi status */ + + +/* + * readmnt() - read mount table + */ + +struct mounts * +readmnt() +{ + char *dn = (char *)NULL; + char *ln; + struct statfs *mb; + struct mounts *mtp; + int n; + int procfs = 0; + struct stat sb; + + if (Lmi || Lmist) + return(Lmi); +/* + * Access mount information. + */ + if ((n = getmntinfo(&mb, MNT_NOWAIT)) <= 0) { + (void) fprintf(stderr, "%s: no mount information\n", Pn); + return(0); + } +/* + * Read mount information. + */ + for (; n; n--, mb++) { + if (mb->f_type == MOUNT_NONE || mb->f_type >= MOUNT_MAXTYPE) + continue; + /* + * Avoid file systems under automounter control if they're not + * currently mounted. + */ + if (mb->f_type == MOUNT_NFS) { + + /* + * The mount-from name of some unmounted file systems under + * automounter control end with ``:(pid):'' -- where + * is the PID of the automounter process. + */ + if ((ln = strchr(mb->f_mntfromname, ':'))) { + if (strncmp(ln+1, "(pid", 4) == 0 && isdigit(*(ln+5))) { + for (ln += 6; *ln && isdigit(*ln); ln++) { + ; + } + if (*ln == ')' && *(ln+1) == '\0') + continue; + } + } + /* + * Another automounter mount-from name form is "amd:" -- + * where is the PID of the automounter process. + */ + if (strncmp(mb->f_mntfromname, "amd:", 4) == 0 + && isdigit(mb->f_mntfromname[4])) { + ln = &mb->f_mntfromname[5]; + while (*ln && isdigit(*ln)) { + ln++; + } + if (!*ln || (*ln == ':' && *(ln+1) == '\0')) + continue; + } + } + /* + * Interpolate a possible symbolic directory link. + */ + if (dn) + (void) free((FREE_P *)dn); + if (!(dn = mkstrcpy(mb->f_mntonname, (MALLOC_S *)NULL))) { + +no_space_for_mount: + + (void) fprintf(stderr, "%s: no space for mount at ", Pn); + safestrprt(mb->f_mntonname, stderr, 0); + (void) fprintf(stderr, " ("); + safestrprt(mb->f_mntfromname, stderr, 0); + (void) fprintf(stderr, ")\n"); + Exit(1); + } + if (!(ln = Readlink(dn))) { + if (!Fwarn) { + (void) fprintf(stderr, + " Output information may be incomplete.\n"); + } + continue; + } + if (ln != dn) { + (void) free((FREE_P *)dn); + dn = ln; + } + if (*dn != '/') + continue; + /* + * Stat() the directory. + */ + if (statsafely(dn, &sb)) { + if (!Fwarn) { + (void) fprintf(stderr, + "%s: WARNING: can't stat() %s file system: ", + Pn, mnt_names[mb->f_type]); + safestrprt(mb->f_mntonname, stderr, 1); + (void) fprintf(stderr, + " Output information may be incomplete.\n"); + } + if (mb->f_type != MOUNT_PROCFS + +#if !defined(ADVFSV) || ADVFSV<400 + && mb->f_type != MOUNT_MSFS +#endif /* !defined(ADVFSV) || ADVFSV<400 */ + + ) { + memset((char *)&sb, 0, 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); + } + } else + continue; + } + /* + * 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->dev = sb.st_dev; + mtp->fsid = mb->f_fsid; + mtp->inode = (INODETYPE)sb.st_ino; + mtp->mode = sb.st_mode; + mtp->next = Lmi; + mtp->rdev = sb.st_rdev; + /* + * Interpolate a possible file system (mounted-on) device path. + */ + if (!(dn = mkstrcpy(mb->f_mntfromname, (MALLOC_S *)NULL))) + goto no_space_for_mount; + mtp->fsname = dn; + ln = Readlink(dn); + dn = (char *)NULL; + /* + * Stat the file system (mounted-on) name and add file sysem + * information to the local mount table. + */ + if (!ln || statsafely(ln, &sb)) + sb.st_mode = 0; + mtp->fsnmres = ln; + mtp->fs_mode = sb.st_mode; + Lmi = mtp; + if (mb->f_type == MOUNT_PROCFS) { + + /* + * Save information on exactly one procfs file system. + */ + if (procfs) + Mtprocfs = (struct mounts *)NULL; + else { + procfs = 1; + Mtprocfs = mtp; + } + } + } +/* + * Clean up and return the local mount info table address. + */ + if (dn) + (void) free((FREE_P *)dn); + Lmist = 1; + return(Lmi); +} + + +/* + * readvfs() - read vfs structure + */ + +struct l_vfs * +readvfs(vm) + KA_T vm; /* mount address in vnode */ +{ + struct mount m; + struct l_vfs *vp; + fsid_t f; + struct mounts *mp; + +#if DUV>=40000 + int bl; + char fb[MAX_MNT_PATHLEN+1]; + char ob[MAX_MNT_PATHLEN+1]; +#endif /* DUV>=40000 */ + +/* + * Search for match on existing entry. + */ + for (vp = Lvfs; vp; vp = vp->next) { + if (vm == vp->addr) + return(vp); + } +/* + * Read the (new) mount structure, allocate a local entry, and fill it. + */ + if (kread((KA_T)vm, (char *)&m, sizeof(m)) != 0) + return((struct l_vfs *)NULL); + if (!(vp = (struct l_vfs *)malloc(sizeof(struct l_vfs)))) { + (void) fprintf(stderr, "%s: PID %d, no space for vfs\n", + Pn, Lp->pid); + Exit(1); + } + +#if DUV<40000 + if (!(vp->dir = mkstrcpy(m.m_stat.f_mntonname, (MALLOC_S *)NULL)) + || !(vp->fsname = mkstrcpy(m.m_stat.f_mntfromname, (MALLOC_S *)NULL))) +#else /* DUV>=40000 */ + bl = sizeof(ob) - 1; + if (!m.m_stat.f_mntonname + || kread((KA_T)m.m_stat.f_mntonname, ob, bl)) + bl = 0; + ob[bl] = '\0'; + bl = sizeof(fb) - 1; + if (!m.m_stat.f_mntfromname + || kread((KA_T)m.m_stat.f_mntfromname, fb, bl)) + bl = 0; + fb[bl] = '\0'; + if (!(vp->dir = mkstrcpy(ob, (MALLOC_S *)NULL)) + || !(vp->fsname = mkstrcpy(fb, (MALLOC_S *)NULL))) +#endif /* DUV<40000 */ + + { + (void) fprintf(stderr, "%s: PID %d, no space for mount names\n", + Pn, Lp->pid); + Exit(1); + } + vp->addr = vm; + vp->fsid = m.m_stat.f_fsid; + vp->type = m.m_stat.f_type; + +#if defined(HASFSINO) + vp->fs_ino = 0; +#endif /* defined(HASFSINO) */ + + vp->next = Lvfs; + Lvfs = vp; +/* + * Derive the device and raw device numbers from a search for the + * file system ID in the local mount table. + */ + vp->dev = vp->rdev = 0; + for (f = vp->fsid, mp = readmnt(); mp; mp = mp->next) { + if (f.val[0] == mp->fsid.val[0] + && f.val[1] == mp->fsid.val[1]) + { + vp->dev = mp->dev; + vp->rdev = mp->rdev; + +#if defined(HASFSINO) + vp->fs_ino = mp->inode; +#endif /* defined(HASFSINO) */ + + break; + } + } + return(vp); +} diff --git a/dialects/du/dnode.c b/dialects/du/dnode.c new file mode 100644 index 0000000..19a8827 --- /dev/null +++ b/dialects/du/dnode.c @@ -0,0 +1,992 @@ +/* + * dnode.c - DEC OSF/1, Digital UNIX, Tru64 UNIX 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"; +static char *rcsid = "$Id: dnode.c,v 1.23 2006/03/27 20:40:59 abe Exp $"; +#endif + + +#include "lsof.h" + + +/* + * Local definitions + */ + +#if ADVFSV>=500 +/* + * AdvFS (MSFS) definitions for AdvFS version 5.0 and above. + */ + +struct fs_stat { /* file system stat(2) info structure + * for AdvFS 5.0 and above */ + unsigned int num; /* node number */ + unsigned int d1; + mode_t d2; + uid_t d3; + gid_t d4; + dev_t rdev; /* character or block device number */ + off_t size; /* file size */ + +# if defined(__arch32__) + unsigned int d5; +# endif /* defined(__arch32__) */ + + time_t d6; + int d7; + time_t d8; + int d9; + time_t d10; + int d11; + unsigned int d12[5]; + unsigned short nlink; /* link count */ +}; + +struct fsContext { /* file system context for AdvFS 5.0 + * and above */ + short d1[2]; + unsigned int d2[2]; + long d3; + int d4[2]; + lock_data_t d5; + long d6; + simple_lock_data_t d7; + unsigned int d8[2]; + long d9; + struct fs_stat st; /* file stats */ +}; + +struct advfsnode { /* AdvFS (MSFS) node definition for + * AdvFS 5.0 and above */ + unsigned long d1; + struct fsContext *a_con; /* context pointer */ +}; +#endif /* ADVFSV>=500 */ + +#if DUV>=50000 +typedef struct cnode { /* CFS node structure definition for + * Tru64 UNIX 5.0 and above */ + udecl_simple_lock_data(, d1) + unsigned int d2; + time_t d3; + unsigned long d4[3]; + +# if DUV<50100 + int d5[2]; + off_t d6; +# endif /* DUV<50100 */ + + unsigned long d7; + vattr_t c_attr; /* 96:Cached vnode attributes */ +} cnode_t; +#endif /* DUV>=50000 */ + +struct l_lock { /* local lock info */ + struct eflock set; /* lock data */ + struct l_lock *next; +}; + +struct l_flinfo { /* local file lock info */ + struct vnode *vp; /* identity of locked vnode */ + struct l_lock *lp; /* lock information */ + struct l_flinfo *next; +}; + +#define L_FLINFO_HSZ 256 /* local file lock information hash + * table size (must be a power of 2) */ +#define L_FLINFO_HASH(va) (((int)((long)(va) * 31415L) >> 5) & (L_FLINFO_HSZ - 1)) + + +/* + * Local static variables + */ + +static struct l_flinfo **Flinfo = (struct l_flinfo **)NULL; + /* local file lock hash buckets */ +static int FlinfoSt = 0; /* Flinfo[] load status */ + + +/* + * Local function prototypes + */ + +_PROTOTYPE(static char isvlocked,(struct vnode *vp)); +_PROTOTYPE(static int load_flinfo,(void)); +_PROTOTYPE(static int readvnode,(KA_T va, struct vnode *v)); +_PROTOTYPE(static void get_proc_sz,(struct procnode *pn)); + + +/* + * clr_flinfo() - clear local file lock table information + */ + +void +clr_flinfo() +{ + struct l_lock *lf, *lfn; + int i; + struct l_flinfo *fi, *fin; + + if (!Flinfo && !FlinfoSt) + return; + for (i = 0; i < L_FLINFO_HSZ; i++) { + if (!(fi = Flinfo[i])) + continue; + do { + if ((lf = fi->lp)) { + do { + lfn = lf->next; + (void) free((FREE_P *)lf); + } while ((lf = lfn)); + } + fin = fi->next; + (void) free((FREE_P *)fi); + } while ((fi = fin)); + Flinfo[i] = (struct l_flinfo *)NULL; + } + FlinfoSt = 0; +} + + +/* + * get_proc_sz() - get size of /proc file system file + */ + +static void +get_proc_sz(pn) + struct procnode *pn; /* pointer to procnode */ +{ + struct vm_map m; + struct proc *p; + KA_T pa; + int px; + struct task t; +/* + * Search for procnode's process by PID. + */ + for (p = Ps, px = 0; px < Psn; p++, px++) { + if (p->p_pid == pn->prc_pid) + break; + } + if (px >= Psn) + return; +/* + * Get the task structure address, then read the task structure. Set + * the procnode's file size from the memory map information in the task + * structure. + */ + +# if DUV<30000 + if (!(pa = (KA_T)p->task)) + return; +# else /* DUV>=30000 */ + if (!(pa = Pa[px])) + return; + pa = (KA_T)((char *)pa - sizeof(t)); +# endif /* DUV<30000 */ + + if (kread(pa, (char *)&t, sizeof(t))) + return; + if (!t.map || kread((KA_T)t.map, (char *)&m, sizeof(m))) + return; + Lf->sz = (SZOFFTYPE)m.vm_size; + Lf->sz_def = 1; +} + + +/* + * isvlocked() - is vnode locked? + */ + +static char +isvlocked(vp) + struct vnode *vp; /* vnode's kernel address */ +{ + struct l_flinfo *fp; + int i, l; + struct l_lock *lp; + + if (!Flinfo || !FlinfoSt) { + if (!load_flinfo()) + return(' '); + } +/* + * Hash the vnode address and see if there's a local file lock information + * structure for it. + */ + i = L_FLINFO_HASH(vp); + for (fp = Flinfo[i]; fp; fp = fp->next) { + if (fp->vp == vp) + break; + } + if (!fp) + return(' '); +/* + * Search the vnode's lock list for one held by this process. + */ + for (lp = fp->lp; lp; lp = lp->next) { + if (lp->set.l_rsys || lp->set.l_pid != (pid_t)Lp->pid) + continue; + if (lp->set.l_whence == 0 && lp->set.l_start == 0 + && ((lp->set.l_len == 0x8000000000000000) + || (lp->set.l_len == 0x7fffffffffffffff))) + l = 1; + else + l = 0; + if (lp->set.l_type == F_WRLCK) + return(l ? 'W' : 'w'); + else if (lp->set.l_type == F_RDLCK) + return(l ? 'R' : 'r'); + return(' '); + } + return(' '); +} + + +/* + * load_flinfo() - load local file lock information + */ + +static int +load_flinfo() +{ + struct flino fi; + struct filock fl; + KA_T fif, fip, flf, flp; + int i; + struct l_flinfo *lfi; + struct l_lock *ll; + KA_T v; + + if (Flinfo && FlinfoSt) + return(1); +/* + * Get kernel fids chain pointer. + */ + if (get_Nl_value("fids", Drive_Nl, &v) < 0 || !v + || kread((KA_T)v, (char *)&fip, sizeof(fip))) + return(0); +/* + * Define local hash buckets, if necessary. + */ + if (!Flinfo) { + if (!(Flinfo = (struct l_flinfo **)calloc(sizeof(struct flinfo *), + L_FLINFO_HSZ))) + { + (void) fprintf(stderr, + "%s: can't allocate %d byte local lock hash buckets\n", + Pn, L_FLINFO_HSZ * sizeof(struct l_flinfo *)); + Exit(1); + } + } +/* + * Follow the fids chain. + */ + if (!(fif = fip)) + return(1); + /* + * Follow the filock chain for this fid entry. + * Duplicate it via the lock file lock information hash buckets. + */ + do { + if (kread(fip, (char *)&fi, sizeof(fi))) + return(0); + if (!(flf = (KA_T)fi.fl_flck)) + continue; + /* + * Allocate a local file lock information structure for this fid. + */ + if (!(lfi = (struct l_flinfo *)malloc(sizeof(struct l_flinfo)))) { + (void) fprintf(stderr, + "%s: no space for local vnode lock info struct\n", Pn); + Exit(1); + } + lfi->vp = fi.vp; + lfi->lp = (struct l_lock *)NULL; + lfi->next = (struct l_flinfo *)NULL; + /* + * Follow the flino's filock chain, duplicating it locally. + */ + flp = flf; + do { + if (kread(flp, (char *)&fl, sizeof(fl))) + break; + /* + * Allocate a local lock information structure and link it + * to the chain for its vnode. + */ + if (!(ll = (struct l_lock *)malloc(sizeof(struct l_lock)))) { + (void) fprintf(stderr, + "%s: no space for local lock struct\n", Pn); + Exit(1); + } + ll->next = lfi->lp; + lfi->lp = ll; + ll->set = fl.set; + } while ((flp = (KA_T)fl.next) && flp != flf); + /* + * Link the file lock information structure to its hash bucket. + */ + i = L_FLINFO_HASH(lfi->vp); + lfi->next = Flinfo[i]; + Flinfo[i] = lfi; + } while ((fip = (KA_T)fi.next) && fip != fif); + FlinfoSt = 1; + return(1); +} + + +/* + * process_node() - process vnode + */ + +void +process_node(va) + KA_T va; /* vnode kernel space address */ +{ + struct advfsnode *a = (struct advfsnode *)NULL; + struct cdnode *c = (struct cdnode *)NULL; + dev_t dev, rdev; + unsigned char devs = 0; + unsigned char rdevs = 0; + struct inode *i = (struct inode *)NULL; + struct mfsnode *m = (struct mfsnode *)NULL; + struct procnode *p = (struct procnode *)NULL; + struct procfsid *pfi; + struct rnode *r = (struct rnode *)NULL; + struct spec_node *s = (struct spec_node *)NULL; + struct spec_node sn; + struct s5inode *s5 = (struct s5inode *)NULL; + char *ty; + enum vtype type; + unsigned long ul; + static struct vnode *v = (struct vnode *)NULL; + struct l_vfs *vfs; + +#if DUV>=30000 + struct fifonode *f = (struct fifonode *)NULL; + struct fifonode fn; + static struct vnode *fv = (struct vnode *)NULL; +#endif /* DUV>=30000 */ + +#if DUV>=50000 + cnode_t *cn = (cnode_t *)NULL; + struct fsContext fsc; + int fscs = 0; +#endif /* DUV>=50000 */ + +/* + * Read the vnode. + */ + if (!va) { + enter_nm("no vnode address"); + return; + } + if (!v) { + + /* + * Allocate space for the Digital UNIX vnode. + */ + if (!(v = (struct vnode *)malloc(sizeof(struct vnode)-1+Vnmxp))) { + (void) fprintf(stderr, "%s: no space for vnode buffer\n", Pn); + Exit(1); + } + +#if DUV>=30000 + if (!(fv = (struct vnode *)malloc(sizeof(struct vnode)-1+Vnmxp))) { + (void) fprintf(stderr, "%s: no space for fvnode buffer\n", Pn); + Exit(1); + } +#endif /* DUV>=30000 */ + + } + if (readvnode(va, v)) { + enter_nm(Namech); + return; + } + +#if defined(HASNCACHE) + Lf->na = va; +# if defined(HASNCVPID) + Lf->id = (unsigned long)v->v_id; +# endif /* defined(HASNCVPID) */ +#endif /* defined(HASNCACHE) */ + +#if defined(HASFSTRUCT) + Lf->fsv |= FSV_NI; + Lf->fna = va; +#endif /* defined(HASFSTRUCT) */ + +/* + * Get the mount structure and determine the vnode type. + */ + if (!v->v_mount) + vfs = (struct l_vfs *)NULL; + else + vfs = readvfs((KA_T)v->v_mount); + if (vfs) { + switch (vfs->type) { + case MOUNT_NFS: + +#if defined(MOUNT_NFS3) + case MOUNT_NFS3: +#endif /* defined(MOUNT_NFS3) */ + + Ntype = N_NFS; + break; + } + if (Ntype == N_REGLR) { + switch (v->v_type) { + case VFIFO: + Ntype = N_FIFO; + break; + } + } + } +/* + * Determine the lock type. + */ + if (FILEPTR && (FILEPTR->f_flag & FSHLOCK)) + Lf->lock = 'R'; + else if (FILEPTR && (FILEPTR->f_flag & FEXLOCK)) + Lf->lock = 'W'; + else + Lf->lock = isvlocked((struct vnode *)va); +/* + * Define the specific Digital UNIX node pointer. + */ + +#if DUV>=30000 + if (Ntype == N_FIFO) { + if (v->v_fifonode + && !kread((KA_T)v->v_fifonode, (char *)&fn, sizeof(fn))) + f = &fn; + } +#endif /* DUV>=30000 */ + + switch (v->v_tag) { + case VT_CDFS: + c = (struct cdnode *)v->v_data; + break; + +#if DUV>=50000 + case VT_CFS: + cn = (cnode_t *)v->v_data; + break; +#endif /* DUV>=50000 */ + + case VT_MFS: + m = (struct mfsnode *)v->v_data; + break; + case VT_NFS: + r = (struct rnode *)v->v_data; + break; + case VT_NON: + +#if DUV<20000 + if (v->v_specinfo + && !kread((KA_T)v->v_specinfo, (char *)&sn, sizeof(sn))) + s = &sn; + else +#else /* DUV>=20000 */ +# if DUV>=30000 + if (!f) +# endif /* DUV>=30000 */ +#endif /* DUV<20000 */ + + s = (struct spec_node *)v->v_data; + break; + case VT_PRFS: + p = (struct procnode *)v->v_data; + break; + case VT_S5FS: + s5 = (struct s5inode *)v->v_data; + break; + case VT_MSFS: + a = (struct advfsnode *)v->v_data; + +#if ADVFSV>=500 + if (a->a_con + && !kread((KA_T)a->a_con, (char *)&fsc, sizeof(fsc))) + fscs = 1; +#endif /* ADVFSV>=500 */ + + break; + case VT_UFS: + i = (struct inode *)v->v_data; + break; + default: + (void) snpf(Namech, Namechl, "unknown node type, v_tag=%d", + v->v_tag); + enter_nm(Namech); + return; + } +/* + * Get device and type for printing. + */ + type = v->v_type; + if (a) { + if (vfs && vfs->dev) { + dev = vfs->dev; + devs = 1; + } + if ((type == VCHR) || (type == VBLK)) { + +#if ADVFSV>=500 + if (fscs) { + rdev = fsc.st.rdev; + rdevs = 1; + } +#else /* ADVFSV<500 */ + rdev = a->a_rdev; + rdevs = 1; +#endif /* ADVFSV>=500 */ + + } + } else if (c) { + dev = c->cd_dev; + devs = 1; + } + +#if DUV>=50000 + else if (cn) { + if (vfs && vfs->dev) { + dev = vfs->dev; + devs = 1; + } + if ((type == VCHR) || (type == VBLK)) { + if (cn->c_attr.va_mask & AT_RDEV) { + rdev = cn->c_attr.va_rdev; + rdevs = 1; + } + } + } +#endif /* DUV>=50000 */ + + else if (i) { + if (i->i_dev) { + dev = i->i_dev; + devs = 1; + } else if (vfs && vfs->dev) { + dev = vfs->dev; + devs = 1; + } + if ((type == VCHR) || (type == VBLK)) { + rdev = i->i_din.di_db[0]; + rdevs = 1; + } + } else if (r) { + dev = r->r_attr.va_fsid; + devs = 1; + if ((type == VCHR) || (type == VBLK)) { + rdev = r->r_attr.va_rdev; + rdevs = 1; + } + } else if (s) { + if (vfs && vfs->dev) + dev = vfs->dev; + else + dev = DevDev; + devs = 1; + rdev = s->sn_vattr.va_rdev; + rdevs = 1; + if (!lkupdev(&dev, &rdev, 0, 0) && HaveCloneMaj) + rdev = makedev(CloneMaj, GET_MAJ_DEV(rdev)); + } else if (s5) { + dev = s5->i_dev; + devs = 1; + } else if (f) { + if (vfs && vfs->dev) { + dev = vfs->dev; + devs = 1; + } + } +/* + * Obtain the inode number. + */ + if (a) { + +#if ADVFSV>=500 + if (fscs) { + Lf->inode = (INODETYPE)fsc.st.num; + Lf->inp_ty = 1; + } +#else /* ADVFSV<500 */ + Lf->inode = (INODETYPE)a->a_number; + Lf->inp_ty = 1; +#endif /* ADVFSV>=500 */ + + +#if defined(HASTAGTOPATH) + /* + * Record the Digital UNIX 4.0 or greater, ADVFS 4.0 or greater + * ADVFS sequence number for later use with tag_to_path(). + */ + Lf->advfs_seq = a->a_seq; + Lf->advfs_seq_stat = 1; +#endif /* defined(HASTAGTOPATH) */ + + } else if (c) { + Lf->inode = (INODETYPE)c->cd_number; + Lf->inp_ty = 1; + } + +#if DUV>=50000 + else if (cn) { + if (cn->c_attr.va_mask & AT_NODEID) { + Lf->inode = (INODETYPE)cn->c_attr.va_fileid; + Lf->inp_ty = 1; + } + } +#endif /* DUV>=50000 */ + + else if (i) { + Lf->inode = (INODETYPE)i->i_number; + Lf->inp_ty = 1; + } else if (p) { + Lf->inode = (INODETYPE)((type == VDIR) ? PR_ROOTINO + : p->prc_pid + PR_INOBIAS); + Lf->inp_ty = 1; + } else if (r) { + Lf->inode = (INODETYPE)r->r_attr.va_fileid; + Lf->inp_ty = 1; + } else if (s5) { + Lf->inode = (INODETYPE)s5->i_number; + Lf->inp_ty = 1; + } + +#if DUV>=30000 + else if (f) { + Lf->inode = (INODETYPE)f->fn_fileid; + Lf->inp_ty = 1; + } +#endif /* DUV>=30000 */ + +/* + * Obtain the file size. + */ + if (Foffset) { + Lf->off_def = 1; + +#if DUV>=30000 + if (Ntype == N_FIFO && f) + Lf->off = (unsigned long) + (Lf->access == 'r') ? f->fn_rptr : f->fn_wptr; +#endif /* DUV>=30000 */ + + } else { + switch (Ntype) { + case N_FIFO: + +#if DUV>=30000 + if (f) { + Lf->sz = (SZOFFTYPE)f->fn_size; + Lf->sz_def = 1; + } else if (!Fsize) + Lf->off_def = 1; +#else /* DUV<30000 */ + if (!Fsize) + Lf->off_def = 1; +#endif /* DUV>=30000 */ + + break; + case N_NFS: + if (r) { + Lf->sz = (SZOFFTYPE)r->r_attr.va_qsize; + Lf->sz_def = 1; + } + break; + case N_REGLR: + if (type == VREG || type == VDIR) { + if (a) { + +#if ADVFSV>=500 + if (fscs) { + Lf->sz = (SZOFFTYPE)fsc.st.size; + Lf->sz_def = 1; + } +#else /* ADVFSV<500 */ + Lf->sz = (SZOFFTYPE)a->a_size; + Lf->sz_def = 1; +#endif /* ADVFSV>=500 */ + + } else if (c) { + Lf->sz = (SZOFFTYPE)c->cd_size; + Lf->sz_def = 1; + } + +#if DUV>=50000 + else if (cn) { + if (cn->c_attr.va_mask & AT_SIZE) { + Lf->sz = (SZOFFTYPE)cn->c_attr.va_qsize; + Lf->sz_def = 1; + } + } +#endif /* DUV>=50000 */ + + else if (i) { + Lf->sz = (SZOFFTYPE)i->i_din.di_qsize; + Lf->sz_def = 1; + } else if (m) { + Lf->sz = (SZOFFTYPE)m->mfs_size; + Lf->sz_def = 1; + } else if (p) { + if (type != VDIR) + get_proc_sz(p); + } else if (s5) { + Lf->sz = (SZOFFTYPE)s5->i_size; + Lf->sz_def = 1; + } + } else if ((type == VBLK) || (type == VCHR) && !Fsize) + Lf->off_def = 1; + } + } + if (Fnlink) { + switch(Ntype) { + case N_FIFO: /* no link count */ + break; + case N_NFS: + Lf->nlink = (long)r->r_attr.va_nlink; + Lf->nlink_def = 1; + break; + case N_REGLR: + +# if ADVFSV>=400 + if (a) { + +#if ADVFSV>=500 + if (fscs) { + Lf->nlink = (long)fsc.st.nlink; + Lf->nlink_def = 1; + } +#else /* ADVFSV<500 */ + Lf->nlink = (long)a->a_nlink; + Lf->nlink_def = 1; +#endif /* ADVFSV>=500 */ + + break; + } +# endif /* ADVFSV>=400 */ + + if (c) { + Lf->nlink = (long)c->cd_nlink; + Lf->nlink_def = 1; + } + +#if DUV>=50000 + else if (cn) { + if (cn->c_attr.va_mask & AT_NLINK) { + Lf->nlink = (long)cn->c_attr.va_nlink; + Lf->nlink_def = 1; + } + } +#endif /* DUV>=50000 */ + + else if (i) { + Lf->nlink = (long)i->i_din.di_nlink; + Lf->nlink_def = 1; + } else if (s5) { + Lf->nlink = (long)s5->i_nlink; + Lf->nlink_def = 1; + } + } + 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 device numbers and their states. + * + * Format the vnode type, and possibly the device name. + */ + Lf->dev = dev; + Lf->dev_def = devs; + Lf->rdev = rdev; + Lf->rdev_def = rdevs; + switch (type) { + case VNON: + ty ="VNON"; + break; + case VREG: + case VDIR: + ty = (type == VREG) ? "VREG" : "VDIR"; + break; + case VBLK: + ty = "VBLK"; + Ntype = N_BLK; + break; + case VCHR: + ty = "VCHR"; + Ntype = N_CHR; + break; + case VLNK: + ty = "VLNK"; + break; + +#if defined(VSOCK) + case VSOCK: + ty = "SOCK"; + break; +#endif /* defined(VSOCK) */ + + case VBAD: + ty = "VBAD"; + break; + case VFIFO: + ty = "FIFO"; + +#if DUV>=30000 + if ((!devs || !dev) && f) { + vfs = (struct l_vfs *)NULL; + devs = Lf->dev_def = 0; + ul = (unsigned long)v->v_fifonode; + enter_dev_ch(print_kptr((KA_T)(ul&0xffffffff),(char *)NULL,0)); + } +#endif /* DUV>=30000 */ + + break; + default: + (void) snpf(Lf->type, sizeof(Lf->type), "%04o", (type & 0xfff)); + ty = (char *)NULL; + } + if (ty) + (void) snpf(Lf->type, sizeof(Lf->type), "%s", ty); + Lf->ntype = Ntype; +/* + * Save the file system names. + */ + if (vfs) { + if (vfs->dir && *vfs->dir) + Lf->fsdir = vfs->dir; + if (vfs->fsname && *vfs->fsname) + Lf->fsdev = vfs->fsname; + +#if defined(HASFSINO) + if (vfs->fs_ino) + Lf->fs_ino = vfs->fs_ino; +#endif /* defined(HASFSINO) */ + + } +/* + * Handle some special cases: + * + * ioctl(fd, TIOCNOTTY) files; + * FIFOs (Digital UNIX V3.0 and higher); + * memory node files; + * /proc files. + */ + + if (type == VBAD) + (void) snpf(Namech, Namechl, "(revoked)"); + if (m) { + devs = Lf->dev_def = Lf->rdev_def = rdevs = 0; + (void) snpf(Namech, Namechl, "%#x", m->mfs_baseoff); + (void) enter_dev_ch("memory"); + } else if (p) { + devs = Lf->dev_def = Lf->rdev_def = rdevs = 0; + if (type != VDIR) + (void) snpf(Namech, Namechl, "/proc/%d", p->prc_pid); + else + (void) snpf(Namech, Namechl, "/proc"); + } + +#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 (p) { + if (Procsrch) { + Procfind = 1; + Lf->sf |= SELNM; + } else { + for (pfi = Procfsid; pfi; pfi = pfi->next) { + if ((pfi->pid && pfi->pid == p->prc_pid) + +#if defined(HASPINODEN) + || (Lf->inp_ty == 1 && pfi->inode == Lf->inode) +#endif /* defined(HASPINODEN) */ + + ) { + pfi->f = 1; + Lf->sf |= SELNM; + break; + } + } + } + } else { + if (Sfile && is_file_named((char *)NULL, (type == VCHR) ? 1 : 0)) + Lf->sf |= SELNM; + } +/* + * Enter name characters. + */ + if (Namech[0]) + enter_nm(Namech); +} + + +/* + * readvnode() - read vnode + */ + +static int +readvnode(va, v) + KA_T va; /* vnode kernel space address */ + struct vnode *v; /* vnode buffer pointer */ +{ + + if (kread((KA_T)va, (char *)v, sizeof(struct vnode) - 1 + Vnmxp)) { + (void) snpf(Namech, Namechl, "can't read vnode at %s", + print_kptr(va, (char *)NULL, 0)); + return(1); + } + return(0); +} diff --git a/dialects/du/dproc.c b/dialects/du/dproc.c new file mode 100644 index 0000000..2b141c0 --- /dev/null +++ b/dialects/du/dproc.c @@ -0,0 +1,1606 @@ +/* + * dproc.c - DEC OSF/1, Digital UNIX, Tru64 UNIX 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"; +static char *rcsid = "$Id: dproc.c,v 1.23 2005/08/08 19:56:44 abe Exp $"; +#endif + +#include "lsof.h" + + +#if DUV>=50000 +# if DUV>=50100 && defined(HASNCACHE) +#include +#include +#define _KERNEL 1 +#include +#include +#undef _KERNEL +#include +#include +#include +# endif /* DUV>=50100 && defined(HASNCACHE) */ +_PROTOTYPE(static KA_T vpo2vp,(struct vm_ubc_object *vpo)); +#endif /* DUV>=50000 */ + +_PROTOTYPE(static void enter_vn_text,(KA_T va, int *n)); +_PROTOTYPE(static void get_kernel_access,(void)); + +#if DUV<30000 +_PROTOTYPE(static void process_text,(KA_T tp, KA_T utp)); +#else /* DUV>=30000 */ +_PROTOTYPE(static void process_text,(KA_T tp)); +#endif /* DUV<30000 */ + +_PROTOTYPE(static void read_proc,(void)); + + +/* + * Local defintions + */ + +#define PAPSINCR 1024 /* Pa and Ps table increment */ +#define PAPSINIT 512 /* Pa and Ps table initial size */ + + +/* + * Local static values + */ + +#if DUV<30000 +static KA_T Kp; /* kernel proc[] address */ +#endif /* DUV<30000 */ + +static int Np = 0; /* number of processes */ +static MALLOC_S Nv = 0; /* allocateed Vp[] entries */ + +#if DUV>=30000 +static KA_T Pidtab; /* kernel pidtab[] address */ +#endif /* DUV>=30000 */ + +static KA_T *Vp = NULL; /* vnode address cache */ + + +/* + * enter_vn_text() - enter a vnode text reference + */ + +static void +enter_vn_text(va, n) + KA_T va; /* vnode address */ + int *n; /* number of vnodes in vp[] */ +{ + int i; + +/* + * Ignore the request if the vnode has already been printed. + */ + for (i = 0; i < *n; i++) { + if (va == Vp[i]) + return; + } +/* + * Print the vnode. + */ + alloc_lfile(" txt", -1); + FILEPTR = (struct file *)NULL; + process_node(va); + if (Lf->sf) + link_lfile(); + if (i >= Nv) { + + /* + * Allocate space for remembering the vnode. + */ + Nv += 10; + if (!Vp) + Vp=(KA_T *)malloc((MALLOC_S)(sizeof(KA_T) * 10)); + else + Vp=(KA_T *)realloc((MALLOC_P *)Vp,(MALLOC_S)(Nv*sizeof(KA_T))); + if (!Vp) { + (void) fprintf(stderr, "%s: no txt ptr space, PID %d\n", + Pn, Lp->pid); + Exit(1); + } + } +/* + * Remember the vnode. + */ + Vp[*n] = va; + (*n)++; +} + + +/* + * gather_proc_info() -- gather process information + */ + +void +gather_proc_info() +{ + MALLOC_S b; + struct file *fp; + int i, j; + struct pgrp pg; + int pgid, px; + struct proc *p; + short pss, sf; + struct ucred pcred; + uid_t uid; + struct utask ut, *utp; + +#if DUV>=30000 + struct pid_entry pe; +#endif /* DUV>=30000 */ + +#if DUV<50000 + static int nufb = 0; + static struct file **ufb = (struct file **)NULL; +#else /* DUV>=50000 */ + int k, l; + KA_T ka; + struct ufile_entry *ofb[U_FE_OF_ALLOC_SIZE]; + struct ufile_entry ufe[U_FE_ALLOC_SIZE]; + struct ufile_entry ufeo[U_FE_OF_ALLOC_SIZE]; +#endif /* DUV<50000 */ + +#if defined(HASFSTRUCT) && DUV>=40000 + static char *pof = (char *)NULL; + static int pofb = 0; + long pv; +#endif /* defined(HASFSTRUCT) && DUV>=40000 */ + +/* + * Clear file lock information. + */ + (void) clr_flinfo(); +/* + * Read process table entries. + */ + read_proc(); +/* + * Examine proc structures and their associated information. + */ + for (p = Ps, px = 0, utp = &ut; px < Psn; p++, px++) { + if (p->p_stat == 0 || p->p_stat == SZOMB) + continue; + if (Fpgid) { + if (!p->p_pgrp + || kread((KA_T)p->p_pgrp, (char *)&pg, sizeof(pg))) + continue; + pgid = pg.pg_id; + } else + pgid = 0; + if (p->p_rcred == NULL + || kread((KA_T)p->p_rcred, (char *)&pcred, sizeof(pcred))) + continue; + uid = (uid_t)pcred.cr_uid; + if (is_proc_excl(p->p_pid, pgid, (UID_ARG)uid, &pss, &sf)) + continue; + +#if DUV<30000 + if (!p->utask + || kread((KA_T)p->utask, (char *)&ut, sizeof(ut))) +#else /* DUV>=30000 */ + if (kread((KA_T)((char *)Pa[px] + sizeof(struct proc)), + (char *)&ut, sizeof(ut))) +#endif /* DUV<30000 */ + + continue; + /* + * Allocate a local process structure. + */ + if (is_cmd_excl(utp->u_comm, &pss, &sf)) + continue; + alloc_lproc((int)p->p_pid, pgid, (int)p->p_ppid, (UID_ARG)uid, + utp->u_comm, (int)pss, (int)sf); + Plf = (struct lfile *)NULL; + /* + * Save current working directory information. + */ + if (utp->uu_utnd.utnd_cdir) { + alloc_lfile(CWD, -1); + FILEPTR = (struct file *)NULL; + process_node((KA_T)utp->uu_utnd.utnd_cdir); + if (Lf->sf) + link_lfile(); + } + /* + * Save root directory information. + */ + if (utp->uu_utnd.utnd_rdir) { + alloc_lfile(RTD, -1); + FILEPTR = (struct file *)NULL; + process_node((KA_T)utp->uu_utnd.utnd_rdir); + if (Lf->sf) + link_lfile(); + } + /* + * Print information on the text file. + */ + +#if DUV<30000 + if (p->task) + process_text((KA_T)p->task, (KA_T)p->utask); +#else /* DUV>=30000 */ + process_text((KA_T)((char *)Pa[px] - sizeof(struct task))); +#endif /* DUV<30000 */ + + /* + * Save information on file descriptors. + */ + +#if DUV<50000 + for (i = j = 0; i <= utp->uu_file_state.uf_lastfile; i++) { + if (i < NOFILE_IN_U) { + fp = utp->uu_file_state.uf_ofile[i]; + +# if defined(HASFSTRUCT) && DUV>=40000 + if (Fsv & FSV_FG) + pv = (long)utp->uu_file_state.uf_pofile[i]; +# endif /* defined(HASFSTRUCT) && DUV>=40000 */ + + } else { + if (!j) { + b = (MALLOC_S)(utp->uu_file_state.uf_of_count + * sizeof(struct file *)); + if (b > nufb) { + if (!ufb) + ufb = (struct file **)malloc(b); + else + ufb = (struct file **)realloc((MALLOC_P *)ufb, + b); + if (!ufb) { + (void) fprintf(stderr, + "%s: PID %d, no file * space\n", + Pn, Lp->pid); + Exit(1); + } + nufb = b; + } + if (kread((KA_T)utp->uu_file_state.uf_ofile_of, + (char *)ufb, b)) + break; + +# if defined(HASFSTRUCT) && DUV>=40000 + if (Fsv & FSV_FG) { + b = (MALLOC_S)(utp->uu_file_state.uf_of_count + * sizeof(char)); + if (b > pofb) { + if (!pof) + pof = (char *)malloc(b); + else + pof = (char *)realloc((MALLOC_P *)pof, b); + if (!pof) { + (void) fprintf(stderr, + "%s: PID %d: no file flags space\n", + Pn, Lp->pid); + Exit(1); + } + pofb = b; + } + if (kread((KA_T)utp->uu_file_state.uf_pofile_of, + pof, b)) + zeromem(pof, b); + } +# endif /* defined(HASFSTRUCT) && DUV>=40000 */ + + } + fp = ufb[j]; + +# if defined(HASFSTRUCT) && DUV>=40000 + if (Fsv & FSV_FG) + pv = pof[j]; +# endif /* defined(HASFSTRUCT) && DUV>=40000 */ + + j++; + } + if (fp && (ulong)fp != 0xffffffffffffffff) { + alloc_lfile(NULL, i); + process_file((KA_T)fp); + if (Lf->sf) { + +# if defined(HASFSTRUCT) && DUV>=40000 + if (Fsv & FSV_FG) { + if ((Lf->pof = pv)) + Lf->fsv |= FSV_FG; + } +# endif /* defined(HASFSTRUCT) && DUV>=40000 */ + + link_lfile(); + } + } + } +#else /* DUV>=50000 */ + for (i = j = k = 0; i <= utp->uu_file_state.uf_lastfile; i++) { + if (i < NOFILE_IN_U) { + if (!k) { + l = i/U_FE_ALLOC_SIZE; + if (!(ka = (KA_T)utp->uu_file_state.uf_entry[l])) { + i += U_FE_ALLOC_SIZE - 1; + continue; + } + } + } else { + if (!j) { + ka = (KA_T)utp->uu_file_state.uf_of_entry; + if (!ka || kread(ka, (char *)&ofb, sizeof(ofb))) + break; + k = 0; + } + if (!k) { + l = j/U_FE_OF_ALLOC_SIZE; + if (!(ka = (KA_T)ofb[l])) { + j += U_FE_OF_ALLOC_SIZE; + i += U_FE_OF_ALLOC_SIZE - 1; + continue; + } + if (kread(ka, (char *)&ufeo, sizeof(ufeo))) + break; + } + fp = ufeo[k].ufe_ofile; + +# if defined(HASFSTRUCT) && DUV>=40000 + if (Fsv & FSV_FG) + pv = ufeo[k].ufe_oflags; +# endif /* defined(HASFSTRUCT) && DUV>=40000 */ + + if (++k >= U_FE_OF_ALLOC_SIZE) + k = 0; + j++; + } + if (!j) { + if (!k) { + if (kread(ka, (char *)&ufe, sizeof(ufe))) + break; + } + fp = ufe[k].ufe_ofile; + +# if defined(HASFSTRUCT) && DUV>=40000 + if (Fsv & FSV_FG) + pv = ufe[k].ufe_oflags; +# endif /* defined(HASFSTRUCT) && DUV>=40000 */ + + if (++k >= U_FE_ALLOC_SIZE) + k = 0; + } + if (fp && (ulong)fp != 0xffffffffffffffff) { + alloc_lfile(NULL, i); + process_file((KA_T)fp); + if (Lf->sf) { + +# if defined(HASFSTRUCT) && DUV>=40000 + if (Fsv & FSV_FG) { + if ((Lf->pof = pv)) + Lf->fsv |= FSV_FG; + } +# endif /* defined(HASFSTRUCT) && DUV>=40000 */ + + link_lfile(); + } + } + } +#endif /* DUV>=50000 */ + + /* + * Examine results. + */ + if (examine_lproc()) + return; + } +} + + +/* + * get_kernel_access() - get access to kernel memory + */ + +static void +get_kernel_access() +{ + dev_t dev; + int rv; + KA_T v; +/* + * Check kernel version. + */ + (void) ckkv("DU", LSOF_VSTR, (char *)NULL, (char *)NULL); +/* + * Set name list file path. + */ + +#if DUV<40000 + if (!Nmlst) { + if (!(Nmlst = get_nlist_path(1))) { + (void) fprintf(stderr, "%s: can't get kernel name list path\n", + Pn); + Exit(1); + } + } +#endif /* DUV<40000 */ + +#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)) + Exit(1); +#endif /* defined(WILLDROPGID) */ + +/* + * Open kernel memory access. + */ + if ((Kd = open(Memory ? Memory : KMEM, O_RDONLY, 0)) < 0) { + (void) fprintf(stderr, "%s: can't open %s: %s\n", Pn, + Memory ? Memory : KMEM, sys_errlist[errno]); + Exit(1); + } + +#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)) + Exit(1); +#endif /* defined(WILLDROPGID) */ + +/* + * Access kernel symbols. + */ + (void) build_Nl(Drive_Nl); + +#if DUV>=40000 + if (!Nmlst) + rv = knlist(Nl); + else +#endif /* DUV>=40000 */ + + rv = nlist(Nmlst, Nl); + if (rv == -1) { + (void) fprintf(stderr, + "%s: can't read kernel name list from %s: %s\n", + Pn, Nmlst ? Nmlst : "knlist(3)", strerror(errno)); + Exit(1); + } + +#if DUV<30000 + if (get_Nl_value("proc", Drive_Nl, &v) < 0 || !v + || kread(v, (char *)&Kp, sizeof(Kp)) + || get_Nl_value("nproc", Drive_Nl, &v) < 0 || !v + || kread(v, (char *)&Np, sizeof(Np))) +#else /* DUV>=30000 */ + if (get_Nl_value("npid", Drive_Nl, &v) < 0 || !v + || kread(v, (char *)&Np, sizeof(Np)) + || get_Nl_value("pidt", Drive_Nl, &v) < 0 || !v + || kread(v, (char *)&Pidtab, sizeof(Pidtab))) +#endif /* DUV<30000 */ + + { + (void) fprintf(stderr, "%s: can't read proc table info\n", Pn); + Exit(1); + } + if (get_Nl_value("vnmaxp", Drive_Nl, &v) < 0 || !v + || kread(v, (char *)&Vnmxp, sizeof(Vnmxp))) { + (void) fprintf(stderr, "%s: can't determine vnode length\n", Pn); + Exit(1); + } + if (get_Nl_value("cldev", Drive_Nl, &v) < 0 || !v + || kread(v, (char *)&dev, sizeof(dev))) { + if (!Fwarn) + (void) fprintf(stderr, "%s: can't read clone device number\n", + Pn); + HaveCloneMaj = 0; + } else { + CloneMaj = GET_MAJ_DEV(dev); + HaveCloneMaj = 1; + } +} + + +/* + * get_nlist_path() - get kernel name list path + */ + +char * +get_nlist_path(ap) + int ap; /* on success, return an allocated path + * string pointer if 1; return a + * constant character pointer if 0; + * return NULL if failure */ +{ + char *ba, buf[MAXPATHLEN+2], *ps; + int len, rv; +/* + * Get bootfile name. + */ + len = 0; + if ((rv = getsysinfo(GSI_BOOTEDFILE, &buf[1], sizeof(buf) - 1, &len, + (char *)NULL)) + != 1) + { + if (rv < 0) { + (void) fprintf(stderr, "%s: can't get booted file name: %s\n", + Pn, strerror(errno)); + Exit(1); + } + return((char *)NULL); + } +/* + * Check for a non-NULL path. + */ + buf[sizeof(buf) - 2] = '\0'; + len = strlen(&buf[1]); + if (len < 1) + return((char *)NULL); +/* + * If no path return is requested by the value of ap, return a NULL string + * pointer. + */ + if (!ap) + return(""); +/* + * Make sure the path has a leading '/'. + */ + if (buf[1] != '/') { + buf[0] = '/'; + ba = buf; + len++; + } else + ba = &buf[1]; +/* + * Allocate permanent space for the path, copy it to the space, and return + * a pointer to the space. + */ + len++; + if (!(ps = (char *)malloc(len))) { + (void) fprintf(stderr, + "%s: can't allocate %d bytes for boot file path: %s\n", + Pn, len, ba); + Exit(1); + } + (void) snpf(ps, len, "%s", ba); + return(ps); +} + + +/* + * initialize() - perform all initialization + */ + +void +initialize() +{ + get_kernel_access(); +} + + +/* + * kread() - read from kernel memory + */ + +int +kread(addr, buf, len) + KA_T addr; /* kernel memory address */ + char *buf; /* buffer to receive data */ + READLEN_T len; /* length to read */ +{ + int br; + + if (lseek(Kd, addr, L_SET) == (off_t)-1L) + return(-1); + br = read(Kd, buf, len); + return((br == len) ? 0 : 1); +} + + +/* + * process_text() - print text information + */ +static void + +#if DUV<30000 +process_text(tp, utp) +#else /* DUV>=30000 */ +process_text(tp) +#endif /* DUV<30000 */ + + KA_T tp; /* kernel task structure */ + +#if DUV<30000 + KA_T utp; /* user task structure address for + * the task */ +#endif /* DUV<30000 */ + +{ + int i; + KA_T ka, kb; + int n = 0; + struct task t; + struct vm_anon_object vmao; + struct vm_map_entry vmme; + struct vm_map vmm; + struct vm_object vmo; + struct vm_seg vms; + +#if DUV<40000 + struct vm_vp_object vpo; +#else /* DUV>=40000 */ + struct vm_ubc_object vpo; +#endif /* DUV<40000 */ + +/* + * Read task structure from kernel. + */ + if (kread(tp, (char *)&t, sizeof(t)) + +#if DUV<30000 + || (KA_T)t.u_address != utp +#endif /* DUV<30000 */ + + ) + return; +/* + * Print information about the text vnode referenced in the procfs + * structure inside the task structure. + */ + if (t.procfs.pr_exvp) + enter_vn_text((KA_T)t.procfs.pr_exvp, &n); +/* + * Read the vm_map structure. Search its vm_map_entry structure list. + */ + if (!t.map + || kread((KA_T)t.map, (char *)&vmm, sizeof(vmm))) + return; + if (!vmm.vm_is_mainmap) + return; + +#if defined(VM_SKIPLIST) + for (i = 0, ka = (KA_T)vmm.vm_links.vml_sl_next[0]; + i < vmm.vm_nentries && ka != (KA_T)t.map; + i++, ka = (KA_T)vmme.vme_links.vml_sl_next[0]) +#else /* !defined(VM_SKIPLIST) */ + for (i = 0, ka = (KA_T)vmm.vm_links.next; + i < vmm.vm_nentries && ka != (KA_T)t.map; + i++, ka = (KA_T)vmme.vme_links.next) +#endif /* defined(VM_SKIPLIST) */ + + { + + /* + * Read the next vm_map_entry structure and its object. + */ + if (kread(ka, (char *)&vmme, sizeof(vmme))) + return; + if (!(kb = (KA_T)vmme.vme_uobject.vm_object) + || kread(kb, (char *)&vmo, sizeof(vmo))) + continue; + /* + * Process by object type. + */ + switch (vmo.ob_type) { + case OT_ANON: + + /* + * If an anonymous object is backed by an OT_UBC or OT_VP object, + * read its vm_ubc_object or vm_vp_object to find a vnode pointer. + */ + if (kread(kb, (char *)&vmao, sizeof(vmao))) + break; + if (!vmao.ao_bobject + || kread((KA_T)vmao.ao_bobject, (char *)&vmo, sizeof(vmo))) + break; + +#if DUV<40000 + if (vmo.ob_type != OT_VP + || kread((KA_T)vmao.ao_bobject, (char *)&vpo, sizeof(vpo))) + break; + enter_vn_text((KA_T)vpo.vo_vp, &n); +#else /* DUV>=40000 */ + if (vmo.ob_type != OT_UBC + || kread((KA_T)vmao.ao_bobject, (char *)&vpo, sizeof(vpo))) + break; +# if DUV>=50000 + enter_vn_text(vpo2vp(&vpo), &n); +# else /* DUV<50000 */ + enter_vn_text((KA_T)vpo.vu_vfp.vp, &n); +#endif /* DUV>=50000 */ +#endif /* DUV<40000 */ + break; + /* + * If this is a segment object, read the segment map, and search + * for backing objects whose object type is OT_UBC or OT_VP. + */ + + case OT_SEG: + for (kb=(KA_T)vmme.vme_seg; kb; kb=(KA_T)vms.seg_vnext) { + if (kread(kb, (char *)&vms, sizeof(vms))) + break; + if (!vms.seg_vop + || kread((KA_T)vms.seg_vop, (char *)&vmo, sizeof(vmo))) + continue; + +#if DUV<40000 + if (vmo.ob_type != OT_VP) +#else /* DUV>=40000 */ + if (vmo.ob_type != OT_UBC) +#endif /* DUV<40000 */ + + continue; + if (kread((KA_T)vms.seg_vop, (char *)&vpo, sizeof(vpo))) + break; + +#if DUV<40000 + enter_vn_text((KA_T)vpo.vo_vp, &n); +#else /* DUV>=40000 */ +# if DUV>=50000 + enter_vn_text(vpo2vp(&vpo), &n); +# else /* DUV<50000 */ + enter_vn_text((KA_T)vpo.vu_vfp.vp, &n); +#endif /* DUV<40000 */ +#endif /* DUV>=50000 */ + + } + } + } +} + + +/* + * read_proc() - read process table entries + */ + +static void +read_proc() +{ + static int ap = 0; + MALLOC_S len; + struct proc *p; + KA_T pa; + int px, try; + +#if DUV>=30000 + struct pid_entry pe; +#endif /* DUV>=30000 */ + + if (!Ps) { + + /* + * Allocate local proc table space. + */ + if (Np < 1) { + (void) fprintf(stderr, "%s: proc table has no entries\n", Pn); + Exit(1); + } + len = (MALLOC_S)(PAPSINIT * sizeof(struct proc)); + if (!(Ps = (struct proc *)malloc(len))) { + (void) fprintf(stderr, "%s: no proc table space (%d bytes)\n", + Pn, len); + Exit(1); + } + +#if DUV>=30000 + /* + * Allocate kernel proc address table space. + */ + len = (MALLOC_S)(PAPSINIT * sizeof(KA_T)); + if (!(Pa = (KA_T *)malloc(len))) { + (void) fprintf(stderr, + "%s: no proc address table space (%d bytes)\n", Pn, len); + Exit(1); + } +#endif /* DUV>=30000 */ + + ap = PAPSINIT; + } +/* + * Try to read the proc structure table PROCTRYLM times. + * The operation must yield PROCMIN structures. + */ + for (try = 0; try < PROCTRYLM; try++) { + for (p = Ps, Psn = px = 0; px < Np; px++) { + + /* + * Insure Ps and Psa space. + */ + if (Psn >= ap) { + ap += PAPSINCR; + len = (MALLOC_S)(ap * sizeof(struct proc)); + if (!(Ps = (struct proc *)realloc((MALLOC_P *)Ps, len))) { + (void) fprintf(stderr, + "%s: no more proc table space (%d bytes)\n", + Pn, len); + Exit(1); + } + p = &Ps[Psn]; + +#if DUV>=30000 + len = (MALLOC_S)(ap * sizeof(KA_T)); + if (!(Pa = (KA_T *)realloc((MALLOC_P *)Pa, len))) { + (void) fprintf(stderr, + "%s: no more proc address table space (%d bytes)\n", + Pn, len); + Exit(1); + } +#endif /* DUV>=30000 */ + + } + +#if DUV<30000 + pa = Kp + (KA_T)(px * sizeof(struct proc)); + if (kread(pa, (char *)p, sizeof(struct proc))) + continue; +#else /* DUV>=30000 */ + pa = Pidtab + (KA_T)(px * sizeof(struct pid_entry)); + if (kread(pa, (char *)&pe, sizeof(struct pid_entry))) + continue; + if ((pa = (KA_T)pe.pe_proc) == NULL + || kread(pa, (char *)p, sizeof(struct proc))) + continue; + if (pe.pe_pid != p->p_pid) + continue; + Pa[Psn] = pa; +#endif /* DUV<30000 */ + + Psn++; + p++; + } + /* + * Check the results of the scan. + */ + if (Psn >= PROCMIN) + break; + } +/* + * Quit if not enough proc structures could be accumulated. + */ + if (try >= PROCTRYLM) { + (void) fprintf(stderr, "%s: can't read proc table\n", Pn); + Exit(1); + } + if (Psn < Np && !RptTm) { + + /* + * Reduce the local proc structure tables to their minimum if + * not in repeat mode. + */ + ap = Psn; + len = (MALLOC_S)(Psn * sizeof(struct proc)); + if (!(Ps = (struct proc *)realloc((MALLOC_P *)Ps, len))) { + (void) fprintf(stderr, + "%s: can't reduce proc table to %d bytes\n", + Pn, len); + Exit(1); + } + +#if DUV>=30000 + len = (MALLOC_S)(Psn * sizeof(KA_T)); + if (!(Pa = (KA_T *)realloc((MALLOC_P *)Pa, len))) { + (void) fprintf(stderr, + "%s: can't reduce proc address table to %d bytes\n", + Pn, len); + Exit(1); + } +#endif /* DUV>=30000 */ + + } +} + + +#if DUV>=50000 +/* + * vfp2vp() -- convert VM object's vu_vfp to a vnode pointer + */ + +static KA_T +vpo2vp(vpo) + struct vm_ubc_object *vpo; /* pointer to local vm_ubc_object */ +{ + struct advfsbfs { /* This structure is referenced in + * vm_ubc.h (as msfsbfs), but never + * defined in a distributed header + * file, so we make a hack definition + * here. */ + unsigned long d1[18]; /* dummies */ + struct vnode *vp; /* vnode */ + } bfa; + static int ft = 1; + KA_T ka; + static KA_T ops = (KA_T)0; +/* + * If this is the first time, get the msfs (AdvFS) UBC operation switch + * address. + */ + if (ft) { + ft = 0; + +#if defined(ADVFSV) + if (get_Nl_value("msfsubc", Drive_Nl, &ops) < 0) +#endif /* defined(ADVFSV) */ + + ops = (KA_T)0; + + } + ka = (KA_T)vpo->vu_vfp.vp; + if (!ops || ((KA_T)vpo->vu_ops != ops)) + return(ka); + if (!ka || kread(ka, (char *)&bfa, sizeof(bfa))) + return(ka); + return((KA_T)bfa.vp); +} +#endif /* DUV>=50000 */ + + +#if DUV>=50100 && defined(HASNCACHE) +/* + * Kernel name cache functions and associate definiitions for Tru64 UNIX + * 5.1 and above. + */ + + +/* + * Definitions + */ + + +/* + * Structures + */ + +struct l_nch { + struct namecache *nc; /* namecache entry */ + struct l_nch *nxt; /* next hashed entry */ +}; + + +/* + * Static variables + */ + +static int Hmsk = 0; /* Nchash[] mask -- (size - 1), where + * size is a power of two */ +static int Nc; /* number of cached namecache structs */ +static struct l_nch **Nchash = (struct l_nch **)NULL; + /* hash pointers buckets */ +static int Ncfirst = 1; /* first-call status */ + +/* + * Definitions + */ + +#define ncachehash(i) (((int)(i*31415)>>3)&Hmsk) + + +/* + * Prototypes + */ + +_PROTOTYPE(static struct l_nch *ncache_addr,(unsigned long id)); +_PROTOTYPE(static int ncache_ckrootid,(KA_T na, unsigned long id)); +_PROTOTYPE(static int ncache_isroot,(KA_T na, char *cp)); + + +/* + * ncache_addr() -- look up a node's local ncache address + */ + +static struct l_nch * +ncache_addr(id) + unsigned long id; /* node's capability ID */ +{ + register struct l_nch *hp; + + for (hp = Nchash[ncachehash(id)]; hp; hp = hp->nxt) { + if ((hp->nc)->nc_vpid == id) + return(hp); + } + return((struct l_nch *)NULL); +} + + +/* + * ncache_ckrootid() - check for a root node ID + */ + +static int +ncache_ckrootid(na, id) + KA_T na; /* vnode address */ + unsigned long id; /* root ID to check */ +{ + +#if defined(ADVFSV) + struct advfsmount { /* This structure should be defined in + * a distributed header file, but it + * isn't, so we make a hack definition + * here. */ + u_long d1[10]; /* dummies */ + struct vnode *am_rootvp; /* root vnode pointer */ + } am; + static KA_T aops = (KA_T)0; +#endif /* defined(ADVFSV) */ + + struct cdfsmount cm; + static KA_T cops = (KA_T)0; + struct dvdfsmount dm; + static KA_T dops = (KA_T)0; + static KA_T fops = (KA_T)0; + static KA_T frvp = (KA_T)0; + static int ft = 1; + register int i; + static unsigned long *ic = (unsigned long *)NULL; + MALLOC_S len; + struct mount m; + static int nia = 0; + static int niu = 0; + struct mntinfo nm; + static KA_T nops = (KA_T)0; + static KA_T n3ops = (KA_T)0; + KA_T rv; + struct ufsmount um; + static KA_T uops = (KA_T)0; + struct vnode v; +/* + * Check the cache. + */ + if (ic && niu) { + for (i = 0; i < niu; i++) { + if (id == ic[i]) + return(1); + } + } +/* + * Read the vnode and the associated mount structure. + */ + if (!na || kread(na, (char *)&v, sizeof(v))) + return(0); + if (!v.v_mount || kread((KA_T)v.v_mount, (char *)&m, sizeof(m))) + return(0); +/* + * If this is the first time this function has been used, get the necessary + * kernel addresses. + */ + if (ft) { + ft = 0; + +#if defined(ADVFSV) + if (get_Nl_value("advfsvfs", (struct drive_Nl *)NULL, &aops) < 0) + aops = (KA_T)0; +#endif /* defined(ADVFSV) */ + + if (get_Nl_value("cdfsvfs", (struct drive_Nl *)NULL, &cops) < 0) + cops = (KA_T)0; + if (get_Nl_value("dvdfsvfs", (struct drive_Nl *)NULL, &dops) < 0) + dops = (KA_T)0; + if (get_Nl_value("fdfsvfs", (struct drive_Nl *)NULL, &fops) < 0) + fops = (KA_T)0; + if (get_Nl_value("fsfsrvp", (struct drive_Nl *)NULL, &frvp) < 0) + frvp = (KA_T)0; + if (get_Nl_value("nfsvfs", (struct drive_Nl *)NULL, &nops) < 0) + nops = (KA_T)0; + if (get_Nl_value("nfs3vfs", (struct drive_Nl *)NULL, &n3ops) < 0) + n3ops = (KA_T)0; + if (get_Nl_value("ufsvfs", (struct drive_Nl *)NULL, &uops) < 0) + uops = (KA_T)0; + } +/* + * See if we know how to find the root vnode pointer for this file system + * type. + */ + +#if defined(ADVFSV) + if (aops && (aops == (KA_T)m.m_op)) { + + /* + * Set AdvFS (MSFS) root vnode address. + */ + if (!m.m_info || kread((KA_T)m.m_info, (char *)&am, sizeof(am))) + return(0); + rv = (KA_T)am.am_rootvp; + } else +#endif /* defined(ADVFSV) */ + + if (cops && (cops == (KA_T)m.m_op)) { + + /* + * Set CDFS root vnode address. + */ + if (!m.m_info || kread((KA_T)m.m_info, (char *)&cm, sizeof(cm))) + return(0); + rv = (KA_T)cm.um_rootvp; + } else if (dops && (dops == (KA_T)m.m_op)) { + + /* + * Set DVDFS root vnode address. + */ + if (!m.m_info || kread((KA_T)m.m_info, (char *)&dm, sizeof(dm))) + return(0); + rv = (KA_T)dm.dm_rootvp; + } else if (fops && (fops == (KA_T)m.m_op)) { + + /* + * Set FDFS root vnode address. + */ + rv = frvp; + } else if ((nops && (nops == (KA_T)m.m_op)) + || (n3ops && (n3ops == (KA_T)m.m_op))) + { + + /* + * Set NFS[3] root vnode address. + */ + if (!m.m_info || kread((KA_T)m.m_info, (char *)&nm, sizeof(nm))) + return(0); + rv = (KA_T)nm.mi_rootvp; + } else if (uops && (uops == (KA_T)m.m_op)) { + + /* + * Set UFS root vnode address. + */ + if (!m.m_info || kread((KA_T)m.m_info, (char *)&um, sizeof(um))) + return(0); + rv = (KA_T)um.um_rootvp; + } else + return(0); +/* + * Read the root vnode. + */ + if (!rv || kread(rv, (char *)&v, sizeof(v))) + return(0); + if (id != v.v_id) + return(0); +/* + * A new root vnode has been located. Cache it. + */ + if (niu >= nia) { + if (!nia) { + len = (MALLOC_S)(10 * sizeof(unsigned long)); + ic = (unsigned long *)malloc(len); + } else { + len = (MALLOC_S)((nia + 10) * sizeof(unsigned long)); + ic = (unsigned long *)realloc((MALLOC_P *)ic, len); + } + if (!ic) { + (void) fprintf(stderr, + "%s: no space for root node VPID table\n", Pn); + Exit(1); + } + nia += 10; + } + ic[niu++] = id; + return(1); +} + + +/* + * ncache_isroot() - is head of name cache path a file system root? + */ + +static int +ncache_isroot(na, cp) + KA_T na; /* vnode address */ + char *cp; /* partial path */ +{ + char buf[MAXPATHLEN]; + int i; + MALLOC_S len; + struct mounts *mtp; + static KA_T *nc = (KA_T *)NULL; + static int nca = 0; + static int ncn = 0; + struct stat sb; + struct vnode v; + + if (!na) + return(0); +/* + * Search the root capability node address 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((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 + || (INODETYPE)sb.st_ino != Lf->inode) + return(0); + } +/* + * Add the capability ID to the root capability ID 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((MALLOC_P *)nc, len); + } + if (!nc) { + (void) fprintf(stderr, + "%s: no space for root node address table\n", Pn); + Exit(1); + } + nca += 10; + } + nc[ncn++] = na; + return(1); +} + + +/* + * ncache_load() - load the kernel's name cache + */ + +void +ncache_load() +{ + register int h, i, n; + KA_T ka, ncp; + int len; + register struct l_nch *lp; + struct l_nch *lpnxt; + static struct namecache *nc = (struct namecache *)NULL; + static int ncl = 0; + static int nchsz = 0; + static int ncpc = 0; + static int ncpus = 0; + register struct namecache *np; + static KA_T *pp = (KA_T *)NULL; + + if (!Fncache) + return; + if (Ncfirst) { + + /* + * Do startup (first-time) functions. + */ + Ncfirst = 0; + /* + * Get CPU count. + */ + ka = (KA_T)0; + if (get_Nl_value("ncpus", (struct drive_Nl *)NULL, &ka) < 0 + || !ka + || kread(ka, (char *)&ncpus, sizeof(ncpus))) + { + if (!Fwarn) + (void) fprintf(stderr, + "%s: WARNING: can't read processor count: %s\n", + Pn, print_kptr(ka, (char *)NULL, 0)); + ncl = nchsz = ncpc = ncpus = 0; + return; + } + if (ncpus < 1) { + if (!Fwarn) + (void) fprintf(stderr, + "%s: WARNING: processor count: %d\n", Pn, ncpus); + ncl = nchsz = ncpc = ncpus = 0; + return; + } + /* + * Get the per-processor table address. + */ + ka = (KA_T)0; + if (get_Nl_value("procptr", (struct drive_Nl *)NULL, &ka) < 0 + || !ka + || kread(ka, (char *)&ka, sizeof(ka)) + || !ka) + { + if (!Fwarn) + (void) fprintf(stderr, + "%s: WARNING: per processor table address: %s\n", + Pn, print_kptr(ka, (char *)NULL, 0)); + ncl = nchsz = ncpc = ncpus = 0; + return; + } + /* + * Allocate space for the processor structure addresses and read them. + */ + len = (int)(ncpus * sizeof(KA_T)); + if (!(pp = (KA_T *)malloc((MALLOC_S)len))) { + (void) fprintf(stderr, + "%s: can't allocate %d bytes for processor addresses\n", + Pn, len); + Exit(1); + } + if (kread(ka, (char *)pp, len)) { + if (!Fwarn) + (void) fprintf(stderr, + "%s: WARNING: can't read processor addresses: %s\n", + Pn, print_kptr(ka, (char *)NULL, 0)); + ncl = nchsz = ncpc = ncpus = 0; + return; + } + for (i = 0; i < ncpus; i++) { + if (pp[i]) + pp[i] = (KA_T)((char *)pp[i] + + offsetof(struct processor, namecache)); + } + /* + * Get the per-processor nchash size. + */ + ka = (KA_T)0; + if (get_Nl_value("nchsz", (struct drive_Nl *)NULL, &ka) < 0 + || !ka + || kread((KA_T)ka, (char *)&nchsz, sizeof(nchsz))) + { + if (!Fwarn) + (void) fprintf(stderr, + "%s: WARNING: processor nchash count address: %s\n", + Pn, print_kptr(ka, (char *)NULL, 0)); + ncl = nchsz = ncpc = ncpus = 0; + return; + } + if (nchsz < 1) { + if (!Fwarn) + (void) fprintf(stderr, + "%s: WARNING: bad per processor nchash count: %d\n", + Pn, nchsz); + nchsz = ncpus = 1; + return; + } + /* + * Allocate space for nchsz * NCHSIZE * ncpus namecache structures. + */ + ncpc = (int)(nchsz * NCHSIZE); + ncl = (int)(ncpc * sizeof(struct namecache)); + len = (int)(ncl * ncpus); + if (!(nc = (struct namecache *)malloc((MALLOC_S)len))) { + (void) fprintf(stderr, + "%s: no space for %d namecache entries (%d bytes)\n", + Pn, ncpc * ncpus, len); + Exit(1); + } + } else { + + /* + * Do setup for repeat calls. + */ + if (Nchash) { + for (i = 0; i <= Hmsk; i++) { + for (lp = Nchash[i]; lp; lp = lpnxt) { + lpnxt = lp->nxt; + (void) free((MALLOC_P *)lp); + } + } + (void) free((MALLOC_P *)Nchash); + Nchash = (struct l_nch **)NULL; + Nc = 0; + } + } +/* + * Loop through the processors, reading the processor structure pointer + * for the processor, then its name cache. Build a local name cache + * table of struct namecache entries for all processors. + */ + for (i = n = 0; i < ncpus; i++) { + if (!pp[i]) + continue; + if (kread(pp[i], (char *)&ncp, sizeof(ncp)) || !ncp) + continue; + if (kread(ncp, (char *)&nc[n], ncl)) + continue; + n += ncpc; + } +/* + * Compute a hash table size and allocate it. + */ + if (!n) + return; + for (i = 1; i < n; i <<= 1) + ; + i += i; + Hmsk = i - 1; + if (!(Nchash = (struct l_nch **)calloc(i, sizeof(struct l_nch *)))) { + if (!Fwarn) + (void) fprintf(stderr, + "%s: no space for %d byte name cache hash buckets\n", + Pn, (int)(i * sizeof(struct l_nch *))); + Exit(1); + } +/* + * Assign hash pointers to the accumulated namecache entries. + */ + for (i = Nc = 0; i < n; i++) { + if (!nc[i].nc_vpid) + continue; + if (((len = nc[i].nc_nlen) < 1) || (len > NCHNAMLEN)) + continue; + if (len < 3 && nc[i].nc_name[0] == '.') { + if ((len == 1) || ((len == 2) && (nc[i].nc_name[1] == '.'))) + continue; + } + h = ncachehash(nc[i].nc_vpid); + /* + * Look for an existing hash entry. Choose among duplicates the one + * with the largest nc_dvpid. + */ + for (lp = Nchash[h]; lp; lp = lp->nxt) { + if ((np = lp->nc) && (np->nc_vpid == nc[i].nc_vpid)) { + if (nc[i].nc_dvpid > np->nc_dvpid) + lp->nc = &nc[i]; + break; + } + } + if (lp) + continue; + /* + * Allocate and fill a new local name cache entry. + */ + if (!(lp = (struct l_nch *)malloc(sizeof(struct l_nch)))) { + (void) fprintf(stderr, "%s: can't allocate l_nch entry\n", Pn); + Exit(1); + } + lp->nc = &nc[i]; + lp->nxt = Nchash[h]; + Nchash[h] = lp; + Nc++; + } +} + + +/* + * ncache_lookup() - look up a node's name in the kernel's name cache + */ + +char * +ncache_lookup(buf, blen, fp) + 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; + struct namecache *nc; + 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 == 0 || !(lc = ncache_addr(Lf->id)) || !(nc = lc->nc)) { + + /* + * 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 = nc->nc_nlen) > (blen - 1)) + return((char *)NULL); + cp = buf + blen - nl - 1; + rlen = blen - nl - 1; + (void) strncpy(cp, nc->nc_name, nl); + cp[nl] = '\0'; +/* + * 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 (!nc->nc_dvpid) { + if (ncache_isroot((KA_T)nc->nc_vp, cp)) + *fp = 1; + break; + } + if (!(lc = ncache_addr(nc->nc_dvpid))) { + if (ncache_ckrootid((KA_T)nc->nc_vp, nc->nc_dvpid)) + *fp = 1; + break; + } + if (!(nc = lc->nc)) + break; + if (((nl = nc->nc_nlen) + 1) > rlen) + break; + *(cp - 1) = '/'; + cp--; + rlen--; + (void) strncpy(cp - nl, nc->nc_name, nl); + cp -= nl; + rlen -= nl; + } + return(cp); +} +#endif /* DUV>=50100 && defined(HASNCACHE) */ diff --git a/dialects/du/dproto.h b/dialects/du/dproto.h new file mode 100644 index 0000000..ebc1d8d --- /dev/null +++ b/dialects/du/dproto.h @@ -0,0 +1,61 @@ +/* + * dproto.h - DEC OSF/1, Digital UNIX, Tru64 UNIX 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.8 99/06/22 08:15:18 abe Exp $ + */ + + +_PROTOTYPE(extern void clr_flinfo,(void)); +_PROTOTYPE(extern char *get_nlist_path,(int ap)); +_PROTOTYPE(extern int is_file_named,(char *p, int cd)); +_PROTOTYPE(extern struct l_vfs *readvfs,(KA_T vm)); + +#if defined(HASDCACHE) +_PROTOTYPE(extern void clr_sect,(void)); +#endif /* defined(HASDCACHE) */ + +#if defined(HASIPv6) +_PROTOTYPE(extern struct hostent *gethostbyname2,(char *nm, int prot)); +#endif /* defined(HASIPv6) */ + +#if defined(HASPRIVNMCACHE) +_PROTOTYPE(extern int tag_to_path,(char *fs, mlBfTagT t2pb, int nl, char *nlb)); +#endif /* defined(HASPRIVNMCACHE) */ + +#if defined(USELOCALREADDIR) +_PROTOTYPE(extern int CloseDir,(DIR *dirp)); +_PROTOTYPE(extern DIR *OpenDir,(char *dir)); +_PROTOTYPE(extern struct DIRTYPE *ReadDir,(DIR *dirp)); +#endif /* defined(USELOCALREADDIR) */ diff --git a/dialects/du/dsock.c b/dialects/du/dsock.c new file mode 100644 index 0000000..94f4589 --- /dev/null +++ b/dialects/du/dsock.c @@ -0,0 +1,325 @@ +/* + * dsock.c - DEC OSF/1, Digital UNIX, Tru64 UNIX 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"; +static char *rcsid = "$Id: dsock.c,v 1.19 2005/08/08 19:56:44 abe Exp $"; +#endif + + +#include "lsof.h" + + +/* + * process_socket() - process socket + */ + +void +process_socket(sa) + KA_T sa; /* socket address in kernel */ +{ + struct domain d; + unsigned char *fa = (unsigned char *)NULL; + int fam; + int fp, lp; + struct inpcb inp; + KA_T ka; + unsigned char *la = (unsigned char *)NULL; + struct mbuf mb; + struct protosw p; + struct socket s; + struct tcpcb t; + struct unpcb uc, unp; + struct sockaddr_un *ua = NULL; + struct sockaddr_un un; + + (void) snpf(Lf->type, sizeof(Lf->type), "sock"); + Lf->inp_ty = 2; +/* + * Read the socket, protocol, and domain structures. + */ + if (!sa) { + enter_nm("no socket address"); + return; + } + if (kread(sa, (char *) &s, sizeof(s))) { + (void) snpf(Namech, Namechl, "can't read socket struct from %s", + print_kptr(sa, (char *)NULL, 0)); + enter_nm(Namech); + return; + } + if (!s.so_type) { + enter_nm("no socket type"); + return; + } + if (!s.so_proto + || kread((KA_T)s.so_proto, (char *)&p, sizeof(p))) { + (void) snpf(Namech, Namechl, "can't read protocol switch from %s", + print_kptr((KA_T)s.so_proto, (char *)NULL, 0)); + enter_nm(Namech); + return; + } + if (!p.pr_domain + || kread((KA_T)p.pr_domain, (char *)&d, sizeof(d))) { + (void) snpf(Namech, Namechl, "can't read domain struct from %s", + print_kptr((KA_T)p.pr_domain, (char *)NULL, 0)); + enter_nm(Namech); + return; + } +/* + * Save size information. + */ + if (Fsize) { + if (Lf->access == 'r') + Lf->sz = (SZOFFTYPE)s.so_rcv.sb_cc; + else if (Lf->access == 'w') + Lf->sz = (SZOFFTYPE)s.so_snd.sb_cc; + else + Lf->sz = (SZOFFTYPE)(s.so_rcv.sb_cc + s.so_snd.sb_cc); + Lf->sz_def = 1; + } else + Lf->off_def = 1; + +#if defined(HASTCPTPIQ) + Lf->lts.rq = s.so_rcv.sb_cc; + Lf->lts.sq = s.so_snd.sb_cc; + Lf->lts.rqs = Lf->lts.sqs = 1; +#endif /* defined(HASTCPTPIQ) */ + +#if defined(HASSOOPT) + Lf->lts.ltm = (unsigned int)s.so_linger; + 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: + (void) snpf(Lf->type, sizeof(Lf->type), + (fam == AF_INET) ? "IPv4" : "IPv6"); +#else /* !defined(HASIPv6) */ + (void) snpf(Lf->type, sizeof(Lf->type), "inet"); +#endif /* defined(HASIPv6) */ + + if (Fnet) { + if (!FnetTy + || ((FnetTy == 4) && (fam == AF_INET)) + +#if defined(HASIPv6) + || ((FnetTy == 6) && (fam == AF_INET6)) +#endif /* defined(HASIPv6) */ + ) + + Lf->sf |= SELNET; + } + printiproto(p.pr_protocol); + /* + * Read protocol control block. + */ + if (!s.so_pcb + || kread((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; + } + /* + * Print Internet socket information. + */ + ka = (KA_T)(inp.inp_ppcb ? inp.inp_ppcb : s.so_pcb); + enter_dev_ch(print_kptr((ka & 0xffffffff), (char *)NULL, 0)); + +#if defined(HASIPv6) + if ((fam == AF_INET && IN6_IS_ADDR_UNSPECIFIED(&inp.inp_laddr)) + || IN6_IS_ADDR_V4MAPPED(&inp.inp_laddr)) { + la = (unsigned char *)&IN6_EXTRACT_V4ADDR(&inp.inp_laddr); + fam = AF_INET; + } else { + la = (unsigned char *)&inp.inp_laddr; + fam = AF_INET6; + } +#else /* !defined(HASIPv6) */ + la = (unsigned char *)&inp.inp_laddr; +#endif /* defined(HASIPv6) */ + + lp = (int)ntohs(inp.inp_lport); + +#if defined(HASIPv6) + if (fam == AF_INET) { + if (inp.inp_fport + || IN6_EXTRACT_V4ADDR(&inp.inp_faddr) != INADDR_ANY) + { + fa = (unsigned char *)&IN6_EXTRACT_V4ADDR(&inp.inp_faddr); + fp = (int)ntohs(inp.inp_fport); + } + } else { + if (inp.inp_fport || !IN6_IS_ADDR_UNSPECIFIED(&inp.inp_faddr)) + { + fa = (unsigned char *)&inp.inp_faddr; + fp = (int)ntohs(inp.inp_fport); + } + } +#else /* !defined(HASIPv6) */ + if (inp.inp_faddr.s_addr != INADDR_ANY || inp.inp_fport != 0) { + fa = (unsigned char *)&inp.inp_faddr; + fp = (int)ntohs(inp.inp_fport); + } +#endif /* defined(HASIPv6) */ + + if (fa || la) + (void) ent_inaddr(la, lp, fa, fp, fam); + if (p.pr_protocol == IPPROTO_TCP && inp.inp_ppcb + && !kread((KA_T)inp.inp_ppcb, (char *)&t, sizeof(t))) { + Lf->lts.type = 0; + Lf->lts.state.i = (int)t.t_state; + +#if defined(HASSOOPT) + Lf->lts.kai = (unsigned int)t.t_timer[TCPT_KEEP]; +#endif /* defined(HASSOOPT) */ + +#if defined(HASTCPOPT) + Lf->lts.mss = (unsigned long)t.t_maxseg; + Lf->lts.msss = (unsigned char)1; + Lf->lts.topt = (unsigned int)t.t_flags; +#endif /* defined(HASTCPOPT) */ + + } + break; +/* + * Process a ROUTE domain socket. + */ + case AF_ROUTE: + (void) snpf(Lf->type, sizeof(Lf->type), "rte"); + if (s.so_pcb) { + ka = (KA_T)(s.so_pcb); + enter_dev_ch(print_kptr((ka & 0xffffffff), (char *)NULL, 0)); + } else + (void) snpf(Namech, Namechl, "no protocol control block"); + if (!Fsize) + Lf->off_def = 1; + break; +/* + * Process a Unix domain socket. + */ + case AF_UNIX: + if (Funix) + Lf->sf |= SELUNX; + (void) snpf(Lf->type, sizeof(Lf->type), "unix"); + /* + * Read Unix protocol control block and the Unix address structure. + */ + enter_dev_ch(print_kptr((sa & 0xffffffff), (char *)NULL, 0)); + if (kread((KA_T) s.so_pcb, (char *) &unp, sizeof(unp))) { + (void) snpf(Namech, Namechl, "can't read unpcb at %s", + print_kptr((KA_T)s.so_pcb, (char *)NULL, 0)); + break; + } + if ((struct socket *)sa != unp.unp_socket) { + (void) snpf(Namech, Namechl, "unp_socket (%s) mismatch", + print_kptr((KA_T)unp.unp_socket, (char *)NULL, 0)); + break; + } + if (unp.unp_addr) { + if (kread((KA_T) unp.unp_addr, (char *) &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_hdr.mh_data - (caddr_t)unp.unp_addr)); + ua->sun_family = AF_UNIX; + } + if (!ua) { + ua = &un; + (void) zeromem((char *)ua, sizeof(un)); + ua->sun_family = AF_UNSPEC; + } + /* + * Print information on Unix socket that has no address bound + * to it, although it may be connected to another Unix domain + * socket as a pipe. + */ + if (ua->sun_family != AF_UNIX) { + if (ua->sun_family == AF_UNSPEC) { + if (unp.unp_conn) { + if (kread((KA_T)unp.unp_conn, (char *)&uc, sizeof(uc))) + (void) snpf(Namech, Namechl, + "can't read unp_conn at %s", + print_kptr((KA_T)unp.unp_conn,(char *)NULL,0)); + else { + ka = (KA_T)uc.unp_socket; + (void) snpf(Namech, Namechl, "->%s", + print_kptr((ka & 0xffffffff), (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 (mb.m_len >= sizeof(struct sockaddr_un)) + mb.m_len = sizeof(struct sockaddr_un) - 1; + *((char *)ua + mb.m_len) = '\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); +} diff --git a/dialects/du/dstore.c b/dialects/du/dstore.c new file mode 100644 index 0000000..7edea3b --- /dev/null +++ b/dialects/du/dstore.c @@ -0,0 +1,162 @@ +/* + * dstore.c - DEC OSF/1, Digital UNIX, Tru64 UNIX 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"; +static char *rcsid = "$Id: dstore.c,v 1.10 2000/08/09 20:06:50 abe Exp $"; +#endif + + +#include "lsof.h" + + +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[] = { + { "cldev", "clonedev" }, + { "fids", "fids" }, + { "msfsubc", "msfs_ubcops" }, + +#if DUV>=50100 + { "advfsvfs", "msfs_vfsops" }, + { "cdfsvfs", "cdfs_vfsops" }, + { "dvdfsvfs", "dvdfs_vfsops" }, + { "fdfsvfs", "fdfs_vfsops" }, + { "fsfsrvp", "fdfs_root_directory" }, + { "nchsz", "nchsz" }, + { "ncpus", "ncpus" }, + { "nfsvfs", "nfs_vfsops" }, + { "nfs3vfs", "nfs3_vfsops" }, + { "procptr", "processor_ptr" }, + { "ufsvfs", "ufs_vfsops" }, +#else /* DUV<50100 */ + { X_NCACHE, "namecache" }, + { X_NCSIZE, "nchsize" }, +#endif /* DUV>=50100 */ + + { "vnmaxp", "vn_maxprivate" }, + +#if DUV<30000 + { "proc", "proc" }, + { "nproc", "nproc" }, +#else /* DUV>=30000 */ + { "npid", "npid" }, + { "pidt", "pidtab" }, +#endif /* DUV<30000 */ + + { "", "", }, + { NULL, NULL, } +}; + +struct file *Fileptr; /* for process_file() in lib/prfp.c */ +int HaveCloneMaj = 0; /* status of CloneMaj */ +int Kd = -1; +struct l_vfs *Lvfs = NULL; + +# if DUV>=30000 +KA_T *Pa = NULL; /* kernel proc structure addresses */ +# endif /* DUV>=30000 */ + +#if defined(HASFSTRUCT) +/* + * Pff_tab[] - table for printing file flags + */ + +struct pff_tab Pff_tab[] = { + { (long)FREAD, FF_READ }, + { (long)FWRITE, FF_WRITE }, + { (long)FNONBLOCK, FF_NBLOCK }, + { (long)FNDELAY, FF_NDELAY }, + { (long)FAPPEND, FF_APPEND }, + { (long)FASYNC, FF_ASYNC }, + { (long)FMARK, FF_MARK }, + { (long)FDEFER, FF_DEFER }, + { (long)FSHLOCK, FF_SHLOCK }, + { (long)FEXLOCK, FF_EXLOCK }, + +# if defined(FKERNEL) + { (long)FKERNEL, FF_KERNEL }, +# endif /* defined(FKERNEL) */ + +# if defined(FKERNEL) + { (long)FVTEXT, FF_VTEXT }, +# endif /* defined(FVTEXT) */ + +# if defined(FSYNC) + { (long)FSYNC, FF_SYNC }, +# endif /* defined(FSYNC) */ + +# if defined(FDSYNC) + { (long)FDSYNC, FF_DSYNC }, +# endif /* defined(FDSYNC) */ + +# if defined(FRSYNC) + { (long)FRSYNC, FF_RSYNC }, +# endif /* defined(FRSYNC) */ + + { (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 /* !defined(UF_EXCLOSE) */ + { (long)1, POF_CLOEXEC }, +# endif /* defined(UF_EXCLOSE) */ + +# if defined(UF_MAPPED) + { (long)UF_MAPPED, POF_MAPPED }, +# endif /* defined(UF_MAPPED) */ + +# if defined(UF_RESERVED_WAIT) + { (long)UF_RESERVED_WAIT, POF_RSVWT }, +# endif /* defined(UF_RESERVED_WAIT) */ + + { (long)0, NULL } +}; +#endif /* defined(HASFSTRUCT) */ + +struct proc *Ps = NULL; /* local proc structures */ +int Psn = 0; /* entries in Paddr[] and Ps[] */ +int Vnmxp; /* vnode's max private area length */ diff --git a/dialects/du/machine.h b/dialects/du/machine.h new file mode 100644 index 0000000..a7f92ac --- /dev/null +++ b/dialects/du/machine.h @@ -0,0 +1,647 @@ +/* + * machine.h - DEC OSF/1, Digital UNIX, Tru64 UNIX 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:02:47 abe Exp $ + */ + + +#if !defined(LSOF_MACHINE_H) +#define LSOF_MACHINE_H 1 + + +#include + +#define _KERNEL 1 +#include + +#if DUV>=50000 +#include +#include +#endif /* DUV>=50000 */ + +#undef _KERNEL + +#include + + +/* + * 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 DUV>=40000 +#define CAN_USE_CLNT_CREATE 1 +#endif /* DUV>=40000 */ + + +/* + * 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 option. + */ + +/* #define HASAOPT 1 */ + + +/* + * HASBLKDEV is defined for those dialects that want block device information + * recorded in BDevtp[]. + * + * NOWARNBLKDEV suppresses warnings about no block devices for Tru64 UNIX 5.0 + * and above. + */ + +#define HASBLKDEV 1 + +#if DUV>=50000 +#define NOWARNBLKDEV 1 +#endif /* DUV>=50000 */ + + +/* + * 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. + */ + +#if defined(HASTAGTOPATH) +#define HASLFILEADD int advfs_seq; unsigned char advfs_seq_stat; +/* #define CLRLFILEADD(lf) (lf)->... = (type)NULL; */ +#define SETLFILEADD Lf->advfs_seq_stat = 0; +#endif /* defined(HASTAGTOPATH) */ + + +/* + * HASMNTSTAT indicates the dialect supports the mount stat(2) result option + * in its l_vfs and mounts structures. + */ + +/* #define HASMNTSTAT 1 */ + + +/* + * HASMNTSUP is defined for those dialects that support the mount supplement + * option. + */ + +/* #define HASMNTSUP 1 */ + + +/* + * HASMOPT is defined for those dialects that support the reading of + * kernel memory from an alternate file. + */ + +#define HASMOPT 1 + + +/* + * HASNCACHE is defined for those dialects that have a kernel name cache + * that lsof can search. A value of 1 directs printname() to prefix the + * cache value with the file system directory name; 2, avoid the prefix. + * + * NCACHELDPFX is a set of C commands to execute before calling ncache_load(). + * + * NCACHELDSFX is a set of C commands to execute after calling ncache_load(). + */ + +#define HASNCACHE 1 +/* #define NCACHELDPFX ??? */ +/* #define NCACHELDSFX ??? */ + + +/* + * HASNLIST is defined for those dialects that use nlist() to acccess + kernel symbols. + */ + +#define HASNLIST 1 + + +/* + * HASPIPEFN is defined for those dialects that have a special function to + * process DTYPE_PIPE file structure entries. Its value is the name of the + * function. + * + * NOTE: don't forget to define a prototype for this function in dproto.h. + */ + +/* #define HASPIPEFN process_pipe? */ + + +/* + * HASPIPENODE is defined for those dialects that have pipe nodes. + */ + +/* #define HASPIPENODE 1 */ + + +/* + * HASPMAPENABLED is defined when the reporting of portmapper registration + * info is enabled by default. + */ + +/* #define HASPMAPENABLED 1 */ + + +/* + * HASPPID is defined for those dialects that support identification of + * the parent process IDentifier (PPID) of a process. + */ + +#define HASPPID 1 + + +/* + * HASPRINTDEV, HASPRINTINO, HASPRINTNM, HASPRINTOFF, and HASPRINTSZ + * define private dialect-specific functions for printing DEVice numbers, + * INOde numbers, NaMes, file OFFsets, and file SiZes. The functions are + * called from print_file(). + */ + +#define HASPRINTDEV print_dev +/* #define HASPRINTINO print_ino? */ +/* #define HASPRINTNM print_nm? */ +/* #define HASPRINTOFF print_off? */ +/* #define HASPRINTSZ print_sz? */ + + +/* + * HASPRIVFILETYPE and PRIVFILETYPE are defined for dialects that have a + * file structure type that isn't defined by a DTYPE_* symbol. They are + * used in lib/prfp.c to select the type's processing. + * + * PRIVFILETYPE is the definition of the f_type value in the file struct. + * + * HASPRIVFILETYPE is the name of the processing function. + */ + +/* #define HASPRIVFILETYPE process_shmf? */ +/* #define PRIVFILETYPE ?? */ + + +/* + * HASPRIVNMCACHE is defined for dialects that have a private method for + * printing cached NAME column values for some files. HASPRIVNAMECACHE + * is defined to be the name of the function. + * + * The function takes one argument, a struct lfile pointer to the file, and + * returns non-zero if it prints a name to stdout. + */ + +#if defined(HASTAGTOPATH) +#define HASPRIVNMCACHE print_advfs_path +#endif /* defined(HASTAGTOPATH) */ + + +/* + * 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 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 DUV>=40000 +#define HASWIDECHAR 1 +# endif /* DUV>=40000 */ + +/* #define WIDECHARINCL */ + + +/* + * 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. + * + * Even though Digital UNIX has vnodes, we don't define HASVNODE, because + * private vnode processing is required. (See the readvnode() function + * in dnode.c.) + */ + +/* #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_ is defined for dialects that use the + * in the lsof library. + * + * Note: other definitions and operations may be required to condition the + * library function source code. They may be found in the dialect dlsof.h + * header files. + */ + +#define USE_LIB_CKKV 1 /* ckkv.c */ +/* #define USE_LIB_COMPLETEVFS 1 cvfs.c */ +#define USE_LIB_FIND_CH_INO 1 /* fino.c */ +#define USE_LIB_IS_FILE_NAMED 1 /* isfn.c */ +#define USE_LIB_LKUPDEV 1 /* lkud.c */ +/* #define USE_LIB_PRINTDEVNAME 1 pdvn.c */ +#define USE_LIB_PROCESS_FILE 1 /* prfp.c */ +#define USE_LIB_PRINT_TCPTPI 1 /* ptti.c */ +/* #define USE_LIB_READDEV 1 rdev.c */ +/* #define USE_LIB_READMNT 1 rmnt.c */ +/* #define USE_LIB_REGEX 1 regex.c */ + +# if DUV<50100 +#define USE_LIB_RNAM 1 /* rnam.c */ +# else /* DUV>=50100 */ +/* Tru64 UNIX 5.1 and above have private name cache functions -- see + * ./dproc.c */ +# endif /* DUV<50100 */ + +/* #define USE_LIB_RNCH 1 rnch.c */ +/* #define USE_LIB_RNMH 1 rnmh.c */ + +# if DUV<50000 +#define USE_LIB_SNPF 1 /* snpf.c */ +# else /* DUV>=50000 */ +#define snpf snprintf /* use the system's snprintf() */ +# endif /* DUV<50000 */ + + +/* + * 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/dialects/freebsd/Makefile b/dialects/freebsd/Makefile new file mode 100644 index 0000000..632bc06 --- /dev/null +++ b/dialects/freebsd/Makefile @@ -0,0 +1,162 @@ + +# FreeBSD Makefile remainder +# +# $Id: Makefile,v 1.12 2009/03/25 19:23:06 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 dzfs.h + +SRC= 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= 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 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 $${MAN} $${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/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_CCDATE "'`date`'"' >> 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 + +dnode2.o: dzfs.h dnode2.c + @if [ -f ./Makefile.zfs ]; then \ + ${MAKE} -f Makefile.zfs dnode2.o; \ + else \ + echo "${CC} ${CFLAGS} -c dnode2.c"; \ + ${CC} ${CFLAGS} -c dnode2.c; \ + fi; + +dproc.o: ${HDR} dproc.c + +dsock.o: ${HDR} dsock.c + +dstore.o: ${HDR} dstore.c + +arg.o: ${HDR} arg.c + +main.o: ${HDR} main.c + +misc.o: ${HDR} misc.c + +node.o: ${HDR} node.c + +print.o: ${HDR} print.c + +proc.o: ${HDR} proc.c + +store.o: ${HDR} store.c + +usage.o: ${HDR} version.h usage.c + +util.o: ${HDR} util.c + +# *** Do not add anything here - It will go away. *** diff --git a/dialects/freebsd/Makefile.zfs b/dialects/freebsd/Makefile.zfs new file mode 100644 index 0000000..bc473e9 --- /dev/null +++ b/dialects/freebsd/Makefile.zfs @@ -0,0 +1,17 @@ + +# Makefile.zfs -- FreeBSD Makefile remainder for ZFS modules +# +# $Id: Makefile.zfs,v 1.3 2011/08/07 22:51:28 abe Exp $ + +CFLAGS+=-D_SOLARIS_C_SOURCE +CFLAGS+=${DEBUG} +CFLAGS+=-I${OPENSOLARIS}/compat/opensolaris +CFLAGS+=-I${OPENSOLARIS}/contrib/opensolaris/uts/common/fs/zfs +CFLAGS+=-I${OPENSOLARIS}/contrib/opensolaris/uts/common/zmod +CFLAGS+=-I${OPENSOLARIS}/contrib/opensolaris/uts/common +CFLAGS+=-I${OPENSOLARIS}/contrib/opensolaris/common/zfs +CFLAGS+=-I${OPENSOLARIS}/contrib/opensolaris/common +CFLAGS+=-I${.CURDIR}/usr/src/include +CFLAGS+=-I`pwd` + +dnode2.o: dzfs.h dnode2.c diff --git a/dialects/freebsd/Mksrc b/dialects/freebsd/Mksrc new file mode 100755 index 0000000..c0745ae --- /dev/null +++ b/dialects/freebsd/Mksrc @@ -0,0 +1,29 @@ +#!/bin/sh +# +# Mksrc - make FreeBSD 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 2008/04/15 13:31:47 abe Exp $ + + +D=dialects/freebsd +L="dlsof.h dmnt.c dnode.c dnode1.c dnode2.c dproc.c dproto.h dsock.c dstore.c dzfs.h machine.h" + +for i in $L +do + rm -f $i + $LSOF_MKC $D/$i $i + echo "$LSOF_MKC $D/$i $i" +done + +# For ZFS + +rm -f vnode_if.h +touch vnode_if.h diff --git a/dialects/freebsd/X b/dialects/freebsd/X new file mode 100644 index 0000000..ae06101 --- /dev/null +++ b/dialects/freebsd/X @@ -0,0 +1,7 @@ +#undef bcmp /* avoid _KERNEL conflict */ +#undef bcopy /* avoid _KERNEL conflict */ +#undef bzero /* avoid _KERNEL conflict */ +#undef memcmp /* avoid _KERNEL conflict */ +#undef memcpy /* avoid _KERNEL conflict */ +#undef memmove /* avoid _KERNEL conflict */ +#undef memset /* avoid _KERNEL conflict */ diff --git a/dialects/freebsd/dlsof.h b/dialects/freebsd/dlsof.h new file mode 100644 index 0000000..606a6de --- /dev/null +++ b/dialects/freebsd/dlsof.h @@ -0,0 +1,705 @@ +/* + * dlsof.h - FreeBSD 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.49 2018/07/14 12:14:55 abe Exp $ + */ + + +#if !defined(FREEBSD_LSOF_H) +#define FREEBSD_LSOF_H 1 + +#include +#include +#include +#include +#include +#include + +# if FREEBSDV>=4000 +# if FREEBSDV>=5000 +# if FREEBSDV<6020 +# if defined(__alpha__) +/* + * For Alpha below 6.2, #include before #define'ing _KERNEL. + * Then #define PCPU_MD_FIELDS independently. This hack avoids a compiler + * complaint about register use. + */ + +#include +#define PCPU_MD_FIELDS \ + struct alpha_pcb pc_idlepcb; /* pcb for idling */ \ + u_int64_t pc_idlepcbphys; /* pa of pc_idlepcb */ \ + u_int64_t pc_pending_ipis; /* pending IPI's */ \ + u_int32_t pc_next_asn; /* next ASN to alloc */ \ + u_int32_t pc_current_asngen /* ASN rollover check */ +# endif /* defined(__alpha__) */ +# endif /* FREEBSDV<6020 */ +#define _KERNEL 1 +# endif /* FREEBSDV>=5000 */ + +# if defined(HAS_VM_MEMATTR_T) +/* + * The d_mmap2_t function typedef in may need the definition + * of vm_memattr_t for a pointer, but that definition is only available + * under _KERNEL in . Defining _KERNEL before including + * causes many compilation problems, so this expediency + * (hack) is used when the vm_memattr_t definition is needed. + */ +#define vm_memattr_t void +# endif /* defined(HAS_VM_MEMATTR_T) */ + +# if defined(NEEDS_BOOLEAN_T) +/* + * In FreeBSD 9 and above the boolean_t typedef is also needed and is also + * under _KERNEL in . + */ + +#define boolean_t int +# endif /* defined(NEEDS_BOOLEAN_T) */ + +# if defined(NEEDS_DEVICE_T) +/* + * In FreeBSD 12 and it needs + * the device_t typedef. + */ +typedef struct device *device_t; +#endif /* defined(NEEDS_DEVICE_T) */ + +/* + * Define KLD_MODULE to avoid the error "ARM_NMMUS is 0" from ARM's + * . + */ + +#define KLD_MODULE + + +#include + +# if defined(HAS_VM_MEMATTR_T) +#undef vm_memattr_t +# endif /* defined(HAS_VM_MEMATTR_T) */ + +# if defined(NEEDS_BOOLEAN_T) +#undef boolean_t +# endif /* defined(NEEDS_BOOLEAN_T) */ + +# if defined(HAS_CONF_MINOR) +#undef minor +#include "fbsd_minor.h" +# endif /* defined(HAS_CONF_MINOR) */ + +# if FREEBSDV>=5000 +#undef _KERNEL +# endif /* FREEBSDV>=5000 */ +# endif /* FREEBSDV>=4000 */ + +#include +#include +#define NFS +#define m_stat mnt_stat + +# if FREEBSDV>=3020 +#define _KERNEL +# endif /* FREEBSDV>=3020 */ + +#include + +# if FREEBSDV>=3020 +# if defined(__clang__) +/* + * This definition is needed when clang is used, because must + * be #include'd when _KERNEL is defined and that causes the getmntinfo() + * function prototype to be skipped. + */ +int getmntinfo(struct statfs **, int); +# endif /* defined(__clang__) */ + +#undef _KERNEL +# endif /* FREEBSDV>=3020 */ + +#include +#include +#include +#define _WANT_SOCKET +#include +#include +#define _WANT_UNPCB +#include + +# if FREEBSDV>=3000 +#undef INADDR_LOOPBACK +# endif /* FREEBSDV>=3000 */ + +#include +#include +#include +#include +#define _WANT_INPCB /* for FreeBSD 12 and above */ +#include +#include +#include +#include +#include +#include +#define _WANT_TCPCB /* for FreeBSD 12 and above */ +#include +#include +#include + +# if defined(HAS_KVM_VNODE) +#define _KVM_VNODE +# endif /* defined(HAS_KVM_VNODE) */ +#include +# if defined(HAS_KVM_VNODE) +#undef _KVM_VNODE +# endif /* defined(HAS_KVM_VNODE) */ + +#include +#include +#define pmap RPC_pmap +#include +#include +#undef pmap + +# if FREEBSDV<2000 +#include +#include +#include +#include +# else /* FREEBSDV>=2000 */ +#include +#include + +# if FREEBSDV>=4000 && FREEBSDV<5000 +# if defined(__alpha__) || defined(__sparc64__) +#define dev_t void * +# endif /* defined(__alpha__) || defined(__sparc64__) */ +# endif /* FREEBSDV>=4000 && FREEBSDV<5000 */ + +#include + +# if defined(HAS_UFS1_2) +#define _KERNEL +struct vop_getextattr_args; +struct vop_deleteextattr_args; +struct vop_setextattr_args; +#include +#define psignal LSOF_psignal +#define panicstr bp + +# if defined(__clang__) +/* + * Two clang work-arounds... + */ +#define KASSERT(exp,msg) do {} while (0) +#include +# endif /* defined(__clang__) */ + +#include + +# if defined(__clang__) +/* + * Undo the clang work-arounds. + */ +#undef KASSERT +# endif /* defined(__clang__) */ + +#undef psignal +#undef panicstr +#undef _KERNEL +# endif /* defined(HAS_UFS1_2) */ + +# if FREEBSDV>=5010 +#undef i_devvp +# endif /* FREEBSDV>=5010 */ + +# if FREEBSDV>=4000 && FREEBSDV<5000 +# if defined(__alpha__) || defined(__sparc64__) +#undef dev_t +# endif /* defined(__alpha__) || defined(__sparc64__) */ +# endif /* FREEBSDV>=4000 && FREEBSDV<5000 */ + +# if FREEBSDV<2020 +#include +# endif /* FREEBSDV<2020 */ + +# endif /* FREEBSDV<2000 */ + +# if FREEBSDV<5000 +#include +# else /* FREEBSDV>=5000 */ +#include +# endif /* FREEBSDV<5000 */ + +# if defined(HASRPCV2H) +#include +# endif /* defined(HASRPCV2H) */ + +# if FREEBSDV>=5000 +#include +#include +# else /* FREEBSDV<5000 */ +#include +#include +# endif /* FREEBSDV>=5000 */ + +#include +#include +#undef TRUE +#undef FALSE + +# if FREEBSDV<2000 +#include +# else /* FREEBSDV>=2000 */ +#include +# endif /* FREEBSDV<2000 */ + +# if defined(HASFDESCFS) +#define _KERNEL +#define KERNEL +# if FREEBSDV>=5000 +#include +# else /* FREEBSDV<5000 */ +#include +# endif /* FREEBSDV>=5000 */ +#undef _KERNEL +#undef KERNEL +# endif /* defined(HASFDESCFS) */ + +# if defined(HASNULLFS) +#define _KERNEL +#define KERNEL +struct vop_generic_args; +# if FREEBSDV>=5000 +#include +# else /* FREEBSDV<5000 */ +#include +# endif /* FREEBSDV>=5000 */ +#undef _KERNEL +#undef KERNEL +# endif /* defined(HASNULLFS) */ + +# if defined(HASPROCFS) +# if FREEBSDV<2000 +#include +# else /* FREEBSDV>=2000 */ +# if FREEBSDV<5000 +#include +# endif /* FREEBSDV<5000 */ +#include +# endif /* FREEBSDV<2000 */ + +#define PNSIZ 5 +# endif /* defined(HASPROCFS) */ + +# if defined(HASPSEUDOFS) +#include +# endif /* defined(HASPSEUDOFS) */ + +# if defined(HAS_ZFS) +#include "dzfs.h" +# endif /* defined(HAS_ZFS) */ + + +# if FREEBSDV<2000 +#define P_COMM p_comm +#define P_FD p_fd +#define P_PID p_pid +#define P_PGID p_pgrp +#define P_STAT p_stat +#define P_VMSPACE p_vmspace +# else /* FREEBSDV>=2000 */ +# if FREEBSDV<5000 +#define P_ADDR kp_eproc.e_paddr +#define P_COMM kp_proc.p_comm +#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_VMSPACE kp_proc.p_vmspace +# else /* FREEBSDV>=5000 */ +#define P_ADDR ki_paddr +#define P_COMM ki_comm +#define P_FD ki_fd +#define P_PID ki_pid +#define P_PGID ki_pgid +#define P_PPID ki_ppid +#define P_STAT ki_stat +#define P_VMSPACE ki_vmspace +# endif /* FREEBSDV<5000 */ +# endif /* FREEBSDV<2000 */ + +#include + +#define _KERNEL +#define KERNEL +#include + +/* + * The following circumventions were first needed in FreeBSD 8.0-CURRENT some + * time in August 2008 to avoid conflicts in /usr/src/sys/sys/libkern.h> and + * /usr/src/sys/sys/systm.h, called by or the header files it + * #include's when KERNEL or _KERNEL is #define'd. + * + * The circumventions may be needed or may be erroneous for earlier FreeBSD + * versions where testing was not possible. + */ + +# if defined(__clang__) +/* + * This work-around is needed when using clang, because must + * be #include'd under KERNEL and that causes the open() function prototype + * definition to be skipped. + */ +int open(const char *, int, ...); +# endif /* defined(__clang__) */ + +#define intrmask_t int +#define log log_kernel_lsof + +# if !defined(HAS_PAUSE_SBT) +#define pause pause_kernel_lsof +# endif /* !defined(HAS_PAUSE_SBT) */ + +#define asprintf asprintf_kernel_lsof +#define setenv setenv_kernel_lsof +#define vasprintf vasprintf_kernel_lsof +#define uintfptr_t int +#define _SYS_LIBKERN_H_ +#include + +/* + * Attempt to remove the circumventions. + */ + +#undef _SYS_LIBKERN_H_ +#undef asprintf_kernel_lsof +#undef intrmask_t_lsof +#undef log_kernel_lsof + +# if !defined(HAS_PAUSE_SBT) +#undef pause_kernel_lsof +# endif /* !defined(HAS_PAUSE_SBT) */ + +#undef setenv_kernel_lsof +#undef vasprintf_kernel_lsof +#undef uintfptr_t +#undef _KERNEL +#undef KERNEL + +# if defined(DTYPE_KQUEUE) +#define HASKQUEUE /* has the kqueue file type */ +# if FREEBSDV>=4090 +#define _KERNEL +# endif /* FREEBSDV>=4090 */ +#include +# if FREEBSDV>=4090 +#undef _KERNEL +# endif /* FREEBSDV>=4090 */ +# endif /* defined(DTYPE_KQUEUE) */ + +# if FREEBSDV<2000 +#include +# else /* FREEBSDV>=2000 */ +struct vop_advlock_args { int dummy; }; /* to pacify lf_advlock() prototype */ +# if FREEBSDV>=5000 +#undef MALLOC_DECLARE +#define MALLOC_DECLARE(type) extern struct malloc_type type[1] + /* to pacify */ +#define _KERNEL + +# if defined(HAS_SYS_SX_H) +#include +# endif /* defined(HAS_SYS_SX_H) */ + +# if defined(HAS_SI_PRIV) || defined(HAS_CONF_MINOR) || defined(HAS_CDEV2PRIV) +#include +# endif /* defined(SI_PRIV) || defined(HAS_CONF_MINOR) || defined(HAS_CDEV2PRIV) */ + +#include +#undef _KERNEL +# endif /* FREEBSDV>=5000 */ +#include +# endif /* FREEBSDV<2000 */ + +# if FREEBSDV>=2020 +# if FREEBSDV>=4090 +#define _KERNEL +# endif /* FREEBSDV>=4090 */ +#include +# if FREEBSDV>=4090 +#undef _KERNEL +# endif /* FREEBSDV>=4090 */ +# if defined(HASVMLOCKH) +#include +# endif /* defined(HASVMLOCKH) */ +#include +# endif /* FREEBSDV>=2020 */ + +#include + +/* + * Compensate for removal of MAP_ENTRY_IS_A_MAP from , + * This work-around was supplied by John Polstra . + */ + +# if defined(MAP_ENTRY_IS_SUB_MAP) && !defined(MAP_ENTRY_IS_A_MAP) +#define MAP_ENTRY_IS_A_MAP 0 +# endif /* defined(MAP_ENTRY_IS_SUB_MAP) && !defined(MAP_ENTRY_IS_A_MAP) */ + +#include +#include + +# if FREEBSDV>=2020 +#undef B_NEEDCOMMIT + +# if FREEBSDV>=5000 +#include +# endif /* FREEBSDV>=5000 */ + +#include +#include + +# if FREEBSDV<5000 +#include +# endif /* FREEBSDV<5000 */ +# endif /* FREEBSDV>=2020 */ + +#undef bcmp /* avoid _KERNEL conflict */ +#undef bcopy /* avoid _KERNEL conflict */ +#undef bzero /* avoid _KERNEL conflict */ +#undef memcmp /* avoid _KERNEL conflict */ +#undef memcpy /* avoid _KERNEL conflict */ +#undef memmove /* avoid _KERNEL conflict */ +#undef memset /* avoid _KERNEL conflict */ +#include + + +#define COMP_P const void +#define DEVINCR 1024 /* device table malloc() increment */ + +# if !defined(FREEBSD_KA_T) +# if FREEBSDV<2000 +typedef off_t KA_T; +# else /* FREEBSDV>=2000 */ +typedef u_long KA_T; +# endif /* FREEBSDV<2000 */ +# endif /* !defined(FREEBSD_KA_T) */ + +#define KMEM "/dev/kmem" +#define MALLOC_P void +#define FREE_P MALLOC_P +#define MALLOC_S size_t +#define MAXSYSCMDL MAXCOMLEN /* max system command name length */ + +# 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 + +# if !defined(READLEN_T) +#define READLEN_T int +# endif /* !defined(READLEN_T) */ + +#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 file * Cfp; + +# if FREEBSDV>=2000 +extern kvm_t *Kd; +# endif /* FREEBSDV>=2000 */ + +# if defined(P_ADDR) +extern KA_T Kpa; +# endif /* defined(P_ADDR) */ + +struct l_vfs { + KA_T addr; /* kernel address */ + fsid_t fsid; /* file system ID */ + +# if defined(MOUNT_NONE) + short type; /* type of file system */ +# else /* !defined(MOUNT_NONE) */ + char *typnm; /* file system type name */ +# endif /* defined(MOUNT_NONE) */ + + char *dir; /* mounted directory */ + char *fsname; /* file system name */ + struct l_vfs *next; /* forward link */ +}; +extern struct l_vfs *Lvfs; + +struct mounts { + char *dir; /* directory (mounted on) */ + char *fsname; /* file system + * (symbolic links unresolved) */ + char *fsnmres; /* file system + * (symbolic links resolved) */ + dev_t dev; /* directory st_dev */ + dev_t rdev; /* directory st_rdev */ + INODETYPE inode; /* directory st_ino */ + mode_t mode; /* directory st_mode */ + mode_t fs_mode; /* file system st_mode */ + struct mounts *next; /* forward link */ +}; + +#define X_BADFILEOPS "badfileops" +extern KA_T X_bfopsa; +#define X_NCACHE "ncache" +#define X_NCSIZE "ncsize" +#define NL_NAME n_name + +extern int Np; /* number of kernel processes */ + +# if FREEBSDV>=2000 +extern struct kinfo_proc *P; /* local process table copy */ +# endif /* FREEBSDV>=2000 */ + +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 FREEBSDV==4100 || FREEBSDV==4110 +#define XDR_VOID (xdrproc_t)xdr_void +#define XDR_PMAPLIST (xdrproc_t)xdr_pmaplist +# endif /* FREEBSDV==4100 || FREEBSDV==4110 */ + +# if FREEBSDV>=5000 +#define XDR_VOID (const xdrproc_t)xdr_void +#define XDR_PMAPLIST (const xdrproc_t)xdr_pmaplist +# endif /* FREEBSDV>=5000 */ + + +/* + * 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) +#include +# if FREEBSDV<4000 || (FREEBSDV>=4000 && defined(HASNAMECACHE)) +#include +# else /* FREEBSDV>=4000 && !defined(HASNAMECACHE) */ +/* + * The namecache struct definition should come from a header file that + * can be #include'd, but it has been moved to a kernel source file in + * 4.0-current for some reason unclear to me. + * + * So we must take the risk of defining it here. !!!! DANGER !!!! + */ + +struct namecache { + LIST_ENTRY(namecache) nc_hash; /* hash chain */ + LIST_ENTRY(namecache) nc_src; /* source vnode list */ + TAILQ_ENTRY(namecache) nc_dst; /* destination vnode list */ + struct vnode *nc_dvp; /* vnode of parent of name */ + struct vnode *nc_vp; /* vnode the name refers to */ + u_char nc_flag; /* flag bits */ + u_char nc_nlen; /* length of name */ + char nc_name[16]; /* segment name -- Strictly composed, + * the size of nc_name[] should be zero + * and rnmh.c in lsof/lib should read + * the name with a separate call to + * kvm_read(). Since that causes extra + * (and slow) calls to kvm_read(), the + * size is set here to an experimentally + * derived guess. The same experiment + * didn't reveal any extra kvm_read() + * suggesting the guess is a safe one. + * (VAA, 10 Apr 2002) */ +}; +# endif /* FREEBSDV<4000 || (FREEBSDV>=4000 && defined(HASNAMECACHE)) */ + +#define NCACHE namecache /* kernel's structure name */ +#define NCACHE_NM nc_name /* name in NCACHE */ +#define NCACHE_NMLEN nc_nlen /* name length in NCACHE */ + +# if FREEBSDV<2005 +#define NCACHE_NXT nc_nxt /* link in NCACHE */ +# else /* FREEBSDV>=2005 */ +# if FREEBSDV<2010 +#define NCACHE_NXT nc_lru.tqe_next /* link in NCACHE */ +# else /* FREEBSDV>=2010 */ +#include +#define NCACHE_NXT nc_hash.le_next /* link in NCACHE */ +# endif /* FREEBSDV<2010 */ +# endif /* FREEBSDV<2005 */ + +#define NCACHE_NODEADDR nc_vp /* node address in NCACHE */ +#define NCACHE_PARADDR nc_dvp /* parent node address in NCACHE */ + +# if defined(HASNCVPID) +#define NCACHE_NODEID nc_vpid /* node ID in NCACHE */ +#define NCACHE_PARID nc_dvpid /* parent node ID in NCACHE */ +# endif /* DEFINED(HASNCVPID) */ +# endif /* defined(HASNCACHE) */ + +# if FREEBSDV>=5000 +#define VNODE_VFLAG v_iflag +#define NCACHE_VROOT VV_ROOT +# endif /* FREEBSDV>=5000 */ + +#endif /* defined(FREEBSD_LSOF_H) */ diff --git a/dialects/freebsd/dmnt.c b/dialects/freebsd/dmnt.c new file mode 100644 index 0000000..3459c7c --- /dev/null +++ b/dialects/freebsd/dmnt.c @@ -0,0 +1,462 @@ +/* + * dmnt.c - FreeBSD 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"; +static char *rcsid = "$Id: dmnt.c,v 1.18 2018/02/14 14:26:03 abe Exp $"; +#endif + + +#include "lsof.h" + + +/* + * Local static information + */ + +static struct mounts *Lmi = (struct mounts *)NULL; /* local mount info */ +static int Lmist = 0; /* Lmi status */ + +#undef HAS_MNT_NAMES + +#if FREEBSDV<2000 +static char *mnt_names[] = { "none", "ufs", "nfs", "mfs", "pc", "iso9600", + "procfs", "devfs" }; +#define HAS_MNT_NAMES 1 +#else /* FREEBSDV>=2000 */ +# if defined(MOUNT_NONE) +static char *mnt_names[] = INITMOUNTNAMES; +#define HAS_MNT_NAMES 1 +# endif /* defined(MOUNT_NONE)) */ +#endif /* FREEBSDV<2000 */ + + +#if FREEBSDV>=5000 && defined(HAS_NO_SI_UDEV) +/* + * Dev2Udev() -- convert a kernel device number to a user device number + */ + +dev_t +Dev2Udev(c) + +# if defined(HAS_CONF_MINOR) || defined(HAS_CDEV2PRIV) + KA_T c; +# else /* !defined(HAS_CONF_MINOR) && !defined(HAS_CDEV2PRIV) */ + struct cdev *c; +# endif /* defined(HAS_CONF_MINOR) || defined(HAS_CDEV2PRIV) */ + +{ + +# if !defined(HAS_CONF_MINOR) && !defined(HAS_CDEV2PRIV) + char *cp; + char *dn = (char *)NULL; + char *ln = (char *)NULL; + struct statfs *mb; + int n, sr; + static u_int s; + struct stat sb; + static int ss = 0; +# endif /* !defined(HAS_CONF_MINOR) && !defined(HAS_CDEV2PRIV) */ + +# if defined(HAS_CONF_MINOR) || defined(HAS_CDEV2PRIV) + KA_T ca; + struct cdev_priv cp; + + if (!c) + return(NODEV); + +# if defined(HAS_CDEV2PRIV) + ca = (KA_T)cdev2priv((struct cdev *)c); +# else /* !defined(HAS_CDEV2PRIV) */ + ca = (KA_T)member2struct(cdev_priv, cdp_c, c); +# endif /* defined(HAS_CDEV2PRIV) */ + + if (kread((KA_T)ca, (char *)&cp, sizeof(cp))) + return(NODEV); + return((dev_t)cp.cdp_inode); +# else /* !defined(HAS_CONF_MINOR) && !defined(HAS_CDEV2PRIV) */ +# if defined(HAS_SI_PRIV) +/* + * If the cdev structure has a private sub-structure, read it. + */ + struct cdev_priv sp; + + if (!c->si_priv || kread((KA_T)c->si_priv, (char *)&sp, sizeof(sp))) + return(0); +# endif /* defined(HAS_SI_PRIV) */ + + if (ss) { + +# if defined(HAS_SI_PRIV) + return(sp.cdp_inode ^ s); +# else /* !defined(HAS_SI_PRIV) */ + return(c->si_inode ^ s); +# endif /* defined(HAS_SI_PRIV) */ + + } + +/* + * Determine the random udev seed from stat(2) operations on "/" and + * its device. + */ + if ((n = getmntinfo(&mb, MNT_NOWAIT)) <= 0) { + (void) fprintf(stderr, "%s: no mount information\n", Pn); + Exit(1); + } + for (; n; n--, mb++) { + +# if defined(MOUNT_NONE) + if (mb->f_type == MOUNT_NONE || mb->f_type >= MOUNT_MAXTYPE) +# else /* !defined(MOUNT_NONE) */ + if (!mb->f_type) +# endif /* defined(MOUNT_NONE) */ + + continue; + /* + * Get the real directory name. Ignore all but the root directory; + * safely stat("/"). + */ + if (dn) + (void) free((FREE_P *)dn); + if (!(dn = mkstrcpy(mb->f_mntonname, (MALLOC_S *)NULL))) { + +Dev2Udev_no_space: + + (void) fprintf(stderr, "%s: no space for mount at ", Pn); + safestrprt(mb->f_mntonname, stderr, 0); + (void) fprintf(stderr, " ("); + safestrprt(mb->f_mntfromname, stderr, 0); + (void) fprintf(stderr, ")\n"); + Exit(1); + } + if (!(ln = Readlink(dn))) { + if (!Fwarn) { + (void) fprintf(stderr, + " Output information may be incomplete.\n"); + } + continue; + } + if (ln != dn) { + (void) free((FREE_P *)dn); + dn = ln; + } + ln = (char *)NULL; + if (strcmp(dn, "/")) + continue; + if (statsafely(dn, &sb)) + continue; + /* + * Get the real device name and safely stat(2) it. + */ + (void) free((FREE_P *)dn); + if (!(dn = mkstrcpy(mb->f_mntfromname, (MALLOC_S *)NULL))) + goto Dev2Udev_no_space; + ln = Readlink(dn); + if ((sr = statsafely(ln, &sb))) { + + /* + * If the device stat(2) failed, see if the device name indicates + * an NFS mount, a cd9660 device, or a ZFS mount. If any condition + * is true, set the user device number seed to zero. + */ + if (((cp = strrchr(ln, ':')) && (*(cp + 1) == '/')) + || !strcasecmp(mb->f_fstypename, "cd9660") + || !strcasecmp(mb->f_fstypename, "zfs") + ) { + ss = 1; + s = (u_int)0; + } + } + if (ln != dn) + (void) free((FREE_P *)ln); + ln = (char *)NULL; + (void) free((FREE_P *)dn); + dn = (char *)NULL; + if (sr && !ss) + continue; + if (!ss) { + ss = 1; + s = (u_int)sb.st_ino ^ (u_int)sb.st_rdev; + } + break; + } +/* + * Free string copies, as required. + */ + if (dn) + (void) free((FREE_P *)dn); + if (ln) + (void) free((FREE_P *)ln); +/* + * If the device seed is known, return its application to the cdev structure's + * inode. + */ + if (ss) { + +# if defined(HAS_SI_PRIV) + return(sp.cdp_inode ^ s); +# else /* !defined(HAS_SI_PRIV) */ + return(c->si_inode ^ s); +# endif /* defined(HAS_SI_PRIV) */ + + } + (void) fprintf(stderr, "%s: can't determine user device random seed.\n", Pn); + Exit(1); + +# endif /* !defined(HAS_CONF_MINOR) */ + +} +#endif /* FREEBSDV>=5000 && defined(HAS_NO_SI_UDEV) */ + + +/* + * readmnt() - read mount table + */ + +struct mounts * +readmnt() +{ + char *dn = (char *)NULL; + char *ln; + struct statfs *mb; + struct mounts *mtp; + int n; + struct stat sb; + +#if defined(HASPROCFS) + unsigned char procfs = 0; +#endif /* defined(HASPROCFS) */ + + 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 defined(MOUNT_NONE) + if (mb->f_type == MOUNT_NONE || mb->f_type >= MOUNT_MAXTYPE) +#else /* !defined(MOUNT_NONE) */ + if (!mb->f_type) +#endif /* defined(MOUNT_NONE) */ + + continue; + /* + * Interpolate a possible symbolic directory link. + */ + if (dn) + (void) free((FREE_P *)dn); + if (!(dn = mkstrcpy(mb->f_mntonname, (MALLOC_S *)NULL))) { + +no_space_for_mount: + + (void) fprintf(stderr, "%s: no space for mount at ", Pn); + safestrprt(mb->f_mntonname, stderr, 0); + (void) fprintf(stderr, " ("); + safestrprt(mb->f_mntfromname, stderr, 0); + (void) fprintf(stderr, ")\n"); + Exit(1); + } + if (!(ln = Readlink(dn))) { + if (!Fwarn) { + (void) fprintf(stderr, + " Output information may be incomplete.\n"); + } + continue; + } + if (ln != dn) { + (void) free((FREE_P *)dn); + dn = ln; + } + if (*dn != '/') + continue; + /* + * Stat() the directory. + */ + if (statsafely(dn, &sb)) { + if (!Fwarn) { + (void) fprintf(stderr, "%s: WARNING: can't stat() ", Pn); + +#if defined(HAS_MNT_NAMES) + safestrprt(mnt_names[mb->f_type], stderr, 0); +#else /* !defined(HAS_MNT_NAMES) */ + safestrprt(mb->f_fstypename, stderr, 0); +#endif /* defined(HAS_MNT_NAMES) */ + + (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=%lx\" from mount table\n", + (unsigned long)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 defined(MOUNT_NONE) + if (mb->f_type == MOUNT_PROCFS) +#else /* !defined(MOUNT_NONE) */ + if (strcasecmp(mb->f_fstypename, "procfs") == 0) +#endif /* defined(MOUNT_NONE) */ + + { + + /* + * 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(dn); + dn = (char *)NULL; + /* + * Stat() the file system (mounted-on) name and add file system + * information to the local mount table entry. + */ + if (!ln || statsafely(ln, &sb)) + sb.st_mode = 0; + mtp->fsnmres = ln; + mtp->fs_mode = sb.st_mode; + Lmi = mtp; + } +/* + * Clean up and return the local mount info table address. + */ + if (dn) + (void) free((FREE_P *)dn); + Lmist = 1; + return(Lmi); +} + + +/* + * readvfs() - read vfs structure + */ + +struct l_vfs * +readvfs(vm) + KA_T vm; /* kernel mount address from vnode */ +{ + struct mount m; + struct l_vfs *vp; +/* + * Search for match on existing entry. + */ + for (vp = Lvfs; vp; vp = vp->next) { + if (vm == vp->addr) + return(vp); + } +/* + * Read the (new) mount structure, allocate a local entry, and fill it. + */ + if (kread((KA_T)vm, (char *)&m, sizeof(m)) != 0) + return((struct l_vfs *)NULL); + if (!(vp = (struct l_vfs *)malloc(sizeof(struct l_vfs)))) { + (void) fprintf(stderr, "%s: PID %d, no space for vfs\n", + Pn, Lp->pid); + Exit(1); + } + if (!(vp->dir = mkstrcpy(m.m_stat.f_mntonname, (MALLOC_S *)NULL)) + || !(vp->fsname = mkstrcpy(m.m_stat.f_mntfromname, (MALLOC_S *)NULL))) + { + (void) fprintf(stderr, "%s: PID %d, no space for mount names\n", + Pn, Lp->pid); + Exit(1); + } + vp->addr = vm; + vp->fsid = m.m_stat.f_fsid; + +#if defined(MOUNT_NONE) + vp->type = m.m_stat.f_type; +#else /* !defined(MOUNT_NONE) */ + { + int len; + + if ((len = strlen(m.m_stat.f_fstypename))) { + if (len > (MFSNAMELEN - 1)) + len = MFSNAMELEN - 1; + if (!(vp->typnm = mkstrcat(m.m_stat.f_fstypename, len, + (char *)NULL, -1, (char *)NULL, -1, + (MALLOC_S *)NULL))) + { + (void) fprintf(stderr, + "%s: no space for fs type name: ", Pn); + safestrprt(m.m_stat.f_fstypename, stderr, 1); + Exit(1); + } + } else + vp->typnm = ""; + } +#endif /* defined(MOUNT_NONE) */ + + vp->next = Lvfs; + Lvfs = vp; + return(vp); +} diff --git a/dialects/freebsd/dnode.c b/dialects/freebsd/dnode.c new file mode 100644 index 0000000..bf743df --- /dev/null +++ b/dialects/freebsd/dnode.c @@ -0,0 +1,1714 @@ +/* + * dnode.c - FreeBSD 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"; +static char *rcsid = "$Id: dnode.c,v 1.45 2018/02/14 14:26:03 abe Exp $"; +#endif + + +#include "lsof.h" + +#if defined(HAS_LOCKF_ENTRY) +#include "./lockf_owner.h" +#endif /* defined(HAS_LOCKF_ENTRY) */ + +#if defined(HAS_ZFS) +#include "dzfs.h" +#endif /* defined(HAS_ZFS) */ + + +#if defined(HASFDESCFS) && HASFDESCFS==1 +_PROTOTYPE(static int lkup_dev_tty,(dev_t *dr, INODETYPE *ir)); +#endif /* defined(HASFDESCFS) && HASFDESCFS==1 */ + + +#if defined(HASPTSFN) && defined(DTYPE_PTS) +#include +#endif /* defined(HASPTSFN) && defined(DTYPE_PTS) */ + + +#if defined(HAS_TMPFS) +#define _KERNEL +#include +#undef _KERNEL +#endif /* defined(HAS_TMPFS) */ + +_PROTOTYPE(static void get_lock_state,(KA_T f)); + + +/* + * get_lock_state() - get the lock state + */ + +static void +get_lock_state(f) + KA_T f; /* inode's lock pointer */ +{ + struct lockf lf; /* lockf structure */ + int lt; /* lock type */ + +#if defined(HAS_LOCKF_ENTRY) + struct lockf_entry le; /* lock_entry structure */ + KA_T lef, lep; /* lock_entry pointers */ + struct lock_owner lo; /* lock owner structure */ + + if (!f || kread(f, (char *)&lf, sizeof(lf))) + return; + if (!(lef = (KA_T)lf.ls_active.lh_first)) + return; + lep = lef; + do { + if (kread(lep, (char *)&le, sizeof(le))) + return; + if (!le.lf_owner + || kread((KA_T)le.lf_owner, (char *)&lo, sizeof(lo))) + continue; + if (lo.lo_pid == (pid_t)Lp->pid) { + if (le.lf_start == (off_t)0 + && le.lf_end == 0x7fffffffffffffffLL) + lt = 1; + else + lt = 0; + if (le.lf_type == F_RDLCK) + Lf->lock = lt ? 'R' : 'r'; + else if (le.lf_type == F_WRLCK) + Lf->lock = lt ? 'W' : 'w'; + else if (le.lf_type == (F_RDLCK | F_WRLCK)) + Lf->lock = 'u'; + return; + } + } while ((lep = (KA_T)le.lf_link.le_next) && (lep != lef)); +#else /* !defined(HAS_LOCKF_ENTRY) */ + + unsigned char l; /* lock status */ + KA_T lfp; /* lockf structure pointer */ + + if ((lfp = f)) { + + /* + * Determine the lock state. + */ + do { + if (kread(lfp, (char *)&lf, sizeof(lf))) + break; + l = 0; + switch (lf.lf_flags & (F_FLOCK|F_POSIX)) { + case F_FLOCK: + if (Cfp && (struct file *)lf.lf_id == Cfp) + l = 1; + break; + case F_POSIX: + +# if defined(P_ADDR) + if ((KA_T)lf.lf_id == Kpa) + l = 1; +# endif /* defined(P_ADDR) */ + + break; + } + if (!l) + continue; + if (lf.lf_start == (off_t)0 + && lf.lf_end == 0xffffffffffffffffLL) + lt = 1; + else + lt = 0; + if (lf.lf_type == F_RDLCK) + Lf->lock = lt ? 'R' : 'r'; + else if (lf.lf_type == F_WRLCK) + Lf->lock = lt ? 'W' : 'w'; + else if (lf.lf_type == (F_RDLCK | F_WRLCK)) + Lf->lock = 'u'; + break; + } while ((lfp = (KA_T)lf.lf_next) && (lfp != f)); + } +#endif /* defined(HAS_LOCKF_ENTRY) */ + +} + + +#if FREEBSDV>=2000 +# if defined(HASPROCFS) +_PROTOTYPE(static void getmemsz,(pid_t pid)); + + +/* + * getmemsz() - get memory size of a /proc//mem entry + */ + +static void +getmemsz(pid) + pid_t pid; +{ + int n; + struct kinfo_proc *p; + struct vmspace vm; + + for (n = 0, p = P; n < Np; n++, p++) { + if (p->P_PID == pid) { + if (!p->P_VMSPACE + || kread((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; + } + } +} +# endif /* defined(HASPROCFS) */ +#endif /* FREEBSDV>=2000 */ + + +#if defined(HASFDESCFS) && HASFDESCFS==1 +/* + * lkup_dev_tty() - look up /dev/tty + */ + +static int +lkup_dev_tty(dr, ir) + dev_t *dr; /* place to return device number */ + INODETYPE *ir; /* place to return inode number */ +{ + int i; + + readdev(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(&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(); + 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(ka) + KA_T ka; /* kqueue file structure address */ +{ + struct kqueue kq; /* kqueue structure */ + + (void) snpf(Lf->type, sizeof(Lf->type), "KQUEUE"); + enter_dev_ch(print_kptr(ka, (char *)NULL, 0)); + if (!ka || kread(ka, (char *)&kq, sizeof(kq))) + return; + (void) snpf(Namech, Namechl, "count=%d, state=%#x", kq.kq_count, + kq.kq_state); + enter_nm(Namech); +} +#endif /* defined(HASKQUEUE) */ + + +/* + * process_node() - process vnode + */ + +void +process_node(va) + KA_T va; /* vnode kernel space address */ +{ + dev_t dev, rdev; + unsigned char devs; + unsigned char rdevs; + char dev_ch[32], *ep; + struct inode *i; + struct nfsnode *n; + size_t sz; + char *ty; + unsigned char ums; + enum vtype type; + struct vnode *v, vb; + struct l_vfs *vfs; + +#if FREEBSDV>=2000 + struct inode ib; + struct nfsnode nb; +# if FREEBSDV>=4000 +# if FREEBSDV<5000 + struct specinfo si; +# else /* FREEBSDV>=5000 */ +# if !defined(HAS_CONF_MINOR) && !defined(HAS_CDEV2PRIV) + struct cdev si; +# endif /* !defined(HAS_CONF_MINOR) && !defined(HAS_CDEV2PRIV) */ +# endif /* FREEBSDV<5000 */ +# endif /* FREEBSDV>=4000 */ +#endif /* FREEBSDV>=2000 */ + +#if FREEBSDV<5000 + struct mfsnode *m; +# if FREEBSDV>=2000 + struct mfsnode mb; +# endif /* FREEBSDV>=2000 */ +#endif /* FREEBSDV<5000 */ + +#if defined(HAS9660FS) + dev_t iso_dev; + int iso_dev_def, iso_stat; + INODETYPE iso_ino; + long iso_links; + 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 */ + +# if FREEBSDV>=2000 + struct fdescnode fb; +# endif /* FREEBSDV>=2000 */ + +#endif /* defined(HASFDESCFS) */ + +#if defined(HASFUSEFS) + dev_t fuse_dev; + int fuse_dev_def, fuse_stat; + INODETYPE fuse_ino; + long fuse_links; + SZOFFTYPE fuse_sz; +#endif /* defined(HASFUSEFS) */ + +#if FREEBSDV>=5000 +# if defined(HAS_UFS1_2) + int ufst; + struct ufsmount um; + struct ufs1_dinode d1; + struct ufs2_dinode d2; +# endif /* !defined(HAS_UFS1_2) */ + +# if !defined(HAS_CONF_MINOR) && !defined(HAS_CDEV2PRIV) + struct cdev cd; +# endif /* !defined(HAS_CONF_MINOR) && !defined(HAS_CDEV2PRIV) */ + + int cds; + struct devfs_dirent de; + struct devfs_dirent *d; + char vtbuf[32]; + char *vtbp; + enum vtagtype { VT_DEVFS, VT_FDESC, VT_FUSEFS, VT_ISOFS, VT_PSEUDOFS, + VT_NFS, VT_NULL, VT_TMPFS, VT_UFS, VT_ZFS, VT_UNKNOWN + }; + +# if defined(HAS_TMPFS) + struct tmpfs_node tn; + struct tmpfs_node *tnp; +# endif /* defined(HAS_TMPFS) */ +#endif /* FREEBSDV>=5000 */ + +#if defined(HASNULLFS) +# if !defined(HASPRINTDEV) + char dbuf[32]; +# endif /* !defined(HASPRINTDEV) */ + char *dp, *np, tbuf[1024]; + struct null_node nu; + int sc = 0; +#endif /* defined(HASNULLFS) */ + +#if defined(HASPROCFS) + struct pfsnode *p; + struct procfsid *pfi; + static int pgsz = -1; + struct vmspace vm; + +# if FREEBSDV>=2000 + struct pfsnode pb; +# endif /* FREEBSDV>=2000 */ +#endif /* defined(HASPROCFS) */ + +#if defined(HASPSEUDOFS) + struct pfs_node pn; + struct pfs_node *pnp; +#endif /* defined(HASPSEUDOFS) */ + +#if defined(HAS_ZFS) + zfs_info_t *z = (zfs_info_t *)NULL; + zfs_info_t zi; + char *zm = (char *)NULL; +#else /* !defined(HAS_ZFS) */ + static unsigned char zw = 0; +#endif /* HAS_VFS */ + + enum vtagtype vtag; /* placed here to use the + * artificial vtagtype + * definition required for + * FREEBSDV>=5000 */ + +#if defined(HASNULLFS) + +process_overlaid_node: + + if (++sc > 1024) { + (void) snpf(Namech, Namechl, "too many overlaid nodes"); + enter_nm(Namech); + return; + } +#endif /* defined(HASNULLFS) */ + +/* + * Initialize miscellaneous variables. This is done so that processing an + * overlaid node will be a fresh start. + */ + devs = rdevs = ums = 0; + i = (struct inode *)NULL; + n = (struct nfsnode *)NULL; + Namech[0] = '\0'; + +#if defined(HAS9660FS) + iso_dev_def = iso_stat = 0; +#endif /* defined(HAS9660FS) */ + +#if defined(HASFDESCFS) + f = (struct fdescnode *)NULL; +#endif /* defined(HASFDESCFS) */ + +#if defined(HASFUSEFS) + fuse_dev_def = fuse_stat = 0; +#endif /* defined(HASFUSEFS) */ + +#if FREEBSDV<5000 + m = (struct mfsnode *)NULL; +#else /* FREEBSDV>=5000 */ + cds = 0; + d = (struct devfs_dirent *)NULL; +# if defined(HAS_UFS1_2) + ufst = 0; +# endif /* !defined(HAS_UFS1_2) */ +#endif /* FREEBSDV<5000 */ + +#if defined(HASPROCFS) + p = (struct pfsnode *)NULL; +#endif /* defined(HASPROCFS) */ + +#if defined(HASPSEUDOFS) + pnp = (struct pfs_node *)NULL; +#endif /* defined(HASPSEUDOFS) */ + +# if defined(HAS_TMPFS) + tnp = (struct tmpfs_node *)NULL; +# endif /* defined(HAS_TMPFS) */ + + +#if defined(HAS_ZFS) + z = (zfs_info_t *)NULL; + zm = (char *)NULL; +#endif /* defined(HAS_ZFS) */ + +/* + * Read the vnode. + */ + if ( ! va) { + enter_nm("no vnode address"); + return; + } + v = &vb; + if (readvnode(va, v)) { + enter_nm(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((KA_T)v->v_mount); + if (vfs) { + +#if defined(MOUNT_NONE) + switch (vfs->type) { + case MOUNT_NFS: + Ntype = N_NFS; + break; + +# if defined(HASPROCFS) + case MOUNT_PROCFS: + Ntype = N_PROC; + break; +# endif /* defined(HASPROCFS) */ + } +#else /* !defined(MOUNT_NONE) */ + if (strcasecmp(vfs->typnm, "nfs") == 0) + Ntype = N_NFS; + +# if defined(HASPROCFS) + else if (strcasecmp(vfs->typnm, "procfs") == 0) + Ntype = N_PROC; +# endif /* defined(HASPROCFS) */ + +# if defined(HASPSEUDOFS) + else if (strcasecmp(vfs->typnm, "pseudofs") == 0) + Ntype = N_PSEU; +# endif /* defined(HASPSEUDOFS) */ + +# if defined(HAS_TMPFS) + else if (strcasecmp(vfs->typnm, "tmpfs") == 0) + Ntype = N_TMP; +# endif /* defined(HAS_TMPFS) */ +#endif /* defined(MOUNT_NONE) */ + + } + } + if (Ntype == N_REGLR) { + switch (v->v_type) { + case VFIFO: + Ntype = N_FIFO; + break; + default: + break; + } + } + +#if FREEBSDV>=5000 +/* + * For FreeBSD 5 and above VCHR and VBLK vnodes get the v_rdev structure. + */ + if (((v->v_type == VCHR) || (v->v_type == VBLK)) + && v->v_rdev + +# if !defined(HAS_CONF_MINOR) && !defined(HAS_CDEV2PRIV) + && !kread((KA_T)v->v_rdev, (char *)&cd, sizeof(cd)) +# endif /* !defined(HAS_CONF_MINOR) && !defined(HAS_CDEV2PRIV) */ + + ) { + cds = 1; + } +#endif /* FREEBSDV>=5000 */ + +/* + * Define the specific node pointer. + */ + +#if FREEBSDV>=5000 +/* + * Get the pseudo vnode tag type for FreeBSD >= 5. + */ + vtag = VT_UNKNOWN; + if (v->v_tag && !kread((KA_T)v->v_tag, (char *)&vtbuf, sizeof(vtbuf))) + { + vtbuf[sizeof(vtbuf) - 1] = '\0'; + vtbp = vtbuf; + if (!strcmp(vtbuf, "ufs")) + vtag = VT_UFS; + else if (!strcmp(vtbuf, "zfs")) { + +#if !defined(HAS_ZFS) + if (!Fwarn && !zw) { + (void) fprintf(stderr, + "%s: WARNING: no ZFS support has been defined.\n", + Pn); + (void) fprintf(stderr, + " See 00FAQ for more information.\n"); + zw = 1; + } +#else /* defined(HAS_ZFS) */ + vtag = VT_ZFS; +#endif /* !defined(HAS_ZFS) */ + + } else if (!strcmp(vtbuf, "devfs")) + vtag = VT_DEVFS; + else if (!strcmp(vtbuf, "nfs")) + vtag = VT_NFS; + else if (!strcmp(vtbuf, "newnfs")) + vtag = VT_NFS; + else if (!strcmp(vtbuf, "oldnfs")) + vtag = VT_NFS; + else if (!strcmp(vtbuf, "isofs")) + vtag = VT_ISOFS; + else if (!strcmp(vtbuf, "pseudofs")) + vtag = VT_PSEUDOFS; + else if (!strcmp(vtbuf, "nullfs")) + vtag = VT_NULL; + else if (!strcmp(vtbuf, "null")) + vtag = VT_NULL; + else if (!strcmp(vtbuf, "fdesc")) + vtag = VT_FDESC; + else if (!strcmp(vtbuf, "fuse")) + vtag = VT_FUSEFS; + else if (!strcmp(vtbuf, "tmpfs")) + vtag = VT_TMPFS; + } else + vtbp = "(unknown)"; +#else /* FREEBSDV<5000 */ + vtag = v->v_tag; +#endif /* FREEBSDV>=5000 */ + + switch (vtag) { + +#if FREEBSDV>=5000 + case VT_DEVFS: + if (!v->v_data + || kread((KA_T)v->v_data, (char *)&de, sizeof(de))) + { + (void) snpf(Namech, Namechl, "no devfs node: %s", + print_kptr((KA_T)v->v_data, (char *)NULL, 0)); + enter_nm(Namech); + return; + } + d = &de; + if (v->v_type == VDIR) { + if (!d->de_dir + || kread((KA_T)d->de_dir, (char *)&de, sizeof(de))) { + (void) snpf(Namech, Namechl, "no devfs dir node: %s", + print_kptr((KA_T)d->de_dir, (char *)NULL, 0)); + enter_nm(Namech); + return; + } + } + break; +#endif /* FREEBSDV>=5000 */ + +#if defined(HASFDESCFS) + case VT_FDESC: + +# if FREEBSDV<2000 + f = (struct fdescnode *)v->v_data; +# else /* FREEBSDV>=2000 */ + if (kread((KA_T)v->v_data, (char *)&fb, sizeof(fb)) != 0) { + (void) snpf(Namech, Namechl, "can't read fdescnode at: %s", + print_kptr((KA_T)v->v_data, (char *)NULL, 0)); + enter_nm(Namech); + return; + } + f = &fb; + break; +# endif /* FREEBSDV<2000 */ +#endif /* defined(HASFDESCFS) */ + +#if defined(HASFUSEFS) + case VT_FUSEFS: + if (read_fuse_node(v, &fuse_dev, &fuse_dev_def, &fuse_ino, + &fuse_links, &fuse_sz)) + { + (void) snpf(Namech, Namechl, "no fuse node: %s", + print_kptr((KA_T)v->v_data, (char *)NULL, 0)); + enter_nm(Namech); + return; + } + fuse_stat = 1; + break; +#endif /* defined(HASFUSEFS) */ + +#if defined(HAS9660FS) + case VT_ISOFS: + if (read_iso_node(v, &iso_dev, &iso_dev_def, &iso_ino, &iso_links, + &iso_sz)) + { + (void) snpf(Namech, Namechl, "no iso node: %s", + print_kptr((KA_T)v->v_data, (char *)NULL, 0)); + enter_nm(Namech); + return; + } + iso_stat = 1; + break; +#endif /* defined(HAS9660FS) */ + +#if FREEBSDV<5000 + case VT_MFS: + +# if FREEBSDV<2000 + m = (struct mfsnode *)v->v_data; +# else /* FREEBSDV>=2000 */ + if (!v->v_data + || kread((KA_T)v->v_data, (char *)&mb, sizeof(mb))) { + (void) snpf(Namech, Namechl, "no mfs node: %s", + print_kptr((KA_T)v->v_data, (char *)NULL, 0)); + enter_nm(Namech); + return; + } + m = &mb; +# endif /* FREEBSDV<2000 */ +#endif /* FREEBSDV<5000 */ + + break; + case VT_NFS: + +#if FREEBSDV<2000 + n = (struct nfsnode *)v->v_data; +#else /* FREEBSDV>=2000 */ + if (!v->v_data + || kread((KA_T)v->v_data, (char *)&nb, sizeof(nb))) { + (void) snpf(Namech, Namechl, "no nfs node: %s", + print_kptr((KA_T)v->v_data, (char *)NULL, 0)); + enter_nm(Namech); + return; + } + n = &nb; +#endif /* FREEBSDV<2000 */ + + break; + +#if defined(HASNULLFS) + case VT_NULL: + if (sc == 1) { + + /* + * If this is the first null_node, enter a name addition containing + * the mounted-on directory, the file system name, and the device + * number. + */ + if (vfs && (vfs->dir || vfs->fsname || vfs->fsid.val[0])) { + if (vfs->fsid.val[0]) { + +#if defined(HASPRINTDEV) + dp = HASPRINTDEV(Lf, &dev); +#else /* !defined(HASPRINTDEV) */ + (void) snpf(dbuf, sizeof(dbuf) - 1, "%d,%d", + GET_MAJ_DEV(dev), GET_MIN_DEV(dev)); + dbuf[sizeof(dbuf) - 1] = '\0'; + dp = dbuf; +#endif /* defined(HASPRINTDEV) */ + + } else + dp = (char *)NULL; + (void) snpf(tbuf, sizeof(tbuf) - 1, + "(nullfs%s%s%s%s%s%s%s)", + (vfs && vfs->fsname) ? " " : "", + (vfs && vfs->fsname) ? vfs->fsname : "", + (vfs && vfs->dir) ? " on " : "", + (vfs && vfs->dir) ? vfs->dir : "", + (dp && vfs && vfs->dir) ? " (" : "", + (dp && vfs && vfs->dir) ? dp : "", + (dp && vfs && vfs->dir) ? ")" : ""); + tbuf[sizeof(tbuf) - 1] = '\0'; + np = tbuf; + } else + np = "(nullfs)"; + (void) add_nma(np, (int)strlen(np)); + } + if (!v->v_data + || kread((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(Namech); + return; + } + if (!nu.null_lowervp) { + (void) snpf(Namech, Namechl, "null_node overlays nothing"); + enter_nm(Namech); + return; + } + va = (KA_T)nu.null_lowervp; + goto process_overlaid_node; +#endif /* defined(HASNULLFS) */ + +#if defined(HASPROCFS) + case VT_PROCFS: + +# if FREEBSDV<2000 + p = (struct pfsnode *)v->v_data; +# else /* FREEBSDV>=2000 */ + if (!v->v_data + || kread((KA_T)v->v_data, (char *)&pb, sizeof(pb))) { + (void) snpf(Namech, Namechl, "no pfs node: %s", + print_kptr((KA_T)v->v_data, (char *)NULL, 0)); + enter_nm(Namech); + return; + } + p = &pb; +# endif /* FREEBSDV<2000 */ + + break; +#endif /* defined(HASPROCFS) */ + +#if defined(HASPSEUDOFS) + case VT_PSEUDOFS: + if (!v->v_data + || kread((KA_T)v->v_data, (char *)&pn, sizeof(pn))) { + (void) snpf(Namech, Namechl, "no pfs_node: %s", + print_kptr((KA_T)v->v_data, (char *)NULL, 0)); + enter_nm(Namech); + return; + } + pnp = &pn; + break; +#endif /* defined(HASPSEUDOFS) */ + +# if defined(HAS_TMPFS) + case VT_TMPFS: + if (!v->v_data + || kread((KA_T)v->v_data, (char *)&tn, sizeof(tn))) { + (void) snpf(Namech, Namechl, "no tmpfs_node: %s", + print_kptr((KA_T)v->v_data, (char *)NULL, 0)); + enter_nm(Namech); + return; + } + tnp = &tn; + break; +# endif /* defined(HAS_TMPFS) */ + + case VT_UFS: + +#if FREEBSDV<2000 + i = (struct inode *)v->v_data; +#else /* FREEBSDV>=2000 */ + if (!v->v_data + || kread((KA_T)v->v_data, (char *)&ib, sizeof(ib))) { + (void) snpf(Namech, Namechl, "no ufs node: %s", + print_kptr((KA_T)v->v_data, (char *)NULL, 0)); + enter_nm(Namech); + return; + } + i = &ib; + +# if defined(HAS_UFS1_2) + if (i->i_ump && !kread((KA_T)i->i_ump, (char *)&um, sizeof(um))) { + ums = 1; + if (um.um_fstype == UFS1) { + if (i->i_din1 + && !kread((KA_T)i->i_din1, (char *)&d1, sizeof(d1))) + ufst = 1; + } else { + if (i->i_din2 + && !kread((KA_T)i->i_din2, (char *)&d2, sizeof(d2))) + ufst = 2; + } + } +# endif /* defined(HAS_UFS1_2) */ +#endif /* FREEBSDV<2000 */ + +#if defined(HAS_V_LOCKF) + if (v->v_lockf) + (void) get_lock_state((KA_T)v->v_lockf); +#else /* !defined(HAS_V_LOCKF) */ + if (i->i_lockf) + (void) get_lock_state((KA_T)i->i_lockf); +#endif /* defined(HAS_V_LOCKF) */ + + break; + +#if defined(HAS_ZFS) + case VT_ZFS: + memset((void *)&zi, 0, sizeof(zfs_info_t)); + if (!v->v_data + || (zm = readzfsnode((KA_T)v->v_data, &zi, + ((v->v_vflag & VV_ROOT) ? 1 : 0))) + ) { + (void) snpf(Namech, Namechl, "%s: %s", zm, + print_kptr((KA_T)v->v_data, (char *)NULL, 0)); + enter_nm(Namech); + return; + } + z = &zi; + +#if defined(HAS_V_LOCKF) + if (v->v_lockf) + (void) get_lock_state((KA_T)v->v_lockf); +#else /* !defined(HAS_V_LOCKF) */ + if (z->lockf) + (void) get_lock_state((KA_T)z->lockf); +#endif /* defined(HAS_V_LOCKF) */ + + break; +#endif /* defined(HAS_ZFS) */ + + default: + if (v->v_type == VBAD || v->v_type == VNON) + break; + +#if FREEBSDV<5000 + (void) snpf(Namech,Namechl,"unknown file system type: %d",v->v_tag); +#else /* FREEBSDV>=5000 */ + (void) snpf(Namech, Namechl, "unknown file system type: %s", vtbp); +#endif /* FREEBSDV<5000 */ + + enter_nm(Namech); + return; + } +/* + * Get device and type for printing. + */ + type = v->v_type; + if (n) { + dev = n->n_vattr.va_fsid; + devs = 1; + if ((type == VCHR) || (type == VBLK)) { + rdev = n->n_vattr.va_rdev; + rdevs = 1; + } + } else if (i) { + +#if FREEBSDV>=4000 +# if defined(HAS_NO_IDEV) + if (ums) { + dev = Dev2Udev((KA_T)um.um_dev); + devs = 1; + } +# else /* !defined(HAS_NO_IDEV) */ + if (i->i_dev + +# if !defined(HAS_CONF_MINOR) && !defined(HAS_CDEV2PRIV) + && !kread((KA_T)i->i_dev, (char *)&si, sizeof(si)) +# endif/* !defined(HAS_CONF_MINOR) && !defined(HAS_CDEV2PRIV) */ + + ) { + +# if defined(HAS_NO_SI_UDEV) +# if defined(HAS_CONF_MINOR) || defined(HAS_CDEV2PRIV) + dev = Dev2Udev((KA_T)i->i_dev); +# else /* !defined(HAS_CONF_MINOR) && !defined(HAS_CDEV2PRIV) */ + dev = Dev2Udev(&si); +# endif /* defined(HAS_CONF_MINOR) || defined(HAS_CDEV2PRIV) */ +# else /* !defined(HAS_NO_SI_UDEV) */ + dev = si.si_udev; +# endif /* defined(HAS_NO_SI_UDEV) */ + + devs = 1; + } +# endif /* defined(HAS_NO_IDEV) */ +#else /* FREEBSDV<4000 */ + dev = i->i_dev; + devs = 1; +#endif /* FREEBSDV>=4000 */ + + if ((type == VCHR) || (type == VBLK)) { + +#if FREEBSDV>=5000 +# if defined(HAS_UFS1_2) + if (ufst == 1) { + rdev = d1.di_rdev; + rdevs = 1; + } else if (ufst == 2) { + rdev = d2.di_rdev; + rdevs = 1; + } else +# endif /* defined(HAS_UFS1_2) */ + + if (cds) { + +# if defined(HAS_NO_SI_UDEV) +# if defined(HAS_CONF_MINOR) || defined(HAS_CDEV2PRIV) + rdev = Dev2Udev((KA_T)v->v_rdev); +# else /* !defined(HAS_CONF_MINOR) && !defined(HAS_CDEV2PRIV) */ + rdev = Dev2Udev(&cd); +# endif /* defined(HAS_CONF_MINOR) || defined(HAS_CDEV2PRIV) */ +# else /* !defined(HAS_NO_SI_UDEV) */ + rdev = cd.si_udev; +# endif /* defined(HAS_NO_SI_UDEV) */ + + rdevs = 1; + } +#else /* FREEBSDV<5000 */ + rdev = i->i_rdev; + rdevs = 1; +#endif /* FREEBSDV>=5000 */ + + } + } + +#if defined(HAS_ZFS) + else if (z) { + + /* + * Record information returned by readzfsnode(). + */ + if (vfs) { + union { + int32_t val[2]; + dev_t dev; + } vfs_fsid; + + vfs_fsid.val[0] = vfs->fsid.val[0]; + vfs_fsid.val[1] = vfs->fsid.val[1]; + dev = vfs_fsid.dev; + devs = 1; + } + if ((type == VCHR) || (type == VBLK)) { + if (z->rdev_def) { + rdev = z->rdev; + rdevs = 1; + } + } + } +#endif /* defined(HAS_ZFS) */ + +#if defined(HASFDESCFS) && (defined(HASFDLINK) || HASFDESCFS==1) + else if (f) { + +# if defined(HASFDLINK) + if (f->fd_link + && kread((KA_T)f->fd_link, Namech, Namechl - 1) == 0) + Namech[Namechl - 1] = '\0'; + +# if HASFDESCFS==1 + else +# endif /* HASFDESCFS==1 */ +# endif /* defined(HASFDLINK) */ + +# if HASFDESCFS==1 + if (f->fd_type == Fctty) { + if (f_tty_s == 0) + f_tty_s = lkup_dev_tty(&f_tty_dev, &f_tty_ino); + if (f_tty_s == 1) { + dev = f_tty_dev; + Lf->inode = f_tty_ino; + devs = Lf->inp_ty = 1; + } + } +# endif /* HASFDESCFS==1 */ + + } +#endif /* defined(HASFDESCFS) && (defined(HASFDLINK) || HASFDESCFS==1) */ + +#if defined(HAS9660FS) + else if (iso_stat && iso_dev_def) { + dev = iso_dev; + devs = Lf->inp_ty = 1; + } +#endif /* defined(HAS9660FS) */ + +#if defined(HASFUSEFS) + else if (fuse_stat && fuse_dev_def) { + dev = fuse_dev; + devs = Lf->inp_ty = 1; + } +#endif /* defined(HASFUSEFS) */ + +#if FREEBSDV>=5000 + else if (d) { + if (vfs) { + dev = vfs->fsid.val[0]; + devs = 1; + } else { + dev = DevDev; + devs = 1; + } + if (type == VCHR) { + +# if defined(HAS_UFS1_2) + if (ufst == 1) { + rdev = d1.di_rdev; + rdevs = 1; + } else if (ufst == 2) { + rdev = d2.di_rdev; + rdevs = 1; + } else +# endif /* defined(HAS_UFS1_2) */ + + if (cds) { + +# if defined(HAS_NO_SI_UDEV) +# if defined(HAS_CONF_MINOR) || defined(HAS_CDEV2PRIV) + rdev = Dev2Udev((KA_T)v->v_rdev); +# else /* !defined(HAS_CONF_MINOR) && !defined(HAS_CDEV2PRIV) */ + rdev = Dev2Udev(&cd); +# endif /* defined(HAS_CONF_MINOR) || defined(HAS_CDEV2PRIV) */ +# else /* !defined(HAS_NO_SI_UDEV) */ + rdev = cd.si_udev; +# endif /* defined(HAS_NO_SI_UDEV) */ + + rdevs = 1; + } + } + } +#endif /* FREEBSDV>=5000 */ + +#if defined(HASPSEUDOFS) + else if (pnp) { + if (vfs) { + dev = vfs->fsid.val[0]; + devs = 1; + } + } +#endif /* defined(HASPSEUDOFS) */ + +# if defined(HAS_TMPFS) + else if (tnp) { + if (vfs) { + dev = vfs->fsid.val[0]; + devs = 1; + } + if (tnp->tn_type == VBLK || tnp->tn_type == VCHR) { + rdev = tnp->tn_rdev; + rdevs = 1; + } + } +# endif /* defined(HAS_TMPFS) */ + +/* + * Obtain the inode number. + */ + if (i) { + Lf->inode = (INODETYPE)i->i_number; + Lf->inp_ty = 1; + } + +#if defined(HAS_ZFS) + else if (z) { + if (z->ino_def) { + Lf->inode = z->ino; + Lf->inp_ty = 1; + } + } +#endif /* defined(HAS_ZFS) */ + + else if (n) { + Lf->inode = (INODETYPE)n->n_vattr.va_fileid; + Lf->inp_ty = 1; + } + +#if defined(HAS9660FS) + else if (iso_stat) { + Lf->inode = iso_ino; + Lf->inp_ty = 1; + } +#endif /* defined(HAS9660FS) */ + +#if defined(HASFUSEFS) + else if (fuse_stat) { + Lf->inode = fuse_ino; + Lf->inp_ty = 1; + } +#endif /* defined(HASFUSEFS) */ + +#if defined(HASPROCFS) +# if FREEBSDV>=2000 + else if (p) { + Lf->inode = (INODETYPE)p->pfs_fileno; + Lf->inp_ty = 1; + } +# endif /* FREEBSDV>=2000 */ +#endif /* defined(HASPROCFS) */ + +#if defined(HASPSEUDOFS) + else if (pnp) { + Lf->inode = (INODETYPE)pnp->pn_fileno; + Lf->inp_ty = 1; + } +#endif /* defined(HASPSEUDOFS) */ + +#if FREEBSDV>=5000 + else if (d) { + Lf->inode = (INODETYPE)d->de_inode; + Lf->inp_ty = 1; + } +#endif /* FREEBSDV>=5000 */ + +# if defined(HAS_TMPFS) + else if (tnp) { + Lf->inode = (INODETYPE)tnp->tn_id; + Lf->inp_ty = 1; + } +# endif /* defined(HAS_TMPFS) */ + +/* + * Obtain the file size. + */ + if (Foffset) + Lf->off_def = 1; + else { + switch (Ntype) { + case N_FIFO: + if (!Fsize) + Lf->off_def = 1; + break; + case N_NFS: + if (n) { + Lf->sz = (SZOFFTYPE)n->n_vattr.va_size; + Lf->sz_def = 1; + } + break; + +#if defined(HASPROCFS) + case N_PROC: + +# if FREEBSDV<2000 + if (type == VDIR || !p || !p->pfs_vs + || kread((KA_T)p->pfs_vs, (char *)&vm, sizeof(vm))) + break; + if (pgsz < 0) + pgsz = getpagesize(); + Lf->sz = (SZOFFTYPE)((pgsz * vm.vm_tsize) + + (pgsz * vm.vm_dsize) + + (pgsz * vm.vm_ssize)); + Lf->sz_def = 1; + break; +# else /* FREEBSDV>=2000 */ + if (p) { + switch(p->pfs_type) { + case Proot: + case Pproc: + Lf->sz = (SZOFFTYPE)DEV_BSIZE; + Lf->sz_def = 1; + break; + case Pmem: + (void) getmemsz(p->pfs_pid); + break; + case Pregs: + Lf->sz = (SZOFFTYPE)sizeof(struct reg); + Lf->sz_def = 1; + break; + case Pfpregs: + Lf->sz = (SZOFFTYPE)sizeof(struct fpreg); + Lf->sz_def = 1; + break; + } + } +# endif /* FREEBSDV<2000 */ +#endif /* defined(HASPROCFS) */ + +#if defined(HASPSEUDOFS) + case N_PSEU: + Lf->sz = 0; + Lf->sz_def = 1; + break; +#endif /* defined(PSEUDOFS) */ + + case N_REGLR: + if (type == VREG || type == VDIR) { + if (i) { + +#if defined(HAS_UFS1_2) + if (ufst == 1) + Lf->sz = (SZOFFTYPE)d1.di_size; + else if (ufst == 2) + Lf->sz = (SZOFFTYPE)d2.di_size; + else +#endif /* defined(HAS_UFS1_2) */ + + Lf->sz = (SZOFFTYPE)i->i_size; + Lf->sz_def = 1; + } + + +#if defined(HAS_ZFS) + else if (z) { + if (z->sz_def) { + Lf->sz = z->sz; + Lf->sz_def = 1; + } + } +#endif /* defined(HAS_ZFS) */ + +#if FREEBSDV<5000 + else if (m) { + Lf->sz = (SZOFFTYPE)m->mfs_size; + Lf->sz_def = 1; + } +#endif /* FREEBSDV<5000 */ + +#if defined(HAS9660FS) + else if (iso_stat) { + Lf->sz = (SZOFFTYPE)iso_sz; + Lf->sz_def = 1; + } + +#endif /* defined(HAS9660FS) */ + +#if defined(HASFUSEFS) + else if (fuse_stat) { + Lf->sz = (SZOFFTYPE)fuse_sz; + Lf->sz_def = 1; + } +#endif /* defined(HASFUSEFS) */ + + } + else if ((type == VCHR || type == VBLK) && !Fsize) + Lf->off_def = 1; + break; + +# if defined(HAS_TMPFS) + case N_TMP: + if ((tnp->tn_type == VBLK || tnp->tn_type == VCHR) + && !Fsize) { + Lf->off_def = 1; + } else { + Lf->sz = (SZOFFTYPE)tnp->tn_size; + Lf->sz_def = 1; + } + break; +# endif /* defined(HAS_TMPFS) */ + + } + } +/* + * Record the link count. + */ + if (Fnlink) { + switch(Ntype) { + case N_NFS: + if (n) { + Lf->nlink = (long)n->n_vattr.va_nlink; + Lf->nlink_def = 1; + } + break; + case N_REGLR: + if (i) { + +#if defined(HASEFFNLINK) + Lf->nlink = (long)i->HASEFFNLINK; +#else /* !defined(HASEFFNLINK) */ + Lf->nlink = (long)i->i_nlink; +#endif /* defined(HASEFFNLINK) */ + + Lf->nlink_def = 1; + } + +#if defined(HAS_ZFS) + else if (z) { + if (z->nl_def) { + Lf->nlink = z->nl; + Lf->nlink_def = 1; + } + } +#endif /* defined(HAS_ZFS) */ + +#if defined(HAS9660FS) + else if (iso_stat) { + Lf->nlink = iso_links; + Lf->nlink_def = 1; + } +#endif /* defined(HAS9660FS) */ + +#if defined(HASFUSEFS) + else if (fuse_stat) { + Lf->nlink = fuse_links; + Lf->nlink_def = 1; + } +#endif /* defined(HASFUSEFS) */ + +#if FREEBSDV>=5000 + else if (d) { + Lf->nlink = d->de_links; + Lf->nlink_def = 1; + } +#endif /* FREEBSDV>=5000 */ + + break; + +#if defined(HASPSEUODOFS) + case N_PSEU: + if (pnp) { + Lf->nlink = 1L; + Lf->nlink_def = 1; + } + break; +#endif /* defined(HASPSEUODOFS) */ + +# if defined(HAS_TMPFS) + case N_TMP: + if (tnp) { + Lf->nlink = (long)tnp->tn_links; + Lf->nlink_def = 1; + } + break; +# endif /* defined(HAS_TMPFS) */ + + } + if (Lf->nlink_def && Nlink && (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; + } +/* + * Save the device numbers and their states. + * + * Format the vnode type, and possibly the device name. + */ + Lf->dev = dev; + Lf->dev_def = devs; + Lf->rdev = rdev; + Lf->rdev_def = rdevs; + switch (type) { + case VNON: + ty ="VNON"; + break; + case VREG: + case VDIR: + ty = (type == VREG) ? "VREG" : "VDIR"; + break; + case VBLK: + ty = "VBLK"; + Ntype = N_BLK; + break; + case VCHR: + ty = "VCHR"; + Ntype = N_CHR; + break; + case VLNK: + ty = "VLNK"; + break; + +#if defined(VSOCK) + case VSOCK: + ty = "SOCK"; + break; +#endif /* defined(VSOCK) */ + + case VBAD: + ty = "VBAD"; + break; + case VFIFO: + ty = "FIFO"; + break; + default: + (void) snpf(Lf->type, sizeof(Lf->type), "%04o", (type & 0xfff)); + ty = (char *)NULL; + } + if (ty) + (void) snpf(Lf->type, sizeof(Lf->type), "%s", ty); + Lf->ntype = Ntype; +/* + * Handle some special cases: + * + * ioctl(fd, TIOCNOTTY) files; + * memory node files; + * /proc files. + */ + + if (type == VBAD) + (void) snpf(Namech, Namechl, "(revoked)"); + +#if FREEBSDV<5000 + else if (m) { + Lf->dev_def = Lf->rdev_def = 0; + (void) snpf(Namech, Namechl, "%#x", m->mfs_baseoff); + (void) snpf(dev_ch, sizeof(dev_ch), " memory"); + enter_dev_ch(dev_ch); + } +#endif /* FREEBSDV<5000 */ + + +#if defined(HASPROCFS) + else if (p) { + Lf->dev_def = Lf->rdev_def = 0; + +# if FREEBSDV<2000 + if (type == VDIR) + (void) snpf(Namech, Namechl, "/%s", HASPROCFS); + else + (void) snpf(Namech, Namechl, "/%s/%0*d", HASPROCFS, PNSIZ, + p->pfs_pid); + enter_nm(Namech); +# else /* FREEBSDV>=2000 */ + ty = (char *)NULL; + (void) snpf(Namech, Namechl, "/%s", HASPROCFS); + switch (p->pfs_type) { + case Proot: + ty = "PDIR"; + break; + case Pproc: + ep = endnm(&sz); + (void) snpf(ep, sz, "/%d", p->pfs_pid); + ty = "PDIR"; + break; + case Pfile: + ep = endnm(&sz); + (void) snpf(ep, sz, "/%d/file", p->pfs_pid); + ty = "PFIL"; + break; + case Pmem: + ep = endnm(&sz); + (void) snpf(ep, sz, "/%d/mem", p->pfs_pid); + ty = "PMEM"; + break; + case Pregs: + ep = endnm(&sz); + (void) snpf(ep, sz, "/%d/regs", p->pfs_pid); + ty = "PREG"; + break; + case Pfpregs: + ep = endnm(&sz); + (void) snpf(ep, sz, "/%d/fpregs", p->pfs_pid); + ty = "PFPR"; + break; + case Pctl: + ep = endnm(&sz); + (void) snpf(ep, sz, "/%d/ctl", p->pfs_pid); + ty = "PCTL"; + break; + case Pstatus: + ep = endnm(&sz); + (void) snpf(ep, sz, "/%d/status", p->pfs_pid); + ty = "PSTA"; + break; + case Pnote: + ep = endnm(&sz); + (void) snpf(ep, sz, "/%d/note", p->pfs_pid); + ty = "PNTF"; + break; + case Pnotepg: + ep = endnm(&sz); + (void) snpf(ep, sz, "/%d/notepg", p->pfs_pid); + ty = "PGID"; + break; + +# if FREEBSDV>=3000 + case Pmap: + ep = endnm(&sz); + (void) snpf(ep, sz, "/%d/map", p->pfs_pid); + ty = "PMAP"; + break; + case Ptype: + ep = endnm(&sz); + (void) snpf(ep, sz, "/%d/etype", p->pfs_pid); + ty = "PETY"; + break; +# endif /* FREEBSDV>=3000 */ + + } + if (ty) + (void) snpf(Lf->type, sizeof(Lf->type), "%s", ty); + enter_nm(Namech); + +# endif /* FREEBSDV<2000 */ + } +#endif /* defined(HASPROCFS) */ + +#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 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 == p->pfs_pid) + +# if defined(HASPINODEN) + || (Lf->inp_ty == 1 && Lf->inode == pfi->inode) +# else /* !defined(HASPINODEN) */ + if (pfi->pid == p->pfs_pid) +# endif /* defined(HASPINODEN) */ + + ) { + pfi->f = 1; + if (!Namech[0]) + (void) snpf(Namech, Namechl, "%s", pfi->nm); + Lf->sf |= SELNM; + break; + } + } + } + } else +#endif /* defined(HASPROCFS) */ + + { + if (Sfile && is_file_named((char *)NULL, + ((type == VCHR) || (type == VBLK)) ? 1 + : 0)) + Lf->sf |= SELNM; + } +/* + * Enter name characters. + */ + if (Namech[0]) + enter_nm(Namech); +} + + +#if FREEBSDV>=2020 +/* + * process_pipe() - process a file structure whose type is DTYPE_PIPE + */ + +void +process_pipe(pa) + KA_T pa; /* pipe structure address */ +{ + char dev_ch[32], *ep; + struct pipe p; + size_t sz; + + if (!pa || kread(pa, (char *)&p, sizeof(p))) { + (void) snpf(Namech, Namechl, + "can't read DTYPE_PIPE pipe struct: %s", + print_kptr((KA_T)pa, (char *)NULL, 0)); + enter_nm(Namech); + return; + } + (void) snpf(Lf->type, sizeof(Lf->type), "PIPE"); + (void) snpf(dev_ch, sizeof(dev_ch), "%s", + print_kptr(pa, (char *)NULL, 0)); + enter_dev_ch(dev_ch); + if (Foffset) + Lf->off_def = 1; + else { + 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(&sz); + (void) snpf(ep, sz, ", cnt=%d", p.pipe_buffer.cnt); + } + if (p.pipe_buffer.in) { + ep = endnm(&sz); + (void) snpf(ep, sz, ", in=%d", p.pipe_buffer.in); + } + if (p.pipe_buffer.out) { + ep = endnm(&sz); + (void) snpf(ep, sz, ", out=%d", p.pipe_buffer.out); + } +/* + * Enter name characters. + */ + if (Namech[0]) + enter_nm(Namech); +} +#endif /* FREEBSDV>=2020 */ + + +#if defined(HASPTSFN) && defined(DTYPE_PTS) +/* + * process_pts - process a file structure whose type is DTYPE_PTS + */ + +void process_pts(tp) + KA_T tp; /* f_data pointer to tty structure */ +{ + dev_t dev; /* IFCHR device number */ + struct tty t; /* tty structure */ + + (void) snpf(Lf->type, sizeof(Lf->type), "PTS"); +/* + * Read the tty structure. Quit if it can't be read. + */ + if (!tp || kread(tp, (char *)&t, sizeof(t))) { + (void) snpf(Namech, Namechl, + "can't read DTYPE_PTS tty struct: %s", + print_kptr((KA_T)tp, (char *)NULL, 0)); + enter_nm(Namech); + return; + } +/* + * Convert the tty's cdev from kernel to user form. + * + * Set the device number to DevDev, the device number of /dev. + * + * Set the inode number to the device number. + * + * Set the file type to N_CHR for a character device (That's what a PTS is.) + * + * Force the use of offset from file structure. + * + * Set rdev to the converted device. + * + * Force the reloading of the device cache. + */ + if ((dev = Dev2Udev((KA_T)t.t_dev)) == NODEV) { + (void) snpf(Namech, Namechl, + "can't convert device in DTYPE_PTS tty struct: %s", + print_kptr((KA_T)tp, (char *)NULL, 0)); + enter_nm(Namech); + return; + } + Lf->dev = DevDev; + Lf->inode = (INODETYPE)dev; + Lf->inp_ty = Lf->dev_def = Lf->rdev_def = 1; + Lf->ntype = N_CHR; + Lf->off_def = 1; + Lf->rdev = dev; + DCunsafe = 1; +} +#endif /* defined(HASPTSFN) && defined(DTYPE_PTS) */ diff --git a/dialects/freebsd/dnode1.c b/dialects/freebsd/dnode1.c new file mode 100644 index 0000000..f78b9f8 --- /dev/null +++ b/dialects/freebsd/dnode1.c @@ -0,0 +1,174 @@ +/* + * dnode1.c - FreeBSD 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"; +static char *rcsid = "$Id: dnode1.c,v 1.11 2018/02/14 14:26:03 abe Exp $"; +#endif + + +#include "lsof.h" + +#if defined(HAS9660FS) + +/* + * Do a little preparation for #include'ing cd9660_node.h, then #include it. + */ + +#undef i_size +#undef doff_t +#undef IN_ACCESS + +# if FREEBSDV>=4000 && defined(__alpha__) +#define dev_t void * +# endif /* FREEBSDV>=4000 && defined(__alpha__) */ + +#include "cd9660_node.h" + +# if defined(HAS_NO_ISO_DEV) +#define _KERNEL +#include +#undef _KERNEL +# endif /* defined(HAS_NO_ISO_DEV) */ + +# if FREEBSDV>=4000 && defined(__alpha__) +#undef dev_t +# endif /* FREEBSDV>=4000 && defined(__alpha__) */ + + +/* + * read_iso_node() -- read CD 9660 iso_node + */ + +int +read_iso_node(v, d, dd, ino, nl, sz) + struct vnode *v; /* containing vnode */ + dev_t *d; /* returned device number */ + int *dd; /* returned device-defined flag */ + INODETYPE *ino; /* returned inode number */ + long *nl; /* returned number of links */ + SZOFFTYPE *sz; /* returned size */ +{ + +# if FREEBSDV<2000 + struct iso_node *ip; +# else /* FREEBSDV>=2000 */ + struct iso_node i; +# endif /* FREEBSDV<2000 */ + +# if FREEBSDV>=4000 +# if FREEBSDV<5000 + struct specinfo udev; +# else /* FREEBSDV>=5000 */ + struct cdev udev; +# if defined(HAS_NO_ISO_DEV) + struct iso_mnt im; +# endif /* defined(HAS_NO_ISO_DEV) */ +# endif /* FREEBSDV<5000 */ +# endif /* FREEBSDV>=4000 */ + +# if FREEBSDV<2000 + ip = (struct iso_node *)v->v_data; + *d = ip->i_dev; + *dd = 1; + *ino = (INODETYPE)ip->i_number; + *nl = (long)ip->inode.iso_links; + *sz = (SZOFFTYPE)ip->i_size; +# else /* FREEBSDV>=2000 */ + if (!v->v_data + || kread((KA_T)v->v_data, (char *)&i, sizeof(i))) + return(1); + +# if FREEBSDV>=4000 +# if defined(HAS_NO_ISO_DEV) + if (i.i_mnt && !kread((KA_T)i.i_mnt, (char *)&im, sizeof(im)) + && im.im_dev && !kread((KA_T)im.im_dev, (char *)&udev, sizeof(udev))) +# else /* !defined(HAS_NO_ISO_DEV) */ + if (i.i_dev && !kread((KA_T)i.i_dev, (char *)&udev, sizeof(udev))) +# endif /* defined(HAS_NO_ISO_DEV) */ + + { + +# if defined(HAS_NO_SI_UDEV) + *d = Dev2Udev(&udev); +# else /* !defined(HAS_NO_SI_UDEV) */ + *d = udev.si_udev; +# endif /* defined(HAS_NO_SI_UDEV) */ + + *dd = 1; + } +# else /* FREEBSDV<4000 */ + *d = i.i_dev; + *dd = 1; +# endif /* FREEBSDV>=4000 */ + + *ino = (INODETYPE)i.i_number; + *nl = (long)i.inode.iso_links; + *sz = (SZOFFTYPE)i.i_size; +# endif /* FREEBSDV<2000 */ + + return(0); +} +#endif /* defined(HAS9660FS) */ + + +#if defined(HASFUSEFS) +#include +/* + * read_fuse_node() -- read FUSE file system fuse_node + */ + +int +read_fuse_node(v, d, dd, ino, nl, sz) + struct vnode *v; /* containing vnode */ + dev_t *d; /* returned device number */ + int *dd; /* returned device-defined flag */ + INODETYPE *ino; /* returned inode number */ + long *nl; /* returned number of links */ + SZOFFTYPE *sz; /* returned size */ +{ + struct fuse_vnode_data fn; /* FUSE node */ + + if (!v->v_data + || kread((KA_T)v->v_data, (char *)&fn, sizeof(fn))) + return(1); + *d = fn.cached_attrs.va_fsid; + *dd = 1; + *ino = (INODETYPE)fn.cached_attrs.va_fileid; + *nl = (long)fn.cached_attrs.va_nlink; + *sz = (SZOFFTYPE)fn.cached_attrs.va_size; + return(0); +} +#endif /* defined(HASFUSEFS) */ diff --git a/dialects/freebsd/dnode2.c b/dialects/freebsd/dnode2.c new file mode 100644 index 0000000..d8c9b87 --- /dev/null +++ b/dialects/freebsd/dnode2.c @@ -0,0 +1,153 @@ +/* + * dnode2.c - FreeBSD ZFS node functions for lsof + * + * This module must be separate to permit use of the OpenSolaris ZFS header + * files. + */ + + +/* + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright 2008 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: dnode2.c,v 1.7 2018/02/14 14:26:03 abe Exp $"; +#endif + + +#if defined(HAS_ZFS) + +#define _KERNEL + +# if defined(__clang__) +/* + * A clang workaround... + * + * Note: clang's complaint about VOP_FSYNC can't be avoided. + */ +#define VOP_UNLOCK(vp, f) ((void)0) +# endif /* defined(__clang__) */ + +#define KLD_MODULE /* for ARM: prevent "ARM_NARCH is 0 " error */ +#include +#undef _KERNEL + +#include "dzfs.h" + + +/* + * readzfsnode() -- read the ZFS node + */ + +char * +readzfsnode(za, zi, vr) + KA_T za; /* ZFS node address */ + zfs_info_t *zi; /* return ZFS info structure pointer */ + int vr; /* vnode's (v_flag & VROOT) */ +{ + struct znode zn; /* ZFS node */ + +# if defined(HAS_Z_PHYS) + znode_phys_t zp; /* ZFS physical node */ +# else /* !defined(HAS_Z_PHYS) */ + KA_T ka; /* temporary kernel address */ + zfsvfs_t zv; /* znode's zfsvfs structure */ +# endif /* defined(HAS_Z_PHYS) */ + + if (!za + || kread(za, (char *)&zn, sizeof(zn)) + ) { + if (!za) + return("No ZFS node address"); + return("Can't read znode"); + } +/* + * Return items contained in the znode. + */ + zi->ino = (INODETYPE)zn.z_id; + zi->ino_def = 1; + +# if !defined(HAS_V_LOCKF) + zi->lockf = (KA_T)zn.z_lockf; +# endif /* !defined(HAS_V_LOCKF) */ + +# if defined(HAS_Z_PHYS) +/* + * If the physical znode exists in this ZFS implementation, read it. + */ + if (!zn.z_phys + || kread((KA_T)zn.z_phys, (char *)&zp, sizeof(zp)) + ) { + if (!zn.z_phys) + return("No physical znode address"); + return("Can't read physical znode"); + } +/* + * Return items contained in the physical znode. + */ + zi->nl = (long)zp.zp_links; + zi->rdev = zp.zp_rdev; + zi->sz = (SZOFFTYPE)zp.zp_size; + zi->nl_def = zi->rdev_def = zi->sz_def = 1; +# else /* !defined(HAS_Z_PHYS) */ +/* + * If this implementation has no physical znode, return items now contained + * in the znode. + */ + zi->nl = (long)zn.z_links; + if (vr && (ka = (KA_T)zn.z_zfsvfs)) { + if (!kread(ka, (char *)&zv, sizeof(zv))) { + if ((zn.z_id == zv.z_root) + && (zv.z_ctldir != NULL) + && (zv.z_show_ctldir) + ) { + zi->nl++; + } + } + } + zi->sz = (SZOFFTYPE)zn.z_size; + zi->nl_def = zi->sz_def = 1; +# endif /* defined(HAS_Z_PHYS) */ + + return((char *)NULL); +} + + + + +# if defined(__GNUC__) && defined(HAS_CV_TIMEDWAIT_SBT) +/* + * A gcc work-around + */ + +int _cv_timedwait_sbt(struct cv *cvp, struct lock_object *lock, + sbintime_t sbt, sbintime_t pr, int flags) +{ + return(0); +} +# endif /* defined(__GNUC__) && HAS_CV_TIMEDWAIT_SBT */ +#endif /* defined(HAS_ZFS) */ diff --git a/dialects/freebsd/dproc.c b/dialects/freebsd/dproc.c new file mode 100644 index 0000000..0185686 --- /dev/null +++ b/dialects/freebsd/dproc.c @@ -0,0 +1,742 @@ +/* + * dproc.c - FreeBSD 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"; +static char *rcsid = "$Id: dproc.c,v 1.20 2018/02/14 14:26:03 abe Exp $"; +#endif + +#include "lsof.h" + + +_PROTOTYPE(static void enter_vn_text,(KA_T va, int *n)); +_PROTOTYPE(static void get_kernel_access,(void)); +_PROTOTYPE(static void process_text,(KA_T vm)); + + +/* + * Local static values + */ + +static MALLOC_S Nv = 0; /* allocated Vp[] entries */ +static KA_T *Vp = NULL; /* vnode address cache */ + + +/* + * enter_vn_text() - enter a vnode text reference + */ + +static void +enter_vn_text(va, n) + KA_T va; /* vnode address */ + int *n; /* Vp[] entries in use */ +{ + int i; +/* + * Ignore the request if the vnode has already been entered. + */ + for (i = 0; i < *n; i++) { + if (va == Vp[i]) + return; + } +/* + * Save the text file information. + */ + alloc_lfile(" txt", -1); + Cfp = (struct file *)NULL; + process_node(va); + if (Lf->sf) + link_lfile(); + if (i >= Nv) { + + /* + * Allocate space for remembering the vnode. + */ + Nv += 10; + if (!Vp) + Vp=(KA_T *)malloc((MALLOC_S)(sizeof(struct vnode *)*10)); + else + Vp=(KA_T *)realloc((MALLOC_P *)Vp,(MALLOC_S)(Nv*sizeof(KA_T))); + if (!Vp) { + (void) fprintf(stderr, "%s: no txt ptr space, PID %d\n", + Pn, Lp->pid); + Exit(1); + } + } +/* + * Remember the vnode. + */ + Vp[*n] = va; + (*n)++; +} + + +/* + * gather_proc_info() -- gather process information + */ + +void +gather_proc_info() +{ + 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 */ + struct filedesc fd; + int i, nf; + MALLOC_S nb; + +#if defined(HAS_FILEDESCENT) + typedef struct filedescent ofb_t; +#else /* !defined(HAS_FILEDESCENT) */ + typedef struct file* ofb_t; +#endif /* defined(HAS_FILEDESCENT) */ + +#if defined(HAS_FDESCENTTBL) + struct fdescenttbl fdt; + KA_T fa; +#endif /* defined(HAS_FDESCENTTBL) */ + + static ofb_t *ofb = NULL; + static int ofbb = 0; + int pgid, pid; + int ppid = 0; + short pss, sf; + int px; + int tid; /* thread (task) ID */ + uid_t uid; + +#if FREEBSDV<2000 + struct proc *p; + struct pcred pc; + struct pgrp pg; +#else /* FREEBSDV>=2000 */ + struct kinfo_proc *p; +#endif /* FREEBSDV<2000 */ + +#if defined(HASFSTRUCT) && !defined(HAS_FILEDESCENT) + static char *pof = (char *)NULL; + static int pofb = 0; +#endif /* defined(HASFSTRUCT) && !defiled(HAS_FILEDESCENT) */ + +/* + * 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 FREEBSDV<2000 + if ((Np = kvm_getprocs(KINFO_PROC_ALL, 0)) < 0) +#else /* FREEBSDV>=2000 */ + +# if !defined(KERN_PROC_PROC) +#define KERN_PROC_PROC KERN_PROC_ALL +# endif /* !defined(KERN_PROC_PROC) */ + + if ((P = kvm_getprocs(Kd, Ftask ? KERN_PROC_ALL : KERN_PROC_PROC, + 0, &Np)) + == NULL) +#endif /* FREEBSDV<2000 */ + + { + (void) fprintf(stderr, "%s: can't read process table: %s\n", + Pn, + +#if FREEBSDV<2000 + kvm_geterr() +#else /* FREEBSDV>=2000 */ + kvm_geterr(Kd) +#endif /* FREEBSDV<2000 */ + + ); + Exit(1); + } +/* + * Examine proc structures and their associated information. + */ + +#if FREEBSDV<2000 + for (px = 0; px < Np; px++) +#else /* FREEBSDV>=2000 */ + for (p = P, px = 0; px < Np; p++, px++) +#endif /* FREEBSDV<2000 */ + + { + +#if FREEBSDV<2000 + /* + * Read process information, process group structure (if + * necessary), and User ID (if necessary). + */ + if (!(p = kvm_nextproc())) + continue; + if (p->P_STAT == 0 || p->P_STAT == SZOMB) + continue; + pg.pg_id = 0; + if (Fpgid && p->P_PGID) { + if (kread((KA_T)p->P_PGID, (char *)&pg, sizeof(pg))) + continue; + } + pgid = pg.pg_id; + if (!p->p_cred + || kread((KA_T)p->p_cred, (char *)&pc, sizeof(pc))) + continue; + uid = pc.p_ruid; +#else /* FREEBSDV>=2000 */ + if (p->P_STAT == 0 || p->P_STAT == SZOMB) + continue; + pgid = p->P_PGID; +# if FREEBSDV<5000 + uid = p->kp_eproc.e_ucred.cr_uid; +# else /* FREEBSDV>=5000 */ + uid = p->ki_uid; +# endif /* FREEBSDV<5000 */ +#endif /* FREEBSDV<2000 */ + +#if defined(HASPPID) + ppid = p->P_PPID; +#endif /* defined(HASPPID) */ + +#if defined(HASTASKS) + /* + * See if process,including its tasks, is excluded. + */ + tid = Ftask ? (int)p->ki_tid : 0; + if (is_proc_excl(p->P_PID, pgid, (UID_ARG)uid, &pss, &sf, tid)) + continue; +#else /* !defined(HASTASKS) */ + /* + * See if process is excluded. + */ + if (is_proc_excl(p->P_PID, pgid, (UID_ARG)uid, &pss, &sf)) + continue; +#endif /* defined(HASTASKS) */ + + /* + * Read file structure pointers. + */ + if (!p->P_FD + || kread((KA_T)p->P_FD, (char *)&fd, sizeof(fd))) + continue; + +#if defined(HAS_FDESCENTTBL) + if (!fd.fd_files + || kread((KA_T)fd.fd_files, (char *)&fdt, sizeof(fdt))) + continue; + if (!fd.fd_refcnt || fd.fd_lastfile > fdt.fdt_nfiles) + continue; +#else /* !defined(HAS_FDESCENTTBL) */ + if (!fd.fd_refcnt || fd.fd_lastfile > fd.fd_nfiles) + continue; +#endif /* defined(HAS_FDESCENTTBL) */ + + /* + * Allocate a local process structure. + */ + if (is_cmd_excl(p->P_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(p->P_PID, pgid, ppid, (UID_ARG)uid, p->P_COMM, + (int)pss, (int)sf); + Plf = (struct lfile *)NULL; + +#if defined(HASTASKS) + /* + * Save the task (thread) ID. + */ + Lp->tid = tid; +#endif /* defined(HASTASKS) */ + +#if defined(P_ADDR) + /* + * Save the kernel proc struct address, if P_ADDR is defined. + */ + Kpa = (KA_T)p->P_ADDR; +#endif /* defined(P_ADDR) */ + + /* + * Save current working directory information. + */ + if (!ckscko && fd.fd_cdir) { + alloc_lfile(CWD, -1); + Cfp = (struct file *)NULL; + process_node((KA_T)fd.fd_cdir); + if (Lf->sf) + link_lfile(); + } + /* + * Save root directory information. + */ + if (!ckscko && fd.fd_rdir) { + alloc_lfile(RTD, -1); + Cfp = (struct file *)NULL; + process_node((KA_T)fd.fd_rdir); + if (Lf->sf) + link_lfile(); + } + +#if FREEBSDV>=5000 + /* + * Save jail directory information. + */ + if (!ckscko && fd.fd_jdir) { + alloc_lfile("jld", -1); + Cfp = (struct file *)NULL; + process_node((KA_T)fd.fd_jdir); + if (Lf->sf) + link_lfile(); + } +#endif /* FREEBSDV>=5000 */ + + /* + * Save information on the text file. + */ + if (!ckscko && p->P_VMSPACE) + process_text((KA_T)p->P_VMSPACE); + /* + * Read open file structure pointers. + */ + +#if defined(HAS_FDESCENTTBL) + if ((nf = fdt.fdt_nfiles) <= 0) + continue; +#else /* !defined(HAS_FDESCENTTBL) */ + if (!fd.fd_ofiles || (nf = fd.fd_nfiles) <= 0) + continue; +#endif /* defined(HAS_FDESCENTTBL) */ + + nb = (MALLOC_S)(sizeof(ofb_t) * nf); + if (nb > ofbb) { + if (!ofb) + ofb = (ofb_t *)malloc(nb); + else + ofb = (ofb_t *)realloc((MALLOC_P *)ofb, nb); + if (!ofb) { + (void) fprintf(stderr, "%s: PID %d, no file * space\n", + Pn, p->P_PID); + Exit(1); + } + ofbb = nb; + } + +#if defined(HAS_FDESCENTTBL) + fa = (KA_T)fd.fd_files + + (KA_T)offsetof(struct fdescenttbl, fdt_ofiles); + if (kread(fa, (char *)ofb, nb)) + continue; +#else /* !defined(HAS_FDESCENTTBL) */ + if (kread((KA_T)fd.fd_ofiles, (char *)ofb, nb)) + continue; +#endif /* defined(HAS_FDESCENTTBL) */ + + +#if defined(HASFSTRUCT) && !defined(HAS_FILEDESCENT) + if (Fsv & FSV_FG) { + nb = (MALLOC_S)(sizeof(char) * nf); + if (nb > pofb) { + if (!pof) + pof = (char *)malloc(nb); + else + pof = (char *)realloc((MALLOC_P *)pof, nb); + if (!pof) { + (void) fprintf(stderr, + "%s: PID %d, no file flag space\n", Pn, p->P_PID); + Exit(1); + } + pofb = nb; + } + if (!fd.fd_ofileflags || kread((KA_T)fd.fd_ofileflags, pof, nb)) + zeromem(pof, nb); + } +#endif /* defined(HASFSTRUCT) && !defined(HAS_FILEDESCENT) */ + + /* + * Save information on file descriptors. + */ + for (i = 0; i < nf; i++) { + +#if defined(HAS_FILEDESCENT) + if ((Cfp = ofb[i].fde_file)) +#else /* !defined(HAS_FILEDESCENT) */ + if ((Cfp = ofb[i])) +#endif /* defined(HAS_FILEDESCENT) */ + + { + alloc_lfile(NULL, i); + process_file((KA_T)Cfp); + if (Lf->sf) { + +#if defined(HASFSTRUCT) + if (Fsv & FSV_FG) +# if defined(HAS_FILEDESCENT) + Lf->pof = (long)ofb[i].fde_flags; +# else /* !defined(HAS_FILEDESCENT) */ + Lf->pof = (long)pof[i]; +# endif /* defined(HAS_FILEDESCENT) */ +#endif /* defined(HASFSTRUCT) */ + + link_lfile(); + } + } + } + /* + * Unless threads (tasks) are being processed, examine results. + */ + if (!Ftask) { + if (examine_lproc()) + return; + } + } +} + + +/* + * get_kernel_access() - get access to kernel memory + */ + +static void +get_kernel_access() +{ + +/* + * Check kernel version. + */ + (void) ckkv("FreeBSD", 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(1))) { + (void) fprintf(stderr, + "%s: can't get kernel name list path\n", Pn); + Exit(1); + } + } +#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(); +#else /* !defined(WILLDROPGID) */ +/* + * See if the non-KMEM memory and the name list files are readable. + */ + if ((Memory && !is_readable(Memory, 1)) + || (Nmlst && !is_readable(Nmlst, 1))) + Exit(1); +#endif /* defined(WILLDROPGID) */ + +/* + * Open kernel memory access. + */ + +#if FREEBSDV<2000 + if (kvm_openfiles(Nmlst, Memory, NULL) == -1) +#else /* FREEBSDV>=2000 */ + if ((Kd = kvm_open(Nmlst, Memory, NULL, O_RDONLY, NULL)) == NULL) +#endif /* FREEBSDV<2000 */ + + { + (void) fprintf(stderr, + "%s: kvm_open%s(execfile=%s, corefile=%s): %s\n", + Pn, + +#if FREEBSDV<2000 + "files", +#else /* FREEBSDV>=2000 */ + "", +#endif /* FREEBSDV<2000 */ + + Nmlst ? Nmlst : "default", + Memory ? Memory : + +#if defined(_PATH_MEM) + _PATH_MEM, +#else /* !defined(_PATH_MEM) */ + "default", +#endif /* defined(_PATH_MEM) */ + + strerror(errno)); + Exit(1); + } + (void) build_Nl(Drive_Nl); + if (kvm_nlist(Kd, Nl) < 0) { + (void) fprintf(stderr, "%s: can't read namelist from %s\n", + Pn, Nmlst); + Exit(1); + } + +#if defined(X_BADFILEOPS) +/* + * Get kernel's badfileops address (for process_file()). + */ + if (get_Nl_value(X_BADFILEOPS, (struct drive_Nl *)NULL, &X_bfopsa) < 0 + || !X_bfopsa) + { + X_bfopsa = (KA_T)0; + } +#endif /* defined(X_BADFILEOPS) */ + +#if defined(WILLDROPGID) +/* + * Drop setgid permission, if necessary. + */ + if (!Memory) + (void) dropgid(); +#endif /* defined(WILLDROPGID) */ + +} + + +#if !defined(N_UNIX) +/* + * get_nlist_path() - get kernel name list path + */ + +char * +get_nlist_path(ap) + 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, (int)bfl, bf); + Exit(1); + } + (void) snpf(bfc, bfl, "%s", bf); + return(bfc); + } + return((char *)NULL); +} +#endif /* !defined(N_UNIX) */ + + +/* + * initialize() - perform all initialization + */ + +void +initialize() +{ + get_kernel_access(); +} + + +/* + * kread() - read from kernel memory + */ + +int +kread(addr, buf, len) + KA_T addr; /* kernel memory address */ + char *buf; /* buffer to receive data */ + READLEN_T len; /* length to read */ +{ + int br; + +#if FREEBSDV<2000 + br = kvm_read((void *)addr, (void *)buf, len); +#else /* FREEBSDV>=2000 */ + br = kvm_read(Kd, (u_long)addr, buf, len); +#endif /* FREEBSDV<2000 */ + + return((br == len) ? 0 : 1); +} + + +/* + * process_text() - process text information + */ +void +process_text(vm) + KA_T vm; /* vm space pointer */ +{ + int i, j; + KA_T ka; + int n = 0; + struct vm_map_entry vmme, *e; + struct vm_object vmo; + struct vmspace vmsp; + +#if FREEBSDV<2020 + struct pager_struct pg; +#endif /* FREEBSDV<2020 */ + +/* + * Read the vmspace structure for the process. + */ + if (kread(vm, (char *)&vmsp, sizeof(vmsp))) + return; +/* + * Read the vm_map structure. Search its vm_map_entry structure list. + */ + for (i = 0; i < vmsp.vm_map.nentries; i++) { + + /* + * Read the next vm_map_entry. + */ + if (i == 0) + e = &vmsp.vm_map.header; + else { + if (!(ka = (KA_T)e->next)) + return; + e = &vmme; + if (kread(ka, (char *)e, sizeof(vmme))) + return; + } + +#if defined(MAP_ENTRY_IS_A_MAP) + if (e->eflags & (MAP_ENTRY_IS_A_MAP|MAP_ENTRY_IS_SUB_MAP)) +#else /* !defined(MAP_ENTRY_IS_A_MAP) */ + if (e->is_a_map || e->is_sub_map) +#endif /* defined(MAP_ENTRY_IS_A_MAP) */ + + continue; + /* + * Read the map entry's object and the object's shadow. + * Look for: a PG_VNODE pager handle (FreeBSD < 2.2); + * an OBJT_VNODE object type (FreeBSD >= 2.2). + */ + for (j = 0, ka = (KA_T)e->object.vm_object; + j < 2 && ka; + j++, + +#if FREEBSDV<2020 + ka = (KA_T)vmo.shadow +#else /* FREEBSDV>=2020 */ + ka = (KA_T)vmo.backing_object +#endif /* FREEBSDV<2020 */ + ) + { + if (kread(ka, (char *)&vmo, sizeof(vmo))) + break; + +#if FREEBSDV<2020 + if ((ka = (KA_T)vmo.pager) == NULL + || kread(ka, (char *)&pg, sizeof(pg))) + continue; + if (pg.pg_handle == NULL || pg.pg_type != PG_VNODE) + continue; + (void) (enter_vn_text((KA_T)pg.pg_handle, &n)); +#else /* FREEBSDV>=2020 */ + if (vmo.type != OBJT_VNODE + || vmo.handle == (void *)NULL) + continue; + (void) (enter_vn_text((KA_T)vmo.handle, &n)); +#endif /* FREEBSDV<2020 */ + + } + } +} diff --git a/dialects/freebsd/dproto.h b/dialects/freebsd/dproto.h new file mode 100644 index 0000000..ca05356 --- /dev/null +++ b/dialects/freebsd/dproto.h @@ -0,0 +1,74 @@ +/* + * dproto.h - FreeBSD 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.15 2018/02/14 14:26:03 abe Exp $ + */ + + +#if FREEBSDV>=5000 && defined(HAS_NO_SI_UDEV) +# if defined(HAS_CONF_MINOR)|| defined(HAS_CDEV2PRIV) +_PROTOTYPE(extern dev_t Dev2Udev,(KA_T c)); +# else /* !defined(HAS_CONF_MINOR) && !defined(HAS_CDEV2PRIV) */ +_PROTOTYPE(extern dev_t Dev2Udev,(struct cdev *c)); +# endif /* defined(HAS_CONF_MINOR) || defined(HAS_CDEV2PRIV) */ +#endif /* FREEBSDV>=5000 && defined(HAS_NO_SI_UDEV) */ + +#if !defined(N_UNIX) +_PROTOTYPE(extern char *get_nlist_path,(int ap)); +#endif /* !defined(N_UNIX) */ + +_PROTOTYPE(extern int is_file_named,(char *p, int cd)); +_PROTOTYPE(extern void process_socket,(KA_T sa)); +_PROTOTYPE(extern struct l_vfs *readvfs,(KA_T vm)); + +#if defined(HASPTSFN) +_PROTOTYPE(extern void process_pts,(KA_T ta)); +#endif /* defined(HASPTSFN) */ + +#if defined(HASKQUEUE) +_PROTOTYPE(extern void process_kqueue,(KA_T ka)); +#endif /* defined(HASKQUEUE) */ + +#if FREEBSDV>=2020 +_PROTOTYPE(extern void process_pipe,(KA_T pa)); +#endif /* FREEBSDV>=2020 */ + +#if defined(HASFUSEFS) +_PROTOTYPE(extern int read_fuse_node,(struct vnode *v, dev_t *d, int *dd, INODETYPE *ino, long *nl, SZOFFTYPE *sz)); +#endif /* defined(HASFUSEFS) */ + +#if defined(HAS9660FS) +_PROTOTYPE(extern int read_iso_node,(struct vnode *v, dev_t *d, int *dd, INODETYPE *ino, long *nl, SZOFFTYPE *sz)); +#endif /* defined(HAS9660FS) */ diff --git a/dialects/freebsd/dsock.c b/dialects/freebsd/dsock.c new file mode 100644 index 0000000..ee8ced7 --- /dev/null +++ b/dialects/freebsd/dsock.c @@ -0,0 +1,573 @@ +/* + * dsock.c - FreeBSD 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"; +static char *rcsid = "$Id: dsock.c,v 1.31 2018/02/14 14:26:03 abe Exp $"; +#endif + + +#include "lsof.h" + + +#if defined(HASIPv6) + +/* + * IPv6_2_IPv4() -- macro to define the address of an IPv4 address contained + * in an IPv6 address + */ + +#define IPv6_2_IPv4(v6) (((uint8_t *)((struct in6_addr *)v6)->s6_addr)+12) + +# if defined(HAS_NO_6PORT) +/* + * If the in_pcb structure no longer has the KAME accommodations of + * in6p_[fl]port, redefine them to inp_[fl]port. + */ + +#define in6p_fport inp_fport +#define in6p_lport inp_lport +# endif /* defined(HAS_NO_6PORT) */ + +# if defined(HAS_NO_6PPCB) +/* + * If the in_pcb structure no longer has the KAME accommodation of in6p_pcb, + * redefine it to inp_ppcb. + */ + +#define in6p_ppcb inp_ppcb +# endif /* defined(HAS_NO_6PPCB) */ +#endif /* defined(HASIPv6) */ + +#if defined(HAS_SB_CCC) +#define SOCK_CC sb_ccc +#else /* !defined(HAS_SB_CCC) */ +#define SOCK_CC sb_cc +#endif /* defined(HAS_SB_CCC) */ + + +/* + * Local function prototypes + */ + +_PROTOTYPE(static int ckstate,(KA_T pcb, KA_T ta, struct tcpcb *t, int fam)); + + +/* + * ckstate() -- read TCP control block and check TCP state for inclusion + * or exclusion + * return: -1 == no TCP CB available + * 0 == TCP DB available; continue processing file + * 1 == stop processing file + */ + +static int +ckstate(pcb, ta, t, fam) + KA_T pcb; /* PCB address */ + KA_T ta; /* TCP control block address */ + struct tcpcb *t; /* TCP control block receptor */ + int fam; /* protocol family */ +{ + int tsnx; +/* + * Read TCP control block. + */ + if (kread(ta, (char *)t, sizeof(struct tcpcb)) + || (KA_T)t->t_inpcb != pcb) + { + return(-1); + } + if (TcpStXn || TcpStIn) { + + /* + * If there are TCP state inclusions or exclusions, check them. + */ + if ((tsnx = (int)t->t_state + TcpStOff) >= TcpNstates) + return(0); + if (TcpStXn) { + if (TcpStX[tsnx]) { + Lf->sf &= ~SELNET; + Lf->sf |= SELEXCLF; + return(1); + } + } + if (TcpStIn) { + if (TcpStI[tsnx]) { + TcpStI[tsnx] = 2; + Lf->sf |= SELNET; + } else { + Lf->sf &= ~SELNET; + Lf->sf |= SELEXCLF; + return(1); + } + } + } + if (!(Lf->sf & SELNET) && !TcpStIn) { + + /* + * See if this TCP file should be selected. + */ + if (Fnet) { + if (!FnetTy + || ((FnetTy == 4) && (fam == AF_INET)) + +#if defined(HASIPv6) + || ((FnetTy == 6) && (fam == AF_INET6)) +#endif /* defined(HASIPv6) */ + + ) { + Lf->sf |= SELNET; + } + } + } + return(0); +} + + +/* + * process_socket() - process socket + */ + +void +process_socket(sa) + KA_T sa; /* socket address in kernel */ +{ + struct domain d; + unsigned char *fa = (unsigned char *)NULL; + int fam; + int fp, lp; + struct inpcb inp; + unsigned char *la = (unsigned char *)NULL; + struct protosw p; + struct socket s; + struct tcpcb t; + int ts = -1; + struct unpcb uc, unp; + struct sockaddr_un *ua = NULL; + struct sockaddr_un un; + +#if FREEBSDV<4050 + struct mbuf mb; +#else /* FREEBSDV>=4050 */ + int unl; +#endif /* FREEBSDV<4050 */ + +#if defined(HASIPv6) && !defined(HASINRIAIPv6) + struct in6pcb in6p; +#endif /* defined(HASIPv6) && !defined(HASINRIAIPv6) */ + + (void) snpf(Lf->type, sizeof(Lf->type), "sock"); + Lf->inp_ty = 2; +/* + * Read the socket, protocol, and domain structures. + */ + if (!sa) { + enter_nm("no socket address"); + return; + } + if (kread(sa, (char *) &s, sizeof(s))) { + (void) snpf(Namech, Namechl, "can't read socket struct from %s", + print_kptr(sa, (char *)NULL, 0)); + enter_nm(Namech); + return; + } + if (!s.so_type) { + enter_nm("no socket type"); + return; + } + if (!s.so_proto + || kread((KA_T)s.so_proto, (char *)&p, sizeof(p))) { + (void) snpf(Namech, Namechl, "can't read protocol switch from %s", + print_kptr((KA_T)s.so_proto, (char *)NULL, 0)); + enter_nm(Namech); + return; + } + if (!p.pr_domain + || kread((KA_T)p.pr_domain, (char *)&d, sizeof(d))) { + (void) snpf(Namech, Namechl, "can't read domain struct from %s", + print_kptr((KA_T)p.pr_domain, (char *)NULL, 0)); + enter_nm(Namech); + return; + } +/* + * Save size information. + */ + if (Fsize) { + if (Lf->access == 'r') + Lf->sz = (SZOFFTYPE)s.so_rcv.SOCK_CC; + else if (Lf->access == 'w') + Lf->sz = (SZOFFTYPE)s.so_snd.SOCK_CC; + else + Lf->sz = (SZOFFTYPE)(s.so_rcv.SOCK_CC + s.so_snd.SOCK_CC); + Lf->sz_def = 1; + } else + Lf->off_def = 1; + +#if defined(HASTCPTPIQ) + Lf->lts.rq = s.so_rcv.SOCK_CC; + Lf->lts.sq = s.so_snd.SOCK_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; + +# if __FreeBSD_version>=1200027 + if (s.so_options & SO_ACCEPTCONN) { + Lf->lts.pqlen = (unsigned int)s.sol_incqlen; + Lf->lts.qlen = (unsigned int)s.sol_qlen; + Lf->lts.qlim = (unsigned int)s.sol_qlimit; + } else { + Lf->lts.rbsz = (unsigned long)s.so_rcv.sb_mbmax; + Lf->lts.sbsz = (unsigned long)s.so_snd.sb_mbmax; + +# if defined(HASSBSTATE) + Lf->lts.sbs_rcv = s.so_rcv.sb_state; + Lf->lts.sbs_snd = s.so_snd.sb_state; +# endif /* defined(HASSBSTATE) */ + + } + +# else /* __FreeBSD_version<1200027 */ + Lf->lts.pqlen = (unsigned int)s.so_incqlen; + Lf->lts.qlen = (unsigned int)s.so_qlen; + Lf->lts.qlim = (unsigned int)s.so_qlimit; + Lf->lts.rbsz = (unsigned long)s.so_rcv.sb_mbmax; + Lf->lts.sbsz = (unsigned long)s.so_snd.sb_mbmax; + +# if defined(HASSBSTATE) + Lf->lts.sbs_rcv = s.so_rcv.sb_state; + Lf->lts.sbs_snd = s.so_snd.sb_state; +# endif /* defined(HASSBSTATE) */ +# endif /*__FreeBSD_version>=1200027 */ + + Lf->lts.pqlens = Lf->lts.qlens = Lf->lts.qlims = Lf->lts.rbszs + = Lf->lts.sbszs = (unsigned char)1; + +# if defined(HASSOSTATE) + Lf->lts.ss = (unsigned int)s.so_state; +# endif /* defined(HASSOSTATE) */ +#endif /* defined(HASSOPT) */ + +/* + * 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) */ + + ) { + if (!TcpStIn && !UdpStIn) + Lf->sf |= SELNET; + } + } + printiproto(p.pr_protocol); + +#if defined(HASIPv6) + (void) snpf(Lf->type, sizeof(Lf->type), + (fam == AF_INET) ? "IPv4" : "IPv6"); +#else /* !defined(HASIPv6) */ + (void) snpf(Lf->type, sizeof(Lf->type), "inet"); +#endif /* defined(HASIPv6) */ + +#if defined(HASIPv6) && !defined(HASINRIAIPv6) + if (fam == AF_INET6) { + + /* + * Read IPv6 protocol control block. + */ + if (!s.so_pcb + || kread((KA_T)s.so_pcb, (char *)&in6p, sizeof(in6p))) { + (void) snpf(Namech, Namechl, "can't read in6pcb at %s", + print_kptr((KA_T)s.so_pcb, (char *)NULL, 0)); + enter_nm(Namech); + return; + } + /* + * Save IPv6 address information. + */ + if (p.pr_protocol == IPPROTO_TCP) { + if (in6p.in6p_ppcb) { + if ((ts = ckstate((KA_T)s.so_pcb, (KA_T)in6p.in6p_ppcb, + &t, fam)) == 1) + { + return; + } + } + } + enter_dev_ch(print_kptr((KA_T)(in6p.in6p_ppcb ? in6p.in6p_ppcb + : s.so_pcb), + (char *)NULL, 0)); + la = (unsigned char *)&in6p.in6p_laddr; + lp = (int)ntohs(in6p.in6p_lport); + if (!IN6_IS_ADDR_UNSPECIFIED(&in6p.in6p_faddr) + || in6p.in6p_fport) + { + fa = (unsigned char *)&in6p.in6p_faddr; + fp = (int)ntohs(in6p.in6p_fport); + } + } else +#endif /* defined(HASIPv6) && !defined(HASINRIAIPv6) */ + + { + + /* + * Read Ipv4 or IPv6 (INRIA) protocol control block. + */ + if (!s.so_pcb + || kread((KA_T) s.so_pcb, (char *) &inp, sizeof(inp))) { + if (!s.so_pcb) { + (void) snpf(Namech, Namechl, "no PCB%s%s", + +#if defined(HASSBSTATE) + (s.so_snd.sb_state & SBS_CANTSENDMORE) ? +#else /* !defined(HASSBSTATE) */ + (s.so_state & SS_CANTSENDMORE) ? +#endif /* defined(HASSBSTATE) */ + + ", CANTSENDMORE" : "", +#if defined(HASSBSTATE) + (s.so_rcv.sb_state & SBS_CANTRCVMORE) ? +#else /* !defined(HASSBSTATE) */ + (s.so_state & SS_CANTRCVMORE) ? +#endif /* defined(HASSBSTATE) */ + + ", CANTRCVMORE" : ""); + } else { + (void) snpf(Namech, Namechl, "can't read inpcb at %s", + print_kptr((KA_T)s.so_pcb, (char *)NULL, 0)); + } + enter_nm(Namech); + return; + } + if (p.pr_protocol == IPPROTO_TCP) { + if (inp.inp_ppcb) { + if ((ts = ckstate((KA_T)s.so_pcb, (KA_T)inp.inp_ppcb, + &t, fam)) == 1) + { + return; + } + } + } + enter_dev_ch(print_kptr((KA_T)(inp.inp_ppcb ? inp.inp_ppcb + : s.so_pcb), + (char *)NULL, 0)); + lp = (int)ntohs(inp.inp_lport); + if (fam == AF_INET) { + + /* + * Save IPv4 address information. + */ + 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); + } + } + +#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(la, lp, fa, fp, fam); + if (ts == 0) { + Lf->lts.type = 0; + Lf->lts.state.i = (int)t.t_state; + +#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: + (void) snpf(Lf->type, sizeof(Lf->type), "rte"); + if (s.so_pcb) + enter_dev_ch(print_kptr((KA_T)(s.so_pcb), (char *)NULL, 0)); + else + (void) snpf(Namech, Namechl, "no protocol control block"); + if (!Fsize) + Lf->off_def = 1; + break; +/* + * Process a Unix domain socket. + */ + case AF_UNIX: + if (Funix) + Lf->sf |= SELUNX; + (void) snpf(Lf->type, sizeof(Lf->type), "unix"); + /* + * Read Unix protocol control block and the Unix address structure. + */ + + enter_dev_ch(print_kptr(sa, (char *)NULL, 0)); + if (kread((KA_T) s.so_pcb, (char *) &unp, sizeof(unp))) { + (void) snpf(Namech, Namechl, "can't read unpcb at %s", + print_kptr((KA_T)s.so_pcb, (char *)NULL, 0)); + break; + } + if ((struct socket *)sa != unp.unp_socket) { + (void) snpf(Namech, Namechl, "unp_socket (%s) mismatch", + print_kptr((KA_T)unp.unp_socket, (char *)NULL, 0)); + break; + } + if (unp.unp_addr) { + +#if FREEBSDV<4050 + if (kread((KA_T)unp.unp_addr, (char *)&mb, sizeof(mb))) +#else /* FREEBSDV>=4050 */ + if (kread((KA_T)unp.unp_addr, (char *)&un, sizeof(un))) +#endif /* FREEBSDV<4050 */ + + { + (void) snpf(Namech, Namechl, "can't read unp_addr at %s", + print_kptr((KA_T)unp.unp_addr, (char *)NULL, 0)); + break; + } + +#if FREEBSDV<4050 + 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 /* FREEBSDV>=4050 */ + ua = &un; +#endif /* FREEBSDV<4050 */ + + } + if (!ua) { + ua = &un; + (void) bzero((char *)ua, sizeof(un)); + ua->sun_family = AF_UNSPEC; + } + /* + * Print information on Unix socket that has no address bound + * to it, although it may be connected to another Unix domain + * socket as a pipe. + */ + if (ua->sun_family != AF_UNIX) { + if (ua->sun_family == AF_UNSPEC) { + if (unp.unp_conn) { + if (kread((KA_T)unp.unp_conn, (char *)&uc, sizeof(uc))) + (void) snpf(Namech, Namechl, + "can't read unp_conn at %s", + print_kptr((KA_T)unp.unp_conn,(char *)NULL,0)); + else + (void) snpf(Namech, Namechl, "->%s", + print_kptr((KA_T)uc.unp_socket,(char *)NULL,0)); + } else + (void) snpf(Namech, Namechl, "->(none)"); + } else + (void) snpf(Namech, Namechl, "unknown sun_family (%d)", + ua->sun_family); + break; + } + if (ua->sun_path[0]) { + +#if FREEBSDV<4050 + if (mb.m_len >= sizeof(struct sockaddr_un)) + mb.m_len = sizeof(struct sockaddr_un) - 1; + *((char *)ua + mb.m_len) = '\0'; +#else /* FREEBSDV>=4050 */ +# if FREEBSDV>4060 + unl = ua->sun_len - offsetof(struct sockaddr_un, sun_path); +# else /* FREEBSDV<4060 */ + unl = sizeof(ua->sun_path) - 1; +# endif /* FREEBSDV>4060 */ + if ((unl < 0) || (unl >= sizeof(ua->sun_path))) + unl = sizeof(ua->sun_path) - 1; + ua->sun_path[unl] = '\0'; +#endif /* FREEBSDV<4050 */ + + if (ua->sun_path[0] && Sfile && is_file_named(ua->sun_path, 0)) + Lf->sf |= SELNM; + if (ua->sun_path[0] && !Namech[0]) + (void) snpf(Namech, Namechl, "%s", ua->sun_path); + } else + (void) snpf(Namech, Namechl, "no address"); + break; + default: + printunkaf(fam, 1); + } + if (Namech[0]) + enter_nm(Namech); +} diff --git a/dialects/freebsd/dstore.c b/dialects/freebsd/dstore.c new file mode 100644 index 0000000..0de224a --- /dev/null +++ b/dialects/freebsd/dstore.c @@ -0,0 +1,140 @@ +/* + * dstore.c - FreeBSD 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"; +static char *rcsid = "$Id: dstore.c,v 1.9 2018/02/14 14:26:03 abe Exp $"; +#endif + + +#include "lsof.h" + +struct file *Cfp; /* curent file's file struct pointer */ + + +/* + * Drive_Nl -- table to drive the building of Nl[] via build_Nl() + * (See lsof.h and misc.c.) + */ + +struct drive_Nl Drive_Nl[] = { + + { X_BADFILEOPS, "badfileops" }, + +#if FREEBSDV<2005 + { X_NCACHE, "_nchhead" }, +#else /* FREEBSDV>=2005 */ +# if FREEBSDV<2010 + { X_NCACHE, "_nclruhead" }, +# else /* FREEBSDV>=2010 */ + { X_NCACHE, "_nchashtbl" }, +# endif /* FREEBSDV<2010 */ +#endif /* FREEBSDV<2005 */ + +#if FREEBSDV<2010 + { X_NCSIZE, "_numcache" }, +#else /* FREEBSDV>=2010 */ + { X_NCSIZE, "_nchash" }, +#endif /* FREEBSDV<2010 */ + + { "", "" }, + { NULL, NULL } +}; + +#if FREEBSDV>=2000 +kvm_t *Kd = NULL; /* kvm descriptor */ +#endif /* FREEBSDV>=2000 */ + +#if defined(P_ADDR) +KA_T Kpa; /* kernel proc struct address */ +#endif /* defined(P_ADDR) */ + +struct l_vfs *Lvfs = NULL; /* local vfs structure table */ + +int Np = 0; /* number of kernel processes */ + +#if FREEBSDV>=2000 +struct kinfo_proc *P = NULL; /* local process table copy */ +#endif /* FREEBSDV>=2000 */ + +#if defined(HASFSTRUCT) +/* + * Pff_tab[] - table for printing file flags + */ + +struct pff_tab Pff_tab[] = { + { (long)FREAD, FF_READ }, + { (long)FWRITE, FF_WRITE }, + { (long)FNONBLOCK, FF_NBLOCK }, + { (long)FNDELAY, FF_NDELAY }, + { (long)FAPPEND, FF_APPEND }, + { (long)FASYNC, FF_ASYNC }, + { (long)FFSYNC, FF_FSYNC }, + +# if defined(FMARK) + { (long)FMARK, FF_MARK }, +# endif /* defined(FMARK) */ + +# if defined(FDEFER) + { (long)FDEFER, FF_DEFER }, +# endif /* defined(FDEFER) */ + + { (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 }, +# endif /* defined(UF_EXCLOSE) */ + +# if defined(UF_MAPPED) + { (long)UF_MAPPED, POF_MAPPED }, +# endif /* defined(UF_MAPPED) */ + + { (long)0, NULL } +}; +#endif /* defined(HASFSTRUCT) */ + + +/* + * Kernel's bad file operations address + */ + +KA_T X_bfopsa; /* badfileops kernel address */ diff --git a/dialects/freebsd/dzfs.h b/dialects/freebsd/dzfs.h new file mode 100644 index 0000000..6ffe7de --- /dev/null +++ b/dialects/freebsd/dzfs.h @@ -0,0 +1,112 @@ +/* + * dzfs.h - FreeBSD header file for ZFS + */ + + +/* + * 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. + */ + + +/* + * $Id: dzfs.h,v 1.3 2011/08/07 22:51:28 abe Exp $ + */ + + +#if !defined(FREEBSD_ZFS_H) +#define FREEBSD_ZFS_H 1 +# if defined(HAS_ZFS) + + +/* + * The _PROTOTYPE macro provides strict ANSI C prototypes if __STDC__ + * is defined, and old-style K&R prototypes otherwise. + * + * (With thanks to Andy Tanenbaum) + */ + +# if defined(__STDC__) +#define _PROTOTYPE(function, params) function params +# else /* !defined(__STDC__) */ +#define _PROTOTYPE(function, params) function() +# endif /* defined(__STDC__) */ + + +/* + * 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 */ + +# if !defined(INODETYPE) +#define INODETYPE unsigned long long +# endif /* !defined(INODETYPE) */ + +# if !defined(FREEBSD_KA_T) +# if FREEBSDV<2000 +typedef off_t KA_T; +# else /* FREEBSDV>=2000 */ +typedef u_long KA_T; +# endif /* FREEBSDV<2000 */ +#define FREEBSD_KA_T 1 /* for dlsof.h */ +# endif /* !defined(FREEBSD_KA_T) */ + +# if !defined(READLEN_T) +#define READLEN_T int +# endif /* !defined(READLEN_T) */ + +# if !defined(SZOFFTYPE) +#define SZOFFTYPE unsigned long long +# endif /* !defined(SZOFFTYPE) */ + + +/* + * Structure for passing znode info + */ + +typedef struct zfs_info { + INODETYPE ino; /* inode number */ + KA_T lockf; /* znode's z_lockf pointer */ + long nl; /* number of links */ + dev_t rdev; /* "raw" device number */ + SZOFFTYPE sz; /* size */ + unsigned char ino_def; /* ino defined status */ + unsigned char nl_def; /* nl defined status */ + unsigned char rdev_def; /* rdev defined status */ + unsigned char sz_def; /* sz defined status */ +} zfs_info_t; + +_PROTOTYPE(extern int kread,(KA_T addr, char *buf, READLEN_T len)); +_PROTOTYPE(extern char *readzfsnode,(KA_T va, zfs_info_t *zi, int vr)); + +# endif /* defined(HAS_ZFS) */ +#endif /* defined(FREEBSD_DZFS_H) */ diff --git a/dialects/freebsd/include/procfs/pfsnode.h b/dialects/freebsd/include/procfs/pfsnode.h new file mode 100644 index 0000000..6979e49 --- /dev/null +++ b/dialects/freebsd/include/procfs/pfsnode.h @@ -0,0 +1,217 @@ +/* + * Copyright (c) 1993 Paul Kranenburg + * 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 Paul Kranenburg. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR 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. + * + * $Id: pfsnode.h,v 1.1 1993/12/12 12:26:39 davidg Exp $ + */ + +/* + * This structure defines the control data for the proc file system. + */ + +struct pfsnode { + struct pfsnode *pfs_next; /* next on list */ + struct vnode *pfs_vnode; /* vnode associated with this pfsnode */ + pid_t pfs_pid; /* associated process */ + u_short pfs_mode; /* mode bits for stat() */ + uid_t pfs_uid; /* process' owner */ + gid_t pfs_gid; /* process' group */ + u_long pfs_vflags; /* chflags() flags */ + u_long pfs_flags; /* open flags */ + struct vmspace *pfs_vs; +}; + +struct pfsnode *pfshead; + +/* + * Format of a directory entry in /proc + */ +struct pfsdent { + unsigned long d_fileno; + unsigned short d_reclen; + unsigned short d_namlen; + char d_nam[8]; +}; +#define PFSDENTSIZE (sizeof(struct direct) - MAXNAMELEN + 8) + +#ifndef DIRBLKSIZ +#define DIRBLKSIZ DEV_BSIZE +#endif + +#ifdef DEBUG +int pfs_debug; +#endif + +/* + * Convert between pfsnode pointers and vnode pointers + */ +#define VTOPFS(vp) ((struct pfsnode *)(vp)->v_data) +#define PFSTOV(pfsp) ((pfsp)->pfs_vnode) + +/* + * Prototypes for PFS operations on vnodes. + */ +int pfs_badop(); +int pfs_doio(); +int pfs_lookup __P(( \ + struct vnode *vp, \ + struct nameidata *ndp, \ + struct proc *p)); +#define pfs_create ((int (*) __P(( \ + struct nameidata *ndp, \ + struct vattr *vap, \ + struct proc *p))) pfs_badop) +#define pfs_mknod ((int (*) __P(( \ + struct nameidata *ndp, \ + struct vattr *vap, \ + struct ucred *cred, \ + struct proc *p))) pfs_badop) +int pfs_open __P(( + struct vnode *vp, + int mode, + struct ucred *cred, + struct proc *p)); +int pfs_close __P(( + struct vnode *vp, + int fflag, + struct ucred *cred, + struct proc *p)); +int pfs_access __P(( + struct vnode *vp, + int mode, + struct ucred *cred, + struct proc *p)); +int pfs_getattr __P(( + struct vnode *vp, + struct vattr *vap, + struct ucred *cred, + struct proc *p)); +int pfs_setattr __P(( + struct vnode *vp, + struct vattr *vap, + struct ucred *cred, + struct proc *p)); +#define pfs_read ((int (*) __P(( \ + struct vnode *vp, \ + struct uio *uio, \ + int ioflag, \ + struct ucred *cred))) pfs_doio) +#define pfs_write ((int (*) __P(( \ + struct vnode *vp, \ + struct uio *uio, \ + int ioflag, \ + struct ucred *cred))) pfs_doio) +int pfs_ioctl __P(( + struct vnode *vp, + int command, + caddr_t data, + int fflag, + struct ucred *cred, + struct proc *p)); +#define pfs_select ((int (*) __P(( \ + struct vnode *vp, \ + int which, \ + int fflags, \ + struct ucred *cred, \ + struct proc *p))) pfs_badop) +#define pfs_mmap ((int (*) __P(( \ + struct vnode *vp, \ + int fflags, \ + struct ucred *cred, \ + struct proc *p))) pfs_badop) +#define pfs_fsync ((int (*) __P(( \ + struct vnode *vp, \ + int fflags, \ + struct ucred *cred, \ + int waitfor, \ + struct proc *p))) pfs_badop) +#define pfs_seek ((int (*) __P(( \ + struct vnode *vp, \ + off_t oldoff, \ + off_t newoff, \ + struct ucred *cred))) pfs_badop) +#define pfs_remove ((int (*) __P(( \ + struct nameidata *ndp, \ + struct proc *p))) pfs_badop) +#define pfs_link ((int (*) __P(( \ + struct vnode *vp, \ + struct nameidata *ndp, \ + struct proc *p))) pfs_badop) +#define pfs_rename ((int (*) __P(( \ + struct nameidata *fndp, \ + struct nameidata *tdnp, \ + struct proc *p))) pfs_badop) +#define pfs_mkdir ((int (*) __P(( \ + struct nameidata *ndp, \ + struct vattr *vap, \ + struct proc *p))) pfs_badop) +#define pfs_rmdir ((int (*) __P(( \ + struct nameidata *ndp, \ + struct proc *p))) pfs_badop) +#define pfs_symlink ((int (*) __P(( \ + struct nameidata *ndp, \ + struct vattr *vap, \ + char *target, \ + struct proc *p))) pfs_badop) +int pfs_readdir __P(( + struct vnode *vp, + struct uio *uio, + struct ucred *cred, + int *eofflagp)); +#define pfs_readlink ((int (*) __P(( \ + struct vnode *vp, \ + struct uio *uio, \ + struct ucred *cred))) pfs_badop) +#define pfs_abortop ((int (*) __P(( \ + struct nameidata *ndp))) pfs_badop) +int pfs_inactive __P(( + struct vnode *vp, + struct proc *p)); +int pfs_reclaim __P(( + struct vnode *vp)); +#define pfs_lock ((int (*) __P(( \ + struct vnode *vp))) nullop) +#define pfs_unlock ((int (*) __P(( \ + struct vnode *vp))) nullop) +int pfs_bmap __P(( + struct vnode *vp, + daddr_t bn, + struct vnode **vpp, + daddr_t *bnp)); +int pfs_strategy __P(( + struct buf *bp)); +void pfs_print __P(( + struct vnode *vp)); +#define pfs_islocked ((int (*) __P(( \ + struct vnode *vp))) nullop) +#define pfs_advlock ((int (*) __P(( \ + struct vnode *vp, \ + caddr_t id, \ + int op, \ + struct flock *fl, \ + int flags))) pfs_badop) diff --git a/dialects/freebsd/machine.h b/dialects/freebsd/machine.h new file mode 100644 index 0000000..d47de0c --- /dev/null +++ b/dialects/freebsd/machine.h @@ -0,0 +1,687 @@ +/* + * machine.h - FreeBSD 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.40 2018/02/14 14:26:03 abe Exp $ + */ + + +#if !defined(LSOF_MACHINE_H) +#define LSOF_MACHINE_H 1 + +#include + +# if defined(HAS_CONF_MINOR) +#undef minor +# endif /* defined(HAS_CONF_MINOR) */ + +#if defined(HASCPUMASK_T) +/* + * In FreeBSD >= 5.2 when the cpumask_t typedef is present, it may be defined + * in only if _KERNEL is predefined. However, predefining + * _KERNEL before #include'ing causes redefinition errors for + * boolean_t and vm_page_t when is #include'd with _KERNEL + * predefined. Since lsof must have _KERNEL predefined when is + * #include'd, the expedient choice is made to duplicate the cpumask_t typedef + * here. + * + * Note: the Configure script defines HASCPUMASK_T if and + * both have cpumask_t references and if the reference in + * is valid only when _KERNEL is defined. + */ + +typedef __cpumask_t cpumask_t; +#endif /* defined(HASCPUMASK_T) */ + +#if defined(NEEDS_BOOL_TYPEDEF) +/* + * Under FreeBSD 10.0 on the i386 architecture the bool typedef is not defined + * unless is #included under _KERNEL. As explained with + * cpumask_t, #include'ing under _KERNEL causes other problems. + * Hence Configure specifies that bool be typedef'd here specifically for the + * i386 architecture on FreeBSD 10.0. + */ +# if __STDC_VERSION__<199901L && __GNUC__<3 && !defined(__INTEL_COMPILER) +typedef int _Bool; +# endif /*__STDC_VERSION__<199901L && __GNUC__<3 && !defined(__INTEL_COMPILER)*/ +typedef _Bool bool; +#endif /* defined(NEEDS_BOOL_TYPEDEF) */ + +#include + + +/* + * 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 option. + */ + +/* #define HASAOPT 1 */ + + +/* + * HASBLKDEV is defined for those dialects that want block device information + * recorded in BDevtp[]. + */ + +# if FREEBSDV<4000 +#define HASBLKDEV 1 +# endif /* FREEBSDV<4000 */ + + +/* + * 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 FREEBSDV>=2020 +#define HASPIPEFN process_pipe +# endif /* FREEBSDV>=2020 */ + + +/* + * 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. + */ + +# if FREEBSDV>=2000 +#define HASPPID 1 +# endif /* FREEBSDV>=2000 */ + + +/* + * HASPRINTDEV, HASPRINTINO, HASPRINTNM, HASPRINTOFF, and HASPRINTSZ + * define private dialect-specific functions for printing DEVice numbers, + * INOde numbers, NaMes, file OFFsets, and file SiZes. The functions are + * called from print_file(). + */ + +/* #define HASPRINTDEV print_dev? */ +/* #define HASPRINTINO print_ino? */ +/* #define HASPRINTNM print_nm? */ +/* #define HASPRINTOFF print_off? */ +/* #define HASPRINTSZ print_sz? */ + + +/* + * HASPRIVFILETYPE and PRIVFILETYPE are defined for dialects that have a + * file structure type that isn't defined by a DTYPE_* symbol. They are + * used in lib/prfp.c to select the type's processing. + * + * PRIVFILETYPE is the definition of the f_type value in the file struct. + * + * HASPRIVFILETYPE is the name of the processing function. + */ + +/* #define HASPRIVFILETYPE process_shmf? */ +/* #define PRIVFILETYPE ?? */ + + +/* + * HASPRIVNMCACHE is defined for dialects that have a private method for + * printing cached NAME column values for some files. HASPRIVNAMECACHE + * is defined to be the name of the function. + * + * The function takes one argument, a struct lfile pointer to the file, and + * returns non-zero if it prints a name to stdout. + */ + +/* #define HASPRIVNMCACHE */ + + +/* + * 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 2.0 and + * above the Configure script defines HASPROCFS when it can find + * /usr/src/sys/miscfs/procfs/procfs.h; below 2.0, Configure always defines + * HASPROCFS. + * + * 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 */ + +# if FREEBSDV>=2000 +#define HASPINODEN 1 +# endif /* FREEBSDV>=2000 */ + + +/* + * HASPTSFN is defined for dialects that have a DTYPE_PTS file descriptor + * type. The definition names the function that processes the type. + * + * + * NOTE: don't forget to define a prototype for this function in dproto.h. + */ + +#define HASPTSFN process_pts + + +/* + * 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 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 FREEBSDV>=5200 +#define HASWIDECHAR 1 +# endif /* FREEBSDV>=5020 */ + +/* #define WIDECHARINCL */ + + +/* + * 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. + * 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_ is defined for dialects that use the + * in the lsof library. + * + * Note: other definitions and operations may be required to condition the + * library function source code. They may be found in the dialect dlsof.h + * header files. + */ + +#define USE_LIB_CKKV 1 /* ckkv.c */ +/* #define USE_LIB_COMPLETEVFS 1 cvfs.c */ +#define USE_LIB_FIND_CH_INO 1 /* fino.c */ +#define USE_LIB_IS_FILE_NAMED 1 /* isfn.c */ +#define USE_LIB_LKUPDEV 1 /* lkud.c */ +#define USE_LIB_PRINTDEVNAME 1 /* pdvn.c */ +#define USE_LIB_PROCESS_FILE 1 /* prfp.c */ +#define USE_LIB_PRINT_TCPTPI 1 /* ptti.c */ +#define USE_LIB_READDEV 1 /* rdev.c */ +/* #define USE_LIB_READMNT 1 rmnt.c */ +/* #define USE_LIB_REGEX 1 regex.c */ + +# if FREEBSDV<2010 +#define USE_LIB_RNAM 1 /* rnam.c */ +# else /* FREEBSDV>=2010 */ +#define USE_LIB_RNMH 1 /* rnmh.c */ +# endif /* FREEBSDV<2010 */ + +/* #define USE_LIB_RNCH 1 rnch.c */ +/* #define USE_LIB_SNPF 1 snpf.c */ +#define snpf snprintf /* use the system's snprintf() */ + + +/* + * WARNDEVACCESS is defined for those dialects that should issue a warning + * when lsof can't access /dev (or /device) or one of its sub-directories. + * The warning can be inhibited by the lsof caller with the -w option. + */ + +#define WARNDEVACCESS 1 + + +/* + * WARNINGSTATE is defined for those dialects that want to suppress all lsof + * warning messages. + */ + +/* #define WARNINGSTATE 1 warnings are enabled by default */ + + +/* + * WILLDROPGID is defined for those dialects whose lsof executable runs + * setgid(not_real_GID) and whose setgid power can be relinquished after + * the dialect's initialize() function has been executed. + */ + +#define WILLDROPGID 1 + + +/* + * zeromem is a macro that uses bzero or memset. + */ + +#define zeromem(a, l) memset(a, 0, l) + +#endif /* !defined(LSOF_MACHINE_H) */ diff --git a/dialects/hpux/kmem/Makefile b/dialects/hpux/kmem/Makefile new file mode 100644 index 0000000..e71696b --- /dev/null +++ b/dialects/hpux/kmem/Makefile @@ -0,0 +1,161 @@ + +# 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_CCDATE "'`date`'"' >> version.h + @echo '#define LSOF_CCFLAGS "'`echo ${CFLAGS} | sed 's/\\\\(/\\(/g' | sed 's/\\\\)/\\)/g' | sed 's/"/\\\\"/g'`'"' >> version.h + @echo '#define LSOF_CINFO "${CINFO}"' >> version.h + @if [ "X${LSOF_HOST}" = "X" ]; then \ + echo '#define LSOF_HOST "'`uname -n`'"' >> version.h; \ + else \ + if [ "${LSOF_HOST}" = "none" ]; then \ + echo '#define LSOF_HOST ""' >> version.h; \ + else \ + echo '#define LSOF_HOST "${LSOF_HOST}"' >> version.h; \ + fi \ + fi + @echo '#define LSOF_LDFLAGS "${CFGL}"' >> version.h + @if [ "X${LSOF_LOGNAME}" = "X" ]; then \ + echo '#define LSOF_LOGNAME "${LOGNAME}"' >> version.h; \ + else \ + if [ "${LSOF_LOGNAME}" = "none" ]; then \ + echo '#define LSOF_LOGNAME ""' >> version.h; \ + else \ + echo '#define LSOF_LOGNAME "${LSOF_LOGNAME}"' >> version.h; \ + fi; \ + fi + @if [ "X${LSOF_SYSINFO}" = "X" ]; then \ + echo '#define LSOF_SYSINFO "'`uname -a`'"' >> version.h; \ + else \ + if [ "${LSOF_SYSINFO}" = "none" ]; then \ + echo '#define LSOF_SYSINFO ""' >> version.h; \ + else \ + echo '#define LSOF_SYSINFO "${LSOF_SYSINFO}"' >> version.h; \ + fi \ + fi + @if [ "X${LSOF_USER}" = "X" ]; then \ + echo '#define LSOF_USER "${USER}"' >> version.h; \ + else \ + if [ "${LSOF_USER}" = "none" ]; then \ + echo '#define LSOF_USER ""' >> version.h; \ + else \ + echo '#define LSOF_USER "${LSOF_USER}"' >> version.h; \ + fi \ + fi + @sed '/VN/s/.ds VN \(.*\)/#define LSOF_VERSION "\1"/' < version >> version.h + +FRC: + +# DO NOT DELETE THIS LINE - make depend DEPENDS ON IT + +dfile.o: ${HDR} dfile.c + +dmnt.o: ${HDR} dmnt.c + +dnode.o: ${HDR} dnode.c + +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/dialects/hpux/kmem/Mksrc b/dialects/hpux/kmem/Mksrc new file mode 100755 index 0000000..f94d164 --- /dev/null +++ b/dialects/hpux/kmem/Mksrc @@ -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/dialects/hpux/kmem/dfile.c b/dialects/hpux/kmem/dfile.c new file mode 100644 index 0000000..f6c866b --- /dev/null +++ b/dialects/hpux/kmem/dfile.c @@ -0,0 +1,266 @@ +/* + * 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"; +static char *rcsid = "$Id: dfile.c,v 1.14 2001/08/14 13:27:16 abe Exp $"; +#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 "lsof.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(lf, 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((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; + + if (f.f_count) { + +#if defined(HASFSTRUCT) + /* + * Save file structure values. + */ + if (Fsv & FSV_CT) { + Lf->fct = (long)f.f_count; + Lf->fsv |= FSV_CT; + } + if (Fsv & FSV_FA) { + Lf->fsa = fp; + Lf->fsv |= FSV_FA; + } + if (Fsv & FSV_FG) { + Lf->ffg = (long)f.f_flag; + Lf->fsv |= FSV_FG; + } + if (Fsv & FSV_NI) { + Lf->fna = (KA_T)f.f_data; + Lf->fsv |= FSV_NI; + } +#endif /* defined(HASFSTRUCT) */ + + /* + * Construct access code. + */ + if ((flag = (f.f_flag & (FREAD | FWRITE))) == FREAD) + Lf->access = 'r'; + else if (flag == FWRITE) + Lf->access = 'w'; + else if (flag == (FREAD | FWRITE)) + Lf->access = 'u'; + /* + * 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(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(qa, (char *)&q, sizeof(q))) + break; + if (!(ka = (KA_T)q.q_qinfo) || kread(ka, (char *)&qi, sizeof(qi))) + continue; + if (!(ka = (KA_T)qi.qi_minfo) || kread(ka, (char *)&mi, sizeof(mi))) + continue; + if (!(ka = (KA_T)mi.mi_idname) || kread(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/dialects/hpux/kmem/dlsof.h b/dialects/hpux/kmem/dlsof.h new file mode 100644 index 0000000..984074b --- /dev/null +++ b/dialects/hpux/kmem/dlsof.h @@ -0,0 +1,441 @@ +/* + * 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 +# endif /* HPUXV>=1030 */ + +#include +#include +#include +#include +#include +#include +#include + +# if HPUXV<1020 +#include +# 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 + +# if HPUXV>=1020 +#define _INCLUDE_STRUCT_FILE +# endif /* HPUXV>=1020 */ + +# if HPUXV>=1030 +struct uio { /* to satisfy function prototypes in */ + int dummy; +}; +# endif /* HPUXV>=1030 */ + +#include + +# if HPUXV>=1020 +#undef _INCLUDE_STRUCT_FILE +# endif /* HPUXV>=1020 */ + +# if HPUXV>=1030 +#include +#include "sth.h" +# endif /* HPUXV>=1030 */ + +#include + +# if HPUXV>=800 +#undef _PROTOTYPES +#include +# endif /* HPUXV>=800 */ + +#include + +# if HPUXV<1010 +#include +# endif /* HPUXV<1010 */ + +#include +#include +#include +#include +#include + +# if HPUXV<1030 +#include +#include +# endif /* HPUXV<1030 */ + +#include +#include +#include + +# if HPUXV<1030 +#include +#include +#include +# else /* HPUXV>=1030 */ +#include +/* + * 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 +#include +#include + +# if HPUXV>=1030 +#include +# endif /* HPUXV>=1030 */ + +# if HPUXV>=1000 +#include +#include +#include +#include +#include +#include +# endif /* HPUXV>=1000 */ + +#include + +/* + * 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 +# if defined(HASRNODE3) +/* + * This rnode structure definition should come from , 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 . + * + * 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 +# endif /* defined(HASRNODE3) */ +# endif /* HPUXV<1030 */ + +#include + +# if HPUXV>=1000 +#define _KERNEL +#include +#undef _KERNEL +# endif /* HPUXV>=1000 */ + +# if defined(DTYPE_LLA) && HPUXV<1030 +#define _KERNEL 1 +#include +#undef _KERNEL +# endif /* defined(DTYPE_LLA) && HPUXV<1030 */ + +#include +#include +#include +#include +#include + +/* + * The hpux_mount.h header file is manufactured from by the + * Configure script to get the mount structure without needing to define + * _KERNEL when including . Defining _KERNEL causes unresolvable + * header file complications. + */ + +#include "hpux_mount.h" + +# if HPUXV>=800 +/* + * These definitions are from , defined under the _KERNEL symbol. + * Unfortunately, defining _KERNEL causes to include other + * header files not in . + */ +#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 +# if HPUXV<1000 +#define ADDR_NCACHE 1 +# endif /* HPUXV<1000 */ +# endif /* defined(HASNCACHE) */ + +#endif /* HPUX_LSOF_H */ diff --git a/dialects/hpux/kmem/dmnt.c b/dialects/hpux/kmem/dmnt.c new file mode 100644 index 0000000..d02acd4 --- /dev/null +++ b/dialects/hpux/kmem/dmnt.c @@ -0,0 +1,252 @@ +/* + * 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"; +static char *rcsid = "$Id: dmnt.c,v 1.8 2005/08/08 19:50:23 abe Exp $"; +#endif + +#if defined(HPUXKERNBITS) && HPUXKERNBITS>=64 +#define _TIME_T +typedef int time_t; +#endif /* defined(HPUXKERNBITS) && HPUXKERNBITS>=64 */ + +#include "lsof.h" + + +/* + * Local static definitions + */ + +static struct mounts *Lmi = (struct mounts *)NULL; /* local mount info */ + + +/* + * 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); + Exit(1); + } + 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(lv) + 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); + Exit(1); + } + 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((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((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((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/dialects/hpux/kmem/dnode.c b/dialects/hpux/kmem/dnode.c new file mode 100644 index 0000000..132b41a --- /dev/null +++ b/dialects/hpux/kmem/dnode.c @@ -0,0 +1,1097 @@ +/* + * 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"; +static char *rcsid = "$Id: dnode.c,v 1.21 2007/04/24 16:25:30 abe Exp $"; +#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 "lsof.h" +#include + +#if HPUXV>=900 +_PROTOTYPE(static void enter_nma,(char *b)); +_PROTOTYPE(static int islocked,(KA_T lp)); +#endif /* HPUXV>=900 */ + +_PROTOTYPE(static int getnodety,(struct vnode *v)); +_PROTOTYPE(static int readinode,(KA_T ia, struct inode *i)); +_PROTOTYPE(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 int +islocked(lp) + 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((int)' '); + 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(llp, (char *)&ll, sizeof(ll))) + return((int)' '); + +#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((int)(l ? 'W' : 'w')); + else if (ll.ll_type == F_RDLCK) + return((int)(l ? 'R' : 'r')); + return((int)' '); + } + +# 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((int)' '); +} +#endif /* HPUXV>=900 */ + + +/* + * getnodety() - get node type + */ + +static int +getnodety(v) + 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], *ty; + 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) */ + + ); + Exit(1); + } + } + 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 = 'u'; + else if (v->v_shlockc) + Lf->lock = 'R'; + else + Lf->lock = 'W'; + } +#else /* HPUXV>900 */ +# if HPUXV>=1000 + Lf->lock = (char)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((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((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((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 = (char)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. + */ + if (Foffset) + Lf->off_def = 1; + else { + 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 (Fsize || (Lf->access != 'r' && Lf->access != 'w')) { + 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 == 'r') ? rp + : wp); + (void) snpf(fb, sizeof(fb), "%s=%#x", + (Lf->access == 'r') ? "rd" : "wr", + (Lf->access == 'r') ? rp : wp); + (void) enter_nma(fb); + } + Lf->off_def = 1; + 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) && !Fsize) + Lf->off_def = 1; + else if (ins) { + Lf->sz = (SZOFFTYPE)i.i_size; + Lf->sz_def = 1; + } + break; + } + } +/* + * Record link count. + */ + if (Fnlink) { + 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: + ty ="VNON"; + break; + case VREG: + case VDIR: + ty = (type == VREG) ? "VREG" : "VDIR"; + break; + case VBLK: + ty = "VBLK"; + Ntype = N_BLK; + break; + case VCHR: + ty = "VCHR"; + Ntype = N_CHR; + break; + case VLNK: + ty = "VLNK"; + break; + +#if defined(VSOCK) + case VSOCK: + ty = "SOCK"; + break; +#endif /* defined(VSOCK) */ + + case VBAD: + ty = "VBAD"; + break; + case VFIFO: + switch (Ntype) { + +#if HPUXV>=1000 + case N_FIFO: + ty = "FIFO"; + break; + case N_PIPE: + ty = "PIPE"; + break; +#endif /* HPUXV>=1000 */ + + default: + ty = "FIFO"; + } + break; + default: + (void) snpf(Lf->type, sizeof(Lf->type), "%04o", (type & 0xfff)); + ty = (char *)NULL; + } + if (ty) + (void) snpf(Lf->type, sizeof(Lf->type), "%s", ty); + Lf->ntype = Ntype; + +#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((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((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/dialects/hpux/kmem/dnode1.c b/dialects/hpux/kmem/dnode1.c new file mode 100644 index 0000000..d6af239 --- /dev/null +++ b/dialects/hpux/kmem/dnode1.c @@ -0,0 +1,157 @@ +/* + * 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"; +static char *rcsid = "$Id: dnode1.c,v 1.11 2005/08/08 19:50:23 abe Exp $"; +#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, requires it when + * _KERNEL is defined. So we fake the pool_id_t definition. + * + * also requires sv_sema_t. It's defined in + * when _KERNEL is defined, but some other header file has + * already included 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 conflict */ +# endif /* HPUXV>=1030 */ + +#include +#include +#include + +# 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 +#include +#undef _KERNEL +# endif /* HPUXV>=1020 */ + + +/* + * read_vxnode() - read Veritas file system inode information + */ + +int +read_vxnode(v, vfs, dev, devs, rdev, rdevs) + 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((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 (Foffset || ((v->v_type == VCHR || v->v_type == VBLK) && !Fsize)) + Lf->off_def = 1; + else { + Lf->sz = (SZOFFTYPE)i.i_size; + Lf->sz_def = 1; + } +/* + * Record link count. + */ + if (Fnlink) { + 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/dialects/hpux/kmem/dnode2.c b/dialects/hpux/kmem/dnode2.c new file mode 100644 index 0000000..3429831 --- /dev/null +++ b/dialects/hpux/kmem/dnode2.c @@ -0,0 +1,371 @@ +/* + * 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"; +static char *rcsid = "$Id: dnode2.c,v 1.7 2005/08/08 19:50:23 abe Exp $"; +#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 +#include +#undef __dontcare__ +#include +#include + + +/* + * 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 +#undef KERNEL + + +/* + * Local function prototypes + */ + +_PROTOTYPE(static struct volume *getvolume,(struct VenusFid *f, int *vols)); +_PROTOTYPE(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(f, vols) + 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(kh, (char *)&vp, sizeof(vp))) + return((struct volume *)NULL); + while (vp) { + if (kread((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(vp) + 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((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(vc, rfid) + 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((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(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/dialects/hpux/kmem/dproc.c b/dialects/hpux/kmem/dproc.c new file mode 100644 index 0000000..62ad048 --- /dev/null +++ b/dialects/hpux/kmem/dproc.c @@ -0,0 +1,842 @@ +/* + * 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"; +static char *rcsid = "$Id: dproc.c,v 1.18 2008/10/08 13:24:36 abe Exp $"; +#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 "lsof.h" + +#if defined(HASNCACHE) +#include +#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 + +#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 */ + + +_PROTOTYPE(static void get_kernel_access,(void)); + +#if HPUXV>=800 +_PROTOTYPE(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(v, (char *)&oftsz, sizeof(oftsz))) { + (void) fprintf(stderr, "%s: can't get FD chunk size\n", + Pn); + Exit(1); + } + if (!oftsz) { + (void) fprintf(stderr, "%s: bad FD chunk size: %d\n", + Pn, oftsz); + Exit(1); + } + } + 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); + Exit(1); + } + if (!(oftp = (char *)malloc((MALLOC_S)oftsz))) { + (void) fprintf(stderr, "%s: no space for %d FD bytes\n", + Pn, oftsz); + Exit(1); + } + } +#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(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(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((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(CWD, -1); + process_node((KA_T)CURDIR); + if (Lf->sf) + link_lfile(); + } + /* + * Save root directory information. + */ + if (ROOTDIR) { + alloc_lfile(RTD, -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((KA_T)pfp, (char *)&ofp, sizeof(ofp)) + || !ofp || kread((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((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(NULL, i); + process_file(fp); + if (Lf->sf) { + +#if defined(USESPOFILE) + if (Fsv & FSV_FG) + 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)); + Exit(1); + } + 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); + Exit(1); + } + } +#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)) + Exit(1); +#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)); + Exit(1); + } + +#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)) + Exit(1); +#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); + Exit(1); + } + (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); + Exit(1); + } + if (get_Nl_value("proc", Drive_Nl, &v) < 0 || !v + || kread((KA_T)v, (char *)&Kp, sizeof(Kp)) + || get_Nl_value("nproc", Drive_Nl, &v) < 0 || !v + || kread((KA_T)v, (char *)&Np, sizeof(Np)) + || !Kp || Np < 1) { + (void) fprintf(stderr, "%s: can't read proc table info\n", Pn); + Exit(1); + } + 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); + Exit(1); + } + if (get_Nl_value("upt", Drive_Nl, (unsigned long *)&usrpt) < 0) { + (void) fprintf(stderr, "%s: can't get kernel's usrpt\n", Pn); + Exit(1); + } +#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); + Exit(1); + } + if (get_Nl_value("npids", Drive_Nl, &v) < 0 || !v + || kread((KA_T)v, (char *)&npids, sizeof(npids))) { + (void) fprintf(stderr, "%s: can't get kernel's npids\n", Pn); + Exit(1); + } +#endif /* HPUXV<800 && defined(hp9000s800) */ + +#if HPUXV>=1030 + if (get_Nl_value("clmaj", Drive_Nl, &v) < 0 || !v + || kread((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(addr, buf, len) + 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(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(prp, (char *)&p, sizeof(p))) + return; + if (kread((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); + Exit(1); + } + } + Vp[i++] = va; + /* + * Allocate local file structure. + */ + switch (p.p_type) { + case PT_DATA: + case PT_TEXT: + alloc_lfile(" txt", -1); + break; + case PT_MMAP: + alloc_lfile(" mem", -1); + break; + default: + (void) snpf(fd, sizeof(fd), "R%02d", p.p_type); + alloc_lfile(fd, -1); + } + /* + * Save vnode information. + */ + process_node(va); + if (Lf->sf) + link_lfile(); + } +} +#endif /* HPUXV>=800 */ diff --git a/dialects/hpux/kmem/dproto.h b/dialects/hpux/kmem/dproto.h new file mode 100644 index 0000000..097ea23 --- /dev/null +++ b/dialects/hpux/kmem/dproto.h @@ -0,0 +1,69 @@ +/* + * 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 +_PROTOTYPE(extern void completevfs,(struct l_vfs *vfs, dev_t *dev, struct vfs *v)); +#else +_PROTOTYPE(extern void completevfs,(struct l_vfs *vfs, dev_t *dev)); +#endif /* HPUXV>=800 */ + +_PROTOTYPE(extern int is_file_named,(char *p, int cd)); +_PROTOTYPE(extern int get_max_fd,(void)); + +#if defined(DTYPE_LLA) +_PROTOTYPE(extern void process_lla,(KA_T la)); +#endif + +_PROTOTYPE(extern struct l_vfs *readvfs,(struct vnode *lv)); + +#if HPUXV>=1030 +_PROTOTYPE(extern void process_stream_sock,(KA_T ip, KA_T pcb, char *pn, enum vtype vt)); +_PROTOTYPE(extern int read_mi,(KA_T sh, KA_T *ip, KA_T *pcb, char **pn)); +#endif /* HPUXV>=1030 */ + +#if defined(HAS_AFS) +_PROTOTYPE(extern struct vnode *alloc_vcache,(void)); +_PROTOTYPE(extern void ckAFSsym,(struct nlist *nl)); +_PROTOTYPE(extern int hasAFS,(struct vnode *vp)); +_PROTOTYPE(extern int readafsnode,(KA_T va, struct vnode *v, struct afsnode *an)); +#endif /* defined(HAS_AFS) */ + +#if defined(HASVXFS) +_PROTOTYPE(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/dialects/hpux/kmem/dsock.c b/dialects/hpux/kmem/dsock.c new file mode 100644 index 0000000..fc54f83 --- /dev/null +++ b/dialects/hpux/kmem/dsock.c @@ -0,0 +1,1170 @@ +/* + * 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"; +static char *rcsid = "$Id: dsock.c,v 1.20 2005/08/08 19:50:23 abe Exp $"; +#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 "lsof.h" + +#if HPUXV>=800 && defined(HPUX_CCITT) +#include +#include +#include +#include +#include +#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; + + (void) snpf(Lf->type, sizeof(Lf->type), "lla"); + Lf->inp_ty = 2; + enter_dev_ch(print_kptr(la, (char *)NULL, 0)); +/* + * Read link level access control block. + */ + if (!la || kread((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 = 'w'; + else if ((lcb.lla_flags & LLA_FWRITE | LLA_FREAD) == LLA_FREAD) + Lf->access = 'r'; + else if (lcb.lla_flags & LLA_FWRITE | LLA_FREAD) + Lf->access = 'u'; +/* + * 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 */ + + (void) snpf(Lf->type, sizeof(Lf->type), "sock"); + Lf->inp_ty = 2; +/* + * Read socket structure. + */ + if (!sa) { + enter_nm("no socket address"); + return; + } + if (kread((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((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((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 (Fsize) { + if (Lf->access == 'r') + Lf->sz = (SZOFFTYPE)s.so_rcv.sb_cc; + else if (Lf->access == 'w') + Lf->sz = (SZOFFTYPE)s.so_snd.sb_cc; + else + Lf->sz = (SZOFFTYPE)(s.so_rcv.sb_cc + s.so_snd.sb_cc); + Lf->sz_def = 1; + } else + Lf->off_def = 1; + +# if defined(HASTCPTPIQ) + Lf->lts.rq = s.so_rcv.sb_cc; + Lf->lts.sq = s.so_snd.sb_cc; + Lf->lts.rqs = Lf->lts.sqs = 1; +# endif /* defined(HASTCPTPIQ) */ +#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; + (void) snpf(Lf->type, sizeof(Lf->type), "x.25"); + (void) snpf(Lf->iproto, sizeof(Lf->iproto), "%.*s", IPROTOL, + "CCITT"); + /* + * Get the X25 PCB and its extension. + */ + if (!s.so_pcb + || kread((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((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; + (void) snpf(Lf->type, sizeof(Lf->type), "inet"); + printiproto(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((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((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((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; + (void) snpf(Lf->type, sizeof(Lf->type), "unix"); + +#if HPUXV>=1030 +/* + * Save size information for HP-UX 10.30 and above. + */ + if (Fsize) { + if (!s.so_rcv + || kread((KA_T)s.so_rcv, (char *)&rb, sizeof(rb))) + rb.sb_cc = 0; + if (!s.so_snd + || kread((KA_T)s.so_snd, (char *)&sb, sizeof(sb))) + sb.sb_cc = 0; + if (Lf->access == 'r') + Lf->sz = (SZOFFTYPE)rb.sb_cc; + else if (Lf->access == 'w') + Lf->sz = (SZOFFTYPE)sb.sb_cc; + else + Lf->sz = (SZOFFTYPE)(rb.sb_cc + sb.sb_cc); + Lf->sz_def = 1; + } else + Lf->off_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((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((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((KA_T)unp.unp_addr, (char *)&mb, sizeof(mb)) == 0 + && mb.b_datap + && kread((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); + Exit(1); + } + } + if (kread((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((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; + (void) snpf(Lf->type, sizeof(Lf->type), "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(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(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((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 (Fsize) { + if (Lf->access == 'r') + Lf->sz = (SZOFFTYPE)rq; + else if (Lf->access == 'w') + Lf->sz = (SZOFFTYPE)sq; + else + Lf->sz = (SZOFFTYPE)(rq + sq); + Lf->sz_def = 1; + } else + Lf->off_def = 1; + +# else /* !defined(HASTCPTPIQ) && !defined(HASTCPTPIW) */ + if (!Fsize) + Lf->off_def = 1; +# endif /* defined(HASTCPTPIQ) || defined(HASTCPTPIW) */ + +# if defined(HASTCPOPT) + if (Ftcptpi & TCPTPI_FLAGS) { + + /* + * 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) + if (Ftcptpi & TCPTPI_FLAGS) { + + /* + * 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(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); + if (!Fsize) + Lf->off_def = 1; + 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/dialects/hpux/kmem/dstore.c b/dialects/hpux/kmem/dstore.c new file mode 100644 index 0000000..bbf18f1 --- /dev/null +++ b/dialects/hpux/kmem/dstore.c @@ -0,0 +1,241 @@ +/* + * 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"; +static char *rcsid = "$Id: dstore.c,v 1.12 2007/04/24 16:25:30 abe Exp $"; +#endif + + +#include "lsof.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/dialects/hpux/kmem/hpux11/ipc_s.h b/dialects/hpux/kmem/hpux11/ipc_s.h new file mode 100644 index 0000000..4945c98 --- /dev/null +++ b/dialects/hpux/kmem/hpux11/ipc_s.h @@ -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 + * February, 1998 + * + * Patch bundle update supplied by: Kevin Vajk + * February, 1999 + */ + +#if !defined(LSOF_IPC_S_H) +#define LSOF_IPC_S_H + +#include "kernbits.h" +#include + +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/dialects/hpux/kmem/hpux11/kernbits.h b/dialects/hpux/kmem/hpux11/kernbits.h new file mode 100644 index 0000000..a0fd166 --- /dev/null +++ b/dialects/hpux/kmem/hpux11/kernbits.h @@ -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/dialects/hpux/kmem/hpux11/lla.h b/dialects/hpux/kmem/hpux11/lla.h new file mode 100644 index 0000000..36ec882 --- /dev/null +++ b/dialects/hpux/kmem/hpux11/lla.h @@ -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 + * February, 1998 + */ + +#if !defined(LSOF_LLA_H) +#define LSOF_LLA_H + +#include "kernbits.h" +#include + +#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/dialects/hpux/kmem/hpux11/nfs_clnt.h b/dialects/hpux/kmem/hpux11/nfs_clnt.h new file mode 100644 index 0000000..6b2df97 --- /dev/null +++ b/dialects/hpux/kmem/hpux11/nfs_clnt.h @@ -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 +#undef TCP_NODELAY +#undef TCP_MAXSEG +#include +#include +#include +#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/dialects/hpux/kmem/hpux11/proc.h b/dialects/hpux/kmem/hpux11/proc.h new file mode 100644 index 0000000..e922bd4 --- /dev/null +++ b/dialects/hpux/kmem/hpux11/proc.h @@ -0,0 +1,245 @@ +/* + * 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 + * February, 1998 + */ + +#if !defined(LSOF_PROC_H) +#define LSOF_PROC_H + +#include "kernbits.h" +#include +#include +#include + +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/dialects/hpux/kmem/hpux11/rnode.h b/dialects/hpux/kmem/hpux11/rnode.h new file mode 100644 index 0000000..f61ec8a --- /dev/null +++ b/dialects/hpux/kmem/hpux11/rnode.h @@ -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 + * February, 1998 + */ + +#if !defined(LSOF_RNODE_H) +#define LSOF_RNODE_H + +#include "kernbits.h" + +#define _KERNEL +#include +#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/dialects/hpux/kmem/hpux11/sth.h b/dialects/hpux/kmem/hpux11/sth.h new file mode 100644 index 0000000..a47d07d --- /dev/null +++ b/dialects/hpux/kmem/hpux11/sth.h @@ -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 + +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/dialects/hpux/kmem/hpux11/tcp_s.h b/dialects/hpux/kmem/hpux11/tcp_s.h new file mode 100644 index 0000000..41f21f6 --- /dev/null +++ b/dialects/hpux/kmem/hpux11/tcp_s.h @@ -0,0 +1,227 @@ +/* + * 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 + +#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/dialects/hpux/kmem/hpux11/udp_s.h b/dialects/hpux/kmem/hpux11/udp_s.h new file mode 100644 index 0000000..111c8db --- /dev/null +++ b/dialects/hpux/kmem/hpux11/udp_s.h @@ -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/dialects/hpux/kmem/hpux11/vnode.h b/dialects/hpux/kmem/hpux11/vnode.h new file mode 100644 index 0000000..5a386a1 --- /dev/null +++ b/dialects/hpux/kmem/hpux11/vnode.h @@ -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 + * February, 1998 + */ + +#if !defined(LSOF_VNODE_H) +#define LSOF_VNODE_H +#define _SYS_VNODE_INCLUDED /* prevent inclusion of */ + +#include "kernbits.h" +#include +#include +#include + +#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/dialects/hpux/kmem/machine.h b/dialects/hpux/kmem/machine.h new file mode 100644 index 0000000..f98934d --- /dev/null +++ b/dialects/hpux/kmem/machine.h @@ -0,0 +1,671 @@ +/* + * 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 +#include "kernbits.h" +# else /* HPUXV<1030 */ +# if HPUXV>=1020 +/* + * Since we need kernel structures from the HP-UX 10.20 , and + * since defining _KERNEL before #include'ing it causes a conflict between + * its FILE enum and the FILE struct definition in , redefine FILE, + * #include , revoke the FILE redefinition, define _KERNEL, + * #include , 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 +# endif /* defined(__GNUC__) */ + +#define FILE STDIO_FILE +#include +#undef FILE +#define _KERNEL 1 +#include +#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 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? */ +/* #define HASPRINTOFF print_off? */ +/* #define HASPRINTSZ print_sz? */ + + +/* + * HASPRIVFILETYPE and PRIVFILETYPE are defined for dialects that have a + * file structure type that isn't defined by a DTYPE_* symbol. They are + * used in lib/prfp.c to select the type's processing. + * + * PRIVFILETYPE is the definition of the f_type value in the file struct. + * + * HASPRIVFILETYPE is the name of the processing function. + */ + +/* #define HASPRIVFILETYPE process_shmf? */ +/* #define PRIVFILETYPE ?? */ + + +/* + * HASPRIVNMCACHE is defined for dialects that have a private method for + * printing cached NAME column values for some files. HASPRIVNAMECACHE + * is defined to be the name of the function. + * + * The function takes one argument, a struct lfile pointer to the file, and + * returns non-zero if it prints a name to stdout. + */ + +/* #define HASPRIVNMCACHE */ + + +/* + * 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 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 */ + + +/* + * 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_ is defined for dialects that use the + * 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_REGEX 1 regex.c */ +/* #define USE_LIB_RNAM 1 rnam.c */ +#define USE_LIB_RNCH 1 /* rnch.c */ +/* #define USE_LIB_RNMH 1 rnmh.c */ + +# if HPUXV<1030 +#define USE_LIB_SNPF 1 /* snpf.c */ +# else /* HPUXV>=1030 */ +#define snpf snprintf /* use the system's snprintf() */ +# endif /* HPUXV<1030 */ + + +/* + * 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/dialects/hpux/pstat/Makefile b/dialects/hpux/pstat/Makefile new file mode 100644 index 0000000..a5fea79 --- /dev/null +++ b/dialects/hpux/pstat/Makefile @@ -0,0 +1,150 @@ + +# 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 $${PROG} $${BIN}' + @echo ' install -m 444 $${MAN} $${DOC}' + @echo '' + @echo 'You will have to complete the 4xxx modes, the 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_CCDATE "'`date`'"' >> version.h + @echo '#define LSOF_CCFLAGS "'`echo ${CFLAGS} | sed 's/\\\\(/\\(/g' | sed 's/\\\\)/\\)/g' | sed 's/"/\\\\"/g'`'"' >> version.h + @echo '#define LSOF_CINFO "${CINFO}"' >> version.h + @if [ "X${LSOF_HOST}" = "X" ]; then \ + echo '#define LSOF_HOST "'`uname -n`'"' >> version.h; \ + else \ + if [ "${LSOF_HOST}" = "none" ]; then \ + echo '#define LSOF_HOST ""' >> version.h; \ + else \ + echo '#define LSOF_HOST "${LSOF_HOST}"' >> version.h; \ + fi \ + fi + @echo '#define LSOF_LDFLAGS "${CFGL}"' >> version.h + @if [ "X${LSOF_LOGNAME}" = "X" ]; then \ + echo '#define LSOF_LOGNAME "${LOGNAME}"' >> version.h; \ + else \ + if [ "${LSOF_LOGNAME}" = "none" ]; then \ + echo '#define LSOF_LOGNAME ""' >> version.h; \ + else \ + echo '#define LSOF_LOGNAME "${LSOF_LOGNAME}"' >> version.h; \ + fi; \ + fi + @if [ "X${LSOF_SYSINFO}" = "X" ]; then \ + echo '#define LSOF_SYSINFO "'`uname -a`'"' >> version.h; \ + else \ + if [ "${LSOF_SYSINFO}" = "none" ]; then \ + echo '#define LSOF_SYSINFO ""' >> version.h; \ + else \ + echo '#define LSOF_SYSINFO "${LSOF_SYSINFO}"' >> version.h; \ + fi \ + fi + @if [ "X${LSOF_USER}" = "X" ]; then \ + echo '#define LSOF_USER "${USER}"' >> version.h; \ + else \ + if [ "${LSOF_USER}" = "none" ]; then \ + echo '#define LSOF_USER ""' >> version.h; \ + else \ + echo '#define LSOF_USER "${LSOF_USER}"' >> version.h; \ + fi \ + fi + @@sed '/VN/s/.ds VN \(.*\)/#define LSOF_VERSION "\1"/' < version >> version.h + +FRC: + +# DO NOT DELETE THIS LINE - make depend DEPENDS ON IT + +dfile.o: ${HDR} dfile.c + +dproc.o: ${HDR} dproc.c + +dsock.o: ${HDR} dsock.c + +dstore.o: ${HDR} dstore.c + +arg.o: ${HDR} arg.c + +main.o: ${HDR} main.c + +misc.o: ${HDR} misc.c + +node.o: ${HDR} node.c + +print.o: ${HDR} print.c + +proc.o: ${HDR} proc.c + +store.o: ${HDR} store.c + +usage.o: ${HDR} version.h usage.c + +util.o: ${HDR} util.c + +# *** Do not add anything here - It will go away. *** diff --git a/dialects/hpux/pstat/Mksrc b/dialects/hpux/pstat/Mksrc new file mode 100755 index 0000000..0840e1a --- /dev/null +++ b/dialects/hpux/pstat/Mksrc @@ -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/dialects/hpux/pstat/dfile.c b/dialects/hpux/pstat/dfile.c new file mode 100644 index 0000000..b68ffdf --- /dev/null +++ b/dialects/hpux/pstat/dfile.c @@ -0,0 +1,806 @@ +/* + * 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"; +static char *rcsid = "$Id"; +#endif + + +#include "lsof.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 + */ + +_PROTOTYPE(static struct l_nc *ncache_addr,(struct psfileid *ps)); +_PROTOTYPE(static void ncache_free,(void)); +_PROTOTYPE(static int ncache_isroot,(struct psfileid *ps)); +_PROTOTYPE(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(nm, prot) + 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(ps) + 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); + Exit(1); + } + 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); + Exit(1); + } +} + + +/* + * 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(ps) + 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(fsid, fh) + 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); + Exit(1); + } + 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); + Exit(1); + } + 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); + Exit(1); + } + /* + * 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(buf, blen, fp) + 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); + Exit(1); + } + 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(lf, 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]; + 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 && (Fsv & FSV_NI)) { + Lf->fna = na; + Lf->fsv |= FSV_NI; + } +#endif /* defined(HASFSTRUCT) */ + +/* + * Construct lock code. + */ + if ((lk = pd->psfd_lckflag) & PS_FPARTRDLCK) + Lf->lock = 'r'; + else if (lk & PS_FPARTWRLCK) + Lf->lock = 'w'; + else if (lk & PS_FFULLRDLCK) + Lf->lock = 'R'; + else if (lk & PS_FFULLWRLCK) + Lf->lock = 'W'; + else + Lf->lock = ' '; +/* + * Derive type from modes. + */ + switch ((int)(pd->psfd_mode & PS_IFMT)) { + case PS_IFREG: + cp = "REG"; + Ntype = N_REGLR; + break; + case PS_IFBLK: + cp = "BLK"; + Ntype = N_BLK; + break; + case PS_IFDIR: + cp = "DIR"; + Ntype = N_REGLR; + break; + case PS_IFCHR: + cp = "CHR"; + Ntype = N_CHR; + break; + case PS_IFIFO: + cp = "FIFO"; + Ntype = N_FIFO; + break; + default: + (void) snpf(buf, sizeof(buf), "%04o", + (unsigned int)(((pd->psfd_mode & PS_IFMT) >> 12) & 0xfff)); + cp = buf; + Ntype = N_REGLR; + } + if (!Lf->type[0]) + (void) snpf(Lf->type, sizeof(Lf->type), "%s", cp); + Lf->ntype = Ntype; +/* + * Save device number. + */ + 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. + */ + if (Fnlink) { + + /* + * 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->off_def && !Lf->sz_def) { + if (Foffset) + Lf->off_def = 1; + else { + switch (Ntype) { + case N_CHR: + case N_FIFO: + Lf->off_def = 1; + 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/dialects/hpux/pstat/dlsof.h b/dialects/hpux/pstat/dlsof.h new file mode 100644 index 0000000..dff34e5 --- /dev/null +++ b/dialects/hpux/pstat/dlsof.h @@ -0,0 +1,206 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include + +#include +#include + +# if defined(HASIPv6) +#include +# endif /* defined(HASIPv6) */ + +#include +#include +#include + +#include +#include +#include +#include + +# 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 + +# 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 +#include + + +/* + * 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 */ + +#endif /* HPUX_LSOF_H */ diff --git a/dialects/hpux/pstat/dproc.c b/dialects/hpux/pstat/dproc.c new file mode 100644 index 0000000..a592301 --- /dev/null +++ b/dialects/hpux/pstat/dproc.c @@ -0,0 +1,904 @@ +/* + * 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"; +static char *rcsid = "$Id"; +#endif + + +#include "lsof.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 + */ + +_PROTOTYPE(static void get_kernel_access,(void)); +_PROTOTYPE(static void process_text,(struct pst_status *p)); +_PROTOTYPE(static struct pst_fileinfo2 *read_files,(struct pst_status *p, + int *n)); +_PROTOTYPE(static struct pst_status *read_proc,(int *n)); +_PROTOTYPE(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(CWD, -1) != 2) ? 0 : 1; + rtds = (ck_fd_status(RTD, -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); + Exit(1); + } + for (fdsa = 0; fdsa < FDS_ALLOC_INIT; fdsa++) { + if (Fand && Fdl) + fds[fdsa] = (ck_fd_status(NULL, 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(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(RTD, -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); + Exit(1); + } + while (fdsa < l) { + fds[fdsa] = (ck_fd_status(NULL, fdsa) == 2) ? 1 : 0; + fdsa++; + } + } + if (!fds[fd]) + continue; + } + alloc_lfile(NULL, (int)f->psf_fd); + /* + * Construct access code. + */ + if ((flag = (long)(f->psf_flag & ~PS_FEXCLOS)) + == (long)PS_FRDONLY) + Lf->access = 'r'; + else if (flag == (long)PS_FWRONLY) + Lf->access = 'w'; + else + Lf->access = 'u'; + +#if defined(HASFSTRUCT) + /* + * Save file structure values. + */ + if (Fsv & FSV_CT) { + Lf->fct = (long)f->psf_count; + Lf->fsv |= FSV_CT; + } + if (Fsv & FSV_FA) { + ka = (((KA_T)(f->psf_hi_fileid & 0xffffffff) << 32) + | (KA_T)(f->psf_lo_fileid & 0xffffffff)); + if ((Lf->fsa = ka)) + Lf->fsv |= FSV_FA; + } + if (Fsv & FSV_FG) { + 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) */ + + /* + * 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: + (void) snpf(Lf->type, sizeof(Lf->type), "UNKN"); + (void) enter_nm("no more information"); + break; + case PS_TYPE_UNSP: + (void) snpf(Lf->type, sizeof(Lf->type), "UNSP"); + (void) enter_nm("no more information"); + break; + case PS_TYPE_LLA: + (void) snpf(Lf->type, sizeof(Lf->type), "LLA"); + (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)); + Exit(1); + } + 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); + Exit(1); + } +/* + * 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; + Exit(1); +} + + +/* + * 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 { + char *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("mem", -1) == 2) ? 1 : 0; + else + mems = 1; + } + if (txts < 0) { + if (Fand && Fdl) + txts = (ck_fd_status("txt", -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); + Exit(1); + } + } +/* + * 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 = "txt"; + tv[0].na = na; + tv[0].opfid = p->pst_fid_text; + tv[0].psfid = p->pst_text; + ntvu = 1; + } else { + alloc_lfile("txt", -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 = "mem"; + tv[ntvu].na = na; + tv[ntvu].opfid = rp->pst_fid; + tv[ntvu].psfid = rp->pst_id; + ntvu++; + } else if (!meme) { + alloc_lfile("mem", -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(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(ki, hf, lf, hn, ln, pd) + 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(p, n) + 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); + Exit(1); + } + } + /* + * 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(n) + 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); + Exit(1); + } + } + /* + * 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(p, n) + 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); + Exit(1); + } + } + /* + * 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/dialects/hpux/pstat/dproto.h b/dialects/hpux/pstat/dproto.h new file mode 100644 index 0000000..66e61ac --- /dev/null +++ b/dialects/hpux/pstat/dproto.h @@ -0,0 +1,59 @@ +/* + * 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 $ + */ + + +_PROTOTYPE(extern int get_max_fd,(void)); +_PROTOTYPE(extern int is_file_named,(char *p, int cd)); +_PROTOTYPE(extern void process_finfo,(struct pst_filedetails *pd, struct pst_fid *opfid, struct psfileid *psfid, KA_T na)); +_PROTOTYPE(extern void process_socket,(struct pst_fileinfo2 *f, + struct pst_socket *s)); +_PROTOTYPE(extern void process_stream,(struct pst_fileinfo2 *f, int ckscko)); +_PROTOTYPE(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)); +_PROTOTYPE(extern struct pst_socket *read_sock,(struct pst_fileinfo2 *f)); + +#if defined(HASIPv6) +_PROTOTYPE(extern struct hostent *gethostbyname2,(char *nm, int proto)); +#endif /* defined(HASIPv6) */ + +#if defined(HASVXFS) +_PROTOTYPE(extern int read_vxnode,(struct vnode *v, struct l_vfs *vfs, dev_t *dev)); +#endif /* defined(HASVXFS) */ + +_PROTOTYPE(extern void scanmnttab,(void)); diff --git a/dialects/hpux/pstat/dsock.c b/dialects/hpux/pstat/dsock.c new file mode 100644 index 0000000..461ba58 --- /dev/null +++ b/dialects/hpux/pstat/dsock.c @@ -0,0 +1,1647 @@ +/* + * 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"; +static char *rcsid = "$Id"; +#endif + + +#include "lsof.h" + + +/* + * Local function prototypes + */ + +#if defined(PS_STR_XPORT_DATA) +_PROTOTYPE(static void make_sock,(struct pst_fileinfo2 *f, + struct pst_stream *sh, + struct pst_socket *s)); +#endif /* defined(PS_STR_XPORT_DATA) */ + +_PROTOTYPE(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(f, s) + 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; + +#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. + */ + (void) snpf(Lf->type, sizeof(Lf->type), "sock"); + 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 && (Fsv & FSV_NI)) { + if (na) { + Lf->fna = na; + Lf->fsv |= FSV_NI; + } + } +#endif /* defined(HASFSTRUCT) */ + +/* + * Save size information, as requested. + */ + if (Fsize) { + if (Lf->access == 'r') + Lf->sz = (SZOFFTYPE)s->pst_idata; + else if (Lf->access == 'w') + Lf->sz = (SZOFFTYPE)s->pst_odata; + else + Lf->sz = (SZOFFTYPE)(s->pst_idata + s->pst_odata); + Lf->sz_def = 1; + } else + Lf->off_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; + (void) snpf(Lf->type, sizeof(Lf->type), + +#if defined(HASIPv6) + "IPv4" +#else /* !defined(HASIPv6) */ + "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; + (void) snpf(Lf->type, sizeof(Lf->type), "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; + (void) snpf(Lf->type, sizeof(Lf->type), "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))) { + (void) fprintf(stderr, + "%s: no unix nma space(1): PID %ld, FD %s", + Pn, (long)Lp->pid, Lf->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))) { + (void) fprintf(stderr, + "%s: no unix nma space(2): PID %ld, FD %s", + Pn, (long)Lp->pid, Lf->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; + char *cp; + 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 && (Fsv & FSV_NI)) { + Lf->fna = na; + Lf->fsv |= FSV_NI; + } +#endif /* defined(HASFSTRUCT) */ + +/* + * Enter type. + */ + switch (f->psf_ftype) { + case PS_TYPE_STREAMS: + cp = "STR"; + break; + case PS_TYPE_SOCKET: + if (f->psf_subtype == PS_SUBTYPE_SOCKSTR) { + cp = "STSO"; + break; + } + /* fall through */ + default: + cp = "unkn"; + } + (void) snpf(Lf->type, sizeof(Lf->type), "%s", cp); +/* + * 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); + Exit(1); + } + 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 (Fsize) { + if (Lf->access == 'r') { + Lf->sz = (SZOFFTYPE)s[hx].val.head.pst_rbytes; + Lf->sz_def = 1; + } else if (Lf->access == 'w') { + Lf->sz = (SZOFFTYPE)s[hx].val.head.pst_wbytes; + Lf->sz_def = 1; + } else if (Lf->access == 'u') { + 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; + if (!Fsize || (Fsize && !Lf->sz_def)) + Lf->off_def = 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(f) + 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/dialects/hpux/pstat/dstore.c b/dialects/hpux/pstat/dstore.c new file mode 100644 index 0000000..d0a87f5 --- /dev/null +++ b/dialects/hpux/pstat/dstore.c @@ -0,0 +1,80 @@ +/* + * 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"; +static char *rcsid = "$Id"; +#endif + + +#include "lsof.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/dialects/hpux/pstat/machine.h b/dialects/hpux/pstat/machine.h new file mode 100644 index 0000000..2555e80 --- /dev/null +++ b/dialects/hpux/pstat/machine.h @@ -0,0 +1,648 @@ +/* + * 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 + +# 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 +# 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 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? */ +/* #define HASPRINTOFF print_off? */ +/* #define HASPRINTSZ print_sz? */ + + +/* + * HASPRIVFILETYPE and PRIVFILETYPE are defined for dialects that have a + * file structure type that isn't defined by a DTYPE_* symbol. They are + * used in lib/prfp.c to select the type's processing. + * + * PRIVFILETYPE is the definition of the f_type value in the file struct. + * + * HASPRIVFILETYPE is the name of the processing function. + */ + +/* #define HASPRIVFILETYPE process_shmf? */ +/* #define PRIVFILETYPE ?? */ + + +/* + * HASPRIVNMCACHE is defined for dialects that have a private method for + * printing cached NAME column values for some files. HASPRIVNAMECACHE + * is defined to be the name of the function. + * + * The function takes one argument, a struct lfile pointer to the file, and + * returns non-zero if it prints a name to stdout. + */ + +/* #define HASPRIVNMCACHE */ + + +/* + * 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 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 + + +/* + * 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_ is defined for dialects that use the + * 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_REGEX 1 regex.c */ +/* #define USE_LIB_RNAM 1 rnam.c */ +/* #define USE_LIB_RNCH 1 rnch.c */ +/* #define USE_LIB_RNMH 1 rnmh.c */ +/* #define USE_LIB_SNPF 1 snpf.c */ +#define snpf snprintf /* use the system's snprintf() */ + + +/* + * WARNDEVACCESS is defined for those dialects that should issue a warning + * when lsof can't access /dev (or /device) or one of its sub-directories. + * The warning can be inhibited by the lsof caller with the -w option. + */ + +/* #define WARNDEVACCESS 1 */ + + +/* + * WARNINGSTATE is defined for those dialects that want to suppress all lsof + * warning messages. + */ + +/* #define WARNINGSTATE 1 warnings are enabled by default */ + + +/* + * WILLDROPGID is defined for those dialects whose lsof executable runs + * setgid(not_real_GID) and whose setgid power can be relinquished after + * the dialect's initialize() function has been executed. + */ + +/* #define WILLDROPGID 1 */ + + +/* + * zeromem is a macro that uses bzero or memset. + */ + +#define zeromem(a, l) memset((void *)a, 0, l) + +#endif /* !defined(LSOF_MACHINE_H) */ diff --git a/dialects/linux/Makefile b/dialects/linux/Makefile new file mode 100644 index 0000000..2bea108 --- /dev/null +++ b/dialects/linux/Makefile @@ -0,0 +1,157 @@ + +# Linux /proc-based Makefile +# +# $Id: Makefile,v 1.11 2008/04/15 13:30:01 abe Exp $ + +PROG= lsof + +BIN= ${DESTDIR} + +DOC= ${DESTDIR} + +I=/usr/include +S=/usr/include/sys +L=/usr/include/local +P= + +CDEF= +CDEFS= ${CDEF} ${CFGF} +DEP= ${CFGD} ${CFGDN} +INCL= ${DINC} +CFLAGS= ${CDEFS} ${INCL} ${DEP} ${DEBUG} + +GRP= + +HDR= lsof.h lsof_fields.h dlsof.h machine.h proto.h dproto.h + +SRC= dfile.c dmnt.c dnode.c dproc.c dsock.c dstore.c \ + arg.c main.c misc.c node.c print.c proc.c store.c usage.c \ + util.c + +OBJ= dfile.o dmnt.o dnode.o dproc.o dsock.o dstore.o \ + arg.o main.o misc.o node.o print.o proc.o store.o usage.o \ + util.o + +MAN= lsof.8 + +OTHER= + +SHELL= /bin/sh + +SOURCE= Makefile ${OTHER} ${MAN} ${HDR} ${SRC} + +all: ${PROG} + +${PROG}: ${P} ${LIB} ${OBJ} + ${CC} -o $@ ${OBJ} ${CFGL} + +clean: FRC + rm -f Makefile.bak ${PROG} a.out core errs lint.out tags *.o version.h ${CFGDN} + rm -f machine.h.old new_machine.h + (cd lib; ${MAKE} -f Makefile.skel clean) + +install: all FRC + @echo '' + @echo 'Please write your own install rule. Lsof should be installed' + @echo 'setuid to root if you wish any lsof user to be able to examine' + @echo 'all open files. Your install rule actions might look something' + @echo 'like this:' + @echo '' + @echo ' install -m 4xxx -o root -g $${GRP} $${PROG} $${BIN}' + @echo ' install -m 444 $${MAN} $${DOC}' + @echo '' + @echo 'You will have to complete the 4xxx modes, the GRP value, and' + @echo 'the skeletons for the BIN and DOC strings, given at the' + @echo 'beginning of this Makefile, e.g.,' + @echo '' + @echo ' BIN= $${DESTDIR}/usr/local/etc' + @echo ' DOC= $${DESTDIR}/usr/man/man8' + @echo ' GRP= sys' + @echo '' + +${LIB}: FRC + (cd lib; ${MAKE} DEBUG="${DEBUG}" CFGF="${CFGF}") + +version.h: FRC + @echo Constructing version.h + @rm -f version.h + @echo '#define LSOF_BLDCMT "${LSOF_BLDCMT}"' > version.h; + @echo '#define LSOF_CC "${CC}"' >> version.h + @echo '#define LSOF_CCV "${CCV}"' >> version.h + @echo '#define LSOF_CCDATE "'`date`'"' >> version.h + @echo '#define LSOF_CCFLAGS "'`echo ${CFLAGS} | sed 's/\\\\(/\\(/g' | sed 's/\\\\)/\\)/g' | sed 's/"/\\\\"/g'`'"' >> version.h + @echo '#define LSOF_CINFO "${CINFO}"' >> version.h + @if [ "X${LSOF_HOST}" = "X" ]; then \ + echo '#define LSOF_HOST "'`uname -n`'"' >> version.h; \ + else \ + if [ "${LSOF_HOST}" = "none" ]; then \ + echo '#define LSOF_HOST ""' >> version.h; \ + else \ + echo '#define LSOF_HOST "${LSOF_HOST}"' >> version.h; \ + fi \ + fi + @echo '#define LSOF_LDFLAGS "${CFGL}"' >> version.h + @if [ "X${LSOF_LOGNAME}" = "X" ]; then \ + echo '#define LSOF_LOGNAME "${LOGNAME}"' >> version.h; \ + else \ + if [ "${LSOF_LOGNAME}" = "none" ]; then \ + echo '#define LSOF_LOGNAME ""' >> version.h; \ + else \ + echo '#define LSOF_LOGNAME "${LSOF_LOGNAME}"' >> version.h; \ + fi; \ + fi + @if [ "X${LSOF_SYSINFO}" = "X" ]; then \ + echo '#define LSOF_SYSINFO "'`uname -a`'"' >> version.h; \ + else \ + if [ "${LSOF_SYSINFO}" = "none" ]; then \ + echo '#define LSOF_SYSINFO ""' >> version.h; \ + else \ + echo '#define LSOF_SYSINFO "${LSOF_SYSINFO}"' >> version.h; \ + fi \ + fi + @if [ "X${LSOF_USER}" = "X" ]; then \ + echo '#define LSOF_USER "${USER}"' >> version.h; \ + else \ + if [ "${LSOF_USER}" = "none" ]; then \ + echo '#define LSOF_USER ""' >> version.h; \ + else \ + echo '#define LSOF_USER "${LSOF_USER}"' >> version.h; \ + fi \ + fi + @sed '/VN/s/.ds VN \(.*\)/#define LSOF_VERSION "\1"/' < version >> version.h + +FRC: + +# DO NOT DELETE THIS LINE - make depend DEPENDS ON IT + +dfile.o: ${HDR} dfile.c + +dmnt.o: ${HDR} dmnt.c + +dnode.o: ${HDR} dnode.c + +dproc.o: ${HDR} dproc.c + +dsock.o: ${HDR} dsock.c + +dstore.o: ${HDR} dstore.c + +arg.o: ${HDR} arg.c + +main.o: ${HDR} main.c + +misc.o: ${HDR} misc.c + +node.o: ${HDR} node.c + +print.o: ${HDR} print.c + +proc.o: ${HDR} proc.c + +store.o: ${HDR} store.c + +usage.o: ${HDR} version.h usage.c + +util.o: ${HDR} util.c + +# *** Do not add anything here - It will go away. *** diff --git a/dialects/linux/Mksrc b/dialects/linux/Mksrc new file mode 100755 index 0000000..8a1ffa1 --- /dev/null +++ b/dialects/linux/Mksrc @@ -0,0 +1,25 @@ +#!/bin/sh +# +# Mksrc - make Linux source files for /proc-based lsof +# +# WARNING: This script assumes it is running from the main directory +# of the lsof, version 4 distribution. +# +# One environment variable applies: +# +# LSOF_MKC is the method for creating the source files. +# It defaults to "ln -s". A common alternative is "cp". +# +# $Id: Mksrc,v 1.2 2000/12/04 14:31:02 abe Exp $ + + +D=dialects/linux +L="dfile.c dlsof.h dmnt.c dnode.c dproc.c dproto.h dsock.c dstore.c machine.h" + +for i in $L +do + rm -f $i + $LSOF_MKC $D/$i $i + echo "$LSOF_MKC $D/$i $i" +done + diff --git a/dialects/linux/dfile.c b/dialects/linux/dfile.c new file mode 100644 index 0000000..e637258 --- /dev/null +++ b/dialects/linux/dfile.c @@ -0,0 +1,387 @@ +/* + * dfile.c - Linux file processing functions for /proc-based lsof + */ + + +/* + * Copyright 1997 Purdue Research Foundation, West Lafayette, Indiana + * 47907. All rights reserved. + * + * Written by Victor A. Abell + * + * This software is not subject to any license of the American Telephone + * and Telegraph Company or the Regents of the University of California. + * + * Permission is granted to anyone to use this software for any purpose on + * any computer system, and to alter it and redistribute it freely, subject + * to the following restrictions: + * + * 1. Neither the authors nor Purdue University are responsible for any + * consequences of the use of this software. + * + * 2. The origin of this software must not be misrepresented, either by + * explicit claim or by omission. Credit to the authors and Purdue + * University must appear in documentation and sources. + * + * 3. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 4. This notice may not be removed or altered. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright 1997 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: dfile.c,v 1.8 2012/04/10 16:39:50 abe Exp abe $"; +#endif + + +#include "lsof.h" + + +/* + * Local structures + */ + +struct hsfile { + struct sfile *s; /* the Sfile table address */ + struct hsfile *next; /* the next hash bucket entry */ +}; + +/* + * Local static variables + */ + +static struct hsfile *HbyFdi = /* hash by file (dev,ino) buckets */ + (struct hsfile *)NULL; +static int HbyFdiCt = 0; /* HbyFdi entry count */ +static struct hsfile *HbyFrd = /* hash by file raw device buckets */ + (struct hsfile *)NULL; +static int HbyFrdCt = 0; /* HbyFrd entry count */ +static struct hsfile *HbyFsd = /* hash by file system buckets */ + (struct hsfile *)NULL; +static int HbyFsdCt = 0; /* HbyFsd entry count */ +static struct hsfile *HbyNm = /* hash by name buckets */ + (struct hsfile *)NULL; +static int HbyNmCt = 0; /* HbyNm entry count */ + + +/* + * Local definitions + */ + +#define SFDIHASH 4094 /* Sfile hash by (device,inode) number + * pair bucket count (power of 2!) */ +#define SFFSHASH 1024 /* Sfile hash by file system device + * number bucket count (power of 2!) */ +#define SFHASHDEVINO(maj, min, ino, mod) ((int)(((int)((((int)(maj+1))*((int)((min+1))))+ino)*31415)&(mod-1))) + /* hash for Sfile by major device, + * minor device, and inode, modulo mod + * (mod must be a power of 2) */ +#define SFRDHASH 1024 /* Sfile hash by raw device number + * bucket count (power of 2!) */ +#define SFHASHRDEVI(maj, min, rmaj, rmin, ino, mod) ((int)(((int)((((int)(maj+1))*((int)((min+1))))+((int)(rmaj+1)*(int)(rmin+1))+ino)*31415)&(mod-1))) + /* hash for Sfile by major device, + * minor device, major raw device, + * minor raw device, and inode, modulo + * mod (mod must be a power of 2) */ +#define SFNMHASH 4096 /* Sfile hash by name bucket count + * (must be a power of 2!) */ + + +/* + * hashSfile() - hash Sfile entries for use in is_file_named() searches + */ + +void +hashSfile() +{ + static int hs = 0; + int i; + struct sfile *s; + struct hsfile *sh, *sn; +/* + * Do nothing if there are no file search arguments cached or if the + * hashes have already been constructed. + */ + if (!Sfile || hs) + return; +/* + * Allocate hash buckets by (device,inode), file system device, and file name. + */ + if (!(HbyFdi = (struct hsfile *)calloc((MALLOC_S)SFDIHASH, + sizeof(struct hsfile)))) + { + (void) fprintf(stderr, + "%s: can't allocate space for %d (dev,ino) hash buckets\n", + Pn, SFDIHASH); + Exit(1); + } + if (!(HbyFrd = (struct hsfile *)calloc((MALLOC_S)SFRDHASH, + sizeof(struct hsfile)))) + { + (void) fprintf(stderr, + "%s: can't allocate space for %d rdev hash buckets\n", + Pn, SFRDHASH); + Exit(1); + } + if (!(HbyFsd = (struct hsfile *)calloc((MALLOC_S)SFFSHASH, + sizeof(struct hsfile)))) + { + (void) fprintf(stderr, + "%s: can't allocate space for %d file sys hash buckets\n", + Pn, SFFSHASH); + Exit(1); + } + if (!(HbyNm = (struct hsfile *)calloc((MALLOC_S)SFNMHASH, + sizeof(struct hsfile)))) + { + (void) fprintf(stderr, + "%s: can't allocate space for %d name hash buckets\n", + Pn, SFNMHASH); + Exit(1); + } + hs++; +/* + * Scan the Sfile chain, building file, file system, raw device, and file + * name hash bucket chains. + */ + for (s = Sfile; s; s = s->next) { + for (i = 0; i < 3; i++) { + switch (i) { + case 0: /* hash by name */ + if (!s->aname) + continue; + sh = &HbyNm[hashbyname(s->aname, SFNMHASH)]; + HbyNmCt++; + break; + case 1: /* hash by device and inode, or file + * system device */ + if (s->type) { + sh = &HbyFdi[SFHASHDEVINO(GET_MAJ_DEV(s->dev), + GET_MIN_DEV(s->dev), s->i, + SFDIHASH)]; + HbyFdiCt++; + } else { + sh = &HbyFsd[SFHASHDEVINO(GET_MAJ_DEV(s->dev), + GET_MIN_DEV(s->dev), + 0, + SFFSHASH)]; + HbyFsdCt++; + } + break; + case 2: /* hash by file's raw device */ + if ((s->mode == S_IFCHR) || (s->mode == S_IFBLK)) { + sh = &HbyFrd[SFHASHRDEVI(GET_MAJ_DEV(s->dev), + GET_MIN_DEV(s->dev), + GET_MAJ_DEV(s->rdev), + GET_MIN_DEV(s->rdev), + s->i, + SFRDHASH)]; + HbyFrdCt++; + } else + continue; + } + /* + * Add hash to the bucket's chain, allocating new entries for + * all after the first. + */ + if (!sh->s) { + sh->s = s; + sh->next = (struct hsfile *)NULL; + continue; + } else { + if (!(sn = (struct hsfile *)malloc( + (MALLOC_S)sizeof(struct hsfile)))) + { + (void) fprintf(stderr, + "%s: can't allocate hsfile bucket for: %s\n", + Pn, s->aname); + Exit(1); + } + sn->s = s; + sn->next = sh->next; + sh->next = sn; + } + } + } +} + + +/* + * is_file_named() - is this file named? + */ + +int +is_file_named(ty, p, mp, cd) + int ty; /* search type: 0 = only by device + * and inode + * 1 = by device and + * inode, or by file + * system device and + * path for NFS file + * systems + * 2 = only by path + */ + char *p; /* path name (device and inode are + * identified via *Lf) */ + struct mounts *mp; /* NFS file system (NULL if not) */ + int cd; /* character or block type file -- + * VCHR or VBLK vnode, or S_IFCHR + * or S_IFBLK inode */ +{ + char *ep; + int f = 0; + struct mounts *smp; + struct sfile *s = (struct sfile *)NULL; + struct hsfile *sh; + size_t sz; +/* + * Check for a path name match, as requested. + */ + if ((ty == 2) && p && HbyNmCt) { + for (sh = &HbyNm[hashbyname(p, SFNMHASH)]; sh; sh = sh->next) { + if ((s = sh->s) && strcmp(p, s->aname) == 0) { + f = 2; + break; + } + } + } +/* + * Check for a regular file by device and inode number. + */ + if (!f && (ty < 2) && HbyFdiCt && Lf->dev_def + && (Lf->inp_ty == 1 || Lf->inp_ty == 3)) + { + for (sh = &HbyFdi[SFHASHDEVINO(GET_MAJ_DEV(Lf->dev), + GET_MIN_DEV(Lf->dev), + Lf->inode, + SFDIHASH)]; + sh; + sh = sh->next) + { + if ((s = sh->s) && (Lf->dev == s->dev) + && (Lf->inode == s->i)) { + f = 1; + break; + } + } + } +/* + * Check for a file system match. + */ + if (!f && (ty == 1) && HbyFsdCt && Lf->dev_def) { + for (sh = &HbyFsd[SFHASHDEVINO(GET_MAJ_DEV(Lf->dev), + GET_MIN_DEV(Lf->dev), 0, + SFFSHASH)]; + sh; + sh = sh->next) + { + if ((s = sh->s) && (s->dev == Lf->dev)) { + if (Lf->ntype != N_NFS) { + + /* + * A non-NFS file matches to a non-NFS file system by + * device. + */ + if (!(smp = s->mp) || (smp->ty != N_NFS)) { + f = 1; + break; + } + } else { + + /* + * An NFS file must also match to a file system by the + * the path name of the file system -- i.e., the first + * part of the file's path. This terrible, non-UNIX + * hack is forced on lsof by an egregious error in + * Linux NFS that can assign the same device number + * to two different NFS mounts. + */ + if (p && mp && mp->dirl && mp->dir && s->name + && !strncmp(mp->dir, s->name, mp->dirl)) + { + f = 1; + break; + } + } + } + } + } +/* + * Check for a character or block device match. + */ + if (!f && !ty && HbyFrdCt && cd + && Lf->dev_def && (Lf->dev == DevDev) + && Lf->rdev_def + && (Lf->inp_ty == 1 || Lf->inp_ty == 3)) + { + for (sh = &HbyFrd[SFHASHRDEVI(GET_MAJ_DEV(Lf->dev), + GET_MIN_DEV(Lf->dev), + GET_MAJ_DEV(Lf->rdev), + GET_MIN_DEV(Lf->rdev), + Lf->inode, SFRDHASH)]; + sh; + sh = sh->next) + { + if ((s = sh->s) && (s->dev == Lf->dev) + && (s->rdev == Lf->rdev) && (s->i == Lf->inode)) + { + f = 1; + break; + } + } + } +/* + * Convert the name if a match occurred. + */ + switch (f) { + case 0: + return(0); + case 1: + if (s->type) { + + /* + * If the search argument isn't a file system, propagate it + * to Namech[]; otherwise, let printname() compose the name. + */ + (void) snpf(Namech, Namechl, "%s", s->name); + if (s->devnm) { + ep = endnm(&sz); + (void) snpf(ep, sz, " (%s)", s->devnm); + } + } + break; + case 2: + (void) strcpy(Namech, p); + break; + } + if (s) + s->f = 1; + return(1); +} + + +/* + * printdevname() - print character device name + * + * Note: this function should not be needed in /proc-based lsof, but + * since it is called by printname() in print.c, an ersatz one + * is provided here. + */ + +int +printdevname(dev, rdev, f, nty) + dev_t *dev; /* device */ + dev_t *rdev; /* raw device */ + int f; /* 1 = follow with '\n' */ + int nty; /* node type: N_BLK or N_chr */ +{ + char buf[128]; + + (void) snpf(buf, sizeof(buf), "%s device: %d,%d", + (nty == N_BLK) ? "BLK" : "CHR", + (int)GET_MAJ_DEV(*rdev), (int)GET_MIN_DEV(*rdev)); + safestrprt(buf, stdout, f); + return(1); +} diff --git a/dialects/linux/dlsof.h b/dialects/linux/dlsof.h new file mode 100644 index 0000000..dc9a08f --- /dev/null +++ b/dialects/linux/dlsof.h @@ -0,0 +1,179 @@ +/* + * dlsof.h - Linux header file for /proc-based lsof + */ + + +/* + * Copyright 1997 Purdue Research Foundation, West Lafayette, Indiana + * 47907. All rights reserved. + * + * Written by Victor A. Abell + * + * This software is not subject to any license of the American Telephone + * and Telegraph Company or the Regents of the University of California. + * + * Permission is granted to anyone to use this software for any purpose on + * any computer system, and to alter it and redistribute it freely, subject + * to the following restrictions: + * + * 1. Neither the authors nor Purdue University are responsible for any + * consequences of the use of this software. + * + * 2. The origin of this software must not be misrepresented, either by + * explicit claim or by omission. Credit to the authors and Purdue + * University must appear in documentation and sources. + * + * 3. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 4. This notice may not be removed or altered. + */ + + +/* + * $Id: dlsof.h,v 1.23 2015/07/07 19:46:33 abe Exp $ + */ + + +#if !defined(LINUX_LSOF_H) +#define LINUX_LSOF_H 1 + +#include +#define DIRTYPE dirent /* for arg.c's enter_dir() */ +#define __USE_GNU /* to get all O_* symbols in fcntl.h */ +#include +#include +#include +#include +#include +#include +#include +#include + +# if defined(GLIBCV) || defined(__UCLIBC__) || defined(NEEDS_NETINET_TCPH) +#include +# else /* !defined(GLIBCV) && !defined(__UCLIBC__) && !defined(NEEDS_NETINET_TCPH) */ +#include +# endif /* defined(GLIBCV) || defined(__UCLIBC__) || defined(NEEDS_NETINET_TCPH) */ + +# if !defined(HASNORPC_H) +#include +#include +# endif /* !defined(HASNORPC_H) */ + +#if defined(HASSELINUX) +#include +#endif /* defined(HASSELINUX) */ + +#include +#include +#include +#include +#include + + +/* + * 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 , while others + * have a "char comm[TASK_COMM_LEN]" member + * with TASK_COMM_LEN #define'd to be 16. + * Hence, a universal, local definition of + * 16 is #define'd here. */ +#define PROCFS "/proc" +#define QSORT_P void +#define READLEN_T size_t + +/* + * Definitions that indicate what values are present in a stat(2) or lstat(2) + * buffer. + */ + +#define SB_DEV 0x01 /* st_dev */ +#define SB_INO 0x02 /* st_ino */ +#define SB_MODE 0x04 /* st_mode */ +#define SB_NLINK 0x08 /* st_nlink */ +#define SB_RDEV 0x10 /* st_rdev */ +#define SB_SIZE 0x20 /* st_size */ +#define SB_ALL (SB_DEV | SB_INO | SB_MODE | SB_NLINK | SB_RDEV | \ + SB_SIZE) /* all values */ + +#define STRNCPY_L size_t +#define STRNML 32 + +# if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS==64 +#define SZOFFTYPE unsigned long long + /* size and offset internal storage + * type */ +#define SZOFFPSPEC "ll" /* SZOFFTYPE print specification + * modifier */ +# endif /* defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS==64 */ + +#define XDR_PMAPLIST (xdrproc_t)xdr_pmaplist +#define XDR_VOID (xdrproc_t)xdr_void + + +/* + * Global storage definitions (including their structure definitions) + */ + +struct mounts { + char *dir; /* directory name (mounted on) */ + char *fsname; /* file system + * (symbolic links unresolved) */ + char *fsnmres; /* file system + * (symbolic links resolved) */ + size_t dirl; /* length of directory name */ + dev_t dev; /* directory st_dev */ + dev_t rdev; /* directory st_rdev */ + INODETYPE inode; /* directory st_ino */ + mode_t mode; /* directory st_mode */ + int ds; /* directory status -- i.e., SB_* + * values */ + mode_t fs_mode; /* file system st_mode */ + int ty; /* node type -- e.g., N_REGLR, N_NFS */ + struct mounts *next; /* forward link */ +}; + +struct sfile { + char *aname; /* argument file name */ + char *name; /* file name (after readlink()) */ + char *devnm; /* device name (optional) */ + dev_t dev; /* device */ + dev_t rdev; /* raw device */ + mode_t mode; /* S_IFMT mode bits from stat() */ + int type; /* file type: 0 = file system + * 1 = regular file */ + INODETYPE i; /* inode number */ + int f; /* file found flag */ + struct mounts *mp; /* mount structure pointer for file + * system type entries */ +#define SAVE_MP_IN_SFILE 1 /* for ck_file_arg() im arg.c */ + struct sfile *next; /* forward link */ +}; + +extern int HasNFS; +extern int OffType; + +#endif /* LINUX_LSOF_H */ diff --git a/dialects/linux/dmnt.c b/dialects/linux/dmnt.c new file mode 100644 index 0000000..87e63db --- /dev/null +++ b/dialects/linux/dmnt.c @@ -0,0 +1,700 @@ +/* + * dmnt.c -- Linux mount support functions for /proc-based lsof + */ + + +/* + * Copyright 1997 Purdue Research Foundation, West Lafayette, Indiana + * 47907. All rights reserved. + * + * Written by Victor A. Abell + * + * This software is not subject to any license of the American Telephone + * and Telegraph Company or the Regents of the University of California. + * + * Permission is granted to anyone to use this software for any purpose on + * any computer system, and to alter it and redistribute it freely, subject + * to the following restrictions: + * + * 1. Neither the authors nor Purdue University are responsible for any + * consequences of the use of this software. + * + * 2. The origin of this software must not be misrepresented, either by + * explicit claim or by omission. Credit to the authors and Purdue + * University must appear in documentation and sources. + * + * 3. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 4. This notice may not be removed or altered. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright 1997 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: dmnt.c,v 1.21 2018/02/14 14:26:38 abe Exp $"; +#endif + + +#include "lsof.h" + + +/* + * Local definitions + */ + +#if defined(HASMNTSUP) +#define HASHMNT 128 /* mount supplement hash bucket count + * !!!MUST BE A POWER OF 2!!! */ +#endif /* defined(HASMNTSUP) */ + + +/* + * Local function prototypes + */ + +_PROTOTYPE(static char *cvtoe,(char *os)); + +#if defined(HASMNTSUP) +_PROTOTYPE(static int getmntdev,(char *dn, size_t dnl, struct stat *s, int *ss)); +_PROTOTYPE(static int hash_mnt,(char *dn)); +#endif /* defined(HASMNTSUP) */ + + +/* + * Local structure definitions. + */ + +#if defined(HASMNTSUP) +typedef struct mntsup { + char *dn; /* mounted directory name */ + size_t dnl; /* strlen(dn) */ + dev_t dev; /* device number */ + int ln; /* line on which defined */ + struct mntsup *next; /* next entry */ +} mntsup_t; +#endif /* defined(HASMNTSUP) */ + + +/* + * Local static definitions + */ + +static struct mounts *Lmi = (struct mounts *)NULL; /* local mount info */ +static int Lmist = 0; /* Lmi status */ +static mntsup_t **MSHash = (mntsup_t **)NULL; /* mount supplement + * hash buckets */ + + +/* + * cvtoe() -- convert octal-escaped characters in string + */ + +static char * +cvtoe(os) + char *os; /* original string */ +{ + int c, cl, cx, ol, ox, tx; + char *cs; + int tc; +/* + * Allocate space for a copy of the string in which octal-escaped characters + * can be replaced by the octal value -- e.g., \040 with ' '. Leave room for + * a '\0' terminator. + */ + if (!(ol = (int)strlen(os))) + return((char *)NULL); + if (!(cs = (char *)malloc(ol + 1))) { + (void) fprintf(stderr, + "%s: can't allocate %d bytes for octal-escaping.\n", + Pn, ol + 1); + Exit(1); + } +/* + * Copy the string, replacing octal-escaped characters as they are found. + */ + for (cx = ox = 0, cl = ol; ox < ol; ox++) { + if (((c = (int)os[ox]) == (int)'\\') && ((ox + 3) < ol)) { + + /* + * The beginning of an octal-escaped character has been found. + * + * Convert the octal value to a character value. + */ + for (tc = 0, tx = 1; os[ox + tx] && (tx < 4); tx++) { + if (((int)os[ox + tx] < (int)'0') + || ((int)os[ox + tx] > (int)'7')) + { + + /* + * The escape isn't followed by octets, so ignore the + * escape and just copy it. + */ + break; + } + tc <<= 3; + tc += (int)(os[ox + tx] - '0'); + } + if (tx == 4) { + + /* + * If three octets (plus the escape) were assembled, use their + * character-forming result. + * + * Otherwise copy the escape and what follows it until another + * escape is found. + */ + ox += 3; + c = (tc & 0xff); + } + } + if (cx >= cl) { + + /* + * Expand the copy string, as required. Leave room for a '\0' + * terminator. + */ + cl += 64; /* (Make an arbitrary increase.) */ + if (!(cs = (char *)realloc(cs, cl + 1))) { + (void) fprintf(stderr, + "%s: can't realloc %d bytes for octal-escaping.\n", + Pn, cl + 1); + Exit(1); + } + } + /* + * Copy the character. + */ + cs[cx++] = (char)c; + } +/* + * Terminate the copy and return its pointer. + */ + cs[cx] = '\0'; + return(cs); +} + + +#if defined(HASMNTSUP) +/* + * getmntdev() - get mount device from mount supplement + */ + +static int +getmntdev(dn, dnl, s, ss) + char *dn; /* mounted directory name */ + size_t dnl; /* strlen(dn) */ + struct stat *s; /* stat(2) buffer receptor */ + int *ss; /* stat(2) status result -- i.e., SB_* + * values */ +{ + static int err = 0; + int h; + mntsup_t *mp, *mpn; + static char *vbuf = (char *)NULL; + static size_t vsz = (size_t)0; + + if (err) + return(0); + if (!MSHash) { + + /* + * No mount supplement hash buckets have been allocated, so read the + * mount supplement file and create hash buckets for its entries. + */ + char buf[(MAXPATHLEN*2) + 1], *dp, path[(MAXPATHLEN*2) + 1]; + dev_t dev; + FILE *fs; + int ln = 0; + size_t sz; + + if ((MntSup != 2) || !MntSupP) + return(0); + if (!is_readable(MntSupP, 1)) { + + /* + * The mount supplement file isn't readable. + */ + err = 1; + return(0); + } + if (!(fs = open_proc_stream(MntSupP, "r", &vbuf, &vsz, 0))) { + + /* + * The mount supplement file can't be opened for reading. + */ + if (!Fwarn) + (void) fprintf(stderr, "%s: can't open(%s): %s\n", + Pn, MntSupP, strerror(errno)); + err = 1; + return(0); + } + buf[sizeof(buf) - 1] = '\0'; + /* + * Read the mount supplement file. + */ + while (fgets(buf, sizeof(buf) - 1, fs)) { + ln++; + if ((dp = strchr(buf, '\n'))) + *dp = '\0'; + if (buf[0] != '/') { + + /* + * The mount supplement line doesn't begin with the absolute + * path character '/'. + */ + if (!Fwarn) + (void) fprintf(stderr, + "%s: %s line %d: no path: \"%s\"\n", + Pn, MntSupP, ln, buf); + err = 1; + continue; + } + if (!(dp = strchr(buf, ' ')) || strncmp(dp + 1, "0x", 2)) { + + /* + * The path on the mount supplement line isn't followed by + * " 0x". + */ + if (!Fwarn) + (void) fprintf(stderr, + "%s: %s line %d: no device: \"%s\"\n", + Pn, MntSupP, ln, buf); + err = 1; + continue; + } + sz = (size_t)(dp - buf); + (void) strncpy(path, buf, sz); + path[sz] = '\0'; + /* + * Assemble the hexadecimal device number of the mount supplement + * line. + */ + for (dev = 0, dp += 3; *dp; dp++) { + if (!isxdigit((int)*dp)) + break; + if (isdigit((int)*dp)) + dev = (dev << 4) + (int)*dp - (int)'0'; + else + dev = (dev << 4) + (int)tolower(*dp) - (int)'a' + 10; + } + if (*dp) { + + /* + * The device number couldn't be assembled. + */ + if (!Fwarn) + (void) fprintf(stderr, + "%s: %s line %d: illegal device: \"%s\"\n", + Pn, MntSupP, ln, buf); + err = 1; + continue; + } + /* + * Search the mount supplement hash buckets. (Allocate them as + * required.) + */ + if (!MSHash) { + if (!(MSHash = (mntsup_t **)calloc(HASHMNT, + sizeof(mntsup_t *))) + ) { + (void) fprintf(stderr, + "%s: no space for mount supplement hash buckets\n", + Pn); + Exit(1); + } + } + h = hash_mnt(path); + for (mp = MSHash[h]; mp; mp = mp->next) { + if ((mp->dnl == dnl) && !strcmp(mp->dn, path)) + break; + } + if (mp) { + + /* + * A path match was located. If the device number is the + * same, skip this mount supplement line. Otherwise, issue + * a warning. + */ + if (mp->dev != dev) { + (void) fprintf(stderr, + "%s: %s line %d path duplicate of %d: \"%s\"\n", + Pn, MntSupP, ln, mp->ln, buf); + err = 1; + } + continue; + } + /* + * Allocate and fill a new mount supplement hash entry. + */ + if (!(mpn = (mntsup_t *)malloc(sizeof(mntsup_t)))) { + (void) fprintf(stderr, + "%s: no space for mount supplement entry: %d \"%s\"\n", + Pn, ln, buf); + Exit(1); + } + if (!(mpn->dn = (char *)malloc(sz + 1))) { + (void) fprintf(stderr, + "%s: no space for mount supplement path: %d \"%s\"\n", + Pn, ln, buf); + Exit(1); + } + (void) strcpy(mpn->dn, path); + mpn->dnl = sz; + mpn->dev = dev; + mpn->ln = ln; + mpn->next = MSHash[h]; + MSHash[h] = mpn; + } + if (ferror(fs)) { + if (!Fwarn) + (void) fprintf(stderr, "%s: error reading %s\n", + Pn, MntSupP); + err = 1; + } + (void) fclose(fs); + if (err) { + if (MSHash) { + for (h = 0; h < HASHMNT; h++) { + for (mp = MSHash[h]; mp; mp = mpn) { + mpn = mp->next; + if (mp->dn) + (void) free((MALLOC_P *)mp->dn); + (void) free((MALLOC_P *)mp); + } + } + (void) free((MALLOC_P *)MSHash); + MSHash = (mntsup_t **)NULL; + } + return(0); + } + } +/* + * If no errors have been detected reading the mount supplement file, search + * its hash buckets for the supplied directory path. + */ + if (err) + return(0); + h = hash_mnt(dn); + for (mp = MSHash[h]; mp; mp = mp->next) { + if ((dnl == mp->dnl) && !strcmp(dn, mp->dn)) { + 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(dn) + char *dn; /* mount point directory name */ +{ + register int i, h; + size_t l; + + if (!(l = strlen(dn))) + return(0); + if (l == 1) + return((int)*dn & (HASHMNT - 1)); + for (i = h = 0; i < (int)(l - 1); i++) { + h ^= ((int)dn[i] * (int)dn[i+1]) << ((i*3)%13); + } + return(h & (HASHMNT - 1)); +} +#endif /* defined(HASMNTSUP) */ + + +/* + * readmnt() - read mount table + */ + +struct mounts * +readmnt() +{ + char buf[MAXPATHLEN], *cp, **fp; + char *dn = (char *)NULL; + size_t dnl; + int ds, ne; + char *fp0 = (char *)NULL; + char *fp1 = (char *)NULL; + int fr, ignrdl, ignstat; + char *ln; + struct mounts *mp; + FILE *ms; + int nfs; + struct stat sb; + static char *vbuf = (char *)NULL; + static size_t vsz = (size_t)0; + + if (Lmi || Lmist) + return(Lmi); +/* + * Open access to /proc/mounts, assigning a page size buffer to its stream. + */ + (void) snpf(buf, sizeof(buf), "%s/mounts", PROCFS); + ms = open_proc_stream(buf, "r", &vbuf, &vsz, 1); +/* + * Read mount table entries. + */ + while (fgets(buf, sizeof(buf), ms)) { + if (get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0) < 3 + || !fp[0] || !fp[1] || !fp[2]) + continue; + /* + * Convert octal-escaped characters in the device name and mounted-on + * path name. + */ + if (fp0) { + (void) free((FREE_P *)fp0); + fp0 = (char *)NULL; + } + if (fp1) { + (void) free((FREE_P *)fp1); + fp1 = (char *)NULL; + } + if (!(fp0 = cvtoe(fp[0])) || !(fp1 = cvtoe(fp[1]))) + continue; + /* + * Locate any colon (':') in the device name. + * + * If the colon is followed by * "(pid*" -- it's probably an + * automounter entry. + * + * Ignore autofs, pipefs, and sockfs entries. + */ + cp = strchr(fp0, ':'); + if (cp && !strncasecmp(++cp, "(pid", 4)) + continue; + if (!strcasecmp(fp[2], "autofs") || !strcasecmp(fp[2], "pipefs") + || !strcasecmp(fp[2], "sockfs")) + continue; + /* + * Interpolate a possible symbolic mounted directory link. + */ + if (dn) + (void) free((FREE_P *)dn); + dn = fp1; + fp1 = (char *)NULL; + +#if defined(HASEOPT) + if (Efsysl) { + + /* + * If there is an -e file system list, check it to decide if a stat() + * and Readlink() on this one should be performed. + */ + efsys_list_t *ep; + + for (ignrdl = ignstat = 0, ep = Efsysl; ep; ep = ep->next) { + if (!strcmp(dn, ep->path)) { + ignrdl = ep->rdlnk; + ignstat = 1; + break; + } + } + } else + +#endif /* defined(HASEOPT */ + + ignrdl = ignstat = 0; + + /* + * Avoid Readlink() when requested. + */ + if (!ignrdl) { + if (!(ln = Readlink(dn))) { + if (!Fwarn) { + (void) fprintf(stderr, + " Output information may be incomplete.\n"); + } + continue; + } + if (ln != dn) { + (void) free((FREE_P *)dn); + dn = ln; + } + } + if (*dn != '/') + continue; + dnl = strlen(dn); + /* + * Test for duplicate and NFS directories. + */ + for (mp = Lmi; mp; mp = mp->next) { + if ((dnl == mp->dirl) && !strcmp(dn, mp->dir)) + break; + } + if ((nfs = strcasecmp(fp[2], "nfs"))) { + if ((nfs = strcasecmp(fp[2], "nfs3"))) + nfs = strcasecmp(fp[2], "nfs4"); + } + if (!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(dn, &sb))) { + if (!Fwarn) { + (void) fprintf(stderr, "%s: WARNING: can't stat() ", + Pn); + safestrprt(fp[2], stderr, 0); + (void) fprintf(stderr, " file system "); + safestrprt(dn, stderr, 1); + (void) fprintf(stderr, + " Output information may be incomplete.\n"); + } + } else + ds = SB_ALL; + } + +#if defined(HASMNTSUP) + if (fr) { + + /* + * If the stat() failed or wasn't called, check the mount + * supplement table, if possible. + */ + if ((MntSup == 2) && MntSupP) { + ds = 0; + if (getmntdev(dn, dnl, &sb, &ds) || !(ds & SB_DEV)) { + (void) fprintf(stderr, + "%s: assuming dev=%#lx for %s from %s\n", + Pn, (long)sb.st_dev, dn, MntSupP); + } + } else { + if (!ignstat) + continue; + ds = 0; /* No stat() was allowed. */ + } + } +#else /* !defined(HASMNTSUP) */ + if (fr) { + if (!ignstat) + continue; + ds = 0; /* No stat() was allowed. */ + } +#endif /* defined(HASMNTSUP) */ + + /* + * Fill a local mount structure or reuse a previous entry when + * indicated. + */ + if (mp) { + ne = 0; + if (mp->dir) { + (void) free((FREE_P *)mp->dir); + mp->dir = (char *)NULL; + } + if (mp->fsname) { + (void) free((FREE_P *)mp->fsname); + mp->fsname = (char *)NULL; + } + } else { + ne = 1; + if (!(mp = (struct mounts *)malloc(sizeof(struct mounts)))) { + (void) fprintf(stderr, + "%s: can't allocate mounts struct for: ", Pn); + safestrprt(dn, stderr, 1); + Exit(1); + } + } + mp->dir = dn; + dn = (char *)NULL; + mp->dirl = dnl; + if (ne) + mp->next = Lmi; + mp->dev = ((mp->ds = ds) & SB_DEV) ? sb.st_dev : 0; + mp->rdev = (ds & SB_RDEV) ? sb.st_rdev : 0; + mp->inode = (INODETYPE)((ds & SB_INO) ? sb.st_ino : 0); + mp->mode = (ds & SB_MODE) ? sb.st_mode : 0; + if (!nfs) { + mp->ty = N_NFS; + if (HasNFS < 2) + HasNFS = 2; + } else + mp->ty = N_REGLR; + +#if defined(HASMNTSUP) + /* + * If support for the mount supplement file is defined and if the + * +m option was supplied, print mount supplement information. + */ + if (MntSup == 1) { + if (mp->dev) + (void) printf("%s %#lx\n", mp->dir, (long)mp->dev); + else + (void) printf("%s 0x0\n", mp->dir); + } +#endif /* defined(HASMNTSUP) */ + + /* + * Save mounted-on device or directory name. + */ + dn = fp0; + fp0 = (char *)NULL; + mp->fsname = dn; + /* + * Interpolate a possible file system (mounted-on) device name or + * directory name link. + * + * Avoid Readlink() when requested. + */ + if (ignrdl || (*dn != '/')) { + if (!(ln = mkstrcpy(dn, (MALLOC_S *)NULL))) { + (void) fprintf(stderr, + "%s: can't allocate space for: ", Pn); + safestrprt(dn, stderr, 1); + Exit(1); + } + ignstat = 1; + } else + ln = Readlink(dn); + dn = (char *)NULL; + /* + * Stat() the file system (mounted-on) name and add file system + * information to the local mount table entry. + */ + if (ignstat || !ln || statsafely(ln, &sb)) + sb.st_mode = 0; + mp->fsnmres = ln; + mp->fs_mode = sb.st_mode; + if (ne) + Lmi = mp; + } +/* + * Clean up and return the local mount info table address. + */ + (void) fclose(ms); + if (dn) + (void) free((FREE_P *)dn); + if (fp0) + (void) free((FREE_P *)fp0); + if (fp1) + (void) free((FREE_P *)fp1); + Lmist = 1; + return(Lmi); +} diff --git a/dialects/linux/dnode.c b/dialects/linux/dnode.c new file mode 100644 index 0000000..58288d6 --- /dev/null +++ b/dialects/linux/dnode.c @@ -0,0 +1,882 @@ +/* + * dnode.c - Linux node functions for /proc-based lsof + */ + + +/* + * Copyright 1997 Purdue Research Foundation, West Lafayette, Indiana + * 47907. All rights reserved. + * + * Written by Victor A. Abell + * + * This software is not subject to any license of the American Telephone + * and Telegraph Company or the Regents of the University of California. + * + * Permission is granted to anyone to use this software for any purpose on + * any computer system, and to alter it and redistribute it freely, subject + * to the following restrictions: + * + * 1. Neither the authors nor Purdue University are responsible for any + * consequences of the use of this software. + * + * 2. The origin of this software must not be misrepresented, either by + * explicit claim or by omission. Credit to the authors and Purdue + * University must appear in documentation and sources. + * + * 3. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 4. This notice may not be removed or altered. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright 1997 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: dnode.c,v 1.27 2018/03/26 21:52:29 abe Exp $"; +#endif + + +#include "lsof.h" + +#if defined(HASEPTOPTS) && defined(HASPTYEPT) +#include +#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; + char type; + struct llock *next; +}; + + +/* + * Local definitions + */ + +struct llock **LckH = (struct llock **)NULL; /* PID-hashed locks */ + + +/* + * Local function prototypes + */ + +_PROTOTYPE(static void check_lock,(void)); + +#if defined(HASEPTOPTS) +_PROTOTYPE(static void enter_pinfo,(void)); +#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) */ +#endif /* defined(HASEPTOPTS) */ + + +/* + * check_lock() - check lock for file *Lf, process *Lp + */ + +static void +check_lock() +{ + int h; + struct llock *lp; + + h = HASHPID(Lp->pid); + for (lp = LckH[h]; lp; lp = lp->next) { + if (Lp->pid == lp->pid + && Lf->dev == lp->dev + && Lf->inode == lp->inode) + { + Lf->lock = lp->type; + return; + } + } +} + + +#if defined(HASEPTOPTS) +/* + * clear_pinfo() -- clear allocated pipe info + */ + +void +clear_pinfo() +{ + int h; /* hash index */ + pxinfo_t *pi, *pp; /* temporary pointers */ + + if (!Pinfo) + return; + for (h = 0; h < PINFOBUCKS; h++) { + if ((pi = Pinfo[h])) { + do { + pp = pi->next; + (void) free((FREE_P *)pi); + pi = pp; + } while (pi); + Pinfo[h] = (pxinfo_t *)NULL; + } + } +} + + +/* + * enter_pinfo() -- enter pipe info + * + * entry Lf = local file structure pointer + * Lp = local process structure pointer + */ + +static void +enter_pinfo() +{ + int h; /* hash result */ + struct lfile *lf; /* local file structure pointer */ + struct lproc *lp; /* local proc structure pointer */ + pxinfo_t *np, *pi, *pe; /* pipe info pointers */ + + 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); + Exit(1); + } + } + /* + * Make sure this is a unique entry. + */ + for (h = HASHPINFO(Lf->inode), pi = Pinfo[h], pe = (pxinfo_t *)NULL; + pi; + pe = pi, pi = pi->next + ) { + lf = pi->lf; + lp = &Lproc[pi->lpx]; + if (pi->ino == Lf->inode) { + if ((lp->pid == Lp->pid) && !strcmp(lf->fd, Lf->fd)) + return; + } + } + /* + * Allocate, fill and link a new pipe info structure to the end of + * the pipe inode hash chain. + */ + if (!(np = (pxinfo_t *)malloc(sizeof(pxinfo_t)))) { + (void) fprintf(stderr, + "%s: no space for pipeinfo, PID %d, FD %s\n", + Pn, Lp->pid, Lf->fd); + Exit(1); + } + np->ino = Lf->inode; + np->lf = Lf; + np->lpx = Lp - Lproc; + np->next = (pxinfo_t *)NULL; + if (pe) + pe->next = np; + else + Pinfo[h] = np; +} + + +#if defined(HASPTYEPT) + + +/* + * clear_ptyinfo() -- clear allocated pseudoterminal info + */ + +void +clear_ptyinfo() +{ + int h; /* hash index */ + pxinfo_t *pi, *pp; /* temporary pointers */ + + if (!PtyInfo) + return; + for (h = 0; h < PINFOBUCKS; h++) { + if ((pi = PtyInfo[h])) { + do { + pp = pi->next; + (void) free((FREE_P *)pi); + pi = pp; + } while (pi); + PtyInfo[h] = (pxinfo_t *)NULL; + } + } +} + + +/* + * enter_ptmxi() -- enter pty info + * + * entry Lf = local file structure pointer + * Lp = local process structure pointer + */ + +void +enter_ptmxi(mn) + int mn; /* minor number of device */ +{ + int h; /* hash result */ + struct lfile *lf; /* local file structure pointer */ + struct lproc *lp; /* local proc structure pointer */ + pxinfo_t *np, *pi, *pe; /* inode hash pointers */ + + if (!PtyInfo) { + + /* + * Allocate pipe info hash buckets (but used for pty). + */ + if (!(PtyInfo = (pxinfo_t **)calloc(PINFOBUCKS, + sizeof(pxinfo_t *)))) + { + (void) fprintf(stderr, + "%s: no space for %d pty info buckets\n", Pn, PINFOBUCKS); + Exit(1); + } + } + /* + * Make sure this is a unique entry. + */ + for (h = HASHPINFO(mn), pi = PtyInfo[h], pe = (pxinfo_t *)NULL; + pi; + pe = pi, pi = pi->next + ) { + lf = pi->lf; + lp = &Lproc[pi->lpx]; + if (pi->ino == mn) { + if ((lp->pid == Lp->pid) && !strcmp(lf->fd, Lf->fd)) + 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)))) { + (void) fprintf(stderr, + "%s: no space for pipeinfo for pty, PID %d, FD %s\n", + Pn, Lp->pid, Lf->fd); + Exit(1); + } + np->ino = mn; + np->lf = Lf; + np->lpx = Lp - Lproc; + np->next = (pxinfo_t *)NULL; + if (pe) + pe->next = np; + else + PtyInfo[h] = np; +} + + +/* + * find_ptyepti() -- find pseudoterminal end point info + */ + +pxinfo_t * +find_ptyepti(lf, m, pp) + 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) */ +{ + struct lfile *ef; /* pseudoterminal end local file */ + int h; /* hash result */ + INODETYPE mn; /* minor number */ + pxinfo_t *pi; /* pseudoterminal info pointer */ + + + mn = m ? GET_MIN_DEV(lf->rdev) : lf->tty_index; + if (PtyInfo) { + if (pp) + pi = pp; + else { + h = HASHPINFO(mn); + pi = PtyInfo[h]; + } + while (pi) { + if (pi->ino == mn) { + ef = pi->lf; + if (((m && is_pty_ptmx(ef->rdev)) + || ((!m) && is_pty_slave(GET_MAJ_DEV(ef->rdev)))) + && strcmp(lf->fd, ef->fd) + ) { + return(pi); + } + } + pi = pi->next; + } + } + return((pxinfo_t *)NULL); +} + + +/* + * is_pty_slave() -- is a pseudoterminal a slave device + */ + +int +is_pty_slave(sm) + int sm; /* slave major device number */ +{ + if ((UNIX98_PTY_SLAVE_MAJOR <= sm) + && (sm < (UNIX98_PTY_SLAVE_MAJOR + UNIX98_PTY_SLAVE_MAJOR)) + ) { + return 1; + } + return 0; +} + + +/* + * is_pty_ptmx() -- is a pseudoterminal a master clone device + */ + +int +is_pty_ptmx(dev) + dev_t dev; /* device number */ +{ + if ((GET_MAJ_DEV(dev) == TTYAUX_MAJOR) && (GET_MIN_DEV(dev) == 2)) + return 1; + return 0; +} +#endif /* defined(HASPTYEPT) */ + + +/* + * find_pepti() -- find pipe end point info + */ + +pxinfo_t * +find_pepti(lf, pp) + struct lfile *lf; /* pipe's lfile */ + pxinfo_t *pp; /* previous pipe info (NULL == none) */ +{ + struct lfile *ef; /* pipe end local file structure */ + int h; /* hash result */ + pxinfo_t *pi; /* pipe info pointer */ + + if (Pinfo) { + if (pp) + pi = pp; + else { + h = HASHPINFO(lf->inode); + pi = Pinfo[h]; + } + while (pi) { + if (pi->ino == lf->inode) { + ef = pi->lf; + if (strcmp(lf->fd, ef->fd)) + return(pi); + } + pi = pi->next; + } + } + return((pxinfo_t *)NULL); + +} +#endif /* defined(HASEPTOPTS) */ + + + +/* + * get_fields() - separate a line into fields + */ + +int +get_fields(ln, sep, fr, eb, en) + char *ln; /* input line */ + char *sep; /* separator list */ + char ***fr; /* field pointer return address */ + int *eb; /* indexes of fields where blank or an + * entry from the separator list may be + * embedded and are not separators + * (may be NULL) */ + int en; /* number of entries in eb[] (may be + * zero) */ +{ + char *bp, *cp, *sp; + int i, j, n; + MALLOC_S len; + static char **fp = (char **)NULL; + static int nfpa = 0; + + for (cp = ln, n = 0; cp && *cp;) { + for (bp = cp; *bp && (*bp == ' ' || *bp == '\t'); bp++); + ; + if (!*bp || *bp == '\n') + break; + for (cp = bp; *cp; cp++) { + if (*cp == '\n') { + *cp = '\0'; + break; + } + if (*cp == '\t') /* TAB is always a separator */ + break; + if (*cp == ' ') { + + /* + * See if this field may have an embedded space. + */ + if (!eb || !en) + break; + else { + for (i = j = 0; i < en; i++) { + if (eb[i] == n) { + j = 1; + break; + } + } + if (!j) + break; + } + } + if (sep) { + + /* + * See if the character is in the separator list. + */ + for (sp = sep; *sp; sp++) { + if (*sp == *cp) + break; + } + if (*sp) { + + /* + * See if this field may have an embedded separator. + */ + if (!eb || !en) + break; + else { + for (i = j = 0; i < en; i++) { + if (eb[i] == n) { + j = 1; + break; + } + } + if (!j) + break; + } + } + } + } + if (*cp) + *cp++ = '\0'; + if (n >= nfpa) { + nfpa += 32; + len = (MALLOC_S)(nfpa * sizeof(char *)); + if (fp) + fp = (char **)realloc((MALLOC_P *)fp, len); + else + fp = (char **)malloc(len); + if (!fp) { + (void) fprintf(stderr, + "%s: can't allocate %d bytes for field pointers.\n", + Pn, (int)len); + Exit(1); + } + } + fp[n++] = bp; + } + *fr = fp; + return(n); +} + + +/* + * get_locks() - get lock information from /proc/locks + */ + +void +get_locks(p) + char *p; /* /proc lock path */ +{ + unsigned long bp, ep; + char buf[MAXPATHLEN], *ec, **fp; + dev_t dev; + int ex, i, h, mode, pid; + INODETYPE inode; + struct llock *lp, *np; + FILE *ls; + long maj, min; + char type; + static char *vbuf = (char *)NULL; + static size_t vsz = (size_t)0; +/* + * Destroy previous lock information. + */ + if (LckH) { + for (i = 0; i < PIDBUCKS; i++) { + for (lp = LckH[i]; lp; lp = np) { + np = lp->next; + (void) free((FREE_P *)lp); + } + LckH[i] = (struct llock *)NULL; + } + } else { + + /* + * If first time, allocate the lock PID hash buckets. + */ + LckH = (struct llock **)calloc((MALLOC_S)PIDBUCKS, + sizeof(struct llock *)); + if (!LckH) { + (void) fprintf(stderr, + "%s: can't allocate %d lock hash bytes\n", + Pn, (int)(sizeof(struct llock *) * PIDBUCKS)); + Exit(1); + } + } +/* + * Open the /proc lock file, assign a page size buffer to its stream, + * and read it. + */ + if (!(ls = open_proc_stream(p, "r", &vbuf, &vsz, 0))) + return; + while (fgets(buf, sizeof(buf), ls)) { + if (get_fields(buf, ":", &fp, (int *)NULL, 0) < 10) + continue; + if (!fp[1] || strcmp(fp[1], "->") == 0) + continue; + /* + * Get lock type. + */ + if (!fp[3]) + continue; + if (*fp[3] == 'R') + mode = 0; + else if (*fp[3] == 'W') + mode = 1; + else + continue; + /* + * Get PID. + */ + if (!fp[4] || !*fp[4]) + continue; + pid = atoi(fp[4]); + /* + * Get device number. + */ + ec = (char *)NULL; + if (!fp[5] || !*fp[5] + || (maj = strtol(fp[5], &ec, 16)) == LONG_MIN || maj == LONG_MAX + || !ec || *ec) + continue; + ec = (char *)NULL; + if (!fp[6] || !*fp[6] + || (min = strtol(fp[6], &ec, 16)) == LONG_MIN || min == LONG_MAX + || !ec || *ec) + continue; + dev = (dev_t)makedev((int)maj, (int)min); + /* + * Get inode number. + */ + ec = (char *)NULL; + if (!fp[7] || !*fp[7] + || (inode = strtoull(fp[7], &ec, 0)) == ULONG_MAX + || !ec || *ec) + continue; + /* + * Get lock extent. Convert it and the lock type to a lock character. + */ + if (!fp[8] || !*fp[8] || !fp[9] || !*fp[9]) + continue; + ec = (char *)NULL; + if ((bp = strtoul(fp[8], &ec, 0)) == ULONG_MAX || !ec || *ec) + continue; + if (!strcmp(fp[9], "EOF")) /* for Linux 2.4.x */ + ep = OFFSET_MAX; + else { + ec = (char *)NULL; + if ((ep = strtoul(fp[9], &ec, 0)) == ULONG_MAX || !ec || *ec) + continue; + } + ex = ((off_t)bp == (off_t)0 && (off_t)ep == OFFSET_MAX) ? 1 : 0; + if (mode) + type = ex ? 'W' : 'w'; + else + type = ex ? 'R' : 'r'; + /* + * Look for this lock via the hash buckets. + */ + h = HASHPID(pid); + for (lp = LckH[h]; lp; lp = lp->next) { + if (lp->pid == pid + && lp->dev == dev + && lp->inode == inode + && lp->type == type) + break; + } + if (lp) + continue; + /* + * Allocate a new llock structure and link it to the PID hash bucket. + */ + if (!(lp = (struct llock *)malloc(sizeof(struct llock)))) { + (void) snpf(buf, sizeof(buf), InodeFmt_d, inode); + (void) fprintf(stderr, + "%s: can't allocate llock: PID %d; dev %x; inode %s\n", + Pn, pid, (int)dev, buf); + Exit(1); + } + lp->pid = pid; + lp->dev = dev; + lp->inode = inode; + lp->type = type; + lp->next = LckH[h]; + LckH[h] = lp; + } + (void) fclose(ls); +} + + +/* + * process_proc_node() - process file node + */ + +void +process_proc_node(p, pbr, s, ss, l, ls) + char *p; /* node's readlink() path */ + char *pbr; /* node's path before readlink() */ + struct stat *s; /* stat() result for path */ + int ss; /* *s status -- i.e., SB_* values */ + struct stat *l; /* lstat() result for FD (NULL for + * others) */ + int ls; /* *l status -- i.e., SB_* values */ +{ + mode_t access; + mode_t type = 0; + char *cp; + struct mounts *mp = (struct mounts *)NULL; + size_t sz; + char *tn; +/* + * Set the access mode, if possible. + */ + if (l && (ls & SB_MODE) && ((l->st_mode & S_IFMT) == S_IFLNK)) { + if ((access = l->st_mode & (S_IRUSR | S_IWUSR)) == S_IRUSR) + Lf->access = 'r'; + else if (access == S_IWUSR) + Lf->access = 'w'; + else + Lf->access = 'u'; + } +/* + * Determine node type. + */ + if (ss & SB_MODE) { + type = s->st_mode & S_IFMT; + switch (type) { + case S_IFBLK: + Lf->ntype = Ntype = N_BLK; + break; + case S_IFCHR: + Lf->ntype = Ntype = N_CHR; + break; + case S_IFIFO: + Lf->ntype = Ntype = N_FIFO; + break; + case S_IFSOCK: + /* Lf->ntype = Ntype = N_REGLR; by alloc_lfile() */ + process_proc_sock(p, pbr, s, ss, l, ls); + return; + case 0: + if (!strcmp(p, "anon_inode")) + Lf->ntype = Ntype = N_ANON_INODE; + break; + } + } + if (Selinet) + return; +/* + * Save the device. If it is an NFS device, change the node type to N_NFS. + */ + if (ss & SB_DEV) { + Lf->dev = s->st_dev; + Lf->dev_def = 1; + } + if ((Ntype == N_CHR || Ntype == N_BLK)) { + if (ss & SB_RDEV) { + Lf->rdev = s->st_rdev; + Lf->rdev_def = 1; + +#if defined(HASEPTOPTS) && defined(HASPTYEPT) + if (FeptE + && (Ntype == N_CHR) + && is_pty_slave(GET_MAJ_DEV(Lf->rdev)) + ) { + enter_ptmxi(GET_MIN_DEV(Lf->rdev)); + Lf->sf |= SELPTYINFO; + } +#endif /* defined(HASEPTOPTS) && defined(HASPTYEPT) */ + + } + } + if (Ntype == N_REGLR && (HasNFS == 2)) { + for (mp = readmnt(); mp; mp = mp->next) { + if ((mp->ty == N_NFS) + && (mp->ds & SB_DEV) && Lf->dev_def && (Lf->dev == mp->dev) + && (mp->dir && mp->dirl + && !strncmp(mp->dir, p, mp->dirl)) + ) { + Lf->ntype = Ntype = N_NFS; + break; + } + } + } +/* + * Save the inode number. + */ + if (ss & SB_INO) { + Lf->inode = (INODETYPE)s->st_ino; + Lf->inp_ty = 1; + +#if defined(HASEPTOPTS) + if ((Lf->ntype == N_FIFO) && FeptE) { + (void) enter_pinfo(); + Lf->sf |= SELPINFO; + } +#endif /* defined(HASEPTOPTS) */ + + } +/* + * Check for a lock. + */ + if (Lf->dev_def && (Lf->inp_ty == 1)) + (void) check_lock(); +/* + * Save the file size. + */ + switch (Ntype) { + case N_BLK: + case N_CHR: + case N_FIFO: + if (!Fsize && l && (ls & SB_SIZE) && OffType) { + Lf->off = (SZOFFTYPE)l->st_size; + Lf->off_def = 1; + } + break; + default: + if (Foffset) { + if (l && (ls & SB_SIZE) && OffType) { + Lf->off = (SZOFFTYPE)l->st_size; + Lf->off_def = 1; + } + } else if (!Foffset || Fsize) { + if (ss & SB_SIZE) { + Lf->sz = (SZOFFTYPE)s->st_size; + Lf->sz_def = 1; + } + } + } +/* + * Record the link count. + */ + if (Fnlink && (ss & SB_NLINK)) { + Lf->nlink = (long)s->st_nlink; + Lf->nlink_def = 1; + if (Nlink && (Lf->nlink < Nlink)) + Lf->sf |= SELNLINK; + } +/* + * Format the type name. + */ + if (ss & SB_MODE) { + switch (type) { + case S_IFBLK: + tn = "BLK"; + break; + case S_IFCHR: + tn = "CHR"; + break; + case S_IFDIR: + tn = "DIR"; + break; + case S_IFIFO: + tn = "FIFO"; + break; + case S_IFREG: + tn = "REG"; + break; + case S_IFLNK: + tn = "LINK"; + break; + case S_ISVTX: + tn = "VTXT"; + break; + default: + if (Ntype == N_ANON_INODE) + tn = "a_inode"; + else { + (void) snpf(Lf->type, sizeof(Lf->type), "%04o", + ((type >> 12) & 0xf)); + tn = (char *)NULL; + } + } + } else + tn = "unknown"; + if (tn) + (void) snpf(Lf->type, sizeof(Lf->type), "%s", tn); +/* + * Record an NFS file selection. + */ + if (Ntype == N_NFS && Fnfs) + Lf->sf |= SELNFS; +/* + * Test for specified file. + */ + if (Sfile + && is_file_named(1, p, mp, + ((type == S_IFCHR) || (type == S_IFBLK)) ? 1 : 0)) + Lf->sf |= SELNM; +/* + * If no NAME information has been stored, store the path. + * + * Store the remote host and mount point for an NFS file. + */ + if (!Namech[0]) { + (void) snpf(Namech, Namechl, "%s", p); + if ((Ntype == N_NFS) && mp && mp->fsname) { + cp = endnm(&sz); + (void) snpf(cp, sz, " (%s)", mp->fsname); + } + } + if (Namech[0]) + enter_nm(Namech); +} diff --git a/dialects/linux/dproc.c b/dialects/linux/dproc.c new file mode 100644 index 0000000..861ce74 --- /dev/null +++ b/dialects/linux/dproc.c @@ -0,0 +1,1715 @@ +/* + * dproc.c - Linux process access functions for /proc-based lsof + */ + + +/* + * Copyright 1997 Purdue Research Foundation, West Lafayette, Indiana + * 47907. All rights reserved. + * + * Written by Victor A. Abell + * + * This software is not subject to any license of the American Telephone + * and Telegraph Company or the Regents of the University of California. + * + * Permission is granted to anyone to use this software for any purpose on + * any computer system, and to alter it and redistribute it freely, subject + * to the following restrictions: + * + * 1. Neither the authors nor Purdue University are responsible for any + * consequences of the use of this software. + * + * 2. The origin of this software must not be misrepresented, either by + * explicit claim or by omission. Credit to the authors and Purdue + * University must appear in documentation and sources. + * + * 3. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 4. This notice may not be removed or altered. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright 1997 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: dproc.c,v 1.31 2018/03/26 21:52:29 abe Exp $"; +#endif + +#include "lsof.h" + + +/* + * Local definitions + */ + +#define FDINFO_FLAGS 1 /* fdinfo flags available */ +#define FDINFO_POS 2 /* fdinfo position available */ + +#if defined(HASEPTOPTS) && defined(HASPTYEPT) +#define FDINFO_TTY_INDEX 4 /* fdinfo tty-index available */ +#endif /* defined(HASEPTOPTS) && defined(HASPTYEPT) */ + +#if defined(HASEPTOPTS) && defined(HASPTYEPT) +#define FDINFO_ALL (FDINFO_FLAGS | FDINFO_POS | FDINFO_TTY_INDEX) +#else /* !(defined(HASEPTOPTS) && defined(HASPTYEPT)) */ +#define FDINFO_ALL (FDINFO_FLAGS | FDINFO_POS ) +#endif /* defined(HASEPTOPTS) && defined(HASPTYEPT) */ + +#define LSTAT_TEST_FILE "/" +#define LSTAT_TEST_SEEK 1 + +#if !defined(ULLONG_MAX) +#define ULLONG_MAX 18446744073709551615ULL +#endif /* !defined(ULLONG_MAX) */ + + +/* + * Local structures + */ + +struct l_fdinfo { + int flags; /* flags: line value */ + off_t pos; /* pos: line value */ + +#if defined(HASEPTOPTS) && defined(HASPTYEPT) + int tty_index; /* pty line index */ +#endif /* defined(HASEPTOPTS) && defined(HASPTYEPT) */ + +}; + + +/* + * Local variables + */ + +static short Cckreg; /* conditional status of regular file + * checking: + * 0 = unconditionally check + * 1 = conditionally check */ +static short Ckscko; /* socket file only checking status: + * 0 = none + * 1 = check only socket files */ + + +/* + * Local function prototypes + */ + +_PROTOTYPE(static MALLOC_S alloc_cbf,(MALLOC_S len, char **cbf, MALLOC_S cbfa)); +_PROTOTYPE(static int get_fdinfo,(char *p, int msk, struct l_fdinfo *fi)); +_PROTOTYPE(static int getlinksrc,(char *ln, char *src, int srcl, char **rest)); +_PROTOTYPE(static int isefsys,(char *path, char *type, int l, + efsys_list_t **rep, struct lfile **lfr)); +_PROTOTYPE(static int nm2id,(char *nm, int *id, int *idl)); +_PROTOTYPE(static int read_id_stat,(char *p, int id, char **cmd, int *ppid, + int *pgid)); +_PROTOTYPE(static void process_proc_map,(char *p, struct stat *s, int ss)); +_PROTOTYPE(static int process_id,(char *idp, int idpl, char *cmd, UID_ARG uid, + int pid, int ppid, int pgid, int tid, + char *tcmd)); +_PROTOTYPE(static int statEx,(char *p, struct stat *s, int *ss)); + + +#if defined(HASSELINUX) +_PROTOTYPE(static int cmp_cntx_eq,(char *pcntx, char *ucntx)); + + +#include + + +/* + * cmp_cntx_eq -- compare program and user security contexts + */ + +static int +cmp_cntx_eq(pcntx, ucntx) + char *pcntx; /* program context */ + char *ucntx; /* user supplied context */ +{ + return !fnmatch(ucntx, pcntx, 0); +} + + +/* + * enter_cntx_arg() - enter name ecurity context argument + */ + +int +enter_cntx_arg(cntx) + char *cntx; /* context */ +{ + cntxlist_t *cntxp; +/* + * Search the argument list for a duplicate. + */ + for (cntxp = CntxArg; cntxp; cntxp = cntxp->next) { + if (!strcmp(cntxp->cntx, cntx)) { + if (!Fwarn) { + (void) fprintf(stderr, "%s: duplicate context: %s\n", + Pn, cntx); + } + return(1); + } + } +/* + * Create and link a new context argument list entry. + */ + if (!(cntxp = (cntxlist_t *)malloc((MALLOC_S)sizeof(cntxlist_t)))) { + (void) fprintf(stderr, "%s: no space for context: %s\n", Pn, cntx); + Exit(1); + } + cntxp->f = 0; + cntxp->cntx = cntx; + cntxp->next = CntxArg; + CntxArg = cntxp; + return(0); +} +#endif /* defined(HASSELINUX) */ + + +/* + * alloc_cbf() -- allocate a command buffer + */ + +static MALLOC_S +alloc_cbf(len, cbf, cbfa) + 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); + Exit(1); + } + return(len); +} + + +/* + * gather_proc_info() -- gather process information + */ + +void +gather_proc_info() +{ + 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/\"\n", + Pn, (int)pidpathl, PROCFS); + Exit(1); + } + (void) snpf(pidpath, pidpathl, "%s/", PROCFS); + } +/* + * Get lock and net information. + */ + (void) make_proc_path(pidpath, pidx, &path, &pathl, "locks"); + (void) get_locks(path); + (void) make_proc_path(pidpath, pidx, &path, &pathl, "net/"); + (void) set_net_paths(path, strlen(path)); +/* + * If only socket files have been selected, or socket files have been selected + * ANDed with other selection options, enable the skipping of regular files. + * + * If socket files and some process options have been selected, enable + * conditional skipping of regular file; i.e., regular files will be skipped + * unless they belong to a process selected by one of the specified options. + */ + if (Selflags & SELNW) { + + /* + * Some network files selection options have been specified. + */ + if (Fand || !(Selflags & ~SELNW)) { + + /* + * Selection ANDing or only network file options have been + * specified, so set unconditional skipping of regular files + * and socket file only checking. + */ + Cckreg = 0; + Ckscko = 1; + } else { + + /* + * If ORed file selection options have been specified, or no ORed + * process selection options have been specified, enable + * unconditional file checking and clear socket file only checking. + * + * If only ORed process selection options have been specified, + * enable conditional file skipping and socket file only checking. + */ + if ((Selflags & SELFILE) || !(Selflags & SelProc)) + Cckreg = Ckscko = 0; + else + Cckreg = Ckscko = 1; + } + } else { + + /* + * No network file selection options were specified. Enable + * unconditional file checking and clear socket file only checking. + */ + Cckreg = Ckscko = 0; + } +/* + * Read /proc, looking for PID directories. Open each one and + * gather its process and file information. + */ + if (!ps) { + if (!(ps = opendir(PROCFS))) { + (void) fprintf(stderr, "%s: can't open %s\n", Pn, PROCFS); + Exit(1); + } + } else + (void) rewinddir(ps); + while ((dp = readdir(ps))) { + if (nm2id(dp->d_name, &pid, &n)) + continue; + /* + * Build path to PID's directory. + */ + if ((pidx + n + 1 + 1) > pidpathl) { + pidpathl = pidx + n + 1 + 1 + 64; + if (!(pidpath = (char *)realloc((MALLOC_P *)pidpath, pidpathl))) + { + (void) fprintf(stderr, + "%s: can't allocate %d bytes for \"%s/%s/\"\n", + Pn, (int)pidpathl, PROCFS, dp->d_name); + Exit(1); + } + } + (void) snpf(pidpath + pidx, pidpathl - pidx, "%s/", dp->d_name); + n += (pidx + 1); + /* + * Process the PID's stat info. + */ + if (stat(pidpath, &sb)) + continue; + uid = (UID_ARG)sb.st_uid; + ht = pidts = 0; + /* + * Get the PID's command name. + */ + (void) make_proc_path(pidpath, n, &path, &pathl, "stat"); + if ((prv = read_id_stat(path, pid, &cmd, &ppid, &pgid)) < 0) + cmd = "(unknown)"; + +#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 -aK" + * options work properly. + */ + else if (!IgnTasks && (Selflags & SELTASK)) { + strncpy(cmdbuf, cmd, sizeof(cmdbuf) - 1); + cmdbuf[sizeof(cmdbuf) - 1] = '\0'; + cmd = cmdbuf; + (void) make_proc_path(pidpath, n, &taskpath, &taskpathl, + "task"); + tx = n + 4; + if ((ts = opendir(taskpath))) { + + /* + * Process the PID's tasks. Record the open files of those + * whose TIDs do not match the PID and which are themselves + * not zombies. + */ + while ((dp = readdir(ts))) { + + /* + * Get the task ID. Skip the task if its ID matches the + * process PID. + */ + if (nm2id(dp->d_name, &tid, &nl)) + continue; + if (tid == pid) { + pidts = 1; + continue; + } + /* + * Form the path for the TID. + */ + if ((tx + 1 + nl + 1 + 4) > tidpathl) { + tidpathl = tx + 1 + n + 1 + 4 + 64; + if (tidpath) + tidpath = (char *)realloc((MALLOC_P *)tidpath, + tidpathl); + else + tidpath = (char *)malloc((MALLOC_S)tidpathl); + if (!tidpath) { + (void) fprintf(stderr, + "%s: can't allocate %d task bytes", Pn, + tidpathl); + (void) fprintf(stderr, " for \"%s/%s/stat\"\n", + taskpath, dp->d_name); + Exit(1); + } + } + (void) snpf(tidpath, tidpathl, "%s/%s/stat", taskpath, + dp->d_name); + /* + * Check the task state. + */ + rv = read_id_stat(tidpath, tid, &tcmd, &tppid, + &tpgid); + if ((rv < 0) || (rv == 1)) + continue; + /* + * Attempt to record the task. + */ + if (!process_id(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(pidpath, n, cmd, uid, pid, ppid, pgid, tid, + (char *)NULL)) + && tid) + { + Lp->tid = 0; + } + } + } +} + + +/* + * get_fdinfo() - get values from /proc/fdinfo/FD + */ + +static int +get_fdinfo(p, msk, fi) + 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) && defined(HASPTYEPT) + fi->tty_index = -1; +#endif /* defined(HASEPTOPTS) && defined(HASPTYEPT) */ + + if (!p || !*p || !(fs = fopen(p, "r"))) + return(0); +/* + * Read the fdinfo file. + */ + while (fgets(buf, sizeof(buf), fs)) { + if (get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0) < 2) + continue; + if (!fp[0] || !*fp[0] || !fp[1] || !*fp[1]) + continue; + if (!strcmp(fp[0], "flags:")) { + + /* + * Process a "flags:" line. + */ + ep = (char *)NULL; + if ((ul = strtoul(fp[1], &ep, 0)) == ULONG_MAX + || !ep || *ep) + continue; + fi->flags = (unsigned int)ul; + if ((rv |= FDINFO_FLAGS) == msk) + break; + } else if (!strcmp(fp[0], "pos:")) { + + /* + * Process a "pos:" line. + */ + ep = (char *)NULL; + if ((ull = strtoull(fp[1], &ep, 0)) == ULLONG_MAX + || !ep || *ep) + continue; + fi->pos = (off_t)ull; + if ((rv |= FDINFO_POS) == FDINFO_ALL) + break; + +#if defined(HASEPTOPTS) && defined(HASPTYEPT) + } else if (!strcmp(fp[0], "tty-index:")) { + + /* + * Process a "tty-index:" line. + */ + ep = (char *)NULL; + if ((ul = strtoul(fp[1], &ep, 0)) == ULONG_MAX + || !ep || *ep) + continue; + fi->tty_index = (int)ul; + if (fi->tty_index < 0) { + + /* + * Oops! If integer overflow occurred, reset the field. + */ + fi->tty_index = -1; + } + if ((rv |= FDINFO_TTY_INDEX) == msk) + break; +#endif /* defined(HASEPTOPTS) && defined(HASPTYEPT) */ + + } + } + fclose(fs); +/* + * Signal via the return value what information was obtained. (0 == none) + */ + return(rv); +} + + +/* + * getlinksrc() - get the source path name for the /proc//fd/ link + */ + + +static int +getlinksrc(ln, src, srcl, rest) + char *ln; /* link path */ + char *src; /* link source path return address */ + int srcl; /* length of src[] */ + char **rest; /* pointer to what follows the ':' in + * the link source path (NULL if no + * return requested) */ +{ + char *cp; + int ll; + + if (rest) + *rest = (char *)NULL; + if ((ll = readlink(ln, src, srcl - 1)) < 1 + || ll >= srcl) + return(-1); + src[ll] = '\0'; + if (*src == '/') + return(ll); + if ((cp = strchr(src, ':'))) { + *cp = '\0'; + ll = strlen(src); + if (rest) + *rest = cp + 1; + } + return(ll); +} + + +/* + * initialize() - perform all initialization + */ + +void +initialize() +{ + int fd; + struct l_fdinfo fi; + char path[MAXPATHLEN]; + struct stat sb; +/* + * Test for -i and -X option conflict. + */ + if (Fxopt && (Fnet || Nwad)) { + (void) fprintf(stderr, "%s: -i is useless when -X is specified.\n", + Pn); + usage(1, 0, 0); + } +/* + * Open LSTAT_TEST_FILE and seek to byte LSTAT_TEST_SEEK, then lstat the + * /proc//fd/ for LSTAT_TEST_FILE to see what position is reported. + * If the result is LSTAT_TEST_SEEK, enable offset reporting. + * + * If the result isn't LSTAT_TEST_SEEK, next check the fdinfo file for the + * open LSTAT_TEST_FILE file descriptor. If it exists and contains a "pos:" + * value, and if the value is LSTAT_TEST_SEEK, enable offset reporting. + */ + if ((fd = open(LSTAT_TEST_FILE, O_RDONLY)) >= 0) { + if (lseek(fd, (off_t)LSTAT_TEST_SEEK, SEEK_SET) + == (off_t)LSTAT_TEST_SEEK) { + (void) snpf(path, sizeof(path), "%s/%d/fd/%d", PROCFS, Mypid, + fd); + if (!lstat(path, &sb)) { + if (sb.st_size == (off_t)LSTAT_TEST_SEEK) + OffType = 1; + } + } + if (!OffType) { + (void) snpf(path, sizeof(path), "%s/%d/fdinfo/%d", PROCFS, + Mypid, fd); + if (get_fdinfo(path, FDINFO_POS, &fi) & FDINFO_POS) { + if (fi.pos == (off_t)LSTAT_TEST_SEEK) + OffType = 2; + } + } + (void) close(fd); + } + if (!OffType) { + if (Foffset && !Fwarn) + (void) fprintf(stderr, + "%s: WARNING: can't report offset; disregarding -o.\n", + Pn); + Foffset = 0; + Fsize = 1; + } + if (Fsv && (OffType != 2)) { + if (!Fwarn && FsvByf) + (void) fprintf(stderr, + "%s: WARNING: can't report file flags; disregarding +f.\n", + Pn); + Fsv = 0; + } +/* + * Make sure the local mount info table is loaded if doing anything other + * than just Internet lookups. (HasNFS is defined during the loading of the + * local mount table.) + */ + if (Selinet == 0) + (void) readmnt(); +} + + +/* + * make_proc_path() - make a path in a /proc directory + * + * entry: + * pp = pointer to /proc prefix + * lp = length of prefix + * np = pointer to malloc'd buffer to receive new file's path + * nl = length of new file path buffer + * sf = new path's suffix + * + * return: length of new path + * np = updated with new path + * nl = updated with new path length + */ + +int +make_proc_path(pp, pl, np, nl, sf) + char *pp; /* path prefix -- e.g., /proc// */ + int pl; /* strlen(pp) */ + char **np; /* malloc'd receiving buffer */ + int *nl; /* strlen(*np) */ + char *sf; /* suffix of new path */ +{ + char *cp; + MALLOC_S rl, sl; + + sl = strlen(sf); + if ((rl = pl + sl + 1) > *nl) { + if ((cp = *np)) + cp = (char *)realloc((MALLOC_P *)cp, rl); + else + cp = (char *)malloc(rl); + if (!cp) { + (void) fprintf(stderr, + "%s: can't allocate %d bytes for %s%s\n", + Pn, (int)rl, pp, sf); + Exit(1); + } + *nl = rl; + *np = cp; + } + (void) snpf(*np, *nl, "%s", pp); + (void) snpf(*np + pl, *nl - pl, "%s", sf); + return(rl - 1); +} + + +/* + * isefsys() -- is path on a file system exempted with -e + * + * Note: alloc_lfile() must have been called in advance. + */ + +static int +isefsys(path, type, l, rep, lfr) + char *path; /* path to file */ + char *type; /* unknown file type */ + int l; /* link request: 0 = report + * 1 = link */ + efsys_list_t **rep; /* returned Efsysl pointer, if not + * NULL */ + struct lfile **lfr; /* allocated struct lfile pointer */ +{ + efsys_list_t *ep; + int ds, len; + struct mounts *mp; + char nmabuf[MAXPATHLEN + 1]; + + len = (int) strlen(path); + for (ep = Efsysl; ep; ep = ep->next) { + + /* + * Look for a matching exempt file system path at the beginning of + * the file path. + */ + if (ep->pathl > len) + continue; + if (strncmp(ep->path, path, ep->pathl)) + continue; + /* + * If only reporting, return information as requested. + */ + if (!l) { + if (rep) + *rep = ep; + return(0); + } + /* + * Process an exempt file. + */ + ds = 0; + if ((mp = ep->mp)) { + if (mp->ds & SB_DEV) { + Lf->dev = mp->dev; + ds = Lf->dev_def = 1; + } + if (mp->ds & SB_RDEV) { + Lf->rdev = mp->rdev; + ds = Lf->rdev_def = 1; + } + } + if (!ds) + (void) enter_dev_ch("UNKNOWN"); + Lf->ntype = N_UNKN; + (void) snpf(Lf->type, sizeof(Lf->type), "%s", + (type ? type : "UNKN")); + (void) enter_nm(path); + (void) snpf(nmabuf, sizeof(nmabuf), "(%ce %s)", + ep->rdlnk ? '+' : '-', ep->path); + nmabuf[sizeof(nmabuf) - 1] = '\0'; + (void) add_nma(nmabuf, strlen(nmabuf)); + if (Lf->sf) { + if (lfr) + *lfr = Lf; + link_lfile(); + } else if (lfr) + *lfr = (struct lfile *)NULL; + return(0); + } + return(1); +} + + +/* + * nm2id() - convert a name to an integer ID + */ + +static int +nm2id(nm, id, idl) + char *nm; /* pointer to name */ + int *id; /* pointer to ID receiver */ + int *idl; /* pointer to ID length receiver */ +{ + register int tid, tidl; + + for (*id = *idl = tid = tidl = 0; *nm; nm++) { + +#if defined(__STDC__) /* { */ + if (!isdigit((unsigned char)*nm)) +#else /* !defined(__STDC__) } { */ + if (!isascii(*nm) || !isdigit((unsigned char)*cp)) +#endif /* defined(__STDC__) } */ + + { + return(1); + } + tid = tid * 10 + (int)(*nm - '0'); + tidl++; + } + *id = tid; + *idl = tidl; + return(0); +} + + +/* + * open_proc_stream() -- open a /proc stream + */ + +FILE * +open_proc_stream(p, m, buf, sz, act) + char *p; /* pointer to path to open */ + char *m; /* pointer to mode -- e.g., "r" */ + char **buf; /* pointer tp setvbuf() address + * (NULL if none) */ + size_t *sz; /* setvbuf() size (0 if none or if + * getpagesize() desired */ + int act; /* fopen() failure action: + * 0 : return (FILE *)NULL + * <>0 : fprintf() an error message + * and Exit(1) + */ +{ + FILE *fs; /* opened stream */ + static size_t psz = (size_t)0; /* page size */ + size_t tsz; /* temporary size */ +/* + * Open the stream. + */ + if (!(fs = fopen(p, m))) { + if (!act) + return((FILE *)NULL); + (void) fprintf(stderr, "%s: can't fopen(%s, \"%s\"): %s\n", + Pn, p, m, strerror(errno)); + Exit(1); + } +/* + * Return the stream if no buffer change is required. + */ + if (!buf) + return(fs); +/* + * Determine the buffer size required. + */ + if (!(tsz = *sz)) { + if (!psz) + psz = getpagesize(); + tsz = psz; + } +/* + * Allocate a buffer for the stream, as required. + */ + if (!*buf) { + if (!(*buf = (char *)malloc((MALLOC_S)tsz))) { + (void) fprintf(stderr, + "%s: can't allocate %d bytes for %s stream buffer\n", + Pn, (int)tsz, p); + Exit(1); + } + *sz = tsz; + } +/* + * Assign the buffer to the stream. + */ + if (setvbuf(fs, *buf, _IOFBF, tsz)) { + (void) fprintf(stderr, "%s: setvbuf(%s)=%d failure: %s\n", + Pn, p, (int)tsz, strerror(errno)); + Exit(1); + } + return(fs); +} + + +/* + * process_id - process ID: PID or LWP + * + * return: 0 == ID processed + * 1 == ID not processed + */ + +static int +process_id(idp, idpl, cmd, uid, pid, ppid, pgid, tid, tcmd) + 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, n, ss, sv; + struct l_fdinfo fi; + DIR *fdp; + struct dirent *fp; + static char *ipath = (char *)NULL; + static int ipathl = 0; + int j = 0; + struct lfile *lfr; + struct stat lsb, sb; + char nmabuf[MAXPATHLEN + 1], pbuf[MAXPATHLEN + 1]; + static char *path = (char *)NULL; + static int pathl = 0; + static char *pathi = (char *)NULL; + static int pathil = 0; + char *rest; + int txts = 0; + +#if defined(HASSELINUX) + cntxlist_t *cntxp; +#endif /* defined(HASSELINUX) */ + +/* + * See if process is excluded. + */ + if (is_proc_excl(pid, pgid, uid, &pss, &sf, tid) + || is_cmd_excl(cmd, &pss, &sf)) + { + +#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(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); + Exit(1); + } + } +#endif /* defined(HASTASKS) */ + +/* + * Process the ID's current working directory info. + */ + efs = 0; + if (!Ckscko) { + (void) make_proc_path(idp, idpl, &path, &pathl, "cwd"); + alloc_lfile(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(nmabuf, strlen(nmabuf)); + pn = 1; + } else + pn = 0; + } else { + lnk = pn = 1; + if (Efsysl && !isefsys(pbuf, "UNKNcwd", 1, NULL, &lfr)) { + efs = 1; + pn = 0; + } else { + ss = SB_ALL; + if (HasNFS) { + if ((sv = statsafely(path, &sb))) + sv = statEx(pbuf, &sb, &ss); + } else + sv = stat(path, &sb); + if (sv) { + ss = 0; + if (!Fwarn) { + (void) snpf(nmabuf, sizeof(nmabuf), "(stat: %s)", + strerror(errno)); + nmabuf[sizeof(nmabuf) - 1] = '\0'; + (void) add_nma(nmabuf, strlen(nmabuf)); + } + } + } + } + if (pn) { + (void) process_proc_node(lnk ? pbuf : path, + path, &sb, ss, + (struct stat *)NULL, 0); + if (Lf->sf) + link_lfile(); + } + } +/* + * Process the ID's root directory info. + */ + lnk = ss = 0; + if (!Ckscko) { + (void) make_proc_path(idp, idpl, &path, &pathl, "root"); + alloc_lfile(RTD, -1); + if (getlinksrc(path, pbuf, sizeof(pbuf), (char **)NULL) < 1) { + if (!Fwarn) { + zeromem((char *)&sb, sizeof(sb)); + (void) snpf(nmabuf, sizeof(nmabuf), "(readlink: %s)", + strerror(errno)); + nmabuf[sizeof(nmabuf) - 1] = '\0'; + (void) add_nma(nmabuf, strlen(nmabuf)); + pn = 1; + } else + pn = 0; + } else { + lnk = pn = 1; + if (Efsysl && !isefsys(pbuf, "UNKNrtd", 1, NULL, NULL)) + pn = 0; + else { + ss = SB_ALL; + if (HasNFS) { + if ((sv = statsafely(path, &sb))) + sv = statEx(pbuf, &sb, &ss); + } else + sv = stat(path, &sb); + if (sv) { + ss = 0; + if (!Fwarn) { + (void) snpf(nmabuf, sizeof(nmabuf), "(stat: %s)", + strerror(errno)); + nmabuf[sizeof(nmabuf) - 1] = '\0'; + (void) add_nma(nmabuf, strlen(nmabuf)); + } + } + } + } + if (pn) { + (void) process_proc_node(lnk ? pbuf : path, + path, &sb, ss, + (struct stat *)NULL, 0); + if (Lf->sf) + link_lfile(); + } + } +/* + * Process the ID's execution info. + */ + lnk = ss = txts = 0; + if (!Ckscko) { + (void) make_proc_path(idp, idpl, &path, &pathl, "exe"); + alloc_lfile("txt", -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(nmabuf, strlen(nmabuf)); + } + pn = 1; + } else + pn = 0; + } else { + lnk = pn = 1; + if (Efsysl && !isefsys(pbuf, "UNKNtxt", 1, NULL, NULL)) + pn = 0; + else { + ss = SB_ALL; + if (HasNFS) { + if ((sv = statsafely(path, &sb))) { + sv = statEx(pbuf, &sb, &ss); + if (!sv && (ss & SB_DEV) && (ss & SB_INO)) + txts = 1; + } + } else + sv = stat(path, &sb); + if (sv) { + ss = 0; + if (!Fwarn) { + (void) snpf(nmabuf, sizeof(nmabuf), "(stat: %s)", + strerror(errno)); + nmabuf[sizeof(nmabuf) - 1] = '\0'; + (void) add_nma(nmabuf, strlen(nmabuf)); + } + } else + txts = 1; + } + } + if (pn) { + (void) process_proc_node(lnk ? pbuf : path, + path, &sb, ss, + (struct stat *)NULL, 0); + if (Lf->sf) + link_lfile(); + } + } +/* + * Process the ID's memory map info. + */ + if (!Ckscko) { + (void) make_proc_path(idp, idpl, &path, &pathl, "maps"); + (void) process_proc_map(path, txts ? &sb : (struct stat *)NULL, + txts ? ss : 0); + } + +#if defined(HASSELINUX) +/* + * Process the PID's SELinux context. + */ + if (Fcntx) { + + /* + * If the -Z (cntx) option was specified, match the valid contexts. + */ + errno = 0; + if (getpidcon(pid, &Lp->cntx) == -1) { + Lp->cntx = (char *)NULL; + if (!Fwarn) { + (void) snpf(nmabuf, sizeof(nmabuf), + "(getpidcon: %s)", strerror(errno)); + if (!(Lp->cntx = strdup(nmabuf))) { + (void) fprintf(stderr, + "%s: no context error space: PID %ld", + Pn, (long)Lp->pid); + Exit(1); + } + } + } else if (CntxArg) { + + /* + * See if context includes the process. + */ + for (cntxp = CntxArg; cntxp; cntxp = cntxp->next) { + if (cmp_cntx_eq(Lp->cntx, cntxp->cntx)) { + cntxp->f = 1; + Lp->pss |= PS_PRI; + Lp->sf |= SELCNTX; + break; + } + } + } + } +#endif /* defined(HASSELINUX) */ + +/* + * Process the ID's file descriptor directory. + */ + if ((i = make_proc_path(idp, idpl, &dpath, &dpathl, "fd/")) < 3) + return(0); + dpath[i - 1] = '\0'; + if ((OffType == 2) + && ((j = make_proc_path(idp, idpl, &ipath, &ipathl, "fdinfo/")) >= 7)) + oty = 1; + else + oty = 0; + if (!(fdp = opendir(dpath))) { + if (!Fwarn) { + (void) snpf(nmabuf, sizeof(nmabuf), "%s (opendir: %s)", + dpath, strerror(errno)); + alloc_lfile("NOFD", -1); + nmabuf[sizeof(nmabuf) - 1] = '\0'; + (void) add_nma(nmabuf, strlen(nmabuf)); + link_lfile(); + } + return(0); + } + dpath[i - 1] = '/'; + while ((fp = readdir(fdp))) { + if (nm2id(fp->d_name, &fd, &n)) + continue; + (void) make_proc_path(dpath, i, &path, &pathl, fp->d_name); + (void) alloc_lfile((char *)NULL, fd); + if (getlinksrc(path, pbuf, sizeof(pbuf), &rest) < 1) { + zeromem((char *)&sb, sizeof(sb)); + lnk = ss = 0; + if (!Fwarn) { + (void) snpf(nmabuf, sizeof(nmabuf), "(readlink: %s)", + strerror(errno)); + nmabuf[sizeof(nmabuf) - 1] = '\0'; + (void) add_nma(nmabuf, strlen(nmabuf)); + pn = 1; + } else + pn = 0; + } else { + lnk = 1; + if (Efsysl && !isefsys(pbuf, "UNKNfd", 1, NULL, &lfr)) { + efs = 1; + pn = 0; + } else { + if (HasNFS) { + if (lstatsafely(path, &lsb)) { + (void) statEx(pbuf, &lsb, &ls); + enls = errno; + } else { + enls = 0; + ls = SB_ALL; + } + if (statsafely(path, &sb)) { + (void) statEx(pbuf, &sb, &ss); + enss = errno; + } else { + enss = 0; + ss = SB_ALL; + } + } else { + ls = lstat(path, &lsb) ? 0 : SB_ALL; + enls = errno; + ss = stat(path, &sb) ? 0 : SB_ALL; + enss = errno; + } + if (!ls && !Fwarn) { + (void) snpf(nmabuf, sizeof(nmabuf), "lstat: %s)", + strerror(enls)); + nmabuf[sizeof(nmabuf) - 1] = '\0'; + (void) add_nma(nmabuf, strlen(nmabuf)); + } + if (!ss && !Fwarn) { + (void) snpf(nmabuf, sizeof(nmabuf), "(stat: %s)", + strerror(enss)); + nmabuf[sizeof(nmabuf) - 1] = '\0'; + (void) add_nma(nmabuf, strlen(nmabuf)); + } + if (Ckscko) { + if ((ss & SB_MODE) + && ((sb.st_mode & S_IFMT) == S_IFSOCK)) + { + pn = 1; + } else + pn = 0; + } else + pn = 1; + } + } + if (pn || (efs && lfr && oty)) { + if (oty) { + (void) make_proc_path(ipath, j, &pathi, &pathil, + fp->d_name); + if ((av = get_fdinfo(pathi,FDINFO_ALL,&fi)) & FDINFO_POS) { + if (efs) { + if (Foffset) { + lfr->off = (SZOFFTYPE)fi.pos; + lfr->off_def = 1; + } + } else { + ls |= SB_SIZE; + lsb.st_size = fi.pos; + } + } else + ls &= ~SB_SIZE; + +#if !defined(HASNOFSFLAGS) + if ((av & FDINFO_FLAGS) && (Fsv & FSV_FG)) { + if (efs) { + lfr->ffg = (long)fi.flags; + lfr->fsv |= FSV_FG; + } else { + Lf->ffg = (long)fi.flags; + Lf->fsv |= FSV_FG; + } + } +# endif /* !defined(HASNOFSFLAGS) */ + + } + if (pn) { + process_proc_node(lnk ? pbuf : path, path, &sb, ss, &lsb, + ls); + if ((Lf->ntype == N_ANON_INODE) && rest && *rest) + enter_nm(rest); + +#if defined(HASEPTOPTS) && defined(HASPTYEPT) + else if (FeptE + && Lf->rdev_def + && is_pty_ptmx(Lf->rdev) + && (av & FDINFO_TTY_INDEX) + ) { + enter_ptmxi(fi.tty_index); + Lf->tty_index = fi.tty_index; + Lf->sf |= SELPTYINFO; + } +#endif /* defined(HASEPTOPTS) && defined(HASPTYEPT) */ + + if (Lf->sf) + link_lfile(); + } + } + } + (void) closedir(fdp); + return(0); +} + + +/* + * process_proc_map() - process the memory map of a process + */ + +static void +process_proc_map(p, s, ss) + char *p; /* path to process maps file */ + struct stat *s; /* executing text file state buffer */ + int ss; /* *s status -- i.e., SB_* values */ +{ + char buf[MAXPATHLEN + 1], *ep, fmtbuf[32], **fp, nmabuf[MAXPATHLEN + 1]; + dev_t dev; + int ds, efs, en, i, mss, nf, sv; + int eb = 6; + INODETYPE inode; + MALLOC_S len; + long maj, min; + FILE *ms; + int ns = 0; + struct stat sb; + struct saved_map { + dev_t dev; + INODETYPE inode; + }; + static struct saved_map *sm = (struct saved_map *)NULL; + efsys_list_t *rep; + static int sma = 0; + static char *vbuf = (char *)NULL; + static size_t vsz = (size_t)0; +/* + * Open the /proc//maps file, assign a page size buffer to its stream, + * and read it/ + */ + if (!(ms = open_proc_stream(p, "r", &vbuf, &vsz, 0))) + return; + while (fgets(buf, sizeof(buf), ms)) { + if ((nf = get_fields(buf, ":", &fp, &eb, 1)) < 7) + continue; /* not enough fields */ + if (!fp[6] || !*fp[6]) + continue; /* no path name */ + /* + * See if the path ends in " (deleted)". If it does, strip the + * " (deleted)" characters and remember that they were there. + */ + if (((ds = (int)strlen(fp[6])) > 10) + && !strcmp(fp[6] + ds - 10, " (deleted)")) + { + *(fp[6] + ds - 10) = '\0'; + } else + ds = 0; + /* + * Assemble the major and minor device numbers. + */ + ep = (char *)NULL; + if (!fp[3] || !*fp[3] + || (maj = strtol(fp[3], &ep, 16)) == LONG_MIN || maj == LONG_MAX + || !ep || *ep) + continue; + ep = (char *)NULL; + if (!fp[4] || !*fp[4] + || (min = strtol(fp[4], &ep, 16)) == LONG_MIN || min == LONG_MAX + || !ep || *ep) + continue; + /* + * Assemble the device and inode numbers. If they are both zero, skip + * the entry. + */ + dev = (dev_t)makedev((int)maj, (int)min); + if (!fp[5] || !*fp[5]) + continue; + ep = (char *)NULL; + if ((inode = strtoull(fp[5], &ep, 0)) == ULLONG_MAX + || !ep || *ep) + continue; + if (!dev && !inode) + continue; + /* + * See if the device + inode pair match that of the executable. + * If they do, skip this map entry. + */ + if (s && (ss & SB_DEV) && (ss & SB_INO) + && (dev == s->st_dev) && (inode == (INODETYPE)s->st_ino)) + continue; + /* + * See if this device + inode pair has already been processed as + * a map entry. + */ + for (i = 0; i < ns; i++) { + if (dev == sm[i].dev && inode == sm[i].inode) + break; + } + if (i < ns) + continue; + /* + * Record the processing of this map entry's device and inode pair. + */ + if (ns >= sma) { + sma += 10; + len = (MALLOC_S)(sma * sizeof(struct saved_map)); + if (sm) + sm = (struct saved_map *)realloc(sm, len); + else + sm = (struct saved_map *)malloc(len); + if (!sm) { + (void) fprintf(stderr, + "%s: can't allocate %d bytes for saved maps, PID %d\n", + Pn, (int)len, Lp->pid); + Exit(1); + } + } + sm[ns].dev = dev; + sm[ns++].inode = inode; + /* + * Allocate space for the mapped file, then get stat(2) information + * for it. Skip the stat(2) operation if this is on an exempt file + * system. + */ + alloc_lfile("mem", -1); + if (Efsysl && !isefsys(fp[6], (char *)NULL, 0, &rep, NULL)) + efs = sv = 1; + else + efs = 0; + if (!efs) { + if (HasNFS) + sv = statsafely(fp[6], &sb); + else + sv = stat(fp[6], &sb); + } + if (sv || efs) { + en = errno; + /* + * Applying stat(2) to the file was not possible (file is on an + * exempt file system) or stat(2) failed, so manufacture a partial + * stat(2) reply from the process' maps file entry. + * + * If the file has been deleted, reset its type to "DEL"; + * otherwise generate a stat() error name addition. + */ + 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("DEL", -1); + else if (!efs && !Fwarn) { + (void) snpf(nmabuf, sizeof(nmabuf), "(stat: %s)", + strerror(en)); + nmabuf[sizeof(nmabuf) - 1] = '\0'; + (void) add_nma(nmabuf, strlen(nmabuf)); + } + } else if ((sb.st_dev != dev) || ((INODETYPE)sb.st_ino != inode)) { + + /* + * The stat(2) device and inode numbers don't match those obtained + * from the process' maps file. + * + * If the file has been deleted, reset its type to "DEL"; otherwise + * generate inconsistency name additions. + * + * Manufacture a partial stat(2) reply from the maps file + * information. + */ + if (ds) + alloc_lfile("DEL", -1); + else if (!Fwarn) { + char *sep; + + if (sb.st_dev != dev) { + (void) snpf(nmabuf, sizeof(nmabuf), + "(path dev=%d,%d%s", + GET_MAJ_DEV(sb.st_dev), GET_MIN_DEV(sb.st_dev), + ((INODETYPE)sb.st_ino == inode) ? ")" : ","); + nmabuf[sizeof(nmabuf) - 1] = '\0'; + (void) add_nma(nmabuf, strlen(nmabuf)); + sep = ""; + } else + sep = "(path "; + if ((INODETYPE)sb.st_ino != inode) { + (void) snpf(fmtbuf, sizeof(fmtbuf), "%%sinode=%s)", + InodeFmt_d); + (void) snpf(nmabuf, sizeof(nmabuf), fmtbuf, + sep, (INODETYPE)sb.st_ino); + nmabuf[sizeof(nmabuf) - 1] = '\0'; + (void) add_nma(nmabuf, strlen(nmabuf)); + } + } + 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(fp[6], fp[6], &sb, mss, (struct stat *)NULL, + 0); + else { + + /* + * If this file is on an exempt file system, complete the lfile + * structure, but change its type and add the exemption note to + * the NAME column. + */ + Lf->dev = sb.st_dev; + Lf->inode = (ino_t)sb.st_ino; + Lf->dev_def = Lf->inp_ty = 1; + (void) enter_nm(fp[6]); + (void) snpf(Lf->type, sizeof(Lf->type), "%s", + (ds ? "UNKNdel" : "UNKNmem")); + (void) snpf(nmabuf, sizeof(nmabuf), "(%ce %s)", + rep->rdlnk ? '+' : '-', rep->path); + nmabuf[sizeof(nmabuf) - 1] = '\0'; + (void) add_nma(nmabuf, strlen(nmabuf)); + } + if (Lf->sf) + link_lfile(); + } + (void) fclose(ms); +} + + +/* + * read_id_stat() - read ID (PID or LWP ID) status + * + * return: -1 == ID is unavailable + * 0 == ID OK + * 1 == ID is a zombie + * 2 == ID is a thread + */ + +static int +read_id_stat(p, id, cmd, ppid, pgid) + 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, nf, 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(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 */ +/* + * 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((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 ((nf = get_fields(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(p, s, ss) + char *p; /* file path */ + struct stat *s; /* stat() result -- NULL if none + * wanted */ + int *ss; /* stat() status -- SB_* values */ +{ + static size_t ca = 0; + static char *cb = NULL; + char *cp; + int ensv = ENOENT; + struct stat sb; + int st = 0; + size_t sz; +/* + * Make a copy of the path. + */ + sz = strlen(p); + if ((sz + 1) > ca) { + if (cb) + cb = (char *)realloc((MALLOC_P *)cb, sz + 1); + else + cb = (char *)malloc(sz + 1); + if (!cb) { + (void) fprintf(stderr, + "%s: PID %ld: no statEx path space: %s\n", + Pn, (long)Lp->pid, p); + Exit(1); + } + ca = sz + 1; + } + (void) strcpy(cb, p); +/* + * Trim trailing leaves from the end of the path one at a time and do a safe + * stat() on each trimmed result. Stop when a safe stat() succeeds or doesn't + * fail because of EACCES or EPERM. + */ + for (cp = strrchr(cb, '/'); cp && (cp != cb);) { + *cp = '\0'; + if (!statsafely(cb, &sb)) { + st = 1; + break; + } + ensv = errno; + if ((ensv != EACCES) && (ensv != EPERM)) + break; + cp = strrchr(cb, '/'); + } +/* + * If a stat() on a trimmed result succeeded, form partial results containing + * only the device and raw device numbers. + */ + 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); +} diff --git a/dialects/linux/dproto.h b/dialects/linux/dproto.h new file mode 100644 index 0000000..1574bbc --- /dev/null +++ b/dialects/linux/dproto.h @@ -0,0 +1,51 @@ +/* + * dproto.h - Linux function prototypes for /proc-based lsof + * + * The _PROTOTYPE macro is defined in the common proto.h. + */ + + +/* + * Copyright 1997 Purdue Research Foundation, West Lafayette, Indiana + * 47907. All rights reserved. + * + * Written by Victor A. Abell + * + * This software is not subject to any license of the American Telephone + * and Telegraph Company or the Regents of the University of California. + * + * Permission is granted to anyone to use this software for any purpose on + * any computer system, and to alter it and redistribute it freely, subject + * to the following restrictions: + * + * 1. Neither the authors nor Purdue University are responsible for any + * consequences of the use of this software. + * + * 2. The origin of this software must not be misrepresented, either by + * explicit claim or by omission. Credit to the authors and Purdue + * University must appear in documentation and sources. + * + * 3. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 4. This notice may not be removed or altered. + */ + + +/* + * $Id: dproto.h,v 1.9 2013/01/02 17:02:36 abe Exp $ + */ + + +#if defined(HASSELINUX) +_PROTOTYPE(extern int enter_cntx_arg,(char *cnxt)); +#endif /* defined(HASSELINUX) */ + +_PROTOTYPE(extern int get_fields,(char *ln, char *sep, char ***fr, int *eb, int en)); +_PROTOTYPE(extern void get_locks,(char *p)); +_PROTOTYPE(extern int is_file_named,(int ty, char *p, struct mounts *mp, int cd)); +_PROTOTYPE(extern int make_proc_path,(char *pp, int lp, char **np, int *npl, char *sf)); +_PROTOTYPE(extern FILE *open_proc_stream,(char *p, char *mode, char **buf, size_t *sz, int act)); +_PROTOTYPE(extern void process_proc_node,(char *p, char *pbr, struct stat *s, int ss, struct stat *l, int ls)); +_PROTOTYPE(extern void process_proc_sock,(char *p, char *pbr, struct stat *s, int ss, struct stat *l, int ls)); +_PROTOTYPE(extern void set_net_paths,(char *p, int pl)); diff --git a/dialects/linux/dsock.c b/dialects/linux/dsock.c new file mode 100644 index 0000000..2ebf07e --- /dev/null +++ b/dialects/linux/dsock.c @@ -0,0 +1,4470 @@ +/* + * dsock.c - Linux socket processing functions for /proc-based lsof + */ + + +/* + * Copyright 1997 Purdue Research Foundation, West Lafayette, Indiana + * 47907. All rights reserved. + * + * Written by Victor A. Abell + * + * This software is not subject to any license of the American Telephone + * and Telegraph Company or the Regents of the University of California. + * + * Permission is granted to anyone to use this software for any purpose on + * any computer system, and to alter it and redistribute it freely, subject + * to the following restrictions: + * + * 1. Neither the authors nor Purdue University are responsible for any + * consequences of the use of this software. + * + * 2. The origin of this software must not be misrepresented, either by + * explicit claim or by omission. Credit to the authors and Purdue + * University must appear in documentation and sources. + * + * 3. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 4. This notice may not be removed or altered. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright 1997 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: dsock.c,v 1.43 2018/03/26 21:52:29 abe Exp $"; +#endif + + +#include "lsof.h" +#include + + +#if defined(HASEPTOPTS) && defined(HASUXSOCKEPT) +/* + * UNIX endpoint definitions + */ + +#include /* for AF_NETLINK */ +#include /* for NETLINK_INET_DIAG */ +#include /* for SOCK_DIAG_BY_FAMILY */ +#include /* for unix_diag_req */ +#include /* memset */ +#include /* for unt8_t */ +#include /* for getpagesize */ +#define SOCKET_BUFFER_SIZE (getpagesize() < 8192L ? getpagesize() : 8192L) +#endif /* defined(HASEPTOPTS) && defined(HASUXSOCKEPT) */ + + +/* + * Local definitions + */ + +#define INOBUCKS 128 /* inode hash bucket count -- must be + * a power of two */ +#define INOHASH(ino) ((int)((ino * 31415) >> 3) & (INOBUCKS - 1)) +#define TCPUDPHASH(ino) ((int)((ino * 31415) >> 3) & (TcpUdp_bucks - 1)) +#define TCPUDP6HASH(ino) ((int)((ino * 31415) >> 3) & (TcpUdp6_bucks - 1)) + + +/* + * Local structures + */ + +struct ax25sin { /* AX25 socket information */ + char *da; /* destination address */ + char *dev_ch; /* device characters */ + char *sa; /* source address */ + INODETYPE inode; + unsigned long sq, rq; /* send and receive queue values */ + unsigned char sqs, rqs; /* send and receive queue states */ + int state; + struct ax25sin *next; +}; + +struct icmpin { + INODETYPE inode; /* node number */ + char *la; /* local address */ + char *ra; /* remote address */ + MALLOC_S lal; /* strlen(la) */ + MALLOC_S ral; /* strlen(ra) */ + struct icmpin *next; +}; + +struct ipxsin { /* IPX socket information */ + INODETYPE inode; + char *la; /* local address */ + char *ra; /* remote address */ + int state; + unsigned long txq, rxq; /* transmit and receive queue values */ + struct ipxsin *next; +}; + +struct nlksin { /* Netlink socket information */ + INODETYPE inode; /* node number */ + unsigned int pr; /* protocol */ + struct nlksin *next; +}; + +struct packin { /* packet information */ + INODETYPE inode; + int ty; /* socket type */ + int pr; /* protocol */ + struct packin *next; +}; + +struct rawsin { /* raw socket information */ + INODETYPE inode; + char *la; /* local address */ + char *ra; /* remote address */ + char *sp; /* state characters */ + MALLOC_S lal; /* strlen(la) */ + MALLOC_S ral; /* strlen(ra) */ + MALLOC_S spl; /* strlen(sp) */ + struct rawsin *next; +}; + +struct sctpsin { /* SCTP socket information */ + INODETYPE inode; + int type; /* type: 0 = assoc + * 1 = eps + * 2 assoc and eps */ + char *addr; /* association or endpoint address */ + char *assocID; /* association ID */ + char *lport; /* local port */ + char *rport; /* remote port */ + char *laddrs; /* local address */ + char *raddrs; /* remote address */ + struct sctpsin *next; +}; + +struct tcp_udp { /* IPv4 TCP and UDP socket + * information */ + INODETYPE inode; + unsigned long faddr, laddr; /* foreign & local 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; +}; + +#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; +}; +#endif /* defined(HASIPv6) */ + + +/* + * Local static values + */ + +static char *AX25path = (char *)NULL; /* path to AX25 /proc information */ +static struct ax25sin **AX25sin = (struct ax25sin **)NULL; + /* AX25 socket info, hashed by inode */ +static char *ax25st[] = { + "LISTENING", /* 0 */ + "SABM SENT", /* 1 */ + "DISC SENT", /* 2 */ + "ESTABLISHED", /* 3 */ + "RECOVERY" /* 4 */ +}; +#define NAX25ST (sizeof(ax25st) / sizeof(char *)) +static char *ICMPpath = (char *)NULL; /* path to ICMP /proc information */ +static struct icmpin **Icmpin = (struct icmpin **)NULL; + /* ICMP socket info, hashed by inode */ +static char *Ipxpath = (char *)NULL; /* path to IPX /proc information */ +static struct ipxsin **Ipxsin = (struct ipxsin **)NULL; + /* IPX socket info, hashed by inode */ +static char *Nlkpath = (char *)NULL; /* path to Netlink /proc information */ +static struct nlksin **Nlksin = (struct nlksin **)NULL; + /* Netlink socket info, hashed by + * inode */ +static struct packin **Packin = (struct packin **)NULL; + /* packet info, hashed by inode */ +static char *Packpath = (char *)NULL; /* path to packet /proc information */ +static char *Rawpath = (char *)NULL; /* path to raw socket /proc + * information */ +static struct rawsin **Rawsin = (struct rawsin **)NULL; + /* raw socket info, hashed by inode */ +static char *SCTPPath[] = { /* paths to /proc/net STCP info */ + (char *)NULL, /* 0 = /proc/net/sctp/assocs */ + (char *)NULL /* 1 = /proc/net/sctp/eps */ +}; +#define NSCTPPATHS sizeof(SCTPPath)/sizeof(char *) +static char *SCTPSfx[] = { /* /proc/net suffixes */ + "sctp/assocs", /* 0 = /proc/net/sctp/assocs */ + "sctp/eps" /* 1 = /proc/net/sctp/eps */ +}; +static struct sctpsin **SCTPsin = (struct sctpsin **)NULL; + /* SCTP info, hashed by inode */ +static char *SockStatPath = (char *)NULL; + /* path to /proc/net socket status */ +static char *TCPpath = (char *)NULL; /* path to TCP /proc information */ +static struct tcp_udp **TcpUdp = (struct tcp_udp **)NULL; + /* IPv4 TCP & UDP info, hashed by + * inode */ +static int TcpUdp_bucks = 0; /* dynamically sized hash bucket + * count for TCP and UDP -- will + * be a power of two */ + +#if defined(HASIPv6) +static char *Raw6path = (char *)NULL; /* path to raw IPv6 /proc information */ +static struct rawsin **Rawsin6 = (struct rawsin **)NULL; + /* IPv6 raw socket info, hashed by + * inode */ +static char *SockStatPath6 = (char *)NULL; + /* path to /proc/net IPv6 socket + * status */ +static char *TCP6path = (char *)NULL; /* path to IPv6 TCP /proc information */ +static struct tcp_udp6 **TcpUdp6 = (struct tcp_udp6 **)NULL; + /* IPv6 TCP & UDP info, hashed by + * inode */ +static int TcpUdp6_bucks = 0; /* dynamically sized hash bucket + * count for IPv6 TCP and UDP -- will + * be a power of two */ +static char *UDP6path = (char *)NULL; /* path to IPv6 UDP /proc information */ +static char *UDPLITE6path = (char *)NULL; + /* path to IPv6 UDPLITE /proc + * information */ +#endif /* defined(HASIPv6) */ + +static char *UDPpath = (char *)NULL; /* path to UDP /proc information */ +static char *UDPLITEpath = (char *)NULL; + /* path to UDPLITE /proc information */ +static char *UNIXpath = (char *)NULL; /* path to UNIX /proc information */ +static uxsin_t **Uxsin = (uxsin_t **)NULL; + /* UNIX socket info, hashed by inode */ + + +/* + * Local function prototypes + */ + +_PROTOTYPE(static struct ax25sin *check_ax25,(INODETYPE i)); + +#if defined(HASEPTOPTS) && defined(HASUXSOCKEPT) +_PROTOTYPE(static void enter_uxsinfo,(uxsin_t *up)); +_PROTOTYPE(static void fill_uxicino,(INODETYPE si, INODETYPE sc)); +_PROTOTYPE(static void fill_uxpino,(INODETYPE si, INODETYPE pi)); +_PROTOTYPE(static int get_diagmsg,(int sockfd)); +_PROTOTYPE(static void get_uxpeeri,(void)); +_PROTOTYPE(static void parse_diag,(struct unix_diag_msg *dm, int len)); +_PROTOTYPE(static void prt_uxs,(uxsin_t *p, int mk)); +#endif /* defined(HASEPTOPTS) && defined(HASUXSOCKEPT) */ + +_PROTOTYPE(static struct icmpin *check_icmp,(INODETYPE i)); +_PROTOTYPE(static struct ipxsin *check_ipx,(INODETYPE i)); +_PROTOTYPE(static struct nlksin *check_netlink,(INODETYPE i)); +_PROTOTYPE(static struct packin *check_pack,(INODETYPE i)); +_PROTOTYPE(static struct rawsin *check_raw,(INODETYPE i)); +_PROTOTYPE(static struct sctpsin *check_sctp,(INODETYPE i)); +_PROTOTYPE(static struct tcp_udp *check_tcpudp,(INODETYPE i, char **p)); +_PROTOTYPE(static uxsin_t *check_unix,(INODETYPE i)); +_PROTOTYPE(static void get_ax25,(char *p)); +_PROTOTYPE(static void get_icmp,(char *p)); +_PROTOTYPE(static void get_ipx,(char *p)); +_PROTOTYPE(static void get_netlink,(char *p)); +_PROTOTYPE(static void get_pack,(char *p)); +_PROTOTYPE(static void get_raw,(char *p)); +_PROTOTYPE(static void get_sctp,(void)); +_PROTOTYPE(static char *get_sctpaddrs,(char **fp, int i, int nf, int *x)); +_PROTOTYPE(static void get_tcpudp,(char *p, int pr, int clr)); +_PROTOTYPE(static void get_unix,(char *p)); +_PROTOTYPE(static int isainb,(char *a, char *b)); +_PROTOTYPE(static void print_ax25info,(struct ax25sin *ap)); +_PROTOTYPE(static void print_ipxinfo,(struct ipxsin *ip)); +_PROTOTYPE(static char *sockty2str,(uint32_t ty, int *rf)); + +#if defined(HASIPv6) +_PROTOTYPE(static struct rawsin *check_raw6,(INODETYPE i)); +_PROTOTYPE(static struct tcp_udp6 *check_tcpudp6,(INODETYPE i, char **p)); +_PROTOTYPE(static void get_raw6,(char *p)); +_PROTOTYPE(static void get_tcpudp6,(char *p, int pr, int clr)); +_PROTOTYPE(static int net6a2in6,(char *as, struct in6_addr *ad)); +#endif /* defined(HASIPv6) */ + + +/* + * build_IPstates() -- build the TCP and UDP state tables + */ + +void +build_IPstates() +{ + if (!TcpSt) { + (void) enter_IPstate("TCP", "ESTABLISHED", TCP_ESTABLISHED); + (void) enter_IPstate("TCP", "SYN_SENT", TCP_SYN_SENT); + (void) enter_IPstate("TCP", "SYN_RECV", TCP_SYN_RECV); + (void) enter_IPstate("TCP", "FIN_WAIT1", TCP_FIN_WAIT1); + (void) enter_IPstate("TCP", "FIN_WAIT2", TCP_FIN_WAIT2); + (void) enter_IPstate("TCP", "TIME_WAIT", TCP_TIME_WAIT); + (void) enter_IPstate("TCP", "CLOSE", TCP_CLOSE); + (void) enter_IPstate("TCP", "CLOSE_WAIT", TCP_CLOSE_WAIT); + (void) enter_IPstate("TCP", "LAST_ACK", TCP_LAST_ACK); + (void) enter_IPstate("TCP", "LISTEN", TCP_LISTEN); + (void) enter_IPstate("TCP", "CLOSING", TCP_CLOSING); + (void) enter_IPstate("TCP", "CLOSED", 0); + (void) enter_IPstate("TCP", (char *)NULL, 0); + } +} + + +/* + * check_ax25() - check for AX25 socket file + */ + +static struct ax25sin * +check_ax25(i) + INODETYPE i; /* socket file's inode number */ +{ + struct ax25sin *ap; + int h; + + h = INOHASH(i); + for (ap = AX25sin[h]; ap; ap = ap->next) { + if (i == ap->inode) + return(ap); + } + return((struct ax25sin *)NULL); +} + + + +/* + * check_icmp() - check for ICMP socket + */ + +static struct icmpin * +check_icmp(i) + INODETYPE i; /* socket file's inode number */ +{ + int h; + struct icmpin *icmpp; + + h = INOHASH(i); + for (icmpp = Icmpin[h]; icmpp; icmpp = icmpp->next) { + if (i == icmpp->inode) + return(icmpp); + } + return((struct icmpin *)NULL); +} + + +/* + * check_ipx() - check for IPX socket file + */ + +static struct ipxsin * +check_ipx(i) + INODETYPE i; /* socket file's inode number */ +{ + int h; + struct ipxsin *ip; + + h = INOHASH(i); + for (ip = Ipxsin[h]; ip; ip = ip->next) { + if (i == ip->inode) + return(ip); + } + return((struct ipxsin *)NULL); +} + + +/* + * check_netlink() - check for Netlink socket file + */ + +static struct nlksin * +check_netlink(i) + INODETYPE i; /* socket file's inode number */ +{ + int h; + struct nlksin *lp; + + h = INOHASH(i); + for (lp = Nlksin[h]; lp; lp = lp->next) { + if (i == lp->inode) + return(lp); + } + return((struct nlksin *)NULL); +} + + +/* + * check_pack() - check for packet file + */ + +static struct packin * +check_pack(i) + INODETYPE i; /* packet file's inode number */ +{ + int h; + struct packin *pp; + + h = INOHASH(i); + for (pp = Packin[h]; pp; pp = pp->next) { + if (i == pp->inode) + return(pp); + } + return((struct packin *)NULL); +} + + +/* + * check_raw() - check for raw socket file + */ + +static struct rawsin * +check_raw(i) + INODETYPE i; /* socket file's inode number */ +{ + int h; + struct rawsin *rp; + + h = INOHASH(i); + for (rp = Rawsin[h]; rp; rp = rp->next) { + if (i == rp->inode) + return(rp); + } + return((struct rawsin *)NULL); +} + + +/* + * check_sctp() - check for SCTP socket file + */ + +static struct sctpsin * +check_sctp(i) + INODETYPE i; /* socket file's inode number */ +{ + int h; + struct sctpsin *sp; + + h = INOHASH(i); + for (sp = SCTPsin[h]; sp; sp = sp->next) { + if (i == sp->inode) + return(sp); + } + return((struct sctpsin *)NULL); +} + + +/* + * check_tcpudp() - check for IPv4 TCP or UDP socket file + */ + +static struct tcp_udp * +check_tcpudp(i, p) + INODETYPE i; /* socket file's inode number */ + char **p; /* protocol return */ +{ + int h; + struct tcp_udp *tp; + + h = TCPUDPHASH(i); + for (tp = TcpUdp[h]; tp; tp = tp->next) { + if (i == tp->inode) { + switch (tp->proto) { + case 0: + *p = "TCP"; + break; + case 1: + *p = "UDP"; + break; + case 2: + *p = "UDPLITE"; + break; + default: + *p = "unknown"; + } + return(tp); + } + } + return((struct tcp_udp *)NULL); +} + + +#if defined(HASIPv6) +/* + * check_raw6() - check for raw IPv6 socket file + */ + +static struct rawsin * +check_raw6(i) + INODETYPE i; /* socket file's inode number */ +{ + int h; + struct rawsin *rp; + + h = INOHASH(i); + for (rp = Rawsin6[h]; rp; rp = rp->next) { + if (i == rp->inode) + return(rp); + } + return((struct rawsin *)NULL); +} + + +/* + * check_tcpudp6() - check for IPv6 TCP or UDP socket file + */ + +static struct tcp_udp6 * +check_tcpudp6(i, p) + INODETYPE i; /* socket file's inode number */ + char **p; /* protocol return */ +{ + int h; + struct tcp_udp6 *tp6; + + h = TCPUDP6HASH(i); + for (tp6 = TcpUdp6[h]; tp6; tp6 = tp6->next) { + if (i == tp6->inode) { + switch (tp6->proto) { + case 0: + *p = "TCP"; + break; + case 1: + *p = "UDP"; + break; + case 2: + *p = "UDPLITE"; + break; + default: + *p = "unknown"; + } + return(tp6); + } + } + return((struct tcp_udp6 *)NULL); +} +#endif /* defined(HASIPv6) */ + + +/* + * check_unix() - check for UNIX domain socket + */ + +static uxsin_t * +check_unix(i) + INODETYPE i; /* socket file's inode number */ +{ + int h; + uxsin_t *up; + + h = INOHASH(i); + for (up = Uxsin[h]; up; up = up->next) { + if (i == up->inode) + return(up); + } + return((uxsin_t *)NULL); +} + + +/* + * clear_uxsinfo -- clear allocated UNIX socket info + */ + +void +clear_uxsinfo() +{ + 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(p) + char *p; /* /proc/net/ipx path */ +{ + struct ax25sin *ap, *np; + FILE *as; + char buf[MAXPATHLEN], *da, *dev_ch, *ep, **fp, *sa; + int h, nf; + INODETYPE inode; + unsigned long rq, sq, state; + MALLOC_S len; + unsigned char rqs, sqs; + static char *vbuf = (char *)NULL; + static size_t vsz = (size_t)0; +/* + * Do second time cleanup or first time setup. + */ + if (AX25sin) { + for (h = 0; h < INOBUCKS; h++) { + for (ap = AX25sin[h]; ap; ap = np) { + np = ap->next; + if (ap->da) + (void) free((FREE_P *)ap->da); + if (ap->dev_ch) + (void) free((FREE_P *)ap->dev_ch); + if (ap->sa) + (void) free((FREE_P *)ap->sa); + (void) free((FREE_P *)ap); + } + AX25sin[h] = (struct ax25sin *)NULL; + } + } else { + AX25sin = (struct ax25sin **)calloc(INOBUCKS, + sizeof(struct ax25sin *)); + if (!AX25sin) { + (void) fprintf(stderr, + "%s: can't allocate %d AX25 hash pointer bytes\n", + Pn, (int)(INOBUCKS * sizeof(struct ax25sin *))); + Exit(1); + } + } +/* + * Open the /proc/net/ax25 file, assign a page size buffer to the stream, + * and read it. Store AX25 socket info in the AX25sin[] hash buckets. + */ + if (!(as = open_proc_stream(p, "r", &vbuf, &vsz, 0))) + return; + while (fgets(buf, sizeof(buf) - 1, as)) { + if ((nf = get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0)) < 24) + continue; + /* + * /proc/net/ax25 has no title line, a very poor deficiency in its + * implementation. + * + * The ax25_get_info() function in kern module .../net/ax25/af_ax25.c + * says the format of the lines in the file is: + * + * magic dev src_addr dest_addr,digi1,digi2,.. st vs vr va t1 t1 \ + * t2 t2 t3 t3 idle idle n2 n2 rtt window paclen Snd-Q Rcv-Q \ + * inode + * + * The code in this function is forced to assume that format is in + * effect.. + */ + + /* + * Assemble the inode number and see if it has already been recorded. + * If it has, skip this line. + */ + ep = (char *)NULL; + if (!fp[23] || !*fp[23] + || (inode = strtoull(fp[23], &ep, 0)) == ULONG_MAX + || !ep || *ep) + continue; + h = INOHASH((INODETYPE)inode); + for (ap = AX25sin[h]; ap; ap = ap->next) { + if (inode == ap->inode) + break; + } + if (ap) + continue; + /* + * Assemble the send and receive queue values and the state. + */ + rq = sq = (unsigned long)0; + rqs = sqs = (unsigned char)0; + ep = (char *)NULL; + if (!fp[21] || !*fp[21] + || (sq = strtoul(fp[21], &ep, 0)) == ULONG_MAX || !ep || *ep) + continue; + sqs = (unsigned char)1; + ep = (char *)NULL; + if (!fp[22] || !*fp[22] + || (rq = strtoul(fp[22], &ep, 0)) == ULONG_MAX || !ep || *ep) + continue; + rqs = (unsigned char)1; + ep = (char *)NULL; + if (!fp[4] || !*fp[4] + || (state = strtoul(fp[4], &ep, 0)) == ULONG_MAX || !ep || *ep) + continue; + /* + * Allocate space for the destination address. + */ + if (!fp[3] || !*fp[3]) + da = (char *)NULL; + else if ((len = strlen(fp[3]))) { + if (!(da = (char *)malloc(len + 1))) { + (void) fprintf(stderr, + "%s: can't allocate %d destination AX25 addr bytes: %s\n", + Pn, (int)(len + 1), fp[3]); + Exit(1); + } + (void) snpf(da, len + 1, "%s", fp[3]); + } else + da = (char *)NULL; + /* + * Allocate space for the source address. + */ + if (!fp[2] || !*fp[2]) + sa = (char *)NULL; + else if ((len = strlen(fp[2]))) { + if (!(sa = (char *)malloc(len + 1))) { + (void) fprintf(stderr, + "%s: can't allocate %d source AX25 address bytes: %s\n", + Pn, (int)(len + 1), fp[2]); + Exit(1); + } + (void) snpf(sa, len + 1, "%s", fp[2]); + } else + sa = (char *)NULL; + /* + * Allocate space for the device characters. + */ + if (!fp[1] || !*fp[1]) + dev_ch = (char *)NULL; + else if ((len = strlen(fp[1]))) { + if (!(dev_ch = (char *)malloc(len + 1))) { + (void) fprintf(stderr, + "%s: can't allocate %d destination AX25 dev bytes: %s\n", + Pn, (int)(len + 1), fp[1]); + Exit(1); + } + (void) snpf(dev_ch, len + 1, "%s", fp[1]); + } else + dev_ch = (char *)NULL; + /* + * Allocate space for an ax25sin entry, fill it, and link it to its + * hash bucket. + */ + if (!(ap = (struct ax25sin *)malloc(sizeof(struct ax25sin)))) { + (void) fprintf(stderr, + "%s: can't allocate %d byte ax25sin structure\n", + Pn, (int)sizeof(struct ax25sin)); + Exit(1); + } + ap->da = da; + ap->dev_ch = dev_ch; + ap->inode = inode; + ap->rq = rq; + ap->rqs = rqs; + ap->sa = sa; + ap->sq = sq; + ap->sqs = sqs; + ap->state = (int)state; + ap->next = AX25sin[h]; + AX25sin[h] = ap; + } + (void) fclose(as); +} + + +#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 (up) + 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) && !strcmp(lf->fd, Lf->fd)) + 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); + Exit(1); + } + 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 (si, ic) + INODETYPE si; /* UNIX socket inode number */ + INODETYPE ic; /* incomining 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(si))) { + if (psi->icstat || psi->icons) + return; + if ((pic = check_unix(ic))) { + psi->icstat = 1; + psi->icons = pic; + } + } +} + + +/* + * fill_uxpino() -- fill in UNIX socket's peer inode number + */ + +static void +fill_uxpino(si, pi) + INODETYPE si; /* UNIX socket inode number */ + INODETYPE pi; /* UNIX socket peer's inode number */ +{ + uxsin_t *pp, *up; + + if ((up = check_unix(si))) { + if (!up->peer) { + if (pp = check_unix(pi)) + up->peer = pp; + } + } +} + + +/* + * find_uxepti(lf) -- find UNIX socket endpoint info + */ + +uxsin_t * +find_uxepti(lf) + struct lfile *lf; /* pipe's lfile */ +{ + uxsin_t *up; + + up = check_unix(lf->inode); + return(up ? up->peer: (uxsin_t *)NULL); +} + + +/* + * get_diagmsg() -- get UNIX socket's diag message + */ + +static int +get_diagmsg(sockfd) + 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 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)); + Exit(1); + } +/* + * 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(dm, rl); + hp = NLMSG_NEXT(hp, nb); + } + } + +get_uxpeeri_exit: + + (void) close(ns); +} + + +/* + * parse_diag() -- parse UNIX diag message + */ + +static void +parse_diag(dm, len) + 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((INODETYPE)inop, (INODETYPE)inoc); + fill_uxpino((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((INODETYPE)inop, (INODETYPE)*icp); + } + } + rp = RTA_NEXT(rp, len); + } +} + + +/* + * prt_uxs() -- print UNIX socket information + */ + +static void +prt_uxs(p, mk) + 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 */ + + (void) strcpy(nma, "->INO="); + len = (int)strlen(nma); + (void) snpf(&nma[len], sizeof(nma) - len - 1, InodeFmt_d, p->inode); + (void) add_nma(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; + for (i = 0; i < (FDLEN - 1); i++) { + if (ef->fd[i] != ' ') + break; + } + (void) snpf(nma, sizeof(nma) - 1, "%d,%.*s,%s%c", + ep->pid, CmdLim, ep->cmd, &ef->fd[i], ef->access); + (void) add_nma(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(f) + 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 (strcmp(Lf->type, "unix")) + continue; + switch (f) { + case 0: + + /* + * Process already selected socket. + */ + if (is_file_sel(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(Lf); + if (p && p->inode) + prt_uxs(p, 1); + if ((tp = check_unix(Lf->inode))) { + if (tp->icons) { + if (tp->icstat) { + p = tp->icons; + while (p != tp) { + if (p && p->inode) + prt_uxs(p, 1); + p = p->icons; + } + } else { + for (p = tp->icons; !p->icstat; p = p->icons) + ; /* DO NOTHING */ + if (p->icstat && p->inode) + prt_uxs (p, 1); + } + } + } + } + break; + case 1: + if (!is_file_sel(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(Lf); + if (p && p->inode) + prt_uxs(p, 0); + else if ((tp = check_unix(Lf->inode))) { + if (tp->icons) { + if (tp->icstat) { + p = tp->icons; + while (p != tp) { + if (p && p->inode) + prt_uxs(p, 0); + p = p->icons; + } + } else { + for (p = tp->icons; !p->icstat; p = p->icons) + ; /* DO NOTHING */ + if (p->icstat && p->inode) + prt_uxs(p, 0); + } + } + } + } + break; + } + } +} +#endif /* defined(HASEPTOPTS) && defined(HASUXSOCKEPT) */ + + +/* + * get_icmp() - get ICMP net info + */ + +static void +get_icmp(p) + char *p; /* /proc/net/icmp path */ +{ + char buf[MAXPATHLEN], *ep, **fp, *la, *ra; + int fl = 1; + int h; + INODETYPE inode; + struct icmpin *np, *icmpp; + 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 *))); + Exit(1); + } + } +/* + * Open the /proc/net/icmp file, assign a page size buffer to its stream, + * and read the file. Store icmp info in the Icmpin[] hash buckets. + */ + if (!(xs = open_proc_stream(p, "r", &vbuf, &vsz, 0))) + return; + while (fgets(buf, sizeof(buf) - 1, xs)) { + if (get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0) < 11) + continue; + if (fl) { + + /* + * Check the column labels in the first line. + * + * NOTE: + * In column header, "inode" is at the 11th column. + * However, in data rows, inode appears at the 9th column. + * + * In column header, "tx_queue" and "rx_queue" are separated + * by a space. It is the same for "tr" and "tm->when"; in + * data rows they are connected with ":". + */ + if (!fp[1] || strcmp(fp[1], "local_address") + || !fp[2] || strcmp(fp[2], "rem_address") + || !fp[11] || strcmp(fp[11], "inode")) + { + if (!Fwarn) { + (void) fprintf(stderr, + "%s: WARNING: unsupported format: %s\n", + Pn, p); + } + break; + } + fl = 0; + continue; + } + /* + * Assemble the inode number and see if the inode is already + * recorded. + */ + ep = (char *)NULL; + if (!fp[9] || !*fp[9] + || (inode = strtoull(fp[9], &ep, 0)) == ULONG_MAX + || !ep || *ep) + continue; + h = INOHASH(inode); + for (icmpp = Icmpin[h]; icmpp; icmpp = icmpp->next) { + if (inode == icmpp->inode) + break; + } + if (icmpp) + continue; + /* + * Save the local address, and remote address. + */ + if (!fp[1] || !*fp[1] || (lal = strlen(fp[1])) < 1) { + la = (char *)NULL; + lal = (MALLOC_S)0; + } else { + if (!(la = (char *)malloc(lal + 1))) { + (void) fprintf(stderr, + "%s: can't allocate %d local icmp address bytes: %s\n", + Pn, (int)(lal + 1), fp[1]); + Exit(1); + } + (void) snpf(la, lal + 1, "%s", fp[1]); + } + if (!fp[2] || !*fp[2] || (ral = strlen(fp[2])) < 1) { + ra = (char *)NULL; + ral = (MALLOC_S)0; + } else { + if (!(ra = (char *)malloc(ral + 1))) { + (void) fprintf(stderr, + "%s: can't allocate %d remote icmp address bytes: %s\n", + Pn, (int)(ral + 1), fp[2]); + Exit(1); + } + (void) snpf(ra, ral + 1, "%s", fp[2]); + } + /* + * Allocate space for a icmpin entry, fill it, and link it to its + * hash bucket. + */ + if (!(icmpp = (struct icmpin *)malloc(sizeof(struct icmpin)))) { + (void) fprintf(stderr, + "%s: can't allocate %d byte icmp structure\n", + Pn, (int)sizeof(struct icmpin)); + Exit(1); + } + icmpp->inode = inode; + icmpp->la = la; + icmpp->lal = lal; + icmpp->ra = ra; + icmpp->ral = ral; + icmpp->next = Icmpin[h]; + Icmpin[h] = icmpp; + } + (void) fclose(xs); +} + + + +/* + * get_ipx() - get /proc/net/ipx info + */ + +static void +get_ipx(p) + char *p; /* /proc/net/ipx path */ +{ + char buf[MAXPATHLEN], *ep, **fp, *la, *ra; + int fl = 1; + int h; + INODETYPE inode; + unsigned long rxq, state, txq; + struct ipxsin *ip, *np; + MALLOC_S len; + static char *vbuf = (char *)NULL; + static size_t vsz = (size_t)0; + FILE *xs; +/* + * Do second time cleanup or first time setup. + */ + if (Ipxsin) { + for (h = 0; h < INOBUCKS; h++) { + for (ip = Ipxsin[h]; ip; ip = np) { + np = ip->next; + if (ip->la) + (void) free((FREE_P *)ip->la); + if (ip->ra) + (void) free((FREE_P *)ip->ra); + (void) free((FREE_P *)ip); + } + Ipxsin[h] = (struct ipxsin *)NULL; + } + } else { + Ipxsin = (struct ipxsin **)calloc(INOBUCKS, + sizeof(struct ipxsin *)); + if (!Ipxsin) { + (void) fprintf(stderr, + "%s: can't allocate %d IPX hash pointer bytes\n", + Pn, (int)(INOBUCKS * sizeof(struct ipxsin *))); + Exit(1); + } + } +/* + * Open the /proc/net/ipx file, assign a page size buffer to the stream, + * and read it. Store IPX socket info in the Ipxsin[] hash buckets. + */ + if (!(xs = open_proc_stream(p, "r", &vbuf, &vsz, 0))) + return; + while (fgets(buf, sizeof(buf) - 1, xs)) { + if (get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0) < 7) + continue; + if (fl) { + + /* + * Check the column labels in the first line. + */ + if (!fp[0] || strcmp(fp[0], "Local_Address") + || !fp[1] || strcmp(fp[1], "Remote_Address") + || !fp[2] || strcmp(fp[2], "Tx_Queue") + || !fp[3] || strcmp(fp[3], "Rx_Queue") + || !fp[4] || strcmp(fp[4], "State") + || !fp[5] || strcmp(fp[5], "Uid") + || !fp[6] || strcmp(fp[6], "Inode")) + { + if (!Fwarn) { + (void) fprintf(stderr, + "%s: WARNING: unsupported format: %s\n", + Pn, p); + } + break; + } + fl = 0; + continue; + } + /* + * Assemble the inode number and see if the inode is already + * recorded. + */ + ep = (char *)NULL; + if (!fp[6] || !*fp[6] + || (inode = strtoull(fp[6], &ep, 0)) == ULONG_MAX + || !ep || *ep) + continue; + h = INOHASH(inode); + for (ip = Ipxsin[h]; ip; ip = ip->next) { + if (inode == ip->inode) + break; + } + if (ip) + continue; + /* + * Assemble the transmit and receive queue values and the state. + */ + ep = (char *)NULL; + if (!fp[2] || !*fp[2] + || (txq = strtoul(fp[2], &ep, 16)) == ULONG_MAX || !ep || *ep) + continue; + ep = (char *)NULL; + if (!fp[3] || !*fp[3] + || (rxq = strtoul(fp[3], &ep, 16)) == ULONG_MAX || !ep || *ep) + continue; + ep = (char *)NULL; + if (!fp[4] || !*fp[4] + || (state = strtoul(fp[4], &ep, 16)) == ULONG_MAX || !ep || *ep) + continue; + /* + * Allocate space for the local address, unless it is "Not_Connected". + */ + if (!fp[0] || !*fp[0] || strcmp(fp[0], "Not_Connected") == 0) + la = (char *)NULL; + else if ((len = strlen(fp[0]))) { + if (!(la = (char *)malloc(len + 1))) { + (void) fprintf(stderr, + "%s: can't allocate %d local IPX address bytes: %s\n", + Pn, (int)(len + 1), fp[0]); + Exit(1); + } + (void) snpf(la, len + 1, "%s", fp[0]); + } else + la = (char *)NULL; + /* + * Allocate space for the remote address, unless it is "Not_Connected". + */ + if (!fp[1] || !*fp[1] || strcmp(fp[1], "Not_Connected") == 0) + ra = (char *)NULL; + else if ((len = strlen(fp[1]))) { + if (!(ra = (char *)malloc(len + 1))) { + (void) fprintf(stderr, + "%s: can't allocate %d remote IPX address bytes: %s\n", + Pn, (int)(len + 1), fp[1]); + Exit(1); + } + (void) snpf(ra, len + 1, "%s", fp[1]); + } else + ra = (char *)NULL; + /* + * Allocate space for an ipxsin entry, fill it, and link it to its + * hash bucket. + */ + if (!(ip = (struct ipxsin *)malloc(sizeof(struct ipxsin)))) { + (void) fprintf(stderr, + "%s: can't allocate %d byte ipxsin structure\n", + Pn, (int)sizeof(struct ipxsin)); + Exit(1); + } + ip->inode = inode; + ip->la = la; + ip->ra = ra; + ip->txq = txq; + ip->rxq = rxq; + ip->state = (int)state; + ip->next = Ipxsin[h]; + Ipxsin[h] = ip; + } + (void) fclose(xs); +} + + +/* + * get_netlink() - get /proc/net/netlink info + */ + +static void +get_netlink(p) + char *p; /* /proc/net/netlink path */ +{ + char buf[MAXPATHLEN], *ep, **fp; + int fr = 1; + int h, pr; + INODETYPE inode; + struct nlksin *np, *lp; + static char *vbuf = (char *)NULL; + static size_t vsz = (size_t)0; + FILE *xs; +/* + * Do second time cleanup or first time setup. + */ + if (Nlksin) { + for (h = 0; h < INOBUCKS; h++) { + for (lp = Nlksin[h]; lp; lp = np) { + np = lp->next; + (void) free((FREE_P *)lp); + } + Nlksin[h] = (struct nlksin *)NULL; + } + } else { + Nlksin = (struct nlksin **)calloc(INOBUCKS,sizeof(struct nlksin *)); + if (!Nlksin) { + (void) fprintf(stderr, + "%s: can't allocate %d netlink hash pointer bytes\n", + Pn, (int)(INOBUCKS * sizeof(struct nlksin *))); + Exit(1); + } + } +/* + * Open the /proc/net/netlink file, assign a page size buffer to its stream, + * and read the file. Store Netlink info in the Nlksin[] hash buckets. + */ + if (!(xs = open_proc_stream(p, "r", &vbuf, &vsz, 0))) + return; + while (fgets(buf, sizeof(buf) - 1, xs)) { + if (get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0) < 10) + continue; + if (fr) { + + /* + * Check the column labels in the first line. + */ + if (!fp[1] || strcmp(fp[1], "Eth") + || !fp[9] || strcmp(fp[9], "Inode")) + { + if (!Fwarn) { + (void) fprintf(stderr, + "%s: WARNING: unsupported format: %s\n", + Pn, p); + } + break; + } + fr = 0; + continue; + } + /* + * Assemble the inode number and see if the inode is already + * recorded. + */ + ep = (char *)NULL; + if (!fp[9] || !*fp[9] + || (inode = strtoull(fp[9], &ep, 0)) == ULONG_MAX + || !ep || *ep) + continue; + h = INOHASH(inode); + for (lp = Nlksin[h]; lp; lp = lp->next) { + if (inode == lp->inode) + break; + } + if (lp) + continue; + /* + * Save the protocol from the Eth column. + */ + if (!fp[1] || !*fp[1] || (strlen(fp[1])) < 1) + continue; + pr = atoi(fp[1]); + /* + * Allocate space for a nlksin entry, fill it, and link it to its + * hash bucket. + */ + if (!(lp = (struct nlksin *)malloc(sizeof(struct nlksin)))) { + (void) fprintf(stderr, + "%s: can't allocate %d byte Netlink structure\n", + Pn, (int)sizeof(struct nlksin)); + Exit(1); + } + lp->inode = inode; + lp->pr = pr; + lp->next = Nlksin[h]; + Nlksin[h] = lp; + } + (void) fclose(xs); +} + + +/* + * get_pack() - get /proc/net/packet info + */ + +static void +get_pack(p) + char *p; /* /proc/net/raw path */ +{ + char buf[MAXPATHLEN], *ep, **fp; + int fl = 1; + int h, ty; + INODETYPE inode; + struct packin *np, *pp; + unsigned long pr; + static char *vbuf = (char *)NULL; + static size_t vsz = (size_t)0; + FILE *xs; +/* + * Do second time cleanup or first time setup. + */ + if (Packin) { + for (h = 0; h < INOBUCKS; h++) { + for (pp = Packin[h]; pp; pp = np) { + np = pp->next; + (void) free((FREE_P *)pp); + } + Packin[h] = (struct packin *)NULL; + } + } else { + Packin = (struct packin **)calloc(INOBUCKS, + sizeof(struct packin *)); + if (!Packin) { + (void) fprintf(stderr, + "%s: can't allocate %d packet hash pointer bytes\n", + Pn, (int)(INOBUCKS * sizeof(struct packin *))); + Exit(1); + } + } +/* + * Open the /proc/net/packet file, assign a page size buffer to its stream, + * and read the file. Store packet info in the Packin[] hash buckets. + */ + if (!(xs = open_proc_stream(p, "r", &vbuf, &vsz, 0))) + return; + while (fgets(buf, sizeof(buf) - 1, xs)) { + if (get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0) < 9) + continue; + if (fl) { + + /* + * Check the column labels in the first line. + */ + if (!fp[2] || strcmp(fp[2], "Type") + || !fp[3] || strcmp(fp[3], "Proto") + || !fp[8] || strcmp(fp[8], "Inode")) + { + if (!Fwarn) { + (void) fprintf(stderr, + "%s: WARNING: unsupported format: %s\n", + Pn, p); + } + break; + } + fl = 0; + continue; + } + /* + * Assemble the inode number and see if the inode is already + * recorded. + */ + ep = (char *)NULL; + if (!fp[8] || !*fp[8] + || (inode = strtoull(fp[8], &ep, 0)) == ULONG_MAX + || !ep || *ep) + continue; + h = INOHASH(inode); + for (pp = Packin[h]; pp; pp = pp->next) { + if (inode == pp->inode) + break; + } + if (pp) + continue; + /* + * Save the socket type and protocol. + */ + if (!fp[2] || !*fp[2] || (strlen(fp[2])) < 1) + continue; + ty = atoi(fp[2]); + ep = (char *)NULL; + if (!fp[3] || !*fp[3] || (strlen(fp[3]) < 1) + || ((pr = strtoul(fp[3], &ep, 16)) == ULONG_MAX) || !ep || *ep) + continue; + /* + * Allocate space for a packin entry, fill it, and link it to its + * hash bucket. + */ + if (!(pp = (struct packin *)malloc(sizeof(struct packin)))) { + (void) fprintf(stderr, + "%s: can't allocate %d byte packet structure\n", + Pn, (int)sizeof(struct packin)); + Exit(1); + } + pp->inode = inode; + pp->pr = (int)pr; + pp->ty = ty; + pp->next = Packin[h]; + Packin[h] = pp; + } + (void) fclose(xs); +} + + +/* + * get_raw() - get /proc/net/raw info + */ + +static void +get_raw(p) + char *p; /* /proc/net/raw path */ +{ + char buf[MAXPATHLEN], *ep, **fp, *la, *ra, *sp; + int h; + INODETYPE inode; + int nf = 12; + struct rawsin *np, *rp; + MALLOC_S lal, ral, spl; + static char *vbuf = (char *)NULL; + static size_t vsz = (size_t)0; + FILE *xs; +/* + * Do second time cleanup or first time setup. + */ + if (Rawsin) { + for (h = 0; h < INOBUCKS; h++) { + for (rp = Rawsin[h]; rp; rp = np) { + np = rp->next; + if (rp->la) + (void) free((FREE_P *)rp->la); + if (rp->ra) + (void) free((FREE_P *)rp->ra); + (void) free((FREE_P *)rp); + } + Rawsin[h] = (struct rawsin *)NULL; + } + } else { + Rawsin = (struct rawsin **)calloc(INOBUCKS, + sizeof(struct rawsin *)); + if (!Rawsin) { + (void) fprintf(stderr, + "%s: can't allocate %d raw hash pointer bytes\n", + Pn, (int)(INOBUCKS * sizeof(struct rawsin *))); + Exit(1); + } + } +/* + * Open the /proc/net/raw file, assign a page size buffer to its stream, + * and read the file. Store raw socket info in the Rawsin[] hash buckets. + */ + if (!(xs = open_proc_stream(p, "r", &vbuf, &vsz, 0))) + return; + while (fgets(buf, sizeof(buf) - 1, xs)) { + if (get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0) < nf) + continue; + if (nf == 12) { + + /* + * Check the column labels in the first line. + */ + if (!fp[1] || strcmp(fp[1], "local_address") + || !fp[2] || strcmp(fp[2], "rem_address") + || !fp[3] || strcmp(fp[3], "st") + || !fp[11] || strcmp(fp[11], "inode")) + { + if (!Fwarn) { + (void) fprintf(stderr, + "%s: WARNING: unsupported format: %s\n", + Pn, p); + } + break; + } + nf = 10; + continue; + } + /* + * Assemble the inode number and see if the inode is already + * recorded. + */ + ep = (char *)NULL; + if (!fp[9] || !*fp[9] + || (inode = strtoull(fp[9], &ep, 0)) == ULONG_MAX + || !ep || *ep) + continue; + h = INOHASH(inode); + for (rp = Rawsin[h]; rp; rp = rp->next) { + if (inode == rp->inode) + break; + } + if (rp) + continue; + /* + * Save the local address, remote address, and state. + */ + if (!fp[1] || !*fp[1] || (lal = strlen(fp[1])) < 1) { + la = (char *)NULL; + lal = (MALLOC_S)0; + } else { + if (!(la = (char *)malloc(lal + 1))) { + (void) fprintf(stderr, + "%s: can't allocate %d local raw address bytes: %s\n", + Pn, (int)(lal + 1), fp[1]); + Exit(1); + } + (void) snpf(la, lal + 1, "%s", fp[1]); + } + if (!fp[2] || !*fp[2] || (ral = strlen(fp[2])) < 1) { + ra = (char *)NULL; + ral = (MALLOC_S)0; + } else { + if (!(ra = (char *)malloc(ral + 1))) { + (void) fprintf(stderr, + "%s: can't allocate %d remote raw address bytes: %s\n", + Pn, (int)(ral + 1), fp[2]); + Exit(1); + } + (void) snpf(ra, ral + 1, "%s", fp[2]); + } + if (!fp[3] || !*fp[3] || (spl = strlen(fp[3])) < 1) { + sp = (char *)NULL; + spl = (MALLOC_S)0; + } else { + if (!(sp = (char *)malloc(spl + 1))) { + (void) fprintf(stderr, + "%s: can't allocate %d remote raw state bytes: %s\n", + Pn, (int)(spl + 1), fp[2]); + Exit(1); + } + (void) snpf(sp, spl + 1, "%s", fp[3]); + } + /* + * Allocate space for an rawsin entry, fill it, and link it to its + * hash bucket. + */ + if (!(rp = (struct rawsin *)malloc(sizeof(struct rawsin)))) { + (void) fprintf(stderr, + "%s: can't allocate %d byte rawsin structure\n", + Pn, (int)sizeof(struct rawsin)); + Exit(1); + } + rp->inode = inode; + rp->la = la; + rp->lal = lal; + rp->ra = ra; + rp->ral = ral; + rp->sp = sp; + rp->spl = spl; + rp->next = Rawsin[h]; + Rawsin[h] = rp; + } + (void) fclose(xs); +} + + +/* + * get_sctp() - get /proc/net/sctp/assocs info + */ + +static void +get_sctp() +{ + char buf[MAXPATHLEN], *a, *ep, **fp, *id, *la, *lp, *ra, *rp, *ta; + int d, err, fl, h, i, j, nf, ty, x; + INODETYPE inode; + MALLOC_S len, plen; + struct sctpsin *sp, *np; + FILE *ss; + static char *vbuf = (char *)NULL; + static size_t vsz = (size_t)0; +/* + * Do second time cleanup or first time setup. + */ + if (SCTPsin) { + for (h = 0; h < INOBUCKS; h++) { + for (sp = SCTPsin[h]; sp; sp = np) { + np = sp->next; + if (sp->addr) + (void) free((FREE_P *)sp->addr); + if (sp->assocID) + (void) free((FREE_P *)sp->assocID); + if (sp->lport) + (void) free((FREE_P *)sp->lport); + if (sp->rport) + (void) free((FREE_P *)sp->rport); + if (sp->laddrs) + (void) free((FREE_P *)sp->laddrs); + if (sp->raddrs) + (void) free((FREE_P *)sp->raddrs); + (void) free((FREE_P *)sp); + } + SCTPsin[h] = (struct sctpsin *)NULL; + } + } else { + SCTPsin = (struct sctpsin **)calloc(INOBUCKS, + sizeof(struct sctpsin *)); + if (!SCTPsin) { + (void) fprintf(stderr, + "%s: can't allocate %d SCTP hash pointer bytes\n", + Pn, (int)(INOBUCKS * sizeof(struct sctpsin *))); + Exit(1); + } + } +/* + * Open the /proc/net/sctp files, assign a page size buffer to the streams, + * and read them. Store SCTP socket info in the SCTPsin[] hash buckets. + */ + for (i = 0; i < NSCTPPATHS; i++ ) { + if (!(ss = open_proc_stream(SCTPPath[i], "r", &vbuf, &vsz, 0))) + continue; + fl = 1; + while (fgets(buf, sizeof(buf) - 1, ss)) { + if ((nf = get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0)) + < (i ? 9 : 16) + ) { + continue; + } + if (fl) { + + /* + * Check the column labels in the first line. + */ + err = 0; + switch (i) { + case 0: + if (!fp[0] || strcmp(fp[0], "ASSOC") + || !fp[6] || strcmp(fp[6], "ASSOC-ID") + || !fp[10] || strcmp(fp[10], "INODE") + || !fp[11] || strcmp(fp[11], "LPORT") + || !fp[12] || strcmp(fp[12], "RPORT") + || !fp[13] || strcmp(fp[13], "LADDRS") + || !fp[14] || strcmp(fp[14], "<->") + || !fp[15] || strcmp(fp[15], "RADDRS") + ) { + err = 1; + } + break; + case 1: + if (!fp[0] || strcmp(fp[0], "ENDPT") + || !fp[5] || strcmp(fp[5], "LPORT") + || !fp[7] || strcmp(fp[7], "INODE") + || !fp[8] || strcmp(fp[8], "LADDRS") + ) { + err = 1; + } + } + if (err) { + if (!Fwarn) + (void) fprintf(stderr, + "%s: WARNING: unsupported format: %s\n", + Pn, SCTPPath[i]); + break; + } + fl = 0; + continue; + } + /* + * Assemble the inode number and see if it has already been + * recorded. + */ + ep = (char *)NULL; + j = i ? 7 : 10; + if (!fp[j] || !*fp[j] + || (inode = strtoull(fp[j], &ep, 0)) == ULONG_MAX + || !ep || *ep) + continue; + h = INOHASH((INODETYPE)inode); + for (sp = SCTPsin[h]; sp; sp = sp->next) { + if (inode == sp->inode) + break; + } + /* + * Set the entry type. + */ + if (sp) + ty = (sp->type == i) ? i : 3; + else + ty = i; + /* + * Allocate space for this line's sctpsin members. + * + * The association or endpoint address is in the first field. + */ + a = sp ? sp->addr : (char *)NULL; + if (fp[0] && *fp[0] && (len = strlen(fp[0]))) { + if (a) { + if (isainb(fp[0], a)) { + plen = strlen(a); + a = (char *)realloc((MALLOC_P *)a, plen + len + 2); + d = 0; + } else + d = 1; + } else { + plen = (MALLOC_S)0; + a = (char *)malloc(len + 1); + d = 0; + } + if (!a) { + (void) fprintf(stderr, + "%s: can't allocate %d SCTP ASSOC bytes: %s\n", + Pn, (int)(len + 1), fp[0]); + Exit(1); + } + if (!d) { + if (plen) + (void) snpf((a + plen), len + 2, ",%s", fp[0]); + else + (void) snpf(a, len + 1, "%s", fp[0]); + } + } + /* + * The association ID is in the seventh field. + */ + id = sp ? sp->assocID : (char *)NULL; + if (!i && fp[6] && *fp[6] && (len = strlen(fp[6]))) { + if (id) { + if (isainb(fp[6], id)) { + plen = strlen(id); + id = (char *)realloc((MALLOC_P *)id,plen+len+2); + d = 0; + } else + d = 1; + } else { + plen = (MALLOC_S)0; + id = (char *)malloc(len + 1); + d = 0; + } + if (!id) { + (void) fprintf(stderr, + "%s: can't allocate %d SCTP ASSOC-ID bytes: %s\n", + Pn, (int)(len + 1), fp[6]); + Exit(1); + } + if (!d) { + if (plen) + (void) snpf((id + plen), len + 2, ",%s", fp[6]); + else + (void) snpf(id, len + 1, "%s", fp[6]); + } + } + /* + * The field number for the local port depends on the entry type. + */ + j = i ? 5 : 11; + lp = sp ? sp->lport : (char *)NULL; + if (fp[j] && *fp[j] && (len = strlen(fp[j]))) { + if (lp) { + if (isainb(fp[j], lp)) { + plen = strlen(lp); + lp = (char *)realloc((MALLOC_P *)lp,plen+len+2); + d = 0; + } else + d = 1; + } else { + plen = (MALLOC_S)0; + lp = (char *)malloc(len + 1); + d = 0; + } + if (!lp) { + (void) fprintf(stderr, + "%s: can't allocate %d SCTP LPORT bytes: %s\n", + Pn, (int)(len + 1), fp[j]); + Exit(1); + } + if (!d) { + if (plen) + (void) snpf((lp + plen), len + 2, ",%s", fp[j]); + else + (void) snpf(lp, len + 1, "%s", fp[j]); + } + } + /* + * The field number for the remote port depends on the entry type. + */ + rp = sp ? sp->rport : (char *)NULL; + if (!i && fp[12] && *fp[12] && (len = strlen(fp[12]))) { + if (rp) { + if (isainb(fp[12], rp)) { + plen = strlen(rp); + rp = (char *)realloc((MALLOC_P *)rp,plen+len+2); + d = 0; + } else + d = 1; + } else { + plen = (MALLOC_S)0; + rp = (char *)malloc(len + 1); + d = 0; + } + if (!rp) { + (void) fprintf(stderr, + "%s: can't allocate %d SCTP RPORT bytes: %s\n", + Pn, (int)(len + 1), fp[12]); + Exit(1); + } + if (!d) { + if (plen) + (void) snpf((rp + plen), len + 2, ",%s", fp[12]); + else + (void) snpf(rp, len + 1, "%s", fp[12]); + } + } + /* + * The local addresses begin in a field whose number depends on + * the entry type. + */ + j = i ? 8 : 13; + la = sp ? sp->laddrs : (char *)NULL; + if (fp[j] && *fp[j] && (len = strlen(fp[j]))) { + if (!(ta = get_sctpaddrs(fp, j, nf, &x))) { + (void) fprintf(stderr, + "%s: can't allocate %d SCTP LADDRS bytes\n", + Pn, (int)len); + Exit(1); + } + if (la) { + if (isainb(ta, la)) { + len = strlen(ta); + plen = strlen(la); + if (!(la=(char *)realloc((MALLOC_P *)la,plen+len+2)) + ) { + (void) fprintf(stderr, + "%s: can't reallocate %d SCTP LADDRS bytes\n", + Pn, (int)len); + Exit(1); + } + (void) snpf(la + plen, len + 2, ",%s", ta); + (void) free((FREE_P *)ta); + } + } else + la = ta; + } + /* + * The remote addresses begin after the local addresses, but only + * for the ASSOC type. + */ + ra = sp ? sp->raddrs : (char *)NULL; + if (!i && x && fp[x+1] && *fp[x+1] && (len = strlen(fp[x+1]))) { + if (!(ta = get_sctpaddrs(fp, x + 1, nf, &x))) { + (void) fprintf(stderr, + "%s: can't allocate %d SCTP RADDRS bytes\n", + Pn, (int)len); + Exit(1); + } + if (ra) { + if (isainb(ta, ra)) { + len = strlen(ta); + plen = strlen(ra); + if (!(ra=(char *)realloc((MALLOC_P *)ra,plen+len+2)) + ) { + (void) fprintf(stderr, + "%s: can't reallocate %d SCTP RADDRS bytes\n", + Pn, (int)len); + Exit(1); + } + (void) snpf(ra + plen, len + 2, ",%s", ta); + (void) free((FREE_P *)ta); + } + } else + ra = ta; + } + /* + * If no matching sctpsin entry was found for this inode, allocate + * space for a new sctpsin entry, fill it, and link it to its hash + * bucket. Update a matching entry. + */ + if (!sp) { + if (!(sp = (struct sctpsin *)malloc(sizeof(struct sctpsin))) ) { + (void) fprintf(stderr, + "%s: can't allocate %d byte sctpsin structure\n", + Pn, (int)sizeof(struct sctpsin)); + Exit(1); + } + sp->inode = inode; + sp->next = SCTPsin[h]; + SCTPsin[h] = sp; + } + sp->addr = a; + sp->assocID = id; + sp->lport = lp; + sp->rport = rp; + sp->laddrs = la; + sp->raddrs = ra; + sp->type = ty; + } + (void) fclose(ss); + } +} + + +static char * +get_sctpaddrs(fp, i, nf, x) + char **fp; /* field pointers */ + int i; /* first address field index in fp */ + int nf; /* number of fields */ + int *x; /* index of first "<->" field entry */ +{ + MALLOC_S al = (MALLOC_S)0; + char *cp = (char *)NULL; + MALLOC_S tl; + + *x = 0; + do { + if ((i >= nf) || !fp[i] || !*fp[i] || !(tl = strlen(fp[i]))) + break; + if (!strcmp(fp[i], "<->")) { + *x = i; + break; + } + if (!strchr(fp[i], (int)'.') && !strchr(fp[i], (int)':')) + break; + if (cp) + cp = (char *)realloc((MALLOC_P *)cp, al + tl + 1); + else + cp = (char *)malloc(al + tl + 1); + if (!cp) + break; + if (al) + *(cp + al - 1) = ','; + (void) strncpy(al ? (cp + al) : cp, fp[i], tl); + al += (tl + 1); + *(cp + al - 1) = '\0'; + } while (++i < nf); + return(cp); +} + + +/* + * get_tcpudp() - get IPv4 TCP, UDP or UDPLITE net info + */ + +static void +get_tcpudp(p, pr, clr) + char *p; /* /proc/net/{tcp,udp} path */ + int pr; /* protocol: 0 = TCP, 1 = UDP, + * 2 = UDPLITE */ + int clr; /* 1 == clear the table */ +{ + char buf[MAXPATHLEN], *ep, **fp; + unsigned long faddr, fport, laddr, lport, rxq, state, txq; + FILE *fs; + int h, nf; + INODETYPE inode; + struct tcp_udp *np, *tp; + static char *vbuf = (char *)NULL; + static size_t vsz = (size_t)0; +/* + * Delete previous table contents. + */ + if (TcpUdp) { + if (clr) { + for (h = 0; h < TcpUdp_bucks; h++) { + for (tp = TcpUdp[h]; tp; tp = np) { + np = tp->next; + (void) free((FREE_P *)tp); + } + TcpUdp[h] = (struct tcp_udp *)NULL; + } + } +/* + * If no hash buckets have been allocated, do so now. + */ + } else { + + /* + * Open the /proc/net/sockstat file and establish the hash bucket + * count from its "sockets: used" line. + */ + TcpUdp_bucks = INOBUCKS; + if ((fs = fopen(SockStatPath, "r"))) { + while (fgets(buf, sizeof(buf) - 1, fs)) { + if (get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0) != 3) + continue; + if (!fp[0] || strcmp(fp[0], "sockets:") + || !fp[1] || strcmp(fp[1], "used") + || !fp[2] || !*fp[2]) + continue; + if ((h = atoi(fp[2])) < 1) + h = INOBUCKS; + while (TcpUdp_bucks < h) + TcpUdp_bucks *= 2; + break; + } + (void) fclose(fs); + } + if (!(TcpUdp = (struct tcp_udp **)calloc(TcpUdp_bucks, + sizeof(struct tcp_udp *)))) + { + (void) fprintf(stderr, + "%s: can't allocate %d bytes for TCP&UDP hash buckets\n", + Pn, (int)(TcpUdp_bucks * sizeof(struct tcp_udp *))); + Exit(1); + } + } +/* + * Open the /proc/net file, assign a page size buffer to the stream, and + * read it. + */ + if (!(fs = open_proc_stream(p, "r", &vbuf, &vsz, 0))) + return; + nf = 12; + while (fgets(buf, sizeof(buf) - 1, fs)) { + if (get_fields(buf, + (nf == 12) ? (char *)NULL : ":", + &fp, (int *)NULL, 0) + < nf) + continue; + if (nf == 12) { + if (!fp[1] || strcmp(fp[1], "local_address") + || !fp[2] || strcmp(fp[2], "rem_address") + || !fp[3] || strcmp(fp[3], "st") + || !fp[4] || strcmp(fp[4], "tx_queue") + || !fp[5] || strcmp(fp[5], "rx_queue") + || !fp[11] || strcmp(fp[11], "inode")) + { + if (!Fwarn) { + (void) fprintf(stderr, + "%s: WARNING: unsupported format: %s\n", + Pn, p); + } + break; + } + nf = 14; + continue; + } + /* + * Get the local and remote addresses. + */ + ep = (char *)NULL; + if (!fp[1] || !*fp[1] + || (laddr = strtoul(fp[1], &ep, 16)) == ULONG_MAX || !ep || *ep) + continue; + ep = (char *)NULL; + if (!fp[2] || !*fp[2] + || (lport = strtoul(fp[2], &ep, 16)) == ULONG_MAX || !ep || *ep) + continue; + ep = (char *)NULL; + if (!fp[3] || !*fp[3] + || (faddr = strtoul(fp[3], &ep, 16)) == ULONG_MAX || !ep || *ep) + continue; + ep = (char *)NULL; + if (!fp[4] || !*fp[4] + || (fport = strtoul(fp[4], &ep, 16)) == ULONG_MAX || !ep || *ep) + continue; + /* + * Get the state and queue sizes. + */ + ep = (char *)NULL; + if (!fp[5] || !*fp[5] + || (state = strtoul(fp[5], &ep, 16)) == ULONG_MAX || !ep || *ep) + continue; + ep = (char *)NULL; + if (!fp[6] || !*fp[6] + || (txq = strtoul(fp[6], &ep, 16)) == ULONG_MAX || !ep || *ep) + continue; + ep = (char *)NULL; + if (!fp[7] || !*fp[7] + || (rxq = strtoul(fp[7], &ep, 16)) == ULONG_MAX || !ep || *ep) + continue; + /* + * Get the inode and use it for hashing and searching. + */ + ep = (char *)NULL; + if (!fp[13] || !*fp[13] + || (inode = strtoull(fp[13], &ep, 0)) == ULONG_MAX || !ep || *ep) + continue; + h = TCPUDPHASH(inode); + for (tp = TcpUdp[h]; tp; tp = tp->next) { + if (tp->inode == inode) + break; + } + if (tp) + continue; + /* + * Create a new entry and link it to its hash bucket. + */ + if (!(tp = (struct tcp_udp *)malloc(sizeof(struct tcp_udp)))) { + (void) fprintf(stderr, + "%s: can't allocate %d bytes for tcp_udp struct\n", + Pn, (int)sizeof(struct tcp_udp)); + Exit(1); + } + tp->inode = inode; + tp->faddr = faddr; + tp->fport = (int)(fport & 0xffff); + tp->laddr = laddr; + tp->lport = (int)(lport & 0xffff); + tp->txq = txq; + tp->rxq = rxq; + tp->proto = pr; + tp->state = (int)state; + tp->next = TcpUdp[h]; + TcpUdp[h] = tp; + } + (void) fclose(fs); +} + + +#if defined(HASIPv6) +/* + * get_raw6() - get /proc/net/raw6 info + */ + +static void +get_raw6(p) + char *p; /* /proc/net/raw path */ +{ + char buf[MAXPATHLEN], *ep, **fp, *la, *ra, *sp; + int h; + INODETYPE inode; + int nf = 12; + struct rawsin *np, *rp; + MALLOC_S lal, ral, spl; + static char *vbuf = (char *)NULL; + static size_t vsz = (size_t)0; + FILE *xs; +/* + * Do second time cleanup or first time setup. + */ + if (Rawsin6) { + for (h = 0; h < INOBUCKS; h++) { + for (rp = Rawsin6[h]; rp; rp = np) { + np = rp->next; + if (rp->la) + (void) free((FREE_P *)rp->la); + if (rp->ra) + (void) free((FREE_P *)rp->ra); + 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 *))); + Exit(1); + } + } +/* + * Open the /proc/net/raw6 file, assign a page size buffer to the stream, + * and read it. Store raw6 socket info in the Rawsin6[] hash buckets. + */ + if (!(xs = open_proc_stream(p, "r", &vbuf, &vsz, 0))) + return; + while (fgets(buf, sizeof(buf) - 1, xs)) { + if (get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0) < nf) + continue; + if (nf == 12) { + + /* + * Check the column labels in the first line. + */ + if (!fp[1] || strcmp(fp[1], "local_address") + || !fp[2] || strcmp(fp[2], "remote_address") + || !fp[3] || strcmp(fp[3], "st") + || !fp[11] || strcmp(fp[11], "inode")) + { + if (!Fwarn) { + (void) fprintf(stderr, + "%s: WARNING: unsupported format: %s\n", + Pn, p); + } + break; + } + nf = 10; + continue; + } + /* + * Assemble the inode number and see if the inode is already + * recorded. + */ + ep = (char *)NULL; + if (!fp[9] || !*fp[9] + || (inode = strtoull(fp[9], &ep, 0)) == ULONG_MAX + || !ep || *ep) + continue; + h = INOHASH(inode); + for (rp = Rawsin6[h]; rp; rp = rp->next) { + if (inode == rp->inode) + break; + } + if (rp) + continue; + /* + * Save the local address, remote address, and state. + */ + if (!fp[1] || !*fp[1] || (lal = strlen(fp[1])) < 1) { + la = (char *)NULL; + lal = (MALLOC_S)0; + } else { + if (!(la = (char *)malloc(lal + 1))) { + (void) fprintf(stderr, + "%s: can't allocate %d local raw6 address bytes: %s\n", + Pn, (int)(lal + 1), fp[1]); + Exit(1); + } + (void) snpf(la, lal + 1, "%s", fp[1]); + } + if (!fp[2] || !*fp[2] || (ral = strlen(fp[2])) < 1) { + ra = (char *)NULL; + ral = (MALLOC_S)0; + } else { + if (!(ra = (char *)malloc(ral + 1))) { + (void) fprintf(stderr, + "%s: can't allocate %d remote raw6 address bytes: %s\n", + Pn, (int)(ral + 1), fp[2]); + Exit(1); + } + (void) snpf(ra, ral + 1, "%s", fp[2]); + } + if (!fp[3] || !*fp[3] || (spl = strlen(fp[3])) < 1) { + sp = (char *)NULL; + spl = (MALLOC_S)0; + } else { + if (!(sp = (char *)malloc(spl + 1))) { + (void) fprintf(stderr, + "%s: can't allocate %d remote raw6 state bytes: %s\n", + Pn, (int)(spl + 1), fp[2]); + Exit(1); + } + (void) snpf(sp, spl + 1, "%s", fp[3]); + } + /* + * Allocate space for an rawsin entry, fill it, and link it to its + * hash bucket. + */ + if (!(rp = (struct rawsin *)malloc(sizeof(struct rawsin)))) { + (void) fprintf(stderr, + "%s: can't allocate %d byte rawsin structure for IPv6\n", + Pn, (int)sizeof(struct rawsin)); + Exit(1); + } + rp->inode = inode; + rp->la = la; + rp->lal = lal; + rp->ra = ra; + rp->ral = ral; + rp->sp = sp; + rp->spl = spl; + rp->next = Rawsin6[h]; + Rawsin6[h] = rp; + } + (void) fclose(xs); +} + + +/* + * get_tcpudp6() - get IPv6 TCP, UDP or UDPLITE net info + */ + +static void +get_tcpudp6(p, pr, clr) + char *p; /* /proc/net/{tcp,udp} path */ + int pr; /* protocol: 0 = TCP, 1 = UDP */ + int clr; /* 1 == clear the table */ +{ + char buf[MAXPATHLEN], *ep, **fp; + struct in6_addr faddr, laddr; + unsigned long fport, lport, rxq, state, txq; + FILE *fs; + int h, i, nf; + INODETYPE inode; + struct tcp_udp6 *np6, *tp6; + static char *vbuf = (char *)NULL; + static size_t vsz = (size_t)0; +/* + * Delete previous table contents. Allocate a table for the first time. + */ + if (TcpUdp6) { + if (clr) { + for (h = 0; h < TcpUdp6_bucks; h++) { + for (tp6 = TcpUdp6[h]; tp6; tp6 = np6) { + np6 = tp6->next; + (void) free((FREE_P *)tp6); + } + TcpUdp6[h] = (struct tcp_udp6 *)NULL; + } + } + } else { + + /* + * Open the /proc/net/sockstat6 file and establish the hash bucket + * count from its "TCP6: inuse" and "UDP6: inuse" lines. + */ + TcpUdp6_bucks = INOBUCKS; + h = i = nf = 0; + if ((fs = fopen(SockStatPath6, "r"))) { + while (fgets(buf, sizeof(buf) - 1, fs)) { + if (get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0) != 3) + continue; + if (!fp[0] + || !fp[1] || strcmp(fp[1], "inuse") + || !fp[2] || !*fp[2]) + continue; + if (!strcmp(fp[0], "TCP6:")) { + nf |= 1; + if ((h = atoi(fp[2])) < 1) + h = INOBUCKS; + i += h; + } else if (!strcmp(fp[0], "UDP6:")) { + nf |= 2; + if ((h = atoi(fp[2])) < 1) + h = INOBUCKS; + i += h; + } else + continue; + if (nf == 3) { + while (TcpUdp6_bucks < i) + TcpUdp6_bucks *= 2; + break; + } + } + (void) fclose(fs); + } + if (!(TcpUdp6 = (struct tcp_udp6 **)calloc(TcpUdp6_bucks, + sizeof(struct tcp_udp6 *)))) + { + (void) fprintf(stderr, + "%s: can't allocate %d bytes for TCP6&UDP6 hash buckets\n", + Pn, (int)(TcpUdp6_bucks * sizeof(struct tcp_udp6 *))); + Exit(1); + } + } +/* + * Open the /proc/net file, assign a page size buffer to the stream, + * and read it. + */ + if (!(fs = open_proc_stream(p, "r", &vbuf, &vsz, 0))) + return; + nf = 12; + while (fgets(buf, sizeof(buf) - 1, fs)) { + if (get_fields(buf, + (nf == 12) ? (char *)NULL : ":", + &fp, (int *)NULL, 0) + < nf) + continue; + if (nf == 12) { + if (!fp[1] || strcmp(fp[1], "local_address") + || !fp[2] || strcmp(fp[2], "remote_address") + || !fp[3] || strcmp(fp[3], "st") + || !fp[4] || strcmp(fp[4], "tx_queue") + || !fp[5] || strcmp(fp[5], "rx_queue") + || !fp[11] || strcmp(fp[11], "inode")) + { + if (!Fwarn) { + (void) fprintf(stderr, + "%s: WARNING: unsupported format: %s\n", + Pn, p); + } + break; + } + nf = 14; + continue; + } + /* + * Get the local and remote addresses. + */ + if (!fp[1] || !*fp[1] || net6a2in6(fp[1], &laddr)) + continue; + ep = (char *)NULL; + if (!fp[2] || !*fp[2] + || (lport = strtoul(fp[2], &ep, 16)) == ULONG_MAX || !ep || *ep) + continue; + if (!fp[3] || !*fp[3] || net6a2in6(fp[3], &faddr)) + continue; + ep = (char *)NULL; + if (!fp[4] || !*fp[4] + || (fport = strtoul(fp[4], &ep, 16)) == ULONG_MAX || !ep || *ep) + continue; + /* + * Get the state and queue sizes. + */ + ep = (char *)NULL; + if (!fp[5] || !*fp[5] + || (state = strtoul(fp[5], &ep, 16)) == ULONG_MAX || !ep || *ep) + continue; + ep = (char *)NULL; + if (!fp[6] || !*fp[6] + || (txq = strtoul(fp[6], &ep, 16)) == ULONG_MAX || !ep || *ep) + continue; + ep = (char *)NULL; + if (!fp[7] || !*fp[7] + || (rxq = strtoul(fp[7], &ep, 16)) == ULONG_MAX || !ep || *ep) + continue; + /* + * Get the inode and use it for hashing and searching. + */ + ep = (char *)NULL; + if (!fp[13] || !*fp[13] + || (inode = strtoull(fp[13], &ep, 0)) == ULONG_MAX || !ep || *ep) + continue; + h = TCPUDP6HASH(inode); + for (tp6 = TcpUdp6[h]; tp6; tp6 = tp6->next) { + if (tp6->inode == inode) + break; + } + if (tp6) + continue; + /* + * Create a new entry and link it to its hash bucket. + */ + if (!(tp6 = (struct tcp_udp6 *)malloc(sizeof(struct tcp_udp6)))) { + (void) fprintf(stderr, + "%s: can't allocate %d bytes for tcp_udp6 struct\n", + Pn, (int)sizeof(struct tcp_udp6)); + Exit(1); + } + tp6->inode = inode; + tp6->faddr = faddr; + tp6->fport = (int)(fport & 0xffff); + tp6->laddr = laddr; + tp6->lport = (int)(lport & 0xffff); + tp6->txq = txq; + tp6->rxq = rxq; + tp6->proto = pr; + tp6->state = (int)state; + tp6->next = TcpUdp6[h]; + TcpUdp6[h] = tp6; + } + (void) fclose(fs); +} +#endif /* defined(HASIPv6) */ + + +/* + * get_unix() - get UNIX net info + */ + +static void +get_unix(p) + char *p; /* /proc/net/unix path */ +{ + char buf[MAXPATHLEN], *ep, **fp, *path, *pcb; + int fl = 1; + int h, nf; + INODETYPE inode; + MALLOC_S len; + 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 *))); + } + } +/* + * Open the /proc/net/unix file, assign a page size buffer to the stream, + * read the file's contents, and add them to the Uxsin hash buckets. + */ + if (!(us = open_proc_stream(p, "r", &vbuf, &vsz, 0))) + return; + while (fgets(buf, sizeof(buf) - 1, us)) { + if ((nf = get_fields(buf, ":", &fp, (int *)NULL, 0)) < 7) + continue; + if (fl) { + + /* + * Check the first line for header words. + */ + if (!fp[0] || strcmp(fp[0], "Num") + || !fp[1] || strcmp(fp[1], "RefCount") + || !fp[2] || strcmp(fp[2], "Protocol") + || !fp[3] || strcmp(fp[3], "Flags") + || !fp[4] || strcmp(fp[4], "Type") + || !fp[5] || strcmp(fp[5], "St") + || !fp[6] || strcmp(fp[6], "Inode") + || nf < 8 + || !fp[7] || strcmp(fp[7], "Path")) + { + if (!Fwarn) { + (void) fprintf(stderr, + "%s: WARNING: unsupported format: %s\n", + Pn, p); + } + break; + } + fl = 0; + continue; + } + /* + * Assemble PCB address, inode number, and path name. If this + * inode is already represented in Uxsin, skip it. + */ + ep = (char *)NULL; + if (!fp[6] || !*fp[6] + || (inode = strtoull(fp[6], &ep, 0)) == ULONG_MAX || !ep || *ep) + continue; + h = INOHASH(inode); + for (up = Uxsin[h]; up; up = up->next) { + if (inode == up->inode) + break; + } + if (up) + continue; + if (!fp[0] || !*fp[0]) + pcb = (char *)NULL; + else { + len = strlen(fp[0]) + 2; + if (!(pcb = (char *)malloc(len + 1))) { + (void) fprintf(stderr, + "%s: can't allocate %d bytes for UNIX PCB: %s\n", + Pn, (int)(len + 1), fp[0]); + Exit(1); + } + (void) snpf(pcb, len + 1, "0x%s", fp[0]); + } + if (nf >= 8 && fp[7] && *fp[7] && (len = strlen(fp[7]))) { + if (!(path = (char *)malloc(len + 1))) { + (void) fprintf(stderr, + "%s: can't allocate %d bytes for UNIX path \"%s\"\n", + Pn, (int)(len + 1), fp[7]); + Exit(1); + } + (void) snpf(path, len + 1, "%s", fp[7]); + } else + path = (char *)NULL; + /* + * 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; + } + /* + * 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)); + Exit(1); + } + up->inode = inode; + up->next = (uxsin_t *)NULL; + up->pcb = pcb; + up->sb_def = 0; + up->ty = ty; + if ((up->path = path) && (*path == '/')) { + + /* + * If an absolute path (i.e., one that begins with a '/') exists + * for the line, attempt to stat(2) it and save the device and + * node numbers reported in the stat buffer. + */ + struct stat sb; + int sr; + + if (HasNFS) + sr = statsafely(path, &sb); + else + sr = stat(path, &sb); + if (sr && ((sb.st_mode & S_IFMT) == S_IFSOCK)) { + up->sb_def = 1; + up->sb_dev = sb.st_dev; + up->sb_ino = (INODETYPE)sb.st_ino; + up->sb_rdev = sb.st_rdev; + } + } + +#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) */ + + up->next = Uxsin[h]; + Uxsin[h] = up; + } + +#if defined(HASEPTOPTS) && defined(HASUXSOCKEPT) +/* + * If endpoint info has been requested, get UNIX socket peer info. + */ + if (FeptE) + get_uxpeeri(); +#endif /* defined(HASEPTOPTS) && defined(HASUXSOCKEPT) */ + + (void) fclose(us); +} + + +#if defined(HASIPv6) +/* + * net6a2in6() - convert ASCII IPv6 address in /proc/net/{tcp,udp} form to + * an in6_addr + */ + +static int +net6a2in6(as, ad) + char *as; /* address source */ + struct in6_addr *ad; /* address destination */ +{ + char buf[9], *ep; + int i; + size_t len; +/* + * Assemble four uint32_t's from 4 X 8 hex digits into s6_addr32[]. + */ + for (i = 0, len = strlen(as); + (i < 4) && (len >= 8); + as += 8, i++, len -= 8) + { + (void) strncpy(buf, as, 8); + buf[8] = '\0'; + ep = (char *)NULL; + if ((ad->s6_addr32[i] = (uint32_t)strtoul(buf, &ep, 16)) + == (uint32_t)UINT32_MAX || !ep || *ep) + break; + } + return((*as || (i != 4) || len) ? 1 : 0); +} +#endif /* defined(HASIPv6) */ + + +/* + * isainb(a,b) is string a in string b + */ + +static int +isainb(a, b) + char *a; /*string a */ + char *b; /* string b */ +{ + char *cp, *pp; + MALLOC_S la, lb, lt; + + if (!a || !b) + return(1); + if (!(la = strlen(a)) || !(lb = strlen(b))) + return(1); + if (!(cp = strchr(b, (int)','))) { + if (la != lb) + return(1); + return(strcmp(a, b)); + } + for (pp = b; pp && *pp; ) { + lt = (MALLOC_S)(cp - pp); + if ((la == lt) && !strncmp(a, pp, lt)) + return(0); + if (*cp) { + pp = cp + 1; + if (!(cp = strchr(pp, (int)','))) + cp = b + lb; + } else + pp = cp; + } + return(1); +} + + +/* + * print_ax25info() - print AX25 socket info + */ + +static void +print_ax25info(ap) + struct ax25sin *ap; /* AX25 socket info */ +{ + char *cp, pbuf[1024]; + int ds; + MALLOC_S pl = (MALLOC_S)0; + + if (Lf->nma) + return; + if (ap->sa) { + ds = (ap->da && strcmp(ap->da, "*")) ? 1 : 0; + (void) snpf(&pbuf[pl], sizeof(pbuf) - pl, "%s%s%s ", ap->sa, + ds ? "->" : "", + ds ? ap->da : ""); + pl = strlen(pbuf); + } + if (ap->sqs) { + (void) snpf(&pbuf[pl], sizeof(pbuf) - pl, "(Sq=%lu ", ap->sq); + pl = strlen(pbuf); + cp = ""; + } else + cp = "("; + if (ap->rqs) { + (void) snpf(&pbuf[pl], sizeof(pbuf) - pl, "%sRq=%lu ", cp, ap->rq); + pl = strlen(pbuf); + cp = ""; + } + (void) snpf(&pbuf[pl], sizeof(pbuf) - pl, "%sState=%d", cp, ap->state); + pl = strlen(pbuf); + if ((ap->state >= 0) && (ap->state < NAX25ST)) + cp = ax25st[ap->state]; + else + cp = NULL; + (void) snpf(&pbuf[pl], sizeof(pbuf) - pl, "%s%s)", + cp ? ", " : "", + cp ? cp : ""); + pl = strlen(pbuf); + if (!(cp = (char *)malloc(pl + 1))) { + (void) fprintf(stderr, + "%s: can't allocate %d bytes for AX25 sock state, PID: %d\n", + Pn, (int)(pl + 1), Lp->pid); + Exit(1); + } + (void) snpf(cp, pl + 1, "%s", pbuf); + Lf->nma = cp; +} + + +/* + * print_ipxinfo() - print IPX socket info + */ + +static void +print_ipxinfo(ip) + struct ipxsin *ip; /* IPX socket info */ +{ + char *cp, pbuf[256]; + MALLOC_S pl; + + if (Lf->nma) + return; + (void) snpf(pbuf, sizeof(pbuf), "(Tx=%lx Rx=%lx State=%02x)", + ip->txq, ip->rxq, ip->state); + pl = strlen(pbuf); + if (!(cp = (char *)malloc(pl + 1))) { + (void) fprintf(stderr, + "%s: can't allocate %d bytes for IPX sock state, PID: %d\n", + Pn, (int)(pl + 1), Lp->pid); + Exit(1); + } + (void) snpf(cp, pl + 1, "%s", pbuf); + Lf->nma = cp; +} + + +/* + * print_tcptpi() - print TCP/TPI state + */ + +void +print_tcptpi(nl) + int nl; /* 1 == '\n' required */ +{ + char buf[128]; + char *cp = (char *)NULL; + int ps = 0; + int s; + + if ((Ftcptpi & TCPTPI_STATE) && Lf->lts.type == 0) { + if (!TcpSt) + (void) build_IPstates(); + if ((s = Lf->lts.state.i + TcpStOff) < 0 || s >= TcpNstates) { + (void) snpf(buf, sizeof(buf), "UNKNOWN_TCP_STATE_%d", + Lf->lts.state.i); + cp = buf; + } else + cp = TcpSt[s]; + if (cp) { + if (Ffield) + (void) printf("%cST=%s%c", LSOF_FID_TCPTPI, cp, Terminator); + else { + putchar('('); + (void) fputs(cp, stdout); + } + ps++; + } + } + +# if defined(HASTCPTPIQ) + if (Ftcptpi & TCPTPI_QUEUES) { + if (Lf->lts.rqs) { + if (Ffield) + putchar(LSOF_FID_TCPTPI); + else { + if (ps) + putchar(' '); + else + putchar('('); + } + (void) printf("QR=%lu", Lf->lts.rq); + if (Ffield) + putchar(Terminator); + ps++; + } + if (Lf->lts.sqs) { + if (Ffield) + putchar(LSOF_FID_TCPTPI); + else { + if (ps) + putchar(' '); + else + putchar('('); + } + (void) printf("QS=%lu", Lf->lts.sq); + if (Ffield) + putchar(Terminator); + ps++; + } + } +# endif /* defined(HASTCPTPIQ) */ + +# if defined(HASTCPTPIW) + if (Ftcptpi & TCPTPI_WINDOWS) { + if (Lf->lts.rws) { + if (Ffield) + putchar(LSOF_FID_TCPTPI); + else { + if (ps) + putchar(' '); + else + putchar('('); + } + (void) printf("WR=%lu", Lf->lts.rw); + if (Ffield) + putchar(Terminator); + ps++; + } + if (Lf->lts.wws) { + if (Ffield) + putchar(LSOF_FID_TCPTPI); + else { + if (ps) + putchar(' '); + else + putchar('('); + } + (void) printf("WW=%lu", Lf->lts.ww); + if (Ffield) + putchar(Terminator); + ps++; + } + } +# endif /* defined(HASTCPTPIW) */ + + if (!Ffield && ps) + putchar(')'); + if (nl) + putchar('\n'); +} + + +/* + * process_proc_sock() - process /proc-based socket + */ + +void +process_proc_sock(p, pbr, s, ss, l, lss) + char *p; /* node's readlink() path */ + char *pbr; /* node's path before readlink() */ + struct stat *s; /* stat() result for path */ + int ss; /* *s status -- i.e, SB_* values */ + struct stat *l; /* lstat() result for FD (NULL for + * others) */ + int lss; /* *l status -- i.e, SB_* values */ +{ + struct ax25sin *ap; + char *cp, *path = (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 (Foffset || !Fsize) { + if (l && (lss & SB_SIZE) && OffType) { + Lf->off = (SZOFFTYPE)l->st_size; + Lf->off_def = 1; + } + } +/* + * Check for socket's inode presence in the protocol info caches. + */ + if (AX25path) { + (void) get_ax25(AX25path); + (void) free((FREE_P *)AX25path); + AX25path = (char *)NULL; + } + if ((ss & SB_INO) + && (ap = check_ax25((INODETYPE)s->st_ino)) + ) { + + /* + * The inode is connected to an AX25 /proc record. + * + * Set the type to "ax25"; save the device name; save the inode number; + * save the destination and source addresses; save the send and receive + * queue sizes; and save the connection state. + */ + (void) snpf(Lf->type, sizeof(Lf->type), "ax25"); + if (ap->dev_ch) + (void) enter_dev_ch(ap->dev_ch); + Lf->inode = ap->inode; + Lf->inp_ty = 1; + print_ax25info(ap); + return; + } + if (Ipxpath) { + (void) get_ipx(Ipxpath); + (void) free((FREE_P *)Ipxpath); + Ipxpath = (char *)NULL; + } + if ((ss & SB_INO) + && (ip = check_ipx((INODETYPE)s->st_ino)) + ) { + + /* + * The inode is connected to an IPX /proc record. + * + * Set the type to "ipx"; enter the inode and device numbers; store + * the addresses, queue sizes, and state in the NAME column. + */ + (void) snpf(Lf->type, sizeof(Lf->type), "ipx"); + if (ss & SB_INO) { + Lf->inode = (INODETYPE)s->st_ino; + Lf->inp_ty = 1; + } + if (ss & SB_DEV) { + Lf->dev = s->st_dev; + Lf->dev_def = 1; + } + cp = Namech; + nl = Namechl; + *cp = '\0'; + if (ip->la && nl) { + + /* + * Store the local IPX address. + */ + len = strlen(ip->la); + if (len > nl) + len = nl; + (void) strncpy(cp, ip->la, len); + cp += len; + *cp = '\0'; + nl -= len; + } + if (ip->ra && nl) { + + /* + * Store the remote IPX address, prefixed with "->". + */ + if (nl > 2) { + (void) snpf(cp, nl, "->"); + cp += 2; + nl -= 2; + } + if (nl) { + (void) snpf(cp, nl, "%s", ip->ra); + cp += len; + nl -= len; + } + } + (void) print_ipxinfo(ip); + if (Namech[0]) + enter_nm(Namech); + return; + } + if (Rawpath) { + (void) get_raw(Rawpath); + (void) free((FREE_P *)Rawpath); + Rawpath = (char *)NULL; + } + if ((ss & SB_INO) + && (rp = check_raw((INODETYPE)s->st_ino)) + ) { + + /* + * The inode is connected to a raw /proc record. + * + * Set the type to "raw"; enter the inode number; store the local + * address, remote address, and state in the NAME column. + */ + (void) snpf(Lf->type, sizeof(Lf->type), "raw"); + if (ss & SB_INO) { + Lf->inode = (INODETYPE)s->st_ino; + Lf->inp_ty = 1; + } + cp = Namech; + nl = Namechl - 2; + *cp = '\0'; + if (rp->la && rp->lal) { + + /* + * Store the local raw address. + */ + if (nl > rp->lal) { + (void) snpf(cp, nl, "%s", rp->la); + cp += rp->lal; + *cp = '\0'; + nl -= rp->lal; + } + } + if (rp->ra && rp->ral) { + + /* + * Store the remote raw address, prefixed with "->". + */ + if (nl > (rp->ral + 2)) { + (void) snpf(cp, nl, "->%s", rp->ra); + cp += (rp->ral + 2); + *cp = '\0'; + nl -= (rp->ral + 2); + } + } + if (rp->sp && rp->spl) { + + /* + * Store the state, optionally prefixed by a space, in the + * form "st=x...x". + */ + + if (nl > (len = ((cp == Namech) ? 0 : 1) + 3 + rp->spl)) { + (void) snpf(cp, nl, "%sst=%s", + (cp == Namech) ? "" : " ", rp->sp); + cp += len; + *cp = '\0'; + nl -= len; + } + } + if (Namech[0]) + enter_nm(Namech); + return; + } + if (Nlkpath) { + (void) get_netlink(Nlkpath); + (void) free((FREE_P *) Nlkpath); + Nlkpath = (char *)NULL; + } + if ((ss & SB_INO) + && (np = check_netlink((INODETYPE)s->st_ino)) + ) { + /* + * The inode is connected to a Netlink /proc record. + * + * Set the type to "netlink" and store the protocol in the NAME + * column. Save the inode number. + */ + + (void) snpf(Lf->type, sizeof(Lf->type), "netlink"); + switch (np->pr) { + +#if defined(NETLINK_ROUTE) + case NETLINK_ROUTE: + cp = "ROUTE"; + break; +#endif /* defined(NETLINK_ROUTE) */ + +#if defined(NETLINK_UNUSED) + case NETLINK_UNUSED: + cp = "UNUSED"; + break; +#endif /* defined(NETLINK_UNUSED) */ + +#if defined(NETLINK_USERSOCK) + case NETLINK_USERSOCK: + cp = "USERSOCK"; + break; +#endif /* defined(NETLINK_USERSOCK) */ + +#if defined(NETLINK_FIREWALL) + case NETLINK_FIREWALL: + cp = "FIREWALL"; + break; +#endif /* defined(NETLINK_FIREWALL) */ + +#if defined(NETLINK_INET_DIAG) + case NETLINK_INET_DIAG: + cp = "INET_DIAG"; + break; +#endif /* defined(NETLINK_INET_DIAG) */ + +#if defined(NETLINK_NFLOG) + case NETLINK_NFLOG: + cp = "NFLOG"; + break; +#endif /* defined(NETLINK_NFLOG) */ + +#if defined(NETLINK_XFRM) + case NETLINK_XFRM: + cp = "XFRM"; + break; +#endif /* defined(NETLINK_XFRM) */ + +#if defined(NETLINK_SELINUX) + case NETLINK_SELINUX: + cp = "SELINUX"; + break; +#endif /* defined(NETLINK_SELINUX) */ + +#if defined(NETLINK_ISCSI) + case NETLINK_ISCSI: + cp = "ISCSI"; + break; +#endif /* defined(NETLINK_ISCSI) */ + +#if defined(NETLINK_AUDIT) + case NETLINK_AUDIT: + cp = "AUDIT"; + break; +#endif /* defined(NETLINK_AUDIT) */ + +#if defined(NETLINK_FIB_LOOKUP) + case NETLINK_FIB_LOOKUP: + cp = "FIB_LOOKUP"; + break; +#endif /* defined(NETLINK_FIB_LOOKUP) */ + +#if defined(NETLINK_CONNECTOR) + case NETLINK_CONNECTOR: + cp = "CONNECTOR"; + break; +#endif /* defined(NETLINK_CONNECTOR) */ + +#if defined(NETLINK_NETFILTER) + case NETLINK_NETFILTER: + cp = "NETFILTER"; + break; +#endif /* defined(NETLINK_NETFILTER) */ + +#if defined(NETLINK_IP6_FW) + case NETLINK_IP6_FW: + cp = "IP6_FW"; + break; +#endif /* defined(NETLINK_IP6_FW) */ + +#if defined(NETLINK_DNRTMSG) + case NETLINK_DNRTMSG: + cp = "DNRTMSG"; + break; +#endif /* defined(NETLINK_DNRTMSG) */ + +#if defined(NETLINK_KOBJECT_UEVENT) + case NETLINK_KOBJECT_UEVENT: + cp = "KOBJECT_UEVENT"; + break; +#endif /* defined(NETLINK_KOBJECT_UEVENT) */ + +#if defined(NETLINK_GENERIC) + case NETLINK_GENERIC: + cp = "GENERIC"; + break; +#endif /* defined(NETLINK_GENERIC) */ + +#if defined(NETLINK_SCSITRANSPORT) + case NETLINK_SCSITRANSPORT: + cp = "SCSITRANSPORT"; + break; +#endif /* defined(NETLINK_SCSITRANSPORT) */ + +#if defined(NETLINK_ECRYPTFS) + case NETLINK_ECRYPTFS: + cp = "ECRYPTFS"; + break; +#endif /* defined(NETLINK_ECRYPTFS) */ + + default: + (void) snpf(Namech, Namechl, "unknown protocol: %d", np->pr); + cp = (char *)NULL; + } + if (cp) + (void) snpf(Namech, Namechl, "%s", cp); + Lf->inode = (INODETYPE)s->st_ino; + Lf->inp_ty = 1; + if (Namech[0]) + enter_nm(Namech); + return; + } + if (Packpath) { + (void) get_pack(Packpath); + (void) free((FREE_P *)Packpath); + Packpath = (char *)NULL; + } + if ((ss & SB_INO) + && (pp = check_pack((INODETYPE)s->st_ino)) + ) { + + /* + * The inode is connected to a packet /proc record. + * + * Set the type to "pack" and store the socket type in the NAME + * column. Put the protocol name in the NODE column and the inode + * number in the DEVICE column. + */ + (void) snpf(Lf->type, sizeof(Lf->type), "pack"); + cp = sockty2str(pp->ty, &rf); + (void) snpf(Namech, Namechl, "type=%s%s", rf ? "" : "SOCK_", cp); + switch (pp->pr) { + +#if defined(ETH_P_LOOP) + case ETH_P_LOOP: + cp = "LOOP"; + break; +#endif /* defined(ETH_P_LOOP) */ + +#if defined(ETH_P_PUP) + case ETH_P_PUP: + cp = "PUP"; + break; +#endif /* defined(ETH_P_PUP) */ + +#if defined(ETH_P_PUPAT) + case ETH_P_PUPAT: + cp = "PUPAT"; + break; +#endif /* defined(ETH_P_PUPAT) */ + +#if defined(ETH_P_IP) + case ETH_P_IP: + cp = "IP"; + break; +#endif /* defined(ETH_P_IP) */ + +#if defined(ETH_P_X25) + case ETH_P_X25: + cp = "X25"; + break; +#endif /* defined(ETH_P_X25) */ + +#if defined(ETH_P_ARP) + case ETH_P_ARP: + cp = "ARP"; + break; +#endif /* defined(ETH_P_ARP) */ + +#if defined(ETH_P_BPQ) + case ETH_P_BPQ: + cp = "BPQ"; + break; +#endif /* defined(ETH_P_BPQ) */ + +#if defined(ETH_P_IEEEPUP) + case ETH_P_IEEEPUP: + cp = "I3EPUP"; + break; +#endif /* defined(ETH_P_IEEEPUP) */ + +#if defined(ETH_P_IEEEPUPAT) + case ETH_P_IEEEPUPAT: + cp = "I3EPUPA"; + break; +#endif /* defined(ETH_P_IEEEPUPAT) */ + +#if defined(ETH_P_DEC) + case ETH_P_DEC: + cp = "DEC"; + break; +#endif /* defined(ETH_P_DEC) */ + +#if defined(ETH_P_DNA_DL) + case ETH_P_DNA_DL: + cp = "DNA_DL"; + break; +#endif /* defined(ETH_P_DNA_DL) */ + +#if defined(ETH_P_DNA_RC) + case ETH_P_DNA_RC: + cp = "DNA_RC"; + break; +#endif /* defined(ETH_P_DNA_RC) */ + +#if defined(ETH_P_DNA_RT) + case ETH_P_DNA_RT: + cp = "DNA_RT"; + break; +#endif /* defined(ETH_P_DNA_RT) */ + +#if defined(ETH_P_LAT) + case ETH_P_LAT: + cp = "LAT"; + break; +#endif /* defined(ETH_P_LAT) */ + +#if defined(ETH_P_DIAG) + case ETH_P_DIAG: + cp = "DIAG"; + break; +#endif /* defined(ETH_P_DIAG) */ + +#if defined(ETH_P_CUST) + case ETH_P_CUST: + cp = "CUST"; + break; +#endif /* defined(ETH_P_CUST) */ + +#if defined(ETH_P_SCA) + case ETH_P_SCA: + cp = "SCA"; + break; +#endif /* defined(ETH_P_SCA) */ + +#if defined(ETH_P_RARP) + case ETH_P_RARP: + cp = "RARP"; + break; +#endif /* defined(ETH_P_RARP) */ + +#if defined(ETH_P_ATALK) + case ETH_P_ATALK: + cp = "ATALK"; + break; +#endif /* defined(ETH_P_ATALK) */ + +#if defined(ETH_P_AARP) + case ETH_P_AARP: + cp = "AARP"; + break; +#endif /* defined(ETH_P_AARP) */ + +#if defined(ETH_P_8021Q) + case ETH_P_8021Q: + cp = "8021Q"; + break; +#endif /* defined(ETH_P_8021Q) */ + +#if defined(ETH_P_IPX) + case ETH_P_IPX: + cp = "IPX"; + break; +#endif /* defined(ETH_P_IPX) */ + +#if defined(ETH_P_IPV6) + case ETH_P_IPV6: + cp = "IPV6"; + break; +#endif /* defined(ETH_P_IPV6) */ + +#if defined(ETH_P_SLOW) + case ETH_P_SLOW: + cp = "SLOW"; + break; +#endif /* defined(ETH_P_SLOW) */ + +#if defined(ETH_P_WCCP) + case ETH_P_WCCP: + cp = "WCCP"; + break; +#endif /* defined(ETH_P_WCCP) */ + +#if defined(ETH_P_PPP_DISC) + case ETH_P_PPP_DISC: + cp = "PPP_DIS"; + break; +#endif /* defined(ETH_P_PPP_DISC) */ + +#if defined(ETH_P_PPP_SES) + case ETH_P_PPP_SES: + cp = "PPP_SES"; + break; +#endif /* defined(ETH_P_PPP_SES) */ + +#if defined(ETH_P_MPLS_UC) + case ETH_P_MPLS_UC: + cp = "MPLS_UC"; + break; +#endif /* defined(ETH_P_MPLS_UC) */ + +#if defined(ETH_P_ATMMPOA) + case ETH_P_ATMMPOA: + cp = "ATMMPOA"; + break; +#endif /* defined(ETH_P_ATMMPOA) */ + +#if defined(ETH_P_MPLS_MC) + case ETH_P_MPLS_MC: + cp = "MPLS_MC"; + break; +#endif /* defined(ETH_P_MPLS_MC) */ + +#if defined(ETH_P_ATMFATE) + case ETH_P_ATMFATE: + cp = "ATMFATE"; + break; +#endif /* defined(ETH_P_ATMFATE) */ + +#if defined(ETH_P_AOE) + case ETH_P_AOE: + cp = "AOE"; + break; +#endif /* defined(ETH_P_AOE) */ + +#if defined(ETH_P_TIPC) + case ETH_P_TIPC: + cp = "TIPC"; + break; +#endif /* defined(ETH_P_TIPC) */ + +#if defined(ETH_P_802_3) + case ETH_P_802_3: + cp = "802.3"; + break; +#endif /* defined(ETH_P_802_3) */ + +#if defined(ETH_P_AX25) + case ETH_P_AX25: + cp = "AX25"; + break; +#endif /* defined(ETH_P_AX25) */ + +#if defined(ETH_P_ALL) + case ETH_P_ALL: + cp = "ALL"; + break; +#endif /* defined(ETH_P_ALL) */ + +#if defined(ETH_P_802_2) + case ETH_P_802_2: + cp = "802.2"; + break; +#endif /* defined(ETH_P_802_2) */ + +#if defined(ETH_P_SNAP) + case ETH_P_SNAP: + cp = "SNAP"; + break; +#endif /* defined(ETH_P_SNAP) */ + +#if defined(ETH_P_DDCMP) + case ETH_P_DDCMP: + cp = "DDCMP"; + break; +#endif /* defined(ETH_P_DDCMP) */ + +#if defined(ETH_P_WAN_PPP) + case ETH_P_WAN_PPP: + cp = "WAN_PPP"; + break; +#endif /* defined(ETH_P_WAN_PPP) */ + +#if defined(ETH_P_PPP_MP) + case ETH_P_PPP_MP: + cp = "PPP MP"; + break; +#endif /* defined(ETH_P_PPP_MP) */ + +#if defined(ETH_P_LOCALTALK) + case ETH_P_LOCALTALK: + cp = "LCLTALK"; + break; +#endif /* defined(ETH_P_LOCALTALK) */ + +#if defined(ETH_P_PPPTALK) + case ETH_P_PPPTALK: + cp = "PPPTALK"; + break; +#endif /* defined(ETH_P_PPPTALK) */ + +#if defined(ETH_P_TR_802_2) + case ETH_P_TR_802_2: + cp = "802.2"; + break; +#endif /* defined(ETH_P_TR_802_2) */ + +#if defined(ETH_P_MOBITEX) + case ETH_P_MOBITEX: + cp = "MOBITEX"; + break; +#endif /* defined(ETH_P_MOBITEX) */ + +#if defined(ETH_P_CONTROL) + case ETH_P_CONTROL: + cp = "CONTROL"; + break; +#endif /* defined(ETH_P_CONTROL) */ + +#if defined(ETH_P_IRDA) + case ETH_P_IRDA: + cp = "IRDA"; + break; +#endif /* defined(ETH_P_IRDA) */ + +#if defined(ETH_P_ECONET) + case ETH_P_ECONET: + cp = "ECONET"; + break; +#endif /* defined(ETH_P_ECONET) */ + +#if defined(ETH_P_HDLC) + case ETH_P_HDLC: + cp = "HDLC"; + break; +#endif /* defined(ETH_P_HDLC) */ + +#if defined(ETH_P_ARCNET) + case ETH_P_ARCNET: + cp = "ARCNET"; + break; +#endif /* defined(ETH_P_ARCNET) */ + + default: + (void) snpf(tbuf, sizeof(tbuf) - 1, "%d", pp->pr); + tbuf[sizeof(tbuf) - 1] = '\0'; + cp = tbuf; + } + (void) snpf(Lf->iproto, sizeof(Lf->iproto), "%.*s", IPROTOL-1, cp); + Lf->inp_ty = 2; + if (ss & SB_INO) { + (void) snpf(tbuf, sizeof(tbuf), InodeFmt_d, + (INODETYPE)s->st_ino); + tbuf[sizeof(tbuf) - 1] = '\0'; + enter_dev_ch(tbuf); + } + if (Namech[0]) + enter_nm(Namech); + return; + } + if (UNIXpath) { + (void) get_unix(UNIXpath); + (void) free((FREE_P *)UNIXpath); + UNIXpath = (char *)NULL; + } + if ((ss & SB_INO) + && (up = check_unix((INODETYPE)s->st_ino)) + ) { + + /* + * The inode is connected to a UNIX /proc record. + * + * Set the type to "unix"; enter the PCB address in the DEVICE column; + * enter the inode number; and save the optional path. + */ + if (Funix) + Lf->sf |= SELUNX; + (void) snpf(Lf->type, sizeof(Lf->type), "unix"); + if (up->pcb) + enter_dev_ch(up->pcb); + if (ss & SB_INO) { + Lf->inode = (INODETYPE)s->st_ino; + Lf->inp_ty = 1; + } + +#if defined(HASEPTOPTS) && defined(HASUXSOCKEPT) + if (FeptE) { + (void) enter_uxsinfo(up); + Lf->sf |= SELUXSINFO; + } +#endif /* defined(HASEPTOPTS) && defined(HASUXSOCKEPT) */ + + cp = sockty2str(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(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(0, path, (struct mounts *)NULL, 0)) { + f = 1; + Lf->sf |= SELNM; + } + Lf->dev_def = sv_dev_def; + Lf->dev = sv_dev; + Lf->inode = sv_inode; + Lf->inp_ty = sv_inp_ty; + Lf->rdev_def = sv_rdev_def; + Lf->rdev = sv_rdev; + } + if (!f && (ss & SB_MODE)) { + + /* + * If the file has not yet been found and the stat buffer has + * st_mode, search for the file by full path. + */ + if (is_file_named(2, 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(Raw6path); + (void) free((FREE_P *)Raw6path); + Raw6path = (char *)NULL; + } + if (!Fxopt && (ss & SB_INO) + && (rp = check_raw6((INODETYPE)s->st_ino)) + ) { + + /* + * The inode is connected to a raw IPv6 /proc record. + * + * Set the type to "raw6"; enter the inode number; store the local + * address, remote address, and state in the NAME column. + */ + (void) snpf(Lf->type, sizeof(Lf->type), "raw6"); + if (ss & SB_INO) { + Lf->inode = (INODETYPE)s->st_ino; + Lf->inp_ty = 1; + } + cp = Namech; + nl = MAXPATHLEN - 2; + if (rp->la && rp->lal) { + + /* + * Store the local raw IPv6 address. + */ + if (nl > rp->lal) { + (void) snpf(cp, nl, "%s", rp->la); + cp += rp->lal; + *cp = '\0'; + nl -= rp->lal; + } + } + if (rp->ra && rp->ral) { + + /* + * Store the remote raw address, prefixed with "->". + */ + if (nl > (rp->ral + 2)) { + (void) snpf(cp, nl, "->%s", rp->ra); + cp += (rp->ral + 2); + nl -= (rp->ral + 2); + } + } + if (rp->sp && rp->spl) { + + /* + * Store the state, optionally prefixed by a space, in the + * form "st=x...x". + */ + + if (nl > (len = ((cp == Namech) ? 0 : 1) + 3 + rp->spl)) { + (void) snpf(cp, nl, "%sst=%s", + (cp == Namech) ? "" : " ", rp->sp); + cp += len; + *cp = '\0'; + nl -= len; + } + } + if (Namech[0]) + enter_nm(Namech); + return; + } + if (TCP6path) { + if (!Fxopt) + (void) get_tcpudp6(TCP6path, 0, 1); + (void) free((FREE_P *)TCP6path); + TCP6path = (char *)NULL; + } + if (UDP6path) { + if (!Fxopt) + (void) get_tcpudp6(UDP6path, 1, 0); + (void) free((FREE_P *)UDP6path); + UDP6path = (char *)NULL; + } + if (UDPLITE6path) { + if (!Fxopt) + (void) get_tcpudp6(UDPLITE6path, 2, 0); + (void) free((FREE_P *)UDPLITE6path); + UDPLITE6path = (char *)NULL; + } + if (!Fxopt && (ss & SB_INO) + && (tp6 = check_tcpudp6((INODETYPE)s->st_ino, &pr)) + ) { + + /* + * The inode is connected to an IPv6 TCP or UDP /proc record. + * + * Set the type to "IPv6"; enter the protocol; put the inode number + * in the DEVICE column in lieu of the PCB address; save the local + * and foreign IPv6 addresses; save the type and protocol; and + * (optionally) save the queue sizes. + */ + i = tp6->state + TcpStOff; + if (TcpStXn) { + + /* + * Check for state exclusion. + */ + if (i >= 0 && i < TcpNstates) { + if (TcpStX[i]) { + Lf->sf |= SELEXCLF; + return; + } + } + } + if (TcpStIn) { + + /* + * Check for state inclusion. + */ + if (i >= 0 && i < TcpNstates) { + if (TcpStI[i]) + TcpStI[i] = 2; + else { + Lf->sf |= SELEXCLF; + return; + } + } + } + if (Fnet && (FnetTy != 4)) + Lf->sf |= SELNET; + (void) snpf(Lf->type, sizeof(Lf->type), "IPv6"); + (void) snpf(Lf->iproto, sizeof(Lf->iproto), "%.*s", IPROTOL-1, pr); + Lf->inp_ty = 2; + if (ss & SB_INO) { + (void) snpf(tbuf, sizeof(tbuf), InodeFmt_d, + (INODETYPE)s->st_ino); + tbuf[sizeof(tbuf) - 1] = '\0'; + enter_dev_ch(tbuf); + } + af = AF_INET6; + if (!IN6_IS_ADDR_UNSPECIFIED(&tp6->faddr) || tp6->fport) + fa = (unsigned char *)&tp6->faddr; + else + fa = (unsigned char *)NULL; + if (!IN6_IS_ADDR_UNSPECIFIED(&tp6->laddr) || tp6->lport) + la = (unsigned char *)&tp6->laddr; + else + la = (unsigned char *)NULL; + if ((fa && IN6_IS_ADDR_V4MAPPED(&tp6->faddr)) + || (la && IN6_IS_ADDR_V4MAPPED(&tp6->laddr))) { + af = AF_INET; + if (fa) + fa += 12; + if (la) + la += 12; + } + ent_inaddr(la, tp6->lport, fa, tp6->fport, af); + Lf->lts.type = tp6->proto; + Lf->lts.state.i = tp6->state; + +#if defined(HASTCPTPIQ) + Lf->lts.rq = tp6->rxq; + Lf->lts.sq = tp6->txq; + Lf->lts.rqs = Lf->lts.sqs = 1; +#endif /* defined(HASTCPTPIQ) */ + + return; + } +#endif /* defined(HASIPv6) */ + + if (TCPpath) { + if (!Fxopt) + (void) get_tcpudp(TCPpath, 0, 1); + (void) free((FREE_P *)TCPpath); + TCPpath = (char *)NULL; + } + if (UDPpath) { + if (!Fxopt) + (void) get_tcpudp(UDPpath, 1, 0); + (void) free((FREE_P *)UDPpath); + UDPpath = (char *)NULL; + } + if (UDPLITEpath) { + if (!Fxopt) + (void) get_tcpudp(UDPLITEpath, 2, 0); + (void) free((FREE_P *)UDPLITEpath); + UDPLITEpath = (char *)NULL; + } + if (!Fxopt && (ss & SB_INO) + && (tp = check_tcpudp((INODETYPE)s->st_ino, &pr)) + ) { + + /* + * The inode is connected to an IPv4 TCP or UDP /proc record. + * + * Set the type to "inet" or "IPv4"; enter the protocol; put the + * inode number in the DEVICE column in lieu of the PCB address; + * save the local and foreign IPv4 addresses; save the type and + * protocol; and (optionally) save the queue sizes. + */ + i = tp->state + TcpStOff; + if (TcpStXn) { + + /* + * Check for state exclusion. + */ + if (i >= 0 && i < TcpNstates) { + if (TcpStX[i]) { + Lf->sf |= SELEXCLF; + return; + } + } + } + if (TcpStIn) { + + /* + * Check for state inclusion. + */ + if (i >= 0 && i < TcpNstates) { + if (TcpStI[i]) + TcpStI[i] = 2; + else { + Lf->sf |= SELEXCLF; + return; + } + } + } + if (Fnet && (FnetTy != 6)) + Lf->sf |= SELNET; + +#if defined(HASIPv6) + (void) snpf(Lf->type, sizeof(Lf->type), "IPv4"); +#else /* !defined(HASIPv6) */ + (void) snpf(Lf->type, sizeof(Lf->type), "inet"); +#endif /* defined(HASIPv6) */ + + (void) snpf(Lf->iproto, sizeof(Lf->iproto), "%.*s", IPROTOL-1, pr); + Lf->inp_ty = 2; + if (ss & SB_INO) { + (void) snpf(tbuf, sizeof(tbuf), InodeFmt_d, + (INODETYPE)s->st_ino); + tbuf[sizeof(tbuf) - 1] = '\0'; + enter_dev_ch(tbuf); + } + if (tp->faddr || tp->fport) { + fs.s_addr = tp->faddr; + fa = (unsigned char *)&fs; + } else + fa = (unsigned char *)NULL; + if (tp->laddr || tp->lport) { + ls.s_addr = tp->laddr; + la = (unsigned char *)&ls; + } else + la = (unsigned char *)NULL; + ent_inaddr(la, tp->lport, fa, tp->fport, AF_INET); + Lf->lts.type = tp->proto; + Lf->lts.state.i = tp->state; + +#if defined(HASTCPTPIQ) + Lf->lts.rq = tp->rxq; + Lf->lts.sq = tp->txq; + Lf->lts.rqs = Lf->lts.sqs = 1; +#endif /* defined(HASTCPTPIQ) */ + + return; + } + if (SCTPPath[0]) { + (void) get_sctp(); + for (i = 0; i < NSCTPPATHS; i++) { + (void) free((FREE_P *)SCTPPath[i]); + SCTPPath[i] = (char *)NULL; + } + } + if ((ss & SB_INO) && (sp = check_sctp((INODETYPE)s->st_ino)) + ) { + + /* + * The inode is connected to an SCTP /proc record. + * + * Set the type to "sock"; enter the inode number in the DEVICE + * column; set the protocol to SCTP; and fill in the NAME column + * with ASSOC, ASSOC-ID, ENDPT, LADDRS, LPORT, RADDRS and RPORT. + */ + (void) snpf(Lf->type, sizeof(Lf->type), "sock"); + (void) snpf(Lf->iproto, sizeof(Lf->iproto), "%.*s", IPROTOL-1, + "SCTP"); + Lf->inp_ty = 2; + (void) snpf(tbuf, sizeof(tbuf), InodeFmt_d, (INODETYPE)s->st_ino); + tbuf[sizeof(tbuf) - 1] = '\0'; + enter_dev_ch(tbuf); + Namech[0] = '\0'; + if (sp->type == 1) { + + /* + * This is an ENDPT SCTP file. + */ + (void) snpf(Namech, Namechl, + "ENDPT: %s%s%s%s%s%s", + sp->addr ? sp->addr : "", + (sp->laddrs || sp->lport) ? " " : "", + sp->laddrs ? sp->laddrs : "", + sp->lport ? "[" : "", + sp->lport ? sp->lport : "", + sp->lport ? "]" : "" + ); + } else { + + /* + * This is an ASSOC, or ASSOC and ENDPT socket file. + */ + (void) snpf(Namech, Namechl, + "%s: %s%s%s %s%s%s%s%s%s%s%s%s", + sp->type ? "ASSOC+ENDPT" : "ASSOC", + sp->addr ? sp->addr : "", + (sp->addr && sp->assocID) ? "," : "", + sp->assocID ? sp->assocID : "", + sp->laddrs ? sp->laddrs : "", + sp->lport ? "[" : "", + sp->lport ? sp->lport : "", + sp->lport ? "]" : "", + ((sp->laddrs || sp->lport) && (sp->raddrs || sp->rport)) + ? "<->" : "", + sp->raddrs ? sp->raddrs : "", + sp->rport ? "[" : "", + sp->rport ? sp->rport : "", + sp->rport ? "]" : "" + ); + } + if (Namech[0]) + enter_nm(Namech); + return; + } + if (ICMPpath) { + (void) get_icmp(ICMPpath); + (void) free((FREE_P *)ICMPpath); + ICMPpath = (char *)NULL; + } + if ((ss & SB_INO) + && (icmpp = check_icmp((INODETYPE)s->st_ino)) + ) { + + /* + * The inode is connected to an ICMP /proc record. + * + * Set the type to "icmp" and store the type in the NAME + * column. Save the inode number. + */ + (void) snpf(Lf->type, sizeof(Lf->type), "icmp"); + Lf->inode = (INODETYPE)s->st_ino; + Lf->inp_ty = 1; + cp = Namech; + nl = Namechl- 2; + *cp = '\0'; + if (icmpp->la && icmpp->lal) { + + /* + * Store the local raw address. + */ + if (nl > icmpp->lal) { + (void) snpf(cp, nl, "%s", icmpp->la); + cp += icmpp->lal; + *cp = '\0'; + nl -= icmpp->lal; + } + } + if (icmpp->ra && icmpp->ral) { + + /* + * Store the remote raw address, prefixed with "->". + */ + if (nl > (icmpp->ral + 2)) { + (void) snpf(cp, nl, "->%s", icmpp->ra); + cp += (icmpp->ral + 2); + *cp = '\0'; + nl -= (icmpp->ral + 2); + } + } + if (Namech[0]) + enter_nm(Namech); + return; + } +/* + * The socket's protocol can't be identified. + */ + (void) snpf(Lf->type, sizeof(Lf->type), "sock"); + if (ss & SB_INO) { + Lf->inode = (INODETYPE)s->st_ino; + Lf->inp_ty = 1; + } + if (ss & SB_DEV) { + Lf->dev = s->st_dev; + Lf->dev_def = 1; + } + if (Fxopt) + enter_nm("can't identify protocol (-X specified)"); + else { + (void) snpf(Namech, Namechl, "protocol: "); + if (!prp) { + i = (int)strlen(Namech); + prp = &Namech[i]; + sz = (ssize_t)(Namechl - i - 1); + } + if ((getxattr(pbr, "system.sockprotoname", prp, sz)) < 0) + enter_nm("can't identify protocol"); + else + enter_nm(Namech); + } +} + + +/* + * set_net_paths() - set /proc/net paths + */ + +void +set_net_paths(p, pl) + char *p; /* path to /proc/net/ */ + int pl; /* strlen(p) */ +{ + int i; + int pathl; + + pathl = 0; + (void) make_proc_path(p, pl, &AX25path, &pathl, "ax25"); + pathl = 0; + (void) make_proc_path(p, pl, &ICMPpath, &pathl, "icmp"); + pathl = 0; + (void) make_proc_path(p, pl, &Ipxpath, &pathl, "ipx"); + pathl = 0; + (void) make_proc_path(p, pl, &Nlkpath, &pathl, "netlink"); + pathl = 0; + (void) make_proc_path(p, pl, &Packpath, &pathl, "packet"); + pathl = 0; + (void) make_proc_path(p, pl, &Rawpath, &pathl, "raw"); + for (i = 0; i < NSCTPPATHS; i++) { + pathl = 0; + (void) make_proc_path(p, pl, &SCTPPath[i], &pathl, SCTPSfx[i]); + } + pathl = 0; + (void) make_proc_path(p, pl, &SockStatPath, &pathl, "sockstat"); + pathl = 0; + (void) make_proc_path(p, pl, &TCPpath, &pathl, "tcp"); + pathl = 0; + (void) make_proc_path(p, pl, &UDPpath, &pathl, "udp"); + pathl = 0; + (void) make_proc_path(p, pl, &UDPLITEpath, &pathl, "udplite"); + +#if defined(HASIPv6) + pathl = 0; + (void) make_proc_path(p, pl, &Raw6path, &pathl, "raw6"); + pathl = 0; + (void) make_proc_path(p, pl, &SockStatPath6, &pathl, "sockstat6"); + pathl = 0; + (void) make_proc_path(p, pl, &TCP6path, &pathl, "tcp6"); + pathl = 0; + (void) make_proc_path(p, pl, &UDP6path, &pathl, "udp6"); + pathl = 0; + (void) make_proc_path(p, pl, &UDPLITE6path, &pathl, "udplite6"); +#endif /* defined(HASIPv6) */ + + pathl = 0; + (void) make_proc_path(p, pl, &UNIXpath, &pathl, "unix"); +} + + +/* + * Sockty2str() -- convert socket type number to a string + */ + +static char * +sockty2str(ty, rf) + 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_PACKET) + case SOCK_PACKET: + sr = "PACKET"; + break; +#endif /* defined(SOCK_PACKET) */ + + default: + f = 1; + sr = "unknown"; + } + *rf = f; + return(sr); +} diff --git a/dialects/linux/dstore.c b/dialects/linux/dstore.c new file mode 100644 index 0000000..80e2826 --- /dev/null +++ b/dialects/linux/dstore.c @@ -0,0 +1,114 @@ +/* + * dstore.c - Linux global storage for /proc-based lsof + */ + + +/* + * Copyright 1997 Purdue Research Foundation, West Lafayette, Indiana + * 47907. All rights reserved. + * + * Written by Victor A. Abell + * + * This software is not subject to any license of the American Telephone + * and Telegraph Company or the Regents of the University of California. + * + * Permission is granted to anyone to use this software for any purpose on + * any computer system, and to alter it and redistribute it freely, subject + * to the following restrictions: + * + * 1. Neither the authors nor Purdue University are responsible for any + * consequences of the use of this software. + * + * 2. The origin of this software must not be misrepresented, either by + * explicit claim or by omission. Credit to the authors and Purdue + * University must appear in documentation and sources. + * + * 3. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 4. This notice may not be removed or altered. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright 1997 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: dstore.c,v 1.4 2011/09/07 19:07:45 abe Exp $"; +#endif + + +#include "lsof.h" + +int HasNFS = 0; /* NFS mount point status: + * 1 == there is an NFS mount point, + * but its device number is + * unknown + * 2 == there is an NFS mount point + * and its device number is + * known + */ +int OffType = 0; /* offset type: + * 0 == unknown + * 1 == lstat's st_size + * 2 == from /proc//fdinfo */ + +/* + * Pff_tab[] - table for printing file flags + */ + +struct pff_tab Pff_tab[] = { + { (long)O_WRONLY, FF_WRITE }, + { (long)O_RDWR, FF_RDWR }, + { (long)O_CREAT, FF_CREAT }, + { (long)O_EXCL, FF_EXCL }, + { (long)O_NOCTTY, FF_NOCTTY }, + { (long)O_TRUNC, FF_TRUNC }, + { (long)O_APPEND, FF_APPEND }, + { (long)O_NDELAY, FF_NDELAY }, + { (long)O_SYNC, FF_SYNC }, + { (long)O_ASYNC, FF_ASYNC }, + +#if defined(O_DIRECT) + { (long)O_DIRECT, FF_DIRECT }, +#endif /* defined(O_DIRECT) */ + +#if defined(O_DIRECTORY) + { (long)O_DIRECTORY, FF_DIRECTORY }, +#endif /* defined(O_DIRECTORY) */ + +#if defined(O_NOFOLLOW) + { (long)O_NOFOLLOW, FF_NOFOLNK }, +#endif /* defined(O_NOFOLLOW) */ + +#if defined(O_NOATIME) + { (long)O_NOATIME, FF_NOATM }, +#endif /* defined(O_NOATIME) */ + +#if defined(O_DSYNC) + { (long)O_DSYNC, FF_DSYNC }, +#endif /* defined(O_DSYNC) */ + +#if defined(O_RSYNC) + { (long)O_RSYNC, FF_RSYNC }, +#endif /* defined(O_RSYNC) */ + +#if defined(O_LARGEFILE) +# if O_LARGEFILE==0 + { (long)0100000, FF_LARGEFILE }, +# else /* O_LARGEFILE!=0 */ + { (long)O_LARGEFILE, FF_LARGEFILE }, +# endif /* O_LARGEFILE==0 */ +#else /* !defined(O_LARGEFILE) */ + { (long)0100000, FF_LARGEFILE }, +#endif /* defined(O_LARGEFILE) */ + + { (long)0, NULL } +}; + + +/* + * Pof_tab[] - table for print process open file flags + */ + +struct pff_tab Pof_tab[] = { + { (long)0, NULL } +}; diff --git a/dialects/linux/machine.h b/dialects/linux/machine.h new file mode 100644 index 0000000..2f17ae0 --- /dev/null +++ b/dialects/linux/machine.h @@ -0,0 +1,651 @@ +/* + * 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 +#include + + +/* + * 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 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? */ +/* #define HASPRINTOFF print_off? */ +/* #define HASPRINTSZ print_sz? */ + + +/* + * HASPRIVFILETYPE and PRIVFILETYPE are defined for dialects that have a + * file structure type that isn't defined by a DTYPE_* symbol. They are + * used in lib/prfp.c to select the type's processing. + * + * PRIVFILETYPE is the definition of the f_type value in the file struct. + * + * HASPRIVFILETYPE is the name of the processing function. + */ + +/* #define HASPRIVFILETYPE process_shmf? */ +/* #define PRIVFILETYPE ?? */ + + +/* + * HASPRIVNMCACHE is defined for dialects that have a private method for + * printing cached NAME column values for some files. HASPRIVNAMECACHE + * is defined to be the name of the function. + * + * The function takes one argument, a struct lfile pointer to the file, and + * returns non-zero if it prints a name to stdout. + */ + +/* #define HASPRIVNMCACHE */ + + +/* + * 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 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 + + +/* + * 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_ is defined for dialects that use the + * in the lsof library. + * + * Note: other definitions and operations may be required to condition the + * library function source code. They may be found in the dialect dlsof.h + * header files. + */ + +/* #define USE_LIB_CKKV 1 ckkv.c */ +/* #define USE_LIB_COMPLETEVFS 1 cvfs.c */ +/* #define USE_LIB_FIND_CH_INO 1 fino.c */ +/* #define USE_LIB_IS_FILE_NAMED 1 isfn.c */ +/* #define USE_LIB_LKUPDEV 1 lkud.c */ +/* #define USE_LIB_PRINTDEVNAME 1 pdvn.c */ +/* #define USE_LIB_PROCESS_FILE 1 prfp.c */ +/* #define USE_LIB_PRINT_TCPTPI 1 ptti.c */ +/* #define USE_LIB_READDEV 1 rdev.c */ +/* #define USE_LIB_READMNT 1 rmnt.c */ +/* #define USE_LIB_REGEX 1 regex.c */ +/* #define USE_LIB_RNAM 1 rnam.c */ +/* #define USE_LIB_RNCH 1 rnch.c */ +/* #define USE_LIB_RNMH 1 rnmh.c */ +/* #define USE_LIB_SNPF 1 snpf.c */ +#define snpf snprintf /* use the system's snprintf() */ + + +/* + * WARNDEVACCESS is defined for those dialects that should issue a warning + * when lsof can't access /dev (or /device) or one of its sub-directories. + * The warning can be inhibited by the lsof caller with the -w option. + * + * CAUTION!!! Don't enable the WARNDEVACCESS definiton for /proc-based Linux + * lsof; it doesn't process /dev at all. + * + * The presence of NEVER_WARNDEVACCESS in this comment prevents the Customize + * script from offering to change WARNDEVACCESS. + */ + +/* #define WARNDEVACCESS 1 DON'T ENABLE!!! -- see above comment */ + + +/* + * WARNINGSTATE is defined for those dialects that want to suppress all lsof + * warning messages. + */ + +/* #define WARNINGSTATE 1 warnings are enabled by default */ + + +/* + * WILLDROPGID is defined for those dialects whose lsof executable runs + * setgid(not_real_GID) and whose setgid power can be relinquished after + * the dialect's initialize() function has been executed. + */ + +/* #define WILLDROPGID 1 */ + + +/* + * zeromem is a macro that uses bzero or memset. + */ + +#define zeromem(a, l) bzero(a, l) + +#endif /* !defined(LSOF_MACHINE_H) */ diff --git a/dialects/n+obsd/Makefile b/dialects/n+obsd/Makefile new file mode 100644 index 0000000..29f88a6 --- /dev/null +++ b/dialects/n+obsd/Makefile @@ -0,0 +1,159 @@ + +# N+OBSD 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} +CFLAGS= ${CDEFS} ${INCL} ${DEBUG} + +GRP= + +HDR= lsof.h lsof_fields.h dlsof.h machine.h proto.h dproto.h + +SRC= dmnt.c dnode.c dnode1.c dproc.c dsock.c dstore.c \ + arg.c main.c misc.c node.c print.c proc.c store.c usage.c \ + util.c + +OBJ= dmnt.o dnode.o dnode1.o dproc.o dsock.o dstore.o \ + arg.o main.o misc.o node.o print.o proc.o store.o usage.o \ + util.o + +MAN= lsof.8 +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_CCDATE "'`date`'"' >> 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/dialects/n+obsd/Mksrc b/dialects/n+obsd/Mksrc new file mode 100755 index 0000000..a6a19b5 --- /dev/null +++ b/dialects/n+obsd/Mksrc @@ -0,0 +1,24 @@ +#!/bin/sh +# +# Mksrc - make NetBSD and 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 $ + + +D=dialects/n+obsd +L="dlsof.h dmnt.c dnode.c dnode1.c dproc.c dproto.h dsock.c dstore.c machine.h" + +for i in $L +do + rm -f $i + $LSOF_MKC $D/$i $i + echo "$LSOF_MKC $D/$i $i" +done diff --git a/dialects/n+obsd/dlsof.h b/dialects/n+obsd/dlsof.h new file mode 100644 index 0000000..2aa2169 --- /dev/null +++ b/dialects/n+obsd/dlsof.h @@ -0,0 +1,584 @@ +/* + * dlsof.h - NetBSD and 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(NETBSD_LSOF_H) +#define NETBSD_LSOF_H 1 + +#include +#include +#include +#include +#include +#include +#include +#include + +# if defined(HASGETBOOTFILE) +#include +# endif /* defined(HASGETBOOTFILE) */ + +#include +#include + +# if defined(HAS_LWP_H) +#include +# endif /* defined(HAS_LWP_H) */ + +# if (defined(OPENBSDV) && OPENBSDV>=3030) \ + || (defined(NETBSDV) && __NetBSD_Version__>=106060000) + +# if defined(OPENBSDV) || __NetBSD_Version__<399001100 +#define _KERNEL +# endif /* defined(OPENBSDV) || __NetBSD_Version__<399001100 */ + +# if defined(NETBSDV) && __NetBSD_Version__<399001100 +struct buf; /* dummy for function prototype in */ +struct uio; /* dummy for function prototype in */ +# endif /* defined(NETBSDV && __NetBSD_Version__<399001100) */ + +#include +# endif /* (defined(OPENBSDV) && OPENBSDV>=3030) + || (defined(NETBSDV) && __NetBSD_Version__>=106060000) */ + +# if defined(NETBSDV) && __NetBSD_Version__<399001100 +#include +# endif /* defined(NETBSDV) && __NetBSD_Version__<399001100 */ + +# if (defined(OPENBSDV) && OPENBSDV>=3030) \ + || (defined(NETBSDV) && __NetBSD_Version__>=106060000 \ + && __NetBSD_Version__<399001100) +#undef _KERNEL +# endif /* (defined(OPENBSDV) && OPENBSDV>=3030) \ + || (defined(NETBSDV) && __NetBSD_Version__>=106060000 \ + && __NetBSD_Version__<399001100) */ + +#define NFS +#define m_stat mnt_stat + +# if (defined(OPENBSDV) && OPENBSDV>=3030) \ + || (defined(NETBSDV) && __NetBSD_Version__>=106060000) +#define _KERNEL +# endif /* (defined(OPENBSDV) && OPENBSDV<3030) + || (defined(NETBSDV) && __NetBSD_Version__>=106060000) */ + +#include + +# if (defined(OPENBSDV) && OPENBSDV>=3030) \ + || (defined(NETBSDV) && __NetBSD_Version__>=106060000) +#undef _KERNEL +# endif /* (defined(OPENBSDV) && OPENBSDV>=3030) + || (defined(NETBSDV) && __NetBSD_Version__>=106060000) */ + +#include +#include + +# if defined(NETBSDV) && NETBSDV>=1003000 +#define sockproto NETBSD_sockproto +# endif /* defined(NETBSDV) && NETBSDV>=1003000 */ + +#include + +# if defined(HASMSDOSFS) +# if HASMSDOSFS==1 +#include +#include +# else /* HASMSDOSFS!=1 */ +#include +#include +# endif /* HASMSDOSFS==1 */ + +# if (defined(OPENBSDV) && OPENBSDV<3030) \ + || (defined(NETBSDV) && __NetBSD_Version__<106060000) +/* + * The netcred and netexport structures may be needed in the msdosfsmount + * structure, defined in . So as a terrible hack, + * the lsof Configure script extracts the netcred and netexport structure + * definitions from and places them in "netexport.h". + * + * When needed, the netcred and netexport structures netcred should really + * be obtained from . However they are hidden in + * under _KERNEL, and that sometimes can't be defined when including + * 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 . + * + * 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(OPENBSDV) && OPENBSDV<3030) + || (defined(NETBSDV) && __NetBSD_Version__<106060000) */ + +#define _KERNEL +struct nameidata; /* to satisfy a function prototype in msdosfsmount.h */ +#include +#undef _KERNEL +#include +#include +# endif /* defined(HASMSDOSFS) */ + +# if defined(NETBSDV) && NETBSDV>=1003000 +#undef sockproto +# endif /* defined(NETBSDV) && NETBSDV>=1003000 */ + +#include +#include +#include +#include +#include +#include + +# if defined(HASIPv6) && defined(NETBSDV) && !defined(HASINRIAIPv6) +#include +#include +# endif /* defined(HASIPv6) && defined(NETBSDV) && !defined(HASINRIAIPv6) */ + +#include +#include +#include +#include +#include +#include +#include +#include + +# if defined(OPENBSDV) +# if !defined(TF_ECN_PERMIT) +#define TF_ECN_PERMIT 0x00008000 /* other side said I could ECN */ +# endif /* !defined(TF_ECN_PERMIT) */ + +# if !defined(TF_RCVD_CE) +#define TF_RCVD_CE 0x00010000 /* send ECE in subsequent segs */ +# endif /* !defined(TF_RCVD_CE) */ + +# if !defined(TF_SEND_CWR) +#define TF_SEND_CWR 0x00020000 /* send CWR in next seg */ +# endif /* !defined(TF_SEND_CWR) */ + +# if !defined(TF_DISABLE_ECN) +#define TF_DISABLE_ECN 0x00040000 /* disable ECN for this connection */ +# endif /* !defined(TF_DISABLE_ECN) */ + +# endif /* defined(OPENBSDV) */ + +#include + +# if defined(UVM) +/* + * Avoid conflicts with definitions in . + */ + +#undef FALSE +#undef TRUE +# endif /* defined(UVM) */ + +#include + +# if defined(NETBSDV) && NETBSDV>=1003000 +/* + * Because late in the 1.3I NetBSD development cycle the sockproto structure + * was placed under _KERNEL in , and because defining _KERNEL + * before #include'ing causes other #include problems, the + * sockproto structure definition that might have been in 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 +#include +#define pmap RPC_pmap +#include +#include +#undef pmap +#define KERNEL +#include +# if defined(DIRBLKSIZ) +#define DIRENT_DIRBLKSIZ DIRBLKSIZ +#undef DIRBLKSIZ +# endif /* defined(DIRBLKSIZ) */ + +# if defined(HASI_FFS1) +#define _KERNEL +#include +#undef _KERNEL +# endif /* defined(HASI_FFS1) */ + +#include + +# 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 +#undef _KERNEL +# endif /* defined(NETBSDV) && NETBSDV>=2099010 */ +#endif /* defined(HASBUFQ_H) */ + +#undef KERNEL +#include + +# if defined(HASNFSPROTO) +#include +#include +# else /* !defined(HASNFSPROTO) */ +#include +# endif /* defined(HASNFSPROTO) */ + +#include +#include +#include +#include +#include +# 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 +#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 +#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 +#undef _KERNEL +# endif /* defined(HASNULLFS) */ + +# if defined(HASPROCFS) +# if defined(HASPROCFS_PFSROOT) +#define _KERNEL +# endif /* defined(HASPROCFS_PFSROOT) */ +#include +# 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 Pctl PFSctl +#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 */ +# endif /* defined(NetBSDV) */ +# endif /* defined(HASPROCFS_PFSROOT) */ +#include +# endif /* defined(HASPROCFS) */ + +# if defined(HASPTYFS) +#define _KERNEL +#include +#include +#undef _KERNEL +# endif /* defined(HASPTYFS) */ + +#define KERNEL +#define _KERNEL +#include +#include + +# 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 */ +# if defined(OPENBSDV) +#include +# endif /* defined(OPENBSDV) */ +# endif /* defined(DTYPE_KQUEUE) */ + +#include +#undef KERNEL +#undef _KERNEL + +# if defined(UVM) +# if defined(OPENBSDV) +#define _UVM_UVM_FAULT_I_H_ 1 /* avoid OpenBSD's + /* +# endif /* defined(UVM) */ + +# if defined(HAS_UVM_INCL) +#include +#include +#include +#include +# else /* !defined(HAS_UVM_INCL) */ +#include +#include +#include +#include +# endif /* defined(HAS_UVM_INCL) */ + +# if defined(HAS_SYS_PIPEH) +# if OPENBSDV==2030 && defined(__sparc__) +# if defined(nbpg) +#undef nbpg +# endif /* defined(nbpg) */ +#define nbpg 4096 /* WARNING!!! This should be 8192 for sun4, + * but there's not much chance this value will + * ever be used by any lsof code. (See the + * use of PIPE_NODIRECT in . */ +# endif /* OPENBSDV==2030 && defined(__sparc__) */ +#include +#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 */ + char type[MFSNAMELEN]; /* type of file system */ + 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(OPENBSDV) && OPENBSDV>=2010) || (defined(NETBSDV) && NETBSDV>=1002000) +#include +#endif /* (defined(OPENBSDV) && OPENBSDV>=2010) || (defined(NETBSDV) && NETBSDV>=1002000) */ + +#include +#include +#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(OPENBSDV) && OPENBSDV>=2010) || (defined(NETBSDV) && NETBSDV>=1002000) +#define NCACHE_NXT nc_hash.le_next /* link in NCACHE */ +# else /* (defined(OPENBSDV) && OPENBSDV>=2010) || (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(OPENBSDV) && OPENBSDV>=2010) || (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) */ + +#endif /* NETBSD_LSOF_H */ diff --git a/dialects/n+obsd/dmnt.c b/dialects/n+obsd/dmnt.c new file mode 100644 index 0000000..51aa4b0 --- /dev/null +++ b/dialects/n+obsd/dmnt.c @@ -0,0 +1,256 @@ +/* + * dmnt.c - NetBSD and 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"; +static char *rcsid = "$Id: dmnt.c,v 1.12 2005/08/08 19:53:24 abe Exp $"; +#endif + + +#if defined(NETBSDV) && defined(HASSTATVFS) +/* + * NetBSD needs the statvfs structure to be defined without the + * pre-definition of _KERNEL. + */ + +#include +#endif /* defined(NETBSDV) && defined(HASSTATVFS) */ + +#include "lsof.h" + + +/* + * Local static definitions + */ + +static struct mounts *Lmi = (struct mounts *)NULL; /* local mount info */ +static int Lmist = 0; /* Lmi status */ + + +/* + * readmnt() - read mount table + */ + +struct mounts * +readmnt() +{ + char *dn = (char *)NULL; + char *ln; + struct 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; + 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"); + Exit(1); + } + if ((ln = Readlink(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(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(dn); + dn = (char *)NULL; + /* + * Stat() the file system (mounted-on) name and add file system + * information to the local mount table entry. + */ + if (!ln || statsafely(ln, &sb)) + sb.st_mode = 0; + mtp->fsnmres = ln; + mtp->fs_mode = sb.st_mode; + Lmi = mtp; + } +/* + * Clean up and return local mount info table address. + */ + if (dn) + (void) free((FREE_P *)dn); + Lmist = 1; + return(Lmi); +} + + +/* + * readvfs() - read vfs structure + */ + +struct l_vfs * +readvfs(vm) + KA_T vm; /* kernel mount address from vnode */ +{ + struct mount m; + struct l_vfs *vp; +/* + * Search for match on existing entry. + */ + for (vp = Lvfs; vp; vp = vp->next) { + if (vm == vp->addr) + return(vp); + } +/* + * Read the (new) mount structure, allocate a local entry, and fill it. + */ + if (kread(vm, (char *)&m, sizeof(m)) != 0) + return((struct l_vfs *)NULL); + if (!(vp = (struct l_vfs *)malloc(sizeof(struct l_vfs)))) { + (void) fprintf(stderr, "%s: PID %d, no space for vfs\n", + Pn, Lp->pid); + Exit(1); + } + if (!(vp->dir = mkstrcpy(m.m_stat.f_mntonname, (MALLOC_S *)NULL)) + || !(vp->fsname = mkstrcpy(m.m_stat.f_mntfromname, (MALLOC_S *)NULL))) + { + (void) fprintf(stderr, "%s: PID %d, no space for mount names\n", + Pn, Lp->pid); + Exit(1); + } + vp->addr = vm; + +#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/dialects/n+obsd/dnode.c b/dialects/n+obsd/dnode.c new file mode 100644 index 0000000..79d7795 --- /dev/null +++ b/dialects/n+obsd/dnode.c @@ -0,0 +1,1459 @@ +/* + * dnode.c - NetBSD and 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"; +static char *rcsid = "$Id: dnode.c,v 1.38 2007/04/24 16:22:02 abe Exp $"; +#endif + + +#include "lsof.h" + + +#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 +_PROTOTYPE(static int lkup_dev_tty,(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) +_PROTOTYPE(static void getmemsz,(pid_t pid)); + +# if !defined(PGSHIFT) +#define PGSHIFT pgshift +# endif /* !defined(PGSHIFT) */ + + +/* + * getmemsz() - get memory size of a /proc//mem entry + */ + +static void +getmemsz(pid) + 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((KA_T)p->P_VMSPACE, (char *)&vm, sizeof(vm))) + return; +# if defined(OPENBSDV) + Lf->sz = (SZOFFTYPE)((vm.vm_tsize + vm.vm_dsize + + vm.vm_ssize) * sysconf(_SC_PAGESIZE)); +# else /* !defined(OPENBSDV */ + Lf->sz = (SZOFFTYPE)ctob(vm.vm_tsize + vm.vm_dsize + + vm.vm_ssize); +# endif /* defined(OPENBSDV) */ + + 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(dr, ir) + dev_t *dr; /* place to return device number */ + INODETYPE *ir; /* place to return inode number */ +{ + int i; + + readdev(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(&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(); + 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(ka) + KA_T ka; /* kqueue file structure address */ +{ + +# if defined(OPENBSDV) + struct kqueue kq; /* kqueue structure */ +# endif /* defined(OPENBSDV) */ + + (void) snpf(Lf->type, sizeof(Lf->type), "KQUEUE"); + enter_dev_ch(print_kptr(ka, (char *)NULL, 0)); + +# if defined(OPENBSDV) + if (!ka || kread(ka, (char *)&kq, sizeof(kq))) + return; + (void) snpf(Namech, Namechl, "count=%d, state=%#x", kq.kq_count, + kq.kq_state); + enter_nm(Namech); +# endif /* defined(OPENBSDV) */ + +} +#endif /* defined(HASKQUEUE) */ + + +/* + * process_node() - process vnode + */ + +void +process_node(va) + 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, *ty; + struct lockf lf, *lff, *lfp; + struct inode i; + struct mfsnode m; + struct nfsnode n; + enum nodetype {NONODE, CDFSNODE, DOSNODE, EXT2NODE, FDESCNODE, INODE, + KERNFSNODE, MFSNODE, NFSNODE, PFSNODE, PTYFSNODE} 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; + 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(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("no vnode address"); + return; + } + v = &vb; + if (readvnode(va, v)) { + enter_nm(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((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(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(Namech); + return; + } + iso_stat = 1; + nty = CDFSNODE; + break; +#endif /* defined(HAS9660FS) */ + +#if defined(HASFDESCFS) + case VT_FDESC: + if (!v->v_data + || kread((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(Namech); + return; + } + nty = FDESCNODE; + break; +#endif /* defined(HASFDESCFS) */ + +#if defined(HASKERNFS) + case VT_KERNFS: + + /* + * Read the kernfs_node. + */ + if (!v->v_data + || kread((KA_T)v->v_data, (char *)&kn, sizeof(kn))) { + if (v->v_type != VDIR || !(v->v_flag && VROOT)) { + (void) snpf(Namech, Namechl, + "can't read kernfs_node at: %s", + print_kptr((KA_T)v->v_data, (char *)NULL, 0)); + enter_nm(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((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((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->v_flag & 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((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(Namech); + return; + } + nty = MFSNODE; + break; + +#if defined(HASMSDOSFS) + case VT_MSDOSFS: + if (!v->v_data + || kread((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(Namech); + return; + } + nty = DOSNODE; + break; +#endif /* defined(HASMSDOSFS) */ + + case VT_NFS: + if (!v->v_data + || kread((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(Namech); + return; + } + +#if defined(HASNFSVATTRP) + if (!n.n_vattr + || kread((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(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((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(Namech); + return; + } + if (!nu.null_lowervp) { + (void) snpf(Namech, Namechl, "null_node overlays nothing"); + enter_nm(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((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(Namech); + return; + } + nty = PFSNODE; + break; +#endif /* defined(HASPROCFS) */ + +#if defined(HASPTYFS) + case VT_PTYFS: + if (!v->v_data + || kread((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(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((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(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((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((KA_T)i.i_ump, (char *)&um, sizeof(um))) { + if (um.um_fstype == UFS1) { + ffs = 1; + if (i.DINODE_U.ffs1_din + && !kread((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((KA_T)i.DINODE_U.ffs2_din, (char *)&u2, + sizeof(u2))) + { + u2s = 1; + } + } + } +#endif /* defined(HASI_FFS1) */ + + } + + if ((lff = i.i_lockf)) { + + /* + * Determine the lock state. + */ + lfp = lff; + do { + if (kread((KA_T)lfp, (char *)&lf, sizeof(lf))) + break; + lt = 0; + switch(lf.lf_flags & (F_FLOCK|F_POSIX)) { + case F_FLOCK: + if (Cfp && (struct file *)lf.lf_id == Cfp) + lt = 1; + break; + case F_POSIX: + if ((KA_T)lf.lf_id == Kpa) + lt = 1; + +#if defined(HAS_LWP_H) && !defined(HAS_LF_LWP) + else { + + struct lwp lw; + + if (!kread((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 ? 'R' : 'r'; + else if (lf.lf_type == F_WRLCK) + Lf->lock = lt ? 'W' : 'w'; + else if (lf.lf_type == (F_RDLCK | F_WRLCK)) + Lf->lock = 'u'; + break; + } while ((lfp = lf.lf_next) && lfp != lff); + } + break; + default: + if (v->v_type == VBAD || v->v_type == VNON) + break; + (void) snpf(Namech, Namechl, "unknown file system type: %d", + v->v_tag); + enter_nm(Namech); + return; + } +/* + * Get device and type for printing. + */ + 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((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(&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((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) */ + + } +/* + * Obtain the inode number. + */ + switch (nty) { + +#if defined(HASMSDOSFS) + case DOSNODE: + if (d.de_pmp && !kread((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) */ + + } + +/* + * Obtain the file size. + */ + if (Foffset) + Lf->off_def = 1; + else { + 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: + if (!Fsize) + Lf->off_def = 1; + 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(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(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) */ + + } + } else if ((type == VCHR || type == VBLK) && !Fsize) + Lf->off_def = 1; + break; + } + } +/* + * Record the link count. + */ + if (Fnlink) { + 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: + ty ="VNON"; + break; + case VREG: + ty = "VREG"; + break; + case VDIR: + ty = "VDIR"; + break; + case VBLK: + ty = "VBLK"; + Ntype = N_BLK; + break; + case VCHR: + ty = "VCHR"; + Ntype = N_CHR; + break; + case VLNK: + ty = "VLNK"; + break; + +#if defined(VSOCK) + case VSOCK: + ty = "SOCK"; + break; +#endif /* defined(VSOCK) */ + + case VBAD: + ty = "VBAD"; + break; + case VFIFO: + ty = "FIFO"; + break; + default: + (void) snpf(Lf->type, sizeof(Lf->type), "%04o", (type & 0xfff)); + ty = NULL; + } + if (ty) + (void) snpf(Lf->type, sizeof(Lf->type), "%s", ty); + 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("memory"); + } + +#if defined(HASPROCFS) + else if (nty == PFSNODE) { + Lf->dev_def= Lf->rdev_def = 0; + ty = NULL; + (void) snpf(Namech, Namechl, "/%s", HASPROCFS); + switch (p.pfs_type) { + case Proot: + ty = "PDIR"; + break; + case Pcurproc: + ep = endnm(&sz); + (void) snpf(ep, sz, "/curproc"); + ty = "PCUR"; + break; + case Pproc: + ep = endnm(&sz); + (void) snpf(ep, sz, "/%d", p.pfs_pid); + ty = "PDIR"; + break; + case Pfile: + ep = endnm(&sz); + (void) snpf(ep, sz, "/%d/file", p.pfs_pid); + ty = "PFIL"; + break; + case Pmem: + ep = endnm(&sz); + (void) snpf(ep, sz, "/%d/mem", p.pfs_pid); + ty = "PMEM"; + break; + case Pregs: + ep = endnm(&sz); + (void) snpf(ep, sz, "/%d/regs", p.pfs_pid); + ty = "PREG"; + break; + case Pfpregs: + ep = endnm(&sz); + (void) snpf(ep, sz, "/%d/fpregs", p.pfs_pid); + ty = "PFPR"; + break; + case Pctl: + ep = endnm(&sz); + (void) snpf(ep, sz, "/%d/ctl", p.pfs_pid); + ty = "PCTL"; + break; + case Pstatus: + ep = endnm(&sz); + (void) snpf(ep, sz, "/%d/status", p.pfs_pid); + ty = "PSTA"; + break; + case Pnote: + ep = endnm(&sz); + (void) snpf(ep, sz, "/%d/note", p.pfs_pid); + ty = "PNTF"; + break; + case Pnotepg: + ep = endnm(&sz); + (void) snpf(ep, sz, "/%d/notepg", p.pfs_pid); + ty = "PGID"; + break; + +# if defined(Pfd) + case Pfd: + ep = endnm(&sz); + (void) snpf(ep, sz, "/%d/fd", p.pfs_pid); + ty = "PFD"; + break; +# endif /* defined(Pfd) */ + +# if defined(Pmap) + case Pmap: + ep = endnm(&sz); + (void) snpf(ep, sz, "/%d/map", p.pfs_pid); + ty = "PMAP"; + break; +# endif /* defined(Pmap) */ + +# if defined(Pmaps) + case Pmaps: + ep = endnm(&sz); + (void) snpf(ep, sz, "/%d/maps", p.pfs_pid); + ty = "PMPS"; + break; +# endif /* defined(Pmaps) */ + + } + if (ty) + (void) snpf(Lf->type, sizeof(Lf->type), ty); + } +#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(&sz); + (void) snpf(ep, sz, "/%lu", (unsigned long)pt.ptyfs_pty); + break; + case PTYFSptc: + ep = endnm(&sz); + (void) snpf(ep, sz, "/%lu (master)", + (unsigned long)pt.ptyfs_pty); + break; + case PTYFSroot: + Lf->sz = 512; + Lf->sz_def = 1; + break; + } + if (ty) + (void) snpf(Lf->type, sizeof(Lf->type), ty); + } +#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(); +#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 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(Namech); + ns = 1; + } else + ns = 0; + if (Sfile && is_file_named((char *)NULL, + ((type == VCHR) || (type == VBLK)) ? 1 + : 0)) + { + Lf->sf |= SELNM; + } + if (ns) + Namech[0] = '\0'; + } +/* + * Enter name characters. + */ + if (Namech[0]) + enter_nm(Namech); +} + + +#if defined(HAS_SYS_PIPEH) +/* + * process_pipe() - process a file structure whose type is DTYPE_PIPE + */ + +void +process_pipe(pa) + KA_T pa; /* pipe structure kernel address */ +{ + char *ep; + struct pipe p; + size_t sz; + + if (!pa || kread((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(Namech); + return; + } + (void) snpf(Lf->type, sizeof(Lf->type), "PIPE"); + enter_dev_ch(print_kptr(pa, (char *)NULL, 0)); + if (Foffset) + Lf->off_def = 1; + else { + 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(&sz); + (void) snpf(ep, sz, ", cnt=%d", p.pipe_buffer.cnt); + } + if (p.pipe_buffer.in) { + ep = endnm(&sz); + (void) snpf(ep, sz, ", in=%d", p.pipe_buffer.in); + } + if (p.pipe_buffer.out) { + ep = endnm(&sz); + (void) snpf(ep, sz, ", out=%d", p.pipe_buffer.out); + } +/* + * Enter name characters. + */ + if (Namech[0]) + enter_nm(Namech); +} +#endif /* defined(HAS_SYS_PIPEH) */ diff --git a/dialects/n+obsd/dnode1.c b/dialects/n+obsd/dnode1.c new file mode 100644 index 0000000..55a1c30 --- /dev/null +++ b/dialects/n+obsd/dnode1.c @@ -0,0 +1,95 @@ +/* + * dnode1.c - NetBSD and OpenBSD 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"; +static char *rcsid = "$Id: dnode1.c,v 1.8 2005/08/08 19:53:24 abe Exp $"; +#endif + + +#include "lsof.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 + + +/* + * At last, #include the desired header files. + */ + +# if HAS9660FS==1 +#include +#include +# else /* HAS9660FS!=1 */ +#include +#include +# endif /* HAS9660FS==1 */ + + +/* + * read_iso_node() -- read CD 9660 iso_node + */ + +int +read_iso_node(v, d, ino, nl, sz) + 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((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/dialects/n+obsd/dproc.c b/dialects/n+obsd/dproc.c new file mode 100644 index 0000000..2cf532b --- /dev/null +++ b/dialects/n+obsd/dproc.c @@ -0,0 +1,584 @@ +/* + * dproc.c - NetBSD and 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"; +static char *rcsid = "$Id: dproc.c,v 1.17 2005/05/11 12:53:54 abe Exp $"; +#endif + +#include "lsof.h" + + +_PROTOTYPE(static void enter_vn_text,(KA_T va, int *n)); +_PROTOTYPE(static void get_kernel_access,(void)); +_PROTOTYPE(static void process_text,(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(d, er, ev, ea) + 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)); + Exit(1); + } +/* + * 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(va, n) + KA_T va; /* vnode address */ + int *n; /* Vp[] entries in use */ +{ + int i; +/* + * Ignore the request if the vnode has already been entered. + */ + for (i = 0; i < *n; i++) { + if (va == Vp[i]) + return; + } +/* + * Save the text file information. + */ + alloc_lfile(" txt", -1); + Cfp = (struct file *)NULL; + process_node((KA_T)va); + if (Lf->sf) + link_lfile(); + if (i >= Nv) { + + /* + * Allocate space for remembering the vnode. + */ + Nv += 10; + if (!Vp) + Vp=(KA_T *)malloc((MALLOC_S)(sizeof(struct vnode *) * 10)); + else + Vp=(KA_T *)realloc((MALLOC_P *)Vp,(MALLOC_S)(Nv*sizeof(KA_T))); + if (!Vp) { + (void) fprintf(stderr, "%s: no txt ptr space, PID %d\n", + Pn, Lp->pid); + Exit(1); + } + } +/* + * Remember the vnode. + */ + Vp[*n] = va; + (*n)++; +} + + +/* + * gather_proc_info() -- gather process information + */ + +void +gather_proc_info() +{ + struct filedesc fd; + int i, nf; + MALLOC_S nb; + static struct file **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) */ + +/* + * 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)); + Exit(1); + } +/* + * 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((int)p->P_PID, (int)p->P_PGID, (UID_ARG)uid, + &pss, &sf)) + { + continue; + } + if (!p->P_FD + || kread((KA_T)p->P_FD, (char *)&fd, sizeof(fd))) + continue; + if (!fd.fd_refcnt || fd.fd_lastfile > fd.fd_nfiles) + continue; + +#if defined(HASCWDINFO) + if (!p->P_CWDI + || kread((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(p->P_COMM, &pss, &sf)) + continue; + alloc_lproc((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(CWD, -1); + Cfp = (struct file *)NULL; + process_node((KA_T)CDIR); + if (Lf->sf) + link_lfile(); + } + /* + * Save root directory information. + */ + if (RDIR) { + alloc_lfile(RTD, -1); + Cfp = (struct file *)NULL; + process_node((KA_T)RDIR); + if (Lf->sf) + link_lfile(); + } + +#if defined(OPENBSDV) && OPENBSDV>=3020 + /* + * Save trace node information. + */ + if (p->P_TRACEP) { + alloc_lfile("tr", -1); + Cfp = (struct file *)NULL; + process_node((KA_T)p->P_TRACEP); + if (Lf->sf) + link_lfile(); + } +#endif /* defined(OPENBSDV) && OPENBSDV>=3020 */ + + /* + * Save information on the text file. + */ + if (p->P_VMSPACE) + process_text((KA_T)p->P_VMSPACE); + /* + * Read open file structure pointers. + */ + if (!fd.fd_ofiles || (nf = fd.fd_nfiles) <= 0) + continue; + nb = (MALLOC_S)(sizeof(struct file *) * nf); + if (nb > ofbb) { + if (!ofb) + ofb = (struct file **)malloc(nb); + else + ofb = (struct file **)realloc((MALLOC_P *)ofb, nb); + if (!ofb) { + (void) fprintf(stderr, "%s: PID %d, no file * space\n", + Pn, p->P_PID); + Exit(1); + } + ofbb = nb; + } + if (kread((KA_T)fd.fd_ofiles, (char *)ofb, nb)) + continue; + +#if defined(HASFSTRUCT) + if (Fsv & FSV_FG) { + nb = (MALLOC_S)(sizeof(char) * nf); + if (nb > pofb) { + if (!pof) + pof = (char *)malloc(nb); + else + pof = (char *)realloc((MALLOC_P *)pof, nb); + if (!pof) { + (void) fprintf(stderr, + "%s: PID %d, no file flag space\n", Pn, p->P_PID); + Exit(1); + } + pofb = nb; + } + if (!fd.fd_ofileflags || kread((KA_T)fd.fd_ofileflags, pof, nb)) + zeromem(pof, nb); + } +#endif /* defined(HASFSTRUCT) */ + + /* + * Save information on file descriptors. + */ + for (i = 0; i < nf; i++) { + if (ofb[i]) { + alloc_lfile(NULL, i); + process_file((KA_T)(Cfp = ofb[i])); + if (Lf->sf) { + +#if defined(HASFSTRUCT) + if (Fsv & FSV_FG) + Lf->pof = (long)pof[i]; +#endif /* defined(HASFSTRUCT) */ + + link_lfile(); + } + } + } + /* + * Examine results. + */ + if (examine_lproc()) + return; + } +} + + +/* + * get_kernel_access() - get access to kernel memory + */ + +static void +get_kernel_access() +{ + KA_T v; +/* + * Check kernel version. + */ + (void) ckkv( + +#if defined(NETBSDV) + "NetBSD", +#else /* !defined(NETBSDV) */ +# if defined(OPENBSDV) + "OpenBSD", +# endif /* defined(OPENBSDV) */ +#endif /* defined(NETBSDV) */ + + 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(1))) { + (void) fprintf(stderr, + "%s: can't get kernel name list path\n", Pn); + Exit(1); + } + } +#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(); +#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))) + Exit(1); +#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)); + Exit(1); + } + (void) build_Nl(Drive_Nl); + if (kvm_nlist(Kd, Nl) < 0) { + (void) fprintf(stderr, "%s: can't read namelist from %s\n", + Pn, Nmlst); + Exit(1); + } + +#if defined(WILLDROPGID) +/* + * Drop setgid permission, if necessary. + */ + if (!Memory) + (void) dropgid(); +#endif /* defined(WILLDROPGID) */ + +/* + * Read the kernel's page shift amount, if possible. + */ + if (get_Nl_value("pgshift", Drive_Nl, &v) < 0 || !v + || kread((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(ap) + 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); + Exit(1); + } + (void) snpf(bfc, bfl, "%s", bf); + return(bfc); + } + return((char *)NULL); +} +#endif /* !defined(N_UNIX) */ + + +/* + * initialize() - perform all initialization + */ + +void +initialize() +{ + get_kernel_access(); +} + + +/* + * kread() - read from kernel memory + */ + +int +kread(addr, buf, len) + KA_T addr; /* kernel memory address */ + char *buf; /* buffer to receive data */ + READLEN_T len; /* length to read */ +{ + int br; + + br = kvm_read(Kd, (u_long)addr, buf, len); + return((br == len) ? 0 : 1); +} + + +/* + * process_text() - process text information + */ +void +process_text(vm) + 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(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(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((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(ka, (char *)&vmo, sizeof(vmo))) + break; + if (!(ka = (KA_T)vmo.pager) + || kread(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/dialects/n+obsd/dproto.h b/dialects/n+obsd/dproto.h new file mode 100644 index 0000000..d94627f --- /dev/null +++ b/dialects/n+obsd/dproto.h @@ -0,0 +1,55 @@ +/* + * dproto.h - NetBSD and 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 $ + */ + + +#if !defined(N_UNIX) +_PROTOTYPE(extern char *get_nlist_path,(int ap)); +#endif /* !defined(N_UNIX) */ + +_PROTOTYPE(extern int is_file_named,(char *p, int cd)); +_PROTOTYPE(extern struct l_vfs *readvfs,(KA_T vm)); + +#if defined(HAS_SYS_PIPE_H) +_PROTOTYPE(extern void process_pipe,(KA_T pa)); +#endif /* defined(HAS_SYS_PIPEH) */ + +#if defined(HAS9660FS) +_PROTOTYPE(extern int read_iso_node,(struct vnode *v, dev_t *d, INODETYPE *ino, long *nl, SZOFFTYPE *sz)); +#endif /* defined(HAS9660FS) */ + +_PROTOTYPE(extern void process_socket,(KA_T sa)); diff --git a/dialects/n+obsd/dsock.c b/dialects/n+obsd/dsock.c new file mode 100644 index 0000000..0e10971 --- /dev/null +++ b/dialects/n+obsd/dsock.c @@ -0,0 +1,425 @@ +/* + * dsock.c - NetBSD and 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"; +static char *rcsid = "$Id: dsock.c,v 1.25 2005/08/08 19:53:24 abe Exp $"; +#endif + + +#include "lsof.h" + + +#if defined(HASIPv6) + +/* + * IPv6_2_IPv4() -- macro to define the address of an IPv4 address contained + * in an IPv6 address + */ + +#define IPv6_2_IPv4(v6) (((uint8_t *)((struct in6_addr *)v6)->s6_addr)+12) +#endif /* defined(HASIPv6) */ + + +/* + * process_socket() - process socket + */ + +void +process_socket(sa) + KA_T sa; /* socket address in kernel */ +{ + struct domain d; + unsigned char *fa = (unsigned char *)NULL; + int fam; + int fp, lp; + struct inpcb inp; + unsigned char *la = (unsigned char *)NULL; + struct protosw p; + struct socket s; + struct tcpcb t; + KA_T ta = (KA_T)NULL; + struct unpcb uc, unp; + struct sockaddr_un *ua = NULL; + struct sockaddr_un un; + +#if defined(HASIPv6) && defined(NETBSDV) && !defined(HASINRIAIPv6) + 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) */ + + (void) snpf(Lf->type, sizeof(Lf->type), "sock"); + Lf->inp_ty = 2; +/* + * Read the socket, protocol, and domain structures. + */ + if (!sa) { + enter_nm("no socket address"); + return; + } + if (kread(sa, (char *) &s, sizeof(s))) { + (void) snpf(Namech, Namechl, "can't read socket struct from %s", + print_kptr(sa, (char *)NULL, 0)); + enter_nm(Namech); + return; + } + if (!s.so_type) { + enter_nm("no socket type"); + return; + } + if (!s.so_proto + || kread((KA_T)s.so_proto, (char *)&p, sizeof(p))) { + (void) snpf(Namech, Namechl, "can't read protocol switch from %s", + print_kptr((KA_T)s.so_proto, (char *)NULL, 0)); + enter_nm(Namech); + return; + } + if (!p.pr_domain + || kread((KA_T)p.pr_domain, (char *)&d, sizeof(d))) { + (void) snpf(Namech, Namechl, "can't read domain struct from %s", + print_kptr((KA_T)p.pr_domain, (char *)NULL, 0)); + enter_nm(Namech); + return; + } +/* + * Save size information. + */ + if (Fsize) { + if (Lf->access == 'r') + Lf->sz = (SZOFFTYPE)s.so_rcv.sb_cc; + else if (Lf->access == 'w') + Lf->sz = (SZOFFTYPE)s.so_snd.sb_cc; + else + Lf->sz = (SZOFFTYPE)(s.so_rcv.sb_cc + s.so_snd.sb_cc); + Lf->sz_def = 1; + } else + Lf->off_def = 1; + +#if defined(HASTCPTPIQ) + Lf->lts.rq = s.so_rcv.sb_cc; + Lf->lts.sq = s.so_snd.sb_cc; + Lf->lts.rqs = Lf->lts.sqs = 1; +#endif /* defined(HASTCPTPIQ) */ + +#if defined(HASSOOPT) + Lf->lts.ltm = (unsigned int)s.so_linger; + 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(p.pr_protocol); + +#if defined(HASIPv6) + (void) snpf(Lf->type, sizeof(Lf->type), + (fam == AF_INET) ? "IPv4" : "IPv6"); +#else /* !defined(HASIPv6) */ + (void) snpf(Lf->type, sizeof(Lf->type), "inet"); +#endif /* defined(HASIPv6) */ + +#if defined(HASIPv6) && defined(NETBSDV) && !defined(HASINRIAIPv6) + if (fam == AF_INET6) { + + /* + * Read IPv6 protocol control block. + */ + if (!s.so_pcb + || kread((KA_T)s.so_pcb, (char *)&in6p, sizeof(in6p))) { + (void) snpf(Namech, Namechl, "can't read in6pcb at %s", + print_kptr((KA_T)s.so_pcb, (char *)NULL, 0)); + enter_nm(Namech); + return; + } + /* + * Save IPv6 address information. + */ + enter_dev_ch(print_kptr((KA_T)(in6p.in6p_ppcb ? in6p.in6p_ppcb + : s.so_pcb), + (char *)NULL, 0)); + if (p.pr_protocol == IPPROTO_TCP) + ta = (KA_T)in6p.in6p_ppcb; + la = (unsigned char *)&in6p.in6p_laddr; + lp = (int)ntohs(in6p.in6p_lport); + if (!IN6_IS_ADDR_UNSPECIFIED(&in6p.in6p_faddr) + || in6p.in6p_fport) + { + fa = (unsigned char *)&in6p.in6p_faddr; + fp = (int)ntohs(in6p.in6p_fport); + } + } else +#endif /* defined(HASIPv6) && defined(NETBSDV) && !defined(HASINRIAIPv6) */ + + { + + /* + * Read IPv4 or IPv6 (OpenBSD) protocol control block. + */ + if (!s.so_pcb + || kread((KA_T)s.so_pcb, (char *)&inp, sizeof(inp))) { + if (!s.so_pcb) { + (void) snpf(Namech, Namechl, "no PCB%s%s", + (s.so_state & SS_CANTSENDMORE) ? ", CANTSENDMORE" + : "", + (s.so_state & SS_CANTRCVMORE) ? ", CANTRCVMORE" + : ""); + } else { + (void) snpf(Namech, Namechl, "can't read inpcb at %s", + print_kptr((KA_T)s.so_pcb, (char *)NULL, 0)); + } + enter_nm(Namech); + return; + } + enter_dev_ch(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); + if (fam == AF_INET) { + + /* + * Save IPv4 address information. + */ + 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); + } + } + +#if defined(HASIPv6) && (defined(OPENBSDV) || 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(OPENBSDV) || 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(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(ta, (char *)&t, sizeof(t))) { + Lf->lts.type = 0; + Lf->lts.state.i = (int)t.t_state; + +#if defined(HASTCPOPT) +# if defined(OPENBSDV) + Lf->lts.mss = (unsigned long)t.t_maxseg; +# else /* !defined(OPENSDV) */ + Lf->lts.mss = (unsigned long)t.t_ourmss; +# endif /* defined(OPENSDV) */ + + 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: + (void) snpf(Lf->type, sizeof(Lf->type), "rte"); + if (s.so_pcb) + enter_dev_ch(print_kptr((KA_T)(s.so_pcb), (char *)NULL, 0)); + else + (void) snpf(Namech, Namechl, "no protocol control block"); + if (!Fsize) + Lf->off_def = 1; + break; +/* + * Process a Unix domain socket. + */ + case AF_UNIX: + if (Funix) + Lf->sf |= SELUNX; + (void) snpf(Lf->type, sizeof(Lf->type), "unix"); + /* + * Read Unix protocol control block and the Unix address structure. + */ + + enter_dev_ch(print_kptr(sa, (char *)NULL, 0)); + if (kread((KA_T) s.so_pcb, (char *) &unp, sizeof(unp))) { + (void) snpf(Namech, Namechl, "can't read unpcb at %s", + print_kptr((KA_T)s.so_pcb, (char *)NULL, 0)); + break; + } + if ((struct socket *)sa != unp.unp_socket) { + (void) snpf(Namech, Namechl, "unp_socket (%s) mismatch", + print_kptr((KA_T)unp.unp_socket, (char *)NULL, 0)); + break; + } + if (unp.unp_addr) { + +#if defined(UNPADDR_IN_MBUF) + if (kread((KA_T)unp.unp_addr, (char *)&mb, sizeof(mb))) +#else /* !defined(UNPADDR_IN_MBUF) */ + if (kread((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((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(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); +} diff --git a/dialects/n+obsd/dstore.c b/dialects/n+obsd/dstore.c new file mode 100644 index 0000000..3205c79 --- /dev/null +++ b/dialects/n+obsd/dstore.c @@ -0,0 +1,132 @@ +/* + * dstore.c - NetBSD and 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"; +static char *rcsid = "$Id: dstore.c,v 1.9 2004/12/30 18:42:24 abe Exp $"; +#endif + + +#include "lsof.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(OPENBSDV) && OPENBSDV>=2010) || (defined(NETBSDV) && NETBSDV>=1002000) + { X_NCACHE, "_nchashtbl", }, + { X_NCSIZE, "_nchash" }, +#else /* (defined(OPENBSDV) && OPENBSDV>=2010) || (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(OPENBSDV) && OPENBSDV>=2010) || (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 }, +# 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/dialects/n+obsd/machine.h b/dialects/n+obsd/machine.h new file mode 100644 index 0000000..20e2ce9 --- /dev/null +++ b/dialects/n+obsd/machine.h @@ -0,0 +1,623 @@ +/* + * machine.h - NetBSD and 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 + + +#include +#include + + +/* + * 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 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? */ +/* #define HASPRINTOFF print_off? */ +/* #define HASPRINTSZ print_sz? */ + + +/* + * HASPRIVFILETYPE and PRIVFILETYPE are defined for dialects that have a + * file structure type that isn't defined by a DTYPE_* symbol. They are + * used in lib/prfp.c to select the type's processing. + * + * PRIVFILETYPE is the definition of the f_type value in the file struct. + * + * HASPRIVFILETYPE is the name of the processing function. + */ + +/* #define HASPRIVFILETYPE process_shmf? */ +/* #define PRIVFILETYPE ?? */ + + +/* + * HASPRIVNMCACHE is defined for dialects that have a private method for + * printing cached NAME column values for some files. HASPRIVNAMECACHE + * is defined to be the name of the function. + * + * The function takes one argument, a struct lfile pointer to the file, and + * returns non-zero if it prints a name to stdout. + */ + +/* #define HASPRIVNMCACHE */ + + +/* + * 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 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 */ + + +/* + * 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_ is defined for dialects that use the + * in the lsof library. + * + * Note: other definitions and operations may be required to condition the + * library function source code. They may be found in the dialect dlsof.h + * header files. + */ + +/* #define USE_LIB_CKKV 1 ckkv.c */ +/* #define USE_LIB_COMPLETEVFS 1 cvfs.c */ +#define USE_LIB_FIND_CH_INO 1 /* fino.c */ +#define USE_LIB_IS_FILE_NAMED 1 /* isfn.c */ +#define USE_LIB_LKUPDEV 1 /* lkud.c */ +#define USE_LIB_PRINTDEVNAME 1 /* pdvn.c */ +#define USE_LIB_PROCESS_FILE 1 /* prfp.c */ +#define USE_LIB_PRINT_TCPTPI 1 /* ptti.c */ +#define USE_LIB_READDEV 1 /* rdev.c */ +/* #define USE_LIB_READMNT 1 rmnt.c */ +/* #define USE_LIB_REGEX 1 regex.c */ + +# if (defined(OPENBSDV) && OPENBSDV>=2010) || (defined(NETBSDV) && NETBSDV>=1002000) +#define USE_LIB_RNMH 1 /* rnmh.c */ +# else /* (defined(OPENBSDV) && OPENBSDV<2010) && (defined(NETBSDV) && NETBSDV<1002000) */ +#define USE_LIB_RNAM 1 /* rnam.c */ +# endif /* (defined(OPENBSDV) && OPENBSDV>=2010) || (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/dialects/n+os/Makefile b/dialects/n+os/Makefile new file mode 100644 index 0000000..8049a88 --- /dev/null +++ b/dialects/n+os/Makefile @@ -0,0 +1,169 @@ + +# N+OS Makefile +# +# $Id: Makefile,v 1.14 2008/04/15 13:30:27 abe Exp $ + +PROG= lsof + +BIN= ${DESTDIR} + +DOC= ${DESTDIR} + +I=/usr/include +S=/usr/include/sys +L=/usr/include/local +P= + +# Use the RC_CFLAGS environment variable to define architecture types. +# To create a "fat" executable, supporting more than one architecture, +# set RC_CFLAGS before executing make -- e.g., to build a "fat" executable +# for m68k, i486, hppa, and SPARC, using /bin/sh: +# +# $ cd +# $ ./Configure ns +# $ RC_CFLAGS="-arch m68k -arch i486 -arch hppa -arch sparc" +# $ export RC_CFLAGS +# $ make + +CDEF= ${RC_CFLAGS} +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= dnode.c denode1.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= dnode.o dnode1.o dproc.o dsock.o dstore.o \ + arg.o main.o misc.o node.o print.o proc.o store.o usage.o \ + util.o + +MAN= lsof.8 + +OTHER= + +SHELL= /bin/sh + +SOURCE= Makefile ${OTHER} ${MAN} ${HDR} ${SRC} + +all: ${PROG} + +${PROG}: ${LIB} ${P} ${OBJ} + ${CC} -o $@ ${CFLAGS} ${OBJ} ${CFGL} + +clean: FRC + rm -f Makefile.bak ${PROG} a.out core errs lint.out tags *.o version.h + rm -f machine.h.old new_machine.h + (cd lib; ${MAKE} -f Makefile.skel clean) + +install: 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 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 $${MAN} $${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= kmem' + @echo '' + +${LIB}: FRC + (cd lib; ${MAKE} DEBUG="${DEBUG}" CFGF="${CFGF}") + +version.h: FRC + @echo Constructing version.h + @rm -f version.h + @echo '#define LSOF_BLDCMT "${LSOF_BLDCMT}"' > version.h; + @echo '#define LSOF_CC "${CC}"' >> version.h + @echo '#define LSOF_CCV "${CCV}"' >> version.h + @echo '#define LSOF_CCDATE "'`date`'"' >> version.h + @echo '#define LSOF_CCFLAGS "'`echo ${CFLAGS} | sed 's/\\\\(/\\(/g' | sed 's/\\\\)/\\)/g' | sed 's/"/\\\\"/g'`'"' >> version.h + @echo '#define LSOF_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_HOST}" = "X" ]; then \ + echo '#define LSOF_HOST "'`hostname`'"' >> 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 + @if [ "X${LSOF_SYSINFO}" = "X" ]; then \ + echo '#define LSOF_SYSINFO "'`hostinfo | head -2 | tail -1`'"' >> version.h; \ + else \ + if [ "${LSOF_SYSINFO}" = "none" ]; then \ + echo '#define LSOF_SYSINFO ""' >> version.h; \ + else \ + echo '#define LSOF_SYSINFO "${LSOF_SYSINFO}"' >> version.h; \ + fi \ + fi + @if [ "X${LSOF_USER}" = "X" ]; then \ + echo '#define LSOF_USER "${USER}"' >> version.h; \ + else \ + if [ "${LSOF_USER}" = "none" ]; then \ + echo '#define LSOF_USER ""' >> version.h; \ + else \ + echo '#define LSOF_USER "${LSOF_USER}"' >> version.h; \ + fi \ + fi + @sed '/VN/s/.ds VN \(.*\)/#define LSOF_VERSION "\1"/' < version >> version.h + +FRC: + +# DO NOT DELETE THIS LINE - make depend DEPENDS ON IT + +ddev.o: ${HDR} ddev.c + +dfile.o: ${HDR} dfile.c + +dmnt.o: ${HDR} dmnt.c + +dnode.o: ${HDR} dnode.c + +dnode1.o: ${HDR} dnode1.c + +dproc.o: ${HDR} dproc.c + +dsock.o: ${HDR} dsock.c + +dstore.o: ${HDR} dstore.c + +arg.o: ${HDR} arg.c + +main.o: ${HDR} main.c + +misc.o: ${HDR} misc.c + +node.o: ${HDR} node.c + +print.o: ${HDR} print.c + +proc.o: ${HDR} proc.c + +store.o: ${HDR} store.c + +usage.o: ${HDR} version.h usage.c + +util.o: ${HDR} util.c + +# *** Do not add anything here - It will go away. *** diff --git a/dialects/n+os/Mksrc b/dialects/n+os/Mksrc new file mode 100755 index 0000000..9abc4be --- /dev/null +++ b/dialects/n+os/Mksrc @@ -0,0 +1,24 @@ +#!/bin/sh +# +# Mksrc - make NEXTSTEP and OPENSTEP source files +# +# WARNING: This script assumes it is running from the main directory +# of the lsof, version 4 distribution. +# +# One environment variable is supplied: +# +# LSOF_MKC is the method for creating the source files. +# It defaults to "ln -s". A common alternative is "cp". +# +# $Id: Mksrc,v 1.6 2001/08/09 11:44:07 abe Exp $ + + +D=dialects/n+os +L="dlsof.h dnode.c dnode1.c dproc.c dproto.h dsock.c dstore.c machine.h" + +for i in $L +do + rm -f $i + $LSOF_MKC $D/$i $i + echo "$LSOF_MKC $D/$i $i" +done diff --git a/dialects/n+os/dlsof.h b/dialects/n+os/dlsof.h new file mode 100644 index 0000000..afd5d9d --- /dev/null +++ b/dialects/n+os/dlsof.h @@ -0,0 +1,272 @@ +/* + * dlsof.h - NEXTSTEP and OPENSTEP 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.14 2006/03/28 22:08:17 abe Exp $ + */ + + +#if !defined(LSOF_NEXT_H) +#define LSOF_NEXT_H 1 + +#include +#include +#include +#include +#include +#include +#include + +# if !defined(NCPUS) +#define NCPUS 1 +# endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +# if !defined(KERNEL) +#define KERNEL +# endif + +#include +#undef KERNEL +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +# if !defined(SHOW_UTT) +#define SHOW_UTT +# endif + +/* + * Define simple_lock_t size. + */ + +# if STEPV>=40 && defined(m68k) +#define SIMPLE_LOCK_SIZE 0 +# elif defined(hppa) /* && (STEPV<40 || !defined(m68k)) */ +#define SIMPLE_LOCK_SIZE 4 +# else /* (STEPV<40 || !defined(m68k)) && !defined(hppa) */ +#define SIMPLE_LOCK_SIZE 1 +# endif /* STEPV>=40 && defined(m68k) */ + +# if !defined(SIMPLE_LOCK_SIZE) +#define SIMPLE_LOCK_SIZE 1 +# endif /* !defined(SIMPLE_LOCK_SIZE) */ + +# if STEPV>=40 +/* + * Define lock_data_t that was removed from OPENSTEP 4.x's . + */ + +typedef struct lock { + char *thread; + unsigned int read_count:16, + want_upgrade:1, + want_write:1, + waiting:1, + can_sleep:1, + recursion_depth:12; + +# if SIMPLE_LOCK_SIZE>0 + caddr_t interlock[SIMPLE_LOCK_SIZE]; +# endif /* SIMPLE_LOCK_SIZE>0 */ + +} lock_data_t; +# endif /* STEPV>=40 */ + +#include +#define u_comm uu_comm +#define u_cdir uu_cdir +#define u_rdir uu_rdir +#undef SHOW_UTT +#include +#include +#include + +typedef int pid_t; + + +/* + * The following substitution compensates for the snode.h that NeXT does + * not supply in NEXTSTEP 2.0 and above. The value of interest is s_realvp. + */ + +struct snode { + struct snode *s_next; /* must be first */ + struct vnode s_vnode; /* vnode associated with this snode */ + struct vnode *s_realvp; /* vnode for the fs entry (if any) */ +}; + + +/* + * Miscellaneous definitions. + */ + +#define COMP_P const void +#define DEVINCR 1024 /* device table malloc() increment */ +typedef off_t KA_T; +#define KMEM "/dev/kmem" +#define MALLOC_P void +#define FREE_P MALLOC_P +#define MALLOC_S size_t +#define MAXSYSCMDL MAXCOMLEN /* max system command name length */ +#define PROCDFLT 256 /* default size of local proc table */ +#define PROCMIN 5 /* processes that make a "good" scan */ +#define PROCSIZE sizeof(struct proc) +#define PROCTRYLM 5 /* times to try to read proc table */ +#define QSORT_P void +#define READLEN_T int +#define STRNCPY_L int +#define U_SIZE sizeof(struct user) + +# if !defined(VMUNIX) +#define VMUNIX "/mach" +# endif + +#define N_UNIX VMUNIX + + +# if defined(HAS_AFS) +/* + * AFS definitions + */ + +#define AFSAPATHDEF "/usr/vice/etc/afs_loadable" +#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) */ + + +/* + * 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 inode number */ + u_short mode; /* directory st_mode */ + u_short fs_mode; /* file system st_mode */ + struct mounts *next; /* forward link */ +}; + + +/* + * Defines for kernel name list + */ + +#define NL_NAME n_un.n_name + + +/* + * For kernel name cache processing + */ + +# if defined(HASNCACHE) +#include +#define X_NCACHE "nch" +#define X_NCSIZE "ncsz" +# endif /* defined(HASNCACHE) */ + + +/* + * Defines for library readdev() function + */ + +#define DIRTYPE direct +#define HASDNAMLEN 1 + + +/* + * 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 */ + 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 + */ + +extern struct file *Fileptr; +#define FILEPTR Fileptr /* for process_file() in lib/prfp.c */ +extern int Kd; + +#endif /* LSOF_NEXT_H */ diff --git a/dialects/n+os/dnode.c b/dialects/n+os/dnode.c new file mode 100644 index 0000000..6747942 --- /dev/null +++ b/dialects/n+os/dnode.c @@ -0,0 +1,711 @@ +/* + * dnode.c - NEXTSTEP and OPENSTEP 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"; +static char *rcsid = "$Id: dnode.c,v 1.17 2006/03/28 22:08:17 abe Exp $"; +#endif + + +#include "lsof.h" + + +#if STEPV>=31 +/* + * Local definitions + */ + +struct l_lockf { /* local lock info */ + short type; /* lock type */ + off_t start, end; /* lock start and end */ + pid_t pid; /* owning process ID */ + struct l_lockf *next; +}; + +struct l_svn { /* shadow vnode */ + KA_T vp; /* associated vnode */ + struct l_lockf *lp; /* local lock chain */ + struct l_svn *next; +}; + +struct posix_proc { + pid_t p_pid; +}; +#define POSIX_KERN 1 +#include + +#define SVNHASH(n) (((int)((long)(n) * 31415l) >> 5) & (LF_SVNODE_HSZ - 1)) + + +/* + * Local static variables + */ + +static struct l_svn **Svnc = (struct l_svn **)NULL; + /* local shadow vnode cache */ +static int SvncSt = 0; /* Svnc[] load status */ + + +/* + * Local function prototypes + */ + +_PROTOTYPE(static char isvlocked,(KA_T vp)); +_PROTOTYPE(static int load_svnc,(void)); + + +/* + * clr_svnc() - clear shadow vnode cache + */ + +void +clr_svnc() +{ + struct l_lockf *lf, *lfn; + int i; + struct l_svn *sv, *svn; + + if (!Svnc || !SvncSt) + return; + for (i = 0; i < LF_SVNODE_HSZ; i++) { + if (!(sv = Svnc[i])) + continue; + do { + if ((lf = sv->lp)) { + do { + lfn = lf->next; + (void) free((FREE_P *)lf); + } while ((lf = lfn)); + } + svn = sv->next; + (void) free((FREE_P *)sv); + } while ((sv = svn)); + Svnc[i] = (struct l_svn *)NULL; + } + SvncSt = 0; +} + + +/* + * isvlocked() - is vnode locked? + */ + +static char +isvlocked(vp) + KA_T vp; /* vnode's kernel address */ +{ + int i; + struct l_lockf *lp; + struct l_svn *sv; + + if (!Svnc || !SvncSt) { + if (!load_svnc()) + return(' '); + } +/* + * Hash the vnode address and see if there's a shadow (lock) vnode structure + * assigned to it. + */ + i = SVNHASH(vp); + for (sv = Svnc[i]; sv; sv = sv->next) { + if ((KA_T)sv->vp == vp) + break; + } + if (!sv) + return(' '); +/* + * Search the lock owners represented by the shadow vnode's lock chain + * for this process. + */ + for (lp = sv->lp; lp; lp = lp->next) { + if (lp->pid == (pid_t)Lp->pid) { + if (lp->start == 0 && lp->end == 0x7fffffff) + i = 1; + else + i = 0; + if (lp->type == F_RDLCK) + return(i ? 'R' : 'r'); + else if (lp->type == F_WRLCK) + return(i ? 'W' : 'w'); + return(' '); + } + } + return(' '); +} + + +/* + * load_svnc() - load the shadow vnode cache + */ + +int +load_svnc() +{ + int i, j; + static KA_T kp = (KA_T)NULL; + struct lockf lf, *lp; + struct l_lockf *lsf; + struct l_svn *lsv; + struct posix_proc p; + struct lf_svnode *sn, *sp[LF_SVNODE_HSZ], sv; + + if (Svnc && SvncSt) + return(1); +/* + * Get the shadow vnode hash table address from the kernel. + */ + if (!kp) { + if (get_Nl_value("lfsvh", Drive_Nl, &kp) < 0 || !kp) + return(0); + } +/* + * Define local hash buckets, if necessary. + */ + if (!Svnc) { + if (!(Svnc = (struct l_svn **)calloc(sizeof(struct l_svn *), + LF_SVNODE_HSZ))) + { + (void) fprintf(stderr, + "%s: no space for %d local shadow vnode hash buckets\n", + Pn, LF_SVNODE_HSZ); + Exit(1); + } + } +/* + * Search the hash buckets of the shadow vnode table. + */ + if (kread(kp, (char *)&sp, sizeof(sp))) + return(0); + for (i = 0; i < LF_SVNODE_HSZ; i++) { + if (!(sn = sp[i])) + continue; + do { + + /* + * Duplicate the chain of shadow vnodes in the bucket. + */ + if (kread((KA_T)sn, (char *)&sv, sizeof(sv)) + || !sv.lf_vnodep + || !sv.lf_lockfp) + break; + /* + * Allocate and initialize a local shadow vnode structure. + */ + if (!(lsv = (struct l_svn *)malloc(sizeof(struct l_svn)))) { + (void) fprintf(stderr, + "%s: no space for local shadow vnode -- PID: %ld\n", + Pn, Lp->pid); + Exit(1); + } + lsv->vp = (KA_T)sv.lf_vnodep; + lsv->lp = (struct l_lockf *)NULL; + lsv->next = (struct l_svn *)NULL; + lp = sv.lf_lockfp; + do { + + /* + * Duplicate the lock chain for this shadow vnode. + */ + if (kread((KA_T)lp, (char *)&lf, sizeof(lf))) + break; + if (!lf.lf_posix_procp + || kread((KA_T)lf.lf_posix_procp, (char *)&p, sizeof(p)) + || !p.p_pid) + continue; + if (!(lsf=(struct l_lockf *)malloc(sizeof(struct l_lockf)))) + { + (void) fprintf(stderr, + "%s: no space for local lock struct -- PID: %ld\n", + Pn, Lp->pid); + Exit(1); + } + lsf->type = lf.lf_type; + lsf->start = lf.lf_start; + lsf->end = lf.lf_end; + lsf->pid = (pid_t)p.p_pid; + lsf->next = lsv->lp; + lsv->lp = lsf; + } while ((lp = lf.lf_next)); + /* + * Link the shadow vnode to its local hash bucket. + */ + j = SVNHASH(lsv->vp); + lsv->next = Svnc[j]; + Svnc[j] = lsv; + } while ((sn = sv.lf_next)); + } + SvncSt = 1; + return(1); +} +#endif /* STEPV>=31 */ + + +/* + * process_node() - process vnode + */ + +void +process_node(va) + KA_T va; /* vnode kernel space address */ +{ + dev_t dev, rdev; + int devs = 0; + static int ft = 1; + static KA_T fvops = (KA_T)0; + struct inode i; + int ins = 0; + static KA_T nvops = (KA_T)0; + struct rnode r; + int rdevs = 0; + struct vnode rv; + struct snode s; + static KA_T svops = (KA_T)0; + char tbuf[32], *ty; + static KA_T uvops = (KA_T)0; + enum vtype type; + static struct vnode *v = (struct vnode *)NULL; + +#if defined(HAS_AFS) + static int afs = 0; /* AFS test status: -1 = no AFS + * 0 = not tested + * 1 = AFS present */ + struct afsnode an; + static KA_T avops = (KA_T)0; +#endif /* defined(HAS_AFS) */ + +/* + * Read the vnode. + */ + if (!va) { + enter_nm("no vnode address"); + return; + } +/* + * Read the vnode. + */ + 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) */ + + ); + Exit(1); + } + } + 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 vnode operations addresses, as required. + */ + if (ft) { + +#if defined(HAS_AFS) + (void) get_Nl_value("avops", Drive_Nl, &avops); +#endif /* defined(HAS_AFS) */ + + (void) get_Nl_value("fvops", Drive_Nl, &fvops); + (void) get_Nl_value("nvops", Drive_Nl, &nvops); + (void) get_Nl_value("svops", Drive_Nl, &svops); + (void) get_Nl_value("uvops", Drive_Nl, &uvops); + ft = 0; + } +/* + * Determine the vnode type. + */ + if ((uvops && (KA_T)v->v_op == uvops) + || (svops && (KA_T)v->v_op == svops)) + Ntype = N_REGLR; + else if (nvops && (KA_T)v->v_op == nvops) + Ntype = N_NFS; + else if (fvops && (KA_T)v->v_op == fvops) + Ntype = N_FIFO; + +#if defined(HAS_AFS) + /* + * Caution: this AFS test should be the last one. + */ + + else if (avops) { + if ((KA_T)v->v_op == avops) + Ntype = 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; + } + } 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; + Ntype = N_AFS; + AFSVfsp = (KA_T)v->v_vfsp; + break; + case 1: + if ((KA_T)v->v_vfsp == AFSVfsp) + Ntype = 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; + } +#endif /* defined(HAS_AFS) */ + +/* + * Determine the lock type. + */ + if (v->v_shlockc || v->v_exlockc) { + if (FILEPTR && (FILEPTR->f_flag & FSHLOCK)) + Lf->lock = 'R'; + else if (FILEPTR && (FILEPTR->f_flag & FEXLOCK)) + Lf->lock = 'W'; + else + +#if STEPV>=31 + Lf->lock = isvlocked(va); +#else /* STEPV<31 */ + Lf->lock = ' '; +#endif /* STEPV>=31 */ + + } +/* + * Read the inode, rnode, snode, or vcache struct. + */ + switch (Ntype) { + +#if defined(HAS_AFS) + case N_AFS: + if (readafsnode(va, v, &an)) + return; + break; +#endif /* defined(HAS_AFS) */ + + 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; + } + break; + case N_REGLR: + default: + + /* + * VBLK, VCHR and VFIFO vnodes point to an snode. The snode's s_realvp + * usually points to a real vnode, which points to an inode. + */ + if (v->v_type == VBLK || v->v_type == VCHR || v->v_type == VFIFO) { + 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) { + if (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 || 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; + } else { + 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; + } + } +/* + * 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_NFS: + dev = r.r_attr.va_fsid; + devs = 1; + if (dev & 0x8000) + dev |= 0xff00; + break; + case N_FIFO: + case N_REGLR: + if (ins) { + dev = i.i_dev; + devs = 1; + } + if ((v->v_type == VBLK) || (v->v_type == VCHR)) { + rdev = v->v_rdev; + rdevs = 1; + } + } + 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_NFS: + Lf->inode = (INODETYPE)r.r_attr.va_nodeid; + Lf->inp_ty = 1; + break; + case N_FIFO: + case N_REGLR: + if (ins) { + Lf->inode = (INODETYPE)i.i_number; + Lf->inp_ty = 1; + } + } +/* + * Obtain the file size. + */ + if (Foffset) + Lf->off_def = 1; + else { + switch (Ntype) { + +#if defined(HAS_AFS) + case N_AFS: + Lf->sz = (SZOFFTYPE)an.size; + Lf->sz_def = 1; + break; +#endif /* defined(HAS_AFS) */ + + case N_NFS: + Lf->sz = (SZOFFTYPE)r.r_attr.va_size; + Lf->sz_def = 1; + break; + case N_FIFO: + Lf->off_def = 1; + break; + case N_REGLR: + if (type == VREG || type == VDIR) { + if (ins) { + Lf->sz = (SZOFFTYPE)i.i_size; + Lf->sz_def = 1; + } + } + else if ((type == VCHR || type == VBLK) && !Fsize) + Lf->off_def = 1; + break; + } + } +/* + * Record the link count. + */ + if (Fnlink) { + +#if defined(HAS_AFS) + case N_AFS: + Lf->nlink = an.nlink; + Lf->nlink_def = an.nlink_st; + break; +#endif /* defined(HAS_AFS) */ + + switch (Ntype) { + case N_NFS: + Lf->nlink = (long)r.r_attr.va_nlink; + Lf->nlink_def = 1; + break; + case N_REGLR: + if (ins) { + Lf->nlink = (long)i.i_nlink; + Lf->nlink_def = 1; + } + 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; +/* + * Defer file system info lookup until printname(). + */ + Lf->lmi_srch = 1; +/* + * Save the device numbers and their states. + * + * Format the vnode type. + */ + Lf->dev = dev; + Lf->dev_def = devs; + Lf->rdev = rdev; + Lf->rdev_def = rdevs; + switch (type) { + case VNON: + ty ="VNON"; + break; + case VREG: + case VDIR: + ty = (type == VREG) ? "VREG" : "VDIR"; + break; + case VBLK: + ty = "VBLK"; + Ntype = N_BLK; + break; + case VCHR: + ty = "VCHR"; + Ntype = N_CHR; + break; + case VLNK: + ty = "VLNK"; + break; + +#if defined(VSOCK) + case VSOCK: + ty = "SOCK"; + break; +#endif + + case VBAD: + ty = "VBAD"; + break; + case VFIFO: + ty = "FIFO"; + break; + default: + (void) snpf(Lf->type, sizeof(Lf->type), "%04o", (type & 0xfff)); + ty = NULL; + } + if (ty) + (void) snpf(Lf->type, sizeof(Lf->type), ty); + Lf->ntype = Ntype; +/* + * If this is a VBLK file and it's missing an inode number, try to + * supply one. + */ + if ((Lf->inp_ty == 0) && (Lf->ntype == N_BLK)) + find_bl_ino(); +/* + * If this is a VCHR file and it's missing an inode number, try to + * supply one. + */ + if ((Lf->inp_ty == 0) && (Lf->ntype == N_CHR)) + 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); +} diff --git a/dialects/n+os/dnode1.c b/dialects/n+os/dnode1.c new file mode 100644 index 0000000..a18c482 --- /dev/null +++ b/dialects/n+os/dnode1.c @@ -0,0 +1,401 @@ +/* + * dnode1.h - NEXTSTEP and OPENSTEP 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"; +static char *rcsid = "$Id: dnode1.c,v 1.7 2005/08/08 19:54:03 abe Exp $"; +#endif + + +#if defined(HAS_AFS) +#include "lsof.h" + +#include +#define __XDR_INCLUDE__ + +#include +#include +#include +#include + + +/* + * 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 char d1[4]; +# else /* HAS_AFS>=304 */ + unsigned char d1[6]; +# endif /* HAS_AFS<304 */ + +}; +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; +}; +typedef struct afs_bozoLock afs_bozoLock_t; + +#define KERNEL +#include +#undef KERNEL + + +/* + * Local function prototypes + */ + +_PROTOTYPE(static struct volume *getvolume,(struct VenusFid *f, int *vols)); +_PROTOTYPE(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_un.n_name && Nl[i].n_un.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 kernel name list 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(f, vols) + 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 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(kh, (char *)&vp, sizeof(vp))) + return((struct volume *)NULL); + while (vp) { + if (kread((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(vp) + 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 && vp->v_vfsp == AFSVfsp) + return(1); + if (vp->v_data + || !vp->v_vfsp + || kread((KA_T)vp->v_vfsp, (char *)&v, sizeof(v)) + || v.vfs_data) + return(0); + if (v.vfs_fsid.val[0] == AFSDEV) { + AFSVfsp = vp->v_vfsp; + return(1); + } +/* + * Search the local mount table for /afs devices or a match on device number. + * 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 (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 = 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(vc, rfid) + struct vcache *vc; /* vcache structure */ + int *rfid; /* root file ID pointer status return */ +{ + unsigned long 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((KA_T)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(va, v, an) + caddr_t va; /* kernel vnode address */ + struct vnode *v; /* vnode buffer pointer */ + struct afsnode *an; /* afsnode recipient */ +{ + char *cp; + 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(ka, cp, len)) { + (void) snpf(Namech, Namechl, + "vnode at %#x: can't read vcache remainder from %#x", va, ka); + 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/dialects/n+os/dproc.c b/dialects/n+os/dproc.c new file mode 100644 index 0000000..cb625b9 --- /dev/null +++ b/dialects/n+os/dproc.c @@ -0,0 +1,767 @@ +/* + * dproc.c - NEXTSTEP and OPENSTEP 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"; +static char *rcsid = "$Id: dproc.c,v 1.12 2001/08/09 11:44:07 abe Exp $"; +#endif + +#include "lsof.h" + + +/* + * Local static values + */ + +static int Mxp = 0; /* maximum number of processes */ +static int Np; /* number of entries in P[] */ +static int Nv = 0; /* allocated Vp[] entries */ +static struct proc *P = (struct proc *)NULL; + /* local proc structure table */ +static KA_T *Pa = (KA_T *)NULL; /* kernel address for each P[] entry */ +static KA_T Kp; /* kernel process table pointer */ +static KA_T *Vp = (KA_T *)NULL; /* vnode address cache */ + + +_PROTOTYPE(static void get_kernel_access,(void)); +_PROTOTYPE(static void process_map,(caddr_t map)); +_PROTOTYPE(static void read_proc,(void)); + + +/* + * ckkv - check kernel version + */ + +void +ckkv(d, er, ev, ea) + char *d; /* dialect */ + char *er; /* expected release */ + char *ev; /* expected version */ + char *ea; /* expected architecture */ +{ + +#if defined(HASKERNIDCK) + char m[128], *t; + kernel_version_t kv; + kern_return_t kr; + char *vt = (char *)NULL; + + if (Fwarn) + return; +/* + * Read Mach kernel version. + */ + if ((kr = host_kernel_version(host_self(), kv)) != KERN_SUCCESS) { + (void) snpf(m, sizeof(m), "%s: can't get kernel version:", Pn); + mach_error(m, kr); + Exit(1); + } +/* + * Skip blank-separated tokens until reaching "Mach". The kernel version + * string follows. Eliminate anything but decimal digits and periods from + * the kernel version string. + */ + if ((t = strtok(kv, " "))) { + do { + if (strcmp(t, "Mach") == 0) + break; + } while ((t = strtok((char *)NULL, " "))); + if (t) + vt = strtok((char *)NULL, " "); + } + if (vt) { + for (t = vt; *t; t++) { + if (*t == '.' || (*t >= '0' && *t <= '9')) + continue; + *t = '\0'; + break; + } + } +/* + * Warn if the actual and expected versions don't match. + */ + if (!ev || !vt || strcmp(ev, vt)) + (void) fprintf(stderr, + "%s: WARNING: compiled for %s version %s; this is %s\n", + Pn, d, ev ? ev : "UNKNOWN", vt ? vt : "UNKNOWN"); +#endif /* defined(HASKERNIDCK) */ + +} + + +/* + * gather_proc_info() -- gather process information + */ + +void +gather_proc_info() +{ + int i, nf, px; + MALLOC_S nb; + short pss, sf; + struct task { /* (Should come from .) */ + caddr_t d1[SIMPLE_LOCK_SIZE + 2]; + caddr_t map; + caddr_t d2[SIMPLE_LOCK_SIZE + 9]; + struct utask *u_address; + struct proc *proc; + } t; + struct utask *u; + static struct file **uf = (struct file **)NULL; + static MALLOC_S ufb = 0; + struct utask ut; + +#if defined(HASFSTRUCT) + static char *pof = (char *)NULL; + static MALLOC_S pofb = 0; +#endif /* defined(HASFSTRUCT) */ + + +/* + * Clear previously loaded tables and read the process table. + */ + +#if STEPV>=31 + (void) clr_svnc(); +#endif /* STEPV>=31 */ + + (void) read_proc(); +/* + * Process proc structures pre-loaded in initialize(). + */ + for (px = 0, u = &ut; px < Np; px++) { + if (is_proc_excl(P[px].p_pid, (int)P[px].p_pgrp, + (UID_ARG)P[px].p_uid, &pss, &sf)) + continue; + /* + * Read the task associated with the process, and the user + * area assocated with the task. + */ + if (kread((KA_T)P[px].task, (char *)&t, sizeof(t))) + continue; + if ((KA_T)t.proc != Pa[px]) + continue; + if (kread((KA_T)t.u_address, (char *)&ut, sizeof(ut))) + continue; + if ((KA_T)ut.uu_procp != Pa[px]) + continue; + /* + * Allocate a local process structure and start filling it. + */ + if (is_cmd_excl(u->u_comm, &pss, &sf)) + continue; + alloc_lproc(P[px].p_pid, (int)P[px].p_pgrp, (int)P[px].p_ppid, + (UID_ARG)P[px].p_uid, u->u_comm, (int)pss, (int)sf); + Plf = (struct lfile *)NULL; + /* + * Save current working directory information. + */ + if (u->u_cdir) { + alloc_lfile(CWD, -1); + FILEPTR = (struct file *)NULL; + process_node((KA_T)u->u_cdir); + if (Lf->sf) + link_lfile(); + } + /* + * Save root directory information. + */ + if (u->u_rdir) { + alloc_lfile(RTD, -1); + FILEPTR = (struct file *)NULL; + process_node((KA_T)u->u_rdir); + if (Lf->sf) + link_lfile(); + } + /* + * Print information on the text files of the virtual memory + * address map. + */ + if (t.map) + process_map(t.map); + /* + * Save information on file descriptors. + * + * NEXTSTEP file pointers come from a structure whose pointer is + * in the user task area. + */ + nf = ut.uu_ofile_cnt; + nb = (MALLOC_S)(sizeof(struct file *) * nf); + if (nb > ufb) { + if (!uf) + uf = (struct file **)malloc(nb); + else + uf = (struct file **)realloc((MALLOC_P *)uf, nb); + if (!uf) { + (void) fprintf(stderr, "%s: no uu_ofile space\n", Pn); + Exit(1); + } + ufb = nb; + } + if (kread((KA_T)ut.uu_ofile, (char *)uf, nb)) + continue; + +#if defined(HASFSTRUCT) + if (Fsv & FSV_FG) { + 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: no uu_pofile space\n", Pn); + Exit(1); + } + pofb = nb; + } + if (kread((KA_T)ut.uu_pofile, (char *)pof, nb)) + zeromem(pof, nb); + } +#endif /* defined(HASFSTRUCT) */ + + for (i = 0; i < nf; i++) { + if (uf[i]) { + alloc_lfile((char *)NULL, i); + process_file((KA_T)uf[i]); + if (Lf->sf) { + +#if defined(HASFSTRUCT) + if (Fsv & FSV_FG) + Lf->pof = (long)pof[i]; +#endif /* defined(HASFSTRUCT) */ + + link_lfile(); + } + } + } + /* + * Examine results. + */ + if (examine_lproc()) + return; + } +} + + +/* + * get_kernel_access() - access the required information in the kernel + */ + +static void +get_kernel_access() +{ + int i; + KA_T lv; + +#if defined(HAS_AFS) + struct nlist *nl = (struct nlist *)NULL; + unsigned long v[3]; +#endif /* defined(HAS_AFS) */ + +/* + * Check kernel version against compiled version. + */ + ckkv("NEXTSTEP", (char *)NULL, LSOF_VSTR, (char *)NULL); + +#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)) + Exit(1); +#endif /* defined(WILLDROPGID) */ + +/* + * Access the 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)); + Exit(1); + } + +#if defined(WILLDROPGID) +/* + * Drop setgid permission, if necessary. + */ + if (!Memory) + (void) dropgid(); +#else /* !defined(WILLDROPGID) */ +/* + * See if the name list file is readable. Build Nl. + */ + if (Nmlst && !is_readable(Nmlst, 1)) + Exit(1); +#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 *)malloc(Nll))) { + (void) fprintf(stderr, + "%s: no space (%d) for Nl[] copy\n", Pn, Nll); + Exit(1); + } + (void) bcopy((char *)Nl, (char *)nl, Nll); + } +#endif /* defined(HAS_AFS) */ + +/* + * Access the name list file. + */ + if (nlist(Nmlst ? Nmlst : VMUNIX, Nl) < 0) { + (void) fprintf(stderr, "%s: can't read namelist from %s\n", + Pn, Nmlst ? Nmlst : VMUNIX); + Exit(1); + } + if (get_Nl_value("aproc", Drive_Nl, &lv) < 0 || !lv) { + (void) fprintf(stderr, "%s: can't get proc table address\n", + Pn); + Exit(1); + } + +#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]) >= 0 + && get_Nl_value("avol", Drive_Nl, &v[1]) >= 0 + && get_Nl_value("avol", Drive_Nl, &v[2]) >= 0 + && (!vo[0] || !v[1] || !v[2])) + (void) ckAFSsym(nl); + (void) free((MALLOC_P *)nl); + } +#endif /* defined(HAS_AFS) */ + +/* + * Establish a maximum process count estimate. + */ + if (get_Nl_value("mxproc", Drive_Nl, &lv) < 0 + || kread((KA_T)lv, (char *)&Mxp, sizeof(Mxp)) + || Mxp < 1) + Mxp = PROCDFLT; +} + + +/* + * initialize() - perform all initialization + */ + +void +initialize() +{ + get_kernel_access(); +} + + +/* + * kread() - read from kernel memory + */ + +int +kread(addr, buf, len) + KA_T addr; /* kernel memory address */ + char *buf; /* buffer to receive data */ + READLEN_T len; /* length to read */ +{ + int br; + + if (lseek(Kd, (off_t)addr, L_SET) == (off_t)-1L) + return(-1); + br = read(Kd, buf, len); + return((br == len) ? 0 : 1); +} + + +/* + * process_map() - process vm map for vnode references + */ + +static void +process_map(map) + caddr_t map; +{ + int i, j, n, ne; + +#if STEPV<40 +/* + * Structures for NeXTSTEP and OPENSTEP < 4.0. + */ + struct vm_map_entry { /* (Should come from ). */ + struct vm_map_entry *prev; + struct vm_map_entry *next; + unsigned int start; + unsigned int end; + caddr_t object; + unsigned int offset; + unsigned int + is_a_map:1, + is_sub_map:1, + copy_on_write:1, + needs_copy:1; + int protection; + int max_protection; + int inheritance; + int wired_count; + } vme, *vmep; + +#define VME_NEXT(entry) entry.next + + struct vm_map { /* (Should come from .) */ + caddr_t d1[SIMPLE_LOCK_SIZE + 2]; + struct vm_map_entry header; + int nentries; + caddr_t pmap; + unsigned int size; + boolean_t is_main_map; + } vmm; + struct vm_object { /* (Should come from .) */ + caddr_t d1[SIMPLE_LOCK_SIZE + 4]; + unsigned int size; + short ref_count, resident_page_count; + caddr_t copy; + caddr_t pager; + int pager_request, pager_name; + unsigned int paging_offset; + caddr_t shadow; + } vmo, vmso; +#else /* STEPV>=40 */ +/* + * Structures for OPENSTEP >= 4.0. + */ + struct vm_map_links { /* (Should come from ). */ + struct vm_map_entry *prev; + struct vm_map_entry *next; + unsigned int start; + unsigned int end; + }; + struct vm_map_entry { /* (Should come from ). */ + struct vm_map_links links; + caddr_t object; + unsigned int offset; + unsigned int + is_shared:1, + is_sub_map:1, + in_transition:1, + needs_wakeup:1, + behavior:2, + needs_copy:1, + protection:3, + max_protection:3, + inheritance:2, + pad1:1, + alias:8; + unsigned short wired_count; + unsigned short user_wired_count; + } vme, *vmep; + +#define VME_NEXT(entry) entry.links.next + + struct vm_map_header { /* (Should come from .) */ + struct vm_map_links links; + int nentries; + int entries_pageable; + }; + struct vm_map { /* (Should come from .) */ + caddr_t d1[SIMPLE_LOCK_SIZE + 2]; + struct vm_map_header hdr; + caddr_t pmap; + unsigned int size; + boolean_t is_main_map; /* Darwin header has this as ref_count, + * but we'll take some liberties ... */ + } vmm; + struct vm_object { /* (Should come from .) */ + caddr_t d1[SIMPLE_LOCK_SIZE + 4]; + unsigned int size; + short ref_count, resident_page_count; + caddr_t copy; + caddr_t shadow; + unsigned int shadow_offset; + caddr_t pager; + unsigned int paging_offset; + int pager_request; + } vmo, vmso; +#endif /* STEPV<40 */ + + struct vstruct { /* (Should come from .) */ + boolean_t is_device; + caddr_t vs_pf; + caddr_t pfMapEntry; + unsigned int vs_swapfile:1; + short vs_count; + int vs_size; + caddr_t vs_vp; + } vmp; +/* + * Read the vm map. + */ + if (!map + || kread((KA_T)map, (char *)&vmm, sizeof(vmm))) + return; + if (!vmm.is_main_map) + return; +/* + * Look for non-map and non-sub-map vm map entries that have an object + * with a shadow whose pager pointer addresses a non-swap-file istruct + * that has a vnode pointer. Process the unique vnodes found. + */ +#if STEPV<40 + vme = vmm.header; + ne = vmm.nentries; +#else /* STEPV>=40 */ + if (!vmm.hdr.links.next + || kread((KA_T)vmm.hdr.links.next, (char *)&vme, sizeof(vme))) + return; + ne = vmm.hdr.nentries; +#endif /* STEPV<40 */ + + if (ne > 1000) + ne = 1000; + for (i = n = 0; i < ne; i++) { + if (i) { + if (!VME_NEXT(vme) + || kread((KA_T)VME_NEXT(vme), (char *)&vme, sizeof(vme))) + continue; + } + +#if STEPV<40 + if (vme.is_a_map || vme.is_sub_map) +#else /* STEPV>=40 */ + if (vme.is_sub_map) +#endif /* STEPV<40 */ + + continue; + if (!vme.object + || kread((KA_T)vme.object, (char *)&vmo, sizeof(vmo))) + continue; + if (!vmo.shadow + || kread((KA_T)vmo.shadow, (char *)&vmso, sizeof(vmso))) + continue; + if (!vmso.pager + || kread((KA_T)vmso.pager, (char *)&vmp, sizeof(vmp))) + continue; + if (vmp.is_device || vmp.vs_swapfile || !vmp.vs_vp) + continue; + /* + * See if the vnode has been processed before. + */ + for (j = 0; j < n; j++) { + if ((KA_T)vmp.vs_vp == Vp[j]) + break; + } + if (j < n) + continue; + /* + * Process a new vnode. + */ + alloc_lfile("txt", -1); + FILEPTR = (struct file *)NULL; + process_node((KA_T)vmp.vs_vp); + if (Lf->sf) + link_lfile(); + /* + * Allocate space for remembering the vnode. + */ + if (!Vp) { + if (!(Vp = (KA_T *)malloc((MALLOC_S) + (sizeof(struct vnode *) * 10)))) + { + (void) fprintf(stderr, "%s: no txt ptr space, PID %d\n", + Pn, Lp->pid); + Exit(1); + } + Nv = 10; + } else if (n >= Nv) { + Nv += 10; + if (!(Vp = (KA_T *)realloc((MALLOC_P *)Vp, + (MALLOC_S)(Nv * sizeof(struct vnode *))))) + { + (void) fprintf(stderr, + "%s: no more txt ptr space, PID %d\n", Pn, Lp->pid); + Exit(1); + } + } + Vp[n++] = (KA_T)vmp.vs_vp; + } +} + + +/* + * read_proc() - read proc structures + */ + +static void +read_proc() +{ + static KA_T apav = (KA_T)0; + static int apax = -1; + int i, try; + static int sz = 0; + KA_T kp; + struct proc *p; +/* + * Try PROCTRYLM times to read a valid proc table. + */ + for (try = 0; try < PROCTRYLM; try++) { + + /* + * Read kernel's process list pointer. This needs to be done each + * time lsof rereads the process list. + */ + if (apax < 0) { + if ((apax = get_Nl_value("aproc", Drive_Nl, &apav)) < 0) { + (void) fprintf(stderr, + "%s: can't get process table address pointer\n", Pn); + Exit(1); + } + } + if (kread((KA_T)apav, (char *)&Kp, sizeof(Kp))) { + if (!Fwarn) + (void) fprintf(stderr, + "%s: WARNING: can't read %s from %#x\n", + Pn, Nl[apax].n_un.n_name, apav); + continue; + } + + /* + * Pre-allocate proc structure space. + */ + if (sz == 0) { + sz = Mxp; + if (!(P = (struct proc *)malloc((MALLOC_S) + (sz * sizeof(struct proc))))) + { + (void) fprintf(stderr, "%s: no proc table space\n", + Pn); + Exit(1); + } + if (!(Pa = (KA_T *)malloc((MALLOC_S)(sz * sizeof(KA_T))))) + { + (void) fprintf(stderr, "%s: no proc pointer space\n", + Pn); + Exit(1); + } + } + /* + * Accumulate proc structures. + */ + for (kp = Kp, Np = 0; kp; ) { + if (kread(kp, (char *)&P[Np], sizeof(struct proc))) { + Np = 0; + break; + } + Pa[Np] = kp; + kp = (KA_T)P[Np].p_nxt; + if (P[Np].p_stat == 0 || P[Np].p_stat == SZOMB) + continue; + Np++; + if (Np >= sz) { + + /* + * Expand the local proc table. + */ + sz += PROCDFLT/2; + if (!(P = (struct proc *)realloc((MALLOC_P *)P, + (MALLOC_S)(sizeof(struct proc) * sz)))) + { + (void) fprintf(stderr, + "%s: no more (%d) proc space\n", + Pn, sz); + Exit(1); + } + if (!(Pa = (KA_T *)realloc((MALLOC_P *)Pa, + (MALLOC_S)(sizeof(KA_T) * sz)))) + { + (void) fprintf(stderr, + "%s: no more (%d) proc ptr space\n", + Pn, sz); + Exit(1); + } + } + } + /* + * If not enough processes were saved in the local table, try again. + */ + if (Np >= PROCMIN) + break; + } +/* + * 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); + Exit(1); + } + if (Np < sz && !RptTm) { + + /* + * Reduce the local proc structure table size to a minimum if + * not in repeat mode. + */ + if (!(P = (struct proc *)realloc((MALLOC_P *)P, + (MALLOC_S)(sizeof(struct proc) * Np)))) + { + (void) fprintf(stderr, + "%s: can't reduce proc table to %d\n", + Pn, Np); + Exit(1); + } + if (!(Pa = (KA_T *)realloc((MALLOC_P *)Pa, + (MALLOC_S)(sizeof(KA_T) * Np)))) + { + (void) fprintf(stderr, + "%s: can't reduce proc ptrs to %d\n", + Pn, Np); + Exit(1); + } + } +} diff --git a/dialects/n+os/dproto.h b/dialects/n+os/dproto.h new file mode 100644 index 0000000..19c1042 --- /dev/null +++ b/dialects/n+os/dproto.h @@ -0,0 +1,53 @@ +/* + * dproto.h - NEXTSTEP and OPENSTEP 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.6 2001/08/09 11:44:07 abe Exp $ + */ + + +#if STEPV>=31 +_PROTOTYPE(extern void clr_svnc,(void)); +#endif /* STEPV>=31 */ + +_PROTOTYPE(extern int is_file_named,(char *p, int cd)); + +#if defined(HAS_AFS) +_PROTOTYPE(extern struct vnode *alloc_vcache,(void)); +_PROTOTYPE(extern void ckAFSsym,(struct nlist *nl)); +_PROTOTYPE(extern int hasAFS,(struct vnode *vp)); +_PROTOTYPE(extern void process_socket,(KA_T vp)); +_PROTOTYPE(extern int readafsnode,(caddr_t va, struct vnode *v, struct afsnode * +an)); +#endif /* defined(HAS_AFS) */ diff --git a/dialects/n+os/dsock.c b/dialects/n+os/dsock.c new file mode 100644 index 0000000..77d3b8a --- /dev/null +++ b/dialects/n+os/dsock.c @@ -0,0 +1,306 @@ +/* + * dsock.c - NEXTSTEP and OPENSTEP 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"; +static char *rcsid = "$Id: dsock.c,v 1.17 2005/08/08 19:54:03 abe Exp $"; +#endif + + +#include "lsof.h" + + +/* + * process_socket() - process socket + */ + +void +process_socket(sa) + KA_T sa; /* socket address in kernel */ +{ + struct domain d; + char *ep; + unsigned char *fa = (unsigned char *)NULL; + int fam; + int fp, lp; + struct inpcb inp; + unsigned char *la = (unsigned char *)NULL; + struct mbuf mb; + struct protosw p; + struct rawcb raw; + struct socket s; + size_t sz; + struct tcpcb t; + struct unpcb uc, unp; + struct sockaddr_un *ua = NULL; + struct sockaddr_un un; + + (void) snpf(Lf->type, sizeof(Lf->type), "sock"); + Lf->inp_ty = 2; +/* + * Read socket structure. + */ + if (!sa) { + enter_nm("no socket address"); + return; + } + if (kread((KA_T) sa, (char *) &s, sizeof(s))) { + (void) snpf(Namech,Namechl,"can't read socket struct from %#x",sa); + enter_nm(Namech); + return; + } + if (!s.so_type) { + enter_nm("no socket type"); + return; + } +/* + * Read protocol switch and domain structures. + */ + if (!s.so_proto + || kread((KA_T) s.so_proto, (char *) &p, sizeof(p))) { + (void) snpf(Namech, Namechl, "no protocol switch"); + enter_nm(Namech); + return; + } + if (kread((KA_T) p.pr_domain, (char *) &d, sizeof(d))) { + (void) snpf(Namech, Namechl, "can't read domain struct from %s", + print_kptr((KA_T)p.pr_domain, (char *)NULL, 0)); + enter_nm(Namech); + return; + } +/* + * Save size information. + */ + if (Fsize) { + if (Lf->access == 'r') + Lf->sz = (SZOFFTYPE)s.so_rcv.sb_cc; + else if (Lf->access == 'w') + Lf->sz = (SZOFFTYPE)s.so_snd.sb_cc; + else + Lf->sz = (SZOFFTYPE)(s.so_rcv.sb_cc + s.so_snd.sb_cc); + Lf->sz_def = 1; + } else + Lf->off_def = 1; + +#if defined(HASTCPTPIQ) + Lf->lts.rq = (unsigned long)s.so_rcv.sb_cc; + Lf->lts.sq = (unsigned long)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 (Fnet) + Lf->sf |= SELNET; + (void) snpf(Lf->type, sizeof(Lf->type), "inet"); + printiproto(p.pr_protocol); + /* + * Read protocol control block. + */ + if (!s.so_pcb) { + (void) snpf(Namech, Namechl, "no PCB%s%s", + (s.so_state & SS_CANTSENDMORE) ? ", CANTSENDMORE" : "", + (s.so_state & SS_CANTRCVMORE) ? ", CANTRCVMORE" : ""); + enter_nm(Namech); + return; + } + if (s.so_type == SOCK_RAW) { + + /* + * Print raw socket information. + */ + if (kread((KA_T) s.so_pcb, (char *)&raw, sizeof(raw)) + || (struct socket *)sa != 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((KA_T)s.so_pcb, (char *) &inp, sizeof(inp)) + || (struct socket *)sa != inp.inp_socket) { + (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)); + /* + * If the protocol is TCP, try to read the TCP protocol + * control block to record its state. + */ + if (p.pr_protocol == IPPROTO_TCP + && inp.inp_ppcb + && kread((KA_T)inp.inp_ppcb, (char *)&t, sizeof(t)) == 0) { + Lf->lts.type = 0; + Lf->lts.state.i = (int)t.t_state; + +#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) */ + + } + /* + * Process the local and foreign addresses from the Internet + * control block. + */ + 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); + } + break; +/* + * Process a Unix domain socket. + */ + case AF_UNIX: + if (Funix) + Lf->sf |= SELUNX; + (void) snpf(Lf->type, sizeof(Lf->type), "unix"); + /* + * Read Unix protocol control block and the Unix address structure. + */ + enter_dev_ch(print_kptr(sa, (char *)NULL, 0)); + if (kread((KA_T) s.so_pcb, (char *) &unp, sizeof(unp))) { + (void) snpf(Namech, Namechl, "can't read unpcb at %s", + print_kptr((KA_T)s.so_pcb, (char *)NULL, 0)); + break; + } + if ((struct socket *)sa != unp.unp_socket) { + (void) snpf(Namech, Namechl, "unp_socket (%s) mismatch", + print_kptr((KA_T)unp.unp_socket, (char *)NULL, 0)); + break; + } + if (unp.unp_addr) { + if (kread((KA_T) unp.unp_addr, (char *) &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); + } + if (!ua) { + ua = &un; + (void) bzero((char *)ua, sizeof(un)); + ua->sun_family = AF_UNSPEC; + } + /* + * Print information on Unix socket that has no address bound + * to it, although it may be connected to another Unix domain + * socket as a pipe. + */ + if (ua->sun_family != AF_UNIX) { + if (ua->sun_family == AF_UNSPEC) { + if (unp.unp_conn) { + if (kread((KA_T)unp.unp_conn, (char *) &uc, sizeof(uc))) + { + (void) snpf(Namech, Namechl, + "can't read unp_conn at %s", + print_kptr((KA_T)unp.unp_conn,(char *)NULL,0)); + } else { + (void) snpf(Namech, Namechl, "->%s", + print_kptr((KA_T)uc.unp_socket,(char *)NULL,0)); + } + } else + (void) snpf(Namech, Namechl, "->(none)"); + } else + (void) snpf(Namech, Namechl, "unknown sun_family (%d)", + ua->sun_family); + break; + } + if (ua->sun_path[0]) { + if (mb.m_len >= sizeof(struct sockaddr_un)) + mb.m_len = sizeof(struct sockaddr_un) - 1; + *((char *)ua + mb.m_len) = '\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); +} diff --git a/dialects/n+os/dstore.c b/dialects/n+os/dstore.c new file mode 100644 index 0000000..b250fde --- /dev/null +++ b/dialects/n+os/dstore.c @@ -0,0 +1,133 @@ +/* + * dstore.c - NEXTSTEP and OPENSTEP 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"; +static char *rcsid = "$Id: dstore.c,v 1.10 2001/08/09 11:44:07 abe Exp $"; +#endif + + +#include "lsof.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) */ + +/* + * Drive_Nl -- table to drive the building of Nl[] via build_Nl() + * (See lsof.h and misc.c.) + */ + +struct drive_Nl Drive_Nl[] = { + { "arFid", "_afs_rootFid" }, + { "avops", "_afs_vnodeops" }, + { "avol", "_afs_volumes" }, + { "aproc", "_allproc" }, + { "fvops", "_fifo_vnodeops" }, + { "lfsvh", "_lf_svnode_hash" }, + { "mxproc", "_max_proc" }, + +#if defined(X_NCACHE) + { X_NCACHE, "_ncache" }, +#endif /* defined(X_NCACHE) */ + +#if defined(X_NCSIZE) + { X_NCSIZE, "_ncsize" }, +#endif /* defined(X_NCSIZE) */ + + { "nvops", "_nfs_vnodeops" }, + { "svops", "_spec_vnodeops" }, + { "uvops", "_ufs_vnodeops" }, + { "", "", }, + { NULL, NULL }, +}; + +struct file *Fileptr; /* for process_file() in lib/prfp.c */ +int Kd = -1; /* /dev/kmem file descriptor */ + +#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)FASYNC, FF_ASYNC }, + { (long)FMARK, FF_MARK }, + { (long)FDEFER, FF_DEFER }, + { (long)FSHLOCK, FF_SHLOCK }, + { (long)FEXLOCK, FF_EXLOCK }, + +#if defined(POSIX_KERN) + { (long)FPOSIX_PIPE, FF_POSIX_PIPE }, +#endif /* defined(POSIX_KERN) */ + + { (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) */ + + { (long)0, NULL } +}; +#endif /* defined(HASFSTRUCT) */ diff --git a/dialects/n+os/machine.h b/dialects/n+os/machine.h new file mode 100644 index 0000000..9119ab6 --- /dev/null +++ b/dialects/n+os/machine.h @@ -0,0 +1,615 @@ +/* + * machine.h - NEXTSTEP and OPENSTEP 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.37 2010/07/29 16:02:55 abe Exp $ + */ + + +#if !defined(LSOF_MACHINE_H) +#define LSOF_MACHINE_H 1 + + +#include + + +/* + * 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 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. + */ + +/* #define HASPIPEFN process_pipe? */ + + +/* + * HASPIPENODE is defined for those dialects that have pipe nodes. + */ + +/* #define HASPIPENODE 1 */ + + +/* + * HASPMAPENABLED is defined when the reporting of portmapper registration + * info is enabled by default. + */ + +/* #define HASPMAPENABLED 1 */ + + +/* + * HASPPID is defined for those dialects that support identification of + * the parent process IDentifier (PPID) of a process. + */ + +#define HASPPID 1 + + +/* + * HASPRINTDEV, HASPRINTINO, HASPRINTNM, HASPRINTOFF, and HASPRINTSZ + * define private dialect-specific functions for printing DEVice numbers, + * INOde numbers, NaMes, file OFFsets, and file SiZes. The functions are + * called from print_file(). + */ + +/* #define HASPRINTDEV print_dev? */ +/* #define HASPRINTINO print_ino? */ +/* #define HASPRINTNM print_nm? */ +/* #define HASPRINTOFF print_off? */ +/* #define HASPRINTSZ print_sz? */ + + +/* + * HASPRIVFILETYPE and PRIVFILETYPE are defined for dialects that have a + * file structure type that isn't defined by a DTYPE_* symbol. They are + * used in lib/prfp.c to select the type's processing. + * + * PRIVFILETYPE is the definition of the f_type value in the file struct. + * + * HASPRIVFILETYPE is the name of the processing function. + */ + +/* #define HASPRIVFILETYPE process_shmf? */ +/* #define PRIVFILETYPE ?? */ + + +/* + * HASPRIVNMCACHE is defined for dialects that have a private method for + * printing cached NAME column values for some files. HASPRIVNAMECACHE + * is defined to be the name of the function. + * + * The function takes one argument, a struct lfile pointer to the file, and + * returns non-zero if it prints a name to stdout. + */ + +/* #define HASPRIVNMCACHE */ + + +/* + * 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 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 */ + + +/* + * 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. + */ + +#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 */ + + +# if !defined(MACH) +/* + * The definition of MACH for NEXTSTEP is required for proper header + * file configuration -- i. e., some header files have ``#ifdef MACH'' + * statements that affect the size of kernel structures. + */ + +#define MACH 1 +# endif + + +/* + * 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_ is defined for dialects that use the + * in the lsof library. + * + * Note: other definitions and operations may be required to condition the + * library function source code. They may be found in the dialect dlsof.h + * header files. + */ + +/* #define USE_LIB_CKKV 1 ckkv.c */ +/* #define USE_LIB_COMPLETEVFS 1 cvfs.c */ +#define USE_LIB_FIND_CH_INO 1 /* fino.c */ +#define USE_LIB_IS_FILE_NAMED 1 /* isfn.c */ +#define USE_LIB_LKUPDEV 1 /* lkud.c */ +#define USE_LIB_PRINTDEVNAME 1 /* pdvn.c */ +#define USE_LIB_PROCESS_FILE 1 /* prfp.c */ +#define USE_LIB_PRINT_TCPTPI 1 /* ptti.c */ +#define USE_LIB_READDEV 1 /* rdev.c */ +#define USE_LIB_READMNT 1 /* rmnt.c */ +#define USE_LIB_REGEX 1 /* regex.c */ +/* #define USE_LIB_RNAM 1 rnam.c */ +#define USE_LIB_RNCH 1 /* rnch.c */ +/* #define USE_LIB_RNMH 1 rnmh.c */ +#define HAS_NO_LONG_LONG 1 /* disable snpf()'s + * long long support */ +#define USE_LIB_SNPF 1 /* snpf.c */ + + +/* + * 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/dialects/osr/Makefile b/dialects/osr/Makefile new file mode 100644 index 0000000..d9e1591 --- /dev/null +++ b/dialects/osr/Makefile @@ -0,0 +1,165 @@ + +# OSR Makefile +# +# $Id: Makefile,v 1.12 2008/04/15 13:30:40 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 + +MODE= 2755 + +OWN= bin + +SRC= dfile.c dmnt.c dnode.c dproc.c dsock.c dstore.c \ + arg.c main.c misc.c node.c print.c proc.c store.c usage.c \ + util.c + +OBJ= dfile.o dmnt.o dnode.o dproc.o dsock.o dstore.o \ + arg.o main.o misc.o node.o print.o proc.o store.o usage.o \ + util.o + +MAN= lsof.man +MANLCL= lsof.LOCAL + +OTHER= + +SHELL= /bin/sh + +SOURCE= Makefile ${OTHER} ${MAN} ${HDR} ${SRC} + +all: ${PROG} + +${MANLCL}: ${MAN} + rm -f ${MANLCL} + cp ${MAN} ${MANLCL} + +${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 ${MANLCL} + rm -f machine.h.old new_machine.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 mem group. Your install rule actions might look' + @echo 'something like this:' + @echo '' + @echo ' strip $${PROG}' + @echo ' mcs -d $${PROG}' + @echo ' /etc/install -o -m -u -g -f $${BIN} $${PROG}' + @echo ' /etc/install -o -m 444 -f $${DOC} $${MANLCL}' + @echo '' + @echo 'You will have to set values for , and ,' + @echo 'and complete the skeletons for the BIN and DOC strings given' + @echo 'at the beginning of this Makefile, e.g.,' + @echo '' + @echo ' BIN= $${DESTDIR}/usr/local/etc' + @echo ' DOC= $${DESTDIR}/usr/man/man8' + @echo '' + +${LIB}: FRC + (cd lib; ${MAKE} DEBUG="${DEBUG}" CFGF="${CFGF}") + +version.h: FRC + @echo Constructing version.h + @rm -f version.h + @echo '#define LSOF_BLDCMT "${LSOF_BLDCMT}"' > version.h; + @echo '#define LSOF_CC "${CC}"' >> version.h + @echo '#define LSOF_CCV "${CCV}"' >> version.h + @echo '#define LSOF_CCDATE "'`date`'"' >> version.h + @echo '#define LSOF_CCFLAGS "'`echo ${CFLAGS} | sed 's/\\\\(/\\(/g' | sed 's/\\\\)/\\)/g' | sed 's/"/\\\\"/g'`'"' >> version.h + @echo '#define LSOF_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_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 + @if [ "X${LSOF_SYSINFO}" = "X" ]; then \ + echo '#define LSOF_SYSINFO "${LSOF_SYSINFO}"' >> version.h; \ + else \ + if [ "${LSOF_SYSINFO}" = "none" ]; then \ + echo '#define LSOF_SYSINFO ""' >> version.h; \ + else \ + echo '#define LSOF_SYSINFO "'`uname -X`'"' >> version.h; \ + fi \ + fi + @if [ "X${LSOF_USER}" = "X" ]; then \ + echo '#define LSOF_USER "${USER}"' >> version.h; \ + else \ + if [ "${LSOF_USER}" = "none" ]; then \ + echo '#define LSOF_USER ""' >> version.h; \ + else \ + echo '#define LSOF_USER "${LSOF_USER}"' >> version.h; \ + fi \ + fi + @sed '/VN/s/.ds VN \(.*\)/#define LSOF_VERSION "\1"/' < version >> version.h + +FRC: + +# DO NOT DELETE THIS LINE - make depend DEPENDS ON IT + +dfile.o: ${HDR} dfile.c + +dmnt.o: ${HDR} dmnt.c + +dnode.o: ${HDR} dnode.c + +dproc.o: ${HDR} dproc.c + +dsock.o: ${HDR} dsock.c + +dstore.o: ${HDR} dstore.c + +arg.o: ${HDR} arg.c + +main.o: ${HDR} main.c + +misc.o: ${HDR} misc.c + +node.o: ${HDR} node.c + +print.o: ${HDR} print.c + +proc.o: ${HDR} proc.c + +store.o: ${HDR} store.c + +usage.o: ${HDR} version.h usage.c + +util.o: ${HDR} util.c + +# *** Do not add anything here - It will go away. *** diff --git a/dialects/osr/Mksrc b/dialects/osr/Mksrc new file mode 100755 index 0000000..535b69c --- /dev/null +++ b/dialects/osr/Mksrc @@ -0,0 +1,25 @@ +#!/bin/sh +# +# Mksrc - make SCO OpenServer 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 99/06/22 08:21:19 abe Exp $ + + +D=dialects/osr +F=dialects/common +L="dfile.c dlsof.h dmnt.c dnode.c dproc.c dproto.h dsock.c dstore.c machine.h" + +for i in $L +do + rm -f $i + $LSOF_MKC $D/$i $i + echo "$LSOF_MKC $D/$i $i" +done diff --git a/dialects/osr/dfile.c b/dialects/osr/dfile.c new file mode 100644 index 0000000..1e9933a --- /dev/null +++ b/dialects/osr/dfile.c @@ -0,0 +1,161 @@ +/* + * dfile.c - SCO OpenServer file processing functions for lsof + */ + + +/* + * 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 1995 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: dfile.c,v 1.11 2000/12/04 14:32:49 abe Exp abe $"; +#endif + +#include "lsof.h" + + +/* + * get_max_fd() - get maximum file descriptor plus one + */ + +int +get_max_fd() +{ + +#if defined(F_GETHFDO) || defined(_SC_OPEN_MAX) + int nd; +#endif /* defined(F_GETHFDO) || defined(_SC_OPEN_MAX) */ + +#if defined(F_GETHFDO) + if ((nd = fcntl(-1, F_GETHFDO, 0)) >= 0) + return(nd); +#endif /* defined(F_GETHFDO) */ + +#if defined(_SC_OPEN_MAX) + if ((nd = sysconf(_SC_OPEN_MAX)) >= 0) + return(nd); +#endif /* defined(_SC_OPEN_MAX) */ + + return(getdtablesize()); +} + + +/* + * print_dev() - print dev + */ + +char * +print_dev(lf, 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,%d", + lf->is_nfs ? ((~(*dev >> 8)) & 0xff) : emajor(*dev), + eminor(*dev)); + return(buf); +} + + +/* + * print_ino() - print inode + */ + +char * +print_ino(lf) + struct lfile *lf; /* file whose device is to be printed */ +{ + static char buf[128]; + + (void) snpf(buf, sizeof(buf), (lf->inode & 0x80000000) ? "%#x" : "%lu", + lf->inode); + return(buf); +} + + +/* + * process_file() - process file + */ + +void +process_file(fp) + KA_T fp; /* kernel file structure address */ +{ + struct file f; + int flag; + + if (kread(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; + + if (f.f_count) { + + /* + * Construct access code. + */ + if ((flag = (f.f_flag & (FREAD | FWRITE))) == FREAD) + Lf->access = 'r'; + else if (flag == FWRITE) + Lf->access = 'w'; + else if (flag == (FREAD | FWRITE)) + Lf->access = 'u'; + /* + * Process structure. + */ + +#if defined(HASFSTRUCT) + /* + * Save file structure values. + */ + if (Fsv & FSV_CT) { + Lf->fct = (long)f.f_count; + Lf->fsv |= FSV_CT; + } + if (Fsv & FSV_FA) { + Lf->fsa = fp; + Lf->fsv |= FSV_FA; + } + if (Fsv & FSV_FG) { + Lf->ffg = (long)f.f_flag; + Lf->fsv |= FSV_FG; + } + if (Fsv & FSV_NI) { + Lf->fna = (KA_T)f.f_inode; + Lf->fsv |= FSV_NI; + } +#endif /* defined(HASFSTRUCT) */ + + process_node((KA_T)f.f_inode); + return; + } + enter_nm("no more information"); +} diff --git a/dialects/osr/dlsof.h b/dialects/osr/dlsof.h new file mode 100644 index 0000000..ebca8f2 --- /dev/null +++ b/dialects/osr/dlsof.h @@ -0,0 +1,255 @@ +/* + * dlsof.h - SCO OpenServer header file for lsof + */ + + +/* + * 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. + */ + + +/* + * $Id: dlsof.h,v 1.14 2007/04/24 16:22:40 abe Exp $ + */ + + +#if !defined(OSR_LSOF_H) +#define OSR_LSOF_H 1 + +#include +#include +#include +#include +#include +#include +#include + +# if OSRV>=500 +#include +# endif /* OSRV>=500 */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * This confusing sequence of redefinitions of xdevmap allows lsof to size + * its copy of the kernel's xdevmap[] table dynamically, based on the + * kernel's nxdevmaps value. + * + * The net result is that there is a dummy struct XDEVMAP[1], defined in + * dstore.c, that is never used. The copy of the kernel's xdevmap[] table + * is stored in the space malloc()'d in dproc.c and addressed by Xdevmap. + * The last redefinition of xdevmap to Xdevmap causes the macros of + * to use Xdevmap. + * + * All this is done: 1) to avoid having to allocate a large amount of fixed + * space in advance to a copy of the kernel's xdevmap; and 2) to keep CC from + * complaining about the absence of a "struct xdevmap xdevmap[]," matching + * the "extern struct xdevmap xdevmap[]" declaration in , + * while still allowing lsof to use the equivalent of a "struct xdevmap *" + * construct instead, particularly with the kernel forms of the major() and + * minor() macros. + */ + +#define xdevmap XDEVMAP +#define _INKERNEL +#include +#undef _INKERNEL +extern struct XDEVMAP *Xdevmap; +#undef xdevmap +#define xdevmap Xdevmap + +#include +#include +#include +#include +#include + +# if defined(HAS_NFS) +#define multiple_groups 1 +#include +#include +#include +#include +# endif /* defined(HAS_NFS) */ + +#include +#include +#undef NOGROUP +#include +#include + +# if OSRV<500 +#include +#include +# else /* OSRV>=500 */ +#include +#include +#include +#include +# endif /* OSRV<500 */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define INKERNEL +#include +#undef INKERNEL + + +/* + * Adjust for the availability of symbolic links. + */ + +# if defined(HAS_STATLSTAT) +#define lstat statlstat +# else /* !defined(HAS_STATLSTAT) */ +#define lstat stat +#define readlink(path, buf, len) (-1) +# endif /* defined(HAS_STATLSTAT) */ + + + +#define COMP_P const void +#define DEVINCR 1024 /* device table malloc() increment */ +#define DIRTYPE dirent +typedef off_t KA_T; +#define KMEM "/dev/kmem" +#define MALLOC_P void +#define MNTTAB "/etc/mnttab" +#define FREE_P MALLOC_P +#define MALLOC_S size_t + +# if !defined(MAXPATHLEN) +#define MAXPATHLEN 1024 +# endif /* !defined(MAXPATHLEN) */ + +#define MAXSEGS 100 /* maximum text segments */ +#define MAXSYSCMDL (PSCOMSIZ - 1) /* max system command name length */ + +# if OSRV<500 +#define N_UNIX "/unix" +# endif /* OSRV<500 */ + +#define PROCBFRD 16 /* count of proc structures buffered */ +#define PROCSIZE sizeof(struct proc) +#define QSORT_P void +#define READLEN_T unsigned +#define STRNCPY_L size_t +#define STRNML 32 +#define U_SIZE sizeof(struct user) + + +/* + * Global storage definitions (including their structure definitions) + */ + +extern char **Cdevsw; +extern int Cdevcnt; +extern int CloneMajor; +extern int EventMajor; +extern char **Fsinfo; +extern int Fsinfomax; +extern int HaveCloneMajor; +extern int HaveEventMajor; +extern int HaveSockdev; +extern int Hz; +extern int Kd; +extern KA_T Lbolt; + +extern int nxdevmaps; /* maximum kernel xdevmap[] index */ + +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; /* st_fstype */ +# endif + +}; + +#define NL_NAME n_name /* name element in struct nlist */ + +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 sfile *next; /* forward link */ +}; + +extern int Sockdev; +extern KA_T Socktab; + +/* + * Definitions for dvch.c, isfn.c, and rdev.c + */ + +#define CLONEMAJ CloneMajor /* clone major variable name */ + +# if defined(HASDCACHE) +# if OSRV<500 +#define DVCH_CHOWN 1 /* no fchown() below release 5.0 */ +# endif /* OSRV<500 */ +# endif /* defined(HASDCACHE) */ + +#define HAS_STD_CLONE 1 /* has standard clone structure */ +#define HAVECLONEMAJ HaveCloneMajor /* clone major status variable name */ + +#endif /* OSR_LSOF_H */ diff --git a/dialects/osr/dmnt.c b/dialects/osr/dmnt.c new file mode 100644 index 0000000..47e33f4 --- /dev/null +++ b/dialects/osr/dmnt.c @@ -0,0 +1,219 @@ +/* + * dmnt.c - SCO OpenServer mount support functions for lsof + */ + + +/* + * 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 1995 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: dmnt.c,v 1.8 2005/08/08 19:54:32 abe Exp $"; +#endif + +#include "lsof.h" + + +/* + * Local static definitions + */ + +static struct mounts *Lmi = (struct mounts *)NULL; /* local mount info */ +static int Lmist = 0; /* Lmi status */ + + +/* + * readmnt() - read mount table + */ + +struct mounts * +readmnt() +{ + int br, fd; + int bx = sizeof(struct mnttab); + char *cp; + char dvnm[MAXPATHLEN], fsnm[MAXPATHLEN]; + MALLOC_S dvnml, fsnml; + MALLOC_S len; + char *ln = (char *)NULL; + struct mnttab m; + struct mounts *mtp; + struct stat sb; + + if (Lmi || Lmist) + return(Lmi); +/* + * Open access to the mount table. + */ + if ((fd = open(MNTTAB, O_RDONLY, 0)) < 0) { + (void) fprintf(stderr, "%s: can't open %s\n", Pn, MNTTAB); + Exit(1); + } +/* + * Read the first mount table entry. + */ + br = read(fd, (char *)&m, bx); + dvnml = fsnml = 0; +/* + * Process the next complete mount table entry. + */ + while (br == bx) { + if (!dvnml) { + + /* + * Start the device and file system name assemblies. + */ + dvnml = strlen(m.mt_dev); + if (dvnml >= MAXPATHLEN) + dvnml = MAXPATHLEN - 1; + (void) strncpy(dvnm, m.mt_dev, dvnml); + dvnm[dvnml] = '\0'; + fsnml = strlen(m.mt_filsys); + if (fsnml >= MAXPATHLEN) + fsnml = MAXPATHLEN - 1; + (void) strncpy(fsnm, m.mt_filsys, fsnml); + fsnm[fsnml] = '\0'; + } + while ((br = read(fd, (char *)&m, bx)) == bx + && strcmp(m.mt_filsys, "nothing") == 0 + && strcmp(m.mt_dev, "nowhere") == 0) { + + /* + * Add the "nothing/nowhere" extensions to the assemblies. + */ + len = strlen(&m.mt_dev[8]); + if (len >= (MAXPATHLEN - dvnml)) + len = MAXPATHLEN - dvnml - 1; + if (len) { + (void) strncpy(&dvnm[dvnml], &m.mt_dev[8], len); + dvnml += len; + dvnm[dvnml] = '\0'; + } + len = strlen(&m.mt_filsys[8]); + if (len >= (MAXPATHLEN - fsnml)) + len = MAXPATHLEN - fsnml - 1; + if (len) { + (void) strncpy(&fsnm[fsnml], &m.mt_filsys[8], len); + fsnml += len; + fsnm[fsnml] = '\0'; + } + } + /* + * Skip automount place markers. + */ + if ((cp = strrchr(dvnm, ':')) && strncmp(cp, ":(pid", 5) == 0) { + dvnml = fsnml = 0; + continue; + } + /* + * Interpolate a possible symbolic directory link. + */ + if (ln) { + (void) free((FREE_P *)ln); + ln = (char *)NULL; + } + if (!(ln = Readlink(fsnm))) { + if (!Fwarn){ + (void) fprintf(stderr, + " Output information may be incomplete.\n"); + } + dvnml = fsnml = 0; + continue; + } + if (*ln != '/') + continue; + if (ln == fsnm) { + + /* + * Allocate space for a copy of the file system name. + */ + if (!(ln = mkstrcpy(fsnm, (MALLOC_S *)NULL))) { + +no_space_for_mount: + + (void) fprintf(stderr, "%s: no space for mount at ", Pn); + safestrprt(fsnm, stderr, 0); + (void) fprintf(stderr, " ("); + safestrprt(dvnm, stderr, 0); + (void) fprintf(stderr, ")\n"); + Exit(1); + } + } + /* + * Stat() the directory. + */ + if (statsafely(ln, &sb)) { + if (!Fwarn) { + (void) fprintf(stderr, + "%s: WARNING: can't stat() file system: ", Pn); + safestrprt(fsnm, stderr, 1); + (void) fprintf(stderr, + " Output information may be incomplete.\n"); + } + dvnml = fsnml = 0; + continue; + } + /* + * Allocate and fill a local mount structure. + */ + if (!(mtp = (struct mounts *)malloc(sizeof(struct mounts)))) + goto no_space_for_mount; + mtp->dir = ln; + ln = (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 (!(cp = mkstrcpy(dvnm, (MALLOC_S *)NULL))) + goto no_space_for_mount; + mtp->fsname = cp; + ln = Readlink(cp); + /* + * Stat() the file system (mounted-on) name and add file system + * information to the local mount table entry. + */ + if (statsafely(ln, &sb)) + sb.st_mode = 0; + mtp->fsnmres = ln; + ln = (char *)NULL; + mtp->fs_mode = sb.st_mode; + Lmi = mtp; + dvnml = fsnml = 0; + } + (void) close(fd); +/* + * Clean up and return the local mount information table address. + */ + if (ln) + (void) free((FREE_P *)ln); + Lmist = 1; + return(Lmi); +} diff --git a/dialects/osr/dnode.c b/dialects/osr/dnode.c new file mode 100644 index 0000000..755c82f --- /dev/null +++ b/dialects/osr/dnode.c @@ -0,0 +1,739 @@ +/* + * dnode.c - SCO OpenServer node functions for lsof + */ + + +/* + * 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 1995 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: dnode.c,v 1.21 2006/03/28 22:09:23 abe Exp $"; +#endif + + +#include "lsof.h" + + +_PROTOTYPE(static struct l_dev * finddev,(dev_t *dev, dev_t *rdev, int stream)); + + +/* + * finddev() - look up device by device number + */ + +static struct l_dev * +finddev(dev, rdev, stream) + dev_t *dev; /* device */ + dev_t *rdev; /* raw device */ + int stream; /* stream if 1 */ +{ + struct clone *c; + struct l_dev *dp; +/* + * Search device table for match. + */ + +#if defined(HASDCACHE) + +finddev_again: + +#endif /* defined(HASDCACHE) */ + + if ((dp = lkupdev(dev, rdev, 0, 0))) + return(dp); +/* + * Search for clone. + */ + if (stream && Clone) { + 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 finddev_again; +#endif /* defined(HASDCACHE) */ + + return(&Devtp[c->dx]); + } + } + } + return((struct l_dev *)NULL); +} + + +/* + * process_node() - process node + */ + +void +process_node(na) + KA_T na; /* inode kernel space address */ +{ + char *cp, tbuf[32]; + short dl; + struct l_dev *dp; + unsigned char *fa = (unsigned char *)NULL; + struct filock fl; + KA_T flf, flp; + int fp, lp; + struct inode i; + short ity, udpsf, udpsl; + int j, k, l; + KA_T ka, qp; + unsigned char *la = (unsigned char *)NULL; + struct mounts *lm; + struct module_info mi; + unsigned short *n; + KA_T p; + struct inpcb pcb; + int port; + int pt = -1; + struct queue q; + struct qinit qi; + struct stdata sd; + char *tn; + int type; + struct udpdev udp; + short udptm = 0; + +#if defined(HAS_NFS) + struct rnode r; +#endif /* defined(HAS_NFS) */ + +#if OSRV>=500 + short hpps = 0; + unsigned short *n1; + struct pipeinode pi; +#endif /* OSRV>=500 */ + +/* + * Read the inode. + */ + if ( ! na) { + enter_nm("no inode address"); + return; + } + if (readinode(na, &i)) { + enter_nm(Namech); + return; + } + +#if defined(HASNCACHE) + Lf->na = na; +#endif /* defined(HASNCACHE) */ + +#if defined(HASFSTRUCT) + Lf->fna = na; + Lf->fsv |= FSV_NI; +#endif /* defined(HASFSTRUCT) */ + +/* + * Identify the node type. + */ + if (HaveSockdev && (i.i_ftype & IFMT) == IFCHR + && GET_MAJ_DEV(i.i_rdev) == Sockdev) + { + + /* + * Process a socket. + */ + process_socket(&i); + return; + } + if (Selinet) + return; + ity = i.i_fstyp; + type = i.i_ftype & IFMT; + if (ity < 1 || ity > Fsinfomax || !Fsinfo[ity-1]) { + +#if OSRV>=500 + if (ity) { +#endif /* OSRV>=500 */ + + (void) snpf(Namech,Namechl,"unknown fstyp (%d) in inode",ity); + enter_nm(Namech); + return; + +#if OSRV>=500 + } +#endif /* OSRV>=500 */ + + } + if (ity && strcasecmp(Fsinfo[ity-1], "HS") == 0) + Ntype = N_HSFS; + +#if defined(HAS_NFS) + else if (ity && strcasecmp(Fsinfo[ity-1], "NFS") == 0) { + + /* + * Get information on NFS file. + */ + Ntype = N_NFS; + Lf->is_nfs = 1; + if (Fnfs) + Lf->sf |= SELNFS; + if (!i.i_fsptr || readrnode((KA_T)i.i_fsptr, &r)) { + (void) snpf(Namech, Namechl, "can't read rnode (%s)", + print_kptr((KA_T)i.i_fsptr, (char *)NULL, 0)); + enter_nm(Namech); + return; + } + +# if defined(HASNCACHE) + Lf->na = (KA_T)i.i_fsptr; +# endif /* defined(HASNCACHE) */ + + } +#endif /* defined(HAS_NFS) */ + + else { + + /* + * Determine the node type from the inode file type. + */ + switch (type) { + case IFBLK: + Ntype = N_BLK; + break; + case IFCHR: + Ntype = N_CHR; + break; + case IFIFO: + Ntype = N_FIFO; + break; + case IFMPB: + case IFMPC: + Ntype = N_MPC; + break; + case IFNAM: + Ntype = N_NM; + break; + } + } +/* + * Obtain lock information. + */ + if ((flf = (KA_T)i.i_filocks)) { + flp = flf; + do { + if ((kread(flp, (char *)&fl, sizeof(fl)))) + break; + if (fl.set.l_pid != (pid_t)Lp->pid) + continue; + if (fl.set.l_whence == (short)0 && fl.set.l_start == (off_t)0 + && fl.set.l_len == 0x7fffffff) + l = 1; + else + l = 0; + +#if OSRV<500 + if (i.i_flag & IXLOCKED) +#else /* OSRV>=500 */ + if (fl.flags & F_XOUT) +#endif /* OSRV<500 */ + + Lf->lock = l ? 'X' : 'x'; + else if (fl.set.l_type == F_RDLCK) + Lf->lock = l ? 'R' : 'r'; + else if (fl.set.l_type == F_WRLCK) + Lf->lock = l ? 'W' : 'w'; + else if (fl.set.l_type == (F_RDLCK | F_WRLCK)) + Lf->lock = 'u'; + break; + } while ((flp = (KA_T)fl.next) && flp != flf); + } + +#if OSRV>=500 +/* + * See if a FIFO node is an HPPS node -- 3.2v5.0.0 and higher. + */ + if (Ntype == N_FIFO && ity && strcasecmp(Fsinfo[ity-1], "HPPS") == 0) + { + hpps = 1; + if (i.i_fsptr) { + enter_dev_ch(print_kptr((KA_T)i.i_fsptr, (char )NULL, 0)); + if (kread((KA_T)i.i_fsptr, (char *)&pi, sizeof(pi)) == 0) + hpps = 2; + } + } +#endif /* OSRV>=500 */ + +/* + * Determine the device. + */ + switch (Ntype) { + case N_BLK: + Lf->dev = i.i_dev; + Lf->rdev = i.i_rdev; + Lf->dev_def = Lf->rdev_def = 1; + break; + case N_FIFO: + case N_HSFS: + case N_NM: + case N_REGLR: + +#if OSRV>=500 + if (hpps) + break; +#endif /* OSRV>=500 */ + + Lf->dev = i.i_dev; + Lf->dev_def = 1; + break; + case N_CHR: + Lf->dev = i.i_dev; + Lf->rdev = i.i_rdev; + Lf->dev_def = Lf->rdev_def = 1; + if (i.i_sptr) { + + /* + * Namech may be: + * /dev/* name if it exists for i.i_rdev; + * cdevsw[].d_name if it exists for GET_MAJ_DEV(i.i_rdev); + * "STR:" otherwise. + */ + (void) snpf(Namech, Namechl, "STR:"); + Lf->is_stream = 1; + k = strlen(Namech); + cp = (char *)NULL; + if ((dp = finddev(&Lf->dev, &Lf->rdev, 1))) { + (void) snpf(&Namech[k], Namechl - k, dp->name); + k += strlen(dp->name); + if ((cp = strrchr(dp->name, '/'))) + cp++; + } else if ((j = GET_MAJ_DEV(i.i_rdev)) + < Cdevcnt && (cp = Cdevsw[j])) + { + (void) snpf(Namech, Namechl, "%s", cp); + k += strlen(cp); + } + /* + * Get the module names of all queue elements of the stream's + * sd_wrq queue. Skip module names that end in "head", + * match the last component of the /dev name, or match the + * cdevsw[].d_name. + */ + p = (KA_T)NULL; + if (!kread((KA_T)i.i_sptr, (char *)&sd, sizeof(sd))) { + dl = sizeof(tbuf) - 1; + tbuf[dl] = '\0'; + qp = (KA_T)sd.sd_wrq; + for (j = 0; qp && j < 20; j++, qp = (KA_T)q.q_next) { + if (kread(qp, (char *)&q, sizeof(q))) + break; + if (!(ka = (KA_T)q.q_qinfo) + || kread(ka, (char *)&qi, sizeof(qi))) + continue; + if (!(ka = (KA_T)qi.qi_minfo) + || kread(ka, (char *)&mi, sizeof(mi))) + continue; + if (!(ka = (KA_T)mi.mi_idname) + || kread(ka, tbuf, dl)) + continue; + if ((l = strlen(tbuf)) < 1) + continue; + if (l >= 4 && strcmp(&tbuf[l - 4], "head") == 0) + continue; + if (cp && strcmp(cp, tbuf) == 0) { + if (q.q_ptr && pt < 0) { + + /* + * If this is a TCP or UDP module and the + * queue structure has a private pointer in + * q_ptr, save it as a PCB address. + */ + if (strcasecmp(cp, "tcp") == 0) { + pt = 0; + (void) snpf(Lf->iproto, + sizeof(Lf->iproto), "TCP"); + } else if (strcasecmp(cp, "udp") == 0) { + pt = 1; + (void) snpf(Lf->iproto, + sizeof(Lf->iproto), "UDP"); + } + if (pt >= 0) + p = (KA_T)q.q_ptr; + else + pt = -1; + } + continue; + } + if (k) { + if ((k + 2) > (Namechl - 1)) + break; + (void) snpf(&Namech[k], Namechl - k, "->"); + k += 2; + } + if ((k + l) > (Namechl - 1)) + break; + (void) snpf(&Namech[k], Namechl - k, tbuf); + k += l; + } + } + if (p && pt >= 0) { + + /* + * If the stream has a TCP or UDP module with a PCB pointer, + * print any associated local and foreign Internet addresses. + */ + if (kread(p, (char *)&pcb, sizeof(pcb))) + break; + if (Fnet) + Lf->sf |= SELNET; + if ((k + 1) > (Namechl - 1)) + break; + if (pt == 1 && pcb.inp_ppcb) { + + /* + * If this is a UDP stream, get the udpdev structure at the + * PCB's per-protocol address. It may contain addresses. + */ + if (kread((KA_T)pcb.inp_ppcb, (char *)&udp, sizeof(udp)) + == 0) { + +#if OSRV>=500 + if (udp.ud_lsin.sin_addr.s_addr != INADDR_ANY + || udp.ud_lsin.sin_port != 0) + udpsl = 1; + else + udpsl = 0; +#endif /* OSRV>=500 */ + + if (udp.ud_fsin.sin_addr.s_addr != INADDR_ANY + || udp.ud_fsin.sin_port != 0) + udpsf = 1; + else + udpsf = 0; + } + } else + udpsf = udpsl = 0; + /* + * Enter the local address from the PCB. If there is none, + * and if this is a 5.0.0 or greater UDP stream, and if it + * has a local address set, use it. + */ + la = (unsigned char *)&pcb.inp_laddr; + lp = (int)ntohs(pcb.inp_lport); + +#if OSRV>=500 + if (((struct in_addr *)la)->s_addr == INADDR_ANY + && lp == 0 && udpsl) { + la = (unsigned char *)&udp.ud_lsin.sin_addr; + lp = (int)ntohs(udp.ud_lsin.sin_port); + } + +#endif /* OSRV>=500 */ + + /* + * Enter the foreign address from the PCB. If there is + * none, and if this is a 5.0.0 or greater UDP stream, and + * if it has a local address set, use it. + */ + if (pcb.inp_faddr.s_addr!=INADDR_ANY || pcb.inp_fport!=0) { + fa = (unsigned char *)&pcb.inp_faddr; + fp = (int)ntohs(pcb.inp_fport); + } else if (udpsf) { + fa = (unsigned char *)&udp.ud_fsin.sin_addr; + fp = (int)ntohs(udp.ud_fsin.sin_port); + udptm = 1; + } + if (fa || la) { + (void) ent_inaddr(la, lp, fa, fp, AF_INET); + if (udptm && !Lf->nma) + (void) udp_tm(udp.ud_ftime); + } + if (!i.i_number) + Lf->inp_ty = 2; + } + } else { + if (ity) { + if (strcasecmp(Fsinfo[ity-1], "COM") == 0) + Ntype = N_COM; + else + Ntype = N_CHR; + } else { + Ntype = N_CHR; + if (!finddev(&i.i_dev, &i.i_rdev, 0) + && HaveEventMajor + && GET_MAJ_DEV(i.i_rdev) == EventMajor) + (void) snpf(Namech, Namechl, + "clone %d:/dev/event", GET_MIN_DEV(i.i_rdev)); + } + } + break; + +#if defined(HAS_NFS) + case N_NFS: + +#if OSRV<500 + Lf->dev = (dev_t)_makedev(~GET_MAJ_DEV(i.i_dev), + GET_MIN_DEV(i.i_dev)); + Lf->rdev = (dev_t)_makedev(~GET_MAJ_DEV(i.i_rdev), + GET_MIN_DEV(i.i_rdev)); +#else /* OSRV>=500 */ + Lf->dev = i.i_dev; + Lf->rdev = i.i_rdev; +#endif /* OSRV<500 */ + + Lf->dev_def = Lf->rdev_def = 1; + break; +#endif /* defined(HAS_NFS) */ + + } +/* + * Determine the inode number. + */ + switch (Ntype) { + case N_HSFS: + +#if OSRV<500 + /* + * High Sierra inode numbers for versions below 5.0.0, as reported + * by "ls -i" and stat(2), are the lower 16 bits of i_number. + */ + if ((Lf->inode = (unsigned long)(i.i_number & 0xffff))) +#else /* OSRV>=500 */ + if ((Lf->inode = (unsigned long)i.i_number)) +#endif /* OSRV<500 */ + + Lf->inp_ty = 1; + break; + +#if defined(HAS_NFS) + case N_NFS: + +#if OSRV<500 + n = (unsigned short *)&r.r_fh.fh_pad[14]; + if ((Lf->inode = (unsigned long)ntohs(*n))) + Lf->inp_ty = 1; + else if ((Lf->inode = (unsigned long)r.r_fh.fh_u.fh_fgen_u)) +#else /* OSRV>=500 */ + n = (unsigned short *)&r.r_fh.fh_u.fh_fid_u[4]; + n1 = (unsigned short *)&r.r_fh.fh_u.fh_fid_u[2]; + if ((Lf->inode = (unsigned long)*n)) + Lf->inp_ty = 1; + else if ((Lf->inode = (unsigned long)*n1)) +#endif /* OSRV<500 */ + + Lf->inp_ty = 1; + break; +#endif /* defined(HAS_NFS) */ + + case N_BLK: + case N_CHR: + case N_COM: + case N_FIFO: + case N_NM: + case N_REGLR: + +#if OSRV>=500 + /* + * Inodes for some 5.0.x HPPS FIFOs have an i_number that is the same + * as i_fsptr. If it is, ignore it, because i_fsptr has already been + * recorded for the DEVICE column. + */ + if (hpps && i.i_fsptr && i.i_number + && (unsigned long)i.i_fsptr == (unsigned long)i.i_number) + break; +#endif /* OSRV>=500 */ + + if (i.i_number) { + Lf->inode = (unsigned long)i.i_number; + Lf->inp_ty = 1; + } + break; + } +/* + * Determine the file size. + */ + if (Foffset) + Lf->off_def = 1; + else { + switch (Ntype) { + case N_BLK: + if (!Fsize) + Lf->off_def = 1; + break; + case N_CHR: + case N_COM: + if (!Fsize) + Lf->off_def = 1; + break; + case N_FIFO: + +#if OSRV>=500 + if (hpps == 2) { + Lf->sz = (SZOFFTYPE)pi.count; + Lf->sz_def = 1; + break; + } +#endif /* OSRV>=500 */ + + if (!Fsize) + Lf->off_def = 1; + break; + case N_HSFS: + +#if defined(HAS_NFS) + case N_NFS: + Lf->sz = (SZOFFTYPE)i.i_size; + Lf->sz_def = 1; + break; +#endif /* defined(HAS_NFS) */ + + case N_REGLR: + if (type == IFREG || type == IFDIR) { + Lf->sz = (SZOFFTYPE)i.i_size; + Lf->sz_def = 1; + } + break; + } + } +/* + * Record link count. + */ + if (Fnlink) { + Lf->nlink = (long)i.i_nlink; + Lf->nlink_def = 1; + if (Nlink && (Lf->nlink < Nlink)) + Lf->sf |= SELNLINK; + } +/* + * Format the type name. + */ + switch (type) { + case IFDIR: + tn = "DIR"; + break; + case IFBLK: + tn = "BLK"; + break; + case IFCHR: + tn = "CHR"; + break; + case IFREG: + tn = "REG"; + break; + case IFMPC: + tn = "MPC"; + break; + case IFMPB: + tn = "MPB"; + break; + case IFNAM: + if (i.i_rdev == S_INSEM) + tn = "XSEM"; + else if (i.i_rdev == S_INSHD) + tn = "XSD"; + else { + tn = "XNAM"; + (void) snpf(Namech, Namechl, + "unknown Xenix special file type: %x", i.i_rdev); + } + break; + case IFIFO: + tn = "FIFO"; + break; + +#if defined(IFLNK) + case IFLNK: + tn = "LINK"; + break; +#endif /* defined(IFLNK) */ + + default: + (void) snpf(Lf->type, sizeof(Lf->type), "%04o", + ((type >> 12) & 0xfff)); + tn = NULL; + } + if (tn) + (void) snpf(Lf->type, sizeof(Lf->type), "%s", tn); +/* + * Save the file system names. + */ + switch (Ntype) { + case N_BLK: + case N_CHR: + case N_FIFO: + case N_HSFS: + +#if defined(HAS_NFS) + case N_NFS: +#endif /* defined(HAS_NFS) */ + + case N_NM: + case N_REGLR: + if (Lf->dev_def) { + + /* + * Defer the local mount info table search until printname(). + */ + Lf->lmi_srch = 1; + } + break; + } + Lf->ntype = Ntype; + +#if defined(HASBLKDEV) +/* + * If this is a IFBLK file and it's missing an inode number, try to + * supply one. + */ + if ((Lf->inp_ty == 0) && (type == IFBLK)) + find_bl_ino(); +#endif /* defined(HASBLKDEV) */ + +/* + * If this is a IFCHR file and it's missing an inode number, try to + * supply one. + */ + if ((Lf->inp_ty == 0) && (type == IFCHR)) + find_ch_ino(); +/* + * Test for specified file. + */ + if (Sfile && is_file_named((char *)NULL, + ((type == IFCHR) || (type == IFBLK) || (type == IFNAM)) ? 1 + : 0)) + Lf->sf |= SELNM; + +#if OSRV>=500 +/* + * If this is an HPPS node and no other name characters have been + * entered, enter HPPS as the name. + */ + if (hpps && Namech[0] == '\0') + (void) snpf(Namech, Namechl, "HPPS"); +#endif /* OSRV>=500 */ + +/* + * Enter name characters. + */ + if (Namech[0]) + enter_nm(Namech); +} diff --git a/dialects/osr/dproc.c b/dialects/osr/dproc.c new file mode 100644 index 0000000..facdb42 --- /dev/null +++ b/dialects/osr/dproc.c @@ -0,0 +1,2003 @@ +/* + * dproc.c - SCO OpenServer process access functions for lsof + */ + + +/* + * 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 1995 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: dproc.c,v 1.18 2007/04/24 16:22:40 abe Exp $"; +#endif + +#include "lsof.h" + + +/* + * Local static values + */ + +static KA_T Kp; /* kernel process table address */ +static KA_T *Nc = (KA_T *)NULL; /* node cache */ +static int Nn = 0; /* number of Nc[] entries allocated */ + +#if OSRV<500 +static int Npp = 0; /* number of pregions per process */ +static struct pregion *Pr = (struct pregion *)NULL; + /* pregion buffer */ +static int Prsz = 0; /* size of Pr */ +#endif /* OSRV<500 */ + + +static struct var Var; /* kernel variables */ + + +_PROTOTYPE(static void get_cdevsw,(void)); +_PROTOTYPE(static void get_kernel_access,(void)); + +#if !defined(N_UNIX) +_PROTOTYPE(static int is_boot,(char *p)); +#endif /* !defined(N_UNIX) */ + +_PROTOTYPE(static int open_kmem,(int nx)); +_PROTOTYPE(static void process_text,(KA_T prp)); +_PROTOTYPE(static void readfsinfo,(void)); + + +/* + * Ckkv - check kernel version + */ + +static void +Ckkv(d, er, ev, ea) + char *d; /* dialect */ + char *er; /* expected release */ + char *ev; /* expected version */ + char *ea; /* expected architecture */ +{ + +#if defined(HASKERNIDCK) + struct scoutsname s; + + if (Fwarn) + return; +/* + * Read OSR kernel information. + */ + if (__scoinfo(&s, sizeof(s)) < 0) { + (void) fprintf(stderr, "%s: can't get __scoinfo: %s\n", + Pn, strerror(errno)); + Exit(1); + } +/* + * Warn if the actual and expected releases don't match. + */ + if (!er || strcmp(er, s.release)) + (void) fprintf(stderr, + "%s: WARNING: compiled for %s release %s; this is %s.\n", + Pn, d, er ? er : "UNKNOWN", s.release); +#endif /* defined(HASKERNIDCK) */ + +} + + +/* + * gather_proc_info() -- gather process information + */ + +void +gather_proc_info() +{ + int i, j, nf, pbc, px; + struct proc *p; + static char *pb = (char *)NULL; + int pid, pgrp; + short pss, sf; + static struct user *u; + static char *ua = (char *)NULL; + static MALLOC_S ual = 0; + unsigned int uid; + +#if defined(HASFSTRUCT) + static MALLOC_S npofb = 0; + char *pof; + static char *pofb = (char *)NULL; +#endif /* defined(HASFSTRUCT) */ + +/* + * Allocate user structure buffer. + */ + if (!ua) { + ual = (MALLOC_S)(MAXUSIZE * NBPC); + if (!(ua = (char *)malloc(ual))) { + (void) fprintf(stderr, + "%s: no space for %d byte user structure buffer\n", + Pn, ual); + Exit(1); + } + u = (struct user *)ua; + } +/* + * Allocate proc structure buffer. + */ + if (!pb) { + if (!(pb = (char *)malloc(sizeof(struct proc) * PROCBFRD))) { + (void) fprintf(stderr, "%s: no space for %d proc structures\n", + Pn, PROCBFRD); + Exit(1); + } + } +/* + * Examine proc structures and their associated information. + */ + for (pbc = px = 0; px < Var.v_proc; px++) { + if (px >= pbc) { + + /* + * Refill proc buffer. + */ + i = Var.v_proc - px; + if (i > PROCBFRD) + i = PROCBFRD; + j = kread((KA_T)(Kp + (px * sizeof(struct proc))), pb, + sizeof(struct proc) * i); + pbc = px + i; + p = (struct proc *)pb; + if (j) { + px += i; + continue; + } + } else + p++; + if (p->p_stat == 0 || p->p_stat == SZOMB) + continue; + /* + * Get Process ID, Process group ID, and User ID. + */ + pid = (int)p->p_pid; + pgrp = (int)p->p_pgrp; + uid = (unsigned int)p->p_uid; + if (is_proc_excl(pid, pgrp, (UID_ARG)uid, &pss, &sf)) + continue; + /* + * Get the user area associated with the process. + */ + if (sysi86(RDUBLK, pid, ua, MAXUSIZE * NBPC) == -1) + continue; + /* + * Allocate a local process structure. + */ + if (is_cmd_excl(u->u_comm, &pss, &sf)) + continue; + alloc_lproc(pid, pgrp, (int)p->p_ppid, (UID_ARG)uid, u->u_comm, + (int)pss, (int)sf); + Plf = (struct lfile *)NULL; + /* + * Save current working directory information. + */ + if (u->u_cdir) { + alloc_lfile(CWD, -1); + process_node((KA_T)u->u_cdir); + if (Lf->sf) + link_lfile(); + } + /* + * Save root directory information. + */ + if (u->u_rdir) { + alloc_lfile(RTD, -1); + process_node((KA_T)u->u_rdir); + if (Lf->sf) + link_lfile(); + } + /* + * Print information on the text file. + */ + if (p->p_region) + process_text((KA_T)p->p_region); + /* + * Save information on file descriptors. + */ + +#if OSRV<42 + nf = Var.v_nofiles; +#else /* OSRV>=42 */ + nf = u->u_nofiles ? u->u_nofiles : Var.v_nofiles; +#endif /* OSRV<42 */ + +#if defined(HASFSTRUCT) + if (Fsv & FSV_FG) { + + /* + * If u_pofile is in the u block, set its address. + */ + if (nf && u->u_pofile + && ((unsigned)u->u_pofile >= UVUBLK) + && ((MALLOC_S)((unsigned)u->u_pofile - UVUBLK + nf) <= ual)) + { + pof = ua + (unsigned)u->u_pofile - UVUBLK; + } else if (nf && u->u_pofile) { + + /* + * Allocate space for u_pofile and read it from kernel memory. + */ + if (nf > npofb) { + if (!pofb) + pofb = (char *)malloc((MALLOC_S)nf); + else + pofb = (char *)realloc((MALLOC_P *)pofb, + (MALLOC_S)nf); + if (!pofb) { + (void) fprintf(stderr, "%s: no pofile space\n", Pn); + Exit(1); + } + npofb = nf; + } + if (kread((KA_T)u->u_pofile, pofb, nf)) + pof = (char *)NULL; + else + pof = pofb; + } else + pof = (char *)NULL; + } +#endif /* defined(HASFSTRUCT) */ + + for (i = 0; i < nf; i++) { + if (u->u_ofile[i]) { + alloc_lfile((char *)NULL, i); + process_file((KA_T)u->u_ofile[i]); + if (Lf->sf) { + +#if defined(HASFSTRUCT) + if (Fsv & FSV_FG && pof) + Lf->pof = (long)pof[i]; +#endif /* defined(HASFSTRUCT) */ + + link_lfile(); + } + } + } + /* + * Examine results. + */ + if (examine_lproc()) + return; + } +} + + +/* + * get_cdevsw() - get cdevsw[] names and record clone major device number + */ + +void +get_cdevsw() +{ + char buf[16]; + struct cdevsw *c, *tmp; + int i, j, len; + struct stat sb; + KA_T v[2]; +/* + * Check cdevsw[] kernel addresses. + * Read cdevsw[] count from kernel's cdevcnt. + */ + if (get_Nl_value("cdev", Drive_Nl, &v[0]) < 0 + || get_Nl_value("ncdev", Drive_Nl, &v[1]) < 0 + || !v[0] || !v[1] + || kread(v[1], (char *)&Cdevcnt, sizeof(Cdevcnt)) + || Cdevcnt < 1) + return; +/* + * Allocate cache space. + */ + if (!(Cdevsw = (char **)malloc(Cdevcnt * sizeof(char *)))) { + (void) fprintf(stderr, "%s: no space for %d cdevsw[] names\n", + Pn, Cdevcnt); + Exit(1); + } +/* + * Allocate temporary space for a copy of cdevsw[] and read it. + */ + i = Cdevcnt * sizeof(struct cdevsw); + if (!(tmp = (struct cdevsw *)malloc(i))) { + (void) fprintf(stderr, "%s: no space for %d cdevsw[] entries\n", + Pn, Cdevcnt); + Exit(1); + } + if (kread((KA_T)v[0], (char *)tmp, i)) { + (void) free((FREE_P *)Cdevsw); + Cdevsw = (char **)NULL; + Cdevcnt = 0; + (void) free((FREE_P *)tmp); + return; + } +/* + * Cache the names from cdevsw[].d_name. + * Record the number of the "clone" device. + */ + j = sizeof(buf) - 1; + buf[j] = '\0'; + for (c = tmp, i = 0; i < Cdevcnt; c++, i++) { + Cdevsw[i] = (char *)NULL; + if (!c->d_name) + continue; + if (kread((KA_T)c->d_name, buf, j)) { + (void) fprintf(stderr, + "%s: WARNING: can't read name for cdevsw[%d]: %#x\n", + Pn, i, c->d_name); + continue; + } + if (!buf[0]) + continue; + len = strlen(buf) + 1; + if (!(Cdevsw[i] = (char *)malloc(len))) { + (void) fprintf(stderr, "%s: no space for cdevsw[%d] name: %s\n", + Pn, i, buf); + Exit(1); + } + (void) snpf(Cdevsw[i], len, "%s", buf); + if (!HaveCloneMajor && strcmp(buf, "clone") == 0) { + CloneMajor = i; + HaveCloneMajor = 1; + continue; + } + if (!HaveEventMajor && strcmp(buf, "ev") == 0) { + if (stat("/dev/event", &sb) == 0 + && GET_MAJ_DEV(sb.st_rdev) == i) { + EventMajor = i; + HaveEventMajor = 1; + } + } + } + (void) free((FREE_P *)tmp); +} + + +/* + * get_kernel_access() - get access to kernel memory + */ + +static void +get_kernel_access() +{ + time_t lbolt; + MALLOC_S len; + KA_T v; +/* + * Check kernel version. + */ + (void) Ckkv("OSR", LSOF_VSTR, (char *)NULL, (char *)NULL); +/* + * See if the name list file is readable. + */ + if (Nmlst && !is_readable(Nmlst, 1)) + Exit(1); +/* + * Access kernel symbols. + */ + +#if defined(N_UNIX) + (void) build_Nl(Drive_Nl); + if (nlist(Nmlst ? Nmlst : N_UNIX, Nl) < 0) +#else /* !defined(N_UNIX) */ + if (!get_nlist_path(0)) +#endif /* defined(N_UNIX) */ + + { + (void) fprintf(stderr, "%s: can't read kernel name list.\n", Pn); + Exit(1); + } +/* + * Open access to kernel memory. + */ + (void) open_kmem(0); + +#if defined(WILLDROPGID) +/* + * Drop setgid permission. + */ + (void) dropgid(); +#endif /* defined(WILLDROPGID) */ + +/* + * Check proc table pointer. + */ + if (get_Nl_value("proc", Drive_Nl, &Kp) < 0 || !Kp) { + (void) fprintf(stderr, "%s: no proc table pointer\n", Pn); + Exit(1); + } + +#if OSRV<500 +/* + * Read pregion information. + */ + v = (KA_T)0; + if (get_Nl_value("pregpp", Drive_Nl, &v) < 0 || !v + || kread(v, (char *)&Npp, sizeof(Npp)) + || Npp < 1) { + (void) fprintf(stderr, + "%s: can't read pregion count (%d) from %s\n", Pn, Npp, + print_kptr(v, (char *)NULL, 0)); + Exit(1); + } + Prsz = (MALLOC_S)(Npp * sizeof(struct pregion)); + if (!(Pr = (struct pregion *)malloc(Prsz))) { + (void) fprintf(stderr, + "%s: can't allocate space for %d pregions\n", + Pn, Npp); + Exit(1); + } +#endif /* OSRV< 500 */ + +/* + * Read system configuration information. + */ + if (get_Nl_value("var", Drive_Nl, &v) < 0 || !v + || kread((KA_T)v, (char *)&Var, sizeof(Var))) + { + (void) fprintf(stderr, + "%s: can't read system configuration info\n", Pn); + Exit(1); + } +/* + * Read system clock values -- Hz and lightning bolt timer. + */ + v = (KA_T)0; + if (get_Nl_value("hz", Drive_Nl, &v) < 0 || !v + || kread(v, (char *)&Hz, sizeof(Hz))) + { + if (!Fwarn) + (void) fprintf(stderr, "%s: WARNING: can't read Hz from %s\n", + Pn, print_kptr(v, (char *)NULL, 0)); + Hz = -1; + } + if (get_Nl_value("lbolt", Drive_Nl, &Lbolt) < 0 || !v + || kread((KA_T)v, (char *)&lbolt, sizeof(lbolt))) + { + if (!Fwarn) + (void) fprintf(stderr, + "%s: WARNING: can't read lightning bolt timer from %s\n", + Pn, print_kptr(v, (char *)NULL, 0)); + Lbolt = (KA_T)0; + } +/* + * Get socket device number and socket table address. + */ + if (get_Nl_value("sockd", Drive_Nl, &v) < 0 || !v + || kread(v, (char *)&Sockdev, sizeof(Sockdev))) + { + (void) fprintf(stderr, + "%s: WARNING: can't identify socket device.\n", Pn); + (void) fprintf(stderr, + " Socket output may be incomplete.\n"); + return; + } + if (get_Nl_value("sockt", Drive_Nl, &Socktab) < 0 || !Socktab) { + (void) fprintf(stderr, + "%s: WARNING: socket table address is NULL.\n", Pn); + (void) fprintf(stderr, + " Socket output may be incomplete.\n"); + return; + } + +#if OSRV>=40 +/* + * Get extended device table parameters. These are needed by the kernel + * versions of the major() and minor() device number macros; they also + * identify socket devices and assist in the conversion of socket device + * numbers to socket table addresses. + */ + v = (KA_T)0; + if (get_Nl_value("nxdm", Drive_Nl, &v) < 0 || !v + || kread(v, (char *)&nxdevmaps, sizeof(nxdevmaps)) + || nxdevmaps < 0) + { + (void) fprintf(stderr, + "%s: bad extended device table size (%d) at %s.\n", + Pn, nxdevmaps, print_kptr(v, (char *)NULL, 0)); + Exit(1); + } + len = (MALLOC_S)((nxdevmaps + 1) * sizeof(struct XDEVMAP)); + if (!(Xdevmap = (struct XDEVMAP *)malloc(len))) { + (void) fprintf(stderr, "%s: no space for %d byte xdevmap table\n", + Pn, len); + Exit(1); + } + v = (KA_T)0; + if (get_Nl_value("xdm", Drive_Nl, &v) < 0 || !v + || kread((KA_T)v, (char *)Xdevmap, len)) + { + (void) fprintf(stderr, + "%s: can't read %d byte xdevmap table at #x\n", Pn, len, v); + Exit(1); + } +#endif /* OSRV>=40 */ + + HaveSockdev = 1; +} + + +#if !defined(N_UNIX) +/* + * get_nlist_path() - get kernel nlist() path + * + * As a side effect on a successful return (non-NULL character pointer), the + * boot path's name list will have been loaded into Nl[]. + */ + +char * +get_nlist_path(ap) + int ap; /* on success, return an allocated path + * string pointer if 1; return a + * constant character pointer if 0; + * return NULL if failure */ +{ + FILE *bf; + char *bfp, b1[MAXPATHLEN+1], b2[MAXPATHLEN+1], *pp, *tp; + struct dirent *de; + char *dir[] = { "/", "/stand/", NULL }; + DIR *dp; + int i; + MALLOC_S len; +/* + * If a kernel name list file was specified, use it. + */ + if (Nmlst) { + if (is_boot(Nmlst)) + return(Nmlst); + return((char *)NULL); + } +/* + * If it's possible to open /etc/ps/booted system, search it for a preferred + * boot path, defined by the value of a line that begins with "KERNEL=". + */ + bfp = pp = (char *)NULL; + if ((bf = fopen("/etc/ps/booted.system", "r"))) { + len = strlen("KERNEL="); + while (fgets(b1, sizeof(b1), bf)) { + if (strncmp(b1, "KERNEL=", len) != 0) + continue; + if ((tp = strrchr(&b1[len], '\n'))) { + *tp = '\0'; + if (b1[len]) { + bfp = &b1[len]; + if (is_boot(bfp)) { + pp = bfp; + (void) fclose(bf); + goto get_nlist_return_path; + } + break; + } + } + } + (void) fclose(bf); + } +/* + * Look for possible unix* boot paths. + */ + for (i = 0; dir[i]; i++) { + if (!(dp = opendir(dir[i]))) + continue; + while ((de = readdir(dp))) { + + /* + * Use the next entry that begins with "unix". + */ + if (strncmp("unix", de->d_name, 4) != 0) + continue; + /* + * Construct a temporary copy of the path name, + * If it matches the preferred boot name, skip it. + */ + len = strlen(dir[i]) + strlen(de->d_name) + 1; + if (len >= sizeof(b2)) + continue; + (void) snpf(b2, sizeof(b2), "%s%s", dir[i], de->d_name); + if (bfp && strcmp(b2, bfp) == 0) + continue; + /* + * See if it's the booted kernel. + */ + if (is_boot(b2)) { + (void) closedir(dp); + pp = b2; + +get_nlist_return_path: + + /* + * A boot path has been located. As requested return a + * malloc'd pointer to it. + */ + if (!ap) + return(""); + len = (MALLOC_S)(strlen(pp) + 1); + if (!(tp = (char *)malloc(len))) { + (void) fprintf(stderr, + "%s: can't allocate %d bytes for: %s\n", + Pn, len , pp); + Exit(1); + } + (void) snpf(tp, len, "%s", pp); + return(tp); + } + } + if (dp) + (void) closedir(dp); + } + return((char *)NULL); +} +#endif /* !defined(N_UNIX) */ + + +/* + * initialize() - perform all initialization + */ + +void +initialize() +{ + get_kernel_access(); + get_cdevsw(); + readfsinfo(); + if (Fsv & FSV_NI) + NiTtl = "INODE-ADDR"; +} + + +#if !defined(N_UNIX) +/* + * is_boot() - does the specified path lead to a booted kernel + */ + +is_boot(p) + char *p; /* specified path */ +{ + int i; + KA_T ka; + union { + struct scoutsname s; + unsigned char sc[sizeof(struct scoutsname)]; + } s1, s2; +/* + * Get the scoutsname structure via __scoinfo() to use as a reference against + * the one obtained via kread()'ing from the nlist() address. + * If __scoinfo() fails, return the default boot path. + */ + if (__scoinfo(&s1.s, sizeof(s1.s)) < 0) + return 0; +/* + * Get the name list for this boot path. Using the scoutsname address, read + * the scoutsname structure and compare it to the _s_scoinfo() one. If the + * two match, this is the boot path. + */ + if (Nl) { + (void) free((FREE_P *)Nl); + Nl = (struct NLIST_TYPE *)NULL; + } + (void) build_Nl(Drive_Nl); + if (nlist(p, Nl) < 0) + return(0); + if (get_Nl_value("scouts", Drive_Nl, &ka) < 0 || !ka) + return(0); + if (Kd < 0) { + if (open_kmem(1)) + return(0); + } + if (kread(ka, (char *)&s2.s, sizeof(s2.s))) + return(0); + for (i = 0; i < sizeof(struct scoutsname); i++) { + if (s1.sc[i] != s2.sc[i]) + return(0); + } + return(1); +} +#endif /* !defined(N_UNIX) */ + + +/* + * kread() - read from kernel memory + */ + +int +kread(addr, buf, len) + KA_T addr; /* kernel memory address */ + char *buf; /* buffer to receive data */ + READLEN_T len; /* length to read */ +{ + int br; + + if (lseek(Kd, (off_t)addr, SEEK_SET) == (off_t)-1L) + return(1); + if ((br = read(Kd, buf, len)) < 0) + return(1); + return(((READLEN_T)br == len) ? 0 : 1); +} + + +/* + * open_kmem() - open kernel memory access + */ + +static int +open_kmem(nx) + int nx; /* no Exit(1) if 1 */ +{ + if (Kd >= 0) + return(0); +/* + * See if the non-KMEM memory file is readable. + */ + if (Memory && !is_readable(Memory, 1)) { + if (nx) + return(1); + Exit(1); + } +/* + * Open kernel memory access. + */ + if ((Kd = open(Memory ? Memory : KMEM, O_RDONLY, 0)) < 0) { + if (nx) + return(1); + (void) fprintf(stderr, "%s: can't open %s: %s\n", Pn, + Memory ? Memory : KMEM, strerror(errno)); + Exit(1); + } + return(0); +} + + +/* + * process_text() - process text access information + */ + +static void +process_text(prp) + KA_T prp; /* process region pointer */ +{ + int i, j, k; + struct pregion *p; + struct region r; + KA_T na; + char *ty, tyb[8]; + +#if OSRV>=500 + KA_T pc; + struct pregion ps; +#endif /* OSRV>=500 */ + +/* + * Read and process the pregions. + */ + +#if OSRV<500 + if (kread(prp, (char *)Pr, Prsz)) + return; + for (i = j = 0, p = Pr; i < Npp; i++, p++) +#else /* OSRV>=500 */ + for (i = j = 0, p = &ps, pc = prp; pc; pc = (KA_T)p->p_next, i++) +#endif /* OSRV<500 */ + + { + +#if OSRV>=500 + /* + * Avoid infinite loop. + */ + if (i > 1000) { + if (!Fwarn) + (void) fprintf(stderr, + "%s: too many virtual address regions for PID %d\n", + Pn, Lp->pid); + return; + } + if ((i && pc == prp) + || kread((KA_T)pc, (char *)p, sizeof(ps))) + return; +#endif /* OSRV>=500 */ + + if (!p->p_reg) + continue; + /* + * Read the region. + * Skip entries with no node pointers and duplicate node addresses. + */ + if (kread((KA_T)p->p_reg, (char *)&r, sizeof(r))) + continue; + if (!(na = (KA_T)r.r_iptr)) + continue; + for (k = 0; k < j; k++) { + if (Nc[k] == na) + break; + } + if (k < j) + continue; + /* + * Cache the node address for duplicate checking. + */ + if (!Nc) { + if (!(Nc = (KA_T *)malloc((MALLOC_S)(sizeof(KA_T) * 10)))) { + (void) fprintf(stderr, "%s: no txt ptr space, PID %d\n", + Pn, Lp->pid); + Exit(1); + } + Nn = 10; + } else if (j >= Nn) { + Nn += 10; + if (!(Nc = (KA_T *)realloc((MALLOC_P *)Nc, + (MALLOC_S)(Nn * sizeof(KA_T))))) + { + (void) fprintf(stderr, + "%s: no more txt ptr space, PID %d\n", Pn, Lp->pid); + Exit(1); + } + } + Nc[j++] = na; + /* + * Save text node and mapped region information. + */ + switch (p->p_type) { + case PT_DATA: /* data and text of */ + case PT_TEXT: /* executing binaries */ + ty = " txt"; + break; + case PT_LIBDAT: /* shared library data and */ + case PT_LIBTXT: /* COFF format text */ + ty = " ltx"; + break; + case PT_SHFIL: /* memory mapped file */ + ty = " mem"; + break; + case PT_V86: /* virtual 8086 mode */ + ty = " v86"; + break; + case PT_VM86: /* MERGE386 vm86 region */ + ty = " m86"; + break; + default: /* all others as a hex number */ + (void) snpf(tyb, sizeof(tyb), " M%02x", p->p_type & 0xff); + ty = tyb; + } + if (ty) { + alloc_lfile(ty, -1); + process_node(na); + if (Lf->sf) + link_lfile(); + } + } +} + + +/* + * readfsinfo() - read file system information + */ + +static void +readfsinfo() +{ + char buf[FSTYPSZ+1]; + int i, len; + + if ((Fsinfomax = sysfs(GETNFSTYP)) == -1) { + (void) fprintf(stderr, "%s: sysfs(GETNFSTYP) error: %s\n", + Pn, strerror(errno)); + Exit(1); + } + if (Fsinfomax == 0) + return; + if (!(Fsinfo = (char **)malloc((MALLOC_S)(Fsinfomax * sizeof(char *))))) + { + (void) fprintf(stderr, "%s: no space for sysfs info\n", Pn); + Exit(1); + } + for (i = 1; i <= Fsinfomax; i++) { + if (sysfs(GETFSTYP, i, buf) == -1) { + (void) fprintf(stderr, "%s: sysfs(GETFSTYP) error: %s\n", + Pn, strerror(errno)); + Exit(1); + } + 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); + Exit(1); + } + (void) snpf(Fsinfo[i-1], len, "%s", buf); + } +} + + +#if defined(HASNCACHE) + +/* + * Prepare for and #include the appropriate header files. + */ + +# if OSRV>=500 +#undef IFIR +#undef IFIW +#undef IRCOLL +#undef IWCOLL +# endif /* OSRV>=500 */ + +#include + +# if defined(HAS_NFS) +#include +# endif /* defined(HAS_NFS) */ + +# if OSRV>=500 +# if OSRV<504 +#include +#undef IFIR +#undef IFIW +#undef IRCOLL +#undef IWCOLL +#define _INKERNEL +#include +#undef _INKERNEL +# else /* OSRV>=504 */ +#include +# endif /* OSRV<504 */ +# endif /* OSRV>=500 */ + + +/* + * Determine the maximum size of the cache name character array. + */ + +# if OSRV<504 +#define MAXNSZ DIRSIZ +# if OSRV>=500 && DTNCMAX>MAXNSZ +#undef MAXNSZ +#define MAXNSZ DTNCMAX +# endif /* OSRV>=500 && DTNCMAX>MAXNSZ */ +# else /* OSRV>=504 */ +#define MAXNSZ DNLC_NAMELEN +# endif /* OSRV<504 */ + +# if defined(HAS_NFS) && NC_NAMLEN>MAXNSZ +#undef MAXNSZ +#define MAXNSZ NC_NAMLEN +# endif /* defined(HAS_NFS) && NC_NAMLEN>MAXNSZ */ + + +/* + * Define the local name cache structures. + */ + +struct lnch { /* local name cache structure */ + union { + struct ldev { /* device-inode info */ + dev_t dev; /* device */ + unsigned long inum; /* inode number */ + unsigned long pa_inum; /* parent inode number */ + } ld; + struct lnfs { /* NFS info */ + KA_T rp; /* rnode address */ + KA_T dp; /* parent rnode address */ + } ln; + } u; + char nm[MAXNSZ+1]; /* name */ + unsigned char nl; /* name length */ + unsigned char dup; /* duplicate if 1 */ + unsigned char type; /* type: 0 = device-inode; 1 = NFS */ + struct lnch *pa; /* parent address */ + struct lnch *next; /* link to next same-type structure */ +}; + +struct lnch_hh { /* device-inode and NFS hash head */ + struct lnch *hp[2]; /* [0] = device-inode; [1] = NFS*/ +}; + + +/* + * Local name cache (LNC) definitions, macros, and static values + */ + +#define LCHUNKSZ 256 /* local "chunk" size for reading the + * kernel DNLC -- used for OSRV>=504 */ +static int LNC_asz = 0; /* LNC cache allocated size */ +static int LNC_csz = 0; /* LNC cache current size */ +#define LNCHHLEN 64 /* hash head length (must be a + * power of 2) */ +#define LNCINCR 256 /* LNC size increment */ +#define LNCINIT 1024 /* LNC initial size */ + +#define DIN_hash(d, i) &LNC_hh[((((int)(d + i)>>2)*31415)&(LNCHHLEN-1))] + +# if defined(HAS_NFS) +#define NFS_hash(r) &LNC_hh[((((int)(r)>>2)*31415)&(LNCHHLEN-1))] +# endif /* defined(HAS_NFS) */ + +static struct lnch_hh *LNC_hh = (struct lnch_hh *)NULL; + /* LNC hash head pointers */ +static struct lnch *LNC_nc = (struct lnch *)NULL; + /* the linear LNC */ + + +/* + * Local function prototypes + */ + +_PROTOTYPE(static struct lnch *DIN_addr,(dev_t *d, unsigned long i)); + +# if OSRV>=500 +# if OSRV>=504 +_PROTOTYPE(static void DNLC_load,()); +# else /* OSRV<504 */ +_PROTOTYPE(static void DTFS_load,()); +_PROTOTYPE(static void HTFS_load,()); +# endif /* OSRV>=504 */ +# endif /* OSRV>=500 */ + +_PROTOTYPE(static int LNC_enter,(struct lnch *le, char *nm, int nl, char *fs)); +_PROTOTYPE(static void LNC_nosp,(int len)); + +# if defined(HAS_NFS) +_PROTOTYPE(static struct lnch *NFS_addr,(KA_T r)); +_PROTOTYPE(static void NFS_load,(void)); +_PROTOTYPE(static int NFS_root,(KA_T r)); +# endif /* defined(HAS_NFS) */ + +# if OSRV<504 +_PROTOTYPE(static void SYSV_load,()); +# endif /* OSRV<504 */ + + +/* + * DIN_addr() - look up a node's local device-inode address + */ + +static struct lnch * +DIN_addr(d, i) + dev_t *d; /* device number */ + unsigned long i; /* inode number */ +{ + struct lnch_hh *hh = DIN_hash(*d, i); + struct lnch *lc = hh->hp[0]; + + while (lc) { + if (lc->u.ld.dev == *d && lc->u.ld.inum == i) + return(lc); + lc = lc->next; + } + return((struct lnch *)NULL); +} + + +# if OSRV>=504 +/* + * DNLC_load() - load DNLC cache + */ + +static void +DNLC_load() +{ + int ccl; /* current "chunk" length */ + int ccs; /* current "chunk" size */ + int ccx; /* current "chunk" index */ + static int cha = 0; /* "chunk" allocation size */ + static int chl = 0; /* "chunk" allocation length */ + struct dnlc__cachent *cp; + static struct dnlc__cachent *dnlc = (struct dnlc__cachent *)NULL; + static int dnlce = 0; + int i, len; + static KA_T ka = (KA_T)0; + struct lnch lc; + char nm[DNLC_NAMELEN+1]; + KA_T v; + char *wa; /* "working" kernel DNLC + * address */ +/* + * Do first-time setup, as required. + */ + if (dnlce == 0) { + + /* + * Quit if the DNLC name cache address is unknown. + */ + if (get_Nl_value("dnlc", Drive_Nl, &ka) < 0 || !ka) + return; + /* + * Determine of the DNLC name cache address is that of an array or a + * pointer to the array. + */ + v = (KA_T)NULL; + if (get_Nl_value("pdnlc", Drive_Nl, &v) >= 0 && v) { + + /* + * If the DNLC name cache address is that of a pointer to an array, + * get the array's address. If that fails, return without comment + * and without further action. + */ + if (kread(ka, (char *)&ka, sizeof(ka))) + return; + } + /* + * Get the kernel's DNLC name cache size. + */ + if (get_Nl_value("ndnlc", Drive_Nl, &v) < 0 || !v + || kread(v, (char *)&dnlce, sizeof(dnlce)) + || dnlce < 1) + return; + /* + * Allocate space for a copy of a portion ("chunk") of the kernel's + * DNLC name cache. + */ + cha = (dnlce <= LCHUNKSZ) ? dnlce : LCHUNKSZ; + chl = sizeof(struct dnlc__cachent) * cha; + if (!(dnlc = (struct dnlc__cachent *)malloc(chl))) { + (void) fprintf(stderr, + "%s: can't allocate %d bytes for DNLC chunk\n", + Pn, chl); + cha = 0; + Exit(1); + } + } +/* + * Prepare to read the kernel's DNLC name cache. + */ + if (!cha || !chl || !dnlc || !ka) + return; +/* + * Build a local copy of the kernel's DNLC name cache, reading the kernel data + * a "chunk" at a time. + */ + nm[DNLC_NAMELEN] = '\0'; + lc.type = 0; + for (ccl = ccs = i = 0, wa = (char *)ka; i < dnlce; i += ccs, wa += ccl) + { + + /* + * Read the next "chunk". + */ + ccs = ((dnlce - i) < cha) ? (dnlce - i) : cha; + ccl = sizeof(struct dnlc__cachent) * ccs; + if (kread((KA_T)wa, (char *)dnlc, ccl)) + break; + /* + * Process the "chunk". + */ + for (ccx = 0, cp = dnlc; ccx < ccs; cp++, ccx++) { + if (!cp->dev && !cp->newinum) + continue; + (void) strncpy(nm, cp->name, DNLC_NAMELEN); + if ((len = strlen(nm)) < 1) + continue; + if (len < 3 && nm[0] == '.') { + if (len == 1 || (len == 2 && nm[1] == '.')) + continue; + } + lc.u.ld.dev = cp->dev; + lc.u.ld.inum = (unsigned long)cp->newinum; + lc.u.ld.pa_inum = (unsigned long)cp->inum; + if (LNC_enter(&lc, nm, len, "DNLC")) + break; + } + } +/* + * If not repeating, free kernel DNLC name cache buffer space. + */ + if (dnlc && !RptTm) { + (void) free((MALLOC_P *)dnlc); + dnlc = (struct dnlc__cachent *)NULL; + dnlce = cha = chl = 0; + } +} +# endif /* OSRV>=504 */ + + +# if OSRV>=500 && OSRV<504 +/* + * DTFS_load() - load DTFS cache + */ + +static void +DTFS_load() +{ + struct dtcachent *cp; + static struct dtcachent *dtnc = (struct dtcachent *)NULL; + static int dtnce = 0; + int i, len; + static KA_T ka = (KA_T)NULL; + static int kcl = 0; + struct lnch lc; + char nm[DTNCMAX+1]; + KA_T v; +/* + * Do first-time setup, as required. + */ + if (dtnce == 0) { + + /* + * Quit if the DTFS name cache address is unknown. + */ + if (get_Nl_value("dtnc", Drive_Nl, &ka) < 0 || !ka) + return; + /* + * Get the kernel's DTFS name cache size. + */ + if (get_Nl_value("ndtnc", Drive_Nl, &v) < 0 || !v + || kread(v, (char *)&dtnce, sizeof(dtnce)) + || dtnce < 1) + return; + /* + * Allocate space for a copy of the kernel's DTFS name cache. + */ + kcl = sizeof(struct dtcachent) * dtnce; + if (!(dtnc = (struct dtcachent *)malloc(kcl))) { + (void) fprintf(stderr, + "%s: can't allocate %d bytes for DTFS name cache\n", + Pn, kcl); + Exit(1); + } + } +/* + * Read the kernel's DTFS name cache. + */ + if (!dtnc || !kcl || !ka || kread(ka, (char *)dtnc, kcl)) + return; +/* + * Build a local copy of the kernel's DTFS name cache. + */ + lc.type = 0; + nm[DTNCMAX] = '\0'; + for (cp = dtnc, i = 0; i < dtnce; cp++, i++) { + if (!cp->dn_dev && !cp->dn_newinum) + continue; + (void) strncpy(nm, cp->dn_name, DTNCMAX); + if ((len = strlen(nm)) < 1) + continue; + if (len < 3 && cp->dn_name[0] == '.') { + if (len == 1 || (len == 2 && cp->dn_name[1] == '.')) + continue; + } + lc.u.ld.dev = cp->dn_dev; + lc.u.ld.inum = (unsigned long)cp->dn_newinum; + lc.u.ld.pa_inum = (unsigned long)cp->dn_inum; + if (LNC_enter(&lc, nm, len, "DTFS")) + break; + } +/* + * If not repeating, free kernel DTFS name cache buffer space. + */ + if (dtnc && !RptTm) { + (void) free((MALLOC_P *)dtnc); + dtnc = (struct dtcachent *)NULL; + dtnce = kcl = 0; + } +} + + +/* + * HTFS_load() - load HTFS cache + */ + +static void +HTFS_load() +{ + struct htcachent *cp; + static struct htcachent *htnc = (struct htcachent *)NULL; + static int htnce = 0; + int i, len; + static KA_T ka = (KA_T)NULL; + static int kcl = 0; + struct lnch lc; + char nm[DIRSIZ+1]; + KA_T v; +/* + * Do first-time setup, as required. + */ + if (htnce == 0) { + + /* + * Quit if the HTFS name cache address is unknown. + */ + if (get_Nl_value("htnc", Drive_Nl, &ka) < 0 || !ka) + return; + /* + * Get the kernel's HTFS name cache size. + */ + if (get_Nl_value("nhtnc", Drive_Nl, &v) < 0 || !v + || kread(v, (char *)&htnce, sizeof(htnce)) + || htnce < 1) + return; + /* + * Allocate space for a copy of the kernel's HTFS name cache. + */ + kcl = sizeof(struct htcachent) * htnce; + if (!(htnc = (struct htcachent *)malloc(kcl))) { + (void) fprintf(stderr, + "%s: can't allocate %d bytes for HTFS name cache\n", + Pn, kcl); + Exit(1); + } + } +/* + * Read the kernel's HTFS name cache. + */ + if (!htnc || !kcl || !ka || kread(ka, (char *)htnc, kcl)) + return; +/* + * Build a local copy of the kernel's HTFS name cache. + */ + lc.type = 0; + nm[DIRSIZ] = '\0'; + for (cp = htnc, i = 0; i < htnce; cp++, i++) { + if (!cp->dev && !cp->newinum) + continue; + (void) strncpy(nm, cp->name, DIRSIZ); + if ((len = strlen(nm)) < 1) + continue; + if (len < 3 && cp->name[0] == '.') { + if (len == 1 || (len == 2 && cp->name[1] == '.')) + continue; + } + lc.u.ld.dev = (dev_t)cp->dev; + lc.u.ld.inum = (unsigned long)cp->newinum; + lc.u.ld.pa_inum = (unsigned long)cp->inum; + if (LNC_enter(&lc, nm, len, "HTFS")) + break; + } +/* + * If not repeating, free kernel HTFS name cache buffer space. + */ + if (htnc && !RptTm) { + (void) free((MALLOC_P *)htnc); + htnc = (struct htcachent *)NULL; + htnce = kcl = 0; + } +} +# endif /* OSRV>=500 && OSRV<504 */ + + +/* + * LNC_enter() - make a local name cache entry + */ + +static int +LNC_enter(le, nm, nl, fs) + struct lnch *le; /* skeleton local entry */ + char *nm; /* name */ + int nl; /* name length */ + char *fs; /* file system name */ +{ + struct lnch *lc; + MALLOC_S len; + + if (LNC_csz >= LNC_asz) { + LNC_asz += LNCINCR; + len = (MALLOC_S)(LNC_asz * sizeof(struct lnch)); + if (!(LNC_nc = (struct lnch *)realloc(LNC_nc, len))) { + (void) fprintf(stderr, + "%s: no more space for %d byte local name cache: %s\n", + Pn, len, fs); + Exit(1); + } + } + lc = &LNC_nc[LNC_csz]; + if ((lc->type = le->type) == 1) { + + /* + * Make an NFS entry. + */ + lc->u.ln.rp = le->u.ln.rp; + lc->u.ln.dp = le->u.ln.dp; + } else { + + /* + * Make a device-inode entry. + */ + lc->u.ld.dev = le->u.ld.dev; + lc->u.ld.inum = le->u.ld.inum; + lc->u.ld.pa_inum = le->u.ld.pa_inum; + } +/* + * Enter the name and its size, clear the duplicate flag, + * and advance the linear cache entry count. + */ + if (nl > MAXNSZ) { + if (!Fwarn) + (void) fprintf(stderr, + "%s: WARNING: length for \"%s\" too large: %d\n", + Pn, nm, nl); + nl = MAXNSZ; + } + (void) strncpy(lc->nm, nm, nl); + lc->nm[nl] = '\0'; + lc->nl = (unsigned char)nl; + lc->dup = 0; + lc->next = lc->pa = (struct lnch *)NULL; + LNC_csz++; + return(0); +} + + +/* + * LNC_nosp() - notify that we're out of space for the local name cache + */ + +static void +LNC_nosp(len) + int len; /* attempted length */ +{ + if (!Fwarn) + (void) fprintf(stderr, + "%s: no space for %d byte local name cache\n", + Pn, len); + Exit(1); +} + + +/* + * ncache_load() - load the kernel's NFS and DEV name caches + */ + +void +ncache_load() +{ + struct lnch_hh *hh; + struct lnch *hl, *hlp, *lc; + int f, i, len; + + if (!Fncache) + return; +/* + * Initialize local name cache, as required. + */ + if (LNC_asz == 0) { + LNC_asz = LNCINIT; + len = LNCINIT * sizeof(struct lnch); + if (!(LNC_nc = (struct lnch *)malloc((MALLOC_S)len))) + (void) LNC_nosp(len); + } + LNC_csz = 0; + +# if defined(HAS_NFS) +/* + * Load NFS cache. + */ + (void) NFS_load(); +# endif /* defined(HAS_NFS) */ + +# if OSRV<504 +/* + * Load the device-inode SYSV file system cache. + */ + (void) SYSV_load(); + +# if OSRV>=500 +/* + * Load the device-inode DT and HT file system caches. + */ + (void) DTFS_load(); + (void) HTFS_load(); +# endif /* OSRV>=500 */ +# else /* OSRV>=504 */ +/* + * Load the device-inode combined file system cache. + */ + (void) DNLC_load(); +# endif /* OSRV<504 */ + +/* + * Reduce local name cache memory usage, as required. + */ + if (LNC_csz < 1) { + LNC_csz = 0; + if (!RptTm) { + (void) free((FREE_P *)LNC_nc); + LNC_nc = (struct lnch *)NULL; + } + return; + } + if (LNC_csz < LNC_asz && !RptTm) { + len = LNC_csz * sizeof(struct lnch); + if (!(LNC_nc = (struct lnch *)realloc(LNC_nc, len))) + (void)LNC_nosp(len); + LNC_asz = LNC_csz; + } +/* + * Initialize hash head pointers. + */ + if (!LNC_hh) { + LNC_hh = (struct lnch_hh *)calloc(LNCHHLEN, sizeof(struct lnch_hh)); + if (!LNC_hh) { + (void) fprintf(stderr, + "%s: can't allocate %d bytes for name cache hash table\n", + Pn, LNCHHLEN * sizeof(struct lnch_hh)); + Exit(1); + } + } else + (void) zeromem((void *)LNC_hh, (LNCHHLEN * sizeof(struct lnch_hh))); +/* + * Enter local name cache pointers in the hash table. Look for entries with + * the same identifications that have different names. + */ + for (i = 0, lc = LNC_nc; i < LNC_csz; i++, lc++) { + +# if defined(HAS_NFS) + if (lc->type) + hh = NFS_hash(lc->u.ln.rp); + else +# endif /* defined(HAS_NFS) */ + + hh = DIN_hash(lc->u.ld.dev, lc->u.ld.inum); + if (!(hl = hh->hp[lc->type])) { + hh->hp[lc->type] = lc; + continue; + } + for (f = 0, hlp = hl; hl; hlp = hl, hl = hl->next) { + +# if defined(HAS_NFS) + if (lc->type == 1) { + if (lc->u.ln.rp != hl->u.ln.rp) + continue; + } else +# endif /* defined(HAS_NFS) */ + + { + if (lc->u.ld.dev != hl->u.ld.dev + || lc->u.ld.inum != hl->u.ld.inum) + continue; + } + if (strcmp(lc->nm, hl->nm) == 0) + f = 1; + else { + f = 2; /* same identifiers, different names */ + break; + } + } + if (!f) + hlp->next = lc; + else if (f == 2) { + + /* + * Since entries with the same identification but different names + * were located, mark entries with the same identification as + * duplicates. + */ + for (hl = hh->hp[lc->type]; hl; hl = hl->next) { + +# if defined(HAS_NFS) + if (lc->type == 1) { + if (lc->u.ln.rp == hl->u.ln.rp) + hl->dup = 1; + continue; + } +# endif /* defined(HAS_NFS) */ + + if (hl->u.ld.dev == lc->u.ld.dev + && hl->u.ld.inum == lc->u.ld.inum) + hl->dup = 1; + } + } + } +/* + * Make a final pass through the local name cache and convert parent + * identifications to local name cache pointers. Ignore duplicates. + */ + for (i = 0, lc = LNC_nc; i < LNC_csz; i++, lc++) { + if (lc->dup) + continue; + +# if defined(HAS_NFS) + if (lc->type == 1) { + if (lc->u.ln.dp) + lc->pa = NFS_addr(lc->u.ln.dp); + continue; + } +# endif /* defined(HAS_NFS) */ + + if (lc->u.ld.dev && lc->u.ld.pa_inum) + lc->pa = DIN_addr(&lc->u.ld.dev, lc->u.ld.pa_inum); + } +} + + +/* + * ncache_lookup() - look up a node's name in the kernel's name caches + */ + +char * +ncache_lookup(buf, blen, fp) + char *buf; /* receiving name buffer */ + int blen; /* receiving buffer length */ + int *fp; /* full path reply */ +{ + char *cp = buf; + int nl, rlen; + struct lnch *lc; + + *cp = '\0'; + *fp = 0; +/* + * 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); + if (!LNC_nc) + return((char *)NULL); + +#if defined(HAS_NFS) +/* + * Look up the NFS name cache entry. + */ + if (Lf->is_nfs) { + if ((lc = NFS_addr(Lf->na)) && !lc->dup) { + if ((nl = (int)lc->nl) > (blen - 1)) + return(*cp ? cp : (char *)NULL); + cp = buf + blen - nl - 1; + rlen = blen - nl - 1; + (void) snpf(cp, nl + 1, "%s", lc->nm); + /* + * Look up the NFS name cache entries that are parents of the + * rnode address. Quit when: + * + * there's no parent; + * the parent is a duplicate; + * the name is too large to fit in the receiving buffer. + */ + for (;;) { + if (!lc->pa) { + if (NFS_root(lc->u.ln.dp)) + *fp = 1; + break; + } + lc = lc->pa; + if (lc->dup) + break; + if (((nl = (int)lc->nl) + 1) > rlen) + break; + *(cp - 1) = '/'; + cp--; + rlen--; + (void) strncpy((cp - nl), lc->nm, nl); + cp -= nl; + rlen -= nl; + } + return(*cp ? cp : (char *)NULL); + } + return((char *)NULL); + } +# endif /* defined(HAS_NFS) */ + +/* + * Look up the device-inode name cache entry. + */ + if (Lf->dev_def && Lf->inp_ty == 1 + && (lc = DIN_addr(&Lf->dev, Lf->inode)) && !lc->dup) { + if ((nl = (int)lc->nl) > (blen - 1)) + return(*cp ? cp : (char *)NULL); + cp = buf + blen - nl - 1; + rlen = blen - nl - 1; + (void) snpf(cp, nl + 1, "%s", lc->nm); + /* + * Look up the LNC name cache entries that are parents of the + * device and inode number. Quit when: + * + * there's no parent; + * the parent is a duplicate cache entry; + * the name is too large to fit in the receiving buffer. + */ + for (;;) { + if (!lc->pa) { + if (lc->u.ld.pa_inum && Lf->fs_ino + && lc->u.ld.pa_inum == Lf->fs_ino) + *fp = 1; + break; + } + lc = lc->pa; + if (lc->dup) + break; + if (lc->u.ld.inum && Lf->fs_ino + && lc->u.ld.inum == Lf->fs_ino) { + *fp = 1; + break; + } + if (((nl = (int)lc->nl) + 1) > rlen) + break; + *(cp - 1) = '/'; + cp--; + rlen--; + (void) strncpy((cp - nl), lc->nm, nl); + cp -= nl; + rlen -= nl; + } + return(*cp ? cp : (char *)NULL); + } + return((char *)NULL); +} + + +# if defined(HAS_NFS) +/* + * NFS_addr() - look up a node's local NFS_nc address + */ + +static struct lnch * +NFS_addr(r) + KA_T r; /* rnode's address */ +{ + struct lnch_hh *hh = NFS_hash(r); + struct lnch *lc = hh->hp[1]; + + while (lc) { + if (lc->u.ln.rp == r) + return(lc); + lc = lc->next; + } + return((struct lnch *)NULL); +} + + +/* + * NFS_load() -- load kernel's NFS name cache + */ + +static void +NFS_load() +{ + struct ncache *cp; + int i, len; + struct lnch lc; + static KA_T ka = (KA_T)NULL; + static int kcl = 0; + static struct ncache *nfnc = (struct ncache *)NULL; + static int nfnce = 0; + char nm[NC_NAMLEN+1]; + KA_T v; +/* + * Do first-time setup, as required. + */ + if (nfnce == 0) { + + /* + * Quit if the NFS name cache address is unknown. + */ + if (get_Nl_value("nfnc", Drive_Nl, &ka) < 0 || !ka) + return; + /* + * Get the kernel's NFS name cache size. + */ + if (get_Nl_value("nnfnc", Drive_Nl, &v) < 0 || !v + || kread(v, (char *)&nfnce, sizeof(nfnce)) + || nfnce < 1) + return; + /* + * Allocate space for a copy of the kernel's NFS name cache. + */ + kcl = nfnce * sizeof(struct ncache); + if (!(nfnc = (struct ncache *)malloc(kcl))) { + (void) fprintf(stderr, + "%s: can't allocate %d bytes for NFS name cache\n", + Pn, kcl); + Exit(1); + } + } +/* + * Read the kernel's NFS name cache. + */ + if (!nfnc || !kcl || !ka || kread(ka, (char *)nfnc, kcl)) + return; +/* + * Build a local copy of the kernel's NFS name cache. + */ + lc.type = 1; + for (cp = nfnc, i = 0; i < nfnce; cp++, i++) { + if (!cp->rp) + continue; + if ((len = cp->namlen) < 0 || len > NC_NAMLEN) + continue; + (void) strncpy(nm, cp->name, len); + nm[len] = '\0'; + if ((len = strlen(nm)) < 1) + continue; + if (len < 3 && nm[0] == '.') { + if (len == 1 || (len == 2 && nm[1] == '.')) + continue; + } + lc.u.ln.rp = (KA_T)cp->rp; + lc.u.ln.dp = (KA_T)cp->dp; + if (LNC_enter(&lc, nm, len, "NFS")) + break; + } +/* + * If not repeating, free kernel NFS name cache buffer space. + */ + if (nfnc && !RptTm) { + (void) free((MALLOC_P *)nfnc); + nfnc = (struct ncache *)NULL; + kcl = nfnce = 0; + } +} + + +static int +NFS_root(r) + KA_T r; /* node's rnode address */ +{ + int i; + MALLOC_S len; + static int rnc = 0; + static int rnca = 0; + static KA_T *rc = (KA_T *)NULL; + struct rnode rn; + unsigned short *n; + unsigned long nnum; + +# if OSRV>=500 + unsigned short *n1; +# endif /* OSRV>=500 */ + + if (!Lf->fs_ino || !r) + return(0); +/* + * Search NFS root rnode cache. + */ + for (i = 0; i < rnc; i++) { + if (rc[i] == r) + return(1); + } +/* + * Read rnode and get the node number. + */ + if (kread(r, (char *)&rn, sizeof(rn))) + return(0); + +# if OSRV<500 + n = (unsigned short *)&rn.r_fh.fh_pad[14]; + if (!(nnum = (unsigned long)ntohs(*n))) + nnum = (unsigned long)rn.r_fh.fh_u.fh_fgen_u; +# else /* OSRV>=500 */ + n = (unsigned short *)&rn.r_fh.fh_u.fh_fid_u[4]; + n1 = (unsigned short *)&rn.r_fh.fh_u.fh_fid_u[2]; + if (!(nnum = (unsigned long)*n)) + nnum = (unsigned long)*n1; +# endif /* OSRV<500 */ + + if (!nnum || nnum != Lf->fs_ino) + return(0); +/* + * Add the rnode address to the NFS root rnode cache. + */ + if (rnc >= rnca) { + if (rnca == 0) { + len = (MALLOC_S)(10 * sizeof(KA_T)); + if ((rc = (KA_T *)malloc(len))) + rnca = 10; + } else { + len = (MALLOC_S)((rnca + 10) * sizeof(KA_T)); + if ((rc = (KA_T *)realloc(rc, len))) + rnca += 10; + } + if (!rc) { + (void) fprintf(stderr, "%s: no space for root rnode table\n", + Pn); + Exit(1); + } + } + rc[rnc++] = r; + return(1); +} +# endif /* defined(HAS_NFS) */ + + +# if OSRV<504 +/* + * SYSV_load() - load SYSV cache + */ + +static void +SYSV_load() +{ + struct s5cachent *cp; + int i, len; + static KA_T ka = (KA_T)NULL; + static int kcl = 0; + struct lnch lc; + char nm[DIRSIZ+1]; + static struct s5cachent *s5nc = (struct s5cachent *)NULL; + static int s5nce = 0; + KA_T v; +/* + * Do first-time setup, as required. + */ + if (s5nce == 0) { + + /* + * Quit if the SYSV name cache address is unknown. + */ + if (get_Nl_value("s5nc", Drive_Nl, &ka) < 0 || !ka) + return; + /* + * Get the kernel's SYSV name cache size. + */ + +# if OSRV<500 + s5nce = Var.v_s5cacheents; +# else /* OSRV>=500 */ + if (get_Nl_value("nsfnc", Drive_Nl, &v) < 0 || !v + || kread(v, (char *)&s5nce, sizeof(s5nce))) + return; +# endif /* OSRV<500 */ + + if (s5nce < 1) + return; + /* + * Allocate space for a copy of the kernel's SYSV name cache. + */ + kcl = sizeof(struct s5cachent) * s5nce; + if (!(s5nc = (struct s5cachent *)malloc(kcl))) { + (void) fprintf(stderr, + "%s: can't allocate %d bytes for SYSV name cache\n", + Pn, kcl); + Exit(1); + } + } +/* + * Read the kernel's SYSV name cache. + */ + if (!s5nc || !kcl || !ka || kread(ka, (char *)s5nc, kcl)) + return; +/* + * Build a local copy of the kernel's SYSV name cache. + */ + nm[DIRSIZ] = '\0'; + lc.type = 0; + for (cp = s5nc, i = 0; i < s5nce; cp++, i++) { + if (!cp->dev && !cp->newinum) + continue; + (void) strncpy(nm, cp->name, DIRSIZ); + if ((len = strlen(nm)) < 1) + continue; + if (len < 3 && cp->name[0] == '.') { + if (len == 1 || (len == 2 && cp->name[1] == '.')) + continue; + } + lc.u.ld.dev = (dev_t)cp->dev; + lc.u.ld.inum = (unsigned long)cp->newinum; + lc.u.ld.pa_inum = (unsigned long)cp->inum; + if (LNC_enter(&lc, nm, len, "SYSV")) + break; + } +/* + * If not repeating, free kernel SYSV name cache buffer space. + */ + if (s5nc && !RptTm) { + (void) free((MALLOC_P *)s5nc); + s5nc = (struct s5cachent *)NULL; + kcl = s5nce = 0; + } +} +# endif /* OSRV<504 */ +#endif /* defined(HASNCACHE) */ diff --git a/dialects/osr/dproto.h b/dialects/osr/dproto.h new file mode 100644 index 0000000..77e029c --- /dev/null +++ b/dialects/osr/dproto.h @@ -0,0 +1,62 @@ +/* + * dproto.h - SCO OpenServer function prototypes for lsof + * + * The _PROTOTYPE macro is defined in the common proto.h. + */ + + +/* + * 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. + */ + + +/* + * $Id: dproto.h,v 1.5 99/06/22 08:22:28 abe Exp $ + */ + +_PROTOTYPE(extern int is_file_named,(char *p, int cd)); +_PROTOTYPE(extern void process_socket,(struct inode *i)); +_PROTOTYPE(extern int get_max_fd,(void)); + +#if OSRV<500 +_PROTOTYPE(extern int endservent,(void)); +_PROTOTYPE(extern int setservent,(int)); + +# if defined(HASSTATLSTAT) +_PROTOTYPE(extern int statlstat,(const char *, struct stat *)); +# endif /* defined(HASTSTATLSTAT) */ + +_PROTOTYPE(extern int strcasecmp,(char *, char *)); +_PROTOTYPE(extern int strncasecmp,(char *, char *, unsigned int)); +_PROTOTYPE(extern pid_t wait,()); +#endif /* OSRV<500 */ + +_PROTOTYPE(extern int sysi86,()); +_PROTOTYPE(extern int sysfs,()); +_PROTOTYPE(extern void udp_tm,(time_t tm)); + +#if !defined(N_UNIX) +_PROTOTYPE(extern char *get_nlist_path,(int pd)); +#endif /* !defined(N_UNIX) */ diff --git a/dialects/osr/dsock.c b/dialects/osr/dsock.c new file mode 100644 index 0000000..80684d1 --- /dev/null +++ b/dialects/osr/dsock.c @@ -0,0 +1,422 @@ +/* + * dsock.c - SCO OpenServer socket processing functions for lsof + */ + + +/* + * 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 1995 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: dsock.c,v 1.15 2004/03/10 23:52:12 abe Exp $"; +#endif + + +#include "lsof.h" + + +/* + * process_socket() - process socket + */ + +void +process_socket(i) + struct inode *i; /* inode pointer */ +{ + char *cp; + struct domain d; + unsigned char *fa = (unsigned char *)NULL; + int fam, j, k; + int fp, lp; + unsigned char *la = (unsigned char *)NULL; + int p; + struct inpcb pcb; + short pcbs = 0; + short udpsf, udpsl; + struct socket s; + KA_T sa, spa; + struct stdata sd; + struct queue sh; + short shs = 0; + struct tcpcb t; + short ts = 0; + struct udpdev udp; + short udptm = 0; + +#if OSRV<500 + struct sockaddr_in *si; +#else /* OSRV>=500 */ + struct sockaddr_in si; + struct un_dev ud; +#endif /* OSRV<500 */ + + (void) snpf(Lf->type, sizeof(Lf->type), "sock"); +/* + * Read socket. + */ + if (!Socktab) { + (void) enter_nm("No kernel socket table"); + return; + } + spa = Socktab + (GET_MIN_DEV(i->i_rdev) * sizeof(struct socket *)); + if (kread(spa, (char *)&sa, sizeof(sa))) { + (void) snpf(Namech, Namechl, "can't read socket pointer at %s", + print_kptr(spa, (char *)NULL, 0)); + enter_nm(Namech); + } + if (kread(sa, (char *)&s, sizeof(s))) { + (void) snpf(Namech, Namechl, "can't read socket structure at %s", + print_kptr(sa, (char *)NULL, 0)); + enter_nm(Namech); + return; + } +/* + * Read domain structure. + */ + if (!s.so_proto.pr_domain + || kread((KA_T)s.so_proto.pr_domain, (char *)&d, sizeof(d))) { + (void) snpf(Namech, Namechl, "can't read protocol domain from %s", + print_kptr((KA_T)s.so_proto.pr_domain, (char *)NULL, 0)); + enter_nm(Namech); + return; + } +/* + * Process by protocol domain. + */ + switch ((fam = d.dom_family)) { + case AF_INET: + if (Fnet) + Lf->sf |= SELNET; + (void) snpf(Lf->type, sizeof(Lf->type), "inet"); + printiproto((int)s.so_proto.pr_protocol); + Lf->inp_ty = 2; + /* + * Get protocol control block address from stream head queue structure. + */ + if (s.so_stp + && !readstdata((KA_T)s.so_stp, &sd) + && !readsthead((KA_T)sd.sd_wrq, &sh)) + shs = 1; + if (shs && sh.q_ptr) { + enter_dev_ch(print_kptr((KA_T)sh.q_ptr, (char *)NULL, 0)); + if (kread((KA_T)sh.q_ptr, (char *)&pcb, sizeof(pcb)) == 0) + pcbs = 1; + } + /* + * Print local and remote addresses. + */ + if (pcbs) { + if (pcb.inp_ppcb && strcasecmp(Lf->iproto, "udp") == 0) { + + /* + * If this is a UDP socket file, get the udpdev structure + * at the PCB's per-protocol control block address. It + * may contain a foreign address. + */ + if (!kread((KA_T)pcb.inp_ppcb, (char *)&udp, sizeof(udp))) { + +#if OSRV>=500 + if (udp.ud_lsin.sin_addr.s_addr != INADDR_ANY + || udp.ud_lsin.sin_port != 0) + udpsl = 1; + else + udpsl = 0; +#endif /* OSRV>=500 */ + + if (udp.ud_fsin.sin_addr.s_addr != INADDR_ANY + || udp.ud_fsin.sin_port != 0) + udpsf = 1; + else + udpsf = 0; + } + } else + udpsf = udpsl = 0; + /* + * Print the local address from the PCB. If there is none, and if + * this is a 5.0.0 or greater UDP stream, and if it has a local + * address set, use it. + */ + la = (unsigned char *)&pcb.inp_laddr; + lp = (int)ntohs(pcb.inp_lport); + +#if OSRV>=500 + if (((struct in_addr *)la)->s_addr == INADDR_ANY + && lp == 0 && udpsl) { + la = (unsigned char *)&udp.ud_lsin.sin_addr; + lp = (int)ntohs(udp.ud_lsin.sin_port); + } + +#endif /* OSRV>=500 */ + + /* + * Use the PCB's foreign address if it is set. If not, and if this + * is a UDP socket file, use the udpdev structure's foreign address + * if it's set. + */ + if (pcb.inp_faddr.s_addr != INADDR_ANY || pcb.inp_fport != 0) { + fa = (unsigned char *)&pcb.inp_faddr; + fp = (int)ntohs(pcb.inp_fport); + } else if (udpsf) { + fa = (unsigned char *)&udp.ud_fsin.sin_addr; + fp = (int)ntohs(udp.ud_fsin.sin_port); + udptm = 1; + } + if (la || fa) { + (void) ent_inaddr(la, lp, fa, fp, AF_INET); + if (udptm && !Lf->nma) + (void)udp_tm(udp.ud_ftime); + } + if (pcb.inp_ppcb && strcasecmp(Lf->iproto, "tcp") == 0 + && kread((KA_T)pcb.inp_ppcb, (char *)&t, sizeof(t)) == 0) { + ts = 1; + /* + * Save the TCP state from its control block. + */ + Lf->lts.type = 0; + Lf->lts.state.i = (int)t.t_state; + } + } else { + +#if OSRV<500 + if ((si = (struct sockaddr_in *)&s.so_name)) { + la = (unsigned char *)&si->sin_addr; + lp = (int)ntohs(si->sin_port); + } + if ((si = (struct sockaddr_in *)&s.so_peer)) { + if (si->sin_addr.s_addr != INADDR_ANY || si->sin_port != 0) + { + fa = (unsigned char *)&si->sin_addr; + fp = (int)ntohs(si->sin_port); + } + } +#else /* OSRV>=500 */ + if (s.so_name + && !kread((KA_T)s.so_name, (char *)&si, sizeof(si))) { + la = (unsigned char *)&si.sin_addr; + lp = (int)ntohs(si.sin_port); + } + if (s.so_peer + && !kread((KA_T)s.so_peer, (char *)&si, sizeof(si))) { + if (si.sin_addr.s_addr != INADDR_ANY || si.sin_port != 0) { + fa = (unsigned char *)&si.sin_addr; + fp = (int)ntohs(si.sin_port); + } + } +#endif /* OSRV<500 */ + + if (la || fa) + (void) ent_inaddr(la, lp, fa, fp, AF_INET); + } + /* + * Save options, sizes, states and values. + */ + +#if defined(HASSOOPT) + Lf->lts.ltm = (unsigned int)s.so_linger; + Lf->lts.opt = (unsigned int)s.so_options; + Lf->lts.qlen = (unsigned int)s.so_qlen; + Lf->lts.qlim = (unsigned int)s.so_qlimit; + Lf->lts.qlens = Lf->lts.qlims = (unsigned char)1; + if (ts && t.t_timer[TCPT_KEEP]) { + Lf->lts.opt |= SO_KEEPALIVE; + Lf->lts.kai = (unsigned long)t.t_timer[TCPT_KEEP]; + } +#endif /* defined(HASSOOPT) */ + +#if defined(HASSOSTATE) + Lf->lts.ss = s.so_state; +#endif /* defined(HASSOSTATE) */ + + + if (ts) { + +#if defined(HASTCPOPT) + Lf->lts.topt = (unsigned int)t.t_flags; + Lf->lts.mss = (unsigned long)t.t_maxseg; + Lf->lts.msss = (unsigned char)1; +#endif /* defined(HASTCPOPT) */ + +#if defined(HASTCPTPIQ) + Lf->lts.rq = (unsigned long)t.t_iqsize; + Lf->lts.sq = (unsigned long)t.t_qsize; + Lf->lts.rqs = Lf->lts.sqs = 1; +#endif /* defined(HASTCPTPIQ) */ + + if (Fsize) { + if (Lf->access == 'r') + Lf->sz = (SZOFFTYPE)t.t_iqsize; + else if (Lf->access == 'w') + Lf->sz = (SZOFFTYPE)t.t_qsize; + else + Lf->sz = (SZOFFTYPE)(t.t_iqsize + t.t_qsize); + Lf->sz_def = 1; + } else + Lf->off_def = 1; + } else if (shs) { + if (Fsize) { + Lf->sz = (SZOFFTYPE)sh.q_count; + Lf->sz_def = 1; + } else + Lf->off_def = 1; + } else + Lf->off_def = 1; + break; + +#if OSRV>=500 + case AF_UNIX: + if (Funix) + Lf->sf |= SELUNX; + (void) snpf(Lf->type, sizeof(Lf->type), "unix"); + /* + * Read Unix protocol control block and the Unix address structure. + */ + enter_dev_ch(print_kptr(sa, (char *)NULL, 0)); + Lf->off_def = 1; + if (s.so_stp + && !readstdata((KA_T)s.so_stp, &sd) + && !readsthead((KA_T)sd.sd_wrq, &sh)) { + if (!sh.q_ptr + || kread((KA_T)sh.q_ptr, (char *)&ud, sizeof(ud))) + { + (void) snpf(Namech, Namechl, "can't read un_dev from %s", + print_kptr((KA_T)sh.q_ptr, (char *)NULL, 0)); + break; + } + if (ud.so_rq) + enter_dev_ch(print_kptr((KA_T)ud.so_rq, (char *)NULL, 0)); + if (ud.local_addr.sun_family == AF_UNIX) { + Lf->inode = (unsigned long)ud.bnd_param.user_addr.inode_no; + Lf->inp_ty = 1; + ud.local_addr.sun_path[sizeof(ud.local_addr.sun_path) - 1] + = '\0'; + if (Sfile && is_file_named(ud.local_addr.sun_path, 0)) + Lf->sf |= SELNM; + if (!Namech[0]) + (void) snpf(Namech,Namechl,"%s",ud.local_addr.sun_path); + } else if (ud.for_addr.sun_family == AF_UNIX) { + Lf->inode = (unsigned long)ud.bnd_param.user_addr.inode_no; + Lf->inp_ty = 1; + ud.for_addr.sun_path[sizeof(ud.for_addr.sun_path) - 1] + = '\0'; + if (Sfile && is_file_named(ud.for_addr.sun_path, 0)) + Lf->sf |= SELNM; + else + (void) snpf(Namech,Namechl,"%s",ud.for_addr.sun_path); + } else if (ud.other_q) + (void) snpf(Namech, Namechl, "->%s", + print_kptr((KA_T)ud.other_q, (char *)NULL, 0)); + } else + (void) snpf(Namech, Namechl, "can't get un_dev"); + break; +#endif /* OSRV>=500 */ + + default: + printunkaf(fam, 1); + } + enter_nm(Namech); +} + + +/* + * udp_tm() - compute time since UDP packet was last sent + */ + +void +udp_tm(tm) + time_t tm; /* time when packet was sent */ +{ + static char buf[32], *cp; + time_t et, lbolt; + MALLOC_S len; + short hr, min, sec; +/* + * Read the lightning bolt timer and compute the elapsed time. + * No elapsed time is returned if: + * the global clock frequency variable, Hz, is negative; + * the lightning bolt timer is unavailable; + * the lightning bolt time is less than the UDP send time; + * the elapsed time is zero. + */ + if (!Lbolt) + return; + if (Hz < 0 + || kread((KA_T)Lbolt, (char *)&lbolt, sizeof(lbolt)) + || tm >= lbolt + || (et = (time_t)((lbolt - tm) / Hz)) == 0) + return; +/* + * If the time is 100 hours or greater, return the elapsed time as seconds. + */ + if (et >= (100 * 60 * 60)) { + (void) snpf(buf, sizeof(buf), "%lds", et); + cp = &buf[strlen(buf)]; + } else { + + /* + * Convert seconds to hours, minutes and seconds. + */ + hr = (short)(et / (60 * 60)); + et %= (60 * 60); + min = (short)(et / 60); + sec = (short)(et % 60); + cp = buf; + /* + * Format the elapsed time and attach single character suffixes to + * represent the units: + * + * `h' = hours + * `m' = minutes + * `s' = seconds + */ + if (hr) { + (void) snpf(cp, sizeof(buf) - (cp - buf), "%dh", hr); + cp += 2 + ((hr > 9) ? 1 : 0); + } + if (min) { + (void) snpf(cp, sizeof(buf) - (cp - buf), "%dm", min); + cp += 2 + ((min > 9) ? 1 : 0); + } + if (sec) { + (void) snpf(cp, sizeof(buf) - (cp - buf), "%ds", sec); + cp += 2 + ((sec > 9) ? 1 : 0); + } + } +/* + * Add the `` ago'' trailer. Return the string's address and length. + */ + (void) snpf(cp, sizeof(buf) - (cp - buf), " ago"); + len = (MALLOC_S)(strlen(buf) + 1); + if (len < 2) + return; + if (!(cp = (char *)malloc(len))) { + (void) fprintf(stderr, "%s: no space for %d character UDP time\n", + Pn, len); + Exit(1); + } + (void) snpf(cp, len, "%s", buf); + Lf->nma = cp; +} diff --git a/dialects/osr/dstore.c b/dialects/osr/dstore.c new file mode 100644 index 0000000..c7a2636 --- /dev/null +++ b/dialects/osr/dstore.c @@ -0,0 +1,154 @@ +/* + * dstore.c - SCO OpenServer global storage for lsof + */ + + +/* + * 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 1995 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: dstore.c,v 1.9 2002/12/03 18:23:08 abe Exp $"; +#endif + + +#include "lsof.h" + + +char **Cdevsw = NULL; /* names from kernel's cdevsw[].d_name */ +int Cdevcnt = 0; /* Cdevsw[] count */ +int CloneMajor; /* clone major device */ + + +/* + * Drive_Nl -- table to drive the building of Nl[] via build_Nl() + * (See lsof.h and misc.c.) + */ + +struct drive_Nl Drive_Nl[] = { + { "ncdev", "cdevcnt" }, + { "cdev", "cdevsw" }, + { "dnlc", "dnlc__cache" }, /* OSRV>=504 */ + { "ndnlc", "dnlc__cacheents" }, /* OSRV>=504 */ + { "pdnlc", "dnlc__cache_is_ptr" }, /* OSRV>=507 */ + { "dtnc", "dtcache" }, /* 500<=OSRV<504 */ + { "htnc", "htcache" }, /* 500<=OSRV<504 */ + { "hz", "Hz" }, + { "lbolt", "lbolt" }, + { "nfnc", "ncache" }, /* HAS_NFS */ + { "nnfnc", "nc_size" }, /* HAS_NFS */ + { "nxdm", "nxdevmaps" }, /* OSRV>=40 */ + { "pregpp", "pregpp" }, /* OSRV<500 */ + { "proc", "proc" }, + { "scouts", "scoutsname" }, /* OSRV>=500 */ + { "sockd", "sockdev" }, + { "sockt", "socktab" }, + { "s5nc", "s5cache" }, /* OSRV<504 */ + { "var", "v" }, + { "ndtnc", "v_dtcacheents" }, /* 500<=OSRV<504 */ + { "nhtnc", "v_htcacheents" }, /* 500<=OSRV<504 */ + { "ns5nc", "v_s5cacheents" }, /* 500<=OSRV<504 */ + { "xdm", "xdevmap" }, /* OSRV>=40 */ + { NULL, NULL } +}; + +int EventMajor; /* event major device number */ +char **Fsinfo = NULL; /* file system information */ +int Fsinfomax = 0; /* maximum file system type */ +int HaveCloneMajor = 0; /* have clone major device number = 1 */ +int HaveEventMajor = 0; /* have event major device number */ +int HaveSockdev = 0; /* socket device number status: 1 = available */ +int Hz = -1; /* system clock frequency */ +int Kd = -1; /* /dev/kmem file descriptor */ +KA_T Lbolt = (KA_T)0; /* kernel's lbolt variable address */ +int Sockdev; /* socket device number */ +KA_T Socktab = (KA_T)0; /* address of socket pointer table */ + +#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)FNONBLOCK, FF_NBLOCK }, + { (long)FRCACH, FF_RCACH }, + { (long)FSTOPIO, FF_STOPIO }, + +# if defined(FASYNC) + { (long)FASYNC, FF_ASYNC }, +# endif /* defined(FASYNC`) */ + +# if defined(FNET) + { (long)FNET, FF_NET }, +# endif /* defined(FNET) */ + +# if defined(FSYNC) + { (long)FSYNC, FF_SYNC }, +# endif /* defined(FSYNC) */ + + { (long)0, NULL } +}; + + +/* + * Pof_tab[] - table for print process open file flags + */ + +struct pff_tab Pof_tab[] = { + + { (long)EXCLOSE, POF_CLOEXEC }, + +# if defined(AUD_READ) + { (long)AUD_READ, POF_BNRD }, +# endif /* defined(AUD_READ) */ + +# if defined(AUD_WRITE) + { (long)AUD_WRITE, POF_BNWR }, +# endif /* defined(AUDWRITE) */ + +# if defined(SEC_SIGHUPPED) + { (long)SEC_SIGHUPPED, POF_BNHUP }, +# endif /* defined(SEC_SIGHUPPED) */ + + { (long)0, NULL } +}; +#endif /* defined(HASFSTRUCT) */ + + +#if OSRV>=40 +/* + * The following items are needed by the internal kernel major() + * and minor() macros for mapping extended minor numbers. + */ + +int nxdevmaps = -1; /* maximum kernel xdevmap[] index */ +struct XDEVMAP *Xdevmap; /* dynamically allocated xdevmap[] */ +#endif /* OSRV>=40 */ diff --git a/dialects/osr/include/netdb.h b/dialects/osr/include/netdb.h new file mode 100644 index 0000000..3d2e3d7 --- /dev/null +++ b/dialects/osr/include/netdb.h @@ -0,0 +1,121 @@ +/*- + * Copyright (c) 1980, 1983, 1988 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. + * + * @(#)netdb.h 5.15 (Berkeley) 4/3/91 + */ + +#ifndef _NETDB_H_ +#define _NETDB_H_ + +#define _PATH_HEQUIV "/etc/hosts.equiv" +#define _PATH_HOSTS "/etc/hosts" +#define _PATH_NETWORKS "/etc/networks" +#define _PATH_PROTOCOLS "/etc/protocols" +#define _PATH_SERVICES "/etc/services" + +/* + * Structures returned by network data base library. All addresses are + * supplied in host order, and returned in network order (suitable for + * use in system calls). + */ +struct hostent { + char *h_name; /* official name of host */ + char **h_aliases; /* alias list */ + int h_addrtype; /* host address type */ + int h_length; /* length of address */ + char **h_addr_list; /* list of addresses from name server */ +#define h_addr h_addr_list[0] /* address, for backward compatiblity */ +}; + +/* + * Assumption here is that a network number + * fits in 32 bits -- probably a poor one. + */ +struct netent { + char *n_name; /* official name of net */ + char **n_aliases; /* alias list */ + int n_addrtype; /* net address type */ + unsigned long n_net; /* network # */ +}; + +struct servent { + char *s_name; /* official service name */ + char **s_aliases; /* alias list */ + int s_port; /* port # */ + char *s_proto; /* protocol to use */ +}; + +struct protoent { + char *p_name; /* official protocol name */ + char **p_aliases; /* alias list */ + int p_proto; /* protocol # */ +}; + +/* + * Error return codes from gethostbyname() and gethostbyaddr() + * (left in extern int h_errno). + */ + +#define HOST_NOT_FOUND 1 /* Authoritative Answer Host not found */ +#define TRY_AGAIN 2 /* Non-Authoritive Host not found, or SERVERFAIL */ +#define NO_RECOVERY 3 /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */ +#define NO_DATA 4 /* Valid name, no data record of requested type */ +#define NO_ADDRESS NO_DATA /* no address, look for MX record */ + +#include + +__BEGIN_DECLS +void endhostent __P((void)); +void endnetent __P((void)); +void endprotoent __P((void)); +/* void endservent __P((void)); */ +struct hostent *gethostbyaddr __P((const char *, int, int)); +struct hostent *gethostbyname __P((char *)); +struct hostent *gethostent __P((void)); +struct netent *getnetbyaddr __P((long, int)); /* u_long? */ +struct netent *getnetbyname __P((const char *)); +struct netent *getnetent __P((void)); +struct protoent *getprotobyname __P((const char *)); +struct protoent *getprotobynumber __P((int)); +struct protoent *getprotoent __P((void)); +struct servent *getservbyname __P((const char *, const char *)); +struct servent *getservbyport __P((int, const char *)); +struct servent *getservent __P((void)); +void herror __P((const char *)); +void sethostent __P((int)); +/* void sethostfile __P((const char *)); */ +void setnetent __P((int)); +void setprotoent __P((int)); +/* void setservent __P((int)); */ +__END_DECLS + +#endif /* !_NETDB_H_ */ diff --git a/dialects/osr/include/sys/cdefs.h b/dialects/osr/include/sys/cdefs.h new file mode 100644 index 0000000..c4157bc --- /dev/null +++ b/dialects/osr/include/sys/cdefs.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 1991, 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. + * + * @(#)cdefs.h 8.2 (Berkeley) 10/4/93 + */ + +#ifndef _CDEFS_H_ +#define _CDEFS_H_ + +#if defined(__cplusplus) +#define __BEGIN_DECLS extern "C" { +#define __END_DECLS }; +#else +#define __BEGIN_DECLS +#define __END_DECLS +#endif + +/* + * The __CONCAT macro is used to concatenate parts of symbol names, e.g. + * with "#define OLD(foo) __CONCAT(old,foo)", OLD(foo) produces oldfoo. + * The __CONCAT macro is a bit tricky -- make sure you don't put spaces + * in between its arguments. __CONCAT can also concatenate double-quoted + * strings produced by the __STRING macro, but this only works with ANSI C. + */ +#if defined(__STDC__) || defined(__cplusplus) +#define __P(protos) protos /* full-blown ANSI C */ +#define __CONCAT(x,y) x ## y +#define __STRING(x) #x + +#if !defined(__GNUC__) && !defined(__cplusplus) +#define inline +#endif + +#else /* !(__STDC__ || __cplusplus) */ +#define __P(protos) () /* traditional C preprocessor */ +#define __CONCAT(x,y) x/**/y +#define __STRING(x) "x" + +#ifdef __GNUC__ +#define const __const /* GCC: ANSI C with -traditional */ +#define inline __inline +#define signed __signed +#define volatile __volatile + +#else /* !__GNUC__ */ +#define const /* delete ANSI C keywords */ +#define inline +#define signed +#define volatile +#endif /* !__GNUC__ */ +#endif /* !(__STDC__ || __cplusplus) */ + +/* + * GCC has extensions for declaring functions as `pure' (always returns + * the same value given the same inputs, i.e., has no external state and + * no side effects) and `dead' (nonreturning). These mainly affect + * optimization and warnings. Unfortunately, GCC complains if these are + * used under strict ANSI mode (`gcc -ansi -pedantic'), hence we need to + * define them only if compiling without this. + */ +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) +#define __dead __volatile +#define __pure __const +#else +#define __dead +#define __pure +#endif + +#endif /* !_CDEFS_H_ */ diff --git a/dialects/osr/machine.h b/dialects/osr/machine.h new file mode 100644 index 0000000..d4f7cb6 --- /dev/null +++ b/dialects/osr/machine.h @@ -0,0 +1,614 @@ +/* + * machine.h - SCO OpenServer definitions for lsof + */ + + +/* + * 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. + */ + + +/* + * $Id: machine.h,v 1.36 2010/07/29 16:02:57 abe Exp $ + */ + +#if !defined(LSOF_MACHINE_H) +#define LSOF_MACHINE_H 1 + + +#include +#include + + +/* + * 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 OSRV>=42 +#define CAN_USE_CLNT_CREATE 1 +#endif /* OSRV>=42 */ + + +/* + * 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 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 systems 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 systems that use nlist() to acccess + * kernel symbols. + */ + +#define HASNLIST 1 + + +/* + * HASPIPEFN is defined for those dialects that have a special function to + * process DTYPE_PIPE file structure entries. Its value is the name of the + * function. + * + * NOTE: don't forget to define a prototype for this function in dproto.h. + */ + +/* #define HASPIPEFN process_pipe? */ + + +/* + * HASPIPENODE is defined for those dialects that have pipe nodes. + */ + +/* #define HASPIPENODE 1 */ + + +/* + * HASPMAPENABLED is defined when the reporting of portmapper registration + * info is enabled by default. + */ + +/* #define HASPMAPENABLED 1 */ + + +/* + * HASPPID is defined for those dialects that support identification of + * the parent process IDentifier (PPID) of a process. + */ + +#define HASPPID 1 + + +/* + * HASPRINTDEV, HASPRINTINO, HASPRINTNM, HASPRINTOFF, and HASPRINTSZ + * define private dialect-specific functions for printing DEVice numbers, + * INOde numbers, NaMes, file OFFsets, and file SiZes. The functions are + * called from print_file(). + */ + +#define HASPRINTDEV print_dev +#define HASPRINTINO print_ino +/* #define HASPRINTNM print_nm? */ +/* #define HASPRINTOFF print_off? */ +/* #define HASPRINTSZ print_sz? */ + + +/* + * HASPRIVFILETYPE and PRIVFILETYPE are defined for dialects that have a + * file structure type that isn't defined by a DTYPE_* symbol. They are + * used in lib/prfp.c to select the type's processing. + * + * PRIVFILETYPE is the definition of the f_type value in the file struct. + * + * HASPRIVFILETYPE is the name of the processing function. + */ + +/* #define HASPRIVFILETYPE process_shmf? */ +/* #define PRIVFILETYPE ?? */ + + +/* + * HASPRIVNMCACHE is defined for dialects that have a private method for + * printing cached NAME column values for some files. HASPRIVNAMECACHE + * is defined to be the name of the function. + * + * The function takes one argument, a struct lfile pointer to the file, and + * returns non-zero if it prints a name to stdout. + */ + +/* #define HASPRIVNMCACHE */ + + +/* + * 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. + */ + +# if defined(HAS_NFS) +#define HASRNODE 1 +# endif /* defined(HAS_NFS) */ + + +/* + * 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 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 OSRV>=506 +#define HASWIDECHAR 1 +# endif /* OSRV>=506 */ + +/* #define WIDECHARINCL */ + + +/* + * 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 systems 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. + */ + +/* #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_ is defined for dialects that use the + * in the lsof library. + * + * Note: other definitions and operations may be required to condition the + * library function source code. They may be found in the dialect dlsof.h + * header files. + */ + +/* #define USE_LIB_CKKV 1 ckkv.c */ +/* #define USE_LIB_COMPLETEVFS 1 cvfs.c */ +#define USE_LIB_FIND_CH_INO 1 /* fino.c */ +#define USE_LIB_IS_FILE_NAMED 1 /* isfn.c */ +#define USE_LIB_LKUPDEV 1 /* lkud.c */ +#define USE_LIB_PRINTDEVNAME 1 /* pdvn.c */ +/* #define USE_LIB_PROCESS_FILE 1 prfp.c */ +#define USE_LIB_PRINT_TCPTPI 1 /* ptti.c */ +#define USE_LIB_READDEV 1 /* rdev.c */ +/* #define USE_LIB_READMNT 1 rmnt.c */ +/* #define USE_LIB_REGEX 1 regex.c */ +/* #define USE_LIB_RNAM 1 rnam.c */ +/* #define USE_LIB_RNCH 1 rnch.c */ +/* #define USE_LIB_RNMH 1 rnmh.c */ + +# if OSRV<500 +#define USE_LIB_SNPF 1 /* snpf.c */ +# else /* OSRV>=500 */ +#define snpf snprintf /* use the system's snprintf() */ +# endif /* OSRV<500 */ + + +/* + * WARNDEVACCESS is defined for those dialects that should issue a warning + * when lsof can't access /dev (or /device) or one of its sub-directories. + * The warning can be inhibited by the lsof caller with the -w option. + */ + +/* #define WARNDEVACCESS 1 */ + + +/* + * WARNINGSTATE is defined for those dialects that want to suppress all lsof + * warning messages. + */ + +/* #define WARNINGSTATE 1 warnings are enabled by default */ + + +/* + * WILLDROPGID is defined for those dialects whose lsof executable runs + * setgid(not_real_GID) and whose setgid power can be relinquished after + * the dialect's initialize() function has been executed. + */ + +#define WILLDROPGID 1 + + +/* + * zeromem is a macro that uses bzero or memset. + */ + +#define zeromem(a, l) memset(a, 0, l) +#endif /* !defined(LSOF_MACHINE_H) */ diff --git a/dialects/sun/Makefile b/dialects/sun/Makefile new file mode 100644 index 0000000..49dac14 --- /dev/null +++ b/dialects/sun/Makefile @@ -0,0 +1,160 @@ + +# 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 -m 2755 -g kmem ${PROG} ' + @echo ' install -m 444 ${MAN} ' + @echo '' + @echo 'Your Solaris install rule actions might look something like + @echo 'this:' + @echo '' + @echo ' install -[cf] -m 2755 -g sys ${PROG}' + @echo ' install -[cf] -m 444 ${MAN}' + @echo '' + @echo 'You may have to put additional values in , 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 ; the appropriate destination for the' + @echo 'man page in .' + @echo '' + +${LIB}: FRC + (cd lib; ${MAKE} DEBUG="${DEBUG}" CFGF="${CFGF}") + +version.h: FRC + @echo Constructing version.h + @rm -f version.h + @echo '#define LSOF_BLDCMT "${LSOF_BLDCMT}"' > version.h; + @echo '#define LSOF_CC "${CC}"' >> version.h + @echo '#define LSOF_CCV "${CCV}"' >> version.h + @echo '#define LSOF_CCDATE "'`date`'"' >> version.h + @echo '#define LSOF_CCFLAGS "'`echo ${CFLAGS} | sed 's/\\\\(/\\(/g' | sed 's/\\\\)/\\)/g' | sed 's/"/\\\\"/g'`'"' >> version.h + @echo '#define LSOF_CINFO "${CINFO}"' >> version.h + @if [ "X${LSOF_HOST}" = "X" ]; then \ + echo '#define LSOF_HOST "'`uname -n`'"' >> version.h; \ + else \ + if [ "${LSOF_HOST}" = "none" ]; then \ + echo '#define LSOF_HOST ""' >> version.h; \ + else \ + echo '#define LSOF_HOST "${LSOF_HOST}"' >> version.h; \ + fi \ + fi + @echo '#define LSOF_LDFLAGS "${CFGL}"' >> version.h + @if [ "X${LSOF_LOGNAME}" = "X" ]; then \ + echo '#define LSOF_LOGNAME "${LOGNAME}"' >> version.h; \ + else \ + if [ "${LSOF_LOGNAME}" = "none" ]; then \ + echo '#define LSOF_LOGNAME ""' >> version.h; \ + else \ + echo '#define LSOF_LOGNAME "${LSOF_LOGNAME}"' >> version.h; \ + fi; \ + fi + @if [ "X${LSOF_SYSINFO}" = "X" ]; then \ + echo '#define LSOF_SYSINFO "'`uname -a`'"' >> version.h; \ + else \ + if [ "${LSOF_SYSINFO}" = "none" ]; then \ + echo '#define LSOF_SYSINFO ""' >> version.h; \ + else \ + echo '#define LSOF_SYSINFO "${LSOF_SYSINFO}"' >> version.h; \ + fi \ + fi + @if [ "X${LSOF_USER}" = "X" ]; then \ + echo '#define LSOF_USER "${USER}"' >> version.h; \ + else \ + if [ "${LSOF_USER}" = "none" ]; then \ + echo '#define LSOF_USER ""' >> version.h; \ + else \ + echo '#define LSOF_USER "${LSOF_USER}"' >> version.h; \ + fi \ + fi + @sed '/VN/s/.ds VN \(.*\)/#define LSOF_VERSION "\1"/' < version >> version.h + +FRC: + +# DO NOT DELETE THIS LINE - make depend DEPENDS ON IT + +ddev.o: ${HDR} ddev.c + +dfile.o: ${HDR} dfile.c + +dmnt.o: ${HDR} dmnt.c + +dnode.o: ${HDR} dnode.c + +dnode1.o: ${HDR} dnode1.c + +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/dialects/sun/Mksrc b/dialects/sun/Mksrc new file mode 100755 index 0000000..4641bb5 --- /dev/null +++ b/dialects/sun/Mksrc @@ -0,0 +1,57 @@ +#!/bin/sh +# +# 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 $ + + +D=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" + +for i in $L +do + rm -f $i + $LSOF_MKC $D/$i $i + echo "$LSOF_MKC $D/$i $i" +done + +# Assemble kernelbase.h for SunOS and Solaris < 2.5 (5.5) + +NM=kernelbase.h +rm -f $NM +if test "X$1" != "Xsolaris" -o $2 -lt 20500 +then + if test "X$1" = "Xsolaris" + then + A=`uname -m` + if test "$A" = "i86pc" + then + H=/usr/include/sys/machparam.h + else + H=/usr/src/uts/$A/sys/machparam.h + fi + else + H=/usr/include/machine/param.h + fi + echo "#if !defined(KERNELSIZE)" > $NM + grep "^#define[ ]*KERNELSIZE" $H >> $NM + echo "#endif" >> $NM + echo "#if !defined(KERNELBASE)" >> $NM + grep "^#define[ ]*KERNELBASE" $H >> $NM + echo "#endif" >> $NM +else + +# To keep the dependency list for dproc.o simple in the Makefile, +# create an empty kernelbase.h for Solaris 2.5 (5.5) and above. + + touch $NM +fi +echo "$NM assembled." diff --git a/dialects/sun/ddev.c b/dialects/sun/ddev.c new file mode 100644 index 0000000..83bd2ce --- /dev/null +++ b/dialects/sun/ddev.c @@ -0,0 +1,1143 @@ +/* + * 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"; +static char *rcsid = "$Id: ddev.c,v 1.20 2005/08/08 19:55:41 abe Exp $"; +#endif + + +#include "lsof.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 + */ + +_PROTOTYPE(static void make_devtp,(struct stat *s, char *p)); +_PROTOTYPE(static int rmdupdev,(struct l_dev ***dp, int n, int ty)); + + +/* + * make_devtp() - make Devtp[] entry + */ + +static void +make_devtp(s, p) + 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); + Exit(1); + } + } +/* + * 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); + Exit(1); + } + Devtp[Devx].rdev = s->st_rdev; + Devtp[Devx].v = 0; + Devx++; +} + + +/* + * printdevname() - print block or character device name + */ + +int +printdevname(dev, rdev, f, nty) + 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(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(dev, rdev, 1, 0); + else +#endif /* defined(HASBLKDEV) */ + + dp = lkupdev(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(&DevDev, rdev, 0, 0); + else +#endif /* defined(HASBLKDEV) */ + + dp = lkupdev(&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); + Exit(1); + } + (void) snpf(cp, len + 1, "(%s %s)", ttl, dp->name); + (void) add_nma(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(&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(&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(); + goto printchdevname_again; + } +#endif /* defined(HASDCACHE) */ + + return(0); +} + + +/* + * read_clone() - read Solaris clone device information + */ + +void +read_clone() +{ + 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); + Exit(1); + } + 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); + Exit(1); + } + +#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(&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); + Exit(1); + } + /* + * 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); + Exit(1); + } + /* + * 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); + Exit(1); + } + /* + * 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(skip) + 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()) == 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); + Exit(1); + } + read_clone(); + Dstk = (char **)NULL; + Dstkn = Dstkx = 0; + (void) stkdir(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); + Exit(1); + } + (void) free((FREE_P *)Dstk[Dstkx]); + Dstk[Dstkx] = (char *)NULL; + /* + * Scan the directory. + */ + for (dp = ReadDir(dfp); dp; dp = ReadDir(dfp)) { + if (dp->d_ino == 0 || dp->d_name[0] == '.') + continue; + /* + * Form the full path name and get its status. + */ + 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); + Exit(1); + } + +#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(fp); + continue; + } + if ((sb.st_mode & S_IFMT) == S_IFCHR) { + + /* + * Make Devtp[] entry. + */ + make_devtp(&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); + Exit(1); + } + } + 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); + Exit(1); + } + for (j = 0; j < BNdev; j++) { + BSdev[j] = &BDevtp[j]; + } + (void) qsort((QSORT_P *)BSdev, (size_t)BNdev, + (size_t)sizeof(struct l_dev *), compdev); + BNdev = rmdupdev(&BSdev, BNdev, 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); + Exit(1); + } + for (i = 0; i < Ndev; i++) { + Sdev[i] = &Devtp[i]; + } + (void) qsort((QSORT_P *)Sdev, (size_t)Ndev, + (size_t)sizeof(struct l_dev *), compdev); + Ndev = rmdupdev(&Sdev, Ndev, 1); + } else { + (void) fprintf(stderr, "%s: no character devices found\n", Pn); + Exit(1); + } + +#if defined(HASDCACHE) +/* + * Write device cache file, as required. + */ + if (DCstate == 1 || (DCstate == 3 && dcrd)) + write_dcache(); +#endif /* defined(HASDCACHE) */ + +} + + +/* + * clr_sect() - clear cached clone and pseudo sections + */ + +void +clr_sect() +{ + 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(m) + 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); + Exit(1); + } + /* + * 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); + Exit(1); + } + 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(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(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); + Exit(1); + return(1); /* to make code analyzers happy */ +} + + +/* + * rereaddev() - reread device names, modes and types + */ + +void +rereaddev() +{ + (void) clr_devtab(); + (void) clr_sect(); + Devx = 0; + +# if defined(DCACHE_CLR) + (void) DCACHE_CLR(); +# endif /* defined(DCACHE_CLR) */ + + readdev(1); + DCunsafe = 0; +} + + +/* + * rw_pseudo_sect() - read/write the device cache pseudo section + */ + +int +rw_pseudo_sect(m) + 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); + Exit(1); + } + /* + * 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); + Exit(1); + } + *(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(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(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(dp) + 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(); + return(0); + } + dp->v = 1; + return(1); +} +#endif /* defined(HASDCACHE) */ + + +/* + * rmdupdev() - remove duplicate (major/minor/inode) devices + */ + +static int +rmdupdev(dp, n, ty) + 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"); + Exit(1); + } + return(j); +} diff --git a/dialects/sun/dfile.c b/dialects/sun/dfile.c new file mode 100644 index 0000000..bb09306 --- /dev/null +++ b/dialects/sun/dfile.c @@ -0,0 +1,669 @@ +/* + * 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"; +static char *rcsid = "$Id: dfile.c,v 1.21 2009/03/25 19:22:16 abe Exp $"; +#endif + + +#include "lsof.h" + + +/* + * Local structures + */ + +struct hsfile { + struct sfile *s; /* the Sfile table address */ + struct hsfile *next; /* the next hash bucket entry */ +}; + + +/* + * Local static variables + */ + +static struct hsfile *HbyCd = /* hash by clone buckets */ + (struct hsfile *)NULL; +static int HbyCdCt = 0; /* HbyCd entry count */ +static struct hsfile *HbyFdi = /* hash by file buckets */ + (struct hsfile *)NULL; +static int HbyFdiCt = 0; /* HbyFdi entry count */ +static struct hsfile *HbyFrd = /* hash by file raw device buckets */ + (struct hsfile *)NULL; +static int HbyFrdCt = 0; /* HbyFrd entry count */ +static struct hsfile *HbyFsd = /* hash by file system buckets */ + (struct hsfile *)NULL; +static int HbyFsdCt = 0; /* HbyFsd entry count */ +static struct hsfile *HbyNm = /* hash by name buckets */ + (struct hsfile *)NULL; +static int HbyNmCt = 0; /* HbyNm entry count */ + + +/* + * Local definitions + */ + +#define 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() +{ + 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); + Exit(1); + } + } + if (!(HbyFdi = (struct hsfile *)calloc((MALLOC_S)SFDIHASH, + sizeof(struct hsfile)))) + { + (void) fprintf(stderr, + "%s: can't allocate space for %d (dev,ino) hash buckets\n", + Pn, SFDIHASH); + Exit(1); + } + if (!(HbyFrd = (struct hsfile *)calloc((MALLOC_S)SFRDHASH, + sizeof(struct hsfile)))) + { + (void) fprintf(stderr, + "%s: can't allocate space for %d rdev hash buckets\n", + Pn, SFRDHASH); + Exit(1); + } + if (!(HbyFsd = (struct hsfile *)calloc((MALLOC_S)SFFSHASH, + sizeof(struct hsfile)))) + { + (void) fprintf(stderr, + "%s: can't allocate space for %d file sys hash buckets\n", + Pn, SFFSHASH); + Exit(1); + } + if (!(HbyNm = (struct hsfile *)calloc((MALLOC_S)SFNMHASH, + sizeof(struct hsfile)))) + { + (void) fprintf(stderr, + "%s: can't allocate space for %d name hash buckets\n", + Pn, SFNMHASH); + Exit(1); + } + hs++; +/* + * Scan the Sfile chain, building file, file system, 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); + Exit(1); + } + sn->s = s; + sn->next = sh->next; + sh->next = sn; + } + } + } +} + + +/* + * is_file_named() - is this file named? + */ + +int +is_file_named(p, nt, vt, ps) + 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(&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(lf, 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 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(lf) + 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((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(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(ka, rb, rbl) + 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(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(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(fp) + KA_T fp; /* kernel file structure address */ +{ + struct file f; + int flag; + +#if defined(FILEPTR) + FILEPTR = &f; +#endif /* defined(FILEPTR) */ + + if (kread(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; + + if (f.f_count) { + + /* + * Construct access code. + */ + if ((flag = (f.f_flag & (FREAD | FWRITE))) == FREAD) + Lf->access = 'r'; + else if (flag == FWRITE) + Lf->access = 'w'; + else if (flag == (FREAD | FWRITE)) + Lf->access = 'u'; + +#if defined(HASFSTRUCT) + /* + * Save file structure values. + */ + if (Fsv & FSV_CT) { + Lf->fct = (long)f.f_count; + Lf->fsv |= FSV_CT; + } + if (Fsv & FSV_FA) { + Lf->fsa = fp; + Lf->fsv |= FSV_FA; + } + if (Fsv & FSV_FG) { + Lf->ffg = (long)f.f_flag; + Lf->fsv |= FSV_FG; + } + if (Fsv & FSV_NI) { + Lf->fna = (KA_T)f.f_vnode; + Lf->fsv |= FSV_NI; + } +#endif /* defined(HASFSTRUCT) */ + + /* + * Solaris file structures contain a vnode pointer. Process it. + */ + process_node((KA_T)f.f_vnode); + return; + } + enter_nm("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/dialects/sun/distfile.kvm b/dialects/sun/distfile.kvm new file mode 100644 index 0000000..9559172 --- /dev/null +++ b/dialects/sun/distfile.kvm @@ -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/dialects/sun/dlsof.h b/dialects/sun/dlsof.h new file mode 100644 index 0000000..1b74eb6 --- /dev/null +++ b/dialects/sun/dlsof.h @@ -0,0 +1,690 @@ +/* + * 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 +#include +#include + +# if solaris<20600 +#define _KMEMUSER 1 +# else /* solaris>=20600 */ +#include +# endif /* solaris<20600 */ + +#include +#include + +# if defined(HASZONES) +#define _KERNEL +#include +#undef _KERNEL +# endif /* defined(HASZONES) */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +# if solaris>=110000 +#define _KERNEL +# endif /* solaris>=110000 */ + +#include + +# if solaris>=110000 +#undef _KERNEL +# endif /* solaris>=110000 */ + + +# if solaris>=70000 +#include +#include +# endif /* solaris>=70000 */ + +#define _KERNEL +#define MI_HRTIMING +#include + +# if solaris<20600 +#undef staticf +# endif /* solaris<20600 */ + +#include + +# if solaris>=70000 +#include +# endif /* solaris>=70000 */ + +# if solaris<20600 +#include +# endif /* solaris<20600 */ + +# if solaris>=80000 +#include +#include +# 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 +# endif /* solaris>=110000 */ +#include +#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 +# endif /* solaris>=110000 */ +# endif /* defined(HAS_IPCLASSIFIER_H) */ + +#include +#undef _KERNEL +#undef MI_HRTIMING +#define exit kernel_exit +#define rval_t char +#define strsignal kernel_strsignal +#include + +# if defined(HAS_SOCKET_PROTO_H) +#define _KERNEL 1 /* DEBUG */ +# endif /* HAS_SOCKET_PROTO_H */ + +#include + +# 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 + +# if solaris>=80000 +#undef _KERNEL +# endif /* solaris>=80000 */ + +#include +#include +#include + +# if solaris<20600 +#undef MAX +#undef MIN +# endif /* solaris<20600 */ + +#include +#include +#include +#include +#include +#include + +# if solaris>=20600 +#define _KERNEL +# endif /* solaris>=20600 */ + +#include + +# if solaris>=20600 +#undef _KERNEL +# endif /* solaris>=20600 */ + +#include + +# if solaris>=20500 +#include +#include +#include + +# if solaris>=110000 +#define _KERNEL +#include +#undef _KERNEL +# endif /* solaris>=110000 */ + +#include +#include +#define _KERNEL +#include + +# 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 +#undef printf +#undef snprintf +#undef sprintf +#undef swab +#undef vprintf +#undef vsnprintf +#undef vsprintf +#include +#include +#include +# endif /* solaris>=100000 */ + +#include +#undef _KERNEL +# endif /* solaris>=20500 */ + +# if !defined(_NETDB_H_) +#include +# endif /* !defined(_NETDB_H_) */ + +#include +#include + +# 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 +# endif /* solaris<20400 */ +# endif /* solaris>=20300 */ + +#include +#include +#include +#include +#include + +# if defined(HASCACHEFS) +#include +# endif /* defined(HACACHEFS) */ + +#include +#include +#include +#include +#include + +# if solaris>=20600 +#undef SLOCKED +# endif /* solaris>=20600 */ + +#include +#include + +# if solaris>=110000 +#define _KERNEL +# endif /* solaris>=110000 */ + +#include + +# if solaris>=110000 +#undef _KERNEL +# endif /* solaris>=110000 */ + +# if solaris>=100000 +#define _KERNEL +# endif /* solaris >= 100000 */ + +#include + +# if solaris>=100000 +#include +#include +#include +# endif /* solaris>=100000 */ + +# if solaris>=100000 +#undef _KERNEL +# endif /* solaris >= 100000 */ + +#include +#include + +# if defined(HASPROCFS) +#include +# endif /* defined(HASPROCFS) */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +# if solaris<100000 +#include +# 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 + +#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((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 + +# 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) */ + +#endif /* SOLARIS_LSOF_H */ diff --git a/dialects/sun/dmnt.c b/dialects/sun/dmnt.c new file mode 100644 index 0000000..c9c023c --- /dev/null +++ b/dialects/sun/dmnt.c @@ -0,0 +1,417 @@ +/* + * 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"; +static char *rcsid = "$Id: dmnt.c,v 1.15 2005/08/29 10:24:25 abe Exp $"; +#endif + + +#include "lsof.h" + + +/* + * Local static definitions + */ + +static struct mounts *Lmi = (struct mounts *)NULL; /* local mount info */ +static int Lmist = 0; /* Lmi status */ + + +_PROTOTYPE(static char *getmntdev,(char *o, int l, struct stat *s, char *f)); + + +/* + * getmntdev() - get mount entry's device number + */ + +static char * +getmntdev(o, l, s, f) + 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() +{ + 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"); + Exit(1); + } + if (!(ln = Readlink(dn))) { + if (!Fwarn) { + (void) fprintf(stderr, + " Output information may be incomplete.\n"); + } + continue; + } + if (ln != dn) { + (void) free((FREE_P *)dn); + dn = ln; + } + if (*dn != '/') + continue; + /* + * Stat() the directory. + * + * 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(dopt, devl, &sb, + +#if defined(HASFSTYPE) + mp->mnt_fstype +#else /* !defined(HASFSTYPE) */ + (char *)NULL +#endif /* defined(HASFSTYPE) */ + + )) + ) + continue; + stat = 1; + } else if (statsafely(dn, &sb)) { + if (dopt) { + if (!(dopte = getmntdev(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(dn); + dn = (char *)NULL; + /* + * Stat() the file system (mounted-on) name and add file system + * information to the local mount table entry. + */ + if (!ln || statsafely(ln, &sb)) + sb.st_mode = 0; + mtp->fsnmres = ln; + mtp->fs_mode = sb.st_mode; + Lmi = mtp; + +#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(ka, la, lv) + 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); + Exit(1); + } + 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((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(); + v->vfs_dev = AFSdevStat ? AFSdev : 0; + } +#endif /* defined(HAS_AFS) */ + +/* + * Complete mount information. + */ + + (void) completevfs(vp, (dev_t *)&v->vfs_dev); + vp->next = Lvfs; + vp->addr = ka; + Lvfs = vp; + return(vp); +} diff --git a/dialects/sun/dnode.c b/dialects/sun/dnode.c new file mode 100644 index 0000000..c27eb7a --- /dev/null +++ b/dialects/sun/dnode.c @@ -0,0 +1,5506 @@ +/* + * 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"; +static char *rcsid = "$Id: dnode.c,v 1.61 2015/07/07 20:27:15 abe Exp $"; +#endif + + +#include "lsof.h" + +#if solaris>=110000 +#include +#endif /* solaris>=110000 */ + +#undef fs_bsize +#include + + +#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/fs/%s/sockfs" +# 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 + */ + +_PROTOTYPE(static int read_nsti,(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 + */ + +_PROTOTYPE(static int read_nzn,(KA_T na, KA_T nza, znode_t *z)); +_PROTOTYPE(static int read_nznp,(KA_T nza, KA_T nzpa, znode_phys_t *zp)); +_PROTOTYPE(static int read_nzvfs,(KA_T nza, KA_T nzva, zfsvfs_t *zv)); +#endif /* defined(HAS_ZFS) && defined(HAS_LIBCTF) */ + + +_PROTOTYPE(static struct l_dev *finddev,(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 + */ + +_PROTOTYPE(static void build_Voptab,(void)); +_PROTOTYPE(static char isvlocked,(struct vnode *va)); +_PROTOTYPE(static int readinode,(KA_T ia, struct inode *i)); +_PROTOTYPE(static void read_mi,(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 +_PROTOTYPE(static int read_nan,(KA_T na, KA_T aa, struct fnnode *rn)); +_PROTOTYPE(static int read_nson,(KA_T na, KA_T sa, struct sonode *sn)); +_PROTOTYPE(static int read_nusa,(struct soaddr *so, struct sockaddr_un *ua)); +# else /* solaris<20600 */ +_PROTOTYPE(static int read_nan,(KA_T na, KA_T aa, struct autonode *a)); +# endif /* solaris>=20600 */ +_PROTOTYPE(static int idoorkeep,(struct door_node *d)); +_PROTOTYPE(static int read_ndn,(KA_T na, KA_T da, struct door_node *d)); +#endif /* solaris>=20500 */ + +#if solaris>=110000 +_PROTOTYPE(static int read_nsdn,(KA_T na, KA_T sa, struct sdev_node *sdn, struct vattr *sdva)); +#endif /* solaris>=110000 */ + +_PROTOTYPE(static int read_nfn,(KA_T na, KA_T fa, struct fifonode *f)); +_PROTOTYPE(static int read_nhn,(KA_T na, KA_T ha, struct hsnode *h)); +_PROTOTYPE(static int read_nin,(KA_T na, KA_T ia, struct inode *i)); +_PROTOTYPE(static int read_nmn,(KA_T na, KA_T ia, struct mvfsnode *m)); +_PROTOTYPE(static int read_npn,(KA_T na, KA_T pa, struct pcnode *p)); +_PROTOTYPE(static int read_nrn,(KA_T na, KA_T ra, struct rnode *r)); + +#if solaris>=100000 +_PROTOTYPE(static int read_nctfsn,(int ty, KA_T na, KA_T ca, char *cn)); +_PROTOTYPE(static int read_nprtn,(KA_T na, KA_T ra, port_t *p)); +_PROTOTYPE(static int read_nrn4,(KA_T na, KA_T ra, struct rnode4 *r)); +#endif /* solaris>=100000 */ + +_PROTOTYPE(static int read_nsn,(KA_T na, KA_T sa, struct snode *s)); +_PROTOTYPE(static int read_ntn,(KA_T na, KA_T ta, struct tmpnode *t)); +_PROTOTYPE(static int read_nvn,(KA_T na, KA_T va, struct vnode *v)); + +#if defined(HASPROCFS) +_PROTOTYPE(static int read_npi,(KA_T na, struct vnode *v, struct pid *pids)); +#endif /* defined(HASPROCFS) */ + +_PROTOTYPE(static char *ent_fa,(KA_T *a1, KA_T *a2, char *d, int *len)); +_PROTOTYPE(static int is_socket,(struct vnode *v)); +_PROTOTYPE(static int read_cni,(struct snode *s, struct vnode *rv, + struct vnode *v, struct snode *rs, struct dev_info *di, char *din, + int dinl)); + +#if defined(HASCACHEFS) +_PROTOTYPE(static int read_ncn,(KA_T na, KA_T ca, struct cnode *cn)); +#endif /* defined(HASCACHEFS) */ + +_PROTOTYPE(static int read_nln,(KA_T na, KA_T la, struct lnode *ln)); +_PROTOTYPE(static int read_nnn,(KA_T na, KA_T nna, struct namenode *n)); + +#if solaris<100000 +_PROTOTYPE(static void savesockmod,(struct so_so *so, struct so_so *sop, int *so_st)); +#else /* solaris>=100000 */ +_PROTOTYPE(static int read_ndvn,(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(name, nl, &ops) < 0) \ + ops = (KA_T)0; \ + else if (kread(ops, (char *)&ops, sizeof(ops))) \ + ops = (KA_T)0 +#else /* !defined(VOPNAME_OPEN) || solaris<100000 */ +#define GETVOPS(name, nl, ops) \ + if (get_Nl_value(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() +{ + 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); + Exit(1); + } + if (!(FxToVoptab = (v_optab_t **)calloc((MALLOC_S)Fsinfomax, + sizeof(v_optab_t *))) + ) { + (void) fprintf(stderr, "%s: no space for FxToVoptab\n", Pn); + Exit(1); + } + 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); + Exit(1); + } + 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(f, mod, ty, mem) + 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(i, t, r) + 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)); + Exit(1); + } + 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(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)); + Exit(1); + } + for (err = 0; r->name; r++) { + if (CTF_getmem(f, kmp, r->name, r->mem)) + err = 1; + } + (void) ctf_close(f); + if (err) + Exit(1); + *i = 1; +} + + +/* + * CTF_memCB() - Callback function for ctf_member_iter() + */ + +int +CTF_memCB(name, id, offset, arg) + 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(a1, a2, d, len) + 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(v) + 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((KA_T)v->v_stream, tcpudp[i].proto); + return(1); + } + } + return(0); +} + + +/* + * isvlocked() - is Solaris vnode locked? + */ + +static char +isvlocked(va) + 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(' '); + +#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(fp, (char *)&f, sizeof(f))) + return(' '); + 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 ? 'R' : 'r'); + case F_WRLCK: + return(l ? 'W' : 'w'); + case F_RDLCK|F_WRLCK: + return('u'); + default: + return('N'); + } + } 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(lp, (char *)&ld, sizeof(ld))) + return(' '); + 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 ? 'R' : 'r'); + case F_WRLCK: + return(l ? 'W' : 'w'); + case (F_RDLCK | F_WRLCK): + return('u'); + default: + return('L'); + } + } while ((lp = (KA_T)LOCK_NEXT) && (lp != lf) && (i < 10000)); + return(' '); +#endif /* solaris>=20300 */ + +} + + +/* + * finddev() - look up device by device number + */ + +static struct l_dev * +finddev(dev, rdev, flags) + 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(0); +/* + * Search device table for match. + */ + +#if defined(HASDCACHE) + +finddev_again: + +#endif /* defined(HASDCACHE) */ + + if (flags & LOOKDEV_TAB) { + if ((dp = lkupdev(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(&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(&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(d) + 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((KA_T)d->door_target, (char *)&dp, sizeof(dp))) + return(0); + if (!dp.p_pidp + || kread((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(buf, (int)strlen(buf)); + return(1); +} +#endif /* solaris>=20500 */ + + +/* + * process_node() - process vnode + */ + +void +process_node(va) + 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; + +#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(); + ft = 0; + } +/* + * 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) */ + + ); + Exit(1); + } + } + 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) */ + +#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(v)) + return; +/* + * Obtain the Solaris virtual file system structure. + */ + if ((ka = (KA_T)v->v_vfsp)) { + if (kread(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(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(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(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(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((KA_T)nn.nm_filevp, (char *)&rv, sizeof(rv))) { + rvs = 1; + if ((ka = (KA_T)rv.v_vfsp) + && !kread(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(&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(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(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(va, (KA_T)v->v_data, &s)) + return; + realvp = (KA_T)s.s_realvp; + if (!realvp && s.s_commonvp) { + if (read_cni(&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(vs, (dev_t *)&s.s_dev, (caddr_t)&soso, &so_st, + so_ad, &sdp); +#else /* solaris>=100000 */ + read_mi(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(va, v, &an)) + return; + break; +#endif /* defined(HAS_AFS) */ + +#if solaris>=20500 + case N_AUTO: + +# if solaris<20600 + if (read_nan(va, (KA_T)v->v_data, &au)) +# else /* solaris>=20600 */ + if (read_nan(va, (KA_T)v->v_data, &fnn)) +# endif /* solaris<20600 */ + + return; + break; + +# if solaris>=100000 + case N_DEV: + if (read_ndvn(va, (KA_T)v->v_data, &dv, &dv_dev, &dv_devs)) + return; + dvs = 1; + break; +# endif /* solaris>=100000 */ + + case N_DOOR: + if (read_ndn(va, (KA_T)v->v_data, &dn)) + return; + dns = 1; + break; +#endif /* solaris>=20500 */ + +#if defined(HASCACHEFS) + case N_CACHE: + if (read_ncn(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(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(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(va, (KA_T)v->v_data, &m)) + return; + break; + case N_NFS: + if (read_nrn(va, (KA_T)v->v_data, &r)) + return; + break; + +#if solaris>=100000 + case N_NFS4: + if (read_nrn4(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(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(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(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(tbuf, tbufx); + break; + } + break; + + case N_HSFS: + if (read_nhn(va, (KA_T)v->v_data, &h)) + return; + break; + case N_LOFS: + llc = 0; + do { + rvs = 0; + if (read_nln(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(Namech); + return; + } + if (read_nvn((KA_T)v->v_data, (KA_T)realvp, &rv)) + return; + rvs = 1; + llc++; + if ((ka = (KA_T)rv.v_vfsp) + && !kread(ka, (char *)&rkv, sizeof(rkv)) + && ((rfx = rkv.vfs_fstype - 1) >= 0) + && (rfx < Fsinfomax) + ) { + rfxs = 1; + } else { + rfx = fx; + rfxs = fxs; + } + if (((vty_tmp = vop2ty(&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(Namech); + return; + } + } while (vty_tmp == N_LOFS); + break; + case N_PCFS: + if (read_npn(va, (KA_T)v->v_data, &pc)) + return; + break; + +#if solaris>=100000 + case N_PORT: + if (read_nprtn(va, (KA_T)v->v_data, &pn)) + return; + break; +#endif /* solaris>=100000 */ + +#if defined(HASPROCFS) + case N_PROC: + if (read_npi(va, v, &pids)) + return; + break; +#endif /* defined(HASPROCFS) */ + +#if solaris>=110000 + case N_SDEV: + if (read_nsdn(va, (KA_T)v->v_data, &sdn, &sdva)) + return; + sdns = 1; + break; +#endif /* solaris>=110000 */ + + case N_SAMFS: + (void) add_nma(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(va, (KA_T)v->v_data, &s)) + return; + if (vs) { + Lf->is_stream = 1; + +#if solaris<100000 + read_mi(vs, (dev_t *)&s.s_dev, (caddr_t)&soso, &so_st, so_ad, + &sdp); +#else /* solaris>=100000 */ + read_mi(vs, (dev_t *)&s.s_dev, NULL, NULL, NULL, &sdp); +#endif /* solaris<100000 */ + + vs = (KA_T)NULL; + } + break; + case N_TMP: + if (read_ntn(va, (KA_T)v->v_data, &t)) + return; + break; + +#if defined(HASVXFS) + case N_VXFS: + if (read_vxnode(va, v, vfs, fx, &vx, Vvops)) + return; + break; +#endif /* defined(HASVXFS) */ + +#if defined(HAS_ZFS) + case N_ZFS: + if (read_nzn(va, (KA_T)v->v_data, &zn)) + return; + zns = 1; + break; +#endif /* defined(HAS_ZFS) */ + + case N_REGLR: + default: + if (read_nin(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((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(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(vs, (dev_t *)&s.s_dev, (caddr_t)&soso, &so_st, so_ad, + &sdp); +#else /* solaris>=100000 */ + read_mi(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(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(v); + switch (vty) { + +#if defined(HAS_AFS) + case N_AFS: + if (readafsnode(va, v, &an)) + return; + break; +#endif /* defined(HAS_AFS) */ + +#if solaris>=20500 + case N_AUTO: + +# if solaris<20600 + if (read_nan(va, (KA_T)v->v_data, &au)) +# else /* solaris>=20600 */ + if (read_nan(va, (KA_T)v->v_data, &fnn)) +# endif /* solaris<20600 */ + + return; + break; + +# if solaris>=100000 + case N_DEV: + if (read_ndvn(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(realvp, (KA_T)v->v_data, &dn)) +# else /* solaris>=20600 */ + if (read_ndn(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(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(vty, va, (KA_T)v->v_data, (char *)&ctfs)) + return; + break; +#endif /* solaris>=100000 */ + + case N_HSFS: + if (read_nhn(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(va, (KA_T)v->v_data, &m)) + return; + break; + case N_NFS: + if (read_nrn(va, (KA_T)v->v_data, &r)) + return; + break; + +#if solaris>=100000 + case N_NFS4: + if (read_nrn4(va, (KA_T)v->v_data, &r4)) + return; + break; +#endif /* solaris>=100000 */ + + case N_NM: + if (read_nnn(va, (KA_T)v->v_data, &nn)) + return; + nns = 1; + break; + +#if solaris>=100000 + case N_PORT: + if (read_nprtn(va, (KA_T)v->v_data, &pn)) + return; + break; +#endif /* solaris>=100000 */ + + case N_PCFS: + if (read_npn(va, (KA_T)v->v_data, &pc)) + return; + break; + case N_SAMFS: + (void) add_nma(SAMFS_NMA_MSG, (int)strlen(SAMFS_NMA_MSG)); + +#if solaris>=110000 + case N_SDEV: + if (read_nsdn(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(va, sona, &so)) + return; + break; +#endif /* solaris>=20600 */ + + case N_STREAM: + if (vs) { + Lf->is_stream = 1; + +#if solaris<100000 + read_mi(vs, (dev_t *)&s.s_dev, (caddr_t)&soso, &so_st, so_ad, + &sdp); +#else /* solaris>=100000 */ + read_mi(vs, (dev_t *)&s.s_dev, NULL, NULL, NULL, &sdp); +#endif /* solaris<100000 */ + + vs = (KA_T)NULL; + } + break; + case N_TMP: + if (read_ntn(va, (KA_T)v->v_data, &t)) + return; + break; + +#if defined(HASVXFS) + case N_VXFS: + if (read_vxnode(va, v, vfs, fx, &vx, Vvops)) + return; + break; +#endif /* defined(HASVXFS) */ + +#if defined(HAS_ZFS) + case N_ZFS: + if (read_nzn(va, (KA_T)v->v_data, &zn)) + return; + zns = 1; + break; +#endif /* defined(HAS_ZFS) */ + + case N_REGLR: + default: + if (read_nin(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(" 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(&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(&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(&sti.sti_laddr, &ua)) > 0) + && (nmrl > (len + 5)) + ) { + if (Sfile + && is_file_named(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(&sti.sti_faddr, &ua)) > 0) + && (nmrl > (len + 5)) + ) { + if (Sfile + && is_file_named(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((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(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(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((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(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((KA_T)v->v_data, (KA_T)zn.z_zfsvfs, &zvfs) + && zvfs.z_vfs + && !kread((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(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((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. + */ + if (Foffset) + Lf->off_def = 1; + else { + 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: + Lf->off_def = 1; + 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: + if (!Fsize) + Lf->off_def = 1; + break; +# endif /* solaris>=100000 */ + + case N_DOOR: + case N_FIFO: + if (!Fsize) + Lf->off_def = 1; + break; + case N_MNT: + +#if defined(CVFS_SZSAVE) + if (vfs) { + Lf->sz = (SZOFFTYPE)vfs->size; + Lf->sz_def = 1; + } else +#endif /* defined(CVFS_SZSAVE) */ + + Lf->off_def = 1; + break; + case N_MVFS: + /* The location of file size isn't known. */ + break; + case N_NFS: + if ((type == VCHR || type == VBLK) && !Fsize) + Lf->off_def = 1; + else { + Lf->sz = (SZOFFTYPE)r.r_size; + Lf->sz_def = 1; + } + break; + +#if solaris>=100000 + case N_NFS4: + if ((type == VCHR || type == VBLK) && !Fsize) + Lf->off_def = 1; + else { + 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; + } + } else if ((type == VCHR || type == VBLK) && !Fsize) + Lf->off_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; + } else if ((type == VCHR || type == VBLK) && !Fsize) + Lf->off_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: + if (!Fsize) + Lf->off_def = 1; + 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; + } else if ((type == VCHR || type == VBLK) && !Fsize) + Lf->off_def = 1; + 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; + } else if ((type == VCHR || type == VBLK) && !Fsize) + Lf->off_def = 1; + } + break; +#endif /* defined(HAS_ZFS) */ + + } + } +/* + * Record link count. + */ + +#if !defined(HASXOPT) + if (Fnlink) +#endif /* !defined(HASXOPT) */ + + { + 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((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((KA_T)nn.nm_mountpt, &fv) && fv.v_vfsp) { + if ((nvfs = readvfs((KA_T)fv.v_vfsp, (struct vfs *)NULL, + nn.nm_filevp)) + && !nvfs->dir) + { + (void) completevfs(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: + ty ="VNON"; + Lf->dev = dev; + Lf->dev_def = devs; + Lf->rdev = rdev; + Lf->rdev_def = rdevs; + break; + case VREG: + case VDIR: + ty = (type == VREG) ? "VREG" : "VDIR"; + Lf->dev = dev; + Lf->dev_def = devs; + Lf->rdev = rdev; + Lf->rdev_def = rdevs; + break; + case VBLK: + ty = "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) { + ty = "unix"; + break; + } + ty = "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; + ty = "DOOR"; + if (dns) + (void) idoorkeep(&dn); + break; +#endif /* solaris>=20500 */ + + case VLNK: + ty = "VLNK"; + Lf->dev = dev; + Lf->dev_def = devs; + Lf->rdev = rdev; + Lf->rdev_def = rdevs; + break; + +#if solaris>=100000 + case VPORT: + ty = "PORT"; + 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; + ty = (char *)NULL; + break; +#endif /* solaris>=20600 */ + +#if defined(HAS_VSOCK) + case VSOCK: + +# if solaris>=20600 + if (so.so_family == AF_UNIX) { + ty = "unix"; + if (Funix) + Lf->sf |= SELUNX; + } else { + if (so.so_family == AF_INET) { + +# if defined(HASIPv6) + ty = "IPv4"; +# else /* !defined(HASIPv6) */ + ty = "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) { + ty = "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 { + ty = "sock"; + (void) printunkaf(so.so_family, 0); + ep = endnm(&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: + ty = "VBAD"; + Lf->dev = dev; + Lf->dev_def = devs; + Lf->rdev = rdev; + Lf->rdev_def = rdevs; + break; + case VFIFO: + ty = "FIFO"; + 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; + (void) snpf(Lf->type, sizeof(Lf->type), "%04o", (type & 0xfff)); + ty = (char *)NULL; + } + if (ty) + (void) snpf(Lf->type, sizeof(Lf->type), "%s", ty); + Lf->ntype = Ntype; +/* + * 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(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(); +#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(); + /* + * 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(devs ? &dev : &DevDev, + rdevs ? &rdev : &Lf->dev, + LOOKDEV_CLONE); + else + sdp = finddev(devs ? &dev : &DevDev, + rdevs ? &rdev : &Lf->dev, + LOOKDEV_PSEUDO); + if (!sdp) + sdp = finddev(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))) { + (void) fprintf(stderr, + "%s: no space for (COMMON): PID %d; FD %s\n", + Pn, Lp->pid, Lf->fd); + Exit(1); + } + (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(NULL, Ntype, type, 1)) + Lf->sf |= SELNM; + if (trdevs) { + Lf->rdev = rdev; + Lf->rdev_def = tdef; + } + } + } +/* + * Enter name characters. + */ + if (Namech[0]) + enter_nm(Namech); +} + + +/* + * read_cni() - read common snode information + */ + +static int +read_cni(s, rv, v, rs, di, din, dinl) + 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((KA_T)v->v_data, (KA_T)s->s_commonvp, rv)) + return(1); + if (read_nsn((KA_T)s->s_commonvp, (KA_T)rv->v_data, rs)) + return(1); + *din = '\0'; + if (rs->s_dip) { + if (kread((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(Namech); + return(1); + } + if (di->devi_name + && kread((KA_T)di->devi_name, din, dinl-1) == 0) + din[dinl-1] = '\0'; + } + return(0); +} + + +/* + * readinode() - read inode + */ + +static int +readinode(ia, i) + KA_T ia; /* inode kernel address */ + struct inode *i; /* inode buffer */ +{ + if (kread((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(Namech); + return(1); + } + return(0); +} + + +#if solaris>=20500 +/* + * read_ndn() - read node's door node + */ + +static int +read_ndn(na, da, dn) + 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((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(Namech); + return(1); + } + return(0); +} +#endif /* solaris>=20500 */ + + + +/* + * read_mi() - read stream's module information + */ + +static void +read_mi(s, rdev, so, so_st, so_ad, sdp) + 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((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(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(&DevDev, rdev, LOOKDEV_CLONE))) + dp = finddev(&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(qp, (char *)&q, sizeof(q))) + break; + if ((ka = (KA_T)q.q_qinfo) == (KA_T)NULL + || kread(ka, (char *)&qi, sizeof(qi))) + continue; + if ((ka = (KA_T)qi.qi_minfo) == (KA_T)NULL + || kread(ka, (char *)&mi, sizeof(mi))) + continue; + if ((ka = (KA_T)mi.mi_idname) == (KA_T)NULL + || kread(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((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(na, aa, rn) + 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((KA_T)aa, (char *)rn, sizeof(struct autonode))) +# else /* solaris>=20600 */ + if (!aa || kread((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(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(na, ca, cn) + 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((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(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(ty, na, ca, cn) + 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(Namech); + return(1); + } + if (!ca || kread((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(Namech); + return(1); + } + return(0); +} +#endif /* solaris>=100000 */ + + +/* + * read_nfn() - read node's fifonode + */ + +static int +read_nfn(na, fa, f) + KA_T na; /* containing node's address */ + KA_T fa; /* fifonode address */ + struct fifonode *f; /* fifonode receiver */ +{ + char tbuf[32]; + + if (!fa || readfifonode(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(Namech); + return(1); + } + return(0); +} + + +/* + * read_nhn() - read node's High Sierra node + */ + +static int +read_nhn(na, ha, h) + KA_T na; /* containing node's address */ + KA_T ha; /* hsnode address */ + struct hsnode *h; /* hsnode receiver */ +{ + char tbuf[32]; + + if (!ha || readhsnode(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(Namech); + return(1); + } + return(0); +} + + +/* + * read_nin() - read node's inode + */ + +static int +read_nin(na, ia, i) + KA_T na; /* containing node's address */ + KA_T ia; /* kernel inode address */ + struct inode *i; /* inode receiver */ +{ + char tbuf[32]; + + if (!ia || readinode(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(Namech); + return(1); + } + return(0); +} + + +/* + * read_nln(na, la, ln) - read node's loopback node + */ + +static int +read_nln(na, la, ln) + 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((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(Namech); + return(1); + } + return(0); +} + + +/* + * read_nnn() - read node's namenode + */ + +static int +read_nnn(na, nna, nn) + KA_T na; /* containing node's address */ + KA_T nna; /* namenode address */ + struct namenode *nn; /* namenode receiver */ +{ + char tbuf[32]; + + if (!nna || kread((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(Namech); + 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((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(Namech); + return(1); + } + return(0); +} + + +#if defined(HASPROCFS) +/* + * read_npi() - read node's /proc file system information + */ + +static int +read_npi(na, v, pids) + 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; + pid_t prpid; + id_t prtid; + char *ty = (char *)NULL; +#endif /* solaris>=20600 */ + + if (!v->v_data || kread((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(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(Namech); + Lf->inode = (INODETYPE)PR_ROOTINO; + Lf->inp_ty = 1; + } else { + (void) snpf(Namech, Namechl - 1, "/%s/", HASPROCFS); + Namech[Namechl - 1] = '\0'; + enter_nm(Namech); + Lf->inp_ty = 0; + } + return(0); + } + if (kread((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(Namech); + return(1); + } + if (p.p_as && !kread((KA_T)p.p_as, (char *)&as, sizeof(as))) { + Lf->sz = (SZOFFTYPE)as.a_size; + Lf->sz_def = 1; + } + if (!p.p_pidp + || kread((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(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((KA_T)pr.pr_common, (char *)&pc, sizeof(pc)) == 0) { + pcs = 1; + if (pc.prc_proc + && kread((KA_T)pc.prc_proc, (char *)&p, sizeof(p)) == 0) + prpcs = 1; + else + prpcs = 0; + } else + pcs = prpcs = 0; + if (pr.pr_pcommon + && kread((KA_T)pr.pr_pcommon, (char *)&ppc, sizeof(ppc)) == 0) { + ppcs = 1; + if (ppc.prc_proc + && kread((KA_T)ppc.prc_proc, (char *)&pp, sizeof(pp)) == 0) + prppcs = 1; + else + prppcs = 0; + } else + ppcs = prppcs = 0; + if (pcs && pc.prc_pid) + pids->pid_id = prpid = pc.prc_pid; + else if (ppcs && ppc.prc_pid) + pids->pid_id = prpid = ppc.prc_pid; + else + pids->pid_id = prpid = (pid_t)0; + if (pcs && pc.prc_tid) + prtid = pc.prc_tid; + else if (ppcs && ppc.prc_tid) + prtid = ppc.prc_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); + ty = "PDIR"; + break; + case PR_PIDDIR: + (void) snpf(Namech, Namechl - 1, "/%s/%d", HASPROCFS, (int)prpid); + ty = "PDIR"; + break; + case PR_AS: + (void) snpf(Namech, Namechl - 1, + "/%s/%d/as", HASPROCFS, (int)prpid); + ty = "PAS"; + if (prpcs + && kread((KA_T)pc.prc_proc, (char *)&p, sizeof(p)) == 0 + && p.p_as + && kread((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); + ty = "PCTL"; + break; + case PR_STATUS: + (void) snpf(Namech, Namechl - 1, + "/%s/%d/status", HASPROCFS, (int)prpid); + ty = "PSTA"; + break; + case PR_LSTATUS: + (void) snpf(Namech, Namechl - 1, + "/%s/%d/lstatus", HASPROCFS, (int)prpid); + ty = "PLST"; + break; + case PR_PSINFO: + (void) snpf(Namech, Namechl - 1, + "/%s/%d/psinfo", HASPROCFS, (int)prpid); + ty = "PSIN"; + break; + case PR_LPSINFO: + (void) snpf(Namech, Namechl - 1, + "/%s/%d/lpsinfo", HASPROCFS, (int)prpid); + ty = "PLPI"; + break; + case PR_MAP: + (void) snpf(Namech, Namechl - 1, + "/%s/%d/map", HASPROCFS, (int)prpid); + ty = "PMAP"; + break; + case PR_RMAP: + (void) snpf(Namech, Namechl - 1, + "/%s/%d/rmap", HASPROCFS, (int)prpid); + ty = "PRMP"; + break; + case PR_XMAP: + (void) snpf(Namech, Namechl - 1, + "/%s/%d/xmap", HASPROCFS, (int)prpid); + ty = "PXMP"; + break; + case PR_CRED: + (void) snpf(Namech, Namechl - 1, + "/%s/%d/cred", HASPROCFS, (int)prpid); + ty = "PCRE"; + break; + case PR_SIGACT: + (void) snpf(Namech, Namechl - 1, + "/%s/%d/sigact", HASPROCFS, (int)prpid); + ty = "PSGA"; + break; + case PR_AUXV: + (void) snpf(Namech, Namechl - 1, + "/%s/%d/auxv", HASPROCFS, (int)prpid); + ty = "PAXV"; + break; + +# if defined(HASPR_LDT) + case PR_LDT: + (void) snpf(Namech, Namechl - 1, + "/%s/%d/ldt", HASPROCFS, (int)prpid); + ty = "PLDT"; + break; +# endif /* defined(HASPR_LDT) */ + + case PR_USAGE: + (void) snpf(Namech, Namechl - 1, + "/%s/%d/usage", HASPROCFS, (int)prpid); + ty = "PUSG"; + break; + case PR_LUSAGE: + (void) snpf(Namech, Namechl - 1, + "/%s/%d/lusage", HASPROCFS, (int)prpid); + ty = "PLU"; + break; + case PR_PAGEDATA: + (void) snpf(Namech, Namechl - 1, + "/%s/%d/pagedata", HASPROCFS, (int)prpid); + ty = "PGD"; + break; + case PR_WATCH: + (void) snpf(Namech, Namechl - 1, + "/%s/%d/watch", HASPROCFS, (int)prpid); + ty = "PW"; + break; + case PR_CURDIR: + (void) snpf(Namech, Namechl - 1, + "/%s/%d/cwd", HASPROCFS, (int)prpid); + ty = "PCWD"; + break; + case PR_ROOTDIR: + (void) snpf(Namech, Namechl - 1, + "/%s/%d/root", HASPROCFS, (int)prpid); + ty = "PRTD"; + break; + case PR_FDDIR: + (void) snpf(Namech, Namechl - 1, + "/%s/%d/fd", HASPROCFS, (int)prpid); + ty = "PFDR"; + break; + case PR_FD: + (void) snpf(Namech, Namechl - 1, + "/%s/%d/fd/%d", HASPROCFS, (int)prpid, + pr.pr_index); + ty = "PFD"; + break; + case PR_OBJECTDIR: + (void) snpf(Namech, Namechl - 1, + "/%s/%d/object", HASPROCFS, (int)prpid); + ty = "PODR"; + break; + case PR_OBJECT: + (void) snpf(Namech, Namechl - 1, + "/%s/%d/object/", HASPROCFS, (int)prpid); + ty = "POBJ"; + break; + case PR_LWPDIR: + (void) snpf(Namech, Namechl - 1, + "/%s/%d/lpw", HASPROCFS, (int)prpid); + ty = "PLDR"; + break; + case PR_LWPIDDIR: + (void) snpf(Namech, Namechl, + "/%s/%d/lwp/%d", HASPROCFS, (int)prpid, (int)prtid); + ty = "PLDR"; + break; + case PR_LWPCTL: + (void) snpf(Namech, Namechl - 1, "/%s/%d/lwp/%d/lwpctl", HASPROCFS, + (int)prpid, (int)prtid); + ty = "PLC"; + break; + case PR_LWPSTATUS: + (void) snpf(Namech, Namechl - 1, + "/%s/%d/lwp/%d/lwpstatus", HASPROCFS, + (int)prpid, (int)prtid); + ty = "PLWS"; + break; + case PR_LWPSINFO: + (void) snpf(Namech, Namechl - 1, + "/%s/%d/lwp/%d/lwpsinfo", HASPROCFS, + (int)prpid, (int)prtid); + ty = "PLWI"; + break; + case PR_LWPUSAGE: + (void) snpf(Namech, Namechl - 1, + "/%s/%d/lwp/%d/lwpusage", HASPROCFS, + (int)prpid, (int)prtid); + ty = "PLWU"; + break; + case PR_XREGS: + (void) snpf(Namech, Namechl - 1, "/%s/%d/lwp/%d/xregs", HASPROCFS, + (int)prpid, (int)prtid); + ty = "PLWX"; + break; + +# if defined(HASPR_GWINDOWS) + case PR_GWINDOWS: + (void) snpf(Namech, Namechl - 1, + "/%s/%d/lwp/%d/gwindows", HASPROCFS, + (int)prpid, (int)prtid); + ty = "PLWG"; + break; +# endif /* defined(HASPR_GWINDOWS) */ + + case PR_PIDFILE: + (void) snpf(Namech, Namechl - 1, "/%s/%d", HASPROCFS, (int)prpid); + ty = "POPF"; + break; + case PR_LWPIDFILE: + (void) snpf(Namech, Namechl - 1, "/%s/%d", HASPROCFS, (int)prpid); + ty = "POLP"; + break; + case PR_OPAGEDATA: + (void) snpf(Namech, Namechl - 1, "/%s/%d", HASPROCFS, (int)prpid); + ty = "POPG"; + break; + default: + ty = (char *)NULL; + } + if (ty) + (void) snpf(Lf->type, sizeof(Lf->type), "%s", ty); + else + (void) snpf(Lf->type, sizeof(Lf->type), "%04o", + (pr.pr_type & 0xfff)); +/* + * 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(Namech); + return(0); +} +#endif /* defined(HASPROCFS) */ + + +/* + * read_npn() - read node's pcnode + */ + +static int +read_npn(na, pa, p) + KA_T na; /* containing node's address */ + KA_T pa; /* pcnode address */ + struct pcnode *p; /* pcnode receiver */ +{ + char tbuf[32]; + + if (!pa || kread(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(Namech); + return(1); + } + return(0); +} + + +#if solaris>=100000 +/* + * read_nprtn() - read node's port node + */ + +static int +read_nprtn(na, pa, p) + 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(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(Namech); + return(1); + } + return(0); +} +#endif /* solaris>=100000 */ + + +/* + * read_nrn() - read node's rnode + */ + +static int +read_nrn(na, ra, r) + KA_T na; /* containing node's address */ + KA_T ra; /* rnode address */ + struct rnode *r; /* rnode receiver */ +{ + char tbuf[32]; + + if (!ra || readrnode(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(Namech); + return(1); + } + return(0); +} + + +#if solaris>=100000 +/* + * read_nrn4() - read node's rnode4 + */ + +static int +read_nrn4(na, ra, r) + KA_T na; /* containing node's address */ + KA_T ra; /* rnode address */ + struct rnode4 *r; /* rnode receiver */ +{ + char tbuf[32]; + + if (!ra || + kread((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(Namech); + return(1); + } + return(0); +} +#endif /* solaris>=100000 */ + + +#if solaris>=110000 +/* + * read_nsdn() - read node's sdev_node + */ + +static int +read_nsdn(na, sa, sdn, sdva) + KA_T na; /* containing node's adress */ + 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((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(Namech); + return(1); + } + if (!(va = (KA_T)sdn->sdev_attr) + || kread(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(Namech); + return(1); + } + return(0); +} +#endif /* solaris>=110000 */ + + +#if solaris>=20600 +/* + * read_nson() - read node's sonode + */ + +static int +read_nson(na, sa, sn) + KA_T na; /* containing node's address */ + KA_T sa; /* sonode address */ + struct sonode *sn; /* sonode receiver */ + +{ + char tbuf[32]; + + if (!sa || kread((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(Namech); + return(1); + } + return(0); +} +#endif /* solaris>=20600 */ + + +/* + * read_nsn() - read node's snode + */ + +static int +read_nsn(na, sa, s) + KA_T na; /* containing node's address */ + KA_T sa; /* snode address */ + struct snode *s; /* snode receiver */ +{ + char tbuf[32]; + + if (!sa || readsnode(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(Namech); + return(1); + } + return(0); +} + + +#if solaris>=110000 +/* + * read_nsti() - read socket node's info + */ + +static int +read_nsti(so, stpi) + struct sonode *so; /* socket's sonode */ + sotpi_info_t *stpi; /* local socket info receiver */ +{ + char tbuf[32]; + + (void) CTF_init(&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(Namech); + return(1); + } + return(0); +} +#endif /* solaris>=110000 */ + + +/* + * read_ntn() - read node's tmpnode + */ + +static int +read_ntn(na, ta, t) + KA_T na; /* containing node's address */ + KA_T ta; /* tmpnode address */ + struct tmpnode *t; /* tmpnode receiver */ +{ + char tbuf[32]; + + if (!ta || readtnode(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(Namech); + return(1); + } + return(0); +} + + +#if solaris>=20600 +/* + * read_nusa() - read sondode's UNIX socket address + */ + +static int +read_nusa(so, ua) + 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(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(na, va, v) + KA_T na; /* node's address */ + KA_T va; /* vnode address */ + struct vnode *v; /* vnode receiver */ +{ + char tbuf[32]; + + if (readvnode(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(Namech); + return(1); + } + return(0); +} + + +#if defined(HAS_ZFS) +/* + * read_nzn() - read node's ZFS node + */ + +static int +read_nzn(na, nza, zn) + 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(&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(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(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(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(Namech); + err = 1; + } + } + return(err); +} + + +/* + * read_nznp() - read znode's persistent znode + */ + +static int +read_nznp(nza, nzpa, zp) + 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(&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(Namech); + return(1); + } + return(0); +} + + +/* + * read_nzvfs() - read znode's associated vfs + */ + +static int +read_nzvfs(nza, nzva, zv) + 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(&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(Namech); + return(1); + } + return(0); +} +#endif /* defined(HAS_ZFS) */ + + +#if solaris<100000 +/* + * savesockmod() - save addresses from sockmod so_so structure + */ + +static void +savesockmod(so, sop, so_st) + 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(vp, fx) + 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]); + Exit(1); + } + *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(na, da, dv, dev, devs) + 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((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(Namech); + return(1); + } +/* + * Read the snode's real vnode. + */ + if (!s.s_realvp + || kread((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(Namech); + return(1); + } +/* + * Read the real vnode's dv_node. + */ + if (!rv.v_data || kread((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(Namech); + return(1); + } +/* + * Return the device number of the underlying file system, if possible. + */ + if (rv.v_vfsp && !kread((KA_T)rv.v_vfsp, (char *)&v, sizeof(v))) { + *dev = v.vfs_dev; + *devs = 1; + } + return(0); +} +#endif /* solaris<100000 */ diff --git a/dialects/sun/dnode1.c b/dialects/sun/dnode1.c new file mode 100644 index 0000000..ac279e5 --- /dev/null +++ b/dialects/sun/dnode1.c @@ -0,0 +1,441 @@ +/* + * 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"; +static char *rcsid = "$Id: dnode1.c,v 1.9 2005/08/08 19:55:41 abe Exp $"; +#endif + + +#if defined(HAS_AFS) +#include "lsof.h" + +#include +#define __XDR_INCLUDE__ +#define int32 old_solaris_int32 + +# if solaris>=20600 +#undef SHARED +#undef PRIVATE +# endif /* solaris>=20600 */ + +#include +#include +#include + + +/* + * 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 +#undef KERNEL + + +/* + * Local function prototypes + */ + +_PROTOTYPE(static struct volume *getvolume,(struct VenusFid *f, int *vols)); +_PROTOTYPE(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; + 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(f, vols) + 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(kh, (char *)&vp, sizeof(vp))) + return((struct volume *)NULL); + while (vp) { + if (kread((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(vp) + 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((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(vc, rfid) + 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(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(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(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; + 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/dialects/sun/dnode2.c b/dialects/sun/dnode2.c new file mode 100644 index 0000000..9d6a94f --- /dev/null +++ b/dialects/sun/dnode2.c @@ -0,0 +1,518 @@ +/* + * 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"; +static char *rcsid = "$Id: dnode2.c,v 1.23 2010/01/18 19:03:54 abe Exp $"; +#endif + + +#include "lsof.h" + +#if defined(HASVXFS) + +# if defined(HASVXFSUTIL) +#include +#define EMSGPFX "vx_inode: " + +_PROTOTYPE(static char *add2em,(char * em, char *fmt, char *arg)); +_PROTOTYPE(static char *ckptr,(char * em, char *ptr, int len, int slen, + char *nm)); +_PROTOTYPE(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 +# endif /* defined(HASVXFS_FS_H) && !defined(HASVXFS_VX_INODE) */ + +# if HASVXFS_SOL_H +#include +# endif /* defined(HSVXFS_SOL_H) */ + +# if defined(HASVXFS_SOLARIS_H) && defined(HASVXFS_U64_T) +#include +# 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 +# endif /* defined(HASVXFS_MACHDEP_H) */ + +# if defined(HASVXFS_SOLARIS_H) +struct kdm_vnode { /* dummy for */ + 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 +# endif /* defined(HASVXFS_SOLARIS_H) && !defined(HASVXFS_U64_T) */ + +#include +#include +#include +# endif /* defined(HASVXFS_SOLARIS_H) */ + +#include +# 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(em, fmt, arg) + 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); + Exit(1); + } + al = eml + nl + 3; + em = (char *)realloc((MALLOC_P *)em, al); + } + if (!em) { + (void) fprintf(stderr, "%s: no VxFS error message space\n", Pn); + Exit(1); + } + (void) snpf(em + eml, al - eml, "%s%s%s", + eml ? "" : EMSGPFX, + eml ? "; " : "", + msg); + return(em); +} + + +/* + * ckptr() - check pointer and length + */ + +static char * +ckptr(em, ptr, len, slen, nm) + 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(vx, vxl, dev, devl, ino, inol, nl, nll, sz, szl) + 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); + Exit(1); + } + *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(lf) + 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); + Exit(1); + } + } + 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(va, v, vfs, fx, li, vnops) + 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((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(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(Namech); + return(1); + } +# endif /* !defined(HASVXFSUTIL) */ + +/* + * Read vnode's vx_inode. + */ + if (!v->v_data || kread((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(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/dialects/sun/dproc.c b/dialects/sun/dproc.c new file mode 100644 index 0000000..eecdf1f --- /dev/null +++ b/dialects/sun/dproc.c @@ -0,0 +1,2239 @@ +/* + * 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"; +static char *rcsid = "$Id: dproc.c,v 1.36 2010/01/18 19:03:54 abe Exp $"; +#endif + +#include "lsof.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 + +# 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 + */ + +_PROTOTYPE(static void get_kernel_access,(void)); +_PROTOTYPE(static void process_text,(KA_T pa)); +_PROTOTYPE(static void read_proc,(void)); +_PROTOTYPE(static void readfsinfo,(void)); + +#if solaris>=20501 +_PROTOTYPE(static void readkam,(KA_T addr)); +#endif /* solaris>=20501 */ + +#if solaris>=20501 && solaris<70000 +_PROTOTYPE(extern u_longlong_t kvm_physaddr,(kvm_t *, struct as *, u_int)); +#endif /* solaris>=20501 && solaris<70000 */ + +#if defined(HASZONES) +_PROTOTYPE(static int hash_zn,(char *zn)); +#endif /* defined(HASZONES) */ + + + +/* + * close_kvm() - close kernel virtual memory access + */ + +void +close_kvm() +{ + if (!Kd) + return; + if (Kd) { + if (kvm_close(Kd) != 0) { + (void) fprintf(stderr, "%s: kvm_close failed\n", Pn); + Exit(1); + } + 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() +{ + 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("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(); + open_kvm(); + +#if solaris>=20501 + /* + * If not the first time and the ALLKMEM device isn't available, + * re-read the kernel's address space map. + */ + readkam((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(); +/* + * 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((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(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((KA_T)p->p_zone, (char *)&z, sizeof(z))) + { + if (!z.zone_name + || kread((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(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(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); + Exit(1); + } + } + 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); + Exit(1); + } + 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); + Exit(1); + } + 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(CWD, -1); + +#if defined(FILEPTR) + FILEPTR = (struct file *)NULL; +#endif /* defined(FILEPTR) */ + + process_node((KA_T)u->u_cdir); + if (Lf->sf) + link_lfile(); + } + /* + * Save root directory information. + */ + if (!ckscko && u->u_rdir) { + alloc_lfile(RTD, -1); + +#if defined(FILEPTR) + FILEPTR = (struct file *)NULL; +#endif /* defined(FILEPTR) */ + + process_node((KA_T)u->u_rdir); + if (Lf->sf) + link_lfile(); + } + /* + * Save information on text files. + */ + if (!ckscko && p->p_as && Sgvops) { + +#if defined(FILEPTR) + FILEPTR = (struct file *)NULL; +#endif /* defined(FILEPTR) */ + + process_text((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((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((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((char *)NULL, i); + +#if solaris<20400 + pofv = (long)u->u_flist.uf_pofile[j-1]; + process_file((KA_T)u->u_flist.uf_ofile[j-1]); +#else /* solaris>=20400 */ + pofv = uf[j-1].uf_pofile; + process_file((KA_T)uf[j-1].uf_ofile); +#endif /* solaris <20400 */ + + if (Lf->sf) { + +#if defined(HASFSTRUCT) + if (Fsv & FSV_FG) + Lf->pof = pofv; +#endif /* defined(HASFSTRUCT) */ + + link_lfile(); + } + } + /* + * Examine results. + */ + if (examine_lproc()) + return; + } +} + + +/* + * get_kernel_access() - access the required information in the kernel + */ + +static void +get_kernel_access() +{ + 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("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)); + Exit(1); + } + 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); + Exit(1); + } + } +#endif /* solaris>=70000 */ + +/* + * Get kernel symbols. + */ + if (Nmlst && !is_readable(Nmlst, 1)) + Exit(1); + (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 + * modload file. + */ + if (!(nl = (struct nlist *)malloc(Nll))) { + (void) fprintf(stderr, "%s: no space (%d) for Nl[] copy\n", + Pn, Nll); + Exit(1); + } + (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); + Exit(1); + } + +#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("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((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(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(); +#else /* !defined(WILLDROPGID) */ +/* + * See if the non-KMEM memory file is readable. + */ + if (Memory && !is_readable(Memory, 1)) + Exit(1); +#endif /* defined(WILLDROPGID) */ + +/* + * Open access to kernel memory. + */ + open_kvm(); + +#if solaris>=20500 +/* + * Get the kernel's KERNELBASE value for Solaris 2.5 and above. + */ + v = (KA_T)0; + if (get_Nl_value("kbase", Drive_Nl, &v) < 0 || !v + || kread((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)); + Exit(1); + } +#endif /* solaris>=20500 */ + +/* + * Get the Solaris clone major device number, if possible. + */ + v = (KA_T)0; + if ((get_Nl_value("clmaj", Drive_Nl, &v) < 0) || !v) { + if (get_Nl_value("clmaj_alt", Drive_Nl, &v) < 0) + v = (KA_T)0; + } + if (v && kread((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("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("kasp", Drive_Nl, &v) >= 0 && v) { + PageSz = getpagesize(); + PSMask = PageSz - 1; + for (i = 1, PSShft = 0; i < PageSz; i <<= 1, PSShft++) + ; + (void) readkam(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(); +#endif /* defined(WILLDROPGID) */ + +} + + +#if defined(HASZONES) +/* + * enter_zone_arg() - enter zone name argument + */ + +int +enter_zone_arg(zn) + 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); + Exit(1); + } + } +/* + * 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); + Exit(1); + } + zpn->f = 0; + zpn->zn = zn; + zpn->next = ZoneArg[zh]; + ZoneArg[zh] = zpn; + return(0); +} + + +/* + * hash_zn() - hash zone name + */ + +static int +hash_zn(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() +{ + get_kernel_access(); +/* + * Read Solaris file system information and construct the clone table. + * + * The clone table is needed to identify sockets. + */ + readfsinfo(); + +#if defined(HASDCACHE) + readdev(0); +#else /* !defined(HASDCACHE) */ + read_clone(); +#endif /*defined(HASDCACHE) */ + +} + + +/* + * kread() - read from kernel memory + */ + +int +kread(addr, buf, len) + KA_T addr; /* kernel memory address */ + char *buf; /* buffer to receive data */ + READLEN_T len; /* length to read */ +{ + 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); + Exit(1); + } + 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() +{ + if (Kd) + return; + +#if defined(WILLDROPGID) +/* + * If this Solaris process began with setgid permission and its been + * surrendered, regain it. + */ + (void) restoregid(); +#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)); + Exit(1); + } + +#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)); + Exit(1); + } +#endif /* solaris>=20501 && solaris<70000 */ + +#if defined(WILLDROPGID) +/* + * If this process has setgid permission, and is willing to surrender it, + * do so. + */ + (void) dropgid(); +/* + * 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 + +/* + * 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 . + */ + +#define READ_AVL_NODE(n,o,s) \ + if (kread((KA_T)AVL_NODE2DATA(n, o), (char*) s, sizeof(*s))) \ + return -1 + +static int +get_first_seg(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(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(pa) + 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((KA_T)pa, (char *)&as, sizeof(as))) { + alloc_lfile(" txt", -1); + (void) snpf(Namech, Namechl, "can't read text segment list (%s)", + print_kptr(pa, (char *)NULL, 0)); + enter_nm(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 (avtp = &as.a_segtree, i = j = 0; + (i < MAXSEGS) && (j < 2*MAXSEGS); + j++) + { + if (j ? get_next_seg(avtp, &s) : get_first_seg(avtp, &s)) + break; + if ((KA_T)s.s_ops == Sgvops && s.s_data) { + if (kread((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(" txt", -1); + +# if defined(FILEPTR) + FILEPTR = (struct file *)NULL; +# endif /* defined(FILEPTR) */ + + process_node((KA_T)vn.vp); + if (Lf->sf) + link_lfile(); + } + } + } + } +} + +#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(pa) + 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((KA_T)pa, (char *)&as, sizeof(as))) { + alloc_lfile(" txt", -1); + (void) snpf(Namech, Namechl, "can't read text segment list (%s)", + print_kptr(pa, (char *)NULL, 0)); + enter_nm(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((KA_T)s.S_NEXT, (char *)&s, sizeof(s))) + break; + if ((KA_T)s.s_ops == Sgvops && s.s_data) { + if (kread((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(" txt", -1); + +# if defined(FILEPTR) + FILEPTR = (struct file *)NULL; +# endif /* defined(FILEPTR) */ + + process_node((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() +{ + char buf[FSTYPSZ+1]; + int i, len; + + if ((Fsinfomax = sysfs(GETNFSTYP)) == -1) { + (void) fprintf(stderr, "%s: sysfs(GETNFSTYP) error: %s\n", + Pn, strerror(errno)); + Exit(1); + } + if (Fsinfomax == 0) + return; + if (!(Fsinfo = (char **)malloc((MALLOC_S)(Fsinfomax * sizeof(char *))))) + { + (void) fprintf(stderr, "%s: no space for sysfs info\n", Pn); + Exit(1); + } + for (i = 1; i <= Fsinfomax; i++) { + if (sysfs(GETFSTYP, i, buf) == -1) { + (void) fprintf(stderr, "%s: sysfs(GETFSTYP) error: %s\n", + Pn, strerror(errno)); + Exit(1); + } + 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); + Exit(1); + } + (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(addr) + 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(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 *))); + Exit(1); + } + } 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() +{ + 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("nproc", Drive_Nl, &pa) < 0 || !pa + || kread(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); + Exit(1); + } + /* + * 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); + Exit(1); + } + } + 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); + Exit(1); + } + Npa = n; + } + if (HasALLKMEM) { + + /* + * Prepare for a proc table scan via direct reading of the active + * chain. + */ + if (!PrAct || kread(PrAct, (char *)&paf, sizeof(pa))) { + (void) fprintf(stderr, "%s: can't read practive from %s\n", + Pn, print_kptr(PrAct, (char *)NULL, 0)); + Exit(1); + } + 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)); + Exit(1); + } + } + /* + * 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); + Exit(1); + } + /* + * 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); + Exit(1); + } + } + if (!(Pid = (int *)realloc((MALLOC_P *)Pid, len))) { + (void) fprintf(stderr, + "%s: no more (%d) PID space\n", Pn, Npa); + Exit(1); + } + } + /* + * 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(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((KA_T)p->p_pgidp, (char *)&pg, sizeof(pg))) + continue; + } + if (!p->p_pidp + || kread((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(); + open_kvm(); + } + } +/* + * 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); + Exit(1); + } + 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); + Exit(1); + } + /* + * 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); + Exit(1); + } + } + if (!(Pid = (int *)realloc((MALLOC_P *)Pid, len))) { + (void) fprintf(stderr, + "%s: can't reduce PID table to %d\n", Pn, Np); + Exit(1); + } + Npa = Np; + } +} + + +#if defined(WILLDROPGID) +/* + * restoregid() -- restore setgid permission, as required + */ + +void +restoregid() +{ + 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)); + Exit(1); + } + 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[] */ + +_PROTOTYPE(static struct l_nch *ncache_addr,(KA_T v)); + +#define ncachehash(v) Nchash+((((int)(v)>>2)*31415)&Mhl) + +_PROTOTYPE(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(v) + 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(va, cp) + 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((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); + Exit(1); + } + } + 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(X_NCSIZE, (struct drive_Nl *)NULL, &v) < 0 + || !v + || kread((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(NCACHE_NEGVN, (struct drive_Nl *)NULL, &NegVN) + < 0) + NegVN = (KA_T)NULL; + /* + * Establish DNLC hash address. + */ + v = (KA_T)0; + if (get_Nl_value(X_NCACHE,(struct drive_Nl *)NULL,(KA_T *)&v) < 0 + || !v + || kread(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); + Exit(1); + } + /* + * 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); + Exit(1); + } + 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("hshav", (struct drive_Nl *)NULL, (KA_T *)&v) < 0) + || !v + || kread(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); + Exit(1); + } + } 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(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(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); + Exit(1); + } + } + cp = &nc->name[XNC + 1]; + v = (KA_T)((char *)kn + nmo + XNC + 1); + xl = len - XNC - 1; + if (kread(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); + Exit(1); + } + (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); + Exit(1); + } + 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); + Exit(1); + } + 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(buf, blen, fp) + 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/dialects/sun/dproto.h b/dialects/sun/dproto.h new file mode 100644 index 0000000..fd6cb2c --- /dev/null +++ b/dialects/sun/dproto.h @@ -0,0 +1,109 @@ +/* + * 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) +_PROTOTYPE(extern int access_vxfs_ioffsets,(void)); +#endif /* defined(HASVXFSUTIL) */ + +_PROTOTYPE(extern void completevfs,(struct l_vfs *vfs, dev_t *dev)); + +# if defined(HAS_LIBCTF) +_PROTOTYPE(extern int CTF_getmem,(ctf_file_t *f, const char *mod, + const char *ty, CTF_member_t *mem)); +_PROTOTYPE(extern void CTF_init,(int *i, char *t, CTF_request_t *r)); +_PROTOTYPE(extern int CTF_memCB,(const char *name, ctf_id_t id, ulong_t offset, + void *arg)); +# endif /* defined(HAS_LIBCTF) */ + +_PROTOTYPE(extern int is_file_named,(char *p, int nt, enum vtype vt, int ps)); +_PROTOTYPE(extern struct l_vfs *readvfs,(KA_T ka, struct vfs *la, struct vnode *lv)); +_PROTOTYPE(extern int vop2ty,(struct vnode *vp, int fx)); + +#if defined(HAS_AFS) +_PROTOTYPE(extern struct vnode *alloc_vcache,(void)); +_PROTOTYPE(extern void ckAFSsym,(struct nlist *nl)); +_PROTOTYPE(extern int hasAFS,(struct vnode *vp)); +_PROTOTYPE(extern int readafsnode,(KA_T va, struct vnode *v, struct afsnode *an)); +#endif /* defined(HAS_AFS) */ + +#if defined(HASDCACHE) +_PROTOTYPE(extern int rw_clone_sect,(int m)); +_PROTOTYPE(extern void clr_sect,(void)); +_PROTOTYPE(extern int rw_pseudo_sect,(int m)); +#endif /* defined(HASDCACHE) */ + +#if defined(HASIPv6) +_PROTOTYPE(extern struct hostent *gethostbyname2,(const char *nm, int proto)); +#endif /* defined(HASIPv6) */ + +#if defined(HAS_V_PATH) +_PROTOTYPE(extern int print_v_path,(struct lfile *lf)); +_PROTOTYPE(extern void read_v_path,(KA_T ka, char *rb, size_t rbl)); +#endif /* defined(HAS_V_PATH) */ + +#if defined(HASVXFS) +_PROTOTYPE(extern int read_vxnode,(KA_T va, struct vnode *v, struct l_vfs *vfs, + int fx, struct l_ino *li, KA_T *vnops)); +# if defined(HASVXFSRNL) +_PROTOTYPE(extern int print_vxfs_rnl_path,(struct lfile *lf)); +# endif /* defined(HASVXFSRNL) */ +#endif /* defined(HASVXFS) */ + +#if defined(HASZONES) +_PROTOTYPE(extern int enter_zone_arg,(char *zn)); +#endif /* defined(HASZONES) */ + +_PROTOTYPE(extern void close_kvm,(void)); +_PROTOTYPE(extern void open_kvm,(void)); +_PROTOTYPE(extern void process_socket,(KA_T sa, char *ty)); + +#if solaris>=110000 +_PROTOTYPE(extern int process_VSOCK,(KA_T va, struct vnode *v, + struct sonode *so)); +#endif /* solaris>=11000 */ + +_PROTOTYPE(extern void read_clone,(void)); + +#if solaris<20500 +_PROTOTYPE(extern int get_max_fd,(void)); +#endif /* solaris<20500 */ + +#if defined(WILLDROPGID) +_PROTOTYPE(extern void restoregid,(void)); +#endif /* defined(WILLDROPGID) */ diff --git a/dialects/sun/dsock.c b/dialects/sun/dsock.c new file mode 100644 index 0000000..50eae2a --- /dev/null +++ b/dialects/sun/dsock.c @@ -0,0 +1,2089 @@ +/* + * 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"; +static char *rcsid = "$Id: dsock.c,v 1.31 2011/08/07 22:53:42 abe Exp $"; +#endif + + +#include "lsof.h" + +#if solaris>=110000 +#include +#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 + */ + +_PROTOTYPE(static int read_icmp_t,(KA_T va, KA_T ph, KA_T ia, icmp_t *ic)); +_PROTOTYPE(static int read_rts_t,(KA_T va, KA_T ph, KA_T ra, rts_t *rt)); +_PROTOTYPE(static int read_udp_t,(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 +# endif /* solaris==20600 */ +#include +#include + +# 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 + */ + +_PROTOTYPE(static void save_TCP_size,(tcp_t *tc)); +_PROTOTYPE(static void save_TCP_states,(tcp_t *tc, caddr_t *fa, tcpb_t *tb, + caddr_t *xp)); + + +/* + * build_IPstates() -- build the TCP and UDP state tables + */ + +void +build_IPstates() +{ + if (!TcpSt) { + (void) enter_IPstate("TCP", "CLOSED", TCPS_CLOSED); + (void) enter_IPstate("TCP", "IDLE", TCPS_IDLE); + (void) enter_IPstate("TCP", "BOUND", TCPS_BOUND); + (void) enter_IPstate("TCP", "LISTEN", TCPS_LISTEN); + (void) enter_IPstate("TCP", "SYN_SENT", TCPS_SYN_SENT); + (void) enter_IPstate("TCP", "SYN_RCVD", TCPS_SYN_RCVD); + (void) enter_IPstate("TCP", "ESTABLISHED", TCPS_ESTABLISHED); + (void) enter_IPstate("TCP", "CLOSE_WAIT", TCPS_CLOSE_WAIT); + (void) enter_IPstate("TCP", "FIN_WAIT_1", TCPS_FIN_WAIT_1); + (void) enter_IPstate("TCP", "CLOSING", TCPS_CLOSING); + (void) enter_IPstate("TCP", "LAST_ACK", TCPS_LAST_ACK); + (void) enter_IPstate("TCP", "FIN_WAIT_2", TCPS_FIN_WAIT_2); + (void) enter_IPstate("TCP", "TIME_WAIT", TCPS_TIME_WAIT); + (void) enter_IPstate("TCP", (char *)NULL, 0); + } + if (!UdpSt) { + (void) enter_IPstate("UDP", "Unbound", TS_UNBND); + (void) enter_IPstate("UDP", "Wait_BIND_REQ_Ack", TS_WACK_BREQ); + (void) enter_IPstate("UDP", "Wait_UNBIND_REQ_Ack", TS_WACK_UREQ); + (void) enter_IPstate("UDP", "Idle", TS_IDLE); + (void) enter_IPstate("UDP", "Wait_OPT_REQ_Ack", TS_WACK_OPTREQ); + (void) enter_IPstate("UDP", "Wait_CONN_REQ_Ack", TS_WACK_CREQ); + (void) enter_IPstate("UDP", "Wait_CONN_REQ_Confirm", TS_WCON_CREQ); + (void) enter_IPstate("UDP", "Wait_CONN_IND_Response", TS_WRES_CIND); + (void) enter_IPstate("UDP", "Wait_CONN_RES_Ack", TS_WACK_CRES); + (void) enter_IPstate("UDP", "Wait_Data_Xfr", TS_DATA_XFER); + (void) enter_IPstate("UDP", "Wait_Read_Release", TS_WIND_ORDREL); + (void) enter_IPstate("UDP", "Wait_Write_Release", TS_WREQ_ORDREL); + (void) enter_IPstate("UDP", "Wait_DISCON_REQ_Ack", TS_WACK_DREQ6); + (void) enter_IPstate("UDP", "Wait_DISCON_REQ_Ack", TS_WACK_DREQ7); + (void) enter_IPstate("UDP", "Wait_DISCON_REQ_Ack", TS_WACK_DREQ9); + (void) enter_IPstate("UDP", "Wait_DISCON_REQ_Ack", TS_WACK_DREQ10); + (void) enter_IPstate("UDP", "Wait_DISCON_REQ_Ack", TS_WACK_DREQ11); + (void) enter_IPstate("UDP", (char *)NULL, 0); + } +} + + +/* + * 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), "UNKNOWN_TCP_STATE_%d", + Lf->lts.state.i); + cp = sbuf; + } else + cp = TcpSt[i]; + break; + case 1: /* TPI */ + if (!UdpSt) + (void) build_IPstates(); + 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(va, v, so) + 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(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(Namech); + return(1); + } + enter_dev_ch(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) + ty = "IPv4"; + else + ty = "IPv6"; + (void) snpf(Lf->type, sizeof(Lf->type), ty); + + 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(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(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(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(ka, (char *)&xa, sizeof(xa)) + ) { + xp = (caddr_t *)&xa; + } + (void) save_TCP_states(&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(ka, (char *)&th, sizeof(th)) + ) { + tha = &th; + } + (void) save_TCP_states(&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(&tc); + break; + case IPPROTO_UDP: + + /* + * Process UDP socket; read its control structure. + */ + if (!(ka = (KA_T)cs.conn_proto_priv.cp_udp) + || kread(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(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(la, (int)ntohs(lp), fa, (int)ntohs(fp), af); + /* + * Save UDP state and size information. + */ + if (!Fsize) + Lf->off_def = 1; + Lf->lts.type = 1; + Lf->lts.state.ui = (unsigned int)uc.udp_state; + +# if defined(HASSOOPT) + /* + * Save UDP flags. + */ + if (Ftcptpi & TCPTPI_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(va, pha, (KA_T)cs.conn_proto_priv.cp_icmp, &ic)) + return(1); + /* + * Save ICMP size and state information. + */ + if (!Fsize) + Lf->off_def = 1; + 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(la, 0, fa, 0, af); + +# if defined(HASSOOPT) + /* + * Save ICMP flags. + */ + if (Ftcptpi & TCPTPI_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(Namech); + return(1); + } + break; + case AF_ROUTE: + + /* + * Set INET type -- IPv4 or IPv6. + */ + if (af == AF_INET) + ty = "IPv4"; + else + ty = "IPv6"; + (void) snpf(Lf->type, sizeof(Lf->type), ty); + /* + * 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(va, pha, (KA_T)cs.conn_proto_priv.cp_rts, &rt)) + return(1); + /* + /* + * Save AF_ROUTE size and state information. + */ + if (!Fsize) + Lf->off_def = 1; + 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 (Ftcptpi & TCPTPI_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((int)cs.conn_ulp); + (void) snpf(Namech, Namechl - 1, "unsupported socket family: %u", + so->so_family); + Namech[Namechl - 1] = '\0'; + enter_nm(Namech); + Lf->inp_ty = 2; + } + return(1); +} +#endif /* solaris>=110000*/ + + +/* + * process_socket() - process Solaris socket + */ + +void +process_socket(sa, ty) + 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')) { + (void) snpf(Lf->type, sizeof(Lf->type), "IPv6"); + af = AF_INET6; + } else { + (void) snpf(Lf->type, sizeof(Lf->type), "IPv4"); + af = AF_INET; + } +#else /* !defined(HASIPv6) */ + (void) snpf(Lf->type, sizeof(Lf->type), "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(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(qp, (char *)&q, sizeof(q))) + break; + if ((ka = (KA_T)q.q_qinfo) == (KA_T)NULL + || kread(ka, (char *)&qi, sizeof(qi))) + continue; + if ((ka = (KA_T)qi.qi_minfo) == (KA_T)NULL + || kread(ka, (char *)&mi, sizeof(mi)) + || (ka = (KA_T)mi.mi_idname) == (KA_T)NULL) + continue; + if (kread(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(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((KA_T)pcb, (char *)&tc, sizeof(tc))) + +# if solaris>=80000 + { + if (tc.tcp_base + && !kread((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(pcb, (char *)&cs, sizeof(cs)) + && (cs.conn_ulp == IPPROTO_TCP) + ) { + ics = 1; + if ((ka = (KA_T)cs.conn_proto_priv.cp_tcp) + && !kread(ka, (char *)&tc, sizeof(tc)) + ) { + tcs = 1; + } + } +# else /* solaris<110000 */ + if (!kread((KA_T)pcb, (char *)&ic, sizeof(ic)) + && ic.conn_tcp + && !kread((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(pcb, (char *)&uc, sizeof(uc)) == 0) + ucs = 1; +#else /* solaris>=110000 */ + if (!kread(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(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(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(la, (int)ntohs(p), (unsigned char *)NULL, + -1, af); + if (!Fsize) + Lf->off_def = 1; + 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((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(la, lp, fa, fp, af); + } + /* + * Save TCP state information. + */ + if (tcs) { + (void) save_TCP_states(&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(&tc); + } + } else + (void) strcat(Namech, "no TCP/UDP/IP information available"); +/* + * Enter name characters if there are some. + */ + if (Namech[0]) + enter_nm(Namech); +} + + +#if solaris>=110000 +/* + * read_icmp_t() - read connections icmp_t info + */ + +static int +read_icmp_t(va, ph, ia, ic) + 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(&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(Namech); + return(1); + } + +# if defined(HAS_CONN_NEW) + if ((ka = (KA_T)ic->icmp_connp) + && !kread(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(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(va, ph, ra, rt) + 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(&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(Namech); + return(1); + } + +# if defined(HAS_CONN_NEW) + if ((ka = (KA_T)rt->rts_connp) + && !kread(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(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(ua, uc) + KA_T ua; /* ucp_t kernel address */ + udp_t *uc; /* receiving udp_t structure */ +{ + (void) CTF_init(&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(Namech); + return(1); + } + return(0); +} +#endif /* solaris>=110000 */ + + +/* + * save_TCP_size() -- save TCP size information + */ + +static void + +save_TCP_size(tc) + 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 (Fsize) { + if (Lf->access == 'r') + Lf->sz = (SZOFFTYPE)rq; + else if (Lf->access == 'w') + Lf->sz = (SZOFFTYPE)sq; + else + Lf->sz = (SZOFFTYPE)(rq + sq); + Lf->sz_def = 1; + } else + Lf->off_def = 1; +#else /* !defined(HASTCPTPIQ) && !defined(HASTCPTPIW) */ + Lf->off_def = 1; +#endif /* defined(HASTCPTPIQ) || defined(HASTCPTPIW) */ + +} + + +/* + * save_TCP_states() - save TCP states + */ + +static void +save_TCP_states(tc, fa, tb, xp) + 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 (Ftcptpi & TCPTPI_FLAGS && 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 (Ftcptpi & TCPTPI_FLAGS) { + 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/dialects/sun/dstore.c b/dialects/sun/dstore.c new file mode 100644 index 0000000..345493a --- /dev/null +++ b/dialects/sun/dstore.c @@ -0,0 +1,234 @@ +/* + * 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"; +static char *rcsid = "$Id: dstore.c,v 1.23 2010/01/18 19:03:54 abe Exp $"; +#endif + + +#include "lsof.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/dialects/sun/machine.h b/dialects/sun/machine.h new file mode 100644 index 0000000..f02eff5 --- /dev/null +++ b/dialects/sun/machine.h @@ -0,0 +1,757 @@ +/* + * 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) +/* + * 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 + * and a macro in . + */ + +#include +# endif /* defined(HAS_LGRP_ROOT_CONFLICT) */ + + +# if solaris>=100000 +# if !defined(HAS_AIO_REQ_STRUCT) +/* + * When lacks one, define a dummy aio_req structure for + * Solaris >= 10 systems. + * + * If this definition causes compilation errors for , 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 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 +# endif /* solaris>=100000 */ + + +# if solaris>=20600 +/* + * must be #include'd for Solaris >= 2.6 while _KMEMUSER is + * defined. Since also #include's and + * 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 + * from colliding with + * the Solaris */ + +# 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 when _KERNEL is defined, and + * doing that causes other difficulties. + * + * So 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 +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 + +# if solaris>=80000 +#include +#include +#define _KERNEL 1 +#include +#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 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? */ +/* #define HASPRINTOFF print_off? */ +/* #define HASPRINTSZ print_sz? */ + + +/* + * HASPRIVFILETYPE and PRIVFILETYPE are defined for dialects that have a + * file structure type that isn't defined by a DTYPE_* symbol. They are + * used in lib/prfp.c to select the type's processing. + * + * PRIVFILETYPE is the definition of the f_type value in the file struct. + * + * HASPRIVFILETYPE is the name of the processing function. + */ + +/* #define HASPRIVFILETYPE process_shmf? */ +/* #define PRIVFILETYPE ?? */ + + +/* + * HASPRIVNMCACHE is defined for dialects that have a private method for + * printing cached NAME column values for some files. HASPRIVNAMECACHE + * is defined to be the name of the function. + * + * The function takes one argument, a struct lfile pointer to the file, and + * returns non-zero if it prints a name to stdout. + */ + +# if 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 */ +# 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 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 + * , do that here. + */ + +#define HASSETLOCALE 1 +#define HASWIDECHAR 1 +#define WIDECHARINCL +#define __XPG4_CHAR_CLASS__ +#include +#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_ is defined for dialects that use the + * in the lsof library. + * + * Note: other definitions and operations may be required to condition the + * library function source code. They may be found in the dialect dlsof.h + * header files. + */ + +#define USE_LIB_CKKV 1 /* ckkv.c */ +#define USE_LIB_COMPLETEVFS 1 /* cvfs.c */ +#define USE_LIB_FIND_CH_INO 1 /* fino.c */ +/* #define USE_LIB_IS_FILE_NAMED 1 isfn.c */ +#define USE_LIB_LKUPDEV 1 /* lkud.c */ +/* #define USE_LIB_PRINTDEVNAME 1 pdvn.c */ +/* #define USE_LIB_PROCESS_FILE 1 prfp.c */ +/* #define USE_LIB_PRINT_TCPTPI 1 ptti.c */ +/* #define USE_LIB_READDEV 1 rdev.c */ +/* #define USE_LIB_READMNT 1 rmnt.c */ +/* #define USE_LIB_REGEX 1 regex.c */ +/* #define USE_LIB_RNAM 1 rnam.c */ + +# if solaris<90000 +#define USE_LIB_RNCH 1 /* rnch.c */ +# endif /* solaris<90000 */ + +/* #define USE_LIB_RNMH 1 rnmh.c */ + +# if solaris<20600 +#define USE_LIB_SNPF 1 /* snpf.c */ +# else /* solaris>=20600 */ +#define snpf snprintf /* use the system's snprintf() */ +# endif /* solaris<20600 */ + + +/* + * 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/dialects/sun/solaris_kaddr_filters b/dialects/sun/solaris_kaddr_filters new file mode 100644 index 0000000..7fcd692 --- /dev/null +++ b/dialects/sun/solaris_kaddr_filters @@ -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 .) + +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 . +Additionally useful is another undocumented function, kvm_pread() +(for physical read), that also is represented by a 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/Makefile.skel b/lib/Makefile.skel new file mode 100644 index 0000000..5c2b022 --- /dev/null +++ b/lib/Makefile.skel @@ -0,0 +1,62 @@ +# 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} + +HDR= ../lsof.h ../proto.h ../dlsof.h ../dproto.h ../machine.h + +SRC= ckkv.c cvfs.c dvch.c fino.c isfn.c lkud.c pdvn.c prfp.c \ + ptti.c rdev.c regex.c rmnt.c rnam.c rnch.c rnmh.c snpf.c + +OBJ= ckkv.o cvfs.o dvch.o fino.o isfn.o lkud.o pdvn.o prfp.o \ + ptti.o rdev.o regex.o rmnt.o rnam.o rnch.o rnmh.o snpf.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 + +regex.o: ${HDR} ../regex.h regex.c + +rmnt.o: ${HDR} rmnt.c + +rnam.o: ${HDR} rnam.c + +rnch.o: ${HDR} rnch.c + +rnmh.o: ${HDR} rnmh.c + +snpf.o: ${HDR} snpf.c diff --git a/lib/ckkv.c b/lib/ckkv.c new file mode 100644 index 0000000..fe36c92 --- /dev/null +++ b/lib/ckkv.c @@ -0,0 +1,93 @@ +/* + * 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 "../machine.h" + +#if defined(USE_LIB_CKKV) + +# if !defined(lint) +static char copyright[] = +"@(#) Copyright 1998 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: ckkv.c,v 1.3 2008/10/21 16:12:36 abe Exp abe $"; +# endif /* !defined(lint) */ + +#include "../lsof.h" +#include + + +/* + * ckkv() - check kernel version + */ + +void +ckkv(d, er, ev, ea) + 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)); + Exit(1); + } + 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/cvfs.c b/lib/cvfs.c new file mode 100644 index 0000000..067e53e --- /dev/null +++ b/lib/cvfs.c @@ -0,0 +1,110 @@ +/* + * 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 "../machine.h" + +#if defined(USE_LIB_COMPLETEVFS) + +# if !defined(lint) +static char copyright[] = +"@(#) Copyright 1997 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: cvfs.c,v 1.6 2008/10/21 16:12:36 abe Exp $"; +# endif /* !defined(lint) */ + +#include "../lsof.h" + + +/* + * completevfs() - complete local vfs structure + */ + +void +completevfs(vfs, dev) + 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(); 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/dvch.c b/lib/dvch.c new file mode 100644 index 0000000..ffdc4b4 --- /dev/null +++ b/lib/dvch.c @@ -0,0 +1,1413 @@ +/* + * 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 "../machine.h" + +#if defined(HASDCACHE) + +# if !defined(lint) +static char copyright[] = +"@(#) Copyright 1997 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: dvch.c,v 1.16 2008/10/21 16:12:36 abe Exp $"; +# endif /* !defined(lint) */ + +#include "../lsof.h" + +/* + * 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 +_PROTOTYPE(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 +_PROTOTYPE(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() +{ + if (!(BDevtp = (struct l_dev *)calloc((MALLOC_S)BNdev, + sizeof(struct l_dev)))) + { + (void) fprintf(stderr, "%s: no space for block devices\n", Pn); + Exit(1); + } + 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); + Exit(1); + } +} +# endif /* defined(HASBLKDEV) */ + + +/* + * alloc_dcache() - allocate device cache + */ + +void +alloc_dcache() +{ + if (!(Devtp = (struct l_dev *)calloc((MALLOC_S)Ndev, + sizeof(struct l_dev)))) + { + (void) fprintf(stderr, "%s: no space for devices\n", Pn); + Exit(1); + } + if (!(Sdev = (struct l_dev **)malloc((MALLOC_S)(sizeof(struct l_dev *) + * Ndev)))) + { + (void) fprintf(stderr, "%s: no space for device pointers\n", + Pn); + Exit(1); + } +} + + +/* + * clr_devtab() - clear the device tables and free their space + */ + +void +clr_devtab() +{ + 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(b, l, s) + 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(rw, npw) + 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) + Exit(1); +/* + * 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(m, r, s) + 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(m, 1)) < 0) + return(1); + } +/* + * Switch to the requested open() action. + */ + switch (m) { + case 1: + + /* + * Check for access permission. + */ + if (!is_readable(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); + Exit(1); + } + return(1); +} + + +/* + * read_dcache() - read device cache file + */ + +int +read_dcache() +{ + 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(1, 0, &sb)) != 0) { + if (DCpathX == 2) { + if (ov == 2 && DCpath[3]) { + DCpathX = 3; + if (open_dcache(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(); + +# if defined(DCACHE_CLR) + (void) DCACHE_CLR(); +# 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(); +/* + * 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); + Exit(1); + } + 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(); + /* + * 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); + Exit(1); + } + BDevtp[i].v = 0; + BSdev[i] = &BDevtp[i]; + } + } +# endif /* defined(HASBLKDEV) */ + +# if defined(DCACHE_CLONE) +/* + * Read the clone section. + */ + if (DCACHE_CLONE(1)) + goto read_close; +# endif /* defined(DCACHE_CLONE) */ + +# if defined(DCACHE_PSEUDO) +/* + * Read the pseudo section. + */ + if (DCACHE_PSEUDO(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(m) + 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); + Exit(1); + } + 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(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(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); + Exit(1); + return(1); /* This useless return(1) keeps some + * compilers happy. */ +} +# endif /* defined(DCACHE_CLONE_LOCAL) */ + + +/* + * write_dcache() - write device cache file + */ + +void +write_dcache() +{ + 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(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(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(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(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(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(buf, &DCcksum)) + return; + } + } +# endif /* defined(HASBLKDEV) */ + +# if defined(DCACHE_CLONE) +/* + * Write the clone section. + */ + if (DCACHE_CLONE(2)) + return; +# endif /* defined(DCACHE_CLONE) */ + +# if defined(DCACHE_PSEUDO) +/* + * Write the pseudo section. + */ + if (DCACHE_PSEUDO(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(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(b, c) + 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 index 0000000..6beff86 --- /dev/null +++ b/lib/fino.c @@ -0,0 +1,148 @@ +/* + * 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 "../machine.h" + +#if defined(HASBLKDEV) || defined(USE_LIB_FIND_CH_INO) + +# if !defined(lint) +static char copyright[] = +"@(#) Copyright 1997 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: fino.c,v 1.5 2008/10/21 16:12:36 abe Exp $"; +# endif /* !defined(lint) */ + +#include "../lsof.h" + +#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() +{ + dev_t ldev, tdev; + int low, hi, mid; + + readdev(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(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() +{ + dev_t ldev, tdev; + int low, hi, mid; + + readdev(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(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/isfn.c b/lib/isfn.c new file mode 100644 index 0000000..b23846d --- /dev/null +++ b/lib/isfn.c @@ -0,0 +1,418 @@ +/* + * 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 "../machine.h" + +#if defined(USE_LIB_IS_FILE_NAMED) + +# if !defined(lint) +static char copyright[] = +"@(#) Copyright 1997 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: isfn.c,v 1.10 2008/10/21 16:12:36 abe Exp $"; +# endif /* !defined(lint) */ + +#include "../lsof.h" + + +/* + * Local structures + */ + +struct hsfile { + struct sfile *s; /* the Sfile table address */ + struct hsfile *next; /* the next hash bucket entry */ +}; + +/* + * Local static variables + */ + +# if defined(HAVECLONEMAJ) +static struct hsfile *HbyCd = /* hash by clone buckets */ + (struct hsfile *)NULL; +static int HbyCdCt = 0; /* HbyCd entry count */ +# endif /* defined(HAVECLONEMAJ) */ + +static struct hsfile *HbyFdi = /* hash by file (dev,ino) buckets */ + (struct hsfile *)NULL; +static int HbyFdiCt = 0; /* HbyFdi entry count */ +static struct hsfile *HbyFrd = /* hash by file raw device buckets */ + (struct hsfile *)NULL; +static int HbyFrdCt = 0; /* HbyFrd entry count */ +static struct hsfile *HbyFsd = /* hash by file system buckets */ + (struct hsfile *)NULL; +static int HbyFsdCt = 0; /* HbyFsd entry count */ +static struct hsfile *HbyNm = /* hash by name buckets */ + (struct hsfile *)NULL; +static int HbyNmCt = 0; /* HbyNm entry count */ + + +/* + * Local definitions + */ + +# 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() +{ + 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); + Exit(1); + } + 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); + Exit(1); + } + if (!(HbyFrd = (struct hsfile *)calloc((MALLOC_S)SFRDHASH, + sizeof(struct hsfile)))) + { + (void) fprintf(stderr, + "%s: can't allocate space for %d rdev hash buckets\n", + Pn, SFRDHASH); + Exit(1); + } + if (!(HbyFsd = (struct hsfile *)calloc((MALLOC_S)SFFSHASH, + sizeof(struct hsfile)))) + { + (void) fprintf(stderr, + "%s: can't allocate space for %d file sys hash buckets\n", + Pn, SFFSHASH); + Exit(1); + } + if (!(HbyNm = (struct hsfile *)calloc((MALLOC_S)SFNMHASH, + sizeof(struct hsfile)))) + { + (void) fprintf(stderr, + "%s: can't allocate space for %d name hash buckets\n", + Pn, SFNMHASH); + Exit(1); + } + hs++; +/* + * Scan the Sfile chain, building file, file system, raw device, and file + * name hash bucket chains. + */ + for (s = Sfile; s; s = s->next) { + for (i = 0; i < 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); + Exit(1); + } + sn->s = s; + sn->next = sh->next; + sh->next = sn; + } + } + } +} + + +/* + * is_file_named() - is this file named? + */ + +int +is_file_named(p, cd) + 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(&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 index 0000000..268af4f --- /dev/null +++ b/lib/lkud.c @@ -0,0 +1,207 @@ +/* + * 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 "../machine.h" + +#if defined(HASBLKDEV) || defined(USE_LIB_LKUPDEV) + +# if !defined(lint) +static char copyright[] = +"@(#) Copyright 1997 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: lkud.c,v 1.7 2008/10/21 16:12:36 abe Exp $"; +# endif /* !defined(lint) */ + +#include "../lsof.h" + +#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(dev, rdev, i, r) + 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(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(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(); + 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(dev, rdev, i, r) + 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(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(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(); + goto lkupdev_again; + } +# endif /* defined(HASDCACHE) */ + + return((struct l_dev *)NULL); +} +#endif /* defined(USE_LIB_LKUPDEV) */ diff --git a/lib/pdvn.c b/lib/pdvn.c new file mode 100644 index 0000000..ccd5c73 --- /dev/null +++ b/lib/pdvn.c @@ -0,0 +1,182 @@ +/* + * 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 "../machine.h" + +#if defined(USE_LIB_PRINTDEVNAME) + +# if !defined(lint) +static char copyright[] = +"@(#) Copyright 1997 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: pdvn.c,v 1.8 2008/10/21 16:12:36 abe Exp $"; +# endif /* !defined(lint) */ + +#include "../lsof.h" + +#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(dev, rdev, f, nty) + 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(dev, rdev, 1, r); + else +# endif /* defined(HASBLKDEV) */ + + dp = lkupdev(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(&DevDev, rdev, 0, r); + else +# endif /* defined(HASBLKDEV) */ + + dp = lkupdev(&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); + Exit(1); + } + (void) snpf(cp, len + 1, "(%s %s)", ttl, dp->name); + (void) add_nma(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(); + 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 index 0000000..fe4812c --- /dev/null +++ b/lib/prfp.c @@ -0,0 +1,235 @@ +/* + * 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 "../machine.h" + +#if defined(USE_LIB_PROCESS_FILE) + +# if !defined(lint) +static char copyright[] = +"@(#) Copyright 1997 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: prfp.c,v 1.15 2018/02/14 14:21:08 abe Exp $"; +# endif /* !defined(lint) */ + +#include "../lsof.h" + + +/* + * process_file() - process file + */ + +/* + * The caller may define: + * + * FILEPTR as the name of the location to store a pointer + * to the current file struct -- e.g., + * + * struct file *foobar; + * #define FILEPTR foobar + */ + +void +process_file(fp) + KA_T fp; /* kernel file structure address */ +{ + 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((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; + if (f.f_count) { + + /* + * Construct access code. + */ + if ((flag = (f.f_flag & (FREAD | FWRITE))) == FREAD) + Lf->access = 'r'; + else if (flag == FWRITE) + Lf->access = 'w'; + else if (flag == (FREAD | FWRITE)) + Lf->access = 'u'; + +#if defined(HASFSTRUCT) + /* + * Save file structure values. + */ + +# if !defined(HASNOFSCOUNT) + if (Fsv & FSV_CT) { + Lf->fct = (long)f.f_count; + Lf->fsv |= FSV_CT; + } +# endif /* !defined(HASNOFSCOUNT) */ + +# if !defined(HASNOFSADDR) + if (Fsv & FSV_FA) { + Lf->fsa = fp; + Lf->fsv |= FSV_FA; + } +# endif /* !defined(HASNOFSADDR) */ + +# if !defined(HASNOFSFLAGS) + if (Fsv & FSV_FG) { + Lf->ffg = (long)f.f_flag; + Lf->fsv |= FSV_FG; + } +# endif /* !defined(HASNOFSFLAGS) */ + +# if !defined(HASNOFSNADDR) + if (Fsv & FSV_NI) { + 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((KA_T)f.f_data); +# endif /* defined(HASPIPEFN) */ + return; +#endif /* defined(DTYPE_PIPE) */ + +#if defined(DTYPE_PTS) + case DTYPE_PTS: +# if defined(HASPTSFN) + HASPTSFN((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((KA_T)f.f_vnode); +#else /* !defined(HASF_VNODE) */ + process_node((KA_T)f.f_data); +#endif /* defined(HASF_VNODE) */ + + return; + case DTYPE_SOCKET: + process_socket((KA_T)f.f_data); + return; + +#if defined(HASKQUEUE) + case DTYPE_KQUEUE: + process_kqueue((KA_T)f.f_data); + return; +#endif /* defined(HASKQUEUE) */ + +#if defined(HASPSXSEM) + case DTYPE_PSXSEM: + process_psxsem((KA_T)f.f_data); + return; +#endif /* defined(HASPSXSEM) */ + +#if defined(HASPSXSHM) + case DTYPE_PSXSHM: + process_psxshm((KA_T)f.f_data); + return; +#endif /* defined(HASPSXSHM) */ + +#if defined(HASPRIVFILETYPE) + case PRIVFILETYPE: + HASPRIVFILETYPE((KA_T)f.f_data); + return; +#endif /* defined(HASPRIVFILETYPE) */ + + default: + +#if 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(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(Namech); + return; + } + } + } + enter_nm("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/ptti.c b/lib/ptti.c new file mode 100644 index 0000000..e542454 --- /dev/null +++ b/lib/ptti.c @@ -0,0 +1,1370 @@ +/* + * 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. + */ + + +#include "../machine.h" + +#if defined(USE_LIB_PRINT_TCPTPI) + +# if !defined(lint) +static char copyright[] = +"@(#) Copyright 1997 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: ptti.c,v 1.6 2008/10/21 16:13:23 abe Exp $"; +# endif /* !defined(lint) */ + +#define TCPSTATES /* activate tcpstates[] */ +#include "../lsof.h" + + +/* + * build_IPstates() -- build the TCP and UDP state tables + * + * Note: this module does not support a UDP state table. + */ + +void +build_IPstates() +{ + +/* + * Set the TcpNstates global variable. + */ + TcpNstates = TCP_NSTATES; + TcpSt = (char **)&tcpstates; +} + + +/* + * print_tcptpi() - print TCP/TPI info + */ + +void +print_tcptpi(nl) + 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(); + 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/lib/rdev.c b/lib/rdev.c new file mode 100644 index 0000000..9c5b6f4 --- /dev/null +++ b/lib/rdev.c @@ -0,0 +1,524 @@ +/* + * 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 "../machine.h" + +#if defined(USE_LIB_READDEV) + +# if !defined(lint) +static char copyright[] = +"@(#) Copyright 1997 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: rdev.c,v 1.12 2008/10/21 16:13:23 abe Exp $"; +# endif /* !defined(lint) */ + +#include "../lsof.h" + + +_PROTOTYPE(static int rmdupdev,(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(skip) + 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()) == 0) + return; + } + } else + dcrd = 1; +# endif /* defined(HASDCACHE) */ + + Dstkn = Dstkx = 0; + Dstk = (char **)NULL; + (void) stkdir("/dev"); +/* + * Unstack the next /dev or /dev/ directory. + */ + while (--Dstkx >= 0) { + if (!(dfp = OpenDir(Dstk[Dstkx]))) { + +# if defined(WARNDEVACCESS) + if (!Fwarn) { + (void) fprintf(stderr, "%s: WARNING: can't open: ", Pn); + safestrprt(Dstk[Dstkx], stderr, 1); + } +# endif /* defined(WARNDEVACCESS) */ + + (void) free((FREE_P *)Dstk[Dstkx]); + Dstk[Dstkx] = (char *)NULL; + continue; + } + if (path) { + (void) free((FREE_P *)path); + path = (char *)NULL; + } + if (!(path = mkstrcat(Dstk[Dstkx], -1, "/", 1, (char *)NULL, -1, + &pl))) + { + (void) fprintf(stderr, "%s: no space for: ", Pn); + safestrprt(Dstk[Dstkx], stderr, 1); + Exit(1); + } + (void) free((FREE_P *)Dstk[Dstkx]); + Dstk[Dstkx] = (char *)NULL; + /* + * Scan the directory. + */ + for (dp = ReadDir(dfp); dp; dp = ReadDir(dfp)) { + if (dp->d_ino == 0 || dp->d_name[0] == '.') + continue; + /* + * Form the full path name and get its status. + */ + +# 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); + Exit(1); + } + 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(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); + Exit(1); + } + } + 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); + Exit(1); + } + 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); + Exit(1); + } + 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); + Exit(1); + } + } + 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); + Exit(1); + } + for (j = 0; j < BNdev; j++) { + BSdev[j] = &BDevtp[j]; + } + (void) qsort((QSORT_P *)BSdev, (size_t)BNdev, + (size_t)sizeof(struct l_dev *), compdev); + BNdev = rmdupdev(&BSdev, BNdev, "block"); + } + +# if !defined(NOWARNBLKDEV) + else { + if (!Fwarn) + (void) fprintf(stderr, + "%s: WARNING: no block devices found\n", Pn); + } +# endif /* !defined(NOWARNBLKDEV) */ +# endif /* defined(HASBLKDEV) */ + + if (Ndev) { + if (Ndev > i) { + Ndev = i; + Devtp = (struct l_dev *)realloc((MALLOC_P *)Devtp, + (MALLOC_S)(sizeof(struct l_dev) * Ndev)); + } + if (!(Sdev = (struct l_dev **)malloc( + (MALLOC_S)(sizeof(struct l_dev *) * Ndev)))) + { + (void) fprintf(stderr, + "%s: no space for character device sort pointers\n", Pn); + Exit(1); + } + for (i = 0; i < Ndev; i++) { + Sdev[i] = &Devtp[i]; + } + (void) qsort((QSORT_P *)Sdev, (size_t)Ndev, + (size_t)sizeof(struct l_dev *), compdev); + Ndev = rmdupdev(&Sdev, Ndev, "char"); + } else { + (void) fprintf(stderr, "%s: no character devices found\n", Pn); + Exit(1); + } + +# if defined(HASDCACHE) +/* + * Write device cache file, as required. + */ + if (DCstate == 1 || (DCstate == 3 && dcrd)) + write_dcache(); +# endif /* defined(HASDCACHE) */ + +} + + +# if defined(HASDCACHE) +/* + * rereaddev() - reread device names, modes and types + */ + +void +rereaddev() +{ + (void) clr_devtab(); + +# if defined(DCACHE_CLR) + (void) DCACHE_CLR(); +# endif /* defined(DCACHE_CLR) */ + + readdev(1); + DCunsafe = 0; +} +#endif /* defined(HASDCACHE) */ + + +/* + * rmdupdev() - remove duplicate (major/minor/inode) devices + */ + +static int +rmdupdev(dp, n, nm) + struct l_dev ***dp; /* device table pointers address */ + int n; /* number of pointers */ + char *nm; /* device table name for error message */ +{ + +# 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); + Exit(1); + } + 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(dp) + 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(); + 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/regex.c b/lib/regex.c new file mode 100644 index 0000000..88e959d --- /dev/null +++ b/lib/regex.c @@ -0,0 +1,6328 @@ +/* + * regex.c -- POSIX-conformant regular expression function set for the lsof + * library + * + * This file is used when the UNIX dialect does not have a POSIX-conformant + * regular expression function set. In that case USE_LIB_REGEX is defined. + * + * V. Abell + * Purdue University Computing Center + */ + + +/* + * Copyright 2000 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. + * + * This software has been adapted from snprintf.c in sendmail 8.9.3. It + * is subject to the sendmail copyright statements listed below, and the + * sendmail licensing terms stated in the sendmail LICENSE file comment + * section of this file. + * + * 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 "../machine.h" + +#ifdef USE_LIB_REGEX +/* + * This file comes from GLIBC 2.2. It is used when the UNIX dialect does not + * have a POSIX-conformant regular expression function set. In that case + * USE_LIB_REGEX is defined. + */ + +/* Extended regular expression matching and search library, + version 0.12. + (Implements POSIX draft P1003.2/D11.2, except for some of the + internationalization features.) + Copyright (C) 1993-1999, 2000 Free Software Foundation, Inc. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* AIX requires this to be the first thing in the file. */ +#if defined _AIX && !defined REGEX_MALLOC + #pragma alloca +#endif + +#undef _GNU_SOURCE +#define _GNU_SOURCE + +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifndef PARAMS +# if defined __GNUC__ || (defined __STDC__ && __STDC__) +# define PARAMS(args) args +# else +# define PARAMS(args) () +# endif /* GCC. */ +#endif /* Not PARAMS. */ + +#if defined STDC_HEADERS && !defined emacs +# include +#else +/* We need this for `regex.h', and perhaps for the Emacs include files. */ +# include +#endif + +#define WIDE_CHAR_SUPPORT (HAVE_WCTYPE_H && HAVE_WCHAR_H && HAVE_BTOWC) + +/* For platform which support the ISO C amendement 1 functionality we + support user defined character classes. */ +#if defined _LIBC || WIDE_CHAR_SUPPORT +/* Solaris 2.5 has a bug: must be included before . */ +# include +# include +#endif + +#ifdef _LIBC +/* We have to keep the namespace clean. */ +# define regfree(preg) __regfree (preg) +# define regexec(pr, st, nm, pm, ef) __regexec (pr, st, nm, pm, ef) +# define regcomp(preg, pattern, cflags) __regcomp (preg, pattern, cflags) +# define regerror(errcode, preg, errbuf, errbuf_size) \ + __regerror(errcode, preg, errbuf, errbuf_size) +# define re_set_registers(bu, re, nu, st, en) \ + __re_set_registers (bu, re, nu, st, en) +# define re_match_2(bufp, string1, size1, string2, size2, pos, regs, stop) \ + __re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) +# define re_match(bufp, string, size, pos, regs) \ + __re_match (bufp, string, size, pos, regs) +# define re_search(bufp, string, size, startpos, range, regs) \ + __re_search (bufp, string, size, startpos, range, regs) +# define re_compile_pattern(pattern, length, bufp) \ + __re_compile_pattern (pattern, length, bufp) +# define re_set_syntax(syntax) __re_set_syntax (syntax) +# define re_search_2(bufp, st1, s1, st2, s2, startpos, range, regs, stop) \ + __re_search_2 (bufp, st1, s1, st2, s2, startpos, range, regs, stop) +# define re_compile_fastmap(bufp) __re_compile_fastmap (bufp) + +# define btowc __btowc + +/* We are also using some library internals. */ +# include +# include +# include +#endif + +/* This is for other GNU distributions with internationalized messages. */ +#if HAVE_LIBINTL_H || defined _LIBC +# include +# ifdef _LIBC +# undef gettext +# define gettext(msgid) __dcgettext ("libc", msgid, LC_MESSAGES) +# endif +#else +# define gettext(msgid) (msgid) +#endif + +#ifndef gettext_noop +/* This define is so xgettext can find the internationalizable + strings. */ +# define gettext_noop(String) String +#endif + +/* The `emacs' switch turns on certain matching commands + that make sense only in Emacs. */ +#ifdef emacs + +# include "lisp.h" +# include "buffer.h" +# include "syntax.h" + +#else /* not emacs */ + +/* If we are not linking with Emacs proper, + we can't use the relocating allocator + even if config.h says that we can. */ +# undef REL_ALLOC + +# if defined STDC_HEADERS || defined _LIBC +# include +# else +char *malloc (); +char *realloc (); +# endif + +/* When used in Emacs's lib-src, we need to get bzero and bcopy somehow. + If nothing else has been done, use the method below. */ +# ifdef INHIBIT_STRING_HEADER +# if !(defined HAVE_BZERO && defined HAVE_BCOPY) +# if !defined bzero && !defined bcopy +# undef INHIBIT_STRING_HEADER +# endif +# endif +# endif + +/* This is the normal way of making sure we have a bcopy and a bzero. + This is used in most programs--a few other programs avoid this + by defining INHIBIT_STRING_HEADER. */ +# ifndef INHIBIT_STRING_HEADER +# if defined HAVE_STRING_H || defined STDC_HEADERS || defined _LIBC +# include +# ifndef bzero +# ifndef _LIBC +# define bzero(s, n) (memset (s, '\0', n), (s)) +# else +# define bzero(s, n) __bzero (s, n) +# endif +# endif +# else +# include +# ifndef memcmp +# define memcmp(s1, s2, n) bcmp (s1, s2, n) +# endif +# ifndef memcpy +# define memcpy(d, s, n) (bcopy (s, d, n), (d)) +# endif +# endif +# endif + +/* Define the syntax stuff for \<, \>, etc. */ + +/* This must be nonzero for the wordchar and notwordchar pattern + commands in re_match_2. */ +# ifndef Sword +# define Sword 1 +# endif + +# ifdef SWITCH_ENUM_BUG +# define SWITCH_ENUM_CAST(x) ((int)(x)) +# else +# define SWITCH_ENUM_CAST(x) (x) +# endif + +#endif /* not emacs */ + +#if defined _LIBC || HAVE_LIMITS_H +# include +#endif + +#ifndef MB_LEN_MAX +# define MB_LEN_MAX 1 +#endif + +/* Get the interface, including the syntax bits. */ +/* Disabled by V. Abell on January 29, 2001: #include */ +#include "../regex.h" + +/* isalpha etc. are used for the character classes. */ +#include + +/* Jim Meyering writes: + + "... Some ctype macros are valid only for character codes that + isascii says are ASCII (SGI's IRIX-4.0.5 is one such system --when + using /bin/cc or gcc but without giving an ansi option). So, all + ctype uses should be through macros like ISPRINT... If + STDC_HEADERS is defined, then autoconf has verified that the ctype + macros don't need to be guarded with references to isascii. ... + Defining isascii to 1 should let any compiler worth its salt + eliminate the && through constant folding." + Solaris defines some of these symbols so we must undefine them first. */ + +#undef ISASCII +#if defined STDC_HEADERS || (!defined isascii && !defined HAVE_ISASCII) +# define ISASCII(c) 1 +#else +# define ISASCII(c) isascii(c) +#endif + +#ifdef isblank +# define ISBLANK(c) (ISASCII (c) && isblank (c)) +#else +# define ISBLANK(c) ((c) == ' ' || (c) == '\t') +#endif +#ifdef isgraph +# define ISGRAPH(c) (ISASCII (c) && isgraph (c)) +#else +# define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c)) +#endif + +#undef ISPRINT +#define ISPRINT(c) (ISASCII (c) && isprint (c)) +#define ISDIGIT(c) (ISASCII (c) && isdigit (c)) +#define ISALNUM(c) (ISASCII (c) && isalnum (c)) +#define ISALPHA(c) (ISASCII (c) && isalpha (c)) +#define ISCNTRL(c) (ISASCII (c) && iscntrl (c)) +#define ISLOWER(c) (ISASCII (c) && islower (c)) +#define ISPUNCT(c) (ISASCII (c) && ispunct (c)) +#define ISSPACE(c) (ISASCII (c) && isspace (c)) +#define ISUPPER(c) (ISASCII (c) && isupper (c)) +#define ISXDIGIT(c) (ISASCII (c) && isxdigit (c)) + +#ifdef _tolower +# define TOLOWER(c) _tolower(c) +#else +# define TOLOWER(c) tolower(c) +#endif + +#ifndef NULL +# define NULL (void *)0 +#endif + +/* We remove any previous definition of `SIGN_EXTEND_CHAR', + since ours (we hope) works properly with all combinations of + machines, compilers, `char' and `unsigned char' argument types. + (Per Bothner suggested the basic approach.) */ +#undef SIGN_EXTEND_CHAR +#if __STDC__ +# define SIGN_EXTEND_CHAR(c) ((signed char) (c)) +#else /* not __STDC__ */ +/* As in Harbison and Steele. */ +# define SIGN_EXTEND_CHAR(c) ((((unsigned char) (c)) ^ 128) - 128) +#endif + +#ifndef emacs +/* How many characters in the character set. */ +# define CHAR_SET_SIZE 256 + +# ifdef SYNTAX_TABLE + +extern char *re_syntax_table; + +# else /* not SYNTAX_TABLE */ + +static char re_syntax_table[CHAR_SET_SIZE]; + +static void +init_syntax_once () +{ + register int c; + static int done = 0; + + if (done) + return; + bzero (re_syntax_table, sizeof re_syntax_table); + + for (c = 0; c < CHAR_SET_SIZE; ++c) + if (ISALNUM (c)) + re_syntax_table[c] = Sword; + + re_syntax_table['_'] = Sword; + + done = 1; +} + +# endif /* not SYNTAX_TABLE */ + +# define SYNTAX(c) re_syntax_table[(unsigned char) (c)] + +#endif /* emacs */ + +/* Should we use malloc or alloca? If REGEX_MALLOC is not defined, we + use `alloca' instead of `malloc'. This is because using malloc in + re_search* or re_match* could cause memory leaks when C-g is used in + Emacs; also, malloc is slower and causes storage fragmentation. On + the other hand, malloc is more portable, and easier to debug. + + Because we sometimes use alloca, some routines have to be macros, + not functions -- `alloca'-allocated space disappears at the end of the + function it is called in. */ + +#ifdef REGEX_MALLOC + +# define REGEX_ALLOCATE malloc +# define REGEX_REALLOCATE(source, osize, nsize) realloc (source, nsize) +# define REGEX_FREE free + +#else /* not REGEX_MALLOC */ + +/* Emacs already defines alloca, sometimes. */ +# ifndef alloca + +/* Make alloca work the best possible way. */ +# ifdef __GNUC__ +# define alloca __builtin_alloca +# else /* not __GNUC__ */ +# if HAVE_ALLOCA_H +# include +# endif /* HAVE_ALLOCA_H */ +# endif /* not __GNUC__ */ + +# endif /* not alloca */ + +# define REGEX_ALLOCATE alloca + +/* Assumes a `char *destination' variable. */ +# define REGEX_REALLOCATE(source, osize, nsize) \ + (destination = (char *) alloca (nsize), \ + memcpy (destination, source, osize)) + +/* No need to do anything to free, after alloca. */ +# define REGEX_FREE(arg) ((void)0) /* Do nothing! But inhibit gcc warning. */ + +#endif /* not REGEX_MALLOC */ + +/* Define how to allocate the failure stack. */ + +#if defined REL_ALLOC && defined REGEX_MALLOC + +# define REGEX_ALLOCATE_STACK(size) \ + r_alloc (&failure_stack_ptr, (size)) +# define REGEX_REALLOCATE_STACK(source, osize, nsize) \ + r_re_alloc (&failure_stack_ptr, (nsize)) +# define REGEX_FREE_STACK(ptr) \ + r_alloc_free (&failure_stack_ptr) + +#else /* not using relocating allocator */ + +# ifdef REGEX_MALLOC + +# define REGEX_ALLOCATE_STACK malloc +# define REGEX_REALLOCATE_STACK(source, osize, nsize) realloc (source, nsize) +# define REGEX_FREE_STACK free + +# else /* not REGEX_MALLOC */ + +# define REGEX_ALLOCATE_STACK alloca + +# define REGEX_REALLOCATE_STACK(source, osize, nsize) \ + REGEX_REALLOCATE (source, osize, nsize) +/* No need to explicitly free anything. */ +# define REGEX_FREE_STACK(arg) + +# endif /* not REGEX_MALLOC */ +#endif /* not using relocating allocator */ + + +/* True if `size1' is non-NULL and PTR is pointing anywhere inside + `string1' or just past its end. This works if PTR is NULL, which is + a good thing. */ +#define FIRST_STRING_P(ptr) \ + (size1 && string1 <= (ptr) && (ptr) <= string1 + size1) + +/* (Re)Allocate N items of type T using malloc, or fail. */ +#define TALLOC(n, t) ((t *) malloc ((n) * sizeof (t))) +#define RETALLOC(addr, n, t) ((addr) = (t *) realloc (addr, (n) * sizeof (t))) +#define RETALLOC_IF(addr, n, t) \ + if (addr) RETALLOC((addr), (n), t); else (addr) = TALLOC ((n), t) +#define REGEX_TALLOC(n, t) ((t *) REGEX_ALLOCATE ((n) * sizeof (t))) + +#define BYTEWIDTH 8 /* In bits. */ + +#define STREQ(s1, s2) ((strcmp (s1, s2) == 0)) + +#undef MAX +#undef MIN +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +typedef char boolean; +#define false 0 +#define true 1 + +static int re_match_2_internal PARAMS ((struct re_pattern_buffer *bufp, + const char *string1, int size1, + const char *string2, int size2, + int pos, + struct re_registers *regs, + int stop)); + +/* These are the command codes that appear in compiled regular + expressions. Some opcodes are followed by argument bytes. A + command code can specify any interpretation whatsoever for its + arguments. Zero bytes may appear in the compiled regular expression. */ + +typedef enum +{ + no_op = 0, + + /* Succeed right away--no more backtracking. */ + succeed, + + /* Followed by one byte giving n, then by n literal bytes. */ + exactn, + + /* Matches any (more or less) character. */ + anychar, + + /* Matches any one char belonging to specified set. First + following byte is number of bitmap bytes. Then come bytes + for a bitmap saying which chars are in. Bits in each byte + are ordered low-bit-first. A character is in the set if its + bit is 1. A character too large to have a bit in the map is + automatically not in the set. */ + charset, + + /* Same parameters as charset, but match any character that is + not one of those specified. */ + charset_not, + + /* Start remembering the text that is matched, for storing in a + register. Followed by one byte with the register number, in + the range 0 to one less than the pattern buffer's re_nsub + field. Then followed by one byte with the number of groups + inner to this one. (This last has to be part of the + start_memory only because we need it in the on_failure_jump + of re_match_2.) */ + start_memory, + + /* Stop remembering the text that is matched and store it in a + memory register. Followed by one byte with the register + number, in the range 0 to one less than `re_nsub' in the + pattern buffer, and one byte with the number of inner groups, + just like `start_memory'. (We need the number of inner + groups here because we don't have any easy way of finding the + corresponding start_memory when we're at a stop_memory.) */ + stop_memory, + + /* Match a duplicate of something remembered. Followed by one + byte containing the register number. */ + duplicate, + + /* Fail unless at beginning of line. */ + begline, + + /* Fail unless at end of line. */ + endline, + + /* Succeeds if at beginning of buffer (if emacs) or at beginning + of string to be matched (if not). */ + begbuf, + + /* Analogously, for end of buffer/string. */ + endbuf, + + /* Followed by two byte relative address to which to jump. */ + jump, + + /* Same as jump, but marks the end of an alternative. */ + jump_past_alt, + + /* Followed by two-byte relative address of place to resume at + in case of failure. */ + on_failure_jump, + + /* Like on_failure_jump, but pushes a placeholder instead of the + current string position when executed. */ + on_failure_keep_string_jump, + + /* Throw away latest failure point and then jump to following + two-byte relative address. */ + pop_failure_jump, + + /* Change to pop_failure_jump if know won't have to backtrack to + match; otherwise change to jump. This is used to jump + back to the beginning of a repeat. If what follows this jump + clearly won't match what the repeat does, such that we can be + sure that there is no use backtracking out of repetitions + already matched, then we change it to a pop_failure_jump. + Followed by two-byte address. */ + maybe_pop_jump, + + /* Jump to following two-byte address, and push a dummy failure + point. This failure point will be thrown away if an attempt + is made to use it for a failure. A `+' construct makes this + before the first repeat. Also used as an intermediary kind + of jump when compiling an alternative. */ + dummy_failure_jump, + + /* Push a dummy failure point and continue. Used at the end of + alternatives. */ + push_dummy_failure, + + /* Followed by two-byte relative address and two-byte number n. + After matching N times, jump to the address upon failure. */ + succeed_n, + + /* Followed by two-byte relative address, and two-byte number n. + Jump to the address N times, then fail. */ + jump_n, + + /* Set the following two-byte relative address to the + subsequent two-byte number. The address *includes* the two + bytes of number. */ + set_number_at, + + wordchar, /* Matches any word-constituent character. */ + notwordchar, /* Matches any char that is not a word-constituent. */ + + wordbeg, /* Succeeds if at word beginning. */ + wordend, /* Succeeds if at word end. */ + + wordbound, /* Succeeds if at a word boundary. */ + notwordbound /* Succeeds if not at a word boundary. */ + +#ifdef emacs + ,before_dot, /* Succeeds if before point. */ + at_dot, /* Succeeds if at point. */ + after_dot, /* Succeeds if after point. */ + + /* Matches any character whose syntax is specified. Followed by + a byte which contains a syntax code, e.g., Sword. */ + syntaxspec, + + /* Matches any character whose syntax is not that specified. */ + notsyntaxspec +#endif /* emacs */ +} re_opcode_t; + +/* Common operations on the compiled pattern. */ + +/* Store NUMBER in two contiguous bytes starting at DESTINATION. */ + +#define STORE_NUMBER(destination, number) \ + do { \ + (destination)[0] = (number) & 0377; \ + (destination)[1] = (number) >> 8; \ + } while (0) + +/* Same as STORE_NUMBER, except increment DESTINATION to + the byte after where the number is stored. Therefore, DESTINATION + must be an lvalue. */ + +#define STORE_NUMBER_AND_INCR(destination, number) \ + do { \ + STORE_NUMBER (destination, number); \ + (destination) += 2; \ + } while (0) + +/* Put into DESTINATION a number stored in two contiguous bytes starting + at SOURCE. */ + +#define EXTRACT_NUMBER(destination, source) \ + do { \ + (destination) = *(source) & 0377; \ + (destination) += SIGN_EXTEND_CHAR (*((source) + 1)) << 8; \ + } while (0) + +#ifdef DEBUG +static void extract_number _RE_ARGS ((int *dest, unsigned char *source)); +static void +extract_number (dest, source) + int *dest; + unsigned char *source; +{ + int temp = SIGN_EXTEND_CHAR (*(source + 1)); + *dest = *source & 0377; + *dest += temp << 8; +} + +# ifndef EXTRACT_MACROS /* To debug the macros. */ +# undef EXTRACT_NUMBER +# define EXTRACT_NUMBER(dest, src) extract_number (&dest, src) +# endif /* not EXTRACT_MACROS */ + +#endif /* DEBUG */ + +/* Same as EXTRACT_NUMBER, except increment SOURCE to after the number. + SOURCE must be an lvalue. */ + +#define EXTRACT_NUMBER_AND_INCR(destination, source) \ + do { \ + EXTRACT_NUMBER (destination, source); \ + (source) += 2; \ + } while (0) + +#ifdef DEBUG +static void extract_number_and_incr _RE_ARGS ((int *destination, + unsigned char **source)); +static void +extract_number_and_incr (destination, source) + int *destination; + unsigned char **source; +{ + extract_number (destination, *source); + *source += 2; +} + +# ifndef EXTRACT_MACROS +# undef EXTRACT_NUMBER_AND_INCR +# define EXTRACT_NUMBER_AND_INCR(dest, src) \ + extract_number_and_incr (&dest, &src) +# endif /* not EXTRACT_MACROS */ + +#endif /* DEBUG */ + +/* If DEBUG is defined, Regex prints many voluminous messages about what + it is doing (if the variable `debug' is nonzero). If linked with the + main program in `iregex.c', you can enter patterns and strings + interactively. And if linked with the main program in `main.c' and + the other test files, you can run the already-written tests. */ + +#ifdef DEBUG + +/* We use standard I/O for debugging. */ +# include + +/* It is useful to test things that ``must'' be true when debugging. */ +# include + +static int debug; + +# define DEBUG_STATEMENT(e) e +# define DEBUG_PRINT1(x) if (debug) printf (x) +# define DEBUG_PRINT2(x1, x2) if (debug) printf (x1, x2) +# define DEBUG_PRINT3(x1, x2, x3) if (debug) printf (x1, x2, x3) +# define DEBUG_PRINT4(x1, x2, x3, x4) if (debug) printf (x1, x2, x3, x4) +# define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) \ + if (debug) print_partial_compiled_pattern (s, e) +# define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2) \ + if (debug) print_double_string (w, s1, sz1, s2, sz2) + + +/* Print the fastmap in human-readable form. */ + +void +print_fastmap (fastmap) + char *fastmap; +{ + unsigned was_a_range = 0; + unsigned i = 0; + + while (i < (1 << BYTEWIDTH)) + { + if (fastmap[i++]) + { + was_a_range = 0; + putchar (i - 1); + while (i < (1 << BYTEWIDTH) && fastmap[i]) + { + was_a_range = 1; + i++; + } + if (was_a_range) + { + printf ("-"); + putchar (i - 1); + } + } + } + putchar ('\n'); +} + + +/* Print a compiled pattern string in human-readable form, starting at + the START pointer into it and ending just before the pointer END. */ + +void +print_partial_compiled_pattern (start, end) + unsigned char *start; + unsigned char *end; +{ + int mcnt, mcnt2; + unsigned char *p1; + unsigned char *p = start; + unsigned char *pend = end; + + if (start == NULL) + { + printf ("(null)\n"); + return; + } + + /* Loop over pattern commands. */ + while (p < pend) + { +#ifdef _LIBC + printf ("%t:\t", p - start); +#else + printf ("%ld:\t", (long int) (p - start)); +#endif + + switch ((re_opcode_t) *p++) + { + case no_op: + printf ("/no_op"); + break; + + case exactn: + mcnt = *p++; + printf ("/exactn/%d", mcnt); + do + { + putchar ('/'); + putchar (*p++); + } + while (--mcnt); + break; + + case start_memory: + mcnt = *p++; + printf ("/start_memory/%d/%d", mcnt, *p++); + break; + + case stop_memory: + mcnt = *p++; + printf ("/stop_memory/%d/%d", mcnt, *p++); + break; + + case duplicate: + printf ("/duplicate/%d", *p++); + break; + + case anychar: + printf ("/anychar"); + break; + + case charset: + case charset_not: + { + register int c, last = -100; + register int in_range = 0; + + printf ("/charset [%s", + (re_opcode_t) *(p - 1) == charset_not ? "^" : ""); + + assert (p + *p < pend); + + for (c = 0; c < 256; c++) + if (c / 8 < *p + && (p[1 + (c/8)] & (1 << (c % 8)))) + { + /* Are we starting a range? */ + if (last + 1 == c && ! in_range) + { + putchar ('-'); + in_range = 1; + } + /* Have we broken a range? */ + else if (last + 1 != c && in_range) + { + putchar (last); + in_range = 0; + } + + if (! in_range) + putchar (c); + + last = c; + } + + if (in_range) + putchar (last); + + putchar (']'); + + p += 1 + *p; + } + break; + + case begline: + printf ("/begline"); + break; + + case endline: + printf ("/endline"); + break; + + case on_failure_jump: + extract_number_and_incr (&mcnt, &p); +#ifdef _LIBC + printf ("/on_failure_jump to %t", p + mcnt - start); +#else + printf ("/on_failure_jump to %ld", (long int) (p + mcnt - start)); +#endif + break; + + case on_failure_keep_string_jump: + extract_number_and_incr (&mcnt, &p); +#ifdef _LIBC + printf ("/on_failure_keep_string_jump to %t", p + mcnt - start); +#else + printf ("/on_failure_keep_string_jump to %ld", + (long int) (p + mcnt - start)); +#endif + break; + + case dummy_failure_jump: + extract_number_and_incr (&mcnt, &p); +#ifdef _LIBC + printf ("/dummy_failure_jump to %t", p + mcnt - start); +#else + printf ("/dummy_failure_jump to %ld", (long int) (p + mcnt - start)); +#endif + break; + + case push_dummy_failure: + printf ("/push_dummy_failure"); + break; + + case maybe_pop_jump: + extract_number_and_incr (&mcnt, &p); +#ifdef _LIBC + printf ("/maybe_pop_jump to %t", p + mcnt - start); +#else + printf ("/maybe_pop_jump to %ld", (long int) (p + mcnt - start)); +#endif + break; + + case pop_failure_jump: + extract_number_and_incr (&mcnt, &p); +#ifdef _LIBC + printf ("/pop_failure_jump to %t", p + mcnt - start); +#else + printf ("/pop_failure_jump to %ld", (long int) (p + mcnt - start)); +#endif + break; + + case jump_past_alt: + extract_number_and_incr (&mcnt, &p); +#ifdef _LIBC + printf ("/jump_past_alt to %t", p + mcnt - start); +#else + printf ("/jump_past_alt to %ld", (long int) (p + mcnt - start)); +#endif + break; + + case jump: + extract_number_and_incr (&mcnt, &p); +#ifdef _LIBC + printf ("/jump to %t", p + mcnt - start); +#else + printf ("/jump to %ld", (long int) (p + mcnt - start)); +#endif + break; + + case succeed_n: + extract_number_and_incr (&mcnt, &p); + p1 = p + mcnt; + extract_number_and_incr (&mcnt2, &p); +#ifdef _LIBC + printf ("/succeed_n to %t, %d times", p1 - start, mcnt2); +#else + printf ("/succeed_n to %ld, %d times", + (long int) (p1 - start), mcnt2); +#endif + break; + + case jump_n: + extract_number_and_incr (&mcnt, &p); + p1 = p + mcnt; + extract_number_and_incr (&mcnt2, &p); + printf ("/jump_n to %d, %d times", p1 - start, mcnt2); + break; + + case set_number_at: + extract_number_and_incr (&mcnt, &p); + p1 = p + mcnt; + extract_number_and_incr (&mcnt2, &p); +#ifdef _LIBC + printf ("/set_number_at location %t to %d", p1 - start, mcnt2); +#else + printf ("/set_number_at location %ld to %d", + (long int) (p1 - start), mcnt2); +#endif + break; + + case wordbound: + printf ("/wordbound"); + break; + + case notwordbound: + printf ("/notwordbound"); + break; + + case wordbeg: + printf ("/wordbeg"); + break; + + case wordend: + printf ("/wordend"); + +# ifdef emacs + case before_dot: + printf ("/before_dot"); + break; + + case at_dot: + printf ("/at_dot"); + break; + + case after_dot: + printf ("/after_dot"); + break; + + case syntaxspec: + printf ("/syntaxspec"); + mcnt = *p++; + printf ("/%d", mcnt); + break; + + case notsyntaxspec: + printf ("/notsyntaxspec"); + mcnt = *p++; + printf ("/%d", mcnt); + break; +# endif /* emacs */ + + case wordchar: + printf ("/wordchar"); + break; + + case notwordchar: + printf ("/notwordchar"); + break; + + case begbuf: + printf ("/begbuf"); + break; + + case endbuf: + printf ("/endbuf"); + break; + + default: + printf ("?%d", *(p-1)); + } + + putchar ('\n'); + } + +#ifdef _LIBC + printf ("%t:\tend of pattern.\n", p - start); +#else + printf ("%ld:\tend of pattern.\n", (long int) (p - start)); +#endif +} + + +void +print_compiled_pattern (bufp) + struct re_pattern_buffer *bufp; +{ + unsigned char *buffer = bufp->buffer; + + print_partial_compiled_pattern (buffer, buffer + bufp->used); + printf ("%ld bytes used/%ld bytes allocated.\n", + bufp->used, bufp->allocated); + + if (bufp->fastmap_accurate && bufp->fastmap) + { + printf ("fastmap: "); + print_fastmap (bufp->fastmap); + } + +#ifdef _LIBC + printf ("re_nsub: %Zd\t", bufp->re_nsub); +#else + printf ("re_nsub: %ld\t", (long int) bufp->re_nsub); +#endif + printf ("regs_alloc: %d\t", bufp->regs_allocated); + printf ("can_be_null: %d\t", bufp->can_be_null); + printf ("newline_anchor: %d\n", bufp->newline_anchor); + printf ("no_sub: %d\t", bufp->no_sub); + printf ("not_bol: %d\t", bufp->not_bol); + printf ("not_eol: %d\t", bufp->not_eol); + printf ("syntax: %lx\n", bufp->syntax); + /* Perhaps we should print the translate table? */ +} + + +void +print_double_string (where, string1, size1, string2, size2) + const char *where; + const char *string1; + const char *string2; + int size1; + int size2; +{ + int this_char; + + if (where == NULL) + printf ("(null)"); + else + { + if (FIRST_STRING_P (where)) + { + for (this_char = where - string1; this_char < size1; this_char++) + putchar (string1[this_char]); + + where = string2; + } + + for (this_char = where - string2; this_char < size2; this_char++) + putchar (string2[this_char]); + } +} + +void +printchar (c) + int c; +{ + putc (c, stderr); +} + +#else /* not DEBUG */ + +# undef assert +# define assert(e) + +# define DEBUG_STATEMENT(e) +# define DEBUG_PRINT1(x) +# define DEBUG_PRINT2(x1, x2) +# define DEBUG_PRINT3(x1, x2, x3) +# define DEBUG_PRINT4(x1, x2, x3, x4) +# define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) +# define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2) + +#endif /* not DEBUG */ + +/* Set by `re_set_syntax' to the current regexp syntax to recognize. Can + also be assigned to arbitrarily: each pattern buffer stores its own + syntax, so it can be changed between regex compilations. */ +/* This has no initializer because initialized variables in Emacs + become read-only after dumping. */ +reg_syntax_t re_syntax_options; + + +/* Specify the precise syntax of regexps for compilation. This provides + for compatibility for various utilities which historically have + different, incompatible syntaxes. + + The argument SYNTAX is a bit mask comprised of the various bits + defined in regex.h. We return the old syntax. */ + +reg_syntax_t +re_set_syntax (syntax) + reg_syntax_t syntax; +{ + reg_syntax_t ret = re_syntax_options; + + re_syntax_options = syntax; +#ifdef DEBUG + if (syntax & RE_DEBUG) + debug = 1; + else if (debug) /* was on but now is not */ + debug = 0; +#endif /* DEBUG */ + return ret; +} +#ifdef _LIBC +weak_alias (__re_set_syntax, re_set_syntax) +#endif + +/* This table gives an error message for each of the error codes listed + in regex.h. Obviously the order here has to be same as there. + POSIX doesn't require that we do anything for REG_NOERROR, + but why not be nice? */ + +static const char re_error_msgid[] = + { +#define REG_NOERROR_IDX 0 + gettext_noop ("Success") /* REG_NOERROR */ + "\0" +#define REG_NOMATCH_IDX (REG_NOERROR_IDX + sizeof "Success") + gettext_noop ("No match") /* REG_NOMATCH */ + "\0" +#define REG_BADPAT_IDX (REG_NOMATCH_IDX + sizeof "No match") + gettext_noop ("Invalid regular expression") /* REG_BADPAT */ + "\0" +#define REG_ECOLLATE_IDX (REG_BADPAT_IDX + sizeof "Invalid regular expression") + gettext_noop ("Invalid collation character") /* REG_ECOLLATE */ + "\0" +#define REG_ECTYPE_IDX (REG_ECOLLATE_IDX + sizeof "Invalid collation character") + gettext_noop ("Invalid character class name") /* REG_ECTYPE */ + "\0" +#define REG_EESCAPE_IDX (REG_ECTYPE_IDX + sizeof "Invalid character class name") + gettext_noop ("Trailing backslash") /* REG_EESCAPE */ + "\0" +#define REG_ESUBREG_IDX (REG_EESCAPE_IDX + sizeof "Trailing backslash") + gettext_noop ("Invalid back reference") /* REG_ESUBREG */ + "\0" +#define REG_EBRACK_IDX (REG_ESUBREG_IDX + sizeof "Invalid back reference") + gettext_noop ("Unmatched [ or [^") /* REG_EBRACK */ + "\0" +#define REG_EPAREN_IDX (REG_EBRACK_IDX + sizeof "Unmatched [ or [^") + gettext_noop ("Unmatched ( or \\(") /* REG_EPAREN */ + "\0" +#define REG_EBRACE_IDX (REG_EPAREN_IDX + sizeof "Unmatched ( or \\(") + gettext_noop ("Unmatched \\{") /* REG_EBRACE */ + "\0" +#define REG_BADBR_IDX (REG_EBRACE_IDX + sizeof "Unmatched \\{") + gettext_noop ("Invalid content of \\{\\}") /* REG_BADBR */ + "\0" +#define REG_ERANGE_IDX (REG_BADBR_IDX + sizeof "Invalid content of \\{\\}") + gettext_noop ("Invalid range end") /* REG_ERANGE */ + "\0" +#define REG_ESPACE_IDX (REG_ERANGE_IDX + sizeof "Invalid range end") + gettext_noop ("Memory exhausted") /* REG_ESPACE */ + "\0" +#define REG_BADRPT_IDX (REG_ESPACE_IDX + sizeof "Memory exhausted") + gettext_noop ("Invalid preceding regular expression") /* REG_BADRPT */ + "\0" +#define REG_EEND_IDX (REG_BADRPT_IDX + sizeof "Invalid preceding regular expression") + gettext_noop ("Premature end of regular expression") /* REG_EEND */ + "\0" +#define REG_ESIZE_IDX (REG_EEND_IDX + sizeof "Premature end of regular expression") + gettext_noop ("Regular expression too big") /* REG_ESIZE */ + "\0" +#define REG_ERPAREN_IDX (REG_ESIZE_IDX + sizeof "Regular expression too big") + gettext_noop ("Unmatched ) or \\)") /* REG_ERPAREN */ + }; + +static const size_t re_error_msgid_idx[] = + { + REG_NOERROR_IDX, + REG_NOMATCH_IDX, + REG_BADPAT_IDX, + REG_ECOLLATE_IDX, + REG_ECTYPE_IDX, + REG_EESCAPE_IDX, + REG_ESUBREG_IDX, + REG_EBRACK_IDX, + REG_EPAREN_IDX, + REG_EBRACE_IDX, + REG_BADBR_IDX, + REG_ERANGE_IDX, + REG_ESPACE_IDX, + REG_BADRPT_IDX, + REG_EEND_IDX, + REG_ESIZE_IDX, + REG_ERPAREN_IDX + }; + +/* Avoiding alloca during matching, to placate r_alloc. */ + +/* Define MATCH_MAY_ALLOCATE unless we need to make sure that the + searching and matching functions should not call alloca. On some + systems, alloca is implemented in terms of malloc, and if we're + using the relocating allocator routines, then malloc could cause a + relocation, which might (if the strings being searched are in the + ralloc heap) shift the data out from underneath the regexp + routines. + + Here's another reason to avoid allocation: Emacs + processes input from X in a signal handler; processing X input may + call malloc; if input arrives while a matching routine is calling + malloc, then we're scrod. But Emacs can't just block input while + calling matching routines; then we don't notice interrupts when + they come in. So, Emacs blocks input around all regexp calls + except the matching calls, which it leaves unprotected, in the + faith that they will not malloc. */ + +/* Normally, this is fine. */ +#define MATCH_MAY_ALLOCATE + +/* When using GNU C, we are not REALLY using the C alloca, no matter + what config.h may say. So don't take precautions for it. */ +#ifdef __GNUC__ +# undef C_ALLOCA +#endif + +/* The match routines may not allocate if (1) they would do it with malloc + and (2) it's not safe for them to use malloc. + Note that if REL_ALLOC is defined, matching would not use malloc for the + failure stack, but we would still use it for the register vectors; + so REL_ALLOC should not affect this. */ +#if (defined C_ALLOCA || defined REGEX_MALLOC) && defined emacs +# undef MATCH_MAY_ALLOCATE +#endif + + +/* Failure stack declarations and macros; both re_compile_fastmap and + re_match_2 use a failure stack. These have to be macros because of + REGEX_ALLOCATE_STACK. */ + + +/* Number of failure points for which to initially allocate space + when matching. If this number is exceeded, we allocate more + space, so it is not a hard limit. */ +#ifndef INIT_FAILURE_ALLOC +# define INIT_FAILURE_ALLOC 5 +#endif + +/* Roughly the maximum number of failure points on the stack. Would be + exactly that if always used MAX_FAILURE_ITEMS items each time we failed. + This is a variable only so users of regex can assign to it; we never + change it ourselves. */ + +#ifdef INT_IS_16BIT + +# if defined MATCH_MAY_ALLOCATE +/* 4400 was enough to cause a crash on Alpha OSF/1, + whose default stack limit is 2mb. */ +long int re_max_failures = 4000; +# else +long int re_max_failures = 2000; +# endif + +union fail_stack_elt +{ + unsigned char *pointer; + long int integer; +}; + +typedef union fail_stack_elt fail_stack_elt_t; + +typedef struct +{ + fail_stack_elt_t *stack; + unsigned long int size; + unsigned long int avail; /* Offset of next open position. */ +} fail_stack_type; + +#else /* not INT_IS_16BIT */ + +# if defined MATCH_MAY_ALLOCATE +/* 4400 was enough to cause a crash on Alpha OSF/1, + whose default stack limit is 2mb. */ +int re_max_failures = 4000; +# else +int re_max_failures = 2000; +# endif + +union fail_stack_elt +{ + unsigned char *pointer; + int integer; +}; + +typedef union fail_stack_elt fail_stack_elt_t; + +typedef struct +{ + fail_stack_elt_t *stack; + unsigned size; + unsigned avail; /* Offset of next open position. */ +} fail_stack_type; + +#endif /* INT_IS_16BIT */ + +#define FAIL_STACK_EMPTY() (fail_stack.avail == 0) +#define FAIL_STACK_PTR_EMPTY() (fail_stack_ptr->avail == 0) +#define FAIL_STACK_FULL() (fail_stack.avail == fail_stack.size) + + +/* Define macros to initialize and free the failure stack. + Do `return -2' if the alloc fails. */ + +#ifdef MATCH_MAY_ALLOCATE +# define INIT_FAIL_STACK() \ + do { \ + fail_stack.stack = (fail_stack_elt_t *) \ + REGEX_ALLOCATE_STACK (INIT_FAILURE_ALLOC * sizeof (fail_stack_elt_t)); \ + \ + if (fail_stack.stack == NULL) \ + return -2; \ + \ + fail_stack.size = INIT_FAILURE_ALLOC; \ + fail_stack.avail = 0; \ + } while (0) + +# define RESET_FAIL_STACK() REGEX_FREE_STACK (fail_stack.stack) +#else +# define INIT_FAIL_STACK() \ + do { \ + fail_stack.avail = 0; \ + } while (0) + +# define RESET_FAIL_STACK() +#endif + + +/* Double the size of FAIL_STACK, up to approximately `re_max_failures' items. + + Return 1 if succeeds, and 0 if either ran out of memory + allocating space for it or it was already too large. + + REGEX_REALLOCATE_STACK requires `destination' be declared. */ + +#define DOUBLE_FAIL_STACK(fail_stack) \ + ((fail_stack).size > (unsigned) (re_max_failures * MAX_FAILURE_ITEMS) \ + ? 0 \ + : ((fail_stack).stack = (fail_stack_elt_t *) \ + REGEX_REALLOCATE_STACK ((fail_stack).stack, \ + (fail_stack).size * sizeof (fail_stack_elt_t), \ + ((fail_stack).size << 1) * sizeof (fail_stack_elt_t)), \ + \ + (fail_stack).stack == NULL \ + ? 0 \ + : ((fail_stack).size <<= 1, \ + 1))) + + +/* Push pointer POINTER on FAIL_STACK. + Return 1 if was able to do so and 0 if ran out of memory allocating + space to do so. */ +#define PUSH_PATTERN_OP(POINTER, FAIL_STACK) \ + ((FAIL_STACK_FULL () \ + && !DOUBLE_FAIL_STACK (FAIL_STACK)) \ + ? 0 \ + : ((FAIL_STACK).stack[(FAIL_STACK).avail++].pointer = POINTER, \ + 1)) + +/* Push a pointer value onto the failure stack. + Assumes the variable `fail_stack'. Probably should only + be called from within `PUSH_FAILURE_POINT'. */ +#define PUSH_FAILURE_POINTER(item) \ + fail_stack.stack[fail_stack.avail++].pointer = (unsigned char *) (item) + +/* This pushes an integer-valued item onto the failure stack. + Assumes the variable `fail_stack'. Probably should only + be called from within `PUSH_FAILURE_POINT'. */ +#define PUSH_FAILURE_INT(item) \ + fail_stack.stack[fail_stack.avail++].integer = (item) + +/* Push a fail_stack_elt_t value onto the failure stack. + Assumes the variable `fail_stack'. Probably should only + be called from within `PUSH_FAILURE_POINT'. */ +#define PUSH_FAILURE_ELT(item) \ + fail_stack.stack[fail_stack.avail++] = (item) + +/* These three POP... operations complement the three PUSH... operations. + All assume that `fail_stack' is nonempty. */ +#define POP_FAILURE_POINTER() fail_stack.stack[--fail_stack.avail].pointer +#define POP_FAILURE_INT() fail_stack.stack[--fail_stack.avail].integer +#define POP_FAILURE_ELT() fail_stack.stack[--fail_stack.avail] + +/* Used to omit pushing failure point id's when we're not debugging. */ +#ifdef DEBUG +# define DEBUG_PUSH PUSH_FAILURE_INT +# define DEBUG_POP(item_addr) *(item_addr) = POP_FAILURE_INT () +#else +# define DEBUG_PUSH(item) +# define DEBUG_POP(item_addr) +#endif + + +/* Push the information about the state we will need + if we ever fail back to it. + + Requires variables fail_stack, regstart, regend, reg_info, and + num_regs_pushed be declared. DOUBLE_FAIL_STACK requires `destination' + be declared. + + Does `return FAILURE_CODE' if runs out of memory. */ + +#define PUSH_FAILURE_POINT(pattern_place, string_place, failure_code) \ + do { \ + char *destination; \ + /* Must be int, so when we don't save any registers, the arithmetic \ + of 0 + -1 isn't done as unsigned. */ \ + /* Can't be int, since there is not a shred of a guarantee that int \ + is wide enough to hold a value of something to which pointer can \ + be assigned */ \ + active_reg_t this_reg; \ + \ + DEBUG_STATEMENT (failure_id++); \ + DEBUG_STATEMENT (nfailure_points_pushed++); \ + DEBUG_PRINT2 ("\nPUSH_FAILURE_POINT #%u:\n", failure_id); \ + DEBUG_PRINT2 (" Before push, next avail: %d\n", (fail_stack).avail);\ + DEBUG_PRINT2 (" size: %d\n", (fail_stack).size);\ + \ + DEBUG_PRINT2 (" slots needed: %ld\n", NUM_FAILURE_ITEMS); \ + DEBUG_PRINT2 (" available: %d\n", REMAINING_AVAIL_SLOTS); \ + \ + /* Ensure we have enough space allocated for what we will push. */ \ + while (REMAINING_AVAIL_SLOTS < NUM_FAILURE_ITEMS) \ + { \ + if (!DOUBLE_FAIL_STACK (fail_stack)) \ + return failure_code; \ + \ + DEBUG_PRINT2 ("\n Doubled stack; size now: %d\n", \ + (fail_stack).size); \ + DEBUG_PRINT2 (" slots available: %d\n", REMAINING_AVAIL_SLOTS);\ + } \ + \ + /* Push the info, starting with the registers. */ \ + DEBUG_PRINT1 ("\n"); \ + \ + if (1) \ + for (this_reg = lowest_active_reg; this_reg <= highest_active_reg; \ + this_reg++) \ + { \ + DEBUG_PRINT2 (" Pushing reg: %lu\n", this_reg); \ + DEBUG_STATEMENT (num_regs_pushed++); \ + \ + DEBUG_PRINT2 (" start: %p\n", regstart[this_reg]); \ + PUSH_FAILURE_POINTER (regstart[this_reg]); \ + \ + DEBUG_PRINT2 (" end: %p\n", regend[this_reg]); \ + PUSH_FAILURE_POINTER (regend[this_reg]); \ + \ + DEBUG_PRINT2 (" info: %p\n ", \ + reg_info[this_reg].word.pointer); \ + DEBUG_PRINT2 (" match_null=%d", \ + REG_MATCH_NULL_STRING_P (reg_info[this_reg])); \ + DEBUG_PRINT2 (" active=%d", IS_ACTIVE (reg_info[this_reg])); \ + DEBUG_PRINT2 (" matched_something=%d", \ + MATCHED_SOMETHING (reg_info[this_reg])); \ + DEBUG_PRINT2 (" ever_matched=%d", \ + EVER_MATCHED_SOMETHING (reg_info[this_reg])); \ + DEBUG_PRINT1 ("\n"); \ + PUSH_FAILURE_ELT (reg_info[this_reg].word); \ + } \ + \ + DEBUG_PRINT2 (" Pushing low active reg: %ld\n", lowest_active_reg);\ + PUSH_FAILURE_INT (lowest_active_reg); \ + \ + DEBUG_PRINT2 (" Pushing high active reg: %ld\n", highest_active_reg);\ + PUSH_FAILURE_INT (highest_active_reg); \ + \ + DEBUG_PRINT2 (" Pushing pattern %p:\n", pattern_place); \ + DEBUG_PRINT_COMPILED_PATTERN (bufp, pattern_place, pend); \ + PUSH_FAILURE_POINTER (pattern_place); \ + \ + DEBUG_PRINT2 (" Pushing string %p: `", string_place); \ + DEBUG_PRINT_DOUBLE_STRING (string_place, string1, size1, string2, \ + size2); \ + DEBUG_PRINT1 ("'\n"); \ + PUSH_FAILURE_POINTER (string_place); \ + \ + DEBUG_PRINT2 (" Pushing failure id: %u\n", failure_id); \ + DEBUG_PUSH (failure_id); \ + } while (0) + +/* This is the number of items that are pushed and popped on the stack + for each register. */ +#define NUM_REG_ITEMS 3 + +/* Individual items aside from the registers. */ +#ifdef DEBUG +# define NUM_NONREG_ITEMS 5 /* Includes failure point id. */ +#else +# define NUM_NONREG_ITEMS 4 +#endif + +/* We push at most this many items on the stack. */ +/* We used to use (num_regs - 1), which is the number of registers + this regexp will save; but that was changed to 5 + to avoid stack overflow for a regexp with lots of parens. */ +#define MAX_FAILURE_ITEMS (5 * NUM_REG_ITEMS + NUM_NONREG_ITEMS) + +/* We actually push this many items. */ +#define NUM_FAILURE_ITEMS \ + (((0 \ + ? 0 : highest_active_reg - lowest_active_reg + 1) \ + * NUM_REG_ITEMS) \ + + NUM_NONREG_ITEMS) + +/* How many items can still be added to the stack without overflowing it. */ +#define REMAINING_AVAIL_SLOTS ((fail_stack).size - (fail_stack).avail) + + +/* Pops what PUSH_FAIL_STACK pushes. + + We restore into the parameters, all of which should be lvalues: + STR -- the saved data position. + PAT -- the saved pattern position. + LOW_REG, HIGH_REG -- the highest and lowest active registers. + REGSTART, REGEND -- arrays of string positions. + REG_INFO -- array of information about each subexpression. + + Also assumes the variables `fail_stack' and (if debugging), `bufp', + `pend', `string1', `size1', `string2', and `size2'. */ + +#define POP_FAILURE_POINT(str, pat, low_reg, high_reg, regstart, regend, reg_info)\ +{ \ + DEBUG_STATEMENT (unsigned failure_id;) \ + active_reg_t this_reg; \ + const unsigned char *string_temp; \ + \ + assert (!FAIL_STACK_EMPTY ()); \ + \ + /* Remove failure points and point to how many regs pushed. */ \ + DEBUG_PRINT1 ("POP_FAILURE_POINT:\n"); \ + DEBUG_PRINT2 (" Before pop, next avail: %d\n", fail_stack.avail); \ + DEBUG_PRINT2 (" size: %d\n", fail_stack.size); \ + \ + assert (fail_stack.avail >= NUM_NONREG_ITEMS); \ + \ + DEBUG_POP (&failure_id); \ + DEBUG_PRINT2 (" Popping failure id: %u\n", failure_id); \ + \ + /* If the saved string location is NULL, it came from an \ + on_failure_keep_string_jump opcode, and we want to throw away the \ + saved NULL, thus retaining our current position in the string. */ \ + string_temp = POP_FAILURE_POINTER (); \ + if (string_temp != NULL) \ + str = (const char *) string_temp; \ + \ + DEBUG_PRINT2 (" Popping string %p: `", str); \ + DEBUG_PRINT_DOUBLE_STRING (str, string1, size1, string2, size2); \ + DEBUG_PRINT1 ("'\n"); \ + \ + pat = (unsigned char *) POP_FAILURE_POINTER (); \ + DEBUG_PRINT2 (" Popping pattern %p:\n", pat); \ + DEBUG_PRINT_COMPILED_PATTERN (bufp, pat, pend); \ + \ + /* Restore register info. */ \ + high_reg = (active_reg_t) POP_FAILURE_INT (); \ + DEBUG_PRINT2 (" Popping high active reg: %ld\n", high_reg); \ + \ + low_reg = (active_reg_t) POP_FAILURE_INT (); \ + DEBUG_PRINT2 (" Popping low active reg: %ld\n", low_reg); \ + \ + if (1) \ + for (this_reg = high_reg; this_reg >= low_reg; this_reg--) \ + { \ + DEBUG_PRINT2 (" Popping reg: %ld\n", this_reg); \ + \ + reg_info[this_reg].word = POP_FAILURE_ELT (); \ + DEBUG_PRINT2 (" info: %p\n", \ + reg_info[this_reg].word.pointer); \ + \ + regend[this_reg] = (const char *) POP_FAILURE_POINTER (); \ + DEBUG_PRINT2 (" end: %p\n", regend[this_reg]); \ + \ + regstart[this_reg] = (const char *) POP_FAILURE_POINTER (); \ + DEBUG_PRINT2 (" start: %p\n", regstart[this_reg]); \ + } \ + else \ + { \ + for (this_reg = highest_active_reg; this_reg > high_reg; this_reg--) \ + { \ + reg_info[this_reg].word.integer = 0; \ + regend[this_reg] = 0; \ + regstart[this_reg] = 0; \ + } \ + highest_active_reg = high_reg; \ + } \ + \ + set_regs_matched_done = 0; \ + DEBUG_STATEMENT (nfailure_points_popped++); \ +} /* POP_FAILURE_POINT */ + + + +/* Structure for per-register (a.k.a. per-group) information. + Other register information, such as the + starting and ending positions (which are addresses), and the list of + inner groups (which is a bits list) are maintained in separate + variables. + + We are making a (strictly speaking) nonportable assumption here: that + the compiler will pack our bit fields into something that fits into + the type of `word', i.e., is something that fits into one item on the + failure stack. */ + + +/* Declarations and macros for re_match_2. */ + +typedef union +{ + fail_stack_elt_t word; + struct + { + /* This field is one if this group can match the empty string, + zero if not. If not yet determined, `MATCH_NULL_UNSET_VALUE'. */ +#define MATCH_NULL_UNSET_VALUE 3 + unsigned match_null_string_p : 2; + unsigned is_active : 1; + unsigned matched_something : 1; + unsigned ever_matched_something : 1; + } bits; +} register_info_type; + +#define REG_MATCH_NULL_STRING_P(R) ((R).bits.match_null_string_p) +#define IS_ACTIVE(R) ((R).bits.is_active) +#define MATCHED_SOMETHING(R) ((R).bits.matched_something) +#define EVER_MATCHED_SOMETHING(R) ((R).bits.ever_matched_something) + + +/* Call this when have matched a real character; it sets `matched' flags + for the subexpressions which we are currently inside. Also records + that those subexprs have matched. */ +#define SET_REGS_MATCHED() \ + do \ + { \ + if (!set_regs_matched_done) \ + { \ + active_reg_t r; \ + set_regs_matched_done = 1; \ + for (r = lowest_active_reg; r <= highest_active_reg; r++) \ + { \ + MATCHED_SOMETHING (reg_info[r]) \ + = EVER_MATCHED_SOMETHING (reg_info[r]) \ + = 1; \ + } \ + } \ + } \ + while (0) + +/* Registers are set to a sentinel when they haven't yet matched. */ +static char reg_unset_dummy; +#define REG_UNSET_VALUE (®_unset_dummy) +#define REG_UNSET(e) ((e) == REG_UNSET_VALUE) + +/* Subroutine declarations and macros for regex_compile. */ + +static reg_errcode_t regex_compile _RE_ARGS ((const char *pattern, size_t size, + reg_syntax_t syntax, + struct re_pattern_buffer *bufp)); +static void store_op1 _RE_ARGS ((re_opcode_t op, unsigned char *loc, int arg)); +static void store_op2 _RE_ARGS ((re_opcode_t op, unsigned char *loc, + int arg1, int arg2)); +static void insert_op1 _RE_ARGS ((re_opcode_t op, unsigned char *loc, + int arg, unsigned char *end)); +static void insert_op2 _RE_ARGS ((re_opcode_t op, unsigned char *loc, + int arg1, int arg2, unsigned char *end)); +static boolean at_begline_loc_p _RE_ARGS ((const char *pattern, const char *p, + reg_syntax_t syntax)); +static boolean at_endline_loc_p _RE_ARGS ((const char *p, const char *pend, + reg_syntax_t syntax)); +static reg_errcode_t compile_range _RE_ARGS ((unsigned int range_start, + const char **p_ptr, + const char *pend, + char *translate, + reg_syntax_t syntax, + unsigned char *b)); + +/* Fetch the next character in the uncompiled pattern---translating it + if necessary. Also cast from a signed character in the constant + string passed to us by the user to an unsigned char that we can use + as an array index (in, e.g., `translate'). */ +#ifndef PATFETCH +# define PATFETCH(c) \ + do {if (p == pend) return REG_EEND; \ + c = (unsigned char) *p++; \ + if (translate) c = (unsigned char) translate[c]; \ + } while (0) +#endif + +/* Fetch the next character in the uncompiled pattern, with no + translation. */ +#define PATFETCH_RAW(c) \ + do {if (p == pend) return REG_EEND; \ + c = (unsigned char) *p++; \ + } while (0) + +/* Go backwards one character in the pattern. */ +#define PATUNFETCH p-- + + +/* If `translate' is non-null, return translate[D], else just D. We + cast the subscript to translate because some data is declared as + `char *', to avoid warnings when a string constant is passed. But + when we use a character as a subscript we must make it unsigned. */ +#ifndef TRANSLATE +# define TRANSLATE(d) \ + (translate ? (char) translate[(unsigned char) (d)] : (d)) +#endif + + +/* Macros for outputting the compiled pattern into `buffer'. */ + +/* If the buffer isn't allocated when it comes in, use this. */ +#define INIT_BUF_SIZE 32 + +/* Make sure we have at least N more bytes of space in buffer. */ +#define GET_BUFFER_SPACE(n) \ + while ((unsigned long) (b - bufp->buffer + (n)) > bufp->allocated) \ + EXTEND_BUFFER () + +/* Make sure we have one more byte of buffer space and then add C to it. */ +#define BUF_PUSH(c) \ + do { \ + GET_BUFFER_SPACE (1); \ + *b++ = (unsigned char) (c); \ + } while (0) + + +/* Ensure we have two more bytes of buffer space and then append C1 and C2. */ +#define BUF_PUSH_2(c1, c2) \ + do { \ + GET_BUFFER_SPACE (2); \ + *b++ = (unsigned char) (c1); \ + *b++ = (unsigned char) (c2); \ + } while (0) + + +/* As with BUF_PUSH_2, except for three bytes. */ +#define BUF_PUSH_3(c1, c2, c3) \ + do { \ + GET_BUFFER_SPACE (3); \ + *b++ = (unsigned char) (c1); \ + *b++ = (unsigned char) (c2); \ + *b++ = (unsigned char) (c3); \ + } while (0) + + +/* Store a jump with opcode OP at LOC to location TO. We store a + relative address offset by the three bytes the jump itself occupies. */ +#define STORE_JUMP(op, loc, to) \ + store_op1 (op, loc, (int) ((to) - (loc) - 3)) + +/* Likewise, for a two-argument jump. */ +#define STORE_JUMP2(op, loc, to, arg) \ + store_op2 (op, loc, (int) ((to) - (loc) - 3), arg) + +/* Like `STORE_JUMP', but for inserting. Assume `b' is the buffer end. */ +#define INSERT_JUMP(op, loc, to) \ + insert_op1 (op, loc, (int) ((to) - (loc) - 3), b) + +/* Like `STORE_JUMP2', but for inserting. Assume `b' is the buffer end. */ +#define INSERT_JUMP2(op, loc, to, arg) \ + insert_op2 (op, loc, (int) ((to) - (loc) - 3), arg, b) + + +/* This is not an arbitrary limit: the arguments which represent offsets + into the pattern are two bytes long. So if 2^16 bytes turns out to + be too small, many things would have to change. */ +/* Any other compiler which, like MSC, has allocation limit below 2^16 + bytes will have to use approach similar to what was done below for + MSC and drop MAX_BUF_SIZE a bit. Otherwise you may end up + reallocating to 0 bytes. Such thing is not going to work too well. + You have been warned!! */ +#if defined _MSC_VER && !defined WIN32 +/* Microsoft C 16-bit versions limit malloc to approx 65512 bytes. + The REALLOC define eliminates a flurry of conversion warnings, + but is not required. */ +# define MAX_BUF_SIZE 65500L +# define REALLOC(p,s) realloc ((p), (size_t) (s)) +#else +# define MAX_BUF_SIZE (1L << 16) +# define REALLOC(p,s) realloc ((p), (s)) +#endif + +/* Extend the buffer by twice its current size via realloc and + reset the pointers that pointed into the old block to point to the + correct places in the new one. If extending the buffer results in it + being larger than MAX_BUF_SIZE, then flag memory exhausted. */ +#if __BOUNDED_POINTERS__ +# define SET_HIGH_BOUND(P) (__ptrhigh (P) = __ptrlow (P) + bufp->allocated) +# define MOVE_BUFFER_POINTER(P) \ + (__ptrlow (P) += incr, SET_HIGH_BOUND (P), __ptrvalue (P) += incr) +# define ELSE_EXTEND_BUFFER_HIGH_BOUND \ + else \ + { \ + SET_HIGH_BOUND (b); \ + SET_HIGH_BOUND (begalt); \ + if (fixup_alt_jump) \ + SET_HIGH_BOUND (fixup_alt_jump); \ + if (laststart) \ + SET_HIGH_BOUND (laststart); \ + if (pending_exact) \ + SET_HIGH_BOUND (pending_exact); \ + } +#else +# define MOVE_BUFFER_POINTER(P) (P) += incr +# define ELSE_EXTEND_BUFFER_HIGH_BOUND +#endif +#define EXTEND_BUFFER() \ + do { \ + unsigned char *old_buffer = bufp->buffer; \ + if (bufp->allocated == MAX_BUF_SIZE) \ + return REG_ESIZE; \ + bufp->allocated <<= 1; \ + if (bufp->allocated > MAX_BUF_SIZE) \ + bufp->allocated = MAX_BUF_SIZE; \ + bufp->buffer = (unsigned char *) REALLOC (bufp->buffer, bufp->allocated);\ + if (bufp->buffer == NULL) \ + return REG_ESPACE; \ + /* If the buffer moved, move all the pointers into it. */ \ + if (old_buffer != bufp->buffer) \ + { \ + int incr = bufp->buffer - old_buffer; \ + MOVE_BUFFER_POINTER (b); \ + MOVE_BUFFER_POINTER (begalt); \ + if (fixup_alt_jump) \ + MOVE_BUFFER_POINTER (fixup_alt_jump); \ + if (laststart) \ + MOVE_BUFFER_POINTER (laststart); \ + if (pending_exact) \ + MOVE_BUFFER_POINTER (pending_exact); \ + } \ + ELSE_EXTEND_BUFFER_HIGH_BOUND \ + } while (0) + + +/* Since we have one byte reserved for the register number argument to + {start,stop}_memory, the maximum number of groups we can report + things about is what fits in that byte. */ +#define MAX_REGNUM 255 + +/* But patterns can have more than `MAX_REGNUM' registers. We just + ignore the excess. */ +typedef unsigned regnum_t; + + +/* Macros for the compile stack. */ + +/* Since offsets can go either forwards or backwards, this type needs to + be able to hold values from -(MAX_BUF_SIZE - 1) to MAX_BUF_SIZE - 1. */ +/* int may be not enough when sizeof(int) == 2. */ +typedef long pattern_offset_t; + +typedef struct +{ + pattern_offset_t begalt_offset; + pattern_offset_t fixup_alt_jump; + pattern_offset_t inner_group_offset; + pattern_offset_t laststart_offset; + regnum_t regnum; +} compile_stack_elt_t; + + +typedef struct +{ + compile_stack_elt_t *stack; + unsigned size; + unsigned avail; /* Offset of next open position. */ +} compile_stack_type; + + +#define INIT_COMPILE_STACK_SIZE 32 + +#define COMPILE_STACK_EMPTY (compile_stack.avail == 0) +#define COMPILE_STACK_FULL (compile_stack.avail == compile_stack.size) + +/* The next available element. */ +#define COMPILE_STACK_TOP (compile_stack.stack[compile_stack.avail]) + + +/* Set the bit for character C in a list. */ +#define SET_LIST_BIT(c) \ + (b[((unsigned char) (c)) / BYTEWIDTH] \ + |= 1 << (((unsigned char) c) % BYTEWIDTH)) + + +/* Get the next unsigned number in the uncompiled pattern. */ +#define GET_UNSIGNED_NUMBER(num) \ + { if (p != pend) \ + { \ + PATFETCH (c); \ + while ('0' <= c && c <= '9') \ + { \ + if (num < 0) \ + num = 0; \ + num = num * 10 + c - '0'; \ + if (p == pend) \ + break; \ + PATFETCH (c); \ + } \ + } \ + } + +#if defined _LIBC || WIDE_CHAR_SUPPORT +/* The GNU C library provides support for user-defined character classes + and the functions from ISO C amendement 1. */ +# ifdef CHARCLASS_NAME_MAX +# define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX +# else +/* This shouldn't happen but some implementation might still have this + problem. Use a reasonable default value. */ +# define CHAR_CLASS_MAX_LENGTH 256 +# endif + +# ifdef _LIBC +# define IS_CHAR_CLASS(string) __wctype (string) +# else +# define IS_CHAR_CLASS(string) wctype (string) +# endif +#else +# define CHAR_CLASS_MAX_LENGTH 6 /* Namely, `xdigit'. */ + +# define IS_CHAR_CLASS(string) \ + (STREQ (string, "alpha") || STREQ (string, "upper") \ + || STREQ (string, "lower") || STREQ (string, "digit") \ + || STREQ (string, "alnum") || STREQ (string, "xdigit") \ + || STREQ (string, "space") || STREQ (string, "print") \ + || STREQ (string, "punct") || STREQ (string, "graph") \ + || STREQ (string, "cntrl") || STREQ (string, "blank")) +#endif + +#ifndef MATCH_MAY_ALLOCATE + +/* If we cannot allocate large objects within re_match_2_internal, + we make the fail stack and register vectors global. + The fail stack, we grow to the maximum size when a regexp + is compiled. + The register vectors, we adjust in size each time we + compile a regexp, according to the number of registers it needs. */ + +static fail_stack_type fail_stack; + +/* Size with which the following vectors are currently allocated. + That is so we can make them bigger as needed, + but never make them smaller. */ +static int regs_allocated_size; + +static const char ** regstart, ** regend; +static const char ** old_regstart, ** old_regend; +static const char **best_regstart, **best_regend; +static register_info_type *reg_info; +static const char **reg_dummy; +static register_info_type *reg_info_dummy; + +/* Make the register vectors big enough for NUM_REGS registers, + but don't make them smaller. */ + +static +regex_grow_registers (num_regs) + int num_regs; +{ + if (num_regs > regs_allocated_size) + { + RETALLOC_IF (regstart, num_regs, const char *); + RETALLOC_IF (regend, num_regs, const char *); + RETALLOC_IF (old_regstart, num_regs, const char *); + RETALLOC_IF (old_regend, num_regs, const char *); + RETALLOC_IF (best_regstart, num_regs, const char *); + RETALLOC_IF (best_regend, num_regs, const char *); + RETALLOC_IF (reg_info, num_regs, register_info_type); + RETALLOC_IF (reg_dummy, num_regs, const char *); + RETALLOC_IF (reg_info_dummy, num_regs, register_info_type); + + regs_allocated_size = num_regs; + } +} + +#endif /* not MATCH_MAY_ALLOCATE */ + +static boolean group_in_compile_stack _RE_ARGS ((compile_stack_type + compile_stack, + regnum_t regnum)); + +/* `regex_compile' compiles PATTERN (of length SIZE) according to SYNTAX. + Returns one of error codes defined in `regex.h', or zero for success. + + Assumes the `allocated' (and perhaps `buffer') and `translate' + fields are set in BUFP on entry. + + If it succeeds, results are put in BUFP (if it returns an error, the + contents of BUFP are undefined): + `buffer' is the compiled pattern; + `syntax' is set to SYNTAX; + `used' is set to the length of the compiled pattern; + `fastmap_accurate' is zero; + `re_nsub' is the number of subexpressions in PATTERN; + `not_bol' and `not_eol' are zero; + + The `fastmap' and `newline_anchor' fields are neither + examined nor set. */ + +/* Return, freeing storage we allocated. */ +#define FREE_STACK_RETURN(value) \ + return (free (compile_stack.stack), value) + +static reg_errcode_t +regex_compile (pattern, size, syntax, bufp) + const char *pattern; + size_t size; + reg_syntax_t syntax; + struct re_pattern_buffer *bufp; +{ + /* We fetch characters from PATTERN here. Even though PATTERN is + `char *' (i.e., signed), we declare these variables as unsigned, so + they can be reliably used as array indices. */ + register unsigned char c, c1; + + /* A random temporary spot in PATTERN. */ + const char *p1; + + /* Points to the end of the buffer, where we should append. */ + register unsigned char *b; + + /* Keeps track of unclosed groups. */ + compile_stack_type compile_stack; + + /* Points to the current (ending) position in the pattern. */ + const char *p = pattern; + const char *pend = pattern + size; + + /* How to translate the characters in the pattern. */ + RE_TRANSLATE_TYPE translate = bufp->translate; + + /* Address of the count-byte of the most recently inserted `exactn' + command. This makes it possible to tell if a new exact-match + character can be added to that command or if the character requires + a new `exactn' command. */ + unsigned char *pending_exact = 0; + + /* Address of start of the most recently finished expression. + This tells, e.g., postfix * where to find the start of its + operand. Reset at the beginning of groups and alternatives. */ + unsigned char *laststart = 0; + + /* Address of beginning of regexp, or inside of last group. */ + unsigned char *begalt; + + /* Place in the uncompiled pattern (i.e., the {) to + which to go back if the interval is invalid. */ + const char *beg_interval; + + /* Address of the place where a forward jump should go to the end of + the containing expression. Each alternative of an `or' -- except the + last -- ends with a forward jump of this sort. */ + unsigned char *fixup_alt_jump = 0; + + /* Counts open-groups as they are encountered. Remembered for the + matching close-group on the compile stack, so the same register + number is put in the stop_memory as the start_memory. */ + regnum_t regnum = 0; + +#ifdef DEBUG + DEBUG_PRINT1 ("\nCompiling pattern: "); + if (debug) + { + unsigned debug_count; + + for (debug_count = 0; debug_count < size; debug_count++) + putchar (pattern[debug_count]); + putchar ('\n'); + } +#endif /* DEBUG */ + + /* Initialize the compile stack. */ + compile_stack.stack = TALLOC (INIT_COMPILE_STACK_SIZE, compile_stack_elt_t); + if (compile_stack.stack == NULL) + return REG_ESPACE; + + compile_stack.size = INIT_COMPILE_STACK_SIZE; + compile_stack.avail = 0; + + /* Initialize the pattern buffer. */ + bufp->syntax = syntax; + bufp->fastmap_accurate = 0; + bufp->not_bol = bufp->not_eol = 0; + + /* Set `used' to zero, so that if we return an error, the pattern + printer (for debugging) will think there's no pattern. We reset it + at the end. */ + bufp->used = 0; + + /* Always count groups, whether or not bufp->no_sub is set. */ + bufp->re_nsub = 0; + +#if !defined emacs && !defined SYNTAX_TABLE + /* Initialize the syntax table. */ + init_syntax_once (); +#endif + + if (bufp->allocated == 0) + { + if (bufp->buffer) + { /* If zero allocated, but buffer is non-null, try to realloc + enough space. This loses if buffer's address is bogus, but + that is the user's responsibility. */ + RETALLOC (bufp->buffer, INIT_BUF_SIZE, unsigned char); + } + else + { /* Caller did not allocate a buffer. Do it for them. */ + bufp->buffer = TALLOC (INIT_BUF_SIZE, unsigned char); + } + if (!bufp->buffer) FREE_STACK_RETURN (REG_ESPACE); + + bufp->allocated = INIT_BUF_SIZE; + } + + begalt = b = bufp->buffer; + + /* Loop through the uncompiled pattern until we're at the end. */ + while (p != pend) + { + PATFETCH (c); + + switch (c) + { + case '^': + { + if ( /* If at start of pattern, it's an operator. */ + p == pattern + 1 + /* If context independent, it's an operator. */ + || syntax & RE_CONTEXT_INDEP_ANCHORS + /* Otherwise, depends on what's come before. */ + || at_begline_loc_p (pattern, p, syntax)) + BUF_PUSH (begline); + else + goto normal_char; + } + break; + + + case '$': + { + if ( /* If at end of pattern, it's an operator. */ + p == pend + /* If context independent, it's an operator. */ + || syntax & RE_CONTEXT_INDEP_ANCHORS + /* Otherwise, depends on what's next. */ + || at_endline_loc_p (p, pend, syntax)) + BUF_PUSH (endline); + else + goto normal_char; + } + break; + + + case '+': + case '?': + if ((syntax & RE_BK_PLUS_QM) + || (syntax & RE_LIMITED_OPS)) + goto normal_char; + handle_plus: + case '*': + /* If there is no previous pattern... */ + if (!laststart) + { + if (syntax & RE_CONTEXT_INVALID_OPS) + FREE_STACK_RETURN (REG_BADRPT); + else if (!(syntax & RE_CONTEXT_INDEP_OPS)) + goto normal_char; + } + + { + /* Are we optimizing this jump? */ + boolean keep_string_p = false; + + /* 1 means zero (many) matches is allowed. */ + char zero_times_ok = 0, many_times_ok = 0; + + /* If there is a sequence of repetition chars, collapse it + down to just one (the right one). We can't combine + interval operators with these because of, e.g., `a{2}*', + which should only match an even number of `a's. */ + + for (;;) + { + zero_times_ok |= c != '+'; + many_times_ok |= c != '?'; + + if (p == pend) + break; + + PATFETCH (c); + + if (c == '*' + || (!(syntax & RE_BK_PLUS_QM) && (c == '+' || c == '?'))) + ; + + else if (syntax & RE_BK_PLUS_QM && c == '\\') + { + if (p == pend) FREE_STACK_RETURN (REG_EESCAPE); + + PATFETCH (c1); + if (!(c1 == '+' || c1 == '?')) + { + PATUNFETCH; + PATUNFETCH; + break; + } + + c = c1; + } + else + { + PATUNFETCH; + break; + } + + /* If we get here, we found another repeat character. */ + } + + /* Star, etc. applied to an empty pattern is equivalent + to an empty pattern. */ + if (!laststart) + break; + + /* Now we know whether or not zero matches is allowed + and also whether or not two or more matches is allowed. */ + if (many_times_ok) + { /* More than one repetition is allowed, so put in at the + end a backward relative jump from `b' to before the next + jump we're going to put in below (which jumps from + laststart to after this jump). + + But if we are at the `*' in the exact sequence `.*\n', + insert an unconditional jump backwards to the ., + instead of the beginning of the loop. This way we only + push a failure point once, instead of every time + through the loop. */ + assert (p - 1 > pattern); + + /* Allocate the space for the jump. */ + GET_BUFFER_SPACE (3); + + /* We know we are not at the first character of the pattern, + because laststart was nonzero. And we've already + incremented `p', by the way, to be the character after + the `*'. Do we have to do something analogous here + for null bytes, because of RE_DOT_NOT_NULL? */ + if (TRANSLATE (*(p - 2)) == TRANSLATE ('.') + && zero_times_ok + && p < pend && TRANSLATE (*p) == TRANSLATE ('\n') + && !(syntax & RE_DOT_NEWLINE)) + { /* We have .*\n. */ + STORE_JUMP (jump, b, laststart); + keep_string_p = true; + } + else + /* Anything else. */ + STORE_JUMP (maybe_pop_jump, b, laststart - 3); + + /* We've added more stuff to the buffer. */ + b += 3; + } + + /* On failure, jump from laststart to b + 3, which will be the + end of the buffer after this jump is inserted. */ + GET_BUFFER_SPACE (3); + INSERT_JUMP (keep_string_p ? on_failure_keep_string_jump + : on_failure_jump, + laststart, b + 3); + pending_exact = 0; + b += 3; + + if (!zero_times_ok) + { + /* At least one repetition is required, so insert a + `dummy_failure_jump' before the initial + `on_failure_jump' instruction of the loop. This + effects a skip over that instruction the first time + we hit that loop. */ + GET_BUFFER_SPACE (3); + INSERT_JUMP (dummy_failure_jump, laststart, laststart + 6); + b += 3; + } + } + break; + + + case '.': + laststart = b; + BUF_PUSH (anychar); + break; + + + case '[': + { + boolean had_char_class = false; + unsigned int range_start = 0xffffffff; + + if (p == pend) FREE_STACK_RETURN (REG_EBRACK); + + /* Ensure that we have enough space to push a charset: the + opcode, the length count, and the bitset; 34 bytes in all. */ + GET_BUFFER_SPACE (34); + + laststart = b; + + /* We test `*p == '^' twice, instead of using an if + statement, so we only need one BUF_PUSH. */ + BUF_PUSH (*p == '^' ? charset_not : charset); + if (*p == '^') + p++; + + /* Remember the first position in the bracket expression. */ + p1 = p; + + /* Push the number of bytes in the bitmap. */ + BUF_PUSH ((1 << BYTEWIDTH) / BYTEWIDTH); + + /* Clear the whole map. */ + bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH); + + /* charset_not matches newline according to a syntax bit. */ + if ((re_opcode_t) b[-2] == charset_not + && (syntax & RE_HAT_LISTS_NOT_NEWLINE)) + SET_LIST_BIT ('\n'); + + /* Read in characters and ranges, setting map bits. */ + for (;;) + { + if (p == pend) FREE_STACK_RETURN (REG_EBRACK); + + PATFETCH (c); + + /* \ might escape characters inside [...] and [^...]. */ + if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\') + { + if (p == pend) FREE_STACK_RETURN (REG_EESCAPE); + + PATFETCH (c1); + SET_LIST_BIT (c1); + range_start = c1; + continue; + } + + /* Could be the end of the bracket expression. If it's + not (i.e., when the bracket expression is `[]' so + far), the ']' character bit gets set way below. */ + if (c == ']' && p != p1 + 1) + break; + + /* Look ahead to see if it's a range when the last thing + was a character class. */ + if (had_char_class && c == '-' && *p != ']') + FREE_STACK_RETURN (REG_ERANGE); + + /* Look ahead to see if it's a range when the last thing + was a character: if this is a hyphen not at the + beginning or the end of a list, then it's the range + operator. */ + if (c == '-' + && !(p - 2 >= pattern && p[-2] == '[') + && !(p - 3 >= pattern && p[-3] == '[' && p[-2] == '^') + && *p != ']') + { + reg_errcode_t ret + = compile_range (range_start, &p, pend, translate, + syntax, b); + if (ret != REG_NOERROR) FREE_STACK_RETURN (ret); + range_start = 0xffffffff; + } + + else if (p[0] == '-' && p[1] != ']') + { /* This handles ranges made up of characters only. */ + reg_errcode_t ret; + + /* Move past the `-'. */ + PATFETCH (c1); + + ret = compile_range (c, &p, pend, translate, syntax, b); + if (ret != REG_NOERROR) FREE_STACK_RETURN (ret); + range_start = 0xffffffff; + } + + /* See if we're at the beginning of a possible character + class. */ + + else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == ':') + { /* Leave room for the null. */ + char str[CHAR_CLASS_MAX_LENGTH + 1]; + + PATFETCH (c); + c1 = 0; + + /* If pattern is `[[:'. */ + if (p == pend) FREE_STACK_RETURN (REG_EBRACK); + + for (;;) + { + PATFETCH (c); + if ((c == ':' && *p == ']') || p == pend) + break; + if (c1 < CHAR_CLASS_MAX_LENGTH) + str[c1++] = c; + else + /* This is in any case an invalid class name. */ + str[0] = '\0'; + } + str[c1] = '\0'; + + /* If isn't a word bracketed by `[:' and `:]': + undo the ending character, the letters, and leave + the leading `:' and `[' (but set bits for them). */ + if (c == ':' && *p == ']') + { +#if defined _LIBC || WIDE_CHAR_SUPPORT + boolean is_lower = STREQ (str, "lower"); + boolean is_upper = STREQ (str, "upper"); + wctype_t wt; + int ch; + + wt = IS_CHAR_CLASS (str); + if (wt == 0) + FREE_STACK_RETURN (REG_ECTYPE); + + /* Throw away the ] at the end of the character + class. */ + PATFETCH (c); + + if (p == pend) FREE_STACK_RETURN (REG_EBRACK); + + for (ch = 0; ch < 1 << BYTEWIDTH; ++ch) + { +# ifdef _LIBC + if (__iswctype (__btowc (ch), wt)) + SET_LIST_BIT (ch); +# else + if (iswctype (btowc (ch), wt)) + SET_LIST_BIT (ch); +# endif + + if (translate && (is_upper || is_lower) + && (ISUPPER (ch) || ISLOWER (ch))) + SET_LIST_BIT (ch); + } + + had_char_class = true; +#else + int ch; + boolean is_alnum = STREQ (str, "alnum"); + boolean is_alpha = STREQ (str, "alpha"); + boolean is_blank = STREQ (str, "blank"); + boolean is_cntrl = STREQ (str, "cntrl"); + boolean is_digit = STREQ (str, "digit"); + boolean is_graph = STREQ (str, "graph"); + boolean is_lower = STREQ (str, "lower"); + boolean is_print = STREQ (str, "print"); + boolean is_punct = STREQ (str, "punct"); + boolean is_space = STREQ (str, "space"); + boolean is_upper = STREQ (str, "upper"); + boolean is_xdigit = STREQ (str, "xdigit"); + + if (!IS_CHAR_CLASS (str)) + FREE_STACK_RETURN (REG_ECTYPE); + + /* Throw away the ] at the end of the character + class. */ + PATFETCH (c); + + if (p == pend) FREE_STACK_RETURN (REG_EBRACK); + + for (ch = 0; ch < 1 << BYTEWIDTH; ch++) + { + /* This was split into 3 if's to + avoid an arbitrary limit in some compiler. */ + if ( (is_alnum && ISALNUM (ch)) + || (is_alpha && ISALPHA (ch)) + || (is_blank && ISBLANK (ch)) + || (is_cntrl && ISCNTRL (ch))) + SET_LIST_BIT (ch); + if ( (is_digit && ISDIGIT (ch)) + || (is_graph && ISGRAPH (ch)) + || (is_lower && ISLOWER (ch)) + || (is_print && ISPRINT (ch))) + SET_LIST_BIT (ch); + if ( (is_punct && ISPUNCT (ch)) + || (is_space && ISSPACE (ch)) + || (is_upper && ISUPPER (ch)) + || (is_xdigit && ISXDIGIT (ch))) + SET_LIST_BIT (ch); + if ( translate && (is_upper || is_lower) + && (ISUPPER (ch) || ISLOWER (ch))) + SET_LIST_BIT (ch); + } + had_char_class = true; +#endif /* libc || wctype.h */ + } + else + { + c1++; + while (c1--) + PATUNFETCH; + SET_LIST_BIT ('['); + SET_LIST_BIT (':'); + range_start = ':'; + had_char_class = false; + } + } + else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == '=') + { + unsigned char str[MB_LEN_MAX + 1]; +#ifdef _LIBC + uint32_t nrules = + _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); +#endif + + PATFETCH (c); + c1 = 0; + + /* If pattern is `[[='. */ + if (p == pend) FREE_STACK_RETURN (REG_EBRACK); + + for (;;) + { + PATFETCH (c); + if ((c == '=' && *p == ']') || p == pend) + break; + if (c1 < MB_LEN_MAX) + str[c1++] = c; + else + /* This is in any case an invalid class name. */ + str[0] = '\0'; + } + str[c1] = '\0'; + + if (c == '=' && *p == ']' && str[0] != '\0') + { + /* If we have no collation data we use the default + collation in which each character is in a class + by itself. It also means that ASCII is the + character set and therefore we cannot have character + with more than one byte in the multibyte + representation. */ +#ifdef _LIBC + if (nrules == 0) +#endif + { + if (c1 != 1) + FREE_STACK_RETURN (REG_ECOLLATE); + + /* Throw away the ] at the end of the equivalence + class. */ + PATFETCH (c); + + /* Set the bit for the character. */ + SET_LIST_BIT (str[0]); + } +#ifdef _LIBC + else + { + /* Try to match the byte sequence in `str' against + those known to the collate implementation. + First find out whether the bytes in `str' are + actually from exactly one character. */ + const int32_t *table; + const unsigned char *weights; + const unsigned char *extra; + const int32_t *indirect; + int32_t idx; + const unsigned char *cp = str; + int ch; + + /* This #include defines a local function! */ +# include + + table = (const int32_t *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB); + weights = (const unsigned char *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTMB); + extra = (const unsigned char *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB); + indirect = (const int32_t *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTMB); + + idx = findidx (&cp); + if (idx == 0 || cp < str + c1) + /* This is no valid character. */ + FREE_STACK_RETURN (REG_ECOLLATE); + + /* Throw away the ] at the end of the equivalence + class. */ + PATFETCH (c); + + /* Now we have to go throught the whole table + and find all characters which have the same + first level weight. + + XXX Note that this is not entirely correct. + we would have to match multibyte sequences + but this is not possible with the current + implementation. */ + for (ch = 1; ch < 256; ++ch) + /* XXX This test would have to be changed if we + would allow matching multibyte sequences. */ + if (table[ch] > 0) + { + int32_t idx2 = table[ch]; + size_t len = weights[idx2]; + + /* Test whether the lenghts match. */ + if (weights[idx] == len) + { + /* They do. New compare the bytes of + the weight. */ + size_t cnt = 0; + + while (cnt < len + && (weights[idx + 1 + cnt] + == weights[idx2 + 1 + cnt])) + ++len; + + if (cnt == len) + /* They match. Mark the character as + acceptable. */ + SET_LIST_BIT (ch); + } + } + } +#endif + had_char_class = true; + } + else + { + c1++; + while (c1--) + PATUNFETCH; + SET_LIST_BIT ('['); + SET_LIST_BIT ('='); + range_start = '='; + had_char_class = false; + } + } + else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == '.') + { + unsigned char str[128]; /* Should be large enough. */ +#ifdef _LIBC + uint32_t nrules = + _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); +#endif + + PATFETCH (c); + c1 = 0; + + /* If pattern is `[[='. */ + if (p == pend) FREE_STACK_RETURN (REG_EBRACK); + + for (;;) + { + PATFETCH (c); + if ((c == '.' && *p == ']') || p == pend) + break; + if (c1 < sizeof (str)) + str[c1++] = c; + else + /* This is in any case an invalid class name. */ + str[0] = '\0'; + } + str[c1] = '\0'; + + if (c == '.' && *p == ']' && str[0] != '\0') + { + /* If we have no collation data we use the default + collation in which each character is the name + for its own class which contains only the one + character. It also means that ASCII is the + character set and therefore we cannot have character + with more than one byte in the multibyte + representation. */ +#ifdef _LIBC + if (nrules == 0) +#endif + { + if (c1 != 1) + FREE_STACK_RETURN (REG_ECOLLATE); + + /* Throw away the ] at the end of the equivalence + class. */ + PATFETCH (c); + + /* Set the bit for the character. */ + SET_LIST_BIT (str[0]); + range_start = ((const unsigned char *) str)[0]; + } +#ifdef _LIBC + else + { + /* Try to match the byte sequence in `str' against + those known to the collate implementation. + First find out whether the bytes in `str' are + actually from exactly one character. */ + int32_t table_size; + const int32_t *symb_table; + const unsigned char *extra; + int32_t idx; + int32_t elem; + int32_t second; + int32_t hash; + + table_size = + _NL_CURRENT_WORD (LC_COLLATE, + _NL_COLLATE_SYMB_HASH_SIZEMB); + symb_table = (const int32_t *) + _NL_CURRENT (LC_COLLATE, + _NL_COLLATE_SYMB_TABLEMB); + extra = (const unsigned char *) + _NL_CURRENT (LC_COLLATE, + _NL_COLLATE_SYMB_EXTRAMB); + + /* Locate the character in the hashing table. */ + hash = elem_hash (str, c1); + + idx = 0; + elem = hash % table_size; + second = hash % (table_size - 2); + while (symb_table[2 * elem] != 0) + { + /* First compare the hashing value. */ + if (symb_table[2 * elem] == hash + && c1 == extra[symb_table[2 * elem + 1]] + && memcmp (str, + &extra[symb_table[2 * elem + 1] + + 1], + c1) == 0) + { + /* Yep, this is the entry. */ + idx = symb_table[2 * elem + 1]; + idx += 1 + extra[idx]; + break; + } + + /* Next entry. */ + elem += second; + } + + if (symb_table[2 * elem] == 0) + /* This is no valid character. */ + FREE_STACK_RETURN (REG_ECOLLATE); + + /* Throw away the ] at the end of the equivalence + class. */ + PATFETCH (c); + + /* Now add the multibyte character(s) we found + to the accept list. + + XXX Note that this is not entirely correct. + we would have to match multibyte sequences + but this is not possible with the current + implementation. Also, we have to match + collating symbols, which expand to more than + one file, as a whole and not allow the + individual bytes. */ + c1 = extra[idx++]; + if (c1 == 1) + range_start = extra[idx]; + while (c1-- > 0) + { + SET_LIST_BIT (extra[idx]); + ++idx; + } + } +#endif + had_char_class = false; + } + else + { + c1++; + while (c1--) + PATUNFETCH; + SET_LIST_BIT ('['); + SET_LIST_BIT ('.'); + range_start = '.'; + had_char_class = false; + } + } + else + { + had_char_class = false; + SET_LIST_BIT (c); + range_start = c; + } + } + + /* Discard any (non)matching list bytes that are all 0 at the + end of the map. Decrease the map-length byte too. */ + while ((int) b[-1] > 0 && b[b[-1] - 1] == 0) + b[-1]--; + b += b[-1]; + } + break; + + + case '(': + if (syntax & RE_NO_BK_PARENS) + goto handle_open; + else + goto normal_char; + + + case ')': + if (syntax & RE_NO_BK_PARENS) + goto handle_close; + else + goto normal_char; + + + case '\n': + if (syntax & RE_NEWLINE_ALT) + goto handle_alt; + else + goto normal_char; + + + case '|': + if (syntax & RE_NO_BK_VBAR) + goto handle_alt; + else + goto normal_char; + + + case '{': + if (syntax & RE_INTERVALS && syntax & RE_NO_BK_BRACES) + goto handle_interval; + else + goto normal_char; + + + case '\\': + if (p == pend) FREE_STACK_RETURN (REG_EESCAPE); + + /* Do not translate the character after the \, so that we can + distinguish, e.g., \B from \b, even if we normally would + translate, e.g., B to b. */ + PATFETCH_RAW (c); + + switch (c) + { + case '(': + if (syntax & RE_NO_BK_PARENS) + goto normal_backslash; + + handle_open: + bufp->re_nsub++; + regnum++; + + if (COMPILE_STACK_FULL) + { + RETALLOC (compile_stack.stack, compile_stack.size << 1, + compile_stack_elt_t); + if (compile_stack.stack == NULL) return REG_ESPACE; + + compile_stack.size <<= 1; + } + + /* These are the values to restore when we hit end of this + group. They are all relative offsets, so that if the + whole pattern moves because of realloc, they will still + be valid. */ + COMPILE_STACK_TOP.begalt_offset = begalt - bufp->buffer; + COMPILE_STACK_TOP.fixup_alt_jump + = fixup_alt_jump ? fixup_alt_jump - bufp->buffer + 1 : 0; + COMPILE_STACK_TOP.laststart_offset = b - bufp->buffer; + COMPILE_STACK_TOP.regnum = regnum; + + /* We will eventually replace the 0 with the number of + groups inner to this one. But do not push a + start_memory for groups beyond the last one we can + represent in the compiled pattern. */ + if (regnum <= MAX_REGNUM) + { + COMPILE_STACK_TOP.inner_group_offset = b - bufp->buffer + 2; + BUF_PUSH_3 (start_memory, regnum, 0); + } + + compile_stack.avail++; + + fixup_alt_jump = 0; + laststart = 0; + begalt = b; + /* If we've reached MAX_REGNUM groups, then this open + won't actually generate any code, so we'll have to + clear pending_exact explicitly. */ + pending_exact = 0; + break; + + + case ')': + if (syntax & RE_NO_BK_PARENS) goto normal_backslash; + + if (COMPILE_STACK_EMPTY) + { + if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) + goto normal_backslash; + else + FREE_STACK_RETURN (REG_ERPAREN); + } + + handle_close: + if (fixup_alt_jump) + { /* Push a dummy failure point at the end of the + alternative for a possible future + `pop_failure_jump' to pop. See comments at + `push_dummy_failure' in `re_match_2'. */ + BUF_PUSH (push_dummy_failure); + + /* We allocated space for this jump when we assigned + to `fixup_alt_jump', in the `handle_alt' case below. */ + STORE_JUMP (jump_past_alt, fixup_alt_jump, b - 1); + } + + /* See similar code for backslashed left paren above. */ + if (COMPILE_STACK_EMPTY) + { + if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) + goto normal_char; + else + FREE_STACK_RETURN (REG_ERPAREN); + } + + /* Since we just checked for an empty stack above, this + ``can't happen''. */ + assert (compile_stack.avail != 0); + { + /* We don't just want to restore into `regnum', because + later groups should continue to be numbered higher, + as in `(ab)c(de)' -- the second group is #2. */ + regnum_t this_group_regnum; + + compile_stack.avail--; + begalt = bufp->buffer + COMPILE_STACK_TOP.begalt_offset; + fixup_alt_jump + = COMPILE_STACK_TOP.fixup_alt_jump + ? bufp->buffer + COMPILE_STACK_TOP.fixup_alt_jump - 1 + : 0; + laststart = bufp->buffer + COMPILE_STACK_TOP.laststart_offset; + this_group_regnum = COMPILE_STACK_TOP.regnum; + /* If we've reached MAX_REGNUM groups, then this open + won't actually generate any code, so we'll have to + clear pending_exact explicitly. */ + pending_exact = 0; + + /* We're at the end of the group, so now we know how many + groups were inside this one. */ + if (this_group_regnum <= MAX_REGNUM) + { + unsigned char *inner_group_loc + = bufp->buffer + COMPILE_STACK_TOP.inner_group_offset; + + *inner_group_loc = regnum - this_group_regnum; + BUF_PUSH_3 (stop_memory, this_group_regnum, + regnum - this_group_regnum); + } + } + break; + + + case '|': /* `\|'. */ + if (syntax & RE_LIMITED_OPS || syntax & RE_NO_BK_VBAR) + goto normal_backslash; + handle_alt: + if (syntax & RE_LIMITED_OPS) + goto normal_char; + + /* Insert before the previous alternative a jump which + jumps to this alternative if the former fails. */ + GET_BUFFER_SPACE (3); + INSERT_JUMP (on_failure_jump, begalt, b + 6); + pending_exact = 0; + b += 3; + + /* The alternative before this one has a jump after it + which gets executed if it gets matched. Adjust that + jump so it will jump to this alternative's analogous + jump (put in below, which in turn will jump to the next + (if any) alternative's such jump, etc.). The last such + jump jumps to the correct final destination. A picture: + _____ _____ + | | | | + | v | v + a | b | c + + If we are at `b', then fixup_alt_jump right now points to a + three-byte space after `a'. We'll put in the jump, set + fixup_alt_jump to right after `b', and leave behind three + bytes which we'll fill in when we get to after `c'. */ + + if (fixup_alt_jump) + STORE_JUMP (jump_past_alt, fixup_alt_jump, b); + + /* Mark and leave space for a jump after this alternative, + to be filled in later either by next alternative or + when know we're at the end of a series of alternatives. */ + fixup_alt_jump = b; + GET_BUFFER_SPACE (3); + b += 3; + + laststart = 0; + begalt = b; + break; + + + case '{': + /* If \{ is a literal. */ + if (!(syntax & RE_INTERVALS) + /* If we're at `\{' and it's not the open-interval + operator. */ + || (syntax & RE_NO_BK_BRACES)) + goto normal_backslash; + + handle_interval: + { + /* If got here, then the syntax allows intervals. */ + + /* At least (most) this many matches must be made. */ + int lower_bound = -1, upper_bound = -1; + + beg_interval = p - 1; + + if (p == pend) + { + if (!(syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES)) + goto unfetch_interval; + else + FREE_STACK_RETURN (REG_EBRACE); + } + + GET_UNSIGNED_NUMBER (lower_bound); + + if (c == ',') + { + GET_UNSIGNED_NUMBER (upper_bound); + if ((!(syntax & RE_NO_BK_BRACES) && c != '\\') + || ((syntax & RE_NO_BK_BRACES) && c != '}')) + FREE_STACK_RETURN (REG_BADBR); + + if (upper_bound < 0) + upper_bound = RE_DUP_MAX; + } + else + /* Interval such as `{1}' => match exactly once. */ + upper_bound = lower_bound; + + if (lower_bound < 0 || upper_bound > RE_DUP_MAX + || lower_bound > upper_bound) + { + if (!(syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES)) + goto unfetch_interval; + else + FREE_STACK_RETURN (REG_BADBR); + } + + if (!(syntax & RE_NO_BK_BRACES)) + { + if (c != '\\') FREE_STACK_RETURN (REG_EBRACE); + + PATFETCH (c); + } + + if (c != '}') + { + if (!(syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES)) + goto unfetch_interval; + else + FREE_STACK_RETURN (REG_BADBR); + } + + /* We just parsed a valid interval. */ + + /* If it's invalid to have no preceding re. */ + if (!laststart) + { + if (syntax & RE_CONTEXT_INVALID_OPS) + FREE_STACK_RETURN (REG_BADRPT); + else if (syntax & RE_CONTEXT_INDEP_OPS) + laststart = b; + else + goto unfetch_interval; + } + + /* If the upper bound is zero, don't want to succeed at + all; jump from `laststart' to `b + 3', which will be + the end of the buffer after we insert the jump. */ + if (upper_bound == 0) + { + GET_BUFFER_SPACE (3); + INSERT_JUMP (jump, laststart, b + 3); + b += 3; + } + + /* Otherwise, we have a nontrivial interval. When + we're all done, the pattern will look like: + set_number_at + set_number_at + succeed_n + + jump_n + (The upper bound and `jump_n' are omitted if + `upper_bound' is 1, though.) */ + else + { /* If the upper bound is > 1, we need to insert + more at the end of the loop. */ + unsigned nbytes = 10 + (upper_bound > 1) * 10; + + GET_BUFFER_SPACE (nbytes); + + /* Initialize lower bound of the `succeed_n', even + though it will be set during matching by its + attendant `set_number_at' (inserted next), + because `re_compile_fastmap' needs to know. + Jump to the `jump_n' we might insert below. */ + INSERT_JUMP2 (succeed_n, laststart, + b + 5 + (upper_bound > 1) * 5, + lower_bound); + b += 5; + + /* Code to initialize the lower bound. Insert + before the `succeed_n'. The `5' is the last two + bytes of this `set_number_at', plus 3 bytes of + the following `succeed_n'. */ + insert_op2 (set_number_at, laststart, 5, lower_bound, b); + b += 5; + + if (upper_bound > 1) + { /* More than one repetition is allowed, so + append a backward jump to the `succeed_n' + that starts this interval. + + When we've reached this during matching, + we'll have matched the interval once, so + jump back only `upper_bound - 1' times. */ + STORE_JUMP2 (jump_n, b, laststart + 5, + upper_bound - 1); + b += 5; + + /* The location we want to set is the second + parameter of the `jump_n'; that is `b-2' as + an absolute address. `laststart' will be + the `set_number_at' we're about to insert; + `laststart+3' the number to set, the source + for the relative address. But we are + inserting into the middle of the pattern -- + so everything is getting moved up by 5. + Conclusion: (b - 2) - (laststart + 3) + 5, + i.e., b - laststart. + + We insert this at the beginning of the loop + so that if we fail during matching, we'll + reinitialize the bounds. */ + insert_op2 (set_number_at, laststart, b - laststart, + upper_bound - 1, b); + b += 5; + } + } + pending_exact = 0; + beg_interval = NULL; + } + break; + + unfetch_interval: + /* If an invalid interval, match the characters as literals. */ + assert (beg_interval); + p = beg_interval; + beg_interval = NULL; + + /* normal_char and normal_backslash need `c'. */ + PATFETCH (c); + + if (!(syntax & RE_NO_BK_BRACES)) + { + if (p > pattern && p[-1] == '\\') + goto normal_backslash; + } + goto normal_char; + +#ifdef emacs + /* There is no way to specify the before_dot and after_dot + operators. rms says this is ok. --karl */ + case '=': + BUF_PUSH (at_dot); + break; + + case 's': + laststart = b; + PATFETCH (c); + BUF_PUSH_2 (syntaxspec, syntax_spec_code[c]); + break; + + case 'S': + laststart = b; + PATFETCH (c); + BUF_PUSH_2 (notsyntaxspec, syntax_spec_code[c]); + break; +#endif /* emacs */ + + + case 'w': + if (syntax & RE_NO_GNU_OPS) + goto normal_char; + laststart = b; + BUF_PUSH (wordchar); + break; + + + case 'W': + if (syntax & RE_NO_GNU_OPS) + goto normal_char; + laststart = b; + BUF_PUSH (notwordchar); + break; + + + case '<': + if (syntax & RE_NO_GNU_OPS) + goto normal_char; + BUF_PUSH (wordbeg); + break; + + case '>': + if (syntax & RE_NO_GNU_OPS) + goto normal_char; + BUF_PUSH (wordend); + break; + + case 'b': + if (syntax & RE_NO_GNU_OPS) + goto normal_char; + BUF_PUSH (wordbound); + break; + + case 'B': + if (syntax & RE_NO_GNU_OPS) + goto normal_char; + BUF_PUSH (notwordbound); + break; + + case '`': + if (syntax & RE_NO_GNU_OPS) + goto normal_char; + BUF_PUSH (begbuf); + break; + + case '\'': + if (syntax & RE_NO_GNU_OPS) + goto normal_char; + BUF_PUSH (endbuf); + break; + + case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': + if (syntax & RE_NO_BK_REFS) + goto normal_char; + + c1 = c - '0'; + + if (c1 > regnum) + FREE_STACK_RETURN (REG_ESUBREG); + + /* Can't back reference to a subexpression if inside of it. */ + if (group_in_compile_stack (compile_stack, (regnum_t) c1)) + goto normal_char; + + laststart = b; + BUF_PUSH_2 (duplicate, c1); + break; + + + case '+': + case '?': + if (syntax & RE_BK_PLUS_QM) + goto handle_plus; + else + goto normal_backslash; + + default: + normal_backslash: + /* You might think it would be useful for \ to mean + not to translate; but if we don't translate it + it will never match anything. */ + c = TRANSLATE (c); + goto normal_char; + } + break; + + + default: + /* Expects the character in `c'. */ + normal_char: + /* If no exactn currently being built. */ + if (!pending_exact + + /* If last exactn not at current position. */ + || pending_exact + *pending_exact + 1 != b + + /* We have only one byte following the exactn for the count. */ + || *pending_exact == (1 << BYTEWIDTH) - 1 + + /* If followed by a repetition operator. */ + || *p == '*' || *p == '^' + || ((syntax & RE_BK_PLUS_QM) + ? *p == '\\' && (p[1] == '+' || p[1] == '?') + : (*p == '+' || *p == '?')) + || ((syntax & RE_INTERVALS) + && ((syntax & RE_NO_BK_BRACES) + ? *p == '{' + : (p[0] == '\\' && p[1] == '{')))) + { + /* Start building a new exactn. */ + + laststart = b; + + BUF_PUSH_2 (exactn, 0); + pending_exact = b - 1; + } + + BUF_PUSH (c); + (*pending_exact)++; + break; + } /* switch (c) */ + } /* while p != pend */ + + + /* Through the pattern now. */ + + if (fixup_alt_jump) + STORE_JUMP (jump_past_alt, fixup_alt_jump, b); + + if (!COMPILE_STACK_EMPTY) + FREE_STACK_RETURN (REG_EPAREN); + + /* If we don't want backtracking, force success + the first time we reach the end of the compiled pattern. */ + if (syntax & RE_NO_POSIX_BACKTRACKING) + BUF_PUSH (succeed); + + free (compile_stack.stack); + + /* We have succeeded; set the length of the buffer. */ + bufp->used = b - bufp->buffer; + +#ifdef DEBUG + if (debug) + { + DEBUG_PRINT1 ("\nCompiled pattern: \n"); + print_compiled_pattern (bufp); + } +#endif /* DEBUG */ + +#ifndef MATCH_MAY_ALLOCATE + /* Initialize the failure stack to the largest possible stack. This + isn't necessary unless we're trying to avoid calling alloca in + the search and match routines. */ + { + int num_regs = bufp->re_nsub + 1; + + /* Since DOUBLE_FAIL_STACK refuses to double only if the current size + is strictly greater than re_max_failures, the largest possible stack + is 2 * re_max_failures failure points. */ + if (fail_stack.size < (2 * re_max_failures * MAX_FAILURE_ITEMS)) + { + fail_stack.size = (2 * re_max_failures * MAX_FAILURE_ITEMS); + +# ifdef emacs + if (! fail_stack.stack) + fail_stack.stack + = (fail_stack_elt_t *) xmalloc (fail_stack.size + * sizeof (fail_stack_elt_t)); + else + fail_stack.stack + = (fail_stack_elt_t *) xrealloc (fail_stack.stack, + (fail_stack.size + * sizeof (fail_stack_elt_t))); +# else /* not emacs */ + if (! fail_stack.stack) + fail_stack.stack + = (fail_stack_elt_t *) malloc (fail_stack.size + * sizeof (fail_stack_elt_t)); + else + fail_stack.stack + = (fail_stack_elt_t *) realloc (fail_stack.stack, + (fail_stack.size + * sizeof (fail_stack_elt_t))); +# endif /* not emacs */ + } + + regex_grow_registers (num_regs); + } +#endif /* not MATCH_MAY_ALLOCATE */ + + return REG_NOERROR; +} /* regex_compile */ + +/* Subroutines for `regex_compile'. */ + +/* Store OP at LOC followed by two-byte integer parameter ARG. */ + +static void +store_op1 (op, loc, arg) + re_opcode_t op; + unsigned char *loc; + int arg; +{ + *loc = (unsigned char) op; + STORE_NUMBER (loc + 1, arg); +} + + +/* Like `store_op1', but for two two-byte parameters ARG1 and ARG2. */ + +static void +store_op2 (op, loc, arg1, arg2) + re_opcode_t op; + unsigned char *loc; + int arg1, arg2; +{ + *loc = (unsigned char) op; + STORE_NUMBER (loc + 1, arg1); + STORE_NUMBER (loc + 3, arg2); +} + + +/* Copy the bytes from LOC to END to open up three bytes of space at LOC + for OP followed by two-byte integer parameter ARG. */ + +static void +insert_op1 (op, loc, arg, end) + re_opcode_t op; + unsigned char *loc; + int arg; + unsigned char *end; +{ + register unsigned char *pfrom = end; + register unsigned char *pto = end + 3; + + while (pfrom != loc) + *--pto = *--pfrom; + + store_op1 (op, loc, arg); +} + + +/* Like `insert_op1', but for two two-byte parameters ARG1 and ARG2. */ + +static void +insert_op2 (op, loc, arg1, arg2, end) + re_opcode_t op; + unsigned char *loc; + int arg1, arg2; + unsigned char *end; +{ + register unsigned char *pfrom = end; + register unsigned char *pto = end + 5; + + while (pfrom != loc) + *--pto = *--pfrom; + + store_op2 (op, loc, arg1, arg2); +} + + +/* P points to just after a ^ in PATTERN. Return true if that ^ comes + after an alternative or a begin-subexpression. We assume there is at + least one character before the ^. */ + +static boolean +at_begline_loc_p (pattern, p, syntax) + const char *pattern, *p; + reg_syntax_t syntax; +{ + const char *prev = p - 2; + boolean prev_prev_backslash = prev > pattern && prev[-1] == '\\'; + + return + /* After a subexpression? */ + (*prev == '(' && (syntax & RE_NO_BK_PARENS || prev_prev_backslash)) + /* After an alternative? */ + || (*prev == '|' && (syntax & RE_NO_BK_VBAR || prev_prev_backslash)); +} + + +/* The dual of at_begline_loc_p. This one is for $. We assume there is + at least one character after the $, i.e., `P < PEND'. */ + +static boolean +at_endline_loc_p (p, pend, syntax) + const char *p, *pend; + reg_syntax_t syntax; +{ + const char *next = p; + boolean next_backslash = *next == '\\'; + const char *next_next = p + 1 < pend ? p + 1 : 0; + + return + /* Before a subexpression? */ + (syntax & RE_NO_BK_PARENS ? *next == ')' + : next_backslash && next_next && *next_next == ')') + /* Before an alternative? */ + || (syntax & RE_NO_BK_VBAR ? *next == '|' + : next_backslash && next_next && *next_next == '|'); +} + + +/* Returns true if REGNUM is in one of COMPILE_STACK's elements and + false if it's not. */ + +static boolean +group_in_compile_stack (compile_stack, regnum) + compile_stack_type compile_stack; + regnum_t regnum; +{ + int this_element; + + for (this_element = compile_stack.avail - 1; + this_element >= 0; + this_element--) + if (compile_stack.stack[this_element].regnum == regnum) + return true; + + return false; +} + + +/* Read the ending character of a range (in a bracket expression) from the + uncompiled pattern *P_PTR (which ends at PEND). We assume the + starting character is in `P[-2]'. (`P[-1]' is the character `-'.) + Then we set the translation of all bits between the starting and + ending characters (inclusive) in the compiled pattern B. + + Return an error code. + + We use these short variable names so we can use the same macros as + `regex_compile' itself. */ + +static reg_errcode_t +compile_range (range_start_char, p_ptr, pend, translate, syntax, b) + unsigned int range_start_char; + const char **p_ptr, *pend; + RE_TRANSLATE_TYPE translate; + reg_syntax_t syntax; + unsigned char *b; +{ + unsigned this_char; + const char *p = *p_ptr; + reg_errcode_t ret; +#if _LIBC + const unsigned char *collseq; + unsigned int start_colseq; + unsigned int end_colseq; +#else + unsigned end_char; +#endif + + if (p == pend) + return REG_ERANGE; + + /* Have to increment the pointer into the pattern string, so the + caller isn't still at the ending character. */ + (*p_ptr)++; + + /* Report an error if the range is empty and the syntax prohibits this. */ + ret = syntax & RE_NO_EMPTY_RANGES ? REG_ERANGE : REG_NOERROR; + +#if _LIBC + collseq = (const unsigned char *) _NL_CURRENT (LC_COLLATE, + _NL_COLLATE_COLLSEQMB); + + start_colseq = collseq[(unsigned char) TRANSLATE (range_start_char)]; + end_colseq = collseq[(unsigned char) TRANSLATE (p[0])]; + for (this_char = 0; this_char <= (unsigned char) -1; ++this_char) + { + unsigned int this_colseq = collseq[(unsigned char) TRANSLATE (this_char)]; + + if (start_colseq <= this_colseq && this_colseq <= end_colseq) + { + SET_LIST_BIT (TRANSLATE (this_char)); + ret = REG_NOERROR; + } + } +#else + /* Here we see why `this_char' has to be larger than an `unsigned + char' -- we would otherwise go into an infinite loop, since all + characters <= 0xff. */ + range_start_char = TRANSLATE (range_start_char); + end_char = TRANSLATE (p[0]); + for (this_char = range_start_char; this_char <= end_char; ++this_char) + { + SET_LIST_BIT (TRANSLATE (this_char)); + ret = REG_NOERROR; + } +#endif + + return ret; +} + +/* re_compile_fastmap computes a ``fastmap'' for the compiled pattern in + BUFP. A fastmap records which of the (1 << BYTEWIDTH) possible + characters can start a string that matches the pattern. This fastmap + is used by re_search to skip quickly over impossible starting points. + + The caller must supply the address of a (1 << BYTEWIDTH)-byte data + area as BUFP->fastmap. + + We set the `fastmap', `fastmap_accurate', and `can_be_null' fields in + the pattern buffer. + + Returns 0 if we succeed, -2 if an internal error. */ + +int +re_compile_fastmap (bufp) + struct re_pattern_buffer *bufp; +{ + int j, k; +#ifdef MATCH_MAY_ALLOCATE + fail_stack_type fail_stack; +#endif +#ifndef REGEX_MALLOC + char *destination; +#endif + + register char *fastmap = bufp->fastmap; + unsigned char *pattern = bufp->buffer; + unsigned char *p = pattern; + register unsigned char *pend = pattern + bufp->used; + +#ifdef REL_ALLOC + /* This holds the pointer to the failure stack, when + it is allocated relocatably. */ + fail_stack_elt_t *failure_stack_ptr; +#endif + + /* Assume that each path through the pattern can be null until + proven otherwise. We set this false at the bottom of switch + statement, to which we get only if a particular path doesn't + match the empty string. */ + boolean path_can_be_null = true; + + /* We aren't doing a `succeed_n' to begin with. */ + boolean succeed_n_p = false; + + assert (fastmap != NULL && p != NULL); + + INIT_FAIL_STACK (); + bzero (fastmap, 1 << BYTEWIDTH); /* Assume nothing's valid. */ + bufp->fastmap_accurate = 1; /* It will be when we're done. */ + bufp->can_be_null = 0; + + while (1) + { + if (p == pend || *p == succeed) + { + /* We have reached the (effective) end of pattern. */ + if (!FAIL_STACK_EMPTY ()) + { + bufp->can_be_null |= path_can_be_null; + + /* Reset for next path. */ + path_can_be_null = true; + + p = fail_stack.stack[--fail_stack.avail].pointer; + + continue; + } + else + break; + } + + /* We should never be about to go beyond the end of the pattern. */ + assert (p < pend); + + switch (SWITCH_ENUM_CAST ((re_opcode_t) *p++)) + { + + /* I guess the idea here is to simply not bother with a fastmap + if a backreference is used, since it's too hard to figure out + the fastmap for the corresponding group. Setting + `can_be_null' stops `re_search_2' from using the fastmap, so + that is all we do. */ + case duplicate: + bufp->can_be_null = 1; + goto done; + + + /* Following are the cases which match a character. These end + with `break'. */ + + case exactn: + fastmap[p[1]] = 1; + break; + + + case charset: + for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) + if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))) + fastmap[j] = 1; + break; + + + case charset_not: + /* Chars beyond end of map must be allowed. */ + for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++) + fastmap[j] = 1; + + for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) + if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))) + fastmap[j] = 1; + break; + + + case wordchar: + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) == Sword) + fastmap[j] = 1; + break; + + + case notwordchar: + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) != Sword) + fastmap[j] = 1; + break; + + + case anychar: + { + int fastmap_newline = fastmap['\n']; + + /* `.' matches anything ... */ + for (j = 0; j < (1 << BYTEWIDTH); j++) + fastmap[j] = 1; + + /* ... except perhaps newline. */ + if (!(bufp->syntax & RE_DOT_NEWLINE)) + fastmap['\n'] = fastmap_newline; + + /* Return if we have already set `can_be_null'; if we have, + then the fastmap is irrelevant. Something's wrong here. */ + else if (bufp->can_be_null) + goto done; + + /* Otherwise, have to check alternative paths. */ + break; + } + +#ifdef emacs + case syntaxspec: + k = *p++; + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) == (enum syntaxcode) k) + fastmap[j] = 1; + break; + + + case notsyntaxspec: + k = *p++; + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) != (enum syntaxcode) k) + fastmap[j] = 1; + break; + + + /* All cases after this match the empty string. These end with + `continue'. */ + + + case before_dot: + case at_dot: + case after_dot: + continue; +#endif /* emacs */ + + + case no_op: + case begline: + case endline: + case begbuf: + case endbuf: + case wordbound: + case notwordbound: + case wordbeg: + case wordend: + case push_dummy_failure: + continue; + + + case jump_n: + case pop_failure_jump: + case maybe_pop_jump: + case jump: + case jump_past_alt: + case dummy_failure_jump: + EXTRACT_NUMBER_AND_INCR (j, p); + p += j; + if (j > 0) + continue; + + /* Jump backward implies we just went through the body of a + loop and matched nothing. Opcode jumped to should be + `on_failure_jump' or `succeed_n'. Just treat it like an + ordinary jump. For a * loop, it has pushed its failure + point already; if so, discard that as redundant. */ + if ((re_opcode_t) *p != on_failure_jump + && (re_opcode_t) *p != succeed_n) + continue; + + p++; + EXTRACT_NUMBER_AND_INCR (j, p); + p += j; + + /* If what's on the stack is where we are now, pop it. */ + if (!FAIL_STACK_EMPTY () + && fail_stack.stack[fail_stack.avail - 1].pointer == p) + fail_stack.avail--; + + continue; + + + case on_failure_jump: + case on_failure_keep_string_jump: + handle_on_failure_jump: + EXTRACT_NUMBER_AND_INCR (j, p); + + /* For some patterns, e.g., `(a?)?', `p+j' here points to the + end of the pattern. We don't want to push such a point, + since when we restore it above, entering the switch will + increment `p' past the end of the pattern. We don't need + to push such a point since we obviously won't find any more + fastmap entries beyond `pend'. Such a pattern can match + the null string, though. */ + if (p + j < pend) + { + if (!PUSH_PATTERN_OP (p + j, fail_stack)) + { + RESET_FAIL_STACK (); + return -2; + } + } + else + bufp->can_be_null = 1; + + if (succeed_n_p) + { + EXTRACT_NUMBER_AND_INCR (k, p); /* Skip the n. */ + succeed_n_p = false; + } + + continue; + + + case succeed_n: + /* Get to the number of times to succeed. */ + p += 2; + + /* Increment p past the n for when k != 0. */ + EXTRACT_NUMBER_AND_INCR (k, p); + if (k == 0) + { + p -= 4; + succeed_n_p = true; /* Spaghetti code alert. */ + goto handle_on_failure_jump; + } + continue; + + + case set_number_at: + p += 4; + continue; + + + case start_memory: + case stop_memory: + p += 2; + continue; + + + default: + abort (); /* We have listed all the cases. */ + } /* switch *p++ */ + + /* Getting here means we have found the possible starting + characters for one path of the pattern -- and that the empty + string does not match. We need not follow this path further. + Instead, look at the next alternative (remembered on the + stack), or quit if no more. The test at the top of the loop + does these things. */ + path_can_be_null = false; + p = pend; + } /* while p */ + + /* Set `can_be_null' for the last path (also the first path, if the + pattern is empty). */ + bufp->can_be_null |= path_can_be_null; + + done: + RESET_FAIL_STACK (); + return 0; +} /* re_compile_fastmap */ +#ifdef _LIBC +weak_alias (__re_compile_fastmap, re_compile_fastmap) +#endif + +/* Set REGS to hold NUM_REGS registers, storing them in STARTS and + ENDS. Subsequent matches using PATTERN_BUFFER and REGS will use + this memory for recording register information. STARTS and ENDS + must be allocated using the malloc library routine, and must each + be at least NUM_REGS * sizeof (regoff_t) bytes long. + + If NUM_REGS == 0, then subsequent matches should allocate their own + register data. + + Unless this function is called, the first search or match using + PATTERN_BUFFER will allocate its own register data, without + freeing the old data. */ + +void +re_set_registers (bufp, regs, num_regs, starts, ends) + struct re_pattern_buffer *bufp; + struct re_registers *regs; + unsigned num_regs; + regoff_t *starts, *ends; +{ + if (num_regs) + { + bufp->regs_allocated = REGS_REALLOCATE; + regs->num_regs = num_regs; + regs->start = starts; + regs->end = ends; + } + else + { + bufp->regs_allocated = REGS_UNALLOCATED; + regs->num_regs = 0; + regs->start = regs->end = (regoff_t *) 0; + } +} +#ifdef _LIBC +weak_alias (__re_set_registers, re_set_registers) +#endif + +/* Searching routines. */ + +/* Like re_search_2, below, but only one string is specified, and + doesn't let you say where to stop matching. */ + +int +re_search (bufp, string, size, startpos, range, regs) + struct re_pattern_buffer *bufp; + const char *string; + int size, startpos, range; + struct re_registers *regs; +{ + return re_search_2 (bufp, NULL, 0, string, size, startpos, range, + regs, size); +} +#ifdef _LIBC +weak_alias (__re_search, re_search) +#endif + + +/* Using the compiled pattern in BUFP->buffer, first tries to match the + virtual concatenation of STRING1 and STRING2, starting first at index + STARTPOS, then at STARTPOS + 1, and so on. + + STRING1 and STRING2 have length SIZE1 and SIZE2, respectively. + + RANGE is how far to scan while trying to match. RANGE = 0 means try + only at STARTPOS; in general, the last start tried is STARTPOS + + RANGE. + + In REGS, return the indices of the virtual concatenation of STRING1 + and STRING2 that matched the entire BUFP->buffer and its contained + subexpressions. + + Do not consider matching one past the index STOP in the virtual + concatenation of STRING1 and STRING2. + + We return either the position in the strings at which the match was + found, -1 if no match, or -2 if error (such as failure + stack overflow). */ + +int +re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop) + struct re_pattern_buffer *bufp; + const char *string1, *string2; + int size1, size2; + int startpos; + int range; + struct re_registers *regs; + int stop; +{ + int val; + register char *fastmap = bufp->fastmap; + register RE_TRANSLATE_TYPE translate = bufp->translate; + int total_size = size1 + size2; + int endpos = startpos + range; + + /* Check for out-of-range STARTPOS. */ + if (startpos < 0 || startpos > total_size) + return -1; + + /* Fix up RANGE if it might eventually take us outside + the virtual concatenation of STRING1 and STRING2. + Make sure we won't move STARTPOS below 0 or above TOTAL_SIZE. */ + if (endpos < 0) + range = 0 - startpos; + else if (endpos > total_size) + range = total_size - startpos; + + /* If the search isn't to be a backwards one, don't waste time in a + search for a pattern that must be anchored. */ + if (bufp->used > 0 && range > 0 + && ((re_opcode_t) bufp->buffer[0] == begbuf + /* `begline' is like `begbuf' if it cannot match at newlines. */ + || ((re_opcode_t) bufp->buffer[0] == begline + && !bufp->newline_anchor))) + { + if (startpos > 0) + return -1; + else + range = 1; + } + +#ifdef emacs + /* In a forward search for something that starts with \=. + don't keep searching past point. */ + if (bufp->used > 0 && (re_opcode_t) bufp->buffer[0] == at_dot && range > 0) + { + range = PT - startpos; + if (range <= 0) + return -1; + } +#endif /* emacs */ + + /* Update the fastmap now if not correct already. */ + if (fastmap && !bufp->fastmap_accurate) + if (re_compile_fastmap (bufp) == -2) + return -2; + + /* Loop through the string, looking for a place to start matching. */ + for (;;) + { + /* If a fastmap is supplied, skip quickly over characters that + cannot be the start of a match. If the pattern can match the + null string, however, we don't need to skip characters; we want + the first null string. */ + if (fastmap && startpos < total_size && !bufp->can_be_null) + { + if (range > 0) /* Searching forwards. */ + { + register const char *d; + register int lim = 0; + int irange = range; + + if (startpos < size1 && startpos + range >= size1) + lim = range - (size1 - startpos); + + d = (startpos >= size1 ? string2 - size1 : string1) + startpos; + + /* Written out as an if-else to avoid testing `translate' + inside the loop. */ + if (translate) + while (range > lim + && !fastmap[(unsigned char) + translate[(unsigned char) *d++]]) + range--; + else + while (range > lim && !fastmap[(unsigned char) *d++]) + range--; + + startpos += irange - range; + } + else /* Searching backwards. */ + { + register char c = (size1 == 0 || startpos >= size1 + ? string2[startpos - size1] + : string1[startpos]); + + if (!fastmap[(unsigned char) TRANSLATE (c)]) + goto advance; + } + } + + /* If can't match the null string, and that's all we have left, fail. */ + if (range >= 0 && startpos == total_size && fastmap + && !bufp->can_be_null) + return -1; + + val = re_match_2_internal (bufp, string1, size1, string2, size2, + startpos, regs, stop); +#ifndef REGEX_MALLOC +# ifdef C_ALLOCA + alloca (0); +# endif +#endif + + if (val >= 0) + return startpos; + + if (val == -2) + return -2; + + advance: + if (!range) + break; + else if (range > 0) + { + range--; + startpos++; + } + else + { + range++; + startpos--; + } + } + return -1; +} /* re_search_2 */ +#ifdef _LIBC +weak_alias (__re_search_2, re_search_2) +#endif + +/* This converts PTR, a pointer into one of the search strings `string1' + and `string2' into an offset from the beginning of that string. */ +#define POINTER_TO_OFFSET(ptr) \ + (FIRST_STRING_P (ptr) \ + ? ((regoff_t) ((ptr) - string1)) \ + : ((regoff_t) ((ptr) - string2 + size1))) + +/* Macros for dealing with the split strings in re_match_2. */ + +#define MATCHING_IN_FIRST_STRING (dend == end_match_1) + +/* Call before fetching a character with *d. This switches over to + string2 if necessary. */ +#define PREFETCH() \ + while (d == dend) \ + { \ + /* End of string2 => fail. */ \ + if (dend == end_match_2) \ + goto fail; \ + /* End of string1 => advance to string2. */ \ + d = string2; \ + dend = end_match_2; \ + } + + +/* Test if at very beginning or at very end of the virtual concatenation + of `string1' and `string2'. If only one string, it's `string2'. */ +#define AT_STRINGS_BEG(d) ((d) == (size1 ? string1 : string2) || !size2) +#define AT_STRINGS_END(d) ((d) == end2) + + +/* Test if D points to a character which is word-constituent. We have + two special cases to check for: if past the end of string1, look at + the first character in string2; and if before the beginning of + string2, look at the last character in string1. */ +#define WORDCHAR_P(d) \ + (SYNTAX ((d) == end1 ? *string2 \ + : (d) == string2 - 1 ? *(end1 - 1) : *(d)) \ + == Sword) + +/* Disabled due to a compiler bug -- see comment at case wordbound */ +#if 0 +/* Test if the character before D and the one at D differ with respect + to being word-constituent. */ +#define AT_WORD_BOUNDARY(d) \ + (AT_STRINGS_BEG (d) || AT_STRINGS_END (d) \ + || WORDCHAR_P (d - 1) != WORDCHAR_P (d)) +#endif + +/* Free everything we malloc. */ +#ifdef MATCH_MAY_ALLOCATE +# define FREE_VAR(var) if (var) REGEX_FREE (var); var = NULL +# define FREE_VARIABLES() \ + do { \ + REGEX_FREE_STACK (fail_stack.stack); \ + FREE_VAR (regstart); \ + FREE_VAR (regend); \ + FREE_VAR (old_regstart); \ + FREE_VAR (old_regend); \ + FREE_VAR (best_regstart); \ + FREE_VAR (best_regend); \ + FREE_VAR (reg_info); \ + FREE_VAR (reg_dummy); \ + FREE_VAR (reg_info_dummy); \ + } while (0) +#else +# define FREE_VARIABLES() ((void)0) /* Do nothing! But inhibit gcc warning. */ +#endif /* not MATCH_MAY_ALLOCATE */ + +/* These values must meet several constraints. They must not be valid + register values; since we have a limit of 255 registers (because + we use only one byte in the pattern for the register number), we can + use numbers larger than 255. They must differ by 1, because of + NUM_FAILURE_ITEMS above. And the value for the lowest register must + be larger than the value for the highest register, so we do not try + to actually save any registers when none are active. */ +#define NO_HIGHEST_ACTIVE_REG (1 << BYTEWIDTH) +#define NO_LOWEST_ACTIVE_REG (NO_HIGHEST_ACTIVE_REG + 1) + +/* Matching routines. */ + +#ifndef emacs /* Emacs never uses this. */ +/* re_match is like re_match_2 except it takes only a single string. */ + +int +re_match (bufp, string, size, pos, regs) + struct re_pattern_buffer *bufp; + const char *string; + int size, pos; + struct re_registers *regs; +{ + int result = re_match_2_internal (bufp, NULL, 0, string, size, + pos, regs, size); +# ifndef REGEX_MALLOC +# ifdef C_ALLOCA + alloca (0); +# endif +# endif + return result; +} +# ifdef _LIBC +weak_alias (__re_match, re_match) +# endif +#endif /* not emacs */ + +static boolean group_match_null_string_p _RE_ARGS ((unsigned char **p, + unsigned char *end, + register_info_type *reg_info)); +static boolean alt_match_null_string_p _RE_ARGS ((unsigned char *p, + unsigned char *end, + register_info_type *reg_info)); +static boolean common_op_match_null_string_p _RE_ARGS ((unsigned char **p, + unsigned char *end, + register_info_type *reg_info)); +static int bcmp_translate _RE_ARGS ((const char *s1, const char *s2, + int len, char *translate)); + +/* re_match_2 matches the compiled pattern in BUFP against the + the (virtual) concatenation of STRING1 and STRING2 (of length SIZE1 + and SIZE2, respectively). We start matching at POS, and stop + matching at STOP. + + If REGS is non-null and the `no_sub' field of BUFP is nonzero, we + store offsets for the substring each group matched in REGS. See the + documentation for exactly how many groups we fill. + + We return -1 if no match, -2 if an internal error (such as the + failure stack overflowing). Otherwise, we return the length of the + matched substring. */ + +int +re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) + struct re_pattern_buffer *bufp; + const char *string1, *string2; + int size1, size2; + int pos; + struct re_registers *regs; + int stop; +{ + int result = re_match_2_internal (bufp, string1, size1, string2, size2, + pos, regs, stop); +#ifndef REGEX_MALLOC +# ifdef C_ALLOCA + alloca (0); +# endif +#endif + return result; +} +#ifdef _LIBC +weak_alias (__re_match_2, re_match_2) +#endif + +/* This is a separate function so that we can force an alloca cleanup + afterwards. */ +static int +re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop) + struct re_pattern_buffer *bufp; + const char *string1, *string2; + int size1, size2; + int pos; + struct re_registers *regs; + int stop; +{ + /* General temporaries. */ + int mcnt; + unsigned char *p1; + + /* Just past the end of the corresponding string. */ + const char *end1, *end2; + + /* Pointers into string1 and string2, just past the last characters in + each to consider matching. */ + const char *end_match_1, *end_match_2; + + /* Where we are in the data, and the end of the current string. */ + const char *d, *dend; + + /* Where we are in the pattern, and the end of the pattern. */ + unsigned char *p = bufp->buffer; + register unsigned char *pend = p + bufp->used; + + /* Mark the opcode just after a start_memory, so we can test for an + empty subpattern when we get to the stop_memory. */ + unsigned char *just_past_start_mem = 0; + + /* We use this to map every character in the string. */ + RE_TRANSLATE_TYPE translate = bufp->translate; + + /* Failure point stack. Each place that can handle a failure further + down the line pushes a failure point on this stack. It consists of + restart, regend, and reg_info for all registers corresponding to + the subexpressions we're currently inside, plus the number of such + registers, and, finally, two char *'s. The first char * is where + to resume scanning the pattern; the second one is where to resume + scanning the strings. If the latter is zero, the failure point is + a ``dummy''; if a failure happens and the failure point is a dummy, + it gets discarded and the next next one is tried. */ +#ifdef MATCH_MAY_ALLOCATE /* otherwise, this is global. */ + fail_stack_type fail_stack; +#endif +#ifdef DEBUG + static unsigned failure_id; + unsigned nfailure_points_pushed = 0, nfailure_points_popped = 0; +#endif + +#ifdef REL_ALLOC + /* This holds the pointer to the failure stack, when + it is allocated relocatably. */ + fail_stack_elt_t *failure_stack_ptr; +#endif + + /* We fill all the registers internally, independent of what we + return, for use in backreferences. The number here includes + an element for register zero. */ + size_t num_regs = bufp->re_nsub + 1; + + /* The currently active registers. */ + active_reg_t lowest_active_reg = NO_LOWEST_ACTIVE_REG; + active_reg_t highest_active_reg = NO_HIGHEST_ACTIVE_REG; + + /* Information on the contents of registers. These are pointers into + the input strings; they record just what was matched (on this + attempt) by a subexpression part of the pattern, that is, the + regnum-th regstart pointer points to where in the pattern we began + matching and the regnum-th regend points to right after where we + stopped matching the regnum-th subexpression. (The zeroth register + keeps track of what the whole pattern matches.) */ +#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */ + const char **regstart, **regend; +#endif + + /* If a group that's operated upon by a repetition operator fails to + match anything, then the register for its start will need to be + restored because it will have been set to wherever in the string we + are when we last see its open-group operator. Similarly for a + register's end. */ +#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */ + const char **old_regstart, **old_regend; +#endif + + /* The is_active field of reg_info helps us keep track of which (possibly + nested) subexpressions we are currently in. The matched_something + field of reg_info[reg_num] helps us tell whether or not we have + matched any of the pattern so far this time through the reg_num-th + subexpression. These two fields get reset each time through any + loop their register is in. */ +#ifdef MATCH_MAY_ALLOCATE /* otherwise, this is global. */ + register_info_type *reg_info; +#endif + + /* The following record the register info as found in the above + variables when we find a match better than any we've seen before. + This happens as we backtrack through the failure points, which in + turn happens only if we have not yet matched the entire string. */ + unsigned best_regs_set = false; +#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */ + const char **best_regstart, **best_regend; +#endif + + /* Logically, this is `best_regend[0]'. But we don't want to have to + allocate space for that if we're not allocating space for anything + else (see below). Also, we never need info about register 0 for + any of the other register vectors, and it seems rather a kludge to + treat `best_regend' differently than the rest. So we keep track of + the end of the best match so far in a separate variable. We + initialize this to NULL so that when we backtrack the first time + and need to test it, it's not garbage. */ + const char *match_end = NULL; + + /* This helps SET_REGS_MATCHED avoid doing redundant work. */ + int set_regs_matched_done = 0; + + /* Used when we pop values we don't care about. */ +#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */ + const char **reg_dummy; + register_info_type *reg_info_dummy; +#endif + +#ifdef DEBUG + /* Counts the total number of registers pushed. */ + unsigned num_regs_pushed = 0; +#endif + + DEBUG_PRINT1 ("\n\nEntering re_match_2.\n"); + + INIT_FAIL_STACK (); + +#ifdef MATCH_MAY_ALLOCATE + /* Do not bother to initialize all the register variables if there are + no groups in the pattern, as it takes a fair amount of time. If + there are groups, we include space for register 0 (the whole + pattern), even though we never use it, since it simplifies the + array indexing. We should fix this. */ + if (bufp->re_nsub) + { + regstart = REGEX_TALLOC (num_regs, const char *); + regend = REGEX_TALLOC (num_regs, const char *); + old_regstart = REGEX_TALLOC (num_regs, const char *); + old_regend = REGEX_TALLOC (num_regs, const char *); + best_regstart = REGEX_TALLOC (num_regs, const char *); + best_regend = REGEX_TALLOC (num_regs, const char *); + reg_info = REGEX_TALLOC (num_regs, register_info_type); + reg_dummy = REGEX_TALLOC (num_regs, const char *); + reg_info_dummy = REGEX_TALLOC (num_regs, register_info_type); + + if (!(regstart && regend && old_regstart && old_regend && reg_info + && best_regstart && best_regend && reg_dummy && reg_info_dummy)) + { + FREE_VARIABLES (); + return -2; + } + } + else + { + /* We must initialize all our variables to NULL, so that + `FREE_VARIABLES' doesn't try to free them. */ + regstart = regend = old_regstart = old_regend = best_regstart + = best_regend = reg_dummy = NULL; + reg_info = reg_info_dummy = (register_info_type *) NULL; + } +#endif /* MATCH_MAY_ALLOCATE */ + + /* The starting position is bogus. */ + if (pos < 0 || pos > size1 + size2) + { + FREE_VARIABLES (); + return -1; + } + + /* Initialize subexpression text positions to -1 to mark ones that no + start_memory/stop_memory has been seen for. Also initialize the + register information struct. */ + for (mcnt = 1; (unsigned) mcnt < num_regs; mcnt++) + { + regstart[mcnt] = regend[mcnt] + = old_regstart[mcnt] = old_regend[mcnt] = REG_UNSET_VALUE; + + REG_MATCH_NULL_STRING_P (reg_info[mcnt]) = MATCH_NULL_UNSET_VALUE; + IS_ACTIVE (reg_info[mcnt]) = 0; + MATCHED_SOMETHING (reg_info[mcnt]) = 0; + EVER_MATCHED_SOMETHING (reg_info[mcnt]) = 0; + } + + /* We move `string1' into `string2' if the latter's empty -- but not if + `string1' is null. */ + if (size2 == 0 && string1 != NULL) + { + string2 = string1; + size2 = size1; + string1 = 0; + size1 = 0; + } + end1 = string1 + size1; + end2 = string2 + size2; + + /* Compute where to stop matching, within the two strings. */ + if (stop <= size1) + { + end_match_1 = string1 + stop; + end_match_2 = string2; + } + else + { + end_match_1 = end1; + end_match_2 = string2 + stop - size1; + } + + /* `p' scans through the pattern as `d' scans through the data. + `dend' is the end of the input string that `d' points within. `d' + is advanced into the following input string whenever necessary, but + this happens before fetching; therefore, at the beginning of the + loop, `d' can be pointing at the end of a string, but it cannot + equal `string2'. */ + if (size1 > 0 && pos <= size1) + { + d = string1 + pos; + dend = end_match_1; + } + else + { + d = string2 + pos - size1; + dend = end_match_2; + } + + DEBUG_PRINT1 ("The compiled pattern is:\n"); + DEBUG_PRINT_COMPILED_PATTERN (bufp, p, pend); + DEBUG_PRINT1 ("The string to match is: `"); + DEBUG_PRINT_DOUBLE_STRING (d, string1, size1, string2, size2); + DEBUG_PRINT1 ("'\n"); + + /* This loops over pattern commands. It exits by returning from the + function if the match is complete, or it drops through if the match + fails at this starting point in the input data. */ + for (;;) + { +#ifdef _LIBC + DEBUG_PRINT2 ("\n%p: ", p); +#else + DEBUG_PRINT2 ("\n0x%x: ", p); +#endif + + if (p == pend) + { /* End of pattern means we might have succeeded. */ + DEBUG_PRINT1 ("end of pattern ... "); + + /* If we haven't matched the entire string, and we want the + longest match, try backtracking. */ + if (d != end_match_2) + { + /* 1 if this match ends in the same string (string1 or string2) + as the best previous match. */ + boolean same_str_p = (FIRST_STRING_P (match_end) + == MATCHING_IN_FIRST_STRING); + /* 1 if this match is the best seen so far. */ + boolean best_match_p; + + /* AIX compiler got confused when this was combined + with the previous declaration. */ + if (same_str_p) + best_match_p = d > match_end; + else + best_match_p = !MATCHING_IN_FIRST_STRING; + + DEBUG_PRINT1 ("backtracking.\n"); + + if (!FAIL_STACK_EMPTY ()) + { /* More failure points to try. */ + + /* If exceeds best match so far, save it. */ + if (!best_regs_set || best_match_p) + { + best_regs_set = true; + match_end = d; + + DEBUG_PRINT1 ("\nSAVING match as best so far.\n"); + + for (mcnt = 1; (unsigned) mcnt < num_regs; mcnt++) + { + best_regstart[mcnt] = regstart[mcnt]; + best_regend[mcnt] = regend[mcnt]; + } + } + goto fail; + } + + /* If no failure points, don't restore garbage. And if + last match is real best match, don't restore second + best one. */ + else if (best_regs_set && !best_match_p) + { + restore_best_regs: + /* Restore best match. It may happen that `dend == + end_match_1' while the restored d is in string2. + For example, the pattern `x.*y.*z' against the + strings `x-' and `y-z-', if the two strings are + not consecutive in memory. */ + DEBUG_PRINT1 ("Restoring best registers.\n"); + + d = match_end; + dend = ((d >= string1 && d <= end1) + ? end_match_1 : end_match_2); + + for (mcnt = 1; (unsigned) mcnt < num_regs; mcnt++) + { + regstart[mcnt] = best_regstart[mcnt]; + regend[mcnt] = best_regend[mcnt]; + } + } + } /* d != end_match_2 */ + + succeed_label: + DEBUG_PRINT1 ("Accepting match.\n"); + + /* If caller wants register contents data back, do it. */ + if (regs && !bufp->no_sub) + { + /* Have the register data arrays been allocated? */ + if (bufp->regs_allocated == REGS_UNALLOCATED) + { /* No. So allocate them with malloc. We need one + extra element beyond `num_regs' for the `-1' marker + GNU code uses. */ + regs->num_regs = MAX (RE_NREGS, num_regs + 1); + regs->start = TALLOC (regs->num_regs, regoff_t); + regs->end = TALLOC (regs->num_regs, regoff_t); + if (regs->start == NULL || regs->end == NULL) + { + FREE_VARIABLES (); + return -2; + } + bufp->regs_allocated = REGS_REALLOCATE; + } + else if (bufp->regs_allocated == REGS_REALLOCATE) + { /* Yes. If we need more elements than were already + allocated, reallocate them. If we need fewer, just + leave it alone. */ + if (regs->num_regs < num_regs + 1) + { + regs->num_regs = num_regs + 1; + RETALLOC (regs->start, regs->num_regs, regoff_t); + RETALLOC (regs->end, regs->num_regs, regoff_t); + if (regs->start == NULL || regs->end == NULL) + { + FREE_VARIABLES (); + return -2; + } + } + } + else + { + /* These braces fend off a "empty body in an else-statement" + warning under GCC when assert expands to nothing. */ + assert (bufp->regs_allocated == REGS_FIXED); + } + + /* Convert the pointer data in `regstart' and `regend' to + indices. Register zero has to be set differently, + since we haven't kept track of any info for it. */ + if (regs->num_regs > 0) + { + regs->start[0] = pos; + regs->end[0] = (MATCHING_IN_FIRST_STRING + ? ((regoff_t) (d - string1)) + : ((regoff_t) (d - string2 + size1))); + } + + /* Go through the first `min (num_regs, regs->num_regs)' + registers, since that is all we initialized. */ + for (mcnt = 1; (unsigned) mcnt < MIN (num_regs, regs->num_regs); + mcnt++) + { + if (REG_UNSET (regstart[mcnt]) || REG_UNSET (regend[mcnt])) + regs->start[mcnt] = regs->end[mcnt] = -1; + else + { + regs->start[mcnt] + = (regoff_t) POINTER_TO_OFFSET (regstart[mcnt]); + regs->end[mcnt] + = (regoff_t) POINTER_TO_OFFSET (regend[mcnt]); + } + } + + /* If the regs structure we return has more elements than + were in the pattern, set the extra elements to -1. If + we (re)allocated the registers, this is the case, + because we always allocate enough to have at least one + -1 at the end. */ + for (mcnt = num_regs; (unsigned) mcnt < regs->num_regs; mcnt++) + regs->start[mcnt] = regs->end[mcnt] = -1; + } /* regs && !bufp->no_sub */ + + DEBUG_PRINT4 ("%u failure points pushed, %u popped (%u remain).\n", + nfailure_points_pushed, nfailure_points_popped, + nfailure_points_pushed - nfailure_points_popped); + DEBUG_PRINT2 ("%u registers pushed.\n", num_regs_pushed); + + mcnt = d - pos - (MATCHING_IN_FIRST_STRING + ? string1 + : string2 - size1); + + DEBUG_PRINT2 ("Returning %d from re_match_2.\n", mcnt); + + FREE_VARIABLES (); + return mcnt; + } + + /* Otherwise match next pattern command. */ + switch (SWITCH_ENUM_CAST ((re_opcode_t) *p++)) + { + /* Ignore these. Used to ignore the n of succeed_n's which + currently have n == 0. */ + case no_op: + DEBUG_PRINT1 ("EXECUTING no_op.\n"); + break; + + case succeed: + DEBUG_PRINT1 ("EXECUTING succeed.\n"); + goto succeed_label; + + /* Match the next n pattern characters exactly. The following + byte in the pattern defines n, and the n bytes after that + are the characters to match. */ + case exactn: + mcnt = *p++; + DEBUG_PRINT2 ("EXECUTING exactn %d.\n", mcnt); + + /* This is written out as an if-else so we don't waste time + testing `translate' inside the loop. */ + if (translate) + { + do + { + PREFETCH (); + if ((unsigned char) translate[(unsigned char) *d++] + != (unsigned char) *p++) + goto fail; + } + while (--mcnt); + } + else + { + do + { + PREFETCH (); + if (*d++ != (char) *p++) goto fail; + } + while (--mcnt); + } + SET_REGS_MATCHED (); + break; + + + /* Match any character except possibly a newline or a null. */ + case anychar: + DEBUG_PRINT1 ("EXECUTING anychar.\n"); + + PREFETCH (); + + if ((!(bufp->syntax & RE_DOT_NEWLINE) && TRANSLATE (*d) == '\n') + || (bufp->syntax & RE_DOT_NOT_NULL && TRANSLATE (*d) == '\000')) + goto fail; + + SET_REGS_MATCHED (); + DEBUG_PRINT2 (" Matched `%d'.\n", *d); + d++; + break; + + + case charset: + case charset_not: + { + register unsigned char c; + boolean not = (re_opcode_t) *(p - 1) == charset_not; + + DEBUG_PRINT2 ("EXECUTING charset%s.\n", not ? "_not" : ""); + + PREFETCH (); + c = TRANSLATE (*d); /* The character to match. */ + + /* Cast to `unsigned' instead of `unsigned char' in case the + bit list is a full 32 bytes long. */ + if (c < (unsigned) (*p * BYTEWIDTH) + && p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH))) + not = !not; + + p += 1 + *p; + + if (!not) goto fail; + + SET_REGS_MATCHED (); + d++; + break; + } + + + /* The beginning of a group is represented by start_memory. + The arguments are the register number in the next byte, and the + number of groups inner to this one in the next. The text + matched within the group is recorded (in the internal + registers data structure) under the register number. */ + case start_memory: + DEBUG_PRINT3 ("EXECUTING start_memory %d (%d):\n", *p, p[1]); + + /* Find out if this group can match the empty string. */ + p1 = p; /* To send to group_match_null_string_p. */ + + if (REG_MATCH_NULL_STRING_P (reg_info[*p]) == MATCH_NULL_UNSET_VALUE) + REG_MATCH_NULL_STRING_P (reg_info[*p]) + = group_match_null_string_p (&p1, pend, reg_info); + + /* Save the position in the string where we were the last time + we were at this open-group operator in case the group is + operated upon by a repetition operator, e.g., with `(a*)*b' + against `ab'; then we want to ignore where we are now in + the string in case this attempt to match fails. */ + old_regstart[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p]) + ? REG_UNSET (regstart[*p]) ? d : regstart[*p] + : regstart[*p]; + DEBUG_PRINT2 (" old_regstart: %d\n", + POINTER_TO_OFFSET (old_regstart[*p])); + + regstart[*p] = d; + DEBUG_PRINT2 (" regstart: %d\n", POINTER_TO_OFFSET (regstart[*p])); + + IS_ACTIVE (reg_info[*p]) = 1; + MATCHED_SOMETHING (reg_info[*p]) = 0; + + /* Clear this whenever we change the register activity status. */ + set_regs_matched_done = 0; + + /* This is the new highest active register. */ + highest_active_reg = *p; + + /* If nothing was active before, this is the new lowest active + register. */ + if (lowest_active_reg == NO_LOWEST_ACTIVE_REG) + lowest_active_reg = *p; + + /* Move past the register number and inner group count. */ + p += 2; + just_past_start_mem = p; + + break; + + + /* The stop_memory opcode represents the end of a group. Its + arguments are the same as start_memory's: the register + number, and the number of inner groups. */ + case stop_memory: + DEBUG_PRINT3 ("EXECUTING stop_memory %d (%d):\n", *p, p[1]); + + /* We need to save the string position the last time we were at + this close-group operator in case the group is operated + upon by a repetition operator, e.g., with `((a*)*(b*)*)*' + against `aba'; then we want to ignore where we are now in + the string in case this attempt to match fails. */ + old_regend[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p]) + ? REG_UNSET (regend[*p]) ? d : regend[*p] + : regend[*p]; + DEBUG_PRINT2 (" old_regend: %d\n", + POINTER_TO_OFFSET (old_regend[*p])); + + regend[*p] = d; + DEBUG_PRINT2 (" regend: %d\n", POINTER_TO_OFFSET (regend[*p])); + + /* This register isn't active anymore. */ + IS_ACTIVE (reg_info[*p]) = 0; + + /* Clear this whenever we change the register activity status. */ + set_regs_matched_done = 0; + + /* If this was the only register active, nothing is active + anymore. */ + if (lowest_active_reg == highest_active_reg) + { + lowest_active_reg = NO_LOWEST_ACTIVE_REG; + highest_active_reg = NO_HIGHEST_ACTIVE_REG; + } + else + { /* We must scan for the new highest active register, since + it isn't necessarily one less than now: consider + (a(b)c(d(e)f)g). When group 3 ends, after the f), the + new highest active register is 1. */ + unsigned char r = *p - 1; + while (r > 0 && !IS_ACTIVE (reg_info[r])) + r--; + + /* If we end up at register zero, that means that we saved + the registers as the result of an `on_failure_jump', not + a `start_memory', and we jumped to past the innermost + `stop_memory'. For example, in ((.)*) we save + registers 1 and 2 as a result of the *, but when we pop + back to the second ), we are at the stop_memory 1. + Thus, nothing is active. */ + if (r == 0) + { + lowest_active_reg = NO_LOWEST_ACTIVE_REG; + highest_active_reg = NO_HIGHEST_ACTIVE_REG; + } + else + highest_active_reg = r; + } + + /* If just failed to match something this time around with a + group that's operated on by a repetition operator, try to + force exit from the ``loop'', and restore the register + information for this group that we had before trying this + last match. */ + if ((!MATCHED_SOMETHING (reg_info[*p]) + || just_past_start_mem == p - 1) + && (p + 2) < pend) + { + boolean is_a_jump_n = false; + + p1 = p + 2; + mcnt = 0; + switch ((re_opcode_t) *p1++) + { + case jump_n: + is_a_jump_n = true; + case pop_failure_jump: + case maybe_pop_jump: + case jump: + case dummy_failure_jump: + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + if (is_a_jump_n) + p1 += 2; + break; + + default: + /* do nothing */ ; + } + p1 += mcnt; + + /* If the next operation is a jump backwards in the pattern + to an on_failure_jump right before the start_memory + corresponding to this stop_memory, exit from the loop + by forcing a failure after pushing on the stack the + on_failure_jump's jump in the pattern, and d. */ + if (mcnt < 0 && (re_opcode_t) *p1 == on_failure_jump + && (re_opcode_t) p1[3] == start_memory && p1[4] == *p) + { + /* If this group ever matched anything, then restore + what its registers were before trying this last + failed match, e.g., with `(a*)*b' against `ab' for + regstart[1], and, e.g., with `((a*)*(b*)*)*' + against `aba' for regend[3]. + + Also restore the registers for inner groups for, + e.g., `((a*)(b*))*' against `aba' (register 3 would + otherwise get trashed). */ + + if (EVER_MATCHED_SOMETHING (reg_info[*p])) + { + unsigned r; + + EVER_MATCHED_SOMETHING (reg_info[*p]) = 0; + + /* Restore this and inner groups' (if any) registers. */ + for (r = *p; r < (unsigned) *p + (unsigned) *(p + 1); + r++) + { + regstart[r] = old_regstart[r]; + + /* xx why this test? */ + if (old_regend[r] >= regstart[r]) + regend[r] = old_regend[r]; + } + } + p1++; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + PUSH_FAILURE_POINT (p1 + mcnt, d, -2); + + goto fail; + } + } + + /* Move past the register number and the inner group count. */ + p += 2; + break; + + + /* \ has been turned into a `duplicate' command which is + followed by the numeric value of as the register number. */ + case duplicate: + { + register const char *d2, *dend2; + int regno = *p++; /* Get which register to match against. */ + DEBUG_PRINT2 ("EXECUTING duplicate %d.\n", regno); + + /* Can't back reference a group which we've never matched. */ + if (REG_UNSET (regstart[regno]) || REG_UNSET (regend[regno])) + goto fail; + + /* Where in input to try to start matching. */ + d2 = regstart[regno]; + + /* Where to stop matching; if both the place to start and + the place to stop matching are in the same string, then + set to the place to stop, otherwise, for now have to use + the end of the first string. */ + + dend2 = ((FIRST_STRING_P (regstart[regno]) + == FIRST_STRING_P (regend[regno])) + ? regend[regno] : end_match_1); + for (;;) + { + /* If necessary, advance to next segment in register + contents. */ + while (d2 == dend2) + { + if (dend2 == end_match_2) break; + if (dend2 == regend[regno]) break; + + /* End of string1 => advance to string2. */ + d2 = string2; + dend2 = regend[regno]; + } + /* At end of register contents => success */ + if (d2 == dend2) break; + + /* If necessary, advance to next segment in data. */ + PREFETCH (); + + /* How many characters left in this segment to match. */ + mcnt = dend - d; + + /* Want how many consecutive characters we can match in + one shot, so, if necessary, adjust the count. */ + if (mcnt > dend2 - d2) + mcnt = dend2 - d2; + + /* Compare that many; failure if mismatch, else move + past them. */ + if (translate + ? bcmp_translate (d, d2, mcnt, translate) + : memcmp (d, d2, mcnt)) + goto fail; + d += mcnt, d2 += mcnt; + + /* Do this because we've match some characters. */ + SET_REGS_MATCHED (); + } + } + break; + + + /* begline matches the empty string at the beginning of the string + (unless `not_bol' is set in `bufp'), and, if + `newline_anchor' is set, after newlines. */ + case begline: + DEBUG_PRINT1 ("EXECUTING begline.\n"); + + if (AT_STRINGS_BEG (d)) + { + if (!bufp->not_bol) break; + } + else if (d[-1] == '\n' && bufp->newline_anchor) + { + break; + } + /* In all other cases, we fail. */ + goto fail; + + + /* endline is the dual of begline. */ + case endline: + DEBUG_PRINT1 ("EXECUTING endline.\n"); + + if (AT_STRINGS_END (d)) + { + if (!bufp->not_eol) break; + } + + /* We have to ``prefetch'' the next character. */ + else if ((d == end1 ? *string2 : *d) == '\n' + && bufp->newline_anchor) + { + break; + } + goto fail; + + + /* Match at the very beginning of the data. */ + case begbuf: + DEBUG_PRINT1 ("EXECUTING begbuf.\n"); + if (AT_STRINGS_BEG (d)) + break; + goto fail; + + + /* Match at the very end of the data. */ + case endbuf: + DEBUG_PRINT1 ("EXECUTING endbuf.\n"); + if (AT_STRINGS_END (d)) + break; + goto fail; + + + /* on_failure_keep_string_jump is used to optimize `.*\n'. It + pushes NULL as the value for the string on the stack. Then + `pop_failure_point' will keep the current value for the + string, instead of restoring it. To see why, consider + matching `foo\nbar' against `.*\n'. The .* matches the foo; + then the . fails against the \n. But the next thing we want + to do is match the \n against the \n; if we restored the + string value, we would be back at the foo. + + Because this is used only in specific cases, we don't need to + check all the things that `on_failure_jump' does, to make + sure the right things get saved on the stack. Hence we don't + share its code. The only reason to push anything on the + stack at all is that otherwise we would have to change + `anychar's code to do something besides goto fail in this + case; that seems worse than this. */ + case on_failure_keep_string_jump: + DEBUG_PRINT1 ("EXECUTING on_failure_keep_string_jump"); + + EXTRACT_NUMBER_AND_INCR (mcnt, p); +#ifdef _LIBC + DEBUG_PRINT3 (" %d (to %p):\n", mcnt, p + mcnt); +#else + DEBUG_PRINT3 (" %d (to 0x%x):\n", mcnt, p + mcnt); +#endif + + PUSH_FAILURE_POINT (p + mcnt, NULL, -2); + break; + + + /* Uses of on_failure_jump: + + Each alternative starts with an on_failure_jump that points + to the beginning of the next alternative. Each alternative + except the last ends with a jump that in effect jumps past + the rest of the alternatives. (They really jump to the + ending jump of the following alternative, because tensioning + these jumps is a hassle.) + + Repeats start with an on_failure_jump that points past both + the repetition text and either the following jump or + pop_failure_jump back to this on_failure_jump. */ + case on_failure_jump: + on_failure: + DEBUG_PRINT1 ("EXECUTING on_failure_jump"); + + EXTRACT_NUMBER_AND_INCR (mcnt, p); +#ifdef _LIBC + DEBUG_PRINT3 (" %d (to %p)", mcnt, p + mcnt); +#else + DEBUG_PRINT3 (" %d (to 0x%x)", mcnt, p + mcnt); +#endif + + /* If this on_failure_jump comes right before a group (i.e., + the original * applied to a group), save the information + for that group and all inner ones, so that if we fail back + to this point, the group's information will be correct. + For example, in \(a*\)*\1, we need the preceding group, + and in \(zz\(a*\)b*\)\2, we need the inner group. */ + + /* We can't use `p' to check ahead because we push + a failure point to `p + mcnt' after we do this. */ + p1 = p; + + /* We need to skip no_op's before we look for the + start_memory in case this on_failure_jump is happening as + the result of a completed succeed_n, as in \(a\)\{1,3\}b\1 + against aba. */ + while (p1 < pend && (re_opcode_t) *p1 == no_op) + p1++; + + if (p1 < pend && (re_opcode_t) *p1 == start_memory) + { + /* We have a new highest active register now. This will + get reset at the start_memory we are about to get to, + but we will have saved all the registers relevant to + this repetition op, as described above. */ + highest_active_reg = *(p1 + 1) + *(p1 + 2); + if (lowest_active_reg == NO_LOWEST_ACTIVE_REG) + lowest_active_reg = *(p1 + 1); + } + + DEBUG_PRINT1 (":\n"); + PUSH_FAILURE_POINT (p + mcnt, d, -2); + break; + + + /* A smart repeat ends with `maybe_pop_jump'. + We change it to either `pop_failure_jump' or `jump'. */ + case maybe_pop_jump: + EXTRACT_NUMBER_AND_INCR (mcnt, p); + DEBUG_PRINT2 ("EXECUTING maybe_pop_jump %d.\n", mcnt); + { + register unsigned char *p2 = p; + + /* Compare the beginning of the repeat with what in the + pattern follows its end. If we can establish that there + is nothing that they would both match, i.e., that we + would have to backtrack because of (as in, e.g., `a*a') + then we can change to pop_failure_jump, because we'll + never have to backtrack. + + This is not true in the case of alternatives: in + `(a|ab)*' we do need to backtrack to the `ab' alternative + (e.g., if the string was `ab'). But instead of trying to + detect that here, the alternative has put on a dummy + failure point which is what we will end up popping. */ + + /* Skip over open/close-group commands. + If what follows this loop is a ...+ construct, + look at what begins its body, since we will have to + match at least one of that. */ + while (1) + { + if (p2 + 2 < pend + && ((re_opcode_t) *p2 == stop_memory + || (re_opcode_t) *p2 == start_memory)) + p2 += 3; + else if (p2 + 6 < pend + && (re_opcode_t) *p2 == dummy_failure_jump) + p2 += 6; + else + break; + } + + p1 = p + mcnt; + /* p1[0] ... p1[2] are the `on_failure_jump' corresponding + to the `maybe_finalize_jump' of this case. Examine what + follows. */ + + /* If we're at the end of the pattern, we can change. */ + if (p2 == pend) + { + /* Consider what happens when matching ":\(.*\)" + against ":/". I don't really understand this code + yet. */ + p[-3] = (unsigned char) pop_failure_jump; + DEBUG_PRINT1 + (" End of pattern: change to `pop_failure_jump'.\n"); + } + + else if ((re_opcode_t) *p2 == exactn + || (bufp->newline_anchor && (re_opcode_t) *p2 == endline)) + { + register unsigned char c + = *p2 == (unsigned char) endline ? '\n' : p2[2]; + + if ((re_opcode_t) p1[3] == exactn && p1[5] != c) + { + p[-3] = (unsigned char) pop_failure_jump; + DEBUG_PRINT3 (" %c != %c => pop_failure_jump.\n", + c, p1[5]); + } + + else if ((re_opcode_t) p1[3] == charset + || (re_opcode_t) p1[3] == charset_not) + { + int not = (re_opcode_t) p1[3] == charset_not; + + if (c < (unsigned char) (p1[4] * BYTEWIDTH) + && p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH))) + not = !not; + + /* `not' is equal to 1 if c would match, which means + that we can't change to pop_failure_jump. */ + if (!not) + { + p[-3] = (unsigned char) pop_failure_jump; + DEBUG_PRINT1 (" No match => pop_failure_jump.\n"); + } + } + } + else if ((re_opcode_t) *p2 == charset) + { + /* We win if the first character of the loop is not part + of the charset. */ + if ((re_opcode_t) p1[3] == exactn + && ! ((int) p2[1] * BYTEWIDTH > (int) p1[5] + && (p2[2 + p1[5] / BYTEWIDTH] + & (1 << (p1[5] % BYTEWIDTH))))) + { + p[-3] = (unsigned char) pop_failure_jump; + DEBUG_PRINT1 (" No match => pop_failure_jump.\n"); + } + + else if ((re_opcode_t) p1[3] == charset_not) + { + int idx; + /* We win if the charset_not inside the loop + lists every character listed in the charset after. */ + for (idx = 0; idx < (int) p2[1]; idx++) + if (! (p2[2 + idx] == 0 + || (idx < (int) p1[4] + && ((p2[2 + idx] & ~ p1[5 + idx]) == 0)))) + break; + + if (idx == p2[1]) + { + p[-3] = (unsigned char) pop_failure_jump; + DEBUG_PRINT1 (" No match => pop_failure_jump.\n"); + } + } + else if ((re_opcode_t) p1[3] == charset) + { + int idx; + /* We win if the charset inside the loop + has no overlap with the one after the loop. */ + for (idx = 0; + idx < (int) p2[1] && idx < (int) p1[4]; + idx++) + if ((p2[2 + idx] & p1[5 + idx]) != 0) + break; + + if (idx == p2[1] || idx == p1[4]) + { + p[-3] = (unsigned char) pop_failure_jump; + DEBUG_PRINT1 (" No match => pop_failure_jump.\n"); + } + } + } + } + p -= 2; /* Point at relative address again. */ + if ((re_opcode_t) p[-1] != pop_failure_jump) + { + p[-1] = (unsigned char) jump; + DEBUG_PRINT1 (" Match => jump.\n"); + goto unconditional_jump; + } + /* Note fall through. */ + + + /* The end of a simple repeat has a pop_failure_jump back to + its matching on_failure_jump, where the latter will push a + failure point. The pop_failure_jump takes off failure + points put on by this pop_failure_jump's matching + on_failure_jump; we got through the pattern to here from the + matching on_failure_jump, so didn't fail. */ + case pop_failure_jump: + { + /* We need to pass separate storage for the lowest and + highest registers, even though we don't care about the + actual values. Otherwise, we will restore only one + register from the stack, since lowest will == highest in + `pop_failure_point'. */ + active_reg_t dummy_low_reg, dummy_high_reg; + unsigned char *pdummy; + const char *sdummy; + + DEBUG_PRINT1 ("EXECUTING pop_failure_jump.\n"); + POP_FAILURE_POINT (sdummy, pdummy, + dummy_low_reg, dummy_high_reg, + reg_dummy, reg_dummy, reg_info_dummy); + } + /* Note fall through. */ + + unconditional_jump: +#ifdef _LIBC + DEBUG_PRINT2 ("\n%p: ", p); +#else + DEBUG_PRINT2 ("\n0x%x: ", p); +#endif + /* Note fall through. */ + + /* Unconditionally jump (without popping any failure points). */ + case jump: + EXTRACT_NUMBER_AND_INCR (mcnt, p); /* Get the amount to jump. */ + DEBUG_PRINT2 ("EXECUTING jump %d ", mcnt); + p += mcnt; /* Do the jump. */ +#ifdef _LIBC + DEBUG_PRINT2 ("(to %p).\n", p); +#else + DEBUG_PRINT2 ("(to 0x%x).\n", p); +#endif + break; + + + /* We need this opcode so we can detect where alternatives end + in `group_match_null_string_p' et al. */ + case jump_past_alt: + DEBUG_PRINT1 ("EXECUTING jump_past_alt.\n"); + goto unconditional_jump; + + + /* Normally, the on_failure_jump pushes a failure point, which + then gets popped at pop_failure_jump. We will end up at + pop_failure_jump, also, and with a pattern of, say, `a+', we + are skipping over the on_failure_jump, so we have to push + something meaningless for pop_failure_jump to pop. */ + case dummy_failure_jump: + DEBUG_PRINT1 ("EXECUTING dummy_failure_jump.\n"); + /* It doesn't matter what we push for the string here. What + the code at `fail' tests is the value for the pattern. */ + PUSH_FAILURE_POINT (NULL, NULL, -2); + goto unconditional_jump; + + + /* At the end of an alternative, we need to push a dummy failure + point in case we are followed by a `pop_failure_jump', because + we don't want the failure point for the alternative to be + popped. For example, matching `(a|ab)*' against `aab' + requires that we match the `ab' alternative. */ + case push_dummy_failure: + DEBUG_PRINT1 ("EXECUTING push_dummy_failure.\n"); + /* See comments just above at `dummy_failure_jump' about the + two zeroes. */ + PUSH_FAILURE_POINT (NULL, NULL, -2); + break; + + /* Have to succeed matching what follows at least n times. + After that, handle like `on_failure_jump'. */ + case succeed_n: + EXTRACT_NUMBER (mcnt, p + 2); + DEBUG_PRINT2 ("EXECUTING succeed_n %d.\n", mcnt); + + assert (mcnt >= 0); + /* Originally, this is how many times we HAVE to succeed. */ + if (mcnt > 0) + { + mcnt--; + p += 2; + STORE_NUMBER_AND_INCR (p, mcnt); +#ifdef _LIBC + DEBUG_PRINT3 (" Setting %p to %d.\n", p - 2, mcnt); +#else + DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p - 2, mcnt); +#endif + } + else if (mcnt == 0) + { +#ifdef _LIBC + DEBUG_PRINT2 (" Setting two bytes from %p to no_op.\n", p+2); +#else + DEBUG_PRINT2 (" Setting two bytes from 0x%x to no_op.\n", p+2); +#endif + p[2] = (unsigned char) no_op; + p[3] = (unsigned char) no_op; + goto on_failure; + } + break; + + case jump_n: + EXTRACT_NUMBER (mcnt, p + 2); + DEBUG_PRINT2 ("EXECUTING jump_n %d.\n", mcnt); + + /* Originally, this is how many times we CAN jump. */ + if (mcnt) + { + mcnt--; + STORE_NUMBER (p + 2, mcnt); +#ifdef _LIBC + DEBUG_PRINT3 (" Setting %p to %d.\n", p + 2, mcnt); +#else + DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p + 2, mcnt); +#endif + goto unconditional_jump; + } + /* If don't have to jump any more, skip over the rest of command. */ + else + p += 4; + break; + + case set_number_at: + { + DEBUG_PRINT1 ("EXECUTING set_number_at.\n"); + + EXTRACT_NUMBER_AND_INCR (mcnt, p); + p1 = p + mcnt; + EXTRACT_NUMBER_AND_INCR (mcnt, p); +#ifdef _LIBC + DEBUG_PRINT3 (" Setting %p to %d.\n", p1, mcnt); +#else + DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p1, mcnt); +#endif + STORE_NUMBER (p1, mcnt); + break; + } + +#if 0 + /* The DEC Alpha C compiler 3.x generates incorrect code for the + test WORDCHAR_P (d - 1) != WORDCHAR_P (d) in the expansion of + AT_WORD_BOUNDARY, so this code is disabled. Expanding the + macro and introducing temporary variables works around the bug. */ + + case wordbound: + DEBUG_PRINT1 ("EXECUTING wordbound.\n"); + if (AT_WORD_BOUNDARY (d)) + break; + goto fail; + + case notwordbound: + DEBUG_PRINT1 ("EXECUTING notwordbound.\n"); + if (AT_WORD_BOUNDARY (d)) + goto fail; + break; +#else + case wordbound: + { + boolean prevchar, thischar; + + DEBUG_PRINT1 ("EXECUTING wordbound.\n"); + if (AT_STRINGS_BEG (d) || AT_STRINGS_END (d)) + break; + + prevchar = WORDCHAR_P (d - 1); + thischar = WORDCHAR_P (d); + if (prevchar != thischar) + break; + goto fail; + } + + case notwordbound: + { + boolean prevchar, thischar; + + DEBUG_PRINT1 ("EXECUTING notwordbound.\n"); + if (AT_STRINGS_BEG (d) || AT_STRINGS_END (d)) + goto fail; + + prevchar = WORDCHAR_P (d - 1); + thischar = WORDCHAR_P (d); + if (prevchar != thischar) + goto fail; + break; + } +#endif + + case wordbeg: + DEBUG_PRINT1 ("EXECUTING wordbeg.\n"); + if (WORDCHAR_P (d) && (AT_STRINGS_BEG (d) || !WORDCHAR_P (d - 1))) + break; + goto fail; + + case wordend: + DEBUG_PRINT1 ("EXECUTING wordend.\n"); + if (!AT_STRINGS_BEG (d) && WORDCHAR_P (d - 1) + && (!WORDCHAR_P (d) || AT_STRINGS_END (d))) + break; + goto fail; + +#ifdef emacs + case before_dot: + DEBUG_PRINT1 ("EXECUTING before_dot.\n"); + if (PTR_CHAR_POS ((unsigned char *) d) >= point) + goto fail; + break; + + case at_dot: + DEBUG_PRINT1 ("EXECUTING at_dot.\n"); + if (PTR_CHAR_POS ((unsigned char *) d) != point) + goto fail; + break; + + case after_dot: + DEBUG_PRINT1 ("EXECUTING after_dot.\n"); + if (PTR_CHAR_POS ((unsigned char *) d) <= point) + goto fail; + break; + + case syntaxspec: + DEBUG_PRINT2 ("EXECUTING syntaxspec %d.\n", mcnt); + mcnt = *p++; + goto matchsyntax; + + case wordchar: + DEBUG_PRINT1 ("EXECUTING Emacs wordchar.\n"); + mcnt = (int) Sword; + matchsyntax: + PREFETCH (); + /* Can't use *d++ here; SYNTAX may be an unsafe macro. */ + d++; + if (SYNTAX (d[-1]) != (enum syntaxcode) mcnt) + goto fail; + SET_REGS_MATCHED (); + break; + + case notsyntaxspec: + DEBUG_PRINT2 ("EXECUTING notsyntaxspec %d.\n", mcnt); + mcnt = *p++; + goto matchnotsyntax; + + case notwordchar: + DEBUG_PRINT1 ("EXECUTING Emacs notwordchar.\n"); + mcnt = (int) Sword; + matchnotsyntax: + PREFETCH (); + /* Can't use *d++ here; SYNTAX may be an unsafe macro. */ + d++; + if (SYNTAX (d[-1]) == (enum syntaxcode) mcnt) + goto fail; + SET_REGS_MATCHED (); + break; + +#else /* not emacs */ + case wordchar: + DEBUG_PRINT1 ("EXECUTING non-Emacs wordchar.\n"); + PREFETCH (); + if (!WORDCHAR_P (d)) + goto fail; + SET_REGS_MATCHED (); + d++; + break; + + case notwordchar: + DEBUG_PRINT1 ("EXECUTING non-Emacs notwordchar.\n"); + PREFETCH (); + if (WORDCHAR_P (d)) + goto fail; + SET_REGS_MATCHED (); + d++; + break; +#endif /* not emacs */ + + default: + abort (); + } + continue; /* Successfully executed one pattern command; keep going. */ + + + /* We goto here if a matching operation fails. */ + fail: + if (!FAIL_STACK_EMPTY ()) + { /* A restart point is known. Restore to that state. */ + DEBUG_PRINT1 ("\nFAIL:\n"); + POP_FAILURE_POINT (d, p, + lowest_active_reg, highest_active_reg, + regstart, regend, reg_info); + + /* If this failure point is a dummy, try the next one. */ + if (!p) + goto fail; + + /* If we failed to the end of the pattern, don't examine *p. */ + assert (p <= pend); + if (p < pend) + { + boolean is_a_jump_n = false; + + /* If failed to a backwards jump that's part of a repetition + loop, need to pop this failure point and use the next one. */ + switch ((re_opcode_t) *p) + { + case jump_n: + is_a_jump_n = true; + case maybe_pop_jump: + case pop_failure_jump: + case jump: + p1 = p + 1; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + p1 += mcnt; + + if ((is_a_jump_n && (re_opcode_t) *p1 == succeed_n) + || (!is_a_jump_n + && (re_opcode_t) *p1 == on_failure_jump)) + goto fail; + break; + default: + /* do nothing */ ; + } + } + + if (d >= string1 && d <= end1) + dend = end_match_1; + } + else + break; /* Matching at this starting point really fails. */ + } /* for (;;) */ + + if (best_regs_set) + goto restore_best_regs; + + FREE_VARIABLES (); + + return -1; /* Failure to match. */ +} /* re_match_2 */ + +/* Subroutine definitions for re_match_2. */ + + +/* We are passed P pointing to a register number after a start_memory. + + Return true if the pattern up to the corresponding stop_memory can + match the empty string, and false otherwise. + + If we find the matching stop_memory, sets P to point to one past its number. + Otherwise, sets P to an undefined byte less than or equal to END. + + We don't handle duplicates properly (yet). */ + +static boolean +group_match_null_string_p (p, end, reg_info) + unsigned char **p, *end; + register_info_type *reg_info; +{ + int mcnt; + /* Point to after the args to the start_memory. */ + unsigned char *p1 = *p + 2; + + while (p1 < end) + { + /* Skip over opcodes that can match nothing, and return true or + false, as appropriate, when we get to one that can't, or to the + matching stop_memory. */ + + switch ((re_opcode_t) *p1) + { + /* Could be either a loop or a series of alternatives. */ + case on_failure_jump: + p1++; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + + /* If the next operation is not a jump backwards in the + pattern. */ + + if (mcnt >= 0) + { + /* Go through the on_failure_jumps of the alternatives, + seeing if any of the alternatives cannot match nothing. + The last alternative starts with only a jump, + whereas the rest start with on_failure_jump and end + with a jump, e.g., here is the pattern for `a|b|c': + + /on_failure_jump/0/6/exactn/1/a/jump_past_alt/0/6 + /on_failure_jump/0/6/exactn/1/b/jump_past_alt/0/3 + /exactn/1/c + + So, we have to first go through the first (n-1) + alternatives and then deal with the last one separately. */ + + + /* Deal with the first (n-1) alternatives, which start + with an on_failure_jump (see above) that jumps to right + past a jump_past_alt. */ + + while ((re_opcode_t) p1[mcnt-3] == jump_past_alt) + { + /* `mcnt' holds how many bytes long the alternative + is, including the ending `jump_past_alt' and + its number. */ + + if (!alt_match_null_string_p (p1, p1 + mcnt - 3, + reg_info)) + return false; + + /* Move to right after this alternative, including the + jump_past_alt. */ + p1 += mcnt; + + /* Break if it's the beginning of an n-th alternative + that doesn't begin with an on_failure_jump. */ + if ((re_opcode_t) *p1 != on_failure_jump) + break; + + /* Still have to check that it's not an n-th + alternative that starts with an on_failure_jump. */ + p1++; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + if ((re_opcode_t) p1[mcnt-3] != jump_past_alt) + { + /* Get to the beginning of the n-th alternative. */ + p1 -= 3; + break; + } + } + + /* Deal with the last alternative: go back and get number + of the `jump_past_alt' just before it. `mcnt' contains + the length of the alternative. */ + EXTRACT_NUMBER (mcnt, p1 - 2); + + if (!alt_match_null_string_p (p1, p1 + mcnt, reg_info)) + return false; + + p1 += mcnt; /* Get past the n-th alternative. */ + } /* if mcnt > 0 */ + break; + + + case stop_memory: + assert (p1[1] == **p); + *p = p1 + 2; + return true; + + + default: + if (!common_op_match_null_string_p (&p1, end, reg_info)) + return false; + } + } /* while p1 < end */ + + return false; +} /* group_match_null_string_p */ + + +/* Similar to group_match_null_string_p, but doesn't deal with alternatives: + It expects P to be the first byte of a single alternative and END one + byte past the last. The alternative can contain groups. */ + +static boolean +alt_match_null_string_p (p, end, reg_info) + unsigned char *p, *end; + register_info_type *reg_info; +{ + int mcnt; + unsigned char *p1 = p; + + while (p1 < end) + { + /* Skip over opcodes that can match nothing, and break when we get + to one that can't. */ + + switch ((re_opcode_t) *p1) + { + /* It's a loop. */ + case on_failure_jump: + p1++; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + p1 += mcnt; + break; + + default: + if (!common_op_match_null_string_p (&p1, end, reg_info)) + return false; + } + } /* while p1 < end */ + + return true; +} /* alt_match_null_string_p */ + + +/* Deals with the ops common to group_match_null_string_p and + alt_match_null_string_p. + + Sets P to one after the op and its arguments, if any. */ + +static boolean +common_op_match_null_string_p (p, end, reg_info) + unsigned char **p, *end; + register_info_type *reg_info; +{ + int mcnt; + boolean ret; + int reg_no; + unsigned char *p1 = *p; + + switch ((re_opcode_t) *p1++) + { + case no_op: + case begline: + case endline: + case begbuf: + case endbuf: + case wordbeg: + case wordend: + case wordbound: + case notwordbound: +#ifdef emacs + case before_dot: + case at_dot: + case after_dot: +#endif + break; + + case start_memory: + reg_no = *p1; + assert (reg_no > 0 && reg_no <= MAX_REGNUM); + ret = group_match_null_string_p (&p1, end, reg_info); + + /* Have to set this here in case we're checking a group which + contains a group and a back reference to it. */ + + if (REG_MATCH_NULL_STRING_P (reg_info[reg_no]) == MATCH_NULL_UNSET_VALUE) + REG_MATCH_NULL_STRING_P (reg_info[reg_no]) = ret; + + if (!ret) + return false; + break; + + /* If this is an optimized succeed_n for zero times, make the jump. */ + case jump: + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + if (mcnt >= 0) + p1 += mcnt; + else + return false; + break; + + case succeed_n: + /* Get to the number of times to succeed. */ + p1 += 2; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + + if (mcnt == 0) + { + p1 -= 4; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + p1 += mcnt; + } + else + return false; + break; + + case duplicate: + if (!REG_MATCH_NULL_STRING_P (reg_info[*p1])) + return false; + break; + + case set_number_at: + p1 += 4; + + default: + /* All other opcodes mean we cannot match the empty string. */ + return false; + } + + *p = p1; + return true; +} /* common_op_match_null_string_p */ + + +/* Return zero if TRANSLATE[S1] and TRANSLATE[S2] are identical for LEN + bytes; nonzero otherwise. */ + +static int +bcmp_translate (s1, s2, len, translate) + const char *s1, *s2; + register int len; + RE_TRANSLATE_TYPE translate; +{ + register const unsigned char *p1 = (const unsigned char *) s1; + register const unsigned char *p2 = (const unsigned char *) s2; + while (len) + { + if (translate[*p1++] != translate[*p2++]) return 1; + len--; + } + return 0; +} + +/* Entry points for GNU code. */ + +/* re_compile_pattern is the GNU regular expression compiler: it + compiles PATTERN (of length SIZE) and puts the result in BUFP. + Returns 0 if the pattern was valid, otherwise an error string. + + Assumes the `allocated' (and perhaps `buffer') and `translate' fields + are set in BUFP on entry. + + We call regex_compile to do the actual compilation. */ + +const char * +re_compile_pattern (pattern, length, bufp) + const char *pattern; + size_t length; + struct re_pattern_buffer *bufp; +{ + reg_errcode_t ret; + + /* GNU code is written to assume at least RE_NREGS registers will be set + (and at least one extra will be -1). */ + bufp->regs_allocated = REGS_UNALLOCATED; + + /* And GNU code determines whether or not to get register information + by passing null for the REGS argument to re_match, etc., not by + setting no_sub. */ + bufp->no_sub = 0; + + /* Match anchors at newline. */ + bufp->newline_anchor = 1; + + ret = regex_compile (pattern, length, re_syntax_options, bufp); + + if (!ret) + return NULL; + return gettext (re_error_msgid + re_error_msgid_idx[(int) ret]); +} +#ifdef _LIBC +weak_alias (__re_compile_pattern, re_compile_pattern) +#endif + +/* Entry points compatible with 4.2 BSD regex library. We don't define + them unless specifically requested. */ + +#if defined _REGEX_RE_COMP || defined _LIBC + +/* BSD has one and only one pattern buffer. */ +static struct re_pattern_buffer re_comp_buf; + +char * +#ifdef _LIBC +/* Make these definitions weak in libc, so POSIX programs can redefine + these names if they don't use our functions, and still use + regcomp/regexec below without link errors. */ +weak_function +#endif +re_comp (s) + const char *s; +{ + reg_errcode_t ret; + + if (!s) + { + if (!re_comp_buf.buffer) + return gettext ("No previous regular expression"); + return 0; + } + + if (!re_comp_buf.buffer) + { + re_comp_buf.buffer = (unsigned char *) malloc (200); + if (re_comp_buf.buffer == NULL) + return (char *) gettext (re_error_msgid + + re_error_msgid_idx[(int) REG_ESPACE]); + re_comp_buf.allocated = 200; + + re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH); + if (re_comp_buf.fastmap == NULL) + return (char *) gettext (re_error_msgid + + re_error_msgid_idx[(int) REG_ESPACE]); + } + + /* Since `re_exec' always passes NULL for the `regs' argument, we + don't need to initialize the pattern buffer fields which affect it. */ + + /* Match anchors at newlines. */ + re_comp_buf.newline_anchor = 1; + + ret = regex_compile (s, strlen (s), re_syntax_options, &re_comp_buf); + + if (!ret) + return NULL; + + /* Yes, we're discarding `const' here if !HAVE_LIBINTL. */ + return (char *) gettext (re_error_msgid + re_error_msgid_idx[(int) ret]); +} + + +int +#ifdef _LIBC +weak_function +#endif +re_exec (s) + const char *s; +{ + const int len = strlen (s); + return + 0 <= re_search (&re_comp_buf, s, len, 0, len, (struct re_registers *) 0); +} + +#endif /* _REGEX_RE_COMP */ + +/* POSIX.2 functions. Don't define these for Emacs. */ + +#ifndef emacs + +/* regcomp takes a regular expression as a string and compiles it. + + PREG is a regex_t *. We do not expect any fields to be initialized, + since POSIX says we shouldn't. Thus, we set + + `buffer' to the compiled pattern; + `used' to the length of the compiled pattern; + `syntax' to RE_SYNTAX_POSIX_EXTENDED if the + REG_EXTENDED bit in CFLAGS is set; otherwise, to + RE_SYNTAX_POSIX_BASIC; + `newline_anchor' to REG_NEWLINE being set in CFLAGS; + `fastmap' to an allocated space for the fastmap; + `fastmap_accurate' to zero; + `re_nsub' to the number of subexpressions in PATTERN. + + PATTERN is the address of the pattern string. + + CFLAGS is a series of bits which affect compilation. + + If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we + use POSIX basic syntax. + + If REG_NEWLINE is set, then . and [^...] don't match newline. + Also, regexec will try a match beginning after every newline. + + If REG_ICASE is set, then we considers upper- and lowercase + versions of letters to be equivalent when matching. + + If REG_NOSUB is set, then when PREG is passed to regexec, that + routine will report only success or failure, and nothing about the + registers. + + It returns 0 if it succeeds, nonzero if it doesn't. (See regex.h for + the return codes and their meanings.) */ + +int +regcomp (preg, pattern, cflags) + regex_t *preg; + const char *pattern; + int cflags; +{ + reg_errcode_t ret; + reg_syntax_t syntax + = (cflags & REG_EXTENDED) ? + RE_SYNTAX_POSIX_EXTENDED : RE_SYNTAX_POSIX_BASIC; + + /* regex_compile will allocate the space for the compiled pattern. */ + preg->buffer = 0; + preg->allocated = 0; + preg->used = 0; + + /* Try to allocate space for the fastmap. */ + preg->fastmap = (char *) malloc (1 << BYTEWIDTH); + + if (cflags & REG_ICASE) + { + unsigned i; + + preg->translate + = (RE_TRANSLATE_TYPE) malloc (CHAR_SET_SIZE + * sizeof (*(RE_TRANSLATE_TYPE)0)); + if (preg->translate == NULL) + return (int) REG_ESPACE; + + /* Map uppercase characters to corresponding lowercase ones. */ + for (i = 0; i < CHAR_SET_SIZE; i++) + preg->translate[i] = ISUPPER (i) ? TOLOWER (i) : i; + } + else + preg->translate = NULL; + + /* If REG_NEWLINE is set, newlines are treated differently. */ + if (cflags & REG_NEWLINE) + { /* REG_NEWLINE implies neither . nor [^...] match newline. */ + syntax &= ~RE_DOT_NEWLINE; + syntax |= RE_HAT_LISTS_NOT_NEWLINE; + /* It also changes the matching behavior. */ + preg->newline_anchor = 1; + } + else + preg->newline_anchor = 0; + + preg->no_sub = !!(cflags & REG_NOSUB); + + /* POSIX says a null character in the pattern terminates it, so we + can use strlen here in compiling the pattern. */ + ret = regex_compile (pattern, strlen (pattern), syntax, preg); + + /* POSIX doesn't distinguish between an unmatched open-group and an + unmatched close-group: both are REG_EPAREN. */ + if (ret == REG_ERPAREN) ret = REG_EPAREN; + + if (ret == REG_NOERROR && preg->fastmap) + { + /* Compute the fastmap now, since regexec cannot modify the pattern + buffer. */ + if (re_compile_fastmap (preg) == -2) + { + /* Some error occurred while computing the fastmap, just forget + about it. */ + free (preg->fastmap); + preg->fastmap = NULL; + } + } + + return (int) ret; +} +#ifdef _LIBC +weak_alias (__regcomp, regcomp) +#endif + + +/* regexec searches for a given pattern, specified by PREG, in the + string STRING. + + If NMATCH is zero or REG_NOSUB was set in the cflags argument to + `regcomp', we ignore PMATCH. Otherwise, we assume PMATCH has at + least NMATCH elements, and we set them to the offsets of the + corresponding matched substrings. + + EFLAGS specifies `execution flags' which affect matching: if + REG_NOTBOL is set, then ^ does not match at the beginning of the + string; if REG_NOTEOL is set, then $ does not match at the end. + + We return 0 if we find a match and REG_NOMATCH if not. */ + +int +regexec (preg, string, nmatch, pmatch, eflags) + const regex_t *preg; + const char *string; + size_t nmatch; + regmatch_t pmatch[]; + int eflags; +{ + int ret; + struct re_registers regs; + regex_t private_preg; + int len = strlen (string); + boolean want_reg_info = !preg->no_sub && nmatch > 0; + + private_preg = *preg; + + private_preg.not_bol = !!(eflags & REG_NOTBOL); + private_preg.not_eol = !!(eflags & REG_NOTEOL); + + /* The user has told us exactly how many registers to return + information about, via `nmatch'. We have to pass that on to the + matching routines. */ + private_preg.regs_allocated = REGS_FIXED; + + if (want_reg_info) + { + regs.num_regs = nmatch; + regs.start = TALLOC (nmatch * 2, regoff_t); + if (regs.start == NULL) + return (int) REG_NOMATCH; + regs.end = regs.start + nmatch; + } + + /* Perform the searching operation. */ + ret = re_search (&private_preg, string, len, + /* start: */ 0, /* range: */ len, + want_reg_info ? ®s : (struct re_registers *) 0); + + /* Copy the register information to the POSIX structure. */ + if (want_reg_info) + { + if (ret >= 0) + { + unsigned r; + + for (r = 0; r < nmatch; r++) + { + pmatch[r].rm_so = regs.start[r]; + pmatch[r].rm_eo = regs.end[r]; + } + } + + /* If we needed the temporary register info, free the space now. */ + free (regs.start); + } + + /* We want zero return to mean success, unlike `re_search'. */ + return ret >= 0 ? (int) REG_NOERROR : (int) REG_NOMATCH; +} +#ifdef _LIBC +weak_alias (__regexec, regexec) +#endif + + +/* Returns a message corresponding to an error code, ERRCODE, returned + from either regcomp or regexec. We don't use PREG here. */ + +size_t +regerror (errcode, preg, errbuf, errbuf_size) + int errcode; + const regex_t *preg; + char *errbuf; + size_t errbuf_size; +{ + const char *msg; + size_t msg_size; + + if (errcode < 0 + || errcode >= (int) (sizeof (re_error_msgid_idx) + / sizeof (re_error_msgid_idx[0]))) + /* Only error codes returned by the rest of the code should be passed + to this routine. If we are given anything else, or if other regex + code generates an invalid error code, then the program has a bug. + Dump core so we can fix it. */ + abort (); + + msg = gettext (re_error_msgid + re_error_msgid_idx[errcode]); + + msg_size = strlen (msg) + 1; /* Includes the null. */ + + if (errbuf_size != 0) + { + if (msg_size > errbuf_size) + { +#if defined HAVE_MEMPCPY || defined _LIBC + *((char *) __mempcpy (errbuf, msg, errbuf_size - 1)) = '\0'; +#else + memcpy (errbuf, msg, errbuf_size - 1); + errbuf[errbuf_size - 1] = 0; +#endif + } + else + memcpy (errbuf, msg, msg_size); + } + + return msg_size; +} +#ifdef _LIBC +weak_alias (__regerror, regerror) +#endif + + +/* Free dynamically allocated space used by PREG. */ + +void +regfree (preg) + regex_t *preg; +{ + if (preg->buffer != NULL) + free (preg->buffer); + preg->buffer = NULL; + + preg->allocated = 0; + preg->used = 0; + + if (preg->fastmap != NULL) + free (preg->fastmap); + preg->fastmap = NULL; + preg->fastmap_accurate = 0; + + if (preg->translate != NULL) + free (preg->translate); + preg->translate = NULL; +} +#ifdef _LIBC +weak_alias (__regfree, regfree) +#endif + +#endif /* not emacs */ +#else /* !defined(USE_LIB_REGEX) */ +char regex_d1[] = "d"; char *regex_d2 = regex_d1; +#endif /* defined(USE_LIB_REGEX) */ diff --git a/lib/rmnt.c b/lib/rmnt.c new file mode 100644 index 0000000..0e1470f --- /dev/null +++ b/lib/rmnt.c @@ -0,0 +1,243 @@ +/* + * 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 "../machine.h" + +#if defined(USE_LIB_READMNT) + +# if !defined(lint) +static char copyright[] = +"@(#) Copyright 1997 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: rmnt.c,v 1.12 2008/10/21 16:13:23 abe Exp $"; +# endif /* !defined(lint) */ + +#include "../lsof.h" + + + +/* + * 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 + */ + +static struct mounts *Lmi = (struct mounts *)NULL; /* local mount info */ +static int Lmist = 0; /* Lmi status */ + + +/* + * readmnt() - read mount table + */ + +struct mounts * +readmnt() +{ + char *dn = (char *)NULL; + char *ln; + 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); + Exit(1); + } +/* + * 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"); + Exit(1); + } + 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); + Exit(1); + } + (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 index 0000000..c7ed582 --- /dev/null +++ b/lib/rnam.c @@ -0,0 +1,669 @@ +/* + * 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 "../machine.h" + +#if defined(HASNCACHE) && defined(USE_LIB_RNAM) + +# if !defined(lint) +static char copyright[] = +"@(#) Copyright 1997 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: rnam.c,v 1.11 2008/10/21 16:13:23 abe Exp $"; +# endif /* !defined(lint) */ + +#include "../lsof.h" + + +/* + * 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., . + * + * 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 + * + * 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 + * must #define NCACHE_NMLEN + * must #define NCACHE_NODEADDR + * must #define NCACHE_NODEID + * optional #define NCACHE_PARID >2)+((int)(i)))*31415)&Mch) +_PROTOTYPE(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) +_PROTOTYPE(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) +_PROTOTYPE(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(i, na) + unsigned long i; /* node's capability ID */ +# else /* !defined(NCACHE_NODEID) */ +ncache_addr(na) +# 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(na, cp) + 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((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); + Exit(1); + } + 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((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((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); + Exit(1); + } +# 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); + Exit(1); + } + } 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(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(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); + Exit(1); + } + 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); + Exit(1); + } + 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(buf, blen, fp) + 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 index 0000000..0bdb7db --- /dev/null +++ b/lib/rnch.c @@ -0,0 +1,811 @@ +/* + * 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 "../machine.h" + +#if defined(HASNCACHE) && defined(USE_LIB_RNCH) + +# if !defined(lint) +static char copyright[] = +"@(#) Copyright 1997 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: rnch.c,v 1.11 2008/10/21 16:13:23 abe Exp $"; +# endif /* !defined(lint) */ + +#include "../lsof.h" + + +/* + * 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., . + * + * 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) +_PROTOTYPE(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) */ +_PROTOTYPE(static struct l_nch *ncache_addr,(KA_T v)); +#define ncachehash(v) Nchash+((((int)(v)>>2)*31415)&Mch) +# endif /* defined(NCACHE_NODEID) */ + +_PROTOTYPE(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 * + +# if defined(NCACHE_NODEID) +ncache_addr(i, v) +# else /* !defined(NCACHE_NODEID) */ +ncache_addr(v) +# endif /* defined(NCACHE_NODEID) */ + +# 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(va, cp) + 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((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); + Exit(1); + } + } + vc[vcn++] = va; + return(1); +} + + +/* + * ncache_load() - load the kernel's name cache + */ + +void +ncache_load() +{ + 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((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((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); + Exit(1); + } +# 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); + Exit(1); + } + } 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(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(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); + Exit(1); + } + } + if (!kc->NCACHE_NAME || kread((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); + Exit(1); + } + (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); + Exit(1); + } + 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); + Exit(1); + } + 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(buf, blen, fp) + 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 index 0000000..9cf00a9 --- /dev/null +++ b/lib/rnmh.c @@ -0,0 +1,743 @@ +/* + * 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 "../machine.h" + +#if defined(HASNCACHE) && defined(USE_LIB_RNMH) + +# if !defined(lint) +static char copyright[] = +"@(#) Copyright 1997 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: rnmh.c,v 1.13 2008/10/21 16:13:23 abe Exp $"; +# endif /* !defined(lint) */ + +#include "../lsof.h" + + +/* + * rnmh.c - read BSD format hashed kernel name cache + */ + +/* + * The caller must: + * + * #include the relevant header file -- e.g., . + * + * 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 + * + * + * 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 + * #define NCACHE_NXT + * #define NCACHE_NODEADDR + * #define NCACHE_PARADDR + * + * Optionally define: + * + * #define NCACHE_NMLEN + * + * Optionally define *both*: + * + * #define NCACHE_NODEID + * #define NCACHE_PARID + * + * 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) +_PROTOTYPE(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) +_PROTOTYPE(static struct l_nch *ncache_addr,(KA_T na)); +# endif /* defined(NCACHE_NODEID) */ + +# if !defined(NCACHE_NO_ROOT) +_PROTOTYPE(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(i, na) + unsigned long i; /* node's capability ID */ +# else /* !defined(NCACHE_NODEID) */ +ncache_addr(na) +# 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(na, cp) + 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((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(); 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); + Exit(1); + } + nca += 10; + } + nc[ncn++] = na; + return(1); +} +# endif /* !defined(NCACHE_NO_ROOT) */ + + +/* + * ncache_load() - load the kernel's name cache + */ + +void +ncache_load() +{ + 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(X_NCSIZE, (struct drive_Nl *)NULL, &v) < 0 + || !v + || kread((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(X_NCACHE, (struct drive_Nl *)NULL, &v) < 0 + || !v + || kread((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); + Exit(1); + } + khpl = len; + } + if (kread((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(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((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(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); + Exit(1); + } + 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(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); + Exit(1); + } + 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(buf, blen, fp) + 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(); 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(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/snpf.c b/lib/snpf.c new file mode 100644 index 0000000..c20b91f --- /dev/null +++ b/lib/snpf.c @@ -0,0 +1,749 @@ +/* + * snpf.c -- snprintf() empulation functions for lsof library + * + * V. Abell + * Purdue University Computing Center + */ + +/* + * Copyright 2000 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. + * + * This software has been adapted from snprintf.c in sendmail 8.9.3. It + * is subject to the sendmail copyright statements listed below, and the + * sendmail licensing terms stated in the sendmail LICENSE file comment + * section of this file. + * + * 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 "../machine.h" + +#ifdef USE_LIB_SNPF + +/* + * Sendmail copyright statements: + * + * Copyright (c) 1998 Sendmail, Inc. All rights reserved. + * Copyright (c) 1997 Eric P. Allman. All rights reserved. + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the sendmail distribution. + * + * The LICENSE file may be found in the following comment section. + */ + + +/* + * Begin endmail LICENSE file. + + SENDMAIL LICENSE + +The following license terms and conditions apply, unless a different +license is obtained from Sendmail, Inc., 1401 Park Avenue, Emeryville, CA +94608, or by electronic mail at license@sendmail.com. + +License Terms: + +Use, Modification and Redistribution (including distribution of any +modified or derived work) in source and binary forms is permitted only if +each of the following conditions is met: + +1. Redistributions qualify as "freeware" or "Open Source Software" under + one of the following terms: + + (a) Redistributions are made at no charge beyond the reasonable cost of + materials and delivery. + + (b) Redistributions are accompanied by a copy of the Source Code or by an + irrevocable offer to provide a copy of the Source Code for up to three + years at the cost of materials and delivery. Such redistributions + must allow further use, modification, and redistribution of the Source + Code under substantially the same terms as this license. For the + purposes of redistribution "Source Code" means the complete source + code of sendmail including all modifications. + + Other forms of redistribution are allowed only under a separate royalty- + free agreement permitting such redistribution subject to standard + commercial terms and conditions. A copy of such agreement may be + obtained from Sendmail, Inc. at the above address. + +2. Redistributions of source code must retain the copyright notices as they + appear in each source code file, these license terms, and the + disclaimer/limitation of liability set forth as paragraph 6 below. + +3. Redistributions in binary form must reproduce the Copyright Notice, + these license terms, and the disclaimer/limitation of liability set + forth as paragraph 6 below, in the documentation and/or other materials + provided with the distribution. For the purposes of binary distribution + the "Copyright Notice" refers to the following language: + "Copyright (c) 1998 Sendmail, Inc. All rights reserved." + +4. Neither the name of Sendmail, Inc. nor the University of California nor + the names of their contributors may be used to endorse or promote + products derived from this software without specific prior written + permission. The name "sendmail" is a trademark of Sendmail, Inc. + +5. All redistributions must comply with the conditions imposed by the + University of California on certain embedded code, whose copyright + notice and conditions for redistribution are as follows: + + (a) Copyright (c) 1988, 1993 The Regents of the University of + California. All rights reserved. + + (b) Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + (i) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (ii) 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. + + (iii) 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." + + (iv) 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. + +6. Disclaimer/Limitation of Liability: THIS SOFTWARE IS PROVIDED BY + SENDMAIL, INC. 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 SENDMAIL, INC., THE REGENTS OF THE UNIVERSITY OF + CALIFORNIA 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 DAMAGES. + +(Version 8.6, last updated 6/24/1998) + + * End endmail LICENSE file. + */ + + +/* + * If "ll" format support is not possible -- e.g., the long long type isn't + * supported -- define HAS_NO_LONG_LONG. + */ + +# ifndef lint +static char copyright[] = +"@(#) Copyright 2000 Purdue Research Foundation.\nAll rights reserved.\n"; +# endif /* !defined(lint) */ + +#include + +#if defined(__STDC__) +#define _PROTOTYPE(function, params) function params +#else /* !defined(__STDC__) */ +#define _PROTOTYPE(function, params) function() +#endif /* defined(__STDC__) */ + + +/* +** SNPRINTF, VSNPRINT -- counted versions of printf +** +** These versions have been grabbed off the net. They have been +** cleaned up to compile properly and support for .precision and +** %lx has been added. +*/ + +/************************************************************** + * Original: + * Patrick Powell Tue Apr 11 09:48:21 PDT 1995 + * A bombproof version of doprnt (dopr) included. + * Sigh. This sort of thing is always nasty do deal with. Note that + * the version here does not include floating point... + * + * snprintf() is used instead of sprintf() as it does limit checks + * for string length. This covers a nasty loophole. + * + * The other functions are there to prevent NULL pointers from + * causing nast effects. + **************************************************************/ + +/*static char _id[] = "$Id: snpf.c,v 1.5 2008/10/21 16:13:23 abe Exp $";*/ + + +/* + * Local function prototypes + */ + +_PROTOTYPE(static void dopr,(char *bp, char *ep, char *fmt, va_list args)); +_PROTOTYPE(static void dopr_outch,(char **bp, char *ep, int c)); +_PROTOTYPE(static void dostr,(char **bp, char *ep, char *str, int)); + +# if !defined(HAS_NO_LONG_LONG) +_PROTOTYPE(static void fmtllnum,(char **bp, char *ep, long long value, + int base, int dosign, int ljust, int len, + int zpad)); +# endif /* !defined(HAS_NO_LONG_LONG) */ + +_PROTOTYPE(static void fmtnum,(char **bp, char *ep, long value, int base, + int dosign, int ljust, int len, int zpad)); +_PROTOTYPE(static void fmtstr,(char **bp, char *ep, char *value, int ljust, + int len, int zpad, + int maxwidth)); + + +/* + * Local variables + */ + +static int Length; + + +/* + * snpf() -- count-controlled sprintf() + */ + +int +snpf(va_alist) + va_dcl /* requires at least three arguments: + * bp = receiving buffer pointer + * ct = length of buffer + * fmt = format string + */ +{ + va_list args; + char *bp, *fmt; + int ct, len; + + va_start(args); + bp = va_arg(args, char *); + ct = va_arg(args, int); + fmt = va_arg(args, char *); + len = vsnpf(bp, ct, fmt, args); + va_end(args); + return(len); +} + + +/* + * vsnpf() -- count-controlled vsprintf() + */ + +int +vsnpf(str, count, fmt, args) + char *str; /* result buffer */ + int count; /* size of buffer */ + char *fmt; /* format */ + va_list args; /* variable length argument list */ +{ + char *ep = str + count - 1; + + *str = '\0'; + (void) dopr(str, ep, fmt, args); + if (count > 0) + *ep = '\0'; + return(Length); +} + + +/* + * dopr() -- poor man's version of doprintf + */ + + +static void +dopr(bp, ep, fmt, args) + char *bp; /* buffer start */ + char *ep; /* buffer end (start + length - 1) */ + char *fmt; /* format */ + va_list args; /* variable length argument list */ +{ + int ch; + char ebuf[64]; + int ebufl = (int)(sizeof(ebuf) - 1); + long value; + int longflag = 0; + int longlongflag = 0; + int pointflag = 0; + int maxwidth = 0; + char *strvalue; + int ljust; + int len; + int zpad; + int zxflag = 0; + +# if !defined(HAS_NO_LONG_LONG) + long long llvalue; +# endif /* !defined(HAS_NO_LONG_LONG) */ + + Length = 0; + while((ch = *fmt++)) { + switch (ch) { + case '%': + ljust = len = zpad = zxflag = maxwidth = 0; + longflag = longlongflag = pointflag = 0; + +nextch: + + ch = *fmt++; + switch (ch) { + case '\0': + dostr(&bp, ep, "**end of format**" , 0); + return; + case '-': + ljust = 1; + goto nextch; + case '0': /* set zero padding if len not set */ + if ((len == 0) && !pointflag) + zpad = '0'; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (pointflag) + maxwidth = (maxwidth * 10) + (int)(ch - '0'); + else + len = (len * 10) + (int)(ch - '0'); + goto nextch; + case '*': + if (pointflag) + maxwidth = va_arg(args, int); + else + len = va_arg(args, int); + goto nextch; + case '#': + zxflag = 1; + goto nextch; + case '.': + pointflag = 1; + goto nextch; + case 'l': + if (longflag) { + longflag = 0; + longlongflag = 1; + goto nextch; + } + longflag = 1; + goto nextch; + case 'u': + case 'U': + if (longlongflag) { + +# if !defined(HAS_NO_LONG_LONG) + llvalue = va_arg(args, long long); + (void) fmtllnum(&bp,ep,llvalue,10,0,ljust,len,zpad); +# else /* defined(HAS_NO_LONG_LONG) */ + (void) strncpy(ebuf, "ll is unsupported", ebufl); + ebuf[(int)ebufl] = '\0'; + (void) dostr(&bp, ep, ebuf, 0); +# endif /* !defined(HAS_NO_LONG_LONG) */ + + break; + } + if (longflag) + value = va_arg(args, long); + else + value = va_arg(args, int); + (void) fmtnum(&bp, ep, value, 10,0, ljust, len, zpad); + break; + case 'o': + case 'O': + if (longlongflag) { + +# if !defined(HAS_NO_LONG_LONG) + llvalue = va_arg(args, long long); + (void) fmtllnum(&bp,ep,llvalue,8,0,ljust,len,zpad); +# else /* defined(HAS_NO_LONG_LONG) */ + (void) strncpy(ebuf, "ll is unsupported", ebufl); + ebuf[(int)ebufl] = '\0'; + (void) dostr(&bp, ep, ebuf, 0); +# endif /* !defined(HAS_NO_LONG_LONG) */ + + break; + } + if (longflag) + value = va_arg(args, long); + else + value = va_arg(args, int); + (void) fmtnum(&bp, ep, value, 8,0, ljust, len, zpad); + break; + case 'd': + case 'D': + if (longlongflag) { + +# if !defined(HAS_NO_LONG_LONG) + llvalue = va_arg(args, long long); + (void) fmtllnum(&bp,ep,llvalue,10,1,ljust,len,zpad); +# else /* defined(HAS_NO_LONG_LONG) */ + (void) strncpy(ebuf, "ll is unsupported", ebufl); + ebuf[(int)ebufl] = '\0'; + (void) dostr(&bp, ep, ebuf, 0); +# endif /* !defined(HAS_NO_LONG_LONG) */ + + break; + } + if (longflag) + value = va_arg(args, long); + else + value = va_arg(args, int); + (void) fmtnum(&bp, ep, value, 10,1, ljust, len, zpad); + break; + case 'x': + if (longlongflag) { + +# if !defined(HAS_NO_LONG_LONG) + llvalue = va_arg(args, long long); + if (zxflag && llvalue) { + (void) dostr(&bp, ep, "0x", 0); + if (len >= 2) + len -= 2; + } + (void) fmtllnum(&bp,ep,llvalue,16,0,ljust,len,zpad); +# else /* defined(HAS_NO_LONG_LONG) */ + (void) strncpy(ebuf, "ll is unsupported", ebufl); + ebuf[(int)ebufl] = '\0'; + (void) dostr(&bp, ep, ebuf, 0); +# endif /* !defined(HAS_NO_LONG_LONG) */ + + break; + } + if (longflag) + value = va_arg(args, long); + else + value = va_arg(args, int); + if (zxflag && value) { + (void) dostr(&bp, ep, "0x", 0); + if (len >= 2) + len -= 2; + } + (void) fmtnum(&bp, ep, value, 16,0, ljust, len, zpad); + break; + case 'X': + if (longlongflag) { + +# if !defined(HAS_NO_LONG_LONG) + llvalue = va_arg(args, long long); + if (zxflag && llvalue) { + (void) dostr(&bp, ep, "0x", 0); + if (len >= 2) + len -= 2; + } + (void) fmtllnum(&bp,ep,llvalue,-16,0,ljust,len,zpad); +# else /* defined(HAS_NO_LONG_LONG) */ + (void) strncpy(ebuf, "ll is unsupported", ebufl); + ebuf[(int)ebufl] = '\0'; + (void) dostr(&bp, ep, ebuf, 0); +# endif /* !defined(HAS_NO_LONG_LONG) */ + + break; + } + if (longflag) + value = va_arg(args, long); + else + value = va_arg(args, int); + if (zxflag && value) { + (void) dostr(&bp, ep, "0x", 0); + if (len >= 2) + len -= 2; + } + (void) fmtnum(&bp, ep, value,-16,0, ljust, len, zpad); + break; + case 's': + strvalue = va_arg(args, char *); + if (maxwidth > 0 || !pointflag) { + if (pointflag && len > maxwidth) + len = maxwidth; /* Adjust padding */ + (void) fmtstr(&bp, ep, strvalue, ljust, len, zpad, + maxwidth); + } + break; + case 'c': + ch = va_arg(args, int); + dopr_outch(&bp, ep, ch); + break; + case '%': + (void) dopr_outch(&bp, ep, ch); + continue; + default: + ebuf[0] = ch; + (void) strncpy(&ebuf[1], " is unsupported", ebufl); + ebuf[(int)ebufl] = '\0'; + (void) dostr(&bp, ep, ebuf, 0); + } + break; + default: + (void) dopr_outch(&bp, ep, ch); + break; + } + } + *bp = '\0'; +} + + +# if !defined(HAS_NO_LONG_LONG) +/* + * fmtllnum() -- format long long number for output + */ + +static void +fmtllnum(bp, ep, value, base, dosign, ljust, len, zpad) + char **bp; /* current buffer pointer */ + char *ep; /* end of buffer (-1) */ + long long value; /* number to format */ + int base; /* number base */ + int dosign; /* sign request */ + int ljust; /* left justfication request */ + int len; /* length request */ + int zpad; /* zero padding request */ +{ + int signvalue = 0; + unsigned long long uvalue; + char convert[20]; + int place = 0; + int padlen = 0; /* amount to pad */ + int caps = 0; + + uvalue = value; + if (dosign) { + if (value < 0) { + signvalue = '-'; + uvalue = -value; + } + } + if (base < 0) { + caps = 1; + base = -base; + } + do { + convert[place++] = + (caps ? "0123456789ABCDEF" : "0123456789abcdef") + [uvalue % (unsigned)base]; + uvalue = (uvalue / (unsigned)base); + } while (uvalue && (place < (int)(sizeof(convert) - 1))); + convert[place] = 0; + padlen = len - place; + if (padlen < 0) + padlen = 0; + if(ljust) + padlen = -padlen; + if (zpad && padlen > 0) { + if (signvalue) { + (void) dopr_outch(bp, ep, signvalue); + --padlen; + signvalue = 0; + } + while (padlen > 0) { + (void) dopr_outch(bp, ep, zpad); + --padlen; + } + } + while (padlen > 0) { + (void) dopr_outch(bp, ep, ' '); + --padlen; + } + if (signvalue) + (void) dopr_outch(bp, ep, signvalue); + while (place > 0) + (void) dopr_outch(bp, ep, convert[--place]); + while (padlen < 0) { + (void) dopr_outch(bp, ep, ' '); + ++padlen; + } +} +# endif /* !defined(HAS_NO_LONG_LONG) */ + + +/* + * fmtnum() -- format number for output + */ + +static void +fmtnum(bp, ep, value, base, dosign, ljust, len, zpad) + char **bp; /* current buffer pointer */ + char *ep; /* end of buffer (-1) */ + long value; /* number to format */ + int base; /* number base */ + int dosign; /* sign request */ + int ljust; /* left justfication request */ + int len; /* length request */ + int zpad; /* zero padding request */ +{ + int signvalue = 0; + unsigned long uvalue; + char convert[20]; + int place = 0; + int padlen = 0; /* amount to pad */ + int caps = 0; + + uvalue = value; + if (dosign) { + if (value < 0) { + signvalue = '-'; + uvalue = -value; + } + } + if (base < 0) { + caps = 1; + base = -base; + } + do { + convert[place++] = + (caps ? "0123456789ABCDEF" : "0123456789abcdef") + [uvalue % (unsigned)base]; + uvalue = (uvalue / (unsigned)base); + } while (uvalue && (place < (int)(sizeof(convert) - 1))); + convert[place] = 0; + padlen = len - place; + if (padlen < 0) + padlen = 0; + if(ljust) + padlen = -padlen; + if (zpad && padlen > 0) { + if (signvalue) { + (void) dopr_outch(bp, ep, signvalue); + --padlen; + signvalue = 0; + } + while (padlen > 0) { + (void) dopr_outch(bp, ep, zpad); + --padlen; + } + } + while (padlen > 0) { + (void) dopr_outch(bp, ep, ' '); + --padlen; + } + if (signvalue) + (void) dopr_outch(bp, ep, signvalue); + while (place > 0) + (void) dopr_outch(bp, ep, convert[--place]); + while (padlen < 0) { + (void) dopr_outch(bp, ep, ' '); + ++padlen; + } +} + + +/* + * fmtstr() -- format string for output + */ + +static void +fmtstr(bp, ep, value, ljust, len, zpad, maxwidth) + char **bp; /* current buffer pointer */ + char *ep; /* end of buffer (-1) */ + char *value; /* string to format */ + int ljust; /* left justification request */ + int len; /* length request */ + int zpad; /* zero padding request */ + int maxwidth; /* maximum width request */ +{ + int padlen, strlen; /* amount to pad */ + + if (value == 0) + value = ""; + for (strlen = 0; value[strlen]; ++ strlen) /* strlen() */ + ; + if ((strlen > maxwidth) && maxwidth) + strlen = maxwidth; + padlen = len - strlen; + if (padlen < 0) + padlen = 0; + if (ljust) + padlen = -padlen; + while (padlen > 0) { + (void) dopr_outch(bp, ep, ' '); + --padlen; + } + (void) dostr(bp, ep, value, maxwidth); + while (padlen < 0) { + (void) dopr_outch(bp, ep, ' '); + ++padlen; + } +} + + +/* + * dostr() -- do string output + */ + +static void +dostr(bp, ep, str, cut) + char **bp; /* current buffer pointer */ + char *ep; /* end of buffer (-1) */ + char *str; /* string to output */ + int cut; /* limit on amount of string to output: + * 0 == no limit */ +{ + int f; + + f = cut ? 1 : 0; + while (*str) { + if (f) { + if (cut-- > 0) + (void) dopr_outch(bp, ep, *str); + } else + (void) dopr_outch(bp, ep, *str); + str++; + } +} + + +/* + * dopr_outch() -- output a character (or two) + */ + +static void +dopr_outch(bp, ep, c) + char **bp; /* current buffer pointer */ + char *ep; /* end of buffer (-1) */ + int c; /* character to output */ +{ + register char *cp = *bp; + + if (iscntrl(c) && c != '\n' && c != '\t') { + c = '@' + (c & 0x1F); + if (cp < ep) + *cp++ = '^'; + Length++; + } + if (cp < ep) + *cp++ = c; + *bp = cp; + Length++; +} + +#else /* !defined(USE_LIB_SNPF) */ +char snpf_d1[] = "d"; char *snpf_d2 = snpf_d1; +#endif /* defined(USE_LIB_SNPF) */ diff --git a/lsof.h b/lsof.h new file mode 100644 index 0000000..44a2848 --- /dev/null +++ b/lsof.h @@ -0,0 +1,1084 @@ +/* + * lsof.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: lsof.h,v 1.70 2018/03/26 21:50:45 abe Exp $ + */ + + +#if !defined(LSOF_H) +#define LSOF_H 1 + +#include "machine.h" + +# if !defined(FSV_DEFAULT) +#define FSV_DEFAULT 0 +# endif /* !defined(FSV_DEFAULT) */ + +#include "lsof_fields.h" + +#include +#include + +# if defined(HASSETLOCALE) +#include +# endif /* defined(HASSETLOCALE) */ + +#include +#include +#include + +#include +#include + + +/* + * 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 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) */ +# 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_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_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 /* just in case -- because utmp.h + * may need it */ +#include "./regex.h" + +# if defined(EMPTY) +#undef EMPTY +# endif /* defined(EMPTY) */ + +# if defined(HASUTMPX) +#include +# else /* !defined(HASUTMPX) */ +#include +# 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) +static struct utmpx dummy_utmp; /* to get login name length */ +#define LOGINML sizeof(dummy_utmp.ut_user) + /* login name length */ +# else /* !defined(HASUTMPX) */ +static struct utmp dummy_utmp; /* to get login name length */ +#define LOGINML sizeof(dummy_utmp.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 */ + +# 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 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 */ + +/* + * 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) */ + +extern int AllProc; + +# 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; +extern efsys_list_t *Efsysl; /* file systems for which kernel blocks + * are to be eliminated */ + +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; +extern lsof_rx_t *CmdRx; +extern int NCmdRxU; + +# 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) */ + +# 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; + +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 */ + +# 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; +# endif /* defined(HASEPTOPTS) */ + + +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) */ +}; + +# if defined(HASBLKDEV) +extern struct l_dev *BDevtp, **BSdev; +extern int BNdev; +# endif /* defined(HASBLKDEV) */ + +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 */ +}; +extern struct str_lst *Cmdl; +extern int CmdLim; +extern int Cmdni; +extern int Cmdnx; + +# if defined(HASSELINUX) +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 cntxlist_t *CntxArg; +extern int CntxStatus; +# endif /* defined(HASSELINUX) */ + +# if defined(HASDCACHE) +extern unsigned DCcksum; +extern int DCfd; +extern FILE *DCfs; +extern char *DCpathArg; +extern char *DCpath[]; +extern int DCpathX; +extern int DCrebuilt; +extern int DCstate; +extern int DCunsafe; +# endif /* defined(HASDCACHE) */ + +extern int DChelp; +extern dev_t DevDev; +extern struct l_dev *Devtp; +extern char **Dstk; +extern int Dstkn; +extern int Dstkx; +extern int ErrStat; +extern uid_t Euid; +extern int Fand; +extern int Fblock; +extern int Fcntx; +extern int Ffield; +extern int Ffilesys; +extern int Fhelp; +extern int Fhost; + +# if defined(HASNCACHE) +extern int Fncache; +extern int NcacheReload; +# endif /* defined(HASNCACHE) */ + +extern int Fnet; +extern int FnetTy; +extern int Fnfs; +extern int Fnlink; +extern int Foffset; +extern int Fovhd; +extern int FeptE; + +extern int Fport; + +# if !defined(HASNORPC_H) +extern int FportMap; +# endif /* !defined(HASNORPC_H) */ + +extern int Fpgid; +extern int Fppid; +extern int Fsize; +extern int Fsv; +extern int FsvByf; +extern int FsvFlagX; +extern int Ftask; +extern int Ftcptpi; +extern int Fterse; +extern int Funix; +extern int Futol; +extern int Fverbose; +extern int Fwarn; + +# if defined(HASXOPT_VALUE) +extern int Fxopt; +# endif /* defined(HASXOPT_VALUE) */ + +extern int Fxover; +extern int Fzone; + +struct fd_lst { + char *nm; /* file descriptor name -- range if + * NULL */ + int lo; /* range start (if nm NULL) */ + int hi; /* range end (if nm NULL) */ + struct fd_lst *next; +}; +extern struct fd_lst *Fdl; +extern int FdlTy; /* Fdl[] type: -1 == none + * 0 == include + * 1 == exclude */ + +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 int IgnTasks; +extern char *InodeFmt_d; +extern char *InodeFmt_x; +extern int LastPid; + +struct lfile { + char access; + char 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 */ +# 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) */ + + char fd[FDLEN]; + char iproto[IPROTOL]; + char type[TYPEL]; + 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; +}; +extern struct lfile *Lf, *Plf; + + +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 struct lproc *Lp, *Lproc; + +extern int MaxFd; +extern char *Memory; +extern int MntSup; +extern char *MntSupP; + +# if defined(HASPROCFS) +extern struct mounts *Mtprocfs; +# endif + +extern int Mxpgid; +extern int Mxpid; +extern int Mxuid; +extern gid_t Mygid; +extern int Mypid; +extern uid_t Myuid; +extern char *Namech; +extern size_t Namechl; +extern int Ndev; + +# 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 long Nlink; +extern int Nlproc; +extern char *Nmlst; +extern int Npgid; +extern int Npgidi; +extern int Npgidx; +extern int Npid; +extern int Npidi; +extern int Npidx; +extern int Npuns; +extern int Ntype; +extern int Nuid; +extern int Nuidexcl; +extern int Nuidincl; + +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; +extern char *Pn; + +# 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 RptTm; +extern struct l_dev **Sdev; +extern int SelAll; +extern int Selflags; +extern int SelProc; +extern int Setgid; +extern int Selinet; +extern int Setuidroot; +extern struct sfile *Sfile; +extern struct int_lst *Spgid; +extern struct int_lst *Spid; +extern struct seluid *Suid; +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 TmLimit; +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; + +# if defined(HASZONES) +typedef struct znhash { + char *zn; /* zone name */ + int f; /* "find" flag (used only in ZoneArg) */ + struct znhash *next; /* next zone hash entry */ +} znhash_t; +extern znhash_t **ZoneArg; +# endif /* defined(HASZONES) */ + +#include "proto.h" +#include "dproto.h" + +#endif /* LSOF_H */ diff --git a/lsof_fields.h b/lsof_fields.h new file mode 100644 index 0000000..81b72ee --- /dev/null +++ b/lsof_fields.h @@ -0,0 +1,184 @@ +/* + * 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: + * + * + * 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" + +#define LSOF_FID_FD 'f' +#define LSOF_FIX_FD 5 +#define LSOF_FNM_FD "file descriptor (always selected)" + +#define LSOF_FID_FA 'F' +#define LSOF_FIX_FA 6 +#define LSOF_FNM_FA "file struct address as 0x" + +#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" + +#define LSOF_FID_OFFSET 'o' +#define LSOF_FIX_OFFSET 17 +#define LSOF_FNM_OFFSET "file offset as 0t or 0x" + +#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" + +#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/main.c b/main.c new file mode 100644 index 0000000..169e334 --- /dev/null +++ b/main.c @@ -0,0 +1,1913 @@ +/* + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: main.c,v 1.59 2018/03/26 21:50:45 abe Exp $"; +#endif + + +#include "lsof.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 */ + + +_PROTOTYPE(static int GetOpt,(int ct, char *opt[], char *rules, int *err)); +_PROTOTYPE(static char *sv_fmt_str,(char *f)); + + +/* + * main() - main function for lsof + */ + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int ad, c, i, n, rv, se1, se2, ss; + char *cp; + int err = 0; + int ev = 0; + 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; + +#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) */ + +/* + * Save program name. + */ + if ((Pn = strrchr(argv[0], '/'))) + Pn++; + else + Pn = argv[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; + +#if defined(HAS_CLOSEFROM) + (void) closefrom(3); +#else /* !defined(HAS_CLOSEFROM) */ + for (i = 3; i < MaxFd; i++) + (void) close(i); +#endif /* !defined(HAS_CLOSEFROM) */ + + while (((i = open("/dev/null", O_RDWR, 0)) >= 0) && (i < 2)) + ; + if (i < 0) + Exit(1); + 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; + if (!(Namech = (char *)malloc(MAXPATHLEN + 1))) { + (void) fprintf(stderr, "%s: no space for name buffer\n", Pn); + Exit(1); + } + Namechl = (size_t)(MAXPATHLEN + 1); +/* + * Create option mask. + */ + (void) snpf(options, sizeof(options), + "?a%sbc:%sD:d:%s%sf:F:g:hi:%s%slL:%s%snNo:Op:Pr:%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(argc, argv, options, &rv)) != EOF) { + if (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': + Fblock = 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 (enter_cmd_rx(GOv)) + err = 1; + } else { + if (enter_str_lst("-c", GOv, &Cmdl, &Cmdni, &Cmdnx)) + err = 1; + +#if defined(MAXSYSCMDL) + else if (Cmdl->len > MAXSYSCMDL) { + (void) fprintf(stderr, "%s: \"-c ", Pn); + (void) safestrprt(Cmdl->str, stderr, 2); + (void) fprintf(stderr, "\" length (%d) > what system", + Cmdl->len); + (void) fprintf(stderr, " provides (%d)\n", + MAXSYSCMDL); + Cmdl->len = 0; /* (to avoid later error report) */ + err = 1; + } +#endif /* defined(MAXSYSCMDL) */ + + } + break; + +#if defined(HASNCACHE) + case 'C': + Fncache = (GOp == '-') ? 0 : 1; + break; + +#endif /* defined(HASNCACHE) */ + case 'd': + if (GOp == '+') { + if (enter_dir(GOv, 0)) + err = 1; + else { + Selflags |= SELNM; + xover = 1; + } + } else { + if (enter_fd(GOv)) + err = 1; + } + break; + case 'D': + if (GOp == '+') { + if (enter_dir(GOv, 1)) + err = 1; + else { + Selflags |= SELNM; + xover = 1; + } + } else { + +#if defined(HASDCACHE) + if (ctrl_dcache(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(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'; + 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(PGID, GOv)) + err = 1; + } + Fpgid = 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(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': + Fovhd = (GOp == '-') ? 1 : 0; + break; + case 'p': + if (enter_id(PID, GOv)) + err = 1; + break; + case 'P': + Fport = (GOp == '-') ? 0 : 1; + break; + case 'r': + if (GOp == '+') + ev = 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 != 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: 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 result: \"%s\"\n", + Pn, (int)fmtl, cp); + Exit(1); + } + if (util_strftime(fmtr, fmtl - 1, fmt) < 1) { + (void) fprintf(stderr, "%s: illegal : \"%s\"\n", + Pn, fmt); + err = 1; + } + } + +#else /* !defined(HAS_STRFTIME) */ + (void) fprintf(stderr, "%s: m 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(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(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(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(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 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())) { + 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(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); + Exit(1); + } + 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(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)); + } + Exit(1); + } + } + DevDev = sb.st_dev; +/* + * Process the file arguments. + */ + if (GOx1 < argc) { + if (ck_file_arg(GOx1, argc, argv, Ffilesys, 0, (struct stat *)NULL)) + usage(1, 0, 0); + } +/* + * Do dialect-specific initialization. + */ + initialize(); + if (Sfile) + (void) hashSfile(); + +#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(); +#endif /* defined(WILLDROPGID) */ + + +#if defined(HASDCACHE) +/* + * If there is a device cache, prepare the device table. + */ + if (DCstate) + readdev(0); +#endif /* defined(HASDCACHE) */ + +/* + * Define the size and offset print formats. + */ + (void) snpf(options, sizeof(options), "%%%su", INODEPSPEC); + InodeFmt_d = sv_fmt_str(options); + (void) snpf(options, sizeof(options), "%%#%sx", INODEPSPEC); + InodeFmt_x = sv_fmt_str(options); + (void) snpf(options, sizeof(options), "0t%%%su", SZOFFPSPEC); + SzOffFmt_0t = sv_fmt_str(options); + (void) snpf(options, sizeof(options), "%%%su", SZOFFPSPEC); + SzOffFmt_d = sv_fmt_str(options); + (void) snpf(options, sizeof(options), "%%*%su", SZOFFPSPEC); + SzOffFmt_dv = sv_fmt_str(options); + (void) snpf(options, sizeof(options), "%%#%sx", SZOFFPSPEC); + SzOffFmt_x = sv_fmt_str(options); + +#if defined(HASMNTSUP) +/* + * Report mount supplement information, as requested. + */ + if (MntSup == 1) { + (void) readmnt(); + Exit(0); + } +#endif /* defined(HASMNTSUP) */ + +/* + * Gather and report process information every RptTm seconds. + */ + if (RptTm) + CkPasswd = 1; + do { + + /* + * Gather information about processes. + */ + gather_proc_info(); + /* + * 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); + Exit(1); + } + } + 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(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(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(0); +# endif /* defined(HASPTYEPT) */ + + } + /* + * 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(1); + +# if defined(HASUXSOCKEPT) + /* + * Process UNIX socket endpoints. + */ + if (Lp->ept & EPT_UXS_END) + (void) process_uxsinfo(1); +# endif /* defined(HASUXSOCKEPT) */ + +# if defined(HASPTYEPT) + /* + * Process pseudo-terminal endpoints. + */ + if (Lp->ept & EPT_PTY_END) + (void) process_ptyinfo(1); +# endif /* defined(HASPTYEPT) */ + + } + 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(); PrPass < 2; PrPass++) { + for (i = n = 0; i < Nlproc; i++) { + Lp = (Nlproc > 1) ? slp[i] : &Lproc[i]; + if (Lp->pss) { + if (print_proc()) + 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(); + +# if defined(HASUXSOCKEPT) + (void) clear_uxsinfo(); +# endif /* defined(HASUXSOCKEPT) */ + +# if defined(HASPTYEPT) + (void) clear_ptyinfo(); +# endif /* defined(HASPTYEPT) */ +#endif /* defined(HASEPTOPTS) */ + + if (rc) { + if (!n) + break; + else + ev = 0; + } + +#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(); + (void) sleep(RptTm); + Hdr = Nlproc = 0; + CkPasswd = 1; + } + } 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(); + rv = 0; + for (str = Cmdl; str; str = str->next) { + + /* + * Check command specifications. + */ + if (str->f) + continue; + rv = 1; + 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 = 1; + 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 = 1; + 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 = 1; + 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 = 1; + 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 = 1; + 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 = 1; + 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 = 1; + 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 = 1; + 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 = 1; + 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 = 1; + 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 = 1; + 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 = 1; + 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 = 1; + 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 = 1; + 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 = 1; + 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 = 1; + Exit(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(ct, opt, rules, err) + 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(f) + 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); + Exit(1); + } + (void) snpf(cp, l, "%s", f); + return(cp); +} diff --git a/misc.c b/misc.c new file mode 100644 index 0000000..1b2c2ef --- /dev/null +++ b/misc.c @@ -0,0 +1,1689 @@ +/* + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: misc.c,v 1.29 2018/02/14 14:20:14 abe Exp $"; +#endif + + +#include "lsof.h" + +#if defined(HASWIDECHAR) +# if defined(WIDECHARINCL) +#include WIDECHARINCL +# endif /* defined(WIDECHARINCL) */ +# if defined(HASWCTYPE_H) +#include +# endif /* defined(HASWCTYPE_H) */ +#endif /* defined(HASWIDECHAR) */ + + +/* + * Local definitions + */ + +#if !defined(MAXSYMLINKS) +#define MAXSYMLINKS 32 +#endif /* !defined(MAXSYMLINKS) */ + + +/* + * Local function prototypes + */ + +_PROTOTYPE(static void closePipes,(void)); +_PROTOTYPE(static int dolstat,(char *path, char *buf, int len)); +_PROTOTYPE(static int dostat,(char *path, char *buf, int len)); +_PROTOTYPE(static int doreadlink,(char *path, char *buf, int len)); +_PROTOTYPE(static int doinchild,(int (*fn)(), char *fp, char *rbuf, int rbln)); + +#if defined(HASINTSIGNAL) +_PROTOTYPE(static int handleint,(int sig)); +#else /* !defined(HASINTSIGNAL) */ +_PROTOTYPE(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(d) + 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); + Exit(1); + } + 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))); + Exit(1); + } + 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() +{ + 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(a1, a2) + COMP_P *a1, *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)); +} + + +/* + * doinchild() -- do a function in a child process + */ + +static int +doinchild(fn, fp, rbuf, rbln) + 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); + Exit(1); + } +/* + * 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(); + 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)); + Exit(1); + } + /* + * Fork a child to execute functions. + */ + if ((Cpid = fork()) == 0) { + + /* + * Begin the child process. + */ + + int r_al, r_rbln; + char r_arg[MAXPATHLEN+1], r_rbuf[MAXPATHLEN+1]; + int (*r_fn)(); + /* + * Close sufficient open file descriptors except Pipes[0] and + * Pipes[3]. + */ + +#if defined(HAS_DUP2) && defined(HAS_CLOSEFROM) + 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)); + Exit(1); + } + 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)); + Exit(1); + } + Pipes[3] = 1; + (void) closefrom(2); + Pipes[1] = -1; + Pipes[2] = -1; + +#else /* !defined(HAS_DUP2) && !defined(HAS_CLOSEFROM) */ + 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) && defined(HAS_CLOSEFROM) */ + + /* + * 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_rbuf)) + break; + rv = r_fn(r_arg, 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_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)); + Exit(1); + } + (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(); + 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(path, rbuf, rbln) + 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(path, rbuf, rbln) + 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(path, rbuf, rbln) + 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() +{ + if (!Setuidroot && Setgid) { + if (setgid(Mygid) < 0) { + (void) fprintf(stderr, "%s: can't setgid(%d): %s\n", + Pn, (int)Mygid, strerror(errno)); + Exit(1); + } + Setgid = 0; + } +} +#endif /* defined(WILLDROPGID) */ + + +/* + * enter_dev_ch() - enter device characters in file structure + */ + +void +enter_dev_ch(m) + 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); + Exit(1); + } + 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(ty, nm, nr) + 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); + Exit(1); + } + 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); + Exit(1); + } +/* + * 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); + Exit(1); + } + } + 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); + Exit(1); + } + } + TcpStAlloc = TcpNstates; + } + } + return; + } +/* + * Check the name and number. + */ + if ((len = (size_t)strlen(nm)) < 1) { + (void) fprintf(stderr, + "%s: bad %s name (\"%s\"), number=%d\n", Pn, ty, nm, nr); + Exit(1); + } +/* + * 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); + Exit(1); + } +/* + * 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); + Exit(1); + } + 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); + Exit(1); + } + 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(m) + 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); + Exit(1); + } + if (Lf->nm) + (void) free((FREE_P *)Lf->nm); + Lf->nm = mp; +} + + +/* + * Exit() - do a clean exit() + */ + +void +Exit(xv) + int xv; /* exit() value */ +{ + (void) childx(); + +#if defined(HASDCACHE) + if (DCrebuilt && !Fwarn) + (void) fprintf(stderr, "%s: WARNING: %s was updated.\n", + Pn, DCpath[DCpathX]); +#endif /* defined(HASDCACHE) */ + + exit(xv); +} + + +#if defined(HASNLIST) +/* + * get_Nl_value() - get Nl value for nickname + */ + +int +get_Nl_value(nn, d, v) + 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(sig) + int sig; +{ + longjmp(Jmp_buf, 1); +} + + +/* + * hashbyname() - hash by name + */ + +int +hashbyname(nm, mod) + 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(ia, p, af) + 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(src, rlp) + 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(s1, l1, s2, l2, s3, l3, clp) + 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(path, msg) + 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(path, buf) + 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(dolstat, path, (char *)buf, sizeof(struct stat))); +} + + +/* + * Readlink() - read and interpret file system symbolic links + */ + +char * +Readlink(arg) + 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(arg); + } +/* + * 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(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(arg); + } +/* + * 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); + Exit(1); + } + 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(s1)); +} + + +#if defined(HASSTREAMS) +/* + * readstdata() - read stream's stdata structure + */ + +int +readstdata(addr, buf) + KA_T addr; /* stdata address in kernel*/ + struct stdata *buf; /* buffer addess */ +{ + if (!addr + || kread(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(addr, buf) + 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(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(addr, buf, len) + KA_T addr; /* module ID name address in kernel */ + char *buf; /* receiving buffer address */ + READLEN_T len; /* buffer length */ +{ + if (!addr || kread(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(addr, buf) + KA_T addr; /* module info address in kernel */ + struct module_info *buf; /* receiving buffer address */ +{ + if (!addr || kread(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(addr, buf) + KA_T addr; /* queue info address in kernel */ + struct qinit *buf; /* receiving buffer address */ +{ + if (!addr || kread(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(c, cl) + 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(sp, flags) + 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(sp, fs, flags) + 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(sp, len, fs, flags) + 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(path, buf) + 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(dostat, path, (char *)buf, sizeof(struct stat))); +} + + +/* + * stkdir() - stack directory name + */ + +void +stkdir(p) + 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); + Exit(1); + } + } +/* + * 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); + Exit(1); + } + Dstkx++; +} + + +/* + * x2dev() - convert hexadecimal ASCII string to device number + */ + +char * +x2dev(s, d) + 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/node.c b/node.c new file mode 100644 index 0000000..2ba020c --- /dev/null +++ b/node.c @@ -0,0 +1,258 @@ +/* + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: node.c,v 1.5 2000/08/01 17:08:05 abe Exp $"; +#endif + + +#include "lsof.h" + + +/* + * print_kptr() - print kernel pointer + */ + +char * +print_kptr(kp, buf, bufl) + 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(ca, c) + KA_T ca; /* cdrnode kernel address */ + struct cdrnode *c; /* cdrnode buffer */ +{ + if (kread((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(fa, f) + KA_T fa; /* fifonode kernel address */ + struct fifonode *f; /* fifonode buffer */ +{ + if (kread((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(ga, g) + KA_T ga; /* gnode kernel address */ + struct gnode *g; /* gnode buffer */ +{ + if (kread((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(ha, h) + KA_T ha; /* hsnode kernel address */ + struct hsnode *h; /* hsnode buffer */ +{ + if (kread((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(ia, i) + KA_T ia; /* inode kernel address */ + struct inode *i; /* inode buffer */ +{ + if (kread((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(pa, p) + KA_T pa; /* pipe node kernel address */ + struct pipenode *p; /* pipe node buffer */ +{ + if (kread((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(ra, r) + KA_T ra; /* rnode kernel space address */ + struct rnode *r; /* rnode buffer pointer */ +{ + if (kread((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(sa, s) + KA_T sa; /* snode kernel space address */ + struct snode *s; /* snode buffer pointer */ +{ + if (kread((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(ta, t) + KA_T ta; /* tmpnode kernel space address */ + struct tmpnode *t; /* tmpnode buffer pointer */ +{ + if (kread((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(va, v) + KA_T va; /* vnode kernel space address */ + struct vnode *v; /* vnode buffer pointer */ +{ + if (kread((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/print.c b/print.c new file mode 100644 index 0000000..f661766 --- /dev/null +++ b/print.c @@ -0,0 +1,2847 @@ +/* + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: print.c,v 1.56 2018/02/14 14:20:14 abe Exp $"; +#endif + + +#include "lsof.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) +_PROTOTYPE(static void fill_portmap,(void)); +_PROTOTYPE(static void update_portmap,(struct porttab *pt, char *pn)); +#endif /* !defined(HASNORPC_H) */ + +_PROTOTYPE(static void fill_porttab,(void)); +_PROTOTYPE(static char *lkup_port,(int p, int pr, int src)); +_PROTOTYPE(static char *lkup_svcnam,(int h, int p, int pr, int ss)); +_PROTOTYPE(static int printinaddr,(void)); + + +/* + * endnm() - locate end of Namech + */ + +char * +endnm(sz) + 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); +} + + +#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() +{ + 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) */ + +/* + * 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); + Exit(1); + } + 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); + Exit(1); + } + 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() +{ + 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); + Exit(1); + } + 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); + Exit(1); + } + 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(ia, af) + 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); + Exit(1); + } +/* + * 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); + Exit(1); + } + } + 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(p, pr, src) + 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]; + static int pm = 0; + 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"); + Exit(1); + } + } + } + +#if !defined(HASNORPC_H) +/* + * If we're looking up program names for portmapped ports, make sure the + * portmap table has been loaded. + */ + if (FportMap && !pm) { + (void) fill_portmap(); + pm++; + } +#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(h, p, pr, 0) : (char *)NULL; + if (!pn) { + (void) snpf(pb, sizeof(pb), "%d", p); + pn = pb; + } + (void) update_portmap(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(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); + Exit(1); + } +/* + * 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); + Exit(1); + } + 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(h, p, pr, ss) + 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(); + ptf++; + ss = 0; + } + return((char *)NULL); +} + + +/* + * print_file() - print file + */ + +void +print_file() +{ + char buf[128]; + char *cp = (char *)NULL; + dev_t dev; + int devs, len; + + 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. + */ + cp = (Lp->cmd && *Lp->cmd != '\0') ? 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((UID_ARG)Lp->uid, NULL))) > UserColW) + UserColW = len; + } else + (void) printf(" %*.*s", UserColW, UserColW, + printuid((UID_ARG)Lp->uid, NULL)); +/* + * Size or print the file descriptor, access mode and lock status. + */ + if (!PrPass) { + (void) snpf(buf, sizeof(buf), "%s%c%c", + Lf->fd, + (Lf->lock == ' ') ? Lf->access + : (Lf->access == ' ') ? '-' + : Lf->access, + Lf->lock); + if ((len = strlen(buf)) > FdColW) + FdColW = len; + } else + (void) printf(" %*.*s%c%c", FdColW - 2, FdColW - 2, Lf->fd, + (Lf->lock == ' ') ? Lf->access + : (Lf->access == ' ') ? '-' + : Lf->access, + Lf->lock); +/* + * Size or print the type. + */ + if (!PrPass) { + if ((len = strlen(Lf->type)) > TypeColW) + TypeColW = len; + } else + (void) printf(" %*.*s", TypeColW, TypeColW, Lf->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(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 (Lf->sz_def) { + +#if defined(HASPRINTSZ) + cp = HASPRINTSZ(Lf); +#else /* !defined(HASPRINTSZ) */ + (void) snpf(buf, sizeof(buf), SzOffFmt_d, Lf->sz); + cp = buf; +#endif /* defined(HASPRINTSZ) */ + + len = strlen(cp); + } else if (Lf->off_def) { + +#if defined(HASPRINTOFF) + cp = HASPRINTOFF(Lf, 0); +#else /* !defined(HASPRINTOFF) */ + (void) snpf(buf, sizeof(buf), SzOffFmt_0t, Lf->off); + cp = buf; +#endif /* defined(HASPRINTOFF) */ + + len = strlen(cp); + if (OffDecDig && len > (OffDecDig + 2)) { + +#if defined(HASPRINTOFF) + cp = HASPRINTOFF(Lf, 1); +#else /* !defined(HASPRINTOFF) */ + (void) snpf(buf, sizeof(buf), SzOffFmt_x, Lf->off); + cp = buf; +#endif /* defined(HASPRINTOFF) */ + + len = strlen(cp); + } + } else + len = 0; + if (len > SzOffColW) + SzOffColW = len; + } else { + putchar(' '); + if (Lf->sz_def) + +#if defined(HASPRINTSZ) + (void) printf("%*.*s", SzOffColW, SzOffColW, HASPRINTSZ(Lf)); +#else /* !defined(HASPRINTSZ) */ + (void) printf(SzOffFmt_dv, SzOffColW, Lf->sz); +#endif /* defined(HASPRINTSZ) */ + + else if (Lf->off_def) { + +#if defined(HASPRINTOFF) + cp = HASPRINTOFF(Lf, 0); +#else /* !defined(HASPRINTOFF) */ + (void) snpf(buf, sizeof(buf), SzOffFmt_0t, Lf->off); + cp = buf; +#endif /* defined(HASPRINTOFF) */ + + if (OffDecDig && (int)strlen(cp) > (OffDecDig + 2)) { + +#if defined(HASPRINTOFF) + cp = HASPRINTOFF(Lf, 1); +#else /* !defined(HASPRINTOFF) */ + (void) snpf(buf, sizeof(buf), SzOffFmt_x, Lf->off); + cp = buf; +#endif /* defined(HASPRINTOFF) */ + + } + (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(Lf); +#else /* !defined(HASPRINTNM) */ + printname(1); +#endif /* defined(HASPRINTNM) */ + + } +} + + +/* + * printinaddr() - print Internet addresses + */ + +static int +printinaddr() +{ + 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((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((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; + } + } +#endif /* !defined(HASNORPC_H) */ + + if (strcasecmp(Lf->iproto, "TCP") == 0) + port = lkup_port(Lf->li[i].p, 0, src); + else if (strcasecmp(Lf->iproto, "UDP") == 0) + port = lkup_port(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() +{ + +/* + * 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) */ + +} + + +#if !defined(HASPRIVPRIPP) +/* + * printiproto() - print Internet protocol name + */ + +void +printiproto(p) + 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) */ + + +/* + * printname() - print output name field + */ + +void +printname(nl) + 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()) + ps++; + goto print_nma; + } + if (((Lf->ntype == N_BLK) || (Lf->ntype == N_CHR)) + && Lf->dev_def && Lf->rdev_def + && printdevname(&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(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(); 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(); + +# if defined(NCACHELDSFX) + NCACHELDSFX +# endif /* defined(NCACHELDSFX) */ + + NcacheReload = 0; + } + if ((cp = ncache_lookup(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(0); + } + if (nl) + putchar('\n'); +} + + +/* + * printrawaddr() - print raw socket address + */ + +void +printrawaddr(sa) + struct sockaddr *sa; /* socket address */ +{ + char *ep; + size_t sz; + + ep = endnm(&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(ty) + 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(uid, ty) + 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)); + Exit(1); + } + } + /* + * 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 *)))); + Exit(1); + } + 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); + Exit(1); + } + (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); +} + + +/* + * printunkaf() - print unknown address family + */ + +void +printunkaf(fam, ty) + 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; +} + + +#if !defined(HASNORPC_H) +/* + * update_portmap() - update a portmap entry with its port number or service + * name + */ + +static void +update_portmap(pt, pn) + 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); + Exit(1); + } + (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) */ diff --git a/proc.c b/proc.c new file mode 100644 index 0000000..34cb4b8 --- /dev/null +++ b/proc.c @@ -0,0 +1,1528 @@ +/* + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: proc.c,v 1.50 2018/02/14 14:20:14 abe Exp $"; +#endif + + +#include "lsof.h" + +#if defined(HASPTYEPT) +_PROTOTYPE(static void prt_ptyinfo,(pxinfo_t *pp, int prt_edev, int ps)); +#endif /* defined(HASPTYEPT) */ + + +/* + * add_nma() - add to NAME column addition + */ + +void +add_nma(cp, len) + char *cp; /* string to add */ + int len; /* string length */ +{ + int nl; + + 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) { + (void) fprintf(stderr, "%s: no name addition space: PID %ld, FD %s", + Pn, (long)Lp->pid, Lf->fd); + Exit(1); + } + 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'; + } +} + + +#if defined(HASFSTRUCT) +_PROTOTYPE(static char *alloc_fflbuf,(char **bp, int *al, int lr)); + + +/* + * alloc_fflbuf() - allocate file flags print buffer + */ + +static char * +alloc_fflbuf(bp, al, lr) + 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); + Exit(1); + } + *al = sz; + return(*bp); +} +#endif /* defined(HASFSTRUCT) */ + + +/* + * alloc_lfile() - allocate local file structure space + */ + +void +alloc_lfile(nm, num) + char *nm; /* file descriptor name (may be NULL) */ + 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); + Exit(1); + } +/* + * Initialize the structure. + */ + Lf->access = Lf->lock = ' '; + 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; +#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] = Lf->type[0] = '\0'; + if (nm) { + (void) strncpy(Lf->fd, nm, FDLEN - 1); + Lf->fd[FDLEN - 1] = '\0'; + } else if (num >= 0) { + if (num < 10000) + (void) snpf(Lf->fd, sizeof(Lf->fd), "%4d", num); + else + (void) snpf(Lf->fd, sizeof(Lf->fd), "*%03d", num % 1000); + } else + Lf->fd[0] = '\0'; + 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 || (!nm && num < 0)) + return; + fds = ck_fd_status(nm, 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(pid, pgid, ppid, uid, cmd, pss, sf) + 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); + Exit(1); + } + 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); + Exit(1); + } + } + 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); + Exit(1); + } + +#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(nm, num) + char *nm; /* file descriptor name (may be NULL) */ + int num; /* file descriptor number -- -1 if + * none */ +{ + char *cp; + struct fd_lst *fp; + + if (!(fp = Fdl) || (!nm && num < 0)) + return(0); + if ((cp = nm)) { + while (*cp && *cp == ' ') + cp++; + } +/* + * Check for an exclusion match. + */ + if (FdlTy == 1) { + for (; fp; fp = fp->next) { + if (cp) { + if (fp->nm && strcmp(fp->nm, cp) == 0) + return(1); + continue; + } + if (num >= fp->lo && num <= fp->hi) + return(1); + } + return(0); + } +/* + * If Fdl isn't an exclusion list, check for an inclusion match. + */ + for (; fp; fp = fp->next) { + if (cp) { + if (fp->nm && strcmp(fp->nm, cp) == 0) + return(2); + continue; + } + if (num >= fp->lo && num <= fp->hi) + return(2); + } + return(0); +} + + +/* + * comppid() - compare PIDs + */ + +int +comppid(a1, a2) + COMP_P *a1, *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(la, lp, fa, fp, af) + 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(fa, fp, af)) ? 1 : 0; + m |= (la && is_nw_addr(la, lp, af)) ? 1 : 0; + if (m) + Lf->sf |= SELNA; + } +} + + +/* + * examine_lproc() - examine local process + * + * return: 1 = last process + */ + +int +examine_lproc() +{ + 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--; + } + } + if (Lp->pss && Npid == 1 && sbp) { + print_init(); + (void) print_proc(); + PrPass++; + if (PrPass < 2) + (void) print_proc(); + Lp->pss = 0; + } +/* + * 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(lp) + 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(cmd, pss, sf) + 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^" 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 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 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(lp, lf) + 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 + +#if defined(HASTASKS) +is_proc_excl(pid, pgid, uid, pss, sf, tid) +#else /* !defined(HASTASKS) */ +is_proc_excl(pid, pgid, uid, pss, sf) +#endif /* defined(HASTASKS) */ + + int pid; /* Process ID */ + int pgid; /* process group ID */ + UID_ARG uid; /* User ID */ + short *pss; /* process select state for lproc */ + short *sf; /* select flags for lproc */ + +#if defined(HASTASKS) + int tid; /* task ID (not a task if zero) */ +#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() +{ + 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; + } + +# 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 SELPINFO + * 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) */ + + } +#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(f) + int f; /* function: + * 0 == process selected pipe + * 1 == process end point + */ +{ + struct lproc *ep; /* pipe endpoint process */ + struct lfile *ef; /* pipe endpoint file */ + int i; /* temporary index */ + char nma[1024]; /* name addition buffer */ + 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(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(Lf, pp))) { + + /* + * This pipe endpoint is linked to the selected pipe + * file. Add its PID and FD to the name column + * addition. + */ + ep = &Lproc[pp->lpx]; + ef = pp->lf; + for (i = 0; i < (FDLEN - 1); i++) { + if (ef->fd[i] != ' ') + break; + } + (void) snpf(nma, sizeof(nma) - 1, "%d,%.*s,%s%c", + ep->pid, CmdLim, ep->cmd,&ef->fd[i], + ef->access); + (void) add_nma(nma, strlen(nma)); + if (FeptE == 2) { + + /* + * 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; + } + pp = pp->next; + } + } while (pp); + } + break; + case 1: + if (!is_file_sel(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(Lf, pp))) { + ep = &Lproc[pp->lpx]; + ef = pp->lf; + for (i = 0; i < (FDLEN - 1); i++) { + if (ef->fd[i] != ' ') + break; + } + (void) snpf(nma, sizeof(nma) - 1, "%d,%.*s,%s%c", + ep->pid, CmdLim, ep->cmd, &ef->fd[i], + ef->access); + (void) add_nma(nma, strlen(nma)); + pp = pp->next; + } + } while (pp); + } + break; + } + } +} +#endif /* defined(HASEPTOPTS) */ + + +#if defined(HASFSTRUCT) +/* + * print_fflags() - print interpreted f_flag[s] + */ + +char * +print_fflags(ffg, pof) + 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(&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(&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(&bp, &bl, 0); + *bp = '\0'; + } + return(bp); +} +#endif /* defined(HASFSTRUCT) */ + + +/* + * print_proc() - print process + */ + +int +print_proc() +{ + char buf[128], *cp; + int lc, len, st, ty; + int rv = 0; + unsigned long ul; +/* + * 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(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(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((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(Lp, Lf)) + continue; + rv = 1; + /* + * If no field output selected, print dialect-specific formatted + * output. + */ + if (!Ffield) { + print_file(); + continue; + } + lc = st = 0; + if (FieldSel[LSOF_FIX_FD].st) { + + /* + * Skip leading spaces in the file descriptor. Print the field + * identifier even if there are no characters after leading + * spaces. + */ + for (cp = Lf->fd; *cp == ' '; cp++) + ; + (void) printf("%c%s%c", LSOF_FID_FD, cp, Terminator); + lc++; + } + /* + * Print selected fields. + */ + if (FieldSel[LSOF_FIX_ACCESS].st) { + (void) printf("%c%c%c", + LSOF_FID_ACCESS, Lf->access, Terminator); + lc++; + } + if (FieldSel[LSOF_FIX_LOCK].st) { + (void) printf("%c%c%c", LSOF_FID_LOCK, Lf->lock, Terminator); + lc++; + } + if (FieldSel[LSOF_FIX_TYPE].st) { + for (cp = Lf->type; *cp == ' '; cp++) + ; + if (*cp) { + (void) printf("%c%s%c", LSOF_FID_TYPE, cp, 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(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); + +#if defined(HASPRINTSZ) + cp = HASPRINTSZ(Lf); +#else /* !defined(HASPRINTSZ) */ + (void) snpf(buf, sizeof(buf), SzOffFmt_d, Lf->sz); + cp = buf; +#endif /* defined(HASPRINTSZ) */ + + (void) printf("%s", cp); + putchar(Terminator); + lc++; + } + if (FieldSel[LSOF_FIX_OFFSET].st && Lf->off_def) { + putchar(LSOF_FID_OFFSET); + +#if defined(HASPRINTOFF) + cp = HASPRINTOFF(Lf, 0); +#else /* !defined(HASPRINTOFF) */ + (void) snpf(buf, sizeof(buf), SzOffFmt_0t, Lf->off); + cp = buf; +#endif /* defined(HASPRINTOFF) */ + + len = strlen(cp); + if (OffDecDig && len > (OffDecDig + 2)) { + +#if defined(HASPRINTOFF) + cp = HASPRINTOFF(Lf, 1); +#else /* !defined(HASPRINTOFF) */ + (void) snpf(buf, sizeof(buf), SzOffFmt_x, Lf->off); + cp = buf; +#endif /* defined(HASPRINTOFF) */ + + } + (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(0); + putchar(Terminator); + lc++; + st++; + } + } + if (st == 0 && FieldSel[LSOF_FIX_NAME].st) { + putchar(LSOF_FID_NAME); + printname(0); + putchar(Terminator); + lc++; + } + if (Lf->lts.type >= 0 && FieldSel[LSOF_FIX_TCPTPI].st) { + print_tcptpi(0); + lc++; + } + if (Terminator == '\0' && lc) + putchar('\n'); + } + return(rv); +} + + +#if defined(HASPTYEPT) +/* + * process_ptyinfo() -- process pseudoterminal info, adding it to selected files and + * selecting pseudoterminal end files (if requested) + */ + +void +process_ptyinfo(f) + 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(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(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(pp, (mos && pc), (FeptE == 2)); + pp = pp->next; + pc = 0; + } + } while (pp); + } + break; + case 1: + if (!is_file_sel(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(Lf, !mos, pp))) { + prt_ptyinfo(pp, (mos && pc), 0); + pp = pp->next; + pc = 0; + } + } while (pp); + } + break; + } + } +} + + +/* + * prt_ptyinfo() -- print pseudoterminal information + */ + +static void +prt_ptyinfo(pp, prt_edev, ps) + 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 */ + + ep = &Lproc[pp->lpx]; + ef = pp->lf; + for (i = 0; i < (FDLEN - 1); i++) { + if (ef->fd[i] != ' ') + break; + } + if (prt_edev) { + (void) snpf(nma, sizeof(nma) - 1, "->/dev/pts/%d %d,%.*s,%s%c", + Lf->tty_index, + ep->pid, CmdLim, ep->cmd, &ef->fd[i], + ef->access); + } else { + (void) snpf(nma, sizeof(nma) - 1, "%d,%.*s,%s%c", + ep->pid, CmdLim, ep->cmd, &ef->fd[i], + ef->access); + } + (void) add_nma(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) */ diff --git a/proto.h b/proto.h new file mode 100644 index 0000000..75c74a1 --- /dev/null +++ b/proto.h @@ -0,0 +1,317 @@ +/* + * 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 _PROTOTYPE macro provides strict ANSI C prototypes if __STDC__ + * is defined, and old-style K&R prototypes otherwise. + * + * (With thanks to Andy Tanenbaum) + */ + +# if defined(__STDC__) +#define _PROTOTYPE(function, params) function params +# else /* !defined(__STDC__) */ +#define _PROTOTYPE(function, params) function() +# endif /* defined(__STDC__) */ + + +/* + * 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 */ + + +_PROTOTYPE(extern void add_nma,(char *cp, int len)); +_PROTOTYPE(extern void alloc_lfile,(char *nm, int num)); +_PROTOTYPE(extern void alloc_lproc,(int pid, int pgid, int ppid, UID_ARG uid, char *cmd, int pss, int sf)); +_PROTOTYPE(extern void build_IPstates,(void)); +_PROTOTYPE(extern void childx,(void)); +_PROTOTYPE(extern int ck_fd_status,(char *nm, int num)); +_PROTOTYPE(extern int ck_file_arg,(int i, int ac, char *av[], int fv, int rs, struct stat *sbp)); +_PROTOTYPE(extern void ckkv,(char *d, char *er, char *ev, char *ea)); +_PROTOTYPE(extern void clr_devtab,(void)); +_PROTOTYPE(extern int compdev,(COMP_P *a1, COMP_P *a2)); +_PROTOTYPE(extern int comppid,(COMP_P *a1, COMP_P *a2)); + +# if defined(WILLDROPGID) +_PROTOTYPE(extern void dropgid,(void)); +# endif /* defined(WILLDROPGID) */ + +_PROTOTYPE(extern char *endnm,(size_t *sz)); +_PROTOTYPE(extern int enter_cmd_rx,(char *x)); +_PROTOTYPE(extern void enter_dev_ch,(char *m)); +_PROTOTYPE(extern int enter_dir,(char *d, int descend)); + +# if defined(HASEOPT) +_PROTOTYPE(extern int enter_efsys,(char *e, int rdlnk)); +# endif /* defined(HASEOPT) */ + +_PROTOTYPE(extern int enter_fd,(char *f)); +_PROTOTYPE(extern int enter_network_address,(char *na)); +_PROTOTYPE(extern int enter_id,(enum IDType ty, char *p)); +_PROTOTYPE(extern void enter_IPstate,(char *ty, char *nm, int nr)); +_PROTOTYPE(extern void enter_nm,(char *m)); + +# if defined(HASTCPUDPSTATE) +_PROTOTYPE(extern int enter_state_spec,(char *ss)); +# endif /* defined(HASTCPUDPSTATE) */ + +_PROTOTYPE(extern int enter_str_lst,(char *opt, char *s, struct str_lst **lp, + int *incl, int *excl)); +_PROTOTYPE(extern int enter_uid,(char *us)); +_PROTOTYPE(extern void ent_inaddr,(unsigned char *la, int lp, unsigned char *fa, int fp, int af)); +_PROTOTYPE(extern int examine_lproc,(void)); +_PROTOTYPE(extern void Exit,(int xv)) exiting; +_PROTOTYPE(extern void find_ch_ino,(void)); + +# if defined(HASEPTOPTS) +_PROTOTYPE(extern void clear_pinfo,(void)); +_PROTOTYPE(extern pxinfo_t *find_pepti,(struct lfile *lf, pxinfo_t *pp)); +_PROTOTYPE(extern void process_pinfo,(int f)); +# if defined(HASUXSOCKEPT) +_PROTOTYPE(extern void clear_uxsinfo,(void)); +_PROTOTYPE(extern struct uxsin *find_uxsepti,(struct lfile *lf)); +_PROTOTYPE(extern void process_uxsinfo,(int f)); +# endif /* defined(HASUXSOCKEPT) */ +# if defined(HASPTYEPT) +_PROTOTYPE(extern void clear_ptyinfo,(void)); +_PROTOTYPE(extern void enter_ptmxi,(int mn)); +_PROTOTYPE(extern pxinfo_t *find_ptyepti,(struct lfile *lf,int m,pxinfo_t *pp)); +_PROTOTYPE(extern int is_pty_slave,(int sm)); +_PROTOTYPE(extern int is_pty_ptmx,(dev_t dev)); +_PROTOTYPE(extern void process_ptyinfo,(int f)); +# endif /* defined(HASPTYEPT) */ +# endif /* defined(HASEPTOPTS) */ + +_PROTOTYPE(extern void free_lproc,(struct lproc *lp)); +_PROTOTYPE(extern void gather_proc_info,(void)); +_PROTOTYPE(extern char *gethostnm,(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) */ + +_PROTOTYPE(extern int hashbyname,(char *nm, int mod)); +_PROTOTYPE(extern void hashSfile,(void)); +_PROTOTYPE(extern void initialize,(void)); +_PROTOTYPE(extern int is_cmd_excl,(char *cmd, short *pss, short *sf)); +_PROTOTYPE(extern int is_file_sel,(struct lproc *lp, struct lfile *lf)); +_PROTOTYPE(extern int is_nw_addr,(unsigned char *ia, int p, int af)); + +#if defined(HASTASKS) +_PROTOTYPE(extern int is_proc_excl,(int pid, int pgid, UID_ARG uid, short *pss, short *sf, int tid)); +#else /* !defined(HASTASKS) */ +_PROTOTYPE(extern int is_proc_excl,(int pid, int pgid, UID_ARG uid, short *pss, short *sf)); +#endif /* defined(HASTASKS) */ + +_PROTOTYPE(extern int is_readable,(char *path, int msg)); +_PROTOTYPE(extern int kread,(KA_T addr, char *buf, READLEN_T len)); +_PROTOTYPE(extern void link_lfile,(void)); +_PROTOTYPE(extern struct l_dev *lkupdev,(dev_t *dev,dev_t *rdev,int i,int r)); +_PROTOTYPE(extern int main,(int argc, char *argv[])); +_PROTOTYPE(extern int lstatsafely,(char *path, struct stat *buf)); +_PROTOTYPE(extern char *mkstrcpy,(char *src, MALLOC_S *rlp)); +_PROTOTYPE(extern char *mkstrcat,(char *s1, int l1, char *s2, int l2, char *s3, int l3, MALLOC_S *clp)); +_PROTOTYPE(extern int printdevname,(dev_t *dev, dev_t *rdev, int f, int nty)); +_PROTOTYPE(extern void print_file,(void)); +_PROTOTYPE(extern void print_init,(void)); +_PROTOTYPE(extern void printname,(int nl)); +_PROTOTYPE(extern char *print_kptr,(KA_T kp, char *buf, size_t bufl)); +_PROTOTYPE(extern int print_proc,(void)); +_PROTOTYPE(extern void printrawaddr,(struct sockaddr *sa)); +_PROTOTYPE(extern void print_tcptpi,(int nl)); +_PROTOTYPE(extern char *printuid,(UID_ARG uid, int *ty)); +_PROTOTYPE(extern void printunkaf,(int fam, int ty)); +_PROTOTYPE(extern char *printsockty,(int ty)); +_PROTOTYPE(extern void process_file,(KA_T fp)); +_PROTOTYPE(extern void process_node,(KA_T f)); +_PROTOTYPE(extern char *Readlink,(char *arg)); +_PROTOTYPE(extern void readdev,(int skip)); +_PROTOTYPE(extern struct mounts *readmnt,(void)); +_PROTOTYPE(extern void rereaddev,(void)); +_PROTOTYPE(extern char *safepup,(unsigned int c, int *cl)); +_PROTOTYPE(extern int safestrlen,(char *sp, int flags)); +_PROTOTYPE(extern void safestrprtn,(char *sp, int len, FILE *fs, int flags)); +_PROTOTYPE(extern void safestrprt,(char *sp, FILE *fs, int flags)); +_PROTOTYPE(extern int statsafely,(char *path, struct stat *buf)); +_PROTOTYPE(extern void stkdir,(char *p)); +_PROTOTYPE(extern void usage,(int xv, int fh, int version)); +_PROTOTYPE(extern int util_strftime,(char *fmtr, int fmtl, char *fmt)); +_PROTOTYPE(extern int vfy_dev,(struct l_dev *dp)); +_PROTOTYPE(extern char *x2dev,(char *s, dev_t *d)); + +# if defined(HASBLKDEV) +_PROTOTYPE(extern void find_bl_ino,(void)); +_PROTOTYPE(extern struct l_dev *lkupbdev,(dev_t *dev,dev_t *rdev,int i,int r)); +_PROTOTYPE(extern int printbdevname,(dev_t *dev, dev_t *rdev, int f)); +# endif /* defined(HASBLKDEV) */ + +# if defined(HASCDRNODE) +_PROTOTYPE(extern int readcdrnode,(KA_T ca, struct cdrnode *c)); +# endif /* defined(HASCDRNODE) */ + +# if defined(HASDCACHE) +_PROTOTYPE(extern void alloc_dcache,(void)); +_PROTOTYPE(extern void crc,(char *b, int l, unsigned *s)); +_PROTOTYPE(extern void crdbld,(void)); +_PROTOTYPE(extern int ctrl_dcache,(char *p)); +_PROTOTYPE(extern int dcpath,(int rw, int npw)); +_PROTOTYPE(extern int open_dcache,(int m, int r, struct stat *sb)); +_PROTOTYPE(extern int read_dcache,(void)); +_PROTOTYPE(extern int wr2DCfd,(char *b, unsigned *c)); +_PROTOTYPE(extern void write_dcache,(void)); +# endif /* defined(HASDCACHE) */ + +# if defined(HASFIFONODE) +_PROTOTYPE(extern int readfifonode,(KA_T fa, struct fifonode *f)); +# endif /* defined(HASFIFONODE) */ + +# if defined(HASFSTRUCT) +_PROTOTYPE(extern char *print_fflags,(long ffg, long pof)); +# endif /* defined(HASFSTRUCT) */ + +# if defined(HASGNODE) +_PROTOTYPE(extern int readgnode,(KA_T ga, struct gnode *g)); +# endif /* defined(HASGNODE) */ + +# if defined(HASKQUEUE) +_PROTOTYPE(extern void process_kqueue,(KA_T ka)); +# endif /* defined(HASKQUEUE) */ + +# if defined(HASHSNODE) +_PROTOTYPE(extern int readhsnode,(KA_T ha, struct hsnode *h)); +# endif /* defined(HASHSNODE) */ + +# if defined(HASINODE) +_PROTOTYPE(extern int readinode,(KA_T ia, struct inode *i)); +# endif /* defined(HASINODE) */ + +# if defined(HASNCACHE) +_PROTOTYPE(extern void ncache_load,(void)); +_PROTOTYPE(extern char *ncache_lookup,(char *buf, int blen, int *fp)); +# endif /* defined(HASNCACHE) */ + +# if defined(HASNLIST) +_PROTOTYPE(extern void build_Nl,(struct drive_Nl *d)); +_PROTOTYPE(extern int get_Nl_value,(char *nn, struct drive_Nl *d, KA_T *v)); +# endif /* defined(HASNLIST) */ + +# if defined(HASPIPENODE) +_PROTOTYPE(extern int readpipenode,(KA_T pa, struct pipenode *p)); +# endif /* defined(HASPIPENODE) */ + +# if defined(HASPRINTDEV) +_PROTOTYPE(extern char *HASPRINTDEV,(struct lfile *lf, dev_t *dev)); +# endif /* defined(HASPRINTDEV) */ + +# if defined(HASPRINTINO) +_PROTOTYPE(extern char *HASPRINTINO,(struct lfile *lf)); +# endif /* defined(HASPRINTINO) */ + +# if defined(HASPRINTNM) +_PROTOTYPE(extern void HASPRINTNM,(struct lfile *lf)); +# endif /* defined(HASPRINTNM) */ + +# if defined(HASPRINTOFF) +_PROTOTYPE(extern char *HASPRINTOFF,(struct lfile *lf, int ty)); +# endif /* defined(HASPRINTOFF) */ + +# if defined(HASPRINTSZ) +_PROTOTYPE(extern char *HASPRINTSZ,(struct lfile *lf)); +# endif /* defined(HASPRINTSZ) */ + +# if defined(HASPRIVNMCACHE) +_PROTOTYPE(extern int HASPRIVNMCACHE,(struct lfile *lf)); +# endif /* defined(HASPRIVNMCACHE) */ + +# if !defined(HASPRIVPRIPP) +_PROTOTYPE(extern void printiproto,(int p)); +# endif /* !defined(HASPRIVPRIPP) */ + +# if defined(HASRNODE) +_PROTOTYPE(extern int readrnode,(KA_T ra, struct rnode *r)); +# endif /* defined(HASRNODE) */ + +# if defined(HASSPECDEVD) +_PROTOTYPE(extern void HASSPECDEVD,(char *p, struct stat *s)); +# endif /* defined(HASSPECDEVD) */ + +# if defined(HASSNODE) +_PROTOTYPE(extern int readsnode,(KA_T sa, struct snode *s)); +# endif /* defined(HASSNODE) */ + +# if defined(HASSTREAMS) +_PROTOTYPE(extern int readstdata,(KA_T addr, struct stdata *buf)); +_PROTOTYPE(extern int readsthead,(KA_T addr, struct queue *buf)); +_PROTOTYPE(extern int readstidnm,(KA_T addr, char *buf, READLEN_T len)); +_PROTOTYPE(extern int readstmin,(KA_T addr, struct module_info *buf)); +_PROTOTYPE(extern int readstqinit,(KA_T addr, struct qinit *buf)); +# endif /* defined(HASSTREAMS) */ + +# if defined(HASTMPNODE) +_PROTOTYPE(extern int readtnode,(KA_T ta, struct tmpnode *t)); +# endif /* defined(HASTMPNODE) */ + +# if defined(HASVNODE) +_PROTOTYPE(extern int readvnode,(KA_T va, struct vnode *v)); +# endif /* defined(HASVNODE) */ + +# if defined(USE_LIB_SNPF) +_PROTOTYPE(extern int snpf,(char *str, int len, char *fmt, ...)); +# endif /* defined(USE_LIB_SNPF) */ + +# endif /* !defined(PROTO_H) */ diff --git a/regex.h b/regex.h new file mode 100644 index 0000000..d1b41a8 --- /dev/null +++ b/regex.h @@ -0,0 +1,617 @@ +/* + * regex.h -- regular expression definitions for lsof + * + * This header file is used only when the dialect has no POSIX-conformant + * regular expression function set. When that is the case, the dialect's + * machine.h will define USE_LIB_REGEX. + * + * When the dialect has a POSIX-conformant regular expression function set, + * USE_LIB_REGEX is not defined and this header file #include's . + * + * V. Abell + * Purdue University + */ + + +/* + * Copyright 2000 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. + * + * This software has been adapted from snprintf.c in sendmail 8.9.3. It + * is subject to the sendmail copyright statements listed below, and the + * sendmail licensing terms stated in the sendmail LICENSE file comment + * section of this file. + * + * 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 USE_LIB_REGEX +/* + * This section comes from GLIBC 2.2. It is used only when the dialect + * has no POSIX-conformant regular expression function set. When that is + * the case, the dialect's machine.h will define USE_LIB_REGEX. + */ + +/* Definitions for data structures and routines for the regular + expression library, version 0.12. + Copyright (C) 1985,1989-1993,1995-1998, 2000 Free Software Foundation, Inc. + + This file is part of the GNU C Library. Its master source is NOT part of + the C library, however. The master source lives in /gd/gnu/lib. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef _REGEX_H +#define _REGEX_H 1 + +/* Allow the use in C++ code. */ +#ifdef __cplusplus +extern "C" { +#endif + +/* POSIX says that must be included (by the caller) before + . */ + +#if !defined _POSIX_C_SOURCE && !defined _POSIX_SOURCE && defined VMS +/* VMS doesn't have `size_t' in , even though POSIX says it + should be there. */ +# include +#endif + +/* The following two types have to be signed and unsigned integer type + wide enough to hold a value of a pointer. For most ANSI compilers + ptrdiff_t and size_t should be likely OK. Still size of these two + types is 2 for Microsoft C. Ugh... */ +typedef long int s_reg_t; +typedef unsigned long int active_reg_t; + +/* The following bits are used to determine the regexp syntax we + recognize. The set/not-set meanings are chosen so that Emacs syntax + remains the value 0. The bits are given in alphabetical order, and + the definitions shifted by one from the previous bit; thus, when we + add or remove a bit, only one other definition need change. */ +typedef unsigned long int reg_syntax_t; + +/* If this bit is not set, then \ inside a bracket expression is literal. + If set, then such a \ quotes the following character. */ +#define RE_BACKSLASH_ESCAPE_IN_LISTS ((unsigned long int) 1) + +/* If this bit is not set, then + and ? are operators, and \+ and \? are + literals. + If set, then \+ and \? are operators and + and ? are literals. */ +#define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1) + +/* If this bit is set, then character classes are supported. They are: + [:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:], + [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:]. + If not set, then character classes are not supported. */ +#define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1) + +/* If this bit is set, then ^ and $ are always anchors (outside bracket + expressions, of course). + If this bit is not set, then it depends: + ^ is an anchor if it is at the beginning of a regular + expression or after an open-group or an alternation operator; + $ is an anchor if it is at the end of a regular expression, or + before a close-group or an alternation operator. + + This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because + POSIX draft 11.2 says that * etc. in leading positions is undefined. + We already implemented a previous draft which made those constructs + invalid, though, so we haven't changed the code back. */ +#define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1) + +/* If this bit is set, then special characters are always special + regardless of where they are in the pattern. + If this bit is not set, then special characters are special only in + some contexts; otherwise they are ordinary. Specifically, + * + ? and intervals are only special when not after the beginning, + open-group, or alternation operator. */ +#define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1) + +/* If this bit is set, then *, +, ?, and { cannot be first in an re or + immediately after an alternation or begin-group operator. */ +#define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1) + +/* If this bit is set, then . matches newline. + If not set, then it doesn't. */ +#define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1) + +/* If this bit is set, then . doesn't match NUL. + If not set, then it does. */ +#define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1) + +/* If this bit is set, nonmatching lists [^...] do not match newline. + If not set, they do. */ +#define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1) + +/* If this bit is set, either \{...\} or {...} defines an + interval, depending on RE_NO_BK_BRACES. + If not set, \{, \}, {, and } are literals. */ +#define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1) + +/* If this bit is set, +, ? and | aren't recognized as operators. + If not set, they are. */ +#define RE_LIMITED_OPS (RE_INTERVALS << 1) + +/* If this bit is set, newline is an alternation operator. + If not set, newline is literal. */ +#define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1) + +/* If this bit is set, then `{...}' defines an interval, and \{ and \} + are literals. + If not set, then `\{...\}' defines an interval. */ +#define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1) + +/* If this bit is set, (...) defines a group, and \( and \) are literals. + If not set, \(...\) defines a group, and ( and ) are literals. */ +#define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1) + +/* If this bit is set, then \ matches . + If not set, then \ is a back-reference. */ +#define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1) + +/* If this bit is set, then | is an alternation operator, and \| is literal. + If not set, then \| is an alternation operator, and | is literal. */ +#define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1) + +/* If this bit is set, then an ending range point collating higher + than the starting range point, as in [z-a], is invalid. + If not set, then when ending range point collates higher than the + starting range point, the range is ignored. */ +#define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1) + +/* If this bit is set, then an unmatched ) is ordinary. + If not set, then an unmatched ) is invalid. */ +#define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1) + +/* If this bit is set, succeed as soon as we match the whole pattern, + without further backtracking. */ +#define RE_NO_POSIX_BACKTRACKING (RE_UNMATCHED_RIGHT_PAREN_ORD << 1) + +/* If this bit is set, do not process the GNU regex operators. + If not set, then the GNU regex operators are recognized. */ +#define RE_NO_GNU_OPS (RE_NO_POSIX_BACKTRACKING << 1) + +/* If this bit is set, turn on internal regex debugging. + If not set, and debugging was on, turn it off. + This only works if regex.c is compiled -DDEBUG. + We define this bit always, so that all that's needed to turn on + debugging is to recompile regex.c; the calling code can always have + this bit set, and it won't affect anything in the normal case. */ +#define RE_DEBUG (RE_NO_GNU_OPS << 1) + +/* This global variable defines the particular regexp syntax to use (for + some interfaces). When a regexp is compiled, the syntax used is + stored in the pattern buffer, so changing this does not affect + already-compiled regexps. */ +extern reg_syntax_t re_syntax_options; + +/* Define combinations of the above bits for the standard possibilities. + (The [[[ comments delimit what gets put into the Texinfo file, so + don't delete them!) */ +/* [[[begin syntaxes]]] */ +#define RE_SYNTAX_EMACS 0 + +#define RE_SYNTAX_AWK \ + (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \ + | RE_NO_BK_PARENS | RE_NO_BK_REFS \ + | RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \ + | RE_DOT_NEWLINE | RE_CONTEXT_INDEP_ANCHORS \ + | RE_UNMATCHED_RIGHT_PAREN_ORD | RE_NO_GNU_OPS) + +#define RE_SYNTAX_GNU_AWK \ + ((RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DEBUG) \ + & ~(RE_DOT_NOT_NULL | RE_INTERVALS | RE_CONTEXT_INDEP_OPS)) + +#define RE_SYNTAX_POSIX_AWK \ + (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS \ + | RE_INTERVALS | RE_NO_GNU_OPS) + +#define RE_SYNTAX_GREP \ + (RE_BK_PLUS_QM | RE_CHAR_CLASSES \ + | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS \ + | RE_NEWLINE_ALT) + +#define RE_SYNTAX_EGREP \ + (RE_CHAR_CLASSES | RE_CONTEXT_INDEP_ANCHORS \ + | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE \ + | RE_NEWLINE_ALT | RE_NO_BK_PARENS \ + | RE_NO_BK_VBAR) + +#define RE_SYNTAX_POSIX_EGREP \ + (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES) + +/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */ +#define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC + +#define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC + +/* Syntax bits common to both basic and extended POSIX regex syntax. */ +#define _RE_SYNTAX_POSIX_COMMON \ + (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \ + | RE_INTERVALS | RE_NO_EMPTY_RANGES) + +#define RE_SYNTAX_POSIX_BASIC \ + (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM) + +/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes + RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this + isn't minimal, since other operators, such as \`, aren't disabled. */ +#define RE_SYNTAX_POSIX_MINIMAL_BASIC \ + (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS) + +#define RE_SYNTAX_POSIX_EXTENDED \ + (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ + | RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \ + | RE_NO_BK_PARENS | RE_NO_BK_VBAR \ + | RE_CONTEXT_INVALID_OPS | RE_UNMATCHED_RIGHT_PAREN_ORD) + +/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INDEP_OPS is + removed and RE_NO_BK_REFS is added. */ +#define RE_SYNTAX_POSIX_MINIMAL_EXTENDED \ + (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ + | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \ + | RE_NO_BK_PARENS | RE_NO_BK_REFS \ + | RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD) +/* [[[end syntaxes]]] */ + +/* Maximum number of duplicates an interval can allow. Some systems + (erroneously) define this in other header files, but we want our + value, so remove any previous define. */ +#ifdef RE_DUP_MAX +# undef RE_DUP_MAX +#endif +/* If sizeof(int) == 2, then ((1 << 15) - 1) overflows. */ +#define RE_DUP_MAX (0x7fff) + + +/* POSIX `cflags' bits (i.e., information for `regcomp'). */ + +/* If this bit is set, then use extended regular expression syntax. + If not set, then use basic regular expression syntax. */ +#define REG_EXTENDED 1 + +/* If this bit is set, then ignore case when matching. + If not set, then case is significant. */ +#define REG_ICASE (REG_EXTENDED << 1) + +/* If this bit is set, then anchors do not match at newline + characters in the string. + If not set, then anchors do match at newlines. */ +#define REG_NEWLINE (REG_ICASE << 1) + +/* If this bit is set, then report only success or fail in regexec. + If not set, then returns differ between not matching and errors. */ +#define REG_NOSUB (REG_NEWLINE << 1) + + +/* POSIX `eflags' bits (i.e., information for regexec). */ + +/* If this bit is set, then the beginning-of-line operator doesn't match + the beginning of the string (presumably because it's not the + beginning of a line). + If not set, then the beginning-of-line operator does match the + beginning of the string. */ +#define REG_NOTBOL 1 + +/* Like REG_NOTBOL, except for the end-of-line. */ +#define REG_NOTEOL (1 << 1) + + +/* If any error codes are removed, changed, or added, update the + `re_error_msg' table in regex.c. */ +typedef enum +{ +#ifdef _XOPEN_SOURCE + REG_ENOSYS = -1, /* This will never happen for this implementation. */ +#endif + + REG_NOERROR = 0, /* Success. */ + REG_NOMATCH, /* Didn't find a match (for regexec). */ + + /* POSIX regcomp return error codes. (In the order listed in the + standard.) */ + REG_BADPAT, /* Invalid pattern. */ + REG_ECOLLATE, /* Not implemented. */ + REG_ECTYPE, /* Invalid character class name. */ + REG_EESCAPE, /* Trailing backslash. */ + REG_ESUBREG, /* Invalid back reference. */ + REG_EBRACK, /* Unmatched left bracket. */ + REG_EPAREN, /* Parenthesis imbalance. */ + REG_EBRACE, /* Unmatched \{. */ + REG_BADBR, /* Invalid contents of \{\}. */ + REG_ERANGE, /* Invalid range end. */ + REG_ESPACE, /* Ran out of memory. */ + REG_BADRPT, /* No preceding re for repetition op. */ + + /* Error codes we've added. */ + REG_EEND, /* Premature end. */ + REG_ESIZE, /* Compiled pattern bigger than 2^16 bytes. */ + REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */ +} reg_errcode_t; + +/* This data structure represents a compiled pattern. Before calling + the pattern compiler, the fields `buffer', `allocated', `fastmap', + `translate', and `no_sub' can be set. After the pattern has been + compiled, the `re_nsub' field is available. All other fields are + private to the regex routines. */ + +#ifndef RE_TRANSLATE_TYPE +# define RE_TRANSLATE_TYPE char * +#endif + +struct re_pattern_buffer +{ +/* [[[begin pattern_buffer]]] */ + /* Space that holds the compiled pattern. It is declared as + `unsigned char *' because its elements are + sometimes used as array indexes. */ + unsigned char *buffer; + + /* Number of bytes to which `buffer' points. */ + unsigned long int allocated; + + /* Number of bytes actually used in `buffer'. */ + unsigned long int used; + + /* Syntax setting with which the pattern was compiled. */ + reg_syntax_t syntax; + + /* Pointer to a fastmap, if any, otherwise zero. re_search uses + the fastmap, if there is one, to skip over impossible + starting points for matches. */ + char *fastmap; + + /* Either a translate table to apply to all characters before + comparing them, or zero for no translation. The translation + is applied to a pattern when it is compiled and to a string + when it is matched. */ + RE_TRANSLATE_TYPE translate; + + /* Number of subexpressions found by the compiler. */ + size_t re_nsub; + + /* Zero if this pattern cannot match the empty string, one else. + Well, in truth it's used only in `re_search_2', to see + whether or not we should use the fastmap, so we don't set + this absolutely perfectly; see `re_compile_fastmap' (the + `duplicate' case). */ + unsigned can_be_null : 1; + + /* If REGS_UNALLOCATED, allocate space in the `regs' structure + for `max (RE_NREGS, re_nsub + 1)' groups. + If REGS_REALLOCATE, reallocate space if necessary. + If REGS_FIXED, use what's there. */ +#define REGS_UNALLOCATED 0 +#define REGS_REALLOCATE 1 +#define REGS_FIXED 2 + unsigned regs_allocated : 2; + + /* Set to zero when `regex_compile' compiles a pattern; set to one + by `re_compile_fastmap' if it updates the fastmap. */ + unsigned fastmap_accurate : 1; + + /* If set, `re_match_2' does not return information about + subexpressions. */ + unsigned no_sub : 1; + + /* If set, a beginning-of-line anchor doesn't match at the + beginning of the string. */ + unsigned not_bol : 1; + + /* Similarly for an end-of-line anchor. */ + unsigned not_eol : 1; + + /* If true, an anchor at a newline matches. */ + unsigned newline_anchor : 1; + +/* [[[end pattern_buffer]]] */ +}; + +typedef struct re_pattern_buffer regex_t; + +/* Type for byte offsets within the string. POSIX mandates this. */ +typedef int regoff_t; + + +/* This is the structure we store register match data in. See + regex.texinfo for a full description of what registers match. */ +struct re_registers +{ + unsigned num_regs; + regoff_t *start; + regoff_t *end; +}; + + +/* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer, + `re_match_2' returns information about at least this many registers + the first time a `regs' structure is passed. */ +#ifndef RE_NREGS +# define RE_NREGS 30 +#endif + + +/* POSIX specification for registers. Aside from the different names than + `re_registers', POSIX uses an array of structures, instead of a + structure of arrays. */ +typedef struct +{ + regoff_t rm_so; /* Byte offset from string's start to substring's start. */ + regoff_t rm_eo; /* Byte offset from string's start to substring's end. */ +} regmatch_t; + +/* Declarations for routines. */ + +/* To avoid duplicating every routine declaration -- once with a + prototype (if we are ANSI), and once without (if we aren't) -- we + use the following macro to declare argument types. This + unfortunately clutters up the declarations a bit, but I think it's + worth it. */ + +#if __STDC__ + +# define _RE_ARGS(args) args + +#else /* not __STDC__ */ + +# define _RE_ARGS(args) () + +#endif /* not __STDC__ */ + +/* Sets the current default syntax to SYNTAX, and return the old syntax. + You can also simply assign to the `re_syntax_options' variable. */ +extern reg_syntax_t re_set_syntax _RE_ARGS ((reg_syntax_t syntax)); + +/* Compile the regular expression PATTERN, with length LENGTH + and syntax given by the global `re_syntax_options', into the buffer + BUFFER. Return NULL if successful, and an error string if not. */ +extern const char *re_compile_pattern + _RE_ARGS ((const char *pattern, size_t length, + struct re_pattern_buffer *buffer)); + + +/* Compile a fastmap for the compiled pattern in BUFFER; used to + accelerate searches. Return 0 if successful and -2 if was an + internal error. */ +extern int re_compile_fastmap _RE_ARGS ((struct re_pattern_buffer *buffer)); + + +/* Search in the string STRING (with length LENGTH) for the pattern + compiled into BUFFER. Start searching at position START, for RANGE + characters. Return the starting position of the match, -1 for no + match, or -2 for an internal error. Also return register + information in REGS (if REGS and BUFFER->no_sub are nonzero). */ +extern int re_search + _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string, + int length, int start, int range, struct re_registers *regs)); + + +/* Like `re_search', but search in the concatenation of STRING1 and + STRING2. Also, stop searching at index START + STOP. */ +extern int re_search_2 + _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1, + int length1, const char *string2, int length2, + int start, int range, struct re_registers *regs, int stop)); + + +/* Like `re_search', but return how many characters in STRING the regexp + in BUFFER matched, starting at position START. */ +extern int re_match + _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string, + int length, int start, struct re_registers *regs)); + + +/* Relates to `re_match' as `re_search_2' relates to `re_search'. */ +extern int re_match_2 + _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1, + int length1, const char *string2, int length2, + int start, struct re_registers *regs, int stop)); + + +/* Set REGS to hold NUM_REGS registers, storing them in STARTS and + ENDS. Subsequent matches using BUFFER and REGS will use this memory + for recording register information. STARTS and ENDS must be + allocated with malloc, and must each be at least `NUM_REGS * sizeof + (regoff_t)' bytes long. + + If NUM_REGS == 0, then subsequent matches should allocate their own + register data. + + Unless this function is called, the first search or match using + PATTERN_BUFFER will allocate its own register data, without + freeing the old data. */ +extern void re_set_registers + _RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs, + unsigned num_regs, regoff_t *starts, regoff_t *ends)); + +#if defined _REGEX_RE_COMP || defined _LIBC +# ifndef _CRAY +/* 4.2 bsd compatibility. */ +extern char *re_comp _RE_ARGS ((const char *)); +extern int re_exec _RE_ARGS ((const char *)); +# endif +#endif + +/* GCC 2.95 and later have "__restrict"; C99 compilers have + "restrict", and "configure" may have defined "restrict". */ +#ifndef __restrict +# if ! (2 < __GNUC__ || (2 == __GNUC__ && 95 <= __GNUC_MINOR__)) +# if defined restrict || 199901L <= __STDC_VERSION__ +# define __restrict restrict +# else +# define __restrict +# endif +# endif +#endif +/* For now unconditionally define __restrict_arr to expand to nothing. + Ideally we would have a test for the compiler which allows defining + it to restrict. */ +#define __restrict_arr + +/* POSIX compatibility. */ +extern int regcomp _RE_ARGS ((regex_t *__restrict __preg, + const char *__restrict __pattern, + int __cflags)); + +extern int regexec _RE_ARGS ((const regex_t *__restrict __preg, + const char *__restrict __string, size_t __nmatch, + regmatch_t __pmatch[__restrict_arr], + int __eflags)); + +extern size_t regerror _RE_ARGS ((int __errcode, const regex_t *__preg, + char *__errbuf, size_t __errbuf_size)); + +extern void regfree _RE_ARGS ((regex_t *__preg)); + +#ifdef __cplusplus +} +#endif /* C++ */ + +#endif /* regex.h */ + +/* +Local variables: +make-backup-files: t +version-control: t +trim-versions-without-asking: nil +End: +*/ + +#else /* !defined(USE_LIB_REGEX) */ +#include +#endif /* defined(USE_LIB_REGEX) */ diff --git a/scripts/00MANIFEST b/scripts/00MANIFEST new file mode 100644 index 0000000..79d6fb3 --- /dev/null +++ b/scripts/00MANIFEST @@ -0,0 +1,58 @@ +The scripts in this subdirectory give examples of using lsof's +field output. + +big_brother.perl5 Perl 5 script, contributed by Lionel Cons + , that watches for new + network connections. + +count_pf.perl Perl 4 or 5 script that runs lsof in repeat + mode, gathering process, file, TCP, and UDP + counts + +count_pf.perl5 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.perl5 Perl 5 script, contributed by Kapil Chowksey + that implements an + identd server. (Thanks, Kapil!) + +idrlogin.perl Perl 4 script that identifies the shell and + network source address of users who have logged + on from remote locations via rlogin, ssh, or + telnet + +idrlogin.perl5 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.perl5 Perl 5 script that prints lsof's NUL terminated + field output + +list_fields.awk AWK script that prints lsof's field output + +list_fields.perl Perl 4 or 5 script that prints lsof's field + output + +shared.perl5 Perl 5 script that uses +ffn output to produce + a list of file descriptors or files shared by + processes. + +sort_res.perl5 Perl 5 script, contributed by Fabian Frederick + , to display top resource + usage. + +watch_a_file.perl 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 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 index 0000000..3cfb9e6 --- /dev/null +++ b/scripts/00README @@ -0,0 +1,55 @@ + + 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. + +The scripts are written in AWK, Perl 4 (4.036), and Perl 5 (5.001e +through 5.006). AWK scripts have a suffix of ``.awk''; Perl 4 +(which will work under Perl 5) scripts have a ``.perl4'' suffix; +and Perl 5 scripts, ``.perl''. + +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: + + Path to: Is: + ======= == + + Perl 4 /usr/local/bin/perl4 + + Perl 5 /usr/local/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 | / list_fields.perl + +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.perl5 b/scripts/big_brother.perl5 new file mode 100755 index 0000000..14c67a8 --- /dev/null +++ b/scripts/big_brother.perl5 @@ -0,0 +1,210 @@ +#!/usr/local/bin/perl -w +#+############################################################################## +# # +# File: big_brother.perl # +# # +# Description: check the network sockets with lsof to detect new connections # +# # +# Contributed by Lionel Cons # +# # +#-############################################################################## + +# @(#)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 "# ", ×tamp, " $LSOF $lsof_opt, pid=$lsof_pid\n" + if $verbose; + print "#COMMAND PID USER P NAME\n"; + $printed = $hanguped = $pid = $proto = 0; + while () { + 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 "# ", ×tamp, " 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 "# ", ×tamp, "\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.perl b/scripts/count_pf.perl new file mode 100755 index 0000000..f063697 --- /dev/null +++ b/scripts/count_pf.perl @@ -0,0 +1,68 @@ +#!/usr/local/bin/perl +# +# count_pf.perl-- 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 -nPF output repeatedly from a pipe. + +$| = 1; # unbuffer output +$SIG{'INT'} = 'interrupt'; # catch interrupt +$proc = $files = $proto{'TCP'} = $proto{'UDP'} = 0; +$progress="/"; # used to show "progress" +open(P, "$LSOF -nPF -r $RPT|") || die "can't open pipe to $LSOF\n"; + +while (

) { + 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, $proto{'TCP'}, $proto{'UDP'}; + $proc = $files = $proto{'TCP'} = $proto{'UDP'} = 0; + if ($progress eq "/") { $progress = "\\"; } else { $progress = "/"; } + next; + } + if (/^p/) { $proc++; next; } # Count processes. + if (/^f/) { $files++; next; } # Count files. + if (/^P(.*)/) { $proto{$1}++; next; } # Count protocols. +} + + +## 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.perl5 b/scripts/count_pf.perl5 new file mode 100755 index 0000000..6b87f78 --- /dev/null +++ b/scripts/count_pf.perl5 @@ -0,0 +1,94 @@ +#!/usr/local/bin/perl +# +# count_pf.perl5 -- 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 (

) { + 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.perl5 b/scripts/identd.perl5 new file mode 100755 index 0000000..32626d8 --- /dev/null +++ b/scripts/identd.perl5 @@ -0,0 +1,131 @@ +#!/usr/local/bin/perl +################################################################### +# identd.perl5 : 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.perl5 -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) +# - assumes 'lsof' binary in /usr/local/sbin +# - Command line arguments : +# -t TIMEOUT Number of seconds to wait for a query before aborting. +# Default is 120. +# +# Kapil Chowksey +################################################################### + +use Socket; +require 'getopts.pl'; + +# 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 + } +} + +# redirect lsof's warnings/errors to /dev/null +close(STDERR); +open(STDERR, ">/dev/null"); + +$Timeout = "120"; + +&Getopts('t:'); +if ($opt_t) { + $Timeout = $opt_t; +} + +($port, $iaddr) = sockaddr_in(getpeername(STDIN)); +$peer_addr = inet_ntoa($iaddr); + +# read ident-query from socket (STDIN) with a timeout. +$timeout = int($Timeout); +eval { + local $SIG{ALRM} = sub { die "alarm\n" }; + alarm $timeout; + $query = ; + alarm 0; +}; +die if $@ && $@ ne "alarm\n"; +if ($@) { + # timed out + exit; +} + +# remove all white-spaces from query +$query =~ s/\s//g; + +$serv_port = ""; +$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."|"); + +$user = "UNKNOWN"; +while ($a_line = ) { + # 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.perl b/scripts/idrlogin.perl new file mode 100755 index 0000000..d244dc7 --- /dev/null +++ b/scripts/idrlogin.perl @@ -0,0 +1,201 @@ +#!/usr/local/bin/perl +# +# $Id: idrlogin.perl,v 1.5 2001/11/18 12:20:46 abe Exp $ +# +# idrlogin.perl -- sample Perl 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 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 = $name = $proto = ""; # fd variables +$fdst = 0; # fd state +$pidst = 0; # process state +$cmd = $login = $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. + +open(P, "$LSOF -R -FcDfLpPRn|") || die "Can't pipe from $LSOF\n"; + +# Process the ``lsof -FcDfLpPRn'' output a line at a time + +while (

) { + chop; + if (/^p(.*)/) { + +# A process set begins with a PID field whose ID character is `p'. + + $tpid = $1; + if ($pidst && $fdst) { &save_proc } + $pidst = 1; + $pid = $tpid; + $cmd = $login = $ppid = ""; + $fdst = 0; + $dev = $name = $proto = ""; + next; + } + +# Save process-related values. + + if (/^c(.*)/) { $cmd = $1; next; } + if (/^L(.*)/) { $login = $1; next; } + if (/^R(.*)/) { $ppid = $1; next; } + +# A file set begins with a file descriptor field. + + if (/^f/) { + if ($pidst && $fdst) { &save_proc } + $fdst = 0; + $dev = $name = $proto = ""; + next; + } + +# Accumulate file information. + + if (/^D(.*)/) { $dev = $1; next; } + if (/^P(.*)/) { $proto = $1; next; } + if (/^n(.*)/) { $name = $1; $fdst = 1; next; } +} + +# Flush any stored file or process output. + +if ($pidst && $fdst) { &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 ($cmd eq "" + || $login eq "" + || $ppid eq "" + || $pid eq "" + || $name eq "" + ) { return; } + if (!defined($Ppid{$pid})) { $Ppid{$pid} = $ppid; } + if ($proto eq "TCP" + && (($cmd =~ /rlogind/) || ($cmd =~ /sshd/) || ($cmd =~ /telnetd/))) { + if (defined($raddr{$pid})) { return; } + if (($name =~ /[^:]*:[^-]*->([^:]*):.*/)) { + $raddr{$pid} = $1; + $rcmd{$pid} = $cmd; + return; + } + } + if (($cmd =~ /.*sh$/)) { + if (defined($shcmd{$pid})) { return; } + if ($proto eq "TCP") { + if (defined($raddr{$pid})) { return; } + if (($name =~ /[^:]*:[^-]*->([^:]*):.*/)) { + $raddr{$pid} = $1; + $shcmd{$pid} = $cmd; + $shlogin{$pid} = $login; + } + } + 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); + } else { return; } + } else { return; } + $shcmd{$pid} = $cmd; + $shtty{$pid} = $tty; + $shlogin{$pid} = $login; +} + + +## 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.perl5 b/scripts/idrlogin.perl5 new file mode 100755 index 0000000..5e7e4bf --- /dev/null +++ b/scripts/idrlogin.perl5 @@ -0,0 +1,197 @@ +#!/usr/local/bin/perl +# +# $Id: idrlogin.perl5,v 1.5 2001/11/18 12:20:46 abe Exp $ +# +# idrlogin.perl5 -- 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 (

) { + 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.perl5 b/scripts/list_NULf.perl5 new file mode 100755 index 0000000..a9cdbed --- /dev/null +++ b/scripts/list_NULf.perl5 @@ -0,0 +1,161 @@ +#!/usr/local/bin/perl +# +# $Id: list_NULf.perl5,v 1.5 2000/07/14 17:03:37 abe Exp $ +# +# list_NULf.perl5 -- 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 index 0000000..d8fbbb4 --- /dev/null +++ b/scripts/list_fields.awk @@ -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.perl b/scripts/list_fields.perl new file mode 100755 index 0000000..41bd3e4 --- /dev/null +++ b/scripts/list_fields.perl @@ -0,0 +1,156 @@ +#!/usr/local/bin/perl4 +# +# $Id: list_fields.perl,v 1.5 2000/07/14 17:03:37 abe Exp $ +# +# list_fields.perl -- 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.perl5 b/scripts/shared.perl5 new file mode 100755 index 0000000..2721413 --- /dev/null +++ b/scripts/shared.perl5 @@ -0,0 +1,409 @@ +#!/usr/local/bin/perl +# +# $Id: shared.perl5,v 1.4 2001/11/18 12:20:46 abe Exp $ +# +# shared.perl5 -- 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 +# +# 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 () { + 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.perl5 b/scripts/sort_res.perl5 new file mode 100755 index 0000000..cf11950 --- /dev/null +++ b/scripts/sort_res.perl5 @@ -0,0 +1,135 @@ +#!/usr/bin/perl +# sort_res.perl5 - Script to group & sort lsof output by resource +# +# Copyright (c) 2004, 2005 - Fabian Frederick +# +# 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.perl5 -> display used resources + size +# or perl sort_res.perl5 +# +# 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 + +require 'getopts.pl'; +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=)){ + $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.perl b/scripts/watch_a_file.perl new file mode 100755 index 0000000..c1cd782 --- /dev/null +++ b/scripts/watch_a_file.perl @@ -0,0 +1,94 @@ +#!/usr/local/bin/perl +# +# watch_a_file.perl -- use lsof -F output to watch a specific file +# (or file system) +# +# usage: watch_a_file.perl 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 (

) { + 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 (

) { 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 index 0000000..ac818b4 --- /dev/null +++ b/scripts/xusers.awk @@ -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 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/store.c b/store.c new file mode 100644 index 0000000..0bf3fa7 --- /dev/null +++ b/store.c @@ -0,0 +1,399 @@ +/* + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: store.c,v 1.44 2018/02/14 14:20:14 abe Exp $"; +#endif + + +#include "lsof.h" + + +/* + * Global storage definitions + */ + +int AllProc = 1; /* all processes are selected (default) */ + +#if defined(HASBLKDEV) +struct l_dev *BDevtp = (struct l_dev *)NULL; + /* block device table pointer */ +int BNdev = 0; /* number of entries in BDevtp[] */ +struct l_dev **BSdev = (struct l_dev **)NULL; + /* pointer to BDevtp[] pointers, sorted + * by device */ +#endif /* defined(HASBLKDEV) */ + +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 */ +struct str_lst *Cmdl = (struct str_lst *)NULL; + /* command names selected with -c */ +int CmdLim = CMDL; /* COMMAND column width limit */ +int Cmdni = 0; /* command name inclusions selected with -c */ +int Cmdnx = 0; /* command name exclusions selected with -c */ +lsof_rx_t *CmdRx = (lsof_rx_t *)NULL; + /* command regular expression table */ + +#if defined(HASSELINUX) +cntxlist_t *CntxArg = (cntxlist_t *)NULL; + /* security context arguments supplied with + * -Z */ +int CntxColW; /* security context column width */ +int CntxStatus = 0; /* security context status: 0 == disabled, + * 1 == enabled */ +#endif /* defined(HASSELINUX) */ + +#if defined(HASDCACHE) +unsigned DCcksum; /* device cache file checksum */ +int DCfd = -1; /* device cache file descriptor */ +FILE *DCfs = (FILE *)NULL; /* stream pointer for DCfd */ +char *DCpathArg = (char *)NULL; /* device cache path from -D[b|r|u] */ +char *DCpath[] = { /* device cache paths, indexed by DCpathX + *when it's >= 0 */ + (char *)NULL, (char *)NULL, (char *)NULL, (char *)NULL +}; +int DCpathX = -1; /* 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 */ +int DCrebuilt = 0; /* an unsafe device cache file has been + * rebuilt */ +int DCstate = 3; /* 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 DCunsafe = 0; /* device cache file is potentially unsafe, + * (The [cm]time check failed.) */ +#endif /* defined(HASDCACHE) */ + +int DChelp = 0; /* -D? status */ + +int DevColW; /* DEVICE column width */ +dev_t DevDev; /* device number of /dev or its equivalent */ +struct l_dev *Devtp = (struct l_dev *)NULL; + /* device table pointer */ + + +/* + * Externals for a stkdir(), dumbed-down for older AIX compilers. + */ + +char **Dstk = (char **)NULL; /* the directory stack */ +int Dstkx = 0; /* Dstk[] index */ +int Dstkn = 0; /* Dstk[] entries allocated */ +efsys_list_t *Efsysl = (efsys_list_t *)NULL; + /* file systems for which kernel blocks are + * to be eliminated */ +int ErrStat = 0; /* path stat() error count */ +uid_t Euid; /* effective UID of this lsof process */ +int Fand = 0; /* -a option status */ +int Fblock = 0; /* -b option status */ +int FcColW; /* FCT column width */ +int Fcntx = 0; /* -Z option status */ +int FdColW; /* FD column width */ +int FeptE = 0; /* -E option status: 0==none, 1==info, + * 2==info+files */ +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 Fncache = 1; /* -C option status */ +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 Fnet = 0; /* -i option status: 0==none + * 1==find all + * 2==some found*/ +int FnetTy = 0; /* Fnet type request: 0==all + * 4==IPv4 + * 6==IPv6 */ +int Fnfs = 0; /* -N option status: 0==none, 1==find all, + * 2==some found*/ +int Fnlink = 0; /* -L option status */ +int Foffset = 0; /* -o option status */ +int Fovhd = 0; /* -O 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 Fsize = 0; /* -s option status */ +int FsColW; /* FSTR-ADDR column width */ +int Fsv = FSV_DEFAULT; /* file struct value selections */ +int FsvByf = 0; /* Fsv was set by +f */ +int FsvFlagX = 0; /* hex format status for FSV_FG */ +int Ftask = 0; /* -K option value */ +int NiColW; /* NODE-ID column width */ +char *NiTtl = NITTL; /* NODE-ID column title */ +int Ftcptpi = TCPTPI_STATE; /* -T option status */ +int Fterse = 0; /* -t option status */ +int Funix = 0; /* -U option status */ +int Futol = 1; /* -l option status */ +int Fverbose = 0; /* -V option status */ + +#if defined(WARNINGSTATE) +int Fwarn = 1; /* +|-w option status */ +#else /* !defined(WARNINGSTATE) */ +int Fwarn = 0; /* +|-w option status */ +#endif /* defined(WARNINGSTATE) */ + +#if defined(HASXOPT_VALUE) +int Fxopt = HASXOPT_VALUE; /* -X option status */ +#endif /* defined(HASXOPT_VALUE) */ + +int Fxover = 0; /* -x option value */ +int Fzone = 0; /* -z option status */ + +struct fd_lst *Fdl = (struct fd_lst *)NULL; + /* file descriptors selected with -d */ +int FdlTy = -1; /* Fdl[] type: -1 == none + * 0 == include + * 1 == exclude */ + +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, 1, 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 */ +int IgnTasks = 0; /* ignore tasks when non-zero */ +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) */ +struct lfile *Lf = (struct lfile *)NULL; + /* current local file structure */ +struct lproc *Lp = (struct lproc *)NULL; + /* current local process table entry */ +struct lproc *Lproc = (struct lproc *)NULL; + /* local process table */ +int MaxFd; /* maximum file descriptors to close */ +char *Memory = (char *)NULL; /* core file path */ +int MntSup = 0; /* mount supplement state: 0 == none + * 1 == create + * 2 == read */ +char *MntSupP = (char *)NULL; /* mount supplement path -- if MntSup == 2 */ + +#if defined(HASPROCFS) +struct mounts *Mtprocfs = (struct mounts *)NULL; + /* /proc mount entry */ +#endif /* defined(HASPROCFS) */ + +int Mxpgid = 0; /* maximum process group ID table entries */ +int Mxpid = 0; /* maximum PID table entries */ +int Mxuid = 0; /* maximum UID table entries */ +gid_t Mygid; /* real GID of this lsof process */ +int Mypid; /* lsof's process ID */ +uid_t Myuid; /* real UID of this lsof process */ +char *Namech = (char *)NULL; /* name characters for printing */ +size_t Namechl = (size_t)0; /* sizeof(Namech) */ +int NCmdRxU = 0; /* number of CmdRx[] entries */ +int Ndev = 0; /* number of entries in Devtp[] */ + +#if defined(HASNLIST) +struct NLIST_TYPE *Nl = (struct NLIST_TYPE *)NULL; + /* kernel name list */ +int Nll = 0; /* Nl calloc'd length */ +#endif /* defined(HASNLIST) */ + +long Nlink = 0l; /* report nlink values below this number + * (0 = report all nlink values) */ +int Nlproc = 0; /* number of entries in Lproc[] */ +int NlColW; /* NLINK column width */ +int NmColW; /* NAME column width */ +char *Nmlst = (char *)NULL; /* namelist file path */ +int NodeColW; /* NODE column width */ +int Npgid = 0; /* -g option count */ +int Npgidi = 0; /* -g option inclusion count */ +int Npgidx = 0; /* -g option exclusion count */ +int Npid = 0; /* -p option count */ +int Npidi = 0; /* -p option inclusion count */ +int Npidx = 0; /* -p option exclusion count */ +int Npuns; /* number of unselected PIDs (starts at Npid) */ +int Ntype; /* node type (see N_* symbols) */ +int Nuid = 0; /* -u option count */ +int Nuidexcl = 0; /* -u option count of UIDs excluded */ +int Nuidincl = 0; /* -u option count of UIDs included */ +struct nwad *Nwad = (struct nwad *)NULL; + /* list of network addresses */ +int OffDecDig = OFFDECDIG; /* offset decimal form (0t...) digit limit */ +int OffColW; /* OFFSET column width */ +int PgidColW; /* PGID column width */ +int PidColW; /* PID column width */ +struct lfile *Plf = (struct lfile *)NULL; + /* previous local file structure */ +char *Pn; /* program name */ +int PpidColW; /* PPID column width */ + +#if defined(HASPROCFS) +int Procfind = 0; /* 1 when searching for an proc file system + * file and one was found */ +struct procfsid *Procfsid = (struct procfsid *)NULL; + /* proc file system PID search table */ +int Procsrch = 0; /* 1 if searching for any proc file system + * file */ +#endif /* defined(HASPROCFS) */ + +int PrPass = 0; /* print pass: 0 = compute column widths + * 1 = print */ +int RptTm = 0; /* repeat time -- set by -r */ +struct l_dev **Sdev = (struct l_dev **)NULL; + /* pointer to Devtp[] pointers, sorted + * by device */ +int SelAll = 0; /* SELALL flags, modified by IgnTasks */ +int Selflags = 0; /* selection flags -- see SEL* in lsof.h */ +int SelProc = 0; /* SELPROC flags, modified by IgnTasks */ +int Setgid = 0; /* setgid state */ +int Selinet = 0; /* select only Internet socket files */ +int Setuidroot = 0; /* setuid-root state */ +struct sfile *Sfile = (struct sfile *)NULL; + /* chain of files to search for */ +struct int_lst *Spgid = (struct int_lst *)NULL; + /* process group IDs to search for */ +struct int_lst *Spid = (struct int_lst *)NULL; + /* Process IDs to search for */ +struct seluid *Suid = (struct seluid *)NULL; + /* User IDs to include or exclude */ +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 */ +int TcpStAlloc = 0; /* allocated (possibly unused) entries in TCP + * state tables */ +unsigned char *TcpStI = (unsigned char *)NULL; + /* included TCP states */ +int TcpStIn = 0; /* number of entries in TcpStI[] */ +int TcpStOff = 0; /* offset for TCP state number to adjust + * negative numbers to an index into TcpSt[], + * TcpStI[] and TcpStX[] */ +unsigned char *TcpStX = (unsigned char *)NULL; + /* excluded TCP states */ +int TcpStXn = 0; /* number of entries in TcpStX[] */ +int TcpNstates = 0; /* number of TCP states -- either in + * tcpstates[] or TcpSt[] */ +char **TcpSt = (char **)NULL; /* local TCP state names, indexed by system + * state value */ +char Terminator = '\n'; /* output field terminator */ +int TaskTidColW = 0; /* task TID column width */ +int TmLimit = TMLIMIT; /* Readlink() and stat() timeout (seconds) */ +int TypeColW; /* TYPE column width */ +int UdpStAlloc = 0; /* allocated (possibly unused) entries in UDP + * state tables */ +unsigned char *UdpStI = (unsigned char *)NULL; + /* included UDP states */ +int UdpStIn = 0; /* number of entries in UdpStI[] */ +int UdpStOff = 0; /* offset for UDP state number to adjust + * negative numbers to an index into UdpSt[], + * UdpStI[] and UdpStX[] */ +unsigned char *UdpStX = (unsigned char *)NULL; + /* excluded UDP states */ +int UdpStXn = 0; /* number of entries in UdpStX[] */ +int UdpNstates = 0; /* number of UDP states in UdpSt[] */ +char **UdpSt = (char **)NULL; /* local UDP state names, indexed by system + * state number */ +int UserColW; /* USER column width */ + +#if defined(HASZONES) +znhash_t **ZoneArg = (znhash_t **)NULL; + /* zone arguments supplied with -z */ +#endif /* defined(HASZONES) */ + +int ZoneColW; /* ZONE column width */ diff --git a/support/AIXDistrib b/support/AIXDistrib new file mode 100755 index 0000000..1d13db6 --- /dev/null +++ b/support/AIXDistrib @@ -0,0 +1,14 @@ +#!/bin/ksh +# +# AIXDistrib -- make AIX distribution of lsof 4.x +# +# Usage: AIXDistrib [] +# +# optional suffix for identification + +if test $# -gt 1 +then + echo "Usage: []" + exit 1 +fi +$HOME/src/lsof4/support/GenericDistrib aix $1 diff --git a/support/DUDistrib b/support/DUDistrib new file mode 100755 index 0000000..a2bdd57 --- /dev/null +++ b/support/DUDistrib @@ -0,0 +1,14 @@ +#!/bin/ksh +# +# OSFDistrib -- make Digital UNIX (DEC OSF/1) distribution of lsof 4.x +# +# Usage: DUDistrib [] +# +# optional suffix for identification + +if test $# -gt 1 +then + echo "Usage: []" + exit 1 +fi +$HOME/src/lsof4/support/GenericDistrib du $1 diff --git a/support/DarwinDistrib b/support/DarwinDistrib new file mode 100755 index 0000000..9ade012 --- /dev/null +++ b/support/DarwinDistrib @@ -0,0 +1,14 @@ +#!/bin/ksh +# +# DarwinDistrib -- make Apple Darwin distribution of lsof 4.x +# +# Usage: DarwindDistrib [] +# +# optional suffix for identification + +if test $# -gt 1 +then + echo "Usage: []" + exit 1 +fi +$HOME/src/lsof4/support/GenericDistrib2 darwin $1 diff --git a/support/Distfile.msrc b/support/Distfile.msrc new file mode 100644 index 0000000..2c175c3 --- /dev/null +++ b/support/Distfile.msrc @@ -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 index 0000000..b58a4a9 --- /dev/null +++ b/support/FreeBSDDistrib @@ -0,0 +1,14 @@ +#!/bin/ksh +# +# FreeBSDDistrib -- make FreeBSD distribution of lsof 4.x +# +# Usage: FreeBSDDistrib [] +# +# optional suffix for identification + +if test $# -gt 1 +then + echo "Usage: []" + exit 1 +fi +$HOME/src/lsof4/support/GenericDistrib2 freebsd $1 diff --git a/support/GPGDistrib b/support/GPGDistrib new file mode 100755 index 0000000..fc950e3 --- /dev/null +++ b/support/GPGDistrib @@ -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 lsof.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_ 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 + or + Victor A. Abell + +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 . + +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 +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_ 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 " >> $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 + +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}..sig ${DT}. + +or + + gpg --verify lsof.tar..sig lsof.tar. + +Where is bz2, gz or Z. + +Problems +======== + +If an MD5 or GPG check reveals a problem, please report it via e-mail +to . + + +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 index 0000000..a9f86a9 --- /dev/null +++ b/support/GenericCopy @@ -0,0 +1,88 @@ +#!/bin/ksh +# +# GenericCopy -- generically copy lsof 4.x sources to a specified destination +# +# Usage: GenericCopy [] +# +# destination host +# +# login name at destination host +# +# dialect subdirectory name +# +# [] directory if other than src/lsof4 + +if test $# -lt 1 -o $? -gt 4 +then + echo "Usage: []" + 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 lsof.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//. + +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//*. + +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 index 0000000..3e1393f --- /dev/null +++ b/support/GenericDistrib @@ -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's subdirectory name +# +# [] optional suffix for version number + +cd $HOME/src/lsof4 + +# 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: []" + 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 +$HOME/src/lsof4/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 index 0000000..e2306c6 --- /dev/null +++ b/support/GenericDistrib2 @@ -0,0 +1 @@ +GenericDistrib \ No newline at end of file diff --git a/support/GenericRdist b/support/GenericRdist new file mode 100755 index 0000000..d001156 --- /dev/null +++ b/support/GenericRdist @@ -0,0 +1,80 @@ +#!/bin/ksh +# +# GenericRdist -- generically rdist lsof 4.x sources to a specified destination +# +# Usage: GenericRdist +# +# destination host +# +# dialect subdirectory name +# +# remote shell -- rsh or ssh + +# Process arguments. + +if test $# -ne 3 +then + echo "Usage: " + 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 index 0000000..3e6e286 --- /dev/null +++ b/support/GenericSubdir @@ -0,0 +1,100 @@ +#!/bin/ksh +# +# GenericSubdir -- create generic lsof 4.x distribution subdirectory +# +# Usage: GenericSubdir [] +# +# dialect's subdirectory name +# +# [] optional suffix for version number + +cd $HOME/src/lsof4 + +# 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: []" + exit 1 +fi +DIALECT=$1 +if test $# -eq 2 +then + V=${V}$2 +fi + +# Set variable names. + +DIR=lsof_${V}.${DIALECT} +F="00.README.FIRST 00CREDITS 00DCACHE 00DIALECTS 00DIST 00FAQ 00LSOF-L 00PORTING 00QUICKSTART 00README 00TEST 00XCONFIG AFSConfig ChangeLog Configure Customize Inventory arg.c lsof_fields.h lsof.h main.c misc.c node.c print.c proc.c proto.h regex.h store.c usage.c util.c 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 +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 index 0000000..fd69bbe --- /dev/null +++ b/support/GitHub-release/00README @@ -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 index 0000000..e3026c4 --- /dev/null +++ b/support/GitHub-release/ITaP @@ -0,0 +1,47 @@ +From: McCartney, William G +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: “Lsof 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.” + +Best wishes, Gerry- + +From: Victor Abell +Sent: Wednesday, June 27, 2018 5:06 AM +To: McCartney, William G +Cc: Vic Abell +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 –l +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’s 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 index 0000000..872be72 --- /dev/null +++ b/support/GitHub-release/Purdue @@ -0,0 +1,157 @@ +From: Sandel, Ken L. +Sent: Tuesday, July 10, 2018 14:28 +To: Victor Abell +Subject: RE: One more question regarding GitHub release + +Vic, + +For clarity – 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. +Sent: Tuesday, July 10, 2018 11:23 AM +To: Victor Abell +Cc: Sandel, Ken L. +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 +Sent: Monday, July 9, 2018 8:26 PM +To: Kasper, Joseph R. +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’t +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 +Sent: Thursday, June 28, 2018 7:43 AM +To: Kasper, Joseph R. +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’s mind at ease if you have Gerry’s blessing. Let me +know if you’ll reach out to him. + +Best, +Joe + +From: Victor Abell +Sent: Tuesday, June 26, 2018 3:57 PM +To: Kasper, Joseph R. +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 – 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 index 0000000..082e253 --- /dev/null +++ b/support/HPUXDistrib @@ -0,0 +1,14 @@ +#!/bin/ksh +# +# HPUXDistrib -- make HP-UX distribution of lsof 4.x +# +# Usage: HPUXDistrib [] +# +# optional suffix for identification + +if test $# -gt 1 +then + echo "Usage: []" + exit 1 +fi +$HOME/src/lsof4/support/GenericDistrib hpux $1 diff --git a/support/LinuxDistrib b/support/LinuxDistrib new file mode 100755 index 0000000..6d41058 --- /dev/null +++ b/support/LinuxDistrib @@ -0,0 +1,14 @@ +#!/bin/ksh +# +# LinuxDistrib -- make Linux distribution of lsof 4.x +# +# Usage: LinuxDistrib [] +# +# optional suffix for identification + +if test $# -gt 1 +then + echo "Usage: []" + exit 1 +fi +$HOME/src/lsof4/support/GenericDistrib2 linux $1 diff --git a/support/N+OBSDDistrib b/support/N+OBSDDistrib new file mode 100755 index 0000000..b0fa2a3 --- /dev/null +++ b/support/N+OBSDDistrib @@ -0,0 +1,14 @@ +#!/bin/ksh +# +# N+OBSDDistrib -- make NetBSD/OpenBSD distribution of lsof 4.x +# +# Usage: N+OBSDDistrib [] +# +# optional suffix for identification + +if test $# -gt 1 +then + echo "Usage: []" + exit 1 +fi +$HOME/src/lsof4/support/GenericDistrib2 n+obsd $1 diff --git a/support/N+OSDistrib b/support/N+OSDistrib new file mode 100755 index 0000000..cc35eab --- /dev/null +++ b/support/N+OSDistrib @@ -0,0 +1,14 @@ +#!/bin/ksh +# +# NOSDistrib -- make NEXTSTEP and OpenStep distribution of lsof 4.x +# +# Usage: NOSDistrib [] +# +# optional suffix for identification + +if test $# -gt 1 +then + echo "Usage: []" + exit 1 +fi +$HOME/src/lsof4/support/GenericDistrib n+os $1 diff --git a/support/NSDistrib b/support/NSDistrib new file mode 100755 index 0000000..ed72809 --- /dev/null +++ b/support/NSDistrib @@ -0,0 +1,14 @@ +#!/bin/ksh +# +# NSDistrib -- make NeXTSTEP distribution of lsof 4.x +# +# Usage: NSDistrib [] +# +# optional suffix for identification + +if test $# -gt 1 +then + echo "Usage: []" + exit 1 +fi +$HOME/src/lsof4/support/GenericDistrib ns $1 diff --git a/support/OSRDistrib b/support/OSRDistrib new file mode 100755 index 0000000..16c860c --- /dev/null +++ b/support/OSRDistrib @@ -0,0 +1,15 @@ +#!/bin/ksh +# +# OSRDistrib -- make SCO OpenServer distribution of lsof 4.x +# +# Usage: OSRDistrib [] +# +# optional suffix for identification + +if test $# -gt 1 +then + echo "Usage: []" + exit 1 +fi +cd $HOME/src/lsof4/support +./GenericDistrib osr $1 diff --git a/support/SpecialRdist b/support/SpecialRdist new file mode 100755 index 0000000..eeaf21a --- /dev/null +++ b/support/SpecialRdist @@ -0,0 +1,74 @@ +#!/bin/ksh +# +# SpecialRdist -- specially rdist lsof 4.x sources to a specified destination +# +# Usage: GenericRdist +# +# destination host +# +# dialect subdirectory name +# +# remote shell -- rsh or ssh + +# Process arguments. + +if test $# -ne 3 +then + echo "Usage: " + 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 index 0000000..d569d59 --- /dev/null +++ b/support/SunDistrib @@ -0,0 +1,14 @@ +#!/bin/ksh +# +# SunDistrib -- make Solaris and SunOS distribution of lsof 4.x +# +# Usage: SunDistrib [] +# +# optional suffix for identification + +if test $# -gt 1 +then + echo "Usage: []" + exit 1 +fi +$HOME/src/lsof4/support/GenericDistrib2 sun $1 diff --git a/support/UWDistrib b/support/UWDistrib new file mode 100755 index 0000000..3710b7e --- /dev/null +++ b/support/UWDistrib @@ -0,0 +1,15 @@ +#!/bin/ksh +# +# UWDistrib -- make SCO UnixWare distribution of lsof 4.x +# +# Usage: UWDistrib [] +# +# optional suffix for identification + +if test $# -gt 1 +then + echo "Usage: []" + exit 1 +fi +cd $HOME/src/lsof4/support +./GenericDistrib2 uw $1 diff --git a/support/argtest b/support/argtest new file mode 100755 index 0000000..b84ffff --- /dev/null +++ b/support/argtest @@ -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 index 0000000..37015e7 --- /dev/null +++ b/support/binaries/README @@ -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 index 0000000..89ab9e7 --- /dev/null +++ b/support/contrib.00INDEX @@ -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 + . + +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 + + +RT_PC.BSD4.3 contains information on a RT/PC BSD 4.3 + port to lsof 3.24 from R. Bernstein + . + + +Vic Abell +February 20, 1997 diff --git a/support/contrib.README b/support/contrib.README new file mode 100644 index 0000000..3c6f84e --- /dev/null +++ b/support/contrib.README @@ -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 index 0000000..c518f32 --- /dev/null +++ b/support/install-lsof @@ -0,0 +1,143 @@ +#!/bin/sh +# +# install-lsof -- install lsof + +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 " + exit 1 +fi +R=$1 +echo $R | grep '^4\.[0-9]*$' > /dev/null 2>&1 +if test $? -ne 0 +then + echo " 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 index 0000000..bd6a15e --- /dev/null +++ b/support/install.log @@ -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 index 0000000..d1f8653 --- /dev/null +++ b/support/look_rlog @@ -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 index 0000000..e69de29 diff --git a/support/lsof.00INDEX b/support/lsof.00INDEX new file mode 100644 index 0000000..7d1fe7e --- /dev/null +++ b/support/lsof.00INDEX @@ -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 . + +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 +July 14, 2018 diff --git a/support/lsof.README b/support/lsof.README new file mode 100644 index 0000000..411a372 --- /dev/null +++ b/support/lsof.README @@ -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 . | + | 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_.tar.bz2 + and + ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof_.tar.gz + and + ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof_.tar.Z + + is the revision number -- e.g., 4.92. These archives are called +wrappers, because the lsof source tar archive, its GPG certificate +(lsof__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 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/. 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_ 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_), 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 +July 14, 2018 diff --git a/support/makeman b/support/makeman new file mode 100755 index 0000000..d330abb --- /dev/null +++ b/support/makeman @@ -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 index 0000000..3c8b155 --- /dev/null +++ b/support/mentor @@ -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 index 0000000..4821f6f --- /dev/null +++ b/support/mirrors @@ -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 . diff --git a/support/rdist.distrib b/support/rdist.distrib new file mode 100755 index 0000000..5afd538 --- /dev/null +++ b/support/rdist.distrib @@ -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 index 0000000..eee8e4d --- /dev/null +++ b/tests/00README @@ -0,0 +1,102 @@ + + .../lsof_/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 index 0000000..893c8a1 --- /dev/null +++ b/tests/Add2TestDB @@ -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 index 0000000..80bee63 --- /dev/null +++ b/tests/CkTestDB @@ -0,0 +1,136 @@ +#!/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 + +# 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 index 0000000..ce04705 --- /dev/null +++ b/tests/LTbasic.c @@ -0,0 +1,445 @@ +/* + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright 2002 Purdue Research Foundation.\nAll rights reserved.\n"; +#endif + +#include "LsofTest.h" +#include "lsof_fields.h" + + +/* + * Local definitions + */ + + +/* + * Globals + */ + +char *Pn = (char *)NULL; /* program name */ + + +/* + * Local function prototypes + */ + +_PROTOTYPE(static void cleanup,(void)); +_PROTOTYPE(static char *tstlsof,(char **texec, char **tkmem, char **tproc)); + + +/* + * Main program for dialects that support locking tests. + */ + +int +main(argc, argv) + 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(texec, tkmem, tproc) + 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 *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. + */ + if (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, "%u", + (unsigned int)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, "%u", + (unsigned int)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, &lsofdc))) { + if (pem) + (void) PrtMsg(pem, Pn); + pem = cem; + break; + } + (void) snprintf(ibuf, sizeof(ibuf) - 1, "%u", + (unsigned int)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/LTbigf.c b/tests/LTbigf.c new file mode 100644 index 0000000..ed740e7 --- /dev/null +++ b/tests/LTbigf.c @@ -0,0 +1,767 @@ +/* + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright 2002 Purdue Research Foundation.\nAll rights reserved.\n"; +#endif + +#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(argc, argv) + 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 */ + +_PROTOTYPE(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 + +#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 + +#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 + */ + +_PROTOTYPE(static void cleanup,(void)); +_PROTOTYPE(static int tstwlsof,(int tt, char *opt, OFFSET_T sz)); + + +/* + * Main program for dialects that support large files + */ + +int +main(argc, argv) + 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(tt, opt, sz) + 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 index 0000000..66c6262 --- /dev/null +++ b/tests/LTdnlc.c @@ -0,0 +1,426 @@ +/* + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright 2002 Purdue Research Foundation.\nAll rights reserved.\n"; +#endif + +#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 + */ + +_PROTOTYPE(static void cleanup,(void)); +_PROTOTYPE(static char *FindLsofCwd,(int *ff, LTdev_t *cwddc, char *ibuf)); + + +/* + * Main program + */ + +int +main(argc, argv) + 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, "%u", (unsigned int)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(ff, cwddc, ibuf) + 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 index 0000000..1c0d960 --- /dev/null +++ b/tests/LTlib.c @@ -0,0 +1,1119 @@ +/* + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright 2002 Purdue Research Foundation.\nAll rights reserved.\n"; +#endif + +#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 + +# if defined(LT_AIXA) && LT_AIXA>=1 + +/* + * Note: the DEVNO64 and ISDEVNO54 #define's come from , 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 +#define major_X(dp, em) ((int)((x2dev(dp, em) >> 32) & 0xffffffff)) +# endif /* defined(LT_DEV64) */ +#endif /* defined(LT_DIAL_freebsd) */ + + +#if defined(LT_DIAL_osr) +/* + * OpenUNIX-specific items + */ + +#include +#endif /* defined(LT_DIAL_osr) */ + + +#if defined(LT_DIAL_ou) +/* + * OpenUNIX-specific items + */ + +#include +#endif /* defined(LT_DIAL_ou) */ + + +#if defined(LT_DIAL_solaris) +/* + * Solaris-specific items + */ + +#include + + +/* + * 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 + * . */ +# else /* LT_VERS<20501 */ +#define LT_MJX 0x3fff /* Avoid 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_K64) + +/* + * Solaris 64 bit kernel + */ + +#undef X2DEV_T +#define X2DEV_T unsigned long long +#undef XDINDEV +#define XDINDEV 16 + +#define major_X(dp, em) ((int)((x2dev(dp, em) >> 32) & 0xffffffff)) +#define minor_X(dp, em) ((int)(x2dev(dp, em) & 0xffffffff)) +# else /* !defined(LT_K64) */ + +/* + * Solaris 32 bit kernel + */ + +#define major_X(dp, em) ((int)((x2dev(dp, em) >> L_BITSMINOR) & LT_MJX)) +#define minor_X(dp, em) ((int)(x2dev(dp, em) & L_MAXMIN)) +# endif /* LT_K64 */ +#endif /* defined(LT_DIAL_solaris) */ + + +#if defined(LT_DIAL_uw) +/* + * UnixWare-specific items + */ + +#include +#endif /* defined(LT_DIAL_uw) */ + + +/* + * 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 + */ + +_PROTOTYPE(static void closepipe,(void)); +_PROTOTYPE(static void getlsofpath,(void)); +_PROTOTYPE(static int GetOpt,(int ct, char *opt[], char *rules, char **em, + char *pn)); +_PROTOTYPE(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(dev, ldev) + 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, ldev) + 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(opt) + 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(ct, opt, rules, em, pn) + 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(src, len) + 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(nf, em) + 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(ac, av, opt, pn) + 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(x, em) + 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 index 0000000..04bf649 --- /dev/null +++ b/tests/LTlock.c @@ -0,0 +1,769 @@ +/* + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright 2002 Purdue Research Foundation.\nAll rights reserved.\n"; +#endif + +#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(argc, argv) + 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 + */ + +_PROTOTYPE(static void cleanup,(void)); +_PROTOTYPE(static char *lkfile,(int ty)); +_PROTOTYPE(static char *tstwlsof,(char *opt, char *xlk)); +_PROTOTYPE(static char *unlkfile,(int ty)); + + +/* + * Main program for dialects that support locking tests. + */ + +int +main(argc, argv) + 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; + xv = 1; + } 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(ty) + 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(opt, xlk) + 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(ty) + 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 index 0000000..1d20b1b --- /dev/null +++ b/tests/LTnfs.c @@ -0,0 +1,531 @@ +/* + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright 2002 Purdue Research Foundation.\nAll rights reserved.\n"; +#endif + +#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 + */ + +_PROTOTYPE(static void cleanup,(void)); +_PROTOTYPE(static char *FindNFSfile,(int *ff, char *szbuf)); + + +/* + * Main program + */ + +int +main(argc, argv) + 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, 1); + } 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, 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) { + if (NFstat == 2) + (void) unlink(Path); + Path = (char *)NULL; + } + } +} + + +/* + * FindNFSfile() -- find the NFS file with lsof + */ + +static char * +FindNFSfile(ff, szbuf) + 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 index 0000000..7f12e86 --- /dev/null +++ b/tests/LTnlink.c @@ -0,0 +1,586 @@ +/* + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright 2002 Purdue Research Foundation.\nAll rights reserved.\n"; +#endif + +#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 + */ + +_PROTOTYPE(static void cleanup,(void)); +_PROTOTYPE(static char *FindFile,(char *opt, int *ff, int ie, LTdev_t *tfdc, + char *ibuf, char *xlnk, char *szbuf)); + + +/* + * Main program + */ + +int +main(argc, argv) + 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, "%u", (unsigned int)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; + } +/* + * 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/\".\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(opt, ff, ie, tfdc, ibuf, xlnk, szbuf) + 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 index 0000000..bc0750f --- /dev/null +++ b/tests/LTsock.c @@ -0,0 +1,886 @@ +/* + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright 2002 Purdue Research Foundation.\nAll rights reserved.\n"; +#endif + +#include "LsofTest.h" +#include "lsof_fields.h" + +#include +#include +#include +#include +#include + + +/* + * 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_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 + */ + +_PROTOTYPE(static void CleanupClnt,(void)); +_PROTOTYPE(static void CleanupSrvr,(void)); +_PROTOTYPE(static SIGHANDLER_T HandleClntAlarm,(int sig)); +_PROTOTYPE(static SIGHANDLER_T HandleSrvrAlarm,(int sig)); +_PROTOTYPE(static char *FindSock,(int fn)); +_PROTOTYPE(static void StartClnt,(struct sockaddr_in *cad)); + + +/* + * Main program + */ + +int +main(argc, argv) + 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))) { + (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(fn) + 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(sig) + 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(sig) + 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 index 0000000..090e752 --- /dev/null +++ b/tests/LTszoff.c @@ -0,0 +1,509 @@ +/* + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright 2002 Purdue Research Foundation.\nAll rights reserved.\n"; +#endif + +#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() */ + +_PROTOTYPE(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 + */ + +_PROTOTYPE(static void cleanup,(void)); +_PROTOTYPE(static char *testlsof,(int tt, char *opt, char *xval)); + + +/* + * Main program + */ + +int +main(argc, argv) + 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(tt, opt, xval) + 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, "%u", (unsigned int)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 index 0000000..6e12c33 --- /dev/null +++ b/tests/LTunix.c @@ -0,0 +1,364 @@ +/* + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright 2002 Purdue Research Foundation.\nAll rights reserved.\n"; +#endif + +#include "LsofTest.h" +#include "lsof_fields.h" + +#include +#include + + +/* + * 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 + */ + +_PROTOTYPE(static void cleanup,(void)); +_PROTOTYPE(static char *FindUsocks,(void)); + + +/* + * Main program + */ + +int +main(argc, argv) + 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 index 0000000..d1a9c96 --- /dev/null +++ b/tests/LsofTest.h @@ -0,0 +1,366 @@ +/* + * 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 _PROTOTYPE macro provides strict ANSI C prototypes if __STDC__ + * is defined, and old-style K&R prototypes otherwise. + * + * (With thanks to Andy Tanenbaum) + */ + +# if defined(__STDC__) +#define _PROTOTYPE(function, params) function params +# else /* !defined(__STDC__) */ +#define _PROTOTYPE(function, params) function() +# endif /* defined(__STDC__) */ + + +/* + * 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 */ + + +/* + * Necessary header files. + */ + +#include +#include +#include +#include + +#include + +#if defined(LT_DIAL_linux) && LT_VERS>=414014 +#undef major +#include +#endif /* defined(LT_DIAL_linux) && LT_VERS>=414014 */ + +#include +#include + + +/* + * 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 +#include +#include +#include +#include +#undef USE_LSOF_C_OPT +#define USE_LSOF_X_OPT +# endif /* defined(LT_DIAL_aix) */ + + +# if defined(LT_DIAL_bsdi) +/* + * OpenBSD-specific items + */ + +#include +#include +#include +#include +#include +# endif /* defined(LT_DIAL_bsdi) */ + + +# if defined(LT_DIAL_darwin) +/* + * Darwin-specific items + */ + +#include +#include +#include +#include +#include +#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 +#include +#include +#include + +# 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 +#include +#include +#include +#include +# endif /* defined(LT_DIAL_freebsd) */ + + +# if defined(LT_DIAL_linux) +/* + * Linux-specific items + */ + +#include +#include +#include +#include +#include +#undef USE_LSOF_C_OPT +# endif /* defined(LT_DIAL_linux) */ + + +# if defined(LT_DIAL_hpux) +/* + * HP-UX-specific items + */ + +#include +#include +#include +#include +#include +# endif /* defined(LT_DIAL_hpux) */ + + +# if defined(LT_DIAL_netbsd) +/* + * NetBSD-specific items + */ + +#include +#include +#include +#include +#include +# endif /* defined(LT_DIAL_netbsd) */ + + +# if defined(LT_DIAL_openbsd) +/* + * OpenBSD-specific items + */ + +#include +#include +#include +#include +#include +# endif /* defined(LT_DIAL_openbsd) */ + + +# if defined(LT_DIAL_ou) +/* + * OpenUNIX-specific items + */ + +#include +#include +#include +#include +# endif /* defined(LT_DIAL_ou) */ + + +# if defined(LT_DIAL_osr) +/* + * OSR-specific items + */ + +#include +#include +#include +#include +# endif /* defined(LT_DIAL_osr) */ + + +# if defined(LT_DIAL_ns) +/* + * NEXTSTEP-specific items + */ + +#include +#include +#include +#include + +typedef int pid_t; +#define snprintf snpf + +#undef USE_GETCWD +# endif /* defined(LT_DIAL_ns) */ + + +# if defined(LT_DIAL_solaris) +/* + * Solaris-specific items + */ + +#include +#include +#include +#include +#include + +# 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 +#include +#include +#include +# 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." +#define LT_DEF_LSOF_PATH "../lsof" + +# 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. + */ + +_PROTOTYPE(extern char *CanRdKmem,(void)); +_PROTOTYPE(extern char *ConvStatDev,(dev_t *dev, LTdev_t *ldev)); +_PROTOTYPE(extern char *ConvLsofDev,(char *dev, LTdev_t *ldev)); +_PROTOTYPE(extern char *ExecLsof,(char **opt)); +_PROTOTYPE(extern char *IsLsofExec,(void)); +_PROTOTYPE(extern void LTlibClean,(void)); +_PROTOTYPE(extern char *MkStrCpy,(char *src, int *len)); +_PROTOTYPE(extern LTfldo_t *RdFrLsof,(int *nf, char **em)); +_PROTOTYPE(extern void PrtMsg,(char *mp, char *pn)); +_PROTOTYPE(extern void PrtMsgX,(char *mp, char *pn, void (*f)(), int xv)); +_PROTOTYPE(extern int ScanArg,(int ac, char *av[], char *opt, char *pn)); +_PROTOTYPE(extern void StopLsof,(void)); + +#endif /* LSOF_TEST_H */ diff --git a/tests/Makefile b/tests/Makefile new file mode 100644 index 0000000..08574a0 --- /dev/null +++ b/tests/Makefile @@ -0,0 +1,159 @@ +# 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.. + +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* + +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* + +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 index 0000000..480bc2b --- /dev/null +++ b/tests/TestDB @@ -0,0 +1,143 @@ +# 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 diff --git a/usage.c b/usage.c new file mode 100644 index 0000000..6707315 --- /dev/null +++ b/usage.c @@ -0,0 +1,979 @@ +/* + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright 1998 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: usage.c,v 1.33 2018/02/14 14:20:14 abe Exp $"; +#endif + + +#include "lsof.h" +#include "version.h" + + +/* + * Local function prototypes + */ + +_PROTOTYPE(static char *isnullstr,(char *s)); +_PROTOTYPE(static int print_in_col,(int col, char *cp)); +_PROTOTYPE(static void report_HASDCACHE,(int type, char *ttl, char *det)); +_PROTOTYPE(static void report_HASKERNIDCK,(char *pfx, char *verb)); +_PROTOTYPE(static void report_SECURITY,(char *pfx, char *punct)); +_PROTOTYPE(static void report_WARNDEVACCESS,(char *pfx, char *verb, + char *punct)); + + +/* + * isnullstr() - is it a null string? + */ + +static char * +isnullstr(s) + 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(col, cp) + 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(type, ttl, det) + 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(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(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(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(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(xv, fh, version) + int xv; /* exit value */ + int fh; /* ``-F ?'' status */ + int version; /* ``-v'' status */ +{ + char buf[MAXPATHLEN+1], *cp, *cp1, *cp2; + int col, i; + + if (Fhelp || xv) { + (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%sh%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 (xv && !Fhelp) { + (void) fprintf(stderr, + "Use the ``-h'' option to get more help information.\n"); + if (!fh) + Exit(xv); + } + 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"; +# 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"); + +#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, "-- 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(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]", +#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; m must separate %s", + "t from and\n"); + (void) fprintf(stderr, " 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(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(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, " 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) */ + + if ((cp = isnullstr(LSOF_CCDATE))) + (void) fprintf(stderr, " constructed: %s\n", cp); + 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); + (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(1, " ", "\t"); + } + Exit(xv); +} diff --git a/util.c b/util.c new file mode 100644 index 0000000..bdb1d2c --- /dev/null +++ b/util.c @@ -0,0 +1,73 @@ +/* + * 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 and 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. + */ + + +#ifndef lint +static char copyright[] = +"@(#) Copyright 2008 Purdue Research Foundation.\nAll rights reserved.\n"; +static char *rcsid = "$Id: util.c,v 1.1 2008/04/01 11:56:53 abe Exp $"; +#endif + +#if defined(HAS_STRFTIME) +#include +#endif /* defined(HAS_STRFTIME) */ + + +/* + * util_strftime() -- utility function to call strftime(3) without header + * file distractions + */ + +int +util_strftime(fmtr, fmtl, fmt) + 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/version b/version new file mode 100644 index 0000000..2c2ab8d --- /dev/null +++ b/version @@ -0,0 +1 @@ +.ds VN 4.93.2 diff --git a/zipme b/zipme new file mode 100755 index 0000000..33faade --- /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