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/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/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/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